From 307a4ce29eca6e637fe86529e98ad2e7f7a52e7b Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Fri, 16 Jan 2015 15:47:01 +0100 Subject: [PATCH 01/16] fixed bug where opening a cluster without smoothcurves went wrong. --- dist/vis.js | 53984 +++++++++++++++++++-------------------- dist/vis.min.css | 2 +- lib/network/Edge.js | 2 +- lib/network/Network.js | 2 +- 4 files changed, 26995 insertions(+), 26995 deletions(-) diff --git a/dist/vis.js b/dist/vis.js index 506f99f1..9ca71393 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -83,67 +83,67 @@ return /******/ (function(modules) { // webpackBootstrap // utils exports.util = __webpack_require__(1); - exports.DOMutil = __webpack_require__(2); + exports.DOMutil = __webpack_require__(6); // data - exports.DataSet = __webpack_require__(3); - exports.DataView = __webpack_require__(4); - exports.Queue = __webpack_require__(5); + exports.DataSet = __webpack_require__(7); + exports.DataView = __webpack_require__(9); + exports.Queue = __webpack_require__(8); // Graph3d - exports.Graph3d = __webpack_require__(6); + exports.Graph3d = __webpack_require__(10); exports.graph3d = { - Camera: __webpack_require__(7), - Filter: __webpack_require__(8), - Point2d: __webpack_require__(9), - Point3d: __webpack_require__(10), - Slider: __webpack_require__(11), - StepNumber: __webpack_require__(12) + Camera: __webpack_require__(14), + Filter: __webpack_require__(15), + Point2d: __webpack_require__(13), + Point3d: __webpack_require__(12), + Slider: __webpack_require__(16), + StepNumber: __webpack_require__(17) }; // Timeline - exports.Timeline = __webpack_require__(13); - exports.Graph2d = __webpack_require__(14); + exports.Timeline = __webpack_require__(18); + exports.Graph2d = __webpack_require__(42); exports.timeline = { - DateUtil: __webpack_require__(15), - DataStep: __webpack_require__(16), - Range: __webpack_require__(17), - stack: __webpack_require__(18), - TimeStep: __webpack_require__(19), + DateUtil: __webpack_require__(24), + DataStep: __webpack_require__(45), + Range: __webpack_require__(21), + stack: __webpack_require__(28), + TimeStep: __webpack_require__(38), components: { items: { - Item: __webpack_require__(31), - BackgroundItem: __webpack_require__(32), - BoxItem: __webpack_require__(33), - PointItem: __webpack_require__(34), - RangeItem: __webpack_require__(35) + Item: __webpack_require__(30), + BackgroundItem: __webpack_require__(34), + BoxItem: __webpack_require__(32), + PointItem: __webpack_require__(33), + RangeItem: __webpack_require__(29) }, - Component: __webpack_require__(20), - CurrentTime: __webpack_require__(21), - CustomTime: __webpack_require__(22), - DataAxis: __webpack_require__(23), - GraphGroup: __webpack_require__(24), - Group: __webpack_require__(25), - BackgroundGroup: __webpack_require__(26), - ItemSet: __webpack_require__(27), - Legend: __webpack_require__(28), - LineGraph: __webpack_require__(29), - TimeAxis: __webpack_require__(30) + Component: __webpack_require__(23), + CurrentTime: __webpack_require__(39), + CustomTime: __webpack_require__(41), + DataAxis: __webpack_require__(44), + GraphGroup: __webpack_require__(46), + Group: __webpack_require__(27), + BackgroundGroup: __webpack_require__(31), + ItemSet: __webpack_require__(26), + Legend: __webpack_require__(50), + LineGraph: __webpack_require__(43), + TimeAxis: __webpack_require__(37) } }; // Network - exports.Network = __webpack_require__(36); + exports.Network = __webpack_require__(51); exports.network = { - Edge: __webpack_require__(37), - Groups: __webpack_require__(38), - Images: __webpack_require__(39), - Node: __webpack_require__(40), - Popup: __webpack_require__(41), - dotparser: __webpack_require__(42), - gephiParser: __webpack_require__(43) + Edge: __webpack_require__(57), + Groups: __webpack_require__(54), + Images: __webpack_require__(55), + Node: __webpack_require__(56), + Popup: __webpack_require__(58), + dotparser: __webpack_require__(52), + gephiParser: __webpack_require__(53) }; // Deprecated since v3.0.0 @@ -152,8 +152,8 @@ return /******/ (function(modules) { // webpackBootstrap }; // bundled external libraries - exports.moment = __webpack_require__(44); - exports.hammer = __webpack_require__(45); + exports.moment = __webpack_require__(2); + exports.hammer = __webpack_require__(19); /***/ }, @@ -164,7 +164,7 @@ return /******/ (function(modules) { // webpackBootstrap // first check if moment.js is already loaded in the browser window, if so, // use this instance. Else, load via commonjs. - var moment = __webpack_require__(44); + var moment = __webpack_require__(2); /** * Test whether given object is a number @@ -1396,32663 +1396,32566 @@ return /******/ (function(modules) { // webpackBootstrap /* 2 */ /***/ function(module, exports, __webpack_require__) { - // DOM utility methods - - /** - * this prepares the JSON container for allocating SVG elements - * @param JSONcontainer - * @private - */ - exports.prepareElements = function(JSONcontainer) { - // cleanup the redundant svgElements; - for (var elementType in JSONcontainer) { - if (JSONcontainer.hasOwnProperty(elementType)) { - JSONcontainer[elementType].redundant = JSONcontainer[elementType].used; - JSONcontainer[elementType].used = []; - } - } - }; - - /** - * this cleans up all the unused SVG elements. By asking for the parentNode, we only need to supply the JSON container from - * which to remove the redundant elements. - * - * @param JSONcontainer - * @private - */ - exports.cleanupElements = function(JSONcontainer) { - // cleanup the redundant svgElements; - for (var elementType in JSONcontainer) { - if (JSONcontainer.hasOwnProperty(elementType)) { - if (JSONcontainer[elementType].redundant) { - for (var i = 0; i < JSONcontainer[elementType].redundant.length; i++) { - JSONcontainer[elementType].redundant[i].parentNode.removeChild(JSONcontainer[elementType].redundant[i]); - } - JSONcontainer[elementType].redundant = []; - } - } - } - }; - - /** - * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer - * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this. - * - * @param elementType - * @param JSONcontainer - * @param svgContainer - * @returns {*} - * @private - */ - exports.getSVGElement = function (elementType, JSONcontainer, svgContainer) { - var element; - // allocate SVG element, if it doesnt yet exist, create one. - if (JSONcontainer.hasOwnProperty(elementType)) { // this element has been created before - // check if there is an redundant element - if (JSONcontainer[elementType].redundant.length > 0) { - element = JSONcontainer[elementType].redundant[0]; - JSONcontainer[elementType].redundant.shift(); - } - else { - // create a new element and add it to the SVG - element = document.createElementNS('http://www.w3.org/2000/svg', elementType); - svgContainer.appendChild(element); - } - } - else { - // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it. - element = document.createElementNS('http://www.w3.org/2000/svg', elementType); - JSONcontainer[elementType] = {used: [], redundant: []}; - svgContainer.appendChild(element); - } - JSONcontainer[elementType].used.push(element); - return element; - }; - - - /** - * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer - * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this. - * - * @param elementType - * @param JSONcontainer - * @param DOMContainer - * @returns {*} - * @private - */ - exports.getDOMElement = function (elementType, JSONcontainer, DOMContainer, insertBefore) { - var element; - // allocate DOM element, if it doesnt yet exist, create one. - if (JSONcontainer.hasOwnProperty(elementType)) { // this element has been created before - // check if there is an redundant element - if (JSONcontainer[elementType].redundant.length > 0) { - element = JSONcontainer[elementType].redundant[0]; - JSONcontainer[elementType].redundant.shift(); - } - else { - // create a new element and add it to the SVG - element = document.createElement(elementType); - if (insertBefore !== undefined) { - DOMContainer.insertBefore(element, insertBefore); - } - else { - DOMContainer.appendChild(element); - } - } - } - else { - // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it. - element = document.createElement(elementType); - JSONcontainer[elementType] = {used: [], redundant: []}; - if (insertBefore !== undefined) { - DOMContainer.insertBefore(element, insertBefore); - } - else { - DOMContainer.appendChild(element); - } - } - JSONcontainer[elementType].used.push(element); - return element; - }; - - - - - /** - * draw a point object. this is a seperate function because it can also be called by the legend. - * The reason the JSONcontainer and the target SVG svgContainer have to be supplied is so the legend can use these functions - * as well. - * - * @param x - * @param y - * @param group - * @param JSONcontainer - * @param svgContainer - * @returns {*} - */ - exports.drawPoint = function(x, y, group, JSONcontainer, svgContainer) { - var point; - if (group.options.drawPoints.style == 'circle') { - point = exports.getSVGElement('circle',JSONcontainer,svgContainer); - point.setAttributeNS(null, "cx", x); - point.setAttributeNS(null, "cy", y); - point.setAttributeNS(null, "r", 0.5 * group.options.drawPoints.size); - } - else { - point = exports.getSVGElement('rect',JSONcontainer,svgContainer); - point.setAttributeNS(null, "x", x - 0.5*group.options.drawPoints.size); - point.setAttributeNS(null, "y", y - 0.5*group.options.drawPoints.size); - point.setAttributeNS(null, "width", group.options.drawPoints.size); - point.setAttributeNS(null, "height", group.options.drawPoints.size); - } - - if(group.options.drawPoints.styles !== undefined) { - point.setAttributeNS(null, "style", group.group.options.drawPoints.styles); - } - point.setAttributeNS(null, "class", group.className + " point"); - return point; - }; + // first check if moment.js is already loaded in the browser window, if so, + // use this instance. Else, load via commonjs. + module.exports = (typeof window !== 'undefined') && window['moment'] || __webpack_require__(3); - /** - * draw a bar SVG element centered on the X coordinate - * - * @param x - * @param y - * @param className - */ - exports.drawBar = function (x, y, width, height, className, JSONcontainer, svgContainer) { - if (height != 0) { - if (height < 0) { - height *= -1; - y -= height; - } - var rect = exports.getSVGElement('rect',JSONcontainer, svgContainer); - rect.setAttributeNS(null, "x", x - 0.5 * width); - rect.setAttributeNS(null, "y", y); - rect.setAttributeNS(null, "width", width); - rect.setAttributeNS(null, "height", height); - rect.setAttributeNS(null, "class", className); - } - }; /***/ }, /* 3 */ /***/ function(module, exports, __webpack_require__) { - var util = __webpack_require__(1); - var Queue = __webpack_require__(5); - - /** - * DataSet - * - * Usage: - * var dataSet = new DataSet({ - * fieldId: '_id', - * type: { - * // ... - * } - * }); - * - * dataSet.add(item); - * dataSet.add(data); - * dataSet.update(item); - * dataSet.update(data); - * dataSet.remove(id); - * dataSet.remove(ids); - * var data = dataSet.get(); - * var data = dataSet.get(id); - * var data = dataSet.get(ids); - * var data = dataSet.get(ids, options, data); - * dataSet.clear(); - * - * A data set can: - * - add/remove/update data - * - gives triggers upon changes in the data - * - can import/export data in various data formats - * - * @param {Array | DataTable} [data] Optional array with initial data - * @param {Object} [options] Available options: - * {String} fieldId Field name of the id in the - * items, 'id' by default. - * {Object. ['10', '00'] or '-1530' > ['-', '15', '30'] + parseTimezoneChunker = /([\+\-]|\d\d)/gi, - if (Array.isArray(data)) { - // Array - for (var i = 0, len = data.length; i < len; i++) { - id = me._addItem(data[i]); - addedIds.push(id); - } - } - else if (util.isDataTable(data)) { - // Google DataTable - var columns = this._getColumnNames(data); - for (var row = 0, rows = data.getNumberOfRows(); row < rows; row++) { - var item = {}; - for (var col = 0, cols = columns.length; col < cols; col++) { - var field = columns[col]; - item[field] = data.getValue(row, col); - } + // getter and setter names + proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), + unitMillisecondFactors = { + 'Milliseconds' : 1, + 'Seconds' : 1e3, + 'Minutes' : 6e4, + 'Hours' : 36e5, + 'Days' : 864e5, + 'Months' : 2592e6, + 'Years' : 31536e6 + }, - id = me._addItem(item); - addedIds.push(id); - } - } - else if (data instanceof Object) { - // Single item - id = me._addItem(data); - addedIds.push(id); - } - else { - throw new Error('Unknown dataType'); - } + unitAliases = { + ms : 'millisecond', + s : 'second', + m : 'minute', + h : 'hour', + d : 'day', + D : 'date', + w : 'week', + W : 'isoWeek', + M : 'month', + Q : 'quarter', + y : 'year', + DDD : 'dayOfYear', + e : 'weekday', + E : 'isoWeekday', + gg: 'weekYear', + GG: 'isoWeekYear' + }, - if (addedIds.length) { - this._trigger('add', {items: addedIds}, senderId); - } + camelFunctions = { + dayofyear : 'dayOfYear', + isoweekday : 'isoWeekday', + isoweek : 'isoWeek', + weekyear : 'weekYear', + isoweekyear : 'isoWeekYear' + }, - return addedIds; - }; + // format function strings + formatFunctions = {}, - /** - * Update existing items. When an item does not exist, it will be created - * @param {Object | Array | DataTable} data - * @param {String} [senderId] Optional sender id - * @return {Array} updatedIds The ids of the added or updated items - */ - DataSet.prototype.update = function (data, senderId) { - var addedIds = []; - var updatedIds = []; - var updatedData = []; - var me = this; - var fieldId = me._fieldId; - - var addOrUpdate = function (item) { - var id = item[fieldId]; - if (me._data[id]) { - // update item - id = me._updateItem(item); - updatedIds.push(id); - updatedData.push(item); - } - else { - // add new item - id = me._addItem(item); - addedIds.push(id); - } - }; - - if (Array.isArray(data)) { - // Array - for (var i = 0, len = data.length; i < len; i++) { - addOrUpdate(data[i]); - } - } - else if (util.isDataTable(data)) { - // Google DataTable - var columns = this._getColumnNames(data); - for (var row = 0, rows = data.getNumberOfRows(); row < rows; row++) { - var item = {}; - for (var col = 0, cols = columns.length; col < cols; col++) { - var field = columns[col]; - item[field] = data.getValue(row, col); - } - - addOrUpdate(item); - } - } - else if (data instanceof Object) { - // Single item - addOrUpdate(data); - } - else { - throw new Error('Unknown dataType'); - } + // default relative time thresholds + relativeTimeThresholds = { + 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 + }, - if (addedIds.length) { - this._trigger('add', {items: addedIds}, senderId); - } - if (updatedIds.length) { - this._trigger('update', {items: updatedIds, data: updatedData}, senderId); - } + // tokens to ordinalize and pad + ordinalizeTokens = 'DDD w W M D d'.split(' '), + paddedTokens = 'M D H h m s w W'.split(' '), - return addedIds.concat(updatedIds); - }; + formatTokenFunctions = { + M : function () { + return this.month() + 1; + }, + MMM : function (format) { + return this.localeData().monthsShort(this, format); + }, + MMMM : function (format) { + return this.localeData().months(this, format); + }, + D : function () { + return this.date(); + }, + DDD : function () { + return this.dayOfYear(); + }, + d : function () { + return this.day(); + }, + dd : function (format) { + return this.localeData().weekdaysMin(this, format); + }, + ddd : function (format) { + return this.localeData().weekdaysShort(this, format); + }, + dddd : function (format) { + return this.localeData().weekdays(this, format); + }, + w : function () { + return this.week(); + }, + W : function () { + return this.isoWeek(); + }, + YY : function () { + return leftZeroFill(this.year() % 100, 2); + }, + YYYY : function () { + return leftZeroFill(this.year(), 4); + }, + YYYYY : function () { + return leftZeroFill(this.year(), 5); + }, + YYYYYY : function () { + var y = this.year(), sign = y >= 0 ? '+' : '-'; + return sign + leftZeroFill(Math.abs(y), 6); + }, + gg : function () { + return leftZeroFill(this.weekYear() % 100, 2); + }, + gggg : function () { + return leftZeroFill(this.weekYear(), 4); + }, + ggggg : function () { + return leftZeroFill(this.weekYear(), 5); + }, + GG : function () { + return leftZeroFill(this.isoWeekYear() % 100, 2); + }, + GGGG : function () { + return leftZeroFill(this.isoWeekYear(), 4); + }, + GGGGG : function () { + return leftZeroFill(this.isoWeekYear(), 5); + }, + e : function () { + return this.weekday(); + }, + E : function () { + return this.isoWeekday(); + }, + a : function () { + return this.localeData().meridiem(this.hours(), this.minutes(), true); + }, + A : function () { + return this.localeData().meridiem(this.hours(), this.minutes(), false); + }, + H : function () { + return this.hours(); + }, + h : function () { + return this.hours() % 12 || 12; + }, + m : function () { + return this.minutes(); + }, + s : function () { + return this.seconds(); + }, + S : function () { + return toInt(this.milliseconds() / 100); + }, + SS : function () { + return leftZeroFill(toInt(this.milliseconds() / 10), 2); + }, + SSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + SSSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + Z : function () { + var a = this.utcOffset(), + b = '+'; + if (a < 0) { + a = -a; + b = '-'; + } + return b + leftZeroFill(toInt(a / 60), 2) + ':' + leftZeroFill(toInt(a) % 60, 2); + }, + ZZ : function () { + var a = this.utcOffset(), + b = '+'; + if (a < 0) { + a = -a; + b = '-'; + } + return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2); + }, + z : function () { + return this.zoneAbbr(); + }, + zz : function () { + return this.zoneName(); + }, + x : function () { + return this.valueOf(); + }, + X : function () { + return this.unix(); + }, + Q : function () { + return this.quarter(); + } + }, - /** - * Get a data item or multiple items. - * - * Usage: - * - * get() - * get(options: Object) - * get(options: Object, data: Array | DataTable) - * - * get(id: Number | String) - * get(id: Number | String, options: Object) - * get(id: Number | String, options: Object, data: Array | DataTable) - * - * get(ids: Number[] | String[]) - * get(ids: Number[] | String[], options: Object) - * get(ids: Number[] | String[], options: Object, data: Array | DataTable) - * - * Where: - * - * {Number | String} id The id of an item - * {Number[] | String{}} ids An array with ids of items - * {Object} options An Object with options. Available options: - * {String} [returnType] Type of data to be - * returned. Can be 'DataTable' or 'Array' (default) - * {Object.} [type] - * {String[]} [fields] field names to be returned - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * {Array | DataTable} [data] If provided, items will be appended to this - * array or table. Required in case of Google - * DataTable. - * - * @throws Error - */ - DataSet.prototype.get = function (args) { - var me = this; + deprecations = {}, - // parse the arguments - var id, ids, options, data; - var firstType = util.getType(arguments[0]); - if (firstType == 'String' || firstType == 'Number') { - // get(id [, options] [, data]) - id = arguments[0]; - options = arguments[1]; - data = arguments[2]; - } - else if (firstType == 'Array') { - // get(ids [, options] [, data]) - ids = arguments[0]; - options = arguments[1]; - data = arguments[2]; - } - else { - // get([, options] [, data]) - options = arguments[0]; - data = arguments[1]; - } + lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin'], - // determine the return type - var returnType; - if (options && options.returnType) { - var allowedValues = ["DataTable", "Array", "Object"]; - returnType = allowedValues.indexOf(options.returnType) == -1 ? "Array" : options.returnType; + updateInProgress = false; - if (data && (returnType != util.getType(data))) { - throw new Error('Type of parameter "data" (' + util.getType(data) + ') ' + - 'does not correspond with specified options.type (' + options.type + ')'); - } - if (returnType == 'DataTable' && !util.isDataTable(data)) { - throw new Error('Parameter "data" must be a DataTable ' + - 'when options.type is "DataTable"'); + // Pick the first defined of two or three arguments. dfl comes from + // default. + function dfl(a, b, c) { + 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'); + } } - } - else if (data) { - returnType = (util.getType(data) == 'DataTable') ? 'DataTable' : 'Array'; - } - else { - returnType = 'Array'; - } - - // build options - var type = options && options.type || this._options.type; - var filter = options && options.filter; - var items = [], item, itemId, i, len; - // convert items - if (id != undefined) { - // return a single item - item = me._getItem(id, type); - if (filter && !filter(item)) { - item = null; + function hasOwnProp(a, b) { + return hasOwnProperty.call(a, b); } - } - else if (ids != undefined) { - // return a subset of items - for (i = 0, len = ids.length; i < len; i++) { - item = me._getItem(ids[i], type); - if (!filter || filter(item)) { - items.push(item); - } + + function defaultParsingFlags() { + // We need to deep clone this object, and es5 standard is not very + // helpful. + return { + empty : false, + unusedTokens : [], + unusedInput : [], + overflow : -2, + charsLeftOver : 0, + nullInput : false, + invalidMonth : null, + invalidFormat : false, + userInvalidated : false, + iso: false + }; } - } - else { - // return all items - for (itemId in this._data) { - if (this._data.hasOwnProperty(itemId)) { - item = me._getItem(itemId, type); - if (!filter || filter(item)) { - items.push(item); + + function printMsg(msg) { + if (moment.suppressDeprecationWarnings === false && + typeof console !== 'undefined' && console.warn) { + console.warn('Deprecation warning: ' + msg); } - } } - } - - // order the results - if (options && options.order && id == undefined) { - this._sort(items, options.order); - } - // filter fields of the items - if (options && options.fields) { - var fields = options.fields; - if (id != undefined) { - item = this._filterFields(item, fields); - } - else { - for (i = 0, len = items.length; i < len; i++) { - items[i] = this._filterFields(items[i], fields); - } + function deprecate(msg, fn) { + var firstTime = true; + return extend(function () { + if (firstTime) { + printMsg(msg); + firstTime = false; + } + return fn.apply(this, arguments); + }, fn); } - } - // return the results - if (returnType == 'DataTable') { - var columns = this._getColumnNames(data); - if (id != undefined) { - // append a single item to the data table - me._appendRow(data, columns, item); - } - else { - // copy the items to the provided data table - for (i = 0; i < items.length; i++) { - me._appendRow(data, columns, items[i]); - } - } - return data; - } - else if (returnType == "Object") { - var result = {}; - for (i = 0; i < items.length; i++) { - result[items[i].id] = items[i]; + function deprecateSimple(name, msg) { + if (!deprecations[name]) { + printMsg(msg); + deprecations[name] = true; + } } - return result; - } - else { - // return an array - if (id != undefined) { - // a single item - return item; + + function padToken(func, count) { + return function (a) { + return leftZeroFill(func.call(this, a), count); + }; } - else { - // multiple items - if (data) { - // copy the items to the provided array - for (i = 0, len = items.length; i < len; i++) { - data.push(items[i]); - } - return data; - } - else { - // just return our array - return items; - } + function ordinalizeToken(func, period) { + return function (a) { + return this.localeData().ordinal(func.call(this, a), period); + }; } - } - }; - /** - * Get ids of all items or from a filtered set of items. - * @param {Object} [options] An Object with options. Available options: - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * @return {Array} ids - */ - DataSet.prototype.getIds = function (options) { - var data = this._data, - filter = options && options.filter, - order = options && options.order, - type = options && options.type || this._options.type, - i, - len, - id, - item, - items, - ids = []; + function monthDiff(a, b) { + // difference in months + var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()), + // b is in (anchor - 1 month, anchor + 1 month) + anchor = a.clone().add(wholeMonthDiff, 'months'), + anchor2, adjust; - if (filter) { - // get filtered items - if (order) { - // create ordered list - items = []; - for (id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, type); - if (filter(item)) { - items.push(item); - } + if (b - anchor < 0) { + anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor - anchor2); + } else { + anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor2 - anchor); } - } - this._sort(items, order); + return -(wholeMonthDiff + adjust); + } - for (i = 0, len = items.length; i < len; i++) { - ids[i] = items[i][this._fieldId]; - } + while (ordinalizeTokens.length) { + i = ordinalizeTokens.pop(); + formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i); } - else { - // create unordered list - for (id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, type); - if (filter(item)) { - ids.push(item[this._fieldId]); - } - } - } + while (paddedTokens.length) { + i = paddedTokens.pop(); + formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); } - } - else { - // get all items - if (order) { - // create an ordered list - items = []; - for (id in data) { - if (data.hasOwnProperty(id)) { - items.push(data[id]); - } - } + formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); - this._sort(items, order); - for (i = 0, len = items.length; i < len; i++) { - ids[i] = items[i][this._fieldId]; - } - } - else { - // create unordered list - for (id in data) { - if (data.hasOwnProperty(id)) { - item = data[id]; - ids.push(item[this._fieldId]); + function meridiemFixWrap(locale, hour, meridiem) { + var isPm; + + if (meridiem == null) { + // nothing to do + return hour; + } + if (locale.meridiemHour != null) { + return locale.meridiemHour(hour, meridiem); + } else if (locale.isPM != null) { + // Fallback + isPm = locale.isPM(meridiem); + if (isPm && hour < 12) { + hour += 12; + } + if (!isPm && hour === 12) { + hour = 0; + } + return hour; + } else { + // thie is not supposed to happen + return hour; } - } } - } - - return ids; - }; - /** - * Returns the DataSet itself. Is overwritten for example by the DataView, - * which returns the DataSet it is connected to instead. - */ - DataSet.prototype.getDataSet = function () { - return this; - }; - - /** - * Execute a callback function for every item in the dataset. - * @param {function} callback - * @param {Object} [options] Available options: - * {Object.} [type] - * {String[]} [fields] filter fields - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - */ - DataSet.prototype.forEach = function (callback, options) { - var filter = options && options.filter, - type = options && options.type || this._options.type, - data = this._data, - item, - id; - - if (options && options.order) { - // execute forEach on ordered list - var items = this.get(options); + /************************************ + Constructors + ************************************/ - for (var i = 0, len = items.length; i < len; i++) { - item = items[i]; - id = item[this._fieldId]; - callback(item, id); + function Locale() { } - } - else { - // unordered - for (id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, type); - if (!filter || filter(item)) { - callback(item, id); + + // Moment prototype object + function Moment(config, skipOverflow) { + if (skipOverflow !== false) { + checkOverflow(config); + } + copyConfig(this, config); + this._d = new Date(+config._d); + // Prevent infinite loop in case updateOffset creates new moment + // objects. + if (updateInProgress === false) { + updateInProgress = true; + moment.updateOffset(this); + updateInProgress = false; } - } } - } - }; - - /** - * Map every item in the dataset. - * @param {function} callback - * @param {Object} [options] Available options: - * {Object.} [type] - * {String[]} [fields] filter fields - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * @return {Object[]} mappedItems - */ - DataSet.prototype.map = function (callback, options) { - var filter = options && options.filter, - type = options && options.type || this._options.type, - mappedItems = [], - data = this._data, - item; - // convert and filter items - for (var id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, type); - if (!filter || filter(item)) { - mappedItems.push(callback(item, id)); - } - } - } + // Duration Constructor + function Duration(duration) { + var normalizedInput = normalizeObjectUnits(duration), + years = normalizedInput.year || 0, + quarters = normalizedInput.quarter || 0, + months = normalizedInput.month || 0, + weeks = normalizedInput.week || 0, + days = normalizedInput.day || 0, + hours = normalizedInput.hour || 0, + minutes = normalizedInput.minute || 0, + seconds = normalizedInput.second || 0, + milliseconds = normalizedInput.millisecond || 0; - // order items - if (options && options.order) { - this._sort(mappedItems, options.order); - } + // representation for dateAddRemove + this._milliseconds = +milliseconds + + seconds * 1e3 + // 1000 + minutes * 6e4 + // 1000 * 60 + hours * 36e5; // 1000 * 60 * 60 + // Because of dateAddRemove treats 24 hours as different from a + // day when working around DST, we need to store them separately + this._days = +days + + weeks * 7; + // It is impossible translate months into days without knowing + // which months you are are talking about, so we have to store + // it separately. + this._months = +months + + quarters * 3 + + years * 12; - return mappedItems; - }; + this._data = {}; - /** - * Filter the fields of an item - * @param {Object} item - * @param {String[]} fields Field names - * @return {Object} filteredItem - * @private - */ - DataSet.prototype._filterFields = function (item, fields) { - var filteredItem = {}; + this._locale = moment.localeData(); - for (var field in item) { - if (item.hasOwnProperty(field) && (fields.indexOf(field) != -1)) { - filteredItem[field] = item[field]; + this._bubble(); } - } - return filteredItem; - }; + /************************************ + Helpers + ************************************/ - /** - * Sort the provided array with items - * @param {Object[]} items - * @param {String | function} order A field name or custom sort function. - * @private - */ - DataSet.prototype._sort = function (items, order) { - if (util.isString(order)) { - // order by provided field name - var name = order; // field name - items.sort(function (a, b) { - var av = a[name]; - var bv = b[name]; - return (av > bv) ? 1 : ((av < bv) ? -1 : 0); - }); - } - else if (typeof order === 'function') { - // order by sort function - items.sort(order); - } - // TODO: extend order by an Object {field:String, direction:String} - // where direction can be 'asc' or 'desc' - else { - throw new TypeError('Order must be a function or a string'); - } - }; - /** - * Remove an object by pointer or by id - * @param {String | Number | Object | Array} id Object or id, or an array with - * objects or ids to be removed - * @param {String} [senderId] Optional sender id - * @return {Array} removedIds - */ - DataSet.prototype.remove = function (id, senderId) { - var removedIds = [], - i, len, removedId; + function extend(a, b) { + for (var i in b) { + if (hasOwnProp(b, i)) { + a[i] = b[i]; + } + } - if (Array.isArray(id)) { - for (i = 0, len = id.length; i < len; i++) { - removedId = this._remove(id[i]); - if (removedId != null) { - removedIds.push(removedId); - } - } - } - else { - removedId = this._remove(id); - if (removedId != null) { - removedIds.push(removedId); + if (hasOwnProp(b, 'toString')) { + a.toString = b.toString; + } + + if (hasOwnProp(b, 'valueOf')) { + a.valueOf = b.valueOf; + } + + return a; } - } - if (removedIds.length) { - this._trigger('remove', {items: removedIds}, senderId); - } + function copyConfig(to, from) { + var i, prop, val; - return removedIds; - }; + 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; + } - /** - * Remove an item by its id - * @param {Number | String | Object} id id or item - * @returns {Number | String | null} id - * @private - */ - DataSet.prototype._remove = function (id) { - if (util.isNumber(id) || util.isString(id)) { - if (this._data[id]) { - delete this._data[id]; - return id; + if (momentProperties.length > 0) { + for (i in momentProperties) { + prop = momentProperties[i]; + val = from[prop]; + if (typeof val !== 'undefined') { + to[prop] = val; + } + } + } + + return to; } - } - else if (id instanceof Object) { - var itemId = id[this._fieldId]; - if (itemId && this._data[itemId]) { - delete this._data[itemId]; - return itemId; + + function absRound(number) { + if (number < 0) { + return Math.ceil(number); + } else { + return Math.floor(number); + } } - } - return null; - }; - /** - * Clear the data - * @param {String} [senderId] Optional sender id - * @return {Array} removedIds The ids of all removed items - */ - DataSet.prototype.clear = function (senderId) { - var ids = Object.keys(this._data); + // left zero fill a number + // see http://jsperf.com/left-zero-filling for performance comparison + function leftZeroFill(number, targetLength, forceSign) { + var output = '' + Math.abs(number), + sign = number >= 0; - this._data = {}; + while (output.length < targetLength) { + output = '0' + output; + } + return (sign ? (forceSign ? '+' : '') : '-') + output; + } - this._trigger('remove', {items: ids}, senderId); + function positiveMomentsDifference(base, other) { + var res = {milliseconds: 0, months: 0}; - return ids; - }; + res.months = other.month() - base.month() + + (other.year() - base.year()) * 12; + if (base.clone().add(res.months, 'M').isAfter(other)) { + --res.months; + } - /** - * Find the item with maximum value of a specified field - * @param {String} field - * @return {Object | null} item Item containing max value, or null if no items - */ - DataSet.prototype.max = function (field) { - var data = this._data, - max = null, - maxField = null; + res.milliseconds = +other - +(base.clone().add(res.months, 'M')); - for (var id in data) { - if (data.hasOwnProperty(id)) { - var item = data[id]; - var itemField = item[field]; - if (itemField != null && (!max || itemField > maxField)) { - max = item; - maxField = itemField; - } + return res; } - } - - return max; - }; - /** - * Find the item with minimum value of a specified field - * @param {String} field - * @return {Object | null} item Item containing max value, or null if no items - */ - DataSet.prototype.min = function (field) { - var data = this._data, - min = null, - minField = null; + 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; + } - for (var id in data) { - if (data.hasOwnProperty(id)) { - var item = data[id]; - var itemField = item[field]; - if (itemField != null && (!min || itemField < minField)) { - min = item; - minField = itemField; - } + return res; } - } - return min; - }; + // 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; + } - /** - * Find all distinct values of a specified field - * @param {String} field - * @return {Array} values Array containing all distinct values. If data items - * do not contain the specified field are ignored. - * The returned array is unordered. - */ - DataSet.prototype.distinct = function (field) { - var data = this._data; - var values = []; - var fieldType = this._options.type && this._options.type[field] || null; - var count = 0; - var i; + val = typeof val === 'string' ? +val : val; + dur = moment.duration(val, period); + addOrSubtractDurationFromMoment(this, dur, direction); + return this; + }; + } - for (var prop in data) { - if (data.hasOwnProperty(prop)) { - var item = data[prop]; - var value = item[field]; - var exists = false; - for (i = 0; i < count; i++) { - if (values[i] == value) { - exists = true; - break; + function addOrSubtractDurationFromMoment(mom, duration, isAdding, updateOffset) { + var milliseconds = duration._milliseconds, + days = duration._days, + months = duration._months; + updateOffset = updateOffset == null ? true : updateOffset; + + if (milliseconds) { + mom._d.setTime(+mom._d + milliseconds * isAdding); + } + if (days) { + rawSetter(mom, 'Date', rawGetter(mom, 'Date') + days * isAdding); + } + if (months) { + rawMonthSetter(mom, rawGetter(mom, 'Month') + months * isAdding); + } + if (updateOffset) { + moment.updateOffset(mom, days || months); } - } - if (!exists && (value !== undefined)) { - values[count] = value; - count++; - } } - } - if (fieldType) { - for (i = 0; i < values.length; i++) { - values[i] = util.convert(values[i], fieldType); + // check if is an array + function isArray(input) { + return Object.prototype.toString.call(input) === '[object Array]'; } - } - - return values; - }; - - /** - * Add a single item. Will fail when an item with the same id already exists. - * @param {Object} item - * @return {String} id - * @private - */ - DataSet.prototype._addItem = function (item) { - var id = item[this._fieldId]; - if (id != undefined) { - // check whether this id is already taken - if (this._data[id]) { - // item already exists - throw new Error('Cannot add item: item with id ' + id + ' already exists'); + function isDate(input) { + return Object.prototype.toString.call(input) === '[object Date]' || + input instanceof Date; } - } - else { - // generate an id - id = util.randomUUID(); - item[this._fieldId] = id; - } - var d = {}; - for (var field in item) { - if (item.hasOwnProperty(field)) { - var fieldType = this._type[field]; // type may be undefined - d[field] = util.convert(item[field], fieldType); + // compare two arrays, return the number of differences + function compareArrays(array1, array2, dontConvert) { + var len = Math.min(array1.length, array2.length), + lengthDiff = Math.abs(array1.length - array2.length), + diffs = 0, + i; + for (i = 0; i < len; i++) { + if ((dontConvert && array1[i] !== array2[i]) || + (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { + diffs++; + } + } + return diffs + lengthDiff; } - } - this._data[id] = d; - return id; - }; - - /** - * Get an item. Fields can be converted to a specific type - * @param {String} id - * @param {Object.} [types] field types to convert - * @return {Object | null} item - * @private - */ - DataSet.prototype._getItem = function (id, types) { - var field, value; - - // get the item from the dataset - var raw = this._data[id]; - if (!raw) { - return null; - } - - // convert the items field types - var converted = {}; - if (types) { - for (field in raw) { - if (raw.hasOwnProperty(field)) { - value = raw[field]; - converted[field] = util.convert(value, types[field]); - } - } - } - else { - // no field types specified, no converting needed - for (field in raw) { - if (raw.hasOwnProperty(field)) { - value = raw[field]; - converted[field] = value; - } - } - } - return converted; - }; - - /** - * Update a single item: merge with existing item. - * Will fail when the item has no id, or when there does not exist an item - * with the same id. - * @param {Object} item - * @return {String} id - * @private - */ - DataSet.prototype._updateItem = function (item) { - var id = item[this._fieldId]; - if (id == undefined) { - throw new Error('Cannot update item: item has no id (item: ' + JSON.stringify(item) + ')'); - } - var d = this._data[id]; - if (!d) { - // item doesn't exist - throw new Error('Cannot update item: no item with id ' + id + ' found'); - } - - // merge with current item - for (var field in item) { - if (item.hasOwnProperty(field)) { - var fieldType = this._type[field]; // type may be undefined - d[field] = util.convert(item[field], fieldType); + function normalizeUnits(units) { + if (units) { + var lowered = units.toLowerCase().replace(/(.)s$/, '$1'); + units = unitAliases[units] || camelFunctions[lowered] || lowered; + } + return units; } - } - - return id; - }; - - /** - * Get an array with the column names of a Google DataTable - * @param {DataTable} dataTable - * @return {String[]} columnNames - * @private - */ - DataSet.prototype._getColumnNames = function (dataTable) { - var columns = []; - for (var col = 0, cols = dataTable.getNumberOfColumns(); col < cols; col++) { - columns[col] = dataTable.getColumnId(col) || dataTable.getColumnLabel(col); - } - return columns; - }; - /** - * Append an item as a row to the dataTable - * @param dataTable - * @param columns - * @param item - * @private - */ - DataSet.prototype._appendRow = function (dataTable, columns, item) { - var row = dataTable.addRow(); + function normalizeObjectUnits(inputObject) { + var normalizedInput = {}, + normalizedProp, + prop; - for (var col = 0, cols = columns.length; col < cols; col++) { - var field = columns[col]; - dataTable.setValue(row, col, item[field]); - } - }; + for (prop in inputObject) { + if (hasOwnProp(inputObject, prop)) { + normalizedProp = normalizeUnits(prop); + if (normalizedProp) { + normalizedInput[normalizedProp] = inputObject[prop]; + } + } + } - module.exports = DataSet; + return normalizedInput; + } + function makeList(field) { + var count, setter; -/***/ }, -/* 4 */ -/***/ function(module, exports, __webpack_require__) { + if (field.indexOf('week') === 0) { + count = 7; + setter = 'day'; + } + else if (field.indexOf('month') === 0) { + count = 12; + setter = 'month'; + } + else { + return; + } - var util = __webpack_require__(1); - var DataSet = __webpack_require__(3); + moment[field] = function (format, index) { + var i, getter, + method = moment._locale[field], + results = []; - /** - * DataView - * - * a dataview offers a filtered view on a dataset or an other dataview. - * - * @param {DataSet | DataView} data - * @param {Object} [options] Available options: see method get - * - * @constructor DataView - */ - function DataView (data, options) { - this._data = null; - this._ids = {}; // ids of the items currently in memory (just contains a boolean true) - this._options = options || {}; - this._fieldId = 'id'; // name of the field containing id - this._subscribers = {}; // event subscribers + if (typeof format === 'number') { + index = format; + format = undefined; + } - var me = this; - this.listener = function () { - me._onEvent.apply(me, arguments); - }; + getter = function (i) { + var m = moment().utc().set(setter, i); + return method.call(moment._locale, m, format || ''); + }; - this.setData(data); - } + if (index != null) { + return getter(index); + } + else { + for (i = 0; i < count; i++) { + results.push(getter(i)); + } + return results; + } + }; + } - // TODO: implement a function .config() to dynamically update things like configured filter - // and trigger changes accordingly + function toInt(argumentForCoercion) { + var coercedNumber = +argumentForCoercion, + value = 0; - /** - * Set a data source for the view - * @param {DataSet | DataView} data - */ - DataView.prototype.setData = function (data) { - var ids, i, len; + if (coercedNumber !== 0 && isFinite(coercedNumber)) { + if (coercedNumber >= 0) { + value = Math.floor(coercedNumber); + } else { + value = Math.ceil(coercedNumber); + } + } - if (this._data) { - // unsubscribe from current dataset - if (this._data.unsubscribe) { - this._data.unsubscribe('*', this.listener); + return value; } - // trigger a remove of all items in memory - ids = []; - for (var id in this._ids) { - if (this._ids.hasOwnProperty(id)) { - ids.push(id); - } + function daysInMonth(year, month) { + return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); } - this._ids = {}; - this._trigger('remove', {items: ids}); - } - - this._data = data; - - if (this._data) { - // update fieldId - this._fieldId = this._options.fieldId || - (this._data && this._data.options && this._data.options.fieldId) || - 'id'; - // trigger an add of all added items - ids = this._data.getIds({filter: this._options && this._options.filter}); - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - this._ids[id] = true; + function weeksInYear(year, dow, doy) { + return weekOfYear(moment([year, 11, 31 + dow - doy]), dow, doy).week; } - this._trigger('add', {items: ids}); - // subscribe to new dataset - if (this._data.on) { - this._data.on('*', this.listener); + function daysInYear(year) { + return isLeapYear(year) ? 366 : 365; } - } - }; - /** - * Get data from the data view - * - * Usage: - * - * get() - * get(options: Object) - * get(options: Object, data: Array | DataTable) - * - * get(id: Number) - * get(id: Number, options: Object) - * get(id: Number, options: Object, data: Array | DataTable) - * - * get(ids: Number[]) - * get(ids: Number[], options: Object) - * get(ids: Number[], options: Object, data: Array | DataTable) - * - * Where: - * - * {Number | String} id The id of an item - * {Number[] | String{}} ids An array with ids of items - * {Object} options An Object with options. Available options: - * {String} [type] Type of data to be returned. Can - * be 'DataTable' or 'Array' (default) - * {Object.} [convert] - * {String[]} [fields] field names to be returned - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * {Array | DataTable} [data] If provided, items will be appended to this - * array or table. Required in case of Google - * DataTable. - * @param args - */ - DataView.prototype.get = function (args) { - var me = this; + function isLeapYear(year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; + } - // parse the arguments - var ids, options, data; - var firstType = util.getType(arguments[0]); - if (firstType == 'String' || firstType == 'Number' || firstType == 'Array') { - // get(id(s) [, options] [, data]) - ids = arguments[0]; // can be a single id or an array with ids - options = arguments[1]; - data = arguments[2]; - } - else { - // get([, options] [, data]) - options = arguments[0]; - data = arguments[1]; - } + function checkOverflow(m) { + var overflow; + if (m._a && m._pf.overflow === -2) { + overflow = + m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH : + m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE : + m._a[HOUR] < 0 || m._a[HOUR] > 24 || + (m._a[HOUR] === 24 && (m._a[MINUTE] !== 0 || + m._a[SECOND] !== 0 || + m._a[MILLISECOND] !== 0)) ? HOUR : + m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE : + m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND : + m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND : + -1; - // extend the options with the default options and provided options - var viewOptions = util.extend({}, this._options, options); + if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { + overflow = DATE; + } - // create a combined filter method when needed - if (this._options.filter && options && options.filter) { - viewOptions.filter = function (item) { - return me._options.filter(item) && options.filter(item); + m._pf.overflow = overflow; + } } - } - // build up the call to the linked data set - var getArguments = []; - if (ids != undefined) { - getArguments.push(ids); - } - getArguments.push(viewOptions); - getArguments.push(data); + function isValid(m) { + if (m._isValid == null) { + m._isValid = !isNaN(m._d.getTime()) && + m._pf.overflow < 0 && + !m._pf.empty && + !m._pf.invalidMonth && + !m._pf.nullInput && + !m._pf.invalidFormat && + !m._pf.userInvalidated; - return this._data && this._data.get.apply(this._data, getArguments); - }; + if (m._strict) { + m._isValid = m._isValid && + m._pf.charsLeftOver === 0 && + m._pf.unusedTokens.length === 0 && + m._pf.bigHour === undefined; + } + } + return m._isValid; + } - /** - * Get ids of all items or from a filtered set of items. - * @param {Object} [options] An Object with options. Available options: - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * @return {Array} ids - */ - DataView.prototype.getIds = function (options) { - var ids; + function normalizeLocale(key) { + return key ? key.toLowerCase().replace('_', '-') : key; + } - if (this._data) { - var defaultFilter = this._options.filter; - var filter; + // 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; - if (options && options.filter) { - if (defaultFilter) { - filter = function (item) { - return defaultFilter(item) && options.filter(item); + 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++; } - } - else { - filter = options.filter; - } + return null; } - else { - filter = defaultFilter; + + 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]; } - ids = this._data.getIds({ - filter: filter, - order: options && options.order - }); - } - else { - ids = []; - } + // Return a moment from input, that is local/utc/utcOffset equivalent to + // model. + function makeAs(input, model) { + var res, diff; + if (model._isUTC) { + res = model.clone(); + diff = (moment.isMoment(input) || isDate(input) ? + +input : +moment(input)) - (+res); + // Use low-level api, because this fn is low-level api. + res._d.setTime(+res._d + diff); + moment.updateOffset(res, false); + return res; + } else { + return moment(input).local(); + } + } - return ids; - }; + /************************************ + Locale + ************************************/ - /** - * Get the DataSet to which this DataView is connected. In case there is a chain - * of multiple DataViews, the root DataSet of this chain is returned. - * @return {DataSet} dataSet - */ - DataView.prototype.getDataSet = function () { - var dataSet = this; - while (dataSet instanceof DataView) { - dataSet = dataSet._data; - } - return dataSet || null; - }; - /** - * Event listener. Will propagate all events from the connected data set to - * the subscribers of the DataView, but will filter the items and only trigger - * when there are changes in the filtered data set. - * @param {String} event - * @param {Object | null} params - * @param {String} senderId - * @private - */ - DataView.prototype._onEvent = function (event, params, senderId) { - var i, len, id, item, - ids = params && params.items, - data = this._data, - added = [], - updated = [], - removed = []; + extend(Locale.prototype, { - if (ids && data) { - switch (event) { - case 'add': - // filter the ids of the added items - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - item = this.get(id); - if (item) { - this._ids[id] = true; - added.push(id); - } - } + set : function (config) { + var prop, i; + for (i in config) { + prop = config[i]; + if (typeof prop === 'function') { + this[i] = prop; + } else { + this['_' + i] = prop; + } + } + // Lenient ordinal parsing accepts just a number in addition to + // number + (possibly) stuff coming from _ordinalParseLenient. + this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + /\d{1,2}/.source); + }, - break; + _months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), + months : function (m) { + return this._months[m.month()]; + }, - case 'update': - // determine the event from the views viewpoint: an updated - // item can be added, updated, or removed from this view. - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - item = this.get(id); + _monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), + monthsShort : function (m) { + return this._monthsShort[m.month()]; + }, - if (item) { - if (this._ids[id]) { - updated.push(id); + monthsParse : function (monthName, format, strict) { + var i, mom, regex; + + if (!this._monthsParse) { + this._monthsParse = []; + this._longMonthsParse = []; + this._shortMonthsParse = []; } - else { - this._ids[id] = true; - added.push(id); - } - } - else { - if (this._ids[id]) { - delete this._ids[id]; - removed.push(id); - } - else { - // nothing interesting for me :-( - } - } - } - break; - - case 'remove': - // filter the ids of the removed items - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - if (this._ids[id]) { - delete this._ids[id]; - removed.push(id); - } - } + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + mom = moment.utc([2000, i]); + if (strict && !this._longMonthsParse[i]) { + this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i'); + this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i'); + } + if (!strict && !this._monthsParse[i]) { + regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); + this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) { + return i; + } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) { + return i; + } else if (!strict && this._monthsParse[i].test(monthName)) { + return i; + } + } + }, - break; - } + _weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), + weekdays : function (m) { + return this._weekdays[m.day()]; + }, - if (added.length) { - this._trigger('add', {items: added}, senderId); - } - if (updated.length) { - this._trigger('update', {items: updated}, senderId); - } - if (removed.length) { - this._trigger('remove', {items: removed}, senderId); - } - } - }; + _weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), + weekdaysShort : function (m) { + return this._weekdaysShort[m.day()]; + }, - // copy subscription functionality from DataSet - DataView.prototype.on = DataSet.prototype.on; - DataView.prototype.off = DataSet.prototype.off; - DataView.prototype._trigger = DataSet.prototype._trigger; + _weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), + weekdaysMin : function (m) { + return this._weekdaysMin[m.day()]; + }, - // TODO: make these functions deprecated (replaced with `on` and `off` since version 0.5) - DataView.prototype.subscribe = DataView.prototype.on; - DataView.prototype.unsubscribe = DataView.prototype.off; + weekdaysParse : function (weekdayName) { + var i, mom, regex; - module.exports = DataView; + if (!this._weekdaysParse) { + this._weekdaysParse = []; + } -/***/ }, -/* 5 */ -/***/ function(module, exports, __webpack_require__) { + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + if (!this._weekdaysParse[i]) { + mom = moment([2000, 1]).day(i); + regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); + this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (this._weekdaysParse[i].test(weekdayName)) { + return i; + } + } + }, - /** - * A queue - * @param {Object} options - * Available options: - * - delay: number When provided, the queue will be flushed - * automatically after an inactivity of this delay - * in milliseconds. - * Default value is null. - * - max: number When the queue exceeds the given maximum number - * of entries, the queue is flushed automatically. - * Default value of max is Infinity. - * @constructor - */ - function Queue(options) { - // options - this.delay = null; - this.max = Infinity; + _longDateFormat : { + LTS : 'h:mm:ss A', + 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]; + if (!output && this._longDateFormat[key.toUpperCase()]) { + output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { + return val.slice(1); + }); + this._longDateFormat[key] = output; + } + return output; + }, - // properties - this._queue = []; - this._timeout = null; - this._extended = null; + isPM : function (input) { + // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays + // Using charAt should be more compatible. + return ((input + '').toLowerCase().charAt(0) === 'p'); + }, - this.setOptions(options); - } + _meridiemParse : /[ap]\.?m?\.?/i, + meridiem : function (hours, minutes, isLower) { + if (hours > 11) { + return isLower ? 'pm' : 'PM'; + } else { + return isLower ? 'am' : 'AM'; + } + }, - /** - * Update the configuration of the queue - * @param {Object} options - * Available options: - * - delay: number When provided, the queue will be flushed - * automatically after an inactivity of this delay - * in milliseconds. - * Default value is null. - * - max: number When the queue exceeds the given maximum number - * of entries, the queue is flushed automatically. - * Default value of max is Infinity. - * @param options - */ - Queue.prototype.setOptions = function (options) { - if (options && typeof options.delay !== 'undefined') { - this.delay = options.delay; - } - if (options && typeof options.max !== 'undefined') { - this.max = options.max; - } - this._flushIfNeeded(); - }; + _calendar : { + sameDay : '[Today at] LT', + nextDay : '[Tomorrow at] LT', + nextWeek : 'dddd [at] LT', + lastDay : '[Yesterday at] LT', + lastWeek : '[Last] dddd [at] LT', + sameElse : 'L' + }, + calendar : function (key, mom, now) { + var output = this._calendar[key]; + return typeof output === 'function' ? output.apply(mom, [now]) : output; + }, - /** - * Extend an object with queuing functionality. - * The object will be extended with a function flush, and the methods provided - * in options.replace will be replaced with queued ones. - * @param {Object} object - * @param {Object} options - * Available options: - * - replace: Array. - * A list with method names of the methods - * on the object to be replaced with queued ones. - * - delay: number When provided, the queue will be flushed - * automatically after an inactivity of this delay - * in milliseconds. - * Default value is null. - * - max: number When the queue exceeds the given maximum number - * of entries, the queue is flushed automatically. - * Default value of max is Infinity. - * @return {Queue} Returns the created queue - */ - Queue.extend = function (object, options) { - var queue = new Queue(options); + _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' + }, - if (object.flush !== undefined) { - throw new Error('Target object already has a property flush'); - } - object.flush = function () { - queue.flush(); - }; + 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); + }, - var methods = [{ - name: 'flush', - original: undefined - }]; + pastFuture : function (diff, output) { + var format = this._relativeTime[diff > 0 ? 'future' : 'past']; + return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); + }, - if (options && options.replace) { - for (var i = 0; i < options.replace.length; i++) { - var name = options.replace[i]; - methods.push({ - name: name, - original: object[name] - }); - queue.replace(object, name); - } - } + ordinal : function (number) { + return this._ordinal.replace('%d', number); + }, + _ordinal : '%d', + _ordinalParse : /\d{1,2}/, - queue._extended = { - object: object, - methods: methods - }; + preparse : function (string) { + return string; + }, - return queue; - }; + postformat : function (string) { + return string; + }, - /** - * Destroy the queue. The queue will first flush all queued actions, and in - * case it has extended an object, will restore the original object. - */ - Queue.prototype.destroy = function () { - this.flush(); + week : function (mom) { + return weekOfYear(mom, this._week.dow, this._week.doy).week; + }, - if (this._extended) { - var object = this._extended.object; - var methods = this._extended.methods; - for (var i = 0; i < methods.length; i++) { - var method = methods[i]; - if (method.original) { - object[method.name] = method.original; - } - else { - delete object[method.name]; - } - } - this._extended = null; - } - }; + _week : { + dow : 0, // Sunday is the first day of the week. + doy : 6 // The week that contains Jan 1st is the first week of the year. + }, - /** - * Replace a method on an object with a queued version - * @param {Object} object Object having the method - * @param {string} method The method name - */ - Queue.prototype.replace = function(object, method) { - var me = this; - var original = object[method]; - if (!original) { - throw new Error('Method ' + method + ' undefined'); - } + firstDayOfWeek : function () { + return this._week.dow; + }, - object[method] = function () { - // create an Array with the arguments - var args = []; - for (var i = 0; i < arguments.length; i++) { - args[i] = arguments[i]; - } + firstDayOfYear : function () { + return this._week.doy; + }, - // add this call to the queue - me.queue({ - args: args, - fn: original, - context: this + _invalidDate: 'Invalid date', + invalidDate: function () { + return this._invalidDate; + } }); - }; - }; - - /** - * Queue a call - * @param {function | {fn: function, args: Array} | {fn: function, args: Array, context: Object}} entry - */ - Queue.prototype.queue = function(entry) { - if (typeof entry === 'function') { - this._queue.push({fn: entry}); - } - else { - this._queue.push(entry); - } - - this._flushIfNeeded(); - }; - - /** - * Check whether the queue needs to be flushed - * @private - */ - Queue.prototype._flushIfNeeded = function () { - // flush when the maximum is exceeded. - if (this._queue.length > this.max) { - this.flush(); - } - - // flush after a period of inactivity when a delay is configured - clearTimeout(this._timeout); - if (this.queue.length > 0 && typeof this.delay === 'number') { - var me = this; - this._timeout = setTimeout(function () { - me.flush(); - }, this.delay); - } - }; - - /** - * Flush all queued calls - */ - Queue.prototype.flush = function () { - while (this._queue.length > 0) { - var entry = this._queue.shift(); - entry.fn.apply(entry.context || entry.fn, entry.args || []); - } - }; - module.exports = Queue; + /************************************ + Formatting + ************************************/ -/***/ }, -/* 6 */ -/***/ function(module, exports, __webpack_require__) { + function removeFormattingTokens(input) { + if (input.match(/\[[\s\S]/)) { + return input.replace(/^\[|\]$/g, ''); + } + return input.replace(/\\/g, ''); + } - var Emitter = __webpack_require__(56); - var DataSet = __webpack_require__(3); - var DataView = __webpack_require__(4); - var util = __webpack_require__(1); - var Point3d = __webpack_require__(10); - var Point2d = __webpack_require__(9); - var Camera = __webpack_require__(7); - var Filter = __webpack_require__(8); - var Slider = __webpack_require__(11); - var StepNumber = __webpack_require__(12); + function makeFormatFunction(format) { + var array = format.match(formattingTokens), i, length; - /** - * @constructor Graph3d - * Graph3d displays data in 3d. - * - * Graph3d is developed in javascript as a Google Visualization Chart. - * - * @param {Element} container The DOM element in which the Graph3d will - * be created. Normally a div element. - * @param {DataSet | DataView | Array} [data] - * @param {Object} [options] - */ - function Graph3d(container, data, options) { - if (!(this instanceof Graph3d)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } + for (i = 0, length = array.length; i < length; i++) { + if (formatTokenFunctions[array[i]]) { + array[i] = formatTokenFunctions[array[i]]; + } else { + array[i] = removeFormattingTokens(array[i]); + } + } - // create variables and set default values - this.containerElement = container; - this.width = '400px'; - this.height = '400px'; - this.margin = 10; // px - this.defaultXCenter = '55%'; - this.defaultYCenter = '50%'; + return function (mom) { + var output = ''; + for (i = 0; i < length; i++) { + output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; + } + return output; + }; + } - this.xLabel = 'x'; - this.yLabel = 'y'; - this.zLabel = 'z'; + // format date using native date object + function formatMoment(m, format) { + if (!m.isValid()) { + return m.localeData().invalidDate(); + } - var passValueFn = function(v) { return v; }; - this.xValueLabel = passValueFn; - this.yValueLabel = passValueFn; - this.zValueLabel = passValueFn; - - this.filterLabel = 'time'; - this.legendLabel = 'value'; + format = expandFormat(format, m.localeData()); - this.style = Graph3d.STYLE.DOT; - this.showPerspective = true; - this.showGrid = true; - this.keepAspectRatio = true; - this.showShadow = false; - this.showGrayBottom = false; // TODO: this does not work correctly - this.showTooltip = false; - this.verticalRatio = 0.5; // 0.1 to 1.0, where 1.0 results in a 'cube' + if (!formatFunctions[format]) { + formatFunctions[format] = makeFormatFunction(format); + } - this.animationInterval = 1000; // milliseconds - this.animationPreload = false; + return formatFunctions[format](m); + } - this.camera = new Camera(); - this.eye = new Point3d(0, 0, -1); // TODO: set eye.z about 3/4 of the width of the window? + function expandFormat(format, locale) { + var i = 5; - this.dataTable = null; // The original data table - this.dataPoints = null; // The table with point objects + function replaceLongDateFormatTokens(input) { + return locale.longDateFormat(input) || input; + } - // the column indexes - this.colX = undefined; - this.colY = undefined; - this.colZ = undefined; - this.colValue = undefined; - this.colFilter = undefined; + localFormattingTokens.lastIndex = 0; + while (i >= 0 && localFormattingTokens.test(format)) { + format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); + localFormattingTokens.lastIndex = 0; + i -= 1; + } - this.xMin = 0; - this.xStep = undefined; // auto by default - this.xMax = 1; - this.yMin = 0; - this.yStep = undefined; // auto by default - this.yMax = 1; - this.zMin = 0; - this.zStep = undefined; // auto by default - this.zMax = 1; - this.valueMin = 0; - this.valueMax = 1; - this.xBarWidth = 1; - this.yBarWidth = 1; - // TODO: customize axis range + return format; + } - // constants - this.colorAxis = '#4D4D4D'; - this.colorGrid = '#D3D3D3'; - this.colorDot = '#7DC1FF'; - this.colorDotBorder = '#3267D2'; - // create a frame and canvas - this.create(); + /************************************ + Parsing + ************************************/ - // apply options (also when undefined) - this.setOptions(options); - // apply data - if (data) { - this.setData(data); - } - } - - // Extend Graph3d with an Emitter mixin - Emitter(Graph3d.prototype); + // get the regex to find the next token + function getParseRegexForToken(token, config) { + var a, strict = config._strict; + switch (token) { + case 'Q': + return parseTokenOneDigit; + case 'DDDD': + return parseTokenThreeDigits; + case 'YYYY': + case 'GGGG': + case 'gggg': + return strict ? parseTokenFourDigits : parseTokenOneToFourDigits; + case 'Y': + case 'G': + case 'g': + return parseTokenSignedNumber; + case 'YYYYYY': + case 'YYYYY': + case 'GGGGG': + case 'ggggg': + return strict ? parseTokenSixDigits : parseTokenOneToSixDigits; + case 'S': + if (strict) { + return parseTokenOneDigit; + } + /* falls through */ + case 'SS': + if (strict) { + return parseTokenTwoDigits; + } + /* falls through */ + case 'SSS': + if (strict) { + return parseTokenThreeDigits; + } + /* falls through */ + case 'DDD': + return parseTokenOneToThreeDigits; + case 'MMM': + case 'MMMM': + case 'dd': + case 'ddd': + case 'dddd': + return parseTokenWord; + case 'a': + case 'A': + return config._locale._meridiemParse; + case 'x': + return parseTokenOffsetMs; + case 'X': + return parseTokenTimestampMs; + case 'Z': + case 'ZZ': + return parseTokenTimezone; + case 'T': + return parseTokenT; + case 'SSSS': + return parseTokenDigits; + case 'MM': + case 'DD': + case 'YY': + case 'GG': + case 'gg': + case 'HH': + case 'hh': + case 'mm': + case 'ss': + case 'ww': + case 'WW': + return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits; + case 'M': + case 'D': + case 'd': + case 'H': + case 'h': + case 'm': + case 's': + case 'w': + case 'W': + case 'e': + case 'E': + return parseTokenOneOrTwoDigits; + case 'Do': + return strict ? config._locale._ordinalParse : config._locale._ordinalParseLenient; + default : + a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), 'i')); + return a; + } + } - /** - * Calculate the scaling values, dependent on the range in x, y, and z direction - */ - Graph3d.prototype._setScale = function() { - this.scale = new Point3d(1 / (this.xMax - this.xMin), - 1 / (this.yMax - this.yMin), - 1 / (this.zMax - this.zMin)); + function utcOffsetFromString(string) { + string = string || ''; + var possibleTzMatches = (string.match(parseTokenTimezone) || []), + tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [], + parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0], + minutes = +(parts[1] * 60) + toInt(parts[2]); - // keep aspect ration between x and y scale if desired - if (this.keepAspectRatio) { - if (this.scale.x < this.scale.y) { - //noinspection JSSuspiciousNameCombination - this.scale.y = this.scale.x; - } - else { - //noinspection JSSuspiciousNameCombination - this.scale.x = this.scale.y; + return parts[0] === '+' ? minutes : -minutes; } - } - - // scale the vertical axis - this.scale.z *= this.verticalRatio; - // TODO: can this be automated? verticalRatio? - // determine scale for (optional) value - this.scale.value = 1 / (this.valueMax - this.valueMin); + // function to convert string input to date + function addTimeToArrayFromToken(token, input, config) { + var a, datePartArray = config._a; - // position the camera arm - var xCenter = (this.xMax + this.xMin) / 2 * this.scale.x; - var yCenter = (this.yMax + this.yMin) / 2 * this.scale.y; - var zCenter = (this.zMax + this.zMin) / 2 * this.scale.z; - this.camera.setArmLocation(xCenter, yCenter, zCenter); - }; + switch (token) { + // QUARTER + case 'Q': + if (input != null) { + datePartArray[MONTH] = (toInt(input) - 1) * 3; + } + break; + // MONTH + case 'M' : // fall through to MM + case 'MM' : + if (input != null) { + datePartArray[MONTH] = toInt(input) - 1; + } + break; + case 'MMM' : // fall through to MMMM + case 'MMMM' : + a = config._locale.monthsParse(input, token, config._strict); + // if we didn't find a month name, mark the date as invalid. + if (a != null) { + datePartArray[MONTH] = a; + } else { + config._pf.invalidMonth = input; + } + break; + // DAY OF MONTH + case 'D' : // fall through to DD + case 'DD' : + if (input != null) { + datePartArray[DATE] = toInt(input); + } + break; + case 'Do' : + if (input != null) { + datePartArray[DATE] = toInt(parseInt( + input.match(/\d{1,2}/)[0], 10)); + } + break; + // DAY OF YEAR + case 'DDD' : // fall through to DDDD + case 'DDDD' : + if (input != null) { + config._dayOfYear = toInt(input); + } + break; + // YEAR + case 'YY' : + datePartArray[YEAR] = moment.parseTwoDigitYear(input); + break; + case 'YYYY' : + case 'YYYYY' : + case 'YYYYYY' : + datePartArray[YEAR] = toInt(input); + break; + // AM / PM + case 'a' : // fall through to A + case 'A' : + config._meridiem = input; + // config._isPm = config._locale.isPM(input); + break; + // HOUR + case 'h' : // fall through to hh + case 'hh' : + config._pf.bigHour = true; + /* falls through */ + case 'H' : // fall through to HH + case 'HH' : + datePartArray[HOUR] = toInt(input); + break; + // MINUTE + case 'm' : // fall through to mm + case 'mm' : + datePartArray[MINUTE] = toInt(input); + break; + // SECOND + case 's' : // fall through to ss + case 'ss' : + datePartArray[SECOND] = toInt(input); + break; + // MILLISECOND + case 'S' : + case 'SS' : + case 'SSS' : + case 'SSSS' : + datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000); + break; + // UNIX OFFSET (MILLISECONDS) + case 'x': + config._d = new Date(toInt(input)); + break; + // UNIX TIMESTAMP WITH MS + case 'X': + config._d = new Date(parseFloat(input) * 1000); + break; + // TIMEZONE + case 'Z' : // fall through to ZZ + case 'ZZ' : + config._useUTC = true; + config._tzm = utcOffsetFromString(input); + break; + // WEEKDAY - human + case 'dd': + case 'ddd': + case 'dddd': + 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 || {}; + config._w['d'] = a; + } else { + config._pf.invalidWeekday = input; + } + break; + // WEEK, WEEK DAY - numeric + case 'w': + case 'ww': + case 'W': + case 'WW': + case 'd': + case 'e': + case 'E': + token = token.substr(0, 1); + /* falls through */ + case 'gggg': + case 'GGGG': + case 'GGGGG': + token = token.substr(0, 2); + if (input) { + config._w = config._w || {}; + config._w[token] = toInt(input); + } + break; + case 'gg': + case 'GG': + config._w = config._w || {}; + config._w[token] = moment.parseTwoDigitYear(input); + } + } - /** - * Convert a 3D location to a 2D location on screen - * http://en.wikipedia.org/wiki/3D_projection - * @param {Point3d} point3d A 3D point with parameters x, y, z - * @return {Point2d} point2d A 2D point with parameters x, y - */ - Graph3d.prototype._convert3Dto2D = function(point3d) { - var translation = this._convertPointToTranslation(point3d); - return this._convertTranslationToScreen(translation); - }; + function dayOfYearFromWeekInfo(config) { + var w, weekYear, week, weekday, dow, doy, temp; - /** - * Convert a 3D location its translation seen from the camera - * http://en.wikipedia.org/wiki/3D_projection - * @param {Point3d} point3d A 3D point with parameters x, y, z - * @return {Point3d} translation A 3D point with parameters x, y, z This is - * the translation of the point, seen from the - * camera - */ - Graph3d.prototype._convertPointToTranslation = function(point3d) { - var ax = point3d.x * this.scale.x, - ay = point3d.y * this.scale.y, - az = point3d.z * this.scale.z, + w = config._w; + if (w.GG != null || w.W != null || w.E != null) { + dow = 1; + doy = 4; - cx = this.camera.getCameraLocation().x, - cy = this.camera.getCameraLocation().y, - cz = this.camera.getCameraLocation().z, + // TODO: We need to take the current isoWeekYear, but that depends on + // how we interpret now (local, utc, fixed offset). So create + // a now version of current config (take local/utc/offset flags, and + // create now). + weekYear = dfl(w.GG, config._a[YEAR], weekOfYear(moment(), 1, 4).year); + week = dfl(w.W, 1); + weekday = dfl(w.E, 1); + } else { + dow = config._locale._week.dow; + doy = config._locale._week.doy; - // calculate angles - sinTx = Math.sin(this.camera.getCameraRotation().x), - cosTx = Math.cos(this.camera.getCameraRotation().x), - sinTy = Math.sin(this.camera.getCameraRotation().y), - cosTy = Math.cos(this.camera.getCameraRotation().y), - sinTz = Math.sin(this.camera.getCameraRotation().z), - cosTz = Math.cos(this.camera.getCameraRotation().z), + weekYear = dfl(w.gg, config._a[YEAR], weekOfYear(moment(), dow, doy).year); + week = dfl(w.w, 1); - // calculate translation - dx = cosTy * (sinTz * (ay - cy) + cosTz * (ax - cx)) - sinTy * (az - cz), - dy = sinTx * (cosTy * (az - cz) + sinTy * (sinTz * (ay - cy) + cosTz * (ax - cx))) + cosTx * (cosTz * (ay - cy) - sinTz * (ax-cx)), - dz = cosTx * (cosTy * (az - cz) + sinTy * (sinTz * (ay - cy) + cosTz * (ax - cx))) - sinTx * (cosTz * (ay - cy) - sinTz * (ax-cx)); + if (w.d != null) { + // weekday -- low day numbers are considered next week + weekday = w.d; + if (weekday < dow) { + ++week; + } + } else if (w.e != null) { + // local weekday -- counting starts from begining of week + weekday = w.e + dow; + } else { + // default to begining of week + weekday = dow; + } + } + temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow); - return new Point3d(dx, dy, dz); - }; + config._a[YEAR] = temp.year; + config._dayOfYear = temp.dayOfYear; + } - /** - * Convert a translation point to a point on the screen - * @param {Point3d} translation A 3D point with parameters x, y, z This is - * the translation of the point, seen from the - * camera - * @return {Point2d} point2d A 2D point with parameters x, y - */ - Graph3d.prototype._convertTranslationToScreen = function(translation) { - var ex = this.eye.x, - ey = this.eye.y, - ez = this.eye.z, - dx = translation.x, - dy = translation.y, - dz = translation.z; + // convert an array to a date. + // the array should mirror the parameters below + // note: all values past the year are optional and will default to the lowest possible value. + // [year, month, day , hour, minute, second, millisecond] + function dateFromConfig(config) { + var i, date, input = [], currentDate, yearToUse; - // calculate position on screen from translation - var bx; - var by; - if (this.showPerspective) { - bx = (dx - ex) * (ez / dz); - by = (dy - ey) * (ez / dz); - } - else { - bx = dx * -(ez / this.camera.getArmLength()); - by = dy * -(ez / this.camera.getArmLength()); - } + if (config._d) { + return; + } - // shift and scale the point to the center of the screen - // use the width of the graph to scale both horizontally and vertically. - return new Point2d( - this.xcenter + bx * this.frame.canvas.clientWidth, - this.ycenter - by * this.frame.canvas.clientWidth); - }; + currentDate = currentDateArray(config); - /** - * Set the background styling for the graph - * @param {string | {fill: string, stroke: string, strokeWidth: string}} backgroundColor - */ - Graph3d.prototype._setBackgroundColor = function(backgroundColor) { - var fill = 'white'; - var stroke = 'gray'; - var strokeWidth = 1; + //compute day of the year from weeks and weekdays + if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { + dayOfYearFromWeekInfo(config); + } - if (typeof(backgroundColor) === 'string') { - fill = backgroundColor; - stroke = 'none'; - strokeWidth = 0; - } - else if (typeof(backgroundColor) === 'object') { - if (backgroundColor.fill !== undefined) fill = backgroundColor.fill; - if (backgroundColor.stroke !== undefined) stroke = backgroundColor.stroke; - if (backgroundColor.strokeWidth !== undefined) strokeWidth = backgroundColor.strokeWidth; - } - else if (backgroundColor === undefined) { - // use use defaults - } - else { - throw 'Unsupported type of backgroundColor'; - } + //if the day of the year is set, figure out what it is + if (config._dayOfYear) { + yearToUse = dfl(config._a[YEAR], currentDate[YEAR]); - this.frame.style.backgroundColor = fill; - this.frame.style.borderColor = stroke; - this.frame.style.borderWidth = strokeWidth + 'px'; - this.frame.style.borderStyle = 'solid'; - }; + if (config._dayOfYear > daysInYear(yearToUse)) { + config._pf._overflowDayOfYear = true; + } + date = makeUTCDate(yearToUse, 0, config._dayOfYear); + config._a[MONTH] = date.getUTCMonth(); + config._a[DATE] = date.getUTCDate(); + } - /// enumerate the available styles - Graph3d.STYLE = { - BAR: 0, - BARCOLOR: 1, - BARSIZE: 2, - DOT : 3, - DOTLINE : 4, - DOTCOLOR: 5, - DOTSIZE: 6, - GRID : 7, - LINE: 8, - SURFACE : 9 - }; + // Default to current date. + // * if no year, month, day of month are given, default to today + // * if day of month is given, default month and year + // * if month is given, default only year + // * if year is given, don't default anything + for (i = 0; i < 3 && config._a[i] == null; ++i) { + config._a[i] = input[i] = currentDate[i]; + } - /** - * Retrieve the style index from given styleName - * @param {string} styleName Style name such as 'dot', 'grid', 'dot-line' - * @return {Number} styleNumber Enumeration value representing the style, or -1 - * when not found - */ - Graph3d.prototype._getStyleNumber = function(styleName) { - switch (styleName) { - case 'dot': return Graph3d.STYLE.DOT; - case 'dot-line': return Graph3d.STYLE.DOTLINE; - case 'dot-color': return Graph3d.STYLE.DOTCOLOR; - case 'dot-size': return Graph3d.STYLE.DOTSIZE; - case 'line': return Graph3d.STYLE.LINE; - case 'grid': return Graph3d.STYLE.GRID; - case 'surface': return Graph3d.STYLE.SURFACE; - case 'bar': return Graph3d.STYLE.BAR; - case 'bar-color': return Graph3d.STYLE.BARCOLOR; - case 'bar-size': return Graph3d.STYLE.BARSIZE; - } + // Zero out whatever was not defaulted, including time + for (; i < 7; i++) { + config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; + } - return -1; - }; + // Check for 24:00:00.000 + if (config._a[HOUR] === 24 && + config._a[MINUTE] === 0 && + config._a[SECOND] === 0 && + config._a[MILLISECOND] === 0) { + config._nextDay = true; + config._a[HOUR] = 0; + } - /** - * Determine the indexes of the data columns, based on the given style and data - * @param {DataSet} data - * @param {Number} style - */ - Graph3d.prototype._determineColumnIndexes = function(data, style) { - if (this.style === Graph3d.STYLE.DOT || - this.style === Graph3d.STYLE.DOTLINE || - this.style === Graph3d.STYLE.LINE || - this.style === Graph3d.STYLE.GRID || - this.style === Graph3d.STYLE.SURFACE || - this.style === Graph3d.STYLE.BAR) { - // 3 columns expected, and optionally a 4th with filter values - this.colX = 0; - this.colY = 1; - this.colZ = 2; - this.colValue = undefined; + config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input); + // Apply timezone offset from input. The actual utcOffset can be changed + // with parseZone. + if (config._tzm != null) { + config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); + } - if (data.getNumberOfColumns() > 3) { - this.colFilter = 3; + if (config._nextDay) { + config._a[HOUR] = 24; + } } - } - else if (this.style === Graph3d.STYLE.DOTCOLOR || - this.style === Graph3d.STYLE.DOTSIZE || - this.style === Graph3d.STYLE.BARCOLOR || - this.style === Graph3d.STYLE.BARSIZE) { - // 4 columns expected, and optionally a 5th with filter values - this.colX = 0; - this.colY = 1; - this.colZ = 2; - this.colValue = 3; - if (data.getNumberOfColumns() > 4) { - this.colFilter = 4; - } - } - else { - throw 'Unknown style "' + this.style + '"'; - } - }; + function dateFromObject(config) { + var normalizedInput; - Graph3d.prototype.getNumberOfRows = function(data) { - return data.length; - } + if (config._d) { + return; + } + normalizedInput = normalizeObjectUnits(config._i); + config._a = [ + normalizedInput.year, + normalizedInput.month, + normalizedInput.day || normalizedInput.date, + normalizedInput.hour, + normalizedInput.minute, + normalizedInput.second, + normalizedInput.millisecond + ]; - Graph3d.prototype.getNumberOfColumns = function(data) { - var counter = 0; - for (var column in data[0]) { - if (data[0].hasOwnProperty(column)) { - counter++; + dateFromConfig(config); } - } - return counter; - } - - Graph3d.prototype.getDistinctValues = function(data, column) { - var distinctValues = []; - for (var i = 0; i < data.length; i++) { - if (distinctValues.indexOf(data[i][column]) == -1) { - distinctValues.push(data[i][column]); + function currentDateArray(config) { + var now = new Date(); + if (config._useUTC) { + return [ + now.getUTCFullYear(), + now.getUTCMonth(), + now.getUTCDate() + ]; + } else { + return [now.getFullYear(), now.getMonth(), now.getDate()]; + } } - } - return distinctValues; - } + // date from string and format string + function makeDateFromStringAndFormat(config) { + if (config._f === moment.ISO_8601) { + parseISO(config); + return; + } - Graph3d.prototype.getColumnRange = function(data,column) { - var minMax = {min:data[0][column],max:data[0][column]}; - for (var i = 0; i < data.length; i++) { - if (minMax.min > data[i][column]) { minMax.min = data[i][column]; } - if (minMax.max < data[i][column]) { minMax.max = data[i][column]; } - } - return minMax; - }; + config._a = []; + config._pf.empty = true; - /** - * Initialize the data from the data table. Calculate minimum and maximum values - * and column index values - * @param {Array | DataSet | DataView} rawData The data containing the items for the Graph. - * @param {Number} style Style Number - */ - Graph3d.prototype._dataInitialize = function (rawData, style) { - var me = this; + // This array is used to make a Date, either with `new Date` or `Date.UTC` + var string = '' + config._i, + i, parsedInput, tokens, token, skipped, + stringLength = string.length, + totalParsedInputLength = 0; - // unsubscribe from the dataTable - if (this.dataSet) { - this.dataSet.off('*', this._onChange); - } + tokens = expandFormat(config._f, config._locale).match(formattingTokens) || []; - if (rawData === undefined) - return; + for (i = 0; i < tokens.length; i++) { + token = tokens[i]; + parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; + if (parsedInput) { + skipped = string.substr(0, string.indexOf(parsedInput)); + if (skipped.length > 0) { + config._pf.unusedInput.push(skipped); + } + string = string.slice(string.indexOf(parsedInput) + parsedInput.length); + totalParsedInputLength += parsedInput.length; + } + // don't parse if it's not a known token + if (formatTokenFunctions[token]) { + if (parsedInput) { + config._pf.empty = false; + } + else { + config._pf.unusedTokens.push(token); + } + addTimeToArrayFromToken(token, parsedInput, config); + } + else if (config._strict && !parsedInput) { + config._pf.unusedTokens.push(token); + } + } - if (Array.isArray(rawData)) { - rawData = new DataSet(rawData); - } + // add remaining unparsed input length to the string + config._pf.charsLeftOver = stringLength - totalParsedInputLength; + if (string.length > 0) { + config._pf.unusedInput.push(string); + } - var data; - if (rawData instanceof DataSet || rawData instanceof DataView) { - data = rawData.get(); - } - else { - throw new Error('Array, DataSet, or DataView expected'); - } + // clear _12h flag if hour is <= 12 + if (config._pf.bigHour === true && config._a[HOUR] <= 12) { + config._pf.bigHour = undefined; + } + // handle meridiem + config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], + config._meridiem); + dateFromConfig(config); + checkOverflow(config); + } - if (data.length == 0) - return; + function unescapeFormat(s) { + return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { + return p1 || p2 || p3 || p4; + }); + } - this.dataSet = rawData; - this.dataTable = data; + // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript + function regexpEscape(s) { + return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } - // subscribe to changes in the dataset - this._onChange = function () { - me.setData(me.dataSet); - }; - this.dataSet.on('*', this._onChange); + // date from string and array of format strings + function makeDateFromStringAndArray(config) { + var tempConfig, + bestMoment, - // _determineColumnIndexes - // getNumberOfRows (points) - // getNumberOfColumns (x,y,z,v,t,t1,t2...) - // getDistinctValues (unique values?) - // getColumnRange + scoreToBeat, + i, + currentScore; - // determine the location of x,y,z,value,filter columns - this.colX = 'x'; - this.colY = 'y'; - this.colZ = 'z'; - this.colValue = 'style'; - this.colFilter = 'filter'; + if (config._f.length === 0) { + config._pf.invalidFormat = true; + config._d = new Date(NaN); + return; + } + for (i = 0; i < config._f.length; i++) { + currentScore = 0; + tempConfig = copyConfig({}, config); + if (config._useUTC != null) { + tempConfig._useUTC = config._useUTC; + } + tempConfig._pf = defaultParsingFlags(); + tempConfig._f = config._f[i]; + makeDateFromStringAndFormat(tempConfig); + if (!isValid(tempConfig)) { + continue; + } - // check if a filter column is provided - if (data[0].hasOwnProperty('filter')) { - if (this.dataFilter === undefined) { - this.dataFilter = new Filter(rawData, this.colFilter, this); - this.dataFilter.setOnLoadCallback(function() {me.redraw();}); - } - } + // if there is any input that was not parsed add a penalty for that format + currentScore += tempConfig._pf.charsLeftOver; + //or tokens + currentScore += tempConfig._pf.unusedTokens.length * 10; - var withBars = this.style == Graph3d.STYLE.BAR || - this.style == Graph3d.STYLE.BARCOLOR || - this.style == Graph3d.STYLE.BARSIZE; + tempConfig._pf.score = currentScore; - // determine barWidth from data - if (withBars) { - if (this.defaultXBarWidth !== undefined) { - this.xBarWidth = this.defaultXBarWidth; - } - else { - var dataX = this.getDistinctValues(data,this.colX); - this.xBarWidth = (dataX[1] - dataX[0]) || 1; - } + if (scoreToBeat == null || currentScore < scoreToBeat) { + scoreToBeat = currentScore; + bestMoment = tempConfig; + } + } - if (this.defaultYBarWidth !== undefined) { - this.yBarWidth = this.defaultYBarWidth; - } - else { - var dataY = this.getDistinctValues(data,this.colY); - this.yBarWidth = (dataY[1] - dataY[0]) || 1; + extend(config, bestMoment || tempConfig); } - } - // calculate minimums and maximums - var xRange = this.getColumnRange(data,this.colX); - if (withBars) { - xRange.min -= this.xBarWidth / 2; - xRange.max += this.xBarWidth / 2; - } - this.xMin = (this.defaultXMin !== undefined) ? this.defaultXMin : xRange.min; - this.xMax = (this.defaultXMax !== undefined) ? this.defaultXMax : xRange.max; - if (this.xMax <= this.xMin) this.xMax = this.xMin + 1; - this.xStep = (this.defaultXStep !== undefined) ? this.defaultXStep : (this.xMax-this.xMin)/5; + // date from iso format + function parseISO(config) { + var i, l, + string = config._i, + match = isoRegex.exec(string); - var yRange = this.getColumnRange(data,this.colY); - if (withBars) { - yRange.min -= this.yBarWidth / 2; - yRange.max += this.yBarWidth / 2; - } - this.yMin = (this.defaultYMin !== undefined) ? this.defaultYMin : yRange.min; - this.yMax = (this.defaultYMax !== undefined) ? this.defaultYMax : yRange.max; - if (this.yMax <= this.yMin) this.yMax = this.yMin + 1; - this.yStep = (this.defaultYStep !== undefined) ? this.defaultYStep : (this.yMax-this.yMin)/5; + if (match) { + config._pf.iso = true; + for (i = 0, l = isoDates.length; i < l; i++) { + if (isoDates[i][1].exec(string)) { + // match[5] should be 'T' or undefined + config._f = isoDates[i][0] + (match[6] || ' '); + break; + } + } + for (i = 0, l = isoTimes.length; i < l; i++) { + if (isoTimes[i][1].exec(string)) { + config._f += isoTimes[i][0]; + break; + } + } + if (string.match(parseTokenTimezone)) { + config._f += 'Z'; + } + makeDateFromStringAndFormat(config); + } else { + config._isValid = false; + } + } - var zRange = this.getColumnRange(data,this.colZ); - this.zMin = (this.defaultZMin !== undefined) ? this.defaultZMin : zRange.min; - this.zMax = (this.defaultZMax !== undefined) ? this.defaultZMax : zRange.max; - if (this.zMax <= this.zMin) this.zMax = this.zMin + 1; - this.zStep = (this.defaultZStep !== undefined) ? this.defaultZStep : (this.zMax-this.zMin)/5; + // date from iso format or fallback + function makeDateFromString(config) { + parseISO(config); + if (config._isValid === false) { + delete config._isValid; + moment.createFromInputFallback(config); + } + } - if (this.colValue !== undefined) { - var valueRange = this.getColumnRange(data,this.colValue); - this.valueMin = (this.defaultValueMin !== undefined) ? this.defaultValueMin : valueRange.min; - this.valueMax = (this.defaultValueMax !== undefined) ? this.defaultValueMax : valueRange.max; - if (this.valueMax <= this.valueMin) this.valueMax = this.valueMin + 1; - } + function map(arr, fn) { + var res = [], i; + for (i = 0; i < arr.length; ++i) { + res.push(fn(arr[i], i)); + } + return res; + } - // set the scale dependent on the ranges. - this._setScale(); - }; + function makeDateFromInput(config) { + var input = config._i, matched; + if (input === undefined) { + config._d = new Date(); + } 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 = map(input.slice(0), function (obj) { + return parseInt(obj, 10); + }); + dateFromConfig(config); + } else if (typeof(input) === 'object') { + dateFromObject(config); + } else if (typeof(input) === 'number') { + // from milliseconds + config._d = new Date(input); + } else { + moment.createFromInputFallback(config); + } + } + function makeDate(y, m, d, h, M, s, ms) { + //can't just apply() to create a date: + //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply + var date = new Date(y, m, d, h, M, s, ms); + //the date constructor doesn't accept years < 1970 + if (y < 1970) { + date.setFullYear(y); + } + return date; + } - /** - * Filter the data based on the current filter - * @param {Array} data - * @return {Array} dataPoints Array with point objects which can be drawn on screen - */ - Graph3d.prototype._getDataPoints = function (data) { - // TODO: store the created matrix dataPoints in the filters instead of reloading each time - var x, y, i, z, obj, point; + function makeUTCDate(y) { + var date = new Date(Date.UTC.apply(null, arguments)); + if (y < 1970) { + date.setUTCFullYear(y); + } + return date; + } - var dataPoints = []; + function parseWeekday(input, locale) { + if (typeof input === 'string') { + if (!isNaN(input)) { + input = parseInt(input, 10); + } + else { + input = locale.weekdaysParse(input); + if (typeof input !== 'number') { + return null; + } + } + } + return input; + } - if (this.style === Graph3d.STYLE.GRID || - this.style === Graph3d.STYLE.SURFACE) { - // copy all values from the google data table to a matrix - // the provided values are supposed to form a grid of (x,y) positions + /************************************ + Relative Time + ************************************/ - // create two lists with all present x and y values - var dataX = []; - var dataY = []; - for (i = 0; i < this.getNumberOfRows(data); i++) { - x = data[i][this.colX] || 0; - y = data[i][this.colY] || 0; - if (dataX.indexOf(x) === -1) { - dataX.push(x); - } - if (dataY.indexOf(y) === -1) { - dataY.push(y); - } + // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize + function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { + return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); } - var sortNumber = function (a, b) { - return a - b; - }; - dataX.sort(sortNumber); - dataY.sort(sortNumber); + 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')), - // create a grid, a 2d matrix, with all values. - var dataMatrix = []; // temporary data matrix - for (i = 0; i < data.length; i++) { - x = data[i][this.colX] || 0; - y = data[i][this.colY] || 0; - z = data[i][this.colZ] || 0; + 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.d && ['dd', days] || + months === 1 && ['M'] || + months < relativeTimeThresholds.M && ['MM', months] || + years === 1 && ['y'] || ['yy', years]; - var xIndex = dataX.indexOf(x); // TODO: implement Array().indexOf() for Internet Explorer - var yIndex = dataY.indexOf(y); + args[2] = withoutSuffix; + args[3] = +posNegDuration > 0; + args[4] = locale; + return substituteTimeAgo.apply({}, args); + } - if (dataMatrix[xIndex] === undefined) { - dataMatrix[xIndex] = []; - } - var point3d = new Point3d(); - point3d.x = x; - point3d.y = y; - point3d.z = z; + /************************************ + Week of Year + ************************************/ - obj = {}; - obj.point = point3d; - obj.trans = undefined; - obj.screen = undefined; - obj.bottom = new Point3d(x, y, this.zMin); - dataMatrix[xIndex][yIndex] = obj; + // firstDayOfWeek 0 = sun, 6 = sat + // the day of the week that starts the week + // (usually sunday or monday) + // firstDayOfWeekOfYear 0 = sun, 6 = sat + // the first week is the week that contains the first + // of this day of the week + // (eg. ISO weeks use thursday (4)) + function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { + var end = firstDayOfWeekOfYear - firstDayOfWeek, + daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), + adjustedMoment; - dataPoints.push(obj); - } - // fill in the pointers to the neighbors. - for (x = 0; x < dataMatrix.length; x++) { - for (y = 0; y < dataMatrix[x].length; y++) { - if (dataMatrix[x][y]) { - dataMatrix[x][y].pointRight = (x < dataMatrix.length-1) ? dataMatrix[x+1][y] : undefined; - dataMatrix[x][y].pointTop = (y < dataMatrix[x].length-1) ? dataMatrix[x][y+1] : undefined; - dataMatrix[x][y].pointCross = - (x < dataMatrix.length-1 && y < dataMatrix[x].length-1) ? - dataMatrix[x+1][y+1] : - undefined; + if (daysToDayOfWeek > end) { + daysToDayOfWeek -= 7; } - } - } - } - else { // 'dot', 'dot-line', etc. - // copy all values from the google data table to a list with Point3d objects - for (i = 0; i < data.length; i++) { - point = new Point3d(); - point.x = data[i][this.colX] || 0; - point.y = data[i][this.colY] || 0; - point.z = data[i][this.colZ] || 0; - if (this.colValue !== undefined) { - point.value = data[i][this.colValue] || 0; - } - - obj = {}; - obj.point = point; - obj.bottom = new Point3d(point.x, point.y, this.zMin); - obj.trans = undefined; - obj.screen = undefined; + if (daysToDayOfWeek < end - 7) { + daysToDayOfWeek += 7; + } - dataPoints.push(obj); + adjustedMoment = moment(mom).add(daysToDayOfWeek, 'd'); + return { + week: Math.ceil(adjustedMoment.dayOfYear() / 7), + year: adjustedMoment.year() + }; } - } - return dataPoints; - }; + //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday + function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { + var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear; - /** - * Create the main frame for the Graph3d. - * This function is executed once when a Graph3d object is created. The frame - * contains a canvas, and this canvas contains all objects like the axis and - * nodes. - */ - Graph3d.prototype.create = function () { - // remove all elements from the container element. - while (this.containerElement.hasChildNodes()) { - this.containerElement.removeChild(this.containerElement.firstChild); - } + d = d === 0 ? 7 : d; + weekday = weekday != null ? weekday : firstDayOfWeek; + daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0); + dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; - this.frame = document.createElement('div'); - this.frame.style.position = 'relative'; - this.frame.style.overflow = 'hidden'; + return { + year: dayOfYear > 0 ? year : year - 1, + dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear + }; + } - // create the graph canvas (HTML canvas element) - this.frame.canvas = document.createElement( 'canvas' ); - this.frame.canvas.style.position = 'relative'; - this.frame.appendChild(this.frame.canvas); - //if (!this.frame.canvas.getContext) { - { - var noCanvas = document.createElement( 'DIV' ); - noCanvas.style.color = 'red'; - noCanvas.style.fontWeight = 'bold' ; - noCanvas.style.padding = '10px'; - noCanvas.innerHTML = 'Error: your browser does not support HTML canvas'; - this.frame.canvas.appendChild(noCanvas); - } + /************************************ + Top Level Functions + ************************************/ - this.frame.filter = document.createElement( 'div' ); - this.frame.filter.style.position = 'absolute'; - this.frame.filter.style.bottom = '0px'; - this.frame.filter.style.left = '0px'; - this.frame.filter.style.width = '100%'; - this.frame.appendChild(this.frame.filter); + function makeMoment(config) { + var input = config._i, + format = config._f, + res; - // add event listeners to handle moving and zooming the contents - var me = this; - var onmousedown = function (event) {me._onMouseDown(event);}; - var ontouchstart = function (event) {me._onTouchStart(event);}; - var onmousewheel = function (event) {me._onWheel(event);}; - var ontooltip = function (event) {me._onTooltip(event);}; - // TODO: these events are never cleaned up... can give a 'memory leakage' + config._locale = config._locale || moment.localeData(config._l); - util.addEventListener(this.frame.canvas, 'keydown', onkeydown); - util.addEventListener(this.frame.canvas, 'mousedown', onmousedown); - util.addEventListener(this.frame.canvas, 'touchstart', ontouchstart); - util.addEventListener(this.frame.canvas, 'mousewheel', onmousewheel); - util.addEventListener(this.frame.canvas, 'mousemove', ontooltip); + if (input === null || (format === undefined && input === '')) { + return moment.invalid({nullInput: true}); + } - // add the new graph to the container element - this.containerElement.appendChild(this.frame); - }; + if (typeof input === 'string') { + config._i = input = config._locale.preparse(input); + } + if (moment.isMoment(input)) { + return new Moment(input, true); + } else if (format) { + if (isArray(format)) { + makeDateFromStringAndArray(config); + } else { + makeDateFromStringAndFormat(config); + } + } else { + makeDateFromInput(config); + } - /** - * Set a new size for the graph - * @param {string} width Width in pixels or percentage (for example '800px' - * or '50%') - * @param {string} height Height in pixels or percentage (for example '400px' - * or '30%') - */ - Graph3d.prototype.setSize = function(width, height) { - this.frame.style.width = width; - this.frame.style.height = height; + res = new Moment(config); + if (res._nextDay) { + // Adding is smart enough around DST + res.add(1, 'd'); + res._nextDay = undefined; + } - this._resizeCanvas(); - }; + return res; + } - /** - * Resize the canvas to the current size of the frame - */ - Graph3d.prototype._resizeCanvas = function() { - this.frame.canvas.style.width = '100%'; - this.frame.canvas.style.height = '100%'; + moment = function (input, format, locale, strict) { + var c; - this.frame.canvas.width = this.frame.canvas.clientWidth; - this.frame.canvas.height = this.frame.canvas.clientHeight; + if (typeof(locale) === 'boolean') { + strict = locale; + locale = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c = {}; + c._isAMomentObject = true; + c._i = input; + c._f = format; + c._l = locale; + c._strict = strict; + c._isUTC = false; + c._pf = defaultParsingFlags(); - // adjust with for margin - this.frame.filter.style.width = (this.frame.canvas.clientWidth - 2 * 10) + 'px'; - }; + return makeMoment(c); + }; - /** - * Start animation - */ - Graph3d.prototype.animationStart = function() { - if (!this.frame.filter || !this.frame.filter.slider) - throw 'No animation available'; + moment.suppressDeprecationWarnings = false; - this.frame.filter.slider.play(); - }; + 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 + (config._useUTC ? ' UTC' : '')); + } + ); + // 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. + // + // moments should either be an array of moment objects or an array, whose + // first element is an array of moment objects. + function pickBy(fn, moments) { + var res, i; + if (moments.length === 1 && isArray(moments[0])) { + moments = moments[0]; + } + if (!moments.length) { + return moment(); + } + res = moments[0]; + for (i = 1; i < moments.length; ++i) { + if (moments[i][fn](res)) { + res = moments[i]; + } + } + return res; + } - /** - * Stop animation - */ - Graph3d.prototype.animationStop = function() { - if (!this.frame.filter || !this.frame.filter.slider) return; + moment.min = function () { + var args = [].slice.call(arguments, 0); - this.frame.filter.slider.stop(); - }; + return pickBy('isBefore', args); + }; + moment.max = function () { + var args = [].slice.call(arguments, 0); - /** - * Resize the center position based on the current values in this.defaultXCenter - * and this.defaultYCenter (which are strings with a percentage or a value - * in pixels). The center positions are the variables this.xCenter - * and this.yCenter - */ - Graph3d.prototype._resizeCenter = function() { - // calculate the horizontal center position - if (this.defaultXCenter.charAt(this.defaultXCenter.length-1) === '%') { - this.xcenter = - parseFloat(this.defaultXCenter) / 100 * - this.frame.canvas.clientWidth; - } - else { - this.xcenter = parseFloat(this.defaultXCenter); // supposed to be in px - } + return pickBy('isAfter', args); + }; - // calculate the vertical center position - if (this.defaultYCenter.charAt(this.defaultYCenter.length-1) === '%') { - this.ycenter = - parseFloat(this.defaultYCenter) / 100 * - (this.frame.canvas.clientHeight - this.frame.filter.clientHeight); - } - else { - this.ycenter = parseFloat(this.defaultYCenter); // supposed to be in px - } - }; + // creating with utc + moment.utc = function (input, format, locale, strict) { + var c; - /** - * Set the rotation and distance of the camera - * @param {Object} pos An object with the camera position. The object - * contains three parameters: - * - horizontal {Number} - * The horizontal rotation, between 0 and 2*PI. - * Optional, can be left undefined. - * - vertical {Number} - * The vertical rotation, between 0 and 0.5*PI - * if vertical=0.5*PI, the graph is shown from the - * top. Optional, can be left undefined. - * - distance {Number} - * The (normalized) distance of the camera to the - * center of the graph, a value between 0.71 and 5.0. - * Optional, can be left undefined. - */ - Graph3d.prototype.setCameraPosition = function(pos) { - if (pos === undefined) { - return; - } + if (typeof(locale) === 'boolean') { + strict = locale; + locale = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c = {}; + c._isAMomentObject = true; + c._useUTC = true; + c._isUTC = true; + c._l = locale; + c._i = input; + c._f = format; + c._strict = strict; + c._pf = defaultParsingFlags(); - if (pos.horizontal !== undefined && pos.vertical !== undefined) { - this.camera.setArmRotation(pos.horizontal, pos.vertical); - } + return makeMoment(c).utc(); + }; - if (pos.distance !== undefined) { - this.camera.setArmLength(pos.distance); - } + // creating with unix timestamp (in seconds) + moment.unix = function (input) { + return moment(input * 1000); + }; - this.redraw(); - }; + // duration + moment.duration = function (input, key) { + var duration = input, + // matching against regexp is expensive, do it on demand + match = null, + sign, + ret, + parseIso, + diffRes; + if (moment.isDuration(input)) { + duration = { + ms: input._milliseconds, + d: input._days, + M: input._months + }; + } else if (typeof input === 'number') { + duration = {}; + if (key) { + duration[key] = input; + } else { + duration.milliseconds = input; + } + } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) { + sign = (match[1] === '-') ? -1 : 1; + duration = { + y: 0, + d: toInt(match[DATE]) * sign, + h: toInt(match[HOUR]) * sign, + m: toInt(match[MINUTE]) * sign, + s: toInt(match[SECOND]) * sign, + ms: toInt(match[MILLISECOND]) * sign + }; + } else if (!!(match = isoDurationRegex.exec(input))) { + sign = (match[1] === '-') ? -1 : 1; + parseIso = function (inp) { + // We'd normally use ~~inp for this, but unfortunately it also + // converts floats to ints. + // inp may be undefined, so careful calling replace on it. + var res = inp && parseFloat(inp.replace(',', '.')); + // apply sign while we're at it + return (isNaN(res) ? 0 : res) * sign; + }; + duration = { + y: parseIso(match[2]), + M: parseIso(match[3]), + d: parseIso(match[4]), + h: parseIso(match[5]), + m: parseIso(match[6]), + s: parseIso(match[7]), + w: parseIso(match[8]) + }; + } else if (duration == null) {// checks for null or undefined + duration = {}; + } else if (typeof duration === 'object' && + ('from' in duration || 'to' in duration)) { + diffRes = momentsDifference(moment(duration.from), moment(duration.to)); - /** - * Retrieve the current camera rotation - * @return {object} An object with parameters horizontal, vertical, and - * distance - */ - Graph3d.prototype.getCameraPosition = function() { - var pos = this.camera.getArmRotation(); - pos.distance = this.camera.getArmLength(); - return pos; - }; + duration = {}; + duration.ms = diffRes.milliseconds; + duration.M = diffRes.months; + } - /** - * Load data into the 3D Graph - */ - Graph3d.prototype._readData = function(data) { - // read the data - this._dataInitialize(data, this.style); + ret = new Duration(duration); + if (moment.isDuration(input) && hasOwnProp(input, '_locale')) { + ret._locale = input._locale; + } - if (this.dataFilter) { - // apply filtering - this.dataPoints = this.dataFilter._getDataPoints(); - } - else { - // no filtering. load all data - this.dataPoints = this._getDataPoints(this.dataTable); - } + return ret; + }; - // draw the filter - this._redrawFilter(); - }; + // version number + moment.version = VERSION; - /** - * Replace the dataset of the Graph3d - * @param {Array | DataSet | DataView} data - */ - Graph3d.prototype.setData = function (data) { - this._readData(data); - this.redraw(); + // default format + moment.defaultFormat = isoFormat; - // start animation when option is true - if (this.animationAutoStart && this.dataFilter) { - this.animationStart(); - } - }; + // constant that refers to the ISO standard + moment.ISO_8601 = function () {}; - /** - * Update the options. Options will be merged with current options - * @param {Object} options - */ - Graph3d.prototype.setOptions = function (options) { - var cameraPosition = undefined; + // Plugins that add properties should also add the key here (null value), + // so we can properly clone ourselves. + moment.momentProperties = momentProperties; - this.animationStop(); + // This function will be called whenever a moment is mutated. + // It is intended to keep the offset in sync with the timezone. + moment.updateOffset = function () {}; - if (options !== undefined) { - // retrieve parameter values - if (options.width !== undefined) this.width = options.width; - if (options.height !== undefined) this.height = options.height; + // This function allows you to set a threshold for relative time strings + moment.relativeTimeThreshold = function (threshold, limit) { + if (relativeTimeThresholds[threshold] === undefined) { + return false; + } + if (limit === undefined) { + return relativeTimeThresholds[threshold]; + } + relativeTimeThresholds[threshold] = limit; + return true; + }; - if (options.xCenter !== undefined) this.defaultXCenter = options.xCenter; - if (options.yCenter !== undefined) this.defaultYCenter = options.yCenter; + moment.lang = deprecate( + 'moment.lang is deprecated. Use moment.locale instead.', + function (key, value) { + return moment.locale(key, value); + } + ); - if (options.filterLabel !== undefined) this.filterLabel = options.filterLabel; - if (options.legendLabel !== undefined) this.legendLabel = options.legendLabel; - if (options.xLabel !== undefined) this.xLabel = options.xLabel; - if (options.yLabel !== undefined) this.yLabel = options.yLabel; - if (options.zLabel !== undefined) this.zLabel = options.zLabel; + // This function will load locale and then set the global locale. If + // no arguments are passed in, it will simply return the current global + // 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 (options.xValueLabel !== undefined) this.xValueLabel = options.xValueLabel; - if (options.yValueLabel !== undefined) this.yValueLabel = options.yValueLabel; - if (options.zValueLabel !== undefined) this.zValueLabel = options.zValueLabel; + if (data) { + moment.duration._locale = moment._locale = data; + } + } - if (options.style !== undefined) { - var styleNumber = this._getStyleNumber(options.style); - if (styleNumber !== -1) { - this.style = styleNumber; - } - } - if (options.showGrid !== undefined) this.showGrid = options.showGrid; - if (options.showPerspective !== undefined) this.showPerspective = options.showPerspective; - if (options.showShadow !== undefined) this.showShadow = options.showShadow; - if (options.tooltip !== undefined) this.showTooltip = options.tooltip; - if (options.showAnimationControls !== undefined) this.showAnimationControls = options.showAnimationControls; - if (options.keepAspectRatio !== undefined) this.keepAspectRatio = options.keepAspectRatio; - if (options.verticalRatio !== undefined) this.verticalRatio = options.verticalRatio; + return moment._locale._abbr; + }; - if (options.animationInterval !== undefined) this.animationInterval = options.animationInterval; - if (options.animationPreload !== undefined) this.animationPreload = options.animationPreload; - if (options.animationAutoStart !== undefined)this.animationAutoStart = options.animationAutoStart; + moment.defineLocale = function (name, values) { + if (values !== null) { + values.abbr = name; + if (!locales[name]) { + locales[name] = new Locale(); + } + locales[name].set(values); - if (options.xBarWidth !== undefined) this.defaultXBarWidth = options.xBarWidth; - if (options.yBarWidth !== undefined) this.defaultYBarWidth = options.yBarWidth; + // backwards compat for now: also set the locale + moment.locale(name); - if (options.xMin !== undefined) this.defaultXMin = options.xMin; - if (options.xStep !== undefined) this.defaultXStep = options.xStep; - if (options.xMax !== undefined) this.defaultXMax = options.xMax; - if (options.yMin !== undefined) this.defaultYMin = options.yMin; - if (options.yStep !== undefined) this.defaultYStep = options.yStep; - if (options.yMax !== undefined) this.defaultYMax = options.yMax; - if (options.zMin !== undefined) this.defaultZMin = options.zMin; - if (options.zStep !== undefined) this.defaultZStep = options.zStep; - if (options.zMax !== undefined) this.defaultZMax = options.zMax; - if (options.valueMin !== undefined) this.defaultValueMin = options.valueMin; - if (options.valueMax !== undefined) this.defaultValueMax = options.valueMax; + return locales[name]; + } else { + // useful for testing + delete locales[name]; + return null; + } + }; - if (options.cameraPosition !== undefined) cameraPosition = options.cameraPosition; + moment.langData = deprecate( + 'moment.langData is deprecated. Use moment.localeData instead.', + function (key) { + return moment.localeData(key); + } + ); - if (cameraPosition !== undefined) { - this.camera.setArmRotation(cameraPosition.horizontal, cameraPosition.vertical); - this.camera.setArmLength(cameraPosition.distance); - } - else { - this.camera.setArmRotation(1.0, 0.5); - this.camera.setArmLength(1.7); - } - } + // returns locale data + moment.localeData = function (key) { + var locale; - this._setBackgroundColor(options && options.backgroundColor); + if (key && key._locale && key._locale._abbr) { + key = key._locale._abbr; + } - this.setSize(this.width, this.height); + if (!key) { + return moment._locale; + } - // re-load the data - if (this.dataTable) { - this.setData(this.dataTable); - } + if (!isArray(key)) { + //short-circuit everything else + locale = loadLocale(key); + if (locale) { + return locale; + } + key = [key]; + } - // start animation when option is true - if (this.animationAutoStart && this.dataFilter) { - this.animationStart(); - } - }; + return chooseLocale(key); + }; - /** - * Redraw the Graph. - */ - Graph3d.prototype.redraw = function() { - if (this.dataPoints === undefined) { - throw 'Error: graph data not initialized'; - } + // compare moment object + moment.isMoment = function (obj) { + return obj instanceof Moment || + (obj != null && hasOwnProp(obj, '_isAMomentObject')); + }; - this._resizeCanvas(); - this._resizeCenter(); - this._redrawSlider(); - this._redrawClear(); - this._redrawAxis(); + // for typechecking Duration objects + moment.isDuration = function (obj) { + return obj instanceof Duration; + }; - if (this.style === Graph3d.STYLE.GRID || - this.style === Graph3d.STYLE.SURFACE) { - this._redrawDataGrid(); - } - else if (this.style === Graph3d.STYLE.LINE) { - this._redrawDataLine(); - } - else if (this.style === Graph3d.STYLE.BAR || - this.style === Graph3d.STYLE.BARCOLOR || - this.style === Graph3d.STYLE.BARSIZE) { - this._redrawDataBar(); - } - else { - // style is DOT, DOTLINE, DOTCOLOR, DOTSIZE - this._redrawDataDot(); - } + for (i = lists.length - 1; i >= 0; --i) { + makeList(lists[i]); + } - this._redrawInfo(); - this._redrawLegend(); - }; + moment.normalizeUnits = function (units) { + return normalizeUnits(units); + }; - /** - * Clear the canvas before redrawing - */ - Graph3d.prototype._redrawClear = function() { - var canvas = this.frame.canvas; - var ctx = canvas.getContext('2d'); + moment.invalid = function (flags) { + var m = moment.utc(NaN); + if (flags != null) { + extend(m._pf, flags); + } + else { + m._pf.userInvalidated = true; + } - ctx.clearRect(0, 0, canvas.width, canvas.height); - }; + return m; + }; + moment.parseZone = function () { + return moment.apply(null, arguments).parseZone(); + }; - /** - * Redraw the legend showing the colors - */ - Graph3d.prototype._redrawLegend = function() { - var y; + moment.parseTwoDigitYear = function (input) { + return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); + }; - if (this.style === Graph3d.STYLE.DOTCOLOR || - this.style === Graph3d.STYLE.DOTSIZE) { + moment.isDate = isDate; - var dotSize = this.frame.clientWidth * 0.02; + /************************************ + Moment Prototype + ************************************/ - var widthMin, widthMax; - if (this.style === Graph3d.STYLE.DOTSIZE) { - widthMin = dotSize / 2; // px - widthMax = dotSize / 2 + dotSize * 2; // Todo: put this in one function - } - else { - widthMin = 20; // px - widthMax = 20; // px - } - var height = Math.max(this.frame.clientHeight * 0.25, 100); - var top = this.margin; - var right = this.frame.clientWidth - this.margin; - var left = right - widthMax; - var bottom = top + height; - } + extend(moment.fn = Moment.prototype, { - var canvas = this.frame.canvas; - var ctx = canvas.getContext('2d'); - ctx.lineWidth = 1; - ctx.font = '14px arial'; // TODO: put in options + clone : function () { + return moment(this); + }, - if (this.style === Graph3d.STYLE.DOTCOLOR) { - // draw the color bar - var ymin = 0; - var ymax = height; // Todo: make height customizable - for (y = ymin; y < ymax; y++) { - var f = (y - ymin) / (ymax - ymin); + valueOf : function () { + return +this._d - ((this._offset || 0) * 60000); + }, - //var width = (dotSize / 2 + (1-f) * dotSize * 2); // Todo: put this in one function - var hue = f * 240; - var color = this._hsv2rgb(hue, 1, 1); + unix : function () { + return Math.floor(+this / 1000); + }, - ctx.strokeStyle = color; - ctx.beginPath(); - ctx.moveTo(left, top + y); - ctx.lineTo(right, top + y); - ctx.stroke(); - } + toString : function () { + return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); + }, - ctx.strokeStyle = this.colorAxis; - ctx.strokeRect(left, top, widthMax, height); - } + toDate : function () { + return this._offset ? new Date(+this) : this._d; + }, - if (this.style === Graph3d.STYLE.DOTSIZE) { - // draw border around color bar - ctx.strokeStyle = this.colorAxis; - ctx.fillStyle = this.colorDot; - ctx.beginPath(); - ctx.moveTo(left, top); - ctx.lineTo(right, top); - ctx.lineTo(right - widthMax + widthMin, bottom); - ctx.lineTo(left, bottom); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - } + toISOString : function () { + var m = moment(this).utc(); + if (0 < m.year() && m.year() <= 9999) { + if ('function' === typeof Date.prototype.toISOString) { + // native implementation is ~50x faster, use it when we can + return this.toDate().toISOString(); + } else { + return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } + } else { + return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } + }, - if (this.style === Graph3d.STYLE.DOTCOLOR || - this.style === Graph3d.STYLE.DOTSIZE) { - // print values along the color bar - var gridLineLen = 5; // px - var step = new StepNumber(this.valueMin, this.valueMax, (this.valueMax-this.valueMin)/5, true); - step.start(); - if (step.getCurrent() < this.valueMin) { - step.next(); - } - while (!step.end()) { - y = bottom - (step.getCurrent() - this.valueMin) / (this.valueMax - this.valueMin) * height; + toArray : function () { + var m = this; + return [ + m.year(), + m.month(), + m.date(), + m.hours(), + m.minutes(), + m.seconds(), + m.milliseconds() + ]; + }, - ctx.beginPath(); - ctx.moveTo(left - gridLineLen, y); - ctx.lineTo(left, y); - ctx.stroke(); + isValid : function () { + return isValid(this); + }, - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - ctx.fillStyle = this.colorAxis; - ctx.fillText(step.getCurrent(), left - 2 * gridLineLen, y); + isDSTShifted : function () { + if (this._a) { + return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0; + } - step.next(); - } + return false; + }, - ctx.textAlign = 'right'; - ctx.textBaseline = 'top'; - var label = this.legendLabel; - ctx.fillText(label, right, bottom + this.margin); - } - }; + parsingFlags : function () { + return extend({}, this._pf); + }, - /** - * Redraw the filter - */ - Graph3d.prototype._redrawFilter = function() { - this.frame.filter.innerHTML = ''; + invalidAt: function () { + return this._pf.overflow; + }, - if (this.dataFilter) { - var options = { - 'visible': this.showAnimationControls - }; - var slider = new Slider(this.frame.filter, options); - this.frame.filter.slider = slider; + utc : function (keepLocalTime) { + return this.utcOffset(0, keepLocalTime); + }, - // TODO: css here is not nice here... - this.frame.filter.style.padding = '10px'; - //this.frame.filter.style.backgroundColor = '#EFEFEF'; + local : function (keepLocalTime) { + if (this._isUTC) { + this.utcOffset(0, keepLocalTime); + this._isUTC = false; - slider.setValues(this.dataFilter.values); - slider.setPlayInterval(this.animationInterval); + if (keepLocalTime) { + this.subtract(this._dateUtcOffset(), 'm'); + } + } + return this; + }, - // create an event handler - var me = this; - var onchange = function () { - var index = slider.getIndex(); + format : function (inputString) { + var output = formatMoment(this, inputString || moment.defaultFormat); + return this.localeData().postformat(output); + }, - me.dataFilter.selectValue(index); - me.dataPoints = me.dataFilter._getDataPoints(); + add : createAdder(1, 'add'), - me.redraw(); - }; - slider.setOnChangeCallback(onchange); - } - else { - this.frame.filter.slider = undefined; - } - }; + subtract : createAdder(-1, 'subtract'), - /** - * Redraw the slider - */ - Graph3d.prototype._redrawSlider = function() { - if ( this.frame.filter.slider !== undefined) { - this.frame.filter.slider.redraw(); - } - }; + diff : function (input, units, asFloat) { + var that = makeAs(input, this), + zoneDiff = (that.utcOffset() - this.utcOffset()) * 6e4, + anchor, diff, output, daysAdjust; + units = normalizeUnits(units); - /** - * Redraw common information - */ - Graph3d.prototype._redrawInfo = function() { - if (this.dataFilter) { - var canvas = this.frame.canvas; - var ctx = canvas.getContext('2d'); + if (units === 'year' || units === 'month' || units === 'quarter') { + output = monthDiff(this, that); + if (units === 'quarter') { + output = output / 3; + } else if (units === 'year') { + output = output / 12; + } + } else { + diff = this - that; + output = units === 'second' ? diff / 1e3 : // 1000 + units === 'minute' ? diff / 6e4 : // 1000 * 60 + units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 + units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst + units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst + diff; + } + return asFloat ? output : absRound(output); + }, - ctx.font = '14px arial'; // TODO: put in options - ctx.lineStyle = 'gray'; - ctx.fillStyle = 'gray'; - ctx.textAlign = 'left'; - ctx.textBaseline = 'top'; + from : function (time, withoutSuffix) { + return moment.duration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix); + }, - var x = this.margin; - var y = this.margin; - ctx.fillText(this.dataFilter.getLabel() + ': ' + this.dataFilter.getSelectedValue(), x, y); - } - }; + fromNow : function (withoutSuffix) { + return this.from(moment(), withoutSuffix); + }, + calendar : function (time) { + // We want to compare the start of today, vs this. + // Getting start-of-today depends on whether we're locat/utc/offset + // or not. + var now = time || moment(), + sod = makeAs(now, this).startOf('day'), + diff = this.diff(sod, 'days', true), + format = diff < -6 ? 'sameElse' : + diff < -1 ? 'lastWeek' : + diff < 0 ? 'lastDay' : + diff < 1 ? 'sameDay' : + diff < 2 ? 'nextDay' : + diff < 7 ? 'nextWeek' : 'sameElse'; + return this.format(this.localeData().calendar(format, this, moment(now))); + }, - /** - * Redraw the axis - */ - Graph3d.prototype._redrawAxis = function() { - var canvas = this.frame.canvas, - ctx = canvas.getContext('2d'), - from, to, step, prettyStep, - text, xText, yText, zText, - offset, xOffset, yOffset, - xMin2d, xMax2d; + isLeapYear : function () { + return isLeapYear(this.year()); + }, - // TODO: get the actual rendered style of the containerElement - //ctx.font = this.containerElement.style.font; - ctx.font = 24 / this.camera.getArmLength() + 'px arial'; + isDST : function () { + return (this.utcOffset() > this.clone().month(0).utcOffset() || + this.utcOffset() > this.clone().month(5).utcOffset()); + }, - // calculate the length for the short grid lines - var gridLenX = 0.025 / this.scale.x; - var gridLenY = 0.025 / this.scale.y; - var textMargin = 5 / this.camera.getArmLength(); // px - var armAngle = this.camera.getArmRotation().horizontal; + day : function (input) { + var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); + if (input != null) { + input = parseWeekday(input, this.localeData()); + return this.add(input - day, 'd'); + } else { + return day; + } + }, - // draw x-grid lines - ctx.lineWidth = 1; - prettyStep = (this.defaultXStep === undefined); - step = new StepNumber(this.xMin, this.xMax, this.xStep, prettyStep); - step.start(); - if (step.getCurrent() < this.xMin) { - step.next(); - } - while (!step.end()) { - var x = step.getCurrent(); + month : makeAccessor('Month', true), - if (this.showGrid) { - from = this._convert3Dto2D(new Point3d(x, this.yMin, this.zMin)); - to = this._convert3Dto2D(new Point3d(x, this.yMax, this.zMin)); - ctx.strokeStyle = this.colorGrid; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); - } - else { - from = this._convert3Dto2D(new Point3d(x, this.yMin, this.zMin)); - to = this._convert3Dto2D(new Point3d(x, this.yMin+gridLenX, this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); + startOf : function (units) { + units = normalizeUnits(units); + // the following switch intentionally omits break keywords + // to utilize falling through the cases. + switch (units) { + case 'year': + this.month(0); + /* falls through */ + case 'quarter': + case 'month': + this.date(1); + /* falls through */ + case 'week': + case 'isoWeek': + case 'day': + this.hours(0); + /* falls through */ + case 'hour': + this.minutes(0); + /* falls through */ + case 'minute': + this.seconds(0); + /* falls through */ + case 'second': + this.milliseconds(0); + /* falls through */ + } - from = this._convert3Dto2D(new Point3d(x, this.yMax, this.zMin)); - to = this._convert3Dto2D(new Point3d(x, this.yMax-gridLenX, this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); - } + // weeks are a special case + if (units === 'week') { + this.weekday(0); + } else if (units === 'isoWeek') { + this.isoWeekday(1); + } - yText = (Math.cos(armAngle) > 0) ? this.yMin : this.yMax; - text = this._convert3Dto2D(new Point3d(x, yText, this.zMin)); - if (Math.cos(armAngle * 2) > 0) { - ctx.textAlign = 'center'; - ctx.textBaseline = 'top'; - text.y += textMargin; - } - else if (Math.sin(armAngle * 2) < 0){ - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - } - else { - ctx.textAlign = 'left'; - ctx.textBaseline = 'middle'; - } - ctx.fillStyle = this.colorAxis; - ctx.fillText(' ' + this.xValueLabel(step.getCurrent()) + ' ', text.x, text.y); + // quarters are also special + if (units === 'quarter') { + this.month(Math.floor(this.month() / 3) * 3); + } - step.next(); - } + return this; + }, - // draw y-grid lines - ctx.lineWidth = 1; - prettyStep = (this.defaultYStep === undefined); - step = new StepNumber(this.yMin, this.yMax, this.yStep, prettyStep); - step.start(); - if (step.getCurrent() < this.yMin) { - step.next(); - } - while (!step.end()) { - if (this.showGrid) { - from = this._convert3Dto2D(new Point3d(this.xMin, step.getCurrent(), this.zMin)); - to = this._convert3Dto2D(new Point3d(this.xMax, step.getCurrent(), this.zMin)); - ctx.strokeStyle = this.colorGrid; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); - } - else { - from = this._convert3Dto2D(new Point3d(this.xMin, step.getCurrent(), this.zMin)); - to = this._convert3Dto2D(new Point3d(this.xMin+gridLenY, step.getCurrent(), this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); + endOf: function (units) { + units = normalizeUnits(units); + if (units === undefined || units === 'millisecond') { + return this; + } + return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms'); + }, - from = this._convert3Dto2D(new Point3d(this.xMax, step.getCurrent(), this.zMin)); - to = this._convert3Dto2D(new Point3d(this.xMax-gridLenY, step.getCurrent(), this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); - } + isAfter: function (input, units) { + var inputMs; + units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); + if (units === 'millisecond') { + input = moment.isMoment(input) ? input : moment(input); + return +this > +input; + } else { + inputMs = moment.isMoment(input) ? +input : +moment(input); + return inputMs < +this.clone().startOf(units); + } + }, - xText = (Math.sin(armAngle ) > 0) ? this.xMin : this.xMax; - text = this._convert3Dto2D(new Point3d(xText, step.getCurrent(), this.zMin)); - if (Math.cos(armAngle * 2) < 0) { - ctx.textAlign = 'center'; - ctx.textBaseline = 'top'; - text.y += textMargin; - } - else if (Math.sin(armAngle * 2) > 0){ - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - } - else { - ctx.textAlign = 'left'; - ctx.textBaseline = 'middle'; - } - ctx.fillStyle = this.colorAxis; - ctx.fillText(' ' + this.yValueLabel(step.getCurrent()) + ' ', text.x, text.y); + isBefore: function (input, units) { + var inputMs; + units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); + if (units === 'millisecond') { + input = moment.isMoment(input) ? input : moment(input); + return +this < +input; + } else { + inputMs = moment.isMoment(input) ? +input : +moment(input); + return +this.clone().endOf(units) < inputMs; + } + }, - step.next(); - } + isBetween: function (from, to, units) { + return this.isAfter(from, units) && this.isBefore(to, units); + }, - // draw z-grid lines and axis - ctx.lineWidth = 1; - prettyStep = (this.defaultZStep === undefined); - step = new StepNumber(this.zMin, this.zMax, this.zStep, prettyStep); - step.start(); - if (step.getCurrent() < this.zMin) { - step.next(); - } - xText = (Math.cos(armAngle ) > 0) ? this.xMin : this.xMax; - yText = (Math.sin(armAngle ) < 0) ? this.yMin : this.yMax; - while (!step.end()) { - // TODO: make z-grid lines really 3d? - from = this._convert3Dto2D(new Point3d(xText, yText, step.getCurrent())); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(from.x - textMargin, from.y); - ctx.stroke(); + isSame: function (input, units) { + var inputMs; + units = normalizeUnits(units || 'millisecond'); + if (units === 'millisecond') { + input = moment.isMoment(input) ? input : moment(input); + return +this === +input; + } else { + inputMs = +moment(input); + return +(this.clone().startOf(units)) <= inputMs && inputMs <= +(this.clone().endOf(units)); + } + }, - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - ctx.fillStyle = this.colorAxis; - ctx.fillText(this.zValueLabel(step.getCurrent()) + ' ', from.x - 5, from.y); + min: deprecate( + '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; + } + ), - step.next(); - } - ctx.lineWidth = 1; - from = this._convert3Dto2D(new Point3d(xText, yText, this.zMin)); - to = this._convert3Dto2D(new Point3d(xText, yText, this.zMax)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); + max: deprecate( + '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; + } + ), - // draw x-axis - ctx.lineWidth = 1; - // line at yMin - xMin2d = this._convert3Dto2D(new Point3d(this.xMin, this.yMin, this.zMin)); - xMax2d = this._convert3Dto2D(new Point3d(this.xMax, this.yMin, this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(xMin2d.x, xMin2d.y); - ctx.lineTo(xMax2d.x, xMax2d.y); - ctx.stroke(); - // line at ymax - xMin2d = this._convert3Dto2D(new Point3d(this.xMin, this.yMax, this.zMin)); - xMax2d = this._convert3Dto2D(new Point3d(this.xMax, this.yMax, this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(xMin2d.x, xMin2d.y); - ctx.lineTo(xMax2d.x, xMax2d.y); - ctx.stroke(); + zone : deprecate( + 'moment().zone is deprecated, use moment().utcOffset instead. ' + + 'https://github.com/moment/moment/issues/1779', + function (input, keepLocalTime) { + if (input != null) { + if (typeof input !== 'string') { + input = -input; + } - // draw y-axis - ctx.lineWidth = 1; - // line at xMin - from = this._convert3Dto2D(new Point3d(this.xMin, this.yMin, this.zMin)); - to = this._convert3Dto2D(new Point3d(this.xMin, this.yMax, this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); - // line at xMax - from = this._convert3Dto2D(new Point3d(this.xMax, this.yMin, this.zMin)); - to = this._convert3Dto2D(new Point3d(this.xMax, this.yMax, this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); + this.utcOffset(input, keepLocalTime); - // draw x-label - var xLabel = this.xLabel; - if (xLabel.length > 0) { - yOffset = 0.1 / this.scale.y; - xText = (this.xMin + this.xMax) / 2; - yText = (Math.cos(armAngle) > 0) ? this.yMin - yOffset: this.yMax + yOffset; - text = this._convert3Dto2D(new Point3d(xText, yText, this.zMin)); - if (Math.cos(armAngle * 2) > 0) { - ctx.textAlign = 'center'; - ctx.textBaseline = 'top'; - } - else if (Math.sin(armAngle * 2) < 0){ - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - } - else { - ctx.textAlign = 'left'; - ctx.textBaseline = 'middle'; - } - ctx.fillStyle = this.colorAxis; - ctx.fillText(xLabel, text.x, text.y); - } + return this; + } else { + return -this.utcOffset(); + } + } + ), - // draw y-label - var yLabel = this.yLabel; - if (yLabel.length > 0) { - xOffset = 0.1 / this.scale.x; - xText = (Math.sin(armAngle ) > 0) ? this.xMin - xOffset : this.xMax + xOffset; - yText = (this.yMin + this.yMax) / 2; - text = this._convert3Dto2D(new Point3d(xText, yText, this.zMin)); - if (Math.cos(armAngle * 2) < 0) { - ctx.textAlign = 'center'; - ctx.textBaseline = 'top'; - } - else if (Math.sin(armAngle * 2) > 0){ - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - } - else { - ctx.textAlign = 'left'; - ctx.textBaseline = 'middle'; - } - ctx.fillStyle = this.colorAxis; - ctx.fillText(yLabel, text.x, text.y); - } + // keepLocalTime = true means only change the timezone, without + // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]--> + // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset + // +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. + utcOffset : function (input, keepLocalTime) { + var offset = this._offset || 0, + localAdjust; + if (input != null) { + if (typeof input === 'string') { + input = utcOffsetFromString(input); + } + if (Math.abs(input) < 16) { + input = input * 60; + } + if (!this._isUTC && keepLocalTime) { + localAdjust = this._dateUtcOffset(); + } + this._offset = input; + this._isUTC = true; + if (localAdjust != null) { + this.add(localAdjust, 'm'); + } + if (offset !== input) { + if (!keepLocalTime || this._changeInProgress) { + addOrSubtractDurationFromMoment(this, + moment.duration(input - offset, 'm'), 1, false); + } else if (!this._changeInProgress) { + this._changeInProgress = true; + moment.updateOffset(this, true); + this._changeInProgress = null; + } + } - // draw z-label - var zLabel = this.zLabel; - if (zLabel.length > 0) { - offset = 30; // pixels. // TODO: relate to the max width of the values on the z axis? - xText = (Math.cos(armAngle ) > 0) ? this.xMin : this.xMax; - yText = (Math.sin(armAngle ) < 0) ? this.yMin : this.yMax; - zText = (this.zMin + this.zMax) / 2; - text = this._convert3Dto2D(new Point3d(xText, yText, zText)); - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - ctx.fillStyle = this.colorAxis; - ctx.fillText(zLabel, text.x - offset, text.y); - } - }; + return this; + } else { + return this._isUTC ? offset : this._dateUtcOffset(); + } + }, - /** - * Calculate the color based on the given value. - * @param {Number} H Hue, a value be between 0 and 360 - * @param {Number} S Saturation, a value between 0 and 1 - * @param {Number} V Value, a value between 0 and 1 - */ - Graph3d.prototype._hsv2rgb = function(H, S, V) { - var R, G, B, C, Hi, X; + isLocal : function () { + return !this._isUTC; + }, - C = V * S; - Hi = Math.floor(H/60); // hi = 0,1,2,3,4,5 - X = C * (1 - Math.abs(((H/60) % 2) - 1)); + isUtcOffset : function () { + return this._isUTC; + }, - switch (Hi) { - case 0: R = C; G = X; B = 0; break; - case 1: R = X; G = C; B = 0; break; - case 2: R = 0; G = C; B = X; break; - case 3: R = 0; G = X; B = C; break; - case 4: R = X; G = 0; B = C; break; - case 5: R = C; G = 0; B = X; break; + isUtc : function () { + return this._isUTC && this._offset === 0; + }, - default: R = 0; G = 0; B = 0; break; - } + zoneAbbr : function () { + return this._isUTC ? 'UTC' : ''; + }, - return 'RGB(' + parseInt(R*255) + ',' + parseInt(G*255) + ',' + parseInt(B*255) + ')'; - }; + zoneName : function () { + return this._isUTC ? 'Coordinated Universal Time' : ''; + }, + parseZone : function () { + if (this._tzm) { + this.utcOffset(this._tzm); + } else if (typeof this._i === 'string') { + this.utcOffset(utcOffsetFromString(this._i)); + } + return this; + }, - /** - * Draw all datapoints as a grid - * This function can be used when the style is 'grid' - */ - Graph3d.prototype._redrawDataGrid = function() { - var canvas = this.frame.canvas, - ctx = canvas.getContext('2d'), - point, right, top, cross, - i, - topSideVisible, fillStyle, strokeStyle, lineWidth, - h, s, v, zAvg; + hasAlignedHourOffset : function (input) { + if (!input) { + input = 0; + } + else { + input = moment(input).utcOffset(); + } + return (this.utcOffset() - input) % 60 === 0; + }, - if (this.dataPoints === undefined || this.dataPoints.length <= 0) - return; // TODO: throw exception? + daysInMonth : function () { + return daysInMonth(this.year(), this.month()); + }, - // calculate the translations and screen position of all points - for (i = 0; i < this.dataPoints.length; i++) { - var trans = this._convertPointToTranslation(this.dataPoints[i].point); - var screen = this._convertTranslationToScreen(trans); + dayOfYear : function (input) { + var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; + return input == null ? dayOfYear : this.add((input - dayOfYear), 'd'); + }, - this.dataPoints[i].trans = trans; - this.dataPoints[i].screen = screen; + quarter : function (input) { + return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3); + }, - // calculate the translation of the point at the bottom (needed for sorting) - var transBottom = this._convertPointToTranslation(this.dataPoints[i].bottom); - this.dataPoints[i].dist = this.showPerspective ? transBottom.length() : -transBottom.z; - } + weekYear : function (input) { + var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year; + return input == null ? year : this.add((input - year), 'y'); + }, - // sort the points on depth of their (x,y) position (not on z) - var sortDepth = function (a, b) { - return b.dist - a.dist; - }; - this.dataPoints.sort(sortDepth); + isoWeekYear : function (input) { + var year = weekOfYear(this, 1, 4).year; + return input == null ? year : this.add((input - year), 'y'); + }, - if (this.style === Graph3d.STYLE.SURFACE) { - for (i = 0; i < this.dataPoints.length; i++) { - point = this.dataPoints[i]; - right = this.dataPoints[i].pointRight; - top = this.dataPoints[i].pointTop; - cross = this.dataPoints[i].pointCross; + week : function (input) { + var week = this.localeData().week(this); + return input == null ? week : this.add((input - week) * 7, 'd'); + }, - if (point !== undefined && right !== undefined && top !== undefined && cross !== undefined) { + isoWeek : function (input) { + var week = weekOfYear(this, 1, 4).week; + return input == null ? week : this.add((input - week) * 7, 'd'); + }, - if (this.showGrayBottom || this.showShadow) { - // calculate the cross product of the two vectors from center - // to left and right, in order to know whether we are looking at the - // bottom or at the top side. We can also use the cross product - // for calculating light intensity - var aDiff = Point3d.subtract(cross.trans, point.trans); - var bDiff = Point3d.subtract(top.trans, right.trans); - var crossproduct = Point3d.crossProduct(aDiff, bDiff); - var len = crossproduct.length(); - // FIXME: there is a bug with determining the surface side (shadow or colored) + weekday : function (input) { + var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; + return input == null ? weekday : this.add(input - weekday, 'd'); + }, - topSideVisible = (crossproduct.z > 0); - } - else { - topSideVisible = true; - } + isoWeekday : function (input) { + // behaves the same as moment#day except + // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) + // as a setter, sunday should belong to the previous week. + return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); + }, - if (topSideVisible) { - // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 - zAvg = (point.point.z + right.point.z + top.point.z + cross.point.z) / 4; - h = (1 - (zAvg - this.zMin) * this.scale.z / this.verticalRatio) * 240; - s = 1; // saturation + isoWeeksInYear : function () { + return weeksInYear(this.year(), 1, 4); + }, - if (this.showShadow) { - v = Math.min(1 + (crossproduct.x / len) / 2, 1); // value. TODO: scale - fillStyle = this._hsv2rgb(h, s, v); - strokeStyle = fillStyle; - } - else { - v = 1; - fillStyle = this._hsv2rgb(h, s, v); - strokeStyle = this.colorAxis; - } - } - else { - fillStyle = 'gray'; - strokeStyle = this.colorAxis; - } - lineWidth = 0.5; + weeksInYear : function () { + var weekInfo = this.localeData()._week; + return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); + }, - ctx.lineWidth = lineWidth; - ctx.fillStyle = fillStyle; - ctx.strokeStyle = strokeStyle; - ctx.beginPath(); - ctx.moveTo(point.screen.x, point.screen.y); - ctx.lineTo(right.screen.x, right.screen.y); - ctx.lineTo(cross.screen.x, cross.screen.y); - ctx.lineTo(top.screen.x, top.screen.y); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - } - } - } - else { // grid style - for (i = 0; i < this.dataPoints.length; i++) { - point = this.dataPoints[i]; - right = this.dataPoints[i].pointRight; - top = this.dataPoints[i].pointTop; + get : function (units) { + units = normalizeUnits(units); + return this[units](); + }, - if (point !== undefined) { - if (this.showPerspective) { - lineWidth = 2 / -point.trans.z; - } - else { - lineWidth = 2 * -(this.eye.z / this.camera.getArmLength()); - } - } + set : function (units, value) { + var unit; + if (typeof units === 'object') { + for (unit in units) { + this.set(unit, units[unit]); + } + } + else { + units = normalizeUnits(units); + if (typeof this[units] === 'function') { + this[units](value); + } + } + return this; + }, - if (point !== undefined && right !== undefined) { - // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 - zAvg = (point.point.z + right.point.z) / 2; - h = (1 - (zAvg - this.zMin) * this.scale.z / this.verticalRatio) * 240; + // If passed a locale key, it will set the locale for this + // instance. Otherwise, it will return the locale configuration + // variables for this instance. + locale : function (key) { + var newLocaleData; - ctx.lineWidth = lineWidth; - ctx.strokeStyle = this._hsv2rgb(h, 1, 1); - ctx.beginPath(); - ctx.moveTo(point.screen.x, point.screen.y); - ctx.lineTo(right.screen.x, right.screen.y); - ctx.stroke(); - } + if (key === undefined) { + return this._locale._abbr; + } else { + newLocaleData = moment.localeData(key); + if (newLocaleData != null) { + this._locale = newLocaleData; + } + return this; + } + }, - if (point !== undefined && top !== undefined) { - // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 - zAvg = (point.point.z + top.point.z) / 2; - h = (1 - (zAvg - this.zMin) * this.scale.z / this.verticalRatio) * 240; + lang : deprecate( + 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', + function (key) { + if (key === undefined) { + return this.localeData(); + } else { + return this.locale(key); + } + } + ), - ctx.lineWidth = lineWidth; - ctx.strokeStyle = this._hsv2rgb(h, 1, 1); - ctx.beginPath(); - ctx.moveTo(point.screen.x, point.screen.y); - ctx.lineTo(top.screen.x, top.screen.y); - ctx.stroke(); - } - } - } - }; - - - /** - * Draw all datapoints as dots. - * This function can be used when the style is 'dot' or 'dot-line' - */ - Graph3d.prototype._redrawDataDot = function() { - var canvas = this.frame.canvas; - var ctx = canvas.getContext('2d'); - var i; - - if (this.dataPoints === undefined || this.dataPoints.length <= 0) - return; // TODO: throw exception? + localeData : function () { + return this._locale; + }, - // calculate the translations of all points - for (i = 0; i < this.dataPoints.length; i++) { - var trans = this._convertPointToTranslation(this.dataPoints[i].point); - var screen = this._convertTranslationToScreen(trans); - this.dataPoints[i].trans = trans; - this.dataPoints[i].screen = screen; + _dateUtcOffset : function () { + // On Firefox.24 Date#getTimezoneOffset returns a floating point. + // https://github.com/moment/moment/pull/1871 + return -Math.round(this._d.getTimezoneOffset() / 15) * 15; + } - // calculate the distance from the point at the bottom to the camera - var transBottom = this._convertPointToTranslation(this.dataPoints[i].bottom); - this.dataPoints[i].dist = this.showPerspective ? transBottom.length() : -transBottom.z; - } + }); - // order the translated points by depth - var sortDepth = function (a, b) { - return b.dist - a.dist; - }; - this.dataPoints.sort(sortDepth); + function rawMonthSetter(mom, value) { + var dayOfMonth; - // draw the datapoints as colored circles - var dotSize = this.frame.clientWidth * 0.02; // px - for (i = 0; i < this.dataPoints.length; i++) { - var point = this.dataPoints[i]; + // TODO: Move this out of here! + if (typeof value === 'string') { + value = mom.localeData().monthsParse(value); + // TODO: Another silent failure? + if (typeof value !== 'number') { + return mom; + } + } - if (this.style === Graph3d.STYLE.DOTLINE) { - // draw a vertical line from the bottom to the graph value - //var from = this._convert3Dto2D(new Point3d(point.point.x, point.point.y, this.zMin)); - var from = this._convert3Dto2D(point.bottom); - ctx.lineWidth = 1; - ctx.strokeStyle = this.colorGrid; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(point.screen.x, point.screen.y); - ctx.stroke(); + dayOfMonth = Math.min(mom.date(), + daysInMonth(mom.year(), value)); + mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); + return mom; } - // calculate radius for the circle - var size; - if (this.style === Graph3d.STYLE.DOTSIZE) { - size = dotSize/2 + 2*dotSize * (point.point.value - this.valueMin) / (this.valueMax - this.valueMin); - } - else { - size = dotSize; + function rawGetter(mom, unit) { + return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit](); } - var radius; - if (this.showPerspective) { - radius = size / -point.trans.z; - } - else { - radius = size * -(this.eye.z / this.camera.getArmLength()); - } - if (radius < 0) { - radius = 0; + function rawSetter(mom, unit, value) { + if (unit === 'Month') { + return rawMonthSetter(mom, value); + } else { + return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); + } } - var hue, color, borderColor; - if (this.style === Graph3d.STYLE.DOTCOLOR ) { - // calculate the color based on the value - hue = (1 - (point.point.value - this.valueMin) * this.scale.value) * 240; - color = this._hsv2rgb(hue, 1, 1); - borderColor = this._hsv2rgb(hue, 1, 0.8); - } - else if (this.style === Graph3d.STYLE.DOTSIZE) { - color = this.colorDot; - borderColor = this.colorDotBorder; - } - else { - // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 - hue = (1 - (point.point.z - this.zMin) * this.scale.z / this.verticalRatio) * 240; - color = this._hsv2rgb(hue, 1, 1); - borderColor = this._hsv2rgb(hue, 1, 0.8); + function makeAccessor(unit, keepTime) { + return function (value) { + if (value != null) { + rawSetter(this, unit, value); + moment.updateOffset(this, keepTime); + return this; + } else { + return rawGetter(this, unit); + } + }; } - // draw the circle - ctx.lineWidth = 1.0; - ctx.strokeStyle = borderColor; - ctx.fillStyle = color; - ctx.beginPath(); - ctx.arc(point.screen.x, point.screen.y, radius, 0, Math.PI*2, true); - ctx.fill(); - ctx.stroke(); - } - }; - - /** - * Draw all datapoints as bars. - * This function can be used when the style is 'bar', 'bar-color', or 'bar-size' - */ - Graph3d.prototype._redrawDataBar = function() { - var canvas = this.frame.canvas; - var ctx = canvas.getContext('2d'); - var i, j, surface, corners; + moment.fn.millisecond = moment.fn.milliseconds = makeAccessor('Milliseconds', false); + moment.fn.second = moment.fn.seconds = makeAccessor('Seconds', false); + moment.fn.minute = moment.fn.minutes = makeAccessor('Minutes', false); + // Setting the hour should keep the time, because the user explicitly + // specified which hour he wants. So trying to maintain the same hour (in + // a new timezone) makes sense. Adding/subtracting hours does not follow + // this rule. + 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.year = makeAccessor('FullYear', true); + moment.fn.years = deprecate('years accessor is deprecated. Use year instead.', makeAccessor('FullYear', true)); - if (this.dataPoints === undefined || this.dataPoints.length <= 0) - return; // TODO: throw exception? + // add plural methods + moment.fn.days = moment.fn.day; + moment.fn.months = moment.fn.month; + moment.fn.weeks = moment.fn.week; + moment.fn.isoWeeks = moment.fn.isoWeek; + moment.fn.quarters = moment.fn.quarter; - // calculate the translations of all points - for (i = 0; i < this.dataPoints.length; i++) { - var trans = this._convertPointToTranslation(this.dataPoints[i].point); - var screen = this._convertTranslationToScreen(trans); - this.dataPoints[i].trans = trans; - this.dataPoints[i].screen = screen; + // add aliased format methods + moment.fn.toJSON = moment.fn.toISOString; - // calculate the distance from the point at the bottom to the camera - var transBottom = this._convertPointToTranslation(this.dataPoints[i].bottom); - this.dataPoints[i].dist = this.showPerspective ? transBottom.length() : -transBottom.z; - } + // alias isUtc for dev-friendliness + moment.fn.isUTC = moment.fn.isUtc; - // order the translated points by depth - var sortDepth = function (a, b) { - return b.dist - a.dist; - }; - this.dataPoints.sort(sortDepth); + /************************************ + Duration Prototype + ************************************/ - // draw the datapoints as bars - var xWidth = this.xBarWidth / 2; - var yWidth = this.yBarWidth / 2; - for (i = 0; i < this.dataPoints.length; i++) { - var point = this.dataPoints[i]; - // determine color - var hue, color, borderColor; - if (this.style === Graph3d.STYLE.BARCOLOR ) { - // calculate the color based on the value - hue = (1 - (point.point.value - this.valueMin) * this.scale.value) * 240; - color = this._hsv2rgb(hue, 1, 1); - borderColor = this._hsv2rgb(hue, 1, 0.8); - } - else if (this.style === Graph3d.STYLE.BARSIZE) { - color = this.colorDot; - borderColor = this.colorDotBorder; - } - else { - // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 - hue = (1 - (point.point.z - this.zMin) * this.scale.z / this.verticalRatio) * 240; - color = this._hsv2rgb(hue, 1, 1); - borderColor = this._hsv2rgb(hue, 1, 0.8); + function daysToYears (days) { + // 400 years have 146097 days (taking into account leap year rules) + return days * 400 / 146097; } - // calculate size for the bar - if (this.style === Graph3d.STYLE.BARSIZE) { - xWidth = (this.xBarWidth / 2) * ((point.point.value - this.valueMin) / (this.valueMax - this.valueMin) * 0.8 + 0.2); - yWidth = (this.yBarWidth / 2) * ((point.point.value - this.valueMin) / (this.valueMax - this.valueMin) * 0.8 + 0.2); + function yearsToDays (years) { + // years * 365 + absRound(years / 4) - + // absRound(years / 100) + absRound(years / 400); + return years * 146097 / 400; } - // calculate all corner points - var me = this; - var point3d = point.point; - var top = [ - {point: new Point3d(point3d.x - xWidth, point3d.y - yWidth, point3d.z)}, - {point: new Point3d(point3d.x + xWidth, point3d.y - yWidth, point3d.z)}, - {point: new Point3d(point3d.x + xWidth, point3d.y + yWidth, point3d.z)}, - {point: new Point3d(point3d.x - xWidth, point3d.y + yWidth, point3d.z)} - ]; - var bottom = [ - {point: new Point3d(point3d.x - xWidth, point3d.y - yWidth, this.zMin)}, - {point: new Point3d(point3d.x + xWidth, point3d.y - yWidth, this.zMin)}, - {point: new Point3d(point3d.x + xWidth, point3d.y + yWidth, this.zMin)}, - {point: new Point3d(point3d.x - xWidth, point3d.y + yWidth, this.zMin)} - ]; - - // calculate screen location of the points - top.forEach(function (obj) { - obj.screen = me._convert3Dto2D(obj.point); - }); - bottom.forEach(function (obj) { - obj.screen = me._convert3Dto2D(obj.point); - }); + extend(moment.duration.fn = Duration.prototype, { - // create five sides, calculate both corner points and center points - var surfaces = [ - {corners: top, center: Point3d.avg(bottom[0].point, bottom[2].point)}, - {corners: [top[0], top[1], bottom[1], bottom[0]], center: Point3d.avg(bottom[1].point, bottom[0].point)}, - {corners: [top[1], top[2], bottom[2], bottom[1]], center: Point3d.avg(bottom[2].point, bottom[1].point)}, - {corners: [top[2], top[3], bottom[3], bottom[2]], center: Point3d.avg(bottom[3].point, bottom[2].point)}, - {corners: [top[3], top[0], bottom[0], bottom[3]], center: Point3d.avg(bottom[0].point, bottom[3].point)} - ]; - point.surfaces = surfaces; + _bubble : function () { + var milliseconds = this._milliseconds, + days = this._days, + months = this._months, + data = this._data, + seconds, minutes, hours, years = 0; - // calculate the distance of each of the surface centers to the camera - for (j = 0; j < surfaces.length; j++) { - surface = surfaces[j]; - var transCenter = this._convertPointToTranslation(surface.center); - surface.dist = this.showPerspective ? transCenter.length() : -transCenter.z; - // TODO: this dept calculation doesn't work 100% of the cases due to perspective, - // but the current solution is fast/simple and works in 99.9% of all cases - // the issue is visible in example 14, with graph.setCameraPosition({horizontal: 2.97, vertical: 0.5, distance: 0.9}) - } + // The following code bubbles up values, see the tests for + // examples of what that means. + data.milliseconds = milliseconds % 1000; - // order the surfaces by their (translated) depth - surfaces.sort(function (a, b) { - var diff = b.dist - a.dist; - if (diff) return diff; + seconds = absRound(milliseconds / 1000); + data.seconds = seconds % 60; - // if equal depth, sort the top surface last - if (a.corners === top) return 1; - if (b.corners === top) return -1; + minutes = absRound(seconds / 60); + data.minutes = minutes % 60; - // both are equal - return 0; - }); + hours = absRound(minutes / 60); + data.hours = hours % 24; - // draw the ordered surfaces - ctx.lineWidth = 1; - ctx.strokeStyle = borderColor; - ctx.fillStyle = color; - // NOTE: we start at j=2 instead of j=0 as we don't need to draw the two surfaces at the backside - for (j = 2; j < surfaces.length; j++) { - surface = surfaces[j]; - corners = surface.corners; - ctx.beginPath(); - ctx.moveTo(corners[3].screen.x, corners[3].screen.y); - ctx.lineTo(corners[0].screen.x, corners[0].screen.y); - ctx.lineTo(corners[1].screen.x, corners[1].screen.y); - ctx.lineTo(corners[2].screen.x, corners[2].screen.y); - ctx.lineTo(corners[3].screen.x, corners[3].screen.y); - ctx.fill(); - ctx.stroke(); - } - } - }; + days += absRound(hours / 24); + // Accurately convert days to years, assume start from year 0. + years = absRound(daysToYears(days)); + days -= absRound(yearsToDays(years)); - /** - * Draw a line through all datapoints. - * This function can be used when the style is 'line' - */ - Graph3d.prototype._redrawDataLine = function() { - var canvas = this.frame.canvas, - ctx = canvas.getContext('2d'), - point, i; + // 30 days to a month + // TODO (iskren): Use anchor date (like 1st Jan) to compute this. + months += absRound(days / 30); + days %= 30; - if (this.dataPoints === undefined || this.dataPoints.length <= 0) - return; // TODO: throw exception? + // 12 months -> 1 year + years += absRound(months / 12); + months %= 12; - // calculate the translations of all points - for (i = 0; i < this.dataPoints.length; i++) { - var trans = this._convertPointToTranslation(this.dataPoints[i].point); - var screen = this._convertTranslationToScreen(trans); + data.days = days; + data.months = months; + data.years = years; + }, - this.dataPoints[i].trans = trans; - this.dataPoints[i].screen = screen; - } + abs : function () { + this._milliseconds = Math.abs(this._milliseconds); + this._days = Math.abs(this._days); + this._months = Math.abs(this._months); - // start the line - if (this.dataPoints.length > 0) { - point = this.dataPoints[0]; + 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); - ctx.lineWidth = 1; // TODO: make customizable - ctx.strokeStyle = 'blue'; // TODO: make customizable - ctx.beginPath(); - ctx.moveTo(point.screen.x, point.screen.y); - } + return this; + }, - // draw the datapoints as colored circles - for (i = 1; i < this.dataPoints.length; i++) { - point = this.dataPoints[i]; - ctx.lineTo(point.screen.x, point.screen.y); - } + weeks : function () { + return absRound(this.days() / 7); + }, - // finish the line - if (this.dataPoints.length > 0) { - ctx.stroke(); - } - }; + valueOf : function () { + return this._milliseconds + + this._days * 864e5 + + (this._months % 12) * 2592e6 + + toInt(this._months / 12) * 31536e6; + }, - /** - * Start a moving operation inside the provided parent element - * @param {Event} event The event that occurred (required for - * retrieving the mouse position) - */ - Graph3d.prototype._onMouseDown = function(event) { - event = event || window.event; + humanize : function (withSuffix) { + var output = relativeTime(this, !withSuffix, this.localeData()); - // check if mouse is still down (may be up when focus is lost for example - // in an iframe) - if (this.leftButtonDown) { - this._onMouseUp(event); - } + if (withSuffix) { + output = this.localeData().pastFuture(+this, output); + } - // only react on left mouse button down - this.leftButtonDown = event.which ? (event.which === 1) : (event.button === 1); - if (!this.leftButtonDown && !this.touchDown) return; + return this.localeData().postformat(output); + }, - // get mouse position (different code for IE and all other browsers) - this.startMouseX = getMouseX(event); - this.startMouseY = getMouseY(event); + add : function (input, val) { + // supports only 2.0-style add(1, 's') or add(moment) + var dur = moment.duration(input, val); - this.startStart = new Date(this.start); - this.startEnd = new Date(this.end); - this.startArmRotation = this.camera.getArmRotation(); + this._milliseconds += dur._milliseconds; + this._days += dur._days; + this._months += dur._months; - this.frame.style.cursor = 'move'; + this._bubble(); - // add event listeners to handle moving the contents - // we store the function onmousemove and onmouseup in the graph, so we can - // remove the eventlisteners lateron in the function mouseUp() - var me = this; - this.onmousemove = function (event) {me._onMouseMove(event);}; - this.onmouseup = function (event) {me._onMouseUp(event);}; - util.addEventListener(document, 'mousemove', me.onmousemove); - util.addEventListener(document, 'mouseup', me.onmouseup); - util.preventDefault(event); - }; + return this; + }, + subtract : function (input, val) { + var dur = moment.duration(input, val); - /** - * Perform moving operating. - * This function activated from within the funcion Graph.mouseDown(). - * @param {Event} event Well, eehh, the event - */ - Graph3d.prototype._onMouseMove = function (event) { - event = event || window.event; + this._milliseconds -= dur._milliseconds; + this._days -= dur._days; + this._months -= dur._months; - // calculate change in mouse position - var diffX = parseFloat(getMouseX(event)) - this.startMouseX; - var diffY = parseFloat(getMouseY(event)) - this.startMouseY; + this._bubble(); - var horizontalNew = this.startArmRotation.horizontal + diffX / 200; - var verticalNew = this.startArmRotation.vertical + diffY / 200; + return this; + }, - var snapAngle = 4; // degrees - var snapValue = Math.sin(snapAngle / 360 * 2 * Math.PI); + get : function (units) { + units = normalizeUnits(units); + return this[units.toLowerCase() + 's'](); + }, - // snap horizontally to nice angles at 0pi, 0.5pi, 1pi, 1.5pi, etc... - // the -0.001 is to take care that the vertical axis is always drawn at the left front corner - if (Math.abs(Math.sin(horizontalNew)) < snapValue) { - horizontalNew = Math.round((horizontalNew / Math.PI)) * Math.PI - 0.001; - } - if (Math.abs(Math.cos(horizontalNew)) < snapValue) { - horizontalNew = (Math.round((horizontalNew/ Math.PI - 0.5)) + 0.5) * Math.PI - 0.001; - } + as : function (units) { + var days, months; + units = normalizeUnits(units); - // snap vertically to nice angles - if (Math.abs(Math.sin(verticalNew)) < snapValue) { - verticalNew = Math.round((verticalNew / Math.PI)) * Math.PI; - } - if (Math.abs(Math.cos(verticalNew)) < snapValue) { - verticalNew = (Math.round((verticalNew/ Math.PI - 0.5)) + 0.5) * Math.PI; - } + if (units === 'month' || units === 'year') { + days = this._days + this._milliseconds / 864e5; + months = this._months + daysToYears(days) * 12; + return units === 'month' ? months : months / 12; + } else { + // handle milliseconds separately because of floating point math errors (issue #1867) + days = this._days + Math.round(yearsToDays(this._months / 12)); + switch (units) { + case 'week': return days / 7 + this._milliseconds / 6048e5; + case 'day': return days + this._milliseconds / 864e5; + case 'hour': return days * 24 + this._milliseconds / 36e5; + case 'minute': return days * 24 * 60 + this._milliseconds / 6e4; + case 'second': return days * 24 * 60 * 60 + this._milliseconds / 1000; + // Math.floor prevents floating point math errors here + case 'millisecond': return Math.floor(days * 24 * 60 * 60 * 1000) + this._milliseconds; + default: throw new Error('Unknown unit ' + units); + } + } + }, - this.camera.setArmRotation(horizontalNew, verticalNew); - this.redraw(); + lang : moment.fn.lang, + locale : moment.fn.locale, - // fire a cameraPositionChange event - var parameters = this.getCameraPosition(); - this.emit('cameraPositionChange', parameters); + toIsoString : deprecate( + 'toIsoString() is deprecated. Please use toISOString() instead ' + + '(notice the capitals)', + function () { + return this.toISOString(); + } + ), - util.preventDefault(event); - }; + 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()), + days = Math.abs(this.days()), + hours = Math.abs(this.hours()), + minutes = Math.abs(this.minutes()), + seconds = Math.abs(this.seconds() + this.milliseconds() / 1000); + if (!this.asSeconds()) { + // this is the same as C#'s (Noda) and python (isodate)... + // but not other JS (goog.date) + return 'P0D'; + } - /** - * Stop moving operating. - * This function activated from within the funcion Graph.mouseDown(). - * @param {event} event The event - */ - Graph3d.prototype._onMouseUp = function (event) { - this.frame.style.cursor = 'auto'; - this.leftButtonDown = false; - - // remove event listeners here - util.removeEventListener(document, 'mousemove', this.onmousemove); - util.removeEventListener(document, 'mouseup', this.onmouseup); - util.preventDefault(event); - }; + return (this.asSeconds() < 0 ? '-' : '') + + 'P' + + (years ? years + 'Y' : '') + + (months ? months + 'M' : '') + + (days ? days + 'D' : '') + + ((hours || minutes || seconds) ? 'T' : '') + + (hours ? hours + 'H' : '') + + (minutes ? minutes + 'M' : '') + + (seconds ? seconds + 'S' : ''); + }, - /** - * After having moved the mouse, a tooltip should pop up when the mouse is resting on a data point - * @param {Event} event A mouse move event - */ - Graph3d.prototype._onTooltip = function (event) { - var delay = 300; // ms - var boundingRect = this.frame.getBoundingClientRect(); - var mouseX = getMouseX(event) - boundingRect.left; - var mouseY = getMouseY(event) - boundingRect.top; + localeData : function () { + return this._locale; + }, - if (!this.showTooltip) { - return; - } + toJSON : function () { + return this.toISOString(); + } + }); - if (this.tooltipTimeout) { - clearTimeout(this.tooltipTimeout); - } + moment.duration.fn.toString = moment.duration.fn.toISOString; - // (delayed) display of a tooltip only if no mouse button is down - if (this.leftButtonDown) { - this._hideTooltip(); - return; - } + function makeDurationGetter(name) { + moment.duration.fn[name] = function () { + return this._data[name]; + }; + } - if (this.tooltip && this.tooltip.dataPoint) { - // tooltip is currently visible - var dataPoint = this._dataPointFromXY(mouseX, mouseY); - if (dataPoint !== this.tooltip.dataPoint) { - // datapoint changed - if (dataPoint) { - this._showTooltip(dataPoint); - } - else { - this._hideTooltip(); - } + for (i in unitMillisecondFactors) { + if (hasOwnProp(unitMillisecondFactors, i)) { + makeDurationGetter(i.toLowerCase()); + } } - } - else { - // tooltip is currently not visible - var me = this; - this.tooltipTimeout = setTimeout(function () { - me.tooltipTimeout = null; - // show a tooltip if we have a data point - var dataPoint = me._dataPointFromXY(mouseX, mouseY); - if (dataPoint) { - me._showTooltip(dataPoint); - } - }, delay); - } - }; + 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.as('M'); + }; + moment.duration.fn.asYears = function () { + return this.as('y'); + }; - /** - * Event handler for touchstart event on mobile devices - */ - Graph3d.prototype._onTouchStart = function(event) { - this.touchDown = true; + /************************************ + Default Locale + ************************************/ - var me = this; - this.ontouchmove = function (event) {me._onTouchMove(event);}; - this.ontouchend = function (event) {me._onTouchEnd(event);}; - util.addEventListener(document, 'touchmove', me.ontouchmove); - util.addEventListener(document, 'touchend', me.ontouchend); - this._onMouseDown(event); - }; + // Set default locale, other locale will inherit from English. + moment.locale('en', { + ordinalParse: /\d{1,2}(th|st|nd|rd)/, + ordinal : function (number) { + var b = number % 10, + output = (toInt(number % 100 / 10) === 1) ? 'th' : + (b === 1) ? 'st' : + (b === 2) ? 'nd' : + (b === 3) ? 'rd' : 'th'; + return number + output; + } + }); - /** - * Event handler for touchmove event on mobile devices - */ - Graph3d.prototype._onTouchMove = function(event) { - this._onMouseMove(event); - }; + /* EMBED_LOCALES */ - /** - * Event handler for touchend event on mobile devices - */ - Graph3d.prototype._onTouchEnd = function(event) { - this.touchDown = false; + /************************************ + Exposing Moment + ************************************/ - util.removeEventListener(document, 'touchmove', this.ontouchmove); - util.removeEventListener(document, 'touchend', this.ontouchend); + function makeGlobal(shouldDeprecate) { + /*global ender:false */ + if (typeof ender !== 'undefined') { + return; + } + oldGlobalMoment = globalScope.moment; + if (shouldDeprecate) { + globalScope.moment = deprecate( + 'Accessing Moment through the global scope is ' + + 'deprecated, and will be removed in an upcoming ' + + 'release.', + moment); + } else { + globalScope.moment = moment; + } + } - this._onMouseUp(event); - }; + // CommonJS module is defined + if (hasModule) { + module.exports = moment; + } else if (true) { + !(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) { + if (module.config && module.config() && module.config().noGlobal === true) { + // release the global variable + globalScope.moment = oldGlobalMoment; + } + + return moment; + }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + makeGlobal(true); + } else { + makeGlobal(); + } + }).call(this); + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()), __webpack_require__(5)(module))) +/***/ }, +/* 4 */ +/***/ function(module, exports, __webpack_require__) { - /** - * Event handler for mouse wheel event, used to zoom the graph - * Code from http://adomas.org/javascript-mouse-wheel/ - * @param {event} event The event - */ - Graph3d.prototype._onWheel = function(event) { - if (!event) /* For IE. */ - event = window.event; + function webpackContext(req) { + throw new Error("Cannot find module '" + req + "'."); + } + webpackContext.keys = function() { return []; }; + webpackContext.resolve = webpackContext; + module.exports = webpackContext; + webpackContext.id = 4; - // retrieve delta - var delta = 0; - if (event.wheelDelta) { /* IE/Opera. */ - delta = event.wheelDelta/120; - } else if (event.detail) { /* Mozilla case. */ - // In Mozilla, sign of delta is different than in IE. - // Also, delta is multiple of 3. - delta = -event.detail/3; - } - // If delta is nonzero, handle it. - // Basically, delta is now positive if wheel was scrolled up, - // and negative, if wheel was scrolled down. - if (delta) { - var oldLength = this.camera.getArmLength(); - var newLength = oldLength * (1 - delta / 10); +/***/ }, +/* 5 */ +/***/ function(module, exports, __webpack_require__) { - this.camera.setArmLength(newLength); - this.redraw(); + module.exports = function(module) { + if(!module.webpackPolyfill) { + module.deprecate = function() {}; + module.paths = []; + // module.parent = undefined by default + module.children = []; + module.webpackPolyfill = 1; + } + return module; + } - this._hideTooltip(); - } - // fire a cameraPositionChange event - var parameters = this.getCameraPosition(); - this.emit('cameraPositionChange', parameters); +/***/ }, +/* 6 */ +/***/ function(module, exports, __webpack_require__) { - // Prevent default actions caused by mouse wheel. - // That might be ugly, but we handle scrolls somehow - // anyway, so don't bother here.. - util.preventDefault(event); - }; + // DOM utility methods /** - * Test whether a point lies inside given 2D triangle - * @param {Point2d} point - * @param {Point2d[]} triangle - * @return {boolean} Returns true if given point lies inside or on the edge of the triangle + * this prepares the JSON container for allocating SVG elements + * @param JSONcontainer * @private */ - Graph3d.prototype._insideTriangle = function (point, triangle) { - var a = triangle[0], - b = triangle[1], - c = triangle[2]; - - function sign (x) { - return x > 0 ? 1 : x < 0 ? -1 : 0; + exports.prepareElements = function(JSONcontainer) { + // cleanup the redundant svgElements; + for (var elementType in JSONcontainer) { + if (JSONcontainer.hasOwnProperty(elementType)) { + JSONcontainer[elementType].redundant = JSONcontainer[elementType].used; + JSONcontainer[elementType].used = []; + } } - - var as = sign((b.x - a.x) * (point.y - a.y) - (b.y - a.y) * (point.x - a.x)); - var bs = sign((c.x - b.x) * (point.y - b.y) - (c.y - b.y) * (point.x - b.x)); - var cs = sign((a.x - c.x) * (point.y - c.y) - (a.y - c.y) * (point.x - c.x)); - - // each of the three signs must be either equal to each other or zero - return (as == 0 || bs == 0 || as == bs) && - (bs == 0 || cs == 0 || bs == cs) && - (as == 0 || cs == 0 || as == cs); }; /** - * Find a data point close to given screen position (x, y) - * @param {Number} x - * @param {Number} y - * @return {Object | null} The closest data point or null if not close to any data point + * this cleans up all the unused SVG elements. By asking for the parentNode, we only need to supply the JSON container from + * which to remove the redundant elements. + * + * @param JSONcontainer * @private */ - Graph3d.prototype._dataPointFromXY = function (x, y) { - var i, - distMax = 100, // px - dataPoint = null, - closestDataPoint = null, - closestDist = null, - center = new Point2d(x, y); - - if (this.style === Graph3d.STYLE.BAR || - this.style === Graph3d.STYLE.BARCOLOR || - this.style === Graph3d.STYLE.BARSIZE) { - // the data points are ordered from far away to closest - for (i = this.dataPoints.length - 1; i >= 0; i--) { - dataPoint = this.dataPoints[i]; - var surfaces = dataPoint.surfaces; - if (surfaces) { - for (var s = surfaces.length - 1; s >= 0; s--) { - // split each surface in two triangles, and see if the center point is inside one of these - var surface = surfaces[s]; - var corners = surface.corners; - var triangle1 = [corners[0].screen, corners[1].screen, corners[2].screen]; - var triangle2 = [corners[2].screen, corners[3].screen, corners[0].screen]; - if (this._insideTriangle(center, triangle1) || - this._insideTriangle(center, triangle2)) { - // return immediately at the first hit - return dataPoint; - } - } - } - } - } - else { - // find the closest data point, using distance to the center of the point on 2d screen - for (i = 0; i < this.dataPoints.length; i++) { - dataPoint = this.dataPoints[i]; - var point = dataPoint.screen; - if (point) { - var distX = Math.abs(x - point.x); - var distY = Math.abs(y - point.y); - var dist = Math.sqrt(distX * distX + distY * distY); - - if ((closestDist === null || dist < closestDist) && dist < distMax) { - closestDist = dist; - closestDataPoint = dataPoint; + exports.cleanupElements = function(JSONcontainer) { + // cleanup the redundant svgElements; + for (var elementType in JSONcontainer) { + if (JSONcontainer.hasOwnProperty(elementType)) { + if (JSONcontainer[elementType].redundant) { + for (var i = 0; i < JSONcontainer[elementType].redundant.length; i++) { + JSONcontainer[elementType].redundant[i].parentNode.removeChild(JSONcontainer[elementType].redundant[i]); } + JSONcontainer[elementType].redundant = []; } } } - - - return closestDataPoint; }; /** - * Display a tooltip for given data point - * @param {Object} dataPoint + * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer + * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this. + * + * @param elementType + * @param JSONcontainer + * @param svgContainer + * @returns {*} * @private */ - Graph3d.prototype._showTooltip = function (dataPoint) { - var content, line, dot; - - if (!this.tooltip) { - content = document.createElement('div'); - content.style.position = 'absolute'; - content.style.padding = '10px'; - content.style.border = '1px solid #4d4d4d'; - content.style.color = '#1a1a1a'; - content.style.background = 'rgba(255,255,255,0.7)'; - content.style.borderRadius = '2px'; - content.style.boxShadow = '5px 5px 10px rgba(128,128,128,0.5)'; - - line = document.createElement('div'); - line.style.position = 'absolute'; - line.style.height = '40px'; - line.style.width = '0'; - line.style.borderLeft = '1px solid #4d4d4d'; - - dot = document.createElement('div'); - dot.style.position = 'absolute'; - dot.style.height = '0'; - dot.style.width = '0'; - dot.style.border = '5px solid #4d4d4d'; - dot.style.borderRadius = '5px'; - - this.tooltip = { - dataPoint: null, - dom: { - content: content, - line: line, - dot: dot - } - }; - } - else { - content = this.tooltip.dom.content; - line = this.tooltip.dom.line; - dot = this.tooltip.dom.dot; - } - - this._hideTooltip(); - - this.tooltip.dataPoint = dataPoint; - if (typeof this.showTooltip === 'function') { - content.innerHTML = this.showTooltip(dataPoint.point); + exports.getSVGElement = function (elementType, JSONcontainer, svgContainer) { + var element; + // allocate SVG element, if it doesnt yet exist, create one. + if (JSONcontainer.hasOwnProperty(elementType)) { // this element has been created before + // check if there is an redundant element + if (JSONcontainer[elementType].redundant.length > 0) { + element = JSONcontainer[elementType].redundant[0]; + JSONcontainer[elementType].redundant.shift(); + } + else { + // create a new element and add it to the SVG + element = document.createElementNS('http://www.w3.org/2000/svg', elementType); + svgContainer.appendChild(element); + } } else { - content.innerHTML = '' + - '' + - '' + - '' + - '
x:' + dataPoint.point.x + '
y:' + dataPoint.point.y + '
z:' + dataPoint.point.z + '
'; + // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it. + element = document.createElementNS('http://www.w3.org/2000/svg', elementType); + JSONcontainer[elementType] = {used: [], redundant: []}; + svgContainer.appendChild(element); } - - content.style.left = '0'; - content.style.top = '0'; - this.frame.appendChild(content); - this.frame.appendChild(line); - this.frame.appendChild(dot); - - // calculate sizes - var contentWidth = content.offsetWidth; - var contentHeight = content.offsetHeight; - var lineHeight = line.offsetHeight; - var dotWidth = dot.offsetWidth; - var dotHeight = dot.offsetHeight; - - var left = dataPoint.screen.x - contentWidth / 2; - left = Math.min(Math.max(left, 10), this.frame.clientWidth - 10 - contentWidth); - - line.style.left = dataPoint.screen.x + 'px'; - line.style.top = (dataPoint.screen.y - lineHeight) + 'px'; - content.style.left = left + 'px'; - content.style.top = (dataPoint.screen.y - lineHeight - contentHeight) + 'px'; - dot.style.left = (dataPoint.screen.x - dotWidth / 2) + 'px'; - dot.style.top = (dataPoint.screen.y - dotHeight / 2) + 'px'; + JSONcontainer[elementType].used.push(element); + return element; }; + /** - * Hide the tooltip when displayed + * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer + * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this. + * + * @param elementType + * @param JSONcontainer + * @param DOMContainer + * @returns {*} * @private */ - Graph3d.prototype._hideTooltip = function () { - if (this.tooltip) { - this.tooltip.dataPoint = null; - - for (var prop in this.tooltip.dom) { - if (this.tooltip.dom.hasOwnProperty(prop)) { - var elem = this.tooltip.dom[prop]; - if (elem && elem.parentNode) { - elem.parentNode.removeChild(elem); - } + exports.getDOMElement = function (elementType, JSONcontainer, DOMContainer, insertBefore) { + var element; + // allocate DOM element, if it doesnt yet exist, create one. + if (JSONcontainer.hasOwnProperty(elementType)) { // this element has been created before + // check if there is an redundant element + if (JSONcontainer[elementType].redundant.length > 0) { + element = JSONcontainer[elementType].redundant[0]; + JSONcontainer[elementType].redundant.shift(); + } + else { + // create a new element and add it to the SVG + element = document.createElement(elementType); + if (insertBefore !== undefined) { + DOMContainer.insertBefore(element, insertBefore); } + else { + DOMContainer.appendChild(element); + } + } + } + else { + // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it. + element = document.createElement(elementType); + JSONcontainer[elementType] = {used: [], redundant: []}; + if (insertBefore !== undefined) { + DOMContainer.insertBefore(element, insertBefore); + } + else { + DOMContainer.appendChild(element); } } + JSONcontainer[elementType].used.push(element); + return element; }; - /**--------------------------------------------------------------------------**/ - /** - * Get the horizontal mouse position from a mouse event - * @param {Event} event - * @return {Number} mouse x - */ - function getMouseX (event) { - if ('clientX' in event) return event.clientX; - return event.targetTouches[0] && event.targetTouches[0].clientX || 0; - } /** - * Get the vertical mouse position from a mouse event - * @param {Event} event - * @return {Number} mouse y - */ - function getMouseY (event) { - if ('clientY' in event) return event.clientY; - return event.targetTouches[0] && event.targetTouches[0].clientY || 0; - } - - module.exports = Graph3d; - - -/***/ }, -/* 7 */ -/***/ function(module, exports, __webpack_require__) { - - var Point3d = __webpack_require__(10); - - /** - * @class Camera - * The camera is mounted on a (virtual) camera arm. The camera arm can rotate - * The camera is always looking in the direction of the origin of the arm. - * This way, the camera always rotates around one fixed point, the location - * of the camera arm. + * draw a point object. this is a seperate function because it can also be called by the legend. + * The reason the JSONcontainer and the target SVG svgContainer have to be supplied is so the legend can use these functions + * as well. * - * Documentation: - * http://en.wikipedia.org/wiki/3D_projection - */ - function Camera() { - this.armLocation = new Point3d(); - this.armRotation = {}; - this.armRotation.horizontal = 0; - this.armRotation.vertical = 0; - this.armLength = 1.7; - - this.cameraLocation = new Point3d(); - this.cameraRotation = new Point3d(0.5*Math.PI, 0, 0); - - this.calculateCameraOrientation(); - } - - /** - * Set the location (origin) of the arm - * @param {Number} x Normalized value of x - * @param {Number} y Normalized value of y - * @param {Number} z Normalized value of z - */ - Camera.prototype.setArmLocation = function(x, y, z) { - this.armLocation.x = x; - this.armLocation.y = y; - this.armLocation.z = z; - - this.calculateCameraOrientation(); - }; - - /** - * Set the rotation of the camera arm - * @param {Number} horizontal The horizontal rotation, between 0 and 2*PI. - * Optional, can be left undefined. - * @param {Number} vertical The vertical rotation, between 0 and 0.5*PI - * if vertical=0.5*PI, the graph is shown from the - * top. Optional, can be left undefined. + * @param x + * @param y + * @param group + * @param JSONcontainer + * @param svgContainer + * @returns {*} */ - Camera.prototype.setArmRotation = function(horizontal, vertical) { - if (horizontal !== undefined) { - this.armRotation.horizontal = horizontal; + exports.drawPoint = function(x, y, group, JSONcontainer, svgContainer) { + var point; + if (group.options.drawPoints.style == 'circle') { + point = exports.getSVGElement('circle',JSONcontainer,svgContainer); + point.setAttributeNS(null, "cx", x); + point.setAttributeNS(null, "cy", y); + point.setAttributeNS(null, "r", 0.5 * group.options.drawPoints.size); } - - if (vertical !== undefined) { - this.armRotation.vertical = vertical; - if (this.armRotation.vertical < 0) this.armRotation.vertical = 0; - if (this.armRotation.vertical > 0.5*Math.PI) this.armRotation.vertical = 0.5*Math.PI; + else { + point = exports.getSVGElement('rect',JSONcontainer,svgContainer); + point.setAttributeNS(null, "x", x - 0.5*group.options.drawPoints.size); + point.setAttributeNS(null, "y", y - 0.5*group.options.drawPoints.size); + point.setAttributeNS(null, "width", group.options.drawPoints.size); + point.setAttributeNS(null, "height", group.options.drawPoints.size); } - if (horizontal !== undefined || vertical !== undefined) { - this.calculateCameraOrientation(); + if(group.options.drawPoints.styles !== undefined) { + point.setAttributeNS(null, "style", group.group.options.drawPoints.styles); } + point.setAttributeNS(null, "class", group.className + " point"); + return point; }; /** - * Retrieve the current arm rotation - * @return {object} An object with parameters horizontal and vertical - */ - Camera.prototype.getArmRotation = function() { - var rot = {}; - rot.horizontal = this.armRotation.horizontal; - rot.vertical = this.armRotation.vertical; - - return rot; - }; - - /** - * Set the (normalized) length of the camera arm. - * @param {Number} length A length between 0.71 and 5.0 - */ - Camera.prototype.setArmLength = function(length) { - if (length === undefined) - return; - - this.armLength = length; - - // Radius must be larger than the corner of the graph, - // which has a distance of sqrt(0.5^2+0.5^2) = 0.71 from the center of the - // graph - if (this.armLength < 0.71) this.armLength = 0.71; - if (this.armLength > 5.0) this.armLength = 5.0; - - this.calculateCameraOrientation(); - }; - - /** - * Retrieve the arm length - * @return {Number} length - */ - Camera.prototype.getArmLength = function() { - return this.armLength; - }; - - /** - * Retrieve the camera location - * @return {Point3d} cameraLocation - */ - Camera.prototype.getCameraLocation = function() { - return this.cameraLocation; - }; - - /** - * Retrieve the camera rotation - * @return {Point3d} cameraRotation - */ - Camera.prototype.getCameraRotation = function() { - return this.cameraRotation; - }; - - /** - * Calculate the location and rotation of the camera based on the - * position and orientation of the camera arm + * draw a bar SVG element centered on the X coordinate + * + * @param x + * @param y + * @param className */ - Camera.prototype.calculateCameraOrientation = function() { - // calculate location of the camera - this.cameraLocation.x = this.armLocation.x - this.armLength * Math.sin(this.armRotation.horizontal) * Math.cos(this.armRotation.vertical); - this.cameraLocation.y = this.armLocation.y - this.armLength * Math.cos(this.armRotation.horizontal) * Math.cos(this.armRotation.vertical); - this.cameraLocation.z = this.armLocation.z + this.armLength * Math.sin(this.armRotation.vertical); - - // calculate rotation of the camera - this.cameraRotation.x = Math.PI/2 - this.armRotation.vertical; - this.cameraRotation.y = 0; - this.cameraRotation.z = -this.armRotation.horizontal; + exports.drawBar = function (x, y, width, height, className, JSONcontainer, svgContainer) { + if (height != 0) { + if (height < 0) { + height *= -1; + y -= height; + } + var rect = exports.getSVGElement('rect',JSONcontainer, svgContainer); + rect.setAttributeNS(null, "x", x - 0.5 * width); + rect.setAttributeNS(null, "y", y); + rect.setAttributeNS(null, "width", width); + rect.setAttributeNS(null, "height", height); + rect.setAttributeNS(null, "class", className); + } }; - module.exports = Camera; - /***/ }, -/* 8 */ +/* 7 */ /***/ function(module, exports, __webpack_require__) { - var DataView = __webpack_require__(4); + var util = __webpack_require__(1); + var Queue = __webpack_require__(8); /** - * @class Filter + * DataSet * - * @param {DataSet} data The google data table - * @param {Number} column The index of the column to be filtered - * @param {Graph} graph The graph + * Usage: + * var dataSet = new DataSet({ + * fieldId: '_id', + * type: { + * // ... + * } + * }); + * + * dataSet.add(item); + * dataSet.add(data); + * dataSet.update(item); + * dataSet.update(data); + * dataSet.remove(id); + * dataSet.remove(ids); + * var data = dataSet.get(); + * var data = dataSet.get(id); + * var data = dataSet.get(ids); + * var data = dataSet.get(ids, options, data); + * dataSet.clear(); + * + * A data set can: + * - add/remove/update data + * - gives triggers upon changes in the data + * - can import/export data in various data formats + * + * @param {Array | DataTable} [data] Optional array with initial data + * @param {Object} [options] Available options: + * {String} fieldId Field name of the id in the + * items, 'id' by default. + * {Object. b ? 1 : a < b ? -1 : 0; - }); - - if (this.values.length > 0) { - this.selectValue(0); + // TODO: add a DataSet constructor DataSet(data, options) + function DataSet (data, options) { + // correctly read optional arguments + if (data && !Array.isArray(data) && !util.isDataTable(data)) { + options = data; + data = null; } - // create an array with the filtered datapoints. this will be loaded afterwards - this.dataPoints = []; - - this.loaded = false; - this.onLoadCallback = undefined; + this._options = options || {}; + this._data = {}; // map with data indexed by id + this._fieldId = this._options.fieldId || 'id'; // name of the field containing id + this._type = {}; // internal field types (NOTE: this can differ from this._options.type) - if (graph.animationPreload) { - this.loaded = false; - this.loadInBackground(); + // all variants of a Date are internally stored as Date, so we can convert + // from everything to everything (also from ISODate to Number for example) + if (this._options.type) { + for (var field in this._options.type) { + if (this._options.type.hasOwnProperty(field)) { + var value = this._options.type[field]; + if (value == 'Date' || value == 'ISODate' || value == 'ASPDate') { + this._type[field] = 'Date'; + } + else { + this._type[field] = value; + } + } + } } - else { - this.loaded = true; + + // TODO: deprecated since version 1.1.1 (or 2.0.0?) + if (this._options.convert) { + throw new Error('Option "convert" is deprecated. Use "type" instead.'); } - }; + this._subscribers = {}; // event subscribers - /** - * Return the label - * @return {string} label - */ - Filter.prototype.isLoaded = function() { - return this.loaded; - }; + // add initial data when provided + if (data) { + this.add(data); + } + this.setOptions(options); + } /** - * Return the loaded progress - * @return {Number} percentage between 0 and 100 + * @param {Object} [options] Available options: + * {Object} queue Queue changes to the DataSet, + * flush them all at once. + * Queue options: + * - {number} delay Delay in ms, null by default + * - {number} max Maximum number of entries in the queue, Infinity by default + * @param options */ - Filter.prototype.getLoadedProgress = function() { - var len = this.values.length; + DataSet.prototype.setOptions = function(options) { + if (options && options.queue !== undefined) { + if (options.queue === false) { + // delete queue if loaded + if (this._queue) { + this._queue.destroy(); + delete this._queue; + } + } + else { + // create queue and update its options + if (!this._queue) { + this._queue = Queue.extend(this, { + replace: ['add', 'update', 'remove'] + }); + } - var i = 0; - while (this.dataPoints[i]) { - i++; + if (typeof options.queue === 'object') { + this._queue.setOptions(options.queue); + } + } } - - return Math.round(i / len * 100); }; - /** - * Return the label - * @return {string} label + * Subscribe to an event, add an event listener + * @param {String} event Event name. Available events: 'put', 'update', + * 'remove' + * @param {function} callback Callback method. Called with three parameters: + * {String} event + * {Object | null} params + * {String | Number} senderId */ - Filter.prototype.getLabel = function() { - return this.graph.filterLabel; + DataSet.prototype.on = function(event, callback) { + var subscribers = this._subscribers[event]; + if (!subscribers) { + subscribers = []; + this._subscribers[event] = subscribers; + } + + subscribers.push({ + callback: callback + }); }; + // TODO: make this function deprecated (replaced with `on` since version 0.5) + DataSet.prototype.subscribe = DataSet.prototype.on; /** - * Return the columnIndex of the filter - * @return {Number} columnIndex + * Unsubscribe from an event, remove an event listener + * @param {String} event + * @param {function} callback */ - Filter.prototype.getColumn = function() { - return this.column; + DataSet.prototype.off = function(event, callback) { + var subscribers = this._subscribers[event]; + if (subscribers) { + this._subscribers[event] = subscribers.filter(function (listener) { + return (listener.callback != callback); + }); + } }; - /** - * Return the currently selected value. Returns undefined if there is no selection - * @return {*} value - */ - Filter.prototype.getSelectedValue = function() { - if (this.index === undefined) - return undefined; - - return this.values[this.index]; - }; + // TODO: make this function deprecated (replaced with `on` since version 0.5) + DataSet.prototype.unsubscribe = DataSet.prototype.off; /** - * Retrieve all values of the filter - * @return {Array} values + * Trigger an event + * @param {String} event + * @param {Object | null} params + * @param {String} [senderId] Optional id of the sender. + * @private */ - Filter.prototype.getValues = function() { - return this.values; - }; + DataSet.prototype._trigger = function (event, params, senderId) { + if (event == '*') { + throw new Error('Cannot trigger event *'); + } - /** - * Retrieve one value of the filter - * @param {Number} index - * @return {*} value - */ - Filter.prototype.getValue = function(index) { - if (index >= this.values.length) - throw 'Error: index out of range'; + var subscribers = []; + if (event in this._subscribers) { + subscribers = subscribers.concat(this._subscribers[event]); + } + if ('*' in this._subscribers) { + subscribers = subscribers.concat(this._subscribers['*']); + } - return this.values[index]; + for (var i = 0; i < subscribers.length; i++) { + var subscriber = subscribers[i]; + if (subscriber.callback) { + subscriber.callback(event, params, senderId || null); + } + } }; - /** - * Retrieve the (filtered) dataPoints for the currently selected filter index - * @param {Number} [index] (optional) - * @return {Array} dataPoints + * Add data. + * Adding an item will fail when there already is an item with the same id. + * @param {Object | Array | DataTable} data + * @param {String} [senderId] Optional sender id + * @return {Array} addedIds Array with the ids of the added items */ - Filter.prototype._getDataPoints = function(index) { - if (index === undefined) - index = this.index; + DataSet.prototype.add = function (data, senderId) { + var addedIds = [], + id, + me = this; - if (index === undefined) - return []; + if (Array.isArray(data)) { + // Array + for (var i = 0, len = data.length; i < len; i++) { + id = me._addItem(data[i]); + addedIds.push(id); + } + } + else if (util.isDataTable(data)) { + // Google DataTable + var columns = this._getColumnNames(data); + for (var row = 0, rows = data.getNumberOfRows(); row < rows; row++) { + var item = {}; + for (var col = 0, cols = columns.length; col < cols; col++) { + var field = columns[col]; + item[field] = data.getValue(row, col); + } - var dataPoints; - if (this.dataPoints[index]) { - dataPoints = this.dataPoints[index]; + id = me._addItem(item); + addedIds.push(id); + } + } + else if (data instanceof Object) { + // Single item + id = me._addItem(data); + addedIds.push(id); } else { - var f = {}; - f.column = this.column; - f.value = this.values[index]; - - var dataView = new DataView(this.data,{filter: function (item) {return (item[f.column] == f.value);}}).get(); - dataPoints = this.graph._getDataPoints(dataView); + throw new Error('Unknown dataType'); + } - this.dataPoints[index] = dataPoints; + if (addedIds.length) { + this._trigger('add', {items: addedIds}, senderId); } - return dataPoints; + return addedIds; }; - - /** - * Set a callback function when the filter is fully loaded. + * Update existing items. When an item does not exist, it will be created + * @param {Object | Array | DataTable} data + * @param {String} [senderId] Optional sender id + * @return {Array} updatedIds The ids of the added or updated items */ - Filter.prototype.setOnLoadCallback = function(callback) { - this.onLoadCallback = callback; - }; + DataSet.prototype.update = function (data, senderId) { + var addedIds = []; + var updatedIds = []; + var updatedData = []; + var me = this; + var fieldId = me._fieldId; + var addOrUpdate = function (item) { + var id = item[fieldId]; + if (me._data[id]) { + // update item + id = me._updateItem(item); + updatedIds.push(id); + updatedData.push(item); + } + else { + // add new item + id = me._addItem(item); + addedIds.push(id); + } + }; - /** - * Add a value to the list with available values for this filter - * No double entries will be created. - * @param {Number} index - */ - Filter.prototype.selectValue = function(index) { - if (index >= this.values.length) - throw 'Error: index out of range'; + if (Array.isArray(data)) { + // Array + for (var i = 0, len = data.length; i < len; i++) { + addOrUpdate(data[i]); + } + } + else if (util.isDataTable(data)) { + // Google DataTable + var columns = this._getColumnNames(data); + for (var row = 0, rows = data.getNumberOfRows(); row < rows; row++) { + var item = {}; + for (var col = 0, cols = columns.length; col < cols; col++) { + var field = columns[col]; + item[field] = data.getValue(row, col); + } - this.index = index; - this.value = this.values[index]; + addOrUpdate(item); + } + } + else if (data instanceof Object) { + // Single item + addOrUpdate(data); + } + else { + throw new Error('Unknown dataType'); + } + + if (addedIds.length) { + this._trigger('add', {items: addedIds}, senderId); + } + if (updatedIds.length) { + this._trigger('update', {items: updatedIds, data: updatedData}, senderId); + } + + return addedIds.concat(updatedIds); }; /** - * Load all filtered rows in the background one by one - * Start this method without providing an index! + * Get a data item or multiple items. + * + * Usage: + * + * get() + * get(options: Object) + * get(options: Object, data: Array | DataTable) + * + * get(id: Number | String) + * get(id: Number | String, options: Object) + * get(id: Number | String, options: Object, data: Array | DataTable) + * + * get(ids: Number[] | String[]) + * get(ids: Number[] | String[], options: Object) + * get(ids: Number[] | String[], options: Object, data: Array | DataTable) + * + * Where: + * + * {Number | String} id The id of an item + * {Number[] | String{}} ids An array with ids of items + * {Object} options An Object with options. Available options: + * {String} [returnType] Type of data to be + * returned. Can be 'DataTable' or 'Array' (default) + * {Object.} [type] + * {String[]} [fields] field names to be returned + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * {Array | DataTable} [data] If provided, items will be appended to this + * array or table. Required in case of Google + * DataTable. + * + * @throws Error */ - Filter.prototype.loadInBackground = function(index) { - if (index === undefined) - index = 0; + DataSet.prototype.get = function (args) { + var me = this; - var frame = this.graph.frame; + // parse the arguments + var id, ids, options, data; + var firstType = util.getType(arguments[0]); + if (firstType == 'String' || firstType == 'Number') { + // get(id [, options] [, data]) + id = arguments[0]; + options = arguments[1]; + data = arguments[2]; + } + else if (firstType == 'Array') { + // get(ids [, options] [, data]) + ids = arguments[0]; + options = arguments[1]; + data = arguments[2]; + } + else { + // get([, options] [, data]) + options = arguments[0]; + data = arguments[1]; + } - if (index < this.values.length) { - var dataPointsTemp = this._getDataPoints(index); - //this.graph.redrawInfo(); // TODO: not neat + // determine the return type + var returnType; + if (options && options.returnType) { + var allowedValues = ["DataTable", "Array", "Object"]; + returnType = allowedValues.indexOf(options.returnType) == -1 ? "Array" : options.returnType; - // create a progress box - if (frame.progress === undefined) { - frame.progress = document.createElement('DIV'); - frame.progress.style.position = 'absolute'; - frame.progress.style.color = 'gray'; - frame.appendChild(frame.progress); + if (data && (returnType != util.getType(data))) { + throw new Error('Type of parameter "data" (' + util.getType(data) + ') ' + + 'does not correspond with specified options.type (' + options.type + ')'); } - var progress = this.getLoadedProgress(); - frame.progress.innerHTML = 'Loading animation... ' + progress + '%'; - // TODO: this is no nice solution... - frame.progress.style.bottom = 60 + 'px'; // TODO: use height of slider - frame.progress.style.left = 10 + 'px'; - - var me = this; - setTimeout(function() {me.loadInBackground(index+1);}, 10); - this.loaded = false; + if (returnType == 'DataTable' && !util.isDataTable(data)) { + throw new Error('Parameter "data" must be a DataTable ' + + 'when options.type is "DataTable"'); + } + } + else if (data) { + returnType = (util.getType(data) == 'DataTable') ? 'DataTable' : 'Array'; } else { - this.loaded = true; + returnType = 'Array'; + } - // remove the progress box - if (frame.progress !== undefined) { - frame.removeChild(frame.progress); - frame.progress = undefined; - } + // build options + var type = options && options.type || this._options.type; + var filter = options && options.filter; + var items = [], item, itemId, i, len; - if (this.onLoadCallback) - this.onLoadCallback(); + // convert items + if (id != undefined) { + // return a single item + item = me._getItem(id, type); + if (filter && !filter(item)) { + item = null; + } + } + else if (ids != undefined) { + // return a subset of items + for (i = 0, len = ids.length; i < len; i++) { + item = me._getItem(ids[i], type); + if (!filter || filter(item)) { + items.push(item); + } + } + } + else { + // return all items + for (itemId in this._data) { + if (this._data.hasOwnProperty(itemId)) { + item = me._getItem(itemId, type); + if (!filter || filter(item)) { + items.push(item); + } + } + } } - }; - module.exports = Filter; + // order the results + if (options && options.order && id == undefined) { + this._sort(items, options.order); + } + // filter fields of the items + if (options && options.fields) { + var fields = options.fields; + if (id != undefined) { + item = this._filterFields(item, fields); + } + else { + for (i = 0, len = items.length; i < len; i++) { + items[i] = this._filterFields(items[i], fields); + } + } + } -/***/ }, -/* 9 */ -/***/ function(module, exports, __webpack_require__) { + // return the results + if (returnType == 'DataTable') { + var columns = this._getColumnNames(data); + if (id != undefined) { + // append a single item to the data table + me._appendRow(data, columns, item); + } + else { + // copy the items to the provided data table + for (i = 0; i < items.length; i++) { + me._appendRow(data, columns, items[i]); + } + } + return data; + } + else if (returnType == "Object") { + var result = {}; + for (i = 0; i < items.length; i++) { + result[items[i].id] = items[i]; + } + return result; + } + else { + // return an array + if (id != undefined) { + // a single item + return item; + } + else { + // multiple items + if (data) { + // copy the items to the provided array + for (i = 0, len = items.length; i < len; i++) { + data.push(items[i]); + } + return data; + } + else { + // just return our array + return items; + } + } + } + }; /** - * @prototype Point2d - * @param {Number} [x] - * @param {Number} [y] + * Get ids of all items or from a filtered set of items. + * @param {Object} [options] An Object with options. Available options: + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * @return {Array} ids */ - function Point2d (x, y) { - this.x = x !== undefined ? x : 0; - this.y = y !== undefined ? y : 0; - } + DataSet.prototype.getIds = function (options) { + var data = this._data, + filter = options && options.filter, + order = options && options.order, + type = options && options.type || this._options.type, + i, + len, + id, + item, + items, + ids = []; - module.exports = Point2d; + if (filter) { + // get filtered items + if (order) { + // create ordered list + items = []; + for (id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, type); + if (filter(item)) { + items.push(item); + } + } + } + this._sort(items, order); -/***/ }, -/* 10 */ -/***/ function(module, exports, __webpack_require__) { + for (i = 0, len = items.length; i < len; i++) { + ids[i] = items[i][this._fieldId]; + } + } + else { + // create unordered list + for (id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, type); + if (filter(item)) { + ids.push(item[this._fieldId]); + } + } + } + } + } + else { + // get all items + if (order) { + // create an ordered list + items = []; + for (id in data) { + if (data.hasOwnProperty(id)) { + items.push(data[id]); + } + } - /** - * @prototype Point3d - * @param {Number} [x] - * @param {Number} [y] - * @param {Number} [z] - */ - function Point3d(x, y, z) { - this.x = x !== undefined ? x : 0; - this.y = y !== undefined ? y : 0; - this.z = z !== undefined ? z : 0; - }; + this._sort(items, order); - /** - * Subtract the two provided points, returns a-b - * @param {Point3d} a - * @param {Point3d} b - * @return {Point3d} a-b - */ - Point3d.subtract = function(a, b) { - var sub = new Point3d(); - sub.x = a.x - b.x; - sub.y = a.y - b.y; - sub.z = a.z - b.z; - return sub; - }; + for (i = 0, len = items.length; i < len; i++) { + ids[i] = items[i][this._fieldId]; + } + } + else { + // create unordered list + for (id in data) { + if (data.hasOwnProperty(id)) { + item = data[id]; + ids.push(item[this._fieldId]); + } + } + } + } - /** - * Add the two provided points, returns a+b - * @param {Point3d} a - * @param {Point3d} b - * @return {Point3d} a+b - */ - Point3d.add = function(a, b) { - var sum = new Point3d(); - sum.x = a.x + b.x; - sum.y = a.y + b.y; - sum.z = a.z + b.z; - return sum; + return ids; }; /** - * Calculate the average of two 3d points - * @param {Point3d} a - * @param {Point3d} b - * @return {Point3d} The average, (a+b)/2 + * Returns the DataSet itself. Is overwritten for example by the DataView, + * which returns the DataSet it is connected to instead. */ - Point3d.avg = function(a, b) { - return new Point3d( - (a.x + b.x) / 2, - (a.y + b.y) / 2, - (a.z + b.z) / 2 - ); + DataSet.prototype.getDataSet = function () { + return this; }; /** - * Calculate the cross product of the two provided points, returns axb - * Documentation: http://en.wikipedia.org/wiki/Cross_product - * @param {Point3d} a - * @param {Point3d} b - * @return {Point3d} cross product axb + * Execute a callback function for every item in the dataset. + * @param {function} callback + * @param {Object} [options] Available options: + * {Object.} [type] + * {String[]} [fields] filter fields + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. */ - Point3d.crossProduct = function(a, b) { - var crossproduct = new Point3d(); + DataSet.prototype.forEach = function (callback, options) { + var filter = options && options.filter, + type = options && options.type || this._options.type, + data = this._data, + item, + id; - crossproduct.x = a.y * b.z - a.z * b.y; - crossproduct.y = a.z * b.x - a.x * b.z; - crossproduct.z = a.x * b.y - a.y * b.x; + if (options && options.order) { + // execute forEach on ordered list + var items = this.get(options); - return crossproduct; + for (var i = 0, len = items.length; i < len; i++) { + item = items[i]; + id = item[this._fieldId]; + callback(item, id); + } + } + else { + // unordered + for (id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, type); + if (!filter || filter(item)) { + callback(item, id); + } + } + } + } }; - /** - * Rtrieve the length of the vector (or the distance from this point to the origin - * @return {Number} length + * Map every item in the dataset. + * @param {function} callback + * @param {Object} [options] Available options: + * {Object.} [type] + * {String[]} [fields] filter fields + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * @return {Object[]} mappedItems */ - Point3d.prototype.length = function() { - return Math.sqrt( - this.x * this.x + - this.y * this.y + - this.z * this.z - ); - }; - - module.exports = Point3d; + DataSet.prototype.map = function (callback, options) { + var filter = options && options.filter, + type = options && options.type || this._options.type, + mappedItems = [], + data = this._data, + item; + // convert and filter items + for (var id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, type); + if (!filter || filter(item)) { + mappedItems.push(callback(item, id)); + } + } + } -/***/ }, -/* 11 */ -/***/ function(module, exports, __webpack_require__) { + // order items + if (options && options.order) { + this._sort(mappedItems, options.order); + } - var util = __webpack_require__(1); + return mappedItems; + }; /** - * @constructor Slider - * - * An html slider control with start/stop/prev/next buttons - * @param {Element} container The element where the slider will be created - * @param {Object} options Available options: - * {boolean} visible If true (default) the - * slider is visible. + * Filter the fields of an item + * @param {Object} item + * @param {String[]} fields Field names + * @return {Object} filteredItem + * @private */ - function Slider(container, options) { - if (container === undefined) { - throw 'Error: No container element defined'; - } - this.container = container; - this.visible = (options && options.visible != undefined) ? options.visible : true; - - if (this.visible) { - this.frame = document.createElement('DIV'); - //this.frame.style.backgroundColor = '#E5E5E5'; - this.frame.style.width = '100%'; - this.frame.style.position = 'relative'; - this.container.appendChild(this.frame); - - this.frame.prev = document.createElement('INPUT'); - this.frame.prev.type = 'BUTTON'; - this.frame.prev.value = 'Prev'; - this.frame.appendChild(this.frame.prev); + DataSet.prototype._filterFields = function (item, fields) { + var filteredItem = {}; - this.frame.play = document.createElement('INPUT'); - this.frame.play.type = 'BUTTON'; - this.frame.play.value = 'Play'; - this.frame.appendChild(this.frame.play); + for (var field in item) { + if (item.hasOwnProperty(field) && (fields.indexOf(field) != -1)) { + filteredItem[field] = item[field]; + } + } - this.frame.next = document.createElement('INPUT'); - this.frame.next.type = 'BUTTON'; - this.frame.next.value = 'Next'; - this.frame.appendChild(this.frame.next); - - this.frame.bar = document.createElement('INPUT'); - this.frame.bar.type = 'BUTTON'; - this.frame.bar.style.position = 'absolute'; - this.frame.bar.style.border = '1px solid red'; - this.frame.bar.style.width = '100px'; - this.frame.bar.style.height = '6px'; - this.frame.bar.style.borderRadius = '2px'; - this.frame.bar.style.MozBorderRadius = '2px'; - this.frame.bar.style.border = '1px solid #7F7F7F'; - this.frame.bar.style.backgroundColor = '#E5E5E5'; - this.frame.appendChild(this.frame.bar); - - this.frame.slide = document.createElement('INPUT'); - this.frame.slide.type = 'BUTTON'; - this.frame.slide.style.margin = '0px'; - this.frame.slide.value = ' '; - this.frame.slide.style.position = 'relative'; - this.frame.slide.style.left = '-100px'; - this.frame.appendChild(this.frame.slide); - - // create events - var me = this; - this.frame.slide.onmousedown = function (event) {me._onMouseDown(event);}; - this.frame.prev.onclick = function (event) {me.prev(event);}; - this.frame.play.onclick = function (event) {me.togglePlay(event);}; - this.frame.next.onclick = function (event) {me.next(event);}; - } - - this.onChangeCallback = undefined; - - this.values = []; - this.index = undefined; - - this.playTimeout = undefined; - this.playInterval = 1000; // milliseconds - this.playLoop = true; - } + return filteredItem; + }; /** - * Select the previous index + * Sort the provided array with items + * @param {Object[]} items + * @param {String | function} order A field name or custom sort function. + * @private */ - Slider.prototype.prev = function() { - var index = this.getIndex(); - if (index > 0) { - index--; - this.setIndex(index); + DataSet.prototype._sort = function (items, order) { + if (util.isString(order)) { + // order by provided field name + var name = order; // field name + items.sort(function (a, b) { + var av = a[name]; + var bv = b[name]; + return (av > bv) ? 1 : ((av < bv) ? -1 : 0); + }); } - }; - - /** - * Select the next index - */ - Slider.prototype.next = function() { - var index = this.getIndex(); - if (index < this.values.length - 1) { - index++; - this.setIndex(index); + else if (typeof order === 'function') { + // order by sort function + items.sort(order); + } + // TODO: extend order by an Object {field:String, direction:String} + // where direction can be 'asc' or 'desc' + else { + throw new TypeError('Order must be a function or a string'); } }; /** - * Select the next index + * Remove an object by pointer or by id + * @param {String | Number | Object | Array} id Object or id, or an array with + * objects or ids to be removed + * @param {String} [senderId] Optional sender id + * @return {Array} removedIds */ - Slider.prototype.playNext = function() { - var start = new Date(); + DataSet.prototype.remove = function (id, senderId) { + var removedIds = [], + i, len, removedId; - var index = this.getIndex(); - if (index < this.values.length - 1) { - index++; - this.setIndex(index); + if (Array.isArray(id)) { + for (i = 0, len = id.length; i < len; i++) { + removedId = this._remove(id[i]); + if (removedId != null) { + removedIds.push(removedId); + } + } } - else if (this.playLoop) { - // jump to the start - index = 0; - this.setIndex(index); + else { + removedId = this._remove(id); + if (removedId != null) { + removedIds.push(removedId); + } } - var end = new Date(); - var diff = (end - start); - - // calculate how much time it to to set the index and to execute the callback - // function. - var interval = Math.max(this.playInterval - diff, 0); - // document.title = diff // TODO: cleanup + if (removedIds.length) { + this._trigger('remove', {items: removedIds}, senderId); + } - var me = this; - this.playTimeout = setTimeout(function() {me.playNext();}, interval); + return removedIds; }; /** - * Toggle start or stop playing + * Remove an item by its id + * @param {Number | String | Object} id id or item + * @returns {Number | String | null} id + * @private */ - Slider.prototype.togglePlay = function() { - if (this.playTimeout === undefined) { - this.play(); - } else { - this.stop(); + DataSet.prototype._remove = function (id) { + if (util.isNumber(id) || util.isString(id)) { + if (this._data[id]) { + delete this._data[id]; + return id; + } + } + else if (id instanceof Object) { + var itemId = id[this._fieldId]; + if (itemId && this._data[itemId]) { + delete this._data[itemId]; + return itemId; + } } + return null; }; /** - * Start playing + * Clear the data + * @param {String} [senderId] Optional sender id + * @return {Array} removedIds The ids of all removed items */ - Slider.prototype.play = function() { - // Test whether already playing - if (this.playTimeout) return; + DataSet.prototype.clear = function (senderId) { + var ids = Object.keys(this._data); - this.playNext(); + this._data = {}; - if (this.frame) { - this.frame.play.value = 'Stop'; - } + this._trigger('remove', {items: ids}, senderId); + + return ids; }; /** - * Stop playing + * Find the item with maximum value of a specified field + * @param {String} field + * @return {Object | null} item Item containing max value, or null if no items */ - Slider.prototype.stop = function() { - clearInterval(this.playTimeout); - this.playTimeout = undefined; + DataSet.prototype.max = function (field) { + var data = this._data, + max = null, + maxField = null; - if (this.frame) { - this.frame.play.value = 'Play'; + for (var id in data) { + if (data.hasOwnProperty(id)) { + var item = data[id]; + var itemField = item[field]; + if (itemField != null && (!max || itemField > maxField)) { + max = item; + maxField = itemField; + } + } } - }; - /** - * Set a callback function which will be triggered when the value of the - * slider bar has changed. - */ - Slider.prototype.setOnChangeCallback = function(callback) { - this.onChangeCallback = callback; + return max; }; /** - * Set the interval for playing the list - * @param {Number} interval The interval in milliseconds + * Find the item with minimum value of a specified field + * @param {String} field + * @return {Object | null} item Item containing max value, or null if no items */ - Slider.prototype.setPlayInterval = function(interval) { - this.playInterval = interval; - }; + DataSet.prototype.min = function (field) { + var data = this._data, + min = null, + minField = null; - /** - * Retrieve the current play interval - * @return {Number} interval The interval in milliseconds - */ - Slider.prototype.getPlayInterval = function(interval) { - return this.playInterval; + for (var id in data) { + if (data.hasOwnProperty(id)) { + var item = data[id]; + var itemField = item[field]; + if (itemField != null && (!min || itemField < minField)) { + min = item; + minField = itemField; + } + } + } + + return min; }; /** - * Set looping on or off - * @pararm {boolean} doLoop If true, the slider will jump to the start when - * the end is passed, and will jump to the end - * when the start is passed. + * Find all distinct values of a specified field + * @param {String} field + * @return {Array} values Array containing all distinct values. If data items + * do not contain the specified field are ignored. + * The returned array is unordered. */ - Slider.prototype.setPlayLoop = function(doLoop) { - this.playLoop = doLoop; - }; + DataSet.prototype.distinct = function (field) { + var data = this._data; + var values = []; + var fieldType = this._options.type && this._options.type[field] || null; + var count = 0; + var i; + for (var prop in data) { + if (data.hasOwnProperty(prop)) { + var item = data[prop]; + var value = item[field]; + var exists = false; + for (i = 0; i < count; i++) { + if (values[i] == value) { + exists = true; + break; + } + } + if (!exists && (value !== undefined)) { + values[count] = value; + count++; + } + } + } - /** - * Execute the onchange callback function - */ - Slider.prototype.onChange = function() { - if (this.onChangeCallback !== undefined) { - this.onChangeCallback(); + if (fieldType) { + for (i = 0; i < values.length; i++) { + values[i] = util.convert(values[i], fieldType); + } } + + return values; }; /** - * redraw the slider on the correct place + * Add a single item. Will fail when an item with the same id already exists. + * @param {Object} item + * @return {String} id + * @private */ - Slider.prototype.redraw = function() { - if (this.frame) { - // resize the bar - this.frame.bar.style.top = (this.frame.clientHeight/2 - - this.frame.bar.offsetHeight/2) + 'px'; - this.frame.bar.style.width = (this.frame.clientWidth - - this.frame.prev.clientWidth - - this.frame.play.clientWidth - - this.frame.next.clientWidth - 30) + 'px'; + DataSet.prototype._addItem = function (item) { + var id = item[this._fieldId]; - // position the slider button - var left = this.indexToLeft(this.index); - this.frame.slide.style.left = (left) + 'px'; + if (id != undefined) { + // check whether this id is already taken + if (this._data[id]) { + // item already exists + throw new Error('Cannot add item: item with id ' + id + ' already exists'); + } + } + else { + // generate an id + id = util.randomUUID(); + item[this._fieldId] = id; } - }; - - /** - * Set the list with values for the slider - * @param {Array} values A javascript array with values (any type) - */ - Slider.prototype.setValues = function(values) { - this.values = values; + var d = {}; + for (var field in item) { + if (item.hasOwnProperty(field)) { + var fieldType = this._type[field]; // type may be undefined + d[field] = util.convert(item[field], fieldType); + } + } + this._data[id] = d; - if (this.values.length > 0) - this.setIndex(0); - else - this.index = undefined; + return id; }; /** - * Select a value by its index - * @param {Number} index + * Get an item. Fields can be converted to a specific type + * @param {String} id + * @param {Object.} [types] field types to convert + * @return {Object | null} item + * @private */ - Slider.prototype.setIndex = function(index) { - if (index < this.values.length) { - this.index = index; + DataSet.prototype._getItem = function (id, types) { + var field, value; - this.redraw(); - this.onChange(); + // get the item from the dataset + var raw = this._data[id]; + if (!raw) { + return null; + } + + // convert the items field types + var converted = {}; + if (types) { + for (field in raw) { + if (raw.hasOwnProperty(field)) { + value = raw[field]; + converted[field] = util.convert(value, types[field]); + } + } } else { - throw 'Error: index out of range'; + // no field types specified, no converting needed + for (field in raw) { + if (raw.hasOwnProperty(field)) { + value = raw[field]; + converted[field] = value; + } + } } + return converted; }; /** - * retrieve the index of the currently selected vaue - * @return {Number} index + * Update a single item: merge with existing item. + * Will fail when the item has no id, or when there does not exist an item + * with the same id. + * @param {Object} item + * @return {String} id + * @private */ - Slider.prototype.getIndex = function() { - return this.index; - }; + DataSet.prototype._updateItem = function (item) { + var id = item[this._fieldId]; + if (id == undefined) { + throw new Error('Cannot update item: item has no id (item: ' + JSON.stringify(item) + ')'); + } + var d = this._data[id]; + if (!d) { + // item doesn't exist + throw new Error('Cannot update item: no item with id ' + id + ' found'); + } + + // merge with current item + for (var field in item) { + if (item.hasOwnProperty(field)) { + var fieldType = this._type[field]; // type may be undefined + d[field] = util.convert(item[field], fieldType); + } + } + return id; + }; /** - * retrieve the currently selected value - * @return {*} value + * Get an array with the column names of a Google DataTable + * @param {DataTable} dataTable + * @return {String[]} columnNames + * @private */ - Slider.prototype.get = function() { - return this.values[this.index]; - }; - - - Slider.prototype._onMouseDown = function(event) { - // only react on left mouse button down - var leftButtonDown = event.which ? (event.which === 1) : (event.button === 1); - if (!leftButtonDown) return; - - this.startClientX = event.clientX; - this.startSlideX = parseFloat(this.frame.slide.style.left); - - this.frame.style.cursor = 'move'; - - // add event listeners to handle moving the contents - // we store the function onmousemove and onmouseup in the graph, so we can - // remove the eventlisteners lateron in the function mouseUp() - var me = this; - this.onmousemove = function (event) {me._onMouseMove(event);}; - this.onmouseup = function (event) {me._onMouseUp(event);}; - util.addEventListener(document, 'mousemove', this.onmousemove); - util.addEventListener(document, 'mouseup', this.onmouseup); - util.preventDefault(event); + DataSet.prototype._getColumnNames = function (dataTable) { + var columns = []; + for (var col = 0, cols = dataTable.getNumberOfColumns(); col < cols; col++) { + columns[col] = dataTable.getColumnId(col) || dataTable.getColumnLabel(col); + } + return columns; }; + /** + * Append an item as a row to the dataTable + * @param dataTable + * @param columns + * @param item + * @private + */ + DataSet.prototype._appendRow = function (dataTable, columns, item) { + var row = dataTable.addRow(); - Slider.prototype.leftToIndex = function (left) { - var width = parseFloat(this.frame.bar.style.width) - - this.frame.slide.clientWidth - 10; - var x = left - 3; - - var index = Math.round(x / width * (this.values.length-1)); - if (index < 0) index = 0; - if (index > this.values.length-1) index = this.values.length-1; - - return index; + for (var col = 0, cols = columns.length; col < cols; col++) { + var field = columns[col]; + dataTable.setValue(row, col, item[field]); + } }; - Slider.prototype.indexToLeft = function (index) { - var width = parseFloat(this.frame.bar.style.width) - - this.frame.slide.clientWidth - 10; - - var x = index / (this.values.length-1) * width; - var left = x + 3; + module.exports = DataSet; - return left; - }; +/***/ }, +/* 8 */ +/***/ function(module, exports, __webpack_require__) { + /** + * A queue + * @param {Object} options + * Available options: + * - delay: number When provided, the queue will be flushed + * automatically after an inactivity of this delay + * in milliseconds. + * Default value is null. + * - max: number When the queue exceeds the given maximum number + * of entries, the queue is flushed automatically. + * Default value of max is Infinity. + * @constructor + */ + function Queue(options) { + // options + this.delay = null; + this.max = Infinity; - Slider.prototype._onMouseMove = function (event) { - var diff = event.clientX - this.startClientX; - var x = this.startSlideX + diff; + // properties + this._queue = []; + this._timeout = null; + this._extended = null; - var index = this.leftToIndex(x); + this.setOptions(options); + } - this.setIndex(index); + /** + * Update the configuration of the queue + * @param {Object} options + * Available options: + * - delay: number When provided, the queue will be flushed + * automatically after an inactivity of this delay + * in milliseconds. + * Default value is null. + * - max: number When the queue exceeds the given maximum number + * of entries, the queue is flushed automatically. + * Default value of max is Infinity. + * @param options + */ + Queue.prototype.setOptions = function (options) { + if (options && typeof options.delay !== 'undefined') { + this.delay = options.delay; + } + if (options && typeof options.max !== 'undefined') { + this.max = options.max; + } - util.preventDefault(); + this._flushIfNeeded(); }; + /** + * Extend an object with queuing functionality. + * The object will be extended with a function flush, and the methods provided + * in options.replace will be replaced with queued ones. + * @param {Object} object + * @param {Object} options + * Available options: + * - replace: Array. + * A list with method names of the methods + * on the object to be replaced with queued ones. + * - delay: number When provided, the queue will be flushed + * automatically after an inactivity of this delay + * in milliseconds. + * Default value is null. + * - max: number When the queue exceeds the given maximum number + * of entries, the queue is flushed automatically. + * Default value of max is Infinity. + * @return {Queue} Returns the created queue + */ + Queue.extend = function (object, options) { + var queue = new Queue(options); - Slider.prototype._onMouseUp = function (event) { - this.frame.style.cursor = 'auto'; - - // remove event listeners - util.removeEventListener(document, 'mousemove', this.onmousemove); - util.removeEventListener(document, 'mouseup', this.onmouseup); - - util.preventDefault(); - }; - - module.exports = Slider; + if (object.flush !== undefined) { + throw new Error('Target object already has a property flush'); + } + object.flush = function () { + queue.flush(); + }; + var methods = [{ + name: 'flush', + original: undefined + }]; -/***/ }, -/* 12 */ -/***/ function(module, exports, __webpack_require__) { + if (options && options.replace) { + for (var i = 0; i < options.replace.length; i++) { + var name = options.replace[i]; + methods.push({ + name: name, + original: object[name] + }); + queue.replace(object, name); + } + } - /** - * @prototype StepNumber - * The class StepNumber is an iterator for Numbers. You provide a start and end - * value, and a best step size. StepNumber itself rounds to fixed values and - * a finds the step that best fits the provided step. - * - * If prettyStep is true, the step size is chosen as close as possible to the - * provided step, but being a round value like 1, 2, 5, 10, 20, 50, .... - * - * Example usage: - * var step = new StepNumber(0, 10, 2.5, true); - * step.start(); - * while (!step.end()) { - * alert(step.getCurrent()); - * step.next(); - * } - * - * Version: 1.0 - * - * @param {Number} start The start value - * @param {Number} end The end value - * @param {Number} step Optional. Step size. Must be a positive value. - * @param {boolean} prettyStep Optional. If true, the step size is rounded - * To a pretty step size (like 1, 2, 5, 10, 20, 50, ...) - */ - function StepNumber(start, end, step, prettyStep) { - // set default values - this._start = 0; - this._end = 0; - this._step = 1; - this.prettyStep = true; - this.precision = 5; + queue._extended = { + object: object, + methods: methods + }; - this._current = 0; - this.setRange(start, end, step, prettyStep); + return queue; }; /** - * Set a new range: start, end and step. - * - * @param {Number} start The start value - * @param {Number} end The end value - * @param {Number} step Optional. Step size. Must be a positive value. - * @param {boolean} prettyStep Optional. If true, the step size is rounded - * To a pretty step size (like 1, 2, 5, 10, 20, 50, ...) + * Destroy the queue. The queue will first flush all queued actions, and in + * case it has extended an object, will restore the original object. */ - StepNumber.prototype.setRange = function(start, end, step, prettyStep) { - this._start = start ? start : 0; - this._end = end ? end : 0; + Queue.prototype.destroy = function () { + this.flush(); - this.setStep(step, prettyStep); + if (this._extended) { + var object = this._extended.object; + var methods = this._extended.methods; + for (var i = 0; i < methods.length; i++) { + var method = methods[i]; + if (method.original) { + object[method.name] = method.original; + } + else { + delete object[method.name]; + } + } + this._extended = null; + } }; /** - * Set a new step size - * @param {Number} step New step size. Must be a positive value - * @param {boolean} prettyStep Optional. If true, the provided step is rounded - * to a pretty step size (like 1, 2, 5, 10, 20, 50, ...) + * Replace a method on an object with a queued version + * @param {Object} object Object having the method + * @param {string} method The method name */ - StepNumber.prototype.setStep = function(step, prettyStep) { - if (step === undefined || step <= 0) - return; + Queue.prototype.replace = function(object, method) { + var me = this; + var original = object[method]; + if (!original) { + throw new Error('Method ' + method + ' undefined'); + } - if (prettyStep !== undefined) - this.prettyStep = prettyStep; + object[method] = function () { + // create an Array with the arguments + var args = []; + for (var i = 0; i < arguments.length; i++) { + args[i] = arguments[i]; + } - if (this.prettyStep === true) - this._step = StepNumber.calculatePrettyStep(step); - else - this._step = step; + // add this call to the queue + me.queue({ + args: args, + fn: original, + context: this + }); + }; }; /** - * Calculate a nice step size, closest to the desired step size. - * Returns a value in one of the ranges 1*10^n, 2*10^n, or 5*10^n, where n is an - * integer Number. For example 1, 2, 5, 10, 20, 50, etc... - * @param {Number} step Desired step size - * @return {Number} Nice step size + * Queue a call + * @param {function | {fn: function, args: Array} | {fn: function, args: Array, context: Object}} entry */ - StepNumber.calculatePrettyStep = function (step) { - var log10 = function (x) {return Math.log(x) / Math.LN10;}; - - // try three steps (multiple of 1, 2, or 5 - var step1 = Math.pow(10, Math.round(log10(step))), - step2 = 2 * Math.pow(10, Math.round(log10(step / 2))), - step5 = 5 * Math.pow(10, Math.round(log10(step / 5))); - - // choose the best step (closest to minimum step) - var prettyStep = step1; - if (Math.abs(step2 - step) <= Math.abs(prettyStep - step)) prettyStep = step2; - if (Math.abs(step5 - step) <= Math.abs(prettyStep - step)) prettyStep = step5; - - // for safety - if (prettyStep <= 0) { - prettyStep = 1; + Queue.prototype.queue = function(entry) { + if (typeof entry === 'function') { + this._queue.push({fn: entry}); + } + else { + this._queue.push(entry); } - return prettyStep; - }; - - /** - * returns the current value of the step - * @return {Number} current value - */ - StepNumber.prototype.getCurrent = function () { - return parseFloat(this._current.toPrecision(this.precision)); - }; - - /** - * returns the current step size - * @return {Number} current step size - */ - StepNumber.prototype.getStep = function () { - return this._step; + this._flushIfNeeded(); }; /** - * Set the current value to the largest value smaller than start, which - * is a multiple of the step size + * Check whether the queue needs to be flushed + * @private */ - StepNumber.prototype.start = function() { - this._current = this._start - this._start % this._step; - }; + Queue.prototype._flushIfNeeded = function () { + // flush when the maximum is exceeded. + if (this._queue.length > this.max) { + this.flush(); + } - /** - * Do a step, add the step size to the current value - */ - StepNumber.prototype.next = function () { - this._current += this._step; + // flush after a period of inactivity when a delay is configured + clearTimeout(this._timeout); + if (this.queue.length > 0 && typeof this.delay === 'number') { + var me = this; + this._timeout = setTimeout(function () { + me.flush(); + }, this.delay); + } }; /** - * Returns true whether the end is reached - * @return {boolean} True if the current value has passed the end value. + * Flush all queued calls */ - StepNumber.prototype.end = function () { - return (this._current > this._end); + Queue.prototype.flush = function () { + while (this._queue.length > 0) { + var entry = this._queue.shift(); + entry.fn.apply(entry.context || entry.fn, entry.args || []); + } }; - module.exports = StepNumber; + module.exports = Queue; /***/ }, -/* 13 */ +/* 9 */ /***/ function(module, exports, __webpack_require__) { - var Emitter = __webpack_require__(56); - var Hammer = __webpack_require__(45); var util = __webpack_require__(1); - var DataSet = __webpack_require__(3); - var DataView = __webpack_require__(4); - var Range = __webpack_require__(17); - var Core = __webpack_require__(46); - var TimeAxis = __webpack_require__(30); - var CurrentTime = __webpack_require__(21); - var CustomTime = __webpack_require__(22); - var ItemSet = __webpack_require__(27); + var DataSet = __webpack_require__(7); /** - * Create a timeline visualization - * @param {HTMLElement} container - * @param {vis.DataSet | Array | google.visualization.DataTable} [items] - * @param {vis.DataSet | Array | google.visualization.DataTable} [groups] - * @param {Object} [options] See Timeline.setOptions for the available options. - * @constructor - * @extends Core + * DataView + * + * a dataview offers a filtered view on a dataset or an other dataview. + * + * @param {DataSet | DataView} data + * @param {Object} [options] Available options: see method get + * + * @constructor DataView */ - function Timeline (container, items, groups, options) { - if (!(this instanceof Timeline)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - // if the third element is options, the forth is groups (optionally); - if (!(Array.isArray(groups) || groups instanceof DataSet) && groups instanceof Object) { - var forthArgument = options; - options = groups; - groups = forthArgument; - } + function DataView (data, options) { + this._data = null; + this._ids = {}; // ids of the items currently in memory (just contains a boolean true) + this._options = options || {}; + this._fieldId = 'id'; // name of the field containing id + this._subscribers = {}; // event subscribers var me = this; - this.defaultOptions = { - start: null, - end: null, - - autoResize: true, - - orientation: 'bottom', - width: null, - height: null, - maxHeight: null, - minHeight: null - }; - this.options = util.deepExtend({}, this.defaultOptions); - - // Create the DOM, props, and emitter - this._create(container); - - // all components listed here will be repainted automatically - this.components = []; - - this.body = { - dom: this.dom, - domProps: this.props, - emitter: { - on: this.on.bind(this), - off: this.off.bind(this), - emit: this.emit.bind(this) - }, - hiddenDates: [], - util: { - snap: null, // will be specified after TimeAxis is created - toScreen: me._toScreen.bind(me), - toGlobalScreen: me._toGlobalScreen.bind(me), // this refers to the root.width - toTime: me._toTime.bind(me), - toGlobalTime : me._toGlobalTime.bind(me) - } + this.listener = function () { + me._onEvent.apply(me, arguments); }; - // range - this.range = new Range(this.body); - this.components.push(this.range); - this.body.range = this.range; + this.setData(data); + } - // time axis - this.timeAxis = new TimeAxis(this.body); - this.components.push(this.timeAxis); - this.body.util.snap = this.timeAxis.snap.bind(this.timeAxis); + // TODO: implement a function .config() to dynamically update things like configured filter + // and trigger changes accordingly - // current time bar - this.currentTime = new CurrentTime(this.body); - this.components.push(this.currentTime); + /** + * Set a data source for the view + * @param {DataSet | DataView} data + */ + DataView.prototype.setData = function (data) { + var ids, i, len; - // custom time bar - // Note: time bar will be attached in this.setOptions when selected - this.customTime = new CustomTime(this.body); - this.components.push(this.customTime); + if (this._data) { + // unsubscribe from current dataset + if (this._data.unsubscribe) { + this._data.unsubscribe('*', this.listener); + } - // item set - this.itemSet = new ItemSet(this.body); - this.components.push(this.itemSet); + // trigger a remove of all items in memory + ids = []; + for (var id in this._ids) { + if (this._ids.hasOwnProperty(id)) { + ids.push(id); + } + } + this._ids = {}; + this._trigger('remove', {items: ids}); + } - this.itemsData = null; // DataSet - this.groupsData = null; // DataSet + this._data = data; - // apply options - if (options) { - this.setOptions(options); - } + if (this._data) { + // update fieldId + this._fieldId = this._options.fieldId || + (this._data && this._data.options && this._data.options.fieldId) || + 'id'; - // IMPORTANT: THIS HAPPENS BEFORE SET ITEMS! - if (groups) { - this.setGroups(groups); - } + // trigger an add of all added items + ids = this._data.getIds({filter: this._options && this._options.filter}); + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + this._ids[id] = true; + } + this._trigger('add', {items: ids}); - // create itemset - if (items) { - this.setItems(items); - } - else { - this.redraw(); + // subscribe to new dataset + if (this._data.on) { + this._data.on('*', this.listener); + } } - } - - // Extend the functionality from Core - Timeline.prototype = new Core(); + }; /** - * Set items - * @param {vis.DataSet | Array | google.visualization.DataTable | null} items + * Get data from the data view + * + * Usage: + * + * get() + * get(options: Object) + * get(options: Object, data: Array | DataTable) + * + * get(id: Number) + * get(id: Number, options: Object) + * get(id: Number, options: Object, data: Array | DataTable) + * + * get(ids: Number[]) + * get(ids: Number[], options: Object) + * get(ids: Number[], options: Object, data: Array | DataTable) + * + * Where: + * + * {Number | String} id The id of an item + * {Number[] | String{}} ids An array with ids of items + * {Object} options An Object with options. Available options: + * {String} [type] Type of data to be returned. Can + * be 'DataTable' or 'Array' (default) + * {Object.} [convert] + * {String[]} [fields] field names to be returned + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * {Array | DataTable} [data] If provided, items will be appended to this + * array or table. Required in case of Google + * DataTable. + * @param args */ - Timeline.prototype.setItems = function(items) { - var initialLoad = (this.itemsData == null); + DataView.prototype.get = function (args) { + var me = this; - // convert to type DataSet when needed - var newDataSet; - if (!items) { - newDataSet = null; - } - else if (items instanceof DataSet || items instanceof DataView) { - newDataSet = items; + // parse the arguments + var ids, options, data; + var firstType = util.getType(arguments[0]); + if (firstType == 'String' || firstType == 'Number' || firstType == 'Array') { + // get(id(s) [, options] [, data]) + ids = arguments[0]; // can be a single id or an array with ids + options = arguments[1]; + data = arguments[2]; } else { - // turn an array into a dataset - newDataSet = new DataSet(items, { - type: { - start: 'Date', - end: 'Date' - } - }); + // get([, options] [, data]) + options = arguments[0]; + data = arguments[1]; } - // set items - this.itemsData = newDataSet; - this.itemSet && this.itemSet.setItems(newDataSet); - - if (initialLoad) { - if (this.options.start != undefined || this.options.end != undefined) { - if (this.options.start == undefined || this.options.end == undefined) { - var dataRange = this._getDataRange(); - } - - var start = this.options.start != undefined ? this.options.start : dataRange.start; - var end = this.options.end != undefined ? this.options.end : dataRange.end; + // extend the options with the default options and provided options + var viewOptions = util.extend({}, this._options, options); - this.setWindow(start, end, {animate: false}); - } - else { - this.fit({animate: false}); + // create a combined filter method when needed + if (this._options.filter && options && options.filter) { + viewOptions.filter = function (item) { + return me._options.filter(item) && options.filter(item); } } - }; - /** - * Set groups - * @param {vis.DataSet | Array | google.visualization.DataTable} groups - */ - Timeline.prototype.setGroups = function(groups) { - // convert to type DataSet when needed - var newDataSet; - if (!groups) { - newDataSet = null; - } - else if (groups instanceof DataSet || groups instanceof DataView) { - newDataSet = groups; - } - else { - // turn an array into a dataset - newDataSet = new DataSet(groups); + // build up the call to the linked data set + var getArguments = []; + if (ids != undefined) { + getArguments.push(ids); } + getArguments.push(viewOptions); + getArguments.push(data); - this.groupsData = newDataSet; - this.itemSet.setGroups(newDataSet); + return this._data && this._data.get.apply(this._data, getArguments); }; /** - * Set selected items by their id. Replaces the current selection - * Unknown id's are silently ignored. - * @param {string[] | string} [ids] An array with zero or more id's of the items to be - * selected. If ids is an empty array, all items will be - * unselected. - * @param {Object} [options] Available options: - * `focus: boolean` - * If true, focus will be set to the selected item(s) - * `animate: boolean | number` - * If true (default), the range is animated - * smoothly to the new window. - * If a number, the number is taken as duration - * for the animation. Default duration is 500 ms. - * Only applicable when option focus is true. + * Get ids of all items or from a filtered set of items. + * @param {Object} [options] An Object with options. Available options: + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * @return {Array} ids */ - Timeline.prototype.setSelection = function(ids, options) { - this.itemSet && this.itemSet.setSelection(ids); + DataView.prototype.getIds = function (options) { + var ids; - if (options && options.focus) { - this.focus(ids, options); + if (this._data) { + var defaultFilter = this._options.filter; + var filter; + + if (options && options.filter) { + if (defaultFilter) { + filter = function (item) { + return defaultFilter(item) && options.filter(item); + } + } + else { + filter = options.filter; + } + } + else { + filter = defaultFilter; + } + + ids = this._data.getIds({ + filter: filter, + order: options && options.order + }); + } + else { + ids = []; } + + return ids; }; /** - * Get the selected items by their id - * @return {Array} ids The ids of the selected items + * Get the DataSet to which this DataView is connected. In case there is a chain + * of multiple DataViews, the root DataSet of this chain is returned. + * @return {DataSet} dataSet */ - Timeline.prototype.getSelection = function() { - return this.itemSet && this.itemSet.getSelection() || []; + DataView.prototype.getDataSet = function () { + var dataSet = this; + while (dataSet instanceof DataView) { + dataSet = dataSet._data; + } + return dataSet || null; }; /** - * Adjust the visible window such that the selected item (or multiple items) - * are centered on screen. - * @param {String | String[]} id An item id or array with item ids - * @param {Object} [options] Available options: - * `animate: boolean | number` - * If true (default), the range is animated - * smoothly to the new window. - * If a number, the number is taken as duration - * for the animation. Default duration is 500 ms. - * Only applicable when option focus is true + * Event listener. Will propagate all events from the connected data set to + * the subscribers of the DataView, but will filter the items and only trigger + * when there are changes in the filtered data set. + * @param {String} event + * @param {Object | null} params + * @param {String} senderId + * @private */ - Timeline.prototype.focus = function(id, options) { - if (!this.itemsData || id == undefined) return; - - var ids = Array.isArray(id) ? id : [id]; - - // get the specified item(s) - var itemsData = this.itemsData.getDataSet().get(ids, { - type: { - start: 'Date', - end: 'Date' - } - }); + DataView.prototype._onEvent = function (event, params, senderId) { + var i, len, id, item, + ids = params && params.items, + data = this._data, + added = [], + updated = [], + removed = []; - // calculate minimum start and maximum end of specified items - var start = null; - var end = null; - itemsData.forEach(function (itemData) { - var s = itemData.start.valueOf(); - var e = 'end' in itemData ? itemData.end.valueOf() : itemData.start.valueOf(); + if (ids && data) { + switch (event) { + case 'add': + // filter the ids of the added items + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + item = this.get(id); + if (item) { + this._ids[id] = true; + added.push(id); + } + } - if (start === null || s < start) { - start = s; - } + break; - if (end === null || e > end) { - end = e; - } - }); + case 'update': + // determine the event from the views viewpoint: an updated + // item can be added, updated, or removed from this view. + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + item = this.get(id); - if (start !== null && end !== null) { - // calculate the new middle and interval for the window - var middle = (start + end) / 2; - var interval = Math.max((this.range.end - this.range.start), (end - start) * 1.1); + if (item) { + if (this._ids[id]) { + updated.push(id); + } + else { + this._ids[id] = true; + added.push(id); + } + } + else { + if (this._ids[id]) { + delete this._ids[id]; + removed.push(id); + } + else { + // nothing interesting for me :-( + } + } + } - var animate = (options && options.animate !== undefined) ? options.animate : true; - this.range.setRange(middle - interval / 2, middle + interval / 2, animate); - } - }; + break; - /** - * Get the data range of the item set. - * @returns {{min: Date, max: Date}} range A range with a start and end Date. - * When no minimum is found, min==null - * When no maximum is found, max==null - */ - Timeline.prototype.getItemRange = function() { - // calculate min from start filed - var dataset = this.itemsData.getDataSet(), - min = null, - max = null; + case 'remove': + // filter the ids of the removed items + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + if (this._ids[id]) { + delete this._ids[id]; + removed.push(id); + } + } - if (dataset) { - // calculate the minimum value of the field 'start' - var minItem = dataset.min('start'); - min = minItem ? util.convert(minItem.start, 'Date').valueOf() : null; - // Note: we convert first to Date and then to number because else - // a conversion from ISODate to Number will fail + break; + } - // calculate maximum value of fields 'start' and 'end' - var maxStartItem = dataset.max('start'); - if (maxStartItem) { - max = util.convert(maxStartItem.start, 'Date').valueOf(); + if (added.length) { + this._trigger('add', {items: added}, senderId); } - var maxEndItem = dataset.max('end'); - if (maxEndItem) { - if (max == null) { - max = util.convert(maxEndItem.end, 'Date').valueOf(); - } - else { - max = Math.max(max, util.convert(maxEndItem.end, 'Date').valueOf()); - } + if (updated.length) { + this._trigger('update', {items: updated}, senderId); + } + if (removed.length) { + this._trigger('remove', {items: removed}, senderId); } } - - return { - min: (min != null) ? new Date(min) : null, - max: (max != null) ? new Date(max) : null - }; }; + // copy subscription functionality from DataSet + DataView.prototype.on = DataSet.prototype.on; + DataView.prototype.off = DataSet.prototype.off; + DataView.prototype._trigger = DataSet.prototype._trigger; - module.exports = Timeline; + // TODO: make these functions deprecated (replaced with `on` and `off` since version 0.5) + DataView.prototype.subscribe = DataView.prototype.on; + DataView.prototype.unsubscribe = DataView.prototype.off; + module.exports = DataView; /***/ }, -/* 14 */ +/* 10 */ /***/ function(module, exports, __webpack_require__) { - var Emitter = __webpack_require__(56); - var Hammer = __webpack_require__(45); + var Emitter = __webpack_require__(11); + var DataSet = __webpack_require__(7); + var DataView = __webpack_require__(9); var util = __webpack_require__(1); - var DataSet = __webpack_require__(3); - var DataView = __webpack_require__(4); - var Range = __webpack_require__(17); - var Core = __webpack_require__(46); - var TimeAxis = __webpack_require__(30); - var CurrentTime = __webpack_require__(21); - var CustomTime = __webpack_require__(22); - var LineGraph = __webpack_require__(29); + var Point3d = __webpack_require__(12); + var Point2d = __webpack_require__(13); + var Camera = __webpack_require__(14); + var Filter = __webpack_require__(15); + var Slider = __webpack_require__(16); + var StepNumber = __webpack_require__(17); /** - * Create a timeline visualization - * @param {HTMLElement} container - * @param {vis.DataSet | Array | google.visualization.DataTable} [items] - * @param {Object} [options] See Graph2d.setOptions for the available options. - * @constructor - * @extends Core + * @constructor Graph3d + * Graph3d displays data in 3d. + * + * Graph3d is developed in javascript as a Google Visualization Chart. + * + * @param {Element} container The DOM element in which the Graph3d will + * be created. Normally a div element. + * @param {DataSet | DataView | Array} [data] + * @param {Object} [options] */ - function Graph2d (container, items, groups, options) { - // if the third element is options, the forth is groups (optionally); - if (!(Array.isArray(groups) || groups instanceof DataSet) && groups instanceof Object) { - var forthArgument = options; - options = groups; - groups = forthArgument; + function Graph3d(container, data, options) { + if (!(this instanceof Graph3d)) { + throw new SyntaxError('Constructor must be called with the new operator'); } - var me = this; - this.defaultOptions = { - start: null, - end: null, - - autoResize: true, - - orientation: 'bottom', - width: null, - height: null, - maxHeight: null, - minHeight: null - }; - this.options = util.deepExtend({}, this.defaultOptions); + // create variables and set default values + this.containerElement = container; + this.width = '400px'; + this.height = '400px'; + this.margin = 10; // px + this.defaultXCenter = '55%'; + this.defaultYCenter = '50%'; - // Create the DOM, props, and emitter - this._create(container); + this.xLabel = 'x'; + this.yLabel = 'y'; + this.zLabel = 'z'; - // all components listed here will be repainted automatically - this.components = []; + var passValueFn = function(v) { return v; }; + this.xValueLabel = passValueFn; + this.yValueLabel = passValueFn; + this.zValueLabel = passValueFn; + + this.filterLabel = 'time'; + this.legendLabel = 'value'; - this.body = { - dom: this.dom, - domProps: this.props, - emitter: { - on: this.on.bind(this), - off: this.off.bind(this), - emit: this.emit.bind(this) - }, - hiddenDates: [], - util: { - snap: null, // will be specified after TimeAxis is created - toScreen: me._toScreen.bind(me), - toGlobalScreen: me._toGlobalScreen.bind(me), // this refers to the root.width - toTime: me._toTime.bind(me), - toGlobalTime : me._toGlobalTime.bind(me) - } - }; + this.style = Graph3d.STYLE.DOT; + this.showPerspective = true; + this.showGrid = true; + this.keepAspectRatio = true; + this.showShadow = false; + this.showGrayBottom = false; // TODO: this does not work correctly + this.showTooltip = false; + this.verticalRatio = 0.5; // 0.1 to 1.0, where 1.0 results in a 'cube' - // range - this.range = new Range(this.body); - this.components.push(this.range); - this.body.range = this.range; + this.animationInterval = 1000; // milliseconds + this.animationPreload = false; - // time axis - this.timeAxis = new TimeAxis(this.body); - this.components.push(this.timeAxis); - this.body.util.snap = this.timeAxis.snap.bind(this.timeAxis); + this.camera = new Camera(); + this.eye = new Point3d(0, 0, -1); // TODO: set eye.z about 3/4 of the width of the window? - // current time bar - this.currentTime = new CurrentTime(this.body); - this.components.push(this.currentTime); + this.dataTable = null; // The original data table + this.dataPoints = null; // The table with point objects - // custom time bar - // Note: time bar will be attached in this.setOptions when selected - this.customTime = new CustomTime(this.body); - this.components.push(this.customTime); + // the column indexes + this.colX = undefined; + this.colY = undefined; + this.colZ = undefined; + this.colValue = undefined; + this.colFilter = undefined; - // item set - this.linegraph = new LineGraph(this.body); - this.components.push(this.linegraph); + this.xMin = 0; + this.xStep = undefined; // auto by default + this.xMax = 1; + this.yMin = 0; + this.yStep = undefined; // auto by default + this.yMax = 1; + this.zMin = 0; + this.zStep = undefined; // auto by default + this.zMax = 1; + this.valueMin = 0; + this.valueMax = 1; + this.xBarWidth = 1; + this.yBarWidth = 1; + // TODO: customize axis range - this.itemsData = null; // DataSet - this.groupsData = null; // DataSet + // constants + this.colorAxis = '#4D4D4D'; + this.colorGrid = '#D3D3D3'; + this.colorDot = '#7DC1FF'; + this.colorDotBorder = '#3267D2'; - // apply options - if (options) { - this.setOptions(options); - } + // create a frame and canvas + this.create(); - // IMPORTANT: THIS HAPPENS BEFORE SET ITEMS! - if (groups) { - this.setGroups(groups); - } + // apply options (also when undefined) + this.setOptions(options); - // create itemset - if (items) { - this.setItems(items); - } - else { - this.redraw(); + // apply data + if (data) { + this.setData(data); } } - // Extend the functionality from Core - Graph2d.prototype = new Core(); + // Extend Graph3d with an Emitter mixin + Emitter(Graph3d.prototype); /** - * Set items - * @param {vis.DataSet | Array | google.visualization.DataTable | null} items + * Calculate the scaling values, dependent on the range in x, y, and z direction */ - Graph2d.prototype.setItems = function(items) { - var initialLoad = (this.itemsData == null); - - // convert to type DataSet when needed - var newDataSet; - if (!items) { - newDataSet = null; - } - else if (items instanceof DataSet || items instanceof DataView) { - newDataSet = items; - } - else { - // turn an array into a dataset - newDataSet = new DataSet(items, { - type: { - start: 'Date', - end: 'Date' - } - }); - } - - // set items - this.itemsData = newDataSet; - this.linegraph && this.linegraph.setItems(newDataSet); - - if (initialLoad) { - if (this.options.start != undefined || this.options.end != undefined) { - var start = this.options.start != undefined ? this.options.start : null; - var end = this.options.end != undefined ? this.options.end : null; + Graph3d.prototype._setScale = function() { + this.scale = new Point3d(1 / (this.xMax - this.xMin), + 1 / (this.yMax - this.yMin), + 1 / (this.zMax - this.zMin)); - this.setWindow(start, end, {animate: false}); + // keep aspect ration between x and y scale if desired + if (this.keepAspectRatio) { + if (this.scale.x < this.scale.y) { + //noinspection JSSuspiciousNameCombination + this.scale.y = this.scale.x; } else { - this.fit({animate: false}); + //noinspection JSSuspiciousNameCombination + this.scale.x = this.scale.y; } } - }; - /** - * Set groups - * @param {vis.DataSet | Array | google.visualization.DataTable} groups - */ - Graph2d.prototype.setGroups = function(groups) { - // convert to type DataSet when needed - var newDataSet; - if (!groups) { - newDataSet = null; - } - else if (groups instanceof DataSet || groups instanceof DataView) { - newDataSet = groups; - } - else { - // turn an array into a dataset - newDataSet = new DataSet(groups); - } + // scale the vertical axis + this.scale.z *= this.verticalRatio; + // TODO: can this be automated? verticalRatio? - this.groupsData = newDataSet; - this.linegraph.setGroups(newDataSet); + // determine scale for (optional) value + this.scale.value = 1 / (this.valueMax - this.valueMin); + + // position the camera arm + var xCenter = (this.xMax + this.xMin) / 2 * this.scale.x; + var yCenter = (this.yMax + this.yMin) / 2 * this.scale.y; + var zCenter = (this.zMax + this.zMin) / 2 * this.scale.z; + this.camera.setArmLocation(xCenter, yCenter, zCenter); }; - /** - * Returns an object containing an SVG element with the icon of the group (size determined by iconWidth and iconHeight), the label of the group (content) and the yAxisOrientation of the group (left or right). - * @param groupId - * @param width - * @param height - */ - Graph2d.prototype.getLegend = function(groupId, width, height) { - if (width === undefined) {width = 15;} - if (height === undefined) {height = 15;} - if (this.linegraph.groups[groupId] !== undefined) { - return this.linegraph.groups[groupId].getLegend(width,height); - } - else { - return "cannot find group:" + groupId; - } - } /** - * This checks if the visible option of the supplied group (by ID) is true or false. - * @param groupId - * @returns {*} + * Convert a 3D location to a 2D location on screen + * http://en.wikipedia.org/wiki/3D_projection + * @param {Point3d} point3d A 3D point with parameters x, y, z + * @return {Point2d} point2d A 2D point with parameters x, y */ - Graph2d.prototype.isGroupVisible = function(groupId) { - if (this.linegraph.groups[groupId] !== undefined) { - return (this.linegraph.groups[groupId].visible && (this.linegraph.options.groups.visibility[groupId] === undefined || this.linegraph.options.groups.visibility[groupId] == true)); - } - else { - return false; - } - } - + Graph3d.prototype._convert3Dto2D = function(point3d) { + var translation = this._convertPointToTranslation(point3d); + return this._convertTranslationToScreen(translation); + }; /** - * Get the data range of the item set. - * @returns {{min: Date, max: Date}} range A range with a start and end Date. - * When no minimum is found, min==null - * When no maximum is found, max==null + * Convert a 3D location its translation seen from the camera + * http://en.wikipedia.org/wiki/3D_projection + * @param {Point3d} point3d A 3D point with parameters x, y, z + * @return {Point3d} translation A 3D point with parameters x, y, z This is + * the translation of the point, seen from the + * camera */ - Graph2d.prototype.getItemRange = function() { - var min = null; - var max = null; - - // calculate min from start filed - for (var groupId in this.linegraph.groups) { - if (this.linegraph.groups.hasOwnProperty(groupId)) { - if (this.linegraph.groups[groupId].visible == true) { - for (var i = 0; i < this.linegraph.groups[groupId].itemsData.length; i++) { - var item = this.linegraph.groups[groupId].itemsData[i]; - var value = util.convert(item.x, 'Date').valueOf(); - min = min == null ? value : min > value ? value : min; - max = max == null ? value : max < value ? value : max; - } - } - } - } - - return { - min: (min != null) ? new Date(min) : null, - max: (max != null) ? new Date(max) : null - }; - }; - + Graph3d.prototype._convertPointToTranslation = function(point3d) { + var ax = point3d.x * this.scale.x, + ay = point3d.y * this.scale.y, + az = point3d.z * this.scale.z, + cx = this.camera.getCameraLocation().x, + cy = this.camera.getCameraLocation().y, + cz = this.camera.getCameraLocation().z, - module.exports = Graph2d; + // calculate angles + sinTx = Math.sin(this.camera.getCameraRotation().x), + cosTx = Math.cos(this.camera.getCameraRotation().x), + sinTy = Math.sin(this.camera.getCameraRotation().y), + cosTy = Math.cos(this.camera.getCameraRotation().y), + sinTz = Math.sin(this.camera.getCameraRotation().z), + cosTz = Math.cos(this.camera.getCameraRotation().z), + // calculate translation + dx = cosTy * (sinTz * (ay - cy) + cosTz * (ax - cx)) - sinTy * (az - cz), + dy = sinTx * (cosTy * (az - cz) + sinTy * (sinTz * (ay - cy) + cosTz * (ax - cx))) + cosTx * (cosTz * (ay - cy) - sinTz * (ax-cx)), + dz = cosTx * (cosTy * (az - cz) + sinTy * (sinTz * (ay - cy) + cosTz * (ax - cx))) - sinTx * (cosTz * (ay - cy) - sinTz * (ax-cx)); -/***/ }, -/* 15 */ -/***/ function(module, exports, __webpack_require__) { + return new Point3d(dx, dy, dz); + }; /** - * Created by Alex on 10/3/2014. + * Convert a translation point to a point on the screen + * @param {Point3d} translation A 3D point with parameters x, y, z This is + * the translation of the point, seen from the + * camera + * @return {Point2d} point2d A 2D point with parameters x, y */ - var moment = __webpack_require__(44); - + Graph3d.prototype._convertTranslationToScreen = function(translation) { + var ex = this.eye.x, + ey = this.eye.y, + ez = this.eye.z, + dx = translation.x, + dy = translation.y, + dz = translation.z; - /** - * used in Core to convert the options into a volatile variable - * - * @param Core - */ - exports.convertHiddenOptions = function(body, hiddenDates) { - body.hiddenDates = []; - if (hiddenDates) { - if (Array.isArray(hiddenDates) == true) { - for (var i = 0; i < hiddenDates.length; i++) { - if (hiddenDates[i].repeat === undefined) { - var dateItem = {}; - dateItem.start = moment(hiddenDates[i].start).toDate().valueOf(); - dateItem.end = moment(hiddenDates[i].end).toDate().valueOf(); - body.hiddenDates.push(dateItem); - } - } - body.hiddenDates.sort(function (a, b) { - return a.start - b.start; - }); // sort by start time - } + // calculate position on screen from translation + var bx; + var by; + if (this.showPerspective) { + bx = (dx - ex) * (ez / dz); + by = (dy - ey) * (ez / dz); + } + else { + bx = dx * -(ez / this.camera.getArmLength()); + by = dy * -(ez / this.camera.getArmLength()); } - }; + // shift and scale the point to the center of the screen + // use the width of the graph to scale both horizontally and vertically. + return new Point2d( + this.xcenter + bx * this.frame.canvas.clientWidth, + this.ycenter - by * this.frame.canvas.clientWidth); + }; /** - * create new entrees for the repeating hidden dates - * @param body - * @param hiddenDates + * Set the background styling for the graph + * @param {string | {fill: string, stroke: string, strokeWidth: string}} backgroundColor */ - exports.updateHiddenDates = function (body, hiddenDates) { - if (hiddenDates && body.domProps.centerContainer.width !== undefined) { - exports.convertHiddenOptions(body, hiddenDates); - - var start = moment(body.range.start); - var end = moment(body.range.end); - - var totalRange = (body.range.end - body.range.start); - var pixelTime = totalRange / body.domProps.centerContainer.width; - - for (var i = 0; i < hiddenDates.length; i++) { - if (hiddenDates[i].repeat !== undefined) { - var startDate = moment(hiddenDates[i].start); - var endDate = moment(hiddenDates[i].end); - - if (startDate._d == "Invalid Date") { - throw new Error("Supplied start date is not valid: " + hiddenDates[i].start); - } - if (endDate._d == "Invalid Date") { - throw new Error("Supplied end date is not valid: " + hiddenDates[i].end); - } - - var duration = endDate - startDate; - if (duration >= 4 * pixelTime) { - - var offset = 0; - var runUntil = end.clone(); - switch (hiddenDates[i].repeat) { - case "daily": // case of time - if (startDate.day() != endDate.day()) { - offset = 1; - } - startDate.dayOfYear(start.dayOfYear()); - startDate.year(start.year()); - startDate.subtract(7,'days'); - - endDate.dayOfYear(start.dayOfYear()); - endDate.year(start.year()); - endDate.subtract(7 - offset,'days'); - - runUntil.add(1, 'weeks'); - break; - case "weekly": - var dayOffset = endDate.diff(startDate,'days') - var day = startDate.day(); - - // set the start date to the range.start - startDate.date(start.date()); - startDate.month(start.month()); - startDate.year(start.year()); - endDate = startDate.clone(); - - // force - startDate.day(day); - endDate.day(day); - endDate.add(dayOffset,'days'); + Graph3d.prototype._setBackgroundColor = function(backgroundColor) { + var fill = 'white'; + var stroke = 'gray'; + var strokeWidth = 1; - startDate.subtract(1,'weeks'); - endDate.subtract(1,'weeks'); + if (typeof(backgroundColor) === 'string') { + fill = backgroundColor; + stroke = 'none'; + strokeWidth = 0; + } + else if (typeof(backgroundColor) === 'object') { + if (backgroundColor.fill !== undefined) fill = backgroundColor.fill; + if (backgroundColor.stroke !== undefined) stroke = backgroundColor.stroke; + if (backgroundColor.strokeWidth !== undefined) strokeWidth = backgroundColor.strokeWidth; + } + else if (backgroundColor === undefined) { + // use use defaults + } + else { + throw 'Unsupported type of backgroundColor'; + } - runUntil.add(1, 'weeks'); - break - case "monthly": - if (startDate.month() != endDate.month()) { - offset = 1; - } - startDate.month(start.month()); - startDate.year(start.year()); - startDate.subtract(1,'months'); + this.frame.style.backgroundColor = fill; + this.frame.style.borderColor = stroke; + this.frame.style.borderWidth = strokeWidth + 'px'; + this.frame.style.borderStyle = 'solid'; + }; - endDate.month(start.month()); - endDate.year(start.year()); - endDate.subtract(1,'months'); - endDate.add(offset,'months'); - runUntil.add(1, 'months'); - break; - case "yearly": - if (startDate.year() != endDate.year()) { - offset = 1; - } - startDate.year(start.year()); - startDate.subtract(1,'years'); - endDate.year(start.year()); - endDate.subtract(1,'years'); - endDate.add(offset,'years'); + /// enumerate the available styles + Graph3d.STYLE = { + BAR: 0, + BARCOLOR: 1, + BARSIZE: 2, + DOT : 3, + DOTLINE : 4, + DOTCOLOR: 5, + DOTSIZE: 6, + GRID : 7, + LINE: 8, + SURFACE : 9 + }; - runUntil.add(1, 'years'); - break; - default: - console.log("Wrong repeat format, allowed are: daily, weekly, monthly, yearly. Given:", hiddenDates[i].repeat); - return; - } - while (startDate < runUntil) { - body.hiddenDates.push({start: startDate.valueOf(), end: endDate.valueOf()}); - switch (hiddenDates[i].repeat) { - case "daily": - startDate.add(1, 'days'); - endDate.add(1, 'days'); - break; - case "weekly": - startDate.add(1, 'weeks'); - endDate.add(1, 'weeks'); - break - case "monthly": - startDate.add(1, 'months'); - endDate.add(1, 'months'); - break; - case "yearly": - startDate.add(1, 'y'); - endDate.add(1, 'y'); - break; - default: - console.log("Wrong repeat format, allowed are: daily, weekly, monthly, yearly. Given:", hiddenDates[i].repeat); - return; - } - } - body.hiddenDates.push({start: startDate.valueOf(), end: endDate.valueOf()}); - } - } - } - // remove duplicates, merge where possible - exports.removeDuplicates(body); - // ensure the new positions are not on hidden dates - var startHidden = exports.isHidden(body.range.start, body.hiddenDates); - var endHidden = exports.isHidden(body.range.end,body.hiddenDates); - var rangeStart = body.range.start; - var rangeEnd = body.range.end; - if (startHidden.hidden == true) {rangeStart = body.range.startToFront == true ? startHidden.startDate - 1 : startHidden.endDate + 1;} - if (endHidden.hidden == true) {rangeEnd = body.range.endToFront == true ? endHidden.startDate - 1 : endHidden.endDate + 1;} - if (startHidden.hidden == true || endHidden.hidden == true) { - body.range._applyRange(rangeStart, rangeEnd); - } + /** + * Retrieve the style index from given styleName + * @param {string} styleName Style name such as 'dot', 'grid', 'dot-line' + * @return {Number} styleNumber Enumeration value representing the style, or -1 + * when not found + */ + Graph3d.prototype._getStyleNumber = function(styleName) { + switch (styleName) { + case 'dot': return Graph3d.STYLE.DOT; + case 'dot-line': return Graph3d.STYLE.DOTLINE; + case 'dot-color': return Graph3d.STYLE.DOTCOLOR; + case 'dot-size': return Graph3d.STYLE.DOTSIZE; + case 'line': return Graph3d.STYLE.LINE; + case 'grid': return Graph3d.STYLE.GRID; + case 'surface': return Graph3d.STYLE.SURFACE; + case 'bar': return Graph3d.STYLE.BAR; + case 'bar-color': return Graph3d.STYLE.BARCOLOR; + case 'bar-size': return Graph3d.STYLE.BARSIZE; } - } - + return -1; + }; /** - * remove duplicates from the hidden dates list. Duplicates are evil. They mess everything up. - * Scales with N^2 - * @param body + * Determine the indexes of the data columns, based on the given style and data + * @param {DataSet} data + * @param {Number} style */ - exports.removeDuplicates = function(body) { - var hiddenDates = body.hiddenDates; - var safeDates = []; - for (var i = 0; i < hiddenDates.length; i++) { - for (var j = 0; j < hiddenDates.length; j++) { - if (i != j && hiddenDates[j].remove != true && hiddenDates[i].remove != true) { - // j inside i - if (hiddenDates[j].start >= hiddenDates[i].start && hiddenDates[j].end <= hiddenDates[i].end) { - hiddenDates[j].remove = true; - } - // j start inside i - else if (hiddenDates[j].start >= hiddenDates[i].start && hiddenDates[j].start <= hiddenDates[i].end) { - hiddenDates[i].end = hiddenDates[j].end; - hiddenDates[j].remove = true; - } - // j end inside i - else if (hiddenDates[j].end >= hiddenDates[i].start && hiddenDates[j].end <= hiddenDates[i].end) { - hiddenDates[i].start = hiddenDates[j].start; - hiddenDates[j].remove = true; - } - } + Graph3d.prototype._determineColumnIndexes = function(data, style) { + if (this.style === Graph3d.STYLE.DOT || + this.style === Graph3d.STYLE.DOTLINE || + this.style === Graph3d.STYLE.LINE || + this.style === Graph3d.STYLE.GRID || + this.style === Graph3d.STYLE.SURFACE || + this.style === Graph3d.STYLE.BAR) { + // 3 columns expected, and optionally a 4th with filter values + this.colX = 0; + this.colY = 1; + this.colZ = 2; + this.colValue = undefined; + + if (data.getNumberOfColumns() > 3) { + this.colFilter = 3; } } + else if (this.style === Graph3d.STYLE.DOTCOLOR || + this.style === Graph3d.STYLE.DOTSIZE || + this.style === Graph3d.STYLE.BARCOLOR || + this.style === Graph3d.STYLE.BARSIZE) { + // 4 columns expected, and optionally a 5th with filter values + this.colX = 0; + this.colY = 1; + this.colZ = 2; + this.colValue = 3; - for (var i = 0; i < hiddenDates.length; i++) { - if (hiddenDates[i].remove !== true) { - safeDates.push(hiddenDates[i]); + if (data.getNumberOfColumns() > 4) { + this.colFilter = 4; } } + else { + throw 'Unknown style "' + this.style + '"'; + } + }; - body.hiddenDates = safeDates; - body.hiddenDates.sort(function (a, b) { - return a.start - b.start; - }); // sort by start time + Graph3d.prototype.getNumberOfRows = function(data) { + return data.length; } - exports.printDates = function(dates) { - for (var i =0; i < dates.length; i++) { - console.log(i, new Date(dates[i].start),new Date(dates[i].end), dates[i].start, dates[i].end, dates[i].remove); + + Graph3d.prototype.getNumberOfColumns = function(data) { + var counter = 0; + for (var column in data[0]) { + if (data[0].hasOwnProperty(column)) { + counter++; + } } + return counter; } - /** - * Used in TimeStep to avoid the hidden times. - * @param timeStep - * @param previousTime - */ - exports.stepOverHiddenDates = function(timeStep, previousTime) { - var stepInHidden = false; - var currentValue = timeStep.current.valueOf(); - for (var i = 0; i < timeStep.hiddenDates.length; i++) { - var startDate = timeStep.hiddenDates[i].start; - var endDate = timeStep.hiddenDates[i].end; - if (currentValue >= startDate && currentValue < endDate) { - stepInHidden = true; - break; + + Graph3d.prototype.getDistinctValues = function(data, column) { + var distinctValues = []; + for (var i = 0; i < data.length; i++) { + if (distinctValues.indexOf(data[i][column]) == -1) { + distinctValues.push(data[i][column]); } } + return distinctValues; + } - if (stepInHidden == true && currentValue < timeStep._end.valueOf() && currentValue != previousTime) { - var prevValue = moment(previousTime); - var newValue = moment(endDate); - //check if the next step should be major - if (prevValue.year() != newValue.year()) {timeStep.switchedYear = true;} - else if (prevValue.month() != newValue.month()) {timeStep.switchedMonth = true;} - else if (prevValue.dayOfYear() != newValue.dayOfYear()) {timeStep.switchedDay = true;} - timeStep.current = newValue.toDate(); + Graph3d.prototype.getColumnRange = function(data,column) { + var minMax = {min:data[0][column],max:data[0][column]}; + for (var i = 0; i < data.length; i++) { + if (minMax.min > data[i][column]) { minMax.min = data[i][column]; } + if (minMax.max < data[i][column]) { minMax.max = data[i][column]; } } + return minMax; }; - - ///** - // * Used in TimeStep to avoid the hidden times. - // * @param timeStep - // * @param previousTime - // */ - //exports.checkFirstStep = function(timeStep) { - // var stepInHidden = false; - // var currentValue = timeStep.current.valueOf(); - // for (var i = 0; i < timeStep.hiddenDates.length; i++) { - // var startDate = timeStep.hiddenDates[i].start; - // var endDate = timeStep.hiddenDates[i].end; - // if (currentValue >= startDate && currentValue < endDate) { - // stepInHidden = true; - // break; - // } - // } - // - // if (stepInHidden == true && currentValue <= timeStep._end.valueOf()) { - // var newValue = moment(endDate); - // timeStep.current = newValue.toDate(); - // } - //}; - /** - * replaces the Core toScreen methods - * @param Core - * @param time - * @param width - * @returns {number} + * Initialize the data from the data table. Calculate minimum and maximum values + * and column index values + * @param {Array | DataSet | DataView} rawData The data containing the items for the Graph. + * @param {Number} style Style Number */ - exports.toScreen = function(Core, time, width) { - if (Core.body.hiddenDates.length == 0) { - var conversion = Core.range.conversion(width); - return (time.valueOf() - conversion.offset) * conversion.scale; + Graph3d.prototype._dataInitialize = function (rawData, style) { + var me = this; + + // unsubscribe from the dataTable + if (this.dataSet) { + this.dataSet.off('*', this._onChange); } - else { - var hidden = exports.isHidden(time, Core.body.hiddenDates) - if (hidden.hidden == true) { - time = hidden.startDate; - } - var duration = exports.getHiddenDurationBetween(Core.body.hiddenDates, Core.range.start, Core.range.end); - time = exports.correctTimeForHidden(Core.body.hiddenDates, Core.range, time); + if (rawData === undefined) + return; - var conversion = Core.range.conversion(width, duration); - return (time.valueOf() - conversion.offset) * conversion.scale; + if (Array.isArray(rawData)) { + rawData = new DataSet(rawData); } - }; - - /** - * Replaces the core toTime methods - * @param body - * @param range - * @param x - * @param width - * @returns {Date} - */ - exports.toTime = function(Core, x, width) { - if (Core.body.hiddenDates.length == 0) { - var conversion = Core.range.conversion(width); - return new Date(x / conversion.scale + conversion.offset); + var data; + if (rawData instanceof DataSet || rawData instanceof DataView) { + data = rawData.get(); } else { - var hiddenDuration = exports.getHiddenDurationBetween(Core.body.hiddenDates, Core.range.start, Core.range.end); - var totalDuration = Core.range.end - Core.range.start - hiddenDuration; - var partialDuration = totalDuration * x / width; - var accumulatedHiddenDuration = exports.getAccumulatedHiddenDuration(Core.body.hiddenDates, Core.range, partialDuration); - - var newTime = new Date(accumulatedHiddenDuration + partialDuration + Core.range.start); - return newTime; + throw new Error('Array, DataSet, or DataView expected'); } - }; + if (data.length == 0) + return; - /** - * Support function - * - * @param hiddenDates - * @param range - * @returns {number} - */ - exports.getHiddenDurationBetween = function(hiddenDates, start, end) { - var duration = 0; - for (var i = 0; i < hiddenDates.length; i++) { - var startDate = hiddenDates[i].start; - var endDate = hiddenDates[i].end; - // if time after the cutout, and the - if (startDate >= start && endDate < end) { - duration += endDate - startDate; - } - } - return duration; - }; + this.dataSet = rawData; + this.dataTable = data; + // subscribe to changes in the dataset + this._onChange = function () { + me.setData(me.dataSet); + }; + this.dataSet.on('*', this._onChange); - /** - * Support function - * @param hiddenDates - * @param range - * @param time - * @returns {{duration: number, time: *, offset: number}} - */ - exports.correctTimeForHidden = function(hiddenDates, range, time) { - time = moment(time).toDate().valueOf(); - time -= exports.getHiddenDurationBefore(hiddenDates,range,time); - return time; - }; + // _determineColumnIndexes + // getNumberOfRows (points) + // getNumberOfColumns (x,y,z,v,t,t1,t2...) + // getDistinctValues (unique values?) + // getColumnRange - exports.getHiddenDurationBefore = function(hiddenDates, range, time) { - var timeOffset = 0; - time = moment(time).toDate().valueOf(); + // determine the location of x,y,z,value,filter columns + this.colX = 'x'; + this.colY = 'y'; + this.colZ = 'z'; + this.colValue = 'style'; + this.colFilter = 'filter'; - for (var i = 0; i < hiddenDates.length; i++) { - var startDate = hiddenDates[i].start; - var endDate = hiddenDates[i].end; - // if time after the cutout, and the - if (startDate >= range.start && endDate < range.end) { - if (time >= endDate) { - timeOffset += (endDate - startDate); - } - } - } - return timeOffset; - } - /** - * sum the duration from start to finish, including the hidden duration, - * until the required amount has been reached, return the accumulated hidden duration - * @param hiddenDates - * @param range - * @param time - * @returns {{duration: number, time: *, offset: number}} - */ - exports.getAccumulatedHiddenDuration = function(hiddenDates, range, requiredDuration) { - var hiddenDuration = 0; - var duration = 0; - var previousPoint = range.start; - //exports.printDates(hiddenDates) - for (var i = 0; i < hiddenDates.length; i++) { - var startDate = hiddenDates[i].start; - var endDate = hiddenDates[i].end; - // if time after the cutout, and the - if (startDate >= range.start && endDate < range.end) { - duration += startDate - previousPoint; - previousPoint = endDate; - if (duration >= requiredDuration) { - break; - } - else { - hiddenDuration += endDate - startDate; - } + + // check if a filter column is provided + if (data[0].hasOwnProperty('filter')) { + if (this.dataFilter === undefined) { + this.dataFilter = new Filter(rawData, this.colFilter, this); + this.dataFilter.setOnLoadCallback(function() {me.redraw();}); } } - return hiddenDuration; - }; + var withBars = this.style == Graph3d.STYLE.BAR || + this.style == Graph3d.STYLE.BARCOLOR || + this.style == Graph3d.STYLE.BARSIZE; + // determine barWidth from data + if (withBars) { + if (this.defaultXBarWidth !== undefined) { + this.xBarWidth = this.defaultXBarWidth; + } + else { + var dataX = this.getDistinctValues(data,this.colX); + this.xBarWidth = (dataX[1] - dataX[0]) || 1; + } - /** - * used to step over to either side of a hidden block. Correction is disabled on tablets, might be set to true - * @param hiddenDates - * @param time - * @param direction - * @param correctionEnabled - * @returns {*} - */ - exports.snapAwayFromHidden = function(hiddenDates, time, direction, correctionEnabled) { - var isHidden = exports.isHidden(time, hiddenDates); - if (isHidden.hidden == true) { - if (direction < 0) { - if (correctionEnabled == true) { - return isHidden.startDate - (isHidden.endDate - time) - 1; - } - else { - return isHidden.startDate - 1; - } + if (this.defaultYBarWidth !== undefined) { + this.yBarWidth = this.defaultYBarWidth; } else { - if (correctionEnabled == true) { - return isHidden.endDate + (time - isHidden.startDate) + 1; - } - else { - return isHidden.endDate + 1; - } + var dataY = this.getDistinctValues(data,this.colY); + this.yBarWidth = (dataY[1] - dataY[0]) || 1; } } - else { - return time; - } - } + // calculate minimums and maximums + var xRange = this.getColumnRange(data,this.colX); + if (withBars) { + xRange.min -= this.xBarWidth / 2; + xRange.max += this.xBarWidth / 2; + } + this.xMin = (this.defaultXMin !== undefined) ? this.defaultXMin : xRange.min; + this.xMax = (this.defaultXMax !== undefined) ? this.defaultXMax : xRange.max; + if (this.xMax <= this.xMin) this.xMax = this.xMin + 1; + this.xStep = (this.defaultXStep !== undefined) ? this.defaultXStep : (this.xMax-this.xMin)/5; + var yRange = this.getColumnRange(data,this.colY); + if (withBars) { + yRange.min -= this.yBarWidth / 2; + yRange.max += this.yBarWidth / 2; + } + this.yMin = (this.defaultYMin !== undefined) ? this.defaultYMin : yRange.min; + this.yMax = (this.defaultYMax !== undefined) ? this.defaultYMax : yRange.max; + if (this.yMax <= this.yMin) this.yMax = this.yMin + 1; + this.yStep = (this.defaultYStep !== undefined) ? this.defaultYStep : (this.yMax-this.yMin)/5; - /** - * Check if a time is hidden - * - * @param time - * @param hiddenDates - * @returns {{hidden: boolean, startDate: Window.start, endDate: *}} - */ - exports.isHidden = function(time, hiddenDates) { - for (var i = 0; i < hiddenDates.length; i++) { - var startDate = hiddenDates[i].start; - var endDate = hiddenDates[i].end; + var zRange = this.getColumnRange(data,this.colZ); + this.zMin = (this.defaultZMin !== undefined) ? this.defaultZMin : zRange.min; + this.zMax = (this.defaultZMax !== undefined) ? this.defaultZMax : zRange.max; + if (this.zMax <= this.zMin) this.zMax = this.zMin + 1; + this.zStep = (this.defaultZStep !== undefined) ? this.defaultZStep : (this.zMax-this.zMin)/5; - if (time >= startDate && time < endDate) { // if the start is entering a hidden zone - return {hidden: true, startDate: startDate, endDate: endDate}; - break; - } + if (this.colValue !== undefined) { + var valueRange = this.getColumnRange(data,this.colValue); + this.valueMin = (this.defaultValueMin !== undefined) ? this.defaultValueMin : valueRange.min; + this.valueMax = (this.defaultValueMax !== undefined) ? this.defaultValueMax : valueRange.max; + if (this.valueMax <= this.valueMin) this.valueMax = this.valueMin + 1; } - return {hidden: false, startDate: startDate, endDate: endDate}; - } -/***/ }, -/* 16 */ -/***/ function(module, exports, __webpack_require__) { + // set the scale dependent on the ranges. + this._setScale(); + }; + + /** - * @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 + * Filter the data based on the current filter + * @param {Array} data + * @return {Array} dataPoints Array with point objects which can be drawn on screen */ - function DataStep(start, end, minimumStep, containerHeight, customRange, alignZeros) { - // variables - this.current = 0; - - this.autoScale = true; - this.stepIndex = 0; - this.step = 1; - this.scale = 1; + Graph3d.prototype._getDataPoints = function (data) { + // TODO: store the created matrix dataPoints in the filters instead of reloading each time + var x, y, i, z, obj, point; - this.marginStart; - this.marginEnd; - this.deadSpace = 0; + var dataPoints = []; - this.majorSteps = [1, 2, 5, 10]; - this.minorSteps = [0.25, 0.5, 1, 2]; + if (this.style === Graph3d.STYLE.GRID || + this.style === Graph3d.STYLE.SURFACE) { + // copy all values from the google data table to a matrix + // the provided values are supposed to form a grid of (x,y) positions - this.alignZeros = alignZeros; + // create two lists with all present x and y values + var dataX = []; + var dataY = []; + for (i = 0; i < this.getNumberOfRows(data); i++) { + x = data[i][this.colX] || 0; + y = data[i][this.colY] || 0; - this.setRange(start, end, minimumStep, containerHeight, customRange); - } + if (dataX.indexOf(x) === -1) { + dataX.push(x); + } + if (dataY.indexOf(y) === -1) { + dataY.push(y); + } + } + var sortNumber = function (a, b) { + return a - b; + }; + dataX.sort(sortNumber); + dataY.sort(sortNumber); + // create a grid, a 2d matrix, with all values. + var dataMatrix = []; // temporary data matrix + for (i = 0; i < data.length; i++) { + x = data[i][this.colX] || 0; + y = data[i][this.colY] || 0; + z = data[i][this.colZ] || 0; - /** - * 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; + var xIndex = dataX.indexOf(x); // TODO: implement Array().indexOf() for Internet Explorer + var yIndex = dataY.indexOf(y); - if (this._start == this._end) { - this._start -= 0.75; - this._end += 1; - } + if (dataMatrix[xIndex] === undefined) { + dataMatrix[xIndex] = []; + } - if (this.autoScale == true) { - this.setMinimumStep(minimumStep, containerHeight); - } + var point3d = new Point3d(); + point3d.x = x; + point3d.y = y; + point3d.z = z; - this.setFirst(customRange); - }; + obj = {}; + obj.point = point3d; + obj.trans = undefined; + obj.screen = undefined; + obj.bottom = new Point3d(x, y, this.zMin); - /** - * 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); + dataMatrix[xIndex][yIndex] = obj; - var minorStepIdx = -1; - var magnitudefactor = Math.pow(10,orderOfMagnitude); + dataPoints.push(obj); + } - var start = 0; - if (orderOfMagnitude < 0) { - start = orderOfMagnitude; + // fill in the pointers to the neighbors. + for (x = 0; x < dataMatrix.length; x++) { + for (y = 0; y < dataMatrix[x].length; y++) { + if (dataMatrix[x][y]) { + dataMatrix[x][y].pointRight = (x < dataMatrix.length-1) ? dataMatrix[x+1][y] : undefined; + dataMatrix[x][y].pointTop = (y < dataMatrix[x].length-1) ? dataMatrix[x][y+1] : undefined; + dataMatrix[x][y].pointCross = + (x < dataMatrix.length-1 && y < dataMatrix[x].length-1) ? + dataMatrix[x+1][y+1] : + undefined; + } + } + } } + else { // 'dot', 'dot-line', etc. + // copy all values from the google data table to a list with Point3d objects + for (i = 0; i < data.length; i++) { + point = new Point3d(); + point.x = data[i][this.colX] || 0; + point.y = data[i][this.colY] || 0; + point.z = data[i][this.colZ] || 0; - 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 (this.colValue !== undefined) { + point.value = data[i][this.colValue] || 0; } - } - if (solutionFound == true) { - break; + + obj = {}; + obj.point = point; + obj.bottom = new Point3d(point.x, point.y, this.zMin); + obj.trans = undefined; + obj.screen = undefined; + + dataPoints.push(obj); } } - this.stepIndex = minorStepIdx; - this.scale = magnitudefactor; - this.step = magnitudefactor * this.minorSteps[minorStepIdx]; - }; - + return dataPoints; + }; /** - * Round the current date to the first minor date value - * This must be executed once when the current date is set to start Date + * Create the main frame for the Graph3d. + * This function is executed once when a Graph3d object is created. The frame + * contains a canvas, and this canvas contains all objects like the axis and + * nodes. */ - DataStep.prototype.setFirst = function(customRange) { - if (customRange === undefined) { - customRange = {}; + Graph3d.prototype.create = function () { + // remove all elements from the container element. + while (this.containerElement.hasChildNodes()) { + this.containerElement.removeChild(this.containerElement.firstChild); } - 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.frame = document.createElement('div'); + this.frame.style.position = 'relative'; + this.frame.style.overflow = 'hidden'; - // if we need to align the zero's we need to make sure that there is a zero to use. - if (this.alignZeros == true && (this.marginEnd - this.marginStart) % this.step != 0) { - this.marginEnd += this.marginEnd % this.step; + // create the graph canvas (HTML canvas element) + this.frame.canvas = document.createElement( 'canvas' ); + this.frame.canvas.style.position = 'relative'; + this.frame.appendChild(this.frame.canvas); + //if (!this.frame.canvas.getContext) { + { + var noCanvas = document.createElement( 'DIV' ); + noCanvas.style.color = 'red'; + noCanvas.style.fontWeight = 'bold' ; + noCanvas.style.padding = '10px'; + noCanvas.innerHTML = 'Error: your browser does not support HTML canvas'; + this.frame.canvas.appendChild(noCanvas); } - this.deadSpace = this.roundToMinor(niceEnd) - niceEnd + this.roundToMinor(niceStart) - niceStart; - this.marginRange = this.marginEnd - this.marginStart; + this.frame.filter = document.createElement( 'div' ); + this.frame.filter.style.position = 'absolute'; + this.frame.filter.style.bottom = '0px'; + this.frame.filter.style.left = '0px'; + this.frame.filter.style.width = '100%'; + this.frame.appendChild(this.frame.filter); + + // add event listeners to handle moving and zooming the contents + var me = this; + var onmousedown = function (event) {me._onMouseDown(event);}; + var ontouchstart = function (event) {me._onTouchStart(event);}; + var onmousewheel = function (event) {me._onWheel(event);}; + var ontooltip = function (event) {me._onTooltip(event);}; + // TODO: these events are never cleaned up... can give a 'memory leakage' + util.addEventListener(this.frame.canvas, 'keydown', onkeydown); + util.addEventListener(this.frame.canvas, 'mousedown', onmousedown); + util.addEventListener(this.frame.canvas, 'touchstart', ontouchstart); + util.addEventListener(this.frame.canvas, 'mousewheel', onmousewheel); + util.addEventListener(this.frame.canvas, 'mousemove', ontooltip); - this.current = this.marginEnd; + // add the new graph to the container element + this.containerElement.appendChild(this.frame); }; - 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 + * Set a new size for the graph + * @param {string} width Width in pixels or percentage (for example '800px' + * or '50%') + * @param {string} height Height in pixels or percentage (for example '400px' + * or '30%') */ - DataStep.prototype.hasNext = function () { - return (this.current >= this.marginStart); + Graph3d.prototype.setSize = function(width, height) { + this.frame.style.width = width; + this.frame.style.height = height; + + this._resizeCanvas(); }; /** - * Do the next step + * Resize the canvas to the current size of the frame */ - DataStep.prototype.next = function() { - var prev = this.current; - this.current -= this.step; + Graph3d.prototype._resizeCanvas = function() { + this.frame.canvas.style.width = '100%'; + this.frame.canvas.style.height = '100%'; - // safety mechanism: if current time is still unchanged, move to the end - if (this.current == prev) { - this.current = this._end; - } + this.frame.canvas.width = this.frame.canvas.clientWidth; + this.frame.canvas.height = this.frame.canvas.clientHeight; + + // adjust with for margin + this.frame.filter.style.width = (this.frame.canvas.clientWidth - 2 * 10) + 'px'; }; /** - * Do the next step + * Start animation */ - DataStep.prototype.previous = function() { - this.current += this.step; - this.marginEnd += this.step; - this.marginRange = this.marginEnd - this.marginStart; - }; + Graph3d.prototype.animationStart = function() { + if (!this.frame.filter || !this.frame.filter.slider) + throw 'No animation available'; + this.frame.filter.slider.play(); + }; /** - * Get the current datetime - * @return {String} current The current date + * Stop animation */ - DataStep.prototype.getCurrent = function(decimals) { - // prevent round-off errors when close to zero - var current = (Math.abs(this.current) < this.step / 2) ? 0 : this.current; - var toPrecision = '' + Number(current).toPrecision(5); + Graph3d.prototype.animationStop = function() { + if (!this.frame.filter || !this.frame.filter.slider) return; - // If decimals is specified, then limit or extend the string as required - if(decimals !== undefined && !isNaN(Number(decimals))) { - // If string includes exponent, then we need to add it to the end - var exp = ""; - var index = toPrecision.indexOf("e"); - if(index != -1) { - // Get the exponent - exp = toPrecision.slice(index); - // Remove the exponent in case we need to zero-extend - toPrecision = toPrecision.slice(0, index); - } - index = Math.max(toPrecision.indexOf(","), toPrecision.indexOf(".")); - if(index === -1) { - // No decimal found - if we want decimals, then we need to add it - if(decimals !== 0) { - toPrecision += '.'; - } - // Calculate how long the string should be - index = toPrecision.length + decimals; - } - else if(decimals !== 0) { - // Calculate how long the string should be - accounting for the decimal place - index += decimals + 1; - } - if(index > toPrecision.length) { - // We need to add zeros! - for(var cnt = index - toPrecision.length; cnt > 0; cnt--) { - toPrecision += '0'; - } - } - else { - // we need to remove characters - toPrecision = toPrecision.slice(0, index); - } - // Add the exponent if there is one - toPrecision += exp; + this.frame.filter.slider.stop(); + }; + + + /** + * Resize the center position based on the current values in this.defaultXCenter + * and this.defaultYCenter (which are strings with a percentage or a value + * in pixels). The center positions are the variables this.xCenter + * and this.yCenter + */ + Graph3d.prototype._resizeCenter = function() { + // calculate the horizontal center position + if (this.defaultXCenter.charAt(this.defaultXCenter.length-1) === '%') { + this.xcenter = + parseFloat(this.defaultXCenter) / 100 * + this.frame.canvas.clientWidth; } else { - if (toPrecision.indexOf(",") != -1 || toPrecision.indexOf(".") != -1) { - // If no decimal is specified, and there are decimal places, remove trailing zeros - 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; - } - } - } + this.xcenter = parseFloat(this.defaultXCenter); // supposed to be in px } - 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); + // calculate the vertical center position + if (this.defaultYCenter.charAt(this.defaultYCenter.length-1) === '%') { + this.ycenter = + parseFloat(this.defaultYCenter) / 100 * + (this.frame.canvas.clientHeight - this.frame.filter.clientHeight); + } + else { + this.ycenter = parseFloat(this.defaultYCenter); // supposed to be in px + } }; - module.exports = DataStep; - - -/***/ }, -/* 17 */ -/***/ function(module, exports, __webpack_require__) { - - var util = __webpack_require__(1); - var hammerUtil = __webpack_require__(47); - var moment = __webpack_require__(44); - var Component = __webpack_require__(20); - var DateUtil = __webpack_require__(15); - /** - * @constructor Range - * A Range controls a numeric range with a start and end value. - * The Range adjusts the range based on mouse events or programmatic changes, - * and triggers events when the range is changing or has been changed. - * @param {{dom: Object, domProps: Object, emitter: Emitter}} body - * @param {Object} [options] See description at Range.setOptions + * Set the rotation and distance of the camera + * @param {Object} pos An object with the camera position. The object + * contains three parameters: + * - horizontal {Number} + * The horizontal rotation, between 0 and 2*PI. + * Optional, can be left undefined. + * - vertical {Number} + * The vertical rotation, between 0 and 0.5*PI + * if vertical=0.5*PI, the graph is shown from the + * top. Optional, can be left undefined. + * - distance {Number} + * The (normalized) distance of the camera to the + * center of the graph, a value between 0.71 and 5.0. + * Optional, can be left undefined. */ - function Range(body, options) { - var now = moment().hours(0).minutes(0).seconds(0).milliseconds(0); - this.start = now.clone().add(-3, 'days').valueOf(); // Number - this.end = now.clone().add(4, 'days').valueOf(); // Number - - this.body = body; - this.deltaDifference = 0; - this.scaleOffset = 0; - this.startToFront = false; - this.endToFront = true; - - // default options - this.defaultOptions = { - start: null, - end: null, - direction: 'horizontal', // 'horizontal' or 'vertical' - moveable: true, - zoomable: true, - min: null, - max: null, - zoomMin: 10, // milliseconds - zoomMax: 1000 * 60 * 60 * 24 * 365 * 10000 // milliseconds - }; - this.options = util.extend({}, this.defaultOptions); - - this.props = { - touch: {} - }; - this.animateTimer = null; - - // drag listeners for dragging - this.body.emitter.on('dragstart', this._onDragStart.bind(this)); - this.body.emitter.on('drag', this._onDrag.bind(this)); - this.body.emitter.on('dragend', this._onDragEnd.bind(this)); - - // ignore dragging when holding - this.body.emitter.on('hold', this._onHold.bind(this)); + Graph3d.prototype.setCameraPosition = function(pos) { + if (pos === undefined) { + return; + } - // mouse wheel for zooming - this.body.emitter.on('mousewheel', this._onMouseWheel.bind(this)); - this.body.emitter.on('DOMMouseScroll', this._onMouseWheel.bind(this)); // For FF + if (pos.horizontal !== undefined && pos.vertical !== undefined) { + this.camera.setArmRotation(pos.horizontal, pos.vertical); + } - // pinch to zoom - this.body.emitter.on('touch', this._onTouch.bind(this)); - this.body.emitter.on('pinch', this._onPinch.bind(this)); + if (pos.distance !== undefined) { + this.camera.setArmLength(pos.distance); + } - this.setOptions(options); - } + this.redraw(); + }; - Range.prototype = new Component(); /** - * Set options for the range controller - * @param {Object} options Available options: - * {Number | Date | String} start Start date for the range - * {Number | Date | String} end End date for the range - * {Number} min Minimum value for start - * {Number} max Maximum value for end - * {Number} zoomMin Set a minimum value for - * (end - start). - * {Number} zoomMax Set a maximum value for - * (end - start). - * {Boolean} moveable Enable moving of the range - * by dragging. True by default - * {Boolean} zoomable Enable zooming of the range - * by pinching/scrolling. True by default + * Retrieve the current camera rotation + * @return {object} An object with parameters horizontal, vertical, and + * distance */ - Range.prototype.setOptions = function (options) { - if (options) { - // copy the options that we know - var fields = ['direction', 'min', 'max', 'zoomMin', 'zoomMax', 'moveable', 'zoomable', 'activate', 'hiddenDates']; - util.selectiveExtend(fields, this.options, options); - - if ('start' in options || 'end' in options) { - // apply a new range. both start and end are optional - this.setRange(options.start, options.end); - } - } + Graph3d.prototype.getCameraPosition = function() { + var pos = this.camera.getArmRotation(); + pos.distance = this.camera.getArmLength(); + return pos; }; /** - * Test whether direction has a valid value - * @param {String} direction 'horizontal' or 'vertical' - */ - function validateDirection (direction) { - if (direction != 'horizontal' && direction != 'vertical') { - throw new TypeError('Unknown direction "' + direction + '". ' + - 'Choose "horizontal" or "vertical".'); - } - } - - /** - * Set a new start and end range - * @param {Date | Number | String} [start] - * @param {Date | Number | String} [end] - * @param {boolean | number} [animate=false] If true, the range is animated - * smoothly to the new window. - * If animate is a number, the - * number is taken as duration - * Default duration is 500 ms. - * @param {Boolean} [byUser=false] - * + * Load data into the 3D Graph */ - Range.prototype.setRange = function(start, end, animate, byUser) { - if (byUser !== true) { - byUser = false; - } - var _start = start != undefined ? util.convert(start, 'Date').valueOf() : null; - var _end = end != undefined ? util.convert(end, 'Date').valueOf() : null; - this._cancelAnimation(); - - if (animate) { - var me = this; - var initStart = this.start; - var initEnd = this.end; - var duration = typeof animate === 'number' ? animate : 500; - var initTime = new Date().valueOf(); - var anyChanged = false; - - var next = function () { - if (!me.props.touch.dragging) { - var now = new Date().valueOf(); - var time = now - initTime; - var done = time > duration; - var s = (done || _start === null) ? _start : util.easeInOutQuad(time, initStart, _start, duration); - var e = (done || _end === null) ? _end : util.easeInOutQuad(time, initEnd, _end, duration); - - changed = me._applyRange(s, e); - DateUtil.updateHiddenDates(me.body, me.options.hiddenDates); - anyChanged = anyChanged || changed; - if (changed) { - me.body.emitter.emit('rangechange', {start: new Date(me.start), end: new Date(me.end), byUser:byUser}); - } + Graph3d.prototype._readData = function(data) { + // read the data + this._dataInitialize(data, this.style); - if (done) { - if (anyChanged) { - me.body.emitter.emit('rangechanged', {start: new Date(me.start), end: new Date(me.end), byUser:byUser}); - } - } - else { - // animate with as high as possible frame rate, leave 20 ms in between - // each to prevent the browser from blocking - me.animateTimer = setTimeout(next, 20); - } - } - } - return next(); + if (this.dataFilter) { + // apply filtering + this.dataPoints = this.dataFilter._getDataPoints(); } else { - var changed = this._applyRange(_start, _end); - DateUtil.updateHiddenDates(this.body, this.options.hiddenDates); - if (changed) { - var params = {start: new Date(this.start), end: new Date(this.end), byUser:byUser}; - this.body.emitter.emit('rangechange', params); - this.body.emitter.emit('rangechanged', params); - } + // no filtering. load all data + this.dataPoints = this._getDataPoints(this.dataTable); } + + // draw the filter + this._redrawFilter(); }; /** - * Stop an animation - * @private + * Replace the dataset of the Graph3d + * @param {Array | DataSet | DataView} data */ - Range.prototype._cancelAnimation = function () { - if (this.animateTimer) { - clearTimeout(this.animateTimer); - this.animateTimer = null; + Graph3d.prototype.setData = function (data) { + this._readData(data); + this.redraw(); + + // start animation when option is true + if (this.animationAutoStart && this.dataFilter) { + this.animationStart(); } }; /** - * Set a new start and end range. This method is the same as setRange, but - * does not trigger a range change and range changed event, and it returns - * true when the range is changed - * @param {Number} [start] - * @param {Number} [end] - * @return {Boolean} changed - * @private + * Update the options. Options will be merged with current options + * @param {Object} options */ - Range.prototype._applyRange = function(start, end) { - var newStart = (start != null) ? util.convert(start, 'Date').valueOf() : this.start, - newEnd = (end != null) ? util.convert(end, 'Date').valueOf() : this.end, - max = (this.options.max != null) ? util.convert(this.options.max, 'Date').valueOf() : null, - min = (this.options.min != null) ? util.convert(this.options.min, 'Date').valueOf() : null, - diff; + Graph3d.prototype.setOptions = function (options) { + var cameraPosition = undefined; - // check for valid number - if (isNaN(newStart) || newStart === null) { - throw new Error('Invalid start "' + start + '"'); - } - if (isNaN(newEnd) || newEnd === null) { - throw new Error('Invalid end "' + end + '"'); - } + this.animationStop(); - // prevent start < end - if (newEnd < newStart) { - newEnd = newStart; - } + if (options !== undefined) { + // retrieve parameter values + if (options.width !== undefined) this.width = options.width; + if (options.height !== undefined) this.height = options.height; - // prevent start < min - if (min !== null) { - if (newStart < min) { - diff = (min - newStart); - newStart += diff; - newEnd += diff; + if (options.xCenter !== undefined) this.defaultXCenter = options.xCenter; + if (options.yCenter !== undefined) this.defaultYCenter = options.yCenter; - // prevent end > max - if (max != null) { - if (newEnd > max) { - newEnd = max; - } - } - } - } + if (options.filterLabel !== undefined) this.filterLabel = options.filterLabel; + if (options.legendLabel !== undefined) this.legendLabel = options.legendLabel; + if (options.xLabel !== undefined) this.xLabel = options.xLabel; + if (options.yLabel !== undefined) this.yLabel = options.yLabel; + if (options.zLabel !== undefined) this.zLabel = options.zLabel; - // prevent end > max - if (max !== null) { - if (newEnd > max) { - diff = (newEnd - max); - newStart -= diff; - newEnd -= diff; + if (options.xValueLabel !== undefined) this.xValueLabel = options.xValueLabel; + if (options.yValueLabel !== undefined) this.yValueLabel = options.yValueLabel; + if (options.zValueLabel !== undefined) this.zValueLabel = options.zValueLabel; - // prevent start < min - if (min != null) { - if (newStart < min) { - newStart = min; - } + if (options.style !== undefined) { + var styleNumber = this._getStyleNumber(options.style); + if (styleNumber !== -1) { + this.style = styleNumber; } } - } + if (options.showGrid !== undefined) this.showGrid = options.showGrid; + if (options.showPerspective !== undefined) this.showPerspective = options.showPerspective; + if (options.showShadow !== undefined) this.showShadow = options.showShadow; + if (options.tooltip !== undefined) this.showTooltip = options.tooltip; + if (options.showAnimationControls !== undefined) this.showAnimationControls = options.showAnimationControls; + if (options.keepAspectRatio !== undefined) this.keepAspectRatio = options.keepAspectRatio; + if (options.verticalRatio !== undefined) this.verticalRatio = options.verticalRatio; - // prevent (end-start) < zoomMin - if (this.options.zoomMin !== null) { - var zoomMin = parseFloat(this.options.zoomMin); - if (zoomMin < 0) { - zoomMin = 0; - } - if ((newEnd - newStart) < zoomMin) { - if ((this.end - this.start) === zoomMin) { - // ignore this action, we are already zoomed to the minimum - newStart = this.start; - newEnd = this.end; - } - else { - // zoom to the minimum - diff = (zoomMin - (newEnd - newStart)); - newStart -= diff / 2; - newEnd += diff / 2; - } - } - } + if (options.animationInterval !== undefined) this.animationInterval = options.animationInterval; + if (options.animationPreload !== undefined) this.animationPreload = options.animationPreload; + if (options.animationAutoStart !== undefined)this.animationAutoStart = options.animationAutoStart; - // prevent (end-start) > zoomMax - if (this.options.zoomMax !== null) { - var zoomMax = parseFloat(this.options.zoomMax); - if (zoomMax < 0) { - zoomMax = 0; + if (options.xBarWidth !== undefined) this.defaultXBarWidth = options.xBarWidth; + if (options.yBarWidth !== undefined) this.defaultYBarWidth = options.yBarWidth; + + if (options.xMin !== undefined) this.defaultXMin = options.xMin; + if (options.xStep !== undefined) this.defaultXStep = options.xStep; + if (options.xMax !== undefined) this.defaultXMax = options.xMax; + if (options.yMin !== undefined) this.defaultYMin = options.yMin; + if (options.yStep !== undefined) this.defaultYStep = options.yStep; + if (options.yMax !== undefined) this.defaultYMax = options.yMax; + if (options.zMin !== undefined) this.defaultZMin = options.zMin; + if (options.zStep !== undefined) this.defaultZStep = options.zStep; + if (options.zMax !== undefined) this.defaultZMax = options.zMax; + if (options.valueMin !== undefined) this.defaultValueMin = options.valueMin; + if (options.valueMax !== undefined) this.defaultValueMax = options.valueMax; + + if (options.cameraPosition !== undefined) cameraPosition = options.cameraPosition; + + if (cameraPosition !== undefined) { + this.camera.setArmRotation(cameraPosition.horizontal, cameraPosition.vertical); + this.camera.setArmLength(cameraPosition.distance); } - if ((newEnd - newStart) > zoomMax) { - if ((this.end - this.start) === zoomMax) { - // ignore this action, we are already zoomed to the maximum - newStart = this.start; - newEnd = this.end; - } - else { - // zoom to the maximum - diff = ((newEnd - newStart) - zoomMax); - newStart += diff / 2; - newEnd -= diff / 2; - } + else { + this.camera.setArmRotation(1.0, 0.5); + this.camera.setArmLength(1.7); } } - var changed = (this.start != newStart || this.end != newEnd); + this._setBackgroundColor(options && options.backgroundColor); - // if the new range does NOT overlap with the old range, emit checkRangedItems to avoid not showing ranged items (ranged meaning has end time, not neccesarily of type Range) - if (!((newStart >= this.start && newStart <= this.end) || (newEnd >= this.start && newEnd <= this.end)) && - !((this.start >= newStart && this.start <= newEnd) || (this.end >= newStart && this.end <= newEnd) )) { - this.body.emitter.emit('checkRangedItems'); + this.setSize(this.width, this.height); + + // re-load the data + if (this.dataTable) { + this.setData(this.dataTable); } - this.start = newStart; - this.end = newEnd; - return changed; + // start animation when option is true + if (this.animationAutoStart && this.dataFilter) { + this.animationStart(); + } }; /** - * Retrieve the current range. - * @return {Object} An object with start and end properties + * Redraw the Graph. */ - Range.prototype.getRange = function() { - return { - start: this.start, - end: this.end - }; - }; + Graph3d.prototype.redraw = function() { + if (this.dataPoints === undefined) { + throw 'Error: graph data not initialized'; + } - /** - * Calculate the conversion offset and scale for current range, based on - * the provided width - * @param {Number} width - * @returns {{offset: number, scale: number}} conversion - */ - Range.prototype.conversion = function (width, totalHidden) { - return Range.conversion(this.start, this.end, width, totalHidden); - }; + this._resizeCanvas(); + this._resizeCenter(); + this._redrawSlider(); + this._redrawClear(); + this._redrawAxis(); - /** - * Static method to calculate the conversion offset and scale for a range, - * based on the provided start, end, and width - * @param {Number} start - * @param {Number} end - * @param {Number} width - * @returns {{offset: number, scale: number}} conversion - */ - Range.conversion = function (start, end, width, totalHidden) { - if (totalHidden === undefined) { - totalHidden = 0; + if (this.style === Graph3d.STYLE.GRID || + this.style === Graph3d.STYLE.SURFACE) { + this._redrawDataGrid(); } - if (width != 0 && (end - start != 0)) { - return { - offset: start, - scale: width / (end - start - totalHidden) - } + else if (this.style === Graph3d.STYLE.LINE) { + this._redrawDataLine(); + } + else if (this.style === Graph3d.STYLE.BAR || + this.style === Graph3d.STYLE.BARCOLOR || + this.style === Graph3d.STYLE.BARSIZE) { + this._redrawDataBar(); } else { - return { - offset: 0, - scale: 1 - }; + // style is DOT, DOTLINE, DOTCOLOR, DOTSIZE + this._redrawDataDot(); } + + this._redrawInfo(); + this._redrawLegend(); }; /** - * Start dragging horizontally or vertically - * @param {Event} event - * @private + * Clear the canvas before redrawing */ - Range.prototype._onDragStart = function(event) { - this.deltaDifference = 0; - this.previousDelta = 0; - // only allow dragging when configured as movable - if (!this.options.moveable) return; - - // refuse to drag when we where pinching to prevent the timeline make a jump - // when releasing the fingers in opposite order from the touch screen - if (!this.props.touch.allowDragging) return; - - this.props.touch.start = this.start; - this.props.touch.end = this.end; - this.props.touch.dragging = true; + Graph3d.prototype._redrawClear = function() { + var canvas = this.frame.canvas; + var ctx = canvas.getContext('2d'); - if (this.body.dom.root) { - this.body.dom.root.style.cursor = 'move'; - } + ctx.clearRect(0, 0, canvas.width, canvas.height); }; + /** - * Perform dragging operation - * @param {Event} event - * @private + * Redraw the legend showing the colors */ - Range.prototype._onDrag = function (event) { - // only allow dragging when configured as movable - if (!this.options.moveable) return; - // refuse to drag when we where pinching to prevent the timeline make a jump - // when releasing the fingers in opposite order from the touch screen - if (!this.props.touch.allowDragging) return; - - var direction = this.options.direction; - validateDirection(direction); - - var delta = (direction == 'horizontal') ? event.gesture.deltaX : event.gesture.deltaY; - delta -= this.deltaDifference; - var interval = (this.props.touch.end - this.props.touch.start); + Graph3d.prototype._redrawLegend = function() { + var y; - // normalize dragging speed if cutout is in between. - var duration = DateUtil.getHiddenDurationBetween(this.body.hiddenDates, this.start, this.end); - interval -= duration; + if (this.style === Graph3d.STYLE.DOTCOLOR || + this.style === Graph3d.STYLE.DOTSIZE) { - var width = (direction == 'horizontal') ? this.body.domProps.center.width : this.body.domProps.center.height; - var diffRange = -delta / width * interval; - var newStart = this.props.touch.start + diffRange; - var newEnd = this.props.touch.end + diffRange; + var dotSize = this.frame.clientWidth * 0.02; + var widthMin, widthMax; + if (this.style === Graph3d.STYLE.DOTSIZE) { + widthMin = dotSize / 2; // px + widthMax = dotSize / 2 + dotSize * 2; // Todo: put this in one function + } + else { + widthMin = 20; // px + widthMax = 20; // px + } - // snapping times away from hidden zones - var safeStart = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newStart, this.previousDelta-delta, true); - var safeEnd = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newEnd, this.previousDelta-delta, true); - if (safeStart != newStart || safeEnd != newEnd) { - this.deltaDifference += delta; - this.props.touch.start = safeStart; - this.props.touch.end = safeEnd; - this._onDrag(event); - return; + var height = Math.max(this.frame.clientHeight * 0.25, 100); + var top = this.margin; + var right = this.frame.clientWidth - this.margin; + var left = right - widthMax; + var bottom = top + height; } - this.previousDelta = delta; - this._applyRange(newStart, newEnd); + var canvas = this.frame.canvas; + var ctx = canvas.getContext('2d'); + ctx.lineWidth = 1; + ctx.font = '14px arial'; // TODO: put in options - // fire a rangechange event - this.body.emitter.emit('rangechange', { - start: new Date(this.start), - end: new Date(this.end), - byUser: true - }); - }; + if (this.style === Graph3d.STYLE.DOTCOLOR) { + // draw the color bar + var ymin = 0; + var ymax = height; // Todo: make height customizable + for (y = ymin; y < ymax; y++) { + var f = (y - ymin) / (ymax - ymin); - /** - * Stop dragging operation - * @param {event} event - * @private - */ - Range.prototype._onDragEnd = function (event) { - // only allow dragging when configured as movable - if (!this.options.moveable) return; + //var width = (dotSize / 2 + (1-f) * dotSize * 2); // Todo: put this in one function + var hue = f * 240; + var color = this._hsv2rgb(hue, 1, 1); - // refuse to drag when we where pinching to prevent the timeline make a jump - // when releasing the fingers in opposite order from the touch screen - if (!this.props.touch.allowDragging) return; + ctx.strokeStyle = color; + ctx.beginPath(); + ctx.moveTo(left, top + y); + ctx.lineTo(right, top + y); + ctx.stroke(); + } - this.props.touch.dragging = false; - if (this.body.dom.root) { - this.body.dom.root.style.cursor = 'auto'; + ctx.strokeStyle = this.colorAxis; + ctx.strokeRect(left, top, widthMax, height); } - // fire a rangechanged event - this.body.emitter.emit('rangechanged', { - start: new Date(this.start), - end: new Date(this.end), - byUser: true - }); - }; - - /** - * Event handler for mouse wheel event, used to zoom - * Code from http://adomas.org/javascript-mouse-wheel/ - * @param {Event} event - * @private - */ - Range.prototype._onMouseWheel = function(event) { - // only allow zooming when configured as zoomable and moveable - if (!(this.options.zoomable && this.options.moveable)) return; - - // retrieve delta - var delta = 0; - if (event.wheelDelta) { /* IE/Opera. */ - delta = event.wheelDelta / 120; - } else if (event.detail) { /* Mozilla case. */ - // In Mozilla, sign of delta is different than in IE. - // Also, delta is multiple of 3. - delta = -event.detail / 3; + if (this.style === Graph3d.STYLE.DOTSIZE) { + // draw border around color bar + ctx.strokeStyle = this.colorAxis; + ctx.fillStyle = this.colorDot; + ctx.beginPath(); + ctx.moveTo(left, top); + ctx.lineTo(right, top); + ctx.lineTo(right - widthMax + widthMin, bottom); + ctx.lineTo(left, bottom); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); } - // If delta is nonzero, handle it. - // Basically, delta is now positive if wheel was scrolled up, - // and negative, if wheel was scrolled down. - if (delta) { - // perform the zoom action. Delta is normally 1 or -1 - - // adjust a negative delta such that zooming in with delta 0.1 - // equals zooming out with a delta -0.1 - var scale; - if (delta < 0) { - scale = 1 - (delta / 5); - } - else { - scale = 1 / (1 + (delta / 5)) ; + if (this.style === Graph3d.STYLE.DOTCOLOR || + this.style === Graph3d.STYLE.DOTSIZE) { + // print values along the color bar + var gridLineLen = 5; // px + var step = new StepNumber(this.valueMin, this.valueMax, (this.valueMax-this.valueMin)/5, true); + step.start(); + if (step.getCurrent() < this.valueMin) { + step.next(); } + while (!step.end()) { + y = bottom - (step.getCurrent() - this.valueMin) / (this.valueMax - this.valueMin) * height; - // calculate center, the date to zoom around - var gesture = hammerUtil.fakeGesture(this, event), - pointer = getPointer(gesture.center, this.body.dom.center), - pointerDate = this._pointerToDate(pointer); - - this.zoom(scale, pointerDate, delta); - } + ctx.beginPath(); + ctx.moveTo(left - gridLineLen, y); + ctx.lineTo(left, y); + ctx.stroke(); - // Prevent default actions caused by mouse wheel - // (else the page and timeline both zoom and scroll) - event.preventDefault(); - }; + ctx.textAlign = 'right'; + ctx.textBaseline = 'middle'; + ctx.fillStyle = this.colorAxis; + ctx.fillText(step.getCurrent(), left - 2 * gridLineLen, y); - /** - * Start of a touch gesture - * @private - */ - Range.prototype._onTouch = function (event) { - this.props.touch.start = this.start; - this.props.touch.end = this.end; - this.props.touch.allowDragging = true; - this.props.touch.center = null; - this.scaleOffset = 0; - this.deltaDifference = 0; - }; + step.next(); + } - /** - * On start of a hold gesture - * @private - */ - Range.prototype._onHold = function () { - this.props.touch.allowDragging = false; + ctx.textAlign = 'right'; + ctx.textBaseline = 'top'; + var label = this.legendLabel; + ctx.fillText(label, right, bottom + this.margin); + } }; /** - * Handle pinch event - * @param {Event} event - * @private + * Redraw the filter */ - Range.prototype._onPinch = function (event) { - // only allow zooming when configured as zoomable and moveable - if (!(this.options.zoomable && this.options.moveable)) return; - - this.props.touch.allowDragging = false; - - if (event.gesture.touches.length > 1) { - if (!this.props.touch.center) { - this.props.touch.center = getPointer(event.gesture.center, this.body.dom.center); - } - - var scale = 1 / (event.gesture.scale + this.scaleOffset); - var centerDate = this._pointerToDate(this.props.touch.center); + Graph3d.prototype._redrawFilter = function() { + this.frame.filter.innerHTML = ''; - var hiddenDuration = DateUtil.getHiddenDurationBetween(this.body.hiddenDates, this.start, this.end); - var hiddenDurationBefore = DateUtil.getHiddenDurationBefore(this.body.hiddenDates, this, centerDate); - var hiddenDurationAfter = hiddenDuration - hiddenDurationBefore; + if (this.dataFilter) { + var options = { + 'visible': this.showAnimationControls + }; + var slider = new Slider(this.frame.filter, options); + this.frame.filter.slider = slider; - // calculate new start and end - var newStart = (centerDate - hiddenDurationBefore) + (this.props.touch.start - (centerDate - hiddenDurationBefore)) * scale; - var newEnd = (centerDate + hiddenDurationAfter) + (this.props.touch.end - (centerDate + hiddenDurationAfter)) * scale; + // TODO: css here is not nice here... + this.frame.filter.style.padding = '10px'; + //this.frame.filter.style.backgroundColor = '#EFEFEF'; - // snapping times away from hidden zones - this.startToFront = 1 - scale > 0 ? false : true; // used to do the right autocorrection with periodic hidden times - this.endToFront = scale - 1 > 0 ? false : true; // used to do the right autocorrection with periodic hidden times + slider.setValues(this.dataFilter.values); + slider.setPlayInterval(this.animationInterval); - var safeStart = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newStart, 1 - scale, true); - var safeEnd = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newEnd, scale - 1, true); - if (safeStart != newStart || safeEnd != newEnd) { - this.props.touch.start = safeStart; - this.props.touch.end = safeEnd; - this.scaleOffset = 1 - event.gesture.scale; - newStart = safeStart; - newEnd = safeEnd; - } + // create an event handler + var me = this; + var onchange = function () { + var index = slider.getIndex(); - this.setRange(newStart, newEnd, false, true); + me.dataFilter.selectValue(index); + me.dataPoints = me.dataFilter._getDataPoints(); - this.startToFront = false; // revert to default - this.endToFront = true; // revert to default + me.redraw(); + }; + slider.setOnChangeCallback(onchange); + } + else { + this.frame.filter.slider = undefined; } }; /** - * Helper function to calculate the center date for zooming - * @param {{x: Number, y: Number}} pointer - * @return {number} date - * @private + * Redraw the slider */ - Range.prototype._pointerToDate = function (pointer) { - var conversion; - var direction = this.options.direction; - - validateDirection(direction); - - if (direction == 'horizontal') { - return this.body.util.toTime(pointer.x).valueOf(); - } - else { - var height = this.body.domProps.center.height; - conversion = this.conversion(height); - return pointer.y / conversion.scale + conversion.offset; + Graph3d.prototype._redrawSlider = function() { + if ( this.frame.filter.slider !== undefined) { + this.frame.filter.slider.redraw(); } }; - /** - * Get the pointer location relative to the location of the dom element - * @param {{pageX: Number, pageY: Number}} touch - * @param {Element} element HTML DOM element - * @return {{x: Number, y: Number}} pointer - * @private - */ - function getPointer (touch, element) { - return { - x: touch.pageX - util.getAbsoluteLeft(element), - y: touch.pageY - util.getAbsoluteTop(element) - }; - } /** - * Zoom the range the given scale in or out. Start and end date will - * be adjusted, and the timeline will be redrawn. You can optionally give a - * date around which to zoom. - * For example, try scale = 0.9 or 1.1 - * @param {Number} scale Scaling factor. Values above 1 will zoom out, - * values below 1 will zoom in. - * @param {Number} [center] Value representing a date around which will - * be zoomed. + * Redraw common information */ - Range.prototype.zoom = function(scale, center, delta) { - // if centerDate is not provided, take it half between start Date and end Date - if (center == null) { - center = (this.start + this.end) / 2; - } - - var hiddenDuration = DateUtil.getHiddenDurationBetween(this.body.hiddenDates, this.start, this.end); - var hiddenDurationBefore = DateUtil.getHiddenDurationBefore(this.body.hiddenDates, this, center); - var hiddenDurationAfter = hiddenDuration - hiddenDurationBefore; + Graph3d.prototype._redrawInfo = function() { + if (this.dataFilter) { + var canvas = this.frame.canvas; + var ctx = canvas.getContext('2d'); - // calculate new start and end - var newStart = (center-hiddenDurationBefore) + (this.start - (center-hiddenDurationBefore)) * scale; - var newEnd = (center+hiddenDurationAfter) + (this.end - (center+hiddenDurationAfter)) * scale; + ctx.font = '14px arial'; // TODO: put in options + ctx.lineStyle = 'gray'; + ctx.fillStyle = 'gray'; + ctx.textAlign = 'left'; + ctx.textBaseline = 'top'; - // snapping times away from hidden zones - this.startToFront = delta > 0 ? false : true; // used to do the right autocorrection with periodic hidden times - this.endToFront = -delta > 0 ? false : true; // used to do the right autocorrection with periodic hidden times - var safeStart = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newStart, delta, true); - var safeEnd = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newEnd, -delta, true); - if (safeStart != newStart || safeEnd != newEnd) { - newStart = safeStart; - newEnd = safeEnd; + var x = this.margin; + var y = this.margin; + ctx.fillText(this.dataFilter.getLabel() + ': ' + this.dataFilter.getSelectedValue(), x, y); } - - this.setRange(newStart, newEnd, false, true); - - this.startToFront = false; // revert to default - this.endToFront = true; // revert to default }; - /** - * Move the range with a given delta to the left or right. Start and end - * value will be adjusted. For example, try delta = 0.1 or -0.1 - * @param {Number} delta Moving amount. Positive value will move right, - * negative value will move left + * Redraw the axis */ - Range.prototype.move = function(delta) { - // zoom start Date and end Date relative to the centerDate - var diff = (this.end - this.start); - - // apply new values - var newStart = this.start + diff * delta; - var newEnd = this.end + diff * delta; + Graph3d.prototype._redrawAxis = function() { + var canvas = this.frame.canvas, + ctx = canvas.getContext('2d'), + from, to, step, prettyStep, + text, xText, yText, zText, + offset, xOffset, yOffset, + xMin2d, xMax2d; - // TODO: reckon with min and max range + // TODO: get the actual rendered style of the containerElement + //ctx.font = this.containerElement.style.font; + ctx.font = 24 / this.camera.getArmLength() + 'px arial'; - this.start = newStart; - this.end = newEnd; - }; + // calculate the length for the short grid lines + var gridLenX = 0.025 / this.scale.x; + var gridLenY = 0.025 / this.scale.y; + var textMargin = 5 / this.camera.getArmLength(); // px + var armAngle = this.camera.getArmRotation().horizontal; - /** - * Move the range to a new center point - * @param {Number} moveTo New center point of the range - */ - Range.prototype.moveTo = function(moveTo) { - var center = (this.start + this.end) / 2; + // draw x-grid lines + ctx.lineWidth = 1; + prettyStep = (this.defaultXStep === undefined); + step = new StepNumber(this.xMin, this.xMax, this.xStep, prettyStep); + step.start(); + if (step.getCurrent() < this.xMin) { + step.next(); + } + while (!step.end()) { + var x = step.getCurrent(); - var diff = center - moveTo; + if (this.showGrid) { + from = this._convert3Dto2D(new Point3d(x, this.yMin, this.zMin)); + to = this._convert3Dto2D(new Point3d(x, this.yMax, this.zMin)); + ctx.strokeStyle = this.colorGrid; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + ctx.stroke(); + } + else { + from = this._convert3Dto2D(new Point3d(x, this.yMin, this.zMin)); + to = this._convert3Dto2D(new Point3d(x, this.yMin+gridLenX, this.zMin)); + ctx.strokeStyle = this.colorAxis; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + ctx.stroke(); - // calculate new start and end - var newStart = this.start - diff; - var newEnd = this.end - diff; + from = this._convert3Dto2D(new Point3d(x, this.yMax, this.zMin)); + to = this._convert3Dto2D(new Point3d(x, this.yMax-gridLenX, this.zMin)); + ctx.strokeStyle = this.colorAxis; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + ctx.stroke(); + } - this.setRange(newStart, newEnd); - }; + yText = (Math.cos(armAngle) > 0) ? this.yMin : this.yMax; + text = this._convert3Dto2D(new Point3d(x, yText, this.zMin)); + if (Math.cos(armAngle * 2) > 0) { + ctx.textAlign = 'center'; + ctx.textBaseline = 'top'; + text.y += textMargin; + } + else if (Math.sin(armAngle * 2) < 0){ + ctx.textAlign = 'right'; + ctx.textBaseline = 'middle'; + } + else { + ctx.textAlign = 'left'; + ctx.textBaseline = 'middle'; + } + ctx.fillStyle = this.colorAxis; + ctx.fillText(' ' + this.xValueLabel(step.getCurrent()) + ' ', text.x, text.y); - module.exports = Range; + step.next(); + } + // draw y-grid lines + ctx.lineWidth = 1; + prettyStep = (this.defaultYStep === undefined); + step = new StepNumber(this.yMin, this.yMax, this.yStep, prettyStep); + step.start(); + if (step.getCurrent() < this.yMin) { + step.next(); + } + while (!step.end()) { + if (this.showGrid) { + from = this._convert3Dto2D(new Point3d(this.xMin, step.getCurrent(), this.zMin)); + to = this._convert3Dto2D(new Point3d(this.xMax, step.getCurrent(), this.zMin)); + ctx.strokeStyle = this.colorGrid; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + ctx.stroke(); + } + else { + from = this._convert3Dto2D(new Point3d(this.xMin, step.getCurrent(), this.zMin)); + to = this._convert3Dto2D(new Point3d(this.xMin+gridLenY, step.getCurrent(), this.zMin)); + ctx.strokeStyle = this.colorAxis; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + ctx.stroke(); -/***/ }, -/* 18 */ -/***/ function(module, exports, __webpack_require__) { + from = this._convert3Dto2D(new Point3d(this.xMax, step.getCurrent(), this.zMin)); + to = this._convert3Dto2D(new Point3d(this.xMax-gridLenY, step.getCurrent(), this.zMin)); + ctx.strokeStyle = this.colorAxis; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + ctx.stroke(); + } - // Utility functions for ordering and stacking of items - var EPSILON = 0.001; // used when checking collisions, to prevent round-off errors + xText = (Math.sin(armAngle ) > 0) ? this.xMin : this.xMax; + text = this._convert3Dto2D(new Point3d(xText, step.getCurrent(), this.zMin)); + if (Math.cos(armAngle * 2) < 0) { + ctx.textAlign = 'center'; + ctx.textBaseline = 'top'; + text.y += textMargin; + } + else if (Math.sin(armAngle * 2) > 0){ + ctx.textAlign = 'right'; + ctx.textBaseline = 'middle'; + } + else { + ctx.textAlign = 'left'; + ctx.textBaseline = 'middle'; + } + ctx.fillStyle = this.colorAxis; + ctx.fillText(' ' + this.yValueLabel(step.getCurrent()) + ' ', text.x, text.y); - /** - * Order items by their start data - * @param {Item[]} items - */ - exports.orderByStart = function(items) { - items.sort(function (a, b) { - return a.data.start - b.data.start; - }); - }; + step.next(); + } - /** - * Order items by their end date. If they have no end date, their start date - * is used. - * @param {Item[]} items - */ - exports.orderByEnd = function(items) { - items.sort(function (a, b) { - var aTime = ('end' in a.data) ? a.data.end : a.data.start, - bTime = ('end' in b.data) ? b.data.end : b.data.start; - - return aTime - bTime; - }); - }; + // draw z-grid lines and axis + ctx.lineWidth = 1; + prettyStep = (this.defaultZStep === undefined); + step = new StepNumber(this.zMin, this.zMax, this.zStep, prettyStep); + step.start(); + if (step.getCurrent() < this.zMin) { + step.next(); + } + xText = (Math.cos(armAngle ) > 0) ? this.xMin : this.xMax; + yText = (Math.sin(armAngle ) < 0) ? this.yMin : this.yMax; + while (!step.end()) { + // TODO: make z-grid lines really 3d? + from = this._convert3Dto2D(new Point3d(xText, yText, step.getCurrent())); + ctx.strokeStyle = this.colorAxis; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(from.x - textMargin, from.y); + ctx.stroke(); - /** - * Adjust vertical positions of the items such that they don't overlap each - * other. - * @param {Item[]} items - * All visible items - * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin - * Margins between items and between items and the axis. - * @param {boolean} [force=false] - * If true, all items will be repositioned. If false (default), only - * items having a top===null will be re-stacked - */ - exports.stack = function(items, margin, force) { - var i, iMax; + ctx.textAlign = 'right'; + ctx.textBaseline = 'middle'; + ctx.fillStyle = this.colorAxis; + ctx.fillText(this.zValueLabel(step.getCurrent()) + ' ', from.x - 5, from.y); - if (force) { - // reset top position of all items - for (i = 0, iMax = items.length; i < iMax; i++) { - items[i].top = null; - } + step.next(); } + ctx.lineWidth = 1; + from = this._convert3Dto2D(new Point3d(xText, yText, this.zMin)); + to = this._convert3Dto2D(new Point3d(xText, yText, this.zMax)); + ctx.strokeStyle = this.colorAxis; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + ctx.stroke(); - // calculate new, non-overlapping positions - for (i = 0, iMax = items.length; i < iMax; i++) { - var item = items[i]; - if (item.stack && item.top === null) { - // initialize top position - item.top = margin.axis; + // draw x-axis + ctx.lineWidth = 1; + // line at yMin + xMin2d = this._convert3Dto2D(new Point3d(this.xMin, this.yMin, this.zMin)); + xMax2d = this._convert3Dto2D(new Point3d(this.xMax, this.yMin, this.zMin)); + ctx.strokeStyle = this.colorAxis; + ctx.beginPath(); + ctx.moveTo(xMin2d.x, xMin2d.y); + ctx.lineTo(xMax2d.x, xMax2d.y); + ctx.stroke(); + // line at ymax + xMin2d = this._convert3Dto2D(new Point3d(this.xMin, this.yMax, this.zMin)); + xMax2d = this._convert3Dto2D(new Point3d(this.xMax, this.yMax, this.zMin)); + ctx.strokeStyle = this.colorAxis; + ctx.beginPath(); + ctx.moveTo(xMin2d.x, xMin2d.y); + ctx.lineTo(xMax2d.x, xMax2d.y); + ctx.stroke(); - do { - // TODO: optimize checking for overlap. when there is a gap without items, - // you only need to check for items from the next item on, not from zero - var collidingItem = null; - for (var j = 0, jj = items.length; j < jj; j++) { - var other = items[j]; - if (other.top !== null && other !== item && other.stack && exports.collision(item, other, margin.item)) { - collidingItem = other; - break; - } - } + // draw y-axis + ctx.lineWidth = 1; + // line at xMin + from = this._convert3Dto2D(new Point3d(this.xMin, this.yMin, this.zMin)); + to = this._convert3Dto2D(new Point3d(this.xMin, this.yMax, this.zMin)); + ctx.strokeStyle = this.colorAxis; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + ctx.stroke(); + // line at xMax + from = this._convert3Dto2D(new Point3d(this.xMax, this.yMin, this.zMin)); + to = this._convert3Dto2D(new Point3d(this.xMax, this.yMax, this.zMin)); + ctx.strokeStyle = this.colorAxis; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + ctx.stroke(); - if (collidingItem != null) { - // There is a collision. Reposition the items above the colliding element - item.top = collidingItem.top + collidingItem.height + margin.item.vertical; - } - } while (collidingItem); + // draw x-label + var xLabel = this.xLabel; + if (xLabel.length > 0) { + yOffset = 0.1 / this.scale.y; + xText = (this.xMin + this.xMax) / 2; + yText = (Math.cos(armAngle) > 0) ? this.yMin - yOffset: this.yMax + yOffset; + text = this._convert3Dto2D(new Point3d(xText, yText, this.zMin)); + if (Math.cos(armAngle * 2) > 0) { + ctx.textAlign = 'center'; + ctx.textBaseline = 'top'; } + else if (Math.sin(armAngle * 2) < 0){ + ctx.textAlign = 'right'; + ctx.textBaseline = 'middle'; + } + else { + ctx.textAlign = 'left'; + ctx.textBaseline = 'middle'; + } + ctx.fillStyle = this.colorAxis; + ctx.fillText(xLabel, text.x, text.y); } - }; - - - /** - * Adjust vertical positions of the items without stacking them - * @param {Item[]} items - * All visible items - * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin - * Margins between items and between items and the axis. - */ - exports.nostack = function(items, margin, subgroups) { - var i, iMax, newTop; - // reset top position of all items - for (i = 0, iMax = items.length; i < iMax; i++) { - if (items[i].data.subgroup !== undefined) { - newTop = margin.axis; - for (var subgroup in subgroups) { - if (subgroups.hasOwnProperty(subgroup)) { - if (subgroups[subgroup].visible == true && subgroups[subgroup].index < subgroups[items[i].data.subgroup].index) { - newTop += subgroups[subgroup].height + margin.item.vertical; - } - } - } - items[i].top = newTop; + // draw y-label + var yLabel = this.yLabel; + if (yLabel.length > 0) { + xOffset = 0.1 / this.scale.x; + xText = (Math.sin(armAngle ) > 0) ? this.xMin - xOffset : this.xMax + xOffset; + yText = (this.yMin + this.yMax) / 2; + text = this._convert3Dto2D(new Point3d(xText, yText, this.zMin)); + if (Math.cos(armAngle * 2) < 0) { + ctx.textAlign = 'center'; + ctx.textBaseline = 'top'; + } + else if (Math.sin(armAngle * 2) > 0){ + ctx.textAlign = 'right'; + ctx.textBaseline = 'middle'; } else { - items[i].top = margin.axis; + ctx.textAlign = 'left'; + ctx.textBaseline = 'middle'; } + ctx.fillStyle = this.colorAxis; + ctx.fillText(yLabel, text.x, text.y); + } + + // draw z-label + var zLabel = this.zLabel; + if (zLabel.length > 0) { + offset = 30; // pixels. // TODO: relate to the max width of the values on the z axis? + xText = (Math.cos(armAngle ) > 0) ? this.xMin : this.xMax; + yText = (Math.sin(armAngle ) < 0) ? this.yMin : this.yMax; + zText = (this.zMin + this.zMax) / 2; + text = this._convert3Dto2D(new Point3d(xText, yText, zText)); + ctx.textAlign = 'right'; + ctx.textBaseline = 'middle'; + ctx.fillStyle = this.colorAxis; + ctx.fillText(zLabel, text.x - offset, text.y); } }; /** - * Test if the two provided items collide - * The items must have parameters left, width, top, and height. - * @param {Item} a The first item - * @param {Item} b The second item - * @param {{horizontal: number, vertical: number}} margin - * An object containing a horizontal and vertical - * minimum required margin. - * @return {boolean} true if a and b collide, else false + * Calculate the color based on the given value. + * @param {Number} H Hue, a value be between 0 and 360 + * @param {Number} S Saturation, a value between 0 and 1 + * @param {Number} V Value, a value between 0 and 1 */ - exports.collision = function(a, b, margin) { - return ((a.left - margin.horizontal + EPSILON) < (b.left + b.width) && - (a.left + a.width + margin.horizontal - EPSILON) > b.left && - (a.top - margin.vertical + EPSILON) < (b.top + b.height) && - (a.top + a.height + margin.vertical - EPSILON) > b.top); - }; + Graph3d.prototype._hsv2rgb = function(H, S, V) { + var R, G, B, C, Hi, X; + C = V * S; + Hi = Math.floor(H/60); // hi = 0,1,2,3,4,5 + X = C * (1 - Math.abs(((H/60) % 2) - 1)); -/***/ }, -/* 19 */ -/***/ function(module, exports, __webpack_require__) { + switch (Hi) { + case 0: R = C; G = X; B = 0; break; + case 1: R = X; G = C; B = 0; break; + case 2: R = 0; G = C; B = X; break; + case 3: R = 0; G = X; B = C; break; + case 4: R = X; G = 0; B = C; break; + case 5: R = C; G = 0; B = X; break; + + default: R = 0; G = 0; B = 0; break; + } + + return 'RGB(' + parseInt(R*255) + ',' + parseInt(G*255) + ',' + parseInt(B*255) + ')'; + }; - var moment = __webpack_require__(44); - var DateUtil = __webpack_require__(15); - var util = __webpack_require__(1); /** - * @constructor TimeStep - * The class TimeStep is an iterator for dates. You provide a start date and an - * end date. The class itself determines the best scale (step size) based on the - * provided start Date, end Date, and minimumStep. - * - * If minimumStep is provided, the step size is chosen as close as possible - * to the minimumStep but larger than minimumStep. If minimumStep is not - * provided, the scale is set to 1 DAY. - * The minimumStep should correspond with the onscreen size of about 6 characters - * - * Alternatively, you can set a scale by hand. - * After creation, you can initialize the class by executing first(). Then you - * can iterate from the start date to the end date via next(). You can check if - * the end date is reached with the function hasNext(). After each step, you can - * retrieve the current date via getCurrent(). - * The TimeStep has scales ranging from milliseconds, seconds, minutes, hours, - * days, to years. - * - * Version: 1.2 - * - * @param {Date} [start] The start date, for example new Date(2010, 9, 21) - * or new Date(2010, 9, 21, 23, 45, 00) - * @param {Date} [end] The end date - * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds + * Draw all datapoints as a grid + * This function can be used when the style is 'grid' */ - function TimeStep(start, end, minimumStep, hiddenDates) { - // variables - this.current = new Date(); - this._start = new Date(); - this._end = new Date(); + Graph3d.prototype._redrawDataGrid = function() { + var canvas = this.frame.canvas, + ctx = canvas.getContext('2d'), + point, right, top, cross, + i, + topSideVisible, fillStyle, strokeStyle, lineWidth, + h, s, v, zAvg; - this.autoScale = true; - this.scale = 'day'; - this.step = 1; - // initialize the range - this.setRange(start, end, minimumStep); + if (this.dataPoints === undefined || this.dataPoints.length <= 0) + return; // TODO: throw exception? - // hidden Dates options - this.switchedDay = false; - this.switchedMonth = false; - this.switchedYear = false; - this.hiddenDates = hiddenDates; - if (hiddenDates === undefined) { - this.hiddenDates = []; - } + // calculate the translations and screen position of all points + for (i = 0; i < this.dataPoints.length; i++) { + var trans = this._convertPointToTranslation(this.dataPoints[i].point); + var screen = this._convertTranslationToScreen(trans); - this.format = TimeStep.FORMAT; // default formatting - } + this.dataPoints[i].trans = trans; + this.dataPoints[i].screen = screen; - // Time formatting - TimeStep.FORMAT = { - minorLabels: { - millisecond:'SSS', - second: 's', - minute: 'HH:mm', - hour: 'HH:mm', - weekday: 'ddd D', - day: 'D', - month: 'MMM', - year: 'YYYY' - }, - majorLabels: { - millisecond:'HH:mm:ss', - second: 'D MMMM HH:mm', - minute: 'ddd D MMMM', - hour: 'ddd D MMMM', - weekday: 'MMMM YYYY', - day: 'MMMM YYYY', - month: 'YYYY', - year: '' + // calculate the translation of the point at the bottom (needed for sorting) + var transBottom = this._convertPointToTranslation(this.dataPoints[i].bottom); + this.dataPoints[i].dist = this.showPerspective ? transBottom.length() : -transBottom.z; } - }; - /** - * Set custom formatting for the minor an major labels of the TimeStep. - * Both `minorLabels` and `majorLabels` are an Object with properties: - * 'millisecond, 'second, 'minute', 'hour', 'weekday, 'day, 'month, 'year'. - * @param {{minorLabels: Object, majorLabels: Object}} format - */ - TimeStep.prototype.setFormat = function (format) { - var defaultFormat = util.deepExtend({}, TimeStep.FORMAT); - this.format = util.deepExtend(defaultFormat, format); - }; + // sort the points on depth of their (x,y) position (not on z) + var sortDepth = function (a, b) { + return b.dist - a.dist; + }; + this.dataPoints.sort(sortDepth); - /** - * Set a new range - * If minimumStep is provided, the step size is chosen as close as possible - * to the minimumStep but larger than minimumStep. If minimumStep is not - * provided, the scale is set to 1 DAY. - * The minimumStep should correspond with the onscreen size of about 6 characters - * @param {Date} [start] The start date and time. - * @param {Date} [end] The end date and time. - * @param {int} [minimumStep] Optional. Minimum step size in milliseconds - */ - TimeStep.prototype.setRange = function(start, end, minimumStep) { - if (!(start instanceof Date) || !(end instanceof Date)) { - throw "No legal start or end date in method setRange"; - } + if (this.style === Graph3d.STYLE.SURFACE) { + for (i = 0; i < this.dataPoints.length; i++) { + point = this.dataPoints[i]; + right = this.dataPoints[i].pointRight; + top = this.dataPoints[i].pointTop; + cross = this.dataPoints[i].pointCross; - this._start = (start != undefined) ? new Date(start.valueOf()) : new Date(); - this._end = (end != undefined) ? new Date(end.valueOf()) : new Date(); + if (point !== undefined && right !== undefined && top !== undefined && cross !== undefined) { - if (this.autoScale) { - this.setMinimumStep(minimumStep); - } - }; + if (this.showGrayBottom || this.showShadow) { + // calculate the cross product of the two vectors from center + // to left and right, in order to know whether we are looking at the + // bottom or at the top side. We can also use the cross product + // for calculating light intensity + var aDiff = Point3d.subtract(cross.trans, point.trans); + var bDiff = Point3d.subtract(top.trans, right.trans); + var crossproduct = Point3d.crossProduct(aDiff, bDiff); + var len = crossproduct.length(); + // FIXME: there is a bug with determining the surface side (shadow or colored) - /** - * Set the range iterator to the start date. - */ - TimeStep.prototype.first = function() { - this.current = new Date(this._start.valueOf()); - this.roundToMinor(); - }; + topSideVisible = (crossproduct.z > 0); + } + else { + topSideVisible = true; + } - /** - * Round the current date to the first minor date value - * This must be executed once when the current date is set to start Date - */ - TimeStep.prototype.roundToMinor = function() { - // round to floor - // IMPORTANT: we have no breaks in this switch! (this is no bug) - // noinspection FallThroughInSwitchStatementJS - switch (this.scale) { - case 'year': - this.current.setFullYear(this.step * Math.floor(this.current.getFullYear() / this.step)); - this.current.setMonth(0); - case 'month': this.current.setDate(1); - case 'day': // intentional fall through - case 'weekday': this.current.setHours(0); - case 'hour': this.current.setMinutes(0); - case 'minute': this.current.setSeconds(0); - case 'second': this.current.setMilliseconds(0); - //case 'millisecond': // nothing to do for milliseconds + if (topSideVisible) { + // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 + zAvg = (point.point.z + right.point.z + top.point.z + cross.point.z) / 4; + h = (1 - (zAvg - this.zMin) * this.scale.z / this.verticalRatio) * 240; + s = 1; // saturation + + if (this.showShadow) { + v = Math.min(1 + (crossproduct.x / len) / 2, 1); // value. TODO: scale + fillStyle = this._hsv2rgb(h, s, v); + strokeStyle = fillStyle; + } + else { + v = 1; + fillStyle = this._hsv2rgb(h, s, v); + strokeStyle = this.colorAxis; + } + } + else { + fillStyle = 'gray'; + strokeStyle = this.colorAxis; + } + lineWidth = 0.5; + + ctx.lineWidth = lineWidth; + ctx.fillStyle = fillStyle; + ctx.strokeStyle = strokeStyle; + ctx.beginPath(); + ctx.moveTo(point.screen.x, point.screen.y); + ctx.lineTo(right.screen.x, right.screen.y); + ctx.lineTo(cross.screen.x, cross.screen.y); + ctx.lineTo(top.screen.x, top.screen.y); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + } + } } + else { // grid style + for (i = 0; i < this.dataPoints.length; i++) { + point = this.dataPoints[i]; + right = this.dataPoints[i].pointRight; + top = this.dataPoints[i].pointTop; - if (this.step != 1) { - // round down to the first minor value that is a multiple of the current step size - switch (this.scale) { - case 'millisecond': this.current.setMilliseconds(this.current.getMilliseconds() - this.current.getMilliseconds() % this.step); break; - case 'second': this.current.setSeconds(this.current.getSeconds() - this.current.getSeconds() % this.step); break; - case 'minute': this.current.setMinutes(this.current.getMinutes() - this.current.getMinutes() % this.step); break; - case 'hour': this.current.setHours(this.current.getHours() - this.current.getHours() % this.step); break; - case 'weekday': // intentional fall through - case 'day': this.current.setDate((this.current.getDate()-1) - (this.current.getDate()-1) % this.step + 1); break; - case 'month': this.current.setMonth(this.current.getMonth() - this.current.getMonth() % this.step); break; - case 'year': this.current.setFullYear(this.current.getFullYear() - this.current.getFullYear() % this.step); break; - default: break; + if (point !== undefined) { + if (this.showPerspective) { + lineWidth = 2 / -point.trans.z; + } + else { + lineWidth = 2 * -(this.eye.z / this.camera.getArmLength()); + } + } + + if (point !== undefined && right !== undefined) { + // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 + zAvg = (point.point.z + right.point.z) / 2; + h = (1 - (zAvg - this.zMin) * this.scale.z / this.verticalRatio) * 240; + + ctx.lineWidth = lineWidth; + ctx.strokeStyle = this._hsv2rgb(h, 1, 1); + ctx.beginPath(); + ctx.moveTo(point.screen.x, point.screen.y); + ctx.lineTo(right.screen.x, right.screen.y); + ctx.stroke(); + } + + if (point !== undefined && top !== undefined) { + // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 + zAvg = (point.point.z + top.point.z) / 2; + h = (1 - (zAvg - this.zMin) * this.scale.z / this.verticalRatio) * 240; + + ctx.lineWidth = lineWidth; + ctx.strokeStyle = this._hsv2rgb(h, 1, 1); + ctx.beginPath(); + ctx.moveTo(point.screen.x, point.screen.y); + ctx.lineTo(top.screen.x, top.screen.y); + ctx.stroke(); + } } } }; - /** - * Check if the there is a next step - * @return {boolean} true if the current date has not passed the end date - */ - TimeStep.prototype.hasNext = function () { - return (this.current.valueOf() <= this._end.valueOf()); - }; /** - * Do the next step + * Draw all datapoints as dots. + * This function can be used when the style is 'dot' or 'dot-line' */ - TimeStep.prototype.next = function() { - var prev = this.current.valueOf(); + Graph3d.prototype._redrawDataDot = function() { + var canvas = this.frame.canvas; + var ctx = canvas.getContext('2d'); + var i; - // Two cases, needed to prevent issues with switching daylight savings - // (end of March and end of October) - if (this.current.getMonth() < 6) { - switch (this.scale) { - case 'millisecond': - - this.current = new Date(this.current.valueOf() + this.step); break; - case 'second': this.current = new Date(this.current.valueOf() + this.step * 1000); break; - case 'minute': this.current = new Date(this.current.valueOf() + this.step * 1000 * 60); break; - case 'hour': - this.current = new Date(this.current.valueOf() + this.step * 1000 * 60 * 60); - // in case of skipping an hour for daylight savings, adjust the hour again (else you get: 0h 5h 9h ... instead of 0h 4h 8h ...) - var h = this.current.getHours(); - this.current.setHours(h - (h % this.step)); - break; - case 'weekday': // intentional fall through - case 'day': this.current.setDate(this.current.getDate() + this.step); break; - case 'month': this.current.setMonth(this.current.getMonth() + this.step); break; - case 'year': this.current.setFullYear(this.current.getFullYear() + this.step); break; - default: break; - } - } - else { - switch (this.scale) { - case 'millisecond': this.current = new Date(this.current.valueOf() + this.step); break; - case 'second': this.current.setSeconds(this.current.getSeconds() + this.step); break; - case 'minute': this.current.setMinutes(this.current.getMinutes() + this.step); break; - case 'hour': this.current.setHours(this.current.getHours() + this.step); break; - case 'weekday': // intentional fall through - case 'day': this.current.setDate(this.current.getDate() + this.step); break; - case 'month': this.current.setMonth(this.current.getMonth() + this.step); break; - case 'year': this.current.setFullYear(this.current.getFullYear() + this.step); break; - default: break; - } - } - - if (this.step != 1) { - // round down to the correct major value - switch (this.scale) { - case 'millisecond': if(this.current.getMilliseconds() < this.step) this.current.setMilliseconds(0); break; - case 'second': if(this.current.getSeconds() < this.step) this.current.setSeconds(0); break; - case 'minute': if(this.current.getMinutes() < this.step) this.current.setMinutes(0); break; - case 'hour': if(this.current.getHours() < this.step) this.current.setHours(0); break; - case 'weekday': // intentional fall through - case 'day': if(this.current.getDate() < this.step+1) this.current.setDate(1); break; - case 'month': if(this.current.getMonth() < this.step) this.current.setMonth(0); break; - case 'year': break; // nothing to do for year - default: break; - } - } - - // safety mechanism: if current time is still unchanged, move to the end - if (this.current.valueOf() == prev) { - this.current = new Date(this._end.valueOf()); - } - - DateUtil.stepOverHiddenDates(this, prev); - }; - - - /** - * Get the current datetime - * @return {Date} current The current date - */ - TimeStep.prototype.getCurrent = function() { - return this.current; - }; - - /** - * Set a custom scale. Autoscaling will be disabled. - * For example setScale(SCALE.MINUTES, 5) will result - * in minor steps of 5 minutes, and major steps of an hour. - * - * @param {string} newScale - * A scale. Choose from 'millisecond, 'second, - * 'minute', 'hour', 'weekday, 'day, 'month, 'year'. - * @param {Number} newStep A step size, by default 1. Choose for - * example 1, 2, 5, or 10. - */ - TimeStep.prototype.setScale = function(newScale, newStep) { - this.scale = newScale; - - if (newStep > 0) { - this.step = newStep; - } - - this.autoScale = false; - }; - - /** - * Enable or disable autoscaling - * @param {boolean} enable If true, autoascaling is set true - */ - TimeStep.prototype.setAutoScale = function (enable) { - this.autoScale = enable; - }; + if (this.dataPoints === undefined || this.dataPoints.length <= 0) + return; // TODO: throw exception? + // calculate the translations of all points + for (i = 0; i < this.dataPoints.length; i++) { + var trans = this._convertPointToTranslation(this.dataPoints[i].point); + var screen = this._convertTranslationToScreen(trans); + this.dataPoints[i].trans = trans; + this.dataPoints[i].screen = screen; - /** - * Automatically determine the scale that bests fits the provided minimum step - * @param {Number} [minimumStep] The minimum step size in milliseconds - */ - TimeStep.prototype.setMinimumStep = function(minimumStep) { - if (minimumStep == undefined) { - return; + // calculate the distance from the point at the bottom to the camera + var transBottom = this._convertPointToTranslation(this.dataPoints[i].bottom); + this.dataPoints[i].dist = this.showPerspective ? transBottom.length() : -transBottom.z; } - //var b = asc + ds; - - var stepYear = (1000 * 60 * 60 * 24 * 30 * 12); - var stepMonth = (1000 * 60 * 60 * 24 * 30); - var stepDay = (1000 * 60 * 60 * 24); - var stepHour = (1000 * 60 * 60); - var stepMinute = (1000 * 60); - var stepSecond = (1000); - var stepMillisecond= (1); + // order the translated points by depth + var sortDepth = function (a, b) { + return b.dist - a.dist; + }; + this.dataPoints.sort(sortDepth); - // find the smallest step that is larger than the provided minimumStep - if (stepYear*1000 > minimumStep) {this.scale = 'year'; this.step = 1000;} - if (stepYear*500 > minimumStep) {this.scale = 'year'; this.step = 500;} - if (stepYear*100 > minimumStep) {this.scale = 'year'; this.step = 100;} - if (stepYear*50 > minimumStep) {this.scale = 'year'; this.step = 50;} - if (stepYear*10 > minimumStep) {this.scale = 'year'; this.step = 10;} - if (stepYear*5 > minimumStep) {this.scale = 'year'; this.step = 5;} - if (stepYear > minimumStep) {this.scale = 'year'; this.step = 1;} - if (stepMonth*3 > minimumStep) {this.scale = 'month'; this.step = 3;} - if (stepMonth > minimumStep) {this.scale = 'month'; this.step = 1;} - if (stepDay*5 > minimumStep) {this.scale = 'day'; this.step = 5;} - if (stepDay*2 > minimumStep) {this.scale = 'day'; this.step = 2;} - if (stepDay > minimumStep) {this.scale = 'day'; this.step = 1;} - if (stepDay/2 > minimumStep) {this.scale = 'weekday'; this.step = 1;} - if (stepHour*4 > minimumStep) {this.scale = 'hour'; this.step = 4;} - if (stepHour > minimumStep) {this.scale = 'hour'; this.step = 1;} - if (stepMinute*15 > minimumStep) {this.scale = 'minute'; this.step = 15;} - if (stepMinute*10 > minimumStep) {this.scale = 'minute'; this.step = 10;} - if (stepMinute*5 > minimumStep) {this.scale = 'minute'; this.step = 5;} - if (stepMinute > minimumStep) {this.scale = 'minute'; this.step = 1;} - if (stepSecond*15 > minimumStep) {this.scale = 'second'; this.step = 15;} - if (stepSecond*10 > minimumStep) {this.scale = 'second'; this.step = 10;} - if (stepSecond*5 > minimumStep) {this.scale = 'second'; this.step = 5;} - if (stepSecond > minimumStep) {this.scale = 'second'; this.step = 1;} - if (stepMillisecond*200 > minimumStep) {this.scale = 'millisecond'; this.step = 200;} - if (stepMillisecond*100 > minimumStep) {this.scale = 'millisecond'; this.step = 100;} - if (stepMillisecond*50 > minimumStep) {this.scale = 'millisecond'; this.step = 50;} - if (stepMillisecond*10 > minimumStep) {this.scale = 'millisecond'; this.step = 10;} - if (stepMillisecond*5 > minimumStep) {this.scale = 'millisecond'; this.step = 5;} - if (stepMillisecond > minimumStep) {this.scale = 'millisecond'; this.step = 1;} - }; + // draw the datapoints as colored circles + var dotSize = this.frame.clientWidth * 0.02; // px + for (i = 0; i < this.dataPoints.length; i++) { + var point = this.dataPoints[i]; - /** - * 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 - */ - TimeStep.prototype.snap = function(date) { - var clone = new Date(date.valueOf()); + if (this.style === Graph3d.STYLE.DOTLINE) { + // draw a vertical line from the bottom to the graph value + //var from = this._convert3Dto2D(new Point3d(point.point.x, point.point.y, this.zMin)); + var from = this._convert3Dto2D(point.bottom); + ctx.lineWidth = 1; + ctx.strokeStyle = this.colorGrid; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(point.screen.x, point.screen.y); + ctx.stroke(); + } - if (this.scale == 'year') { - var year = clone.getFullYear() + Math.round(clone.getMonth() / 12); - clone.setFullYear(Math.round(year / this.step) * this.step); - clone.setMonth(0); - clone.setDate(0); - clone.setHours(0); - clone.setMinutes(0); - clone.setSeconds(0); - clone.setMilliseconds(0); - } - else if (this.scale == 'month') { - if (clone.getDate() > 15) { - clone.setDate(1); - clone.setMonth(clone.getMonth() + 1); - // important: first set Date to 1, after that change the month. + // calculate radius for the circle + var size; + if (this.style === Graph3d.STYLE.DOTSIZE) { + size = dotSize/2 + 2*dotSize * (point.point.value - this.valueMin) / (this.valueMax - this.valueMin); } else { - clone.setDate(1); + size = dotSize; } - clone.setHours(0); - clone.setMinutes(0); - clone.setSeconds(0); - clone.setMilliseconds(0); - } - else if (this.scale == 'day') { - //noinspection FallthroughInSwitchStatementJS - switch (this.step) { - case 5: - case 2: - clone.setHours(Math.round(clone.getHours() / 24) * 24); break; - default: - clone.setHours(Math.round(clone.getHours() / 12) * 12); break; - } - clone.setMinutes(0); - clone.setSeconds(0); - clone.setMilliseconds(0); - } - else if (this.scale == 'weekday') { - //noinspection FallthroughInSwitchStatementJS - switch (this.step) { - case 5: - case 2: - clone.setHours(Math.round(clone.getHours() / 12) * 12); break; - default: - clone.setHours(Math.round(clone.getHours() / 6) * 6); break; - } - clone.setMinutes(0); - clone.setSeconds(0); - clone.setMilliseconds(0); - } - else if (this.scale == 'hour') { - switch (this.step) { - case 4: - clone.setMinutes(Math.round(clone.getMinutes() / 60) * 60); break; - default: - clone.setMinutes(Math.round(clone.getMinutes() / 30) * 30); break; + var radius; + if (this.showPerspective) { + radius = size / -point.trans.z; } - clone.setSeconds(0); - clone.setMilliseconds(0); - } else if (this.scale == 'minute') { - //noinspection FallthroughInSwitchStatementJS - switch (this.step) { - case 15: - case 10: - clone.setMinutes(Math.round(clone.getMinutes() / 5) * 5); - clone.setSeconds(0); - break; - case 5: - clone.setSeconds(Math.round(clone.getSeconds() / 60) * 60); break; - default: - clone.setSeconds(Math.round(clone.getSeconds() / 30) * 30); break; + else { + radius = size * -(this.eye.z / this.camera.getArmLength()); } - clone.setMilliseconds(0); - } - else if (this.scale == 'second') { - //noinspection FallthroughInSwitchStatementJS - switch (this.step) { - case 15: - case 10: - clone.setSeconds(Math.round(clone.getSeconds() / 5) * 5); - clone.setMilliseconds(0); - break; - case 5: - clone.setMilliseconds(Math.round(clone.getMilliseconds() / 1000) * 1000); break; - default: - clone.setMilliseconds(Math.round(clone.getMilliseconds() / 500) * 500); break; + if (radius < 0) { + radius = 0; } - } - else if (this.scale == 'millisecond') { - var step = this.step > 5 ? this.step / 2 : 1; - clone.setMilliseconds(Math.round(clone.getMilliseconds() / step) * step); - } - - return clone; - }; - /** - * 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. - */ - TimeStep.prototype.isMajor = function() { - if (this.switchedYear == true) { - this.switchedYear = false; - switch (this.scale) { - case 'year': - case 'month': - case 'weekday': - case 'day': - case 'hour': - case 'minute': - case 'second': - case 'millisecond': - return true; - default: - return false; + var hue, color, borderColor; + if (this.style === Graph3d.STYLE.DOTCOLOR ) { + // calculate the color based on the value + hue = (1 - (point.point.value - this.valueMin) * this.scale.value) * 240; + color = this._hsv2rgb(hue, 1, 1); + borderColor = this._hsv2rgb(hue, 1, 0.8); } - } - else if (this.switchedMonth == true) { - this.switchedMonth = false; - switch (this.scale) { - case 'weekday': - case 'day': - case 'hour': - case 'minute': - case 'second': - case 'millisecond': - return true; - default: - return false; + else if (this.style === Graph3d.STYLE.DOTSIZE) { + color = this.colorDot; + borderColor = this.colorDotBorder; } - } - else if (this.switchedDay == true) { - this.switchedDay = false; - switch (this.scale) { - case 'millisecond': - case 'second': - case 'minute': - case 'hour': - return true; - default: - return false; + else { + // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 + hue = (1 - (point.point.z - this.zMin) * this.scale.z / this.verticalRatio) * 240; + color = this._hsv2rgb(hue, 1, 1); + borderColor = this._hsv2rgb(hue, 1, 0.8); } - } - switch (this.scale) { - case 'millisecond': - return (this.current.getMilliseconds() == 0); - case 'second': - return (this.current.getSeconds() == 0); - case 'minute': - return (this.current.getHours() == 0) && (this.current.getMinutes() == 0); - case 'hour': - return (this.current.getHours() == 0); - case 'weekday': // intentional fall through - case 'day': - return (this.current.getDate() == 1); - case 'month': - return (this.current.getMonth() == 0); - case 'year': - return false; - default: - return false; + // draw the circle + ctx.lineWidth = 1.0; + ctx.strokeStyle = borderColor; + ctx.fillStyle = color; + ctx.beginPath(); + ctx.arc(point.screen.x, point.screen.y, radius, 0, Math.PI*2, true); + ctx.fill(); + ctx.stroke(); } }; - /** - * Returns formatted text for the minor axislabel, depending on the current - * date and the scale. For example when scale is MINUTE, the current time is - * formatted as "hh:mm". - * @param {Date} [date] custom date. if not provided, current date is taken + * Draw all datapoints as bars. + * This function can be used when the style is 'bar', 'bar-color', or 'bar-size' */ - TimeStep.prototype.getLabelMinor = function(date) { - if (date == undefined) { - date = this.current; - } + Graph3d.prototype._redrawDataBar = function() { + var canvas = this.frame.canvas; + var ctx = canvas.getContext('2d'); + var i, j, surface, corners; - var format = this.format.minorLabels[this.scale]; - return (format && format.length > 0) ? moment(date).format(format) : ''; - }; + if (this.dataPoints === undefined || this.dataPoints.length <= 0) + return; // TODO: throw exception? - /** - * Returns formatted text for the major axis label, depending on the current - * date and the scale. For example when scale is MINUTE, the major scale is - * hours, and the hour will be formatted as "hh". - * @param {Date} [date] custom date. if not provided, current date is taken - */ - TimeStep.prototype.getLabelMajor = function(date) { - if (date == undefined) { - date = this.current; - } + // calculate the translations of all points + for (i = 0; i < this.dataPoints.length; i++) { + var trans = this._convertPointToTranslation(this.dataPoints[i].point); + var screen = this._convertTranslationToScreen(trans); + this.dataPoints[i].trans = trans; + this.dataPoints[i].screen = screen; - var format = this.format.majorLabels[this.scale]; - return (format && format.length > 0) ? moment(date).format(format) : ''; - }; + // calculate the distance from the point at the bottom to the camera + var transBottom = this._convertPointToTranslation(this.dataPoints[i].bottom); + this.dataPoints[i].dist = this.showPerspective ? transBottom.length() : -transBottom.z; + } - TimeStep.prototype.getClassName = function() { - var m = moment(this.current); - var date = m.locale ? m.locale('en') : m.lang('en'); // old versions of moment have .lang() function - var step = this.step; + // order the translated points by depth + var sortDepth = function (a, b) { + return b.dist - a.dist; + }; + this.dataPoints.sort(sortDepth); - function even(value) { - return (value / step % 2 == 0) ? ' even' : ' odd'; - } + // draw the datapoints as bars + var xWidth = this.xBarWidth / 2; + var yWidth = this.yBarWidth / 2; + for (i = 0; i < this.dataPoints.length; i++) { + var point = this.dataPoints[i]; - function today(date) { - if (date.isSame(new Date(), 'day')) { - return ' today'; + // determine color + var hue, color, borderColor; + if (this.style === Graph3d.STYLE.BARCOLOR ) { + // calculate the color based on the value + hue = (1 - (point.point.value - this.valueMin) * this.scale.value) * 240; + color = this._hsv2rgb(hue, 1, 1); + borderColor = this._hsv2rgb(hue, 1, 0.8); } - if (date.isSame(moment().add(1, 'day'), 'day')) { - return ' tomorrow'; + else if (this.style === Graph3d.STYLE.BARSIZE) { + color = this.colorDot; + borderColor = this.colorDotBorder; } - if (date.isSame(moment().add(-1, 'day'), 'day')) { - return ' yesterday'; + else { + // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 + hue = (1 - (point.point.z - this.zMin) * this.scale.z / this.verticalRatio) * 240; + color = this._hsv2rgb(hue, 1, 1); + borderColor = this._hsv2rgb(hue, 1, 0.8); } - return ''; - } - function currentWeek(date) { - return date.isSame(new Date(), 'week') ? ' current-week' : ''; - } + // calculate size for the bar + if (this.style === Graph3d.STYLE.BARSIZE) { + xWidth = (this.xBarWidth / 2) * ((point.point.value - this.valueMin) / (this.valueMax - this.valueMin) * 0.8 + 0.2); + yWidth = (this.yBarWidth / 2) * ((point.point.value - this.valueMin) / (this.valueMax - this.valueMin) * 0.8 + 0.2); + } - function currentMonth(date) { - return date.isSame(new Date(), 'month') ? ' current-month' : ''; - } + // calculate all corner points + var me = this; + var point3d = point.point; + var top = [ + {point: new Point3d(point3d.x - xWidth, point3d.y - yWidth, point3d.z)}, + {point: new Point3d(point3d.x + xWidth, point3d.y - yWidth, point3d.z)}, + {point: new Point3d(point3d.x + xWidth, point3d.y + yWidth, point3d.z)}, + {point: new Point3d(point3d.x - xWidth, point3d.y + yWidth, point3d.z)} + ]; + var bottom = [ + {point: new Point3d(point3d.x - xWidth, point3d.y - yWidth, this.zMin)}, + {point: new Point3d(point3d.x + xWidth, point3d.y - yWidth, this.zMin)}, + {point: new Point3d(point3d.x + xWidth, point3d.y + yWidth, this.zMin)}, + {point: new Point3d(point3d.x - xWidth, point3d.y + yWidth, this.zMin)} + ]; - function currentYear(date) { - return date.isSame(new Date(), 'year') ? ' current-year' : ''; - } + // calculate screen location of the points + top.forEach(function (obj) { + obj.screen = me._convert3Dto2D(obj.point); + }); + bottom.forEach(function (obj) { + obj.screen = me._convert3Dto2D(obj.point); + }); - switch (this.scale) { - case 'millisecond': - return even(date.milliseconds()).trim(); + // create five sides, calculate both corner points and center points + var surfaces = [ + {corners: top, center: Point3d.avg(bottom[0].point, bottom[2].point)}, + {corners: [top[0], top[1], bottom[1], bottom[0]], center: Point3d.avg(bottom[1].point, bottom[0].point)}, + {corners: [top[1], top[2], bottom[2], bottom[1]], center: Point3d.avg(bottom[2].point, bottom[1].point)}, + {corners: [top[2], top[3], bottom[3], bottom[2]], center: Point3d.avg(bottom[3].point, bottom[2].point)}, + {corners: [top[3], top[0], bottom[0], bottom[3]], center: Point3d.avg(bottom[0].point, bottom[3].point)} + ]; + point.surfaces = surfaces; - case 'second': - return even(date.seconds()).trim(); + // calculate the distance of each of the surface centers to the camera + for (j = 0; j < surfaces.length; j++) { + surface = surfaces[j]; + var transCenter = this._convertPointToTranslation(surface.center); + surface.dist = this.showPerspective ? transCenter.length() : -transCenter.z; + // TODO: this dept calculation doesn't work 100% of the cases due to perspective, + // but the current solution is fast/simple and works in 99.9% of all cases + // the issue is visible in example 14, with graph.setCameraPosition({horizontal: 2.97, vertical: 0.5, distance: 0.9}) + } - case 'minute': - return even(date.minutes()).trim(); + // order the surfaces by their (translated) depth + surfaces.sort(function (a, b) { + var diff = b.dist - a.dist; + if (diff) return diff; - case 'hour': - var hours = date.hours(); - if (this.step == 4) { - hours = hours + '-' + (hours + 4); - } - return hours + 'h' + today(date) + even(date.hours()); + // if equal depth, sort the top surface last + if (a.corners === top) return 1; + if (b.corners === top) return -1; - case 'weekday': - return date.format('dddd').toLowerCase() + - today(date) + currentWeek(date) + even(date.date()); + // both are equal + return 0; + }); - case 'day': - var day = date.date(); - var month = date.format('MMMM').toLowerCase(); - return 'day' + day + ' ' + month + currentMonth(date) + even(day - 1); + // draw the ordered surfaces + ctx.lineWidth = 1; + ctx.strokeStyle = borderColor; + ctx.fillStyle = color; + // NOTE: we start at j=2 instead of j=0 as we don't need to draw the two surfaces at the backside + for (j = 2; j < surfaces.length; j++) { + surface = surfaces[j]; + corners = surface.corners; + ctx.beginPath(); + ctx.moveTo(corners[3].screen.x, corners[3].screen.y); + ctx.lineTo(corners[0].screen.x, corners[0].screen.y); + ctx.lineTo(corners[1].screen.x, corners[1].screen.y); + ctx.lineTo(corners[2].screen.x, corners[2].screen.y); + ctx.lineTo(corners[3].screen.x, corners[3].screen.y); + ctx.fill(); + ctx.stroke(); + } + } + }; - case 'month': - return date.format('MMMM').toLowerCase() + - currentMonth(date) + even(date.month()); - case 'year': - var year = date.year(); - return 'year' + year + currentYear(date)+ even(year); + /** + * Draw a line through all datapoints. + * This function can be used when the style is 'line' + */ + Graph3d.prototype._redrawDataLine = function() { + var canvas = this.frame.canvas, + ctx = canvas.getContext('2d'), + point, i; - default: - return ''; - } - }; + if (this.dataPoints === undefined || this.dataPoints.length <= 0) + return; // TODO: throw exception? - module.exports = TimeStep; + // calculate the translations of all points + for (i = 0; i < this.dataPoints.length; i++) { + var trans = this._convertPointToTranslation(this.dataPoints[i].point); + var screen = this._convertTranslationToScreen(trans); + this.dataPoints[i].trans = trans; + this.dataPoints[i].screen = screen; + } -/***/ }, -/* 20 */ -/***/ function(module, exports, __webpack_require__) { + // start the line + if (this.dataPoints.length > 0) { + point = this.dataPoints[0]; - /** - * Prototype for visual components - * @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} [body] - * @param {Object} [options] - */ - function Component (body, options) { - this.options = null; - this.props = null; - } + ctx.lineWidth = 1; // TODO: make customizable + ctx.strokeStyle = 'blue'; // TODO: make customizable + ctx.beginPath(); + ctx.moveTo(point.screen.x, point.screen.y); + } - /** - * Set options for the component. The new options will be merged into the - * current options. - * @param {Object} options - */ - Component.prototype.setOptions = function(options) { - if (options) { - util.extend(this.options, options); + // draw the datapoints as colored circles + for (i = 1; i < this.dataPoints.length; i++) { + point = this.dataPoints[i]; + ctx.lineTo(point.screen.x, point.screen.y); } - }; - /** - * Repaint the component - * @return {boolean} Returns true if the component is resized - */ - Component.prototype.redraw = function() { - // should be implemented by the component - return false; + // finish the line + if (this.dataPoints.length > 0) { + ctx.stroke(); + } }; /** - * Destroy the component. Cleanup DOM and event listeners + * Start a moving operation inside the provided parent element + * @param {Event} event The event that occurred (required for + * retrieving the mouse position) */ - Component.prototype.destroy = function() { - // should be implemented by the component - }; + Graph3d.prototype._onMouseDown = function(event) { + event = event || window.event; - /** - * Test whether the component is resized since the last time _isResized() was - * called. - * @return {Boolean} Returns true if the component is resized - * @protected - */ - Component.prototype._isResized = function() { - var resized = (this.props._previousWidth !== this.props.width || - this.props._previousHeight !== this.props.height); + // check if mouse is still down (may be up when focus is lost for example + // in an iframe) + if (this.leftButtonDown) { + this._onMouseUp(event); + } - this.props._previousWidth = this.props.width; - this.props._previousHeight = this.props.height; + // only react on left mouse button down + this.leftButtonDown = event.which ? (event.which === 1) : (event.button === 1); + if (!this.leftButtonDown && !this.touchDown) return; - return resized; - }; + // get mouse position (different code for IE and all other browsers) + this.startMouseX = getMouseX(event); + this.startMouseY = getMouseY(event); - module.exports = Component; + this.startStart = new Date(this.start); + this.startEnd = new Date(this.end); + this.startArmRotation = this.camera.getArmRotation(); + this.frame.style.cursor = 'move'; -/***/ }, -/* 21 */ -/***/ function(module, exports, __webpack_require__) { + // add event listeners to handle moving the contents + // we store the function onmousemove and onmouseup in the graph, so we can + // remove the eventlisteners lateron in the function mouseUp() + var me = this; + this.onmousemove = function (event) {me._onMouseMove(event);}; + this.onmouseup = function (event) {me._onMouseUp(event);}; + util.addEventListener(document, 'mousemove', me.onmousemove); + util.addEventListener(document, 'mouseup', me.onmouseup); + util.preventDefault(event); + }; - var util = __webpack_require__(1); - var Component = __webpack_require__(20); - var moment = __webpack_require__(44); - var locales = __webpack_require__(48); /** - * A current time bar - * @param {{range: Range, dom: Object, domProps: Object}} body - * @param {Object} [options] Available parameters: - * {Boolean} [showCurrentTime] - * @constructor CurrentTime - * @extends Component + * Perform moving operating. + * This function activated from within the funcion Graph.mouseDown(). + * @param {Event} event Well, eehh, the event */ - function CurrentTime (body, options) { - this.body = body; - - // default options - this.defaultOptions = { - showCurrentTime: true, + Graph3d.prototype._onMouseMove = function (event) { + event = event || window.event; - locales: locales, - locale: 'en' - }; - this.options = util.extend({}, this.defaultOptions); - this.offset = 0; + // calculate change in mouse position + var diffX = parseFloat(getMouseX(event)) - this.startMouseX; + var diffY = parseFloat(getMouseY(event)) - this.startMouseY; - this._create(); + var horizontalNew = this.startArmRotation.horizontal + diffX / 200; + var verticalNew = this.startArmRotation.vertical + diffY / 200; - this.setOptions(options); - } + var snapAngle = 4; // degrees + var snapValue = Math.sin(snapAngle / 360 * 2 * Math.PI); - CurrentTime.prototype = new Component(); + // snap horizontally to nice angles at 0pi, 0.5pi, 1pi, 1.5pi, etc... + // the -0.001 is to take care that the vertical axis is always drawn at the left front corner + if (Math.abs(Math.sin(horizontalNew)) < snapValue) { + horizontalNew = Math.round((horizontalNew / Math.PI)) * Math.PI - 0.001; + } + if (Math.abs(Math.cos(horizontalNew)) < snapValue) { + horizontalNew = (Math.round((horizontalNew/ Math.PI - 0.5)) + 0.5) * Math.PI - 0.001; + } - /** - * Create the HTML DOM for the current time bar - * @private - */ - CurrentTime.prototype._create = function() { - var bar = document.createElement('div'); - bar.className = 'currenttime'; - bar.style.position = 'absolute'; - bar.style.top = '0px'; - bar.style.height = '100%'; + // snap vertically to nice angles + if (Math.abs(Math.sin(verticalNew)) < snapValue) { + verticalNew = Math.round((verticalNew / Math.PI)) * Math.PI; + } + if (Math.abs(Math.cos(verticalNew)) < snapValue) { + verticalNew = (Math.round((verticalNew/ Math.PI - 0.5)) + 0.5) * Math.PI; + } - this.bar = bar; - }; + this.camera.setArmRotation(horizontalNew, verticalNew); + this.redraw(); - /** - * Destroy the CurrentTime bar - */ - CurrentTime.prototype.destroy = function () { - this.options.showCurrentTime = false; - this.redraw(); // will remove the bar from the DOM and stop refreshing + // fire a cameraPositionChange event + var parameters = this.getCameraPosition(); + this.emit('cameraPositionChange', parameters); - this.body = null; + util.preventDefault(event); }; + /** - * Set options for the component. Options will be merged in current options. - * @param {Object} options Available parameters: - * {boolean} [showCurrentTime] + * Stop moving operating. + * This function activated from within the funcion Graph.mouseDown(). + * @param {event} event The event */ - CurrentTime.prototype.setOptions = function(options) { - if (options) { - // copy all options that we know - util.selectiveExtend(['showCurrentTime', 'locale', 'locales'], this.options, options); - } + Graph3d.prototype._onMouseUp = function (event) { + this.frame.style.cursor = 'auto'; + this.leftButtonDown = false; + + // remove event listeners here + util.removeEventListener(document, 'mousemove', this.onmousemove); + util.removeEventListener(document, 'mouseup', this.onmouseup); + util.preventDefault(event); }; /** - * Repaint the component - * @return {boolean} Returns true if the component is resized + * After having moved the mouse, a tooltip should pop up when the mouse is resting on a data point + * @param {Event} event A mouse move event */ - CurrentTime.prototype.redraw = function() { - if (this.options.showCurrentTime) { - var parent = this.body.dom.backgroundVertical; - if (this.bar.parentNode != parent) { - // attach to the dom - if (this.bar.parentNode) { - this.bar.parentNode.removeChild(this.bar); - } - parent.appendChild(this.bar); - - this.start(); - } + Graph3d.prototype._onTooltip = function (event) { + var delay = 300; // ms + var boundingRect = this.frame.getBoundingClientRect(); + var mouseX = getMouseX(event) - boundingRect.left; + var mouseY = getMouseY(event) - boundingRect.top; - var now = new Date(new Date().valueOf() + this.offset); - var x = this.body.util.toScreen(now); + if (!this.showTooltip) { + return; + } - 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); + if (this.tooltipTimeout) { + clearTimeout(this.tooltipTimeout); + } - this.bar.style.left = x + 'px'; - this.bar.title = title; + // (delayed) display of a tooltip only if no mouse button is down + if (this.leftButtonDown) { + this._hideTooltip(); + return; } - else { - // remove the line from the DOM - if (this.bar.parentNode) { - this.bar.parentNode.removeChild(this.bar); + + if (this.tooltip && this.tooltip.dataPoint) { + // tooltip is currently visible + var dataPoint = this._dataPointFromXY(mouseX, mouseY); + if (dataPoint !== this.tooltip.dataPoint) { + // datapoint changed + if (dataPoint) { + this._showTooltip(dataPoint); + } + else { + this._hideTooltip(); + } } - this.stop(); } + else { + // tooltip is currently not visible + var me = this; + this.tooltipTimeout = setTimeout(function () { + me.tooltipTimeout = null; - return false; + // show a tooltip if we have a data point + var dataPoint = me._dataPointFromXY(mouseX, mouseY); + if (dataPoint) { + me._showTooltip(dataPoint); + } + }, delay); + } }; /** - * Start auto refreshing the current time bar + * Event handler for touchstart event on mobile devices */ - CurrentTime.prototype.start = function() { - var me = this; - - function update () { - me.stop(); - - // determine interval to refresh - var scale = me.body.range.conversion(me.body.domProps.center.width).scale; - var interval = 1 / scale / 10; - if (interval < 30) interval = 30; - if (interval > 1000) interval = 1000; - - me.redraw(); - - // start a timer to adjust for the new time - me.currentTimeTimer = setTimeout(update, interval); - } + Graph3d.prototype._onTouchStart = function(event) { + this.touchDown = true; - update(); - }; + var me = this; + this.ontouchmove = function (event) {me._onTouchMove(event);}; + this.ontouchend = function (event) {me._onTouchEnd(event);}; + util.addEventListener(document, 'touchmove', me.ontouchmove); + util.addEventListener(document, 'touchend', me.ontouchend); - /** - * Stop auto refreshing the current time bar - */ - CurrentTime.prototype.stop = function() { - if (this.currentTimeTimer !== undefined) { - clearTimeout(this.currentTimeTimer); - delete this.currentTimeTimer; - } + this._onMouseDown(event); }; /** - * Set a current time. This can be used for example to ensure that a client's - * time is synchronized with a shared server time. - * @param {Date | String | Number} time A Date, unix timestamp, or - * ISO date string. + * Event handler for touchmove event on mobile devices */ - CurrentTime.prototype.setCurrentTime = function(time) { - var t = util.convert(time, 'Date').valueOf(); - var now = new Date().valueOf(); - this.offset = t - now; - this.redraw(); + Graph3d.prototype._onTouchMove = function(event) { + this._onMouseMove(event); }; /** - * Get the current time. - * @return {Date} Returns the current time. + * Event handler for touchend event on mobile devices */ - CurrentTime.prototype.getCurrentTime = function() { - return new Date(new Date().valueOf() + this.offset); - }; - - module.exports = CurrentTime; + Graph3d.prototype._onTouchEnd = function(event) { + this.touchDown = false; + util.removeEventListener(document, 'touchmove', this.ontouchmove); + util.removeEventListener(document, 'touchend', this.ontouchend); -/***/ }, -/* 22 */ -/***/ function(module, exports, __webpack_require__) { + this._onMouseUp(event); + }; - var Hammer = __webpack_require__(45); - var util = __webpack_require__(1); - var Component = __webpack_require__(20); - var moment = __webpack_require__(44); - var locales = __webpack_require__(48); /** - * A custom time bar - * @param {{range: Range, dom: Object}} body - * @param {Object} [options] Available parameters: - * {Boolean} [showCustomTime] - * @constructor CustomTime - * @extends Component + * Event handler for mouse wheel event, used to zoom the graph + * Code from http://adomas.org/javascript-mouse-wheel/ + * @param {event} event The event */ + Graph3d.prototype._onWheel = function(event) { + if (!event) /* For IE. */ + event = window.event; - function CustomTime (body, options) { - this.body = body; - - // default options - this.defaultOptions = { - showCustomTime: false, - locales: locales, - locale: 'en' - }; - this.options = util.extend({}, this.defaultOptions); + // retrieve delta + var delta = 0; + if (event.wheelDelta) { /* IE/Opera. */ + delta = event.wheelDelta/120; + } else if (event.detail) { /* Mozilla case. */ + // In Mozilla, sign of delta is different than in IE. + // Also, delta is multiple of 3. + delta = -event.detail/3; + } - this.customTime = new Date(); - this.eventParams = {}; // stores state parameters while dragging the bar + // If delta is nonzero, handle it. + // Basically, delta is now positive if wheel was scrolled up, + // and negative, if wheel was scrolled down. + if (delta) { + var oldLength = this.camera.getArmLength(); + var newLength = oldLength * (1 - delta / 10); - // create the DOM - this._create(); + this.camera.setArmLength(newLength); + this.redraw(); - this.setOptions(options); - } + this._hideTooltip(); + } - CustomTime.prototype = new Component(); + // fire a cameraPositionChange event + var parameters = this.getCameraPosition(); + this.emit('cameraPositionChange', parameters); - /** - * Set options for the component. Options will be merged in current options. - * @param {Object} options Available parameters: - * {boolean} [showCustomTime] - */ - CustomTime.prototype.setOptions = function(options) { - if (options) { - // copy all options that we know - util.selectiveExtend(['showCustomTime', 'locale', 'locales'], this.options, options); - } + // Prevent default actions caused by mouse wheel. + // That might be ugly, but we handle scrolls somehow + // anyway, so don't bother here.. + util.preventDefault(event); }; /** - * Create the DOM for the custom time + * Test whether a point lies inside given 2D triangle + * @param {Point2d} point + * @param {Point2d[]} triangle + * @return {boolean} Returns true if given point lies inside or on the edge of the triangle * @private */ - CustomTime.prototype._create = function() { - var bar = document.createElement('div'); - bar.className = 'customtime'; - bar.style.position = 'absolute'; - bar.style.top = '0px'; - bar.style.height = '100%'; - this.bar = bar; + Graph3d.prototype._insideTriangle = function (point, triangle) { + var a = triangle[0], + b = triangle[1], + c = triangle[2]; - var drag = document.createElement('div'); - drag.style.position = 'relative'; - drag.style.top = '0px'; - drag.style.left = '-10px'; - drag.style.height = '100%'; - drag.style.width = '20px'; - bar.appendChild(drag); + function sign (x) { + return x > 0 ? 1 : x < 0 ? -1 : 0; + } - // attach event listeners - this.hammer = Hammer(bar, { - prevent_default: true - }); - this.hammer.on('dragstart', this._onDragStart.bind(this)); - this.hammer.on('drag', this._onDrag.bind(this)); - this.hammer.on('dragend', this._onDragEnd.bind(this)); + var as = sign((b.x - a.x) * (point.y - a.y) - (b.y - a.y) * (point.x - a.x)); + var bs = sign((c.x - b.x) * (point.y - b.y) - (c.y - b.y) * (point.x - b.x)); + var cs = sign((a.x - c.x) * (point.y - c.y) - (a.y - c.y) * (point.x - c.x)); + + // each of the three signs must be either equal to each other or zero + return (as == 0 || bs == 0 || as == bs) && + (bs == 0 || cs == 0 || bs == cs) && + (as == 0 || cs == 0 || as == cs); }; /** - * Destroy the CustomTime bar + * Find a data point close to given screen position (x, y) + * @param {Number} x + * @param {Number} y + * @return {Object | null} The closest data point or null if not close to any data point + * @private */ - CustomTime.prototype.destroy = function () { - this.options.showCustomTime = false; - this.redraw(); // will remove the bar from the DOM + Graph3d.prototype._dataPointFromXY = function (x, y) { + var i, + distMax = 100, // px + dataPoint = null, + closestDataPoint = null, + closestDist = null, + center = new Point2d(x, y); - this.hammer.enable(false); - this.hammer = null; + if (this.style === Graph3d.STYLE.BAR || + this.style === Graph3d.STYLE.BARCOLOR || + this.style === Graph3d.STYLE.BARSIZE) { + // the data points are ordered from far away to closest + for (i = this.dataPoints.length - 1; i >= 0; i--) { + dataPoint = this.dataPoints[i]; + var surfaces = dataPoint.surfaces; + if (surfaces) { + for (var s = surfaces.length - 1; s >= 0; s--) { + // split each surface in two triangles, and see if the center point is inside one of these + var surface = surfaces[s]; + var corners = surface.corners; + var triangle1 = [corners[0].screen, corners[1].screen, corners[2].screen]; + var triangle2 = [corners[2].screen, corners[3].screen, corners[0].screen]; + if (this._insideTriangle(center, triangle1) || + this._insideTriangle(center, triangle2)) { + // return immediately at the first hit + return dataPoint; + } + } + } + } + } + else { + // find the closest data point, using distance to the center of the point on 2d screen + for (i = 0; i < this.dataPoints.length; i++) { + dataPoint = this.dataPoints[i]; + var point = dataPoint.screen; + if (point) { + var distX = Math.abs(x - point.x); + var distY = Math.abs(y - point.y); + var dist = Math.sqrt(distX * distX + distY * distY); - this.body = null; + if ((closestDist === null || dist < closestDist) && dist < distMax) { + closestDist = dist; + closestDataPoint = dataPoint; + } + } + } + } + + + return closestDataPoint; }; /** - * Repaint the component - * @return {boolean} Returns true if the component is resized + * Display a tooltip for given data point + * @param {Object} dataPoint + * @private */ - CustomTime.prototype.redraw = function () { - if (this.options.showCustomTime) { - var parent = this.body.dom.backgroundVertical; - if (this.bar.parentNode != parent) { - // attach to the dom - if (this.bar.parentNode) { - this.bar.parentNode.removeChild(this.bar); - } - parent.appendChild(this.bar); - } + Graph3d.prototype._showTooltip = function (dataPoint) { + var content, line, dot; - var x = this.body.util.toScreen(this.customTime); + if (!this.tooltip) { + content = document.createElement('div'); + content.style.position = 'absolute'; + content.style.padding = '10px'; + content.style.border = '1px solid #4d4d4d'; + content.style.color = '#1a1a1a'; + content.style.background = 'rgba(255,255,255,0.7)'; + content.style.borderRadius = '2px'; + content.style.boxShadow = '5px 5px 10px rgba(128,128,128,0.5)'; - 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); + line = document.createElement('div'); + line.style.position = 'absolute'; + line.style.height = '40px'; + line.style.width = '0'; + line.style.borderLeft = '1px solid #4d4d4d'; - this.bar.style.left = x + 'px'; - this.bar.title = title; + dot = document.createElement('div'); + dot.style.position = 'absolute'; + dot.style.height = '0'; + dot.style.width = '0'; + dot.style.border = '5px solid #4d4d4d'; + dot.style.borderRadius = '5px'; + + this.tooltip = { + dataPoint: null, + dom: { + content: content, + line: line, + dot: dot + } + }; } else { - // remove the line from the DOM - if (this.bar.parentNode) { - this.bar.parentNode.removeChild(this.bar); - } + content = this.tooltip.dom.content; + line = this.tooltip.dom.line; + dot = this.tooltip.dom.dot; } - return false; - }; + this._hideTooltip(); - /** - * Set custom time. - * @param {Date | number | string} time - */ - CustomTime.prototype.setCustomTime = function(time) { - this.customTime = util.convert(time, 'Date'); - this.redraw(); - }; + this.tooltip.dataPoint = dataPoint; + if (typeof this.showTooltip === 'function') { + content.innerHTML = this.showTooltip(dataPoint.point); + } + else { + content.innerHTML = '' + + '' + + '' + + '' + + '
x:' + dataPoint.point.x + '
y:' + dataPoint.point.y + '
z:' + dataPoint.point.z + '
'; + } - /** - * Retrieve the current custom time. - * @return {Date} customTime - */ - CustomTime.prototype.getCustomTime = function() { - return new Date(this.customTime.valueOf()); - }; + content.style.left = '0'; + content.style.top = '0'; + this.frame.appendChild(content); + this.frame.appendChild(line); + this.frame.appendChild(dot); - /** - * Start moving horizontally - * @param {Event} event - * @private - */ - CustomTime.prototype._onDragStart = function(event) { - this.eventParams.dragging = true; - this.eventParams.customTime = this.customTime; + // calculate sizes + var contentWidth = content.offsetWidth; + var contentHeight = content.offsetHeight; + var lineHeight = line.offsetHeight; + var dotWidth = dot.offsetWidth; + var dotHeight = dot.offsetHeight; - event.stopPropagation(); - event.preventDefault(); + var left = dataPoint.screen.x - contentWidth / 2; + left = Math.min(Math.max(left, 10), this.frame.clientWidth - 10 - contentWidth); + + line.style.left = dataPoint.screen.x + 'px'; + line.style.top = (dataPoint.screen.y - lineHeight) + 'px'; + content.style.left = left + 'px'; + content.style.top = (dataPoint.screen.y - lineHeight - contentHeight) + 'px'; + dot.style.left = (dataPoint.screen.x - dotWidth / 2) + 'px'; + dot.style.top = (dataPoint.screen.y - dotHeight / 2) + 'px'; }; /** - * Perform moving operating. - * @param {Event} event + * Hide the tooltip when displayed * @private */ - CustomTime.prototype._onDrag = function (event) { - if (!this.eventParams.dragging) return; - - var deltaX = event.gesture.deltaX, - x = this.body.util.toScreen(this.eventParams.customTime) + deltaX, - time = this.body.util.toTime(x); + Graph3d.prototype._hideTooltip = function () { + if (this.tooltip) { + this.tooltip.dataPoint = null; - this.setCustomTime(time); + for (var prop in this.tooltip.dom) { + if (this.tooltip.dom.hasOwnProperty(prop)) { + var elem = this.tooltip.dom[prop]; + if (elem && elem.parentNode) { + elem.parentNode.removeChild(elem); + } + } + } + } + }; - // fire a timechange event - this.body.emitter.emit('timechange', { - time: new Date(this.customTime.valueOf()) - }); + /**--------------------------------------------------------------------------**/ - event.stopPropagation(); - event.preventDefault(); - }; /** - * Stop moving operating. - * @param {event} event - * @private + * Get the horizontal mouse position from a mouse event + * @param {Event} event + * @return {Number} mouse x */ - CustomTime.prototype._onDragEnd = function (event) { - if (!this.eventParams.dragging) return; - - // fire a timechanged event - this.body.emitter.emit('timechanged', { - time: new Date(this.customTime.valueOf()) - }); + function getMouseX (event) { + if ('clientX' in event) return event.clientX; + return event.targetTouches[0] && event.targetTouches[0].clientX || 0; + } - event.stopPropagation(); - event.preventDefault(); - }; + /** + * Get the vertical mouse position from a mouse event + * @param {Event} event + * @return {Number} mouse y + */ + function getMouseY (event) { + if ('clientY' in event) return event.clientY; + return event.targetTouches[0] && event.targetTouches[0].clientY || 0; + } - module.exports = CustomTime; + module.exports = Graph3d; /***/ }, -/* 23 */ +/* 11 */ /***/ function(module, exports, __webpack_require__) { - var util = __webpack_require__(1); - var DOMutil = __webpack_require__(2); - var Component = __webpack_require__(20); - var DataStep = __webpack_require__(16); - + /** - * A horizontal time axis - * @param {Object} [options] See DataAxis.setOptions for the available - * options. - * @constructor DataAxis - * @extends Component - * @param body + * Expose `Emitter`. */ - function DataAxis (body, options, svg, linegraphOptions) { - this.id = util.randomUUID(); - this.body = body; - - this.defaultOptions = { - orientation: 'left', // supported: 'left', 'right' - showMinorLabels: true, - showMajorLabels: true, - icons: true, - majorLinesOffset: 7, - minorLinesOffset: 4, - labelOffsetX: 10, - labelOffsetY: 2, - iconWidth: 20, - width: '40px', - visible: true, - alignZeros: true, - customRange: { - left: {min:undefined, max:undefined}, - right: {min:undefined, max:undefined} - }, - title: { - left: {text:undefined}, - right: {text:undefined} - }, - format: { - left: {decimals: undefined}, - right: {decimals: undefined} - } - }; - this.linegraphOptions = linegraphOptions; - this.linegraphSVG = svg; - this.props = {}; - this.DOMelements = { // dynamic elements - lines: {}, - labels: {}, - title: {} - }; + module.exports = Emitter; - this.dom = {}; + /** + * Initialize a new `Emitter`. + * + * @api public + */ - this.range = {start:0, end:0}; + function Emitter(obj) { + if (obj) return mixin(obj); + }; - this.options = util.extend({}, this.defaultOptions); - this.conversionFactor = 1; + /** + * Mixin the emitter properties. + * + * @param {Object} obj + * @return {Object} + * @api private + */ - this.setOptions(options); - this.width = Number(('' + this.options.width).replace("px","")); - this.minWidth = this.width; - this.height = this.linegraphSVG.offsetHeight; - this.hidden = false; + function mixin(obj) { + for (var key in Emitter.prototype) { + obj[key] = Emitter.prototype[key]; + } + return obj; + } - this.stepPixels = 25; - this.stepPixelsForced = 25; - this.zeroCrossing = -1; + /** + * Listen on the given `event` with `fn`. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ - this.lineOffset = 0; - this.master = true; - this.svgElements = {}; - this.iconsRemoved = false; + Emitter.prototype.on = + Emitter.prototype.addEventListener = function(event, fn){ + this._callbacks = this._callbacks || {}; + (this._callbacks[event] = this._callbacks[event] || []) + .push(fn); + return this; + }; + /** + * Adds an `event` listener that will be invoked a single + * time then automatically removed. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ - this.groups = {}; - this.amountOfGroups = 0; + Emitter.prototype.once = function(event, fn){ + var self = this; + this._callbacks = this._callbacks || {}; - // create the HTML DOM - this._create(); + function on() { + self.off(event, on); + fn.apply(this, arguments); + } - var me = this; - this.body.emitter.on("verticalDrag", function() { - me.dom.lineContainer.style.top = me.body.domProps.scrollTop + 'px'; - }); - } + on.fn = fn; + this.on(event, on); + return this; + }; - DataAxis.prototype = new Component(); + /** + * Remove the given callback for `event` or all + * registered callbacks. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + Emitter.prototype.off = + Emitter.prototype.removeListener = + Emitter.prototype.removeAllListeners = + Emitter.prototype.removeEventListener = function(event, fn){ + this._callbacks = this._callbacks || {}; - DataAxis.prototype.addGroup = function(label, graphOptions) { - if (!this.groups.hasOwnProperty(label)) { - this.groups[label] = graphOptions; + // all + if (0 == arguments.length) { + this._callbacks = {}; + return this; } - this.amountOfGroups += 1; - }; - DataAxis.prototype.updateGroup = function(label, graphOptions) { - this.groups[label] = graphOptions; - }; + // specific event + var callbacks = this._callbacks[event]; + if (!callbacks) return this; - DataAxis.prototype.removeGroup = function(label) { - if (this.groups.hasOwnProperty(label)) { - delete this.groups[label]; - this.amountOfGroups -= 1; + // remove all handlers + if (1 == arguments.length) { + delete this._callbacks[event]; + return this; } - }; - - - DataAxis.prototype.setOptions = function (options) { - if (options) { - var redraw = false; - if (this.options.orientation != options.orientation && options.orientation !== undefined) { - redraw = true; - } - var fields = [ - 'orientation', - 'showMinorLabels', - 'showMajorLabels', - 'icons', - 'majorLinesOffset', - 'minorLinesOffset', - 'labelOffsetX', - 'labelOffsetY', - 'iconWidth', - 'width', - 'visible', - 'customRange', - 'title', - 'format', - 'alignZeros' - ]; - util.selectiveExtend(fields, this.options, options); - - this.minWidth = Number(('' + this.options.width).replace("px","")); - if (redraw == true && this.dom.frame) { - this.hide(); - this.show(); + // remove specific handler + var cb; + for (var i = 0; i < callbacks.length; i++) { + cb = callbacks[i]; + if (cb === fn || cb.fn === fn) { + callbacks.splice(i, 1); + break; } } + return this; }; - /** - * Create the HTML DOM for the DataAxis + * Emit `event` with the given args. + * + * @param {String} event + * @param {Mixed} ... + * @return {Emitter} */ - DataAxis.prototype._create = function() { - this.dom.frame = document.createElement('div'); - this.dom.frame.style.width = this.options.width; - this.dom.frame.style.height = this.height; - - this.dom.lineContainer = document.createElement('div'); - this.dom.lineContainer.style.width = '100%'; - this.dom.lineContainer.style.height = this.height; - this.dom.lineContainer.style.position = 'relative'; - - // create svg element for graph drawing. - this.svg = document.createElementNS('http://www.w3.org/2000/svg',"svg"); - this.svg.style.position = "absolute"; - this.svg.style.top = '0px'; - this.svg.style.height = '100%'; - this.svg.style.width = '100%'; - this.svg.style.display = "block"; - this.dom.frame.appendChild(this.svg); - }; - - DataAxis.prototype._redrawGroupIcons = function () { - DOMutil.prepareElements(this.svgElements); - var x; - var iconWidth = this.options.iconWidth; - var iconHeight = 15; - var iconOffset = 4; - var y = iconOffset + 0.5 * iconHeight; - - if (this.options.orientation == 'left') { - x = iconOffset; - } - else { - x = this.width - iconWidth - iconOffset; - } + Emitter.prototype.emit = function(event){ + this._callbacks = this._callbacks || {}; + var args = [].slice.call(arguments, 1) + , callbacks = this._callbacks[event]; - for (var groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) { - this.groups[groupId].drawIcon(x, y, this.svgElements, this.svg, iconWidth, iconHeight); - y += iconHeight + iconOffset; - } + if (callbacks) { + callbacks = callbacks.slice(0); + for (var i = 0, len = callbacks.length; i < len; ++i) { + callbacks[i].apply(this, args); } } - DOMutil.cleanupElements(this.svgElements); - this.iconsRemoved = false; + return this; }; - DataAxis.prototype._cleanupIcons = function() { - if (this.iconsRemoved == false) { - DOMutil.prepareElements(this.svgElements); - DOMutil.cleanupElements(this.svgElements); - this.iconsRemoved = true; - } - } - /** - * Create the HTML DOM for the DataAxis + * Return array of callbacks for `event`. + * + * @param {String} event + * @return {Array} + * @api public */ - DataAxis.prototype.show = function() { - this.hidden = false; - if (!this.dom.frame.parentNode) { - if (this.options.orientation == 'left') { - this.body.dom.left.appendChild(this.dom.frame); - } - else { - this.body.dom.right.appendChild(this.dom.frame); - } - } - if (!this.dom.lineContainer.parentNode) { - this.body.dom.backgroundHorizontal.appendChild(this.dom.lineContainer); - } + Emitter.prototype.listeners = function(event){ + this._callbacks = this._callbacks || {}; + return this._callbacks[event] || []; }; /** - * Create the HTML DOM for the DataAxis + * Check if this emitter has `event` handlers. + * + * @param {String} event + * @return {Boolean} + * @api public */ - DataAxis.prototype.hide = function() { - this.hidden = true; - if (this.dom.frame.parentNode) { - this.dom.frame.parentNode.removeChild(this.dom.frame); - } - if (this.dom.lineContainer.parentNode) { - this.dom.lineContainer.parentNode.removeChild(this.dom.lineContainer); - } + Emitter.prototype.hasListeners = function(event){ + return !! this.listeners(event).length; }; + +/***/ }, +/* 12 */ +/***/ function(module, exports, __webpack_require__) { + /** - * Set a range (start and end) - * @param end - * @param start - * @param end + * @prototype Point3d + * @param {Number} [x] + * @param {Number} [y] + * @param {Number} [z] */ - DataAxis.prototype.setRange = function (start, end) { - if (this.master == false && this.options.alignZeros == true && this.zeroCrossing != -1) { - if (start > 0) { - start = 0; - } - } - this.range.start = start; - this.range.end = end; + function Point3d(x, y, z) { + this.x = x !== undefined ? x : 0; + this.y = y !== undefined ? y : 0; + this.z = z !== undefined ? z : 0; }; /** - * Repaint the component - * @return {boolean} Returns true if the component is resized + * Subtract the two provided points, returns a-b + * @param {Point3d} a + * @param {Point3d} b + * @return {Point3d} a-b */ - DataAxis.prototype.redraw = function () { - var resized = false; - var activeGroups = 0; - - // Make sure the line container adheres to the vertical scrolling. - this.dom.lineContainer.style.top = this.body.domProps.scrollTop + 'px'; - - for (var groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) { - activeGroups++; - } - } - } - if (this.amountOfGroups == 0 || activeGroups == 0) { - this.hide(); - } - else { - this.show(); - this.height = Number(this.linegraphSVG.style.height.replace("px","")); - - // svg offsetheight did not work in firefox and explorer... - this.dom.lineContainer.style.height = this.height + 'px'; - this.width = this.options.visible == true ? Number(('' + this.options.width).replace("px","")) : 0; - - var props = this.props; - var frame = this.dom.frame; - - // update classname - frame.className = 'dataaxis'; - - // calculate character width and height - this._calculateCharSize(); - - var orientation = this.options.orientation; - var showMinorLabels = this.options.showMinorLabels; - var showMajorLabels = this.options.showMajorLabels; - - // determine the width and height of the elements for the axis - props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; - props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; - - props.minorLineWidth = this.body.dom.backgroundHorizontal.offsetWidth - this.lineOffset - this.width + 2 * this.options.minorLinesOffset; - props.minorLineHeight = 1; - props.majorLineWidth = this.body.dom.backgroundHorizontal.offsetWidth - this.lineOffset - this.width + 2 * this.options.majorLinesOffset; - props.majorLineHeight = 1; - - // take frame offline while updating (is almost twice as fast) - if (orientation == 'left') { - frame.style.top = '0'; - frame.style.left = '0'; - frame.style.bottom = ''; - frame.style.width = this.width + 'px'; - frame.style.height = this.height + "px"; - this.props.width = this.body.domProps.left.width; - this.props.height = this.body.domProps.left.height; - } - else { // right - frame.style.top = ''; - frame.style.bottom = '0'; - frame.style.left = '0'; - frame.style.width = this.width + 'px'; - frame.style.height = this.height + "px"; - this.props.width = this.body.domProps.right.width; - this.props.height = this.body.domProps.right.height; - } - - resized = this._redrawLabels(); - resized = this._isResized() || resized; + Point3d.subtract = function(a, b) { + var sub = new Point3d(); + sub.x = a.x - b.x; + sub.y = a.y - b.y; + sub.z = a.z - b.z; + return sub; + }; - if (this.options.icons == true) { - this._redrawGroupIcons(); - } - else { - this._cleanupIcons(); - } + /** + * Add the two provided points, returns a+b + * @param {Point3d} a + * @param {Point3d} b + * @return {Point3d} a+b + */ + Point3d.add = function(a, b) { + var sum = new Point3d(); + sum.x = a.x + b.x; + sum.y = a.y + b.y; + sum.z = a.z + b.z; + return sum; + }; - this._redrawTitle(orientation); - } - return resized; + /** + * Calculate the average of two 3d points + * @param {Point3d} a + * @param {Point3d} b + * @return {Point3d} The average, (a+b)/2 + */ + Point3d.avg = function(a, b) { + return new Point3d( + (a.x + b.x) / 2, + (a.y + b.y) / 2, + (a.z + b.z) / 2 + ); }; /** - * Repaint major and minor text labels and vertical grid lines - * @private + * Calculate the cross product of the two provided points, returns axb + * Documentation: http://en.wikipedia.org/wiki/Cross_product + * @param {Point3d} a + * @param {Point3d} b + * @return {Point3d} cross product axb */ - DataAxis.prototype._redrawLabels = function () { - var resized = false; - DOMutil.prepareElements(this.DOMelements.lines); - DOMutil.prepareElements(this.DOMelements.labels); + Point3d.crossProduct = function(a, b) { + var crossproduct = new Point3d(); - var orientation = this.options['orientation']; + crossproduct.x = a.y * b.z - a.z * b.y; + crossproduct.y = a.z * b.x - a.x * b.z; + crossproduct.z = a.x * b.y - a.y * b.x; - // calculate range and step (step such that we have space for 7 characters per label) - var minimumStep = this.master ? this.props.majorCharHeight || 10 : this.stepPixelsForced; + return crossproduct; + }; - var step = new DataStep( - this.range.start, - this.range.end, - minimumStep, - this.dom.frame.offsetHeight, - this.options.customRange[this.options.orientation], - this.master == false && this.options.alignZeros // doess the step have to align zeros? only if not master and the options is on - ); - this.step = step; - // get the distance in pixels for a step - // dead space is space that is "left over" after a step - var stepPixels = (this.dom.frame.offsetHeight - (step.deadSpace * (this.dom.frame.offsetHeight / step.marginRange))) / (((step.marginRange - step.deadSpace) / step.step)); + /** + * Rtrieve the length of the vector (or the distance from this point to the origin + * @return {Number} length + */ + Point3d.prototype.length = function() { + return Math.sqrt( + this.x * this.x + + this.y * this.y + + this.z * this.z + ); + }; - this.stepPixels = stepPixels; + module.exports = Point3d; - var amountOfSteps = this.height / stepPixels; - var stepDifference = 0; - // the slave axis needs to use the same horizontal lines as the master axis. - if (this.master == false) { - stepPixels = this.stepPixelsForced; - stepDifference = Math.round((this.dom.frame.offsetHeight / stepPixels) - amountOfSteps); - for (var i = 0; i < 0.5 * stepDifference; i++) { - step.previous(); - } - amountOfSteps = this.height / stepPixels; +/***/ }, +/* 13 */ +/***/ function(module, exports, __webpack_require__) { - if (this.zeroCrossing != -1 && this.options.alignZeros == true) { - var zeroStepDifference = (step.marginEnd / step.step) - this.zeroCrossing; - if (zeroStepDifference > 0) { - for (var i = 0; i < zeroStepDifference; i++) {step.next();} - } - else if (zeroStepDifference < 0) { - for (var i = 0; i < -zeroStepDifference; i++) {step.previous();} - } - } - } - else { - amountOfSteps += 0.25; - } + /** + * @prototype Point2d + * @param {Number} [x] + * @param {Number} [y] + */ + function Point2d (x, y) { + this.x = x !== undefined ? x : 0; + this.y = y !== undefined ? y : 0; + } + module.exports = Point2d; - this.valueAtZero = step.marginEnd; - var marginStartPos = 0; - // do not draw the first label - var max = 1; +/***/ }, +/* 14 */ +/***/ function(module, exports, __webpack_require__) { - // Get the number of decimal places - var decimals; - if(this.options.format[orientation] !== undefined) { - decimals = this.options.format[orientation].decimals; - } + var Point3d = __webpack_require__(12); - this.maxLabelSize = 0; - var y = 0; - while (max < Math.round(amountOfSteps)) { - step.next(); - y = Math.round(max * stepPixels); - marginStartPos = max * stepPixels; - var isMajor = step.isMajor(); + /** + * @class Camera + * The camera is mounted on a (virtual) camera arm. The camera arm can rotate + * The camera is always looking in the direction of the origin of the arm. + * This way, the camera always rotates around one fixed point, the location + * of the camera arm. + * + * Documentation: + * http://en.wikipedia.org/wiki/3D_projection + */ + function Camera() { + this.armLocation = new Point3d(); + this.armRotation = {}; + this.armRotation.horizontal = 0; + this.armRotation.vertical = 0; + this.armLength = 1.7; - if (this.options['showMinorLabels'] && isMajor == false || this.master == false && this.options['showMinorLabels'] == true) { - this._redrawLabel(y - 2, step.getCurrent(decimals), orientation, 'yAxis minor', this.props.minorCharHeight); - } + this.cameraLocation = new Point3d(); + this.cameraRotation = new Point3d(0.5*Math.PI, 0, 0); - if (isMajor && this.options['showMajorLabels'] && this.master == true || - this.options['showMinorLabels'] == false && this.master == false && isMajor == true) { - if (y >= 0) { - this._redrawLabel(y - 2, step.getCurrent(decimals), orientation, 'yAxis major', this.props.majorCharHeight); - } - this._redrawLine(y, orientation, 'grid horizontal major', this.options.majorLinesOffset, this.props.majorLineWidth); - } - else { - this._redrawLine(y, orientation, 'grid horizontal minor', this.options.minorLinesOffset, this.props.minorLineWidth); - } + this.calculateCameraOrientation(); + } - if (this.master == true && step.current == 0) { - this.zeroCrossing = max; - } + /** + * Set the location (origin) of the arm + * @param {Number} x Normalized value of x + * @param {Number} y Normalized value of y + * @param {Number} z Normalized value of z + */ + Camera.prototype.setArmLocation = function(x, y, z) { + this.armLocation.x = x; + this.armLocation.y = y; + this.armLocation.z = z; - max++; - } + this.calculateCameraOrientation(); + }; - if (this.master == false) { - this.conversionFactor = y / (this.valueAtZero - step.current); - } - else { - this.conversionFactor = this.dom.frame.offsetHeight / step.marginRange; + /** + * Set the rotation of the camera arm + * @param {Number} horizontal The horizontal rotation, between 0 and 2*PI. + * Optional, can be left undefined. + * @param {Number} vertical The vertical rotation, between 0 and 0.5*PI + * if vertical=0.5*PI, the graph is shown from the + * top. Optional, can be left undefined. + */ + Camera.prototype.setArmRotation = function(horizontal, vertical) { + if (horizontal !== undefined) { + this.armRotation.horizontal = horizontal; } - // Note that title is rotated, so we're using the height, not width! - var titleWidth = 0; - if (this.options.title[orientation] !== undefined && this.options.title[orientation].text !== undefined) { - titleWidth = this.props.titleCharHeight; + if (vertical !== undefined) { + this.armRotation.vertical = vertical; + if (this.armRotation.vertical < 0) this.armRotation.vertical = 0; + if (this.armRotation.vertical > 0.5*Math.PI) this.armRotation.vertical = 0.5*Math.PI; } - var offset = this.options.icons == true ? Math.max(this.options.iconWidth, titleWidth) + this.options.labelOffsetX + 15 : titleWidth + this.options.labelOffsetX + 15; - // this will resize the yAxis to accommodate the labels. - if (this.maxLabelSize > (this.width - offset) && this.options.visible == true) { - this.width = this.maxLabelSize + offset; - this.options.width = this.width + "px"; - DOMutil.cleanupElements(this.DOMelements.lines); - DOMutil.cleanupElements(this.DOMelements.labels); - this.redraw(); - resized = true; - } - // this will resize the yAxis if it is too big for the labels. - else if (this.maxLabelSize < (this.width - offset) && this.options.visible == true && this.width > this.minWidth) { - this.width = Math.max(this.minWidth,this.maxLabelSize + offset); - this.options.width = this.width + "px"; - DOMutil.cleanupElements(this.DOMelements.lines); - DOMutil.cleanupElements(this.DOMelements.labels); - this.redraw(); - resized = true; - } - else { - DOMutil.cleanupElements(this.DOMelements.lines); - DOMutil.cleanupElements(this.DOMelements.labels); - resized = false; + if (horizontal !== undefined || vertical !== undefined) { + this.calculateCameraOrientation(); } - - return resized; }; - DataAxis.prototype.convertValue = function (value) { - var invertedValue = this.valueAtZero - value; - var convertedValue = invertedValue * this.conversionFactor; - return convertedValue; + /** + * Retrieve the current arm rotation + * @return {object} An object with parameters horizontal and vertical + */ + Camera.prototype.getArmRotation = function() { + var rot = {}; + rot.horizontal = this.armRotation.horizontal; + rot.vertical = this.armRotation.vertical; + + return rot; }; /** - * Create a label for the axis at position x - * @private - * @param y - * @param text - * @param orientation - * @param className - * @param characterHeight + * Set the (normalized) length of the camera arm. + * @param {Number} length A length between 0.71 and 5.0 */ - DataAxis.prototype._redrawLabel = function (y, text, orientation, className, characterHeight) { - // reuse redundant label - var label = DOMutil.getDOMElement('div',this.DOMelements.labels, this.dom.frame); //this.dom.redundant.labels.shift(); - label.className = className; - label.innerHTML = text; - if (orientation == 'left') { - label.style.left = '-' + this.options.labelOffsetX + 'px'; - label.style.textAlign = "right"; - } - else { - label.style.right = '-' + this.options.labelOffsetX + 'px'; - label.style.textAlign = "left"; - } + Camera.prototype.setArmLength = function(length) { + if (length === undefined) + return; - label.style.top = y - 0.5 * characterHeight + this.options.labelOffsetY + 'px'; + this.armLength = length; - text += ''; + // Radius must be larger than the corner of the graph, + // which has a distance of sqrt(0.5^2+0.5^2) = 0.71 from the center of the + // graph + if (this.armLength < 0.71) this.armLength = 0.71; + if (this.armLength > 5.0) this.armLength = 5.0; - var largestWidth = Math.max(this.props.majorCharWidth,this.props.minorCharWidth); - if (this.maxLabelSize < text.length * largestWidth) { - this.maxLabelSize = text.length * largestWidth; - } + this.calculateCameraOrientation(); }; /** - * Create a minor line for the axis at position y - * @param y - * @param orientation - * @param className - * @param offset - * @param width + * Retrieve the arm length + * @return {Number} length */ - DataAxis.prototype._redrawLine = function (y, orientation, className, offset, width) { - if (this.master == true) { - var line = DOMutil.getDOMElement('div',this.DOMelements.lines, this.dom.lineContainer);//this.dom.redundant.lines.shift(); - line.className = className; - line.innerHTML = ''; - - if (orientation == 'left') { - line.style.left = (this.width - offset) + 'px'; - } - else { - line.style.right = (this.width - offset) + 'px'; - } - - line.style.width = width + 'px'; - line.style.top = y + 'px'; - } + Camera.prototype.getArmLength = function() { + return this.armLength; }; /** - * Create a title for the axis - * @private - * @param orientation + * Retrieve the camera location + * @return {Point3d} cameraLocation */ - DataAxis.prototype._redrawTitle = function (orientation) { - DOMutil.prepareElements(this.DOMelements.title); - - // Check if the title is defined for this axes - if (this.options.title[orientation] !== undefined && this.options.title[orientation].text !== undefined) { - var title = DOMutil.getDOMElement('div', this.DOMelements.title, this.dom.frame); - title.className = 'yAxis title ' + orientation; - title.innerHTML = this.options.title[orientation].text; - - // Add style - if provided - if (this.options.title[orientation].style !== undefined) { - util.addCssText(title, this.options.title[orientation].style); - } + Camera.prototype.getCameraLocation = function() { + return this.cameraLocation; + }; - if (orientation == 'left') { - title.style.left = this.props.titleCharHeight + 'px'; - } - else { - title.style.right = this.props.titleCharHeight + 'px'; - } + /** + * Retrieve the camera rotation + * @return {Point3d} cameraRotation + */ + Camera.prototype.getCameraRotation = function() { + return this.cameraRotation; + }; - title.style.width = this.height + 'px'; - } + /** + * Calculate the location and rotation of the camera based on the + * position and orientation of the camera arm + */ + Camera.prototype.calculateCameraOrientation = function() { + // calculate location of the camera + this.cameraLocation.x = this.armLocation.x - this.armLength * Math.sin(this.armRotation.horizontal) * Math.cos(this.armRotation.vertical); + this.cameraLocation.y = this.armLocation.y - this.armLength * Math.cos(this.armRotation.horizontal) * Math.cos(this.armRotation.vertical); + this.cameraLocation.z = this.armLocation.z + this.armLength * Math.sin(this.armRotation.vertical); - // we need to clean up in case we did not use all elements. - DOMutil.cleanupElements(this.DOMelements.title); + // calculate rotation of the camera + this.cameraRotation.x = Math.PI/2 - this.armRotation.vertical; + this.cameraRotation.y = 0; + this.cameraRotation.z = -this.armRotation.horizontal; }; + module.exports = Camera; +/***/ }, +/* 15 */ +/***/ function(module, exports, __webpack_require__) { + var DataView = __webpack_require__(9); /** - * Determine the size of text on the axis (both major and minor axis). - * The size is calculated only once and then cached in this.props. - * @private + * @class Filter + * + * @param {DataSet} data The google data table + * @param {Number} column The index of the column to be filtered + * @param {Graph} graph The graph */ - DataAxis.prototype._calculateCharSize = function () { - // determine the char width and height on the minor axis - if (!('minorCharHeight' in this.props)) { - var textMinor = document.createTextNode('0'); - var measureCharMinor = document.createElement('div'); - measureCharMinor.className = 'yAxis minor measure'; - measureCharMinor.appendChild(textMinor); - this.dom.frame.appendChild(measureCharMinor); - - this.props.minorCharHeight = measureCharMinor.clientHeight; - this.props.minorCharWidth = measureCharMinor.clientWidth; + function Filter (data, column, graph) { + this.data = data; + this.column = column; + this.graph = graph; // the parent graph - this.dom.frame.removeChild(measureCharMinor); - } + this.index = undefined; + this.value = undefined; - if (!('majorCharHeight' in this.props)) { - var textMajor = document.createTextNode('0'); - var measureCharMajor = document.createElement('div'); - measureCharMajor.className = 'yAxis major measure'; - measureCharMajor.appendChild(textMajor); - this.dom.frame.appendChild(measureCharMajor); + // read all distinct values and select the first one + this.values = graph.getDistinctValues(data.get(), this.column); - this.props.majorCharHeight = measureCharMajor.clientHeight; - this.props.majorCharWidth = measureCharMajor.clientWidth; + // sort both numeric and string values correctly + this.values.sort(function (a, b) { + return a > b ? 1 : a < b ? -1 : 0; + }); - this.dom.frame.removeChild(measureCharMajor); + if (this.values.length > 0) { + this.selectValue(0); } - if (!('titleCharHeight' in this.props)) { - var textTitle = document.createTextNode('0'); - var measureCharTitle = document.createElement('div'); - measureCharTitle.className = 'yAxis title measure'; - measureCharTitle.appendChild(textTitle); - this.dom.frame.appendChild(measureCharTitle); + // create an array with the filtered datapoints. this will be loaded afterwards + this.dataPoints = []; - this.props.titleCharHeight = measureCharTitle.clientHeight; - this.props.titleCharWidth = measureCharTitle.clientWidth; + this.loaded = false; + this.onLoadCallback = undefined; - this.dom.frame.removeChild(measureCharTitle); + if (graph.animationPreload) { + this.loaded = false; + this.loadInBackground(); + } + else { + this.loaded = true; } }; + /** - * 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 + * Return the label + * @return {string} label */ - DataAxis.prototype.snap = function(date) { - return this.step.snap(date); + Filter.prototype.isLoaded = function() { + return this.loaded; }; - module.exports = DataAxis; + /** + * Return the loaded progress + * @return {Number} percentage between 0 and 100 + */ + Filter.prototype.getLoadedProgress = function() { + var len = this.values.length; -/***/ }, -/* 24 */ -/***/ function(module, exports, __webpack_require__) { + var i = 0; + while (this.dataPoints[i]) { + i++; + } + + return Math.round(i / len * 100); + }; - var util = __webpack_require__(1); - var DOMutil = __webpack_require__(2); - var Line = __webpack_require__(51); - var Bar = __webpack_require__(52); - var Points = __webpack_require__(53); /** - * /** - * @param {object} group | the object of the group from the dataset - * @param {string} groupId | ID of the group - * @param {object} options | the default options - * @param {array} groupsUsingDefaultStyles | this array has one entree. - * It is passed as an array so it is passed by reference. - * It enumerates through the default styles - * @constructor + * Return the label + * @return {string} label */ - function GraphGroup (group, groupId, options, groupsUsingDefaultStyles) { - this.id = groupId; - var fields = ['sampling','style','sort','yAxisOrientation','barChart','drawPoints','shaded','catmullRom'] - this.options = util.selectiveBridgeObject(fields,options); - this.usingDefaultStyle = group.className === undefined; - this.groupsUsingDefaultStyles = groupsUsingDefaultStyles; - this.zeroPosition = 0; - this.update(group); - if (this.usingDefaultStyle == true) { - this.groupsUsingDefaultStyles[0] += 1; - } - this.itemsData = []; - this.visible = group.visible === undefined ? true : group.visible; - } + Filter.prototype.getLabel = function() { + return this.graph.filterLabel; + }; /** - * this loads a reference to all items in this group into this group. - * @param {array} items + * Return the columnIndex of the filter + * @return {Number} columnIndex */ - GraphGroup.prototype.setItems = function(items) { - if (items != null) { - this.itemsData = items; - if (this.options.sort == true) { - this.itemsData.sort(function (a,b) {return a.x - b.x;}) - } - } - else { - this.itemsData = []; - } + Filter.prototype.getColumn = function() { + return this.column; + }; + + /** + * Return the currently selected value. Returns undefined if there is no selection + * @return {*} value + */ + Filter.prototype.getSelectedValue = function() { + if (this.index === undefined) + return undefined; + + return this.values[this.index]; }; + /** + * Retrieve all values of the filter + * @return {Array} values + */ + Filter.prototype.getValues = function() { + return this.values; + }; /** - * this is used for plotting barcharts, this way, we only have to calculate it once. - * @param pos + * Retrieve one value of the filter + * @param {Number} index + * @return {*} value */ - GraphGroup.prototype.setZeroPosition = function(pos) { - this.zeroPosition = pos; + Filter.prototype.getValue = function(index) { + if (index >= this.values.length) + throw 'Error: index out of range'; + + return this.values[index]; }; /** - * set the options of the graph group over the default options. - * @param options + * Retrieve the (filtered) dataPoints for the currently selected filter index + * @param {Number} [index] (optional) + * @return {Array} dataPoints */ - GraphGroup.prototype.setOptions = function(options) { - if (options !== undefined) { - var fields = ['sampling','style','sort','yAxisOrientation','barChart']; - util.selectiveDeepExtend(fields, this.options, options); + Filter.prototype._getDataPoints = function(index) { + if (index === undefined) + index = this.index; - util.mergeOptions(this.options, options,'catmullRom'); - util.mergeOptions(this.options, options,'drawPoints'); - util.mergeOptions(this.options, options,'shaded'); + if (index === undefined) + return []; - if (options.catmullRom) { - if (typeof options.catmullRom == 'object') { - if (options.catmullRom.parametrization) { - if (options.catmullRom.parametrization == 'uniform') { - this.options.catmullRom.alpha = 0; - } - else if (options.catmullRom.parametrization == 'chordal') { - this.options.catmullRom.alpha = 1.0; - } - else { - this.options.catmullRom.parametrization = 'centripetal'; - this.options.catmullRom.alpha = 0.5; - } - } - } - } + var dataPoints; + if (this.dataPoints[index]) { + dataPoints = this.dataPoints[index]; } + else { + var f = {}; + f.column = this.column; + f.value = this.values[index]; - if (this.options.style == 'line') { - this.type = new Line(this.id, this.options); - } - else if (this.options.style == 'bar') { - this.type = new Bar(this.id, this.options); - } - else if (this.options.style == 'points') { - this.type = new Points(this.id, this.options); + var dataView = new DataView(this.data,{filter: function (item) {return (item[f.column] == f.value);}}).get(); + dataPoints = this.graph._getDataPoints(dataView); + + this.dataPoints[index] = dataPoints; } + + return dataPoints; }; + /** - * this updates the current group class with the latest group dataset entree, used in _updateGroup in linegraph - * @param group + * Set a callback function when the filter is fully loaded. */ - GraphGroup.prototype.update = function(group) { - this.group = group; - this.content = group.content || 'graph'; - this.className = group.className || this.className || "graphGroup" + this.groupsUsingDefaultStyles[0] % 10; - this.visible = group.visible === undefined ? true : group.visible; - this.style = group.style; - this.setOptions(group.options); + Filter.prototype.setOnLoadCallback = function(callback) { + this.onLoadCallback = callback; }; /** - * draw the icon for the legend. - * - * @param x - * @param y - * @param JSONcontainer - * @param SVGcontainer - * @param iconWidth - * @param iconHeight + * Add a value to the list with available values for this filter + * No double entries will be created. + * @param {Number} index */ - GraphGroup.prototype.drawIcon = function(x, y, JSONcontainer, SVGcontainer, iconWidth, iconHeight) { - var fillHeight = iconHeight * 0.5; - var path, fillPath; + Filter.prototype.selectValue = function(index) { + if (index >= this.values.length) + throw 'Error: index out of range'; - var outline = DOMutil.getSVGElement("rect", JSONcontainer, SVGcontainer); - outline.setAttributeNS(null, "x", x); - outline.setAttributeNS(null, "y", y - fillHeight); - outline.setAttributeNS(null, "width", iconWidth); - outline.setAttributeNS(null, "height", 2*fillHeight); - outline.setAttributeNS(null, "class", "outline"); + this.index = index; + this.value = this.values[index]; + }; - if (this.options.style == 'line') { - path = DOMutil.getSVGElement("path", JSONcontainer, SVGcontainer); - path.setAttributeNS(null, "class", this.className); - if(this.style !== undefined) { - path.setAttributeNS(null, "style", this.style); - } + /** + * Load all filtered rows in the background one by one + * Start this method without providing an index! + */ + Filter.prototype.loadInBackground = function(index) { + if (index === undefined) + index = 0; - path.setAttributeNS(null, "d", "M" + x + ","+y+" L" + (x + iconWidth) + ","+y+""); - if (this.options.shaded.enabled == true) { - fillPath = DOMutil.getSVGElement("path", JSONcontainer, SVGcontainer); - if (this.options.shaded.orientation == 'top') { - fillPath.setAttributeNS(null, "d", "M"+x+", " + (y - fillHeight) + - "L"+x+","+y+" L"+ (x + iconWidth) + ","+y+" L"+ (x + iconWidth) + "," + (y - fillHeight)); - } - else { - fillPath.setAttributeNS(null, "d", "M"+x+","+y+" " + - "L"+x+"," + (y + fillHeight) + " " + - "L"+ (x + iconWidth) + "," + (y + fillHeight) + - "L"+ (x + iconWidth) + ","+y); - } - fillPath.setAttributeNS(null, "class", this.className + " iconFill"); - } + var frame = this.graph.frame; - if (this.options.drawPoints.enabled == true) { - DOMutil.drawPoint(x + 0.5 * iconWidth,y, this, JSONcontainer, SVGcontainer); + if (index < this.values.length) { + var dataPointsTemp = this._getDataPoints(index); + //this.graph.redrawInfo(); // TODO: not neat + + // create a progress box + if (frame.progress === undefined) { + frame.progress = document.createElement('DIV'); + frame.progress.style.position = 'absolute'; + frame.progress.style.color = 'gray'; + frame.appendChild(frame.progress); } + var progress = this.getLoadedProgress(); + frame.progress.innerHTML = 'Loading animation... ' + progress + '%'; + // TODO: this is no nice solution... + frame.progress.style.bottom = 60 + 'px'; // TODO: use height of slider + frame.progress.style.left = 10 + 'px'; + + var me = this; + setTimeout(function() {me.loadInBackground(index+1);}, 10); + this.loaded = false; } else { - var barWidth = Math.round(0.3 * iconWidth); - var bar1Height = Math.round(0.4 * iconHeight); - var bar2Height = Math.round(0.75 * iconHeight); + this.loaded = true; - var offset = Math.round((iconWidth - (2 * barWidth))/3); + // remove the progress box + if (frame.progress !== undefined) { + frame.removeChild(frame.progress); + frame.progress = undefined; + } - DOMutil.drawBar(x + 0.5*barWidth + offset , y + fillHeight - bar1Height - 1, barWidth, bar1Height, this.className + ' bar', JSONcontainer, SVGcontainer); - DOMutil.drawBar(x + 1.5*barWidth + offset + 2, y + fillHeight - bar2Height - 1, barWidth, bar2Height, this.className + ' bar', JSONcontainer, SVGcontainer); + if (this.onLoadCallback) + this.onLoadCallback(); } }; - - /** - * return the legend entree for this group. - * - * @param iconWidth - * @param iconHeight - * @returns {{icon: HTMLElement, label: (group.content|*|string), orientation: (.options.yAxisOrientation|*)}} - */ - GraphGroup.prototype.getLegend = function(iconWidth, iconHeight) { - var svg = document.createElementNS('http://www.w3.org/2000/svg',"svg"); - this.drawIcon(0,0.5*iconHeight,[],svg,iconWidth,iconHeight); - return {icon: svg, label: this.content, orientation:this.options.yAxisOrientation}; - } - - GraphGroup.prototype.getYRange = function(groupData) { - return this.type.getYRange(groupData); - } - - GraphGroup.prototype.draw = function(dataset, group, framework) { - this.type.draw(dataset, group, framework); - } - - - module.exports = GraphGroup; + module.exports = Filter; /***/ }, -/* 25 */ +/* 16 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); - var stack = __webpack_require__(18); - var RangeItem = __webpack_require__(35); /** - * @constructor Group - * @param {Number | String} groupId - * @param {Object} data - * @param {ItemSet} itemSet + * @constructor Slider + * + * An html slider control with start/stop/prev/next buttons + * @param {Element} container The element where the slider will be created + * @param {Object} options Available options: + * {boolean} visible If true (default) the + * slider is visible. */ - function Group (groupId, data, itemSet) { - this.groupId = groupId; - this.subgroups = {}; - this.subgroupIndex = 0; - this.subgroupOrderer = data && data.subgroupOrder; - this.itemSet = itemSet; + function Slider(container, options) { + if (container === undefined) { + throw 'Error: No container element defined'; + } + this.container = container; + this.visible = (options && options.visible != undefined) ? options.visible : true; - this.dom = {}; - this.props = { - label: { - width: 0, - height: 0 - } - }; - this.className = null; + if (this.visible) { + this.frame = document.createElement('DIV'); + //this.frame.style.backgroundColor = '#E5E5E5'; + this.frame.style.width = '100%'; + this.frame.style.position = 'relative'; + this.container.appendChild(this.frame); - this.items = {}; // items filtered by groupId of this group - this.visibleItems = []; // items currently visible in window - this.orderedItems = { - byStart: [], - byEnd: [] - }; - this.checkRangedItems = false; // needed to refresh the ranged items if the window is programatically changed with NO overlap. - var me = this; - this.itemSet.body.emitter.on("checkRangedItems", function () { - me.checkRangedItems = true; - }) + this.frame.prev = document.createElement('INPUT'); + this.frame.prev.type = 'BUTTON'; + this.frame.prev.value = 'Prev'; + this.frame.appendChild(this.frame.prev); - this._create(); + this.frame.play = document.createElement('INPUT'); + this.frame.play.type = 'BUTTON'; + this.frame.play.value = 'Play'; + this.frame.appendChild(this.frame.play); - this.setData(data); - } + this.frame.next = document.createElement('INPUT'); + this.frame.next.type = 'BUTTON'; + this.frame.next.value = 'Next'; + this.frame.appendChild(this.frame.next); - /** - * Create DOM elements for the group - * @private - */ - Group.prototype._create = function() { - var label = document.createElement('div'); - label.className = 'vlabel'; - this.dom.label = label; + this.frame.bar = document.createElement('INPUT'); + this.frame.bar.type = 'BUTTON'; + this.frame.bar.style.position = 'absolute'; + this.frame.bar.style.border = '1px solid red'; + this.frame.bar.style.width = '100px'; + this.frame.bar.style.height = '6px'; + this.frame.bar.style.borderRadius = '2px'; + this.frame.bar.style.MozBorderRadius = '2px'; + this.frame.bar.style.border = '1px solid #7F7F7F'; + this.frame.bar.style.backgroundColor = '#E5E5E5'; + this.frame.appendChild(this.frame.bar); - var inner = document.createElement('div'); - inner.className = 'inner'; - label.appendChild(inner); - this.dom.inner = inner; + this.frame.slide = document.createElement('INPUT'); + this.frame.slide.type = 'BUTTON'; + this.frame.slide.style.margin = '0px'; + this.frame.slide.value = ' '; + this.frame.slide.style.position = 'relative'; + this.frame.slide.style.left = '-100px'; + this.frame.appendChild(this.frame.slide); - var foreground = document.createElement('div'); - foreground.className = 'group'; - foreground['timeline-group'] = this; - this.dom.foreground = foreground; + // create events + var me = this; + this.frame.slide.onmousedown = function (event) {me._onMouseDown(event);}; + this.frame.prev.onclick = function (event) {me.prev(event);}; + this.frame.play.onclick = function (event) {me.togglePlay(event);}; + this.frame.next.onclick = function (event) {me.next(event);}; + } - this.dom.background = document.createElement('div'); - this.dom.background.className = 'group'; + this.onChangeCallback = undefined; - this.dom.axis = document.createElement('div'); - this.dom.axis.className = 'group'; + this.values = []; + this.index = undefined; - // create a hidden marker to detect when the Timelines container is attached - // to the DOM, or the style of a parent of the Timeline is changed from - // display:none is changed to visible. - this.dom.marker = document.createElement('div'); - this.dom.marker.style.visibility = 'hidden'; // TODO: ask jos why this is not none? - this.dom.marker.innerHTML = '?'; - this.dom.background.appendChild(this.dom.marker); - }; + this.playTimeout = undefined; + this.playInterval = 1000; // milliseconds + this.playLoop = true; + } /** - * Set the group data for this group - * @param {Object} data Group data, can contain properties content and className + * Select the previous index */ - Group.prototype.setData = function(data) { - // update contents - var content = data && data.content; - if (content instanceof Element) { - this.dom.inner.appendChild(content); - } - else if (content !== undefined && content !== null) { - this.dom.inner.innerHTML = content; + Slider.prototype.prev = function() { + var index = this.getIndex(); + if (index > 0) { + index--; + this.setIndex(index); } - else { - this.dom.inner.innerHTML = this.groupId || ''; // groupId can be null + }; + + /** + * Select the next index + */ + Slider.prototype.next = function() { + var index = this.getIndex(); + if (index < this.values.length - 1) { + index++; + this.setIndex(index); } + }; - // update title - this.dom.label.title = data && data.title || ''; + /** + * Select the next index + */ + Slider.prototype.playNext = function() { + var start = new Date(); - if (!this.dom.inner.firstChild) { - util.addClassName(this.dom.inner, 'hidden'); + var index = this.getIndex(); + if (index < this.values.length - 1) { + index++; + this.setIndex(index); } - else { - util.removeClassName(this.dom.inner, 'hidden'); + else if (this.playLoop) { + // jump to the start + index = 0; + this.setIndex(index); } - // update className - var className = data && data.className || null; - if (className != this.className) { - if (this.className) { - util.removeClassName(this.dom.label, this.className); - util.removeClassName(this.dom.foreground, this.className); - util.removeClassName(this.dom.background, this.className); - util.removeClassName(this.dom.axis, this.className); - } - util.addClassName(this.dom.label, className); - util.addClassName(this.dom.foreground, className); - util.addClassName(this.dom.background, className); - util.addClassName(this.dom.axis, className); - this.className = className; - } + var end = new Date(); + var diff = (end - start); - // update style - if (this.style) { - util.removeCssText(this.dom.label, this.style); - this.style = null; - } - if (data && data.style) { - util.addCssText(this.dom.label, data.style); - this.style = data.style; - } + // calculate how much time it to to set the index and to execute the callback + // function. + var interval = Math.max(this.playInterval - diff, 0); + // document.title = diff // TODO: cleanup + + var me = this; + this.playTimeout = setTimeout(function() {me.playNext();}, interval); }; /** - * Get the width of the group label - * @return {number} width + * Toggle start or stop playing */ - Group.prototype.getLabelWidth = function() { - return this.props.label.width; + Slider.prototype.togglePlay = function() { + if (this.playTimeout === undefined) { + this.play(); + } else { + this.stop(); + } }; - /** - * Repaint this group - * @param {{start: number, end: number}} range - * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin - * @param {boolean} [restack=false] Force restacking of all items - * @return {boolean} Returns true if the group is resized + * Start playing */ - Group.prototype.redraw = function(range, margin, restack) { - var resized = false; - - this.visibleItems = this._updateVisibleItems(this.orderedItems, this.visibleItems, range); - - // force recalculation of the height of the items when the marker height changed - // (due to the Timeline being attached to the DOM or changed from display:none to visible) - var markerHeight = this.dom.marker.clientHeight; - if (markerHeight != this.lastMarkerHeight) { - this.lastMarkerHeight = markerHeight; - - util.forEach(this.items, function (item) { - item.dirty = true; - if (item.displayed) item.redraw(); - }); + Slider.prototype.play = function() { + // Test whether already playing + if (this.playTimeout) return; - restack = true; - } + this.playNext(); - // reposition visible items vertically - if (this.itemSet.options.stack) { // TODO: ugly way to access options... - stack.stack(this.visibleItems, margin, restack); - } - else { // no stacking - stack.nostack(this.visibleItems, margin, this.subgroups); + if (this.frame) { + this.frame.play.value = 'Stop'; } + }; - // recalculate the height of the group - var height = this._calculateHeight(margin); - - // calculate actual size and position - var foreground = this.dom.foreground; - this.top = foreground.offsetTop; - this.left = foreground.offsetLeft; - this.width = foreground.offsetWidth; - resized = util.updateProperty(this, 'height', height) || resized; - - // recalculate size of label - resized = util.updateProperty(this.props.label, 'width', this.dom.inner.clientWidth) || resized; - resized = util.updateProperty(this.props.label, 'height', this.dom.inner.clientHeight) || resized; - - // apply new height - this.dom.background.style.height = height + 'px'; - this.dom.foreground.style.height = height + 'px'; - this.dom.label.style.height = height + 'px'; + /** + * Stop playing + */ + Slider.prototype.stop = function() { + clearInterval(this.playTimeout); + this.playTimeout = undefined; - // update vertical position of items after they are re-stacked and the height of the group is calculated - for (var i = 0, ii = this.visibleItems.length; i < ii; i++) { - var item = this.visibleItems[i]; - item.repositionY(margin); + if (this.frame) { + this.frame.play.value = 'Play'; } - - return resized; }; /** - * recalculate the height of the group - * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin - * @returns {number} Returns the height - * @private + * Set a callback function which will be triggered when the value of the + * slider bar has changed. */ - Group.prototype._calculateHeight = function (margin) { - // recalculate the height of the group - var height; - var visibleItems = this.visibleItems; - //var visibleSubgroups = []; - //this.visibleSubgroups = 0; - this.resetSubgroups(); - var me = this; - if (visibleItems.length) { - var min = visibleItems[0].top; - var max = visibleItems[0].top + visibleItems[0].height; - util.forEach(visibleItems, function (item) { - min = Math.min(min, item.top); - max = Math.max(max, (item.top + item.height)); - if (item.data.subgroup !== undefined) { - me.subgroups[item.data.subgroup].height = Math.max(me.subgroups[item.data.subgroup].height,item.height); - me.subgroups[item.data.subgroup].visible = true; - //if (visibleSubgroups.indexOf(item.data.subgroup) == -1){ - // visibleSubgroups.push(item.data.subgroup); - // me.visibleSubgroups += 1; - //} - } - }); - if (min > margin.axis) { - // there is an empty gap between the lowest item and the axis - var offset = min - margin.axis; - max -= offset; - util.forEach(visibleItems, function (item) { - item.top -= offset; - }); - } - height = max + margin.item.vertical / 2; - } - else { - height = margin.axis + margin.item.vertical; - } - height = Math.max(height, this.props.label.height); + Slider.prototype.setOnChangeCallback = function(callback) { + this.onChangeCallback = callback; + }; - return height; + /** + * Set the interval for playing the list + * @param {Number} interval The interval in milliseconds + */ + Slider.prototype.setPlayInterval = function(interval) { + this.playInterval = interval; }; /** - * Show this group: attach to the DOM + * Retrieve the current play interval + * @return {Number} interval The interval in milliseconds */ - Group.prototype.show = function() { - if (!this.dom.label.parentNode) { - this.itemSet.dom.labelSet.appendChild(this.dom.label); - } + Slider.prototype.getPlayInterval = function(interval) { + return this.playInterval; + }; - if (!this.dom.foreground.parentNode) { - this.itemSet.dom.foreground.appendChild(this.dom.foreground); - } + /** + * Set looping on or off + * @pararm {boolean} doLoop If true, the slider will jump to the start when + * the end is passed, and will jump to the end + * when the start is passed. + */ + Slider.prototype.setPlayLoop = function(doLoop) { + this.playLoop = doLoop; + }; - if (!this.dom.background.parentNode) { - this.itemSet.dom.background.appendChild(this.dom.background); - } - if (!this.dom.axis.parentNode) { - this.itemSet.dom.axis.appendChild(this.dom.axis); + /** + * Execute the onchange callback function + */ + Slider.prototype.onChange = function() { + if (this.onChangeCallback !== undefined) { + this.onChangeCallback(); } }; /** - * Hide this group: remove from the DOM + * redraw the slider on the correct place */ - Group.prototype.hide = function() { - var label = this.dom.label; - if (label.parentNode) { - label.parentNode.removeChild(label); - } - - var foreground = this.dom.foreground; - if (foreground.parentNode) { - foreground.parentNode.removeChild(foreground); - } - - var background = this.dom.background; - if (background.parentNode) { - background.parentNode.removeChild(background); - } + Slider.prototype.redraw = function() { + if (this.frame) { + // resize the bar + this.frame.bar.style.top = (this.frame.clientHeight/2 - + this.frame.bar.offsetHeight/2) + 'px'; + this.frame.bar.style.width = (this.frame.clientWidth - + this.frame.prev.clientWidth - + this.frame.play.clientWidth - + this.frame.next.clientWidth - 30) + 'px'; - var axis = this.dom.axis; - if (axis.parentNode) { - axis.parentNode.removeChild(axis); + // position the slider button + var left = this.indexToLeft(this.index); + this.frame.slide.style.left = (left) + 'px'; } }; + /** - * Add an item to the group - * @param {Item} item + * Set the list with values for the slider + * @param {Array} values A javascript array with values (any type) */ - Group.prototype.add = function(item) { - this.items[item.id] = item; - item.setParent(this); - - // add to - if (item.data.subgroup !== undefined) { - if (this.subgroups[item.data.subgroup] === undefined) { - this.subgroups[item.data.subgroup] = {height:0, visible: false, index:this.subgroupIndex, items: []}; - this.subgroupIndex++; - } - this.subgroups[item.data.subgroup].items.push(item); - } - this.orderSubgroups(); + Slider.prototype.setValues = function(values) { + this.values = values; - if (this.visibleItems.indexOf(item) == -1) { - var range = this.itemSet.body.range; // TODO: not nice accessing the range like this - this._checkIfVisible(item, this.visibleItems, range); - } + if (this.values.length > 0) + this.setIndex(0); + else + this.index = undefined; }; - Group.prototype.orderSubgroups = function() { - if (this.subgroupOrderer !== undefined) { - var sortArray = []; - if (typeof this.subgroupOrderer == 'string') { - for (var subgroup in this.subgroups) { - sortArray.push({subgroup: subgroup, sortField: this.subgroups[subgroup].items[0].data[this.subgroupOrderer]}) - } - sortArray.sort(function (a, b) { - return a.sortField - b.sortField; - }) - } - else if (typeof this.subgroupOrderer == 'function') { - for (var subgroup in this.subgroups) { - sortArray.push(this.subgroups[subgroup].items[0].data); - } - sortArray.sort(this.subgroupOrderer); - } + /** + * Select a value by its index + * @param {Number} index + */ + Slider.prototype.setIndex = function(index) { + if (index < this.values.length) { + this.index = index; - if (sortArray.length > 0) { - for (var i = 0; i < sortArray.length; i++) { - this.subgroups[sortArray[i].subgroup].index = i; - } - } + this.redraw(); + this.onChange(); } - }; - - Group.prototype.resetSubgroups = function() { - for (var subgroup in this.subgroups) { - if (this.subgroups.hasOwnProperty(subgroup)) { - this.subgroups[subgroup].visible = false; - } + else { + throw 'Error: index out of range'; } }; /** - * Remove an item from the group - * @param {Item} item + * retrieve the index of the currently selected vaue + * @return {Number} index */ - Group.prototype.remove = function(item) { - delete this.items[item.id]; - item.setParent(null); - - // remove from visible items - var index = this.visibleItems.indexOf(item); - if (index != -1) this.visibleItems.splice(index, 1); - - // TODO: also remove from ordered items? + Slider.prototype.getIndex = function() { + return this.index; }; /** - * Remove an item from the corresponding DataSet - * @param {Item} item + * retrieve the currently selected value + * @return {*} value */ - Group.prototype.removeFromDataSet = function(item) { - this.itemSet.removeItem(item.id); + Slider.prototype.get = function() { + return this.values[this.index]; }; - /** - * Reorder the items - */ - Group.prototype.order = function() { - var array = util.toArray(this.items); - var startArray = []; - var endArray = []; + Slider.prototype._onMouseDown = function(event) { + // only react on left mouse button down + var leftButtonDown = event.which ? (event.which === 1) : (event.button === 1); + if (!leftButtonDown) return; - for (var i = 0; i < array.length; i++) { - if (array[i].data.end !== undefined) { - endArray.push(array[i]); - } - startArray.push(array[i]); - } - this.orderedItems = { - byStart: startArray, - byEnd: endArray - }; + this.startClientX = event.clientX; + this.startSlideX = parseFloat(this.frame.slide.style.left); - stack.orderByStart(this.orderedItems.byStart); - stack.orderByEnd(this.orderedItems.byEnd); + this.frame.style.cursor = 'move'; + + // add event listeners to handle moving the contents + // we store the function onmousemove and onmouseup in the graph, so we can + // remove the eventlisteners lateron in the function mouseUp() + var me = this; + this.onmousemove = function (event) {me._onMouseMove(event);}; + this.onmouseup = function (event) {me._onMouseUp(event);}; + util.addEventListener(document, 'mousemove', this.onmousemove); + util.addEventListener(document, 'mouseup', this.onmouseup); + util.preventDefault(event); }; - /** - * Update the visible items - * @param {{byStart: Item[], byEnd: Item[]}} orderedItems All items ordered by start date and by end date - * @param {Item[]} visibleItems The previously visible items. - * @param {{start: number, end: number}} range Visible range - * @return {Item[]} visibleItems The new visible items. - * @private - */ - Group.prototype._updateVisibleItems = function(orderedItems, oldVisibleItems, range) { - var visibleItems = []; - var visibleItemsLookup = {}; // we keep this to quickly look up if an item already exists in the list without using indexOf on visibleItems - var interval = (range.end - range.start) / 4; - var lowerBound = range.start - interval; - var upperBound = range.end + interval; - var item, i; + Slider.prototype.leftToIndex = function (left) { + var width = parseFloat(this.frame.bar.style.width) - + this.frame.slide.clientWidth - 10; + var x = left - 3; - // this function is used to do the binary search. - var searchFunction = function (value) { - if (value < lowerBound) {return -1;} - else if (value <= upperBound) {return 0;} - else {return 1;} - } + var index = Math.round(x / width * (this.values.length-1)); + if (index < 0) index = 0; + if (index > this.values.length-1) index = this.values.length-1; - // first check if the items that were in view previously are still in view. - // IMPORTANT: this handles the case for the items with startdate before the window and enddate after the window! - // also cleans up invisible items. - if (oldVisibleItems.length > 0) { - for (i = 0; i < oldVisibleItems.length; i++) { - this._checkIfVisibleWithReference(oldVisibleItems[i], visibleItems, visibleItemsLookup, range); - } - } + return index; + }; - // we do a binary search for the items that have only start values. - var initialPosByStart = util.binarySearchCustom(orderedItems.byStart, searchFunction, 'data','start'); + Slider.prototype.indexToLeft = function (index) { + var width = parseFloat(this.frame.bar.style.width) - + this.frame.slide.clientWidth - 10; - // trace the visible items from the inital start pos both ways until an invisible item is found, we only look at the start values. - this._traceVisible(initialPosByStart, orderedItems.byStart, visibleItems, visibleItemsLookup, function (item) { - return (item.data.start < lowerBound || item.data.start > upperBound); - }); + var x = index / (this.values.length-1) * width; + var left = x + 3; - // if the window has changed programmatically without overlapping the old window, the ranged items with start < lowerBound and end > upperbound are not shown. - // We therefore have to brute force check all items in the byEnd list - if (this.checkRangedItems == true) { - this.checkRangedItems = false; - for (i = 0; i < orderedItems.byEnd.length; i++) { - this._checkIfVisibleWithReference(orderedItems.byEnd[i], visibleItems, visibleItemsLookup, range); - } - } - else { - // we do a binary search for the items that have defined end times. - var initialPosByEnd = util.binarySearchCustom(orderedItems.byEnd, searchFunction, 'data','end'); + return left; + }; - // trace the visible items from the inital start pos both ways until an invisible item is found, we only look at the end values. - this._traceVisible(initialPosByEnd, orderedItems.byEnd, visibleItems, visibleItemsLookup, function (item) { - return (item.data.end < lowerBound || item.data.end > upperBound); - }); - } - // finally, we reposition all the visible items. - for (i = 0; i < visibleItems.length; i++) { - item = visibleItems[i]; - if (!item.displayed) item.show(); - // reposition item horizontally - item.repositionX(); - } + Slider.prototype._onMouseMove = function (event) { + var diff = event.clientX - this.startClientX; + var x = this.startSlideX + diff; - // debug - //console.log("new line") - //if (this.groupId == null) { - // for (i = 0; i < orderedItems.byStart.length; i++) { - // item = orderedItems.byStart[i].data; - // console.log('start',i,initialPosByStart, item.start.valueOf(), item.content, item.start >= lowerBound && item.start <= upperBound,i == initialPosByStart ? "<------------------- HEREEEE" : "") - // } - // for (i = 0; i < orderedItems.byEnd.length; i++) { - // item = orderedItems.byEnd[i].data; - // console.log('rangeEnd',i,initialPosByEnd, item.end.valueOf(), item.content, item.end >= range.start && item.end <= range.end,i == initialPosByEnd ? "<------------------- HEREEEE" : "") - // } - //} + var index = this.leftToIndex(x); - return visibleItems; - }; + this.setIndex(index); - Group.prototype._traceVisible = function (initialPos, items, visibleItems, visibleItemsLookup, breakCondition) { - var item; - var i; + util.preventDefault(); + }; - if (initialPos != -1) { - for (i = initialPos; i >= 0; i--) { - item = items[i]; - if (breakCondition(item)) { - break; - } - else { - if (visibleItemsLookup[item.id] === undefined) { - visibleItemsLookup[item.id] = true; - visibleItems.push(item); - } - } - } - for (i = initialPos + 1; i < items.length; i++) { - item = items[i]; - if (breakCondition(item)) { - break; - } - else { - if (visibleItemsLookup[item.id] === undefined) { - visibleItemsLookup[item.id] = true; - visibleItems.push(item); - } - } - } - } - } + Slider.prototype._onMouseUp = function (event) { + this.frame.style.cursor = 'auto'; + // remove event listeners + util.removeEventListener(document, 'mousemove', this.onmousemove); + util.removeEventListener(document, 'mouseup', this.onmouseup); - /** - * this function is very similar to the _checkIfInvisible() but it does not - * return booleans, hides the item if it should not be seen and always adds to - * the visibleItems. - * this one is for brute forcing and hiding. - * - * @param {Item} item - * @param {Array} visibleItems - * @param {{start:number, end:number}} range - * @private - */ - Group.prototype._checkIfVisible = function(item, visibleItems, range) { - if (item.isVisible(range)) { - if (!item.displayed) item.show(); - // reposition item horizontally - item.repositionX(); - visibleItems.push(item); - } - else { - if (item.displayed) item.hide(); - } + util.preventDefault(); }; + module.exports = Slider; - /** - * this function is very similar to the _checkIfInvisible() but it does not - * return booleans, hides the item if it should not be seen and always adds to - * the visibleItems. - * this one is for brute forcing and hiding. + +/***/ }, +/* 17 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * @prototype StepNumber + * The class StepNumber is an iterator for Numbers. You provide a start and end + * value, and a best step size. StepNumber itself rounds to fixed values and + * a finds the step that best fits the provided step. * - * @param {Item} item - * @param {Array} visibleItems - * @param {{start:number, end:number}} range - * @private + * If prettyStep is true, the step size is chosen as close as possible to the + * provided step, but being a round value like 1, 2, 5, 10, 20, 50, .... + * + * Example usage: + * var step = new StepNumber(0, 10, 2.5, true); + * step.start(); + * while (!step.end()) { + * alert(step.getCurrent()); + * step.next(); + * } + * + * Version: 1.0 + * + * @param {Number} start The start value + * @param {Number} end The end value + * @param {Number} step Optional. Step size. Must be a positive value. + * @param {boolean} prettyStep Optional. If true, the step size is rounded + * To a pretty step size (like 1, 2, 5, 10, 20, 50, ...) */ - Group.prototype._checkIfVisibleWithReference = function(item, visibleItems, visibleItemsLookup, range) { - if (item.isVisible(range)) { - if (visibleItemsLookup[item.id] === undefined) { - visibleItemsLookup[item.id] = true; - visibleItems.push(item); - } - } - else { - if (item.displayed) item.hide(); - } - }; + function StepNumber(start, end, step, prettyStep) { + // set default values + this._start = 0; + this._end = 0; + this._step = 1; + this.prettyStep = true; + this.precision = 5; + this._current = 0; + this.setRange(start, end, step, prettyStep); + }; + /** + * Set a new range: start, end and step. + * + * @param {Number} start The start value + * @param {Number} end The end value + * @param {Number} step Optional. Step size. Must be a positive value. + * @param {boolean} prettyStep Optional. If true, the step size is rounded + * To a pretty step size (like 1, 2, 5, 10, 20, 50, ...) + */ + StepNumber.prototype.setRange = function(start, end, step, prettyStep) { + this._start = start ? start : 0; + this._end = end ? end : 0; - module.exports = Group; + this.setStep(step, prettyStep); + }; + /** + * Set a new step size + * @param {Number} step New step size. Must be a positive value + * @param {boolean} prettyStep Optional. If true, the provided step is rounded + * to a pretty step size (like 1, 2, 5, 10, 20, 50, ...) + */ + StepNumber.prototype.setStep = function(step, prettyStep) { + if (step === undefined || step <= 0) + return; -/***/ }, -/* 26 */ -/***/ function(module, exports, __webpack_require__) { + if (prettyStep !== undefined) + this.prettyStep = prettyStep; - var util = __webpack_require__(1); - var Group = __webpack_require__(25); + if (this.prettyStep === true) + this._step = StepNumber.calculatePrettyStep(step); + else + this._step = step; + }; /** - * @constructor BackgroundGroup - * @param {Number | String} groupId - * @param {Object} data - * @param {ItemSet} itemSet + * Calculate a nice step size, closest to the desired step size. + * Returns a value in one of the ranges 1*10^n, 2*10^n, or 5*10^n, where n is an + * integer Number. For example 1, 2, 5, 10, 20, 50, etc... + * @param {Number} step Desired step size + * @return {Number} Nice step size */ - function BackgroundGroup (groupId, data, itemSet) { - Group.call(this, groupId, data, itemSet); + StepNumber.calculatePrettyStep = function (step) { + var log10 = function (x) {return Math.log(x) / Math.LN10;}; - this.width = 0; - this.height = 0; - this.top = 0; - this.left = 0; - } + // try three steps (multiple of 1, 2, or 5 + var step1 = Math.pow(10, Math.round(log10(step))), + step2 = 2 * Math.pow(10, Math.round(log10(step / 2))), + step5 = 5 * Math.pow(10, Math.round(log10(step / 5))); - BackgroundGroup.prototype = Object.create(Group.prototype); + // choose the best step (closest to minimum step) + var prettyStep = step1; + if (Math.abs(step2 - step) <= Math.abs(prettyStep - step)) prettyStep = step2; + if (Math.abs(step5 - step) <= Math.abs(prettyStep - step)) prettyStep = step5; - /** - * Repaint this group - * @param {{start: number, end: number}} range - * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin - * @param {boolean} [restack=false] Force restacking of all items - * @return {boolean} Returns true if the group is resized - */ - BackgroundGroup.prototype.redraw = function(range, margin, restack) { - var resized = false; + // for safety + if (prettyStep <= 0) { + prettyStep = 1; + } - this.visibleItems = this._updateVisibleItems(this.orderedItems, this.visibleItems, range); + return prettyStep; + }; - // calculate actual size - this.width = this.dom.background.offsetWidth; + /** + * returns the current value of the step + * @return {Number} current value + */ + StepNumber.prototype.getCurrent = function () { + return parseFloat(this._current.toPrecision(this.precision)); + }; - // apply new height (just always zero for BackgroundGroup - this.dom.background.style.height = '0'; + /** + * returns the current step size + * @return {Number} current step size + */ + StepNumber.prototype.getStep = function () { + return this._step; + }; - // update vertical position of items after they are re-stacked and the height of the group is calculated - for (var i = 0, ii = this.visibleItems.length; i < ii; i++) { - var item = this.visibleItems[i]; - item.repositionY(margin); - } + /** + * Set the current value to the largest value smaller than start, which + * is a multiple of the step size + */ + StepNumber.prototype.start = function() { + this._current = this._start - this._start % this._step; + }; - return resized; + /** + * Do a step, add the step size to the current value + */ + StepNumber.prototype.next = function () { + this._current += this._step; }; /** - * Show this group: attach to the DOM + * Returns true whether the end is reached + * @return {boolean} True if the current value has passed the end value. */ - BackgroundGroup.prototype.show = function() { - if (!this.dom.background.parentNode) { - this.itemSet.dom.background.appendChild(this.dom.background); - } + StepNumber.prototype.end = function () { + return (this._current > this._end); }; - module.exports = BackgroundGroup; + module.exports = StepNumber; /***/ }, -/* 27 */ +/* 18 */ /***/ function(module, exports, __webpack_require__) { - var Hammer = __webpack_require__(45); + var Emitter = __webpack_require__(11); + var Hammer = __webpack_require__(19); var util = __webpack_require__(1); - var DataSet = __webpack_require__(3); - var DataView = __webpack_require__(4); - var Component = __webpack_require__(20); - var Group = __webpack_require__(25); - var BackgroundGroup = __webpack_require__(26); - var BoxItem = __webpack_require__(33); - var PointItem = __webpack_require__(34); - var RangeItem = __webpack_require__(35); - var BackgroundItem = __webpack_require__(32); - - - var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items - var BACKGROUND = '__background__'; // reserved group id for background items without group + var DataSet = __webpack_require__(7); + var DataView = __webpack_require__(9); + var Range = __webpack_require__(21); + var Core = __webpack_require__(25); + var TimeAxis = __webpack_require__(37); + var CurrentTime = __webpack_require__(39); + var CustomTime = __webpack_require__(41); + var ItemSet = __webpack_require__(26); /** - * An ItemSet holds a set of items and ranges which can be displayed in a - * range. The width is determined by the parent of the ItemSet, and the height - * is determined by the size of the items. - * @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} body - * @param {Object} [options] See ItemSet.setOptions for the available options. - * @constructor ItemSet - * @extends Component + * Create a timeline visualization + * @param {HTMLElement} container + * @param {vis.DataSet | Array | google.visualization.DataTable} [items] + * @param {vis.DataSet | Array | google.visualization.DataTable} [groups] + * @param {Object} [options] See Timeline.setOptions for the available options. + * @constructor + * @extends Core */ - function ItemSet(body, options) { - this.body = body; - - this.defaultOptions = { - type: null, // 'box', 'point', 'range', 'background' - orientation: 'bottom', // 'top' or 'bottom' - align: 'auto', // alignment of box items - stack: true, - groupOrder: null, - - selectable: true, - editable: { - updateTime: false, - updateGroup: false, - add: false, - remove: false - }, - - onAdd: function (item, callback) { - callback(item); - }, - onUpdate: function (item, callback) { - callback(item); - }, - onMove: function (item, callback) { - callback(item); - }, - onRemove: function (item, callback) { - callback(item); - }, - onMoving: function (item, callback) { - callback(item); - }, + function Timeline (container, items, groups, options) { + if (!(this instanceof Timeline)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } - margin: { - item: { - horizontal: 10, - vertical: 10 - }, - axis: 20 - }, - padding: 5 - }; + // if the third element is options, the forth is groups (optionally); + if (!(Array.isArray(groups) || groups instanceof DataSet) && groups instanceof Object) { + var forthArgument = options; + options = groups; + groups = forthArgument; + } - // options is shared by this ItemSet and all its items - this.options = util.extend({}, this.defaultOptions); + var me = this; + this.defaultOptions = { + start: null, + end: null, - // options for getting items from the DataSet with the correct type - this.itemOptions = { - type: {start: 'Date', end: 'Date'} - }; + autoResize: true, - this.conversion = { - toScreen: body.util.toScreen, - toTime: body.util.toTime + orientation: 'bottom', + width: null, + height: null, + maxHeight: null, + minHeight: null }; - this.dom = {}; - this.props = {}; - this.hammer = null; + this.options = util.deepExtend({}, this.defaultOptions); - var me = this; - this.itemsData = null; // DataSet - this.groupsData = null; // DataSet + // Create the DOM, props, and emitter + this._create(container); - // listeners for the DataSet of the items - this.itemListeners = { - 'add': function (event, params, senderId) { - me._onAdd(params.items); - }, - 'update': function (event, params, senderId) { - me._onUpdate(params.items); - }, - 'remove': function (event, params, senderId) { - me._onRemove(params.items); - } - }; + // all components listed here will be repainted automatically + this.components = []; - // listeners for the DataSet of the groups - this.groupListeners = { - 'add': function (event, params, senderId) { - me._onAddGroups(params.items); - }, - 'update': function (event, params, senderId) { - me._onUpdateGroups(params.items); + this.body = { + dom: this.dom, + domProps: this.props, + emitter: { + on: this.on.bind(this), + off: this.off.bind(this), + emit: this.emit.bind(this) }, - 'remove': function (event, params, senderId) { - me._onRemoveGroups(params.items); + hiddenDates: [], + util: { + snap: null, // will be specified after TimeAxis is created + toScreen: me._toScreen.bind(me), + toGlobalScreen: me._toGlobalScreen.bind(me), // this refers to the root.width + toTime: me._toTime.bind(me), + toGlobalTime : me._toGlobalTime.bind(me) } }; - this.items = {}; // object with an Item for every data item - this.groups = {}; // Group object for every group - this.groupIds = []; + // range + this.range = new Range(this.body); + this.components.push(this.range); + this.body.range = this.range; - this.selection = []; // list with the ids of all selected nodes - this.stackDirty = true; // if true, all items will be restacked on next redraw + // time axis + this.timeAxis = new TimeAxis(this.body); + this.components.push(this.timeAxis); + this.body.util.snap = this.timeAxis.snap.bind(this.timeAxis); - this.touchParams = {}; // stores properties while dragging - // create the HTML DOM + // current time bar + this.currentTime = new CurrentTime(this.body); + this.components.push(this.currentTime); - this._create(); + // custom time bar + // Note: time bar will be attached in this.setOptions when selected + this.customTime = new CustomTime(this.body); + this.components.push(this.customTime); - this.setOptions(options); - } + // item set + this.itemSet = new ItemSet(this.body); + this.components.push(this.itemSet); - ItemSet.prototype = new Component(); + this.itemsData = null; // DataSet + this.groupsData = null; // DataSet - // available item types will be registered here - ItemSet.types = { - background: BackgroundItem, - box: BoxItem, - range: RangeItem, - point: PointItem - }; + // apply options + if (options) { + this.setOptions(options); + } - /** - * Create the HTML DOM for the ItemSet - */ - ItemSet.prototype._create = function(){ - var frame = document.createElement('div'); - frame.className = 'itemset'; - frame['timeline-itemset'] = this; - this.dom.frame = frame; + // IMPORTANT: THIS HAPPENS BEFORE SET ITEMS! + if (groups) { + this.setGroups(groups); + } - // create background panel - var background = document.createElement('div'); - background.className = 'background'; - frame.appendChild(background); - this.dom.background = background; + // create itemset + if (items) { + this.setItems(items); + } + else { + this.redraw(); + } + } - // create foreground panel - var foreground = document.createElement('div'); - foreground.className = 'foreground'; - frame.appendChild(foreground); - this.dom.foreground = foreground; + // Extend the functionality from Core + Timeline.prototype = new Core(); - // create axis panel - var axis = document.createElement('div'); - axis.className = 'axis'; - this.dom.axis = axis; + /** + * Set items + * @param {vis.DataSet | Array | google.visualization.DataTable | null} items + */ + Timeline.prototype.setItems = function(items) { + var initialLoad = (this.itemsData == null); - // create labelset - var labelSet = document.createElement('div'); - labelSet.className = 'labelset'; - this.dom.labelSet = labelSet; + // convert to type DataSet when needed + var newDataSet; + if (!items) { + newDataSet = null; + } + else if (items instanceof DataSet || items instanceof DataView) { + newDataSet = items; + } + else { + // turn an array into a dataset + newDataSet = new DataSet(items, { + type: { + start: 'Date', + end: 'Date' + } + }); + } - // create ungrouped Group - this._updateUngrouped(); + // set items + this.itemsData = newDataSet; + this.itemSet && this.itemSet.setItems(newDataSet); - // create background Group - var backgroundGroup = new BackgroundGroup(BACKGROUND, null, this); - backgroundGroup.show(); - this.groups[BACKGROUND] = backgroundGroup; + if (initialLoad) { + if (this.options.start != undefined || this.options.end != undefined) { + if (this.options.start == undefined || this.options.end == undefined) { + var dataRange = this._getDataRange(); + } - // attach event listeners - // Note: we bind to the centerContainer for the case where the height - // of the center container is larger than of the ItemSet, so we - // can click in the empty area to create a new item or deselect an item. - this.hammer = Hammer(this.body.dom.centerContainer, { - preventDefault: true - }); + var start = this.options.start != undefined ? this.options.start : dataRange.start; + var end = this.options.end != undefined ? this.options.end : dataRange.end; - // drag items when selected - this.hammer.on('touch', this._onTouch.bind(this)); - this.hammer.on('dragstart', this._onDragStart.bind(this)); - this.hammer.on('drag', this._onDrag.bind(this)); - this.hammer.on('dragend', this._onDragEnd.bind(this)); + this.setWindow(start, end, {animate: false}); + } + else { + this.fit({animate: false}); + } + } + }; - // single select (or unselect) when tapping an item - this.hammer.on('tap', this._onSelectItem.bind(this)); + /** + * Set groups + * @param {vis.DataSet | Array | google.visualization.DataTable} groups + */ + Timeline.prototype.setGroups = function(groups) { + // convert to type DataSet when needed + var newDataSet; + if (!groups) { + newDataSet = null; + } + else if (groups instanceof DataSet || groups instanceof DataView) { + newDataSet = groups; + } + else { + // turn an array into a dataset + newDataSet = new DataSet(groups); + } - // multi select when holding mouse/touch, or on ctrl+click - this.hammer.on('hold', this._onMultiSelectItem.bind(this)); + this.groupsData = newDataSet; + this.itemSet.setGroups(newDataSet); + }; - // add item on doubletap - this.hammer.on('doubletap', this._onAddItem.bind(this)); + /** + * Set selected items by their id. Replaces the current selection + * Unknown id's are silently ignored. + * @param {string[] | string} [ids] An array with zero or more id's of the items to be + * selected. If ids is an empty array, all items will be + * unselected. + * @param {Object} [options] Available options: + * `focus: boolean` + * If true, focus will be set to the selected item(s) + * `animate: boolean | number` + * If true (default), the range is animated + * smoothly to the new window. + * If a number, the number is taken as duration + * for the animation. Default duration is 500 ms. + * Only applicable when option focus is true. + */ + Timeline.prototype.setSelection = function(ids, options) { + this.itemSet && this.itemSet.setSelection(ids); - // attach to the DOM - this.show(); + if (options && options.focus) { + this.focus(ids, options); + } }; /** - * Set options for the ItemSet. Existing options will be extended/overwritten. - * @param {Object} [options] The following options are available: - * {String} type - * Default type for the items. Choose from 'box' - * (default), 'point', 'range', or 'background'. - * The default style can be overwritten by - * individual items. - * {String} align - * Alignment for the items, only applicable for - * BoxItem. Choose 'center' (default), 'left', or - * 'right'. - * {String} orientation - * Orientation of the item set. Choose 'top' or - * 'bottom' (default). - * {Function} groupOrder - * A sorting function for ordering groups - * {Boolean} stack - * If true (deafult), items will be stacked on - * top of each other. - * {Number} margin.axis - * Margin between the axis and the items in pixels. - * Default is 20. - * {Number} margin.item.horizontal - * Horizontal margin between items in pixels. - * Default is 10. - * {Number} margin.item.vertical - * Vertical Margin between items in pixels. - * Default is 10. - * {Number} margin.item - * Margin between items in pixels in both horizontal - * and vertical direction. Default is 10. - * {Number} margin - * Set margin for both axis and items in pixels. - * {Number} padding - * Padding of the contents of an item in pixels. - * Must correspond with the items css. Default is 5. - * {Boolean} selectable - * If true (default), items can be selected. - * {Boolean} editable - * Set all editable options to true or false - * {Boolean} editable.updateTime - * Allow dragging an item to an other moment in time - * {Boolean} editable.updateGroup - * Allow dragging an item to an other group - * {Boolean} editable.add - * Allow creating new items on double tap - * {Boolean} editable.remove - * Allow removing items by clicking the delete button - * top right of a selected item. - * {Function(item: Item, callback: Function)} onAdd - * Callback function triggered when an item is about to be added: - * when the user double taps an empty space in the Timeline. - * {Function(item: Item, callback: Function)} onUpdate - * Callback function fired when an item is about to be updated. - * This function typically has to show a dialog where the user - * change the item. If not implemented, nothing happens. - * {Function(item: Item, callback: Function)} onMove - * Fired when an item has been moved. If not implemented, - * the move action will be accepted. - * {Function(item: Item, callback: Function)} onRemove - * Fired when an item is about to be deleted. - * If not implemented, the item will be always removed. + * Get the selected items by their id + * @return {Array} ids The ids of the selected items */ - ItemSet.prototype.setOptions = function(options) { - if (options) { - // copy all options that we know - var fields = ['type', 'align', 'orientation', 'padding', 'stack', 'selectable', 'groupOrder', 'dataAttributes', 'template','hide']; - util.selectiveExtend(fields, this.options, options); + Timeline.prototype.getSelection = function() { + return this.itemSet && this.itemSet.getSelection() || []; + }; - if ('margin' in options) { - if (typeof options.margin === 'number') { - this.options.margin.axis = options.margin; - this.options.margin.item.horizontal = options.margin; - this.options.margin.item.vertical = options.margin; - } - else if (typeof options.margin === 'object') { - util.selectiveExtend(['axis'], this.options.margin, options.margin); - if ('item' in options.margin) { - if (typeof options.margin.item === 'number') { - this.options.margin.item.horizontal = options.margin.item; - this.options.margin.item.vertical = options.margin.item; - } - else if (typeof options.margin.item === 'object') { - util.selectiveExtend(['horizontal', 'vertical'], this.options.margin.item, options.margin.item); - } - } - } + /** + * Adjust the visible window such that the selected item (or multiple items) + * are centered on screen. + * @param {String | String[]} id An item id or array with item ids + * @param {Object} [options] Available options: + * `animate: boolean | number` + * If true (default), the range is animated + * smoothly to the new window. + * If a number, the number is taken as duration + * for the animation. Default duration is 500 ms. + * Only applicable when option focus is true + */ + Timeline.prototype.focus = function(id, options) { + if (!this.itemsData || id == undefined) return; + + var ids = Array.isArray(id) ? id : [id]; + + // get the specified item(s) + var itemsData = this.itemsData.getDataSet().get(ids, { + type: { + start: 'Date', + end: 'Date' } + }); - if ('editable' in options) { - if (typeof options.editable === 'boolean') { - this.options.editable.updateTime = options.editable; - this.options.editable.updateGroup = options.editable; - this.options.editable.add = options.editable; - this.options.editable.remove = options.editable; - } - else if (typeof options.editable === 'object') { - util.selectiveExtend(['updateTime', 'updateGroup', 'add', 'remove'], this.options.editable, options.editable); - } + // calculate minimum start and maximum end of specified items + var start = null; + var end = null; + itemsData.forEach(function (itemData) { + var s = itemData.start.valueOf(); + var e = 'end' in itemData ? itemData.end.valueOf() : itemData.start.valueOf(); + + if (start === null || s < start) { + start = s; } - // callback functions - var addCallback = (function (name) { - var fn = options[name]; - if (fn) { - if (!(fn instanceof Function)) { - throw new Error('option ' + name + ' must be a function ' + name + '(item, callback)'); - } - this.options[name] = fn; - } - }).bind(this); - ['onAdd', 'onUpdate', 'onRemove', 'onMove', 'onMoving'].forEach(addCallback); + if (end === null || e > end) { + end = e; + } + }); - // force the itemSet to refresh: options like orientation and margins may be changed - this.markDirty(); + if (start !== null && end !== null) { + // calculate the new middle and interval for the window + var middle = (start + end) / 2; + var interval = Math.max((this.range.end - this.range.start), (end - start) * 1.1); + + var animate = (options && options.animate !== undefined) ? options.animate : true; + this.range.setRange(middle - interval / 2, middle + interval / 2, animate); } }; /** - * Mark the ItemSet dirty so it will refresh everything with next redraw + * Get the data range of the item set. + * @returns {{min: Date, max: Date}} range A range with a start and end Date. + * When no minimum is found, min==null + * When no maximum is found, max==null */ - ItemSet.prototype.markDirty = function() { - this.groupIds = []; - this.stackDirty = true; - }; + Timeline.prototype.getItemRange = function() { + // calculate min from start filed + var dataset = this.itemsData.getDataSet(), + min = null, + max = null; - /** - * Destroy the ItemSet - */ - ItemSet.prototype.destroy = function() { - this.hide(); - this.setItems(null); - this.setGroups(null); + if (dataset) { + // calculate the minimum value of the field 'start' + var minItem = dataset.min('start'); + min = minItem ? util.convert(minItem.start, 'Date').valueOf() : null; + // Note: we convert first to Date and then to number because else + // a conversion from ISODate to Number will fail - this.hammer = null; + // calculate maximum value of fields 'start' and 'end' + var maxStartItem = dataset.max('start'); + if (maxStartItem) { + max = util.convert(maxStartItem.start, 'Date').valueOf(); + } + var maxEndItem = dataset.max('end'); + if (maxEndItem) { + if (max == null) { + max = util.convert(maxEndItem.end, 'Date').valueOf(); + } + else { + max = Math.max(max, util.convert(maxEndItem.end, 'Date').valueOf()); + } + } + } - this.body = null; - this.conversion = null; + return { + min: (min != null) ? new Date(min) : null, + max: (max != null) ? new Date(max) : null + }; }; - /** - * Hide the component from the DOM - */ - ItemSet.prototype.hide = function() { - // remove the frame containing the items - if (this.dom.frame.parentNode) { - this.dom.frame.parentNode.removeChild(this.dom.frame); - } - - // remove the axis with dots - if (this.dom.axis.parentNode) { - this.dom.axis.parentNode.removeChild(this.dom.axis); - } - // remove the labelset containing all group labels - if (this.dom.labelSet.parentNode) { - this.dom.labelSet.parentNode.removeChild(this.dom.labelSet); - } - }; + module.exports = Timeline; - /** - * Show the component in the DOM (when not already visible). - * @return {Boolean} changed - */ - ItemSet.prototype.show = function() { - // show frame containing the items - if (!this.dom.frame.parentNode) { - this.body.dom.center.appendChild(this.dom.frame); - } - // show axis with dots - if (!this.dom.axis.parentNode) { - this.body.dom.backgroundVertical.appendChild(this.dom.axis); - } +/***/ }, +/* 19 */ +/***/ function(module, exports, __webpack_require__) { - // show labelset containing labels - if (!this.dom.labelSet.parentNode) { - this.body.dom.left.appendChild(this.dom.labelSet); + // Only load hammer.js when in a browser environment + // (loading hammer.js in a node.js environment gives errors) + if (typeof window !== 'undefined') { + module.exports = window['Hammer'] || __webpack_require__(20); + } + else { + module.exports = function () { + throw Error('hammer.js is only available in a browser, not in node.js.'); } - }; + } - /** - * Set selected items by their id. Replaces the current selection - * Unknown id's are silently ignored. - * @param {string[] | string} [ids] An array with zero or more id's of the items to be - * selected, or a single item id. If ids is undefined - * or an empty array, all items will be unselected. - */ - ItemSet.prototype.setSelection = function(ids) { - var i, ii, id, item; - if (ids == undefined) ids = []; - if (!Array.isArray(ids)) ids = [ids]; +/***/ }, +/* 20 */ +/***/ function(module, exports, __webpack_require__) { - // unselect currently selected items - for (i = 0, ii = this.selection.length; i < ii; i++) { - id = this.selection[i]; - item = this.items[id]; - if (item) item.unselect(); - } + var __WEBPACK_AMD_DEFINE_RESULT__;/*! Hammer.JS - v1.1.3 - 2014-05-20 + * http://eightmedia.github.io/hammer.js + * + * Copyright (c) 2014 Jorik Tangelder ; + * Licensed under the MIT license */ - // select items - this.selection = []; - for (i = 0, ii = ids.length; i < ii; i++) { - id = ids[i]; - item = this.items[id]; - if (item) { - this.selection.push(id); - item.select(); - } - } - }; + (function(window, undefined) { + 'use strict'; /** - * Get the selected items by their id - * @return {Array} ids The ids of the selected items + * @main + * @module hammer + * + * @class Hammer + * @static */ - ItemSet.prototype.getSelection = function() { - return this.selection.concat([]); - }; /** - * Get the id's of the currently visible items. - * @returns {Array} The ids of the visible items + * Hammer, use this to create instances + * ```` + * var hammertime = new Hammer(myElement); + * ```` + * + * @method Hammer + * @param {HTMLElement} element + * @param {Object} [options={}] + * @return {Hammer.Instance} */ - ItemSet.prototype.getVisibleItems = function() { - var range = this.body.range.getRange(); - var left = this.body.util.toScreen(range.start); - var right = this.body.util.toScreen(range.end); - - var ids = []; - for (var groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - var group = this.groups[groupId]; - var rawVisibleItems = group.visibleItems; - - // filter the "raw" set with visibleItems into a set which is really - // visible by pixels - for (var i = 0; i < rawVisibleItems.length; i++) { - var item = rawVisibleItems[i]; - // TODO: also check whether visible vertically - if ((item.left < right) && (item.left + item.width > left)) { - ids.push(item.id); - } - } - } - } - - return ids; + var Hammer = function Hammer(element, options) { + return new Hammer.Instance(element, options || {}); }; /** - * Deselect a selected item - * @param {String | Number} id - * @private + * version, as defined in package.json + * the value will be set at each build + * @property VERSION + * @final + * @type {String} */ - ItemSet.prototype._deselect = function(id) { - var selection = this.selection; - for (var i = 0, ii = selection.length; i < ii; i++) { - if (selection[i] == id) { // non-strict comparison! - selection.splice(i, 1); - break; - } - } - }; + Hammer.VERSION = '1.1.3'; /** - * Repaint the component - * @return {boolean} Returns true if the component is resized + * default settings. + * more settings are defined per gesture at `/gestures`. Each gesture can be disabled/enabled + * by setting it's name (like `swipe`) to false. + * You can set the defaults for all instances by changing this object before creating an instance. + * @example + * ```` + * Hammer.defaults.drag = false; + * Hammer.defaults.behavior.touchAction = 'pan-y'; + * delete Hammer.defaults.behavior.userSelect; + * ```` + * @property defaults + * @type {Object} */ - ItemSet.prototype.redraw = function() { - var margin = this.options.margin, - range = this.body.range, - asSize = util.option.asSize, - options = this.options, - orientation = options.orientation, - resized = false, - frame = this.dom.frame, - editable = options.editable.updateTime || options.editable.updateGroup; - - // recalculate absolute position (before redrawing groups) - this.props.top = this.body.domProps.top.height + this.body.domProps.border.top; - this.props.left = this.body.domProps.left.width + this.body.domProps.border.left; - - // update class name - frame.className = 'itemset' + (editable ? ' editable' : ''); - - // reorder the groups (if needed) - resized = this._orderGroups() || resized; - - // check whether zoomed (in that case we need to re-stack everything) - // TODO: would be nicer to get this as a trigger from Range - var visibleInterval = range.end - range.start; - var zoomed = (visibleInterval != this.lastVisibleInterval) || (this.props.width != this.props.lastWidth); - if (zoomed) this.stackDirty = true; - this.lastVisibleInterval = visibleInterval; - this.props.lastWidth = this.props.width; - - var restack = this.stackDirty; - var firstGroup = this._firstGroup(); - var firstMargin = { - item: margin.item, - axis: margin.axis - }; - var nonFirstMargin = { - item: margin.item, - axis: margin.item.vertical / 2 - }; - var height = 0; - var minHeight = margin.axis + margin.item.vertical; - - // redraw the background group - this.groups[BACKGROUND].redraw(range, nonFirstMargin, restack); - - // redraw all regular groups - util.forEach(this.groups, function (group) { - var groupMargin = (group == firstGroup) ? firstMargin : nonFirstMargin; - var groupResized = group.redraw(range, groupMargin, restack); - resized = groupResized || resized; - height += group.height; - }); - height = Math.max(height, minHeight); - this.stackDirty = false; + Hammer.defaults = { + /** + * this setting object adds styles and attributes to the element to prevent the browser from doing + * its native behavior. The css properties are auto prefixed for the browsers when needed. + * @property defaults.behavior + * @type {Object} + */ + behavior: { + /** + * Disables text selection to improve the dragging gesture. When the value is `none` it also sets + * `onselectstart=false` for IE on the element. Mainly for desktop browsers. + * @property defaults.behavior.userSelect + * @type {String} + * @default 'none' + */ + userSelect: 'none', - // update frame height - frame.style.height = asSize(height); + /** + * Specifies whether and how a given region can be manipulated by the user (for instance, by panning or zooming). + * Used by Chrome 35> and IE10>. By default this makes the element blocking any touch event. + * @property defaults.behavior.touchAction + * @type {String} + * @default: 'pan-y' + */ + touchAction: 'pan-y', - // calculate actual size - this.props.width = frame.offsetWidth; - this.props.height = height; + /** + * Disables the default callout shown when you touch and hold a touch target. + * On iOS, when you touch and hold a touch target such as a link, Safari displays + * a callout containing information about the link. This property allows you to disable that callout. + * @property defaults.behavior.touchCallout + * @type {String} + * @default 'none' + */ + touchCallout: 'none', - // reposition axis - this.dom.axis.style.top = asSize((orientation == 'top') ? - (this.body.domProps.top.height + this.body.domProps.border.top) : - (this.body.domProps.top.height + this.body.domProps.centerContainer.height)); - this.dom.axis.style.left = '0'; + /** + * Specifies whether zooming is enabled. Used by IE10> + * @property defaults.behavior.contentZooming + * @type {String} + * @default 'none' + */ + contentZooming: 'none', - // check if this component is resized - resized = this._isResized() || resized; + /** + * Specifies that an entire element should be draggable instead of its contents. + * Mainly for desktop browsers. + * @property defaults.behavior.userDrag + * @type {String} + * @default 'none' + */ + userDrag: 'none', - return resized; + /** + * Overrides the highlight color shown when the user taps a link or a JavaScript + * clickable element in Safari on iPhone. This property obeys the alpha value, if specified. + * + * If you don't specify an alpha value, Safari on iPhone applies a default alpha value + * to the color. To disable tap highlighting, set the alpha value to 0 (invisible). + * If you set the alpha value to 1.0 (opaque), the element is not visible when tapped. + * @property defaults.behavior.tapHighlightColor + * @type {String} + * @default 'rgba(0,0,0,0)' + */ + tapHighlightColor: 'rgba(0,0,0,0)' + } }; /** - * Get the first group, aligned with the axis - * @return {Group | null} firstGroup - * @private + * hammer document where the base events are added at + * @property DOCUMENT + * @type {HTMLElement} + * @default window.document */ - ItemSet.prototype._firstGroup = function() { - var firstGroupIndex = (this.options.orientation == 'top') ? 0 : (this.groupIds.length - 1); - var firstGroupId = this.groupIds[firstGroupIndex]; - var firstGroup = this.groups[firstGroupId] || this.groups[UNGROUPED]; - - return firstGroup || null; - }; + Hammer.DOCUMENT = document; /** - * Create or delete the group holding all ungrouped items. This group is used when - * there are no groups specified. - * @protected + * detect support for pointer events + * @property HAS_POINTEREVENTS + * @type {Boolean} */ - ItemSet.prototype._updateUngrouped = function() { - var ungrouped = this.groups[UNGROUPED]; - var background = this.groups[BACKGROUND]; - var item, itemId; - - if (this.groupsData) { - // remove the group holding all ungrouped items - if (ungrouped) { - ungrouped.hide(); - delete this.groups[UNGROUPED]; - - for (itemId in this.items) { - if (this.items.hasOwnProperty(itemId)) { - item = this.items[itemId]; - item.parent && item.parent.remove(item); - var groupId = this._getGroupId(item.data); - var group = this.groups[groupId]; - group && group.add(item) || item.hide(); - } - } - } - } - else { - // create a group holding all (unfiltered) items - if (!ungrouped) { - var id = null; - var data = null; - ungrouped = new Group(id, data, this); - this.groups[UNGROUPED] = ungrouped; - - for (itemId in this.items) { - if (this.items.hasOwnProperty(itemId)) { - item = this.items[itemId]; - ungrouped.add(item); - } - } - - ungrouped.show(); - } - } - }; - - /** - * Get the element for the labelset - * @return {HTMLElement} labelSet - */ - ItemSet.prototype.getLabelSet = function() { - return this.dom.labelSet; - }; - - /** - * Set items - * @param {vis.DataSet | null} items - */ - ItemSet.prototype.setItems = function(items) { - var me = this, - ids, - oldItemsData = this.itemsData; - - // replace the dataset - if (!items) { - this.itemsData = null; - } - else if (items instanceof DataSet || items instanceof DataView) { - this.itemsData = items; - } - else { - throw new TypeError('Data must be an instance of DataSet or DataView'); - } - - if (oldItemsData) { - // unsubscribe from old dataset - util.forEach(this.itemListeners, function (callback, event) { - oldItemsData.off(event, callback); - }); - - // remove all drawn items - ids = oldItemsData.getIds(); - this._onRemove(ids); - } - - if (this.itemsData) { - // subscribe to new dataset - var id = this.id; - util.forEach(this.itemListeners, function (callback, event) { - me.itemsData.on(event, callback, id); - }); - - // add all new items - ids = this.itemsData.getIds(); - this._onAdd(ids); - - // update the group holding all ungrouped items - this._updateUngrouped(); - } - }; + Hammer.HAS_POINTEREVENTS = navigator.pointerEnabled || navigator.msPointerEnabled; /** - * Get the current items - * @returns {vis.DataSet | null} + * detect support for touch events + * @property HAS_TOUCHEVENTS + * @type {Boolean} */ - ItemSet.prototype.getItems = function() { - return this.itemsData; - }; + Hammer.HAS_TOUCHEVENTS = ('ontouchstart' in window); /** - * Set groups - * @param {vis.DataSet} groups + * detect mobile browsers + * @property IS_MOBILE + * @type {Boolean} */ - ItemSet.prototype.setGroups = function(groups) { - var me = this, - ids; - - // unsubscribe from current dataset - if (this.groupsData) { - util.forEach(this.groupListeners, function (callback, event) { - me.groupsData.unsubscribe(event, callback); - }); - - // remove all drawn groups - ids = this.groupsData.getIds(); - this.groupsData = null; - this._onRemoveGroups(ids); // note: this will cause a redraw - } - - // replace the dataset - if (!groups) { - this.groupsData = null; - } - else if (groups instanceof DataSet || groups instanceof DataView) { - this.groupsData = groups; - } - else { - throw new TypeError('Data must be an instance of DataSet or DataView'); - } - - if (this.groupsData) { - // subscribe to new dataset - var id = this.id; - util.forEach(this.groupListeners, function (callback, event) { - me.groupsData.on(event, callback, id); - }); - - // draw all ms - ids = this.groupsData.getIds(); - this._onAddGroups(ids); - } - - // update the group holding all ungrouped items - this._updateUngrouped(); - - // update the order of all items in each group - this._order(); - - this.body.emitter.emit('change', {queue: true}); - }; + Hammer.IS_MOBILE = /mobile|tablet|ip(ad|hone|od)|android|silk/i.test(navigator.userAgent); /** - * Get the current groups - * @returns {vis.DataSet | null} groups + * detect if we want to support mouseevents at all + * @property NO_MOUSEEVENTS + * @type {Boolean} */ - ItemSet.prototype.getGroups = function() { - return this.groupsData; - }; + Hammer.NO_MOUSEEVENTS = (Hammer.HAS_TOUCHEVENTS && Hammer.IS_MOBILE) || Hammer.HAS_POINTEREVENTS; /** - * Remove an item by its id - * @param {String | Number} id + * interval in which Hammer recalculates current velocity/direction/angle in ms + * @property CALCULATE_INTERVAL + * @type {Number} + * @default 25 */ - ItemSet.prototype.removeItem = function(id) { - var item = this.itemsData.get(id), - dataset = this.itemsData.getDataSet(); - - if (item) { - // confirm deletion - this.options.onRemove(item, function (item) { - if (item) { - // remove by id here, it is possible that an item has no id defined - // itself, so better not delete by the item itself - dataset.remove(id); - } - }); - } - }; + Hammer.CALCULATE_INTERVAL = 25; /** - * Get the time of an item based on it's data and options.type - * @param {Object} itemData - * @returns {string} Returns the type + * eventtypes per touchevent (start, move, end) are filled by `Event.determineEventTypes` on `setup` + * the object contains the DOM event names per type (`EVENT_START`, `EVENT_MOVE`, `EVENT_END`) + * @property EVENT_TYPES * @private + * @writeOnce + * @type {Object} */ - ItemSet.prototype._getType = function (itemData) { - return itemData.type || this.options.type || (itemData.end ? 'range' : 'box'); - }; - + var EVENT_TYPES = {}; /** - * Get the group id for an item - * @param {Object} itemData - * @returns {string} Returns the groupId - * @private + * direction strings, for safe comparisons + * @property DIRECTION_DOWN|LEFT|UP|RIGHT + * @final + * @type {String} + * @default 'down' 'left' 'up' 'right' */ - ItemSet.prototype._getGroupId = function (itemData) { - var type = this._getType(itemData); - if (type == 'background' && itemData.group == undefined) { - return BACKGROUND; - } - else { - return this.groupsData ? itemData.group : UNGROUPED; - } - }; + var DIRECTION_DOWN = Hammer.DIRECTION_DOWN = 'down'; + var DIRECTION_LEFT = Hammer.DIRECTION_LEFT = 'left'; + var DIRECTION_UP = Hammer.DIRECTION_UP = 'up'; + var DIRECTION_RIGHT = Hammer.DIRECTION_RIGHT = 'right'; /** - * Handle updated items - * @param {Number[]} ids - * @protected + * pointertype strings, for safe comparisons + * @property POINTER_MOUSE|TOUCH|PEN + * @final + * @type {String} + * @default 'mouse' 'touch' 'pen' */ - ItemSet.prototype._onUpdate = function(ids) { - var me = this; - - ids.forEach(function (id) { - var itemData = me.itemsData.get(id, me.itemOptions); - var item = me.items[id]; - var type = me._getType(itemData); - - var constructor = ItemSet.types[type]; - - if (item) { - // update item - if (!constructor || !(item instanceof constructor)) { - // item type has changed, delete the item and recreate it - me._removeItem(item); - item = null; - } - else { - me._updateItem(item, itemData); - } - } - - if (!item) { - // create item - if (constructor) { - item = new constructor(itemData, me.conversion, me.options); - item.id = id; // TODO: not so nice setting id afterwards - me._addItem(item); - } - else if (type == 'rangeoverflow') { - // TODO: deprecated since version 2.1.0 (or 3.0.0?). cleanup some day - throw new TypeError('Item type "rangeoverflow" is deprecated. Use css styling instead: ' + - '.vis.timeline .item.range .content {overflow: visible;}'); - } - else { - throw new TypeError('Unknown item type "' + type + '"'); - } - } - }); - - this._order(); - this.stackDirty = true; // force re-stacking of all items next redraw - this.body.emitter.emit('change', {queue: true}); - }; + var POINTER_MOUSE = Hammer.POINTER_MOUSE = 'mouse'; + var POINTER_TOUCH = Hammer.POINTER_TOUCH = 'touch'; + var POINTER_PEN = Hammer.POINTER_PEN = 'pen'; /** - * Handle added items - * @param {Number[]} ids - * @protected + * eventtypes + * @property EVENT_START|MOVE|END|RELEASE|TOUCH + * @final + * @type {String} + * @default 'start' 'change' 'move' 'end' 'release' 'touch' */ - ItemSet.prototype._onAdd = ItemSet.prototype._onUpdate; + var EVENT_START = Hammer.EVENT_START = 'start'; + var EVENT_MOVE = Hammer.EVENT_MOVE = 'move'; + var EVENT_END = Hammer.EVENT_END = 'end'; + var EVENT_RELEASE = Hammer.EVENT_RELEASE = 'release'; + var EVENT_TOUCH = Hammer.EVENT_TOUCH = 'touch'; /** - * Handle removed items - * @param {Number[]} ids - * @protected + * if the window events are set... + * @property READY + * @writeOnce + * @type {Boolean} + * @default false */ - ItemSet.prototype._onRemove = function(ids) { - var count = 0; - var me = this; - ids.forEach(function (id) { - var item = me.items[id]; - if (item) { - count++; - me._removeItem(item); - } - }); - - if (count) { - // update order - this._order(); - this.stackDirty = true; // force re-stacking of all items next redraw - this.body.emitter.emit('change', {queue: true}); - } - }; + Hammer.READY = false; /** - * Update the order of item in all groups - * @private + * plugins namespace + * @property plugins + * @type {Object} */ - ItemSet.prototype._order = function() { - // reorder the items in all groups - // TODO: optimization: only reorder groups affected by the changed items - util.forEach(this.groups, function (group) { - group.order(); - }); - }; + Hammer.plugins = Hammer.plugins || {}; /** - * Handle updated groups - * @param {Number[]} ids - * @private + * gestures namespace + * see `/gestures` for the definitions + * @property gestures + * @type {Object} */ - ItemSet.prototype._onUpdateGroups = function(ids) { - this._onAddGroups(ids); - }; + Hammer.gestures = Hammer.gestures || {}; /** - * Handle changed groups (added or updated) - * @param {Number[]} ids + * setup events to detect gestures on the document + * this function is called when creating an new instance * @private */ - ItemSet.prototype._onAddGroups = function(ids) { - var me = this; - - ids.forEach(function (id) { - var groupData = me.groupsData.get(id); - var group = me.groups[id]; - - if (!group) { - // check for reserved ids - if (id == UNGROUPED || id == BACKGROUND) { - throw new Error('Illegal group id. ' + id + ' is a reserved id.'); - } - - var groupOptions = Object.create(me.options); - util.extend(groupOptions, { - height: null - }); - - group = new Group(id, groupData, me); - me.groups[id] = group; - - // add items with this groupId to the new group - for (var itemId in me.items) { - if (me.items.hasOwnProperty(itemId)) { - var item = me.items[itemId]; - if (item.data.group == id) { - group.add(item); - } - } - } - - group.order(); - group.show(); - } - else { - // update group - group.setData(groupData); + function setup() { + if(Hammer.READY) { + return; } - }); - - this.body.emitter.emit('change', {queue: true}); - }; - /** - * Handle removed groups - * @param {Number[]} ids - * @private - */ - ItemSet.prototype._onRemoveGroups = function(ids) { - var groups = this.groups; - ids.forEach(function (id) { - var group = groups[id]; + // find what eventtypes we add listeners to + Event.determineEventTypes(); - if (group) { - group.hide(); - delete groups[id]; - } - }); + // Register all gestures inside Hammer.gestures + Utils.each(Hammer.gestures, function(gesture) { + Detection.register(gesture); + }); - this.markDirty(); + // Add touch events on the document + Event.onTouch(Hammer.DOCUMENT, EVENT_MOVE, Detection.detect); + Event.onTouch(Hammer.DOCUMENT, EVENT_END, Detection.detect); - this.body.emitter.emit('change', {queue: true}); - }; + // Hammer is ready...! + Hammer.READY = true; + } /** - * Reorder the groups if needed - * @return {boolean} changed - * @private + * @module hammer + * + * @class Utils + * @static */ - ItemSet.prototype._orderGroups = function () { - if (this.groupsData) { - // reorder the groups - var groupIds = this.groupsData.getIds({ - order: this.options.groupOrder - }); - - var changed = !util.equalArray(groupIds, this.groupIds); - if (changed) { - // hide all groups, removes them from the DOM - var groups = this.groups; - groupIds.forEach(function (groupId) { - groups[groupId].hide(); - }); + var Utils = Hammer.utils = { + /** + * extend method, could also be used for cloning when `dest` is an empty object. + * changes the dest object + * @method extend + * @param {Object} dest + * @param {Object} src + * @param {Boolean} [merge=false] do a merge + * @return {Object} dest + */ + extend: function extend(dest, src, merge) { + for(var key in src) { + if(!src.hasOwnProperty(key) || (dest[key] !== undefined && merge)) { + continue; + } + dest[key] = src[key]; + } + return dest; + }, - // show the groups again, attach them to the DOM in correct order - groupIds.forEach(function (groupId) { - groups[groupId].show(); - }); + /** + * simple addEventListener wrapper + * @method on + * @param {HTMLElement} element + * @param {String} type + * @param {Function} handler + */ + on: function on(element, type, handler) { + element.addEventListener(type, handler, false); + }, - this.groupIds = groupIds; - } + /** + * simple removeEventListener wrapper + * @method off + * @param {HTMLElement} element + * @param {String} type + * @param {Function} handler + */ + off: function off(element, type, handler) { + element.removeEventListener(type, handler, false); + }, - return changed; - } - else { - return false; - } - }; + /** + * forEach over arrays and objects + * @method each + * @param {Object|Array} obj + * @param {Function} iterator + * @param {any} iterator.item + * @param {Number} iterator.index + * @param {Object|Array} iterator.obj the source object + * @param {Object} context value to use as `this` in the iterator + */ + each: function each(obj, iterator, context) { + var i, len; - /** - * Add a new item - * @param {Item} item - * @private - */ - ItemSet.prototype._addItem = function(item) { - this.items[item.id] = item; + // native forEach on arrays + if('forEach' in obj) { + obj.forEach(iterator, context); + // arrays + } else if(obj.length !== undefined) { + for(i = 0, len = obj.length; i < len; i++) { + if(iterator.call(context, obj[i], i, obj) === false) { + return; + } + } + // objects + } else { + for(i in obj) { + if(obj.hasOwnProperty(i) && + iterator.call(context, obj[i], i, obj) === false) { + return; + } + } + } + }, - // add to group - var groupId = this._getGroupId(item.data); - var group = this.groups[groupId]; - if (group) group.add(item); - }; + /** + * find if a string contains the string using indexOf + * @method inStr + * @param {String} src + * @param {String} find + * @return {Boolean} found + */ + inStr: function inStr(src, find) { + return src.indexOf(find) > -1; + }, - /** - * Update an existing item - * @param {Item} item - * @param {Object} itemData - * @private - */ - ItemSet.prototype._updateItem = function(item, itemData) { - var oldGroupId = item.data.group; + /** + * find if a array contains the object using indexOf or a simple polyfill + * @method inArray + * @param {String} src + * @param {String} find + * @return {Boolean|Number} false when not found, or the index + */ + inArray: function inArray(src, find) { + if(src.indexOf) { + var index = src.indexOf(find); + return (index === -1) ? false : index; + } else { + for(var i = 0, len = src.length; i < len; i++) { + if(src[i] === find) { + return i; + } + } + return false; + } + }, - // update the items data (will redraw the item when displayed) - item.setData(itemData); + /** + * convert an array-like object (`arguments`, `touchlist`) to an array + * @method toArray + * @param {Object} obj + * @return {Array} + */ + toArray: function toArray(obj) { + return Array.prototype.slice.call(obj, 0); + }, - // update group - if (oldGroupId != item.data.group) { - var oldGroup = this.groups[oldGroupId]; - if (oldGroup) oldGroup.remove(item); + /** + * find if a node is in the given parent + * @method hasParent + * @param {HTMLElement} node + * @param {HTMLElement} parent + * @return {Boolean} found + */ + hasParent: function hasParent(node, parent) { + while(node) { + if(node == parent) { + return true; + } + node = node.parentNode; + } + return false; + }, - var groupId = this._getGroupId(item.data); - var group = this.groups[groupId]; - if (group) group.add(item); - } - }; + /** + * get the center of all the touches + * @method getCenter + * @param {Array} touches + * @return {Object} center contains `pageX`, `pageY`, `clientX` and `clientY` properties + */ + getCenter: function getCenter(touches) { + var pageX = [], + pageY = [], + clientX = [], + clientY = [], + min = Math.min, + max = Math.max; - /** - * Delete an item from the ItemSet: remove it from the DOM, from the map - * with items, and from the map with visible items, and from the selection - * @param {Item} item - * @private - */ - ItemSet.prototype._removeItem = function(item) { - // remove from DOM - item.hide(); + // no need to loop when only one touch + if(touches.length === 1) { + return { + pageX: touches[0].pageX, + pageY: touches[0].pageY, + clientX: touches[0].clientX, + clientY: touches[0].clientY + }; + } - // remove from items - delete this.items[item.id]; + Utils.each(touches, function(touch) { + pageX.push(touch.pageX); + pageY.push(touch.pageY); + clientX.push(touch.clientX); + clientY.push(touch.clientY); + }); - // remove from selection - var index = this.selection.indexOf(item.id); - if (index != -1) this.selection.splice(index, 1); + return { + pageX: (min.apply(Math, pageX) + max.apply(Math, pageX)) / 2, + pageY: (min.apply(Math, pageY) + max.apply(Math, pageY)) / 2, + clientX: (min.apply(Math, clientX) + max.apply(Math, clientX)) / 2, + clientY: (min.apply(Math, clientY) + max.apply(Math, clientY)) / 2 + }; + }, - // remove from group - item.parent && item.parent.remove(item); - }; + /** + * calculate the velocity between two points. unit is in px per ms. + * @method getVelocity + * @param {Number} deltaTime + * @param {Number} deltaX + * @param {Number} deltaY + * @return {Object} velocity `x` and `y` + */ + getVelocity: function getVelocity(deltaTime, deltaX, deltaY) { + return { + x: Math.abs(deltaX / deltaTime) || 0, + y: Math.abs(deltaY / deltaTime) || 0 + }; + }, - /** - * Create an array containing all items being a range (having an end date) - * @param array - * @returns {Array} - * @private - */ - ItemSet.prototype._constructByEndArray = function(array) { - var endArray = []; + /** + * calculate the angle between two coordinates + * @method getAngle + * @param {Touch} touch1 + * @param {Touch} touch2 + * @return {Number} angle + */ + getAngle: function getAngle(touch1, touch2) { + var x = touch2.clientX - touch1.clientX, + y = touch2.clientY - touch1.clientY; - for (var i = 0; i < array.length; i++) { - if (array[i] instanceof RangeItem) { - endArray.push(array[i]); - } - } - return endArray; - }; + return Math.atan2(y, x) * 180 / Math.PI; + }, - /** - * Register the clicked item on touch, before dragStart is initiated. - * - * dragStart is initiated from a mousemove event, which can have left the item - * already resulting in an item == null - * - * @param {Event} event - * @private - */ - ItemSet.prototype._onTouch = function (event) { - // store the touched item, used in _onDragStart - this.touchParams.item = ItemSet.itemFromTarget(event); - }; + /** + * do a small comparision to get the direction between two touches. + * @method getDirection + * @param {Touch} touch1 + * @param {Touch} touch2 + * @return {String} direction matches `DIRECTION_LEFT|RIGHT|UP|DOWN` + */ + getDirection: function getDirection(touch1, touch2) { + var x = Math.abs(touch1.clientX - touch2.clientX), + y = Math.abs(touch1.clientY - touch2.clientY); - /** - * Start dragging the selected events - * @param {Event} event - * @private - */ - ItemSet.prototype._onDragStart = function (event) { - if (!this.options.editable.updateTime && !this.options.editable.updateGroup) { - return; - } + if(x >= y) { + return touch1.clientX - touch2.clientX > 0 ? DIRECTION_LEFT : DIRECTION_RIGHT; + } + return touch1.clientY - touch2.clientY > 0 ? DIRECTION_UP : DIRECTION_DOWN; + }, - var item = this.touchParams.item || null; - var me = this; - var props; + /** + * calculate the distance between two touches + * @method getDistance + * @param {Touch}touch1 + * @param {Touch} touch2 + * @return {Number} distance + */ + getDistance: function getDistance(touch1, touch2) { + var x = touch2.clientX - touch1.clientX, + y = touch2.clientY - touch1.clientY; - if (item && item.selected) { - var dragLeftItem = event.target.dragLeftItem; - var dragRightItem = event.target.dragRightItem; + return Math.sqrt((x * x) + (y * y)); + }, - if (dragLeftItem) { - props = { - item: dragLeftItem, - initialX: event.gesture.center.clientX - }; + /** + * calculate the scale factor between two touchLists + * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out + * @method getScale + * @param {Array} start array of touches + * @param {Array} end array of touches + * @return {Number} scale + */ + getScale: function getScale(start, end) { + // need two fingers... + if(start.length >= 2 && end.length >= 2) { + return this.getDistance(end[0], end[1]) / this.getDistance(start[0], start[1]); + } + return 1; + }, - if (me.options.editable.updateTime) { - props.start = item.data.start.valueOf(); - } - if (me.options.editable.updateGroup) { - if ('group' in item.data) props.group = item.data.group; - } + /** + * calculate the rotation degrees between two touchLists + * @method getRotation + * @param {Array} start array of touches + * @param {Array} end array of touches + * @return {Number} rotation + */ + getRotation: function getRotation(start, end) { + // need two fingers + if(start.length >= 2 && end.length >= 2) { + return this.getAngle(end[1], end[0]) - this.getAngle(start[1], start[0]); + } + return 0; + }, - this.touchParams.itemProps = [props]; - } - else if (dragRightItem) { - props = { - item: dragRightItem, - initialX: event.gesture.center.clientX - }; + /** + * find out if the direction is vertical * + * @method isVertical + * @param {String} direction matches `DIRECTION_UP|DOWN` + * @return {Boolean} is_vertical + */ + isVertical: function isVertical(direction) { + return direction == DIRECTION_UP || direction == DIRECTION_DOWN; + }, - if (me.options.editable.updateTime) { - props.end = item.data.end.valueOf(); - } - if (me.options.editable.updateGroup) { - if ('group' in item.data) props.group = item.data.group; - } + /** + * set css properties with their prefixes + * @param {HTMLElement} element + * @param {String} prop + * @param {String} value + * @param {Boolean} [toggle=true] + * @return {Boolean} + */ + setPrefixedCss: function setPrefixedCss(element, prop, value, toggle) { + var prefixes = ['', 'Webkit', 'Moz', 'O', 'ms']; + prop = Utils.toCamelCase(prop); - this.touchParams.itemProps = [props]; - } - else { - this.touchParams.itemProps = this.getSelection().map(function (id) { - var item = me.items[id]; - var props = { - item: item, - initialX: event.gesture.center.clientX + for(var i = 0; i < prefixes.length; i++) { + var p = prop; + // prefixes + if(prefixes[i]) { + p = prefixes[i] + p.slice(0, 1).toUpperCase() + p.slice(1); + } + + // test the style + if(p in element.style) { + element.style[p] = (toggle == null || toggle) && value || ''; + break; + } + } + }, + + /** + * toggle browser default behavior by setting css properties. + * `userSelect='none'` also sets `element.onselectstart` to false + * `userDrag='none'` also sets `element.ondragstart` to false + * + * @method toggleBehavior + * @param {HtmlElement} element + * @param {Object} props + * @param {Boolean} [toggle=true] + */ + toggleBehavior: function toggleBehavior(element, props, toggle) { + if(!props || !element || !element.style) { + return; + } + + // set the css properties + Utils.each(props, function(value, prop) { + Utils.setPrefixedCss(element, prop, value, toggle); + }); + + var falseFn = toggle && function() { + return false; }; - if (me.options.editable.updateTime) { - if ('start' in item.data) props.start = item.data.start.valueOf(); - if ('end' in item.data) props.end = item.data.end.valueOf(); + // also the disable onselectstart + if(props.userSelect == 'none') { + element.onselectstart = falseFn; } - if (me.options.editable.updateGroup) { - if ('group' in item.data) props.group = item.data.group; + // and disable ondragstart + if(props.userDrag == 'none') { + element.ondragstart = falseFn; } + }, - return props; - }); + /** + * convert a string with underscores to camelCase + * so prevent_default becomes preventDefault + * @param {String} str + * @return {String} camelCaseStr + */ + toCamelCase: function toCamelCase(str) { + return str.replace(/[_-]([a-z])/g, function(s) { + return s[1].toUpperCase(); + }); } - - event.stopPropagation(); - } }; + /** - * Drag selected items - * @param {Event} event - * @private + * @module hammer */ - ItemSet.prototype._onDrag = function (event) { - event.preventDefault() + /** + * @class Event + * @static + */ + var Event = Hammer.event = { + /** + * when touch events have been fired, this is true + * this is used to stop mouse events + * @property prevent_mouseevents + * @private + * @type {Boolean} + */ + preventMouseEvents: false, - if (this.touchParams.itemProps) { - var me = this; - var snap = this.body.util.snap || null; - var xOffset = this.body.dom.root.offsetLeft + this.body.domProps.left.width; + /** + * if EVENT_START has been fired + * @property started + * @private + * @type {Boolean} + */ + started: false, - // move - this.touchParams.itemProps.forEach(function (props) { - var newProps = {}; - var current = me.body.util.toTime(event.gesture.center.clientX - xOffset); - var initial = me.body.util.toTime(props.initialX - xOffset); - var offset = current - initial; + /** + * when the mouse is hold down, this is true + * @property should_detect + * @private + * @type {Boolean} + */ + shouldDetect: false, - if ('start' in props) { - var start = new Date(props.start + offset); - newProps.start = snap ? snap(start) : start; - } + /** + * simple event binder with a hook and support for multiple types + * @method on + * @param {HTMLElement} element + * @param {String} type + * @param {Function} handler + * @param {Function} [hook] + * @param {Object} hook.type + */ + on: function on(element, type, handler, hook) { + var types = type.split(' '); + Utils.each(types, function(type) { + Utils.on(element, type, handler); + hook && hook(type); + }); + }, - if ('end' in props) { - var end = new Date(props.end + offset); - newProps.end = snap ? snap(end) : end; - } + /** + * simple event unbinder with a hook and support for multiple types + * @method off + * @param {HTMLElement} element + * @param {String} type + * @param {Function} handler + * @param {Function} [hook] + * @param {Object} hook.type + */ + off: function off(element, type, handler, hook) { + var types = type.split(' '); + Utils.each(types, function(type) { + Utils.off(element, type, handler); + hook && hook(type); + }); + }, - if ('group' in props) { - // drag from one group to another - var group = ItemSet.groupFromTarget(event); - newProps.group = group && group.groupId; - } + /** + * the core touch event handler. + * this finds out if we should to detect gestures + * @method onTouch + * @param {HTMLElement} element + * @param {String} eventType matches `EVENT_START|MOVE|END` + * @param {Function} handler + * @return onTouchHandler {Function} the core event handler + */ + onTouch: function onTouch(element, eventType, handler) { + var self = this; - // confirm moving the item - var itemData = util.extend({}, props.item.data, newProps); - me.options.onMoving(itemData, function (itemData) { - if (itemData) { - me._updateItemProps(props.item, itemData); - } - }); - }); + var onTouchHandler = function onTouchHandler(ev) { + var srcType = ev.type.toLowerCase(), + isPointer = Hammer.HAS_POINTEREVENTS, + isMouse = Utils.inStr(srcType, 'mouse'), + triggerType; - this.stackDirty = true; // force re-stacking of all items next redraw - this.body.emitter.emit('change'); + // if we are in a mouseevent, but there has been a touchevent triggered in this session + // we want to do nothing. simply break out of the event. + if(isMouse && self.preventMouseEvents) { + return; - event.stopPropagation(); - } - }; + // mousebutton must be down + } else if(isMouse && eventType == EVENT_START && ev.button === 0) { + self.preventMouseEvents = false; + self.shouldDetect = true; + } else if(isPointer && eventType == EVENT_START) { + self.shouldDetect = (ev.buttons === 1 || PointerEvent.matchType(POINTER_TOUCH, ev)); + // just a valid start event, but no mouse + } else if(!isMouse && eventType == EVENT_START) { + self.preventMouseEvents = true; + self.shouldDetect = true; + } - /** - * Update an items properties - * @param {Item} item - * @param {Object} props Can contain properties start, end, and group. - * @private - */ - ItemSet.prototype._updateItemProps = function(item, props) { - // TODO: copy all properties from props to item? (also new ones) - if ('start' in props) item.data.start = props.start; - if ('end' in props) item.data.end = props.end; - if ('group' in props && item.data.group != props.group) { - this._moveToGroup(item, props.group) - } - }; + // update the pointer event before entering the detection + if(isPointer && eventType != EVENT_END) { + PointerEvent.updatePointer(eventType, ev); + } - /** - * Move an item to another group - * @param {Item} item - * @param {String | Number} groupId - * @private - */ - ItemSet.prototype._moveToGroup = function(item, groupId) { - var group = this.groups[groupId]; - if (group && group.groupId != item.data.group) { - var oldGroup = item.parent; - oldGroup.remove(item); - oldGroup.order(); - group.add(item); - group.order(); + // we are in a touch/down state, so allowed detection of gestures + if(self.shouldDetect) { + triggerType = self.doDetect.call(self, ev, eventType, element, handler); + } - item.data.group = group.groupId; - } - }; + // ...and we are done with the detection + // so reset everything to start each detection totally fresh + if(triggerType == EVENT_END) { + self.preventMouseEvents = false; + self.shouldDetect = false; + PointerEvent.reset(); + // update the pointerevent object after the detection + } - /** - * End of dragging selected items - * @param {Event} event - * @private - */ - ItemSet.prototype._onDragEnd = function (event) { - event.preventDefault() + if(isPointer && eventType == EVENT_END) { + PointerEvent.updatePointer(eventType, ev); + } + }; - if (this.touchParams.itemProps) { - // prepare a change set for the changed items - var changes = [], - me = this, - dataset = this.itemsData.getDataSet(); + this.on(element, EVENT_TYPES[eventType], onTouchHandler); + return onTouchHandler; + }, - var itemProps = this.touchParams.itemProps ; - this.touchParams.itemProps = null; - itemProps.forEach(function (props) { - var id = props.item.id, - itemData = me.itemsData.get(id, me.itemOptions); + /** + * the core detection method + * this finds out what hammer-touch-events to trigger + * @method doDetect + * @param {Object} ev + * @param {String} eventType matches `EVENT_START|MOVE|END` + * @param {HTMLElement} element + * @param {Function} handler + * @return {String} triggerType matches `EVENT_START|MOVE|END` + */ + doDetect: function doDetect(ev, eventType, element, handler) { + var touchList = this.getTouchList(ev, eventType); + var touchListLength = touchList.length; + var triggerType = eventType; + var triggerChange = touchList.trigger; // used by fakeMultitouch plugin + var changedLength = touchListLength; - var changed = false; - if ('start' in props.item.data) { - changed = (props.start != props.item.data.start.valueOf()); - itemData.start = util.convert(props.item.data.start, - dataset._options.type && dataset._options.type.start || 'Date'); - } - if ('end' in props.item.data) { - changed = changed || (props.end != props.item.data.end.valueOf()); - itemData.end = util.convert(props.item.data.end, - dataset._options.type && dataset._options.type.end || 'Date'); - } - if ('group' in props.item.data) { - changed = changed || (props.group != props.item.data.group); - itemData.group = props.item.data.group; - } + // at each touchstart-like event we want also want to trigger a TOUCH event... + if(eventType == EVENT_START) { + triggerChange = EVENT_TOUCH; + // ...the same for a touchend-like event + } else if(eventType == EVENT_END) { + triggerChange = EVENT_RELEASE; - // only apply changes when start or end is actually changed - if (changed) { - me.options.onMove(itemData, function (itemData) { - if (itemData) { - // apply changes - itemData[dataset._fieldId] = id; // ensure the item contains its id (can be undefined) - changes.push(itemData); - } - else { - // restore original values - me._updateItemProps(props.item, props); + // keep track of how many touches have been removed + changedLength = touchList.length - ((ev.changedTouches) ? ev.changedTouches.length : 1); + } - me.stackDirty = true; // force re-stacking of all items next redraw - me.body.emitter.emit('change'); - } - }); - } - }); + // after there are still touches on the screen, + // we just want to trigger a MOVE event. so change the START or END to a MOVE + // but only after detection has been started, the first time we actualy want a START + if(changedLength > 0 && this.started) { + triggerType = EVENT_MOVE; + } - // apply the changes to the data (if there are changes) - if (changes.length) { - dataset.update(changes); - } + // detection has been started, we keep track of this, see above + this.started = true; - event.stopPropagation(); - } - }; + // generate some event data, some basic information + var evData = this.collectEventData(element, triggerType, touchList, ev); - /** - * Handle selecting/deselecting an item when tapping it - * @param {Event} event - * @private - */ - ItemSet.prototype._onSelectItem = function (event) { - if (!this.options.selectable) return; + // trigger the triggerType event before the change (TOUCH, RELEASE) events + // but the END event should be at last + if(eventType != EVENT_END) { + handler.call(Detection, evData); + } - var ctrlKey = event.gesture.srcEvent && event.gesture.srcEvent.ctrlKey; - var shiftKey = event.gesture.srcEvent && event.gesture.srcEvent.shiftKey; - if (ctrlKey || shiftKey) { - this._onMultiSelectItem(event); - return; - } + // trigger a change (TOUCH, RELEASE) event, this means the length of the touches changed + if(triggerChange) { + evData.changedLength = changedLength; + evData.eventType = triggerChange; - var oldSelection = this.getSelection(); + handler.call(Detection, evData); - var item = ItemSet.itemFromTarget(event); - var selection = item ? [item.id] : []; - this.setSelection(selection); + evData.eventType = triggerType; + delete evData.changedLength; + } - var newSelection = this.getSelection(); + // trigger the END event + if(triggerType == EVENT_END) { + handler.call(Detection, evData); - // emit a select event, - // except when old selection is empty and new selection is still empty - if (newSelection.length > 0 || oldSelection.length > 0) { - this.body.emitter.emit('select', { - items: newSelection - }); - } - }; + // ...and we are done with the detection + // so reset everything to start each detection totally fresh + this.started = false; + } - /** - * Handle creation and updates of an item on double tap - * @param event - * @private - */ - ItemSet.prototype._onAddItem = function (event) { - if (!this.options.selectable) return; - if (!this.options.editable.add) return; + return triggerType; + }, - var me = this, - snap = this.body.util.snap || null, - item = ItemSet.itemFromTarget(event); + /** + * we have different events for each device/browser + * determine what we need and set them in the EVENT_TYPES constant + * the `onTouch` method is bind to these properties. + * @method determineEventTypes + * @return {Object} events + */ + determineEventTypes: function determineEventTypes() { + var types; + if(Hammer.HAS_POINTEREVENTS) { + if(window.PointerEvent) { + types = [ + 'pointerdown', + 'pointermove', + 'pointerup pointercancel lostpointercapture' + ]; + } else { + types = [ + 'MSPointerDown', + 'MSPointerMove', + 'MSPointerUp MSPointerCancel MSLostPointerCapture' + ]; + } + } else if(Hammer.NO_MOUSEEVENTS) { + types = [ + 'touchstart', + 'touchmove', + 'touchend touchcancel' + ]; + } else { + types = [ + 'touchstart mousedown', + 'touchmove mousemove', + 'touchend touchcancel mouseup' + ]; + } - if (item) { - // update item + EVENT_TYPES[EVENT_START] = types[0]; + EVENT_TYPES[EVENT_MOVE] = types[1]; + EVENT_TYPES[EVENT_END] = types[2]; + return EVENT_TYPES; + }, - // execute async handler to update the item (or cancel it) - var itemData = me.itemsData.get(item.id); // get a clone of the data from the dataset - this.options.onUpdate(itemData, function (itemData) { - if (itemData) { - me.itemsData.getDataSet().update(itemData); - } - }); - } - else { - // add item - var xAbs = util.getAbsoluteLeft(this.dom.frame); - var x = event.gesture.center.pageX - xAbs; - var start = this.body.util.toTime(x); - var newItem = { - start: snap ? snap(start) : start, - content: 'new item' - }; + /** + * create touchList depending on the event + * @method getTouchList + * @param {Object} ev + * @param {String} eventType + * @return {Array} touches + */ + getTouchList: function getTouchList(ev, eventType) { + // get the fake pointerEvent touchlist + if(Hammer.HAS_POINTEREVENTS) { + return PointerEvent.getTouchList(); + } - // when default type is a range, add a default end date to the new item - if (this.options.type === 'range') { - var end = this.body.util.toTime(x + this.props.width / 5); - newItem.end = snap ? snap(end) : end; - } + // get the touchlist + if(ev.touches) { + if(eventType == EVENT_MOVE) { + return ev.touches; + } - newItem[this.itemsData._fieldId] = util.randomUUID(); + var identifiers = []; + var concat = [].concat(Utils.toArray(ev.touches), Utils.toArray(ev.changedTouches)); + var touchList = []; - var group = ItemSet.groupFromTarget(event); - if (group) { - newItem.group = group.groupId; - } + Utils.each(concat, function(touch) { + if(Utils.inArray(identifiers, touch.identifier) === false) { + touchList.push(touch); + } + identifiers.push(touch.identifier); + }); - // execute async handler to customize (or cancel) adding an item - this.options.onAdd(newItem, function (item) { - if (item) { - me.itemsData.getDataSet().add(item); - // TODO: need to trigger a redraw? - } - }); - } + return touchList; + } + + // make fake touchList from mouse position + ev.identifier = 1; + return [ev]; + }, + + /** + * collect basic event data + * @method collectEventData + * @param {HTMLElement} element + * @param {String} eventType matches `EVENT_START|MOVE|END` + * @param {Array} touches + * @param {Object} ev + * @return {Object} ev + */ + collectEventData: function collectEventData(element, eventType, touches, ev) { + // find out pointerType + var pointerType = POINTER_TOUCH; + if(Utils.inStr(ev.type, 'mouse') || PointerEvent.matchType(POINTER_MOUSE, ev)) { + pointerType = POINTER_MOUSE; + } else if(PointerEvent.matchType(POINTER_PEN, ev)) { + pointerType = POINTER_PEN; + } + + return { + center: Utils.getCenter(touches), + timeStamp: Date.now(), + target: ev.target, + touches: touches, + eventType: eventType, + pointerType: pointerType, + srcEvent: ev, + + /** + * prevent the browser default actions + * mostly used to disable scrolling of the browser + */ + preventDefault: function() { + var srcEvent = this.srcEvent; + srcEvent.preventManipulation && srcEvent.preventManipulation(); + srcEvent.preventDefault && srcEvent.preventDefault(); + }, + + /** + * stop bubbling the event up to its parents + */ + stopPropagation: function() { + this.srcEvent.stopPropagation(); + }, + + /** + * immediately stop gesture detection + * might be useful after a swipe was detected + * @return {*} + */ + stopDetect: function() { + return Detection.stopDetect(); + } + }; + } }; + /** - * Handle selecting/deselecting multiple items when holding an item - * @param {Event} event - * @private + * @module hammer + * + * @class PointerEvent + * @static */ - ItemSet.prototype._onMultiSelectItem = function (event) { - if (!this.options.selectable) return; + var PointerEvent = Hammer.PointerEvent = { + /** + * holds all pointers, by `identifier` + * @property pointers + * @type {Object} + */ + pointers: {}, - var selection, - item = ItemSet.itemFromTarget(event); + /** + * get the pointers as an array + * @method getTouchList + * @return {Array} touchlist + */ + getTouchList: function getTouchList() { + var touchlist = []; + // we can use forEach since pointerEvents only is in IE10 + Utils.each(this.pointers, function(pointer) { + touchlist.push(pointer); + }); + return touchlist; + }, - if (item) { - // multi select items - selection = this.getSelection(); // current selection + /** + * update the position of a pointer + * @method updatePointer + * @param {String} eventType matches `EVENT_START|MOVE|END` + * @param {Object} pointerEvent + */ + updatePointer: function updatePointer(eventType, pointerEvent) { + if(eventType == EVENT_END || (eventType != EVENT_END && pointerEvent.buttons !== 1)) { + delete this.pointers[pointerEvent.pointerId]; + } else { + pointerEvent.identifier = pointerEvent.pointerId; + this.pointers[pointerEvent.pointerId] = pointerEvent; + } + }, - var shiftKey = event.gesture.touches[0] && event.gesture.touches[0].shiftKey || false; - if (shiftKey) { - // select all items between the old selection and the tapped item + /** + * check if ev matches pointertype + * @method matchType + * @param {String} pointerType matches `POINTER_MOUSE|TOUCH|PEN` + * @param {PointerEvent} ev + */ + matchType: function matchType(pointerType, ev) { + if(!ev.pointerType) { + return false; + } - // determine the selection range - selection.push(item.id); - var range = ItemSet._getItemRange(this.itemsData.get(selection, this.itemOptions)); + var pt = ev.pointerType, + types = {}; - // select all items within the selection range - selection = []; - for (var id in this.items) { - if (this.items.hasOwnProperty(id)) { - var _item = this.items[id]; - var start = _item.data.start; - var end = (_item.data.end !== undefined) ? _item.data.end : start; + types[POINTER_MOUSE] = (pt === (ev.MSPOINTER_TYPE_MOUSE || POINTER_MOUSE)); + types[POINTER_TOUCH] = (pt === (ev.MSPOINTER_TYPE_TOUCH || POINTER_TOUCH)); + types[POINTER_PEN] = (pt === (ev.MSPOINTER_TYPE_PEN || POINTER_PEN)); + return types[pointerType]; + }, - if (start >= range.min && end <= range.max) { - selection.push(_item.id); // do not use id but item.id, id itself is stringified - } - } - } - } - else { - // add/remove this item from the current selection - var index = selection.indexOf(item.id); - if (index == -1) { - // item is not yet selected -> select it - selection.push(item.id); - } - else { - // item is already selected -> deselect it - selection.splice(index, 1); - } + /** + * reset the stored pointers + * @method reset + */ + reset: function resetList() { + this.pointers = {}; } - - this.setSelection(selection); - - this.body.emitter.emit('select', { - items: this.getSelection() - }); - } }; + /** - * Calculate the time range of a list of items - * @param {Array.} itemsData - * @return {{min: Date, max: Date}} Returns the range of the provided items - * @private + * @module hammer + * + * @class Detection + * @static */ - ItemSet._getItemRange = function(itemsData) { - var max = null; - var min = null; + var Detection = Hammer.detection = { + // contains all registred Hammer.gestures in the correct order + gestures: [], - itemsData.forEach(function (data) { - if (min == null || data.start < min) { - min = data.start; - } + // data of the current Hammer.gesture detection session + current: null, - if (data.end != undefined) { - if (max == null || data.end > max) { - max = data.end; - } - } - else { - if (max == null || data.start > max) { - max = data.start; - } - } - }); + // the previous Hammer.gesture session data + // is a full clone of the previous gesture.current object + previous: null, - return { - min: min, - max: max - } - }; + // when this becomes true, no gestures are fired + stopped: false, - /** - * Find an item from an event target: - * searches for the attribute 'timeline-item' in the event target's element tree - * @param {Event} event - * @return {Item | null} item - */ - ItemSet.itemFromTarget = function(event) { - var target = event.target; - while (target) { - if (target.hasOwnProperty('timeline-item')) { - return target['timeline-item']; - } - target = target.parentNode; - } + /** + * start Hammer.gesture detection + * @method startDetect + * @param {Hammer.Instance} inst + * @param {Object} eventData + */ + startDetect: function startDetect(inst, eventData) { + // already busy with a Hammer.gesture detection on an element + if(this.current) { + return; + } - return null; - }; + this.stopped = false; - /** - * Find the Group from an event target: - * searches for the attribute 'timeline-group' in the event target's element tree - * @param {Event} event - * @return {Group | null} group - */ - ItemSet.groupFromTarget = function(event) { - var target = event.target; - while (target) { - if (target.hasOwnProperty('timeline-group')) { - return target['timeline-group']; - } - target = target.parentNode; - } + // holds current session + this.current = { + inst: inst, // reference to HammerInstance we're working for + startEvent: Utils.extend({}, eventData), // start eventData for distances, timing etc + lastEvent: false, // last eventData + lastCalcEvent: false, // last eventData for calculations. + futureCalcEvent: false, // last eventData for calculations. + lastCalcData: {}, // last lastCalcData + name: '' // current gesture we're in/detected, can be 'tap', 'hold' etc + }; - return null; - }; + this.detect(eventData); + }, - /** - * Find the ItemSet from an event target: - * searches for the attribute 'timeline-itemset' in the event target's element tree - * @param {Event} event - * @return {ItemSet | null} item - */ - ItemSet.itemSetFromTarget = function(event) { - var target = event.target; - while (target) { - if (target.hasOwnProperty('timeline-itemset')) { - return target['timeline-itemset']; - } - target = target.parentNode; - } + /** + * Hammer.gesture detection + * @method detect + * @param {Object} eventData + * @return {any} + */ + detect: function detect(eventData) { + if(!this.current || this.stopped) { + return; + } - return null; - }; + // extend event data with calculations about scale, distance etc + eventData = this.extendEventData(eventData); - module.exports = ItemSet; + // hammer instance and instance options + var inst = this.current.inst, + instOptions = inst.options; + // call Hammer.gesture handlers + Utils.each(this.gestures, function triggerGesture(gesture) { + // only when the instance options have enabled this gesture + if(!this.stopped && inst.enabled && instOptions[gesture.name]) { + gesture.handler.call(gesture, eventData, inst); + } + }, this); -/***/ }, -/* 28 */ -/***/ function(module, exports, __webpack_require__) { + // store as previous event event + if(this.current) { + this.current.lastEvent = eventData; + } - var util = __webpack_require__(1); - var DOMutil = __webpack_require__(2); - var Component = __webpack_require__(20); + if(eventData.eventType == EVENT_END) { + this.stopDetect(); + } - /** - * Legend for Graph2d - */ - function Legend(body, options, side, linegraphOptions) { - this.body = body; - this.defaultOptions = { - enabled: true, - icons: true, - iconSize: 20, - iconSpacing: 6, - left: { - visible: true, - position: 'top-left' // top/bottom - left,center,right + return eventData; }, - right: { - visible: true, - position: 'top-left' // top/bottom - left,center,right - } - } - this.side = side; - this.options = util.extend({},this.defaultOptions); - this.linegraphOptions = linegraphOptions; - this.svgElements = {}; - this.dom = {}; - this.groups = {}; - this.amountOfGroups = 0; - this._create(); + /** + * clear the Hammer.gesture vars + * this is called on endDetect, but can also be used when a final Hammer.gesture has been detected + * to stop other Hammer.gestures from being fired + * @method stopDetect + */ + stopDetect: function stopDetect() { + // clone current data to the store as the previous gesture + // used for the double tap gesture, since this is an other gesture detect session + this.previous = Utils.extend({}, this.current); - this.setOptions(options); - } + // reset the current + this.current = null; + this.stopped = true; + }, - Legend.prototype = new Component(); + /** + * calculate velocity, angle and direction + * @method getVelocityData + * @param {Object} ev + * @param {Object} center + * @param {Number} deltaTime + * @param {Number} deltaX + * @param {Number} deltaY + */ + getCalculatedData: function getCalculatedData(ev, center, deltaTime, deltaX, deltaY) { + var cur = this.current, + recalc = false, + calcEv = cur.lastCalcEvent, + calcData = cur.lastCalcData; - Legend.prototype.clear = function() { - this.groups = {}; - this.amountOfGroups = 0; - } + if(calcEv && ev.timeStamp - calcEv.timeStamp > Hammer.CALCULATE_INTERVAL) { + center = calcEv.center; + deltaTime = ev.timeStamp - calcEv.timeStamp; + deltaX = ev.center.clientX - calcEv.center.clientX; + deltaY = ev.center.clientY - calcEv.center.clientY; + recalc = true; + } - Legend.prototype.addGroup = function(label, graphOptions) { + if(ev.eventType == EVENT_TOUCH || ev.eventType == EVENT_RELEASE) { + cur.futureCalcEvent = ev; + } - if (!this.groups.hasOwnProperty(label)) { - this.groups[label] = graphOptions; - } - this.amountOfGroups += 1; - }; + if(!cur.lastCalcEvent || recalc) { + calcData.velocity = Utils.getVelocity(deltaTime, deltaX, deltaY); + calcData.angle = Utils.getAngle(center, ev.center); + calcData.direction = Utils.getDirection(center, ev.center); - Legend.prototype.updateGroup = function(label, graphOptions) { - this.groups[label] = graphOptions; - }; + cur.lastCalcEvent = cur.futureCalcEvent || ev; + cur.futureCalcEvent = ev; + } - Legend.prototype.removeGroup = function(label) { - if (this.groups.hasOwnProperty(label)) { - delete this.groups[label]; - this.amountOfGroups -= 1; - } - }; + ev.velocityX = calcData.velocity.x; + ev.velocityY = calcData.velocity.y; + ev.interimAngle = calcData.angle; + ev.interimDirection = calcData.direction; + }, - Legend.prototype._create = function() { - this.dom.frame = document.createElement('div'); - this.dom.frame.className = 'legend'; - this.dom.frame.style.position = "absolute"; - this.dom.frame.style.top = "10px"; - this.dom.frame.style.display = "block"; + /** + * extend eventData for Hammer.gestures + * @method extendEventData + * @param {Object} ev + * @return {Object} ev + */ + extendEventData: function extendEventData(ev) { + var cur = this.current, + startEv = cur.startEvent, + lastEv = cur.lastEvent || startEv; - this.dom.textArea = document.createElement('div'); - this.dom.textArea.className = 'legendText'; - this.dom.textArea.style.position = "relative"; - this.dom.textArea.style.top = "0px"; + // update the start touchlist to calculate the scale/rotation + if(ev.eventType == EVENT_TOUCH || ev.eventType == EVENT_RELEASE) { + startEv.touches = []; + Utils.each(ev.touches, function(touch) { + startEv.touches.push({ + clientX: touch.clientX, + clientY: touch.clientY + }); + }); + } - this.svg = document.createElementNS('http://www.w3.org/2000/svg',"svg"); - this.svg.style.position = 'absolute'; - this.svg.style.top = 0 +'px'; - this.svg.style.width = this.options.iconSize + 5 + 'px'; - this.svg.style.height = '100%'; + var deltaTime = ev.timeStamp - startEv.timeStamp, + deltaX = ev.center.clientX - startEv.center.clientX, + deltaY = ev.center.clientY - startEv.center.clientY; - this.dom.frame.appendChild(this.svg); - this.dom.frame.appendChild(this.dom.textArea); - }; + this.getCalculatedData(ev, lastEv.center, deltaTime, deltaX, deltaY); - /** - * Hide the component from the DOM - */ - Legend.prototype.hide = function() { - // remove the frame containing the items - if (this.dom.frame.parentNode) { - this.dom.frame.parentNode.removeChild(this.dom.frame); - } - }; + Utils.extend(ev, { + startEvent: startEv, - /** - * Show the component in the DOM (when not already visible). - * @return {Boolean} changed - */ - Legend.prototype.show = function() { - // show frame containing the items - if (!this.dom.frame.parentNode) { - this.body.dom.center.appendChild(this.dom.frame); - } - }; + deltaTime: deltaTime, + deltaX: deltaX, + deltaY: deltaY, - Legend.prototype.setOptions = function(options) { - var fields = ['enabled','orientation','icons','left','right']; - util.selectiveDeepExtend(fields, this.options, options); - }; + distance: Utils.getDistance(startEv.center, ev.center), + angle: Utils.getAngle(startEv.center, ev.center), + direction: Utils.getDirection(startEv.center, ev.center), + scale: Utils.getScale(startEv.touches, ev.touches), + rotation: Utils.getRotation(startEv.touches, ev.touches) + }); - Legend.prototype.redraw = function() { - var activeGroups = 0; - for (var groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) { - activeGroups++; - } - } - } + return ev; + }, - if (this.options[this.side].visible == false || this.amountOfGroups == 0 || this.options.enabled == false || activeGroups == 0) { - this.hide(); - } - else { - this.show(); - if (this.options[this.side].position == 'top-left' || this.options[this.side].position == 'bottom-left') { - this.dom.frame.style.left = '4px'; - this.dom.frame.style.textAlign = "left"; - this.dom.textArea.style.textAlign = "left"; - this.dom.textArea.style.left = (this.options.iconSize + 15) + 'px'; - this.dom.textArea.style.right = ''; - this.svg.style.left = 0 +'px'; - this.svg.style.right = ''; - } - else { - this.dom.frame.style.right = '4px'; - this.dom.frame.style.textAlign = "right"; - this.dom.textArea.style.textAlign = "right"; - this.dom.textArea.style.right = (this.options.iconSize + 15) + 'px'; - this.dom.textArea.style.left = ''; - this.svg.style.right = 0 +'px'; - this.svg.style.left = ''; - } + /** + * register new gesture + * @method register + * @param {Object} gesture object, see `gestures/` for documentation + * @return {Array} gestures + */ + register: function register(gesture) { + // add an enable gesture options if there is no given + var options = gesture.defaults || {}; + if(options[gesture.name] === undefined) { + options[gesture.name] = true; + } - if (this.options[this.side].position == 'top-left' || this.options[this.side].position == 'top-right') { - this.dom.frame.style.top = 4 - Number(this.body.dom.center.style.top.replace("px","")) + 'px'; - this.dom.frame.style.bottom = ''; - } - else { - var scrollableHeight = this.body.domProps.center.height - this.body.domProps.centerContainer.height; - this.dom.frame.style.bottom = 4 + scrollableHeight + Number(this.body.dom.center.style.top.replace("px","")) + 'px'; - this.dom.frame.style.top = ''; - } + // extend Hammer default options with the Hammer.gesture options + Utils.extend(Hammer.defaults, options, true); - if (this.options.icons == false) { - this.dom.frame.style.width = this.dom.textArea.offsetWidth + 10 + 'px'; - this.dom.textArea.style.right = ''; - this.dom.textArea.style.left = ''; - this.svg.style.width = '0px'; - } - else { - this.dom.frame.style.width = this.options.iconSize + 15 + this.dom.textArea.offsetWidth + 10 + 'px' - this.drawLegendIcons(); - } + // set its index + gesture.index = gesture.index || 1000; - var content = ''; - for (var groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) { - content += this.groups[groupId].content + '
'; - } - } + // add Hammer.gesture to the list + this.gestures.push(gesture); + + // sort the list by index + this.gestures.sort(function(a, b) { + if(a.index < b.index) { + return -1; + } + if(a.index > b.index) { + return 1; + } + return 0; + }); + + return this.gestures; } - this.dom.textArea.innerHTML = content; - this.dom.textArea.style.lineHeight = ((0.75 * this.options.iconSize) + this.options.iconSpacing) + 'px'; - } }; - Legend.prototype.drawLegendIcons = function() { - if (this.dom.frame.parentNode) { - DOMutil.prepareElements(this.svgElements); - var padding = window.getComputedStyle(this.dom.frame).paddingTop; - var iconOffset = Number(padding.replace('px','')); - var x = iconOffset; - var iconWidth = this.options.iconSize; - var iconHeight = 0.75 * this.options.iconSize; - var y = iconOffset + 0.5 * iconHeight + 3; - this.svg.style.width = iconWidth + 5 + iconOffset + 'px'; + /** + * @module hammer + */ - for (var groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) { - this.groups[groupId].drawIcon(x, y, this.svgElements, this.svg, iconWidth, iconHeight); - y += iconHeight + this.options.iconSpacing; - } - } - } + /** + * create new hammer instance + * all methods should return the instance itself, so it is chainable. + * + * @class Instance + * @constructor + * @param {HTMLElement} element + * @param {Object} [options={}] options are merged with `Hammer.defaults` + * @return {Hammer.Instance} + */ + Hammer.Instance = function(element, options) { + var self = this; - DOMutil.cleanupElements(this.svgElements); - } - }; + // setup HammerJS window events and register all gestures + // this also sets up the default options + setup(); - module.exports = Legend; + /** + * @property element + * @type {HTMLElement} + */ + this.element = element; + /** + * @property enabled + * @type {Boolean} + * @protected + */ + this.enabled = true; -/***/ }, -/* 29 */ -/***/ function(module, exports, __webpack_require__) { + /** + * options, merged with the defaults + * options with an _ are converted to camelCase + * @property options + * @type {Object} + */ + Utils.each(options, function(value, name) { + delete options[name]; + options[Utils.toCamelCase(name)] = value; + }); - var util = __webpack_require__(1); - var DOMutil = __webpack_require__(2); - var DataSet = __webpack_require__(3); - var DataView = __webpack_require__(4); - var Component = __webpack_require__(20); - var DataAxis = __webpack_require__(23); - var GraphGroup = __webpack_require__(24); - var Legend = __webpack_require__(28); - var BarGraphFunctions = __webpack_require__(52); + this.options = Utils.extend(Utils.extend({}, Hammer.defaults), options || {}); - var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items + // add some css to the element to prevent the browser from doing its native behavoir + if(this.options.behavior) { + Utils.toggleBehavior(this.element, this.options.behavior, true); + } - /** - * This is the constructor of the LineGraph. It requires a Timeline body and options. - * - * @param body - * @param options - * @constructor - */ - function LineGraph(body, options) { - this.id = util.randomUUID(); - this.body = body; + /** + * event start handler on the element to start the detection + * @property eventStartHandler + * @type {Object} + */ + this.eventStartHandler = Event.onTouch(element, EVENT_START, function(ev) { + if(self.enabled && ev.eventType == EVENT_START) { + Detection.startDetect(self, ev); + } else if(ev.eventType == EVENT_TOUCH) { + Detection.detect(ev); + } + }); - this.defaultOptions = { - yAxisOrientation: 'left', - defaultGroup: 'default', - sort: true, - sampling: true, - graphHeight: '400px', - shaded: { - enabled: false, - orientation: 'bottom' // top, bottom - }, - style: 'line', // line, bar - barChart: { - width: 50, - handleOverlap: 'overlap', - align: 'center' // left, center, right - }, - catmullRom: { - enabled: true, - parametrization: 'centripetal', // uniform (alpha = 0.0), chordal (alpha = 1.0), centripetal (alpha = 0.5) - alpha: 0.5 - }, - drawPoints: { - enabled: true, - size: 6, - style: 'square' // square, circle - }, - dataAxis: { - showMinorLabels: true, - showMajorLabels: true, - icons: false, - width: '40px', - visible: true, - alignZeros: true, - customRange: { - left: {min:undefined, max:undefined}, - right: {min:undefined, max:undefined} - } - //, these options are not set by default, but this shows the format they will be in - //format: { - // left: {decimals: 2}, - // right: {decimals: 2} - //}, - //title: { - // left: { - // text: 'left', - // style: 'color:black;' - // }, - // right: { - // text: 'right', - // style: 'color:black;' - // } - //} - }, - legend: { - enabled: false, - icons: true, - left: { - visible: true, - position: 'top-left' // top/bottom - left,right - }, - right: { - visible: true, - position: 'top-right' // top/bottom - left,right - } - }, - groups: { - visibility: {} - } - }; - - // options is shared by this ItemSet and all its items - this.options = util.extend({}, this.defaultOptions); - this.dom = {}; - this.props = {}; - this.hammer = null; - this.groups = {}; - this.abortedGraphUpdate = false; - this.updateSVGheight = false; - this.updateSVGheightOnResize = false; - - var me = this; - this.itemsData = null; // DataSet - this.groupsData = null; // DataSet - - // listeners for the DataSet of the items - this.itemListeners = { - 'add': function (event, params, senderId) { - me._onAdd(params.items); - }, - 'update': function (event, params, senderId) { - me._onUpdate(params.items); - }, - 'remove': function (event, params, senderId) { - me._onRemove(params.items); - } - }; + /** + * keep a list of user event handlers which needs to be removed when calling 'dispose' + * @property eventHandlers + * @type {Array} + */ + this.eventHandlers = []; + }; - // listeners for the DataSet of the groups - this.groupListeners = { - 'add': function (event, params, senderId) { - me._onAddGroups(params.items); - }, - 'update': function (event, params, senderId) { - me._onUpdateGroups(params.items); + Hammer.Instance.prototype = { + /** + * bind events to the instance + * @method on + * @chainable + * @param {String} gestures multiple gestures by splitting with a space + * @param {Function} handler + * @param {Object} handler.ev event object + */ + on: function onEvent(gestures, handler) { + var self = this; + Event.on(self.element, gestures, handler, function(type) { + self.eventHandlers.push({ gesture: type, handler: handler }); + }); + return self; }, - 'remove': function (event, params, senderId) { - me._onRemoveGroups(params.items); - } - }; - - this.items = {}; // object with an Item for every data item - this.selection = []; // list with the ids of all selected nodes - this.lastStart = this.body.range.start; - this.touchParams = {}; // stores properties while dragging - - this.svgElements = {}; - this.setOptions(options); - this.groupsUsingDefaultStyles = [0]; - this.COUNTER = 0; - this.body.emitter.on('rangechanged', function() { - me.lastStart = me.body.range.start; - me.svg.style.left = util.option.asSize(-me.props.width); - me.redraw.call(me,true); - }); - - // create the HTML DOM - this._create(); - this.framework = {svg: this.svg, svgElements: this.svgElements, options: this.options, groups: this.groups}; - this.body.emitter.emit('change'); - } + /** + * unbind events to the instance + * @method off + * @chainable + * @param {String} gestures + * @param {Function} handler + */ + off: function offEvent(gestures, handler) { + var self = this; - LineGraph.prototype = new Component(); + Event.off(self.element, gestures, handler, function(type) { + var index = Utils.inArray({ gesture: type, handler: handler }); + if(index !== false) { + self.eventHandlers.splice(index, 1); + } + }); + return self; + }, - /** - * Create the HTML DOM for the ItemSet - */ - LineGraph.prototype._create = function(){ - var frame = document.createElement('div'); - frame.className = 'LineGraph'; - this.dom.frame = frame; + /** + * trigger gesture event + * @method trigger + * @chainable + * @param {String} gesture + * @param {Object} [eventData] + */ + trigger: function triggerEvent(gesture, eventData) { + // optional + if(!eventData) { + eventData = {}; + } - // create svg element for graph drawing. - this.svg = document.createElementNS('http://www.w3.org/2000/svg','svg'); - this.svg.style.position = 'relative'; - this.svg.style.height = ('' + this.options.graphHeight).replace('px','') + 'px'; - this.svg.style.display = 'block'; - frame.appendChild(this.svg); + // create DOM event + var event = Hammer.DOCUMENT.createEvent('Event'); + event.initEvent(gesture, true, true); + event.gesture = eventData; - // data axis - this.options.dataAxis.orientation = 'left'; - this.yAxisLeft = new DataAxis(this.body, this.options.dataAxis, this.svg, this.options.groups); + // trigger on the target if it is in the instance element, + // this is for event delegation tricks + var element = this.element; + if(Utils.hasParent(eventData.target, element)) { + element = eventData.target; + } - this.options.dataAxis.orientation = 'right'; - this.yAxisRight = new DataAxis(this.body, this.options.dataAxis, this.svg, this.options.groups); - delete this.options.dataAxis.orientation; + element.dispatchEvent(event); + return this; + }, - // legends - this.legendLeft = new Legend(this.body, this.options.legend, 'left', this.options.groups); - this.legendRight = new Legend(this.body, this.options.legend, 'right', this.options.groups); + /** + * enable of disable hammer.js detection + * @method enable + * @chainable + * @param {Boolean} state + */ + enable: function enable(state) { + this.enabled = state; + return this; + }, - this.show(); - }; + /** + * dispose this hammer instance + * @method dispose + * @return {Null} + */ + dispose: function dispose() { + var i, eh; - /** - * set the options of the LineGraph. the mergeOptions is used for subObjects that have an enabled element. - * @param {object} options - */ - LineGraph.prototype.setOptions = function(options) { - if (options) { - var fields = ['sampling','defaultGroup','height','graphHeight','yAxisOrientation','style','barChart','dataAxis','sort','groups']; - if (options.graphHeight === undefined && options.height !== undefined && this.body.domProps.centerContainer.height !== undefined) { - this.updateSVGheight = true; - this.updateSVGheightOnResize = true; - } - else if (this.body.domProps.centerContainer.height !== undefined && options.graphHeight !== undefined) { - if (parseInt((options.graphHeight + '').replace("px",'')) < this.body.domProps.centerContainer.height) { - this.updateSVGheight = true; - } - } - util.selectiveDeepExtend(fields, this.options, options); - util.mergeOptions(this.options, options,'catmullRom'); - util.mergeOptions(this.options, options,'drawPoints'); - util.mergeOptions(this.options, options,'shaded'); - util.mergeOptions(this.options, options,'legend'); + // undo all changes made by stop_browser_behavior + Utils.toggleBehavior(this.element, this.options.behavior, false); - if (options.catmullRom) { - if (typeof options.catmullRom == 'object') { - if (options.catmullRom.parametrization) { - if (options.catmullRom.parametrization == 'uniform') { - this.options.catmullRom.alpha = 0; - } - else if (options.catmullRom.parametrization == 'chordal') { - this.options.catmullRom.alpha = 1.0; - } - else { - this.options.catmullRom.parametrization = 'centripetal'; - this.options.catmullRom.alpha = 0.5; - } + // unbind all custom event handlers + for(i = -1; (eh = this.eventHandlers[++i]);) { + Utils.off(this.element, eh.gesture, eh.handler); } - } - } - if (this.yAxisLeft) { - if (options.dataAxis !== undefined) { - this.yAxisLeft.setOptions(this.options.dataAxis); - this.yAxisRight.setOptions(this.options.dataAxis); - } - } + this.eventHandlers = []; - if (this.legendLeft) { - if (options.legend !== undefined) { - this.legendLeft.setOptions(this.options.legend); - this.legendRight.setOptions(this.options.legend); - } - } + // unbind the start event listener + Event.off(this.element, EVENT_TYPES[EVENT_START], this.eventStartHandler); - if (this.groups.hasOwnProperty(UNGROUPED)) { - this.groups[UNGROUPED].setOptions(options); + return null; } - } - - // this is used to redraw the graph if the visibility of the groups is changed. - if (this.dom.frame) { - this.redraw(true); - } }; + /** - * Hide the component from the DOM + * @module gestures */ - LineGraph.prototype.hide = function() { - // remove the frame containing the items - if (this.dom.frame.parentNode) { - this.dom.frame.parentNode.removeChild(this.dom.frame); - } - }; - - /** - * Show the component in the DOM (when not already visible). - * @return {Boolean} changed + * Move with x fingers (default 1) around on the page. + * Preventing the default browser behavior is a good way to improve feel and working. + * ```` + * hammertime.on("drag", function(ev) { + * console.log(ev); + * ev.gesture.preventDefault(); + * }); + * ```` + * + * @class Drag + * @static + */ + /** + * @event drag + * @param {Object} ev + */ + /** + * @event dragstart + * @param {Object} ev + */ + /** + * @event dragend + * @param {Object} ev + */ + /** + * @event drapleft + * @param {Object} ev + */ + /** + * @event dragright + * @param {Object} ev + */ + /** + * @event dragup + * @param {Object} ev + */ + /** + * @event dragdown + * @param {Object} ev */ - LineGraph.prototype.show = function() { - // show frame containing the items - if (!this.dom.frame.parentNode) { - this.body.dom.center.appendChild(this.dom.frame); - } - }; - /** - * Set items - * @param {vis.DataSet | null} items + * @param {String} name */ - LineGraph.prototype.setItems = function(items) { - var me = this, - ids, - oldItemsData = this.itemsData; + (function(name) { + var triggered = false; - // replace the dataset - if (!items) { - this.itemsData = null; - } - else if (items instanceof DataSet || items instanceof DataView) { - this.itemsData = items; - } - else { - throw new TypeError('Data must be an instance of DataSet or DataView'); - } + function dragGesture(ev, inst) { + var cur = Detection.current; - if (oldItemsData) { - // unsubscribe from old dataset - util.forEach(this.itemListeners, function (callback, event) { - oldItemsData.off(event, callback); - }); + // max touches + if(inst.options.dragMaxTouches > 0 && + ev.touches.length > inst.options.dragMaxTouches) { + return; + } - // remove all drawn items - ids = oldItemsData.getIds(); - this._onRemove(ids); - } + switch(ev.eventType) { + case EVENT_START: + triggered = false; + break; - if (this.itemsData) { - // subscribe to new dataset - var id = this.id; - util.forEach(this.itemListeners, function (callback, event) { - me.itemsData.on(event, callback, id); - }); + case EVENT_MOVE: + // when the distance we moved is too small we skip this gesture + // or we can be already in dragging + if(ev.distance < inst.options.dragMinDistance && + cur.name != name) { + return; + } - // add all new items - ids = this.itemsData.getIds(); - this._onAdd(ids); - } - this._updateUngrouped(); - //this._updateGraph(); - this.redraw(true); - }; + var startCenter = cur.startEvent.center; + // we are dragging! + if(cur.name != name) { + cur.name = name; + if(inst.options.dragDistanceCorrection && ev.distance > 0) { + // When a drag is triggered, set the event center to dragMinDistance pixels from the original event center. + // Without this correction, the dragged distance would jumpstart at dragMinDistance pixels instead of at 0. + // It might be useful to save the original start point somewhere + var factor = Math.abs(inst.options.dragMinDistance / ev.distance); + startCenter.pageX += ev.deltaX * factor; + startCenter.pageY += ev.deltaY * factor; + startCenter.clientX += ev.deltaX * factor; + startCenter.clientY += ev.deltaY * factor; - /** - * Set groups - * @param {vis.DataSet} groups - */ - LineGraph.prototype.setGroups = function(groups) { - var me = this; - var ids; + // recalculate event data using new start point + ev = Detection.extendEventData(ev); + } + } - // unsubscribe from current dataset - if (this.groupsData) { - util.forEach(this.groupListeners, function (callback, event) { - me.groupsData.unsubscribe(event, callback); - }); + // lock drag to axis? + if(cur.lastEvent.dragLockToAxis || + ( inst.options.dragLockToAxis && + inst.options.dragLockMinDistance <= ev.distance + )) { + ev.dragLockToAxis = true; + } - // remove all drawn groups - ids = this.groupsData.getIds(); - this.groupsData = null; - this._onRemoveGroups(ids); // note: this will cause a redraw - } + // keep direction on the axis that the drag gesture started on + var lastDirection = cur.lastEvent.direction; + if(ev.dragLockToAxis && lastDirection !== ev.direction) { + if(Utils.isVertical(lastDirection)) { + ev.direction = (ev.deltaY < 0) ? DIRECTION_UP : DIRECTION_DOWN; + } else { + ev.direction = (ev.deltaX < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT; + } + } - // replace the dataset - if (!groups) { - this.groupsData = null; - } - else if (groups instanceof DataSet || groups instanceof DataView) { - this.groupsData = groups; - } - else { - throw new TypeError('Data must be an instance of DataSet or DataView'); - } + // first time, trigger dragstart event + if(!triggered) { + inst.trigger(name + 'start', ev); + triggered = true; + } - if (this.groupsData) { - // subscribe to new dataset - var id = this.id; - util.forEach(this.groupListeners, function (callback, event) { - me.groupsData.on(event, callback, id); - }); + // trigger events + inst.trigger(name, ev); + inst.trigger(name + ev.direction, ev); - // draw all ms - ids = this.groupsData.getIds(); - this._onAddGroups(ids); - } - this._onUpdate(); - }; + var isVertical = Utils.isVertical(ev.direction); + // block the browser events + if((inst.options.dragBlockVertical && isVertical) || + (inst.options.dragBlockHorizontal && !isVertical)) { + ev.preventDefault(); + } + break; - /** - * Update the data - * @param [ids] - * @private - */ - LineGraph.prototype._onUpdate = function(ids) { - this._updateUngrouped(); - this._updateAllGroupData(); - //this._updateGraph(); - this.redraw(true); - }; - LineGraph.prototype._onAdd = function (ids) {this._onUpdate(ids);}; - LineGraph.prototype._onRemove = function (ids) {this._onUpdate(ids);}; - LineGraph.prototype._onUpdateGroups = function (groupIds) { - for (var i = 0; i < groupIds.length; i++) { - var group = this.groupsData.get(groupIds[i]); - this._updateGroup(group, groupIds[i]); - } + case EVENT_RELEASE: + if(triggered && ev.changedLength <= inst.options.dragMaxTouches) { + inst.trigger(name + 'end', ev); + triggered = false; + } + break; - //this._updateGraph(); - this.redraw(true); - }; - LineGraph.prototype._onAddGroups = function (groupIds) {this._onUpdateGroups(groupIds);}; + case EVENT_END: + triggered = false; + break; + } + } + Hammer.gestures.Drag = { + name: name, + index: 50, + handler: dragGesture, + defaults: { + /** + * minimal movement that have to be made before the drag event gets triggered + * @property dragMinDistance + * @type {Number} + * @default 10 + */ + dragMinDistance: 10, - /** - * this cleans the group out off the legends and the dataaxis, updates the ungrouped and updates the graph - * @param {Array} groupIds - * @private - */ - LineGraph.prototype._onRemoveGroups = function (groupIds) { - for (var i = 0; i < groupIds.length; i++) { - if (this.groups.hasOwnProperty(groupIds[i])) { - if (this.groups[groupIds[i]].options.yAxisOrientation == 'right') { - this.yAxisRight.removeGroup(groupIds[i]); - this.legendRight.removeGroup(groupIds[i]); - this.legendRight.redraw(); - } - else { - this.yAxisLeft.removeGroup(groupIds[i]); - this.legendLeft.removeGroup(groupIds[i]); - this.legendLeft.redraw(); - } - delete this.groups[groupIds[i]]; - } - } - this._updateUngrouped(); - //this._updateGraph(); - this.redraw(true); - }; + /** + * Set dragDistanceCorrection to true to make the starting point of the drag + * be calculated from where the drag was triggered, not from where the touch started. + * Useful to avoid a jerk-starting drag, which can make fine-adjustments + * through dragging difficult, and be visually unappealing. + * @property dragDistanceCorrection + * @type {Boolean} + * @default true + */ + dragDistanceCorrection: true, + + /** + * set 0 for unlimited, but this can conflict with transform + * @property dragMaxTouches + * @type {Number} + * @default 1 + */ + dragMaxTouches: 1, + + /** + * prevent default browser behavior when dragging occurs + * be careful with it, it makes the element a blocking element + * when you are using the drag gesture, it is a good practice to set this true + * @property dragBlockHorizontal + * @type {Boolean} + * @default false + */ + dragBlockHorizontal: false, + + /** + * same as `dragBlockHorizontal`, but for vertical movement + * @property dragBlockVertical + * @type {Boolean} + * @default false + */ + dragBlockVertical: false, + + /** + * dragLockToAxis keeps the drag gesture on the axis that it started on, + * It disallows vertical directions if the initial direction was horizontal, and vice versa. + * @property dragLockToAxis + * @type {Boolean} + * @default false + */ + dragLockToAxis: false, + /** + * drag lock only kicks in when distance > dragLockMinDistance + * This way, locking occurs only when the distance has become large enough to reliably determine the direction + * @property dragLockMinDistance + * @type {Number} + * @default 25 + */ + dragLockMinDistance: 25 + } + }; + })('drag'); /** - * update a group object with the group dataset entree + * @module gestures + */ + /** + * trigger a simple gesture event, so you can do anything in your handler. + * only usable if you know what your doing... * - * @param group - * @param groupId - * @private + * @class Gesture + * @static */ - LineGraph.prototype._updateGroup = function (group, groupId) { - if (!this.groups.hasOwnProperty(groupId)) { - this.groups[groupId] = new GraphGroup(group, groupId, this.options, this.groupsUsingDefaultStyles); - if (this.groups[groupId].options.yAxisOrientation == 'right') { - this.yAxisRight.addGroup(groupId, this.groups[groupId]); - this.legendRight.addGroup(groupId, this.groups[groupId]); - } - else { - this.yAxisLeft.addGroup(groupId, this.groups[groupId]); - this.legendLeft.addGroup(groupId, this.groups[groupId]); - } - } - else { - this.groups[groupId].update(group); - if (this.groups[groupId].options.yAxisOrientation == 'right') { - this.yAxisRight.updateGroup(groupId, this.groups[groupId]); - this.legendRight.updateGroup(groupId, this.groups[groupId]); - } - else { - this.yAxisLeft.updateGroup(groupId, this.groups[groupId]); - this.legendLeft.updateGroup(groupId, this.groups[groupId]); + /** + * @event gesture + * @param {Object} ev + */ + Hammer.gestures.Gesture = { + name: 'gesture', + index: 1337, + handler: function releaseGesture(ev, inst) { + inst.trigger(this.name, ev); } - } - this.legendLeft.redraw(); - this.legendRight.redraw(); }; - /** - * this updates all groups, it is used when there is an update the the itemset. + * @module gestures + */ + /** + * Touch stays at the same place for x time * - * @private + * @class Hold + * @static */ - LineGraph.prototype._updateAllGroupData = function () { - if (this.itemsData != null) { - var groupsContent = {}; - var groupId; - for (groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - groupsContent[groupId] = []; - } - } - for (var itemId in this.itemsData._data) { - if (this.itemsData._data.hasOwnProperty(itemId)) { - var item = this.itemsData._data[itemId]; - if (groupsContent[item.group] === undefined) { - throw new Error('Cannot find referenced group. Possible reason: items added before groups? Groups need to be added before items, as items refer to groups.') - } - item.x = util.convert(item.x,'Date'); - groupsContent[item.group].push(item); - } - } - for (groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - this.groups[groupId].setItems(groupsContent[groupId]); - } - } - } - }; - - /** - * Create or delete the group holding all ungrouped items. This group is used when - * there are no groups specified. This anonymous group is called 'graph'. - * @protected + * @event hold + * @param {Object} ev */ - LineGraph.prototype._updateUngrouped = function() { - if (this.itemsData && this.itemsData != null) { - var ungroupedCounter = 0; - for (var itemId in this.itemsData._data) { - if (this.itemsData._data.hasOwnProperty(itemId)) { - var item = this.itemsData._data[itemId]; - if (item != undefined) { - if (item.hasOwnProperty('group')) { - if (item.group === undefined) { - item.group = UNGROUPED; - } - } - else { - item.group = UNGROUPED; - } - ungroupedCounter = item.group == UNGROUPED ? ungroupedCounter + 1 : ungroupedCounter; - } - } - } - - if (ungroupedCounter == 0) { - delete this.groups[UNGROUPED]; - this.legendLeft.removeGroup(UNGROUPED); - this.legendRight.removeGroup(UNGROUPED); - this.yAxisLeft.removeGroup(UNGROUPED); - this.yAxisRight.removeGroup(UNGROUPED); - } - else { - var group = {id: UNGROUPED, content: this.options.defaultGroup}; - this._updateGroup(group, UNGROUPED); - } - } - else { - delete this.groups[UNGROUPED]; - this.legendLeft.removeGroup(UNGROUPED); - this.legendRight.removeGroup(UNGROUPED); - this.yAxisLeft.removeGroup(UNGROUPED); - this.yAxisRight.removeGroup(UNGROUPED); - } - - this.legendLeft.redraw(); - this.legendRight.redraw(); - }; - /** - * Redraw the component, mandatory function - * @return {boolean} Returns true if the component is resized + * @param {String} name */ - LineGraph.prototype.redraw = function(forceGraphUpdate) { - var resized = false; - - // calculate actual size and position - this.props.width = this.dom.frame.offsetWidth; - this.props.height = this.body.domProps.centerContainer.height; - - // update the graph if there is no lastWidth or with, used for the initial draw - if (this.lastWidth === undefined && this.props.width) { - forceGraphUpdate = true; - } - - // check if this component is resized - resized = this._isResized() || resized; + (function(name) { + var timer; - // check whether zoomed (in that case we need to re-stack everything) - var visibleInterval = this.body.range.end - this.body.range.start; - var zoomed = (visibleInterval != this.lastVisibleInterval); - this.lastVisibleInterval = visibleInterval; + function holdGesture(ev, inst) { + var options = inst.options, + current = Detection.current; + switch(ev.eventType) { + case EVENT_START: + clearTimeout(timer); - // the svg element is three times as big as the width, this allows for fully dragging left and right - // without reloading the graph. the controls for this are bound to events in the constructor - if (resized == true) { - this.svg.style.width = util.option.asSize(3*this.props.width); - this.svg.style.left = util.option.asSize(-this.props.width); + // set the gesture so we can check in the timeout if it still is + current.name = name; - // if the height of the graph is set as proportional, change the height of the svg - if ((this.options.height + '').indexOf("%") != -1 || this.updateSVGheightOnResize == true) { - this.updateSVGheight = true; - } - } + // set timer and if after the timeout it still is hold, + // we trigger the hold event + timer = setTimeout(function() { + if(current && current.name == name) { + inst.trigger(name, ev); + } + }, options.holdTimeout); + break; - // update the height of the graph on each redraw of the graph. - if (this.updateSVGheight == true) { - if (this.options.graphHeight != this.body.domProps.centerContainer.height + 'px') { - this.options.graphHeight = this.body.domProps.centerContainer.height + 'px'; - this.svg.style.height = this.body.domProps.centerContainer.height + 'px'; - } - this.updateSVGheight = false; - } - else { - this.svg.style.height = ('' + this.options.graphHeight).replace('px','') + 'px'; - } + case EVENT_MOVE: + if(ev.distance > options.holdThreshold) { + clearTimeout(timer); + } + break; - // zoomed is here to ensure that animations are shown correctly. - if (resized == true || zoomed == true || this.abortedGraphUpdate == true || forceGraphUpdate == true) { - resized = this._updateGraph() || resized; - } - else { - // move the whole svg while dragging - if (this.lastStart != 0) { - var offset = this.body.range.start - this.lastStart; - var range = this.body.range.end - this.body.range.start; - if (this.props.width != 0) { - var rangePerPixelInv = this.props.width/range; - var xOffset = offset * rangePerPixelInv; - this.svg.style.left = (-this.props.width - xOffset) + 'px'; - } + case EVENT_RELEASE: + clearTimeout(timer); + break; + } } - } - this.legendLeft.redraw(); - this.legendRight.redraw(); - return resized; - }; + Hammer.gestures.Hold = { + name: name, + index: 10, + defaults: { + /** + * @property holdTimeout + * @type {Number} + * @default 500 + */ + holdTimeout: 500, + /** + * movement allowed while holding + * @property holdThreshold + * @type {Number} + * @default 2 + */ + holdThreshold: 2 + }, + handler: holdGesture + }; + })('hold'); /** - * Update and redraw the graph. + * @module gestures + */ + /** + * when a touch is being released from the page * + * @class Release + * @static */ - LineGraph.prototype._updateGraph = function () { - // reset the svg elements - DOMutil.prepareElements(this.svgElements); - if (this.props.width != 0 && this.itemsData != null) { - var group, i; - var preprocessedGroupData = {}; - var processedGroupData = {}; - var groupRanges = {}; - var changeCalled = false; - - // getting group Ids - var groupIds = []; - for (var groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - group = this.groups[groupId]; - if (group.visible == true && (this.options.groups.visibility[groupId] === undefined || this.options.groups.visibility[groupId] == true)) { - groupIds.push(groupId); + /** + * @event release + * @param {Object} ev + */ + Hammer.gestures.Release = { + name: 'release', + index: Infinity, + handler: function releaseGesture(ev, inst) { + if(ev.eventType == EVENT_RELEASE) { + inst.trigger(this.name, ev); } - } } - if (groupIds.length > 0) { - // this is the range of the SVG canvas - var minDate = this.body.util.toGlobalTime(-this.body.domProps.root.width); - var maxDate = this.body.util.toGlobalTime(2 * this.body.domProps.root.width); - var groupsData = {}; - // fill groups data, this only loads the data we require based on the timewindow - this._getRelevantData(groupIds, groupsData, minDate, maxDate); + }; - // apply sampling, if disabled, it will pass through this function. - this._applySampling(groupIds, groupsData); + /** + * @module gestures + */ + /** + * triggers swipe events when the end velocity is above the threshold + * for best usage, set `preventDefault` (on the drag gesture) to `true` + * ```` + * hammertime.on("dragleft swipeleft", function(ev) { + * console.log(ev); + * ev.gesture.preventDefault(); + * }); + * ```` + * + * @class Swipe + * @static + */ + /** + * @event swipe + * @param {Object} ev + */ + /** + * @event swipeleft + * @param {Object} ev + */ + /** + * @event swiperight + * @param {Object} ev + */ + /** + * @event swipeup + * @param {Object} ev + */ + /** + * @event swipedown + * @param {Object} ev + */ + Hammer.gestures.Swipe = { + name: 'swipe', + index: 40, + defaults: { + /** + * @property swipeMinTouches + * @type {Number} + * @default 1 + */ + swipeMinTouches: 1, - // we transform the X coordinates to detect collisions - for (i = 0; i < groupIds.length; i++) { - preprocessedGroupData[groupIds[i]] = this._convertXcoordinates(groupsData[groupIds[i]]); - } + /** + * @property swipeMaxTouches + * @type {Number} + * @default 1 + */ + swipeMaxTouches: 1, - // now all needed data has been collected we start the processing. - this._getYRanges(groupIds, preprocessedGroupData, groupRanges); + /** + * horizontal swipe velocity + * @property swipeVelocityX + * @type {Number} + * @default 0.6 + */ + swipeVelocityX: 0.6, - // update the Y axis first, we use this data to draw at the correct Y points - // changeCalled is required to clean the SVG on a change emit. - changeCalled = this._updateYAxis(groupIds, groupRanges); - var MAX_CYCLES = 5; - if (changeCalled == true && this.COUNTER < MAX_CYCLES) { - DOMutil.cleanupElements(this.svgElements); - this.abortedGraphUpdate = true; - this.COUNTER++; - this.body.emitter.emit('change'); - return true; - } - else { - if (this.COUNTER > MAX_CYCLES) { - console.log("WARNING: there may be an infinite loop in the _updateGraph emitter cycle.") - } - this.COUNTER = 0; - this.abortedGraphUpdate = false; + /** + * vertical swipe velocity + * @property swipeVelocityY + * @type {Number} + * @default 0.6 + */ + swipeVelocityY: 0.6 + }, - // With the yAxis scaled correctly, use this to get the Y values of the points. - for (i = 0; i < groupIds.length; i++) { - group = this.groups[groupIds[i]]; - processedGroupData[groupIds[i]] = this._convertYcoordinates(groupsData[groupIds[i]], group); - } + handler: function swipeGesture(ev, inst) { + if(ev.eventType == EVENT_RELEASE) { + var touches = ev.touches.length, + options = inst.options; - // draw the groups - for (i = 0; i < groupIds.length; i++) { - group = this.groups[groupIds[i]]; - if (group.options.style != 'bar') { // bar needs to be drawn enmasse - group.draw(processedGroupData[groupIds[i]], group, this.framework); - } + // max touches + if(touches < options.swipeMinTouches || + touches > options.swipeMaxTouches) { + return; + } + + // when the distance we moved is too small we skip this gesture + // or we can be already in dragging + if(ev.velocityX > options.swipeVelocityX || + ev.velocityY > options.swipeVelocityY) { + // trigger swipe events + inst.trigger(this.name, ev); + inst.trigger(this.name + ev.direction, ev); + } } - BarGraphFunctions.draw(groupIds, processedGroupData, this.framework); - } } - } - - // cleanup unused svg elements - DOMutil.cleanupElements(this.svgElements); - return false; }; - /** - * first select and preprocess the data from the datasets. - * the groups have their preselection of data, we now loop over this data to see - * what data we need to draw. Sorted data is much faster. - * more optimization is possible by doing the sampling before and using the binary search - * to find the end date to determine the increment. + * @module gestures + */ + /** + * Single tap and a double tap on a place * - * @param {array} groupIds - * @param {object} groupsData - * @param {date} minDate - * @param {date} maxDate - * @private + * @class Tap + * @static + */ + /** + * @event tap + * @param {Object} ev + */ + /** + * @event doubletap + * @param {Object} ev */ - LineGraph.prototype._getRelevantData = function (groupIds, groupsData, minDate, maxDate) { - var group, i, j, item; - if (groupIds.length > 0) { - for (i = 0; i < groupIds.length; i++) { - group = this.groups[groupIds[i]]; - groupsData[groupIds[i]] = []; - var dataContainer = groupsData[groupIds[i]]; - // optimization for sorted data - if (group.options.sort == true) { - var guess = Math.max(0, util.binarySearchValue(group.itemsData, minDate, 'x', 'before')); - for (j = guess; j < group.itemsData.length; j++) { - item = group.itemsData[j]; - if (item !== undefined) { - if (item.x > maxDate) { - dataContainer.push(item); - break; - } - else { - dataContainer.push(item); - } - } - } - } - else { - for (j = 0; j < group.itemsData.length; j++) { - item = group.itemsData[j]; - if (item !== undefined) { - if (item.x > minDate && item.x < maxDate) { - dataContainer.push(item); - } - } - } - } - } - } - }; - /** - * - * @param groupIds - * @param groupsData - * @private + * @param {String} name */ - LineGraph.prototype._applySampling = function (groupIds, groupsData) { - var group; - if (groupIds.length > 0) { - for (var i = 0; i < groupIds.length; i++) { - group = this.groups[groupIds[i]]; - if (group.options.sampling == true) { - var dataContainer = groupsData[groupIds[i]]; - if (dataContainer.length > 0) { - var increment = 1; - var amountOfPoints = dataContainer.length; + (function(name) { + var hasMoved = false; - // the global screen is used because changing the width of the yAxis may affect the increment, resulting in an endless loop - // of width changing of the yAxis. - var xDistance = this.body.util.toGlobalScreen(dataContainer[dataContainer.length - 1].x) - this.body.util.toGlobalScreen(dataContainer[0].x); - var pointsPerPixel = amountOfPoints / xDistance; - increment = Math.min(Math.ceil(0.2 * amountOfPoints), Math.max(1, Math.round(pointsPerPixel))); + function tapGesture(ev, inst) { + var options = inst.options, + current = Detection.current, + prev = Detection.previous, + sincePrev, + didDoubleTap; - var sampledData = []; - for (var j = 0; j < amountOfPoints; j += increment) { - sampledData.push(dataContainer[j]); + switch(ev.eventType) { + case EVENT_START: + hasMoved = false; + break; - } - groupsData[groupIds[i]] = sampledData; - } - } - } - } - }; + case EVENT_MOVE: + hasMoved = hasMoved || (ev.distance > options.tapMaxDistance); + break; + case EVENT_END: + if(!Utils.inStr(ev.srcEvent.type, 'cancel') && ev.deltaTime < options.tapMaxTime && !hasMoved) { + // previous gesture, for the double tap since these are two different gesture detections + sincePrev = prev && prev.lastEvent && ev.timeStamp - prev.lastEvent.timeStamp; + didDoubleTap = false; - /** - * - * - * @param {array} groupIds - * @param {object} groupsData - * @param {object} groupRanges | this is being filled here - * @private - */ - LineGraph.prototype._getYRanges = function (groupIds, groupsData, groupRanges) { - var groupData, group, i; - var barCombinedDataLeft = []; - var barCombinedDataRight = []; - var options; - if (groupIds.length > 0) { - for (i = 0; i < groupIds.length; i++) { - groupData = groupsData[groupIds[i]]; - options = this.groups[groupIds[i]].options; - if (groupData.length > 0) { - group = this.groups[groupIds[i]]; - // if bar graphs are stacked, their range need to be handled differently and accumulated over all groups. - if (options.barChart.handleOverlap == 'stack' && options.style == 'bar') { - if (options.yAxisOrientation == 'left') {barCombinedDataLeft = barCombinedDataLeft.concat(group.getYRange(groupData)) ;} - else {barCombinedDataRight = barCombinedDataRight.concat(group.getYRange(groupData));} - } - else { - groupRanges[groupIds[i]] = group.getYRange(groupData,groupIds[i]); + // check if double tap + if(prev && prev.name == name && + (sincePrev && sincePrev < options.doubleTapInterval) && + ev.distance < options.doubleTapDistance) { + inst.trigger('doubletap', ev); + didDoubleTap = true; + } + + // do a single tap + if(!didDoubleTap || options.tapAlways) { + current.name = name; + inst.trigger(current.name, ev); + } + } + break; } - } } - // if bar graphs are stacked, their range need to be handled differently and accumulated over all groups. - BarGraphFunctions.getStackedBarYRange(barCombinedDataLeft , groupRanges, groupIds, '__barchartLeft' , 'left' ); - BarGraphFunctions.getStackedBarYRange(barCombinedDataRight, groupRanges, groupIds, '__barchartRight', 'right'); - } - }; + Hammer.gestures.Tap = { + name: name, + index: 100, + handler: tapGesture, + defaults: { + /** + * max time of a tap, this is for the slow tappers + * @property tapMaxTime + * @type {Number} + * @default 250 + */ + tapMaxTime: 250, + /** + * max distance of movement of a tap, this is for the slow tappers + * @property tapMaxDistance + * @type {Number} + * @default 10 + */ + tapMaxDistance: 10, - /** - * this sets the Y ranges for the Y axis. It also determines which of the axis should be shown or hidden. - * @param {Array} groupIds - * @param {Object} groupRanges - * @private - */ - LineGraph.prototype._updateYAxis = function (groupIds, groupRanges) { - var resized = false; - var yAxisLeftUsed = false; - var yAxisRightUsed = false; - var minLeft = 1e9, minRight = 1e9, maxLeft = -1e9, maxRight = -1e9, minVal, maxVal; - // if groups are present - if (groupIds.length > 0) { - // this is here to make sure that if there are no items in the axis but there are groups, that there is no infinite draw/redraw loop. - for (var i = 0; i < groupIds.length; i++) { - var group = this.groups[groupIds[i]]; - if (group && group.options.yAxisOrientation != 'right') { - yAxisLeftUsed = true; - minLeft = 0; - maxLeft = 0; - } - else if (group && group.options.yAxisOrientation) { - yAxisRightUsed = true; - minRight = 0; - maxRight = 0; - } - } + /** + * always trigger the `tap` event, even while double-tapping + * @property tapAlways + * @type {Boolean} + * @default true + */ + tapAlways: true, - // if there are items: - for (var i = 0; i < groupIds.length; i++) { - if (groupRanges.hasOwnProperty(groupIds[i])) { - if (groupRanges[groupIds[i]].ignore !== true) { - minVal = groupRanges[groupIds[i]].min; - maxVal = groupRanges[groupIds[i]].max; + /** + * max distance between two taps + * @property doubleTapDistance + * @type {Number} + * @default 20 + */ + doubleTapDistance: 20, - if (groupRanges[groupIds[i]].yAxisOrientation != 'right') { - yAxisLeftUsed = true; - minLeft = minLeft > minVal ? minVal : minLeft; - maxLeft = maxLeft < maxVal ? maxVal : maxLeft; - } - else { - yAxisRightUsed = true; - minRight = minRight > minVal ? minVal : minRight; - maxRight = maxRight < maxVal ? maxVal : maxRight; - } + /** + * max time between two taps + * @property doubleTapInterval + * @type {Number} + * @default 300 + */ + doubleTapInterval: 300 } - } - } - - if (yAxisLeftUsed == true) { - this.yAxisLeft.setRange(minLeft, maxLeft); - } - if (yAxisRightUsed == true) { - this.yAxisRight.setRange(minRight, maxRight); - } - } - resized = this._toggleAxisVisiblity(yAxisLeftUsed , this.yAxisLeft) || resized; - resized = this._toggleAxisVisiblity(yAxisRightUsed, this.yAxisRight) || resized; + }; + })('tap'); - if (yAxisRightUsed == true && yAxisLeftUsed == true) { - this.yAxisLeft.drawIcons = true; - this.yAxisRight.drawIcons = true; - } - else { - this.yAxisLeft.drawIcons = false; - this.yAxisRight.drawIcons = false; - } - this.yAxisRight.master = !yAxisLeftUsed; - if (this.yAxisRight.master == false) { - if (yAxisRightUsed == true) {this.yAxisLeft.lineOffset = this.yAxisRight.width;} - else {this.yAxisLeft.lineOffset = 0;} + /** + * @module gestures + */ + /** + * when a touch is being touched at the page + * + * @class Touch + * @static + */ + /** + * @event touch + * @param {Object} ev + */ + Hammer.gestures.Touch = { + name: 'touch', + index: -Infinity, + defaults: { + /** + * call preventDefault at touchstart, and makes the element blocking by disabling the scrolling of the page, + * but it improves gestures like transforming and dragging. + * be careful with using this, it can be very annoying for users to be stuck on the page + * @property preventDefault + * @type {Boolean} + * @default false + */ + preventDefault: false, - resized = this.yAxisLeft.redraw() || resized; - this.yAxisRight.stepPixelsForced = this.yAxisLeft.stepPixels; - this.yAxisRight.zeroCrossing = this.yAxisLeft.zeroCrossing; - resized = this.yAxisRight.redraw() || resized; - } - else { - resized = this.yAxisRight.redraw() || resized; - } + /** + * disable mouse events, so only touch (or pen!) input triggers events + * @property preventMouse + * @type {Boolean} + * @default false + */ + preventMouse: false + }, + handler: function touchGesture(ev, inst) { + if(inst.options.preventMouse && ev.pointerType == POINTER_MOUSE) { + ev.stopDetect(); + return; + } - // clean the accumulated lists - if (groupIds.indexOf('__barchartLeft') != -1) { - groupIds.splice(groupIds.indexOf('__barchartLeft'),1); - } - if (groupIds.indexOf('__barchartRight') != -1) { - groupIds.splice(groupIds.indexOf('__barchartRight'),1); - } + if(inst.options.preventDefault) { + ev.preventDefault(); + } - return resized; + if(ev.eventType == EVENT_TOUCH) { + inst.trigger('touch', ev); + } + } }; - /** - * This shows or hides the Y axis if needed. If there is a change, the changed event is emitted by the updateYAxis function + * @module gestures + */ + /** + * User want to scale or rotate with 2 fingers + * Preventing the default browser behavior is a good way to improve feel and working. This can be done with the + * `preventDefault` option. * - * @param {boolean} axisUsed - * @returns {boolean} - * @private - * @param axis + * @class Transform + * @static + */ + /** + * @event transform + * @param {Object} ev + */ + /** + * @event transformstart + * @param {Object} ev + */ + /** + * @event transformend + * @param {Object} ev + */ + /** + * @event pinchin + * @param {Object} ev + */ + /** + * @event pinchout + * @param {Object} ev + */ + /** + * @event rotate + * @param {Object} ev */ - LineGraph.prototype._toggleAxisVisiblity = function (axisUsed, axis) { - var changed = false; - if (axisUsed == false) { - if (axis.dom.frame.parentNode && axis.hidden == false) { - axis.hide() - changed = true; - } - } - else { - if (!axis.dom.frame.parentNode && axis.hidden == true) { - axis.show(); - changed = true; - } - } - return changed; - }; - /** - * This uses the DataAxis object to generate the correct X coordinate on the SVG window. It uses the - * util function toScreen to get the x coordinate from the timestamp. It also pre-filters the data and get the minMax ranges for - * the yAxis. - * - * @param datapoints - * @returns {Array} - * @private + * @param {String} name */ - LineGraph.prototype._convertXcoordinates = function (datapoints) { - var extractedData = []; - var xValue, yValue; - var toScreen = this.body.util.toScreen; + (function(name) { + var triggered = false; - for (var i = 0; i < datapoints.length; i++) { - xValue = toScreen(datapoints[i].x) + this.props.width; - yValue = datapoints[i].y; - extractedData.push({x: xValue, y: yValue}); - } + function transformGesture(ev, inst) { + switch(ev.eventType) { + case EVENT_START: + triggered = false; + break; - return extractedData; - }; + case EVENT_MOVE: + // at least multitouch + if(ev.touches.length < 2) { + return; + } + var scaleThreshold = Math.abs(1 - ev.scale); + var rotationThreshold = Math.abs(ev.rotation); - /** - * This uses the DataAxis object to generate the correct X coordinate on the SVG window. It uses the - * util function toScreen to get the x coordinate from the timestamp. It also pre-filters the data and get the minMax ranges for - * the yAxis. - * - * @param datapoints - * @param group - * @returns {Array} - * @private - */ - LineGraph.prototype._convertYcoordinates = function (datapoints, group) { - var extractedData = []; - var xValue, yValue; - var toScreen = this.body.util.toScreen; - var axis = this.yAxisLeft; - var svgHeight = Number(this.svg.style.height.replace('px','')); - if (group.options.yAxisOrientation == 'right') { - axis = this.yAxisRight; - } + // when the distance we moved is too small we skip this gesture + // or we can be already in dragging + if(scaleThreshold < inst.options.transformMinScale && + rotationThreshold < inst.options.transformMinRotation) { + return; + } - for (var i = 0; i < datapoints.length; i++) { - xValue = toScreen(datapoints[i].x) + this.props.width; - yValue = Math.round(axis.convertValue(datapoints[i].y)); - extractedData.push({x: xValue, y: yValue}); - } + // we are transforming! + Detection.current.name = name; - group.setZeroPosition(Math.min(svgHeight, axis.convertValue(0))); + // first time, trigger dragstart event + if(!triggered) { + inst.trigger(name + 'start', ev); + triggered = true; + } - return extractedData; - }; + inst.trigger(name, ev); // basic transform event + // trigger rotate event + if(rotationThreshold > inst.options.transformMinRotation) { + inst.trigger('rotate', ev); + } - module.exports = LineGraph; + // trigger pinch event + if(scaleThreshold > inst.options.transformMinScale) { + inst.trigger('pinch', ev); + inst.trigger('pinch' + (ev.scale < 1 ? 'in' : 'out'), ev); + } + break; + case EVENT_RELEASE: + if(triggered && ev.changedLength < 2) { + inst.trigger(name + 'end', ev); + triggered = false; + } + break; + } + } -/***/ }, -/* 30 */ -/***/ function(module, exports, __webpack_require__) { + Hammer.gestures.Transform = { + name: name, + index: 45, + defaults: { + /** + * minimal scale factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1 + * @property transformMinScale + * @type {Number} + * @default 0.01 + */ + transformMinScale: 0.01, - var util = __webpack_require__(1); - var Component = __webpack_require__(20); - var TimeStep = __webpack_require__(19); - var DateUtil = __webpack_require__(15); - var moment = __webpack_require__(44); + /** + * rotation in degrees + * @property transformMinRotation + * @type {Number} + * @default 1 + */ + transformMinRotation: 1 + }, + + handler: transformGesture + }; + })('transform'); /** - * A horizontal time axis - * @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} body - * @param {Object} [options] See TimeAxis.setOptions for the available - * options. - * @constructor TimeAxis - * @extends Component + * @module hammer */ - function TimeAxis (body, options) { - this.dom = { - foreground: null, - lines: [], - majorTexts: [], - minorTexts: [], - redundant: { - lines: [], - majorTexts: [], - minorTexts: [] - } - }; - this.props = { - range: { - start: 0, - end: 0, - minimumStep: 0 - }, - lineTop: 0 - }; + // AMD export + if(true) { + !(__WEBPACK_AMD_DEFINE_RESULT__ = function() { + return Hammer; + }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + // commonjs export + } else if(typeof module !== 'undefined' && module.exports) { + module.exports = Hammer; + // browser export + } else { + window.Hammer = Hammer; + } + + })(window); + +/***/ }, +/* 21 */ +/***/ function(module, exports, __webpack_require__) { + + var util = __webpack_require__(1); + var hammerUtil = __webpack_require__(22); + var moment = __webpack_require__(2); + var Component = __webpack_require__(23); + var DateUtil = __webpack_require__(24); + + /** + * @constructor Range + * A Range controls a numeric range with a start and end value. + * The Range adjusts the range based on mouse events or programmatic changes, + * and triggers events when the range is changing or has been changed. + * @param {{dom: Object, domProps: Object, emitter: Emitter}} body + * @param {Object} [options] See description at Range.setOptions + */ + function Range(body, options) { + var now = moment().hours(0).minutes(0).seconds(0).milliseconds(0); + this.start = now.clone().add(-3, 'days').valueOf(); // Number + this.end = now.clone().add(4, 'days').valueOf(); // Number + + this.body = body; + this.deltaDifference = 0; + this.scaleOffset = 0; + this.startToFront = false; + this.endToFront = true; + + // default options this.defaultOptions = { - orientation: 'bottom', // supported: 'top', 'bottom' - // TODO: implement timeaxis orientations 'left' and 'right' - showMinorLabels: true, - showMajorLabels: true, - format: null + start: null, + end: null, + direction: 'horizontal', // 'horizontal' or 'vertical' + moveable: true, + zoomable: true, + min: null, + max: null, + zoomMin: 10, // milliseconds + zoomMax: 1000 * 60 * 60 * 24 * 365 * 10000 // milliseconds }; this.options = util.extend({}, this.defaultOptions); - this.body = body; + this.props = { + touch: {} + }; + this.animateTimer = null; - // create the HTML DOM - this._create(); + // drag listeners for dragging + this.body.emitter.on('dragstart', this._onDragStart.bind(this)); + this.body.emitter.on('drag', this._onDrag.bind(this)); + this.body.emitter.on('dragend', this._onDragEnd.bind(this)); + + // ignore dragging when holding + this.body.emitter.on('hold', this._onHold.bind(this)); + + // mouse wheel for zooming + this.body.emitter.on('mousewheel', this._onMouseWheel.bind(this)); + this.body.emitter.on('DOMMouseScroll', this._onMouseWheel.bind(this)); // For FF + + // pinch to zoom + this.body.emitter.on('touch', this._onTouch.bind(this)); + this.body.emitter.on('pinch', this._onPinch.bind(this)); this.setOptions(options); } - TimeAxis.prototype = new Component(); + Range.prototype = new Component(); /** - * Set options for the TimeAxis. - * Parameters will be merged in current options. - * @param {Object} options Available options: - * {string} [orientation] - * {boolean} [showMinorLabels] - * {boolean} [showMajorLabels] + * Set options for the range controller + * @param {Object} options Available options: + * {Number | Date | String} start Start date for the range + * {Number | Date | String} end End date for the range + * {Number} min Minimum value for start + * {Number} max Maximum value for end + * {Number} zoomMin Set a minimum value for + * (end - start). + * {Number} zoomMax Set a maximum value for + * (end - start). + * {Boolean} moveable Enable moving of the range + * by dragging. True by default + * {Boolean} zoomable Enable zooming of the range + * by pinching/scrolling. True by default */ - TimeAxis.prototype.setOptions = function(options) { + Range.prototype.setOptions = function (options) { if (options) { - // copy all options that we know - util.selectiveExtend([ - 'orientation', - 'showMinorLabels', - 'showMajorLabels', - 'hiddenDates', - 'format' - ], this.options, options); + // copy the options that we know + var fields = ['direction', 'min', 'max', 'zoomMin', 'zoomMax', 'moveable', 'zoomable', 'activate', 'hiddenDates']; + util.selectiveExtend(fields, 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); - } + if ('start' in options || 'end' in options) { + // apply a new range. both start and end are optional + this.setRange(options.start, options.end); } } }; /** - * Create the HTML DOM for the TimeAxis - */ - TimeAxis.prototype._create = function() { - this.dom.foreground = document.createElement('div'); - this.dom.background = document.createElement('div'); - - this.dom.foreground.className = 'timeaxis foreground'; - this.dom.background.className = 'timeaxis background'; - }; - - /** - * Destroy the TimeAxis + * Test whether direction has a valid value + * @param {String} direction 'horizontal' or 'vertical' */ - TimeAxis.prototype.destroy = function() { - // remove from DOM - if (this.dom.foreground.parentNode) { - this.dom.foreground.parentNode.removeChild(this.dom.foreground); - } - if (this.dom.background.parentNode) { - this.dom.background.parentNode.removeChild(this.dom.background); + function validateDirection (direction) { + if (direction != 'horizontal' && direction != 'vertical') { + throw new TypeError('Unknown direction "' + direction + '". ' + + 'Choose "horizontal" or "vertical".'); } - - this.body = null; - }; + } /** - * Repaint the component - * @return {boolean} Returns true if the component is resized + * Set a new start and end range + * @param {Date | Number | String} [start] + * @param {Date | Number | String} [end] + * @param {boolean | number} [animate=false] If true, the range is animated + * smoothly to the new window. + * If animate is a number, the + * number is taken as duration + * Default duration is 500 ms. + * @param {Boolean} [byUser=false] + * */ - TimeAxis.prototype.redraw = function () { - var options = this.options; - var props = this.props; - var foreground = this.dom.foreground; - var background = this.dom.background; - - // determine the correct parent DOM element (depending on option orientation) - var parent = (options.orientation == 'top') ? this.body.dom.top : this.body.dom.bottom; - var parentChanged = (foreground.parentNode !== parent); - - // calculate character width and height - this._calculateCharSize(); - - // TODO: recalculate sizes only needed when parent is resized or options is changed - var orientation = this.options.orientation, - showMinorLabels = this.options.showMinorLabels, - showMajorLabels = this.options.showMajorLabels; - - // determine the width and height of the elemens for the axis - props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; - props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; - props.height = props.minorLabelHeight + props.majorLabelHeight; - props.width = foreground.offsetWidth; + Range.prototype.setRange = function(start, end, animate, byUser) { + if (byUser !== true) { + byUser = false; + } + var _start = start != undefined ? util.convert(start, 'Date').valueOf() : null; + var _end = end != undefined ? util.convert(end, 'Date').valueOf() : null; + this._cancelAnimation(); - props.minorLineHeight = this.body.domProps.root.height - props.majorLabelHeight - - (options.orientation == 'top' ? this.body.domProps.bottom.height : this.body.domProps.top.height); - props.minorLineWidth = 1; // TODO: really calculate width - props.majorLineHeight = props.minorLineHeight + props.majorLabelHeight; - props.majorLineWidth = 1; // TODO: really calculate width + if (animate) { + var me = this; + var initStart = this.start; + var initEnd = this.end; + var duration = typeof animate === 'number' ? animate : 500; + var initTime = new Date().valueOf(); + var anyChanged = false; - // take foreground and background offline while updating (is almost twice as fast) - var foregroundNextSibling = foreground.nextSibling; - var backgroundNextSibling = background.nextSibling; - foreground.parentNode && foreground.parentNode.removeChild(foreground); - background.parentNode && background.parentNode.removeChild(background); + var next = function () { + if (!me.props.touch.dragging) { + var now = new Date().valueOf(); + var time = now - initTime; + var done = time > duration; + var s = (done || _start === null) ? _start : util.easeInOutQuad(time, initStart, _start, duration); + var e = (done || _end === null) ? _end : util.easeInOutQuad(time, initEnd, _end, duration); - foreground.style.height = this.props.height + 'px'; + changed = me._applyRange(s, e); + DateUtil.updateHiddenDates(me.body, me.options.hiddenDates); + anyChanged = anyChanged || changed; + if (changed) { + me.body.emitter.emit('rangechange', {start: new Date(me.start), end: new Date(me.end), byUser:byUser}); + } - this._repaintLabels(); + if (done) { + if (anyChanged) { + me.body.emitter.emit('rangechanged', {start: new Date(me.start), end: new Date(me.end), byUser:byUser}); + } + } + else { + // animate with as high as possible frame rate, leave 20 ms in between + // each to prevent the browser from blocking + me.animateTimer = setTimeout(next, 20); + } + } + } - // put DOM online again (at the same place) - if (foregroundNextSibling) { - parent.insertBefore(foreground, foregroundNextSibling); - } - else { - parent.appendChild(foreground) - } - if (backgroundNextSibling) { - this.body.dom.backgroundVertical.insertBefore(background, backgroundNextSibling); + return next(); } else { - this.body.dom.backgroundVertical.appendChild(background) + var changed = this._applyRange(_start, _end); + DateUtil.updateHiddenDates(this.body, this.options.hiddenDates); + if (changed) { + var params = {start: new Date(this.start), end: new Date(this.end), byUser:byUser}; + this.body.emitter.emit('rangechange', params); + this.body.emitter.emit('rangechanged', params); + } } - - return this._isResized() || parentChanged; }; /** - * Repaint major and minor text labels and vertical grid lines + * Stop an animation * @private */ - TimeAxis.prototype._repaintLabels = function () { - var orientation = this.options.orientation; - - // calculate range and step (step such that we have space for 7 characters per label) - var start = util.convert(this.body.range.start, 'Number'); - var end = util.convert(this.body.range.end, 'Number'); - var timeLabelsize = this.body.util.toTime((this.props.minorCharWidth || 10) * 7).valueOf(); - var minimumStep = timeLabelsize - DateUtil.getHiddenDurationBefore(this.body.hiddenDates, this.body.range, timeLabelsize); - minimumStep -= this.body.util.toTime(0).valueOf(); - - var step = new TimeStep(new Date(start), new Date(end), minimumStep, this.body.hiddenDates); - if (this.options.format) { - step.setFormat(this.options.format); + Range.prototype._cancelAnimation = function () { + if (this.animateTimer) { + clearTimeout(this.animateTimer); + this.animateTimer = null; } - this.step = step; + }; - // Move all DOM elements to a "redundant" list, where they - // can be picked for re-use, and clear the lists with lines and texts. - // At the end of the function _repaintLabels, left over elements will be cleaned up - var dom = this.dom; - dom.redundant.lines = dom.lines; - dom.redundant.majorTexts = dom.majorTexts; - dom.redundant.minorTexts = dom.minorTexts; - dom.lines = []; - dom.majorTexts = []; - dom.minorTexts = []; + /** + * Set a new start and end range. This method is the same as setRange, but + * does not trigger a range change and range changed event, and it returns + * true when the range is changed + * @param {Number} [start] + * @param {Number} [end] + * @return {Boolean} changed + * @private + */ + Range.prototype._applyRange = function(start, end) { + var newStart = (start != null) ? util.convert(start, 'Date').valueOf() : this.start, + newEnd = (end != null) ? util.convert(end, 'Date').valueOf() : this.end, + max = (this.options.max != null) ? util.convert(this.options.max, 'Date').valueOf() : null, + min = (this.options.min != null) ? util.convert(this.options.min, 'Date').valueOf() : null, + diff; - var cur; - var x = 0; - var isMajor; - var xPrev = 0; - var width = 0; - var prevLine; - var xFirstMajorLabel = undefined; - var max = 0; - var className; + // check for valid number + if (isNaN(newStart) || newStart === null) { + throw new Error('Invalid start "' + start + '"'); + } + if (isNaN(newEnd) || newEnd === null) { + throw new Error('Invalid end "' + end + '"'); + } - step.first(); - while (step.hasNext() && max < 1000) { - max++; + // prevent start < end + if (newEnd < newStart) { + newEnd = newStart; + } - cur = step.getCurrent(); - isMajor = step.isMajor(); - className = step.getClassName(); + // prevent start < min + if (min !== null) { + if (newStart < min) { + diff = (min - newStart); + newStart += diff; + newEnd += diff; - xPrev = x; - x = this.body.util.toScreen(cur); - width = x - xPrev; - if (prevLine) { - prevLine.style.width = width + 'px'; + // prevent end > max + if (max != null) { + if (newEnd > max) { + newEnd = max; + } + } } + } - if (this.options.showMinorLabels) { - this._repaintMinorText(x, step.getLabelMinor(), orientation, className); - } + // prevent end > max + if (max !== null) { + if (newEnd > max) { + diff = (newEnd - max); + newStart -= diff; + newEnd -= diff; - if (isMajor && this.options.showMajorLabels) { - if (x > 0) { - if (xFirstMajorLabel == undefined) { - xFirstMajorLabel = x; + // prevent start < min + if (min != null) { + if (newStart < min) { + newStart = min; } - this._repaintMajorText(x, step.getLabelMajor(), orientation, className); } - prevLine = this._repaintMajorLine(x, orientation, className); - } - else { - prevLine = this._repaintMinorLine(x, orientation, className); } - - step.next(); } - // create a major label on the left when needed - if (this.options.showMajorLabels) { - var leftTime = this.body.util.toTime(0), - leftText = step.getLabelMajor(leftTime), - widthText = leftText.length * (this.props.majorCharWidth || 10) + 10; // upper bound estimation - - if (xFirstMajorLabel == undefined || widthText < xFirstMajorLabel) { - this._repaintMajorText(0, leftText, orientation, className); + // prevent (end-start) < zoomMin + if (this.options.zoomMin !== null) { + var zoomMin = parseFloat(this.options.zoomMin); + if (zoomMin < 0) { + zoomMin = 0; + } + if ((newEnd - newStart) < zoomMin) { + if ((this.end - this.start) === zoomMin) { + // ignore this action, we are already zoomed to the minimum + newStart = this.start; + newEnd = this.end; + } + else { + // zoom to the minimum + diff = (zoomMin - (newEnd - newStart)); + newStart -= diff / 2; + newEnd += diff / 2; + } } } - // Cleanup leftover DOM elements from the redundant list - util.forEach(this.dom.redundant, function (arr) { - while (arr.length) { - var elem = arr.pop(); - if (elem && elem.parentNode) { - elem.parentNode.removeChild(elem); + // prevent (end-start) > zoomMax + if (this.options.zoomMax !== null) { + var zoomMax = parseFloat(this.options.zoomMax); + if (zoomMax < 0) { + zoomMax = 0; + } + if ((newEnd - newStart) > zoomMax) { + if ((this.end - this.start) === zoomMax) { + // ignore this action, we are already zoomed to the maximum + newStart = this.start; + newEnd = this.end; + } + else { + // zoom to the maximum + diff = ((newEnd - newStart) - zoomMax); + newStart += diff / 2; + newEnd -= diff / 2; } } - }); - }; + } - /** - * Create a minor label for the axis at position x - * @param {Number} x - * @param {String} text - * @param {String} orientation "top" or "bottom" (default) - * @param {String} className - * @private - */ - TimeAxis.prototype._repaintMinorText = function (x, text, orientation, className) { - // reuse redundant label - var label = this.dom.redundant.minorTexts.shift(); + var changed = (this.start != newStart || this.end != newEnd); - if (!label) { - // create new label - var content = document.createTextNode(''); - label = document.createElement('div'); - label.appendChild(content); - this.dom.foreground.appendChild(label); + // if the new range does NOT overlap with the old range, emit checkRangedItems to avoid not showing ranged items (ranged meaning has end time, not neccesarily of type Range) + if (!((newStart >= this.start && newStart <= this.end) || (newEnd >= this.start && newEnd <= this.end)) && + !((this.start >= newStart && this.start <= newEnd) || (this.end >= newStart && this.end <= newEnd) )) { + this.body.emitter.emit('checkRangedItems'); } - this.dom.minorTexts.push(label); - - label.childNodes[0].nodeValue = text; - label.style.top = (orientation == 'top') ? (this.props.majorLabelHeight + 'px') : '0'; - label.style.left = x + 'px'; - label.className = 'text minor ' + className; - //label.title = title; // TODO: this is a heavy operation + this.start = newStart; + this.end = newEnd; + return changed; }; /** - * Create a Major label for the axis at position x - * @param {Number} x - * @param {String} text - * @param {String} orientation "top" or "bottom" (default) - * @param {String} className - * @private + * Retrieve the current range. + * @return {Object} An object with start and end properties */ - TimeAxis.prototype._repaintMajorText = function (x, text, orientation, className) { - // reuse redundant label - var label = this.dom.redundant.majorTexts.shift(); - - if (!label) { - // create label - var content = document.createTextNode(text); - label = document.createElement('div'); - label.appendChild(content); - this.dom.foreground.appendChild(label); - } - this.dom.majorTexts.push(label); - - label.childNodes[0].nodeValue = text; - label.className = 'text major ' + className; - //label.title = title; // TODO: this is a heavy operation - - label.style.top = (orientation == 'top') ? '0' : (this.props.minorLabelHeight + 'px'); - label.style.left = x + 'px'; + Range.prototype.getRange = function() { + return { + start: this.start, + end: this.end + }; }; /** - * Create a minor line for the axis at position x - * @param {Number} x - * @param {String} orientation "top" or "bottom" (default) - * @param {String} className - * @return {Element} Returns the created line - * @private + * Calculate the conversion offset and scale for current range, based on + * the provided width + * @param {Number} width + * @returns {{offset: number, scale: number}} conversion */ - TimeAxis.prototype._repaintMinorLine = function (x, orientation, className) { - // reuse redundant line - var line = this.dom.redundant.lines.shift(); - if (!line) { - // create vertical line - line = document.createElement('div'); - this.dom.background.appendChild(line); - } - this.dom.lines.push(line); - - var props = this.props; - if (orientation == 'top') { - line.style.top = props.majorLabelHeight + 'px'; - } - else { - line.style.top = this.body.domProps.top.height + 'px'; - } - line.style.height = props.minorLineHeight + 'px'; - line.style.left = (x - props.minorLineWidth / 2) + 'px'; - - line.className = 'grid vertical minor ' + className; - - return line; + Range.prototype.conversion = function (width, totalHidden) { + return Range.conversion(this.start, this.end, width, totalHidden); }; /** - * Create a Major line for the axis at position x - * @param {Number} x - * @param {String} orientation "top" or "bottom" (default) - * @param {String} className - * @return {Element} Returns the created line - * @private + * Static method to calculate the conversion offset and scale for a range, + * based on the provided start, end, and width + * @param {Number} start + * @param {Number} end + * @param {Number} width + * @returns {{offset: number, scale: number}} conversion */ - TimeAxis.prototype._repaintMajorLine = function (x, orientation, className) { - // reuse redundant line - var line = this.dom.redundant.lines.shift(); - if (!line) { - // create vertical line - line = document.createElement('div'); - this.dom.background.appendChild(line); + Range.conversion = function (start, end, width, totalHidden) { + if (totalHidden === undefined) { + totalHidden = 0; } - this.dom.lines.push(line); - - var props = this.props; - if (orientation == 'top') { - line.style.top = '0'; + if (width != 0 && (end - start != 0)) { + return { + offset: start, + scale: width / (end - start - totalHidden) + } } else { - line.style.top = this.body.domProps.top.height + 'px'; + return { + offset: 0, + scale: 1 + }; } - line.style.left = (x - props.majorLineWidth / 2) + 'px'; - line.style.height = props.majorLineHeight + 'px'; - - line.className = 'grid vertical major ' + className; - - return line; }; /** - * Determine the size of text on the axis (both major and minor axis). - * The size is calculated only once and then cached in this.props. + * Start dragging horizontally or vertically + * @param {Event} event * @private */ - TimeAxis.prototype._calculateCharSize = function () { - // Note: We calculate char size with every redraw. Size may change, for - // example when any of the timelines parents had display:none for example. - - // determine the char width and height on the minor axis - if (!this.dom.measureCharMinor) { - this.dom.measureCharMinor = document.createElement('DIV'); - this.dom.measureCharMinor.className = 'text minor measure'; - this.dom.measureCharMinor.style.position = 'absolute'; + Range.prototype._onDragStart = function(event) { + this.deltaDifference = 0; + this.previousDelta = 0; + // only allow dragging when configured as movable + if (!this.options.moveable) return; - this.dom.measureCharMinor.appendChild(document.createTextNode('0')); - this.dom.foreground.appendChild(this.dom.measureCharMinor); - } - this.props.minorCharHeight = this.dom.measureCharMinor.clientHeight; - this.props.minorCharWidth = this.dom.measureCharMinor.clientWidth; + // refuse to drag when we where pinching to prevent the timeline make a jump + // when releasing the fingers in opposite order from the touch screen + if (!this.props.touch.allowDragging) return; - // determine the char width and height on the major axis - if (!this.dom.measureCharMajor) { - this.dom.measureCharMajor = document.createElement('DIV'); - this.dom.measureCharMajor.className = 'text major measure'; - this.dom.measureCharMajor.style.position = 'absolute'; + this.props.touch.start = this.start; + this.props.touch.end = this.end; + this.props.touch.dragging = true; - this.dom.measureCharMajor.appendChild(document.createTextNode('0')); - this.dom.foreground.appendChild(this.dom.measureCharMajor); + if (this.body.dom.root) { + this.body.dom.root.style.cursor = 'move'; } - this.props.majorCharHeight = this.dom.measureCharMajor.clientHeight; - this.props.majorCharWidth = this.dom.measureCharMajor.clientWidth; }; /** - * 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 + * Perform dragging operation + * @param {Event} event + * @private */ - TimeAxis.prototype.snap = function(date) { - return this.step.snap(date); - }; - - module.exports = TimeAxis; + Range.prototype._onDrag = function (event) { + // only allow dragging when configured as movable + if (!this.options.moveable) return; + // refuse to drag when we where pinching to prevent the timeline make a jump + // when releasing the fingers in opposite order from the touch screen + if (!this.props.touch.allowDragging) return; + var direction = this.options.direction; + validateDirection(direction); -/***/ }, -/* 31 */ -/***/ function(module, exports, __webpack_require__) { + var delta = (direction == 'horizontal') ? event.gesture.deltaX : event.gesture.deltaY; + delta -= this.deltaDifference; + var interval = (this.props.touch.end - this.props.touch.start); - var Hammer = __webpack_require__(45); - var util = __webpack_require__(1); + // normalize dragging speed if cutout is in between. + var duration = DateUtil.getHiddenDurationBetween(this.body.hiddenDates, this.start, this.end); + interval -= duration; - /** - * @constructor Item - * @param {Object} data Object containing (optional) parameters type, - * start, end, content, group, className. - * @param {{toScreen: function, toTime: function}} conversion - * Conversion functions from time to screen and vice versa - * @param {Object} options Configuration options - * // TODO: describe available options - */ - function Item (data, conversion, options) { - this.id = null; - this.parent = null; - this.data = data; - this.dom = null; - this.conversion = conversion || {}; - this.options = options || {}; + var width = (direction == 'horizontal') ? this.body.domProps.center.width : this.body.domProps.center.height; + var diffRange = -delta / width * interval; + var newStart = this.props.touch.start + diffRange; + var newEnd = this.props.touch.end + diffRange; - this.selected = false; - this.displayed = false; - this.dirty = true; - this.top = null; - this.left = null; - this.width = null; - this.height = null; - } + // snapping times away from hidden zones + var safeStart = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newStart, this.previousDelta-delta, true); + var safeEnd = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newEnd, this.previousDelta-delta, true); + if (safeStart != newStart || safeEnd != newEnd) { + this.deltaDifference += delta; + this.props.touch.start = safeStart; + this.props.touch.end = safeEnd; + this._onDrag(event); + return; + } - Item.prototype.stack = true; + this.previousDelta = delta; + this._applyRange(newStart, newEnd); - /** - * Select current item - */ - Item.prototype.select = function() { - this.selected = true; - this.dirty = true; - if (this.displayed) this.redraw(); + // fire a rangechange event + this.body.emitter.emit('rangechange', { + start: new Date(this.start), + end: new Date(this.end), + byUser: true + }); }; /** - * Unselect current item + * Stop dragging operation + * @param {event} event + * @private */ - Item.prototype.unselect = function() { - this.selected = false; - this.dirty = true; - if (this.displayed) this.redraw(); - }; + Range.prototype._onDragEnd = function (event) { + // only allow dragging when configured as movable + if (!this.options.moveable) return; - /** - * Set data for the item. Existing data will be updated. The id should not - * be changed. When the item is displayed, it will be redrawn immediately. - * @param {Object} data - */ - Item.prototype.setData = function(data) { - this.data = data; - this.dirty = true; - if (this.displayed) this.redraw(); + // refuse to drag when we where pinching to prevent the timeline make a jump + // when releasing the fingers in opposite order from the touch screen + if (!this.props.touch.allowDragging) return; + + this.props.touch.dragging = false; + if (this.body.dom.root) { + this.body.dom.root.style.cursor = 'auto'; + } + + // fire a rangechanged event + this.body.emitter.emit('rangechanged', { + start: new Date(this.start), + end: new Date(this.end), + byUser: true + }); }; /** - * Set a parent for the item - * @param {ItemSet | Group} parent + * Event handler for mouse wheel event, used to zoom + * Code from http://adomas.org/javascript-mouse-wheel/ + * @param {Event} event + * @private */ - Item.prototype.setParent = function(parent) { - if (this.displayed) { - this.hide(); - this.parent = parent; - if (this.parent) { - this.show(); - } + Range.prototype._onMouseWheel = function(event) { + // only allow zooming when configured as zoomable and moveable + if (!(this.options.zoomable && this.options.moveable)) return; + + // retrieve delta + var delta = 0; + if (event.wheelDelta) { /* IE/Opera. */ + delta = event.wheelDelta / 120; + } else if (event.detail) { /* Mozilla case. */ + // In Mozilla, sign of delta is different than in IE. + // Also, delta is multiple of 3. + delta = -event.detail / 3; } - else { - this.parent = parent; + + // If delta is nonzero, handle it. + // Basically, delta is now positive if wheel was scrolled up, + // and negative, if wheel was scrolled down. + if (delta) { + // perform the zoom action. Delta is normally 1 or -1 + + // adjust a negative delta such that zooming in with delta 0.1 + // equals zooming out with a delta -0.1 + var scale; + if (delta < 0) { + scale = 1 - (delta / 5); + } + else { + scale = 1 / (1 + (delta / 5)) ; + } + + // calculate center, the date to zoom around + var gesture = hammerUtil.fakeGesture(this, event), + pointer = getPointer(gesture.center, this.body.dom.center), + pointerDate = this._pointerToDate(pointer); + + this.zoom(scale, pointerDate, delta); } - }; - /** - * Check whether this item is visible inside given range - * @returns {{start: Number, end: Number}} range with a timestamp for start and end - * @returns {boolean} True if visible - */ - Item.prototype.isVisible = function(range) { - // Should be implemented by Item implementations - return false; + // Prevent default actions caused by mouse wheel + // (else the page and timeline both zoom and scroll) + event.preventDefault(); }; /** - * Show the Item in the DOM (when not already visible) - * @return {Boolean} changed + * Start of a touch gesture + * @private */ - Item.prototype.show = function() { - return false; + Range.prototype._onTouch = function (event) { + this.props.touch.start = this.start; + this.props.touch.end = this.end; + this.props.touch.allowDragging = true; + this.props.touch.center = null; + this.scaleOffset = 0; + this.deltaDifference = 0; }; /** - * Hide the Item from the DOM (when visible) - * @return {Boolean} changed + * On start of a hold gesture + * @private */ - Item.prototype.hide = function() { - return false; + Range.prototype._onHold = function () { + this.props.touch.allowDragging = false; }; /** - * Repaint the item + * Handle pinch event + * @param {Event} event + * @private */ - Item.prototype.redraw = function() { - // should be implemented by the item - }; + Range.prototype._onPinch = function (event) { + // only allow zooming when configured as zoomable and moveable + if (!(this.options.zoomable && this.options.moveable)) return; - /** - * Reposition the Item horizontally - */ - Item.prototype.repositionX = function() { - // should be implemented by the item - }; + this.props.touch.allowDragging = false; - /** - * Reposition the Item vertically - */ - Item.prototype.repositionY = function() { - // should be implemented by the item - }; + if (event.gesture.touches.length > 1) { + if (!this.props.touch.center) { + this.props.touch.center = getPointer(event.gesture.center, this.body.dom.center); + } - /** - * Repaint a delete button on the top right of the item when the item is selected - * @param {HTMLElement} anchor - * @protected - */ - Item.prototype._repaintDeleteButton = function (anchor) { - if (this.selected && this.options.editable.remove && !this.dom.deleteButton) { - // create and show button - var me = this; + var scale = 1 / (event.gesture.scale + this.scaleOffset); + var centerDate = this._pointerToDate(this.props.touch.center); - var deleteButton = document.createElement('div'); - deleteButton.className = 'delete'; - deleteButton.title = 'Delete this item'; + var hiddenDuration = DateUtil.getHiddenDurationBetween(this.body.hiddenDates, this.start, this.end); + var hiddenDurationBefore = DateUtil.getHiddenDurationBefore(this.body.hiddenDates, this, centerDate); + var hiddenDurationAfter = hiddenDuration - hiddenDurationBefore; - Hammer(deleteButton, { - preventDefault: true - }).on('tap', function (event) { - me.parent.removeFromDataSet(me); - event.stopPropagation(); - }); + // calculate new start and end + var newStart = (centerDate - hiddenDurationBefore) + (this.props.touch.start - (centerDate - hiddenDurationBefore)) * scale; + var newEnd = (centerDate + hiddenDurationAfter) + (this.props.touch.end - (centerDate + hiddenDurationAfter)) * scale; - anchor.appendChild(deleteButton); - this.dom.deleteButton = deleteButton; - } - else if (!this.selected && this.dom.deleteButton) { - // remove button - if (this.dom.deleteButton.parentNode) { - this.dom.deleteButton.parentNode.removeChild(this.dom.deleteButton); + // snapping times away from hidden zones + this.startToFront = 1 - scale > 0 ? false : true; // used to do the right autocorrection with periodic hidden times + this.endToFront = scale - 1 > 0 ? false : true; // used to do the right autocorrection with periodic hidden times + + var safeStart = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newStart, 1 - scale, true); + var safeEnd = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newEnd, scale - 1, true); + if (safeStart != newStart || safeEnd != newEnd) { + this.props.touch.start = safeStart; + this.props.touch.end = safeEnd; + this.scaleOffset = 1 - event.gesture.scale; + newStart = safeStart; + newEnd = safeEnd; } - this.dom.deleteButton = null; + + this.setRange(newStart, newEnd, false, true); + + this.startToFront = false; // revert to default + this.endToFront = true; // revert to default } }; /** - * Set HTML contents for the item - * @param {Element} element HTML element to fill with the contents + * Helper function to calculate the center date for zooming + * @param {{x: Number, y: Number}} pointer + * @return {number} date * @private */ - Item.prototype._updateContents = function (element) { - var content; - if (this.options.template) { - var itemData = this.parent.itemSet.itemsData.get(this.id); // get a clone of the data from the dataset - content = this.options.template(itemData); - } - else { - content = this.data.content; - } + Range.prototype._pointerToDate = function (pointer) { + var conversion; + var direction = this.options.direction; - if(content !== this.content) { - // only replace the content when changed - if (content instanceof Element) { - element.innerHTML = ''; - element.appendChild(content); - } - else if (content != undefined) { - element.innerHTML = content; - } - else { - if (!(this.data.type == 'background' && this.data.content === undefined)) { - throw new Error('Property "content" missing in item ' + this.id); - } - } + validateDirection(direction); - this.content = content; + if (direction == 'horizontal') { + return this.body.util.toTime(pointer.x).valueOf(); + } + else { + var height = this.body.domProps.center.height; + conversion = this.conversion(height); + return pointer.y / conversion.scale + conversion.offset; } }; /** - * Set HTML contents for the item - * @param {Element} element HTML element to fill with the contents + * Get the pointer location relative to the location of the dom element + * @param {{pageX: Number, pageY: Number}} touch + * @param {Element} element HTML DOM element + * @return {{x: Number, y: Number}} pointer * @private */ - Item.prototype._updateTitle = function (element) { - if (this.data.title != null) { - element.title = this.data.title || ''; - } - else { - element.removeAttribute('title'); - } - }; + function getPointer (touch, element) { + return { + x: touch.pageX - util.getAbsoluteLeft(element), + y: touch.pageY - util.getAbsoluteTop(element) + }; + } /** - * Process dataAttributes timeline option and set as data- attributes on dom.content - * @param {Element} element HTML element to which the attributes will be attached - * @private + * Zoom the range the given scale in or out. Start and end date will + * be adjusted, and the timeline will be redrawn. You can optionally give a + * date around which to zoom. + * For example, try scale = 0.9 or 1.1 + * @param {Number} scale Scaling factor. Values above 1 will zoom out, + * values below 1 will zoom in. + * @param {Number} [center] Value representing a date around which will + * be zoomed. */ - Item.prototype._updateDataAttributes = function(element) { - if (this.options.dataAttributes && this.options.dataAttributes.length > 0) { - var attributes = []; + Range.prototype.zoom = function(scale, center, delta) { + // if centerDate is not provided, take it half between start Date and end Date + if (center == null) { + center = (this.start + this.end) / 2; + } - if (Array.isArray(this.options.dataAttributes)) { - attributes = this.options.dataAttributes; - } - else if (this.options.dataAttributes == 'all') { - attributes = Object.keys(this.data); - } - else { - return; - } + var hiddenDuration = DateUtil.getHiddenDurationBetween(this.body.hiddenDates, this.start, this.end); + var hiddenDurationBefore = DateUtil.getHiddenDurationBefore(this.body.hiddenDates, this, center); + var hiddenDurationAfter = hiddenDuration - hiddenDurationBefore; - for (var i = 0; i < attributes.length; i++) { - var name = attributes[i]; - var value = this.data[name]; + // calculate new start and end + var newStart = (center-hiddenDurationBefore) + (this.start - (center-hiddenDurationBefore)) * scale; + var newEnd = (center+hiddenDurationAfter) + (this.end - (center+hiddenDurationAfter)) * scale; - if (value != null) { - element.setAttribute('data-' + name, value); - } - else { - element.removeAttribute('data-' + name); - } - } + // snapping times away from hidden zones + this.startToFront = delta > 0 ? false : true; // used to do the right autocorrection with periodic hidden times + this.endToFront = -delta > 0 ? false : true; // used to do the right autocorrection with periodic hidden times + var safeStart = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newStart, delta, true); + var safeEnd = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newEnd, -delta, true); + if (safeStart != newStart || safeEnd != newEnd) { + newStart = safeStart; + newEnd = safeEnd; } + + this.setRange(newStart, newEnd, false, true); + + this.startToFront = false; // revert to default + this.endToFront = true; // revert to default }; + + /** - * Update custom styles of the element - * @param element - * @private + * Move the range with a given delta to the left or right. Start and end + * value will be adjusted. For example, try delta = 0.1 or -0.1 + * @param {Number} delta Moving amount. Positive value will move right, + * negative value will move left */ - Item.prototype._updateStyle = function(element) { - // remove old styles - if (this.style) { - util.removeCssText(element, this.style); - this.style = null; - } - - // append new styles - if (this.data.style) { - util.addCssText(element, this.data.style); - this.style = this.data.style; - } - }; - - module.exports = Item; + Range.prototype.move = function(delta) { + // zoom start Date and end Date relative to the centerDate + var diff = (this.end - this.start); + // apply new values + var newStart = this.start + diff * delta; + var newEnd = this.end + diff * delta; -/***/ }, -/* 32 */ -/***/ function(module, exports, __webpack_require__) { + // TODO: reckon with min and max range - var Hammer = __webpack_require__(45); - var Item = __webpack_require__(31); - var BackgroundGroup = __webpack_require__(26); - var RangeItem = __webpack_require__(35); + this.start = newStart; + this.end = newEnd; + }; /** - * @constructor BackgroundItem - * @extends Item - * @param {Object} data Object containing parameters start, end - * content, className. - * @param {{toScreen: function, toTime: function}} conversion - * Conversion functions from time to screen and vice versa - * @param {Object} [options] Configuration options - * // TODO: describe options + * Move the range to a new center point + * @param {Number} moveTo New center point of the range */ - // TODO: implement support for the BackgroundItem just having a start, then being displayed as a sort of an annotation - function BackgroundItem (data, conversion, options) { - this.props = { - content: { - width: 0 - } - }; - this.overflow = false; // if contents can overflow (css styling), this flag is set to true + Range.prototype.moveTo = function(moveTo) { + var center = (this.start + this.end) / 2; - // validate data - if (data) { - if (data.start == undefined) { - throw new Error('Property "start" missing in item ' + data.id); - } - if (data.end == undefined) { - throw new Error('Property "end" missing in item ' + data.id); - } - } + var diff = center - moveTo; - Item.call(this, data, conversion, options); + // calculate new start and end + var newStart = this.start - diff; + var newEnd = this.end - diff; - this.emptyContent = false; - } + this.setRange(newStart, newEnd); + }; - BackgroundItem.prototype = new Item (null, null, null); + module.exports = Range; - BackgroundItem.prototype.baseClassName = 'item background'; - BackgroundItem.prototype.stack = false; - /** - * Check whether this item is visible inside given range - * @returns {{start: Number, end: Number}} range with a timestamp for start and end - * @returns {boolean} True if visible - */ - BackgroundItem.prototype.isVisible = function(range) { - // determine visibility - return (this.data.start < range.end) && (this.data.end > range.start); - }; +/***/ }, +/* 22 */ +/***/ function(module, exports, __webpack_require__) { + + var Hammer = __webpack_require__(19); /** - * Repaint the item + * Fake a hammer.js gesture. Event can be a ScrollEvent or MouseMoveEvent + * @param {Element} element + * @param {Event} event */ - BackgroundItem.prototype.redraw = function() { - var dom = this.dom; - if (!dom) { - // create DOM - this.dom = {}; - dom = this.dom; - - // background box - dom.box = document.createElement('div'); - // className is updated in redraw() - - // contents box - dom.content = document.createElement('div'); - dom.content.className = 'content'; - dom.box.appendChild(dom.content); + exports.fakeGesture = function(element, event) { + var eventType = null; - // Note: we do NOT attach this item as attribute to the DOM, - // such that background items cannot be selected - //dom.box['timeline-item'] = this; + // for hammer.js 1.0.5 + // var gesture = Hammer.event.collectEventData(this, eventType, event); - this.dirty = true; - } + // for hammer.js 1.0.6+ + var touches = Hammer.event.getTouchList(event, eventType); + var gesture = Hammer.event.collectEventData(this, eventType, touches, event); - // append DOM to parent DOM - if (!this.parent) { - throw new Error('Cannot redraw item: no parent attached'); + // on IE in standards mode, no touches are recognized by hammer.js, + // resulting in NaN values for center.pageX and center.pageY + if (isNaN(gesture.center.pageX)) { + gesture.center.pageX = event.pageX; } - if (!dom.box.parentNode) { - var background = this.parent.dom.background; - if (!background) { - throw new Error('Cannot redraw item: parent has no background container element'); - } - background.appendChild(dom.box); + if (isNaN(gesture.center.pageY)) { + gesture.center.pageY = event.pageY; } - this.displayed = true; - - // Update DOM when item is marked dirty. An item is marked dirty when: - // - the item is not yet rendered - // - the item's data is changed - // - the item is selected/deselected - if (this.dirty) { - this._updateContents(this.dom.content); - this._updateTitle(this.dom.content); - this._updateDataAttributes(this.dom.content); - this._updateStyle(this.dom.box); - // update class - var className = (this.data.className ? (' ' + this.data.className) : '') + - (this.selected ? ' selected' : ''); - dom.box.className = this.baseClassName + className; + return gesture; + }; - // determine from css whether this box has overflow - this.overflow = window.getComputedStyle(dom.content).overflow !== 'hidden'; - // recalculate size - this.props.content.width = this.dom.content.offsetWidth; - this.height = 0; // set height zero, so this item will be ignored when stacking items +/***/ }, +/* 23 */ +/***/ function(module, exports, __webpack_require__) { - this.dirty = false; - } - }; + /** + * Prototype for visual components + * @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} [body] + * @param {Object} [options] + */ + function Component (body, options) { + this.options = null; + this.props = null; + } /** - * Show the item in the DOM (when not already visible). The items DOM will - * be created when needed. + * Set options for the component. The new options will be merged into the + * current options. + * @param {Object} options */ - BackgroundItem.prototype.show = RangeItem.prototype.show; + Component.prototype.setOptions = function(options) { + if (options) { + util.extend(this.options, options); + } + }; /** - * Hide the item from the DOM (when visible) - * @return {Boolean} changed + * Repaint the component + * @return {boolean} Returns true if the component is resized */ - BackgroundItem.prototype.hide = RangeItem.prototype.hide; + Component.prototype.redraw = function() { + // should be implemented by the component + return false; + }; /** - * Reposition the item horizontally - * @Override + * Destroy the component. Cleanup DOM and event listeners */ - BackgroundItem.prototype.repositionX = RangeItem.prototype.repositionX; + Component.prototype.destroy = function() { + // should be implemented by the component + }; /** - * Reposition the item vertically - * @Override + * Test whether the component is resized since the last time _isResized() was + * called. + * @return {Boolean} Returns true if the component is resized + * @protected */ - BackgroundItem.prototype.repositionY = function(margin) { - var onTop = this.options.orientation === 'top'; - this.dom.content.style.top = onTop ? '' : '0'; - this.dom.content.style.bottom = onTop ? '0' : ''; - var height; + Component.prototype._isResized = function() { + var resized = (this.props._previousWidth !== this.props.width || + this.props._previousHeight !== this.props.height); - // special positioning for subgroups - if (this.data.subgroup !== undefined) { - var itemSubgroup = this.data.subgroup; - var subgroups = this.parent.subgroups; - var subgroupIndex = subgroups[itemSubgroup].index; - // if the orientation is top, we need to take the difference in height into account. - if (onTop == true) { - // the first subgroup will have to account for the distance from the top to the first item. - height = this.parent.subgroups[itemSubgroup].height + margin.item.vertical; - height += subgroupIndex == 0 ? margin.axis - 0.5*margin.item.vertical : 0; - var newTop = this.parent.top; - for (var subgroup in subgroups) { - if (subgroups.hasOwnProperty(subgroup)) { - if (subgroups[subgroup].visible == true && subgroups[subgroup].index < subgroupIndex) { - newTop += subgroups[subgroup].height + margin.item.vertical; - } - } - } + this.props._previousWidth = this.props.width; + this.props._previousHeight = this.props.height; - // the others will have to be offset downwards with this same distance. - newTop += subgroupIndex != 0 ? margin.axis - 0.5 * margin.item.vertical : 0; - this.dom.box.style.top = newTop + 'px'; - this.dom.box.style.bottom = ''; - } - // and when the orientation is bottom: - else { - var newTop = this.parent.top; - for (var subgroup in subgroups) { - if (subgroups.hasOwnProperty(subgroup)) { - if (subgroups[subgroup].visible == true && subgroups[subgroup].index > subgroupIndex) { - newTop += subgroups[subgroup].height + margin.item.vertical; - } - } - } - height = this.parent.subgroups[itemSubgroup].height + margin.item.vertical; - this.dom.box.style.top = newTop + 'px'; - this.dom.box.style.bottom = ''; - } - } - // and in the case of no subgroups: - else { - // we want backgrounds with groups to only show in groups. - if (this.parent instanceof BackgroundGroup) { - // if the item is not in a group: - height = Math.max(this.parent.height, - this.parent.itemSet.body.domProps.center.height, - this.parent.itemSet.body.domProps.centerContainer.height); - this.dom.box.style.top = onTop ? '0' : ''; - this.dom.box.style.bottom = onTop ? '' : '0'; - } - else { - height = this.parent.height; - // same alignment for items when orientation is top or bottom - this.dom.box.style.top = this.parent.top + 'px'; - this.dom.box.style.bottom = ''; - } - } - this.dom.box.style.height = height + 'px'; + return resized; }; - module.exports = BackgroundItem; + module.exports = Component; /***/ }, -/* 33 */ +/* 24 */ /***/ function(module, exports, __webpack_require__) { - var Item = __webpack_require__(31); - var util = __webpack_require__(1); - /** - * @constructor BoxItem - * @extends Item - * @param {Object} data Object containing parameters start - * content, className. - * @param {{toScreen: function, toTime: function}} conversion - * Conversion functions from time to screen and vice versa - * @param {Object} [options] Configuration options - * // TODO: describe available options + * Created by Alex on 10/3/2014. */ - function BoxItem (data, conversion, options) { - this.props = { - dot: { - width: 0, - height: 0 - }, - line: { - width: 0, - height: 0 - } - }; - - // validate data - if (data) { - if (data.start == undefined) { - throw new Error('Property "start" missing in item ' + data); - } - } - - Item.call(this, data, conversion, options); - } + var moment = __webpack_require__(2); - BoxItem.prototype = new Item (null, null, null); /** - * Check whether this item is visible inside given range - * @returns {{start: Number, end: Number}} range with a timestamp for start and end - * @returns {boolean} True if visible + * used in Core to convert the options into a volatile variable + * + * @param Core */ - BoxItem.prototype.isVisible = function(range) { - // determine visibility - // TODO: account for the real width of the item. Right now we just add 1/4 to the window - var interval = (range.end - range.start) / 4; - return (this.data.start > range.start - interval) && (this.data.start < range.end + interval); + exports.convertHiddenOptions = function(body, hiddenDates) { + body.hiddenDates = []; + if (hiddenDates) { + if (Array.isArray(hiddenDates) == true) { + for (var i = 0; i < hiddenDates.length; i++) { + if (hiddenDates[i].repeat === undefined) { + var dateItem = {}; + dateItem.start = moment(hiddenDates[i].start).toDate().valueOf(); + dateItem.end = moment(hiddenDates[i].end).toDate().valueOf(); + body.hiddenDates.push(dateItem); + } + } + body.hiddenDates.sort(function (a, b) { + return a.start - b.start; + }); // sort by start time + } + } }; + /** - * Repaint the item + * create new entrees for the repeating hidden dates + * @param body + * @param hiddenDates */ - BoxItem.prototype.redraw = function() { - var dom = this.dom; - if (!dom) { - // create DOM - this.dom = {}; - dom = this.dom; - - // create main box - dom.box = document.createElement('DIV'); - - // contents box (inside the background box). used for making margins - dom.content = document.createElement('DIV'); - dom.content.className = 'content'; - dom.box.appendChild(dom.content); - - // line to axis - dom.line = document.createElement('DIV'); - dom.line.className = 'line'; + exports.updateHiddenDates = function (body, hiddenDates) { + if (hiddenDates && body.domProps.centerContainer.width !== undefined) { + exports.convertHiddenOptions(body, hiddenDates); - // dot on axis - dom.dot = document.createElement('DIV'); - dom.dot.className = 'dot'; + var start = moment(body.range.start); + var end = moment(body.range.end); - // attach this item as attribute - dom.box['timeline-item'] = this; + var totalRange = (body.range.end - body.range.start); + var pixelTime = totalRange / body.domProps.centerContainer.width; - this.dirty = true; - } + for (var i = 0; i < hiddenDates.length; i++) { + if (hiddenDates[i].repeat !== undefined) { + var startDate = moment(hiddenDates[i].start); + var endDate = moment(hiddenDates[i].end); - // append DOM to parent DOM - if (!this.parent) { - throw new Error('Cannot redraw item: no parent attached'); - } - if (!dom.box.parentNode) { - var foreground = this.parent.dom.foreground; - if (!foreground) throw new Error('Cannot redraw item: parent has no foreground container element'); - foreground.appendChild(dom.box); - } - if (!dom.line.parentNode) { - var background = this.parent.dom.background; - if (!background) throw new Error('Cannot redraw item: parent has no background container element'); - background.appendChild(dom.line); - } - if (!dom.dot.parentNode) { - var axis = this.parent.dom.axis; - if (!background) throw new Error('Cannot redraw item: parent has no axis container element'); - axis.appendChild(dom.dot); - } - this.displayed = true; + if (startDate._d == "Invalid Date") { + throw new Error("Supplied start date is not valid: " + hiddenDates[i].start); + } + if (endDate._d == "Invalid Date") { + throw new Error("Supplied end date is not valid: " + hiddenDates[i].end); + } - // Update DOM when item is marked dirty. An item is marked dirty when: - // - the item is not yet rendered - // - the item's data is changed - // - the item is selected/deselected - if (this.dirty) { - this._updateContents(this.dom.content); - this._updateTitle(this.dom.box); - this._updateDataAttributes(this.dom.box); - this._updateStyle(this.dom.box); + var duration = endDate - startDate; + if (duration >= 4 * pixelTime) { - // update class - var className = (this.data.className? ' ' + this.data.className : '') + - (this.selected ? ' selected' : ''); - dom.box.className = 'item box' + className; - dom.line.className = 'item line' + className; - dom.dot.className = 'item dot' + className; + var offset = 0; + var runUntil = end.clone(); + switch (hiddenDates[i].repeat) { + case "daily": // case of time + if (startDate.day() != endDate.day()) { + offset = 1; + } + startDate.dayOfYear(start.dayOfYear()); + startDate.year(start.year()); + startDate.subtract(7,'days'); - // recalculate size - this.props.dot.height = dom.dot.offsetHeight; - this.props.dot.width = dom.dot.offsetWidth; - this.props.line.width = dom.line.offsetWidth; - this.width = dom.box.offsetWidth; - this.height = dom.box.offsetHeight; + endDate.dayOfYear(start.dayOfYear()); + endDate.year(start.year()); + endDate.subtract(7 - offset,'days'); - this.dirty = false; - } + runUntil.add(1, 'weeks'); + break; + case "weekly": + var dayOffset = endDate.diff(startDate,'days') + var day = startDate.day(); - this._repaintDeleteButton(dom.box); - }; + // set the start date to the range.start + startDate.date(start.date()); + startDate.month(start.month()); + startDate.year(start.year()); + endDate = startDate.clone(); - /** - * Show the item in the DOM (when not already displayed). The items DOM will - * be created when needed. - */ - BoxItem.prototype.show = function() { - if (!this.displayed) { - this.redraw(); - } - }; + // force + startDate.day(day); + endDate.day(day); + endDate.add(dayOffset,'days'); - /** - * Hide the item from the DOM (when visible) - */ - BoxItem.prototype.hide = function() { - if (this.displayed) { - var dom = this.dom; + startDate.subtract(1,'weeks'); + endDate.subtract(1,'weeks'); - if (dom.box.parentNode) dom.box.parentNode.removeChild(dom.box); - if (dom.line.parentNode) dom.line.parentNode.removeChild(dom.line); - if (dom.dot.parentNode) dom.dot.parentNode.removeChild(dom.dot); + runUntil.add(1, 'weeks'); + break + case "monthly": + if (startDate.month() != endDate.month()) { + offset = 1; + } + startDate.month(start.month()); + startDate.year(start.year()); + startDate.subtract(1,'months'); - this.top = null; - this.left = null; + endDate.month(start.month()); + endDate.year(start.year()); + endDate.subtract(1,'months'); + endDate.add(offset,'months'); - this.displayed = false; - } - }; + runUntil.add(1, 'months'); + break; + case "yearly": + if (startDate.year() != endDate.year()) { + offset = 1; + } + startDate.year(start.year()); + startDate.subtract(1,'years'); + endDate.year(start.year()); + endDate.subtract(1,'years'); + endDate.add(offset,'years'); - /** - * Reposition the item horizontally - * @Override - */ - BoxItem.prototype.repositionX = function() { - var start = this.conversion.toScreen(this.data.start); - var align = this.options.align; - var left; - var box = this.dom.box; - var line = this.dom.line; - var dot = this.dom.dot; - - // calculate left position of the box - if (align == 'right') { - this.left = start - this.width; - } - else if (align == 'left') { - this.left = start; - } - else { - // default or 'center' - this.left = start - this.width / 2; + runUntil.add(1, 'years'); + break; + default: + console.log("Wrong repeat format, allowed are: daily, weekly, monthly, yearly. Given:", hiddenDates[i].repeat); + return; + } + while (startDate < runUntil) { + body.hiddenDates.push({start: startDate.valueOf(), end: endDate.valueOf()}); + switch (hiddenDates[i].repeat) { + case "daily": + startDate.add(1, 'days'); + endDate.add(1, 'days'); + break; + case "weekly": + startDate.add(1, 'weeks'); + endDate.add(1, 'weeks'); + break + case "monthly": + startDate.add(1, 'months'); + endDate.add(1, 'months'); + break; + case "yearly": + startDate.add(1, 'y'); + endDate.add(1, 'y'); + break; + default: + console.log("Wrong repeat format, allowed are: daily, weekly, monthly, yearly. Given:", hiddenDates[i].repeat); + return; + } + } + body.hiddenDates.push({start: startDate.valueOf(), end: endDate.valueOf()}); + } + } + } + // remove duplicates, merge where possible + exports.removeDuplicates(body); + // ensure the new positions are not on hidden dates + var startHidden = exports.isHidden(body.range.start, body.hiddenDates); + var endHidden = exports.isHidden(body.range.end,body.hiddenDates); + var rangeStart = body.range.start; + var rangeEnd = body.range.end; + if (startHidden.hidden == true) {rangeStart = body.range.startToFront == true ? startHidden.startDate - 1 : startHidden.endDate + 1;} + if (endHidden.hidden == true) {rangeEnd = body.range.endToFront == true ? endHidden.startDate - 1 : endHidden.endDate + 1;} + if (startHidden.hidden == true || endHidden.hidden == true) { + body.range._applyRange(rangeStart, rangeEnd); + } } - // reposition box - box.style.left = this.left + 'px'; - - // reposition line - line.style.left = (start - this.props.line.width / 2) + 'px'; + } - // reposition dot - dot.style.left = (start - this.props.dot.width / 2) + 'px'; - }; /** - * Reposition the item vertically - * @Override + * remove duplicates from the hidden dates list. Duplicates are evil. They mess everything up. + * Scales with N^2 + * @param body */ - BoxItem.prototype.repositionY = function() { - var orientation = this.options.orientation; - var box = this.dom.box; - var line = this.dom.line; - var dot = this.dom.dot; - - if (orientation == 'top') { - box.style.top = (this.top || 0) + 'px'; - - line.style.top = '0'; - line.style.height = (this.parent.top + this.top + 1) + 'px'; - line.style.bottom = ''; + exports.removeDuplicates = function(body) { + var hiddenDates = body.hiddenDates; + var safeDates = []; + for (var i = 0; i < hiddenDates.length; i++) { + for (var j = 0; j < hiddenDates.length; j++) { + if (i != j && hiddenDates[j].remove != true && hiddenDates[i].remove != true) { + // j inside i + if (hiddenDates[j].start >= hiddenDates[i].start && hiddenDates[j].end <= hiddenDates[i].end) { + hiddenDates[j].remove = true; + } + // j start inside i + else if (hiddenDates[j].start >= hiddenDates[i].start && hiddenDates[j].start <= hiddenDates[i].end) { + hiddenDates[i].end = hiddenDates[j].end; + hiddenDates[j].remove = true; + } + // j end inside i + else if (hiddenDates[j].end >= hiddenDates[i].start && hiddenDates[j].end <= hiddenDates[i].end) { + hiddenDates[i].start = hiddenDates[j].start; + hiddenDates[j].remove = true; + } + } + } } - else { // orientation 'bottom' - var itemSetHeight = this.parent.itemSet.props.height; // TODO: this is nasty - var lineHeight = itemSetHeight - this.parent.top - this.parent.height + this.top; - box.style.top = (this.parent.height - this.top - this.height || 0) + 'px'; - line.style.top = (itemSetHeight - lineHeight) + 'px'; - line.style.bottom = '0'; + for (var i = 0; i < hiddenDates.length; i++) { + if (hiddenDates[i].remove !== true) { + safeDates.push(hiddenDates[i]); + } } - dot.style.top = (-this.props.dot.height / 2) + 'px'; - }; - - module.exports = BoxItem; - - -/***/ }, -/* 34 */ -/***/ function(module, exports, __webpack_require__) { + body.hiddenDates = safeDates; + body.hiddenDates.sort(function (a, b) { + return a.start - b.start; + }); // sort by start time + } - var Item = __webpack_require__(31); + exports.printDates = function(dates) { + for (var i =0; i < dates.length; i++) { + console.log(i, new Date(dates[i].start),new Date(dates[i].end), dates[i].start, dates[i].end, dates[i].remove); + } + } /** - * @constructor PointItem - * @extends Item - * @param {Object} data Object containing parameters start - * content, className. - * @param {{toScreen: function, toTime: function}} conversion - * Conversion functions from time to screen and vice versa - * @param {Object} [options] Configuration options - * // TODO: describe available options + * Used in TimeStep to avoid the hidden times. + * @param timeStep + * @param previousTime */ - function PointItem (data, conversion, options) { - this.props = { - dot: { - top: 0, - width: 0, - height: 0 - }, - content: { - height: 0, - marginLeft: 0 - } - }; - - // validate data - if (data) { - if (data.start == undefined) { - throw new Error('Property "start" missing in item ' + data); + exports.stepOverHiddenDates = function(timeStep, previousTime) { + var stepInHidden = false; + var currentValue = timeStep.current.valueOf(); + for (var i = 0; i < timeStep.hiddenDates.length; i++) { + var startDate = timeStep.hiddenDates[i].start; + var endDate = timeStep.hiddenDates[i].end; + if (currentValue >= startDate && currentValue < endDate) { + stepInHidden = true; + break; } } - Item.call(this, data, conversion, options); - } - - PointItem.prototype = new Item (null, null, null); + if (stepInHidden == true && currentValue < timeStep._end.valueOf() && currentValue != previousTime) { + var prevValue = moment(previousTime); + var newValue = moment(endDate); + //check if the next step should be major + if (prevValue.year() != newValue.year()) {timeStep.switchedYear = true;} + else if (prevValue.month() != newValue.month()) {timeStep.switchedMonth = true;} + else if (prevValue.dayOfYear() != newValue.dayOfYear()) {timeStep.switchedDay = true;} - /** - * Check whether this item is visible inside given range - * @returns {{start: Number, end: Number}} range with a timestamp for start and end - * @returns {boolean} True if visible - */ - PointItem.prototype.isVisible = function(range) { - // determine visibility - // TODO: account for the real width of the item. Right now we just add 1/4 to the window - var interval = (range.end - range.start) / 4; - return (this.data.start > range.start - interval) && (this.data.start < range.end + interval); + timeStep.current = newValue.toDate(); + } }; - /** - * Repaint the item - */ - PointItem.prototype.redraw = function() { - var dom = this.dom; - if (!dom) { - // create DOM - this.dom = {}; - dom = this.dom; - - // background box - dom.point = document.createElement('div'); - // className is updated in redraw() - - // contents box, right from the dot - dom.content = document.createElement('div'); - dom.content.className = 'content'; - dom.point.appendChild(dom.content); - - // dot at start - dom.dot = document.createElement('div'); - dom.point.appendChild(dom.dot); - - // attach this item as attribute - dom.point['timeline-item'] = this; - this.dirty = true; - } + ///** + // * Used in TimeStep to avoid the hidden times. + // * @param timeStep + // * @param previousTime + // */ + //exports.checkFirstStep = function(timeStep) { + // var stepInHidden = false; + // var currentValue = timeStep.current.valueOf(); + // for (var i = 0; i < timeStep.hiddenDates.length; i++) { + // var startDate = timeStep.hiddenDates[i].start; + // var endDate = timeStep.hiddenDates[i].end; + // if (currentValue >= startDate && currentValue < endDate) { + // stepInHidden = true; + // break; + // } + // } + // + // if (stepInHidden == true && currentValue <= timeStep._end.valueOf()) { + // var newValue = moment(endDate); + // timeStep.current = newValue.toDate(); + // } + //}; - // append DOM to parent DOM - if (!this.parent) { - throw new Error('Cannot redraw item: no parent attached'); + /** + * replaces the Core toScreen methods + * @param Core + * @param time + * @param width + * @returns {number} + */ + exports.toScreen = function(Core, time, width) { + if (Core.body.hiddenDates.length == 0) { + var conversion = Core.range.conversion(width); + return (time.valueOf() - conversion.offset) * conversion.scale; } - if (!dom.point.parentNode) { - var foreground = this.parent.dom.foreground; - if (!foreground) { - throw new Error('Cannot redraw item: parent has no foreground container element'); + else { + var hidden = exports.isHidden(time, Core.body.hiddenDates) + if (hidden.hidden == true) { + time = hidden.startDate; } - foreground.appendChild(dom.point); - } - this.displayed = true; - - // Update DOM when item is marked dirty. An item is marked dirty when: - // - the item is not yet rendered - // - the item's data is changed - // - the item is selected/deselected - if (this.dirty) { - this._updateContents(this.dom.content); - this._updateTitle(this.dom.point); - this._updateDataAttributes(this.dom.point); - this._updateStyle(this.dom.point); - - // update class - var className = (this.data.className? ' ' + this.data.className : '') + - (this.selected ? ' selected' : ''); - dom.point.className = 'item point' + className; - dom.dot.className = 'item dot' + className; - // recalculate size - this.width = dom.point.offsetWidth; - this.height = dom.point.offsetHeight; - this.props.dot.width = dom.dot.offsetWidth; - this.props.dot.height = dom.dot.offsetHeight; - this.props.content.height = dom.content.offsetHeight; + var duration = exports.getHiddenDurationBetween(Core.body.hiddenDates, Core.range.start, Core.range.end); + time = exports.correctTimeForHidden(Core.body.hiddenDates, Core.range, time); - // resize contents - dom.content.style.marginLeft = 2 * this.props.dot.width + 'px'; - //dom.content.style.marginRight = ... + 'px'; // TODO: margin right + var conversion = Core.range.conversion(width, duration); + return (time.valueOf() - conversion.offset) * conversion.scale; + } + }; - dom.dot.style.top = ((this.height - this.props.dot.height) / 2) + 'px'; - dom.dot.style.left = (this.props.dot.width / 2) + 'px'; - this.dirty = false; + /** + * Replaces the core toTime methods + * @param body + * @param range + * @param x + * @param width + * @returns {Date} + */ + exports.toTime = function(Core, x, width) { + if (Core.body.hiddenDates.length == 0) { + var conversion = Core.range.conversion(width); + return new Date(x / conversion.scale + conversion.offset); } + else { + var hiddenDuration = exports.getHiddenDurationBetween(Core.body.hiddenDates, Core.range.start, Core.range.end); + var totalDuration = Core.range.end - Core.range.start - hiddenDuration; + var partialDuration = totalDuration * x / width; + var accumulatedHiddenDuration = exports.getAccumulatedHiddenDuration(Core.body.hiddenDates, Core.range, partialDuration); - this._repaintDeleteButton(dom.point); + var newTime = new Date(accumulatedHiddenDuration + partialDuration + Core.range.start); + return newTime; + } }; + /** - * Show the item in the DOM (when not already visible). The items DOM will - * be created when needed. + * Support function + * + * @param hiddenDates + * @param range + * @returns {number} */ - PointItem.prototype.show = function() { - if (!this.displayed) { - this.redraw(); + exports.getHiddenDurationBetween = function(hiddenDates, start, end) { + var duration = 0; + for (var i = 0; i < hiddenDates.length; i++) { + var startDate = hiddenDates[i].start; + var endDate = hiddenDates[i].end; + // if time after the cutout, and the + if (startDate >= start && endDate < end) { + duration += endDate - startDate; + } } + return duration; }; + /** - * Hide the item from the DOM (when visible) + * Support function + * @param hiddenDates + * @param range + * @param time + * @returns {{duration: number, time: *, offset: number}} */ - PointItem.prototype.hide = function() { - if (this.displayed) { - if (this.dom.point.parentNode) { - this.dom.point.parentNode.removeChild(this.dom.point); - } + exports.correctTimeForHidden = function(hiddenDates, range, time) { + time = moment(time).toDate().valueOf(); + time -= exports.getHiddenDurationBefore(hiddenDates,range,time); + return time; + }; - this.top = null; - this.left = null; + exports.getHiddenDurationBefore = function(hiddenDates, range, time) { + var timeOffset = 0; + time = moment(time).toDate().valueOf(); - this.displayed = false; + for (var i = 0; i < hiddenDates.length; i++) { + var startDate = hiddenDates[i].start; + var endDate = hiddenDates[i].end; + // if time after the cutout, and the + if (startDate >= range.start && endDate < range.end) { + if (time >= endDate) { + timeOffset += (endDate - startDate); + } + } } - }; + return timeOffset; + } /** - * Reposition the item horizontally - * @Override + * sum the duration from start to finish, including the hidden duration, + * until the required amount has been reached, return the accumulated hidden duration + * @param hiddenDates + * @param range + * @param time + * @returns {{duration: number, time: *, offset: number}} */ - PointItem.prototype.repositionX = function() { - var start = this.conversion.toScreen(this.data.start); - - this.left = start - this.props.dot.width; + exports.getAccumulatedHiddenDuration = function(hiddenDates, range, requiredDuration) { + var hiddenDuration = 0; + var duration = 0; + var previousPoint = range.start; + //exports.printDates(hiddenDates) + for (var i = 0; i < hiddenDates.length; i++) { + var startDate = hiddenDates[i].start; + var endDate = hiddenDates[i].end; + // if time after the cutout, and the + if (startDate >= range.start && endDate < range.end) { + duration += startDate - previousPoint; + previousPoint = endDate; + if (duration >= requiredDuration) { + break; + } + else { + hiddenDuration += endDate - startDate; + } + } + } - // reposition point - this.dom.point.style.left = this.left + 'px'; + return hiddenDuration; }; + + /** - * Reposition the item vertically - * @Override + * used to step over to either side of a hidden block. Correction is disabled on tablets, might be set to true + * @param hiddenDates + * @param time + * @param direction + * @param correctionEnabled + * @returns {*} */ - PointItem.prototype.repositionY = function() { - var orientation = this.options.orientation, - point = this.dom.point; - - if (orientation == 'top') { - point.style.top = this.top + 'px'; + exports.snapAwayFromHidden = function(hiddenDates, time, direction, correctionEnabled) { + var isHidden = exports.isHidden(time, hiddenDates); + if (isHidden.hidden == true) { + if (direction < 0) { + if (correctionEnabled == true) { + return isHidden.startDate - (isHidden.endDate - time) - 1; + } + else { + return isHidden.startDate - 1; + } + } + else { + if (correctionEnabled == true) { + return isHidden.endDate + (time - isHidden.startDate) + 1; + } + else { + return isHidden.endDate + 1; + } + } } else { - point.style.top = (this.parent.height - this.top - this.height) + 'px'; + return time; } - }; - module.exports = PointItem; - - -/***/ }, -/* 35 */ -/***/ function(module, exports, __webpack_require__) { + } - var Hammer = __webpack_require__(45); - var Item = __webpack_require__(31); /** - * @constructor RangeItem - * @extends Item - * @param {Object} data Object containing parameters start, end - * content, className. - * @param {{toScreen: function, toTime: function}} conversion - * Conversion functions from time to screen and vice versa - * @param {Object} [options] Configuration options - * // TODO: describe options + * Check if a time is hidden + * + * @param time + * @param hiddenDates + * @returns {{hidden: boolean, startDate: Window.start, endDate: *}} */ - function RangeItem (data, conversion, options) { - this.props = { - content: { - width: 0 - } - }; - this.overflow = false; // if contents can overflow (css styling), this flag is set to true + exports.isHidden = function(time, hiddenDates) { + for (var i = 0; i < hiddenDates.length; i++) { + var startDate = hiddenDates[i].start; + var endDate = hiddenDates[i].end; - // validate data - if (data) { - if (data.start == undefined) { - throw new Error('Property "start" missing in item ' + data.id); - } - if (data.end == undefined) { - throw new Error('Property "end" missing in item ' + data.id); + if (time >= startDate && time < endDate) { // if the start is entering a hidden zone + return {hidden: true, startDate: startDate, endDate: endDate}; + break; } } - - Item.call(this, data, conversion, options); + return {hidden: false, startDate: startDate, endDate: endDate}; } - RangeItem.prototype = new Item (null, null, null); +/***/ }, +/* 25 */ +/***/ function(module, exports, __webpack_require__) { - RangeItem.prototype.baseClassName = 'item range'; + var Emitter = __webpack_require__(11); + var Hammer = __webpack_require__(19); + var util = __webpack_require__(1); + var DataSet = __webpack_require__(7); + var DataView = __webpack_require__(9); + var Range = __webpack_require__(21); + var ItemSet = __webpack_require__(26); + var Activator = __webpack_require__(35); + var DateUtil = __webpack_require__(24); /** - * Check whether this item is visible inside given range - * @returns {{start: Number, end: Number}} range with a timestamp for start and end - * @returns {boolean} True if visible + * Create a timeline visualization + * @param {HTMLElement} container + * @param {vis.DataSet | Array | google.visualization.DataTable} [items] + * @param {Object} [options] See Core.setOptions for the available options. + * @constructor */ - RangeItem.prototype.isVisible = function(range) { - // determine visibility - return (this.data.start < range.end) && (this.data.end > range.start); - }; + function Core () {} + + // turn Core into an event emitter + Emitter(Core.prototype); /** - * Repaint the item + * Create the main DOM for the Core: a root panel containing left, right, + * top, bottom, content, and background panel. + * @param {Element} container The container element where the Core will + * be attached. + * @private */ - RangeItem.prototype.redraw = function() { - var dom = this.dom; - if (!dom) { - // create DOM - this.dom = {}; - dom = this.dom; + Core.prototype._create = function (container) { + this.dom = {}; - // background box - dom.box = document.createElement('div'); - // className is updated in redraw() + this.dom.root = document.createElement('div'); + this.dom.background = document.createElement('div'); + this.dom.backgroundVertical = document.createElement('div'); + this.dom.backgroundHorizontal = document.createElement('div'); + this.dom.centerContainer = document.createElement('div'); + this.dom.leftContainer = document.createElement('div'); + this.dom.rightContainer = document.createElement('div'); + this.dom.center = document.createElement('div'); + this.dom.left = document.createElement('div'); + this.dom.right = document.createElement('div'); + this.dom.top = document.createElement('div'); + this.dom.bottom = document.createElement('div'); + this.dom.shadowTop = document.createElement('div'); + this.dom.shadowBottom = document.createElement('div'); + this.dom.shadowTopLeft = document.createElement('div'); + this.dom.shadowBottomLeft = document.createElement('div'); + this.dom.shadowTopRight = document.createElement('div'); + this.dom.shadowBottomRight = document.createElement('div'); - // contents box - dom.content = document.createElement('div'); - dom.content.className = 'content'; - dom.box.appendChild(dom.content); + this.dom.root.className = 'vis timeline root'; + this.dom.background.className = 'vispanel background'; + this.dom.backgroundVertical.className = 'vispanel background vertical'; + this.dom.backgroundHorizontal.className = 'vispanel background horizontal'; + this.dom.centerContainer.className = 'vispanel center'; + this.dom.leftContainer.className = 'vispanel left'; + this.dom.rightContainer.className = 'vispanel right'; + this.dom.top.className = 'vispanel top'; + this.dom.bottom.className = 'vispanel bottom'; + this.dom.left.className = 'content'; + this.dom.center.className = 'content'; + this.dom.right.className = 'content'; + this.dom.shadowTop.className = 'shadow top'; + this.dom.shadowBottom.className = 'shadow bottom'; + this.dom.shadowTopLeft.className = 'shadow top'; + this.dom.shadowBottomLeft.className = 'shadow bottom'; + this.dom.shadowTopRight.className = 'shadow top'; + this.dom.shadowBottomRight.className = 'shadow bottom'; - // attach this item as attribute - dom.box['timeline-item'] = this; + this.dom.root.appendChild(this.dom.background); + this.dom.root.appendChild(this.dom.backgroundVertical); + this.dom.root.appendChild(this.dom.backgroundHorizontal); + this.dom.root.appendChild(this.dom.centerContainer); + this.dom.root.appendChild(this.dom.leftContainer); + this.dom.root.appendChild(this.dom.rightContainer); + this.dom.root.appendChild(this.dom.top); + this.dom.root.appendChild(this.dom.bottom); - this.dirty = true; - } + this.dom.centerContainer.appendChild(this.dom.center); + this.dom.leftContainer.appendChild(this.dom.left); + this.dom.rightContainer.appendChild(this.dom.right); - // append DOM to parent DOM - if (!this.parent) { - throw new Error('Cannot redraw item: no parent attached'); - } - if (!dom.box.parentNode) { - var foreground = this.parent.dom.foreground; - if (!foreground) { - throw new Error('Cannot redraw item: parent has no foreground container element'); - } - foreground.appendChild(dom.box); - } - this.displayed = true; + this.dom.centerContainer.appendChild(this.dom.shadowTop); + this.dom.centerContainer.appendChild(this.dom.shadowBottom); + this.dom.leftContainer.appendChild(this.dom.shadowTopLeft); + this.dom.leftContainer.appendChild(this.dom.shadowBottomLeft); + this.dom.rightContainer.appendChild(this.dom.shadowTopRight); + this.dom.rightContainer.appendChild(this.dom.shadowBottomRight); - // Update DOM when item is marked dirty. An item is marked dirty when: - // - the item is not yet rendered - // - the item's data is changed - // - the item is selected/deselected - if (this.dirty) { - this._updateContents(this.dom.content); - this._updateTitle(this.dom.box); - this._updateDataAttributes(this.dom.box); - this._updateStyle(this.dom.box); + this.on('rangechange', this.redraw.bind(this)); + this.on('touch', this._onTouch.bind(this)); + this.on('pinch', this._onPinch.bind(this)); + this.on('dragstart', this._onDragStart.bind(this)); + this.on('drag', this._onDrag.bind(this)); - // update class - var className = (this.data.className ? (' ' + this.data.className) : '') + - (this.selected ? ' selected' : ''); - dom.box.className = this.baseClassName + className; + var me = this; + this.on('change', function (properties) { + if (properties && properties.queue == true) { + // redraw once on next tick + if (!me._redrawTimer) { + me._redrawTimer = setTimeout(function () { + me._redrawTimer = null; + me.redraw(); + }, 0) + } + } + else { + // redraw immediately + me.redraw(); + } + }); - // determine from css whether this box has overflow - this.overflow = window.getComputedStyle(dom.content).overflow !== 'hidden'; + // create event listeners for all interesting events, these events will be + // emitted via emitter + this.hammer = Hammer(this.dom.root, { + preventDefault: true + }); + this.listeners = {}; - // recalculate size - // turn off max-width to be able to calculate the real width - // this causes an extra browser repaint/reflow, but so be it - this.dom.content.style.maxWidth = 'none'; - this.props.content.width = this.dom.content.offsetWidth; - this.height = this.dom.box.offsetHeight; - this.dom.content.style.maxWidth = ''; + var events = [ + 'touch', 'pinch', + 'tap', 'doubletap', 'hold', + 'dragstart', 'drag', 'dragend', + 'mousewheel', 'DOMMouseScroll' // DOMMouseScroll is needed for Firefox + ]; + events.forEach(function (event) { + var listener = function () { + var args = [event].concat(Array.prototype.slice.call(arguments, 0)); + if (me.isActive()) { + me.emit.apply(me, args); + } + }; + me.hammer.on(event, listener); + me.listeners[event] = listener; + }); - this.dirty = false; - } + // size properties of each of the panels + this.props = { + root: {}, + background: {}, + centerContainer: {}, + leftContainer: {}, + rightContainer: {}, + center: {}, + left: {}, + right: {}, + top: {}, + bottom: {}, + border: {}, + scrollTop: 0, + scrollTopMin: 0 + }; + this.touch = {}; // store state information needed for touch events - this._repaintDeleteButton(dom.box); - this._repaintDragLeft(); - this._repaintDragRight(); - }; + this.redrawCount = 0; - /** - * Show the item in the DOM (when not already visible). The items DOM will - * be created when needed. - */ - RangeItem.prototype.show = function() { - if (!this.displayed) { - this.redraw(); - } + // attach the root panel to the provided container + if (!container) throw new Error('No container provided'); + container.appendChild(this.dom.root); }; /** - * Hide the item from the DOM (when visible) - * @return {Boolean} changed + * Set options. Options will be passed to all components loaded in the Timeline. + * @param {Object} [options] + * {String} orientation + * Vertical orientation for the Timeline, + * can be 'bottom' (default) or 'top'. + * {String | Number} width + * Width for the timeline, a number in pixels or + * a css string like '1000px' or '75%'. '100%' by default. + * {String | Number} height + * Fixed height for the Timeline, a number in pixels or + * a css string like '400px' or '75%'. If undefined, + * The Timeline will automatically size such that + * its contents fit. + * {String | Number} minHeight + * Minimum height for the Timeline, a number in pixels or + * a css string like '400px' or '75%'. + * {String | Number} maxHeight + * Maximum height for the Timeline, a number in pixels or + * a css string like '400px' or '75%'. + * {Number | Date | String} start + * Start date for the visible window + * {Number | Date | String} end + * End date for the visible window */ - RangeItem.prototype.hide = function() { - if (this.displayed) { - var box = this.dom.box; + Core.prototype.setOptions = function (options) { + if (options) { + // copy the known options + var fields = ['width', 'height', 'minHeight', 'maxHeight', 'autoResize', 'start', 'end', 'orientation', 'clickToUse', 'dataAttributes', 'hiddenDates']; + util.selectiveExtend(fields, this.options, options); - if (box.parentNode) { - box.parentNode.removeChild(box); + if ('hiddenDates' in this.options) { + DateUtil.convertHiddenOptions(this.body, this.options.hiddenDates); } - this.top = null; - this.left = null; + if ('clickToUse' in options) { + if (options.clickToUse) { + if (!this.activator) { + this.activator = new Activator(this.dom.root); + } + } + else { + if (this.activator) { + this.activator.destroy(); + delete this.activator; + } + } + } - this.displayed = false; + // enable/disable autoResize + this._initAutoResize(); + } + + // propagate options to all components + this.components.forEach(function (component) { + component.setOptions(options); + }); + + // TODO: remove deprecation error one day (deprecated since version 0.8.0) + if (options && options.order) { + throw new Error('Option order is deprecated. There is no replacement for this feature.'); } + + // redraw everything + this.redraw(); }; /** - * Reposition the item horizontally - * @Override + * Returns true when the Timeline is active. + * @returns {boolean} */ - RangeItem.prototype.repositionX = function() { - var parentWidth = this.parent.width; - var start = this.conversion.toScreen(this.data.start); - var end = this.conversion.toScreen(this.data.end); - var contentLeft; - var contentWidth; + Core.prototype.isActive = function () { + return !this.activator || this.activator.active; + }; - // limit the width of the this, as browsers cannot draw very wide divs - if (start < -parentWidth) { - start = -parentWidth; - } - if (end > 2 * parentWidth) { - end = 2 * parentWidth; - } - var boxWidth = Math.max(end - start, 1); + /** + * Destroy the Core, clean up all DOM elements and event listeners. + */ + Core.prototype.destroy = function () { + // unbind datasets + this.clear(); - if (this.overflow) { - this.left = start; - this.width = boxWidth + this.props.content.width; - contentWidth = this.props.content.width; + // remove all event listeners + this.off(); - // Note: The calculation of width is an optimistic calculation, giving - // a width which will not change when moving the Timeline - // So no re-stacking needed, which is nicer for the eye; + // stop checking for changed size + this._stopAutoResize(); + + // remove from DOM + if (this.dom.root.parentNode) { + this.dom.root.parentNode.removeChild(this.dom.root); } - else { - this.left = start; - this.width = boxWidth; - contentWidth = Math.min(end - start - 2 * this.options.padding, this.props.content.width); + this.dom = null; + + // remove Activator + if (this.activator) { + this.activator.destroy(); + delete this.activator; } - this.dom.box.style.left = this.left + 'px'; - this.dom.box.style.width = boxWidth + 'px'; + // cleanup hammer touch events + for (var event in this.listeners) { + if (this.listeners.hasOwnProperty(event)) { + delete this.listeners[event]; + } + } + this.listeners = null; + this.hammer = null; - switch (this.options.align) { - case 'left': - this.dom.content.style.left = '0'; - break; + // give all components the opportunity to cleanup + this.components.forEach(function (component) { + component.destroy(); + }); - case 'right': - this.dom.content.style.left = Math.max((boxWidth - contentWidth - 2 * this.options.padding), 0) + 'px'; - break; + this.body = null; + }; - case 'center': - this.dom.content.style.left = Math.max((boxWidth - contentWidth - 2 * this.options.padding) / 2, 0) + 'px'; - break; - default: // 'auto' - // when range exceeds left of the window, position the contents at the left of the visible area - if (this.overflow) { - if (end > 0) { - contentLeft = Math.max(-start, 0); - } - else { - contentLeft = -contentWidth; // ensure it's not visible anymore - } - } - else { - if (start < 0) { - contentLeft = Math.min(-start, - (end - start - contentWidth - 2 * this.options.padding)); - // TODO: remove the need for options.padding. it's terrible. - } - else { - contentLeft = 0; - } - } - this.dom.content.style.left = contentLeft + 'px'; + /** + * Set a custom time bar + * @param {Date} time + */ + Core.prototype.setCustomTime = function (time) { + if (!this.customTime) { + throw new Error('Cannot get custom time: Custom time bar is not enabled'); } + + this.customTime.setCustomTime(time); }; /** - * Reposition the item vertically - * @Override + * Retrieve the current custom time. + * @return {Date} customTime */ - RangeItem.prototype.repositionY = function() { - var orientation = this.options.orientation, - box = this.dom.box; - - if (orientation == 'top') { - box.style.top = this.top + 'px'; - } - else { - box.style.top = (this.parent.height - this.top - this.height) + 'px'; + Core.prototype.getCustomTime = function() { + if (!this.customTime) { + throw new Error('Cannot get custom time: Custom time bar is not enabled'); } + + return this.customTime.getCustomTime(); }; + /** - * Repaint a drag area on the left side of the range when the range is selected - * @protected + * Get the id's of the currently visible items. + * @returns {Array} The ids of the visible items */ - RangeItem.prototype._repaintDragLeft = function () { - if (this.selected && this.options.editable.updateTime && !this.dom.dragLeft) { - // create and show drag area - var dragLeft = document.createElement('div'); - dragLeft.className = 'drag-left'; - dragLeft.dragLeftItem = this; + Core.prototype.getVisibleItems = function() { + return this.itemSet && this.itemSet.getVisibleItems() || []; + }; - // TODO: this should be redundant? - Hammer(dragLeft, { - preventDefault: true - }).on('drag', function () { - //console.log('drag left') - }); - this.dom.box.appendChild(dragLeft); - this.dom.dragLeft = dragLeft; - } - else if (!this.selected && this.dom.dragLeft) { - // delete drag area - if (this.dom.dragLeft.parentNode) { - this.dom.dragLeft.parentNode.removeChild(this.dom.dragLeft); - } - this.dom.dragLeft = null; - } - }; /** - * Repaint a drag area on the right side of the range when the range is selected - * @protected + * Clear the Core. By Default, items, groups and options are cleared. + * Example usage: + * + * timeline.clear(); // clear items, groups, and options + * timeline.clear({options: true}); // clear options only + * + * @param {Object} [what] Optionally specify what to clear. By default: + * {items: true, groups: true, options: true} */ - RangeItem.prototype._repaintDragRight = function () { - if (this.selected && this.options.editable.updateTime && !this.dom.dragRight) { - // create and show drag area - var dragRight = document.createElement('div'); - dragRight.className = 'drag-right'; - dragRight.dragRightItem = this; + Core.prototype.clear = function(what) { + // clear items + if (!what || what.items) { + this.setItems(null); + } - // TODO: this should be redundant? - Hammer(dragRight, { - preventDefault: true - }).on('drag', function () { - //console.log('drag right') + // clear groups + if (!what || what.groups) { + this.setGroups(null); + } + + // clear options of timeline and of each of the components + if (!what || what.options) { + this.components.forEach(function (component) { + component.setOptions(component.defaultOptions); }); - this.dom.box.appendChild(dragRight); - this.dom.dragRight = dragRight; - } - else if (!this.selected && this.dom.dragRight) { - // delete drag area - if (this.dom.dragRight.parentNode) { - this.dom.dragRight.parentNode.removeChild(this.dom.dragRight); - } - this.dom.dragRight = null; + this.setOptions(this.defaultOptions); // this will also do a redraw } }; - module.exports = RangeItem; - - -/***/ }, -/* 36 */ -/***/ function(module, exports, __webpack_require__) { + /** + * Set Core window such that it fits all items + * @param {Object} [options] Available options: + * `animate: boolean | number` + * If true (default), the range is animated + * smoothly to the new window. + * If a number, the number is taken as duration + * for the animation. Default duration is 500 ms. + */ + Core.prototype.fit = function(options) { + var range = this._getDataRange(); - var Emitter = __webpack_require__(56); - var Hammer = __webpack_require__(45); - var keycharm = __webpack_require__(57); - var util = __webpack_require__(1); - var hammerUtil = __webpack_require__(47); - var DataSet = __webpack_require__(3); - var DataView = __webpack_require__(4); - var dotparser = __webpack_require__(42); - var gephiParser = __webpack_require__(43); - var Groups = __webpack_require__(38); - var Images = __webpack_require__(39); - var Node = __webpack_require__(40); - var Edge = __webpack_require__(37); - var Popup = __webpack_require__(41); - var MixinLoader = __webpack_require__(54); - var Activator = __webpack_require__(55); - var locales = __webpack_require__(49); + // skip range set if there is no start and end date + if (range.start === null && range.end === null) { + return; + } - // Load custom shapes into CanvasRenderingContext2D - __webpack_require__(50); + var animate = (options && options.animate !== undefined) ? options.animate : true; + this.range.setRange(range.start, range.end, animate); + }; /** - * @constructor Network - * Create a network visualization, displaying nodes and edges. - * - * @param {Element} container The DOM element in which the Network will - * be created. Normally a div element. - * @param {Object} data An object containing parameters - * {Array} nodes - * {Array} edges - * @param {Object} options Options + * Calculate the data range of the items and applies a 5% window around it. + * @returns {{start: Date | null, end: Date | null}} + * @protected */ - function Network (container, data, options) { - if (!(this instanceof Network)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - this._determineBrowserMethod(); - this._initializeMixinLoaders(); - - // create variables and set default values - this.containerElement = container; - - // render and calculation settings - this.renderRefreshRate = 60; // hz (fps) - this.renderTimestep = 1000 / this.renderRefreshRate; // ms -- saves calculation later on - this.renderTime = 0; // measured time it takes to render a frame - this.physicsTime = 0; // measured time it takes to render a frame - this.runDoubleSpeed = false; - this.physicsDiscreteStepsize = 0.50; // discrete stepsize of the simulation - - this.initializing = true; - - this.triggerFunctions = {add:null,edit:null,editEdge:null,connect:null,del:null}; - - // set constant values - this.defaultOptions = { - nodes: { - mass: 1, - radiusMin: 10, - radiusMax: 30, - radius: 10, - shape: 'ellipse', - image: undefined, - widthMin: 16, // px - widthMax: 64, // px - fontColor: 'black', - fontSize: 14, // px - fontFace: 'verdana', - fontFill: undefined, - fontStrokeWidth: 0, // px - fontStrokeColor: 'white', - level: -1, - color: { - border: '#2B7CE9', - background: '#97C2FC', - highlight: { - border: '#2B7CE9', - background: '#D2E5FF' - }, - hover: { - border: '#2B7CE9', - background: '#D2E5FF' - } - }, - group: undefined, - borderWidth: 1, - borderWidthSelected: undefined - }, - edges: { - widthMin: 1, // - widthMax: 15,// - width: 1, - widthSelectionMultiplier: 2, - hoverWidth: 1.5, - style: 'line', - color: { - color:'#848484', - highlight:'#848484', - hover: '#848484' - }, - fontColor: '#343434', - fontSize: 14, // px - fontFace: 'arial', - fontFill: 'white', - fontStrokeWidth: 0, // px - fontStrokeColor: 'white', - labelAlignment:'horizontal', - arrowScaleFactor: 1, - dash: { - length: 10, - gap: 5, - altLength: undefined - }, - inheritColor: "from" // to, from, false, true (== from) - }, - configurePhysics:false, - physics: { - barnesHut: { - enabled: true, - thetaInverted: 1 / 0.5, // inverted to save time during calculation - gravitationalConstant: -2000, - centralGravity: 0.3, - springLength: 95, - springConstant: 0.04, - damping: 0.09 - }, - repulsion: { - centralGravity: 0.0, - springLength: 200, - springConstant: 0.05, - nodeDistance: 100, - damping: 0.09 - }, - hierarchicalRepulsion: { - enabled: false, - centralGravity: 0.0, - springLength: 100, - springConstant: 0.01, - nodeDistance: 150, - damping: 0.09 - }, - damping: null, - centralGravity: null, - springLength: null, - springConstant: null - }, - clustering: { // Per Node in Cluster = PNiC - enabled: false, // (Boolean) | global on/off switch for clustering. - initialMaxNodes: 100, // (# nodes) | if the initial amount of nodes is larger than this, we cluster until the total number is less than this threshold. - clusterThreshold:500, // (# nodes) | during calculate forces, we check if the total number of nodes is larger than this. If it is, cluster until reduced to reduceToNodes - reduceToNodes:300, // (# nodes) | during calculate forces, we check if the total number of nodes is larger than clusterThreshold. If it is, cluster until reduced to this - chainThreshold: 0.4, // (% of all drawn nodes)| maximum percentage of allowed chainnodes (long strings of connected nodes) within all nodes. (lower means less chains). - clusterEdgeThreshold: 20, // (px) | edge length threshold. if smaller, this node is clustered. - sectorThreshold: 100, // (# nodes in cluster) | cluster size threshold. If larger, expanding in own sector. - screenSizeThreshold: 0.2, // (% of canvas) | relative size threshold. If the width or height of a clusternode takes up this much of the screen, decluster node. - fontSizeMultiplier: 4.0, // (px PNiC) | how much the cluster font size grows per node in cluster (in px). - maxFontSize: 1000, - forceAmplification: 0.1, // (multiplier PNiC) | factor of increase fo the repulsion force of a cluster (per node in cluster). - distanceAmplification: 0.1, // (multiplier PNiC) | factor how much the repulsion distance of a cluster increases (per node in cluster). - edgeGrowth: 20, // (px PNiC) | amount of clusterSize connected to the edge is multiplied with this and added to edgeLength. - nodeScaling: {width: 1, // (px PNiC) | growth of the width per node in cluster. - height: 1, // (px PNiC) | growth of the height per node in cluster. - radius: 1}, // (px PNiC) | growth of the radius per node in cluster. - maxNodeSizeIncrements: 600, // (# increments) | max growth of the width per node in cluster. - activeAreaBoxSize: 80, // (px) | box area around the curser where clusters are popped open. - clusterLevelDifference: 2 - }, - navigation: { - enabled: false - }, - keyboard: { - enabled: false, - speed: {x: 10, y: 10, zoom: 0.02} - }, - dataManipulation: { - enabled: false, - initiallyVisible: false - }, - hierarchicalLayout: { - enabled:false, - levelSeparation: 150, - nodeSpacing: 100, - direction: "UD", // UD, DU, LR, RL - layout: "hubsize" // hubsize, directed - }, - freezeForStabilization: false, - smoothCurves: { - enabled: true, - dynamic: true, - type: "continuous", - roundness: 0.5 - }, - maxVelocity: 30, - minVelocity: 0.1, // px/s - stabilize: true, // stabilize before displaying the network - stabilizationIterations: 1000, // maximum number of iteration to stabilize - zoomExtentOnStabilize: true, - locale: 'en', - locales: locales, - tooltip: { - delay: 300, - fontColor: 'black', - fontSize: 14, // px - fontFace: 'verdana', - color: { - border: '#666', - background: '#FFFFC6' - } - }, - dragNetwork: true, - dragNodes: true, - zoomable: true, - hover: false, - hideEdgesOnDrag: false, - hideNodesOnDrag: false, - width : '100%', - height : '100%', - selectable: true - }; - this.constants = util.extend({}, this.defaultOptions); - this.pixelRatio = 1; - - - this.hoverObj = {nodes:{},edges:{}}; - this.controlNodesActive = false; - this.navigationHammers = {existing:[], _new: []}; - - // animation properties - this.animationSpeed = 1/this.renderRefreshRate; - this.animationEasingFunction = "easeInOutQuint"; - this.easingTime = 0; - this.sourceScale = 0; - this.targetScale = 0; - this.sourceTranslation = 0; - this.targetTranslation = 0; - this.lockedOnNodeId = null; - this.lockedOnNodeOffset = null; - this.touchTime = 0; - - // Node variables - var network = this; - this.groups = new Groups(); // object with groups - this.images = new Images(); // object with images - this.images.setOnloadCallback(function (status) { - network._redraw(); - }); - - // keyboard navigation variables - this.xIncrement = 0; - this.yIncrement = 0; - this.zoomIncrement = 0; - - // loading all the mixins: - // load the force calculation functions, grouped under the physics system. - this._loadPhysicsSystem(); - // create a frame and canvas - this._create(); - // load the sector system. (mandatory, fully integrated with Network) - this._loadSectorSystem(); - // load the cluster system. (mandatory, even when not using the cluster system, there are function calls to it) - this._loadClusterSystem(); - // load the selection system. (mandatory, required by Network) - this._loadSelectionSystem(); - // load the selection system. (mandatory, required by Network) - this._loadHierarchySystem(); - - - // apply options - this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2); - this._setScale(1); - this.setOptions(options); - - // other vars - this.freezeSimulation = false;// freeze the simulation - this.cachedFunctions = {}; - this.startedStabilization = false; - this.stabilized = false; - this.stabilizationIterations = null; - this.draggingNodes = false; - - // containers for nodes and edges - this.calculationNodes = {}; - this.calculationNodeIndices = []; - this.nodeIndices = []; // array with all the indices of the nodes. Used to speed up forces calculation - this.nodes = {}; // object with Node objects - this.edges = {}; // object with Edge objects - - // position and scale variables and objects - this.canvasTopLeft = {"x": 0,"y": 0}; // coordinates of the top left of the canvas. they will be set during _redraw. - this.canvasBottomRight = {"x": 0,"y": 0}; // coordinates of the bottom right of the canvas. they will be set during _redraw - this.pointerPosition = {"x": 0,"y": 0}; // coordinates of the bottom right of the canvas. they will be set during _redraw - this.areaCenter = {}; // object with x and y elements used for determining the center of the zoom action - this.scale = 1; // defining the global scale variable in the constructor - this.previousScale = this.scale; // this is used to check if the zoom operation is zooming in or out - - // datasets or dataviews - this.nodesData = null; // A DataSet or DataView - this.edgesData = null; // A DataSet or DataView - - // create event listeners used to subscribe on the DataSets of the nodes and edges - this.nodesListeners = { - 'add': function (event, params) { - network._addNodes(params.items); - network.start(); - }, - 'update': function (event, params) { - network._updateNodes(params.items, params.data); - network.start(); - }, - 'remove': function (event, params) { - network._removeNodes(params.items); - network.start(); - } - }; - this.edgesListeners = { - 'add': function (event, params) { - network._addEdges(params.items); - network.start(); - }, - 'update': function (event, params) { - network._updateEdges(params.items); - network.start(); - }, - 'remove': function (event, params) { - network._removeEdges(params.items); - network.start(); - } - }; - - // properties for the animation - this.moving = true; - this.timer = undefined; // Scheduling function. Is definded in this.start(); - - // load data (the disable start variable will be the same as the enabled clustering) - this.setData(data,this.constants.clustering.enabled || this.constants.hierarchicalLayout.enabled); + Core.prototype._getDataRange = function() { + // apply the data range as range + var dataRange = this.getItemRange(); - // hierarchical layout - this.initializing = false; - if (this.constants.hierarchicalLayout.enabled == true) { - this._setupHierarchicalLayout(); - } - else { - // zoom so all data will fit on the screen, if clustering is enabled, we do not want start to be called here. - if (this.constants.stabilize == false) { - this.zoomExtent(undefined, true,this.constants.clustering.enabled); + // add 5% space on both sides + var start = dataRange.min; + var end = dataRange.max; + if (start != null && end != null) { + var interval = (end.valueOf() - start.valueOf()); + if (interval <= 0) { + // prevent an empty interval + interval = 24 * 60 * 60 * 1000; // 1 day } + start = new Date(start.valueOf() - interval * 0.05); + end = new Date(end.valueOf() + interval * 0.05); } - // if clustering is disabled, the simulation will have started in the setData function - if (this.constants.clustering.enabled) { - this.startWithClustering(); + return { + start: start, + end: end } - } - - // Extend Network with an Emitter mixin - Emitter(Network.prototype); + }; /** - * Determine if the browser requires a setTimeout or a requestAnimationFrame. This was required because - * some implementations (safari and IE9) did not support requestAnimationFrame - * @private + * Set the visible window. Both parameters are optional, you can change only + * start or only end. Syntax: + * + * TimeLine.setWindow(start, end) + * TimeLine.setWindow(range) + * + * Where start and end can be a Date, number, or string, and range is an + * object with properties start and end. + * + * @param {Date | Number | String | Object} [start] Start date of visible window + * @param {Date | Number | String} [end] End date of visible window + * @param {Object} [options] Available options: + * `animate: boolean | number` + * If true (default), the range is animated + * smoothly to the new window. + * If a number, the number is taken as duration + * for the animation. Default duration is 500 ms. */ - Network.prototype._determineBrowserMethod = function() { - var browserType = navigator.userAgent.toLowerCase(); - this.requiresTimeout = false; - if (browserType.indexOf('msie 9.0') != -1) { // IE 9 - this.requiresTimeout = true; + Core.prototype.setWindow = function(start, end, options) { + var animate = (options && options.animate !== undefined) ? options.animate : true; + if (arguments.length == 1) { + var range = arguments[0]; + this.range.setRange(range.start, range.end, animate); } - else if (browserType.indexOf('safari') != -1) { // safari - if (browserType.indexOf('chrome') <= -1) { - this.requiresTimeout = true; - } + else { + this.range.setRange(start, end, animate); } - } - + }; /** - * Get the script path where the vis.js library is located - * - * @returns {string | null} path Path or null when not found. Path does not - * end with a slash. - * @private + * Move the window such that given time is centered on screen. + * @param {Date | Number | String} time + * @param {Object} [options] Available options: + * `animate: boolean | number` + * If true (default), the range is animated + * smoothly to the new window. + * If a number, the number is taken as duration + * for the animation. Default duration is 500 ms. */ - Network.prototype._getScriptPath = function() { - var scripts = document.getElementsByTagName( 'script' ); + Core.prototype.moveTo = function(time, options) { + var interval = this.range.end - this.range.start; + var t = util.convert(time, 'Date').valueOf(); - // find script named vis.js or vis.min.js - for (var i = 0; i < scripts.length; i++) { - var src = scripts[i].src; - var match = src && /\/?vis(.min)?\.js$/.exec(src); - if (match) { - // return path without the script name - return src.substring(0, src.length - match[0].length); - } - } + var start = t - interval / 2; + var end = t + interval / 2; + var animate = (options && options.animate !== undefined) ? options.animate : true; - return null; + this.range.setRange(start, end, animate); }; - /** - * Find the center position of the network - * @private + * Get the visible window + * @return {{start: Date, end: Date}} Visible range */ - Network.prototype._getRange = function() { - var minY = 1e9, maxY = -1e9, minX = 1e9, maxX = -1e9, node; - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - if (minX > (node.boundingBox.left)) {minX = node.boundingBox.left;} - if (maxX < (node.boundingBox.right)) {maxX = node.boundingBox.right;} - if (minY > (node.boundingBox.bottom)) {minY = node.boundingBox.bottom;} - if (maxY < (node.boundingBox.top)) {maxY = node.boundingBox.top;} - } - } - if (minX == 1e9 && maxX == -1e9 && minY == 1e9 && maxY == -1e9) { - minY = 0, maxY = 0, minX = 0, maxX = 0; - } - return {minX: minX, maxX: maxX, minY: minY, maxY: maxY}; + Core.prototype.getWindow = function() { + var range = this.range.getRange(); + return { + start: new Date(range.start), + end: new Date(range.end) + }; }; - /** - * @param {object} range = {minX: minX, maxX: maxX, minY: minY, maxY: maxY}; - * @returns {{x: number, y: number}} - * @private + * Force a redraw of the Core. Can be useful to manually redraw when + * option autoResize=false */ - Network.prototype._findCenter = function(range) { - return {x: (0.5 * (range.maxX + range.minX)), - y: (0.5 * (range.maxY + range.minY))}; - }; + Core.prototype.redraw = function() { + var resized = false; + var options = this.options; + var props = this.props; + var dom = this.dom; + if (!dom) return; // when destroyed - /** - * This function zooms out to fit all data on screen based on amount of nodes - * - * @param {Boolean} [initialZoom] | zoom based on fitted formula or range, true = fitted, default = false; - * @param {Boolean} [disableStart] | If true, start is not called. - */ - Network.prototype.zoomExtent = function(animationOptions, initialZoom, disableStart) { - this._redraw(true); + DateUtil.updateHiddenDates(this.body, this.options.hiddenDates); - if (initialZoom === undefined) { - initialZoom = false; - } - if (disableStart === undefined) { - disableStart = false; + // update class names + if (options.orientation == 'top') { + util.addClassName(dom.root, 'top'); + util.removeClassName(dom.root, 'bottom'); } - if (animationOptions === undefined) { - animationOptions = false; + else { + util.removeClassName(dom.root, 'top'); + util.addClassName(dom.root, 'bottom'); } - var range = this._getRange(); - var zoomLevel; + // update root width and height options + dom.root.style.maxHeight = util.option.asSize(options.maxHeight, ''); + dom.root.style.minHeight = util.option.asSize(options.minHeight, ''); + dom.root.style.width = util.option.asSize(options.width, ''); - if (initialZoom == true) { - var numberOfNodes = this.nodeIndices.length; - if (this.constants.smoothCurves == true) { - if (this.constants.clustering.enabled == true && - numberOfNodes >= this.constants.clustering.initialMaxNodes) { - zoomLevel = 49.07548 / (numberOfNodes + 142.05338) + 9.1444e-04; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. - } - else { - zoomLevel = 12.662 / (numberOfNodes + 7.4147) + 0.0964822; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. - } - } - else { - if (this.constants.clustering.enabled == true && - numberOfNodes >= this.constants.clustering.initialMaxNodes) { - zoomLevel = 77.5271985 / (numberOfNodes + 187.266146) + 4.76710517e-05; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. - } - else { - zoomLevel = 30.5062972 / (numberOfNodes + 19.93597763) + 0.08413486; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. - } - } + // calculate border widths + props.border.left = (dom.centerContainer.offsetWidth - dom.centerContainer.clientWidth) / 2; + props.border.right = props.border.left; + props.border.top = (dom.centerContainer.offsetHeight - dom.centerContainer.clientHeight) / 2; + props.border.bottom = props.border.top; + var borderRootHeight= dom.root.offsetHeight - dom.root.clientHeight; + var borderRootWidth = dom.root.offsetWidth - dom.root.clientWidth; - // correct for larger canvasses. - var factor = Math.min(this.frame.canvas.clientWidth / 600, this.frame.canvas.clientHeight / 600); - zoomLevel *= factor; - } - else { - var xDistance = Math.abs(range.maxX - range.minX) * 1.1; - var yDistance = Math.abs(range.maxY - range.minY) * 1.1; + // workaround for a bug in IE: the clientWidth of an element with + // a height:0px and overflow:hidden is not calculated and always has value 0 + if (dom.centerContainer.clientHeight === 0) { + props.border.left = props.border.top; + props.border.right = props.border.left; + } + if (dom.root.clientHeight === 0) { + borderRootWidth = borderRootHeight; + } - var xZoomLevel = this.frame.canvas.clientWidth / xDistance; - var yZoomLevel = this.frame.canvas.clientHeight / yDistance; + // calculate the heights. If any of the side panels is empty, we set the height to + // minus the border width, such that the border will be invisible + props.center.height = dom.center.offsetHeight; + props.left.height = dom.left.offsetHeight; + props.right.height = dom.right.offsetHeight; + props.top.height = dom.top.clientHeight || -props.border.top; + props.bottom.height = dom.bottom.clientHeight || -props.border.bottom; - zoomLevel = (xZoomLevel <= yZoomLevel) ? xZoomLevel : yZoomLevel; - } + // TODO: compensate borders when any of the panels is empty. - if (zoomLevel > 1.0) { - zoomLevel = 1.0; - } + // apply auto height + // TODO: only calculate autoHeight when needed (else we cause an extra reflow/repaint of the DOM) + var contentHeight = Math.max(props.left.height, props.center.height, props.right.height); + var autoHeight = props.top.height + contentHeight + props.bottom.height + + borderRootHeight + props.border.top + props.border.bottom; + dom.root.style.height = util.option.asSize(options.height, autoHeight + 'px'); + // calculate heights of the content panels + props.root.height = dom.root.offsetHeight; + props.background.height = props.root.height - borderRootHeight; + var containerHeight = props.root.height - props.top.height - props.bottom.height - + borderRootHeight; + props.centerContainer.height = containerHeight; + props.leftContainer.height = containerHeight; + props.rightContainer.height = props.leftContainer.height; - var center = this._findCenter(range); - if (disableStart == false) { - var options = {position: center, scale: zoomLevel, animation: animationOptions}; - this.moveTo(options); - this.moving = true; - this.start(); - } - else { - center.x *= zoomLevel; - center.y *= zoomLevel; - center.x -= 0.5 * this.frame.canvas.clientWidth; - center.y -= 0.5 * this.frame.canvas.clientHeight; - this._setScale(zoomLevel); - this._setTranslation(-center.x,-center.y); + // calculate the widths of the panels + props.root.width = dom.root.offsetWidth; + props.background.width = props.root.width - borderRootWidth; + props.left.width = dom.leftContainer.clientWidth || -props.border.left; + props.leftContainer.width = props.left.width; + props.right.width = dom.rightContainer.clientWidth || -props.border.right; + props.rightContainer.width = props.right.width; + var centerWidth = props.root.width - props.left.width - props.right.width - borderRootWidth; + props.center.width = centerWidth; + props.centerContainer.width = centerWidth; + props.top.width = centerWidth; + props.bottom.width = centerWidth; + + // resize the panels + dom.background.style.height = props.background.height + 'px'; + dom.backgroundVertical.style.height = props.background.height + 'px'; + dom.backgroundHorizontal.style.height = props.centerContainer.height + 'px'; + dom.centerContainer.style.height = props.centerContainer.height + 'px'; + dom.leftContainer.style.height = props.leftContainer.height + 'px'; + dom.rightContainer.style.height = props.rightContainer.height + 'px'; + + dom.background.style.width = props.background.width + 'px'; + dom.backgroundVertical.style.width = props.centerContainer.width + 'px'; + dom.backgroundHorizontal.style.width = props.background.width + 'px'; + dom.centerContainer.style.width = props.center.width + 'px'; + dom.top.style.width = props.top.width + 'px'; + dom.bottom.style.width = props.bottom.width + 'px'; + + // reposition the panels + dom.background.style.left = '0'; + dom.background.style.top = '0'; + dom.backgroundVertical.style.left = (props.left.width + props.border.left) + 'px'; + dom.backgroundVertical.style.top = '0'; + dom.backgroundHorizontal.style.left = '0'; + dom.backgroundHorizontal.style.top = props.top.height + 'px'; + dom.centerContainer.style.left = props.left.width + 'px'; + dom.centerContainer.style.top = props.top.height + 'px'; + dom.leftContainer.style.left = '0'; + dom.leftContainer.style.top = props.top.height + 'px'; + dom.rightContainer.style.left = (props.left.width + props.center.width) + 'px'; + dom.rightContainer.style.top = props.top.height + 'px'; + dom.top.style.left = props.left.width + 'px'; + dom.top.style.top = '0'; + dom.bottom.style.left = props.left.width + 'px'; + dom.bottom.style.top = (props.top.height + props.centerContainer.height) + 'px'; + + // update the scrollTop, feasible range for the offset can be changed + // when the height of the Core or of the contents of the center changed + this._updateScrollTop(); + + // reposition the scrollable contents + var offset = this.props.scrollTop; + if (options.orientation == 'bottom') { + offset += Math.max(this.props.centerContainer.height - this.props.center.height - + this.props.border.top - this.props.border.bottom, 0); } - }; + dom.center.style.left = '0'; + dom.center.style.top = offset + 'px'; + dom.left.style.left = '0'; + dom.left.style.top = offset + 'px'; + dom.right.style.left = '0'; + dom.right.style.top = offset + 'px'; + // show shadows when vertical scrolling is available + var visibilityTop = this.props.scrollTop == 0 ? 'hidden' : ''; + var visibilityBottom = this.props.scrollTop == this.props.scrollTopMin ? 'hidden' : ''; + dom.shadowTop.style.visibility = visibilityTop; + dom.shadowBottom.style.visibility = visibilityBottom; + dom.shadowTopLeft.style.visibility = visibilityTop; + dom.shadowBottomLeft.style.visibility = visibilityBottom; + dom.shadowTopRight.style.visibility = visibilityTop; + dom.shadowBottomRight.style.visibility = visibilityBottom; - /** - * Update the this.nodeIndices with the most recent node index list - * @private - */ - Network.prototype._updateNodeIndexList = function() { - this._clearNodeIndexList(); - for (var idx in this.nodes) { - if (this.nodes.hasOwnProperty(idx)) { - this.nodeIndices.push(idx); + // redraw all components + this.components.forEach(function (component) { + resized = component.redraw() || resized; + }); + if (resized) { + // keep repainting until all sizes are settled + var MAX_REDRAWS = 3; // maximum number of consecutive redraws + if (this.redrawCount < MAX_REDRAWS) { + this.redrawCount++; + this.redraw(); + } + else { + console.log('WARNING: infinite loop in redraw?'); } + this.redrawCount = 0; } + + this.emit("finishedRedraw"); }; + // TODO: deprecated since version 1.1.0, remove some day + Core.prototype.repaint = function () { + throw new Error('Function repaint is deprecated. Use redraw instead.'); + }; /** - * Set nodes and edges, and optionally options as well. - * - * @param {Object} data Object containing parameters: - * {Array | DataSet | DataView} [nodes] Array with nodes - * {Array | DataSet | DataView} [edges] Array with edges - * {String} [dot] String containing data in DOT format - * {String} [gephi] String containing data in gephi JSON format - * {Options} [options] Object with options - * @param {Boolean} [disableStart] | optional: disable the calling of the start function. + * Set a current time. This can be used for example to ensure that a client's + * time is synchronized with a shared server time. + * Only applicable when option `showCurrentTime` is true. + * @param {Date | String | Number} time A Date, unix timestamp, or + * ISO date string. */ - Network.prototype.setData = function(data, disableStart) { - if (disableStart === undefined) { - disableStart = false; + Core.prototype.setCurrentTime = function(time) { + if (!this.currentTime) { + throw new Error('Option showCurrentTime must be true'); } - // we set initializing to true to ensure that the hierarchical layout is not performed until both nodes and edges are added. - this.initializing = true; - if (data && data.dot && (data.nodes || data.edges)) { - throw new SyntaxError('Data must contain either parameter "dot" or ' + - ' parameter pair "nodes" and "edges", but not both.'); - } + this.currentTime.setCurrentTime(time); + }; - // clean up in case there is anyone in an active mode of the manipulation. This is the same option as bound to the escape button. - if (this.constants.dataManipulation.enabled == true) { - this._createManipulatorBar(); + /** + * Get the current time. + * Only applicable when option `showCurrentTime` is true. + * @return {Date} Returns the current time. + */ + Core.prototype.getCurrentTime = function() { + if (!this.currentTime) { + throw new Error('Option showCurrentTime must be true'); } - // set options - this.setOptions(data && data.options); - // set all data - if (data && data.dot) { - // parse DOT file - if(data && data.dot) { - var dotData = dotparser.DOTToGraph(data.dot); - this.setData(dotData); - return; - } - } - else if (data && data.gephi) { - // parse DOT file - if(data && data.gephi) { - var gephiData = gephiParser.parseGephi(data.gephi); - this.setData(gephiData); - return; - } - } - else { - this._setNodes(data && data.nodes); - this._setEdges(data && data.edges); - } - this._putDataInSector(); - if (disableStart == false) { - if (this.constants.hierarchicalLayout.enabled == true) { - this._resetLevels(); - this._setupHierarchicalLayout(); - } - else { - // find a stable position or start animating to a stable position - if (this.constants.stabilize) { - this._stabilize(); - } - } - this.start(); - } - this.initializing = false; + return this.currentTime.getCurrentTime(); }; /** - * Set options - * @param {Object} options + * Convert a position on screen (pixels) to a datetime + * @param {int} x Position on the screen in pixels + * @return {Date} time The datetime the corresponds with given position x + * @private */ - Network.prototype.setOptions = function (options) { - if (options) { - var prop; - var fields = ['nodes','edges','smoothCurves','hierarchicalLayout','clustering','navigation', - 'keyboard','dataManipulation','onAdd','onEdit','onEditEdge','onConnect','onDelete','clickToUse' - ]; - // extend all but the values in fields - util.selectiveNotDeepExtend(fields,this.constants, options); - util.selectiveNotDeepExtend(['color'],this.constants.nodes, options.nodes); - util.selectiveNotDeepExtend(['color','length'],this.constants.edges, options.edges); + // TODO: move this function to Range + Core.prototype._toTime = function(x) { + return DateUtil.toTime(this, x, this.props.center.width); + }; - if (options.physics) { - util.mergeOptions(this.constants.physics, options.physics,'barnesHut'); - util.mergeOptions(this.constants.physics, options.physics,'repulsion'); + /** + * Convert a position on the global screen (pixels) to a datetime + * @param {int} x Position on the screen in pixels + * @return {Date} time The datetime the corresponds with given position x + * @private + */ + // TODO: move this function to Range + Core.prototype._toGlobalTime = function(x) { + return DateUtil.toTime(this, x, this.props.root.width); + //var conversion = this.range.conversion(this.props.root.width); + //return new Date(x / conversion.scale + conversion.offset); + }; - if (options.physics.hierarchicalRepulsion) { - this.constants.hierarchicalLayout.enabled = true; - this.constants.physics.hierarchicalRepulsion.enabled = true; - this.constants.physics.barnesHut.enabled = false; - for (prop in options.physics.hierarchicalRepulsion) { - if (options.physics.hierarchicalRepulsion.hasOwnProperty(prop)) { - this.constants.physics.hierarchicalRepulsion[prop] = options.physics.hierarchicalRepulsion[prop]; - } - } - } - } + /** + * Convert a datetime (Date object) into a position on the screen + * @param {Date} time A date + * @return {int} x The position on the screen in pixels which corresponds + * with the given date. + * @private + */ + // TODO: move this function to Range + Core.prototype._toScreen = function(time) { + return DateUtil.toScreen(this, time, this.props.center.width); + }; - if (options.onAdd) {this.triggerFunctions.add = options.onAdd;} - if (options.onEdit) {this.triggerFunctions.edit = options.onEdit;} - if (options.onEditEdge) {this.triggerFunctions.editEdge = options.onEditEdge;} - if (options.onConnect) {this.triggerFunctions.connect = options.onConnect;} - if (options.onDelete) {this.triggerFunctions.del = options.onDelete;} - util.mergeOptions(this.constants, options,'smoothCurves'); - util.mergeOptions(this.constants, options,'hierarchicalLayout'); - util.mergeOptions(this.constants, options,'clustering'); - util.mergeOptions(this.constants, options,'navigation'); - util.mergeOptions(this.constants, options,'keyboard'); - util.mergeOptions(this.constants, options,'dataManipulation'); + /** + * Convert a datetime (Date object) into a position on the root + * This is used to get the pixel density estimate for the screen, not the center panel + * @param {Date} time A date + * @return {int} x The position on root in pixels which corresponds + * with the given date. + * @private + */ + // TODO: move this function to Range + Core.prototype._toGlobalScreen = function(time) { + return DateUtil.toScreen(this, time, this.props.root.width); + //var conversion = this.range.conversion(this.props.root.width); + //return (time.valueOf() - conversion.offset) * conversion.scale; + }; - if (options.dataManipulation) { - this.editMode = this.constants.dataManipulation.initiallyVisible; - } + /** + * Initialize watching when option autoResize is true + * @private + */ + Core.prototype._initAutoResize = function () { + if (this.options.autoResize == true) { + this._startAutoResize(); + } + else { + this._stopAutoResize(); + } + }; - // TODO: work out these options and document them - if (options.edges) { - if (options.edges.color !== undefined) { - if (util.isString(options.edges.color)) { - this.constants.edges.color = {}; - this.constants.edges.color.color = options.edges.color; - this.constants.edges.color.highlight = options.edges.color; - this.constants.edges.color.hover = options.edges.color; - } - else { - if (options.edges.color.color !== undefined) {this.constants.edges.color.color = options.edges.color.color;} - if (options.edges.color.highlight !== undefined) {this.constants.edges.color.highlight = options.edges.color.highlight;} - if (options.edges.color.hover !== undefined) {this.constants.edges.color.hover = options.edges.color.hover;} - } - this.constants.edges.inheritColor = false; - } + /** + * Watch for changes in the size of the container. On resize, the Panel will + * automatically redraw itself. + * @private + */ + Core.prototype._startAutoResize = function () { + var me = this; - if (!options.edges.fontColor) { - if (options.edges.color !== undefined) { - if (util.isString(options.edges.color)) {this.constants.edges.fontColor = options.edges.color;} - else if (options.edges.color.color !== undefined) {this.constants.edges.fontColor = options.edges.color.color;} - } - } - } + this._stopAutoResize(); - if (options.nodes) { - if (options.nodes.color) { - var newColorObj = util.parseColor(options.nodes.color); - this.constants.nodes.color.background = newColorObj.background; - this.constants.nodes.color.border = newColorObj.border; - this.constants.nodes.color.highlight.background = newColorObj.highlight.background; - this.constants.nodes.color.highlight.border = newColorObj.highlight.border; - this.constants.nodes.color.hover.background = newColorObj.hover.background; - this.constants.nodes.color.hover.border = newColorObj.hover.border; - } - } - if (options.groups) { - for (var groupname in options.groups) { - if (options.groups.hasOwnProperty(groupname)) { - var group = options.groups[groupname]; - this.groups.add(groupname, group); - } - } + this._onResize = function() { + if (me.options.autoResize != true) { + // stop watching when the option autoResize is changed to false + me._stopAutoResize(); + return; } - if (options.tooltip) { - for (prop in options.tooltip) { - if (options.tooltip.hasOwnProperty(prop)) { - this.constants.tooltip[prop] = options.tooltip[prop]; - } - } - if (options.tooltip.color) { - this.constants.tooltip.color = util.parseColor(options.tooltip.color); - } - } + if (me.dom.root) { + // check whether the frame is resized + // Note: we compare offsetWidth here, not clientWidth. For some reason, + // IE does not restore the clientWidth from 0 to the actual width after + // changing the timeline's container display style from none to visible + if ((me.dom.root.offsetWidth != me.props.lastWidth) || + (me.dom.root.offsetHeight != me.props.lastHeight)) { + me.props.lastWidth = me.dom.root.offsetWidth; + me.props.lastHeight = me.dom.root.offsetHeight; - if ('clickToUse' in options) { - if (options.clickToUse) { - if (!this.activator) { - this.activator = new Activator(this.frame); - this.activator.on('change', this._createKeyBinds.bind(this)); - } - } - else { - if (this.activator) { - this.activator.destroy(); - delete this.activator; - } + me.emit('change'); } } + }; - 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. - // load the force calculation functions, grouped under the physics system. - this._loadPhysicsSystem(); - // load the navigation system. - this._loadNavigationControls(); - // load the data manipulation system - this._loadManipulationSystem(); - // configure the smooth curves - this._configureSmoothCurves(); - + // add event listener to window resize + util.addEventListener(window, 'resize', this._onResize); - // bind keys. If disabled, this will not do anything; - this._createKeyBinds(); + this.watchTimer = setInterval(this._onResize, 1000); + }; - this.setSize(this.constants.width, this.constants.height); - this.moving = true; - this.start(); + /** + * Stop watching for a resize of the frame. + * @private + */ + Core.prototype._stopAutoResize = function () { + if (this.watchTimer) { + clearInterval(this.watchTimer); + this.watchTimer = undefined; } + + // remove event listener on window.resize + util.removeEventListener(window, 'resize', this._onResize); + this._onResize = null; }; + /** + * Start moving the timeline vertically + * @param {Event} event + * @private + */ + Core.prototype._onTouch = function (event) { + this.touch.allowDragging = true; + }; + /** + * Start moving the timeline vertically + * @param {Event} event + * @private + */ + Core.prototype._onPinch = function (event) { + this.touch.allowDragging = false; + }; /** - * Create the main frame for the Network. - * This function is executed once when a Network object is created. The frame - * contains a canvas, and this canvas contains all objects like the axis and - * nodes. + * Start moving the timeline vertically + * @param {Event} event * @private */ - Network.prototype._create = function () { - // remove all elements from the container element. - while (this.containerElement.hasChildNodes()) { - this.containerElement.removeChild(this.containerElement.firstChild); - } + Core.prototype._onDragStart = function (event) { + this.touch.initialScrollTop = this.props.scrollTop; + }; - this.frame = document.createElement('div'); - this.frame.className = 'vis network-frame'; - this.frame.style.position = 'relative'; - this.frame.style.overflow = 'hidden'; + /** + * Move the timeline vertically + * @param {Event} event + * @private + */ + Core.prototype._onDrag = function (event) { + // refuse to drag when we where pinching to prevent the timeline make a jump + // when releasing the fingers in opposite order from the touch screen + if (!this.touch.allowDragging) return; + var delta = event.gesture.deltaY; - ////////////////////////////////////////////////////////////////// + var oldScrollTop = this._getScrollTop(); + var newScrollTop = this._setScrollTop(this.touch.initialScrollTop + delta); - this.frame.canvas = document.createElement("canvas"); - this.frame.canvas.style.position = 'relative'; - this.frame.appendChild(this.frame.canvas); - if (!this.frame.canvas.getContext) { - var noCanvas = document.createElement( 'DIV' ); - noCanvas.style.color = 'red'; - noCanvas.style.fontWeight = 'bold' ; - noCanvas.style.padding = '10px'; - noCanvas.innerHTML = 'Error: your browser does not support HTML canvas'; - this.frame.canvas.appendChild(noCanvas); + if (newScrollTop != oldScrollTop) { + this.redraw(); // TODO: this causes two redraws when dragging, the other is triggered by rangechange already + this.emit("verticalDrag"); } - else { - var ctx = this.frame.canvas.getContext("2d"); - this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || - ctx.mozBackingStorePixelRatio || - ctx.msBackingStorePixelRatio || - ctx.oBackingStorePixelRatio || - ctx.backingStorePixelRatio || 1); - - this.frame.canvas.getContext("2d").setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); - } - - ////////////////////////////////////////////////////////////////// - - - var me = this; - this.drag = {}; - this.pinch = {}; - this.hammer = Hammer(this.frame.canvas, { - prevent_default: true - }); - this.hammer.on('tap', me._onTap.bind(me) ); - this.hammer.on('doubletap', me._onDoubleTap.bind(me) ); - this.hammer.on('hold', me._onHold.bind(me) ); - this.hammer.on('pinch', me._onPinch.bind(me) ); - this.hammer.on('touch', me._onTouch.bind(me) ); - this.hammer.on('dragstart', me._onDragStart.bind(me) ); - this.hammer.on('drag', me._onDrag.bind(me) ); - this.hammer.on('dragend', me._onDragEnd.bind(me) ); - this.hammer.on('mousewheel',me._onMouseWheel.bind(me) ); - this.hammer.on('DOMMouseScroll',me._onMouseWheel.bind(me) ); // for FF - this.hammer.on('mousemove', me._onMouseMoveTitle.bind(me) ); - - this.hammerFrame = Hammer(this.frame, { - prevent_default: true - }); - this.hammerFrame.on('release', me._onRelease.bind(me) ); - - // add the frame to the container element - this.containerElement.appendChild(this.frame); - }; - /** - * Binding the keys for keyboard navigation. These functions are defined in the NavigationMixin + * Apply a scrollTop + * @param {Number} scrollTop + * @returns {Number} scrollTop Returns the applied scrollTop * @private */ - Network.prototype._createKeyBinds = function() { - var me = this; - if (this.keycharm !== undefined) { - this.keycharm.destroy(); - } - this.keycharm = keycharm(); - - this.keycharm.reset(); - - if (this.constants.keyboard.enabled && this.isActive()) { - this.keycharm.bind("up", this._moveUp.bind(me) , "keydown"); - this.keycharm.bind("up", this._yStopMoving.bind(me), "keyup"); - this.keycharm.bind("down", this._moveDown.bind(me) , "keydown"); - this.keycharm.bind("down", this._yStopMoving.bind(me), "keyup"); - this.keycharm.bind("left", this._moveLeft.bind(me) , "keydown"); - this.keycharm.bind("left", this._xStopMoving.bind(me), "keyup"); - this.keycharm.bind("right",this._moveRight.bind(me), "keydown"); - this.keycharm.bind("right",this._xStopMoving.bind(me), "keyup"); - this.keycharm.bind("=", this._zoomIn.bind(me), "keydown"); - this.keycharm.bind("=", this._stopZoom.bind(me), "keyup"); - this.keycharm.bind("num+", this._zoomIn.bind(me), "keydown"); - this.keycharm.bind("num+", this._stopZoom.bind(me), "keyup"); - this.keycharm.bind("num-", this._zoomOut.bind(me), "keydown"); - this.keycharm.bind("num-", this._stopZoom.bind(me), "keyup"); - this.keycharm.bind("-", this._zoomOut.bind(me), "keydown"); - this.keycharm.bind("-", this._stopZoom.bind(me), "keyup"); - this.keycharm.bind("[", this._zoomIn.bind(me), "keydown"); - this.keycharm.bind("[", this._stopZoom.bind(me), "keyup"); - this.keycharm.bind("]", this._zoomOut.bind(me), "keydown"); - this.keycharm.bind("]", this._stopZoom.bind(me), "keyup"); - this.keycharm.bind("pageup",this._zoomIn.bind(me), "keydown"); - this.keycharm.bind("pageup",this._stopZoom.bind(me), "keyup"); - this.keycharm.bind("pagedown",this._zoomOut.bind(me),"keydown"); - this.keycharm.bind("pagedown",this._stopZoom.bind(me), "keyup"); - } - - if (this.constants.dataManipulation.enabled == true) { - this.keycharm.bind("esc",this._createManipulatorBar.bind(me)); - this.keycharm.bind("delete",this._deleteSelected.bind(me)); - } + Core.prototype._setScrollTop = function (scrollTop) { + this.props.scrollTop = scrollTop; + this._updateScrollTop(); + return this.props.scrollTop; }; /** - * Cleans up all bindings of the network, removing it fully from the memory IF the variable is set to null after calling this function. - * var network = new vis.Network(..); - * network.destroy(); - * network = null; + * Update the current scrollTop when the height of the containers has been changed + * @returns {Number} scrollTop Returns the applied scrollTop + * @private */ - Network.prototype.destroy = function() { - this.start = function () {}; - this.redraw = function () {}; - this.timer = false; - - // cleanup physicsConfiguration if it exists - this._cleanupPhysicsConfiguration(); - - // remove keybindings - this.keycharm.reset(); - - // clear hammer bindings - this.hammer.dispose(); - - // clear events - this.off(); + Core.prototype._updateScrollTop = function () { + // recalculate the scrollTopMin + var scrollTopMin = Math.min(this.props.centerContainer.height - this.props.center.height, 0); // is negative or zero + if (scrollTopMin != this.props.scrollTopMin) { + // in case of bottom orientation, change the scrollTop such that the contents + // do not move relative to the time axis at the bottom + if (this.options.orientation == 'bottom') { + this.props.scrollTop += (scrollTopMin - this.props.scrollTopMin); + } + this.props.scrollTopMin = scrollTopMin; + } - this._recursiveDOMDelete(this.containerElement); - } + // limit the scrollTop to the feasible scroll range + if (this.props.scrollTop > 0) this.props.scrollTop = 0; + if (this.props.scrollTop < scrollTopMin) this.props.scrollTop = scrollTopMin; - Network.prototype._recursiveDOMDelete = function(DOMobject) { - while (DOMobject.hasChildNodes() == true) { - this._recursiveDOMDelete(DOMobject.firstChild); - DOMobject.removeChild(DOMobject.firstChild); - } - } + return this.props.scrollTop; + }; /** - * Get the pointer location from a touch location - * @param {{pageX: Number, pageY: Number}} touch - * @return {{x: Number, y: Number}} pointer + * Get the current scrollTop + * @returns {number} scrollTop * @private */ - Network.prototype._getPointer = function (touch) { - return { - x: touch.pageX - util.getAbsoluteLeft(this.frame.canvas), - y: touch.pageY - util.getAbsoluteTop(this.frame.canvas) - }; + Core.prototype._getScrollTop = function () { + return this.props.scrollTop; }; - /** - * On start of a touch gesture, store the pointer - * @param event - * @private - */ - Network.prototype._onTouch = function (event) { - if (new Date().valueOf() - this.touchTime > 100) { - this.drag.pointer = this._getPointer(event.gesture.center); - this.drag.pinched = false; - this.pinch.scale = this._getScale(); + module.exports = Core; - // to avoid double fireing of this event because we have two hammer instances. (on canvas and on frame) - this.touchTime = new Date().valueOf(); - this._handleTouch(this.drag.pointer); - } - }; +/***/ }, +/* 26 */ +/***/ function(module, exports, __webpack_require__) { + + var Hammer = __webpack_require__(19); + var util = __webpack_require__(1); + var DataSet = __webpack_require__(7); + var DataView = __webpack_require__(9); + var Component = __webpack_require__(23); + var Group = __webpack_require__(27); + var BackgroundGroup = __webpack_require__(31); + var BoxItem = __webpack_require__(32); + var PointItem = __webpack_require__(33); + var RangeItem = __webpack_require__(29); + var BackgroundItem = __webpack_require__(34); - /** - * handle drag start event - * @private - */ - Network.prototype._onDragStart = function (event) { - this._handleDragStart(event); - }; + var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items + var BACKGROUND = '__background__'; // reserved group id for background items without group /** - * This function is called by _onDragStart. - * It is separated out because we can then overload it for the datamanipulation system. - * - * @private + * An ItemSet holds a set of items and ranges which can be displayed in a + * range. The width is determined by the parent of the ItemSet, and the height + * is determined by the size of the items. + * @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} body + * @param {Object} [options] See ItemSet.setOptions for the available options. + * @constructor ItemSet + * @extends Component */ - Network.prototype._handleDragStart = function(event) { - // in case the touch event was triggered on an external div, do the initial touch now. - if (this.drag.pointer === undefined) { - this._onTouch(event); - } - - var node = this._getNodeAt(this.drag.pointer); - // note: drag.pointer is set in _onTouch to get the initial touch location - - this.drag.dragging = true; - this.drag.selection = []; - this.drag.translation = this._getTranslation(); - this.drag.nodeId = null; - this.draggingNodes = false; - - if (node != null && this.constants.dragNodes == true) { - this.draggingNodes = true; - this.drag.nodeId = node.id; - // select the clicked node if not yet selected - if (!node.isSelected()) { - this._selectObject(node,false); - } + function ItemSet(body, options) { + this.body = body; - this.emit("dragStart",{nodeIds:this.getSelection().nodes}); + this.defaultOptions = { + type: null, // 'box', 'point', 'range', 'background' + orientation: 'bottom', // 'top' or 'bottom' + align: 'auto', // alignment of box items + stack: true, + groupOrder: null, - // create an array with the selected nodes and their original location and status - for (var objectId in this.selectionObj.nodes) { - if (this.selectionObj.nodes.hasOwnProperty(objectId)) { - var object = this.selectionObj.nodes[objectId]; - var s = { - id: object.id, - node: object, + selectable: true, + editable: { + updateTime: false, + updateGroup: false, + add: false, + remove: false + }, - // store original x, y, xFixed and yFixed, make the node temporarily Fixed - x: object.x, - y: object.y, - xFixed: object.xFixed, - yFixed: object.yFixed - }; + onAdd: function (item, callback) { + callback(item); + }, + onUpdate: function (item, callback) { + callback(item); + }, + onMove: function (item, callback) { + callback(item); + }, + onRemove: function (item, callback) { + callback(item); + }, + onMoving: function (item, callback) { + callback(item); + }, - object.xFixed = true; - object.yFixed = true; + margin: { + item: { + horizontal: 10, + vertical: 10 + }, + axis: 20 + }, + padding: 5 + }; - this.drag.selection.push(s); - } - } - } - }; + // options is shared by this ItemSet and all its items + this.options = util.extend({}, this.defaultOptions); + // options for getting items from the DataSet with the correct type + this.itemOptions = { + type: {start: 'Date', end: 'Date'} + }; - /** - * handle drag event - * @private - */ - Network.prototype._onDrag = function (event) { - this._handleOnDrag(event) - }; + this.conversion = { + toScreen: body.util.toScreen, + toTime: body.util.toTime + }; + this.dom = {}; + this.props = {}; + this.hammer = null; + var me = this; + this.itemsData = null; // DataSet + this.groupsData = null; // DataSet - /** - * This function is called by _onDrag. - * It is separated out because we can then overload it for the datamanipulation system. - * - * @private - */ - Network.prototype._handleOnDrag = function(event) { - if (this.drag.pinched) { - return; - } + // listeners for the DataSet of the items + this.itemListeners = { + 'add': function (event, params, senderId) { + me._onAdd(params.items); + }, + 'update': function (event, params, senderId) { + me._onUpdate(params.items); + }, + 'remove': function (event, params, senderId) { + me._onRemove(params.items); + } + }; - // remove the focus on node if it is focussed on by the focusOnNode - this.releaseNode(); + // listeners for the DataSet of the groups + this.groupListeners = { + 'add': function (event, params, senderId) { + me._onAddGroups(params.items); + }, + 'update': function (event, params, senderId) { + me._onUpdateGroups(params.items); + }, + 'remove': function (event, params, senderId) { + me._onRemoveGroups(params.items); + } + }; - var pointer = this._getPointer(event.gesture.center); - var me = this; - var drag = this.drag; - var selection = drag.selection; - if (selection && selection.length && this.constants.dragNodes == true) { - // calculate delta's and new location - var deltaX = pointer.x - drag.pointer.x; - var deltaY = pointer.y - drag.pointer.y; + this.items = {}; // object with an Item for every data item + this.groups = {}; // Group object for every group + this.groupIds = []; - // update position of all selected nodes - selection.forEach(function (s) { - var node = s.node; + this.selection = []; // list with the ids of all selected nodes + this.stackDirty = true; // if true, all items will be restacked on next redraw - if (!s.xFixed) { - node.x = me._XconvertDOMtoCanvas(me._XconvertCanvasToDOM(s.x) + deltaX); - } + this.touchParams = {}; // stores properties while dragging + // create the HTML DOM - if (!s.yFixed) { - node.y = me._YconvertDOMtoCanvas(me._YconvertCanvasToDOM(s.y) + deltaY); - } - }); + this._create(); + this.setOptions(options); + } - // start _animationStep if not yet running - if (!this.moving) { - this.moving = true; - this.start(); - } - } - else { - // move the network - if (this.constants.dragNetwork == true) { - // if the drag was not started properly because the click started outside the network div, start it now. - if (this.drag.pointer === undefined) { - this._handleDragStart(event); - return; - } - var diffX = pointer.x - this.drag.pointer.x; - var diffY = pointer.y - this.drag.pointer.y; + ItemSet.prototype = new Component(); - this._setTranslation( - this.drag.translation.x + diffX, - this.drag.translation.y + diffY - ); - this._redraw(); - } - } + // available item types will be registered here + ItemSet.types = { + background: BackgroundItem, + box: BoxItem, + range: RangeItem, + point: PointItem }; /** - * handle drag start event - * @private + * Create the HTML DOM for the ItemSet */ - Network.prototype._onDragEnd = function (event) { - this._handleDragEnd(event); - }; + ItemSet.prototype._create = function(){ + var frame = document.createElement('div'); + frame.className = 'itemset'; + frame['timeline-itemset'] = this; + this.dom.frame = frame; + // create background panel + var background = document.createElement('div'); + background.className = 'background'; + frame.appendChild(background); + this.dom.background = background; - Network.prototype._handleDragEnd = function(event) { - this.drag.dragging = false; - var selection = this.drag.selection; - if (selection && selection.length) { - selection.forEach(function (s) { - // restore original xFixed and yFixed - s.node.xFixed = s.xFixed; - s.node.yFixed = s.yFixed; - }); - this.moving = true; - this.start(); - } - else { - this._redraw(); - } - if (this.draggingNodes == false) { - this.emit("dragEnd",{nodeIds:[]}); - } - else { - this.emit("dragEnd",{nodeIds:this.getSelection().nodes}); - } + // create foreground panel + var foreground = document.createElement('div'); + foreground.className = 'foreground'; + frame.appendChild(foreground); + this.dom.foreground = foreground; - } - /** - * handle tap/click event: select/unselect a node - * @private - */ - Network.prototype._onTap = function (event) { - var pointer = this._getPointer(event.gesture.center); - this.pointerPosition = pointer; - this._handleTap(pointer); + // create axis panel + var axis = document.createElement('div'); + axis.className = 'axis'; + this.dom.axis = axis; - }; + // create labelset + var labelSet = document.createElement('div'); + labelSet.className = 'labelset'; + this.dom.labelSet = labelSet; + // create ungrouped Group + this._updateUngrouped(); - /** - * handle doubletap event - * @private - */ - Network.prototype._onDoubleTap = function (event) { - var pointer = this._getPointer(event.gesture.center); - this._handleDoubleTap(pointer); - }; + // create background Group + var backgroundGroup = new BackgroundGroup(BACKGROUND, null, this); + backgroundGroup.show(); + this.groups[BACKGROUND] = backgroundGroup; + // attach event listeners + // Note: we bind to the centerContainer for the case where the height + // of the center container is larger than of the ItemSet, so we + // can click in the empty area to create a new item or deselect an item. + this.hammer = Hammer(this.body.dom.centerContainer, { + preventDefault: true + }); - /** - * handle long tap event: multi select nodes - * @private - */ - Network.prototype._onHold = function (event) { - var pointer = this._getPointer(event.gesture.center); - this.pointerPosition = pointer; - this._handleOnHold(pointer); - }; + // drag items when selected + this.hammer.on('touch', this._onTouch.bind(this)); + this.hammer.on('dragstart', this._onDragStart.bind(this)); + this.hammer.on('drag', this._onDrag.bind(this)); + this.hammer.on('dragend', this._onDragEnd.bind(this)); - /** - * handle the release of the screen - * - * @private - */ - Network.prototype._onRelease = function (event) { - var pointer = this._getPointer(event.gesture.center); - this._handleOnRelease(pointer); - }; + // single select (or unselect) when tapping an item + this.hammer.on('tap', this._onSelectItem.bind(this)); - /** - * Handle pinch event - * @param event - * @private - */ - Network.prototype._onPinch = function (event) { - var pointer = this._getPointer(event.gesture.center); + // multi select when holding mouse/touch, or on ctrl+click + this.hammer.on('hold', this._onMultiSelectItem.bind(this)); - this.drag.pinched = true; - if (!('scale' in this.pinch)) { - this.pinch.scale = 1; - } + // add item on doubletap + this.hammer.on('doubletap', this._onAddItem.bind(this)); - // TODO: enabled moving while pinching? - var scale = this.pinch.scale * event.gesture.scale; - this._zoom(scale, pointer) + // attach to the DOM + this.show(); }; /** - * Zoom the network in or out - * @param {Number} scale a number around 1, and between 0.01 and 10 - * @param {{x: Number, y: Number}} pointer Position on screen - * @return {Number} appliedScale scale is limited within the boundaries - * @private + * Set options for the ItemSet. Existing options will be extended/overwritten. + * @param {Object} [options] The following options are available: + * {String} type + * Default type for the items. Choose from 'box' + * (default), 'point', 'range', or 'background'. + * The default style can be overwritten by + * individual items. + * {String} align + * Alignment for the items, only applicable for + * BoxItem. Choose 'center' (default), 'left', or + * 'right'. + * {String} orientation + * Orientation of the item set. Choose 'top' or + * 'bottom' (default). + * {Function} groupOrder + * A sorting function for ordering groups + * {Boolean} stack + * If true (deafult), items will be stacked on + * top of each other. + * {Number} margin.axis + * Margin between the axis and the items in pixels. + * Default is 20. + * {Number} margin.item.horizontal + * Horizontal margin between items in pixels. + * Default is 10. + * {Number} margin.item.vertical + * Vertical Margin between items in pixels. + * Default is 10. + * {Number} margin.item + * Margin between items in pixels in both horizontal + * and vertical direction. Default is 10. + * {Number} margin + * Set margin for both axis and items in pixels. + * {Number} padding + * Padding of the contents of an item in pixels. + * Must correspond with the items css. Default is 5. + * {Boolean} selectable + * If true (default), items can be selected. + * {Boolean} editable + * Set all editable options to true or false + * {Boolean} editable.updateTime + * Allow dragging an item to an other moment in time + * {Boolean} editable.updateGroup + * Allow dragging an item to an other group + * {Boolean} editable.add + * Allow creating new items on double tap + * {Boolean} editable.remove + * Allow removing items by clicking the delete button + * top right of a selected item. + * {Function(item: Item, callback: Function)} onAdd + * Callback function triggered when an item is about to be added: + * when the user double taps an empty space in the Timeline. + * {Function(item: Item, callback: Function)} onUpdate + * Callback function fired when an item is about to be updated. + * This function typically has to show a dialog where the user + * change the item. If not implemented, nothing happens. + * {Function(item: Item, callback: Function)} onMove + * Fired when an item has been moved. If not implemented, + * the move action will be accepted. + * {Function(item: Item, callback: Function)} onRemove + * Fired when an item is about to be deleted. + * If not implemented, the item will be always removed. */ - Network.prototype._zoom = function(scale, pointer) { - if (this.constants.zoomable == true) { - var scaleOld = this._getScale(); - if (scale < 0.00001) { - scale = 0.00001; - } - if (scale > 10) { - scale = 10; - } + ItemSet.prototype.setOptions = function(options) { + if (options) { + // copy all options that we know + var fields = ['type', 'align', 'orientation', 'padding', 'stack', 'selectable', 'groupOrder', 'dataAttributes', 'template','hide']; + util.selectiveExtend(fields, this.options, options); - var preScaleDragPointer = null; - if (this.drag !== undefined) { - if (this.drag.dragging == true) { - preScaleDragPointer = this.DOMtoCanvas(this.drag.pointer); + if ('margin' in options) { + if (typeof options.margin === 'number') { + this.options.margin.axis = options.margin; + this.options.margin.item.horizontal = options.margin; + this.options.margin.item.vertical = options.margin; + } + else if (typeof options.margin === 'object') { + util.selectiveExtend(['axis'], this.options.margin, options.margin); + if ('item' in options.margin) { + if (typeof options.margin.item === 'number') { + this.options.margin.item.horizontal = options.margin.item; + this.options.margin.item.vertical = options.margin.item; + } + else if (typeof options.margin.item === 'object') { + util.selectiveExtend(['horizontal', 'vertical'], this.options.margin.item, options.margin.item); + } + } } } - // + this.frame.canvas.clientHeight / 2 - var translation = this._getTranslation(); - - var scaleFrac = scale / scaleOld; - var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac; - var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac; - - this.areaCenter = {"x" : this._XconvertDOMtoCanvas(pointer.x), - "y" : this._YconvertDOMtoCanvas(pointer.y)}; - - this._setScale(scale); - this._setTranslation(tx, ty); - this.updateClustersDefault(); - if (preScaleDragPointer != null) { - var postScaleDragPointer = this.canvasToDOM(preScaleDragPointer); - this.drag.pointer.x = postScaleDragPointer.x; - this.drag.pointer.y = postScaleDragPointer.y; + if ('editable' in options) { + if (typeof options.editable === 'boolean') { + this.options.editable.updateTime = options.editable; + this.options.editable.updateGroup = options.editable; + this.options.editable.add = options.editable; + this.options.editable.remove = options.editable; + } + else if (typeof options.editable === 'object') { + util.selectiveExtend(['updateTime', 'updateGroup', 'add', 'remove'], this.options.editable, options.editable); + } } - this._redraw(); - - if (scaleOld < scale) { - this.emit("zoom", {direction:"+"}); - } - else { - this.emit("zoom", {direction:"-"}); - } + // callback functions + var addCallback = (function (name) { + var fn = options[name]; + if (fn) { + if (!(fn instanceof Function)) { + throw new Error('option ' + name + ' must be a function ' + name + '(item, callback)'); + } + this.options[name] = fn; + } + }).bind(this); + ['onAdd', 'onUpdate', 'onRemove', 'onMove', 'onMoving'].forEach(addCallback); - return scale; + // force the itemSet to refresh: options like orientation and margins may be changed + this.markDirty(); } }; + /** + * Mark the ItemSet dirty so it will refresh everything with next redraw + */ + ItemSet.prototype.markDirty = function() { + this.groupIds = []; + this.stackDirty = true; + }; /** - * Event handler for mouse wheel event, used to zoom the timeline - * See http://adomas.org/javascript-mouse-wheel/ - * https://github.com/EightMedia/hammer.js/issues/256 - * @param {MouseEvent} event - * @private + * Destroy the ItemSet */ - Network.prototype._onMouseWheel = function(event) { - // retrieve delta - var delta = 0; - if (event.wheelDelta) { /* IE/Opera. */ - delta = event.wheelDelta/120; - } else if (event.detail) { /* Mozilla case. */ - // In Mozilla, sign of delta is different than in IE. - // Also, delta is multiple of 3. - delta = -event.detail/3; - } + ItemSet.prototype.destroy = function() { + this.hide(); + this.setItems(null); + this.setGroups(null); - // If delta is nonzero, handle it. - // Basically, delta is now positive if wheel was scrolled up, - // and negative, if wheel was scrolled down. - if (delta) { + this.hammer = null; - // calculate the new scale - var scale = this._getScale(); - var zoom = delta / 10; - if (delta < 0) { - zoom = zoom / (1 - zoom); - } - scale *= (1 + zoom); + this.body = null; + this.conversion = null; + }; - // calculate the pointer location - var gesture = hammerUtil.fakeGesture(this, event); - var pointer = this._getPointer(gesture.center); + /** + * Hide the component from the DOM + */ + ItemSet.prototype.hide = function() { + // remove the frame containing the items + if (this.dom.frame.parentNode) { + this.dom.frame.parentNode.removeChild(this.dom.frame); + } - // apply the new scale - this._zoom(scale, pointer); + // remove the axis with dots + if (this.dom.axis.parentNode) { + this.dom.axis.parentNode.removeChild(this.dom.axis); } - // Prevent default actions caused by mouse wheel. - event.preventDefault(); + // remove the labelset containing all group labels + if (this.dom.labelSet.parentNode) { + this.dom.labelSet.parentNode.removeChild(this.dom.labelSet); + } }; - /** - * Mouse move handler for checking whether the title moves over a node with a title. - * @param {Event} event - * @private + * Show the component in the DOM (when not already visible). + * @return {Boolean} changed */ - Network.prototype._onMouseMoveTitle = function (event) { - var gesture = hammerUtil.fakeGesture(this, event); - var pointer = this._getPointer(gesture.center); - - // check if the previously selected node is still selected - if (this.popupObj) { - this._checkHidePopup(pointer); + ItemSet.prototype.show = function() { + // show frame containing the items + if (!this.dom.frame.parentNode) { + this.body.dom.center.appendChild(this.dom.frame); } - // start a timeout that will check if the mouse is positioned above - // an element - var me = this; - var checkShow = function() { - me._checkShowPopup(pointer); - }; - if (this.popupTimer) { - clearInterval(this.popupTimer); // stop any running calculationTimer + // show axis with dots + if (!this.dom.axis.parentNode) { + this.body.dom.backgroundVertical.appendChild(this.dom.axis); } - if (!this.drag.dragging) { - this.popupTimer = setTimeout(checkShow, this.constants.tooltip.delay); + + // show labelset containing labels + if (!this.dom.labelSet.parentNode) { + this.body.dom.left.appendChild(this.dom.labelSet); } + }; + /** + * Set selected items by their id. Replaces the current selection + * Unknown id's are silently ignored. + * @param {string[] | string} [ids] An array with zero or more id's of the items to be + * selected, or a single item id. If ids is undefined + * or an empty array, all items will be unselected. + */ + ItemSet.prototype.setSelection = function(ids) { + var i, ii, id, item; - /** - * Adding hover highlights - */ - if (this.constants.hover == true) { - // removing all hover highlights - for (var edgeId in this.hoverObj.edges) { - if (this.hoverObj.edges.hasOwnProperty(edgeId)) { - this.hoverObj.edges[edgeId].hover = false; - delete this.hoverObj.edges[edgeId]; - } - } + if (ids == undefined) ids = []; + if (!Array.isArray(ids)) ids = [ids]; - // adding hover highlights - var obj = this._getNodeAt(pointer); - if (obj == null) { - obj = this._getEdgeAt(pointer); - } - if (obj != null) { - this._hoverObject(obj); - } + // unselect currently selected items + for (i = 0, ii = this.selection.length; i < ii; i++) { + id = this.selection[i]; + item = this.items[id]; + if (item) item.unselect(); + } - // removing all node hover highlights except for the selected one. - for (var nodeId in this.hoverObj.nodes) { - if (this.hoverObj.nodes.hasOwnProperty(nodeId)) { - if (obj instanceof Node && obj.id != nodeId || obj instanceof Edge || obj == null) { - this._blurObject(this.hoverObj.nodes[nodeId]); - delete this.hoverObj.nodes[nodeId]; - } - } + // select items + this.selection = []; + for (i = 0, ii = ids.length; i < ii; i++) { + id = ids[i]; + item = this.items[id]; + if (item) { + this.selection.push(id); + item.select(); } - this.redraw(); } }; /** - * Check if there is an element on the given position in the network - * (a node or edge). If so, and if this element has a title, - * show a popup window with its title. - * - * @param {{x:Number, y:Number}} pointer - * @private + * Get the selected items by their id + * @return {Array} ids The ids of the selected items */ - Network.prototype._checkShowPopup = function (pointer) { - var obj = { - left: this._XconvertDOMtoCanvas(pointer.x), - top: this._YconvertDOMtoCanvas(pointer.y), - right: this._XconvertDOMtoCanvas(pointer.x), - bottom: this._YconvertDOMtoCanvas(pointer.y) - }; - - var id; - var lastPopupNode = this.popupObj; - var nodeUnderCursor = false; + ItemSet.prototype.getSelection = function() { + return this.selection.concat([]); + }; - if (this.popupObj == undefined) { - // search the nodes for overlap, select the top one in case of multiple nodes - var nodes = this.nodes; - var overlappingNodes = []; - for (id in nodes) { - if (nodes.hasOwnProperty(id)) { - var node = nodes[id]; - if (node.isOverlappingWith(obj)) { - if (node.getTitle() !== undefined) { - overlappingNodes.push(id); - } - } - } - } + /** + * Get the id's of the currently visible items. + * @returns {Array} The ids of the visible items + */ + ItemSet.prototype.getVisibleItems = function() { + var range = this.body.range.getRange(); + var left = this.body.util.toScreen(range.start); + var right = this.body.util.toScreen(range.end); - if (overlappingNodes.length > 0) { - // if there are overlapping nodes, select the last one, this is the - // one which is drawn on top of the others - this.popupObj = this.nodes[overlappingNodes[overlappingNodes.length - 1]]; - // if you hover over a node, the title of the edge is not supposed to be shown. - nodeUnderCursor = true; - } - } + var ids = []; + for (var groupId in this.groups) { + if (this.groups.hasOwnProperty(groupId)) { + var group = this.groups[groupId]; + var rawVisibleItems = group.visibleItems; - if (this.popupObj === undefined && nodeUnderCursor == false) { - // search the edges for overlap - var edges = this.edges; - var overlappingEdges = []; - for (id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - if (edge.connected && (edge.getTitle() !== undefined) && - edge.isOverlappingWith(obj)) { - overlappingEdges.push(id); + // filter the "raw" set with visibleItems into a set which is really + // visible by pixels + for (var i = 0; i < rawVisibleItems.length; i++) { + var item = rawVisibleItems[i]; + // TODO: also check whether visible vertically + if ((item.left < right) && (item.left + item.width > left)) { + ids.push(item.id); } } } - - if (overlappingEdges.length > 0) { - this.popupObj = this.edges[overlappingEdges[overlappingEdges.length - 1]]; - } } - if (this.popupObj) { - // show popup message window - if (this.popupObj != lastPopupNode) { - var me = this; - if (!me.popup) { - me.popup = new Popup(me.frame, me.constants.tooltip); - } - - // adjust a small offset such that the mouse cursor is located in the - // bottom left location of the popup, and you can easily move over the - // popup area - me.popup.setPosition(pointer.x - 3, pointer.y - 3); - me.popup.setText(me.popupObj.getTitle()); - me.popup.show(); - } - } - else { - if (this.popup) { - this.popup.hide(); - } - } + return ids; }; - /** - * Check if the popup must be hided, which is the case when the mouse is no - * longer hovering on the object - * @param {{x:Number, y:Number}} pointer + * Deselect a selected item + * @param {String | Number} id * @private */ - Network.prototype._checkHidePopup = function (pointer) { - if (!this.popupObj || !this._getNodeAt(pointer) ) { - this.popupObj = undefined; - if (this.popup) { - this.popup.hide(); + ItemSet.prototype._deselect = function(id) { + var selection = this.selection; + for (var i = 0, ii = selection.length; i < ii; i++) { + if (selection[i] == id) { // non-strict comparison! + selection.splice(i, 1); + break; } } }; - /** - * Set a new size for the network - * @param {string} width Width in pixels or percentage (for example '800px' - * or '50%') - * @param {string} height Height in pixels or percentage (for example '400px' - * or '30%') + * Repaint the component + * @return {boolean} Returns true if the component is resized */ - Network.prototype.setSize = function(width, height) { - var emitEvent = false; - var oldWidth = this.frame.canvas.width; - var oldHeight = this.frame.canvas.height; - if (width != this.constants.width || height != this.constants.height || this.frame.style.width != width || this.frame.style.height != height) { - this.frame.style.width = width; - this.frame.style.height = height; + ItemSet.prototype.redraw = function() { + var margin = this.options.margin, + range = this.body.range, + asSize = util.option.asSize, + options = this.options, + orientation = options.orientation, + resized = false, + frame = this.dom.frame, + editable = options.editable.updateTime || options.editable.updateGroup; - this.frame.canvas.style.width = '100%'; - this.frame.canvas.style.height = '100%'; + // recalculate absolute position (before redrawing groups) + this.props.top = this.body.domProps.top.height + this.body.domProps.border.top; + this.props.left = this.body.domProps.left.width + this.body.domProps.border.left; - this.frame.canvas.width = this.frame.canvas.clientWidth * this.pixelRatio; - this.frame.canvas.height = this.frame.canvas.clientHeight * this.pixelRatio; + // update class name + frame.className = 'itemset' + (editable ? ' editable' : ''); - this.constants.width = width; - this.constants.height = height; + // reorder the groups (if needed) + resized = this._orderGroups() || resized; - emitEvent = true; - } - else { - // this would adapt the width of the canvas to the width from 100% if and only if - // there is a change. + // check whether zoomed (in that case we need to re-stack everything) + // TODO: would be nicer to get this as a trigger from Range + var visibleInterval = range.end - range.start; + var zoomed = (visibleInterval != this.lastVisibleInterval) || (this.props.width != this.props.lastWidth); + if (zoomed) this.stackDirty = true; + this.lastVisibleInterval = visibleInterval; + this.props.lastWidth = this.props.width; - if (this.frame.canvas.width != this.frame.canvas.clientWidth * this.pixelRatio) { - this.frame.canvas.width = this.frame.canvas.clientWidth * this.pixelRatio; - emitEvent = true; - } - if (this.frame.canvas.height != this.frame.canvas.clientHeight * this.pixelRatio) { - this.frame.canvas.height = this.frame.canvas.clientHeight * this.pixelRatio; - emitEvent = true; - } - } + var restack = this.stackDirty; + var firstGroup = this._firstGroup(); + var firstMargin = { + item: margin.item, + axis: margin.axis + }; + var nonFirstMargin = { + item: margin.item, + axis: margin.item.vertical / 2 + }; + var height = 0; + var minHeight = margin.axis + margin.item.vertical; - if (emitEvent == true) { - this.emit('resize', {width:this.frame.canvas.width * this.pixelRatio,height:this.frame.canvas.height * this.pixelRatio, oldWidth: oldWidth * this.pixelRatio, oldHeight: oldHeight * this.pixelRatio}); - } - }; + // redraw the background group + this.groups[BACKGROUND].redraw(range, nonFirstMargin, restack); - /** - * Set a data set with nodes for the network - * @param {Array | DataSet | DataView} nodes The data containing the nodes. - * @private - */ - Network.prototype._setNodes = function(nodes) { - var oldNodesData = this.nodesData; + // redraw all regular groups + util.forEach(this.groups, function (group) { + var groupMargin = (group == firstGroup) ? firstMargin : nonFirstMargin; + var groupResized = group.redraw(range, groupMargin, restack); + resized = groupResized || resized; + height += group.height; + }); + height = Math.max(height, minHeight); + this.stackDirty = false; - if (nodes instanceof DataSet || nodes instanceof DataView) { - this.nodesData = nodes; - } - else if (Array.isArray(nodes)) { - this.nodesData = new DataSet(); - this.nodesData.add(nodes); - } - else if (!nodes) { - this.nodesData = new DataSet(); - } - else { - throw new TypeError('Array or DataSet expected'); - } + // update frame height + frame.style.height = asSize(height); - if (oldNodesData) { - // unsubscribe from old dataset - util.forEach(this.nodesListeners, function (callback, event) { - oldNodesData.off(event, callback); - }); - } + // calculate actual size + this.props.width = frame.offsetWidth; + this.props.height = height; - // remove drawn nodes - this.nodes = {}; + // reposition axis + this.dom.axis.style.top = asSize((orientation == 'top') ? + (this.body.domProps.top.height + this.body.domProps.border.top) : + (this.body.domProps.top.height + this.body.domProps.centerContainer.height)); + this.dom.axis.style.left = '0'; - if (this.nodesData) { - // subscribe to new dataset - var me = this; - util.forEach(this.nodesListeners, function (callback, event) { - me.nodesData.on(event, callback); - }); + // check if this component is resized + resized = this._isResized() || resized; - // draw all new nodes - var ids = this.nodesData.getIds(); - this._addNodes(ids); - } - this._updateSelection(); + return resized; }; /** - * Add nodes - * @param {Number[] | String[]} ids + * Get the first group, aligned with the axis + * @return {Group | null} firstGroup * @private */ - Network.prototype._addNodes = function(ids) { - var id; - for (var i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - var data = this.nodesData.get(id); - var node = new Node(data, this.images, this.groups, this.constants); - this.nodes[id] = node; // note: this may replace an existing node - if ((node.xFixed == false || node.yFixed == false) && (node.x === null || node.y === null)) { - var radius = 10 * 0.1*ids.length + 10; - var angle = 2 * Math.PI * Math.random(); - if (node.xFixed == false) {node.x = radius * Math.cos(angle);} - if (node.yFixed == false) {node.y = radius * Math.sin(angle);} - } - this.moving = true; - } + ItemSet.prototype._firstGroup = function() { + var firstGroupIndex = (this.options.orientation == 'top') ? 0 : (this.groupIds.length - 1); + var firstGroupId = this.groupIds[firstGroupIndex]; + var firstGroup = this.groups[firstGroupId] || this.groups[UNGROUPED]; - this._updateNodeIndexList(); - if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { - this._resetLevels(); - this._setupHierarchicalLayout(); - } - this._updateCalculationNodes(); - this._reconnectEdges(); - this._updateValueRange(this.nodes); - this.updateLabels(); + return firstGroup || null; }; /** - * Update existing nodes, or create them when not yet existing - * @param {Number[] | String[]} ids - * @private + * Create or delete the group holding all ungrouped items. This group is used when + * there are no groups specified. + * @protected */ - Network.prototype._updateNodes = function(ids,changedData) { - var nodes = this.nodes; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - var node = nodes[id]; - var data = changedData[i]; - if (node) { - // update node - node.setProperties(data, this.constants); - } - else { - // create node - node = new Node(properties, this.images, this.groups, this.constants); - nodes[id] = node; + ItemSet.prototype._updateUngrouped = function() { + var ungrouped = this.groups[UNGROUPED]; + var background = this.groups[BACKGROUND]; + var item, itemId; + + if (this.groupsData) { + // remove the group holding all ungrouped items + if (ungrouped) { + ungrouped.hide(); + delete this.groups[UNGROUPED]; + + for (itemId in this.items) { + if (this.items.hasOwnProperty(itemId)) { + item = this.items[itemId]; + item.parent && item.parent.remove(item); + var groupId = this._getGroupId(item.data); + var group = this.groups[groupId]; + group && group.add(item) || item.hide(); + } + } } } - this.moving = true; - if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { - this._resetLevels(); - this._setupHierarchicalLayout(); + else { + // create a group holding all (unfiltered) items + if (!ungrouped) { + var id = null; + var data = null; + ungrouped = new Group(id, data, this); + this.groups[UNGROUPED] = ungrouped; + + for (itemId in this.items) { + if (this.items.hasOwnProperty(itemId)) { + item = this.items[itemId]; + ungrouped.add(item); + } + } + + ungrouped.show(); + } } - this._updateNodeIndexList(); - this._updateValueRange(nodes); }; /** - * Remove existing nodes. If nodes do not exist, the method will just ignore it. - * @param {Number[] | String[]} ids - * @private + * Get the element for the labelset + * @return {HTMLElement} labelSet */ - Network.prototype._removeNodes = function(ids) { - var nodes = this.nodes; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - delete nodes[id]; - } - this._updateNodeIndexList(); - if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { - this._resetLevels(); - this._setupHierarchicalLayout(); - } - this._updateCalculationNodes(); - this._reconnectEdges(); - this._updateSelection(); - this._updateValueRange(nodes); + ItemSet.prototype.getLabelSet = function() { + return this.dom.labelSet; }; /** - * Load edges by reading the data table - * @param {Array | DataSet | DataView} edges The data containing the edges. - * @private - * @private + * Set items + * @param {vis.DataSet | null} items */ - Network.prototype._setEdges = function(edges) { - var oldEdgesData = this.edgesData; + ItemSet.prototype.setItems = function(items) { + var me = this, + ids, + oldItemsData = this.itemsData; - if (edges instanceof DataSet || edges instanceof DataView) { - this.edgesData = edges; - } - else if (Array.isArray(edges)) { - this.edgesData = new DataSet(); - this.edgesData.add(edges); + // replace the dataset + if (!items) { + this.itemsData = null; } - else if (!edges) { - this.edgesData = new DataSet(); + else if (items instanceof DataSet || items instanceof DataView) { + this.itemsData = items; } else { - throw new TypeError('Array or DataSet expected'); + throw new TypeError('Data must be an instance of DataSet or DataView'); } - if (oldEdgesData) { + if (oldItemsData) { // unsubscribe from old dataset - util.forEach(this.edgesListeners, function (callback, event) { - oldEdgesData.off(event, callback); + util.forEach(this.itemListeners, function (callback, event) { + oldItemsData.off(event, callback); }); - } - // remove drawn edges - this.edges = {}; + // remove all drawn items + ids = oldItemsData.getIds(); + this._onRemove(ids); + } - if (this.edgesData) { + if (this.itemsData) { // subscribe to new dataset - var me = this; - util.forEach(this.edgesListeners, function (callback, event) { - me.edgesData.on(event, callback); + var id = this.id; + util.forEach(this.itemListeners, function (callback, event) { + me.itemsData.on(event, callback, id); }); - // draw all new nodes - var ids = this.edgesData.getIds(); - this._addEdges(ids); + // add all new items + ids = this.itemsData.getIds(); + this._onAdd(ids); + + // update the group holding all ungrouped items + this._updateUngrouped(); } + }; - this._reconnectEdges(); + /** + * Get the current items + * @returns {vis.DataSet | null} + */ + ItemSet.prototype.getItems = function() { + return this.itemsData; }; /** - * Add edges - * @param {Number[] | String[]} ids - * @private + * Set groups + * @param {vis.DataSet} groups */ - Network.prototype._addEdges = function (ids) { - var edges = this.edges, - edgesData = this.edgesData; + ItemSet.prototype.setGroups = function(groups) { + var me = this, + ids; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; + // unsubscribe from current dataset + if (this.groupsData) { + util.forEach(this.groupListeners, function (callback, event) { + me.groupsData.unsubscribe(event, callback); + }); - var oldEdge = edges[id]; - if (oldEdge) { - oldEdge.disconnect(); - } + // remove all drawn groups + ids = this.groupsData.getIds(); + this.groupsData = null; + this._onRemoveGroups(ids); // note: this will cause a redraw + } - var data = edgesData.get(id, {"showInternalIds" : true}); - edges[id] = new Edge(data, this, this.constants); + // replace the dataset + if (!groups) { + this.groupsData = null; } - this.moving = true; - this._updateValueRange(edges); - this._createBezierNodes(); - this._updateCalculationNodes(); - if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { - this._resetLevels(); - this._setupHierarchicalLayout(); + else if (groups instanceof DataSet || groups instanceof DataView) { + this.groupsData = groups; + } + else { + throw new TypeError('Data must be an instance of DataSet or DataView'); } + + if (this.groupsData) { + // subscribe to new dataset + var id = this.id; + util.forEach(this.groupListeners, function (callback, event) { + me.groupsData.on(event, callback, id); + }); + + // draw all ms + ids = this.groupsData.getIds(); + this._onAddGroups(ids); + } + + // update the group holding all ungrouped items + this._updateUngrouped(); + + // update the order of all items in each group + this._order(); + + this.body.emitter.emit('change', {queue: true}); }; /** - * Update existing edges, or create them when not yet existing - * @param {Number[] | String[]} ids - * @private + * Get the current groups + * @returns {vis.DataSet | null} groups */ - Network.prototype._updateEdges = function (ids) { - var edges = this.edges, - edgesData = this.edgesData; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; + ItemSet.prototype.getGroups = function() { + return this.groupsData; + }; - var data = edgesData.get(id); - var edge = edges[id]; - if (edge) { - // update edge - edge.disconnect(); - edge.setProperties(data, this.constants); - edge.connect(); - } - else { - // create edge - edge = new Edge(data, this, this.constants); - this.edges[id] = edge; - } - } + /** + * Remove an item by its id + * @param {String | Number} id + */ + ItemSet.prototype.removeItem = function(id) { + var item = this.itemsData.get(id), + dataset = this.itemsData.getDataSet(); - this._createBezierNodes(); - if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { - this._resetLevels(); - this._setupHierarchicalLayout(); + if (item) { + // confirm deletion + this.options.onRemove(item, function (item) { + if (item) { + // remove by id here, it is possible that an item has no id defined + // itself, so better not delete by the item itself + dataset.remove(id); + } + }); } - this.moving = true; - this._updateValueRange(edges); }; /** - * Remove existing edges. Non existing ids will be ignored - * @param {Number[] | String[]} ids + * Get the time of an item based on it's data and options.type + * @param {Object} itemData + * @returns {string} Returns the type * @private */ - Network.prototype._removeEdges = function (ids) { - var edges = this.edges; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - var edge = edges[id]; - if (edge) { - if (edge.via != null) { - delete this.sectors['support']['nodes'][edge.via.id]; - } - edge.disconnect(); - delete edges[id]; - } - } - - this.moving = true; - this._updateValueRange(edges); - if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { - this._resetLevels(); - this._setupHierarchicalLayout(); - } - this._updateCalculationNodes(); + ItemSet.prototype._getType = function (itemData) { + return itemData.type || this.options.type || (itemData.end ? 'range' : 'box'); }; + /** - * Reconnect all edges + * Get the group id for an item + * @param {Object} itemData + * @returns {string} Returns the groupId * @private */ - Network.prototype._reconnectEdges = function() { - var id, - nodes = this.nodes, - edges = this.edges; - for (id in nodes) { - if (nodes.hasOwnProperty(id)) { - nodes[id].edges = []; - nodes[id].dynamicEdges = []; - } + ItemSet.prototype._getGroupId = function (itemData) { + var type = this._getType(itemData); + if (type == 'background' && itemData.group == undefined) { + return BACKGROUND; } - - for (id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - edge.from = null; - edge.to = null; - edge.connect(); - } + else { + return this.groupsData ? itemData.group : UNGROUPED; } }; /** - * Update the values of all object in the given array according to the current - * value range of the objects in the array. - * @param {Object} obj An object containing a set of Edges or Nodes - * The objects must have a method getValue() and - * setValueRange(min, max). - * @private + * Handle updated items + * @param {Number[]} ids + * @protected */ - Network.prototype._updateValueRange = function(obj) { - var id; + ItemSet.prototype._onUpdate = function(ids) { + var me = this; - // determine the range of the objects - var valueMin = undefined; - var valueMax = undefined; - for (id in obj) { - if (obj.hasOwnProperty(id)) { - var value = obj[id].getValue(); - if (value !== undefined) { - valueMin = (valueMin === undefined) ? value : Math.min(value, valueMin); - valueMax = (valueMax === undefined) ? value : Math.max(value, valueMax); + ids.forEach(function (id) { + var itemData = me.itemsData.get(id, me.itemOptions); + var item = me.items[id]; + var type = me._getType(itemData); + + var constructor = ItemSet.types[type]; + + if (item) { + // update item + if (!constructor || !(item instanceof constructor)) { + // item type has changed, delete the item and recreate it + me._removeItem(item); + item = null; + } + else { + me._updateItem(item, itemData); } } - } - // adjust the range of all objects - if (valueMin !== undefined && valueMax !== undefined) { - for (id in obj) { - if (obj.hasOwnProperty(id)) { - obj[id].setValueRange(valueMin, valueMax); + if (!item) { + // create item + if (constructor) { + item = new constructor(itemData, me.conversion, me.options); + item.id = id; // TODO: not so nice setting id afterwards + me._addItem(item); + } + else if (type == 'rangeoverflow') { + // TODO: deprecated since version 2.1.0 (or 3.0.0?). cleanup some day + throw new TypeError('Item type "rangeoverflow" is deprecated. Use css styling instead: ' + + '.vis.timeline .item.range .content {overflow: visible;}'); } + else { + throw new TypeError('Unknown item type "' + type + '"'); + } + } + }); + + this._order(); + this.stackDirty = true; // force re-stacking of all items next redraw + this.body.emitter.emit('change', {queue: true}); + }; + + /** + * Handle added items + * @param {Number[]} ids + * @protected + */ + ItemSet.prototype._onAdd = ItemSet.prototype._onUpdate; + + /** + * Handle removed items + * @param {Number[]} ids + * @protected + */ + ItemSet.prototype._onRemove = function(ids) { + var count = 0; + var me = this; + ids.forEach(function (id) { + var item = me.items[id]; + if (item) { + count++; + me._removeItem(item); } + }); + + if (count) { + // update order + this._order(); + this.stackDirty = true; // force re-stacking of all items next redraw + this.body.emitter.emit('change', {queue: true}); } }; /** - * Redraw the network with the current data - * chart will be resized too. + * Update the order of item in all groups + * @private */ - Network.prototype.redraw = function() { - this.setSize(this.constants.width, this.constants.height); - this._redraw(); + ItemSet.prototype._order = function() { + // reorder the items in all groups + // TODO: optimization: only reorder groups affected by the changed items + util.forEach(this.groups, function (group) { + group.order(); + }); }; /** - * Redraw the network with the current data - * @param hidden | used to get the first estimate of the node sizes. only the nodes are drawn after which they are quickly drawn over. + * Handle updated groups + * @param {Number[]} ids * @private */ - Network.prototype._redraw = function(hidden) { - var ctx = this.frame.canvas.getContext('2d'); + ItemSet.prototype._onUpdateGroups = function(ids) { + this._onAddGroups(ids); + }; - ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); + /** + * Handle changed groups (added or updated) + * @param {Number[]} ids + * @private + */ + ItemSet.prototype._onAddGroups = function(ids) { + var me = this; - // clear the canvas - var w = this.frame.canvas.width * this.pixelRatio; - var h = this.frame.canvas.height * this.pixelRatio; - ctx.clearRect(0, 0, w, h); + ids.forEach(function (id) { + var groupData = me.groupsData.get(id); + var group = me.groups[id]; - // set scaling and translation - ctx.save(); - ctx.translate(this.translation.x, this.translation.y); - ctx.scale(this.scale, this.scale); + if (!group) { + // check for reserved ids + if (id == UNGROUPED || id == BACKGROUND) { + throw new Error('Illegal group id. ' + id + ' is a reserved id.'); + } - this.canvasTopLeft = { - "x": this._XconvertDOMtoCanvas(0), - "y": this._YconvertDOMtoCanvas(0) - }; - this.canvasBottomRight = { - "x": this._XconvertDOMtoCanvas(this.frame.canvas.clientWidth * this.pixelRatio), - "y": this._YconvertDOMtoCanvas(this.frame.canvas.clientHeight * this.pixelRatio) - }; + var groupOptions = Object.create(me.options); + util.extend(groupOptions, { + height: null + }); - if (!(hidden == true)) { - this._doInAllSectors("_drawAllSectorNodes", ctx); - if (this.drag.dragging == false || this.drag.dragging === undefined || this.constants.hideEdgesOnDrag == false) { - this._doInAllSectors("_drawEdges", ctx); - } - } + group = new Group(id, groupData, me); + me.groups[id] = group; - if (this.drag.dragging == false || this.drag.dragging === undefined || this.constants.hideNodesOnDrag == false) { - this._doInAllSectors("_drawNodes",ctx,false); - } + // add items with this groupId to the new group + for (var itemId in me.items) { + if (me.items.hasOwnProperty(itemId)) { + var item = me.items[itemId]; + if (item.data.group == id) { + group.add(item); + } + } + } - if (!(hidden == true)) { - if (this.controlNodesActive == true) { - this._doInAllSectors("_drawControlNodes", ctx); + group.order(); + group.show(); } - } - - // this._doInSupportSector("_drawNodes",ctx,true); - // this._drawTree(ctx,"#F00F0F"); - - // restore original scaling and translation - ctx.restore(); + else { + // update group + group.setData(groupData); + } + }); - if (hidden == true) { - ctx.clearRect(0, 0, w, h); - } + this.body.emitter.emit('change', {queue: true}); }; /** - * Set the translation of the network - * @param {Number} offsetX Horizontal offset - * @param {Number} offsetY Vertical offset + * Handle removed groups + * @param {Number[]} ids * @private */ - Network.prototype._setTranslation = function(offsetX, offsetY) { - if (this.translation === undefined) { - this.translation = { - x: 0, - y: 0 - }; - } + ItemSet.prototype._onRemoveGroups = function(ids) { + var groups = this.groups; + ids.forEach(function (id) { + var group = groups[id]; - if (offsetX !== undefined) { - this.translation.x = offsetX; - } - if (offsetY !== undefined) { - this.translation.y = offsetY; - } + if (group) { + group.hide(); + delete groups[id]; + } + }); - this.emit('viewChanged'); - }; + this.markDirty(); - /** - * Get the translation of the network - * @return {Object} translation An object with parameters x and y, both a number - * @private - */ - Network.prototype._getTranslation = function() { - return { - x: this.translation.x, - y: this.translation.y - }; + this.body.emitter.emit('change', {queue: true}); }; /** - * Scale the network - * @param {Number} scale Scaling factor 1.0 is unscaled + * Reorder the groups if needed + * @return {boolean} changed * @private */ - Network.prototype._setScale = function(scale) { - this.scale = scale; - }; + ItemSet.prototype._orderGroups = function () { + if (this.groupsData) { + // reorder the groups + var groupIds = this.groupsData.getIds({ + order: this.options.groupOrder + }); - /** - * Get the current scale of the network - * @return {Number} scale Scaling factor 1.0 is unscaled - * @private - */ - Network.prototype._getScale = function() { - return this.scale; + var changed = !util.equalArray(groupIds, this.groupIds); + if (changed) { + // hide all groups, removes them from the DOM + var groups = this.groups; + groupIds.forEach(function (groupId) { + groups[groupId].hide(); + }); + + // show the groups again, attach them to the DOM in correct order + groupIds.forEach(function (groupId) { + groups[groupId].show(); + }); + + this.groupIds = groupIds; + } + + return changed; + } + else { + return false; + } }; /** - * Convert the X coordinate in DOM-space (coordinate point in browser relative to the container div) to - * the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon) - * @param {number} x - * @returns {number} + * Add a new item + * @param {Item} item * @private */ - Network.prototype._XconvertDOMtoCanvas = function(x) { - return (x - this.translation.x) / this.scale; + ItemSet.prototype._addItem = function(item) { + this.items[item.id] = item; + + // add to group + var groupId = this._getGroupId(item.data); + var group = this.groups[groupId]; + if (group) group.add(item); }; /** - * Convert the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to - * the X coordinate in DOM-space (coordinate point in browser relative to the container div) - * @param {number} x - * @returns {number} + * Update an existing item + * @param {Item} item + * @param {Object} itemData * @private */ - Network.prototype._XconvertCanvasToDOM = function(x) { - return x * this.scale + this.translation.x; + ItemSet.prototype._updateItem = function(item, itemData) { + var oldGroupId = item.data.group; + + // update the items data (will redraw the item when displayed) + item.setData(itemData); + + // update group + if (oldGroupId != item.data.group) { + var oldGroup = this.groups[oldGroupId]; + if (oldGroup) oldGroup.remove(item); + + var groupId = this._getGroupId(item.data); + var group = this.groups[groupId]; + if (group) group.add(item); + } }; /** - * Convert the Y coordinate in DOM-space (coordinate point in browser relative to the container div) to - * the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon) - * @param {number} y - * @returns {number} + * Delete an item from the ItemSet: remove it from the DOM, from the map + * with items, and from the map with visible items, and from the selection + * @param {Item} item * @private */ - Network.prototype._YconvertDOMtoCanvas = function(y) { - return (y - this.translation.y) / this.scale; + ItemSet.prototype._removeItem = function(item) { + // remove from DOM + item.hide(); + + // remove from items + delete this.items[item.id]; + + // remove from selection + var index = this.selection.indexOf(item.id); + if (index != -1) this.selection.splice(index, 1); + + // remove from group + item.parent && item.parent.remove(item); }; /** - * Convert the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to - * the Y coordinate in DOM-space (coordinate point in browser relative to the container div) - * @param {number} y - * @returns {number} + * Create an array containing all items being a range (having an end date) + * @param array + * @returns {Array} * @private */ - Network.prototype._YconvertCanvasToDOM = function(y) { - return y * this.scale + this.translation.y ; - }; - + ItemSet.prototype._constructByEndArray = function(array) { + var endArray = []; - /** - * - * @param {object} pos = {x: number, y: number} - * @returns {{x: number, y: number}} - * @constructor - */ - Network.prototype.canvasToDOM = function (pos) { - return {x: this._XconvertCanvasToDOM(pos.x), y: this._YconvertCanvasToDOM(pos.y)}; + for (var i = 0; i < array.length; i++) { + if (array[i] instanceof RangeItem) { + endArray.push(array[i]); + } + } + return endArray; }; /** + * Register the clicked item on touch, before dragStart is initiated. * - * @param {object} pos = {x: number, y: number} - * @returns {{x: number, y: number}} - * @constructor + * dragStart is initiated from a mousemove event, which can have left the item + * already resulting in an item == null + * + * @param {Event} event + * @private */ - Network.prototype.DOMtoCanvas = function (pos) { - return {x: this._XconvertDOMtoCanvas(pos.x), y: this._YconvertDOMtoCanvas(pos.y)}; + ItemSet.prototype._onTouch = function (event) { + // store the touched item, used in _onDragStart + this.touchParams.item = ItemSet.itemFromTarget(event); }; /** - * Redraw all nodes - * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); - * @param {CanvasRenderingContext2D} ctx - * @param {Boolean} [alwaysShow] + * Start dragging the selected events + * @param {Event} event * @private */ - Network.prototype._drawNodes = function(ctx,alwaysShow) { - if (alwaysShow === undefined) { - alwaysShow = false; + ItemSet.prototype._onDragStart = function (event) { + if (!this.options.editable.updateTime && !this.options.editable.updateGroup) { + return; } - // first draw the unselected nodes - var nodes = this.nodes; - var selected = []; + var item = this.touchParams.item || null; + var me = this; + var props; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - nodes[id].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight); - if (nodes[id].isSelected()) { - selected.push(id); + if (item && item.selected) { + var dragLeftItem = event.target.dragLeftItem; + var dragRightItem = event.target.dragRightItem; + + if (dragLeftItem) { + props = { + item: dragLeftItem, + initialX: event.gesture.center.clientX + }; + + if (me.options.editable.updateTime) { + props.start = item.data.start.valueOf(); } - else { - if (nodes[id].inArea() || alwaysShow) { - nodes[id].draw(ctx); - } + if (me.options.editable.updateGroup) { + if ('group' in item.data) props.group = item.data.group; } - } - } - // draw the selected nodes on top - for (var s = 0, sMax = selected.length; s < sMax; s++) { - if (nodes[selected[s]].inArea() || alwaysShow) { - nodes[selected[s]].draw(ctx); + this.touchParams.itemProps = [props]; } - } - }; + else if (dragRightItem) { + props = { + item: dragRightItem, + initialX: event.gesture.center.clientX + }; - /** - * Redraw all edges - * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); - * @param {CanvasRenderingContext2D} ctx - * @private - */ - Network.prototype._drawEdges = function(ctx) { - var edges = this.edges; - for (var id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - edge.setScale(this.scale); - if (edge.connected) { - edges[id].draw(ctx); + if (me.options.editable.updateTime) { + props.end = item.data.end.valueOf(); } + if (me.options.editable.updateGroup) { + if ('group' in item.data) props.group = item.data.group; + } + + this.touchParams.itemProps = [props]; } - } - }; + else { + this.touchParams.itemProps = this.getSelection().map(function (id) { + var item = me.items[id]; + var props = { + item: item, + initialX: event.gesture.center.clientX + }; - /** - * Redraw all edges - * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); - * @param {CanvasRenderingContext2D} ctx - * @private - */ - Network.prototype._drawControlNodes = function(ctx) { - var edges = this.edges; - for (var id in edges) { - if (edges.hasOwnProperty(id)) { - edges[id]._drawControlNodes(ctx); + if (me.options.editable.updateTime) { + if ('start' in item.data) props.start = item.data.start.valueOf(); + if ('end' in item.data) props.end = item.data.end.valueOf(); + } + if (me.options.editable.updateGroup) { + if ('group' in item.data) props.group = item.data.group; + } + + return props; + }); } + + event.stopPropagation(); } }; /** - * Find a stable position for all nodes + * Drag selected items + * @param {Event} event * @private */ - Network.prototype._stabilize = function() { - if (this.constants.freezeForStabilization == true) { - this._freezeDefinedNodes(); - } + ItemSet.prototype._onDrag = function (event) { + event.preventDefault() - // find stable position - var count = 0; - while (this.moving && count < this.constants.stabilizationIterations) { - this._physicsTick(); - count++; - } + if (this.touchParams.itemProps) { + var me = this; + var snap = this.body.util.snap || null; + var xOffset = this.body.dom.root.offsetLeft + this.body.domProps.left.width; - if (this.constants.zoomExtentOnStabilize == true) { - this.zoomExtent(undefined, false, true); - } + // move + this.touchParams.itemProps.forEach(function (props) { + var newProps = {}; + var current = me.body.util.toTime(event.gesture.center.clientX - xOffset); + var initial = me.body.util.toTime(props.initialX - xOffset); + var offset = current - initial; - if (this.constants.freezeForStabilization == true) { - this._restoreFrozenNodes(); - } - }; + if ('start' in props) { + var start = new Date(props.start + offset); + newProps.start = snap ? snap(start) : start; + } - /** - * When initializing and stabilizing, we can freeze nodes with a predefined position. This greatly speeds up stabilization - * because only the supportnodes for the smoothCurves have to settle. - * - * @private - */ - Network.prototype._freezeDefinedNodes = function() { - var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - if (nodes[id].x != null && nodes[id].y != null) { - nodes[id].fixedData.x = nodes[id].xFixed; - nodes[id].fixedData.y = nodes[id].yFixed; - nodes[id].xFixed = true; - nodes[id].yFixed = true; + if ('end' in props) { + var end = new Date(props.end + offset); + newProps.end = snap ? snap(end) : end; } - } + + if ('group' in props) { + // drag from one group to another + var group = ItemSet.groupFromTarget(event); + newProps.group = group && group.groupId; + } + + // confirm moving the item + var itemData = util.extend({}, props.item.data, newProps); + me.options.onMoving(itemData, function (itemData) { + if (itemData) { + me._updateItemProps(props.item, itemData); + } + }); + }); + + this.stackDirty = true; // force re-stacking of all items next redraw + this.body.emitter.emit('change'); + + event.stopPropagation(); } }; /** - * Unfreezes the nodes that have been frozen by _freezeDefinedNodes. - * + * Update an items properties + * @param {Item} item + * @param {Object} props Can contain properties start, end, and group. * @private */ - Network.prototype._restoreFrozenNodes = function() { - var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - if (nodes[id].fixedData.x != null) { - nodes[id].xFixed = nodes[id].fixedData.x; - nodes[id].yFixed = nodes[id].fixedData.y; - } - } + ItemSet.prototype._updateItemProps = function(item, props) { + // TODO: copy all properties from props to item? (also new ones) + if ('start' in props) item.data.start = props.start; + if ('end' in props) item.data.end = props.end; + if ('group' in props && item.data.group != props.group) { + this._moveToGroup(item, props.group) } }; - /** - * Check if any of the nodes is still moving - * @param {number} vmin the minimum velocity considered as 'moving' - * @return {boolean} true if moving, false if non of the nodes is moving + * Move an item to another group + * @param {Item} item + * @param {String | Number} groupId * @private */ - Network.prototype._isMoving = function(vmin) { - var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id) && nodes[id].isMoving(vmin)) { - return true; - } + ItemSet.prototype._moveToGroup = function(item, groupId) { + var group = this.groups[groupId]; + if (group && group.groupId != item.data.group) { + var oldGroup = item.parent; + oldGroup.remove(item); + oldGroup.order(); + group.add(item); + group.order(); + + item.data.group = group.groupId; } - return false; }; - /** - * /** - * Perform one discrete step for all nodes - * + * End of dragging selected items + * @param {Event} event * @private */ - Network.prototype._discreteStepNodes = function() { - var interval = this.physicsDiscreteStepsize; - var nodes = this.nodes; - var nodeId; - var nodesPresent = false; + ItemSet.prototype._onDragEnd = function (event) { + event.preventDefault() - if (this.constants.maxVelocity > 0) { - for (nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - nodes[nodeId].discreteStepLimited(interval, this.constants.maxVelocity); - nodesPresent = true; - } - } - } - else { - for (nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - nodes[nodeId].discreteStep(interval); - nodesPresent = true; + if (this.touchParams.itemProps) { + // prepare a change set for the changed items + var changes = [], + me = this, + dataset = this.itemsData.getDataSet(); + + var itemProps = this.touchParams.itemProps ; + this.touchParams.itemProps = null; + itemProps.forEach(function (props) { + var id = props.item.id, + itemData = me.itemsData.get(id, me.itemOptions); + + var changed = false; + if ('start' in props.item.data) { + changed = (props.start != props.item.data.start.valueOf()); + itemData.start = util.convert(props.item.data.start, + dataset._options.type && dataset._options.type.start || 'Date'); + } + if ('end' in props.item.data) { + changed = changed || (props.end != props.item.data.end.valueOf()); + itemData.end = util.convert(props.item.data.end, + dataset._options.type && dataset._options.type.end || 'Date'); + } + if ('group' in props.item.data) { + changed = changed || (props.group != props.item.data.group); + itemData.group = props.item.data.group; } - } - } - if (nodesPresent == true) { - var vminCorrected = this.constants.minVelocity / Math.max(this.scale,0.05); - if (vminCorrected > 0.5*this.constants.maxVelocity) { - return true; - } - else { - return this._isMoving(vminCorrected); - } - } - return false; - }; + // only apply changes when start or end is actually changed + if (changed) { + me.options.onMove(itemData, function (itemData) { + if (itemData) { + // apply changes + itemData[dataset._fieldId] = id; // ensure the item contains its id (can be undefined) + changes.push(itemData); + } + else { + // restore original values + me._updateItemProps(props.item, props); + me.stackDirty = true; // force re-stacking of all items next redraw + me.body.emitter.emit('change'); + } + }); + } + }); - Network.prototype._revertPhysicsState = function() { - var nodes = this.nodes; - for (var nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - nodes[nodeId].revertPosition(); + // apply the changes to the data (if there are changes) + if (changes.length) { + dataset.update(changes); } - } - } - Network.prototype._revertPhysicsTick = function() { - this._doInAllActiveSectors("_revertPhysicsState"); - if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { - this._doInSupportSector("_revertPhysicsState"); + event.stopPropagation(); } - } + }; /** - * A single simulation step (or "tick") in the physics simulation - * + * Handle selecting/deselecting an item when tapping it + * @param {Event} event * @private */ - Network.prototype._physicsTick = function() { - if (!this.freezeSimulation) { - if (this.moving == true) { - var mainMovingStatus = false; - var supportMovingStatus = false; + ItemSet.prototype._onSelectItem = function (event) { + if (!this.options.selectable) return; - this._doInAllActiveSectors("_initializeForceCalculation"); - var mainMoving = this._doInAllActiveSectors("_discreteStepNodes"); - if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { - supportMovingStatus = this._doInSupportSector("_discreteStepNodes"); - } + var ctrlKey = event.gesture.srcEvent && event.gesture.srcEvent.ctrlKey; + var shiftKey = event.gesture.srcEvent && event.gesture.srcEvent.shiftKey; + if (ctrlKey || shiftKey) { + this._onMultiSelectItem(event); + return; + } - // gather movement data from all sectors, if one moves, we are NOT stabilzied - for (var i = 0; i < mainMoving.length; i++) {mainMovingStatus = mainMoving[0] || mainMovingStatus;} + var oldSelection = this.getSelection(); - // determine if the network has stabilzied - this.moving = mainMovingStatus || supportMovingStatus; + var item = ItemSet.itemFromTarget(event); + var selection = item ? [item.id] : []; + this.setSelection(selection); - if (this.moving == false) { - this._revertPhysicsTick(); - } - else { - // this is here to ensure that there is no start event when the network is already stable. - if (this.startedStabilization == false) { - this.emit("startStabilization"); - this.startedStabilization = true; - } - } + var newSelection = this.getSelection(); - this.stabilizationIterations++; - } + // emit a select event, + // except when old selection is empty and new selection is still empty + if (newSelection.length > 0 || oldSelection.length > 0) { + this.body.emitter.emit('select', { + items: newSelection + }); } }; - /** - * This function runs one step of the animation. It calls an x amount of physics ticks and one render tick. - * It reschedules itself at the beginning of the function - * + * Handle creation and updates of an item on double tap + * @param event * @private */ - Network.prototype._animationStep = function() { - // reset the timer so a new scheduled animation step can be set - this.timer = undefined; - - // handle the keyboad movement - this._handleNavigation(); + ItemSet.prototype._onAddItem = function (event) { + if (!this.options.selectable) return; + if (!this.options.editable.add) return; - var startTime = Date.now(); - this._physicsTick(); - var physicsTime = Date.now() - startTime; + var me = this, + snap = this.body.util.snap || null, + item = ItemSet.itemFromTarget(event); - // run double speed if it is a little graph - if ((this.renderTimestep - this.renderTime > 2 * physicsTime || this.runDoubleSpeed == true) && this.moving == true) { - this._physicsTick(); + if (item) { + // update item - // this makes sure there is no jitter. The decision is taken once to run it at double speed. - if (this.renderTime != 0) { - this.runDoubleSpeed = true - } + // execute async handler to update the item (or cancel it) + var itemData = me.itemsData.get(item.id); // get a clone of the data from the dataset + this.options.onUpdate(itemData, function (itemData) { + if (itemData) { + me.itemsData.getDataSet().update(itemData); + } + }); } + else { + // add item + var xAbs = util.getAbsoluteLeft(this.dom.frame); + var x = event.gesture.center.pageX - xAbs; + var start = this.body.util.toTime(x); + var newItem = { + start: snap ? snap(start) : start, + content: 'new item' + }; - var renderStartTime = Date.now(); - this._redraw(); - this.renderTime = Date.now() - renderStartTime; + // when default type is a range, add a default end date to the new item + if (this.options.type === 'range') { + var end = this.body.util.toTime(x + this.props.width / 5); + newItem.end = snap ? snap(end) : end; + } - // this schedules a new animation step - this.start(); - }; + newItem[this.itemsData._fieldId] = util.randomUUID(); - if (typeof window !== 'undefined') { - window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || - window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; - } + var group = ItemSet.groupFromTarget(event); + if (group) { + newItem.group = group.groupId; + } - /** - * Schedule a animation step with the refreshrate interval. - */ - Network.prototype.start = function() { - if (this.moving == true || this.xIncrement != 0 || this.yIncrement != 0 || this.zoomIncrement != 0) { - if (!this.timer) { - if (this.requiresTimeout == true) { - this.timer = window.setTimeout(this._animationStep.bind(this), this.renderTimestep); // wait this.renderTimeStep milliseconds and perform the animation step function - } - else { - this.timer = window.requestAnimationFrame(this._animationStep.bind(this)); // wait this.renderTimeStep milliseconds and perform the animation step function + // execute async handler to customize (or cancel) adding an item + this.options.onAdd(newItem, function (item) { + if (item) { + me.itemsData.getDataSet().add(item); + // TODO: need to trigger a redraw? } - } - } - else { - this._redraw(); - // this check is to ensure that the network does not emit these events if it was already stabilized and setOptions is called (setting moving to true and calling start()) - if (this.stabilizationIterations > 1) { - // trigger the "stabilized" event. - // The event is triggered on the next tick, to prevent the case that - // it is fired while initializing the Network, in which case you would not - // be able to catch it - var me = this; - var params = { - iterations: me.stabilizationIterations - }; - this.stabilizationIterations = 0; - this.startedStabilization = false; - setTimeout(function () { - me.emit("stabilized", params); - }, 0); - } - else { - this.stabilizationIterations = 0; - } + }); } }; - /** - * Move the network according to the keyboard presses. - * + * Handle selecting/deselecting multiple items when holding an item + * @param {Event} event * @private */ - Network.prototype._handleNavigation = function() { - if (this.xIncrement != 0 || this.yIncrement != 0) { - var translation = this._getTranslation(); - this._setTranslation(translation.x+this.xIncrement, translation.y+this.yIncrement); - } - if (this.zoomIncrement != 0) { - var center = { - x: this.frame.canvas.clientWidth / 2, - y: this.frame.canvas.clientHeight / 2 - }; - this._zoom(this.scale*(1 + this.zoomIncrement), center); - } - }; + ItemSet.prototype._onMultiSelectItem = function (event) { + if (!this.options.selectable) return; + var selection, + item = ItemSet.itemFromTarget(event); - /** - * Freeze the _animationStep - */ - Network.prototype.toggleFreeze = function() { - if (this.freezeSimulation == false) { - this.freezeSimulation = true; - } - else { - this.freezeSimulation = false; - this.start(); - } - }; + if (item) { + // multi select items + selection = this.getSelection(); // current selection + var shiftKey = event.gesture.touches[0] && event.gesture.touches[0].shiftKey || false; + if (shiftKey) { + // select all items between the old selection and the tapped item - /** - * This function cleans the support nodes if they are not needed and adds them when they are. - * - * @param {boolean} [disableStart] - * @private - */ - Network.prototype._configureSmoothCurves = function(disableStart) { - if (disableStart === undefined) { - disableStart = true; - } - if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { - this._createBezierNodes(); - // cleanup unused support nodes - for (var nodeId in this.sectors['support']['nodes']) { - if (this.sectors['support']['nodes'].hasOwnProperty(nodeId)) { - if (this.edges[this.sectors['support']['nodes'][nodeId].parentEdgeId] === undefined) { - delete this.sectors['support']['nodes'][nodeId]; + // determine the selection range + selection.push(item.id); + var range = ItemSet._getItemRange(this.itemsData.get(selection, this.itemOptions)); + + // select all items within the selection range + selection = []; + for (var id in this.items) { + if (this.items.hasOwnProperty(id)) { + var _item = this.items[id]; + var start = _item.data.start; + var end = (_item.data.end !== undefined) ? _item.data.end : start; + + if (start >= range.min && end <= range.max) { + selection.push(_item.id); // do not use id but item.id, id itself is stringified + } } } } - } - else { - // delete the support nodes - this.sectors['support']['nodes'] = {}; - for (var edgeId in this.edges) { - if (this.edges.hasOwnProperty(edgeId)) { - this.edges[edgeId].via = null; + else { + // add/remove this item from the current selection + var index = selection.indexOf(item.id); + if (index == -1) { + // item is not yet selected -> select it + selection.push(item.id); + } + else { + // item is already selected -> deselect it + selection.splice(index, 1); } } - } + this.setSelection(selection); - this._updateCalculationNodes(); - if (!disableStart) { - this.moving = true; - this.start(); + this.body.emitter.emit('select', { + items: this.getSelection() + }); } }; - /** - * Bezier curves require an anchor point to calculate the smooth flow. These points are nodes. These nodes are invisible but - * are used for the force calculation. - * + * Calculate the time range of a list of items + * @param {Array.} itemsData + * @return {{min: Date, max: Date}} Returns the range of the provided items * @private */ - Network.prototype._createBezierNodes = function() { - if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { - for (var edgeId in this.edges) { - if (this.edges.hasOwnProperty(edgeId)) { - var edge = this.edges[edgeId]; - if (edge.via == null) { - var nodeId = "edgeId:".concat(edge.id); - this.sectors['support']['nodes'][nodeId] = new Node( - {id:nodeId, - mass:1, - shape:'circle', - image:"", - internalMultiplier:1 - },{},{},this.constants); - edge.via = this.sectors['support']['nodes'][nodeId]; - edge.via.parentEdgeId = edge.id; - edge.positionBezierNode(); - } + ItemSet._getItemRange = function(itemsData) { + var max = null; + var min = null; + + itemsData.forEach(function (data) { + if (min == null || data.start < min) { + min = data.start; + } + + if (data.end != undefined) { + if (max == null || data.end > max) { + max = data.end; + } + } + else { + if (max == null || data.start > max) { + max = data.start; } } + }); + + return { + min: min, + max: max } }; /** - * load the functions that load the mixins into the prototype. - * - * @private + * Find an item from an event target: + * searches for the attribute 'timeline-item' in the event target's element tree + * @param {Event} event + * @return {Item | null} item */ - Network.prototype._initializeMixinLoaders = function () { - for (var mixin in MixinLoader) { - if (MixinLoader.hasOwnProperty(mixin)) { - Network.prototype[mixin] = MixinLoader[mixin]; + ItemSet.itemFromTarget = function(event) { + var target = event.target; + while (target) { + if (target.hasOwnProperty('timeline-item')) { + return target['timeline-item']; } + target = target.parentNode; } - }; - /** - * Load the XY positions of the nodes into the dataset. - */ - Network.prototype.storePosition = function() { - console.log("storePosition is depricated: use .storePositions() from now on.") - this.storePositions(); + return null; }; /** - * Load the XY positions of the nodes into the dataset. + * Find the Group from an event target: + * searches for the attribute 'timeline-group' in the event target's element tree + * @param {Event} event + * @return {Group | null} group */ - Network.prototype.storePositions = function() { - var dataArray = []; - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - var node = this.nodes[nodeId]; - var allowedToMoveX = !this.nodes.xFixed; - var allowedToMoveY = !this.nodes.yFixed; - if (this.nodesData._data[nodeId].x != Math.round(node.x) || this.nodesData._data[nodeId].y != Math.round(node.y)) { - dataArray.push({id:nodeId,x:Math.round(node.x),y:Math.round(node.y),allowedToMoveX:allowedToMoveX,allowedToMoveY:allowedToMoveY}); - } + ItemSet.groupFromTarget = function(event) { + var target = event.target; + while (target) { + if (target.hasOwnProperty('timeline-group')) { + return target['timeline-group']; } + target = target.parentNode; } - this.nodesData.update(dataArray); + + return null; }; /** - * Return the positions of the nodes. + * Find the ItemSet from an event target: + * searches for the attribute 'timeline-itemset' in the event target's element tree + * @param {Event} event + * @return {ItemSet | null} item */ - Network.prototype.getPositions = function(ids) { - var dataArray = {}; - if (ids !== undefined) { - if (Array.isArray(ids) == true) { - for (var i = 0; i < ids.length; i++) { - if (this.nodes[ids[i]] !== undefined) { - var node = this.nodes[ids[i]]; - dataArray[ids[i]] = {x: Math.round(node.x), y: Math.round(node.y)}; - } - } - } - else { - if (this.nodes[ids] !== undefined) { - var node = this.nodes[ids]; - dataArray[ids] = {x: Math.round(node.x), y: Math.round(node.y)}; - } - } - } - else { - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - var node = this.nodes[nodeId]; - dataArray[nodeId] = {x: Math.round(node.x), y: Math.round(node.y)}; - } + ItemSet.itemSetFromTarget = function(event) { + var target = event.target; + while (target) { + if (target.hasOwnProperty('timeline-itemset')) { + return target['timeline-itemset']; } + target = target.parentNode; } - return dataArray; + + return null; }; + module.exports = ItemSet; - /** - * Center a node in view. - * - * @param {Number} nodeId - * @param {Number} [options] - */ - Network.prototype.focusOnNode = function (nodeId, options) { - if (this.nodes.hasOwnProperty(nodeId)) { - if (options === undefined) { - options = {}; - } - var nodePosition = {x: this.nodes[nodeId].x, y: this.nodes[nodeId].y}; - options.position = nodePosition; - options.lockedOnNode = nodeId; +/***/ }, +/* 27 */ +/***/ function(module, exports, __webpack_require__) { - this.moveTo(options) - } - else { - console.log("This nodeId cannot be found."); - } - }; + var util = __webpack_require__(1); + var stack = __webpack_require__(28); + var RangeItem = __webpack_require__(29); /** - * - * @param {Object} options | options.offset = {x:Number, y:Number} // offset from the center in DOM pixels - * | options.scale = Number // scale to move to - * | options.position = {x:Number, y:Number} // position to move to - * | options.animation = {duration:Number, easingFunction:String} || Boolean // position to move to + * @constructor Group + * @param {Number | String} groupId + * @param {Object} data + * @param {ItemSet} itemSet */ - Network.prototype.moveTo = function (options) { - if (options === undefined) { - options = {}; - return; - } - if (options.offset === undefined) {options.offset = {x: 0, y: 0}; } - if (options.offset.x === undefined) {options.offset.x = 0; } - if (options.offset.y === undefined) {options.offset.y = 0; } - if (options.scale === undefined) {options.scale = this._getScale(); } - if (options.position === undefined) {options.position = this._getTranslation();} - if (options.animation === undefined) {options.animation = {duration:0}; } - if (options.animation === false ) {options.animation = {duration:0}; } - if (options.animation === true ) {options.animation = {}; } - if (options.animation.duration === undefined) {options.animation.duration = 1000; } // default duration - if (options.animation.easingFunction === undefined) {options.animation.easingFunction = "easeInOutQuad"; } // default easing function - - this.animateView(options); - }; - - /** - * - * @param {Object} options | options.offset = {x:Number, y:Number} // offset from the center in DOM pixels - * | options.time = Number // animation time in milliseconds - * | options.scale = Number // scale to animate to - * | options.position = {x:Number, y:Number} // position to animate to - * | options.easingFunction = String // linear, easeInQuad, easeOutQuad, easeInOutQuad, - * // easeInCubic, easeOutCubic, easeInOutCubic, - * // easeInQuart, easeOutQuart, easeInOutQuart, - * // easeInQuint, easeOutQuint, easeInOutQuint - */ - Network.prototype.animateView = function (options) { - if (options === undefined) { - options = {}; - return; - } - - // release if something focussed on the node - this.releaseNode(); - if (options.locked == true) { - this.lockedOnNodeId = options.lockedOnNode; - this.lockedOnNodeOffset = options.offset; - } - - // forcefully complete the old animation if it was still running - if (this.easingTime != 0) { - this._transitionRedraw(1); // by setting easingtime to 1, we finish the animation. - } - - this.sourceScale = this._getScale(); - this.sourceTranslation = this._getTranslation(); - this.targetScale = options.scale; - - // set the scale so the viewCenter is based on the correct zoom level. This is overridden in the transitionRedraw - // but at least then we'll have the target transition - this._setScale(this.targetScale); - var viewCenter = this.DOMtoCanvas({x: 0.5 * this.frame.canvas.clientWidth, y: 0.5 * this.frame.canvas.clientHeight}); - var distanceFromCenter = { // offset from view, distance view has to change by these x and y to center the node - x: viewCenter.x - options.position.x, - y: viewCenter.y - options.position.y - }; - this.targetTranslation = { - x: this.sourceTranslation.x + distanceFromCenter.x * this.targetScale + options.offset.x, - y: this.sourceTranslation.y + distanceFromCenter.y * this.targetScale + options.offset.y - }; + function Group (groupId, data, itemSet) { + this.groupId = groupId; + this.subgroups = {}; + this.subgroupIndex = 0; + this.subgroupOrderer = data && data.subgroupOrder; + this.itemSet = itemSet; - // if the time is set to 0, don't do an animation - if (options.animation.duration == 0) { - if (this.lockedOnNodeId != null) { - this._classicRedraw = this._redraw; - this._redraw = this._lockedRedraw; - } - else { - this._setScale(this.targetScale); - this._setTranslation(this.targetTranslation.x, this.targetTranslation.y); - this._redraw(); + this.dom = {}; + this.props = { + label: { + width: 0, + height: 0 } - } - else { - this.animationSpeed = 1 / (this.renderRefreshRate * options.animation.duration * 0.001) || 1 / this.renderRefreshRate; - this.animationEasingFunction = options.animation.easingFunction; - this._classicRedraw = this._redraw; - this._redraw = this._transitionRedraw; - this._redraw(); - this.moving = true; - this.start(); - } - }; - - /** - * used to animate smoothly by hijacking the redraw function. - * @private - */ - Network.prototype._lockedRedraw = function () { - var nodePosition = {x: this.nodes[this.lockedOnNodeId].x, y: this.nodes[this.lockedOnNodeId].y}; - var viewCenter = this.DOMtoCanvas({x: 0.5 * this.frame.canvas.clientWidth, y: 0.5 * this.frame.canvas.clientHeight}); - var distanceFromCenter = { // offset from view, distance view has to change by these x and y to center the node - x: viewCenter.x - nodePosition.x, - y: viewCenter.y - nodePosition.y }; - var sourceTranslation = this._getTranslation(); - var targetTranslation = { - x: sourceTranslation.x + distanceFromCenter.x * this.scale + this.lockedOnNodeOffset.x, - y: sourceTranslation.y + distanceFromCenter.y * this.scale + this.lockedOnNodeOffset.y + this.className = null; + + this.items = {}; // items filtered by groupId of this group + this.visibleItems = []; // items currently visible in window + this.orderedItems = { + byStart: [], + byEnd: [] }; + this.checkRangedItems = false; // needed to refresh the ranged items if the window is programatically changed with NO overlap. + var me = this; + this.itemSet.body.emitter.on("checkRangedItems", function () { + me.checkRangedItems = true; + }) - this._setTranslation(targetTranslation.x,targetTranslation.y); - this._classicRedraw(); - } + this._create(); - Network.prototype.releaseNode = function () { - if (this.lockedOnNodeId != null) { - this._redraw = this._classicRedraw; - this.lockedOnNodeId = null; - this.lockedOnNodeOffset = null; - } + this.setData(data); } /** - * - * @param easingTime + * Create DOM elements for the group * @private */ - Network.prototype._transitionRedraw = function (easingTime) { - this.easingTime = easingTime || this.easingTime + this.animationSpeed; - this.easingTime += this.animationSpeed; + Group.prototype._create = function() { + var label = document.createElement('div'); + label.className = 'vlabel'; + this.dom.label = label; - var progress = util.easingFunctions[this.animationEasingFunction](this.easingTime); + var inner = document.createElement('div'); + inner.className = 'inner'; + label.appendChild(inner); + this.dom.inner = inner; - this._setScale(this.sourceScale + (this.targetScale - this.sourceScale) * progress); - this._setTranslation( - this.sourceTranslation.x + (this.targetTranslation.x - this.sourceTranslation.x) * progress, - this.sourceTranslation.y + (this.targetTranslation.y - this.sourceTranslation.y) * progress - ); + var foreground = document.createElement('div'); + foreground.className = 'group'; + foreground['timeline-group'] = this; + this.dom.foreground = foreground; - this._classicRedraw(); - this.moving = true; + this.dom.background = document.createElement('div'); + this.dom.background.className = 'group'; - // cleanup - if (this.easingTime >= 1.0) { - this.easingTime = 0; - if (this.lockedOnNodeId != null) { - this._redraw = this._lockedRedraw; - } - else { - this._redraw = this._classicRedraw; - } - this.emit("animationFinished"); - } - }; + this.dom.axis = document.createElement('div'); + this.dom.axis.className = 'group'; - Network.prototype._classicRedraw = function () { - // placeholder function to be overloaded by animations; + // create a hidden marker to detect when the Timelines container is attached + // to the DOM, or the style of a parent of the Timeline is changed from + // display:none is changed to visible. + this.dom.marker = document.createElement('div'); + this.dom.marker.style.visibility = 'hidden'; // TODO: ask jos why this is not none? + this.dom.marker.innerHTML = '?'; + this.dom.background.appendChild(this.dom.marker); }; /** - * Returns true when the Network is active. - * @returns {boolean} + * Set the group data for this group + * @param {Object} data Group data, can contain properties content and className */ - Network.prototype.isActive = function () { - return !this.activator || this.activator.active; - }; + Group.prototype.setData = function(data) { + // update contents + var content = data && data.content; + if (content instanceof Element) { + this.dom.inner.appendChild(content); + } + else if (content !== undefined && content !== null) { + this.dom.inner.innerHTML = content; + } + else { + this.dom.inner.innerHTML = this.groupId || ''; // groupId can be null + } + // update title + this.dom.label.title = data && data.title || ''; - /** - * Sets the scale - * @returns {Number} - */ - Network.prototype.setScale = function () { - return this._setScale(); - }; + if (!this.dom.inner.firstChild) { + util.addClassName(this.dom.inner, 'hidden'); + } + else { + util.removeClassName(this.dom.inner, 'hidden'); + } + // update className + var className = data && data.className || null; + if (className != this.className) { + if (this.className) { + util.removeClassName(this.dom.label, this.className); + util.removeClassName(this.dom.foreground, this.className); + util.removeClassName(this.dom.background, this.className); + util.removeClassName(this.dom.axis, this.className); + } + util.addClassName(this.dom.label, className); + util.addClassName(this.dom.foreground, className); + util.addClassName(this.dom.background, className); + util.addClassName(this.dom.axis, className); + this.className = className; + } - /** - * Returns the scale - * @returns {Number} - */ - Network.prototype.getScale = function () { - return this._getScale(); + // update style + if (this.style) { + util.removeCssText(this.dom.label, this.style); + this.style = null; + } + if (data && data.style) { + util.addCssText(this.dom.label, data.style); + this.style = data.style; + } }; - /** - * Returns the scale - * @returns {Number} + * Get the width of the group label + * @return {number} width */ - Network.prototype.getCenterCoordinates = function () { - return this.DOMtoCanvas({x: 0.5 * this.frame.canvas.clientWidth, y: 0.5 * this.frame.canvas.clientHeight}); + Group.prototype.getLabelWidth = function() { + return this.props.label.width; }; - Network.prototype.getBoundingBox = function(nodeId) { - if (this.nodes[nodeId] !== undefined) { - return this.nodes[nodeId].boundingBox; - } - } - - module.exports = Network; - - -/***/ }, -/* 37 */ -/***/ function(module, exports, __webpack_require__) { - - var util = __webpack_require__(1); - var Node = __webpack_require__(40); - /** - * @class Edge - * - * A edge connects two nodes - * @param {Object} properties Object with properties. Must contain - * At least properties from and to. - * Available properties: from (number), - * to (number), label (string, color (string), - * width (number), style (string), - * length (number), title (string) - * @param {Network} network A Network object, used to find and edge to - * nodes. - * @param {Object} constants An object with default values for - * example for the color + * Repaint this group + * @param {{start: number, end: number}} range + * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin + * @param {boolean} [restack=false] Force restacking of all items + * @return {boolean} Returns true if the group is resized */ - function Edge (properties, network, networkConstants) { - if (!network) { - throw "No network provided"; - } - var fields = ['edges','physics']; - var constants = util.selectiveBridgeObject(fields,networkConstants); - this.options = constants.edges; - this.physics = constants.physics; - this.options['smoothCurves'] = networkConstants['smoothCurves']; - + Group.prototype.redraw = function(range, margin, restack) { + var resized = false; - this.network = network; + this.visibleItems = this._updateVisibleItems(this.orderedItems, this.visibleItems, range); - // initialize variables - this.id = undefined; - this.fromId = undefined; - this.toId = undefined; - this.title = undefined; - this.widthSelected = this.options.width * this.options.widthSelectionMultiplier; - this.value = undefined; - this.selected = false; - this.hover = false; - this.labelDimensions = {top:0,left:0,width:0,height:0,yLine:0}; // could be cached - this.dirtyLabel = true; + // force recalculation of the height of the items when the marker height changed + // (due to the Timeline being attached to the DOM or changed from display:none to visible) + var markerHeight = this.dom.marker.clientHeight; + if (markerHeight != this.lastMarkerHeight) { + this.lastMarkerHeight = markerHeight; - this.from = null; // a node - this.to = null; // a node - this.via = null; // a temp node + util.forEach(this.items, function (item) { + item.dirty = true; + if (item.displayed) item.redraw(); + }); - this.fromBackup = null; // used to clean up after reconnect - this.toBackup = null;; // used to clean up after reconnect + restack = true; + } - // we use this to be able to reconnect the edge to a cluster if its node is put into a cluster - // by storing the original information we can revert to the original connection when the cluser is opened. - this.originalFromId = []; - this.originalToId = []; + // reposition visible items vertically + if (this.itemSet.options.stack) { // TODO: ugly way to access options... + stack.stack(this.visibleItems, margin, restack); + } + else { // no stacking + stack.nostack(this.visibleItems, margin, this.subgroups); + } - this.connected = false; + // recalculate the height of the group + var height = this._calculateHeight(margin); - this.widthFixed = false; - this.lengthFixed = false; + // calculate actual size and position + var foreground = this.dom.foreground; + this.top = foreground.offsetTop; + this.left = foreground.offsetLeft; + this.width = foreground.offsetWidth; + resized = util.updateProperty(this, 'height', height) || resized; - this.setProperties(properties); + // recalculate size of label + resized = util.updateProperty(this.props.label, 'width', this.dom.inner.clientWidth) || resized; + resized = util.updateProperty(this.props.label, 'height', this.dom.inner.clientHeight) || resized; - this.controlNodesEnabled = false; - this.controlNodes = {from:null, to:null, positions:{}}; - this.connectedNode = null; - } + // apply new height + this.dom.background.style.height = height + 'px'; + this.dom.foreground.style.height = height + 'px'; + this.dom.label.style.height = height + 'px'; - /** - * Set or overwrite properties for the edge - * @param {Object} properties an object with properties - * @param {Object} constants and object with default, global properties - */ - Edge.prototype.setProperties = function(properties) { - if (!properties) { - return; + // update vertical position of items after they are re-stacked and the height of the group is calculated + for (var i = 0, ii = this.visibleItems.length; i < ii; i++) { + var item = this.visibleItems[i]; + item.repositionY(margin); } - var fields = ['style','fontSize','fontFace','fontColor','fontFill','fontStrokeWidth','fontStrokeColor','width', - 'widthSelectionMultiplier','hoverWidth','arrowScaleFactor','dash','inheritColor','labelAlignment' - ]; - util.selectiveDeepExtend(fields, this.options, properties); - - if (properties.from !== undefined) {this.fromId = properties.from;} - if (properties.to !== undefined) {this.toId = properties.to;} - - if (properties.id !== undefined) {this.id = properties.id;} - if (properties.label !== undefined) {this.label = properties.label; this.dirtyLabel = true;} - - if (properties.title !== undefined) {this.title = properties.title;} - if (properties.value !== undefined) {this.value = properties.value;} - if (properties.length !== undefined) {this.physics.springLength = properties.length;} + return resized; + }; - if (properties.color !== undefined) { - this.options.inheritColor = false; - if (util.isString(properties.color)) { - this.options.color.color = properties.color; - this.options.color.highlight = properties.color; - } - else { - if (properties.color.color !== undefined) {this.options.color.color = properties.color.color;} - if (properties.color.highlight !== undefined) {this.options.color.highlight = properties.color.highlight;} - if (properties.color.hover !== undefined) {this.options.color.hover = properties.color.hover;} + /** + * recalculate the height of the group + * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin + * @returns {number} Returns the height + * @private + */ + Group.prototype._calculateHeight = function (margin) { + // recalculate the height of the group + var height; + var visibleItems = this.visibleItems; + //var visibleSubgroups = []; + //this.visibleSubgroups = 0; + this.resetSubgroups(); + var me = this; + if (visibleItems.length) { + var min = visibleItems[0].top; + var max = visibleItems[0].top + visibleItems[0].height; + util.forEach(visibleItems, function (item) { + min = Math.min(min, item.top); + max = Math.max(max, (item.top + item.height)); + if (item.data.subgroup !== undefined) { + me.subgroups[item.data.subgroup].height = Math.max(me.subgroups[item.data.subgroup].height,item.height); + me.subgroups[item.data.subgroup].visible = true; + //if (visibleSubgroups.indexOf(item.data.subgroup) == -1){ + // visibleSubgroups.push(item.data.subgroup); + // me.visibleSubgroups += 1; + //} + } + }); + if (min > margin.axis) { + // there is an empty gap between the lowest item and the axis + var offset = min - margin.axis; + max -= offset; + util.forEach(visibleItems, function (item) { + item.top -= offset; + }); } + height = max + margin.item.vertical / 2; } - - // A node is connected when it has a from and to node. - this.connect(); - - this.widthFixed = this.widthFixed || (properties.width !== undefined); - this.lengthFixed = this.lengthFixed || (properties.length !== undefined); - - this.widthSelected = this.options.width* this.options.widthSelectionMultiplier; - - // set draw method based on style - switch (this.options.style) { - case 'line': this.draw = this._drawLine; break; - case 'arrow': this.draw = this._drawArrow; break; - case 'arrow-center': this.draw = this._drawArrowCenter; break; - case 'dash-line': this.draw = this._drawDashLine; break; - default: this.draw = this._drawLine; break; + else { + height = margin.axis + margin.item.vertical; } - + height = Math.max(height, this.props.label.height); + + return height; }; /** - * Connect an edge to its nodes + * Show this group: attach to the DOM */ - Edge.prototype.connect = function () { - this.disconnect(); + Group.prototype.show = function() { + if (!this.dom.label.parentNode) { + this.itemSet.dom.labelSet.appendChild(this.dom.label); + } - this.from = this.network.nodes[this.fromId] || null; - this.to = this.network.nodes[this.toId] || null; - this.connected = (this.from && this.to); + if (!this.dom.foreground.parentNode) { + this.itemSet.dom.foreground.appendChild(this.dom.foreground); + } - if (this.connected) { - this.from.attachEdge(this); - this.to.attachEdge(this); + if (!this.dom.background.parentNode) { + this.itemSet.dom.background.appendChild(this.dom.background); } - else { - if (this.from) { - this.from.detachEdge(this); - } - if (this.to) { - this.to.detachEdge(this); - } + + if (!this.dom.axis.parentNode) { + this.itemSet.dom.axis.appendChild(this.dom.axis); } }; /** - * Disconnect an edge from its nodes + * Hide this group: remove from the DOM */ - Edge.prototype.disconnect = function () { - if (this.from) { - this.from.detachEdge(this); - this.from = null; + Group.prototype.hide = function() { + var label = this.dom.label; + if (label.parentNode) { + label.parentNode.removeChild(label); } - if (this.to) { - this.to.detachEdge(this); - this.to = null; + + var foreground = this.dom.foreground; + if (foreground.parentNode) { + foreground.parentNode.removeChild(foreground); } - this.connected = false; - }; + var background = this.dom.background; + if (background.parentNode) { + background.parentNode.removeChild(background); + } - /** - * get the title of this edge. - * @return {string} title The title of the edge, or undefined when no title - * has been set. - */ - Edge.prototype.getTitle = function() { - return typeof this.title === "function" ? this.title() : this.title; + var axis = this.dom.axis; + if (axis.parentNode) { + axis.parentNode.removeChild(axis); + } }; - /** - * Retrieve the value of the edge. Can be undefined - * @return {Number} value + * Add an item to the group + * @param {Item} item */ - Edge.prototype.getValue = function() { - return this.value; + Group.prototype.add = function(item) { + this.items[item.id] = item; + item.setParent(this); + + // add to + if (item.data.subgroup !== undefined) { + if (this.subgroups[item.data.subgroup] === undefined) { + this.subgroups[item.data.subgroup] = {height:0, visible: false, index:this.subgroupIndex, items: []}; + this.subgroupIndex++; + } + this.subgroups[item.data.subgroup].items.push(item); + } + this.orderSubgroups(); + + if (this.visibleItems.indexOf(item) == -1) { + var range = this.itemSet.body.range; // TODO: not nice accessing the range like this + this._checkIfVisible(item, this.visibleItems, range); + } }; - /** - * Adjust the value range of the edge. The edge will adjust it's width - * based on its value. - * @param {Number} min - * @param {Number} max - */ - Edge.prototype.setValueRange = function(min, max) { - if (!this.widthFixed && this.value !== undefined) { - var scale = (this.options.widthMax - this.options.widthMin) / (max - min); - this.options.width= (this.value - min) * scale + this.options.widthMin; - this.widthSelected = this.options.width* this.options.widthSelectionMultiplier; + Group.prototype.orderSubgroups = function() { + if (this.subgroupOrderer !== undefined) { + var sortArray = []; + if (typeof this.subgroupOrderer == 'string') { + for (var subgroup in this.subgroups) { + sortArray.push({subgroup: subgroup, sortField: this.subgroups[subgroup].items[0].data[this.subgroupOrderer]}) + } + sortArray.sort(function (a, b) { + return a.sortField - b.sortField; + }) + } + else if (typeof this.subgroupOrderer == 'function') { + for (var subgroup in this.subgroups) { + sortArray.push(this.subgroups[subgroup].items[0].data); + } + sortArray.sort(this.subgroupOrderer); + } + + if (sortArray.length > 0) { + for (var i = 0; i < sortArray.length; i++) { + this.subgroups[sortArray[i].subgroup].index = i; + } + } } }; - /** - * Redraw a edge - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - */ - Edge.prototype.draw = function(ctx) { - throw "Method draw not initialized in edge"; + Group.prototype.resetSubgroups = function() { + for (var subgroup in this.subgroups) { + if (this.subgroups.hasOwnProperty(subgroup)) { + this.subgroups[subgroup].visible = false; + } + } }; /** - * Check if this object is overlapping with the provided object - * @param {Object} obj an object with parameters left, top - * @return {boolean} True if location is located on the edge + * Remove an item from the group + * @param {Item} item */ - Edge.prototype.isOverlappingWith = function(obj) { - if (this.connected) { - var distMax = 10; - var xFrom = this.from.x; - var yFrom = this.from.y; - var xTo = this.to.x; - var yTo = this.to.y; - var xObj = obj.left; - var yObj = obj.top; + Group.prototype.remove = function(item) { + delete this.items[item.id]; + item.setParent(null); - var dist = this._getDistanceToEdge(xFrom, yFrom, xTo, yTo, xObj, yObj); + // remove from visible items + var index = this.visibleItems.indexOf(item); + if (index != -1) this.visibleItems.splice(index, 1); - return (dist < distMax); - } - else { - return false - } + // TODO: also remove from ordered items? }; - Edge.prototype._getColor = function() { - var colorObj = this.options.color; - if (this.options.inheritColor == "to") { - colorObj = { - highlight: this.to.options.color.highlight.border, - hover: this.to.options.color.hover.border, - color: this.to.options.color.border - }; - } - else if (this.options.inheritColor == "from" || this.options.inheritColor == true) { - colorObj = { - highlight: this.from.options.color.highlight.border, - hover: this.from.options.color.hover.border, - color: this.from.options.color.border - }; - } - if (this.selected == true) {return colorObj.highlight;} - else if (this.hover == true) {return colorObj.hover;} - else {return colorObj.color;} + /** + * Remove an item from the corresponding DataSet + * @param {Item} item + */ + Group.prototype.removeFromDataSet = function(item) { + this.itemSet.removeItem(item.id); }; /** - * Redraw a edge as a line - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private + * Reorder the items */ - Edge.prototype._drawLine = function(ctx) { - // set style - ctx.strokeStyle = this._getColor(); - ctx.lineWidth = this._getLineWidth(); - - if (this.from != this.to) { - // draw line - var via = this._line(ctx); + Group.prototype.order = function() { + var array = util.toArray(this.items); + var startArray = []; + var endArray = []; - // draw label - var point; - if (this.label) { - if (this.options.smoothCurves.enabled == true && via != null) { - var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); - var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); - point = {x:midpointX, y:midpointY}; - } - else { - point = this._pointOnLine(0.5); - } - this._label(ctx, this.label, point.x, point.y); - } - } - else { - var x, y; - var radius = this.physics.springLength / 4; - var node = this.from; - if (!node.width) { - node.resize(ctx); - } - if (node.width > node.height) { - x = node.x + node.width / 2; - y = node.y - radius; - } - else { - x = node.x + radius; - y = node.y - node.height / 2; + for (var i = 0; i < array.length; i++) { + if (array[i].data.end !== undefined) { + endArray.push(array[i]); } - this._circle(ctx, x, y, radius); - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); + startArray.push(array[i]); } + this.orderedItems = { + byStart: startArray, + byEnd: endArray + }; + + stack.orderByStart(this.orderedItems.byStart); + stack.orderByEnd(this.orderedItems.byEnd); }; + /** - * Get the line width of the edge. Depends on width and whether one of the - * connected nodes is selected. - * @return {Number} width + * Update the visible items + * @param {{byStart: Item[], byEnd: Item[]}} orderedItems All items ordered by start date and by end date + * @param {Item[]} visibleItems The previously visible items. + * @param {{start: number, end: number}} range Visible range + * @return {Item[]} visibleItems The new visible items. * @private */ - Edge.prototype._getLineWidth = function() { - if (this.selected == true) { - return Math.max(Math.min(this.widthSelected, this.options.widthMax), 0.3*this.networkScaleInv); + Group.prototype._updateVisibleItems = function(orderedItems, oldVisibleItems, range) { + var visibleItems = []; + var visibleItemsLookup = {}; // we keep this to quickly look up if an item already exists in the list without using indexOf on visibleItems + var interval = (range.end - range.start) / 4; + var lowerBound = range.start - interval; + var upperBound = range.end + interval; + var item, i; + + // this function is used to do the binary search. + var searchFunction = function (value) { + if (value < lowerBound) {return -1;} + else if (value <= upperBound) {return 0;} + else {return 1;} } - else { - if (this.hover == true) { - return Math.max(Math.min(this.options.hoverWidth, this.options.widthMax), 0.3*this.networkScaleInv); + + // first check if the items that were in view previously are still in view. + // IMPORTANT: this handles the case for the items with startdate before the window and enddate after the window! + // also cleans up invisible items. + if (oldVisibleItems.length > 0) { + for (i = 0; i < oldVisibleItems.length; i++) { + this._checkIfVisibleWithReference(oldVisibleItems[i], visibleItems, visibleItemsLookup, range); } - else { - return Math.max(this.options.width, 0.3*this.networkScaleInv); + } + + // we do a binary search for the items that have only start values. + var initialPosByStart = util.binarySearchCustom(orderedItems.byStart, searchFunction, 'data','start'); + + // trace the visible items from the inital start pos both ways until an invisible item is found, we only look at the start values. + this._traceVisible(initialPosByStart, orderedItems.byStart, visibleItems, visibleItemsLookup, function (item) { + return (item.data.start < lowerBound || item.data.start > upperBound); + }); + + // if the window has changed programmatically without overlapping the old window, the ranged items with start < lowerBound and end > upperbound are not shown. + // We therefore have to brute force check all items in the byEnd list + if (this.checkRangedItems == true) { + this.checkRangedItems = false; + for (i = 0; i < orderedItems.byEnd.length; i++) { + this._checkIfVisibleWithReference(orderedItems.byEnd[i], visibleItems, visibleItemsLookup, range); } } - }; + else { + // we do a binary search for the items that have defined end times. + var initialPosByEnd = util.binarySearchCustom(orderedItems.byEnd, searchFunction, 'data','end'); - Edge.prototype._getViaCoordinates = function () { - if (this.options.smoothCurves.dynamic == true && this.options.smoothCurves.enabled == true ) { - return this.via; + // trace the visible items from the inital start pos both ways until an invisible item is found, we only look at the end values. + this._traceVisible(initialPosByEnd, orderedItems.byEnd, visibleItems, visibleItemsLookup, function (item) { + return (item.data.end < lowerBound || item.data.end > upperBound); + }); } - else if (this.options.smoothCurves.enabled == false) { - return {x:0,y:0}; + + + // finally, we reposition all the visible items. + for (i = 0; i < visibleItems.length; i++) { + item = visibleItems[i]; + if (!item.displayed) item.show(); + // reposition item horizontally + item.repositionX(); } - else { - var xVia = null; - var yVia = null; - var factor = this.options.smoothCurves.roundness; - var type = this.options.smoothCurves.type; - var dx = Math.abs(this.from.x - this.to.x); - var dy = Math.abs(this.from.y - this.to.y); - if (type == 'discrete' || type == 'diagonalCross') { - if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { - if (this.from.y > this.to.y) { - if (this.from.x < this.to.x) { - xVia = this.from.x + factor * dy; - yVia = this.from.y - factor * dy; - } - else if (this.from.x > this.to.x) { - xVia = this.from.x - factor * dy; - yVia = this.from.y - factor * dy; - } - } - else if (this.from.y < this.to.y) { - if (this.from.x < this.to.x) { - xVia = this.from.x + factor * dy; - yVia = this.from.y + factor * dy; - } - else if (this.from.x > this.to.x) { - xVia = this.from.x - factor * dy; - yVia = this.from.y + factor * dy; - } - } - if (type == "discrete") { - xVia = dx < factor * dy ? this.from.x : xVia; - } - } - else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { - if (this.from.y > this.to.y) { - if (this.from.x < this.to.x) { - xVia = this.from.x + factor * dx; - yVia = this.from.y - factor * dx; - } - else if (this.from.x > this.to.x) { - xVia = this.from.x - factor * dx; - yVia = this.from.y - factor * dx; - } - } - else if (this.from.y < this.to.y) { - if (this.from.x < this.to.x) { - xVia = this.from.x + factor * dx; - yVia = this.from.y + factor * dx; - } - else if (this.from.x > this.to.x) { - xVia = this.from.x - factor * dx; - yVia = this.from.y + factor * dx; - } - } - if (type == "discrete") { - yVia = dy < factor * dx ? this.from.y : yVia; - } - } - } - else if (type == "straightCross") { - if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { // up - down - xVia = this.from.x; - if (this.from.y < this.to.y) { - yVia = this.to.y - (1 - factor) * dy; - } - else { - yVia = this.to.y + (1 - factor) * dy; - } - } - else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { // left - right - if (this.from.x < this.to.x) { - xVia = this.to.x - (1 - factor) * dx; - } - else { - xVia = this.to.x + (1 - factor) * dx; - } - yVia = this.from.y; - } - } - else if (type == 'horizontal') { - if (this.from.x < this.to.x) { - xVia = this.to.x - (1 - factor) * dx; + // debug + //console.log("new line") + //if (this.groupId == null) { + // for (i = 0; i < orderedItems.byStart.length; i++) { + // item = orderedItems.byStart[i].data; + // console.log('start',i,initialPosByStart, item.start.valueOf(), item.content, item.start >= lowerBound && item.start <= upperBound,i == initialPosByStart ? "<------------------- HEREEEE" : "") + // } + // for (i = 0; i < orderedItems.byEnd.length; i++) { + // item = orderedItems.byEnd[i].data; + // console.log('rangeEnd',i,initialPosByEnd, item.end.valueOf(), item.content, item.end >= range.start && item.end <= range.end,i == initialPosByEnd ? "<------------------- HEREEEE" : "") + // } + //} + + return visibleItems; + }; + + Group.prototype._traceVisible = function (initialPos, items, visibleItems, visibleItemsLookup, breakCondition) { + var item; + var i; + + if (initialPos != -1) { + for (i = initialPos; i >= 0; i--) { + item = items[i]; + if (breakCondition(item)) { + break; } else { - xVia = this.to.x + (1 - factor) * dx; + if (visibleItemsLookup[item.id] === undefined) { + visibleItemsLookup[item.id] = true; + visibleItems.push(item); + } } - yVia = this.from.y; } - else if (type == 'vertical') { - xVia = this.from.x; - if (this.from.y < this.to.y) { - yVia = this.to.y - (1 - factor) * dy; + + for (i = initialPos + 1; i < items.length; i++) { + item = items[i]; + if (breakCondition(item)) { + break; } else { - yVia = this.to.y + (1 - factor) * dy; - } - } - else { // continuous - if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { - if (this.from.y > this.to.y) { - if (this.from.x < this.to.x) { - // console.log(1) - xVia = this.from.x + factor * dy; - yVia = this.from.y - factor * dy; - xVia = this.to.x < xVia ? this.to.x : xVia; - } - else if (this.from.x > this.to.x) { - // console.log(2) - xVia = this.from.x - factor * dy; - yVia = this.from.y - factor * dy; - xVia = this.to.x > xVia ? this.to.x : xVia; - } - } - else if (this.from.y < this.to.y) { - if (this.from.x < this.to.x) { - // console.log(3) - xVia = this.from.x + factor * dy; - yVia = this.from.y + factor * dy; - xVia = this.to.x < xVia ? this.to.x : xVia; - } - else if (this.from.x > this.to.x) { - // console.log(4, this.from.x, this.to.x) - xVia = this.from.x - factor * dy; - yVia = this.from.y + factor * dy; - xVia = this.to.x > xVia ? this.to.x : xVia; - } - } - } - else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { - if (this.from.y > this.to.y) { - if (this.from.x < this.to.x) { - // console.log(5) - xVia = this.from.x + factor * dx; - yVia = this.from.y - factor * dx; - yVia = this.to.y > yVia ? this.to.y : yVia; - } - else if (this.from.x > this.to.x) { - // console.log(6) - xVia = this.from.x - factor * dx; - yVia = this.from.y - factor * dx; - yVia = this.to.y > yVia ? this.to.y : yVia; - } - } - else if (this.from.y < this.to.y) { - if (this.from.x < this.to.x) { - // console.log(7) - xVia = this.from.x + factor * dx; - yVia = this.from.y + factor * dx; - yVia = this.to.y < yVia ? this.to.y : yVia; - } - else if (this.from.x > this.to.x) { - // console.log(8) - xVia = this.from.x - factor * dx; - yVia = this.from.y + factor * dx; - yVia = this.to.y < yVia ? this.to.y : yVia; - } + if (visibleItemsLookup[item.id] === undefined) { + visibleItemsLookup[item.id] = true; + visibleItems.push(item); } } } - - - return {x: xVia, y: yVia}; } - }; + } + /** - * Draw a line between two nodes - * @param {CanvasRenderingContext2D} ctx + * this function is very similar to the _checkIfInvisible() but it does not + * return booleans, hides the item if it should not be seen and always adds to + * the visibleItems. + * this one is for brute forcing and hiding. + * + * @param {Item} item + * @param {Array} visibleItems + * @param {{start:number, end:number}} range * @private */ - Edge.prototype._line = function (ctx) { - // draw a straight line - ctx.beginPath(); - ctx.moveTo(this.from.x, this.from.y); - if (this.options.smoothCurves.enabled == true) { - if (this.options.smoothCurves.dynamic == false) { - var via = this._getViaCoordinates(); - if (via.x == null) { - ctx.lineTo(this.to.x, this.to.y); - ctx.stroke(); - return null; - } - else { - // this.via.x = via.x; - // this.via.y = via.y; - ctx.quadraticCurveTo(via.x,via.y,this.to.x, this.to.y); - ctx.stroke(); - return via; - } + Group.prototype._checkIfVisible = function(item, visibleItems, range) { + if (item.isVisible(range)) { + if (!item.displayed) item.show(); + // reposition item horizontally + item.repositionX(); + visibleItems.push(item); } else { - ctx.quadraticCurveTo(this.via.x,this.via.y,this.to.x, this.to.y); - ctx.stroke(); - return this.via; + if (item.displayed) item.hide(); } - } - else { - ctx.lineTo(this.to.x, this.to.y); - ctx.stroke(); - return null; - } }; + /** - * Draw a line from a node to itself, a circle - * @param {CanvasRenderingContext2D} ctx - * @param {Number} x - * @param {Number} y - * @param {Number} radius + * this function is very similar to the _checkIfInvisible() but it does not + * return booleans, hides the item if it should not be seen and always adds to + * the visibleItems. + * this one is for brute forcing and hiding. + * + * @param {Item} item + * @param {Array} visibleItems + * @param {{start:number, end:number}} range * @private */ - Edge.prototype._circle = function (ctx, x, y, radius) { - // draw a circle - ctx.beginPath(); - ctx.arc(x, y, radius, 0, 2 * Math.PI, false); - ctx.stroke(); + Group.prototype._checkIfVisibleWithReference = function(item, visibleItems, visibleItemsLookup, range) { + if (item.isVisible(range)) { + if (visibleItemsLookup[item.id] === undefined) { + visibleItemsLookup[item.id] = true; + visibleItems.push(item); + } + } + else { + if (item.displayed) item.hide(); + } }; - /** - * Draw label with white background and with the middle at (x, y) - * @param {CanvasRenderingContext2D} ctx - * @param {String} text - * @param {Number} x - * @param {Number} y - * @private - */ - Edge.prototype._label = function (ctx, text, x, y) { - if (text) { - ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") + - this.options.fontSize + "px " + this.options.fontFace; - var yLine; - if (this.dirtyLabel == true) { - var lines = String(text).split('\n'); - var lineCount = lines.length; - var fontSize = Number(this.options.fontSize); - yLine = y + (1 - lineCount) / 2 * fontSize; - var width = ctx.measureText(lines[0]).width; - for (var i = 1; i < lineCount; i++) { - var lineWidth = ctx.measureText(lines[i]).width; - width = lineWidth > width ? lineWidth : width; - } - var height = this.options.fontSize * lineCount; - var left = x - width / 2; - var top = y - height / 2; + module.exports = Group; - // cache - this.labelDimensions = {top:top,left:left,width:width,height:height,yLine:yLine}; - } - var yLine = this.labelDimensions.yLine; - - ctx.save(); - - if (this.options.labelAlignment != "horizontal"){ - ctx.translate(x, yLine); - this._rotateForLabelAlignment(ctx); - x = 0; - yLine = 0; - } +/***/ }, +/* 28 */ +/***/ function(module, exports, __webpack_require__) { - - this._drawLabelRect(ctx); - this._drawLabelText(ctx,x,yLine, lines, lineCount, fontSize); - - ctx.restore(); - } + // Utility functions for ordering and stacking of items + var EPSILON = 0.001; // used when checking collisions, to prevent round-off errors + + /** + * Order items by their start data + * @param {Item[]} items + */ + exports.orderByStart = function(items) { + items.sort(function (a, b) { + return a.data.start - b.data.start; + }); }; /** - * Rotates the canvas so the text is most readable - * @param {CanvasRenderingContext2D} ctx - * @private + * Order items by their end date. If they have no end date, their start date + * is used. + * @param {Item[]} items */ - Edge.prototype._rotateForLabelAlignment = function(ctx) { - var dy = this.from.y - this.to.y; - var dx = this.from.x - this.to.x; - var angleInDegrees = Math.atan2(dy, dx); + exports.orderByEnd = function(items) { + items.sort(function (a, b) { + var aTime = ('end' in a.data) ? a.data.end : a.data.start, + bTime = ('end' in b.data) ? b.data.end : b.data.start; - // rotate so label it is readable - if((angleInDegrees < -1 && dx < 0) || (angleInDegrees > 0 && dx < 0)){ - angleInDegrees = angleInDegrees + Math.PI; - } - - ctx.rotate(angleInDegrees); + return aTime - bTime; + }); }; /** - * Draws the label rectangle - * @param {CanvasRenderingContext2D} ctx - * @param {String} labelAlignment - * @private + * Adjust vertical positions of the items such that they don't overlap each + * other. + * @param {Item[]} items + * All visible items + * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin + * Margins between items and between items and the axis. + * @param {boolean} [force=false] + * If true, all items will be repositioned. If false (default), only + * items having a top===null will be re-stacked */ - Edge.prototype._drawLabelRect = function(ctx) { - if (this.options.fontFill !== undefined && this.options.fontFill !== null && this.options.fontFill !== "none") { - ctx.fillStyle = this.options.fontFill; - - var lineMargin = 2; + exports.stack = function(items, margin, force) { + var i, iMax; - if (this.options.labelAlignment == 'line-center') { - ctx.fillRect(-this.labelDimensions.width * 0.5, -this.labelDimensions.height * 0.5, this.labelDimensions.width, this.labelDimensions.height); - } - else if (this.options.labelAlignment == 'line-above') { - ctx.fillRect(-this.labelDimensions.width * 0.5, -(this.labelDimensions.height + lineMargin), this.labelDimensions.width, this.labelDimensions.height); - } - else if (this.options.labelAlignment == 'line-below') { - ctx.fillRect(-this.labelDimensions.width * 0.5, lineMargin, this.labelDimensions.width, this.labelDimensions.height); + if (force) { + // reset top position of all items + for (i = 0, iMax = items.length; i < iMax; i++) { + items[i].top = null; } - else { - ctx.fillRect(this.labelDimensions.left, this.labelDimensions.top, this.labelDimensions.width, this.labelDimensions.height); + } + + // calculate new, non-overlapping positions + for (i = 0, iMax = items.length; i < iMax; i++) { + var item = items[i]; + if (item.stack && item.top === null) { + // initialize top position + item.top = margin.axis; + + do { + // TODO: optimize checking for overlap. when there is a gap without items, + // you only need to check for items from the next item on, not from zero + var collidingItem = null; + for (var j = 0, jj = items.length; j < jj; j++) { + var other = items[j]; + if (other.top !== null && other !== item && other.stack && exports.collision(item, other, margin.item)) { + collidingItem = other; + break; + } + } + + if (collidingItem != null) { + // There is a collision. Reposition the items above the colliding element + item.top = collidingItem.top + collidingItem.height + margin.item.vertical; + } + } while (collidingItem); } } }; + /** - * Draws the label text - * @param {CanvasRenderingContext2D} ctx - * @param {Number} x - * @param {Number} yLine - * @param {Array} lines - * @param {Number} lineCount - * @param {Number} fontSize - * @private + * Adjust vertical positions of the items without stacking them + * @param {Item[]} items + * All visible items + * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin + * Margins between items and between items and the axis. */ - Edge.prototype._drawLabelText = function(ctx, x, yLine, lines, lineCount, fontSize) { - // draw text - ctx.fillStyle = this.options.fontColor || "black"; - ctx.textAlign = "center"; + exports.nostack = function(items, margin, subgroups) { + var i, iMax, newTop; - // check for label alignment - if (this.options.labelAlignment != 'horizontal') { - var lineMargin = 2; - if (this.options.labelAlignment == 'line-above') { - ctx.textBaseline = "alphabetic"; - yLine -= 2 * lineMargin; // distance from edge, required because we use alphabetic. Alphabetic has less difference between browsers - } - else if (this.options.labelAlignment == 'line-below') { - ctx.textBaseline = "hanging"; - yLine += 2 * lineMargin;// distance from edge, required because we use hanging. Hanging has less difference between browsers + // reset top position of all items + for (i = 0, iMax = items.length; i < iMax; i++) { + if (items[i].data.subgroup !== undefined) { + newTop = margin.axis; + for (var subgroup in subgroups) { + if (subgroups.hasOwnProperty(subgroup)) { + if (subgroups[subgroup].visible == true && subgroups[subgroup].index < subgroups[items[i].data.subgroup].index) { + newTop += subgroups[subgroup].height + margin.item.vertical; + } + } + } + items[i].top = newTop; } else { - ctx.textBaseline = "middle"; + items[i].top = margin.axis; } } - else { - ctx.textBaseline = "middle"; - } - - // check for strokeWidth - if (this.options.fontStrokeWidth > 0){ - ctx.lineWidth = this.options.fontStrokeWidth; - ctx.strokeStyle = this.options.fontStrokeColor; - ctx.lineJoin = 'round'; - } - for (var i = 0; i < lineCount; i++) { - if(this.options.fontStrokeWidth > 0){ - ctx.strokeText(lines[i], x, yLine); - } - ctx.fillText(lines[i], x, yLine); - yLine += fontSize; - } }; /** - * Redraw a edge as a dashed line - * Draw this edge in the given canvas - * @author David Jordan - * @date 2012-08-08 - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private + * Test if the two provided items collide + * The items must have parameters left, width, top, and height. + * @param {Item} a The first item + * @param {Item} b The second item + * @param {{horizontal: number, vertical: number}} margin + * An object containing a horizontal and vertical + * minimum required margin. + * @return {boolean} true if a and b collide, else false */ - Edge.prototype._drawDashLine = function(ctx) { - // set style - ctx.strokeStyle = this._getColor(); - ctx.lineWidth = this._getLineWidth(); + exports.collision = function(a, b, margin) { + return ((a.left - margin.horizontal + EPSILON) < (b.left + b.width) && + (a.left + a.width + margin.horizontal - EPSILON) > b.left && + (a.top - margin.vertical + EPSILON) < (b.top + b.height) && + (a.top + a.height + margin.vertical - EPSILON) > b.top); + }; - var via = null; - // only firefox and chrome support this method, else we use the legacy one. - if (ctx.setLineDash !== undefined) { - ctx.save(); - // configure the dash pattern - var pattern = [0]; - if (this.options.dash.length !== undefined && this.options.dash.gap !== undefined) { - pattern = [this.options.dash.length,this.options.dash.gap]; - } - else { - pattern = [5,5]; - } - // set dash settings for chrome or firefox - ctx.setLineDash(pattern); - ctx.lineDashOffset = 0; +/***/ }, +/* 29 */ +/***/ function(module, exports, __webpack_require__) { - // draw the line - via = this._line(ctx); + var Hammer = __webpack_require__(19); + var Item = __webpack_require__(30); - // restore the dash settings. - ctx.setLineDash([0]); - ctx.lineDashOffset = 0; - ctx.restore(); - } - else { // unsupporting smooth lines - // draw dashed line - ctx.beginPath(); - ctx.lineCap = 'round'; - if (this.options.dash.altLength !== undefined) //If an alt dash value has been set add to the array this value - { - ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, - [this.options.dash.length,this.options.dash.gap,this.options.dash.altLength,this.options.dash.gap]); - } - else if (this.options.dash.length !== undefined && this.options.dash.gap !== undefined) //If a dash and gap value has been set add to the array this value - { - ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, - [this.options.dash.length,this.options.dash.gap]); - } - else //If all else fails draw a line - { - ctx.moveTo(this.from.x, this.from.y); - ctx.lineTo(this.to.x, this.to.y); + /** + * @constructor RangeItem + * @extends Item + * @param {Object} data Object containing parameters start, end + * content, className. + * @param {{toScreen: function, toTime: function}} conversion + * Conversion functions from time to screen and vice versa + * @param {Object} [options] Configuration options + * // TODO: describe options + */ + function RangeItem (data, conversion, options) { + this.props = { + content: { + width: 0 } - ctx.stroke(); - } + }; + this.overflow = false; // if contents can overflow (css styling), this flag is set to true - // draw label - if (this.label) { - var point; - if (this.options.smoothCurves.enabled == true && via != null) { - var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); - var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); - point = {x:midpointX, y:midpointY}; + // validate data + if (data) { + if (data.start == undefined) { + throw new Error('Property "start" missing in item ' + data.id); } - else { - point = this._pointOnLine(0.5); + if (data.end == undefined) { + throw new Error('Property "end" missing in item ' + data.id); } - this._label(ctx, this.label, point.x, point.y); } - }; - /** - * Get a point on a line - * @param {Number} percentage. Value between 0 (line start) and 1 (line end) - * @return {Object} point - * @private - */ - Edge.prototype._pointOnLine = function (percentage) { - return { - x: (1 - percentage) * this.from.x + percentage * this.to.x, - y: (1 - percentage) * this.from.y + percentage * this.to.y - } - }; + Item.call(this, data, conversion, options); + } + + RangeItem.prototype = new Item (null, null, null); + + RangeItem.prototype.baseClassName = 'item range'; /** - * Get a point on a circle - * @param {Number} x - * @param {Number} y - * @param {Number} radius - * @param {Number} percentage. Value between 0 (line start) and 1 (line end) - * @return {Object} point - * @private + * Check whether this item is visible inside given range + * @returns {{start: Number, end: Number}} range with a timestamp for start and end + * @returns {boolean} True if visible */ - Edge.prototype._pointOnCircle = function (x, y, radius, percentage) { - var angle = (percentage - 3/8) * 2 * Math.PI; - return { - x: x + radius * Math.cos(angle), - y: y - radius * Math.sin(angle) - } + RangeItem.prototype.isVisible = function(range) { + // determine visibility + return (this.data.start < range.end) && (this.data.end > range.start); }; /** - * Redraw a edge as a line with an arrow halfway the line - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private + * Repaint the item */ - Edge.prototype._drawArrowCenter = function(ctx) { - var point; - // set style - ctx.strokeStyle = this._getColor(); - ctx.fillStyle = ctx.strokeStyle; - ctx.lineWidth = this._getLineWidth(); + RangeItem.prototype.redraw = function() { + var dom = this.dom; + if (!dom) { + // create DOM + this.dom = {}; + dom = this.dom; - if (this.from != this.to) { - // draw line - var via = this._line(ctx); + // background box + dom.box = document.createElement('div'); + // className is updated in redraw() - var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; - // draw an arrow halfway the line - if (this.options.smoothCurves.enabled == true && via != null) { - var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); - var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); - point = {x:midpointX, y:midpointY}; - } - else { - point = this._pointOnLine(0.5); - } + // contents box + dom.content = document.createElement('div'); + dom.content.className = 'content'; + dom.box.appendChild(dom.content); - ctx.arrow(point.x, point.y, angle, length); - ctx.fill(); - ctx.stroke(); + // attach this item as attribute + dom.box['timeline-item'] = this; - // draw label - if (this.label) { - this._label(ctx, this.label, point.x, point.y); - } + this.dirty = true; } - else { - // draw circle - var x, y; - var radius = 0.25 * Math.max(100,this.physics.springLength); - var node = this.from; - if (!node.width) { - node.resize(ctx); - } - if (node.width > node.height) { - x = node.x + node.width * 0.5; - y = node.y - radius; - } - else { - x = node.x + radius; - y = node.y - node.height * 0.5; - } - this._circle(ctx, x, y, radius); - - // draw all arrows - var angle = 0.2 * Math.PI; - var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; - point = this._pointOnCircle(x, y, radius, 0.5); - ctx.arrow(point.x, point.y, angle, length); - ctx.fill(); - ctx.stroke(); - // draw label - if (this.label) { - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); + // append DOM to parent DOM + if (!this.parent) { + throw new Error('Cannot redraw item: no parent attached'); + } + if (!dom.box.parentNode) { + var foreground = this.parent.dom.foreground; + if (!foreground) { + throw new Error('Cannot redraw item: parent has no foreground container element'); } + foreground.appendChild(dom.box); } - }; + this.displayed = true; - Edge.prototype._pointOnBezier = function(t) { - var via = this._getViaCoordinates(); + // Update DOM when item is marked dirty. An item is marked dirty when: + // - the item is not yet rendered + // - the item's data is changed + // - the item is selected/deselected + if (this.dirty) { + this._updateContents(this.dom.content); + this._updateTitle(this.dom.box); + this._updateDataAttributes(this.dom.box); + this._updateStyle(this.dom.box); - var x = Math.pow(1-t,2)*this.from.x + (2*t*(1 - t))*via.x + Math.pow(t,2)*this.to.x; - var y = Math.pow(1-t,2)*this.from.y + (2*t*(1 - t))*via.y + Math.pow(t,2)*this.to.y; + // update class + var className = (this.data.className ? (' ' + this.data.className) : '') + + (this.selected ? ' selected' : ''); + dom.box.className = this.baseClassName + className; - return {x:x,y:y}; - } + // determine from css whether this box has overflow + this.overflow = window.getComputedStyle(dom.content).overflow !== 'hidden'; + + // recalculate size + // turn off max-width to be able to calculate the real width + // this causes an extra browser repaint/reflow, but so be it + this.dom.content.style.maxWidth = 'none'; + this.props.content.width = this.dom.content.offsetWidth; + this.height = this.dom.box.offsetHeight; + this.dom.content.style.maxWidth = ''; + + this.dirty = false; + } + + this._repaintDeleteButton(dom.box); + this._repaintDragLeft(); + this._repaintDragRight(); + }; /** - * This function uses binary search to look for the point where the bezier curve crosses the border of the node. - * - * @param from - * @param ctx - * @returns {*} - * @private + * Show the item in the DOM (when not already visible). The items DOM will + * be created when needed. */ - Edge.prototype._findBorderPosition = function(from,ctx) { - var maxIterations = 10; - var iteration = 0; - var low = 0; - var high = 1; - var pos,angle,distanceToBorder, distanceToNodes, difference; - var threshold = 0.2; - var node = this.to; - if (from == true) { - node = this.from; + RangeItem.prototype.show = function() { + if (!this.displayed) { + this.redraw(); } + }; - while (low <= high && iteration < maxIterations) { - var middle = (low + high) * 0.5; + /** + * Hide the item from the DOM (when visible) + * @return {Boolean} changed + */ + RangeItem.prototype.hide = function() { + if (this.displayed) { + var box = this.dom.box; - pos = this._pointOnBezier(middle); - angle = Math.atan2((node.y - pos.y), (node.x - pos.x)); - distanceToBorder = node.distanceToBorder(ctx,angle); - distanceToNodes = Math.sqrt(Math.pow(pos.x-node.x,2) + Math.pow(pos.y-node.y,2)); - difference = distanceToBorder - distanceToNodes; - if (Math.abs(difference) < threshold) { - break; // found - } - else if (difference < 0) { // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node. - if (from == false) { - low = middle; - } - else { - high = middle; - } - } - else { - if (from == false) { - high = middle; - } - else { - low = middle; - } + if (box.parentNode) { + box.parentNode.removeChild(box); } - iteration++; - } - pos.t = middle; + this.top = null; + this.left = null; - return pos; + this.displayed = false; + } }; /** - * Redraw a edge as a line with an arrow - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private + * Reposition the item horizontally + * @Override */ - Edge.prototype._drawArrow = function(ctx) { - // set style - ctx.strokeStyle = this._getColor(); - ctx.fillStyle = ctx.strokeStyle; - ctx.lineWidth = this._getLineWidth(); + RangeItem.prototype.repositionX = function() { + var parentWidth = this.parent.width; + var start = this.conversion.toScreen(this.data.start); + var end = this.conversion.toScreen(this.data.end); + var contentLeft; + var contentWidth; - // set vars - var angle, length, arrowPos; + // limit the width of the this, as browsers cannot draw very wide divs + if (start < -parentWidth) { + start = -parentWidth; + } + if (end > 2 * parentWidth) { + end = 2 * parentWidth; + } + var boxWidth = Math.max(end - start, 1); - // if not connected to itself - if (this.from != this.to) { - // draw line - this._line(ctx); + if (this.overflow) { + this.left = start; + this.width = boxWidth + this.props.content.width; + contentWidth = this.props.content.width; - // draw arrow head - if (this.options.smoothCurves.enabled == true) { - var via = this._getViaCoordinates(); - arrowPos = this._findBorderPosition(false, ctx); - var guidePos = this._pointOnBezier(Math.max(0.0, arrowPos.t - 0.1)) - angle = Math.atan2((arrowPos.y - guidePos.y), (arrowPos.x - guidePos.x)); - } - else { - angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var dx = (this.to.x - this.from.x); - var dy = (this.to.y - this.from.y); - var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); - var toBorderDist = this.to.distanceToBorder(ctx, angle); - var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; + // Note: The calculation of width is an optimistic calculation, giving + // a width which will not change when moving the Timeline + // So no re-stacking needed, which is nicer for the eye; + } + else { + this.left = start; + this.width = boxWidth; + contentWidth = Math.min(end - start - 2 * this.options.padding, this.props.content.width); + } - arrowPos = {}; - arrowPos.x = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x; - arrowPos.y = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y; - } + this.dom.box.style.left = this.left + 'px'; + this.dom.box.style.width = boxWidth + 'px'; - // draw arrow at the end of the line - length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; - ctx.arrow(arrowPos.x,arrowPos.y, angle, length); - ctx.fill(); - ctx.stroke(); + switch (this.options.align) { + case 'left': + this.dom.content.style.left = '0'; + break; - // draw label - if (this.label) { - var point; - if (this.options.smoothCurves.enabled == true && via != null) { - point = this._pointOnBezier(0.5); + case 'right': + this.dom.content.style.left = Math.max((boxWidth - contentWidth - 2 * this.options.padding), 0) + 'px'; + break; + + case 'center': + this.dom.content.style.left = Math.max((boxWidth - contentWidth - 2 * this.options.padding) / 2, 0) + 'px'; + break; + + default: // 'auto' + // when range exceeds left of the window, position the contents at the left of the visible area + if (this.overflow) { + if (end > 0) { + contentLeft = Math.max(-start, 0); + } + else { + contentLeft = -contentWidth; // ensure it's not visible anymore + } } else { - point = this._pointOnLine(0.5); + if (start < 0) { + contentLeft = Math.min(-start, + (end - start - contentWidth - 2 * this.options.padding)); + // TODO: remove the need for options.padding. it's terrible. + } + else { + contentLeft = 0; + } } - this._label(ctx, this.label, point.x, point.y); - } - } - else { - // draw circle - var node = this.from; - var x, y, arrow; - var radius = 0.25 * Math.max(100,this.physics.springLength); - if (!node.width) { - node.resize(ctx); - } - if (node.width > node.height) { - x = node.x + node.width * 0.5; - y = node.y - radius; - arrow = { - x: x, - y: node.y, - angle: 0.9 * Math.PI - }; - } - else { - x = node.x + radius; - y = node.y - node.height * 0.5; - arrow = { - x: node.x, - y: y, - angle: 0.6 * Math.PI - }; - } - ctx.beginPath(); - // TODO: similarly, for a line without arrows, draw to the border of the nodes instead of the center - ctx.arc(x, y, radius, 0, 2 * Math.PI, false); - ctx.stroke(); - - // draw all arrows - var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; - ctx.arrow(arrow.x, arrow.y, arrow.angle, length); - ctx.fill(); - ctx.stroke(); - - // draw label - if (this.label) { - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); - } + this.dom.content.style.left = contentLeft + 'px'; } }; /** - * Calculate the distance between a point (x3,y3) and a line segment from - * (x1,y1) to (x2,y2). - * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment - * @param {number} x1 - * @param {number} y1 - * @param {number} x2 - * @param {number} y2 - * @param {number} x3 - * @param {number} y3 - * @private + * Reposition the item vertically + * @Override */ - Edge.prototype._getDistanceToEdge = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point - var returnValue = 0; - if (this.from != this.to) { - if (this.options.smoothCurves.enabled == true) { - var xVia, yVia; - if (this.options.smoothCurves.enabled == true && this.options.smoothCurves.dynamic == true) { - xVia = this.via.x; - yVia = this.via.y; - } - else { - var via = this._getViaCoordinates(); - xVia = via.x; - yVia = via.y; - } - var minDistance = 1e9; - var distance; - var i,t,x,y, lastX, lastY; - for (i = 0; i < 10; i++) { - t = 0.1*i; - x = Math.pow(1-t,2)*x1 + (2*t*(1 - t))*xVia + Math.pow(t,2)*x2; - y = Math.pow(1-t,2)*y1 + (2*t*(1 - t))*yVia + Math.pow(t,2)*y2; - if (i > 0) { - distance = this._getDistanceToLine(lastX,lastY,x,y, x3,y3); - minDistance = distance < minDistance ? distance : minDistance; - } - lastX = x; lastY = y; - } - returnValue = minDistance; - } - else { - returnValue = this._getDistanceToLine(x1,y1,x2,y2,x3,y3); - } + RangeItem.prototype.repositionY = function() { + var orientation = this.options.orientation, + box = this.dom.box; + + if (orientation == 'top') { + box.style.top = this.top + 'px'; } else { - var x, y, dx, dy; - var radius = 0.25 * this.physics.springLength; - var node = this.from; - if (node.width > node.height) { - x = node.x + 0.5 * node.width; - y = node.y - radius; - } - else { - x = node.x + radius; - y = node.y - 0.5 * node.height; - } - dx = x - x3; - dy = y - y3; - returnValue = Math.abs(Math.sqrt(dx*dx + dy*dy) - radius); + box.style.top = (this.parent.height - this.top - this.height) + 'px'; } + }; - if (this.labelDimensions.left < x3 && - this.labelDimensions.left + this.labelDimensions.width > x3 && - this.labelDimensions.top < y3 && - this.labelDimensions.top + this.labelDimensions.height > y3) { - return 0; + /** + * Repaint a drag area on the left side of the range when the range is selected + * @protected + */ + RangeItem.prototype._repaintDragLeft = function () { + if (this.selected && this.options.editable.updateTime && !this.dom.dragLeft) { + // create and show drag area + var dragLeft = document.createElement('div'); + dragLeft.className = 'drag-left'; + dragLeft.dragLeftItem = this; + + // TODO: this should be redundant? + Hammer(dragLeft, { + preventDefault: true + }).on('drag', function () { + //console.log('drag left') + }); + + this.dom.box.appendChild(dragLeft); + this.dom.dragLeft = dragLeft; } - else { - return returnValue; + else if (!this.selected && this.dom.dragLeft) { + // delete drag area + if (this.dom.dragLeft.parentNode) { + this.dom.dragLeft.parentNode.removeChild(this.dom.dragLeft); + } + this.dom.dragLeft = null; } }; - Edge.prototype._getDistanceToLine = function(x1,y1,x2,y2,x3,y3) { - var px = x2-x1, - py = y2-y1, - something = px*px + py*py, - u = ((x3 - x1) * px + (y3 - y1) * py) / something; + /** + * Repaint a drag area on the right side of the range when the range is selected + * @protected + */ + RangeItem.prototype._repaintDragRight = function () { + if (this.selected && this.options.editable.updateTime && !this.dom.dragRight) { + // create and show drag area + var dragRight = document.createElement('div'); + dragRight.className = 'drag-right'; + dragRight.dragRightItem = this; - if (u > 1) { - u = 1; + // TODO: this should be redundant? + Hammer(dragRight, { + preventDefault: true + }).on('drag', function () { + //console.log('drag right') + }); + + this.dom.box.appendChild(dragRight); + this.dom.dragRight = dragRight; } - else if (u < 0) { - u = 0; + else if (!this.selected && this.dom.dragRight) { + // delete drag area + if (this.dom.dragRight.parentNode) { + this.dom.dragRight.parentNode.removeChild(this.dom.dragRight); + } + this.dom.dragRight = null; } + }; - var x = x1 + u * px, - y = y1 + u * py, - dx = x - x3, - dy = y - y3; + module.exports = RangeItem; - //# Note: If the actual distance does not matter, - //# if you only want to compare what this function - //# returns to other results of this function, you - //# can just return the squared distance instead - //# (i.e. remove the sqrt) to gain a little performance - return Math.sqrt(dx*dx + dy*dy); - }; +/***/ }, +/* 30 */ +/***/ function(module, exports, __webpack_require__) { + + var Hammer = __webpack_require__(19); + var util = __webpack_require__(1); /** - * This allows the zoom level of the network to influence the rendering - * - * @param scale + * @constructor Item + * @param {Object} data Object containing (optional) parameters type, + * start, end, content, group, className. + * @param {{toScreen: function, toTime: function}} conversion + * Conversion functions from time to screen and vice versa + * @param {Object} options Configuration options + * // TODO: describe available options */ - Edge.prototype.setScale = function(scale) { - this.networkScaleInv = 1.0/scale; - }; + function Item (data, conversion, options) { + this.id = null; + this.parent = null; + this.data = data; + this.dom = null; + this.conversion = conversion || {}; + this.options = options || {}; + this.selected = false; + this.displayed = false; + this.dirty = true; - Edge.prototype.select = function() { + this.top = null; + this.left = null; + this.width = null; + this.height = null; + } + + Item.prototype.stack = true; + + /** + * Select current item + */ + Item.prototype.select = function() { this.selected = true; + this.dirty = true; + if (this.displayed) this.redraw(); }; - Edge.prototype.unselect = function() { + /** + * Unselect current item + */ + Item.prototype.unselect = function() { this.selected = false; + this.dirty = true; + if (this.displayed) this.redraw(); }; - Edge.prototype.positionBezierNode = function() { - if (this.via !== null && this.from !== null && this.to !== null) { - this.via.x = 0.5 * (this.from.x + this.to.x); - this.via.y = 0.5 * (this.from.y + this.to.y); - } - else { - this.via.x = 0; - this.via.y = 0; - } + /** + * Set data for the item. Existing data will be updated. The id should not + * be changed. When the item is displayed, it will be redrawn immediately. + * @param {Object} data + */ + Item.prototype.setData = function(data) { + this.data = data; + this.dirty = true; + if (this.displayed) this.redraw(); }; /** - * This function draws the control nodes for the manipulator. - * In order to enable this, only set the this.controlNodesEnabled to true. - * @param ctx + * Set a parent for the item + * @param {ItemSet | Group} parent */ - Edge.prototype._drawControlNodes = function(ctx) { - if (this.controlNodesEnabled == true) { - if (this.controlNodes.from === null && this.controlNodes.to === null) { - var nodeIdFrom = "edgeIdFrom:".concat(this.id); - var nodeIdTo = "edgeIdTo:".concat(this.id); - var constants = { - nodes:{group:'', radius:7, borderWidth:2, borderWidthSelected: 2}, - physics:{damping:0}, - clustering: {maxNodeSizeIncrements: 0 ,nodeScaling: {width:0, height: 0, radius:0}} - }; - this.controlNodes.from = new Node( - {id:nodeIdFrom, - shape:'dot', - color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}} - },{},{},constants); - this.controlNodes.to = new Node( - {id:nodeIdTo, - shape:'dot', - color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}} - },{},{},constants); - } - - this.controlNodes.positions = {}; - if (this.controlNodes.from.selected == false) { - this.controlNodes.positions.from = this.getControlNodeFromPosition(ctx); - this.controlNodes.from.x = this.controlNodes.positions.from.x; - this.controlNodes.from.y = this.controlNodes.positions.from.y; - } - if (this.controlNodes.to.selected == false) { - this.controlNodes.positions.to = this.getControlNodeToPosition(ctx); - this.controlNodes.to.x = this.controlNodes.positions.to.x; - this.controlNodes.to.y = this.controlNodes.positions.to.y; + Item.prototype.setParent = function(parent) { + if (this.displayed) { + this.hide(); + this.parent = parent; + if (this.parent) { + this.show(); } - - this.controlNodes.from.draw(ctx); - this.controlNodes.to.draw(ctx); } else { - this.controlNodes = {from:null, to:null, positions:{}}; + this.parent = parent; } }; /** - * Enable control nodes. - * @private + * Check whether this item is visible inside given range + * @returns {{start: Number, end: Number}} range with a timestamp for start and end + * @returns {boolean} True if visible */ - Edge.prototype._enableControlNodes = function() { - this.fromBackup = this.from; - this.toBackup = this.to; - this.controlNodesEnabled = true; + Item.prototype.isVisible = function(range) { + // Should be implemented by Item implementations + return false; }; /** - * disable control nodes and remove from dynamicEdges from old node - * @private + * Show the Item in the DOM (when not already visible) + * @return {Boolean} changed */ - Edge.prototype._disableControlNodes = function() { - this.fromId = this.from.id; - this.toId = this.to.id; - if (this.fromId != this.fromBackup.id) { // from was changed, remove edge from old 'from' node dynamic edges - this.fromBackup.detachEdge(this); - } - else if (this.toId != this.toBackup.id) { // to was changed, remove edge from old 'to' node dynamic edges - this.toBackup.detachEdge(this); - } - - this.fromBackup = null; - this.toBackup = null; - this.controlNodesEnabled = false; + Item.prototype.show = function() { + return false; }; - /** - * This checks if one of the control nodes is selected and if so, returns the control node object. Else it returns null. - * @param x - * @param y - * @returns {null} - * @private + * Hide the Item from the DOM (when visible) + * @return {Boolean} changed */ - Edge.prototype._getSelectedControlNode = function(x,y) { - var positions = this.controlNodes.positions; - var fromDistance = Math.sqrt(Math.pow(x - positions.from.x,2) + Math.pow(y - positions.from.y,2)); - var toDistance = Math.sqrt(Math.pow(x - positions.to.x ,2) + Math.pow(y - positions.to.y ,2)); - - if (fromDistance < 15) { - this.connectedNode = this.from; - this.from = this.controlNodes.from; - return this.controlNodes.from; - } - else if (toDistance < 15) { - this.connectedNode = this.to; - this.to = this.controlNodes.to; - return this.controlNodes.to; - } - else { - return null; - } + Item.prototype.hide = function() { + return false; }; - /** - * this resets the control nodes to their original position. - * @private + * Repaint the item */ - Edge.prototype._restoreControlNodes = function() { - if (this.controlNodes.from.selected == true) { - this.from = this.connectedNode; - this.connectedNode = null; - this.controlNodes.from.unselect(); - } - else if (this.controlNodes.to.selected == true) { - this.to = this.connectedNode; - this.connectedNode = null; - this.controlNodes.to.unselect(); - } + Item.prototype.redraw = function() { + // should be implemented by the item }; /** - * this calculates the position of the control nodes on the edges of the parent nodes. - * - * @param ctx - * @returns {x: *, y: *} + * Reposition the Item horizontally */ - Edge.prototype.getControlNodeFromPosition = function(ctx) { - // draw arrow head - var controlnodeFromPos; - if (this.options.smoothCurves.enabled == true) { - controlnodeFromPos = this._findBorderPosition(true, ctx); - } - else { - var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var dx = (this.to.x - this.from.x); - var dy = (this.to.y - this.from.y); - var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); - - var fromBorderDist = this.from.distanceToBorder(ctx, angle + Math.PI); - var fromBorderPoint = (edgeSegmentLength - fromBorderDist) / edgeSegmentLength; - controlnodeFromPos = {}; - controlnodeFromPos.x = (fromBorderPoint) * this.from.x + (1 - fromBorderPoint) * this.to.x; - controlnodeFromPos.y = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y; - } - - return controlnodeFromPos; + Item.prototype.repositionX = function() { + // should be implemented by the item }; /** - * this calculates the position of the control nodes on the edges of the parent nodes. - * - * @param ctx - * @returns {{from: {x: number, y: number}, to: {x: *, y: *}}} + * Reposition the Item vertically */ - Edge.prototype.getControlNodeToPosition = function(ctx) { - // draw arrow head - var controlnodeFromPos,controlnodeToPos; - if (this.options.smoothCurves.enabled == true) { - controlnodeToPos = this._findBorderPosition(false, ctx); - } - else { - var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var dx = (this.to.x - this.from.x); - var dy = (this.to.y - this.from.y); - var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); - var toBorderDist = this.to.distanceToBorder(ctx, angle); - var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; - - controlnodeToPos = {}; - controlnodeToPos.x = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x; - controlnodeToPos.y = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y; - } - - return controlnodeToPos; + Item.prototype.repositionY = function() { + // should be implemented by the item }; - module.exports = Edge; - -/***/ }, -/* 38 */ -/***/ function(module, exports, __webpack_require__) { - - var util = __webpack_require__(1); - /** - * @class Groups - * This class can store groups and properties specific for groups. + * Repaint a delete button on the top right of the item when the item is selected + * @param {HTMLElement} anchor + * @protected */ - function Groups() { - this.clear(); - this.defaultIndex = 0; - } - + Item.prototype._repaintDeleteButton = function (anchor) { + if (this.selected && this.options.editable.remove && !this.dom.deleteButton) { + // create and show button + var me = this; - /** - * default constants for group colors - */ - Groups.DEFAULT = [ - {border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}, hover: {border: "#2B7CE9", background: "#D2E5FF"}}, // blue - {border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}, hover: {border: "#FFA500", background: "#FFFFA3"}}, // yellow - {border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}, hover: {border: "#FA0A10", background: "#FFAFB1"}}, // red - {border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}, hover: {border: "#41A906", background: "#A1EC76"}}, // green - {border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}, hover: {border: "#E129F0", background: "#F0B3F5"}}, // magenta - {border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}, hover: {border: "#7C29F0", background: "#D3BDF0"}}, // purple - {border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}, hover: {border: "#C37F00", background: "#FFCA66"}}, // orange - {border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}, hover: {border: "#4220FB", background: "#9B9BFD"}}, // darkblue - {border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}, hover: {border: "#FD5A77", background: "#FFD1D9"}}, // pink - {border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}, hover: {border: "#4AD63A", background: "#E6FFE3"}} // mint - ]; + var deleteButton = document.createElement('div'); + deleteButton.className = 'delete'; + deleteButton.title = 'Delete this item'; + Hammer(deleteButton, { + preventDefault: true + }).on('tap', function (event) { + me.parent.removeFromDataSet(me); + event.stopPropagation(); + }); - /** - * Clear all groups - */ - Groups.prototype.clear = function () { - this.groups = {}; - this.groups.length = function() - { - var i = 0; - for ( var p in this ) { - if (this.hasOwnProperty(p)) { - i++; - } + anchor.appendChild(deleteButton); + this.dom.deleteButton = deleteButton; + } + else if (!this.selected && this.dom.deleteButton) { + // remove button + if (this.dom.deleteButton.parentNode) { + this.dom.deleteButton.parentNode.removeChild(this.dom.deleteButton); } - return i; + this.dom.deleteButton = null; } }; - /** - * get group properties of a groupname. If groupname is not found, a new group - * is added. - * @param {*} groupname Can be a number, string, Date, etc. - * @return {Object} group The created group, containing all group properties + * Set HTML contents for the item + * @param {Element} element HTML element to fill with the contents + * @private */ - Groups.prototype.get = function (groupname) { - var group = this.groups[groupname]; - if (group == undefined) { - // create new group - var index = this.defaultIndex % Groups.DEFAULT.length; - this.defaultIndex++; - group = {}; - group.color = Groups.DEFAULT[index]; - this.groups[groupname] = group; + Item.prototype._updateContents = function (element) { + var content; + if (this.options.template) { + var itemData = this.parent.itemSet.itemsData.get(this.id); // get a clone of the data from the dataset + content = this.options.template(itemData); + } + else { + content = this.data.content; } - return group; - }; + if(content !== this.content) { + // only replace the content when changed + if (content instanceof Element) { + element.innerHTML = ''; + element.appendChild(content); + } + else if (content != undefined) { + element.innerHTML = content; + } + else { + if (!(this.data.type == 'background' && this.data.content === undefined)) { + throw new Error('Property "content" missing in item ' + this.id); + } + } - /** - * Add a custom group style - * @param {String} groupname - * @param {Object} style An object containing borderColor, - * backgroundColor, etc. - * @return {Object} group The created group object - */ - Groups.prototype.add = function (groupname, style) { - this.groups[groupname] = style; - return style; + this.content = content; + } }; - module.exports = Groups; - - -/***/ }, -/* 39 */ -/***/ function(module, exports, __webpack_require__) { - - /** - * @class Images - * This class loads images and keeps them stored. - */ - function Images() { - this.images = {}; - this.imageBroken = {}; - this.callback = undefined; - } - /** - * Set an onload callback function. This will be called each time an image - * is loaded - * @param {function} callback + * Set HTML contents for the item + * @param {Element} element HTML element to fill with the contents + * @private */ - Images.prototype.setOnloadCallback = function(callback) { - this.callback = callback; + Item.prototype._updateTitle = function (element) { + if (this.data.title != null) { + element.title = this.data.title || ''; + } + else { + element.removeAttribute('title'); + } }; /** - * - * @param {string} url Url of the image - * @param {string} url Url of an image to use if the url image is not found - * @return {Image} img The image object + * Process dataAttributes timeline option and set as data- attributes on dom.content + * @param {Element} element HTML element to which the attributes will be attached + * @private */ - Images.prototype.load = function(url, brokenUrl) { - var img = this.images[url]; // make a pointer - if (img === undefined) { - // create the image - var me = this; - img = new Image(); - img.onload = function () { - // IE11 fix -- thanks dponch! - if (this.width == 0) { - document.body.appendChild(this); - this.width = this.offsetWidth; - this.height = this.offsetHeight; - document.body.removeChild(this); - } + Item.prototype._updateDataAttributes = function(element) { + if (this.options.dataAttributes && this.options.dataAttributes.length > 0) { + var attributes = []; - if (me.callback) { - me.images[url] = img; - me.callback(this); - } - }; + if (Array.isArray(this.options.dataAttributes)) { + attributes = this.options.dataAttributes; + } + else if (this.options.dataAttributes == 'all') { + attributes = Object.keys(this.data); + } + else { + return; + } - img.onerror = function () { - if (brokenUrl === undefined) { - console.error("Could not load image:", url); - delete this.src; - if (me.callback) { - me.callback(this); - } - } - else if (me.imageBroken[url] === true) { - console.error("Could not load brokenImage:", brokenUrl); - delete this.src; - if (me.callback) { - me.callback(this); - } + for (var i = 0; i < attributes.length; i++) { + var name = attributes[i]; + var value = this.data[name]; + + if (value != null) { + element.setAttribute('data-' + name, value); } else { - this.src = brokenUrl; - me.imageBroken[url] = true; + element.removeAttribute('data-' + name); } - }; + } + } + }; - img.src = url; + /** + * Update custom styles of the element + * @param element + * @private + */ + Item.prototype._updateStyle = function(element) { + // remove old styles + if (this.style) { + util.removeCssText(element, this.style); + this.style = null; } - return img; + // append new styles + if (this.data.style) { + util.addCssText(element, this.data.style); + this.style = this.data.style; + } }; - module.exports = Images; + module.exports = Item; /***/ }, -/* 40 */ +/* 31 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); + var Group = __webpack_require__(27); /** - * @class Node - * A node. A node can be connected to other nodes via one or multiple edges. - * @param {object} properties An object containing properties for the node. All - * properties are optional, except for the id. - * {number} id Id of the node. Required - * {string} label Text label for the node - * {number} x Horizontal position of the node - * {number} y Vertical position of the node - * {string} shape Node shape, available: - * "database", "circle", "ellipse", - * "box", "image", "text", "dot", - * "star", "triangle", "triangleDown", - * "square" - * {string} image An image url - * {string} title An title text, can be HTML - * {anytype} group A group name or number - * @param {Network.Images} imagelist A list with images. Only needed - * when the node has an image - * @param {Network.Groups} grouplist A list with groups. Needed for - * retrieving group properties - * @param {Object} constants An object with default values for - * example for the color - * + * @constructor BackgroundGroup + * @param {Number | String} groupId + * @param {Object} data + * @param {ItemSet} itemSet */ - function Node(properties, imagelist, grouplist, networkConstants) { - var constants = util.selectiveBridgeObject(['nodes'],networkConstants); - this.options = constants.nodes; + function BackgroundGroup (groupId, data, itemSet) { + Group.call(this, groupId, data, itemSet); - this.selected = false; - this.hover = false; + this.width = 0; + this.height = 0; + this.top = 0; + this.left = 0; + } - this.edges = []; // all edges connected to this node - this.dynamicEdges = []; - this.reroutedEdges = {}; + BackgroundGroup.prototype = Object.create(Group.prototype); - this.fontDrawThreshold = 3; + /** + * Repaint this group + * @param {{start: number, end: number}} range + * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin + * @param {boolean} [restack=false] Force restacking of all items + * @return {boolean} Returns true if the group is resized + */ + BackgroundGroup.prototype.redraw = function(range, margin, restack) { + var resized = false; - // set defaults for the properties - this.id = undefined; - this.allowedToMoveX = false; - this.allowedToMoveY = false; - this.xFixed = false; - this.yFixed = false; - this.horizontalAlignLeft = true; // these are for the navigation controls - this.verticalAlignTop = true; // these are for the navigation controls - this.baseRadiusValue = networkConstants.nodes.radius; - this.radiusFixed = false; - this.level = -1; - this.preassignedLevel = false; - this.hierarchyEnumerated = false; - this.labelDimensions = {top:0, left:0, width:0, height:0, yLine:0}; // could be cached - this.boundingBox = {top:0, left:0, right:0, bottom:0}; + this.visibleItems = this._updateVisibleItems(this.orderedItems, this.visibleItems, range); - this.imagelist = imagelist; - this.grouplist = grouplist; + // calculate actual size + this.width = this.dom.background.offsetWidth; - // physics properties - this.fx = 0.0; // external force x - this.fy = 0.0; // external force y - this.vx = 0.0; // velocity x - this.vy = 0.0; // velocity y - this.x = null; - this.y = null; + // apply new height (just always zero for BackgroundGroup + this.dom.background.style.height = '0'; - // used for reverting to previous position on stabilization - this.previousState = {vx:0,vy:0,x:0,y:0}; + // update vertical position of items after they are re-stacked and the height of the group is calculated + for (var i = 0, ii = this.visibleItems.length; i < ii; i++) { + var item = this.visibleItems[i]; + item.repositionY(margin); + } - this.damping = networkConstants.physics.damping; // written every time gravity is calculated - this.fixedData = {x:null,y:null}; + return resized; + }; - this.setProperties(properties, constants); + /** + * Show this group: attach to the DOM + */ + BackgroundGroup.prototype.show = function() { + if (!this.dom.background.parentNode) { + this.itemSet.dom.background.appendChild(this.dom.background); + } + }; - // creating the variables for clustering - this.resetCluster(); - this.dynamicEdgesLength = 0; - this.clusterSession = 0; - this.clusterSizeWidthFactor = networkConstants.clustering.nodeScaling.width; - this.clusterSizeHeightFactor = networkConstants.clustering.nodeScaling.height; - this.clusterSizeRadiusFactor = networkConstants.clustering.nodeScaling.radius; - this.maxNodeSizeIncrements = networkConstants.clustering.maxNodeSizeIncrements; - this.growthIndicator = 0; + module.exports = BackgroundGroup; - // variables to tell the node about the network. - this.networkScaleInv = 1; - this.networkScale = 1; - this.canvasTopLeft = {"x": -300, "y": -300}; - this.canvasBottomRight = {"x": 300, "y": 300}; - this.parentEdgeId = null; - } +/***/ }, +/* 32 */ +/***/ function(module, exports, __webpack_require__) { + + var Item = __webpack_require__(30); + var util = __webpack_require__(1); /** - * Revert the position and velocity of the previous step. + * @constructor BoxItem + * @extends Item + * @param {Object} data Object containing parameters start + * content, className. + * @param {{toScreen: function, toTime: function}} conversion + * Conversion functions from time to screen and vice versa + * @param {Object} [options] Configuration options + * // TODO: describe available options */ - Node.prototype.revertPosition = function() { - this.x = this.previousState.x; - this.y = this.previousState.y; - this.vx = this.previousState.vx; - this.vy = this.previousState.vy; + function BoxItem (data, conversion, options) { + this.props = { + dot: { + width: 0, + height: 0 + }, + line: { + width: 0, + height: 0 + } + }; + + // validate data + if (data) { + if (data.start == undefined) { + throw new Error('Property "start" missing in item ' + data); + } + } + + Item.call(this, data, conversion, options); } + BoxItem.prototype = new Item (null, null, null); /** - * (re)setting the clustering variables and objects + * Check whether this item is visible inside given range + * @returns {{start: Number, end: Number}} range with a timestamp for start and end + * @returns {boolean} True if visible */ - Node.prototype.resetCluster = function() { - // clustering variables - this.formationScale = undefined; // this is used to determine when to open the cluster - this.clusterSize = 1; // this signifies the total amount of nodes in this cluster - this.containedNodes = {}; - this.containedEdges = {}; - this.clusterSessions = []; + BoxItem.prototype.isVisible = function(range) { + // determine visibility + // TODO: account for the real width of the item. Right now we just add 1/4 to the window + var interval = (range.end - range.start) / 4; + return (this.data.start > range.start - interval) && (this.data.start < range.end + interval); }; /** - * Attach a edge to the node - * @param {Edge} edge + * Repaint the item */ - Node.prototype.attachEdge = function(edge) { - if (this.edges.indexOf(edge) == -1) { - this.edges.push(edge); - } - if (this.dynamicEdges.indexOf(edge) == -1) { - this.dynamicEdges.push(edge); - } - this.dynamicEdgesLength = this.dynamicEdges.length; - }; + BoxItem.prototype.redraw = function() { + var dom = this.dom; + if (!dom) { + // create DOM + this.dom = {}; + dom = this.dom; - /** - * Detach a edge from the node - * @param {Edge} edge - */ - Node.prototype.detachEdge = function(edge) { - var index = this.edges.indexOf(edge); - if (index != -1) { - this.edges.splice(index, 1); - } - index = this.dynamicEdges.indexOf(edge); - if (index != -1) { - this.dynamicEdges.splice(index, 1); - } - this.dynamicEdgesLength = this.dynamicEdges.length; - }; + // create main box + dom.box = document.createElement('DIV'); + // contents box (inside the background box). used for making margins + dom.content = document.createElement('DIV'); + dom.content.className = 'content'; + dom.box.appendChild(dom.content); - /** - * Set or overwrite properties for the node - * @param {Object} properties an object with properties - * @param {Object} constants and object with default, global properties - */ - Node.prototype.setProperties = function(properties, constants) { - if (!properties) { - return; - } - - var fields = ['borderWidth','borderWidthSelected','shape','image','brokenImage','radius','fontColor', - 'fontSize','fontFace','fontFill','fontStrokeWidth','fontStrokeColor','group','mass' - ]; - util.selectiveDeepExtend(fields, this.options, properties); + // line to axis + dom.line = document.createElement('DIV'); + dom.line.className = 'line'; - // basic properties - if (properties.id !== undefined) {this.id = properties.id;} - if (properties.label !== undefined) {this.label = properties.label; this.originalLabel = properties.label;} - if (properties.title !== undefined) {this.title = properties.title;} - if (properties.x !== undefined) {this.x = properties.x;} - if (properties.y !== undefined) {this.y = properties.y;} - if (properties.value !== undefined) {this.value = properties.value;} - if (properties.level !== undefined) {this.level = properties.level; this.preassignedLevel = true;} + // dot on axis + dom.dot = document.createElement('DIV'); + dom.dot.className = 'dot'; - // navigation controls properties - if (properties.horizontalAlignLeft !== undefined) {this.horizontalAlignLeft = properties.horizontalAlignLeft;} - if (properties.verticalAlignTop !== undefined) {this.verticalAlignTop = properties.verticalAlignTop;} - if (properties.triggerFunction !== undefined) {this.triggerFunction = properties.triggerFunction;} + // attach this item as attribute + dom.box['timeline-item'] = this; - if (this.id === undefined) { - throw "Node must have an id"; + this.dirty = true; } - // copy group properties - if (typeof this.options.group === 'number' || (typeof this.options.group === 'string' && this.options.group != '')) { - var groupObj = this.grouplist.get(this.options.group); - util.deepExtend(this.options, groupObj); - // the color object needs to be completely defined. Since groups can partially overwrite the colors, we parse it again, just in case. - this.options.color = util.parseColor(this.options.color); + // append DOM to parent DOM + if (!this.parent) { + throw new Error('Cannot redraw item: no parent attached'); } - - // individual shape properties - if (properties.radius !== undefined) {this.baseRadiusValue = this.options.radius;} - if (properties.color !== undefined) {this.options.color = util.parseColor(properties.color);} - if (this.options.image !== undefined && this.options.image!= "") { - if (this.imagelist) { - this.imageObj = this.imagelist.load(this.options.image, this.options.brokenImage); - } - else { - throw "No imagelist provided"; - } + if (!dom.box.parentNode) { + var foreground = this.parent.dom.foreground; + if (!foreground) throw new Error('Cannot redraw item: parent has no foreground container element'); + foreground.appendChild(dom.box); } - - if (properties.allowedToMoveX !== undefined) { - this.xFixed = !properties.allowedToMoveX; - this.allowedToMoveX = properties.allowedToMoveX; + if (!dom.line.parentNode) { + var background = this.parent.dom.background; + if (!background) throw new Error('Cannot redraw item: parent has no background container element'); + background.appendChild(dom.line); } - else if (properties.x !== undefined && this.allowedToMoveX == false) { - this.xFixed = true; + if (!dom.dot.parentNode) { + var axis = this.parent.dom.axis; + if (!background) throw new Error('Cannot redraw item: parent has no axis container element'); + axis.appendChild(dom.dot); } + this.displayed = true; + // Update DOM when item is marked dirty. An item is marked dirty when: + // - the item is not yet rendered + // - the item's data is changed + // - the item is selected/deselected + if (this.dirty) { + this._updateContents(this.dom.content); + this._updateTitle(this.dom.box); + this._updateDataAttributes(this.dom.box); + this._updateStyle(this.dom.box); - if (properties.allowedToMoveY !== undefined) { - this.yFixed = !properties.allowedToMoveY; - this.allowedToMoveY = properties.allowedToMoveY; - } - else if (properties.y !== undefined && this.allowedToMoveY == false) { - this.yFixed = true; - } - - this.radiusFixed = this.radiusFixed || (properties.radius !== undefined); + // update class + var className = (this.data.className? ' ' + this.data.className : '') + + (this.selected ? ' selected' : ''); + dom.box.className = 'item box' + className; + dom.line.className = 'item line' + className; + dom.dot.className = 'item dot' + className; - if (this.options.shape === 'image' || this.options.shape === 'circularImage') { - this.options.radiusMin = constants.nodes.widthMin; - this.options.radiusMax = constants.nodes.widthMax; - } + // recalculate size + this.props.dot.height = dom.dot.offsetHeight; + this.props.dot.width = dom.dot.offsetWidth; + this.props.line.width = dom.line.offsetWidth; + this.width = dom.box.offsetWidth; + this.height = dom.box.offsetHeight; - // choose draw method depending on the shape - switch (this.options.shape) { - case 'database': this.draw = this._drawDatabase; this.resize = this._resizeDatabase; break; - case 'box': this.draw = this._drawBox; this.resize = this._resizeBox; break; - case 'circle': this.draw = this._drawCircle; this.resize = this._resizeCircle; break; - case 'ellipse': this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break; - // TODO: add diamond shape - case 'image': this.draw = this._drawImage; this.resize = this._resizeImage; break; - case 'circularImage': this.draw = this._drawCircularImage; this.resize = this._resizeCircularImage; break; - case 'text': this.draw = this._drawText; this.resize = this._resizeText; break; - case 'dot': this.draw = this._drawDot; this.resize = this._resizeShape; break; - case 'square': this.draw = this._drawSquare; this.resize = this._resizeShape; break; - case 'triangle': this.draw = this._drawTriangle; this.resize = this._resizeShape; break; - case 'triangleDown': this.draw = this._drawTriangleDown; this.resize = this._resizeShape; break; - case 'star': this.draw = this._drawStar; this.resize = this._resizeShape; break; - default: this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break; + this.dirty = false; } - // reset the size of the node, this can be changed - this._reset(); + this._repaintDeleteButton(dom.box); }; /** - * select this node + * Show the item in the DOM (when not already displayed). The items DOM will + * be created when needed. */ - Node.prototype.select = function() { - this.selected = true; - this._reset(); + BoxItem.prototype.show = function() { + if (!this.displayed) { + this.redraw(); + } }; /** - * unselect this node + * Hide the item from the DOM (when visible) */ - Node.prototype.unselect = function() { - this.selected = false; - this._reset(); - }; + BoxItem.prototype.hide = function() { + if (this.displayed) { + var dom = this.dom; + if (dom.box.parentNode) dom.box.parentNode.removeChild(dom.box); + if (dom.line.parentNode) dom.line.parentNode.removeChild(dom.line); + if (dom.dot.parentNode) dom.dot.parentNode.removeChild(dom.dot); - /** - * Reset the calculated size of the node, forces it to recalculate its size - */ - Node.prototype.clearSizeCache = function() { - this._reset(); - }; + this.top = null; + this.left = null; - /** - * Reset the calculated size of the node, forces it to recalculate its size - * @private - */ - Node.prototype._reset = function() { - this.width = undefined; - this.height = undefined; + this.displayed = false; + } }; /** - * get the title of this node. - * @return {string} title The title of the node, or undefined when no title - * has been set. + * Reposition the item horizontally + * @Override */ - Node.prototype.getTitle = function() { - return typeof this.title === "function" ? this.title() : this.title; + BoxItem.prototype.repositionX = function() { + var start = this.conversion.toScreen(this.data.start); + var align = this.options.align; + var left; + var box = this.dom.box; + var line = this.dom.line; + var dot = this.dom.dot; + + // calculate left position of the box + if (align == 'right') { + this.left = start - this.width; + } + else if (align == 'left') { + this.left = start; + } + else { + // default or 'center' + this.left = start - this.width / 2; + } + + // reposition box + box.style.left = this.left + 'px'; + + // reposition line + line.style.left = (start - this.props.line.width / 2) + 'px'; + + // reposition dot + dot.style.left = (start - this.props.dot.width / 2) + 'px'; }; /** - * Calculate the distance to the border of the Node - * @param {CanvasRenderingContext2D} ctx - * @param {Number} angle Angle in radians - * @returns {number} distance Distance to the border in pixels + * Reposition the item vertically + * @Override */ - Node.prototype.distanceToBorder = function (ctx, angle) { - var borderWidth = 1; + BoxItem.prototype.repositionY = function() { + var orientation = this.options.orientation; + var box = this.dom.box; + var line = this.dom.line; + var dot = this.dom.dot; - if (!this.width) { - this.resize(ctx); + if (orientation == 'top') { + box.style.top = (this.top || 0) + 'px'; + + line.style.top = '0'; + line.style.height = (this.parent.top + this.top + 1) + 'px'; + line.style.bottom = ''; } + else { // orientation 'bottom' + var itemSetHeight = this.parent.itemSet.props.height; // TODO: this is nasty + var lineHeight = itemSetHeight - this.parent.top - this.parent.height + this.top; - switch (this.options.shape) { - case 'circle': - case 'dot': - return this.options.radius+ borderWidth; + box.style.top = (this.parent.height - this.top - this.height || 0) + 'px'; + line.style.top = (itemSetHeight - lineHeight) + 'px'; + line.style.bottom = '0'; + } - case 'ellipse': - var a = this.width / 2; - var b = this.height / 2; - var w = (Math.sin(angle) * a); - var h = (Math.cos(angle) * b); - return a * b / Math.sqrt(w * w + h * h); + dot.style.top = (-this.props.dot.height / 2) + 'px'; + }; - // TODO: implement distanceToBorder for database - // TODO: implement distanceToBorder for triangle - // TODO: implement distanceToBorder for triangleDown + module.exports = BoxItem; - case 'box': - case 'image': - case 'text': - default: - if (this.width) { - return Math.min( - Math.abs(this.width / 2 / Math.cos(angle)), - Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth; - // TODO: reckon with border radius too in case of box - } - else { - return 0; - } - } - // TODO: implement calculation of distance to border for all shapes - }; +/***/ }, +/* 33 */ +/***/ function(module, exports, __webpack_require__) { + + var Item = __webpack_require__(30); /** - * Set forces acting on the node - * @param {number} fx Force in horizontal direction - * @param {number} fy Force in vertical direction + * @constructor PointItem + * @extends Item + * @param {Object} data Object containing parameters start + * content, className. + * @param {{toScreen: function, toTime: function}} conversion + * Conversion functions from time to screen and vice versa + * @param {Object} [options] Configuration options + * // TODO: describe available options */ - Node.prototype._setForce = function(fx, fy) { - this.fx = fx; - this.fy = fy; - }; + function PointItem (data, conversion, options) { + this.props = { + dot: { + top: 0, + width: 0, + height: 0 + }, + content: { + height: 0, + marginLeft: 0 + } + }; + + // validate data + if (data) { + if (data.start == undefined) { + throw new Error('Property "start" missing in item ' + data); + } + } + + Item.call(this, data, conversion, options); + } + + PointItem.prototype = new Item (null, null, null); /** - * Add forces acting on the node - * @param {number} fx Force in horizontal direction - * @param {number} fy Force in vertical direction - * @private + * Check whether this item is visible inside given range + * @returns {{start: Number, end: Number}} range with a timestamp for start and end + * @returns {boolean} True if visible */ - Node.prototype._addForce = function(fx, fy) { - this.fx += fx; - this.fy += fy; + PointItem.prototype.isVisible = function(range) { + // determine visibility + // TODO: account for the real width of the item. Right now we just add 1/4 to the window + var interval = (range.end - range.start) / 4; + return (this.data.start > range.start - interval) && (this.data.start < range.end + interval); }; /** - * Store the state before the next step + * Repaint the item */ - Node.prototype.storeState = function() { - this.previousState.x = this.x; - this.previousState.y = this.y; - this.previousState.vx = this.vx; - this.previousState.vy = this.vy; - } + PointItem.prototype.redraw = function() { + var dom = this.dom; + if (!dom) { + // create DOM + this.dom = {}; + dom = this.dom; - /** - * Perform one discrete step for the node - * @param {number} interval Time interval in seconds - */ - Node.prototype.discreteStep = function(interval) { - this.storeState(); - if (!this.xFixed) { - var dx = this.damping * this.vx; // damping force - var ax = (this.fx - dx) / this.options.mass; // acceleration - this.vx += ax * interval; // velocity - this.x += this.vx * interval; // position - } - else { - this.fx = 0; - this.vx = 0; + // background box + dom.point = document.createElement('div'); + // className is updated in redraw() + + // contents box, right from the dot + dom.content = document.createElement('div'); + dom.content.className = 'content'; + dom.point.appendChild(dom.content); + + // dot at start + dom.dot = document.createElement('div'); + dom.point.appendChild(dom.dot); + + // attach this item as attribute + dom.point['timeline-item'] = this; + + this.dirty = true; } - if (!this.yFixed) { - var dy = this.damping * this.vy; // damping force - var ay = (this.fy - dy) / this.options.mass; // acceleration - this.vy += ay * interval; // velocity - this.y += this.vy * interval; // position + // append DOM to parent DOM + if (!this.parent) { + throw new Error('Cannot redraw item: no parent attached'); } - else { - this.fy = 0; - this.vy = 0; + if (!dom.point.parentNode) { + var foreground = this.parent.dom.foreground; + if (!foreground) { + throw new Error('Cannot redraw item: parent has no foreground container element'); + } + foreground.appendChild(dom.point); } - }; + this.displayed = true; + // Update DOM when item is marked dirty. An item is marked dirty when: + // - the item is not yet rendered + // - the item's data is changed + // - the item is selected/deselected + if (this.dirty) { + this._updateContents(this.dom.content); + this._updateTitle(this.dom.point); + this._updateDataAttributes(this.dom.point); + this._updateStyle(this.dom.point); + // update class + var className = (this.data.className? ' ' + this.data.className : '') + + (this.selected ? ' selected' : ''); + dom.point.className = 'item point' + className; + dom.dot.className = 'item dot' + className; - /** - * Perform one discrete step for the node - * @param {number} interval Time interval in seconds - * @param {number} maxVelocity The speed limit imposed on the velocity - */ - Node.prototype.discreteStepLimited = function(interval, maxVelocity) { - this.storeState(); - if (!this.xFixed) { - var dx = this.damping * this.vx; // damping force - var ax = (this.fx - dx) / this.options.mass; // acceleration - this.vx += ax * interval; // velocity - this.vx = (Math.abs(this.vx) > maxVelocity) ? ((this.vx > 0) ? maxVelocity : -maxVelocity) : this.vx; - this.x += this.vx * interval; // position - } - else { - this.fx = 0; - this.vx = 0; - } + // recalculate size + this.width = dom.point.offsetWidth; + this.height = dom.point.offsetHeight; + this.props.dot.width = dom.dot.offsetWidth; + this.props.dot.height = dom.dot.offsetHeight; + this.props.content.height = dom.content.offsetHeight; - if (!this.yFixed) { - var dy = this.damping * this.vy; // damping force - var ay = (this.fy - dy) / this.options.mass; // acceleration - this.vy += ay * interval; // velocity - this.vy = (Math.abs(this.vy) > maxVelocity) ? ((this.vy > 0) ? maxVelocity : -maxVelocity) : this.vy; - this.y += this.vy * interval; // position - } - else { - this.fy = 0; - this.vy = 0; + // resize contents + dom.content.style.marginLeft = 2 * this.props.dot.width + 'px'; + //dom.content.style.marginRight = ... + 'px'; // TODO: margin right + + dom.dot.style.top = ((this.height - this.props.dot.height) / 2) + 'px'; + dom.dot.style.left = (this.props.dot.width / 2) + 'px'; + + this.dirty = false; } - }; - /** - * Check if this node has a fixed x and y position - * @return {boolean} true if fixed, false if not - */ - Node.prototype.isFixed = function() { - return (this.xFixed && this.yFixed); + this._repaintDeleteButton(dom.point); }; /** - * Check if this node is moving - * @param {number} vmin the minimum velocity considered as "moving" - * @return {boolean} true if moving, false if it has no velocity + * Show the item in the DOM (when not already visible). The items DOM will + * be created when needed. */ - Node.prototype.isMoving = function(vmin) { - var velocity = Math.sqrt(Math.pow(this.vx,2) + Math.pow(this.vy,2)); - // this.velocity = Math.sqrt(Math.pow(this.vx,2) + Math.pow(this.vy,2)) - return (velocity > vmin); + PointItem.prototype.show = function() { + if (!this.displayed) { + this.redraw(); + } }; /** - * check if this node is selecte - * @return {boolean} selected True if node is selected, else false + * Hide the item from the DOM (when visible) */ - Node.prototype.isSelected = function() { - return this.selected; + PointItem.prototype.hide = function() { + if (this.displayed) { + if (this.dom.point.parentNode) { + this.dom.point.parentNode.removeChild(this.dom.point); + } + + this.top = null; + this.left = null; + + this.displayed = false; + } }; /** - * Retrieve the value of the node. Can be undefined - * @return {Number} value + * Reposition the item horizontally + * @Override */ - Node.prototype.getValue = function() { - return this.value; + PointItem.prototype.repositionX = function() { + var start = this.conversion.toScreen(this.data.start); + + this.left = start - this.props.dot.width; + + // reposition point + this.dom.point.style.left = this.left + 'px'; }; /** - * Calculate the distance from the nodes location to the given location (x,y) - * @param {Number} x - * @param {Number} y - * @return {Number} value + * Reposition the item vertically + * @Override */ - Node.prototype.getDistance = function(x, y) { - var dx = this.x - x, - dy = this.y - y; - return Math.sqrt(dx * dx + dy * dy); - }; - + PointItem.prototype.repositionY = function() { + var orientation = this.options.orientation, + point = this.dom.point; + + if (orientation == 'top') { + point.style.top = this.top + 'px'; + } + else { + point.style.top = (this.parent.height - this.top - this.height) + 'px'; + } + }; + + module.exports = PointItem; + + +/***/ }, +/* 34 */ +/***/ function(module, exports, __webpack_require__) { + + var Hammer = __webpack_require__(19); + var Item = __webpack_require__(30); + var BackgroundGroup = __webpack_require__(31); + var RangeItem = __webpack_require__(29); /** - * Adjust the value range of the node. The node will adjust it's radius - * based on its value. - * @param {Number} min - * @param {Number} max + * @constructor BackgroundItem + * @extends Item + * @param {Object} data Object containing parameters start, end + * content, className. + * @param {{toScreen: function, toTime: function}} conversion + * Conversion functions from time to screen and vice versa + * @param {Object} [options] Configuration options + * // TODO: describe options */ - Node.prototype.setValueRange = function(min, max) { - if (!this.radiusFixed && this.value !== undefined) { - if (max == min) { - this.options.radius= (this.options.radiusMin + this.options.radiusMax) / 2; + // TODO: implement support for the BackgroundItem just having a start, then being displayed as a sort of an annotation + function BackgroundItem (data, conversion, options) { + this.props = { + content: { + width: 0 } - else { - var scale = (this.options.radiusMax - this.options.radiusMin) / (max - min); - this.options.radius= (this.value - min) * scale + this.options.radiusMin; + }; + this.overflow = false; // if contents can overflow (css styling), this flag is set to true + + // validate data + if (data) { + if (data.start == undefined) { + throw new Error('Property "start" missing in item ' + data.id); + } + if (data.end == undefined) { + throw new Error('Property "end" missing in item ' + data.id); } } - this.baseRadiusValue = this.options.radius; - }; - /** - * Draw this node in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - */ - Node.prototype.draw = function(ctx) { - throw "Draw method not initialized for node"; - }; + Item.call(this, data, conversion, options); + + this.emptyContent = false; + } + + BackgroundItem.prototype = new Item (null, null, null); + + BackgroundItem.prototype.baseClassName = 'item background'; + BackgroundItem.prototype.stack = false; /** - * Recalculate the size of this node in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx + * Check whether this item is visible inside given range + * @returns {{start: Number, end: Number}} range with a timestamp for start and end + * @returns {boolean} True if visible */ - Node.prototype.resize = function(ctx) { - throw "Resize method not initialized for node"; + BackgroundItem.prototype.isVisible = function(range) { + // determine visibility + return (this.data.start < range.end) && (this.data.end > range.start); }; /** - * Check if this object is overlapping with the provided object - * @param {Object} obj an object with parameters left, top, right, bottom - * @return {boolean} True if location is located on node + * Repaint the item */ - Node.prototype.isOverlappingWith = function(obj) { - return (this.left < obj.right && - this.left + this.width > obj.left && - this.top < obj.bottom && - this.top + this.height > obj.top); - }; + BackgroundItem.prototype.redraw = function() { + var dom = this.dom; + if (!dom) { + // create DOM + this.dom = {}; + dom = this.dom; - Node.prototype._resizeImage = function (ctx) { - // TODO: pre calculate the image size + // background box + dom.box = document.createElement('div'); + // className is updated in redraw() - if (!this.width || !this.height) { // undefined or 0 - var width, height; - if (this.value) { - this.options.radius= this.baseRadiusValue; - var scale = this.imageObj.height / this.imageObj.width; - if (scale !== undefined) { - width = this.options.radius|| this.imageObj.width; - height = this.options.radius* scale || this.imageObj.height; - } - else { - width = 0; - height = 0; - } - } - else { - width = this.imageObj.width; - height = this.imageObj.height; - } - this.width = width; - this.height = height; + // contents box + dom.content = document.createElement('div'); + dom.content.className = 'content'; + dom.box.appendChild(dom.content); - this.growthIndicator = 0; - if (this.width > 0 && this.height > 0) { - this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; - this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; - this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor; - this.growthIndicator = this.width - width; + // Note: we do NOT attach this item as attribute to the DOM, + // such that background items cannot be selected + //dom.box['timeline-item'] = this; + + this.dirty = true; + } + + // append DOM to parent DOM + if (!this.parent) { + throw new Error('Cannot redraw item: no parent attached'); + } + if (!dom.box.parentNode) { + var background = this.parent.dom.background; + if (!background) { + throw new Error('Cannot redraw item: parent has no background container element'); } + background.appendChild(dom.box); } - }; + this.displayed = true; - Node.prototype._drawImageAtPosition = function (ctx) { - if (this.imageObj.width != 0 ) { - // draw the shade - if (this.clusterSize > 1) { - var lineWidth = ((this.clusterSize > 1) ? 10 : 0.0); - lineWidth *= this.networkScaleInv; - lineWidth = Math.min(0.2 * this.width,lineWidth); + // Update DOM when item is marked dirty. An item is marked dirty when: + // - the item is not yet rendered + // - the item's data is changed + // - the item is selected/deselected + if (this.dirty) { + this._updateContents(this.dom.content); + this._updateTitle(this.dom.content); + this._updateDataAttributes(this.dom.content); + this._updateStyle(this.dom.box); - ctx.globalAlpha = 0.5; - ctx.drawImage(this.imageObj, this.left - lineWidth, this.top - lineWidth, this.width + 2*lineWidth, this.height + 2*lineWidth); - } + // update class + var className = (this.data.className ? (' ' + this.data.className) : '') + + (this.selected ? ' selected' : ''); + dom.box.className = this.baseClassName + className; - // draw the image - ctx.globalAlpha = 1.0; - ctx.drawImage(this.imageObj, this.left, this.top, this.width, this.height); - } - }; + // determine from css whether this box has overflow + this.overflow = window.getComputedStyle(dom.content).overflow !== 'hidden'; - Node.prototype._drawImageLabel = function (ctx) { - var yLabel; - var offset = 0; - - if (this.height){ - offset = this.height / 2; - var labelDimensions = this.getTextSize(ctx); - - if (labelDimensions.lineCount >= 1){ - offset += labelDimensions.height / 2; - offset += 3; - } - } - - yLabel = this.y + offset; + // recalculate size + this.props.content.width = this.dom.content.offsetWidth; + this.height = 0; // set height zero, so this item will be ignored when stacking items - this._label(ctx, this.label, this.x, yLabel, undefined); + this.dirty = false; + } }; - Node.prototype._drawImage = function (ctx) { - this._resizeImage(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; + /** + * Show the item in the DOM (when not already visible). The items DOM will + * be created when needed. + */ + BackgroundItem.prototype.show = RangeItem.prototype.show; - this._drawImageAtPosition(ctx); + /** + * Hide the item from the DOM (when visible) + * @return {Boolean} changed + */ + BackgroundItem.prototype.hide = RangeItem.prototype.hide; - this.boundingBox.top = this.top; - this.boundingBox.left = this.left; - this.boundingBox.right = this.left + this.width; - this.boundingBox.bottom = this.top + this.height; + /** + * Reposition the item horizontally + * @Override + */ + BackgroundItem.prototype.repositionX = RangeItem.prototype.repositionX; - this._drawImageLabel(ctx); - this.boundingBox.left = Math.min(this.boundingBox.left, this.labelDimensions.left); - this.boundingBox.right = Math.max(this.boundingBox.right, this.labelDimensions.left + this.labelDimensions.width); - this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelDimensions.height); - }; + /** + * Reposition the item vertically + * @Override + */ + BackgroundItem.prototype.repositionY = function(margin) { + var onTop = this.options.orientation === 'top'; + this.dom.content.style.top = onTop ? '' : '0'; + this.dom.content.style.bottom = onTop ? '0' : ''; + var height; - Node.prototype._resizeCircularImage = function (ctx) { - if(!this.imageObj.src || !this.imageObj.width || !this.imageObj.height){ - if (!this.width) { - var diameter = this.options.radius * 2; - this.width = diameter; - this.height = diameter; + // special positioning for subgroups + if (this.data.subgroup !== undefined) { + var itemSubgroup = this.data.subgroup; + var subgroups = this.parent.subgroups; + var subgroupIndex = subgroups[itemSubgroup].index; + // if the orientation is top, we need to take the difference in height into account. + if (onTop == true) { + // the first subgroup will have to account for the distance from the top to the first item. + height = this.parent.subgroups[itemSubgroup].height + margin.item.vertical; + height += subgroupIndex == 0 ? margin.axis - 0.5*margin.item.vertical : 0; + var newTop = this.parent.top; + for (var subgroup in subgroups) { + if (subgroups.hasOwnProperty(subgroup)) { + if (subgroups[subgroup].visible == true && subgroups[subgroup].index < subgroupIndex) { + newTop += subgroups[subgroup].height + margin.item.vertical; + } + } + } - // scaling used for clustering - //this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor; - //this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor; - this.options.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor; - this.growthIndicator = this.options.radius- 0.5*diameter; - this._swapToImageResizeWhenImageLoaded = true; + // the others will have to be offset downwards with this same distance. + newTop += subgroupIndex != 0 ? margin.axis - 0.5 * margin.item.vertical : 0; + this.dom.box.style.top = newTop + 'px'; + this.dom.box.style.bottom = ''; + } + // and when the orientation is bottom: + else { + var newTop = this.parent.top; + for (var subgroup in subgroups) { + if (subgroups.hasOwnProperty(subgroup)) { + if (subgroups[subgroup].visible == true && subgroups[subgroup].index > subgroupIndex) { + newTop += subgroups[subgroup].height + margin.item.vertical; + } + } + } + height = this.parent.subgroups[itemSubgroup].height + margin.item.vertical; + this.dom.box.style.top = newTop + 'px'; + this.dom.box.style.bottom = ''; } } + // and in the case of no subgroups: else { - if (this._swapToImageResizeWhenImageLoaded) { - this.width = 0; - this.height = 0; - delete this._swapToImageResizeWhenImageLoaded; + // we want backgrounds with groups to only show in groups. + if (this.parent instanceof BackgroundGroup) { + // if the item is not in a group: + height = Math.max(this.parent.height, + this.parent.itemSet.body.domProps.center.height, + this.parent.itemSet.body.domProps.centerContainer.height); + this.dom.box.style.top = onTop ? '0' : ''; + this.dom.box.style.bottom = onTop ? '' : '0'; + } + else { + height = this.parent.height; + // same alignment for items when orientation is top or bottom + this.dom.box.style.top = this.parent.top + 'px'; + this.dom.box.style.bottom = ''; } - this._resizeImage(ctx); } - + this.dom.box.style.height = height + 'px'; }; - Node.prototype._drawCircularImage = function (ctx) { - this._resizeCircularImage(ctx); + module.exports = BackgroundItem; - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - var centerX = this.left + (this.width / 2); - var centerY = this.top + (this.height / 2); - var radius = Math.abs(this.height / 2); - this._drawRawCircle(ctx, centerX, centerY, radius); +/***/ }, +/* 35 */ +/***/ function(module, exports, __webpack_require__) { - ctx.save(); - ctx.circle(this.x, this.y, radius); - ctx.stroke(); - ctx.clip(); + var keycharm = __webpack_require__(36); + var Emitter = __webpack_require__(11); + var Hammer = __webpack_require__(19); + var util = __webpack_require__(1); - this._drawImageAtPosition(ctx); + /** + * Turn an element into an clickToUse element. + * When not active, the element has a transparent overlay. When the overlay is + * clicked, the mode is changed to active. + * When active, the element is displayed with a blue border around it, and + * the interactive contents of the element can be used. When clicked outside + * the element, the elements mode is changed to inactive. + * @param {Element} container + * @constructor + */ + function Activator(container) { + this.active = false; - ctx.restore(); + this.dom = { + container: container + }; - this.boundingBox.top = this.y - this.options.radius; - this.boundingBox.left = this.x - this.options.radius; - this.boundingBox.right = this.x + this.options.radius; - this.boundingBox.bottom = this.y + this.options.radius; + this.dom.overlay = document.createElement('div'); + this.dom.overlay.className = 'overlay'; - this._drawImageLabel(ctx); - - this.boundingBox.left = Math.min(this.boundingBox.left, this.labelDimensions.left); - this.boundingBox.right = Math.max(this.boundingBox.right, this.labelDimensions.left + this.labelDimensions.width); - this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelDimensions.height); - }; + this.dom.container.appendChild(this.dom.overlay); - Node.prototype._resizeBox = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - this.width = textSize.width + 2 * margin; - this.height = textSize.height + 2 * margin; + this.hammer = Hammer(this.dom.overlay, {prevent_default: false}); + this.hammer.on('tap', this._onTapOverlay.bind(this)); - this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor; - this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor; - this.growthIndicator = this.width - (textSize.width + 2 * margin); - // this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor; + // block all touch events (except tap) + var me = this; + var events = [ + 'touch', 'pinch', + 'doubletap', 'hold', + 'dragstart', 'drag', 'dragend', + 'mousewheel', 'DOMMouseScroll' // DOMMouseScroll is needed for Firefox + ]; + events.forEach(function (event) { + me.hammer.on(event, function (event) { + event.stopPropagation(); + }); + }); + + // attach a tap event to the window, in order to deactivate when clicking outside the timeline + this.windowHammer = Hammer(window, {prevent_default: false}); + this.windowHammer.on('tap', function (event) { + // deactivate when clicked outside the container + if (!_hasParent(event.target, container)) { + me.deactivate(); + } + }); + if (this.keycharm !== undefined) { + this.keycharm.destroy(); } - }; + this.keycharm = keycharm(); - Node.prototype._drawBox = function (ctx) { - this._resizeBox(ctx); + // keycharm listener only bounded when active) + this.escListener = this.deactivate.bind(this); + } - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; + // turn into an event emitter + Emitter(Activator.prototype); - var clusterLineWidth = 2.5; - var borderWidth = this.options.borderWidth; - var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; + // The currently active activator + Activator.current = null; - ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; + /** + * Destroy the activator. Cleans up all created DOM and event listeners + */ + Activator.prototype.destroy = function () { + this.deactivate(); - // draw the outer border - if (this.clusterSize > 1) { - ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.networkScaleInv; - ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + // remove dom + this.dom.overlay.parentNode.removeChild(this.dom.overlay); - ctx.roundRect(this.left-2*ctx.lineWidth, this.top-2*ctx.lineWidth, this.width+4*ctx.lineWidth, this.height+4*ctx.lineWidth, this.options.radius); - ctx.stroke(); - } - ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.networkScaleInv; - ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + // cleanup hammer instances + this.hammer = null; + this.windowHammer = null; + // FIXME: cleaning up hammer instances doesn't work (Timeline not removed from memory) + }; - ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; + /** + * Activate the element + * Overlay is hidden, element is decorated with a blue shadow border + */ + Activator.prototype.activate = function () { + // we allow only one active activator at a time + if (Activator.current) { + Activator.current.deactivate(); + } + Activator.current = this; - ctx.roundRect(this.left, this.top, this.width, this.height, this.options.radius); - ctx.fill(); - ctx.stroke(); + this.active = true; + this.dom.overlay.style.display = 'none'; + util.addClassName(this.dom.container, 'vis-active'); - this.boundingBox.top = this.top; - this.boundingBox.left = this.left; - this.boundingBox.right = this.left + this.width; - this.boundingBox.bottom = this.top + this.height; + this.emit('change'); + this.emit('activate'); - this._label(ctx, this.label, this.x, this.y); + // ugly hack: bind ESC after emitting the events, as the Network rebinds all + // keyboard events on a 'change' event + this.keycharm.bind('esc', this.escListener); }; + /** + * Deactivate the element + * Overlay is displayed on top of the element + */ + Activator.prototype.deactivate = function () { + this.active = false; + this.dom.overlay.style.display = ''; + util.removeClassName(this.dom.container, 'vis-active'); + this.keycharm.unbind('esc', this.escListener); - Node.prototype._resizeDatabase = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - var size = textSize.width + 2 * margin; - this.width = size; - this.height = size; - - // scaling used for clustering - this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; - this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; - this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor; - this.growthIndicator = this.width - size; - } + this.emit('change'); + this.emit('deactivate'); }; - Node.prototype._drawDatabase = function (ctx) { - this._resizeDatabase(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - var clusterLineWidth = 2.5; - var borderWidth = this.options.borderWidth; - var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; - - ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; - - // draw the outer border - if (this.clusterSize > 1) { - ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.networkScaleInv; - ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + /** + * Handle a tap event: activate the container + * @param event + * @private + */ + Activator.prototype._onTapOverlay = function (event) { + // activate the container + this.activate(); + event.stopPropagation(); + }; - ctx.database(this.x - this.width/2 - 2*ctx.lineWidth, this.y - this.height*0.5 - 2*ctx.lineWidth, this.width + 4*ctx.lineWidth, this.height + 4*ctx.lineWidth); - ctx.stroke(); + /** + * Test whether the element has the requested parent element somewhere in + * its chain of parent nodes. + * @param {HTMLElement} element + * @param {HTMLElement} parent + * @returns {boolean} Returns true when the parent is found somewhere in the + * chain of parent nodes. + * @private + */ + function _hasParent(element, parent) { + while (element) { + if (element === parent) { + return true + } + element = element.parentNode; } - ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.networkScaleInv; - ctx.lineWidth = Math.min(this.width,ctx.lineWidth); - - ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; - ctx.database(this.x - this.width/2, this.y - this.height*0.5, this.width, this.height); - ctx.fill(); - ctx.stroke(); - - this.boundingBox.top = this.top; - this.boundingBox.left = this.left; - this.boundingBox.right = this.left + this.width; - this.boundingBox.bottom = this.top + this.height; + return false; + } - this._label(ctx, this.label, this.x, this.y); - }; + module.exports = Activator; - Node.prototype._resizeCircle = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - var diameter = Math.max(textSize.width, textSize.height) + 2 * margin; - this.options.radius = diameter / 2; +/***/ }, +/* 36 */ +/***/ function(module, exports, __webpack_require__) { - this.width = diameter; - this.height = diameter; + var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;"use strict"; + /** + * Created by Alex on 11/6/2014. + */ - // scaling used for clustering - // this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor; - // this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor; - this.options.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor; - this.growthIndicator = this.options.radius- 0.5*diameter; + // https://github.com/umdjs/umd/blob/master/returnExports.js#L40-L60 + // if the module has no dependencies, the above pattern can be simplified to + (function (root, factory) { + if (true) { + // AMD. Register as an anonymous module. + !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + } else if (typeof exports === 'object') { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); + } else { + // Browser globals (root is window) + root.keycharm = factory(); } - }; + }(this, function () { - Node.prototype._drawRawCircle = function (ctx, x, y, radius) { - var clusterLineWidth = 2.5; - var borderWidth = this.options.borderWidth; - var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; - - ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; + function keycharm(options) { + var preventDefault = options && options.preventDefault || false; - // draw the outer border - if (this.clusterSize > 1) { - ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.networkScaleInv; - ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + var container = options && options.container || window; - ctx.circle(x, y, radius+2*ctx.lineWidth); - ctx.stroke(); - } - ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.networkScaleInv; - ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + var _exportFunctions = {}; + var _bound = {keydown:{}, keyup:{}}; + var _keys = {}; + var i; - ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; - ctx.circle(this.x, this.y, radius); - ctx.fill(); - ctx.stroke(); - }; + // a - z + for (i = 97; i <= 122; i++) {_keys[String.fromCharCode(i)] = {code:65 + (i - 97), shift: false};} + // A - Z + for (i = 65; i <= 90; i++) {_keys[String.fromCharCode(i)] = {code:i, shift: true};} + // 0 - 9 + for (i = 0; i <= 9; i++) {_keys['' + i] = {code:48 + i, shift: false};} + // F1 - F12 + for (i = 1; i <= 12; i++) {_keys['F' + i] = {code:111 + i, shift: false};} + // num0 - num9 + for (i = 0; i <= 9; i++) {_keys['num' + i] = {code:96 + i, shift: false};} - Node.prototype._drawCircle = function (ctx) { - this._resizeCircle(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; + // numpad misc + _keys['num*'] = {code:106, shift: false}; + _keys['num+'] = {code:107, shift: false}; + _keys['num-'] = {code:109, shift: false}; + _keys['num/'] = {code:111, shift: false}; + _keys['num.'] = {code:110, shift: false}; + // arrows + _keys['left'] = {code:37, shift: false}; + _keys['up'] = {code:38, shift: false}; + _keys['right'] = {code:39, shift: false}; + _keys['down'] = {code:40, shift: false}; + // extra keys + _keys['space'] = {code:32, shift: false}; + _keys['enter'] = {code:13, shift: false}; + _keys['shift'] = {code:16, shift: undefined}; + _keys['esc'] = {code:27, shift: false}; + _keys['backspace'] = {code:8, shift: false}; + _keys['tab'] = {code:9, shift: false}; + _keys['ctrl'] = {code:17, shift: false}; + _keys['alt'] = {code:18, shift: false}; + _keys['delete'] = {code:46, shift: false}; + _keys['pageup'] = {code:33, shift: false}; + _keys['pagedown'] = {code:34, shift: false}; + // symbols + _keys['='] = {code:187, shift: false}; + _keys['-'] = {code:189, shift: false}; + _keys[']'] = {code:221, shift: false}; + _keys['['] = {code:219, shift: false}; - this._drawRawCircle(ctx, this.x, this.y, this.options.radius); - this.boundingBox.top = this.y - this.options.radius; - this.boundingBox.left = this.x - this.options.radius; - this.boundingBox.right = this.x + this.options.radius; - this.boundingBox.bottom = this.y + this.options.radius; - this._label(ctx, this.label, this.x, this.y); - }; + var down = function(event) {handleEvent(event,'keydown');}; + var up = function(event) {handleEvent(event,'keyup');}; - Node.prototype._resizeEllipse = function (ctx) { - if (!this.width) { - var textSize = this.getTextSize(ctx); + // handle the actualy bound key with the event + var handleEvent = function(event,type) { + if (_bound[type][event.keyCode] !== undefined) { + var bound = _bound[type][event.keyCode]; + for (var i = 0; i < bound.length; i++) { + if (bound[i].shift === undefined) { + bound[i].fn(event); + } + else if (bound[i].shift == true && event.shiftKey == true) { + bound[i].fn(event); + } + else if (bound[i].shift == false && event.shiftKey == false) { + bound[i].fn(event); + } + } - this.width = textSize.width * 1.5; - this.height = textSize.height * 2; - if (this.width < this.height) { - this.width = this.height; - } - var defaultSize = this.width; + if (preventDefault == true) { + event.preventDefault(); + } + } + }; - // scaling used for clustering - this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; - this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; - this.options.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor; - this.growthIndicator = this.width - defaultSize; - } - }; + // bind a key to a callback + _exportFunctions.bind = function(key, callback, type) { + if (type === undefined) { + type = 'keydown'; + } + if (_keys[key] === undefined) { + throw new Error("unsupported key: " + key); + } + if (_bound[type][_keys[key].code] === undefined) { + _bound[type][_keys[key].code] = []; + } + _bound[type][_keys[key].code].push({fn:callback, shift:_keys[key].shift}); + }; - Node.prototype._drawEllipse = function (ctx) { - this._resizeEllipse(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - var clusterLineWidth = 2.5; - var borderWidth = this.options.borderWidth; - var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; + // bind all keys to a call back (demo purposes) + _exportFunctions.bindAll = function(callback, type) { + if (type === undefined) { + type = 'keydown'; + } + for (var key in _keys) { + if (_keys.hasOwnProperty(key)) { + _exportFunctions.bind(key,callback,type); + } + } + }; - ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; + // get the key label from an event + _exportFunctions.getKey = function(event) { + for (var key in _keys) { + if (_keys.hasOwnProperty(key)) { + if (event.shiftKey == true && _keys[key].shift == true && event.keyCode == _keys[key].code) { + return key; + } + else if (event.shiftKey == false && _keys[key].shift == false && event.keyCode == _keys[key].code) { + return key; + } + else if (event.keyCode == _keys[key].code && key == 'shift') { + return key; + } + } + } + return "unknown key, currently not supported"; + }; - // draw the outer border - if (this.clusterSize > 1) { - ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.networkScaleInv; - ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + // unbind either a specific callback from a key or all of them (by leaving callback undefined) + _exportFunctions.unbind = function(key, callback, type) { + if (type === undefined) { + type = 'keydown'; + } + if (_keys[key] === undefined) { + throw new Error("unsupported key: " + key); + } + if (callback !== undefined) { + var newBindings = []; + var bound = _bound[type][_keys[key].code]; + if (bound !== undefined) { + for (var i = 0; i < bound.length; i++) { + if (!(bound[i].fn == callback && bound[i].shift == _keys[key].shift)) { + newBindings.push(_bound[type][_keys[key].code][i]); + } + } + } + _bound[type][_keys[key].code] = newBindings; + } + else { + _bound[type][_keys[key].code] = []; + } + }; - ctx.ellipse(this.left-2*ctx.lineWidth, this.top-2*ctx.lineWidth, this.width+4*ctx.lineWidth, this.height+4*ctx.lineWidth); - ctx.stroke(); - } - ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.networkScaleInv; - ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + // reset all bound variables. + _exportFunctions.reset = function() { + _bound = {keydown:{}, keyup:{}}; + }; - ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; + // unbind all listeners and reset all variables. + _exportFunctions.destroy = function() { + _bound = {keydown:{}, keyup:{}}; + container.removeEventListener('keydown', down, true); + container.removeEventListener('keyup', up, true); + }; - ctx.ellipse(this.left, this.top, this.width, this.height); - ctx.fill(); - ctx.stroke(); + // create listeners. + container.addEventListener('keydown',down,true); + container.addEventListener('keyup',up,true); - this.boundingBox.top = this.top; - this.boundingBox.left = this.left; - this.boundingBox.right = this.left + this.width; - this.boundingBox.bottom = this.top + this.height; + // return the public functions. + return _exportFunctions; + } - this._label(ctx, this.label, this.x, this.y); - }; + return keycharm; + })); - Node.prototype._drawDot = function (ctx) { - this._drawShape(ctx, 'circle'); - }; - Node.prototype._drawTriangle = function (ctx) { - this._drawShape(ctx, 'triangle'); - }; - Node.prototype._drawTriangleDown = function (ctx) { - this._drawShape(ctx, 'triangleDown'); - }; - Node.prototype._drawSquare = function (ctx) { - this._drawShape(ctx, 'square'); - }; +/***/ }, +/* 37 */ +/***/ function(module, exports, __webpack_require__) { - Node.prototype._drawStar = function (ctx) { - this._drawShape(ctx, 'star'); - }; + var util = __webpack_require__(1); + var Component = __webpack_require__(23); + var TimeStep = __webpack_require__(38); + var DateUtil = __webpack_require__(24); + var moment = __webpack_require__(2); - Node.prototype._resizeShape = function (ctx) { - if (!this.width) { - this.options.radius= this.baseRadiusValue; - var size = 2 * this.options.radius; - this.width = size; - this.height = size; + /** + * A horizontal time axis + * @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} body + * @param {Object} [options] See TimeAxis.setOptions for the available + * options. + * @constructor TimeAxis + * @extends Component + */ + function TimeAxis (body, options) { + this.dom = { + foreground: null, + lines: [], + majorTexts: [], + minorTexts: [], + redundant: { + lines: [], + majorTexts: [], + minorTexts: [] + } + }; + this.props = { + range: { + start: 0, + end: 0, + minimumStep: 0 + }, + lineTop: 0 + }; - // scaling used for clustering - this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; - this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; - this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor; - this.growthIndicator = this.width - size; - } - }; + this.defaultOptions = { + orientation: 'bottom', // supported: 'top', 'bottom' + // TODO: implement timeaxis orientations 'left' and 'right' + showMinorLabels: true, + showMajorLabels: true, + format: null + }; + this.options = util.extend({}, this.defaultOptions); - Node.prototype._drawShape = function (ctx, shape) { - this._resizeShape(ctx); + this.body = body; - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; + // create the HTML DOM + this._create(); - var clusterLineWidth = 2.5; - var borderWidth = this.options.borderWidth; - var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; - var radiusMultiplier = 2; + this.setOptions(options); + } - // choose draw method depending on the shape - switch (shape) { - case 'dot': radiusMultiplier = 2; break; - case 'square': radiusMultiplier = 2; break; - case 'triangle': radiusMultiplier = 3; break; - case 'triangleDown': radiusMultiplier = 3; break; - case 'star': radiusMultiplier = 4; break; - } + TimeAxis.prototype = new Component(); - ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; - // draw the outer border - if (this.clusterSize > 1) { - ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.networkScaleInv; - ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + /** + * Set options for the TimeAxis. + * Parameters will be merged in current options. + * @param {Object} options Available options: + * {string} [orientation] + * {boolean} [showMinorLabels] + * {boolean} [showMajorLabels] + */ + TimeAxis.prototype.setOptions = function(options) { + if (options) { + // copy all options that we know + util.selectiveExtend([ + 'orientation', + 'showMinorLabels', + 'showMajorLabels', + 'hiddenDates', + 'format' + ], this.options, options); - ctx[shape](this.x, this.y, this.options.radius+ radiusMultiplier * ctx.lineWidth); - ctx.stroke(); + // 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); + } + } } - ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.networkScaleInv; - ctx.lineWidth = Math.min(this.width,ctx.lineWidth); - - ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; - ctx[shape](this.x, this.y, this.options.radius); - ctx.fill(); - ctx.stroke(); + }; - this.boundingBox.top = this.y - this.options.radius; - this.boundingBox.left = this.x - this.options.radius; - this.boundingBox.right = this.x + this.options.radius; - this.boundingBox.bottom = this.y + this.options.radius; + /** + * Create the HTML DOM for the TimeAxis + */ + TimeAxis.prototype._create = function() { + this.dom.foreground = document.createElement('div'); + this.dom.background = document.createElement('div'); - if (this.label) { - this._label(ctx, this.label, this.x, this.y + this.height / 2, undefined, 'hanging',true); - this.boundingBox.left = Math.min(this.boundingBox.left, this.labelDimensions.left); - this.boundingBox.right = Math.max(this.boundingBox.right, this.labelDimensions.left + this.labelDimensions.width); - this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelDimensions.height); - } + this.dom.foreground.className = 'timeaxis foreground'; + this.dom.background.className = 'timeaxis background'; }; - Node.prototype._resizeText = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - this.width = textSize.width + 2 * margin; - this.height = textSize.height + 2 * margin; - - // scaling used for clustering - this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; - this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; - this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor; - this.growthIndicator = this.width - (textSize.width + 2 * margin); + /** + * Destroy the TimeAxis + */ + TimeAxis.prototype.destroy = function() { + // remove from DOM + if (this.dom.foreground.parentNode) { + this.dom.foreground.parentNode.removeChild(this.dom.foreground); + } + if (this.dom.background.parentNode) { + this.dom.background.parentNode.removeChild(this.dom.background); } + + this.body = null; }; - Node.prototype._drawText = function (ctx) { - this._resizeText(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; + /** + * Repaint the component + * @return {boolean} Returns true if the component is resized + */ + TimeAxis.prototype.redraw = function () { + var options = this.options; + var props = this.props; + var foreground = this.dom.foreground; + var background = this.dom.background; - this._label(ctx, this.label, this.x, this.y); + // determine the correct parent DOM element (depending on option orientation) + var parent = (options.orientation == 'top') ? this.body.dom.top : this.body.dom.bottom; + var parentChanged = (foreground.parentNode !== parent); - this.boundingBox.top = this.top; - this.boundingBox.left = this.left; - this.boundingBox.right = this.left + this.width; - this.boundingBox.bottom = this.top + this.height; - }; + // calculate character width and height + this._calculateCharSize(); + // TODO: recalculate sizes only needed when parent is resized or options is changed + var orientation = this.options.orientation, + showMinorLabels = this.options.showMinorLabels, + showMajorLabels = this.options.showMajorLabels; - Node.prototype._label = function (ctx, text, x, y, align, baseline, labelUnderNode) { - if (text && Number(this.options.fontSize) * this.networkScale > this.fontDrawThreshold) { - ctx.font = (this.selected ? "bold " : "") + this.options.fontSize + "px " + this.options.fontFace; - - var lines = text.split('\n'); - var lineCount = lines.length; - var fontSize = Number(this.options.fontSize); - var yLine = y + (1 - lineCount) / 2 * fontSize; - if (labelUnderNode == true) { - yLine = y + (1 - lineCount) / (2 * fontSize); - } - - // font fill from edges now for nodes! - var width = ctx.measureText(lines[0]).width; - for (var i = 1; i < lineCount; i++) { - var lineWidth = ctx.measureText(lines[i]).width; - width = lineWidth > width ? lineWidth : width; - } - var height = this.options.fontSize * lineCount; - var left = x - width / 2; - var top = y - height / 2; - if (baseline == "hanging") { - top += 0.5 * fontSize; - top += 4; // distance from node, required because we use hanging. Hanging has less difference between browsers - yLine += 4; // distance from node - } - this.labelDimensions = {top:top,left:left,width:width,height:height,yLine:yLine}; - - // create the fontfill background - if (this.options.fontFill !== undefined && this.options.fontFill !== null && this.options.fontFill !== "none") { - ctx.fillStyle = this.options.fontFill; - ctx.fillRect(left, top, width, height); - } - - // draw text - ctx.fillStyle = this.options.fontColor || "black"; - ctx.textAlign = align || "center"; - ctx.textBaseline = baseline || "middle"; - if (this.options.fontStrokeWidth > 0){ - ctx.lineWidth = this.options.fontStrokeWidth; - ctx.strokeStyle = this.options.fontStrokeColor; - ctx.lineJoin = 'round'; - } - for (var i = 0; i < lineCount; i++) { - if(this.options.fontStrokeWidth){ - ctx.strokeText(lines[i], x, yLine); - } - ctx.fillText(lines[i], x, yLine); - yLine += fontSize; - } - } - }; + // determine the width and height of the elemens for the axis + props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; + props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; + props.height = props.minorLabelHeight + props.majorLabelHeight; + props.width = foreground.offsetWidth; + props.minorLineHeight = this.body.domProps.root.height - props.majorLabelHeight - + (options.orientation == 'top' ? this.body.domProps.bottom.height : this.body.domProps.top.height); + props.minorLineWidth = 1; // TODO: really calculate width + props.majorLineHeight = props.minorLineHeight + props.majorLabelHeight; + props.majorLineWidth = 1; // TODO: really calculate width - Node.prototype.getTextSize = function(ctx) { - if (this.label !== undefined) { - ctx.font = (this.selected ? "bold " : "") + this.options.fontSize + "px " + this.options.fontFace; + // take foreground and background offline while updating (is almost twice as fast) + var foregroundNextSibling = foreground.nextSibling; + var backgroundNextSibling = background.nextSibling; + foreground.parentNode && foreground.parentNode.removeChild(foreground); + background.parentNode && background.parentNode.removeChild(background); - var lines = this.label.split('\n'), - height = (Number(this.options.fontSize) + 4) * lines.length, - width = 0; + foreground.style.height = this.props.height + 'px'; - for (var i = 0, iMax = lines.length; i < iMax; i++) { - width = Math.max(width, ctx.measureText(lines[i]).width); - } + this._repaintLabels(); - return {"width": width, "height": height, lineCount: lines.length}; + // put DOM online again (at the same place) + if (foregroundNextSibling) { + parent.insertBefore(foreground, foregroundNextSibling); } else { - return {"width": 0, "height": 0, lineCount: 0}; + parent.appendChild(foreground) } - }; - - /** - * this is used to determine if a node is visible at all. this is used to determine when it needs to be drawn. - * there is a safety margin of 0.3 * width; - * - * @returns {boolean} - */ - Node.prototype.inArea = function() { - if (this.width !== undefined) { - return (this.x + this.width *this.networkScaleInv >= this.canvasTopLeft.x && - this.x - this.width *this.networkScaleInv < this.canvasBottomRight.x && - this.y + this.height*this.networkScaleInv >= this.canvasTopLeft.y && - this.y - this.height*this.networkScaleInv < this.canvasBottomRight.y); + if (backgroundNextSibling) { + this.body.dom.backgroundVertical.insertBefore(background, backgroundNextSibling); } else { - return true; + this.body.dom.backgroundVertical.appendChild(background) } - }; - /** - * checks if the core of the node is in the display area, this is used for opening clusters around zoom - * @returns {boolean} - */ - Node.prototype.inView = function() { - return (this.x >= this.canvasTopLeft.x && - this.x < this.canvasBottomRight.x && - this.y >= this.canvasTopLeft.y && - this.y < this.canvasBottomRight.y); + return this._isResized() || parentChanged; }; /** - * This allows the zoom level of the network to influence the rendering - * We store the inverted scale and the coordinates of the top left, and bottom right points of the canvas - * - * @param scale - * @param canvasTopLeft - * @param canvasBottomRight + * Repaint major and minor text labels and vertical grid lines + * @private */ - Node.prototype.setScaleAndPos = function(scale,canvasTopLeft,canvasBottomRight) { - this.networkScaleInv = 1.0/scale; - this.networkScale = scale; - this.canvasTopLeft = canvasTopLeft; - this.canvasBottomRight = canvasBottomRight; - }; - + TimeAxis.prototype._repaintLabels = function () { + var orientation = this.options.orientation; - /** - * This allows the zoom level of the network to influence the rendering - * - * @param scale - */ - Node.prototype.setScale = function(scale) { - this.networkScaleInv = 1.0/scale; - this.networkScale = scale; - }; + // calculate range and step (step such that we have space for 7 characters per label) + var start = util.convert(this.body.range.start, 'Number'); + var end = util.convert(this.body.range.end, 'Number'); + var timeLabelsize = this.body.util.toTime((this.props.minorCharWidth || 10) * 7).valueOf(); + var minimumStep = timeLabelsize - DateUtil.getHiddenDurationBefore(this.body.hiddenDates, this.body.range, timeLabelsize); + minimumStep -= this.body.util.toTime(0).valueOf(); + var step = new TimeStep(new Date(start), new Date(end), minimumStep, this.body.hiddenDates); + if (this.options.format) { + step.setFormat(this.options.format); + } + this.step = step; + // Move all DOM elements to a "redundant" list, where they + // can be picked for re-use, and clear the lists with lines and texts. + // At the end of the function _repaintLabels, left over elements will be cleaned up + var dom = this.dom; + dom.redundant.lines = dom.lines; + dom.redundant.majorTexts = dom.majorTexts; + dom.redundant.minorTexts = dom.minorTexts; + dom.lines = []; + dom.majorTexts = []; + dom.minorTexts = []; - /** - * set the velocity at 0. Is called when this node is contained in another during clustering - */ - Node.prototype.clearVelocity = function() { - this.vx = 0; - this.vy = 0; - }; + var cur; + var x = 0; + var isMajor; + var xPrev = 0; + var width = 0; + var prevLine; + var xFirstMajorLabel = undefined; + var max = 0; + var className; + step.first(); + while (step.hasNext() && max < 1000) { + max++; - /** - * Basic preservation of (kinectic) energy - * - * @param massBeforeClustering - */ - Node.prototype.updateVelocity = function(massBeforeClustering) { - var energyBefore = this.vx * this.vx * massBeforeClustering; - //this.vx = (this.vx < 0) ? -Math.sqrt(energyBefore/this.options.mass) : Math.sqrt(energyBefore/this.options.mass); - this.vx = Math.sqrt(energyBefore/this.options.mass); - energyBefore = this.vy * this.vy * massBeforeClustering; - //this.vy = (this.vy < 0) ? -Math.sqrt(energyBefore/this.options.mass) : Math.sqrt(energyBefore/this.options.mass); - this.vy = Math.sqrt(energyBefore/this.options.mass); - }; + cur = step.getCurrent(); + isMajor = step.isMajor(); + className = step.getClassName(); - module.exports = Node; + xPrev = x; + x = this.body.util.toScreen(cur); + width = x - xPrev; + if (prevLine) { + prevLine.style.width = width + 'px'; + } + if (this.options.showMinorLabels) { + this._repaintMinorText(x, step.getLabelMinor(), orientation, className); + } -/***/ }, -/* 41 */ -/***/ function(module, exports, __webpack_require__) { + if (isMajor && this.options.showMajorLabels) { + if (x > 0) { + if (xFirstMajorLabel == undefined) { + xFirstMajorLabel = x; + } + this._repaintMajorText(x, step.getLabelMajor(), orientation, className); + } + prevLine = this._repaintMajorLine(x, orientation, className); + } + else { + prevLine = this._repaintMinorLine(x, orientation, className); + } - /** - * Popup is a class to create a popup window with some text - * @param {Element} container The container object. - * @param {Number} [x] - * @param {Number} [y] - * @param {String} [text] - * @param {Object} [style] An object containing borderColor, - * backgroundColor, etc. - */ - function Popup(container, x, y, text, style) { - if (container) { - this.container = container; + step.next(); } - else { - this.container = document.body; + + // create a major label on the left when needed + if (this.options.showMajorLabels) { + var leftTime = this.body.util.toTime(0), + leftText = step.getLabelMajor(leftTime), + widthText = leftText.length * (this.props.majorCharWidth || 10) + 10; // upper bound estimation + + if (xFirstMajorLabel == undefined || widthText < xFirstMajorLabel) { + this._repaintMajorText(0, leftText, orientation, className); + } } - // x, y and text are optional, see if a style object was passed in their place - if (style === undefined) { - if (typeof x === "object") { - style = x; - x = undefined; - } else if (typeof text === "object") { - style = text; - text = undefined; - } else { - // for backwards compatibility, in case clients other than Network are creating Popup directly - style = { - fontColor: 'black', - fontSize: 14, // px - fontFace: 'verdana', - color: { - border: '#666', - background: '#FFFFC6' - } + // Cleanup leftover DOM elements from the redundant list + util.forEach(this.dom.redundant, function (arr) { + while (arr.length) { + var elem = arr.pop(); + if (elem && elem.parentNode) { + elem.parentNode.removeChild(elem); } } - } + }); + }; - this.x = 0; - this.y = 0; - this.padding = 5; + /** + * Create a minor label for the axis at position x + * @param {Number} x + * @param {String} text + * @param {String} orientation "top" or "bottom" (default) + * @param {String} className + * @private + */ + TimeAxis.prototype._repaintMinorText = function (x, text, orientation, className) { + // reuse redundant label + var label = this.dom.redundant.minorTexts.shift(); - if (x !== undefined && y !== undefined ) { - this.setPosition(x, y); - } - if (text !== undefined) { - this.setText(text); + if (!label) { + // create new label + var content = document.createTextNode(''); + label = document.createElement('div'); + label.appendChild(content); + this.dom.foreground.appendChild(label); } + this.dom.minorTexts.push(label); - // create the frame - this.frame = document.createElement("div"); - var styleAttr = this.frame.style; - styleAttr.position = "absolute"; - styleAttr.visibility = "hidden"; - styleAttr.border = "1px solid " + style.color.border; - styleAttr.color = style.fontColor; - styleAttr.fontSize = style.fontSize + "px"; - styleAttr.fontFamily = style.fontFace; - styleAttr.padding = this.padding + "px"; - styleAttr.backgroundColor = style.color.background; - styleAttr.borderRadius = "3px"; - styleAttr.MozBorderRadius = "3px"; - styleAttr.WebkitBorderRadius = "3px"; - styleAttr.boxShadow = "3px 3px 10px rgba(128, 128, 128, 0.5)"; - styleAttr.whiteSpace = "nowrap"; - this.container.appendChild(this.frame); - } + label.childNodes[0].nodeValue = text; + + label.style.top = (orientation == 'top') ? (this.props.majorLabelHeight + 'px') : '0'; + label.style.left = x + 'px'; + label.className = 'text minor ' + className; + //label.title = title; // TODO: this is a heavy operation + }; /** - * @param {number} x Horizontal position of the popup window - * @param {number} y Vertical position of the popup window + * Create a Major label for the axis at position x + * @param {Number} x + * @param {String} text + * @param {String} orientation "top" or "bottom" (default) + * @param {String} className + * @private */ - Popup.prototype.setPosition = function(x, y) { - this.x = parseInt(x); - this.y = parseInt(y); + TimeAxis.prototype._repaintMajorText = function (x, text, orientation, className) { + // reuse redundant label + var label = this.dom.redundant.majorTexts.shift(); + + if (!label) { + // create label + var content = document.createTextNode(text); + label = document.createElement('div'); + label.appendChild(content); + this.dom.foreground.appendChild(label); + } + this.dom.majorTexts.push(label); + + label.childNodes[0].nodeValue = text; + label.className = 'text major ' + className; + //label.title = title; // TODO: this is a heavy operation + + label.style.top = (orientation == 'top') ? '0' : (this.props.minorLabelHeight + 'px'); + label.style.left = x + 'px'; }; /** - * Set the content for the popup window. This can be HTML code or text. - * @param {string | Element} content + * Create a minor line for the axis at position x + * @param {Number} x + * @param {String} orientation "top" or "bottom" (default) + * @param {String} className + * @return {Element} Returns the created line + * @private */ - Popup.prototype.setText = function(content) { - if (content instanceof Element) { - this.frame.innerHTML = ''; - this.frame.appendChild(content); + TimeAxis.prototype._repaintMinorLine = function (x, orientation, className) { + // reuse redundant line + var line = this.dom.redundant.lines.shift(); + if (!line) { + // create vertical line + line = document.createElement('div'); + this.dom.background.appendChild(line); + } + this.dom.lines.push(line); + + var props = this.props; + if (orientation == 'top') { + line.style.top = props.majorLabelHeight + 'px'; } else { - this.frame.innerHTML = content; // string containing text or HTML + line.style.top = this.body.domProps.top.height + 'px'; } + line.style.height = props.minorLineHeight + 'px'; + line.style.left = (x - props.minorLineWidth / 2) + 'px'; + + line.className = 'grid vertical minor ' + className; + + return line; }; /** - * Show the popup window - * @param {boolean} show Optional. Show or hide the window + * Create a Major line for the axis at position x + * @param {Number} x + * @param {String} orientation "top" or "bottom" (default) + * @param {String} className + * @return {Element} Returns the created line + * @private */ - Popup.prototype.show = function (show) { - if (show === undefined) { - show = true; + TimeAxis.prototype._repaintMajorLine = function (x, orientation, className) { + // reuse redundant line + var line = this.dom.redundant.lines.shift(); + if (!line) { + // create vertical line + line = document.createElement('div'); + this.dom.background.appendChild(line); } + this.dom.lines.push(line); - if (show) { - var height = this.frame.clientHeight; - var width = this.frame.clientWidth; - var maxHeight = this.frame.parentNode.clientHeight; - var maxWidth = this.frame.parentNode.clientWidth; + var props = this.props; + if (orientation == 'top') { + line.style.top = '0'; + } + else { + line.style.top = this.body.domProps.top.height + 'px'; + } + line.style.left = (x - props.majorLineWidth / 2) + 'px'; + line.style.height = props.majorLineHeight + 'px'; - var top = (this.y - height); - if (top + height + this.padding > maxHeight) { - top = maxHeight - height - this.padding; - } - if (top < this.padding) { - top = this.padding; - } + line.className = 'grid vertical major ' + className; - var left = this.x; - if (left + width + this.padding > maxWidth) { - left = maxWidth - width - this.padding; - } - if (left < this.padding) { - left = this.padding; - } + return line; + }; - this.frame.style.left = left + "px"; - this.frame.style.top = top + "px"; - this.frame.style.visibility = "visible"; + /** + * Determine the size of text on the axis (both major and minor axis). + * The size is calculated only once and then cached in this.props. + * @private + */ + TimeAxis.prototype._calculateCharSize = function () { + // Note: We calculate char size with every redraw. Size may change, for + // example when any of the timelines parents had display:none for example. + + // determine the char width and height on the minor axis + if (!this.dom.measureCharMinor) { + this.dom.measureCharMinor = document.createElement('DIV'); + this.dom.measureCharMinor.className = 'text minor measure'; + this.dom.measureCharMinor.style.position = 'absolute'; + + this.dom.measureCharMinor.appendChild(document.createTextNode('0')); + this.dom.foreground.appendChild(this.dom.measureCharMinor); } - else { - this.hide(); + this.props.minorCharHeight = this.dom.measureCharMinor.clientHeight; + this.props.minorCharWidth = this.dom.measureCharMinor.clientWidth; + + // determine the char width and height on the major axis + if (!this.dom.measureCharMajor) { + this.dom.measureCharMajor = document.createElement('DIV'); + this.dom.measureCharMajor.className = 'text major measure'; + this.dom.measureCharMajor.style.position = 'absolute'; + + this.dom.measureCharMajor.appendChild(document.createTextNode('0')); + this.dom.foreground.appendChild(this.dom.measureCharMajor); } + this.props.majorCharHeight = this.dom.measureCharMajor.clientHeight; + this.props.majorCharWidth = this.dom.measureCharMajor.clientWidth; }; /** - * Hide the popup window + * 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 */ - Popup.prototype.hide = function () { - this.frame.style.visibility = "hidden"; + TimeAxis.prototype.snap = function(date) { + return this.step.snap(date); }; - module.exports = Popup; + module.exports = TimeAxis; /***/ }, -/* 42 */ +/* 38 */ /***/ function(module, exports, __webpack_require__) { + var moment = __webpack_require__(2); + var DateUtil = __webpack_require__(24); + var util = __webpack_require__(1); + /** - * Parse a text source containing data in DOT language into a JSON object. - * The object contains two lists: one with nodes and one with edges. + * @constructor TimeStep + * The class TimeStep is an iterator for dates. You provide a start date and an + * end date. The class itself determines the best scale (step size) based on the + * provided start Date, end Date, and minimumStep. * - * DOT language reference: http://www.graphviz.org/doc/info/lang.html + * 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 {String} data Text containing a graph in DOT-notation - * @return {Object} graph An object containing two parameters: - * {Object[]} nodes - * {Object[]} edges + * Alternatively, you can set a scale by hand. + * After creation, you can initialize the class by executing first(). Then you + * can iterate from the start date to the end date via next(). You can check if + * the end date is reached with the function hasNext(). After each step, you can + * retrieve the current date via getCurrent(). + * The TimeStep has scales ranging from milliseconds, seconds, minutes, hours, + * days, to years. + * + * Version: 1.2 + * + * @param {Date} [start] The start date, for example new Date(2010, 9, 21) + * or new Date(2010, 9, 21, 23, 45, 00) + * @param {Date} [end] The end date + * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds */ - function parseDOT (data) { - dot = data; - return parseGraph(); - } - - // token types enumeration - var TOKENTYPE = { - NULL : 0, - DELIMITER : 1, - IDENTIFIER: 2, - UNKNOWN : 3 - }; + function TimeStep(start, end, minimumStep, hiddenDates) { + // variables + this.current = new Date(); + this._start = new Date(); + this._end = new Date(); - // map with all delimiters - var DELIMITERS = { - '{': true, - '}': true, - '[': true, - ']': true, - ';': true, - '=': true, - ',': true, + this.autoScale = true; + this.scale = 'day'; + this.step = 1; - '->': true, - '--': true - }; + // initialize the range + this.setRange(start, end, minimumStep); - var dot = ''; // current dot file - var index = 0; // current index in dot file - var c = ''; // current token character in expr - var token = ''; // current token - var tokenType = TOKENTYPE.NULL; // type of the token + // hidden Dates options + this.switchedDay = false; + this.switchedMonth = false; + this.switchedYear = false; + this.hiddenDates = hiddenDates; + if (hiddenDates === undefined) { + this.hiddenDates = []; + } - /** - * Get the first character from the dot file. - * The character is stored into the char c. If the end of the dot file is - * reached, the function puts an empty string in c. - */ - function first() { - index = 0; - c = dot.charAt(0); + this.format = TimeStep.FORMAT; // default formatting } + // Time formatting + TimeStep.FORMAT = { + minorLabels: { + millisecond:'SSS', + second: 's', + minute: 'HH:mm', + hour: 'HH:mm', + weekday: 'ddd D', + day: 'D', + month: 'MMM', + year: 'YYYY' + }, + majorLabels: { + millisecond:'HH:mm:ss', + second: 'D MMMM HH:mm', + minute: 'ddd D MMMM', + hour: 'ddd D MMMM', + weekday: 'MMMM YYYY', + day: 'MMMM YYYY', + month: 'YYYY', + year: '' + } + }; + /** - * Get the next character from the dot file. - * The character is stored into the char c. If the end of the dot file is - * reached, the function puts an empty string in c. + * Set custom formatting for the minor an major labels of the TimeStep. + * Both `minorLabels` and `majorLabels` are an Object with properties: + * 'millisecond, 'second, 'minute', 'hour', 'weekday, 'day, 'month, 'year'. + * @param {{minorLabels: Object, majorLabels: Object}} format */ - function next() { - index++; - c = dot.charAt(index); - } + TimeStep.prototype.setFormat = function (format) { + var defaultFormat = util.deepExtend({}, TimeStep.FORMAT); + this.format = util.deepExtend(defaultFormat, format); + }; /** - * Preview the next character from the dot file. - * @return {String} cNext + * Set a new range + * If minimumStep is provided, the step size is chosen as close as possible + * to the minimumStep but larger than minimumStep. If minimumStep is not + * provided, the scale is set to 1 DAY. + * The minimumStep should correspond with the onscreen size of about 6 characters + * @param {Date} [start] The start date and time. + * @param {Date} [end] The end date and time. + * @param {int} [minimumStep] Optional. Minimum step size in milliseconds */ - function nextPreview() { - return dot.charAt(index + 1); - } + TimeStep.prototype.setRange = function(start, end, minimumStep) { + if (!(start instanceof Date) || !(end instanceof Date)) { + throw "No legal start or end date in method setRange"; + } + + this._start = (start != undefined) ? new Date(start.valueOf()) : new Date(); + this._end = (end != undefined) ? new Date(end.valueOf()) : new Date(); + + if (this.autoScale) { + this.setMinimumStep(minimumStep); + } + }; /** - * Test whether given character is alphabetic or numeric - * @param {String} c - * @return {Boolean} isAlphaNumeric + * Set the range iterator to the start date. */ - var regexAlphaNumeric = /[a-zA-Z_0-9.:#]/; - function isAlphaNumeric(c) { - return regexAlphaNumeric.test(c); - } + TimeStep.prototype.first = function() { + this.current = new Date(this._start.valueOf()); + this.roundToMinor(); + }; /** - * Merge all properties of object b into object b - * @param {Object} a - * @param {Object} b - * @return {Object} a + * Round the current date to the first minor date value + * This must be executed once when the current date is set to start Date */ - function merge (a, b) { - if (!a) { - a = {}; + TimeStep.prototype.roundToMinor = function() { + // round to floor + // IMPORTANT: we have no breaks in this switch! (this is no bug) + // noinspection FallThroughInSwitchStatementJS + switch (this.scale) { + case 'year': + this.current.setFullYear(this.step * Math.floor(this.current.getFullYear() / this.step)); + this.current.setMonth(0); + case 'month': this.current.setDate(1); + case 'day': // intentional fall through + case 'weekday': this.current.setHours(0); + case 'hour': this.current.setMinutes(0); + case 'minute': this.current.setSeconds(0); + case 'second': this.current.setMilliseconds(0); + //case 'millisecond': // nothing to do for milliseconds } - if (b) { - for (var name in b) { - if (b.hasOwnProperty(name)) { - a[name] = b[name]; - } + if (this.step != 1) { + // round down to the first minor value that is a multiple of the current step size + switch (this.scale) { + case 'millisecond': this.current.setMilliseconds(this.current.getMilliseconds() - this.current.getMilliseconds() % this.step); break; + case 'second': this.current.setSeconds(this.current.getSeconds() - this.current.getSeconds() % this.step); break; + case 'minute': this.current.setMinutes(this.current.getMinutes() - this.current.getMinutes() % this.step); break; + case 'hour': this.current.setHours(this.current.getHours() - this.current.getHours() % this.step); break; + case 'weekday': // intentional fall through + case 'day': this.current.setDate((this.current.getDate()-1) - (this.current.getDate()-1) % this.step + 1); break; + case 'month': this.current.setMonth(this.current.getMonth() - this.current.getMonth() % this.step); break; + case 'year': this.current.setFullYear(this.current.getFullYear() - this.current.getFullYear() % this.step); break; + default: break; } } - return a; - } + }; /** - * Set a value in an object, where the provided parameter name can be a - * path with nested parameters. For example: - * - * var obj = {a: 2}; - * setValue(obj, 'b.c', 3); // obj = {a: 2, b: {c: 3}} - * - * @param {Object} obj - * @param {String} path A parameter name or dot-separated parameter path, - * like "color.highlight.border". - * @param {*} value + * Check if the there is a next step + * @return {boolean} true if the current date has not passed the end date */ - function setValue(obj, path, value) { - var keys = path.split('.'); - var o = obj; - while (keys.length) { - var key = keys.shift(); - if (keys.length) { - // this isn't the end point - if (!o[key]) { - o[key] = {}; - } - o = o[key]; - } - else { - // this is the end point - o[key] = value; - } - } - } + TimeStep.prototype.hasNext = function () { + return (this.current.valueOf() <= this._end.valueOf()); + }; /** - * Add a node to a graph object. If there is already a node with - * the same id, their attributes will be merged. - * @param {Object} graph - * @param {Object} node + * Do the next step */ - function addNode(graph, node) { - var i, len; - var current = null; + TimeStep.prototype.next = function() { + var prev = this.current.valueOf(); - // find root graph (in case of subgraph) - var graphs = [graph]; // list with all graphs from current graph to root graph - var root = graph; - while (root.parent) { - graphs.push(root.parent); - root = root.parent; - } + // Two cases, needed to prevent issues with switching daylight savings + // (end of March and end of October) + if (this.current.getMonth() < 6) { + switch (this.scale) { + case 'millisecond': - // find existing node (at root level) by its id - if (root.nodes) { - for (i = 0, len = root.nodes.length; i < len; i++) { - if (node.id === root.nodes[i].id) { - current = root.nodes[i]; + this.current = new Date(this.current.valueOf() + this.step); break; + case 'second': this.current = new Date(this.current.valueOf() + this.step * 1000); break; + case 'minute': this.current = new Date(this.current.valueOf() + this.step * 1000 * 60); break; + case 'hour': + this.current = new Date(this.current.valueOf() + this.step * 1000 * 60 * 60); + // in case of skipping an hour for daylight savings, adjust the hour again (else you get: 0h 5h 9h ... instead of 0h 4h 8h ...) + var h = this.current.getHours(); + this.current.setHours(h - (h % this.step)); break; - } + case 'weekday': // intentional fall through + case 'day': this.current.setDate(this.current.getDate() + this.step); break; + case 'month': this.current.setMonth(this.current.getMonth() + this.step); break; + case 'year': this.current.setFullYear(this.current.getFullYear() + this.step); break; + default: break; } } - - if (!current) { - // this is a new node - current = { - id: node.id - }; - if (graph.node) { - // clone default attributes - current.attr = merge(current.attr, graph.node); + else { + switch (this.scale) { + case 'millisecond': this.current = new Date(this.current.valueOf() + this.step); break; + case 'second': this.current.setSeconds(this.current.getSeconds() + this.step); break; + case 'minute': this.current.setMinutes(this.current.getMinutes() + this.step); break; + case 'hour': this.current.setHours(this.current.getHours() + this.step); break; + case 'weekday': // intentional fall through + case 'day': this.current.setDate(this.current.getDate() + this.step); break; + case 'month': this.current.setMonth(this.current.getMonth() + this.step); break; + case 'year': this.current.setFullYear(this.current.getFullYear() + this.step); break; + default: break; } } - // add node to this (sub)graph and all its parent graphs - for (i = graphs.length - 1; i >= 0; i--) { - var g = graphs[i]; - - if (!g.nodes) { - g.nodes = []; - } - if (g.nodes.indexOf(current) == -1) { - g.nodes.push(current); + if (this.step != 1) { + // round down to the correct major value + switch (this.scale) { + case 'millisecond': if(this.current.getMilliseconds() < this.step) this.current.setMilliseconds(0); break; + case 'second': if(this.current.getSeconds() < this.step) this.current.setSeconds(0); break; + case 'minute': if(this.current.getMinutes() < this.step) this.current.setMinutes(0); break; + case 'hour': if(this.current.getHours() < this.step) this.current.setHours(0); break; + case 'weekday': // intentional fall through + case 'day': if(this.current.getDate() < this.step+1) this.current.setDate(1); break; + case 'month': if(this.current.getMonth() < this.step) this.current.setMonth(0); break; + case 'year': break; // nothing to do for year + default: break; } } - // merge attributes - if (node.attr) { - current.attr = merge(current.attr, node.attr); + // safety mechanism: if current time is still unchanged, move to the end + if (this.current.valueOf() == prev) { + this.current = new Date(this._end.valueOf()); } - } + + DateUtil.stepOverHiddenDates(this, prev); + }; + /** - * Add an edge to a graph object - * @param {Object} graph - * @param {Object} edge + * Get the current datetime + * @return {Date} current The current date */ - function addEdge(graph, edge) { - if (!graph.edges) { - graph.edges = []; - } - graph.edges.push(edge); - if (graph.edge) { - var attr = merge({}, graph.edge); // clone default attributes - edge.attr = merge(attr, edge.attr); // merge attributes - } - } + TimeStep.prototype.getCurrent = function() { + return this.current; + }; /** - * Create an edge to a graph object - * @param {Object} graph - * @param {String | Number | Object} from - * @param {String | Number | Object} to - * @param {String} type - * @param {Object | null} attr - * @return {Object} edge + * Set a custom scale. Autoscaling will be disabled. + * For example setScale(SCALE.MINUTES, 5) will result + * in minor steps of 5 minutes, and major steps of an hour. + * + * @param {string} newScale + * A scale. Choose from 'millisecond, 'second, + * 'minute', 'hour', 'weekday, 'day, 'month, 'year'. + * @param {Number} newStep A step size, by default 1. Choose for + * example 1, 2, 5, or 10. */ - function createEdge(graph, from, to, type, attr) { - var edge = { - from: from, - to: to, - type: type - }; + TimeStep.prototype.setScale = function(newScale, newStep) { + this.scale = newScale; - if (graph.edge) { - edge.attr = merge({}, graph.edge); // clone default attributes + if (newStep > 0) { + this.step = newStep; } - edge.attr = merge(edge.attr || {}, attr); // merge attributes - return edge; - } + this.autoScale = false; + }; /** - * Get next token in the current dot file. - * The token and token type are available as token and tokenType + * Enable or disable autoscaling + * @param {boolean} enable If true, autoascaling is set true */ - function getToken() { - tokenType = TOKENTYPE.NULL; - token = ''; - - // skip over whitespaces - while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter - next(); - } - - do { - var isComment = false; - - // skip comment - if (c == '#') { - // find the previous non-space character - var i = index - 1; - while (dot.charAt(i) == ' ' || dot.charAt(i) == '\t') { - i--; - } - if (dot.charAt(i) == '\n' || dot.charAt(i) == '') { - // the # is at the start of a line, this is indeed a line comment - while (c != '' && c != '\n') { - next(); - } - isComment = true; - } - } - if (c == '/' && nextPreview() == '/') { - // skip line comment - while (c != '' && c != '\n') { - next(); - } - isComment = true; - } - if (c == '/' && nextPreview() == '*') { - // skip block comment - while (c != '') { - if (c == '*' && nextPreview() == '/') { - // end of block comment found. skip these last two characters - next(); - next(); - break; - } - else { - next(); - } - } - isComment = true; - } + TimeStep.prototype.setAutoScale = function (enable) { + this.autoScale = enable; + }; - // skip over whitespaces - while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter - next(); - } - } - while (isComment); - // check for end of dot file - if (c == '') { - // token is still empty - tokenType = TOKENTYPE.DELIMITER; + /** + * Automatically determine the scale that bests fits the provided minimum step + * @param {Number} [minimumStep] The minimum step size in milliseconds + */ + TimeStep.prototype.setMinimumStep = function(minimumStep) { + if (minimumStep == undefined) { return; } - // check for delimiters consisting of 2 characters - var c2 = c + nextPreview(); - if (DELIMITERS[c2]) { - tokenType = TOKENTYPE.DELIMITER; - token = c2; - next(); - next(); - return; - } + //var b = asc + ds; - // check for delimiters consisting of 1 character - if (DELIMITERS[c]) { - tokenType = TOKENTYPE.DELIMITER; - token = c; - next(); - return; - } + var stepYear = (1000 * 60 * 60 * 24 * 30 * 12); + var stepMonth = (1000 * 60 * 60 * 24 * 30); + var stepDay = (1000 * 60 * 60 * 24); + var stepHour = (1000 * 60 * 60); + var stepMinute = (1000 * 60); + var stepSecond = (1000); + var stepMillisecond= (1); - // check for an identifier (number or string) - // TODO: more precise parsing of numbers/strings (and the port separator ':') - if (isAlphaNumeric(c) || c == '-') { - token += c; - next(); + // find the smallest step that is larger than the provided minimumStep + if (stepYear*1000 > minimumStep) {this.scale = 'year'; this.step = 1000;} + if (stepYear*500 > minimumStep) {this.scale = 'year'; this.step = 500;} + if (stepYear*100 > minimumStep) {this.scale = 'year'; this.step = 100;} + if (stepYear*50 > minimumStep) {this.scale = 'year'; this.step = 50;} + if (stepYear*10 > minimumStep) {this.scale = 'year'; this.step = 10;} + if (stepYear*5 > minimumStep) {this.scale = 'year'; this.step = 5;} + if (stepYear > minimumStep) {this.scale = 'year'; this.step = 1;} + if (stepMonth*3 > minimumStep) {this.scale = 'month'; this.step = 3;} + if (stepMonth > minimumStep) {this.scale = 'month'; this.step = 1;} + if (stepDay*5 > minimumStep) {this.scale = 'day'; this.step = 5;} + if (stepDay*2 > minimumStep) {this.scale = 'day'; this.step = 2;} + if (stepDay > minimumStep) {this.scale = 'day'; this.step = 1;} + if (stepDay/2 > minimumStep) {this.scale = 'weekday'; this.step = 1;} + if (stepHour*4 > minimumStep) {this.scale = 'hour'; this.step = 4;} + if (stepHour > minimumStep) {this.scale = 'hour'; this.step = 1;} + if (stepMinute*15 > minimumStep) {this.scale = 'minute'; this.step = 15;} + if (stepMinute*10 > minimumStep) {this.scale = 'minute'; this.step = 10;} + if (stepMinute*5 > minimumStep) {this.scale = 'minute'; this.step = 5;} + if (stepMinute > minimumStep) {this.scale = 'minute'; this.step = 1;} + if (stepSecond*15 > minimumStep) {this.scale = 'second'; this.step = 15;} + if (stepSecond*10 > minimumStep) {this.scale = 'second'; this.step = 10;} + if (stepSecond*5 > minimumStep) {this.scale = 'second'; this.step = 5;} + if (stepSecond > minimumStep) {this.scale = 'second'; this.step = 1;} + if (stepMillisecond*200 > minimumStep) {this.scale = 'millisecond'; this.step = 200;} + if (stepMillisecond*100 > minimumStep) {this.scale = 'millisecond'; this.step = 100;} + if (stepMillisecond*50 > minimumStep) {this.scale = 'millisecond'; this.step = 50;} + if (stepMillisecond*10 > minimumStep) {this.scale = 'millisecond'; this.step = 10;} + if (stepMillisecond*5 > minimumStep) {this.scale = 'millisecond'; this.step = 5;} + if (stepMillisecond > minimumStep) {this.scale = 'millisecond'; this.step = 1;} + }; - while (isAlphaNumeric(c)) { - token += c; - next(); + /** + * 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 + */ + TimeStep.prototype.snap = function(date) { + var clone = new Date(date.valueOf()); + + if (this.scale == 'year') { + var year = clone.getFullYear() + Math.round(clone.getMonth() / 12); + clone.setFullYear(Math.round(year / this.step) * this.step); + clone.setMonth(0); + clone.setDate(0); + clone.setHours(0); + clone.setMinutes(0); + clone.setSeconds(0); + clone.setMilliseconds(0); + } + else if (this.scale == 'month') { + if (clone.getDate() > 15) { + clone.setDate(1); + clone.setMonth(clone.getMonth() + 1); + // important: first set Date to 1, after that change the month. } - if (token == 'false') { - token = false; // convert to boolean + else { + clone.setDate(1); } - else if (token == 'true') { - token = true; // convert to boolean + + clone.setHours(0); + clone.setMinutes(0); + clone.setSeconds(0); + clone.setMilliseconds(0); + } + else if (this.scale == 'day') { + //noinspection FallthroughInSwitchStatementJS + switch (this.step) { + case 5: + case 2: + clone.setHours(Math.round(clone.getHours() / 24) * 24); break; + default: + clone.setHours(Math.round(clone.getHours() / 12) * 12); break; } - else if (!isNaN(Number(token))) { - token = Number(token); // convert to number + clone.setMinutes(0); + clone.setSeconds(0); + clone.setMilliseconds(0); + } + else if (this.scale == 'weekday') { + //noinspection FallthroughInSwitchStatementJS + switch (this.step) { + case 5: + case 2: + clone.setHours(Math.round(clone.getHours() / 12) * 12); break; + default: + clone.setHours(Math.round(clone.getHours() / 6) * 6); break; } - tokenType = TOKENTYPE.IDENTIFIER; - return; + clone.setMinutes(0); + clone.setSeconds(0); + clone.setMilliseconds(0); } - - // check for a string enclosed by double quotes - if (c == '"') { - next(); - while (c != '' && (c != '"' || (c == '"' && nextPreview() == '"'))) { - token += c; - if (c == '"') { // skip the escape character - next(); - } - next(); + else if (this.scale == 'hour') { + switch (this.step) { + case 4: + clone.setMinutes(Math.round(clone.getMinutes() / 60) * 60); break; + default: + clone.setMinutes(Math.round(clone.getMinutes() / 30) * 30); break; } - if (c != '"') { - throw newSyntaxError('End of string " expected'); + clone.setSeconds(0); + clone.setMilliseconds(0); + } else if (this.scale == 'minute') { + //noinspection FallthroughInSwitchStatementJS + switch (this.step) { + case 15: + case 10: + clone.setMinutes(Math.round(clone.getMinutes() / 5) * 5); + clone.setSeconds(0); + break; + case 5: + clone.setSeconds(Math.round(clone.getSeconds() / 60) * 60); break; + default: + clone.setSeconds(Math.round(clone.getSeconds() / 30) * 30); break; } - next(); - tokenType = TOKENTYPE.IDENTIFIER; - return; + clone.setMilliseconds(0); } - - // something unknown is found, wrong characters, a syntax error - tokenType = TOKENTYPE.UNKNOWN; - while (c != '') { - token += c; - next(); + else if (this.scale == 'second') { + //noinspection FallthroughInSwitchStatementJS + switch (this.step) { + case 15: + case 10: + clone.setSeconds(Math.round(clone.getSeconds() / 5) * 5); + clone.setMilliseconds(0); + break; + case 5: + clone.setMilliseconds(Math.round(clone.getMilliseconds() / 1000) * 1000); break; + default: + clone.setMilliseconds(Math.round(clone.getMilliseconds() / 500) * 500); break; + } } - throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"'); - } + else if (this.scale == 'millisecond') { + var step = this.step > 5 ? this.step / 2 : 1; + clone.setMilliseconds(Math.round(clone.getMilliseconds() / step) * step); + } + + return clone; + }; /** - * Parse a graph. - * @returns {Object} graph + * 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. */ - function parseGraph() { - var graph = {}; - - first(); - getToken(); - - // optional strict keyword - if (token == 'strict') { - graph.strict = true; - getToken(); + TimeStep.prototype.isMajor = function() { + if (this.switchedYear == true) { + this.switchedYear = false; + switch (this.scale) { + case 'year': + case 'month': + case 'weekday': + case 'day': + case 'hour': + case 'minute': + case 'second': + case 'millisecond': + return true; + default: + return false; + } } - - // graph or digraph keyword - if (token == 'graph' || token == 'digraph') { - graph.type = token; - getToken(); + else if (this.switchedMonth == true) { + this.switchedMonth = false; + switch (this.scale) { + case 'weekday': + case 'day': + case 'hour': + case 'minute': + case 'second': + case 'millisecond': + return true; + default: + return false; + } } - - // optional graph id - if (tokenType == TOKENTYPE.IDENTIFIER) { - graph.id = token; - getToken(); + else if (this.switchedDay == true) { + this.switchedDay = false; + switch (this.scale) { + case 'millisecond': + case 'second': + case 'minute': + case 'hour': + return true; + default: + return false; + } } - // open angle bracket - if (token != '{') { - throw newSyntaxError('Angle bracket { expected'); + switch (this.scale) { + case 'millisecond': + return (this.current.getMilliseconds() == 0); + case 'second': + return (this.current.getSeconds() == 0); + case 'minute': + return (this.current.getHours() == 0) && (this.current.getMinutes() == 0); + case 'hour': + return (this.current.getHours() == 0); + case 'weekday': // intentional fall through + case 'day': + return (this.current.getDate() == 1); + case 'month': + return (this.current.getMonth() == 0); + case 'year': + return false; + default: + return false; } - getToken(); - - // statements - parseStatements(graph); + }; - // close angle bracket - if (token != '}') { - throw newSyntaxError('Angle bracket } expected'); - } - getToken(); - // end of file - if (token !== '') { - throw newSyntaxError('End of file expected'); + /** + * Returns formatted text for the minor axislabel, depending on the current + * date and the scale. For example when scale is MINUTE, the current time is + * formatted as "hh:mm". + * @param {Date} [date] custom date. if not provided, current date is taken + */ + TimeStep.prototype.getLabelMinor = function(date) { + if (date == undefined) { + date = this.current; } - getToken(); - - // remove temporary default properties - delete graph.node; - delete graph.edge; - delete graph.graph; - return graph; - } + var format = this.format.minorLabels[this.scale]; + return (format && format.length > 0) ? moment(date).format(format) : ''; + }; /** - * Parse a list with statements. - * @param {Object} graph + * Returns formatted text for the major axis label, depending on the current + * date and the scale. For example when scale is MINUTE, the major scale is + * hours, and the hour will be formatted as "hh". + * @param {Date} [date] custom date. if not provided, current date is taken */ - function parseStatements (graph) { - while (token !== '' && token != '}') { - parseStatement(graph); - if (token == ';') { - getToken(); - } + TimeStep.prototype.getLabelMajor = function(date) { + if (date == undefined) { + date = this.current; } - } - /** - * Parse a single statement. Can be a an attribute statement, node - * statement, a series of node statements and edge statements, or a - * parameter. - * @param {Object} graph - */ - function parseStatement(graph) { - // parse subgraph - var subgraph = parseSubgraph(graph); - if (subgraph) { - // edge statements - parseEdge(graph, subgraph); + var format = this.format.majorLabels[this.scale]; + return (format && format.length > 0) ? moment(date).format(format) : ''; + }; - return; + TimeStep.prototype.getClassName = function() { + var m = moment(this.current); + var date = m.locale ? m.locale('en') : m.lang('en'); // old versions of moment have .lang() function + var step = this.step; + + function even(value) { + return (value / step % 2 == 0) ? ' even' : ' odd'; } - // parse an attribute statement - var attr = parseAttributeStatement(graph); - if (attr) { - return; + function today(date) { + if (date.isSame(new Date(), 'day')) { + return ' today'; + } + if (date.isSame(moment().add(1, 'day'), 'day')) { + return ' tomorrow'; + } + if (date.isSame(moment().add(-1, 'day'), 'day')) { + return ' yesterday'; + } + return ''; } - // parse node - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier expected'); + function currentWeek(date) { + return date.isSame(new Date(), 'week') ? ' current-week' : ''; } - var id = token; // id can be a string or a number - getToken(); - if (token == '=') { - // id statement - getToken(); - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier expected'); - } - graph[id] = token; - getToken(); - // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] " + function currentMonth(date) { + return date.isSame(new Date(), 'month') ? ' current-month' : ''; } - else { - parseNodeStatement(graph, id); + + function currentYear(date) { + return date.isSame(new Date(), 'year') ? ' current-year' : ''; } - } - /** - * Parse a subgraph - * @param {Object} graph parent graph object - * @return {Object | null} subgraph - */ - function parseSubgraph (graph) { - var subgraph = null; + switch (this.scale) { + case 'millisecond': + return even(date.milliseconds()).trim(); - // optional subgraph keyword - if (token == 'subgraph') { - subgraph = {}; - subgraph.type = 'subgraph'; - getToken(); + case 'second': + return even(date.seconds()).trim(); - // optional graph id - if (tokenType == TOKENTYPE.IDENTIFIER) { - subgraph.id = token; - getToken(); - } - } + case 'minute': + return even(date.minutes()).trim(); - // open angle bracket - if (token == '{') { - getToken(); + case 'hour': + var hours = date.hours(); + if (this.step == 4) { + hours = hours + '-' + (hours + 4); + } + return hours + 'h' + today(date) + even(date.hours()); - if (!subgraph) { - subgraph = {}; - } - subgraph.parent = graph; - subgraph.node = graph.node; - subgraph.edge = graph.edge; - subgraph.graph = graph.graph; + case 'weekday': + return date.format('dddd').toLowerCase() + + today(date) + currentWeek(date) + even(date.date()); - // statements - parseStatements(subgraph); + case 'day': + var day = date.date(); + var month = date.format('MMMM').toLowerCase(); + return 'day' + day + ' ' + month + currentMonth(date) + even(day - 1); - // close angle bracket - if (token != '}') { - throw newSyntaxError('Angle bracket } expected'); - } - getToken(); + case 'month': + return date.format('MMMM').toLowerCase() + + currentMonth(date) + even(date.month()); - // remove temporary default properties - delete subgraph.node; - delete subgraph.edge; - delete subgraph.graph; - delete subgraph.parent; + case 'year': + var year = date.year(); + return 'year' + year + currentYear(date)+ even(year); - // register at the parent graph - if (!graph.subgraphs) { - graph.subgraphs = []; - } - graph.subgraphs.push(subgraph); + default: + return ''; } + }; - return subgraph; - } + module.exports = TimeStep; + + +/***/ }, +/* 39 */ +/***/ function(module, exports, __webpack_require__) { + + var util = __webpack_require__(1); + var Component = __webpack_require__(23); + var moment = __webpack_require__(2); + var locales = __webpack_require__(40); /** - * parse an attribute statement like "node [shape=circle fontSize=16]". - * Available keywords are 'node', 'edge', 'graph'. - * The previous list with default attributes will be replaced - * @param {Object} graph - * @returns {String | null} keyword Returns the name of the parsed attribute - * (node, edge, graph), or null if nothing - * is parsed. + * A current time bar + * @param {{range: Range, dom: Object, domProps: Object}} body + * @param {Object} [options] Available parameters: + * {Boolean} [showCurrentTime] + * @constructor CurrentTime + * @extends Component */ - function parseAttributeStatement (graph) { - // attribute statements - if (token == 'node') { - getToken(); + function CurrentTime (body, options) { + this.body = body; - // node attributes - graph.node = parseAttributeList(); - return 'node'; - } - else if (token == 'edge') { - getToken(); + // default options + this.defaultOptions = { + showCurrentTime: true, - // edge attributes - graph.edge = parseAttributeList(); - return 'edge'; - } - else if (token == 'graph') { - getToken(); + locales: locales, + locale: 'en' + }; + this.options = util.extend({}, this.defaultOptions); + this.offset = 0; - // graph attributes - graph.graph = parseAttributeList(); - return 'graph'; - } + this._create(); - return null; + this.setOptions(options); } + CurrentTime.prototype = new Component(); + /** - * parse a node statement - * @param {Object} graph - * @param {String | Number} id + * Create the HTML DOM for the current time bar + * @private */ - function parseNodeStatement(graph, id) { - // node statement - var node = { - id: id - }; - var attr = parseAttributeList(); - if (attr) { - node.attr = attr; - } - addNode(graph, node); + CurrentTime.prototype._create = function() { + var bar = document.createElement('div'); + bar.className = 'currenttime'; + bar.style.position = 'absolute'; + bar.style.top = '0px'; + bar.style.height = '100%'; - // edge statements - parseEdge(graph, id); - } + this.bar = bar; + }; /** - * Parse an edge or a series of edges - * @param {Object} graph - * @param {String | Number} from Id of the from node + * Destroy the CurrentTime bar */ - function parseEdge(graph, from) { - while (token == '->' || token == '--') { - var to; - var type = token; - getToken(); - - var subgraph = parseSubgraph(graph); - if (subgraph) { - to = subgraph; - } - else { - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier or subgraph expected'); - } - to = token; - addNode(graph, { - id: to - }); - getToken(); - } - - // parse edge attributes - var attr = parseAttributeList(); + CurrentTime.prototype.destroy = function () { + this.options.showCurrentTime = false; + this.redraw(); // will remove the bar from the DOM and stop refreshing - // create edge - var edge = createEdge(graph, from, to, type, attr); - addEdge(graph, edge); + this.body = null; + }; - from = to; + /** + * Set options for the component. Options will be merged in current options. + * @param {Object} options Available parameters: + * {boolean} [showCurrentTime] + */ + CurrentTime.prototype.setOptions = function(options) { + if (options) { + // copy all options that we know + util.selectiveExtend(['showCurrentTime', 'locale', 'locales'], this.options, options); } - } + }; /** - * Parse a set with attributes, - * for example [label="1.000", shape=solid] - * @return {Object | null} attr + * Repaint the component + * @return {boolean} Returns true if the component is resized */ - function parseAttributeList() { - var attr = null; - - while (token == '[') { - getToken(); - attr = {}; - while (token !== '' && token != ']') { - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Attribute name expected'); + CurrentTime.prototype.redraw = function() { + if (this.options.showCurrentTime) { + var parent = this.body.dom.backgroundVertical; + if (this.bar.parentNode != parent) { + // attach to the dom + if (this.bar.parentNode) { + this.bar.parentNode.removeChild(this.bar); } - var name = token; + parent.appendChild(this.bar); - getToken(); - if (token != '=') { - throw newSyntaxError('Equal sign = expected'); - } - getToken(); + this.start(); + } - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Attribute value expected'); - } - var value = token; - setValue(attr, name, value); // name can be a path + var now = new Date(new Date().valueOf() + this.offset); + var x = this.body.util.toScreen(now); - getToken(); - if (token ==',') { - getToken(); - } - } + 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); - if (token != ']') { - throw newSyntaxError('Bracket ] expected'); + this.bar.style.left = x + 'px'; + this.bar.title = title; + } + else { + // remove the line from the DOM + if (this.bar.parentNode) { + this.bar.parentNode.removeChild(this.bar); } - getToken(); + this.stop(); } - return attr; - } + return false; + }; /** - * Create a syntax error with extra information on current token and index. - * @param {String} message - * @returns {SyntaxError} err + * Start auto refreshing the current time bar */ - function newSyntaxError(message) { - return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ')'); - } + CurrentTime.prototype.start = function() { + var me = this; + + function update () { + me.stop(); + + // determine interval to refresh + var scale = me.body.range.conversion(me.body.domProps.center.width).scale; + var interval = 1 / scale / 10; + if (interval < 30) interval = 30; + if (interval > 1000) interval = 1000; + + me.redraw(); + + // start a timer to adjust for the new time + me.currentTimeTimer = setTimeout(update, interval); + } + + update(); + }; /** - * Chop off text after a maximum length - * @param {String} text - * @param {Number} maxLength - * @returns {String} + * Stop auto refreshing the current time bar */ - function chop (text, maxLength) { - return (text.length <= maxLength) ? text : (text.substr(0, 27) + '...'); - } + CurrentTime.prototype.stop = function() { + if (this.currentTimeTimer !== undefined) { + clearTimeout(this.currentTimeTimer); + delete this.currentTimeTimer; + } + }; /** - * Execute a function fn for each pair of elements in two arrays - * @param {Array | *} array1 - * @param {Array | *} array2 - * @param {function} fn + * Set a current time. This can be used for example to ensure that a client's + * time is synchronized with a shared server time. + * @param {Date | String | Number} time A Date, unix timestamp, or + * ISO date string. */ - function forEach2(array1, array2, fn) { - if (Array.isArray(array1)) { - array1.forEach(function (elem1) { - if (Array.isArray(array2)) { - array2.forEach(function (elem2) { - fn(elem1, elem2); - }); - } - else { - fn(elem1, array2); - } - }); - } - else { - if (Array.isArray(array2)) { - array2.forEach(function (elem2) { - fn(array1, elem2); - }); - } - else { - fn(array1, array2); - } - } - } + CurrentTime.prototype.setCurrentTime = function(time) { + var t = util.convert(time, 'Date').valueOf(); + var now = new Date().valueOf(); + this.offset = t - now; + this.redraw(); + }; /** - * Convert a string containing a graph in DOT language into a map containing - * with nodes and edges in the format of graph. - * @param {String} data Text containing a graph in DOT-notation - * @return {Object} graphData + * Get the current time. + * @return {Date} Returns the current time. */ - function DOTToGraph (data) { - // parse the DOT file - var dotData = parseDOT(data); - var graphData = { - nodes: [], - edges: [], - options: {} - }; + CurrentTime.prototype.getCurrentTime = function() { + return new Date(new Date().valueOf() + this.offset); + }; - // copy the nodes - if (dotData.nodes) { - dotData.nodes.forEach(function (dotNode) { - var graphNode = { - id: dotNode.id, - label: String(dotNode.label || dotNode.id) - }; - merge(graphNode, dotNode.attr); - if (graphNode.image) { - graphNode.shape = 'image'; - } - graphData.nodes.push(graphNode); - }); - } + module.exports = CurrentTime; - // copy the edges - if (dotData.edges) { - /** - * Convert an edge in DOT format to an edge with VisGraph format - * @param {Object} dotEdge - * @returns {Object} graphEdge - */ - var convertEdge = function (dotEdge) { - var graphEdge = { - from: dotEdge.from, - to: dotEdge.to - }; - merge(graphEdge, dotEdge.attr); - graphEdge.style = (dotEdge.type == '->') ? 'arrow' : 'line'; - return graphEdge; - } - dotData.edges.forEach(function (dotEdge) { - var from, to; - if (dotEdge.from instanceof Object) { - from = dotEdge.from.nodes; - } - else { - from = { - id: dotEdge.from - } - } +/***/ }, +/* 40 */ +/***/ function(module, exports, __webpack_require__) { - if (dotEdge.to instanceof Object) { - to = dotEdge.to.nodes; - } - else { - to = { - id: dotEdge.to - } - } + // English + exports['en'] = { + current: 'current', + time: 'time' + }; + exports['en_EN'] = exports['en']; + exports['en_US'] = exports['en']; - if (dotEdge.from instanceof Object && dotEdge.from.edges) { - dotEdge.from.edges.forEach(function (subEdge) { - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - } + // Dutch + exports['nl'] = { + custom: 'aangepaste', + time: 'tijd' + }; + exports['nl_NL'] = exports['nl']; + exports['nl_BE'] = exports['nl']; - forEach2(from, to, function (from, to) { - var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr); - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - if (dotEdge.to instanceof Object && dotEdge.to.edges) { - dotEdge.to.edges.forEach(function (subEdge) { - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - } - }); - } +/***/ }, +/* 41 */ +/***/ function(module, exports, __webpack_require__) { - // copy the options - if (dotData.attr) { - graphData.options = dotData.attr; - } + var Hammer = __webpack_require__(19); + var util = __webpack_require__(1); + var Component = __webpack_require__(23); + var moment = __webpack_require__(2); + var locales = __webpack_require__(40); - return graphData; - } + /** + * A custom time bar + * @param {{range: Range, dom: Object}} body + * @param {Object} [options] Available parameters: + * {Boolean} [showCustomTime] + * @constructor CustomTime + * @extends Component + */ - // exports - exports.parseDOT = parseDOT; - exports.DOTToGraph = DOTToGraph; + function CustomTime (body, options) { + this.body = body; + + // default options + this.defaultOptions = { + showCustomTime: false, + locales: locales, + locale: 'en' + }; + this.options = util.extend({}, this.defaultOptions); + this.customTime = new Date(); + this.eventParams = {}; // stores state parameters while dragging the bar -/***/ }, -/* 43 */ -/***/ function(module, exports, __webpack_require__) { + // create the DOM + this._create(); - - function parseGephi(gephiJSON, options) { - var edges = []; - var nodes = []; - this.options = { - edges: { - inheritColor: true - }, - nodes: { - allowedToMove: false, - parseColor: false - } - }; + this.setOptions(options); + } - if (options !== undefined) { - this.options.nodes['allowedToMove'] = options.allowedToMove | false; - this.options.nodes['parseColor'] = options.parseColor | false; - this.options.edges['inheritColor'] = options.inheritColor | true; - } + CustomTime.prototype = new Component(); - var gEdges = gephiJSON.edges; - var gNodes = gephiJSON.nodes; - for (var i = 0; i < gEdges.length; i++) { - var edge = {}; - var gEdge = gEdges[i]; - edge['id'] = gEdge.id; - edge['from'] = gEdge.source; - edge['to'] = gEdge.target; - edge['attributes'] = gEdge.attributes; - // edge['value'] = gEdge.attributes !== undefined ? gEdge.attributes.Weight : undefined; - // edge['width'] = edge['value'] !== undefined ? undefined : edgegEdge.size; - edge['color'] = gEdge.color; - edge['inheritColor'] = edge['color'] !== undefined ? false : this.options.inheritColor; - edges.push(edge); + /** + * Set options for the component. Options will be merged in current options. + * @param {Object} options Available parameters: + * {boolean} [showCustomTime] + */ + CustomTime.prototype.setOptions = function(options) { + if (options) { + // copy all options that we know + util.selectiveExtend(['showCustomTime', 'locale', 'locales'], this.options, options); } + }; - for (var i = 0; i < gNodes.length; i++) { - var node = {}; - var gNode = gNodes[i]; - node['id'] = gNode.id; - node['attributes'] = gNode.attributes; - node['x'] = gNode.x; - node['y'] = gNode.y; - node['label'] = gNode.label; - if (this.options.nodes.parseColor == true) { - node['color'] = gNode.color; + /** + * Create the DOM for the custom time + * @private + */ + CustomTime.prototype._create = function() { + var bar = document.createElement('div'); + bar.className = 'customtime'; + bar.style.position = 'absolute'; + bar.style.top = '0px'; + bar.style.height = '100%'; + this.bar = bar; + + var drag = document.createElement('div'); + drag.style.position = 'relative'; + drag.style.top = '0px'; + drag.style.left = '-10px'; + drag.style.height = '100%'; + drag.style.width = '20px'; + bar.appendChild(drag); + + // attach event listeners + this.hammer = Hammer(bar, { + prevent_default: true + }); + this.hammer.on('dragstart', this._onDragStart.bind(this)); + this.hammer.on('drag', this._onDrag.bind(this)); + this.hammer.on('dragend', this._onDragEnd.bind(this)); + }; + + /** + * Destroy the CustomTime bar + */ + CustomTime.prototype.destroy = function () { + this.options.showCustomTime = false; + this.redraw(); // will remove the bar from the DOM + + this.hammer.enable(false); + this.hammer = null; + + this.body = null; + }; + + /** + * Repaint the component + * @return {boolean} Returns true if the component is resized + */ + CustomTime.prototype.redraw = function () { + if (this.options.showCustomTime) { + var parent = this.body.dom.backgroundVertical; + if (this.bar.parentNode != parent) { + // attach to the dom + if (this.bar.parentNode) { + this.bar.parentNode.removeChild(this.bar); + } + parent.appendChild(this.bar); } - else { - node['color'] = gNode.color !== undefined ? {background:gNode.color, border:gNode.color} : undefined; + + 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 = title; + } + else { + // remove the line from the DOM + if (this.bar.parentNode) { + this.bar.parentNode.removeChild(this.bar); } - node['radius'] = gNode.size; - node['allowedToMoveX'] = this.options.nodes.allowedToMove; - node['allowedToMoveY'] = this.options.nodes.allowedToMove; - nodes.push(node); } - return {nodes:nodes, edges:edges}; - } + return false; + }; - exports.parseGephi = parseGephi; + /** + * Set custom time. + * @param {Date | number | string} time + */ + CustomTime.prototype.setCustomTime = function(time) { + this.customTime = util.convert(time, 'Date'); + this.redraw(); + }; -/***/ }, -/* 44 */ -/***/ function(module, exports, __webpack_require__) { + /** + * Retrieve the current custom time. + * @return {Date} customTime + */ + CustomTime.prototype.getCustomTime = function() { + return new Date(this.customTime.valueOf()); + }; - // first check if moment.js is already loaded in the browser window, if so, - // use this instance. Else, load via commonjs. - module.exports = (typeof window !== 'undefined') && window['moment'] || __webpack_require__(58); + /** + * Start moving horizontally + * @param {Event} event + * @private + */ + CustomTime.prototype._onDragStart = function(event) { + this.eventParams.dragging = true; + this.eventParams.customTime = this.customTime; + event.stopPropagation(); + event.preventDefault(); + }; -/***/ }, -/* 45 */ -/***/ function(module, exports, __webpack_require__) { + /** + * Perform moving operating. + * @param {Event} event + * @private + */ + CustomTime.prototype._onDrag = function (event) { + if (!this.eventParams.dragging) return; - // Only load hammer.js when in a browser environment - // (loading hammer.js in a node.js environment gives errors) - if (typeof window !== 'undefined') { - module.exports = window['Hammer'] || __webpack_require__(59); - } - else { - module.exports = function () { - throw Error('hammer.js is only available in a browser, not in node.js.'); - } - } + var deltaX = event.gesture.deltaX, + x = this.body.util.toScreen(this.eventParams.customTime) + deltaX, + time = this.body.util.toTime(x); + + this.setCustomTime(time); + + // fire a timechange event + this.body.emitter.emit('timechange', { + time: new Date(this.customTime.valueOf()) + }); + + event.stopPropagation(); + event.preventDefault(); + }; + + /** + * Stop moving operating. + * @param {event} event + * @private + */ + CustomTime.prototype._onDragEnd = function (event) { + if (!this.eventParams.dragging) return; + + // fire a timechanged event + this.body.emitter.emit('timechanged', { + time: new Date(this.customTime.valueOf()) + }); + + event.stopPropagation(); + event.preventDefault(); + }; + + module.exports = CustomTime; /***/ }, -/* 46 */ +/* 42 */ /***/ function(module, exports, __webpack_require__) { - var Emitter = __webpack_require__(56); - var Hammer = __webpack_require__(45); + var Emitter = __webpack_require__(11); + var Hammer = __webpack_require__(19); var util = __webpack_require__(1); - var DataSet = __webpack_require__(3); - var DataView = __webpack_require__(4); - var Range = __webpack_require__(17); - var ItemSet = __webpack_require__(27); - var Activator = __webpack_require__(55); - var DateUtil = __webpack_require__(15); + var DataSet = __webpack_require__(7); + var DataView = __webpack_require__(9); + var Range = __webpack_require__(21); + var Core = __webpack_require__(25); + var TimeAxis = __webpack_require__(37); + var CurrentTime = __webpack_require__(39); + var CustomTime = __webpack_require__(41); + var LineGraph = __webpack_require__(43); /** * Create a timeline visualization * @param {HTMLElement} container * @param {vis.DataSet | Array | google.visualization.DataTable} [items] - * @param {Object} [options] See Core.setOptions for the available options. + * @param {Object} [options] See Graph2d.setOptions for the available options. * @constructor + * @extends Core */ - function Core () {} + function Graph2d (container, items, groups, options) { + // if the third element is options, the forth is groups (optionally); + if (!(Array.isArray(groups) || groups instanceof DataSet) && groups instanceof Object) { + var forthArgument = options; + options = groups; + groups = forthArgument; + } - // turn Core into an event emitter - Emitter(Core.prototype); + var me = this; + this.defaultOptions = { + start: null, + end: null, - /** - * Create the main DOM for the Core: a root panel containing left, right, - * top, bottom, content, and background panel. - * @param {Element} container The container element where the Core will - * be attached. - * @private - */ - Core.prototype._create = function (container) { - this.dom = {}; - - this.dom.root = document.createElement('div'); - this.dom.background = document.createElement('div'); - this.dom.backgroundVertical = document.createElement('div'); - this.dom.backgroundHorizontal = document.createElement('div'); - this.dom.centerContainer = document.createElement('div'); - this.dom.leftContainer = document.createElement('div'); - this.dom.rightContainer = document.createElement('div'); - this.dom.center = document.createElement('div'); - this.dom.left = document.createElement('div'); - this.dom.right = document.createElement('div'); - this.dom.top = document.createElement('div'); - this.dom.bottom = document.createElement('div'); - this.dom.shadowTop = document.createElement('div'); - this.dom.shadowBottom = document.createElement('div'); - this.dom.shadowTopLeft = document.createElement('div'); - this.dom.shadowBottomLeft = document.createElement('div'); - this.dom.shadowTopRight = document.createElement('div'); - this.dom.shadowBottomRight = document.createElement('div'); - - this.dom.root.className = 'vis timeline root'; - this.dom.background.className = 'vispanel background'; - this.dom.backgroundVertical.className = 'vispanel background vertical'; - this.dom.backgroundHorizontal.className = 'vispanel background horizontal'; - this.dom.centerContainer.className = 'vispanel center'; - this.dom.leftContainer.className = 'vispanel left'; - this.dom.rightContainer.className = 'vispanel right'; - this.dom.top.className = 'vispanel top'; - this.dom.bottom.className = 'vispanel bottom'; - this.dom.left.className = 'content'; - this.dom.center.className = 'content'; - this.dom.right.className = 'content'; - this.dom.shadowTop.className = 'shadow top'; - this.dom.shadowBottom.className = 'shadow bottom'; - this.dom.shadowTopLeft.className = 'shadow top'; - this.dom.shadowBottomLeft.className = 'shadow bottom'; - this.dom.shadowTopRight.className = 'shadow top'; - this.dom.shadowBottomRight.className = 'shadow bottom'; - - this.dom.root.appendChild(this.dom.background); - this.dom.root.appendChild(this.dom.backgroundVertical); - this.dom.root.appendChild(this.dom.backgroundHorizontal); - this.dom.root.appendChild(this.dom.centerContainer); - this.dom.root.appendChild(this.dom.leftContainer); - this.dom.root.appendChild(this.dom.rightContainer); - this.dom.root.appendChild(this.dom.top); - this.dom.root.appendChild(this.dom.bottom); + autoResize: true, - this.dom.centerContainer.appendChild(this.dom.center); - this.dom.leftContainer.appendChild(this.dom.left); - this.dom.rightContainer.appendChild(this.dom.right); + orientation: 'bottom', + width: null, + height: null, + maxHeight: null, + minHeight: null + }; + this.options = util.deepExtend({}, this.defaultOptions); - this.dom.centerContainer.appendChild(this.dom.shadowTop); - this.dom.centerContainer.appendChild(this.dom.shadowBottom); - this.dom.leftContainer.appendChild(this.dom.shadowTopLeft); - this.dom.leftContainer.appendChild(this.dom.shadowBottomLeft); - this.dom.rightContainer.appendChild(this.dom.shadowTopRight); - this.dom.rightContainer.appendChild(this.dom.shadowBottomRight); + // Create the DOM, props, and emitter + this._create(container); - this.on('rangechange', this.redraw.bind(this)); - this.on('touch', this._onTouch.bind(this)); - this.on('pinch', this._onPinch.bind(this)); - this.on('dragstart', this._onDragStart.bind(this)); - this.on('drag', this._onDrag.bind(this)); + // all components listed here will be repainted automatically + this.components = []; - var me = this; - this.on('change', function (properties) { - if (properties && properties.queue == true) { - // redraw once on next tick - if (!me._redrawTimer) { - me._redrawTimer = setTimeout(function () { - me._redrawTimer = null; - me.redraw(); - }, 0) - } - } - else { - // redraw immediately - me.redraw(); + this.body = { + dom: this.dom, + domProps: this.props, + emitter: { + on: this.on.bind(this), + off: this.off.bind(this), + emit: this.emit.bind(this) + }, + hiddenDates: [], + util: { + snap: null, // will be specified after TimeAxis is created + toScreen: me._toScreen.bind(me), + toGlobalScreen: me._toGlobalScreen.bind(me), // this refers to the root.width + toTime: me._toTime.bind(me), + toGlobalTime : me._toGlobalTime.bind(me) } - }); - - // create event listeners for all interesting events, these events will be - // emitted via emitter - this.hammer = Hammer(this.dom.root, { - preventDefault: true - }); - this.listeners = {}; - - var events = [ - 'touch', 'pinch', - 'tap', 'doubletap', 'hold', - 'dragstart', 'drag', 'dragend', - 'mousewheel', 'DOMMouseScroll' // DOMMouseScroll is needed for Firefox - ]; - events.forEach(function (event) { - var listener = function () { - var args = [event].concat(Array.prototype.slice.call(arguments, 0)); - if (me.isActive()) { - me.emit.apply(me, args); - } - }; - me.hammer.on(event, listener); - me.listeners[event] = listener; - }); - - // size properties of each of the panels - this.props = { - root: {}, - background: {}, - centerContainer: {}, - leftContainer: {}, - rightContainer: {}, - center: {}, - left: {}, - right: {}, - top: {}, - bottom: {}, - border: {}, - scrollTop: 0, - scrollTopMin: 0 }; - this.touch = {}; // store state information needed for touch events - this.redrawCount = 0; + // range + this.range = new Range(this.body); + this.components.push(this.range); + this.body.range = this.range; - // attach the root panel to the provided container - if (!container) throw new Error('No container provided'); - container.appendChild(this.dom.root); - }; + // time axis + this.timeAxis = new TimeAxis(this.body); + this.components.push(this.timeAxis); + this.body.util.snap = this.timeAxis.snap.bind(this.timeAxis); - /** - * Set options. Options will be passed to all components loaded in the Timeline. - * @param {Object} [options] - * {String} orientation - * Vertical orientation for the Timeline, - * can be 'bottom' (default) or 'top'. - * {String | Number} width - * Width for the timeline, a number in pixels or - * a css string like '1000px' or '75%'. '100%' by default. - * {String | Number} height - * Fixed height for the Timeline, a number in pixels or - * a css string like '400px' or '75%'. If undefined, - * The Timeline will automatically size such that - * its contents fit. - * {String | Number} minHeight - * Minimum height for the Timeline, a number in pixels or - * a css string like '400px' or '75%'. - * {String | Number} maxHeight - * Maximum height for the Timeline, a number in pixels or - * a css string like '400px' or '75%'. - * {Number | Date | String} start - * Start date for the visible window - * {Number | Date | String} end - * End date for the visible window - */ - Core.prototype.setOptions = function (options) { - if (options) { - // copy the known options - var fields = ['width', 'height', 'minHeight', 'maxHeight', 'autoResize', 'start', 'end', 'orientation', 'clickToUse', 'dataAttributes', 'hiddenDates']; - util.selectiveExtend(fields, this.options, options); + // current time bar + this.currentTime = new CurrentTime(this.body); + this.components.push(this.currentTime); - if ('hiddenDates' in this.options) { - DateUtil.convertHiddenOptions(this.body, this.options.hiddenDates); - } + // custom time bar + // Note: time bar will be attached in this.setOptions when selected + this.customTime = new CustomTime(this.body); + this.components.push(this.customTime); - if ('clickToUse' in options) { - if (options.clickToUse) { - if (!this.activator) { - this.activator = new Activator(this.dom.root); - } - } - else { - if (this.activator) { - this.activator.destroy(); - delete this.activator; - } - } - } + // item set + this.linegraph = new LineGraph(this.body); + this.components.push(this.linegraph); - // enable/disable autoResize - this._initAutoResize(); - } + this.itemsData = null; // DataSet + this.groupsData = null; // DataSet - // propagate options to all components - this.components.forEach(function (component) { - component.setOptions(options); - }); + // apply options + if (options) { + this.setOptions(options); + } - // TODO: remove deprecation error one day (deprecated since version 0.8.0) - if (options && options.order) { - throw new Error('Option order is deprecated. There is no replacement for this feature.'); + // IMPORTANT: THIS HAPPENS BEFORE SET ITEMS! + if (groups) { + this.setGroups(groups); } - // redraw everything - this.redraw(); - }; + // create itemset + if (items) { + this.setItems(items); + } + else { + this.redraw(); + } + } - /** - * Returns true when the Timeline is active. - * @returns {boolean} - */ - Core.prototype.isActive = function () { - return !this.activator || this.activator.active; - }; + // Extend the functionality from Core + Graph2d.prototype = new Core(); /** - * Destroy the Core, clean up all DOM elements and event listeners. + * Set items + * @param {vis.DataSet | Array | google.visualization.DataTable | null} items */ - Core.prototype.destroy = function () { - // unbind datasets - this.clear(); - - // remove all event listeners - this.off(); - - // stop checking for changed size - this._stopAutoResize(); + Graph2d.prototype.setItems = function(items) { + var initialLoad = (this.itemsData == null); - // remove from DOM - if (this.dom.root.parentNode) { - this.dom.root.parentNode.removeChild(this.dom.root); + // convert to type DataSet when needed + var newDataSet; + if (!items) { + newDataSet = null; } - this.dom = null; - - // remove Activator - if (this.activator) { - this.activator.destroy(); - delete this.activator; + else if (items instanceof DataSet || items instanceof DataView) { + newDataSet = items; } - - // cleanup hammer touch events - for (var event in this.listeners) { - if (this.listeners.hasOwnProperty(event)) { - delete this.listeners[event]; - } + else { + // turn an array into a dataset + newDataSet = new DataSet(items, { + type: { + start: 'Date', + end: 'Date' + } + }); } - this.listeners = null; - this.hammer = null; - - // give all components the opportunity to cleanup - this.components.forEach(function (component) { - component.destroy(); - }); - this.body = null; - }; + // set items + this.itemsData = newDataSet; + this.linegraph && this.linegraph.setItems(newDataSet); + if (initialLoad) { + if (this.options.start != undefined || this.options.end != undefined) { + var start = this.options.start != undefined ? this.options.start : null; + var end = this.options.end != undefined ? this.options.end : null; - /** - * Set a custom time bar - * @param {Date} time - */ - Core.prototype.setCustomTime = function (time) { - if (!this.customTime) { - throw new Error('Cannot get custom time: Custom time bar is not enabled'); + this.setWindow(start, end, {animate: false}); + } + else { + this.fit({animate: false}); + } } - - this.customTime.setCustomTime(time); }; /** - * Retrieve the current custom time. - * @return {Date} customTime + * Set groups + * @param {vis.DataSet | Array | google.visualization.DataTable} groups */ - Core.prototype.getCustomTime = function() { - if (!this.customTime) { - throw new Error('Cannot get custom time: Custom time bar is not enabled'); + Graph2d.prototype.setGroups = function(groups) { + // convert to type DataSet when needed + var newDataSet; + if (!groups) { + newDataSet = null; + } + else if (groups instanceof DataSet || groups instanceof DataView) { + newDataSet = groups; + } + else { + // turn an array into a dataset + newDataSet = new DataSet(groups); } - return this.customTime.getCustomTime(); - }; - - - /** - * Get the id's of the currently visible items. - * @returns {Array} The ids of the visible items - */ - Core.prototype.getVisibleItems = function() { - return this.itemSet && this.itemSet.getVisibleItems() || []; + this.groupsData = newDataSet; + this.linegraph.setGroups(newDataSet); }; - - /** - * Clear the Core. By Default, items, groups and options are cleared. - * Example usage: - * - * timeline.clear(); // clear items, groups, and options - * timeline.clear({options: true}); // clear options only - * - * @param {Object} [what] Optionally specify what to clear. By default: - * {items: true, groups: true, options: true} + * Returns an object containing an SVG element with the icon of the group (size determined by iconWidth and iconHeight), the label of the group (content) and the yAxisOrientation of the group (left or right). + * @param groupId + * @param width + * @param height */ - Core.prototype.clear = function(what) { - // clear items - if (!what || what.items) { - this.setItems(null); - } - - // clear groups - if (!what || what.groups) { - this.setGroups(null); + Graph2d.prototype.getLegend = function(groupId, width, height) { + if (width === undefined) {width = 15;} + if (height === undefined) {height = 15;} + if (this.linegraph.groups[groupId] !== undefined) { + return this.linegraph.groups[groupId].getLegend(width,height); } - - // clear options of timeline and of each of the components - if (!what || what.options) { - this.components.forEach(function (component) { - component.setOptions(component.defaultOptions); - }); - - this.setOptions(this.defaultOptions); // this will also do a redraw + else { + return "cannot find group:" + groupId; } - }; + } /** - * Set Core window such that it fits all items - * @param {Object} [options] Available options: - * `animate: boolean | number` - * If true (default), the range is animated - * smoothly to the new window. - * If a number, the number is taken as duration - * for the animation. Default duration is 500 ms. + * This checks if the visible option of the supplied group (by ID) is true or false. + * @param groupId + * @returns {*} */ - Core.prototype.fit = function(options) { - var range = this._getDataRange(); - - // skip range set if there is no start and end date - if (range.start === null && range.end === null) { - return; + Graph2d.prototype.isGroupVisible = function(groupId) { + if (this.linegraph.groups[groupId] !== undefined) { + return (this.linegraph.groups[groupId].visible && (this.linegraph.options.groups.visibility[groupId] === undefined || this.linegraph.options.groups.visibility[groupId] == true)); + } + else { + return false; } + } - var animate = (options && options.animate !== undefined) ? options.animate : true; - this.range.setRange(range.start, range.end, animate); - }; /** - * Calculate the data range of the items and applies a 5% window around it. - * @returns {{start: Date | null, end: Date | null}} - * @protected + * Get the data range of the item set. + * @returns {{min: Date, max: Date}} range A range with a start and end Date. + * When no minimum is found, min==null + * When no maximum is found, max==null */ - Core.prototype._getDataRange = function() { - // apply the data range as range - var dataRange = this.getItemRange(); + Graph2d.prototype.getItemRange = function() { + var min = null; + var max = null; - // add 5% space on both sides - var start = dataRange.min; - var end = dataRange.max; - if (start != null && end != null) { - var interval = (end.valueOf() - start.valueOf()); - if (interval <= 0) { - // prevent an empty interval - interval = 24 * 60 * 60 * 1000; // 1 day + // calculate min from start filed + for (var groupId in this.linegraph.groups) { + if (this.linegraph.groups.hasOwnProperty(groupId)) { + if (this.linegraph.groups[groupId].visible == true) { + for (var i = 0; i < this.linegraph.groups[groupId].itemsData.length; i++) { + var item = this.linegraph.groups[groupId].itemsData[i]; + var value = util.convert(item.x, 'Date').valueOf(); + min = min == null ? value : min > value ? value : min; + max = max == null ? value : max < value ? value : max; + } + } } - start = new Date(start.valueOf() - interval * 0.05); - end = new Date(end.valueOf() + interval * 0.05); } return { - start: start, - end: end - } + min: (min != null) ? new Date(min) : null, + max: (max != null) ? new Date(max) : null + }; }; - /** - * Set the visible window. Both parameters are optional, you can change only - * start or only end. Syntax: - * - * TimeLine.setWindow(start, end) - * TimeLine.setWindow(range) - * - * Where start and end can be a Date, number, or string, and range is an - * object with properties start and end. - * - * @param {Date | Number | String | Object} [start] Start date of visible window - * @param {Date | Number | String} [end] End date of visible window - * @param {Object} [options] Available options: - * `animate: boolean | number` - * If true (default), the range is animated - * smoothly to the new window. - * If a number, the number is taken as duration - * for the animation. Default duration is 500 ms. - */ - Core.prototype.setWindow = function(start, end, options) { - var animate = (options && options.animate !== undefined) ? options.animate : true; - if (arguments.length == 1) { - var range = arguments[0]; - this.range.setRange(range.start, range.end, animate); - } - else { - this.range.setRange(start, end, animate); - } - }; - /** - * Move the window such that given time is centered on screen. - * @param {Date | Number | String} time - * @param {Object} [options] Available options: - * `animate: boolean | number` - * If true (default), the range is animated - * smoothly to the new window. - * If a number, the number is taken as duration - * for the animation. Default duration is 500 ms. - */ - Core.prototype.moveTo = function(time, options) { - var interval = this.range.end - this.range.start; - var t = util.convert(time, 'Date').valueOf(); - var start = t - interval / 2; - var end = t + interval / 2; - var animate = (options && options.animate !== undefined) ? options.animate : true; + module.exports = Graph2d; - this.range.setRange(start, end, animate); - }; - /** - * Get the visible window - * @return {{start: Date, end: Date}} Visible range - */ - Core.prototype.getWindow = function() { - var range = this.range.getRange(); - return { - start: new Date(range.start), - end: new Date(range.end) - }; - }; +/***/ }, +/* 43 */ +/***/ function(module, exports, __webpack_require__) { + + var util = __webpack_require__(1); + var DOMutil = __webpack_require__(6); + var DataSet = __webpack_require__(7); + var DataView = __webpack_require__(9); + var Component = __webpack_require__(23); + var DataAxis = __webpack_require__(44); + var GraphGroup = __webpack_require__(46); + var Legend = __webpack_require__(50); + var BarGraphFunctions = __webpack_require__(49); + + var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items /** - * Force a redraw of the Core. Can be useful to manually redraw when - * option autoResize=false + * This is the constructor of the LineGraph. It requires a Timeline body and options. + * + * @param body + * @param options + * @constructor */ - Core.prototype.redraw = function() { - var resized = false; - var options = this.options; - var props = this.props; - var dom = this.dom; - - if (!dom) return; // when destroyed + function LineGraph(body, options) { + this.id = util.randomUUID(); + this.body = body; - DateUtil.updateHiddenDates(this.body, this.options.hiddenDates); + this.defaultOptions = { + yAxisOrientation: 'left', + defaultGroup: 'default', + sort: true, + sampling: true, + graphHeight: '400px', + shaded: { + enabled: false, + orientation: 'bottom' // top, bottom + }, + style: 'line', // line, bar + barChart: { + width: 50, + handleOverlap: 'overlap', + align: 'center' // left, center, right + }, + catmullRom: { + enabled: true, + parametrization: 'centripetal', // uniform (alpha = 0.0), chordal (alpha = 1.0), centripetal (alpha = 0.5) + alpha: 0.5 + }, + drawPoints: { + enabled: true, + size: 6, + style: 'square' // square, circle + }, + dataAxis: { + showMinorLabels: true, + showMajorLabels: true, + icons: false, + width: '40px', + visible: true, + alignZeros: true, + customRange: { + left: {min:undefined, max:undefined}, + right: {min:undefined, max:undefined} + } + //, these options are not set by default, but this shows the format they will be in + //format: { + // left: {decimals: 2}, + // right: {decimals: 2} + //}, + //title: { + // left: { + // text: 'left', + // style: 'color:black;' + // }, + // right: { + // text: 'right', + // style: 'color:black;' + // } + //} + }, + legend: { + enabled: false, + icons: true, + left: { + visible: true, + position: 'top-left' // top/bottom - left,right + }, + right: { + visible: true, + position: 'top-right' // top/bottom - left,right + } + }, + groups: { + visibility: {} + } + }; - // update class names - if (options.orientation == 'top') { - util.addClassName(dom.root, 'top'); - util.removeClassName(dom.root, 'bottom'); - } - else { - util.removeClassName(dom.root, 'top'); - util.addClassName(dom.root, 'bottom'); - } + // options is shared by this ItemSet and all its items + this.options = util.extend({}, this.defaultOptions); + this.dom = {}; + this.props = {}; + this.hammer = null; + this.groups = {}; + this.abortedGraphUpdate = false; + this.updateSVGheight = false; + this.updateSVGheightOnResize = false; - // update root width and height options - dom.root.style.maxHeight = util.option.asSize(options.maxHeight, ''); - dom.root.style.minHeight = util.option.asSize(options.minHeight, ''); - dom.root.style.width = util.option.asSize(options.width, ''); + var me = this; + this.itemsData = null; // DataSet + this.groupsData = null; // DataSet - // calculate border widths - props.border.left = (dom.centerContainer.offsetWidth - dom.centerContainer.clientWidth) / 2; - props.border.right = props.border.left; - props.border.top = (dom.centerContainer.offsetHeight - dom.centerContainer.clientHeight) / 2; - props.border.bottom = props.border.top; - var borderRootHeight= dom.root.offsetHeight - dom.root.clientHeight; - var borderRootWidth = dom.root.offsetWidth - dom.root.clientWidth; + // listeners for the DataSet of the items + this.itemListeners = { + 'add': function (event, params, senderId) { + me._onAdd(params.items); + }, + 'update': function (event, params, senderId) { + me._onUpdate(params.items); + }, + 'remove': function (event, params, senderId) { + me._onRemove(params.items); + } + }; - // workaround for a bug in IE: the clientWidth of an element with - // a height:0px and overflow:hidden is not calculated and always has value 0 - if (dom.centerContainer.clientHeight === 0) { - props.border.left = props.border.top; - props.border.right = props.border.left; - } - if (dom.root.clientHeight === 0) { - borderRootWidth = borderRootHeight; - } + // listeners for the DataSet of the groups + this.groupListeners = { + 'add': function (event, params, senderId) { + me._onAddGroups(params.items); + }, + 'update': function (event, params, senderId) { + me._onUpdateGroups(params.items); + }, + 'remove': function (event, params, senderId) { + me._onRemoveGroups(params.items); + } + }; - // calculate the heights. If any of the side panels is empty, we set the height to - // minus the border width, such that the border will be invisible - props.center.height = dom.center.offsetHeight; - props.left.height = dom.left.offsetHeight; - props.right.height = dom.right.offsetHeight; - props.top.height = dom.top.clientHeight || -props.border.top; - props.bottom.height = dom.bottom.clientHeight || -props.border.bottom; + this.items = {}; // object with an Item for every data item + this.selection = []; // list with the ids of all selected nodes + this.lastStart = this.body.range.start; + this.touchParams = {}; // stores properties while dragging - // TODO: compensate borders when any of the panels is empty. + this.svgElements = {}; + this.setOptions(options); + this.groupsUsingDefaultStyles = [0]; + this.COUNTER = 0; + this.body.emitter.on('rangechanged', function() { + me.lastStart = me.body.range.start; + me.svg.style.left = util.option.asSize(-me.props.width); + me.redraw.call(me,true); + }); - // apply auto height - // TODO: only calculate autoHeight when needed (else we cause an extra reflow/repaint of the DOM) - var contentHeight = Math.max(props.left.height, props.center.height, props.right.height); - var autoHeight = props.top.height + contentHeight + props.bottom.height + - borderRootHeight + props.border.top + props.border.bottom; - dom.root.style.height = util.option.asSize(options.height, autoHeight + 'px'); + // create the HTML DOM + this._create(); + this.framework = {svg: this.svg, svgElements: this.svgElements, options: this.options, groups: this.groups}; + this.body.emitter.emit('change'); - // calculate heights of the content panels - props.root.height = dom.root.offsetHeight; - props.background.height = props.root.height - borderRootHeight; - var containerHeight = props.root.height - props.top.height - props.bottom.height - - borderRootHeight; - props.centerContainer.height = containerHeight; - props.leftContainer.height = containerHeight; - props.rightContainer.height = props.leftContainer.height; + } - // calculate the widths of the panels - props.root.width = dom.root.offsetWidth; - props.background.width = props.root.width - borderRootWidth; - props.left.width = dom.leftContainer.clientWidth || -props.border.left; - props.leftContainer.width = props.left.width; - props.right.width = dom.rightContainer.clientWidth || -props.border.right; - props.rightContainer.width = props.right.width; - var centerWidth = props.root.width - props.left.width - props.right.width - borderRootWidth; - props.center.width = centerWidth; - props.centerContainer.width = centerWidth; - props.top.width = centerWidth; - props.bottom.width = centerWidth; + LineGraph.prototype = new Component(); - // resize the panels - dom.background.style.height = props.background.height + 'px'; - dom.backgroundVertical.style.height = props.background.height + 'px'; - dom.backgroundHorizontal.style.height = props.centerContainer.height + 'px'; - dom.centerContainer.style.height = props.centerContainer.height + 'px'; - dom.leftContainer.style.height = props.leftContainer.height + 'px'; - dom.rightContainer.style.height = props.rightContainer.height + 'px'; + /** + * Create the HTML DOM for the ItemSet + */ + LineGraph.prototype._create = function(){ + var frame = document.createElement('div'); + frame.className = 'LineGraph'; + this.dom.frame = frame; - dom.background.style.width = props.background.width + 'px'; - dom.backgroundVertical.style.width = props.centerContainer.width + 'px'; - dom.backgroundHorizontal.style.width = props.background.width + 'px'; - dom.centerContainer.style.width = props.center.width + 'px'; - dom.top.style.width = props.top.width + 'px'; - dom.bottom.style.width = props.bottom.width + 'px'; + // create svg element for graph drawing. + this.svg = document.createElementNS('http://www.w3.org/2000/svg','svg'); + this.svg.style.position = 'relative'; + this.svg.style.height = ('' + this.options.graphHeight).replace('px','') + 'px'; + this.svg.style.display = 'block'; + frame.appendChild(this.svg); - // reposition the panels - dom.background.style.left = '0'; - dom.background.style.top = '0'; - dom.backgroundVertical.style.left = (props.left.width + props.border.left) + 'px'; - dom.backgroundVertical.style.top = '0'; - dom.backgroundHorizontal.style.left = '0'; - dom.backgroundHorizontal.style.top = props.top.height + 'px'; - dom.centerContainer.style.left = props.left.width + 'px'; - dom.centerContainer.style.top = props.top.height + 'px'; - dom.leftContainer.style.left = '0'; - dom.leftContainer.style.top = props.top.height + 'px'; - dom.rightContainer.style.left = (props.left.width + props.center.width) + 'px'; - dom.rightContainer.style.top = props.top.height + 'px'; - dom.top.style.left = props.left.width + 'px'; - dom.top.style.top = '0'; - dom.bottom.style.left = props.left.width + 'px'; - dom.bottom.style.top = (props.top.height + props.centerContainer.height) + 'px'; + // data axis + this.options.dataAxis.orientation = 'left'; + this.yAxisLeft = new DataAxis(this.body, this.options.dataAxis, this.svg, this.options.groups); - // update the scrollTop, feasible range for the offset can be changed - // when the height of the Core or of the contents of the center changed - this._updateScrollTop(); + this.options.dataAxis.orientation = 'right'; + this.yAxisRight = new DataAxis(this.body, this.options.dataAxis, this.svg, this.options.groups); + delete this.options.dataAxis.orientation; - // reposition the scrollable contents - var offset = this.props.scrollTop; - if (options.orientation == 'bottom') { - offset += Math.max(this.props.centerContainer.height - this.props.center.height - - this.props.border.top - this.props.border.bottom, 0); - } - dom.center.style.left = '0'; - dom.center.style.top = offset + 'px'; - dom.left.style.left = '0'; - dom.left.style.top = offset + 'px'; - dom.right.style.left = '0'; - dom.right.style.top = offset + 'px'; + // legends + this.legendLeft = new Legend(this.body, this.options.legend, 'left', this.options.groups); + this.legendRight = new Legend(this.body, this.options.legend, 'right', this.options.groups); - // show shadows when vertical scrolling is available - var visibilityTop = this.props.scrollTop == 0 ? 'hidden' : ''; - var visibilityBottom = this.props.scrollTop == this.props.scrollTopMin ? 'hidden' : ''; - dom.shadowTop.style.visibility = visibilityTop; - dom.shadowBottom.style.visibility = visibilityBottom; - dom.shadowTopLeft.style.visibility = visibilityTop; - dom.shadowBottomLeft.style.visibility = visibilityBottom; - dom.shadowTopRight.style.visibility = visibilityTop; - dom.shadowBottomRight.style.visibility = visibilityBottom; + this.show(); + }; - // redraw all components - this.components.forEach(function (component) { - resized = component.redraw() || resized; - }); - if (resized) { - // keep repainting until all sizes are settled - var MAX_REDRAWS = 3; // maximum number of consecutive redraws - if (this.redrawCount < MAX_REDRAWS) { - this.redrawCount++; - this.redraw(); + /** + * set the options of the LineGraph. the mergeOptions is used for subObjects that have an enabled element. + * @param {object} options + */ + LineGraph.prototype.setOptions = function(options) { + if (options) { + var fields = ['sampling','defaultGroup','height','graphHeight','yAxisOrientation','style','barChart','dataAxis','sort','groups']; + if (options.graphHeight === undefined && options.height !== undefined && this.body.domProps.centerContainer.height !== undefined) { + this.updateSVGheight = true; + this.updateSVGheightOnResize = true; } - else { - console.log('WARNING: infinite loop in redraw?'); + else if (this.body.domProps.centerContainer.height !== undefined && options.graphHeight !== undefined) { + if (parseInt((options.graphHeight + '').replace("px",'')) < this.body.domProps.centerContainer.height) { + this.updateSVGheight = true; + } } - this.redrawCount = 0; - } + util.selectiveDeepExtend(fields, this.options, options); + util.mergeOptions(this.options, options,'catmullRom'); + util.mergeOptions(this.options, options,'drawPoints'); + util.mergeOptions(this.options, options,'shaded'); + util.mergeOptions(this.options, options,'legend'); - this.emit("finishedRedraw"); - }; + if (options.catmullRom) { + if (typeof options.catmullRom == 'object') { + if (options.catmullRom.parametrization) { + if (options.catmullRom.parametrization == 'uniform') { + this.options.catmullRom.alpha = 0; + } + else if (options.catmullRom.parametrization == 'chordal') { + this.options.catmullRom.alpha = 1.0; + } + else { + this.options.catmullRom.parametrization = 'centripetal'; + this.options.catmullRom.alpha = 0.5; + } + } + } + } - // TODO: deprecated since version 1.1.0, remove some day - Core.prototype.repaint = function () { - throw new Error('Function repaint is deprecated. Use redraw instead.'); - }; + if (this.yAxisLeft) { + if (options.dataAxis !== undefined) { + this.yAxisLeft.setOptions(this.options.dataAxis); + this.yAxisRight.setOptions(this.options.dataAxis); + } + } - /** - * Set a current time. This can be used for example to ensure that a client's - * time is synchronized with a shared server time. - * Only applicable when option `showCurrentTime` is true. - * @param {Date | String | Number} time A Date, unix timestamp, or - * ISO date string. - */ - Core.prototype.setCurrentTime = function(time) { - if (!this.currentTime) { - throw new Error('Option showCurrentTime must be true'); + if (this.legendLeft) { + if (options.legend !== undefined) { + this.legendLeft.setOptions(this.options.legend); + this.legendRight.setOptions(this.options.legend); + } + } + + if (this.groups.hasOwnProperty(UNGROUPED)) { + this.groups[UNGROUPED].setOptions(options); + } } - this.currentTime.setCurrentTime(time); + // this is used to redraw the graph if the visibility of the groups is changed. + if (this.dom.frame) { + this.redraw(true); + } }; /** - * Get the current time. - * Only applicable when option `showCurrentTime` is true. - * @return {Date} Returns the current time. + * Hide the component from the DOM */ - Core.prototype.getCurrentTime = function() { - if (!this.currentTime) { - throw new Error('Option showCurrentTime must be true'); + LineGraph.prototype.hide = function() { + // remove the frame containing the items + if (this.dom.frame.parentNode) { + this.dom.frame.parentNode.removeChild(this.dom.frame); } - - return this.currentTime.getCurrentTime(); }; - /** - * Convert a position on screen (pixels) to a datetime - * @param {int} x Position on the screen in pixels - * @return {Date} time The datetime the corresponds with given position x - * @private - */ - // TODO: move this function to Range - Core.prototype._toTime = function(x) { - return DateUtil.toTime(this, x, this.props.center.width); - }; /** - * Convert a position on the global screen (pixels) to a datetime - * @param {int} x Position on the screen in pixels - * @return {Date} time The datetime the corresponds with given position x - * @private + * Show the component in the DOM (when not already visible). + * @return {Boolean} changed */ - // TODO: move this function to Range - Core.prototype._toGlobalTime = function(x) { - return DateUtil.toTime(this, x, this.props.root.width); - //var conversion = this.range.conversion(this.props.root.width); - //return new Date(x / conversion.scale + conversion.offset); + LineGraph.prototype.show = function() { + // show frame containing the items + if (!this.dom.frame.parentNode) { + this.body.dom.center.appendChild(this.dom.frame); + } }; + /** - * Convert a datetime (Date object) into a position on the screen - * @param {Date} time A date - * @return {int} x The position on the screen in pixels which corresponds - * with the given date. - * @private + * Set items + * @param {vis.DataSet | null} items */ - // TODO: move this function to Range - Core.prototype._toScreen = function(time) { - return DateUtil.toScreen(this, time, this.props.center.width); - }; + LineGraph.prototype.setItems = function(items) { + var me = this, + ids, + oldItemsData = this.itemsData; + // replace the dataset + if (!items) { + this.itemsData = null; + } + else if (items instanceof DataSet || items instanceof DataView) { + this.itemsData = items; + } + else { + throw new TypeError('Data must be an instance of DataSet or DataView'); + } + if (oldItemsData) { + // unsubscribe from old dataset + util.forEach(this.itemListeners, function (callback, event) { + oldItemsData.off(event, callback); + }); - /** - * Convert a datetime (Date object) into a position on the root - * This is used to get the pixel density estimate for the screen, not the center panel - * @param {Date} time A date - * @return {int} x The position on root in pixels which corresponds - * with the given date. - * @private - */ - // TODO: move this function to Range - Core.prototype._toGlobalScreen = function(time) { - return DateUtil.toScreen(this, time, this.props.root.width); - //var conversion = this.range.conversion(this.props.root.width); - //return (time.valueOf() - conversion.offset) * conversion.scale; - }; + // remove all drawn items + ids = oldItemsData.getIds(); + this._onRemove(ids); + } + if (this.itemsData) { + // subscribe to new dataset + var id = this.id; + util.forEach(this.itemListeners, function (callback, event) { + me.itemsData.on(event, callback, id); + }); - /** - * Initialize watching when option autoResize is true - * @private - */ - Core.prototype._initAutoResize = function () { - if (this.options.autoResize == true) { - this._startAutoResize(); - } - else { - this._stopAutoResize(); + // add all new items + ids = this.itemsData.getIds(); + this._onAdd(ids); } + this._updateUngrouped(); + //this._updateGraph(); + this.redraw(true); }; + /** - * Watch for changes in the size of the container. On resize, the Panel will - * automatically redraw itself. - * @private + * Set groups + * @param {vis.DataSet} groups */ - Core.prototype._startAutoResize = function () { + LineGraph.prototype.setGroups = function(groups) { var me = this; + var ids; - this._stopAutoResize(); + // unsubscribe from current dataset + if (this.groupsData) { + util.forEach(this.groupListeners, function (callback, event) { + me.groupsData.unsubscribe(event, callback); + }); - this._onResize = function() { - if (me.options.autoResize != true) { - // stop watching when the option autoResize is changed to false - me._stopAutoResize(); - return; - } - - if (me.dom.root) { - // check whether the frame is resized - // Note: we compare offsetWidth here, not clientWidth. For some reason, - // IE does not restore the clientWidth from 0 to the actual width after - // changing the timeline's container display style from none to visible - if ((me.dom.root.offsetWidth != me.props.lastWidth) || - (me.dom.root.offsetHeight != me.props.lastHeight)) { - me.props.lastWidth = me.dom.root.offsetWidth; - me.props.lastHeight = me.dom.root.offsetHeight; + // remove all drawn groups + ids = this.groupsData.getIds(); + this.groupsData = null; + this._onRemoveGroups(ids); // note: this will cause a redraw + } - me.emit('change'); - } - } - }; + // replace the dataset + if (!groups) { + this.groupsData = null; + } + else if (groups instanceof DataSet || groups instanceof DataView) { + this.groupsData = groups; + } + else { + throw new TypeError('Data must be an instance of DataSet or DataView'); + } - // add event listener to window resize - util.addEventListener(window, 'resize', this._onResize); + if (this.groupsData) { + // subscribe to new dataset + var id = this.id; + util.forEach(this.groupListeners, function (callback, event) { + me.groupsData.on(event, callback, id); + }); - this.watchTimer = setInterval(this._onResize, 1000); + // draw all ms + ids = this.groupsData.getIds(); + this._onAddGroups(ids); + } + this._onUpdate(); }; + /** - * Stop watching for a resize of the frame. + * Update the data + * @param [ids] * @private */ - Core.prototype._stopAutoResize = function () { - if (this.watchTimer) { - clearInterval(this.watchTimer); - this.watchTimer = undefined; + LineGraph.prototype._onUpdate = function(ids) { + this._updateUngrouped(); + this._updateAllGroupData(); + //this._updateGraph(); + this.redraw(true); + }; + LineGraph.prototype._onAdd = function (ids) {this._onUpdate(ids);}; + LineGraph.prototype._onRemove = function (ids) {this._onUpdate(ids);}; + LineGraph.prototype._onUpdateGroups = function (groupIds) { + for (var i = 0; i < groupIds.length; i++) { + var group = this.groupsData.get(groupIds[i]); + this._updateGroup(group, groupIds[i]); } - // remove event listener on window.resize - util.removeEventListener(window, 'resize', this._onResize); - this._onResize = null; + //this._updateGraph(); + this.redraw(true); }; + LineGraph.prototype._onAddGroups = function (groupIds) {this._onUpdateGroups(groupIds);}; - /** - * Start moving the timeline vertically - * @param {Event} event - * @private - */ - Core.prototype._onTouch = function (event) { - this.touch.allowDragging = true; - }; /** - * Start moving the timeline vertically - * @param {Event} event + * this cleans the group out off the legends and the dataaxis, updates the ungrouped and updates the graph + * @param {Array} groupIds * @private */ - Core.prototype._onPinch = function (event) { - this.touch.allowDragging = false; + LineGraph.prototype._onRemoveGroups = function (groupIds) { + for (var i = 0; i < groupIds.length; i++) { + if (this.groups.hasOwnProperty(groupIds[i])) { + if (this.groups[groupIds[i]].options.yAxisOrientation == 'right') { + this.yAxisRight.removeGroup(groupIds[i]); + this.legendRight.removeGroup(groupIds[i]); + this.legendRight.redraw(); + } + else { + this.yAxisLeft.removeGroup(groupIds[i]); + this.legendLeft.removeGroup(groupIds[i]); + this.legendLeft.redraw(); + } + delete this.groups[groupIds[i]]; + } + } + this._updateUngrouped(); + //this._updateGraph(); + this.redraw(true); }; - /** - * Start moving the timeline vertically - * @param {Event} event - * @private - */ - Core.prototype._onDragStart = function (event) { - this.touch.initialScrollTop = this.props.scrollTop; - }; /** - * Move the timeline vertically - * @param {Event} event + * update a group object with the group dataset entree + * + * @param group + * @param groupId * @private */ - Core.prototype._onDrag = function (event) { - // refuse to drag when we where pinching to prevent the timeline make a jump - // when releasing the fingers in opposite order from the touch screen - if (!this.touch.allowDragging) return; - - var delta = event.gesture.deltaY; - - var oldScrollTop = this._getScrollTop(); - var newScrollTop = this._setScrollTop(this.touch.initialScrollTop + delta); - - - if (newScrollTop != oldScrollTop) { - this.redraw(); // TODO: this causes two redraws when dragging, the other is triggered by rangechange already - this.emit("verticalDrag"); + LineGraph.prototype._updateGroup = function (group, groupId) { + if (!this.groups.hasOwnProperty(groupId)) { + this.groups[groupId] = new GraphGroup(group, groupId, this.options, this.groupsUsingDefaultStyles); + if (this.groups[groupId].options.yAxisOrientation == 'right') { + this.yAxisRight.addGroup(groupId, this.groups[groupId]); + this.legendRight.addGroup(groupId, this.groups[groupId]); + } + else { + this.yAxisLeft.addGroup(groupId, this.groups[groupId]); + this.legendLeft.addGroup(groupId, this.groups[groupId]); + } + } + else { + this.groups[groupId].update(group); + if (this.groups[groupId].options.yAxisOrientation == 'right') { + this.yAxisRight.updateGroup(groupId, this.groups[groupId]); + this.legendRight.updateGroup(groupId, this.groups[groupId]); + } + else { + this.yAxisLeft.updateGroup(groupId, this.groups[groupId]); + this.legendLeft.updateGroup(groupId, this.groups[groupId]); + } } + this.legendLeft.redraw(); + this.legendRight.redraw(); }; - /** - * Apply a scrollTop - * @param {Number} scrollTop - * @returns {Number} scrollTop Returns the applied scrollTop - * @private - */ - Core.prototype._setScrollTop = function (scrollTop) { - this.props.scrollTop = scrollTop; - this._updateScrollTop(); - return this.props.scrollTop; - }; /** - * Update the current scrollTop when the height of the containers has been changed - * @returns {Number} scrollTop Returns the applied scrollTop + * this updates all groups, it is used when there is an update the the itemset. + * * @private */ - Core.prototype._updateScrollTop = function () { - // recalculate the scrollTopMin - var scrollTopMin = Math.min(this.props.centerContainer.height - this.props.center.height, 0); // is negative or zero - if (scrollTopMin != this.props.scrollTopMin) { - // in case of bottom orientation, change the scrollTop such that the contents - // do not move relative to the time axis at the bottom - if (this.options.orientation == 'bottom') { - this.props.scrollTop += (scrollTopMin - this.props.scrollTopMin); + LineGraph.prototype._updateAllGroupData = function () { + if (this.itemsData != null) { + var groupsContent = {}; + var groupId; + for (groupId in this.groups) { + if (this.groups.hasOwnProperty(groupId)) { + groupsContent[groupId] = []; + } + } + for (var itemId in this.itemsData._data) { + if (this.itemsData._data.hasOwnProperty(itemId)) { + var item = this.itemsData._data[itemId]; + if (groupsContent[item.group] === undefined) { + throw new Error('Cannot find referenced group. Possible reason: items added before groups? Groups need to be added before items, as items refer to groups.') + } + item.x = util.convert(item.x,'Date'); + groupsContent[item.group].push(item); + } + } + for (groupId in this.groups) { + if (this.groups.hasOwnProperty(groupId)) { + this.groups[groupId].setItems(groupsContent[groupId]); + } } - this.props.scrollTopMin = scrollTopMin; } - - // limit the scrollTop to the feasible scroll range - if (this.props.scrollTop > 0) this.props.scrollTop = 0; - if (this.props.scrollTop < scrollTopMin) this.props.scrollTop = scrollTopMin; - - return this.props.scrollTop; }; + /** - * Get the current scrollTop - * @returns {number} scrollTop - * @private + * Create or delete the group holding all ungrouped items. This group is used when + * there are no groups specified. This anonymous group is called 'graph'. + * @protected */ - Core.prototype._getScrollTop = function () { - return this.props.scrollTop; - }; - - module.exports = Core; + LineGraph.prototype._updateUngrouped = function() { + if (this.itemsData && this.itemsData != null) { + var ungroupedCounter = 0; + for (var itemId in this.itemsData._data) { + if (this.itemsData._data.hasOwnProperty(itemId)) { + var item = this.itemsData._data[itemId]; + if (item != undefined) { + if (item.hasOwnProperty('group')) { + if (item.group === undefined) { + item.group = UNGROUPED; + } + } + else { + item.group = UNGROUPED; + } + ungroupedCounter = item.group == UNGROUPED ? ungroupedCounter + 1 : ungroupedCounter; + } + } + } + if (ungroupedCounter == 0) { + delete this.groups[UNGROUPED]; + this.legendLeft.removeGroup(UNGROUPED); + this.legendRight.removeGroup(UNGROUPED); + this.yAxisLeft.removeGroup(UNGROUPED); + this.yAxisRight.removeGroup(UNGROUPED); + } + else { + var group = {id: UNGROUPED, content: this.options.defaultGroup}; + this._updateGroup(group, UNGROUPED); + } + } + else { + delete this.groups[UNGROUPED]; + this.legendLeft.removeGroup(UNGROUPED); + this.legendRight.removeGroup(UNGROUPED); + this.yAxisLeft.removeGroup(UNGROUPED); + this.yAxisRight.removeGroup(UNGROUPED); + } -/***/ }, -/* 47 */ -/***/ function(module, exports, __webpack_require__) { + this.legendLeft.redraw(); + this.legendRight.redraw(); + }; - var Hammer = __webpack_require__(45); /** - * Fake a hammer.js gesture. Event can be a ScrollEvent or MouseMoveEvent - * @param {Element} element - * @param {Event} event + * Redraw the component, mandatory function + * @return {boolean} Returns true if the component is resized */ - exports.fakeGesture = function(element, event) { - var eventType = null; - - // for hammer.js 1.0.5 - // var gesture = Hammer.event.collectEventData(this, eventType, event); + LineGraph.prototype.redraw = function(forceGraphUpdate) { + var resized = false; - // for hammer.js 1.0.6+ - var touches = Hammer.event.getTouchList(event, eventType); - var gesture = Hammer.event.collectEventData(this, eventType, touches, event); + // calculate actual size and position + this.props.width = this.dom.frame.offsetWidth; + this.props.height = this.body.domProps.centerContainer.height; - // on IE in standards mode, no touches are recognized by hammer.js, - // resulting in NaN values for center.pageX and center.pageY - if (isNaN(gesture.center.pageX)) { - gesture.center.pageX = event.pageX; - } - if (isNaN(gesture.center.pageY)) { - gesture.center.pageY = event.pageY; + // update the graph if there is no lastWidth or with, used for the initial draw + if (this.lastWidth === undefined && this.props.width) { + forceGraphUpdate = true; } - return gesture; - }; - + // check if this component is resized + resized = this._isResized() || resized; -/***/ }, -/* 48 */ -/***/ function(module, exports, __webpack_require__) { + // check whether zoomed (in that case we need to re-stack everything) + var visibleInterval = this.body.range.end - this.body.range.start; + var zoomed = (visibleInterval != this.lastVisibleInterval); + this.lastVisibleInterval = visibleInterval; - // 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']; + // the svg element is three times as big as the width, this allows for fully dragging left and right + // without reloading the graph. the controls for this are bound to events in the constructor + if (resized == true) { + this.svg.style.width = util.option.asSize(3*this.props.width); + this.svg.style.left = util.option.asSize(-this.props.width); + // if the height of the graph is set as proportional, change the height of the svg + if ((this.options.height + '').indexOf("%") != -1 || this.updateSVGheightOnResize == true) { + this.updateSVGheight = true; + } + } -/***/ }, -/* 49 */ -/***/ function(module, exports, __webpack_require__) { + // update the height of the graph on each redraw of the graph. + if (this.updateSVGheight == true) { + if (this.options.graphHeight != this.body.domProps.centerContainer.height + 'px') { + this.options.graphHeight = this.body.domProps.centerContainer.height + 'px'; + this.svg.style.height = this.body.domProps.centerContainer.height + 'px'; + } + this.updateSVGheight = false; + } + else { + this.svg.style.height = ('' + this.options.graphHeight).replace('px','') + 'px'; + } - // English - exports['en'] = { - edit: 'Edit', - del: 'Delete selected', - back: 'Back', - addNode: 'Add Node', - addEdge: 'Add Edge', - editNode: 'Edit Node', - editEdge: 'Edit Edge', - addDescription: 'Click in an empty space to place a new node.', - edgeDescription: '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']; + // zoomed is here to ensure that animations are shown correctly. + if (resized == true || zoomed == true || this.abortedGraphUpdate == true || forceGraphUpdate == true) { + resized = this._updateGraph() || resized; + } + else { + // move the whole svg while dragging + if (this.lastStart != 0) { + var offset = this.body.range.start - this.lastStart; + var range = this.body.range.end - this.body.range.start; + if (this.props.width != 0) { + var rangePerPixelInv = this.props.width/range; + var xOffset = offset * rangePerPixelInv; + this.svg.style.left = (-this.props.width - xOffset) + 'px'; + } + } + } - // Dutch - exports['nl'] = { - edit: 'Wijzigen', - del: 'Selectie verwijderen', - back: 'Terug', - addNode: 'Node toevoegen', - addEdge: 'Link toevoegen', - editNode: 'Node wijzigen', - editEdge: 'Link wijzigen', - addDescription: 'Klik op een leeg gebied om een nieuwe node te maken.', - edgeDescription: '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.' + this.legendLeft.redraw(); + this.legendRight.redraw(); + return resized; }; - exports['nl_NL'] = exports['nl']; - exports['nl_BE'] = exports['nl']; - -/***/ }, -/* 50 */ -/***/ function(module, exports, __webpack_require__) { /** - * Canvas shapes used by Network + * Update and redraw the graph. + * */ - if (typeof CanvasRenderingContext2D !== 'undefined') { - - /** - * Draw a circle shape - */ - CanvasRenderingContext2D.prototype.circle = function(x, y, r) { - this.beginPath(); - this.arc(x, y, r, 0, 2*Math.PI, false); - }; + LineGraph.prototype._updateGraph = function () { + // reset the svg elements + DOMutil.prepareElements(this.svgElements); + if (this.props.width != 0 && this.itemsData != null) { + var group, i; + var preprocessedGroupData = {}; + var processedGroupData = {}; + var groupRanges = {}; + var changeCalled = false; - /** - * Draw a square shape - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r size, width and height of the square - */ - CanvasRenderingContext2D.prototype.square = function(x, y, r) { - this.beginPath(); - this.rect(x - r, y - r, r * 2, r * 2); - }; + // getting group Ids + var groupIds = []; + for (var groupId in this.groups) { + if (this.groups.hasOwnProperty(groupId)) { + group = this.groups[groupId]; + if (group.visible == true && (this.options.groups.visibility[groupId] === undefined || this.options.groups.visibility[groupId] == true)) { + groupIds.push(groupId); + } + } + } + if (groupIds.length > 0) { + // this is the range of the SVG canvas + var minDate = this.body.util.toGlobalTime(-this.body.domProps.root.width); + var maxDate = this.body.util.toGlobalTime(2 * this.body.domProps.root.width); + var groupsData = {}; + // fill groups data, this only loads the data we require based on the timewindow + this._getRelevantData(groupIds, groupsData, minDate, maxDate); - /** - * Draw a triangle shape - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r radius, half the length of the sides of the triangle - */ - CanvasRenderingContext2D.prototype.triangle = function(x, y, r) { - // http://en.wikipedia.org/wiki/Equilateral_triangle - this.beginPath(); + // apply sampling, if disabled, it will pass through this function. + this._applySampling(groupIds, groupsData); - var s = r * 2; - var s2 = s / 2; - var ir = Math.sqrt(3) / 6 * s; // radius of inner circle - var h = Math.sqrt(s * s - s2 * s2); // height + // we transform the X coordinates to detect collisions + for (i = 0; i < groupIds.length; i++) { + preprocessedGroupData[groupIds[i]] = this._convertXcoordinates(groupsData[groupIds[i]]); + } - this.moveTo(x, y - (h - ir)); - this.lineTo(x + s2, y + ir); - this.lineTo(x - s2, y + ir); - this.lineTo(x, y - (h - ir)); - this.closePath(); - }; + // now all needed data has been collected we start the processing. + this._getYRanges(groupIds, preprocessedGroupData, groupRanges); - /** - * Draw a triangle shape in downward orientation - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r radius - */ - CanvasRenderingContext2D.prototype.triangleDown = function(x, y, r) { - // http://en.wikipedia.org/wiki/Equilateral_triangle - this.beginPath(); + // update the Y axis first, we use this data to draw at the correct Y points + // changeCalled is required to clean the SVG on a change emit. + changeCalled = this._updateYAxis(groupIds, groupRanges); + var MAX_CYCLES = 5; + if (changeCalled == true && this.COUNTER < MAX_CYCLES) { + DOMutil.cleanupElements(this.svgElements); + this.abortedGraphUpdate = true; + this.COUNTER++; + this.body.emitter.emit('change'); + return true; + } + else { + if (this.COUNTER > MAX_CYCLES) { + console.log("WARNING: there may be an infinite loop in the _updateGraph emitter cycle.") + } + this.COUNTER = 0; + this.abortedGraphUpdate = false; - var s = r * 2; - var s2 = s / 2; - var ir = Math.sqrt(3) / 6 * s; // radius of inner circle - var h = Math.sqrt(s * s - s2 * s2); // height + // With the yAxis scaled correctly, use this to get the Y values of the points. + for (i = 0; i < groupIds.length; i++) { + group = this.groups[groupIds[i]]; + processedGroupData[groupIds[i]] = this._convertYcoordinates(groupsData[groupIds[i]], group); + } - this.moveTo(x, y + (h - ir)); - this.lineTo(x + s2, y - ir); - this.lineTo(x - s2, y - ir); - this.lineTo(x, y + (h - ir)); - this.closePath(); - }; - - /** - * Draw a star shape, a star with 5 points - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r radius, half the length of the sides of the triangle - */ - CanvasRenderingContext2D.prototype.star = function(x, y, r) { - // http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/ - this.beginPath(); - - for (var n = 0; n < 10; n++) { - var radius = (n % 2 === 0) ? r * 1.3 : r * 0.5; - this.lineTo( - x + radius * Math.sin(n * 2 * Math.PI / 10), - y - radius * Math.cos(n * 2 * Math.PI / 10) - ); + // draw the groups + for (i = 0; i < groupIds.length; i++) { + group = this.groups[groupIds[i]]; + if (group.options.style != 'bar') { // bar needs to be drawn enmasse + group.draw(processedGroupData[groupIds[i]], group, this.framework); + } + } + BarGraphFunctions.draw(groupIds, processedGroupData, this.framework); + } } + } - this.closePath(); - }; - - /** - * http://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas - */ - CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) { - var r2d = Math.PI/180; - if( w - ( 2 * r ) < 0 ) { r = ( w / 2 ); } //ensure that the radius isn't too large for x - if( h - ( 2 * r ) < 0 ) { r = ( h / 2 ); } //ensure that the radius isn't too large for y - this.beginPath(); - this.moveTo(x+r,y); - this.lineTo(x+w-r,y); - this.arc(x+w-r,y+r,r,r2d*270,r2d*360,false); - this.lineTo(x+w,y+h-r); - this.arc(x+w-r,y+h-r,r,0,r2d*90,false); - this.lineTo(x+r,y+h); - this.arc(x+r,y+h-r,r,r2d*90,r2d*180,false); - this.lineTo(x,y+r); - this.arc(x+r,y+r,r,r2d*180,r2d*270,false); - }; - - /** - * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - */ - CanvasRenderingContext2D.prototype.ellipse = function(x, y, w, h) { - var kappa = .5522848, - ox = (w / 2) * kappa, // control point offset horizontal - oy = (h / 2) * kappa, // control point offset vertical - xe = x + w, // x-end - ye = y + h, // y-end - xm = x + w / 2, // x-middle - ym = y + h / 2; // y-middle - - this.beginPath(); - this.moveTo(x, ym); - this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - }; - - - - /** - * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - */ - CanvasRenderingContext2D.prototype.database = function(x, y, w, h) { - var f = 1/3; - var wEllipse = w; - var hEllipse = h * f; - - var kappa = .5522848, - ox = (wEllipse / 2) * kappa, // control point offset horizontal - oy = (hEllipse / 2) * kappa, // control point offset vertical - xe = x + wEllipse, // x-end - ye = y + hEllipse, // y-end - xm = x + wEllipse / 2, // x-middle - ym = y + hEllipse / 2, // y-middle - ymb = y + (h - hEllipse/2), // y-midlle, bottom ellipse - yeb = y + h; // y-end, bottom ellipse - - this.beginPath(); - this.moveTo(xe, ym); - - this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - - this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - - this.lineTo(xe, ymb); - - this.bezierCurveTo(xe, ymb + oy, xm + ox, yeb, xm, yeb); - this.bezierCurveTo(xm - ox, yeb, x, ymb + oy, x, ymb); - - this.lineTo(x, ym); - }; - - - /** - * Draw an arrow point (no line) - */ - CanvasRenderingContext2D.prototype.arrow = function(x, y, angle, length) { - // tail - var xt = x - length * Math.cos(angle); - var yt = y - length * Math.sin(angle); - - // inner tail - // TODO: allow to customize different shapes - var xi = x - length * 0.9 * Math.cos(angle); - var yi = y - length * 0.9 * Math.sin(angle); - - // left - var xl = xt + length / 3 * Math.cos(angle + 0.5 * Math.PI); - var yl = yt + length / 3 * Math.sin(angle + 0.5 * Math.PI); - - // right - var xr = xt + length / 3 * Math.cos(angle - 0.5 * Math.PI); - var yr = yt + length / 3 * Math.sin(angle - 0.5 * Math.PI); + // cleanup unused svg elements + DOMutil.cleanupElements(this.svgElements); + return false; + }; - this.beginPath(); - this.moveTo(x, y); - this.lineTo(xl, yl); - this.lineTo(xi, yi); - this.lineTo(xr, yr); - this.closePath(); - }; - /** - * Sets up the dashedLine functionality for drawing - * Original code came from http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas - * @author David Jordan - * @date 2012-08-08 - */ - CanvasRenderingContext2D.prototype.dashedLine = function(x,y,x2,y2,dashArray){ - if (!dashArray) dashArray=[10,5]; - if (dashLength==0) dashLength = 0.001; // Hack for Safari - var dashCount = dashArray.length; - this.moveTo(x, y); - var dx = (x2-x), dy = (y2-y); - var slope = dy/dx; - var distRemaining = Math.sqrt( dx*dx + dy*dy ); - var dashIndex=0, draw=true; - while (distRemaining>=0.1){ - var dashLength = dashArray[dashIndex++%dashCount]; - if (dashLength > distRemaining) dashLength = distRemaining; - var xStep = Math.sqrt( dashLength*dashLength / (1 + slope*slope) ); - if (dx<0) xStep = -xStep; - x += xStep; - y += slope*xStep; - this[draw ? 'lineTo' : 'moveTo'](x,y); - distRemaining -= dashLength; - draw = !draw; + /** + * first select and preprocess the data from the datasets. + * the groups have their preselection of data, we now loop over this data to see + * what data we need to draw. Sorted data is much faster. + * more optimization is possible by doing the sampling before and using the binary search + * to find the end date to determine the increment. + * + * @param {array} groupIds + * @param {object} groupsData + * @param {date} minDate + * @param {date} maxDate + * @private + */ + LineGraph.prototype._getRelevantData = function (groupIds, groupsData, minDate, maxDate) { + var group, i, j, item; + if (groupIds.length > 0) { + for (i = 0; i < groupIds.length; i++) { + group = this.groups[groupIds[i]]; + groupsData[groupIds[i]] = []; + var dataContainer = groupsData[groupIds[i]]; + // optimization for sorted data + if (group.options.sort == true) { + var guess = Math.max(0, util.binarySearchValue(group.itemsData, minDate, 'x', 'before')); + for (j = guess; j < group.itemsData.length; j++) { + item = group.itemsData[j]; + if (item !== undefined) { + if (item.x > maxDate) { + dataContainer.push(item); + break; + } + else { + dataContainer.push(item); + } + } + } + } + else { + for (j = 0; j < group.itemsData.length; j++) { + item = group.itemsData[j]; + if (item !== undefined) { + if (item.x > minDate && item.x < maxDate) { + dataContainer.push(item); + } + } + } + } } - }; - - // TODO: add diamond shape - } - + } + }; -/***/ }, -/* 51 */ -/***/ function(module, exports, __webpack_require__) { /** - * Created by Alex on 11/11/2014. + * + * @param groupIds + * @param groupsData + * @private */ - var DOMutil = __webpack_require__(2); - var Points = __webpack_require__(53); + LineGraph.prototype._applySampling = function (groupIds, groupsData) { + var group; + if (groupIds.length > 0) { + for (var i = 0; i < groupIds.length; i++) { + group = this.groups[groupIds[i]]; + if (group.options.sampling == true) { + var dataContainer = groupsData[groupIds[i]]; + if (dataContainer.length > 0) { + var increment = 1; + var amountOfPoints = dataContainer.length; - function Line(groupId, options) { - this.groupId = groupId; - this.options = options; - } + // the global screen is used because changing the width of the yAxis may affect the increment, resulting in an endless loop + // of width changing of the yAxis. + var xDistance = this.body.util.toGlobalScreen(dataContainer[dataContainer.length - 1].x) - this.body.util.toGlobalScreen(dataContainer[0].x); + var pointsPerPixel = amountOfPoints / xDistance; + increment = Math.min(Math.ceil(0.2 * amountOfPoints), Math.max(1, Math.round(pointsPerPixel))); - Line.prototype.getYRange = function(groupData) { - var yMin = groupData[0].y; - var yMax = groupData[0].y; - for (var j = 0; j < groupData.length; j++) { - yMin = yMin > groupData[j].y ? groupData[j].y : yMin; - yMax = yMax < groupData[j].y ? groupData[j].y : yMax; + var sampledData = []; + for (var j = 0; j < amountOfPoints; j += increment) { + sampledData.push(dataContainer[j]); + + } + groupsData[groupIds[i]] = sampledData; + } + } + } } - return {min: yMin, max: yMax, yAxisOrientation: this.options.yAxisOrientation}; }; /** - * draw a line graph * - * @param dataset - * @param group + * + * @param {array} groupIds + * @param {object} groupsData + * @param {object} groupRanges | this is being filled here + * @private */ - Line.prototype.draw = function (dataset, group, framework) { - if (dataset != null) { - if (dataset.length > 0) { - var path, d; - var svgHeight = Number(framework.svg.style.height.replace('px','')); - path = DOMutil.getSVGElement('path', framework.svgElements, framework.svg); - path.setAttributeNS(null, "class", group.className); - if(group.style !== undefined) { - path.setAttributeNS(null, "style", group.style); - } - - // construct path from dataset - if (group.options.catmullRom.enabled == true) { - d = Line._catmullRom(dataset, group); - } - else { - d = Line._linear(dataset); - } - - // append with points for fill and finalize the path - if (group.options.shaded.enabled == true) { - var fillPath = DOMutil.getSVGElement('path', framework.svgElements, framework.svg); - var dFill; - if (group.options.shaded.orientation == 'top') { - dFill = 'M' + dataset[0].x + ',' + 0 + ' ' + d + 'L' + dataset[dataset.length - 1].x + ',' + 0; + LineGraph.prototype._getYRanges = function (groupIds, groupsData, groupRanges) { + var groupData, group, i; + var barCombinedDataLeft = []; + var barCombinedDataRight = []; + var options; + if (groupIds.length > 0) { + for (i = 0; i < groupIds.length; i++) { + groupData = groupsData[groupIds[i]]; + options = this.groups[groupIds[i]].options; + if (groupData.length > 0) { + group = this.groups[groupIds[i]]; + // if bar graphs are stacked, their range need to be handled differently and accumulated over all groups. + if (options.barChart.handleOverlap == 'stack' && options.style == 'bar') { + if (options.yAxisOrientation == 'left') {barCombinedDataLeft = barCombinedDataLeft.concat(group.getYRange(groupData)) ;} + else {barCombinedDataRight = barCombinedDataRight.concat(group.getYRange(groupData));} } else { - dFill = 'M' + dataset[0].x + ',' + svgHeight + ' ' + d + 'L' + dataset[dataset.length - 1].x + ',' + svgHeight; - } - fillPath.setAttributeNS(null, "class", group.className + " fill"); - if(group.options.shaded.style !== undefined) { - fillPath.setAttributeNS(null, "style", group.options.shaded.style); + groupRanges[groupIds[i]] = group.getYRange(groupData,groupIds[i]); } - fillPath.setAttributeNS(null, "d", dFill); - } - // copy properties to path for drawing. - path.setAttributeNS(null, 'd', 'M' + d); - - // draw points - if (group.options.drawPoints.enabled == true) { - Points.draw(dataset, group, framework); } } + + // if bar graphs are stacked, their range need to be handled differently and accumulated over all groups. + BarGraphFunctions.getStackedBarYRange(barCombinedDataLeft , groupRanges, groupIds, '__barchartLeft' , 'left' ); + BarGraphFunctions.getStackedBarYRange(barCombinedDataRight, groupRanges, groupIds, '__barchartRight', 'right'); } }; - /** - * This uses an uniform parametrization of the CatmullRom algorithm: - * 'On the Parameterization of Catmull-Rom Curves' by Cem Yuksel et al. - * @param data - * @returns {string} + * this sets the Y ranges for the Y axis. It also determines which of the axis should be shown or hidden. + * @param {Array} groupIds + * @param {Object} groupRanges * @private */ - Line._catmullRomUniform = function(data) { - // catmull rom - var p0, p1, p2, p3, bp1, bp2; - var d = Math.round(data[0].x) + ',' + Math.round(data[0].y) + ' '; - var normalization = 1/6; - var length = data.length; - for (var i = 0; i < length - 1; i++) { + LineGraph.prototype._updateYAxis = function (groupIds, groupRanges) { + var resized = false; + var yAxisLeftUsed = false; + var yAxisRightUsed = false; + var minLeft = 1e9, minRight = 1e9, maxLeft = -1e9, maxRight = -1e9, minVal, maxVal; + // if groups are present + if (groupIds.length > 0) { + // this is here to make sure that if there are no items in the axis but there are groups, that there is no infinite draw/redraw loop. + for (var i = 0; i < groupIds.length; i++) { + var group = this.groups[groupIds[i]]; + if (group && group.options.yAxisOrientation != 'right') { + yAxisLeftUsed = true; + minLeft = 0; + maxLeft = 0; + } + else if (group && group.options.yAxisOrientation) { + yAxisRightUsed = true; + minRight = 0; + maxRight = 0; + } + } - p0 = (i == 0) ? data[0] : data[i-1]; - p1 = data[i]; - p2 = data[i+1]; - p3 = (i + 2 < length) ? data[i+2] : p2; + // if there are items: + for (var i = 0; i < groupIds.length; i++) { + if (groupRanges.hasOwnProperty(groupIds[i])) { + if (groupRanges[groupIds[i]].ignore !== true) { + minVal = groupRanges[groupIds[i]].min; + maxVal = groupRanges[groupIds[i]].max; + + if (groupRanges[groupIds[i]].yAxisOrientation != 'right') { + yAxisLeftUsed = true; + minLeft = minLeft > minVal ? minVal : minLeft; + maxLeft = maxLeft < maxVal ? maxVal : maxLeft; + } + else { + yAxisRightUsed = true; + minRight = minRight > minVal ? minVal : minRight; + maxRight = maxRight < maxVal ? maxVal : maxRight; + } + } + } + } + if (yAxisLeftUsed == true) { + this.yAxisLeft.setRange(minLeft, maxLeft); + } + if (yAxisRightUsed == true) { + this.yAxisRight.setRange(minRight, maxRight); + } + } + resized = this._toggleAxisVisiblity(yAxisLeftUsed , this.yAxisLeft) || resized; + resized = this._toggleAxisVisiblity(yAxisRightUsed, this.yAxisRight) || resized; - // Catmull-Rom to Cubic Bezier conversion matrix - // 0 1 0 0 - // -1/6 1 1/6 0 - // 0 1/6 1 -1/6 - // 0 0 1 0 + if (yAxisRightUsed == true && yAxisLeftUsed == true) { + this.yAxisLeft.drawIcons = true; + this.yAxisRight.drawIcons = true; + } + else { + this.yAxisLeft.drawIcons = false; + this.yAxisRight.drawIcons = false; + } + this.yAxisRight.master = !yAxisLeftUsed; + if (this.yAxisRight.master == false) { + if (yAxisRightUsed == true) {this.yAxisLeft.lineOffset = this.yAxisRight.width;} + else {this.yAxisLeft.lineOffset = 0;} - // bp0 = { x: p1.x, y: p1.y }; - bp1 = { x: ((-p0.x + 6*p1.x + p2.x) *normalization), y: ((-p0.y + 6*p1.y + p2.y) *normalization)}; - bp2 = { x: (( p1.x + 6*p2.x - p3.x) *normalization), y: (( p1.y + 6*p2.y - p3.y) *normalization)}; - // bp0 = { x: p2.x, y: p2.y }; + resized = this.yAxisLeft.redraw() || resized; + this.yAxisRight.stepPixelsForced = this.yAxisLeft.stepPixels; + this.yAxisRight.zeroCrossing = this.yAxisLeft.zeroCrossing; + resized = this.yAxisRight.redraw() || resized; + } + else { + resized = this.yAxisRight.redraw() || resized; + } - d += 'C' + - bp1.x + ',' + - bp1.y + ' ' + - bp2.x + ',' + - bp2.y + ' ' + - p2.x + ',' + - p2.y + ' '; + // clean the accumulated lists + if (groupIds.indexOf('__barchartLeft') != -1) { + groupIds.splice(groupIds.indexOf('__barchartLeft'),1); + } + if (groupIds.indexOf('__barchartRight') != -1) { + groupIds.splice(groupIds.indexOf('__barchartRight'),1); } - return d; + return resized; }; + /** - * This uses either the chordal or centripetal parameterization of the catmull-rom algorithm. - * By default, the centripetal parameterization is used because this gives the nicest results. - * These parameterizations are relatively heavy because the distance between 4 points have to be calculated. + * This shows or hides the Y axis if needed. If there is a change, the changed event is emitted by the updateYAxis function * - * One optimization can be used to reuse distances since this is a sliding window approach. - * @param data - * @param group - * @returns {string} + * @param {boolean} axisUsed + * @returns {boolean} * @private + * @param axis */ - Line._catmullRom = function(data, group) { - var alpha = group.options.catmullRom.alpha; - if (alpha == 0 || alpha === undefined) { - return this._catmullRomUniform(data); + LineGraph.prototype._toggleAxisVisiblity = function (axisUsed, axis) { + var changed = false; + if (axisUsed == false) { + if (axis.dom.frame.parentNode && axis.hidden == false) { + axis.hide() + changed = true; + } } else { - var p0, p1, p2, p3, bp1, bp2, d1,d2,d3, A, B, N, M; - var d3powA, d2powA, d3pow2A, d2pow2A, d1pow2A, d1powA; - var d = Math.round(data[0].x) + ',' + Math.round(data[0].y) + ' '; - var length = data.length; - for (var i = 0; i < length - 1; i++) { + if (!axis.dom.frame.parentNode && axis.hidden == true) { + axis.show(); + changed = true; + } + } + return changed; + }; - p0 = (i == 0) ? data[0] : data[i-1]; - p1 = data[i]; - p2 = data[i+1]; - p3 = (i + 2 < length) ? data[i+2] : p2; - d1 = Math.sqrt(Math.pow(p0.x - p1.x,2) + Math.pow(p0.y - p1.y,2)); - d2 = Math.sqrt(Math.pow(p1.x - p2.x,2) + Math.pow(p1.y - p2.y,2)); - d3 = Math.sqrt(Math.pow(p2.x - p3.x,2) + Math.pow(p2.y - p3.y,2)); + /** + * This uses the DataAxis object to generate the correct X coordinate on the SVG window. It uses the + * util function toScreen to get the x coordinate from the timestamp. It also pre-filters the data and get the minMax ranges for + * the yAxis. + * + * @param datapoints + * @returns {Array} + * @private + */ + LineGraph.prototype._convertXcoordinates = function (datapoints) { + var extractedData = []; + var xValue, yValue; + var toScreen = this.body.util.toScreen; - // Catmull-Rom to Cubic Bezier conversion matrix + for (var i = 0; i < datapoints.length; i++) { + xValue = toScreen(datapoints[i].x) + this.props.width; + yValue = datapoints[i].y; + extractedData.push({x: xValue, y: yValue}); + } - // A = 2d1^2a + 3d1^a * d2^a + d3^2a - // B = 2d3^2a + 3d3^a * d2^a + d2^2a + return extractedData; + }; - // [ 0 1 0 0 ] - // [ -d2^2a /N A/N d1^2a /N 0 ] - // [ 0 d3^2a /M B/M -d2^2a /M ] - // [ 0 0 1 0 ] - - d3powA = Math.pow(d3, alpha); - d3pow2A = Math.pow(d3,2*alpha); - d2powA = Math.pow(d2, alpha); - d2pow2A = Math.pow(d2,2*alpha); - d1powA = Math.pow(d1, alpha); - d1pow2A = Math.pow(d1,2*alpha); - - A = 2*d1pow2A + 3*d1powA * d2powA + d2pow2A; - B = 2*d3pow2A + 3*d3powA * d2powA + d2pow2A; - N = 3*d1powA * (d1powA + d2powA); - if (N > 0) {N = 1 / N;} - M = 3*d3powA * (d3powA + d2powA); - if (M > 0) {M = 1 / M;} - - bp1 = { x: ((-d2pow2A * p0.x + A*p1.x + d1pow2A * p2.x) * N), - y: ((-d2pow2A * p0.y + A*p1.y + d1pow2A * p2.y) * N)}; - - bp2 = { x: (( d3pow2A * p1.x + B*p2.x - d2pow2A * p3.x) * M), - y: (( d3pow2A * p1.y + B*p2.y - d2pow2A * p3.y) * M)}; - - if (bp1.x == 0 && bp1.y == 0) {bp1 = p1;} - if (bp2.x == 0 && bp2.y == 0) {bp2 = p2;} - d += 'C' + - bp1.x + ',' + - bp1.y + ' ' + - bp2.x + ',' + - bp2.y + ' ' + - p2.x + ',' + - p2.y + ' '; - } - - return d; - } - }; /** - * this generates the SVG path for a linear drawing between datapoints. - * @param data - * @returns {string} + * This uses the DataAxis object to generate the correct X coordinate on the SVG window. It uses the + * util function toScreen to get the x coordinate from the timestamp. It also pre-filters the data and get the minMax ranges for + * the yAxis. + * + * @param datapoints + * @param group + * @returns {Array} * @private */ - Line._linear = function(data) { - // linear - var d = ''; - for (var i = 0; i < data.length; i++) { - if (i == 0) { - d += data[i].x + ',' + data[i].y; - } - else { - d += ' ' + data[i].x + ',' + data[i].y; - } + LineGraph.prototype._convertYcoordinates = function (datapoints, group) { + var extractedData = []; + var xValue, yValue; + var toScreen = this.body.util.toScreen; + var axis = this.yAxisLeft; + var svgHeight = Number(this.svg.style.height.replace('px','')); + if (group.options.yAxisOrientation == 'right') { + axis = this.yAxisRight; } - return d; + + for (var i = 0; i < datapoints.length; i++) { + xValue = toScreen(datapoints[i].x) + this.props.width; + yValue = Math.round(axis.convertValue(datapoints[i].y)); + extractedData.push({x: xValue, y: yValue}); + } + + group.setZeroPosition(Math.min(svgHeight, axis.convertValue(0))); + + return extractedData; }; - module.exports = Line; + + module.exports = LineGraph; /***/ }, -/* 52 */ +/* 44 */ /***/ function(module, exports, __webpack_require__) { + var util = __webpack_require__(1); + var DOMutil = __webpack_require__(6); + var Component = __webpack_require__(23); + var DataStep = __webpack_require__(45); + /** - * Created by Alex on 11/11/2014. + * A horizontal time axis + * @param {Object} [options] See DataAxis.setOptions for the available + * options. + * @constructor DataAxis + * @extends Component + * @param body */ - var DOMutil = __webpack_require__(2); - var Points = __webpack_require__(53); - - function Bargraph(groupId, options) { - this.groupId = groupId; - this.options = options; - } + function DataAxis (body, options, svg, linegraphOptions) { + this.id = util.randomUUID(); + this.body = body; - Bargraph.prototype.getYRange = function(groupData) { - if (this.options.barChart.handleOverlap != 'stack') { - var yMin = groupData[0].y; - var yMax = groupData[0].y; - for (var j = 0; j < groupData.length; j++) { - yMin = yMin > groupData[j].y ? groupData[j].y : yMin; - yMax = yMax < groupData[j].y ? groupData[j].y : yMax; - } - return {min: yMin, max: yMax, yAxisOrientation: this.options.yAxisOrientation}; - } - else { - var barCombinedData = []; - for (var j = 0; j < groupData.length; j++) { - barCombinedData.push({ - x: groupData[j].x, - y: groupData[j].y, - groupId: this.groupId - }); + this.defaultOptions = { + orientation: 'left', // supported: 'left', 'right' + showMinorLabels: true, + showMajorLabels: true, + icons: true, + majorLinesOffset: 7, + minorLinesOffset: 4, + labelOffsetX: 10, + labelOffsetY: 2, + iconWidth: 20, + width: '40px', + visible: true, + alignZeros: true, + customRange: { + left: {min:undefined, max:undefined}, + right: {min:undefined, max:undefined} + }, + title: { + left: {text:undefined}, + right: {text:undefined} + }, + format: { + left: {decimals: undefined}, + right: {decimals: undefined} } - return barCombinedData; - } - }; + }; + this.linegraphOptions = linegraphOptions; + this.linegraphSVG = svg; + this.props = {}; + this.DOMelements = { // dynamic elements + lines: {}, + labels: {}, + title: {} + }; + this.dom = {}; - /** - * draw a bar graph - * - * @param groupIds - * @param processedGroupData - */ - Bargraph.draw = function (groupIds, processedGroupData, framework) { - var combinedData = []; - var intersections = {}; - var coreDistance; - var key, drawData; - var group; - var i,j; - var barPoints = 0; + this.range = {start:0, end:0}; - // combine all barchart data - for (i = 0; i < groupIds.length; i++) { - group = framework.groups[groupIds[i]]; - if (group.options.style == 'bar') { - if (group.visible == true && (framework.options.groups.visibility[groupIds[i]] === undefined || framework.options.groups.visibility[groupIds[i]] == true)) { - for (j = 0; j < processedGroupData[groupIds[i]].length; j++) { - combinedData.push({ - x: processedGroupData[groupIds[i]][j].x, - y: processedGroupData[groupIds[i]][j].y, - groupId: groupIds[i] - }); - barPoints += 1; - } - } - } - } + this.options = util.extend({}, this.defaultOptions); + this.conversionFactor = 1; - if (barPoints == 0) {return;} + this.setOptions(options); + this.width = Number(('' + this.options.width).replace("px","")); + this.minWidth = this.width; + this.height = this.linegraphSVG.offsetHeight; + this.hidden = false; - // sort by time and by group - combinedData.sort(function (a, b) { - if (a.x == b.x) { - return a.groupId - b.groupId; - } else { - return a.x - b.x; - } + this.stepPixels = 25; + this.stepPixelsForced = 25; + this.zeroCrossing = -1; + + this.lineOffset = 0; + this.master = true; + this.svgElements = {}; + this.iconsRemoved = false; + + + this.groups = {}; + this.amountOfGroups = 0; + + // create the HTML DOM + this._create(); + + var me = this; + this.body.emitter.on("verticalDrag", function() { + me.dom.lineContainer.style.top = me.body.domProps.scrollTop + 'px'; }); + } - // get intersections - Bargraph._getDataIntersections(intersections, combinedData); + DataAxis.prototype = new Component(); - // plot barchart - for (i = 0; i < combinedData.length; i++) { - group = framework.groups[combinedData[i].groupId]; - var minWidth = 0.1 * group.options.barChart.width; - key = combinedData[i].x; - var heightOffset = 0; - if (intersections[key] === undefined) { - if (i+1 < combinedData.length) {coreDistance = Math.abs(combinedData[i+1].x - key);} - if (i > 0) {coreDistance = Math.min(coreDistance,Math.abs(combinedData[i-1].x - key));} - drawData = Bargraph._getSafeDrawData(coreDistance, group, minWidth); - } - else { - var nextKey = i + (intersections[key].amount - intersections[key].resolved); - var prevKey = i - (intersections[key].resolved + 1); - if (nextKey < combinedData.length) {coreDistance = Math.abs(combinedData[nextKey].x - key);} - if (prevKey > 0) {coreDistance = Math.min(coreDistance,Math.abs(combinedData[prevKey].x - key));} - drawData = Bargraph._getSafeDrawData(coreDistance, group, minWidth); - intersections[key].resolved += 1; + DataAxis.prototype.addGroup = function(label, graphOptions) { + if (!this.groups.hasOwnProperty(label)) { + this.groups[label] = graphOptions; + } + this.amountOfGroups += 1; + }; - if (group.options.barChart.handleOverlap == 'stack') { - heightOffset = intersections[key].accumulated; - intersections[key].accumulated += group.zeroPosition - combinedData[i].y; - } - else if (group.options.barChart.handleOverlap == 'sideBySide') { - drawData.width = drawData.width / intersections[key].amount; - drawData.offset += (intersections[key].resolved) * drawData.width - (0.5*drawData.width * (intersections[key].amount+1)); - if (group.options.barChart.align == 'left') {drawData.offset -= 0.5*drawData.width;} - else if (group.options.barChart.align == 'right') {drawData.offset += 0.5*drawData.width;} - } - } - DOMutil.drawBar(combinedData[i].x + drawData.offset, combinedData[i].y - heightOffset, drawData.width, group.zeroPosition - combinedData[i].y, group.className + ' bar', framework.svgElements, framework.svg); - // draw points - if (group.options.drawPoints.enabled == true) { - DOMutil.drawPoint(combinedData[i].x + drawData.offset, combinedData[i].y, group, framework.svgElements, framework.svg); - } + DataAxis.prototype.updateGroup = function(label, graphOptions) { + this.groups[label] = graphOptions; + }; + + DataAxis.prototype.removeGroup = function(label) { + if (this.groups.hasOwnProperty(label)) { + delete this.groups[label]; + this.amountOfGroups -= 1; } }; - /** - * Fill the intersections object with counters of how many datapoints share the same x coordinates - * @param intersections - * @param combinedData - * @private - */ - Bargraph._getDataIntersections = function (intersections, combinedData) { - // get intersections - var coreDistance; - for (var i = 0; i < combinedData.length; i++) { - if (i + 1 < combinedData.length) { - coreDistance = Math.abs(combinedData[i + 1].x - combinedData[i].x); - } - if (i > 0) { - coreDistance = Math.min(coreDistance, Math.abs(combinedData[i - 1].x - combinedData[i].x)); + DataAxis.prototype.setOptions = function (options) { + if (options) { + var redraw = false; + if (this.options.orientation != options.orientation && options.orientation !== undefined) { + redraw = true; } - if (coreDistance == 0) { - if (intersections[combinedData[i].x] === undefined) { - intersections[combinedData[i].x] = {amount: 0, resolved: 0, accumulated: 0}; - } - intersections[combinedData[i].x].amount += 1; + var fields = [ + 'orientation', + 'showMinorLabels', + 'showMajorLabels', + 'icons', + 'majorLinesOffset', + 'minorLinesOffset', + 'labelOffsetX', + 'labelOffsetY', + 'iconWidth', + 'width', + 'visible', + 'customRange', + 'title', + 'format', + 'alignZeros' + ]; + util.selectiveExtend(fields, this.options, options); + + this.minWidth = Number(('' + this.options.width).replace("px","")); + + if (redraw == true && this.dom.frame) { + this.hide(); + this.show(); } } }; /** - * Get the width and offset for bargraphs based on the coredistance between datapoints - * - * @param coreDistance - * @param group - * @param minWidth - * @returns {{width: Number, offset: Number}} - * @private + * Create the HTML DOM for the DataAxis */ - Bargraph._getSafeDrawData = function (coreDistance, group, minWidth) { - var width, offset; - if (coreDistance < group.options.barChart.width && coreDistance > 0) { - width = coreDistance < minWidth ? minWidth : coreDistance; + DataAxis.prototype._create = function() { + this.dom.frame = document.createElement('div'); + this.dom.frame.style.width = this.options.width; + this.dom.frame.style.height = this.height; - offset = 0; // recalculate offset with the new width; - if (group.options.barChart.align == 'left') { - offset -= 0.5 * coreDistance; - } - else if (group.options.barChart.align == 'right') { - offset += 0.5 * coreDistance; - } + this.dom.lineContainer = document.createElement('div'); + this.dom.lineContainer.style.width = '100%'; + this.dom.lineContainer.style.height = this.height; + this.dom.lineContainer.style.position = 'relative'; + + // create svg element for graph drawing. + this.svg = document.createElementNS('http://www.w3.org/2000/svg',"svg"); + this.svg.style.position = "absolute"; + this.svg.style.top = '0px'; + this.svg.style.height = '100%'; + this.svg.style.width = '100%'; + this.svg.style.display = "block"; + this.dom.frame.appendChild(this.svg); + }; + + DataAxis.prototype._redrawGroupIcons = function () { + DOMutil.prepareElements(this.svgElements); + + var x; + var iconWidth = this.options.iconWidth; + var iconHeight = 15; + var iconOffset = 4; + var y = iconOffset + 0.5 * iconHeight; + + if (this.options.orientation == 'left') { + x = iconOffset; } else { - // default settings - width = group.options.barChart.width; - offset = 0; - if (group.options.barChart.align == 'left') { - offset -= 0.5 * group.options.barChart.width; - } - else if (group.options.barChart.align == 'right') { - offset += 0.5 * group.options.barChart.width; + x = this.width - iconWidth - iconOffset; + } + + for (var groupId in this.groups) { + if (this.groups.hasOwnProperty(groupId)) { + if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) { + this.groups[groupId].drawIcon(x, y, this.svgElements, this.svg, iconWidth, iconHeight); + y += iconHeight + iconOffset; + } } } - return {width: width, offset: offset}; + DOMutil.cleanupElements(this.svgElements); + this.iconsRemoved = false; }; - Bargraph.getStackedBarYRange = function(barCombinedData, groupRanges, groupIds, groupLabel, orientation) { - if (barCombinedData.length > 0) { - // sort by time and by group - barCombinedData.sort(function (a, b) { - if (a.x == b.x) { - return a.groupId - b.groupId; - } else { - return a.x - b.x; - } - }); - var intersections = {}; - - Bargraph._getDataIntersections(intersections, barCombinedData); - groupRanges[groupLabel] = Bargraph._getStackedBarYRange(intersections, barCombinedData); - groupRanges[groupLabel].yAxisOrientation = orientation; - groupIds.push(groupLabel); + DataAxis.prototype._cleanupIcons = function() { + if (this.iconsRemoved == false) { + DOMutil.prepareElements(this.svgElements); + DOMutil.cleanupElements(this.svgElements); + this.iconsRemoved = true; } } - Bargraph._getStackedBarYRange = function (intersections, combinedData) { - var key; - var yMin = combinedData[0].y; - var yMax = combinedData[0].y; - for (var i = 0; i < combinedData.length; i++) { - key = combinedData[i].x; - if (intersections[key] === undefined) { - yMin = yMin > combinedData[i].y ? combinedData[i].y : yMin; - yMax = yMax < combinedData[i].y ? combinedData[i].y : yMax; + /** + * Create the HTML DOM for the DataAxis + */ + DataAxis.prototype.show = function() { + this.hidden = false; + if (!this.dom.frame.parentNode) { + if (this.options.orientation == 'left') { + this.body.dom.left.appendChild(this.dom.frame); } else { - intersections[key].accumulated += combinedData[i].y; - } - } - for (var xpos in intersections) { - if (intersections.hasOwnProperty(xpos)) { - yMin = yMin > intersections[xpos].accumulated ? intersections[xpos].accumulated : yMin; - yMax = yMax < intersections[xpos].accumulated ? intersections[xpos].accumulated : yMax; + this.body.dom.right.appendChild(this.dom.frame); } } - return {min: yMin, max: yMax}; + if (!this.dom.lineContainer.parentNode) { + this.body.dom.backgroundHorizontal.appendChild(this.dom.lineContainer); + } }; - module.exports = Bargraph; - -/***/ }, -/* 53 */ -/***/ function(module, exports, __webpack_require__) { - /** - * Created by Alex on 11/11/2014. + * Create the HTML DOM for the DataAxis */ - var DOMutil = __webpack_require__(2); - - function Points(groupId, options) { - this.groupId = groupId; - this.options = options; - } - - - Points.prototype.getYRange = function(groupData) { - var yMin = groupData[0].y; - var yMax = groupData[0].y; - for (var j = 0; j < groupData.length; j++) { - yMin = yMin > groupData[j].y ? groupData[j].y : yMin; - yMax = yMax < groupData[j].y ? groupData[j].y : yMax; + DataAxis.prototype.hide = function() { + this.hidden = true; + if (this.dom.frame.parentNode) { + this.dom.frame.parentNode.removeChild(this.dom.frame); } - return {min: yMin, max: yMax, yAxisOrientation: this.options.yAxisOrientation}; - }; - - Points.prototype.draw = function(dataset, group, framework, offset) { - Points.draw(dataset, group, framework, offset); - } - /** - * draw the data points - * - * @param {Array} dataset - * @param {Object} JSONcontainer - * @param {Object} svg | SVG DOM element - * @param {GraphGroup} group - * @param {Number} [offset] - */ - Points.draw = function (dataset, group, framework, offset) { - if (offset === undefined) {offset = 0;} - for (var i = 0; i < dataset.length; i++) { - DOMutil.drawPoint(dataset[i].x + offset, dataset[i].y, group, framework.svgElements, framework.svg); + if (this.dom.lineContainer.parentNode) { + this.dom.lineContainer.parentNode.removeChild(this.dom.lineContainer); } }; - - module.exports = Points; - -/***/ }, -/* 54 */ -/***/ function(module, exports, __webpack_require__) { - - var PhysicsMixin = __webpack_require__(66); - var ClusterMixin = __webpack_require__(60); - var SectorsMixin = __webpack_require__(61); - var SelectionMixin = __webpack_require__(62); - var ManipulationMixin = __webpack_require__(63); - var NavigationMixin = __webpack_require__(64); - var HierarchicalLayoutMixin = __webpack_require__(65); - /** - * Load a mixin into the network object - * - * @param {Object} sourceVariable | this object has to contain functions. - * @private + * Set a range (start and end) + * @param end + * @param start + * @param end */ - exports._loadMixin = function (sourceVariable) { - for (var mixinFunction in sourceVariable) { - if (sourceVariable.hasOwnProperty(mixinFunction)) { - this[mixinFunction] = sourceVariable[mixinFunction]; + DataAxis.prototype.setRange = function (start, end) { + if (this.master == false && this.options.alignZeros == true && this.zeroCrossing != -1) { + if (start > 0) { + start = 0; } } + this.range.start = start; + this.range.end = end; }; - /** - * removes a mixin from the network object. - * - * @param {Object} sourceVariable | this object has to contain functions. - * @private + * Repaint the component + * @return {boolean} Returns true if the component is resized */ - exports._clearMixin = function (sourceVariable) { - for (var mixinFunction in sourceVariable) { - if (sourceVariable.hasOwnProperty(mixinFunction)) { - this[mixinFunction] = undefined; + DataAxis.prototype.redraw = function () { + var resized = false; + var activeGroups = 0; + + // Make sure the line container adheres to the vertical scrolling. + this.dom.lineContainer.style.top = this.body.domProps.scrollTop + 'px'; + + for (var groupId in this.groups) { + if (this.groups.hasOwnProperty(groupId)) { + if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) { + activeGroups++; + } } } - }; - - - /** - * Mixin the physics system and initialize the parameters required. - * - * @private - */ - exports._loadPhysicsSystem = function () { - this._loadMixin(PhysicsMixin); - this._loadSelectedForceSolver(); - if (this.constants.configurePhysics == true) { - this._loadPhysicsConfiguration(); + if (this.amountOfGroups == 0 || activeGroups == 0) { + this.hide(); } else { - this._cleanupPhysicsConfiguration(); - } - }; + this.show(); + this.height = Number(this.linegraphSVG.style.height.replace("px","")); + // svg offsetheight did not work in firefox and explorer... + this.dom.lineContainer.style.height = this.height + 'px'; + this.width = this.options.visible == true ? Number(('' + this.options.width).replace("px","")) : 0; - /** - * Mixin the cluster system and initialize the parameters required. - * - * @private - */ - exports._loadClusterSystem = function () { - this.clusterSession = 0; - this.hubThreshold = 5; - this._loadMixin(ClusterMixin); - }; + var props = this.props; + var frame = this.dom.frame; + // update classname + frame.className = 'dataaxis'; - /** - * Mixin the sector system and initialize the parameters required - * - * @private - */ - exports._loadSectorSystem = function () { - this.sectors = {}; - this.activeSector = ["default"]; - this.sectors["active"] = {}; - this.sectors["active"]["default"] = {"nodes": {}, - "edges": {}, - "nodeIndices": [], - "formationScale": 1.0, - "drawingNode": undefined }; - this.sectors["frozen"] = {}; - this.sectors["support"] = {"nodes": {}, - "edges": {}, - "nodeIndices": [], - "formationScale": 1.0, - "drawingNode": undefined }; + // calculate character width and height + this._calculateCharSize(); - this.nodeIndices = this.sectors["active"]["default"]["nodeIndices"]; // the node indices list is used to speed up the computation of the repulsion fields + var orientation = this.options.orientation; + var showMinorLabels = this.options.showMinorLabels; + var showMajorLabels = this.options.showMajorLabels; - this._loadMixin(SectorsMixin); - }; + // determine the width and height of the elements for the axis + props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; + props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; + props.minorLineWidth = this.body.dom.backgroundHorizontal.offsetWidth - this.lineOffset - this.width + 2 * this.options.minorLinesOffset; + props.minorLineHeight = 1; + props.majorLineWidth = this.body.dom.backgroundHorizontal.offsetWidth - this.lineOffset - this.width + 2 * this.options.majorLinesOffset; + props.majorLineHeight = 1; - /** - * Mixin the selection system and initialize the parameters required - * - * @private - */ - exports._loadSelectionSystem = function () { - this.selectionObj = {nodes: {}, edges: {}}; + // take frame offline while updating (is almost twice as fast) + if (orientation == 'left') { + frame.style.top = '0'; + frame.style.left = '0'; + frame.style.bottom = ''; + frame.style.width = this.width + 'px'; + frame.style.height = this.height + "px"; + this.props.width = this.body.domProps.left.width; + this.props.height = this.body.domProps.left.height; + } + else { // right + frame.style.top = ''; + frame.style.bottom = '0'; + frame.style.left = '0'; + frame.style.width = this.width + 'px'; + frame.style.height = this.height + "px"; + this.props.width = this.body.domProps.right.width; + this.props.height = this.body.domProps.right.height; + } - this._loadMixin(SelectionMixin); - }; + resized = this._redrawLabels(); + resized = this._isResized() || resized; + + if (this.options.icons == true) { + this._redrawGroupIcons(); + } + else { + this._cleanupIcons(); + } + this._redrawTitle(orientation); + } + return resized; + }; /** - * Mixin the navigationUI (User Interface) system and initialize the parameters required - * + * Repaint major and minor text labels and vertical grid lines * @private */ - exports._loadManipulationSystem = function () { - // reset global variables -- these are used by the selection of nodes and edges. - this.blockConnectingEdgeSelection = false; - this.forceAppendSelection = false; + DataAxis.prototype._redrawLabels = function () { + var resized = false; + DOMutil.prepareElements(this.DOMelements.lines); + DOMutil.prepareElements(this.DOMelements.labels); - if (this.constants.dataManipulation.enabled == true) { - // load the manipulator HTML elements. All styling done in css. - if (this.manipulationDiv === undefined) { - this.manipulationDiv = document.createElement('div'); - this.manipulationDiv.className = 'network-manipulationDiv'; - if (this.editMode == true) { - this.manipulationDiv.style.display = "block"; - } - else { - this.manipulationDiv.style.display = "none"; - } - this.frame.appendChild(this.manipulationDiv); + var orientation = this.options['orientation']; + + // calculate range and step (step such that we have space for 7 characters per label) + var minimumStep = this.master ? this.props.majorCharHeight || 10 : this.stepPixelsForced; + + var step = new DataStep( + this.range.start, + this.range.end, + minimumStep, + this.dom.frame.offsetHeight, + this.options.customRange[this.options.orientation], + this.master == false && this.options.alignZeros // doess the step have to align zeros? only if not master and the options is on + ); + + this.step = step; + // get the distance in pixels for a step + // dead space is space that is "left over" after a step + var stepPixels = (this.dom.frame.offsetHeight - (step.deadSpace * (this.dom.frame.offsetHeight / step.marginRange))) / (((step.marginRange - step.deadSpace) / step.step)); + + this.stepPixels = stepPixels; + + var amountOfSteps = this.height / stepPixels; + var stepDifference = 0; + + // the slave axis needs to use the same horizontal lines as the master axis. + if (this.master == false) { + stepPixels = this.stepPixelsForced; + stepDifference = Math.round((this.dom.frame.offsetHeight / stepPixels) - amountOfSteps); + for (var i = 0; i < 0.5 * stepDifference; i++) { + step.previous(); } + amountOfSteps = this.height / stepPixels; - if (this.editModeDiv === undefined) { - this.editModeDiv = document.createElement('div'); - this.editModeDiv.className = 'network-manipulation-editMode'; - if (this.editMode == true) { - this.editModeDiv.style.display = "none"; + if (this.zeroCrossing != -1 && this.options.alignZeros == true) { + var zeroStepDifference = (step.marginEnd / step.step) - this.zeroCrossing; + if (zeroStepDifference > 0) { + for (var i = 0; i < zeroStepDifference; i++) {step.next();} } - else { - this.editModeDiv.style.display = "block"; + else if (zeroStepDifference < 0) { + for (var i = 0; i < -zeroStepDifference; i++) {step.previous();} } - this.frame.appendChild(this.editModeDiv); } + } + else { + amountOfSteps += 0.25; + } - if (this.closeDiv === undefined) { - this.closeDiv = document.createElement('div'); - this.closeDiv.className = 'network-manipulation-closeDiv'; - this.closeDiv.style.display = this.manipulationDiv.style.display; - this.frame.appendChild(this.closeDiv); - } - // load the manipulation functions - this._loadMixin(ManipulationMixin); + this.valueAtZero = step.marginEnd; + var marginStartPos = 0; - // create the manipulator toolbar - this._createManipulatorBar(); + // do not draw the first label + var max = 1; + + // Get the number of decimal places + var decimals; + if(this.options.format[orientation] !== undefined) { + decimals = this.options.format[orientation].decimals; } - else { - if (this.manipulationDiv !== undefined) { - // removes all the bindings and overloads - this._createManipulatorBar(); - // remove the manipulation divs - this.frame.removeChild(this.manipulationDiv); - this.frame.removeChild(this.editModeDiv); - this.frame.removeChild(this.closeDiv); + this.maxLabelSize = 0; + var y = 0; + while (max < Math.round(amountOfSteps)) { + step.next(); + y = Math.round(max * stepPixels); + marginStartPos = max * stepPixels; + var isMajor = step.isMajor(); - this.manipulationDiv = undefined; - this.editModeDiv = undefined; - this.closeDiv = undefined; - // remove the mixin functions - this._clearMixin(ManipulationMixin); + if (this.options['showMinorLabels'] && isMajor == false || this.master == false && this.options['showMinorLabels'] == true) { + this._redrawLabel(y - 2, step.getCurrent(decimals), orientation, 'yAxis minor', this.props.minorCharHeight); + } + + if (isMajor && this.options['showMajorLabels'] && this.master == true || + this.options['showMinorLabels'] == false && this.master == false && isMajor == true) { + if (y >= 0) { + this._redrawLabel(y - 2, step.getCurrent(decimals), orientation, 'yAxis major', this.props.majorCharHeight); + } + this._redrawLine(y, orientation, 'grid horizontal major', this.options.majorLinesOffset, this.props.majorLineWidth); + } + else { + this._redrawLine(y, orientation, 'grid horizontal minor', this.options.minorLinesOffset, this.props.minorLineWidth); } + + if (this.master == true && step.current == 0) { + this.zeroCrossing = max; + } + + max++; } - }; + if (this.master == false) { + this.conversionFactor = y / (this.valueAtZero - step.current); + } + else { + this.conversionFactor = this.dom.frame.offsetHeight / step.marginRange; + } - /** - * Mixin the navigation (User Interface) system and initialize the parameters required - * - * @private - */ - exports._loadNavigationControls = function () { - this._loadMixin(NavigationMixin); - // the clean function removes the button divs, this is done to remove the bindings. - this._cleanNavigation(); - if (this.constants.navigation.enabled == true) { - this._loadNavigationElements(); + // Note that title is rotated, so we're using the height, not width! + var titleWidth = 0; + if (this.options.title[orientation] !== undefined && this.options.title[orientation].text !== undefined) { + titleWidth = this.props.titleCharHeight; + } + var offset = this.options.icons == true ? Math.max(this.options.iconWidth, titleWidth) + this.options.labelOffsetX + 15 : titleWidth + this.options.labelOffsetX + 15; + + // this will resize the yAxis to accommodate the labels. + if (this.maxLabelSize > (this.width - offset) && this.options.visible == true) { + this.width = this.maxLabelSize + offset; + this.options.width = this.width + "px"; + DOMutil.cleanupElements(this.DOMelements.lines); + DOMutil.cleanupElements(this.DOMelements.labels); + this.redraw(); + resized = true; + } + // this will resize the yAxis if it is too big for the labels. + else if (this.maxLabelSize < (this.width - offset) && this.options.visible == true && this.width > this.minWidth) { + this.width = Math.max(this.minWidth,this.maxLabelSize + offset); + this.options.width = this.width + "px"; + DOMutil.cleanupElements(this.DOMelements.lines); + DOMutil.cleanupElements(this.DOMelements.labels); + this.redraw(); + resized = true; } + else { + DOMutil.cleanupElements(this.DOMelements.lines); + DOMutil.cleanupElements(this.DOMelements.labels); + resized = false; + } + + return resized; }; + DataAxis.prototype.convertValue = function (value) { + var invertedValue = this.valueAtZero - value; + var convertedValue = invertedValue * this.conversionFactor; + return convertedValue; + }; /** - * Mixin the hierarchical layout system. - * + * Create a label for the axis at position x * @private + * @param y + * @param text + * @param orientation + * @param className + * @param characterHeight */ - exports._loadHierarchySystem = function () { - this._loadMixin(HierarchicalLayoutMixin); - }; + DataAxis.prototype._redrawLabel = function (y, text, orientation, className, characterHeight) { + // reuse redundant label + var label = DOMutil.getDOMElement('div',this.DOMelements.labels, this.dom.frame); //this.dom.redundant.labels.shift(); + label.className = className; + label.innerHTML = text; + if (orientation == 'left') { + label.style.left = '-' + this.options.labelOffsetX + 'px'; + label.style.textAlign = "right"; + } + else { + label.style.right = '-' + this.options.labelOffsetX + 'px'; + label.style.textAlign = "left"; + } + label.style.top = y - 0.5 * characterHeight + this.options.labelOffsetY + 'px'; -/***/ }, -/* 55 */ -/***/ function(module, exports, __webpack_require__) { + text += ''; - var keycharm = __webpack_require__(57); - var Emitter = __webpack_require__(56); - var Hammer = __webpack_require__(45); - var util = __webpack_require__(1); + var largestWidth = Math.max(this.props.majorCharWidth,this.props.minorCharWidth); + if (this.maxLabelSize < text.length * largestWidth) { + this.maxLabelSize = text.length * largestWidth; + } + }; /** - * Turn an element into an clickToUse element. - * When not active, the element has a transparent overlay. When the overlay is - * clicked, the mode is changed to active. - * When active, the element is displayed with a blue border around it, and - * the interactive contents of the element can be used. When clicked outside - * the element, the elements mode is changed to inactive. - * @param {Element} container - * @constructor + * Create a minor line for the axis at position y + * @param y + * @param orientation + * @param className + * @param offset + * @param width */ - function Activator(container) { - this.active = false; + DataAxis.prototype._redrawLine = function (y, orientation, className, offset, width) { + if (this.master == true) { + var line = DOMutil.getDOMElement('div',this.DOMelements.lines, this.dom.lineContainer);//this.dom.redundant.lines.shift(); + line.className = className; + line.innerHTML = ''; - this.dom = { - container: container - }; + if (orientation == 'left') { + line.style.left = (this.width - offset) + 'px'; + } + else { + line.style.right = (this.width - offset) + 'px'; + } - this.dom.overlay = document.createElement('div'); - this.dom.overlay.className = 'overlay'; + line.style.width = width + 'px'; + line.style.top = y + 'px'; + } + }; - this.dom.container.appendChild(this.dom.overlay); + /** + * Create a title for the axis + * @private + * @param orientation + */ + DataAxis.prototype._redrawTitle = function (orientation) { + DOMutil.prepareElements(this.DOMelements.title); - this.hammer = Hammer(this.dom.overlay, {prevent_default: false}); - this.hammer.on('tap', this._onTapOverlay.bind(this)); + // Check if the title is defined for this axes + if (this.options.title[orientation] !== undefined && this.options.title[orientation].text !== undefined) { + var title = DOMutil.getDOMElement('div', this.DOMelements.title, this.dom.frame); + title.className = 'yAxis title ' + orientation; + title.innerHTML = this.options.title[orientation].text; - // block all touch events (except tap) - var me = this; - var events = [ - 'touch', 'pinch', - 'doubletap', 'hold', - 'dragstart', 'drag', 'dragend', - 'mousewheel', 'DOMMouseScroll' // DOMMouseScroll is needed for Firefox - ]; - events.forEach(function (event) { - me.hammer.on(event, function (event) { - event.stopPropagation(); - }); - }); + // Add style - if provided + if (this.options.title[orientation].style !== undefined) { + util.addCssText(title, this.options.title[orientation].style); + } - // attach a tap event to the window, in order to deactivate when clicking outside the timeline - this.windowHammer = Hammer(window, {prevent_default: false}); - this.windowHammer.on('tap', function (event) { - // deactivate when clicked outside the container - if (!_hasParent(event.target, container)) { - me.deactivate(); + if (orientation == 'left') { + title.style.left = this.props.titleCharHeight + 'px'; + } + else { + title.style.right = this.props.titleCharHeight + 'px'; } - }); - if (this.keycharm !== undefined) { - this.keycharm.destroy(); + title.style.width = this.height + 'px'; } - this.keycharm = keycharm(); - // keycharm listener only bounded when active) - this.escListener = this.deactivate.bind(this); - } + // we need to clean up in case we did not use all elements. + DOMutil.cleanupElements(this.DOMelements.title); + }; + - // turn into an event emitter - Emitter(Activator.prototype); - // The currently active activator - Activator.current = null; /** - * Destroy the activator. Cleans up all created DOM and event listeners + * Determine the size of text on the axis (both major and minor axis). + * The size is calculated only once and then cached in this.props. + * @private */ - Activator.prototype.destroy = function () { - this.deactivate(); + DataAxis.prototype._calculateCharSize = function () { + // determine the char width and height on the minor axis + if (!('minorCharHeight' in this.props)) { + var textMinor = document.createTextNode('0'); + var measureCharMinor = document.createElement('div'); + measureCharMinor.className = 'yAxis minor measure'; + measureCharMinor.appendChild(textMinor); + this.dom.frame.appendChild(measureCharMinor); - // remove dom - this.dom.overlay.parentNode.removeChild(this.dom.overlay); + this.props.minorCharHeight = measureCharMinor.clientHeight; + this.props.minorCharWidth = measureCharMinor.clientWidth; - // cleanup hammer instances - this.hammer = null; - this.windowHammer = null; - // FIXME: cleaning up hammer instances doesn't work (Timeline not removed from memory) - }; + this.dom.frame.removeChild(measureCharMinor); + } - /** - * Activate the element - * Overlay is hidden, element is decorated with a blue shadow border - */ - Activator.prototype.activate = function () { - // we allow only one active activator at a time - if (Activator.current) { - Activator.current.deactivate(); + if (!('majorCharHeight' in this.props)) { + var textMajor = document.createTextNode('0'); + var measureCharMajor = document.createElement('div'); + measureCharMajor.className = 'yAxis major measure'; + measureCharMajor.appendChild(textMajor); + this.dom.frame.appendChild(measureCharMajor); + + this.props.majorCharHeight = measureCharMajor.clientHeight; + this.props.majorCharWidth = measureCharMajor.clientWidth; + + this.dom.frame.removeChild(measureCharMajor); } - Activator.current = this; - this.active = true; - this.dom.overlay.style.display = 'none'; - util.addClassName(this.dom.container, 'vis-active'); + if (!('titleCharHeight' in this.props)) { + var textTitle = document.createTextNode('0'); + var measureCharTitle = document.createElement('div'); + measureCharTitle.className = 'yAxis title measure'; + measureCharTitle.appendChild(textTitle); + this.dom.frame.appendChild(measureCharTitle); - this.emit('change'); - this.emit('activate'); + this.props.titleCharHeight = measureCharTitle.clientHeight; + this.props.titleCharWidth = measureCharTitle.clientWidth; - // ugly hack: bind ESC after emitting the events, as the Network rebinds all - // keyboard events on a 'change' event - this.keycharm.bind('esc', this.escListener); + this.dom.frame.removeChild(measureCharTitle); + } }; /** - * Deactivate the element - * Overlay is displayed on top of the element - */ - Activator.prototype.deactivate = function () { - this.active = false; - this.dom.overlay.style.display = ''; - util.removeClassName(this.dom.container, 'vis-active'); - this.keycharm.unbind('esc', this.escListener); - - this.emit('change'); - this.emit('deactivate'); - }; - - /** - * Handle a tap event: activate the container - * @param event - * @private + * 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 */ - Activator.prototype._onTapOverlay = function (event) { - // activate the container - this.activate(); - event.stopPropagation(); + DataAxis.prototype.snap = function(date) { + return this.step.snap(date); }; - /** - * Test whether the element has the requested parent element somewhere in - * its chain of parent nodes. - * @param {HTMLElement} element - * @param {HTMLElement} parent - * @returns {boolean} Returns true when the parent is found somewhere in the - * chain of parent nodes. - * @private - */ - function _hasParent(element, parent) { - while (element) { - if (element === parent) { - return true - } - element = element.parentNode; - } - return false; - } - - module.exports = Activator; + module.exports = DataAxis; /***/ }, -/* 56 */ +/* 45 */ /***/ function(module, exports, __webpack_require__) { - /** - * Expose `Emitter`. + * @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, alignZeros) { + // variables + this.current = 0; - module.exports = Emitter; + this.autoScale = true; + this.stepIndex = 0; + this.step = 1; + this.scale = 1; - /** - * Initialize a new `Emitter`. - * - * @api public - */ + this.marginStart; + this.marginEnd; + this.deadSpace = 0; - function Emitter(obj) { - if (obj) return mixin(obj); - }; + this.majorSteps = [1, 2, 5, 10]; + this.minorSteps = [0.25, 0.5, 1, 2]; - /** - * Mixin the emitter properties. - * - * @param {Object} obj - * @return {Object} - * @api private - */ + this.alignZeros = alignZeros; - function mixin(obj) { - for (var key in Emitter.prototype) { - obj[key] = Emitter.prototype[key]; - } - return obj; + this.setRange(start, end, minimumStep, containerHeight, customRange); } + + /** - * Listen on the given `event` with `fn`. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public + * 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; - Emitter.prototype.on = - Emitter.prototype.addEventListener = function(event, fn){ - this._callbacks = this._callbacks || {}; - (this._callbacks[event] = this._callbacks[event] || []) - .push(fn); - return this; + if (this._start == this._end) { + this._start -= 0.75; + this._end += 1; + } + + if (this.autoScale == true) { + this.setMinimumStep(minimumStep, containerHeight); + } + + this.setFirst(customRange); }; /** - * Adds an `event` listener that will be invoked a single - * time then automatically removed. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public + * 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); - Emitter.prototype.once = function(event, fn){ - var self = this; - this._callbacks = this._callbacks || {}; + var minorStepIdx = -1; + var magnitudefactor = Math.pow(10,orderOfMagnitude); - function on() { - self.off(event, on); - fn.apply(this, arguments); + var start = 0; + if (orderOfMagnitude < 0) { + start = orderOfMagnitude; } - on.fn = fn; - this.on(event, on); - return this; + 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]; }; + + /** - * Remove the given callback for `event` or all - * registered callbacks. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public + * 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 = {}; + } - Emitter.prototype.off = - Emitter.prototype.removeListener = - Emitter.prototype.removeAllListeners = - Emitter.prototype.removeEventListener = function(event, fn){ - this._callbacks = this._callbacks || {}; + 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; - // all - if (0 == arguments.length) { - this._callbacks = {}; - return this; + this.marginEnd = customRange.max === undefined ? this.roundToMinor(niceEnd) : customRange.max; + this.marginStart = customRange.min === undefined ? this.roundToMinor(niceStart) : customRange.min; + + // if we need to align the zero's we need to make sure that there is a zero to use. + if (this.alignZeros == true && (this.marginEnd - this.marginStart) % this.step != 0) { + this.marginEnd += this.marginEnd % this.step; } - // specific event - var callbacks = this._callbacks[event]; - if (!callbacks) return this; + this.deadSpace = this.roundToMinor(niceEnd) - niceEnd + this.roundToMinor(niceStart) - niceStart; + this.marginRange = this.marginEnd - this.marginStart; - // remove all handlers - if (1 == arguments.length) { - delete this._callbacks[event]; - return this; + + 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; } + } - // remove specific handler - var cb; - for (var i = 0; i < callbacks.length; i++) { - cb = callbacks[i]; - if (cb === fn || cb.fn === fn) { - callbacks.splice(i, 1); - break; - } + + /** + * 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; } - return this; }; /** - * Emit `event` with the given args. - * - * @param {String} event - * @param {Mixed} ... - * @return {Emitter} + * Do the next step */ + DataStep.prototype.previous = function() { + this.current += this.step; + this.marginEnd += this.step; + this.marginRange = this.marginEnd - this.marginStart; + }; - Emitter.prototype.emit = function(event){ - this._callbacks = this._callbacks || {}; - var args = [].slice.call(arguments, 1) - , callbacks = this._callbacks[event]; - if (callbacks) { - callbacks = callbacks.slice(0); - for (var i = 0, len = callbacks.length; i < len; ++i) { - callbacks[i].apply(this, args); + + /** + * Get the current datetime + * @return {String} current The current date + */ + DataStep.prototype.getCurrent = function(decimals) { + // prevent round-off errors when close to zero + var current = (Math.abs(this.current) < this.step / 2) ? 0 : this.current; + var toPrecision = '' + Number(current).toPrecision(5); + + // If decimals is specified, then limit or extend the string as required + if(decimals !== undefined && !isNaN(Number(decimals))) { + // If string includes exponent, then we need to add it to the end + var exp = ""; + var index = toPrecision.indexOf("e"); + if(index != -1) { + // Get the exponent + exp = toPrecision.slice(index); + // Remove the exponent in case we need to zero-extend + toPrecision = toPrecision.slice(0, index); + } + index = Math.max(toPrecision.indexOf(","), toPrecision.indexOf(".")); + if(index === -1) { + // No decimal found - if we want decimals, then we need to add it + if(decimals !== 0) { + toPrecision += '.'; + } + // Calculate how long the string should be + index = toPrecision.length + decimals; + } + else if(decimals !== 0) { + // Calculate how long the string should be - accounting for the decimal place + index += decimals + 1; + } + if(index > toPrecision.length) { + // We need to add zeros! + for(var cnt = index - toPrecision.length; cnt > 0; cnt--) { + toPrecision += '0'; + } + } + else { + // we need to remove characters + toPrecision = toPrecision.slice(0, index); + } + // Add the exponent if there is one + toPrecision += exp; + } + else { + if (toPrecision.indexOf(",") != -1 || toPrecision.indexOf(".") != -1) { + // If no decimal is specified, and there are decimal places, remove trailing zeros + 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 this; + return toPrecision; }; + + /** - * Return array of callbacks for `event`. - * - * @param {String} event - * @return {Array} - * @api public + * 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) { - Emitter.prototype.listeners = function(event){ - this._callbacks = this._callbacks || {}; - return this._callbacks[event] || []; }; /** - * Check if this emitter has `event` handlers. - * - * @param {String} event - * @return {Boolean} - * @api public + * 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. */ - - Emitter.prototype.hasListeners = function(event){ - return !! this.listeners(event).length; + DataStep.prototype.isMajor = function() { + return (this.current % (this.scale * this.majorSteps[this.stepIndex]) == 0); }; + module.exports = DataStep; + /***/ }, -/* 57 */ +/* 46 */ /***/ function(module, exports, __webpack_require__) { - var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;"use strict"; + var util = __webpack_require__(1); + var DOMutil = __webpack_require__(6); + var Line = __webpack_require__(47); + var Bar = __webpack_require__(49); + var Points = __webpack_require__(48); + /** - * Created by Alex on 11/6/2014. + * /** + * @param {object} group | the object of the group from the dataset + * @param {string} groupId | ID of the group + * @param {object} options | the default options + * @param {array} groupsUsingDefaultStyles | this array has one entree. + * It is passed as an array so it is passed by reference. + * It enumerates through the default styles + * @constructor */ - - // https://github.com/umdjs/umd/blob/master/returnExports.js#L40-L60 - // if the module has no dependencies, the above pattern can be simplified to - (function (root, factory) { - if (true) { - // AMD. Register as an anonymous module. - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - } else if (typeof exports === 'object') { - // Node. Does not work with strict CommonJS, but - // only CommonJS-like environments that support module.exports, - // like Node. - module.exports = factory(); - } else { - // Browser globals (root is window) - root.keycharm = factory(); + function GraphGroup (group, groupId, options, groupsUsingDefaultStyles) { + this.id = groupId; + var fields = ['sampling','style','sort','yAxisOrientation','barChart','drawPoints','shaded','catmullRom'] + this.options = util.selectiveBridgeObject(fields,options); + this.usingDefaultStyle = group.className === undefined; + this.groupsUsingDefaultStyles = groupsUsingDefaultStyles; + this.zeroPosition = 0; + this.update(group); + if (this.usingDefaultStyle == true) { + this.groupsUsingDefaultStyles[0] += 1; } - }(this, function () { - - function keycharm(options) { - var preventDefault = options && options.preventDefault || false; + this.itemsData = []; + this.visible = group.visible === undefined ? true : group.visible; + } - var container = options && options.container || window; - var _exportFunctions = {}; - var _bound = {keydown:{}, keyup:{}}; - var _keys = {}; - var i; + /** + * this loads a reference to all items in this group into this group. + * @param {array} items + */ + GraphGroup.prototype.setItems = function(items) { + if (items != null) { + this.itemsData = items; + if (this.options.sort == true) { + this.itemsData.sort(function (a,b) {return a.x - b.x;}) + } + } + else { + this.itemsData = []; + } + }; - // a - z - for (i = 97; i <= 122; i++) {_keys[String.fromCharCode(i)] = {code:65 + (i - 97), shift: false};} - // A - Z - for (i = 65; i <= 90; i++) {_keys[String.fromCharCode(i)] = {code:i, shift: true};} - // 0 - 9 - for (i = 0; i <= 9; i++) {_keys['' + i] = {code:48 + i, shift: false};} - // F1 - F12 - for (i = 1; i <= 12; i++) {_keys['F' + i] = {code:111 + i, shift: false};} - // num0 - num9 - for (i = 0; i <= 9; i++) {_keys['num' + i] = {code:96 + i, shift: false};} - // numpad misc - _keys['num*'] = {code:106, shift: false}; - _keys['num+'] = {code:107, shift: false}; - _keys['num-'] = {code:109, shift: false}; - _keys['num/'] = {code:111, shift: false}; - _keys['num.'] = {code:110, shift: false}; - // arrows - _keys['left'] = {code:37, shift: false}; - _keys['up'] = {code:38, shift: false}; - _keys['right'] = {code:39, shift: false}; - _keys['down'] = {code:40, shift: false}; - // extra keys - _keys['space'] = {code:32, shift: false}; - _keys['enter'] = {code:13, shift: false}; - _keys['shift'] = {code:16, shift: undefined}; - _keys['esc'] = {code:27, shift: false}; - _keys['backspace'] = {code:8, shift: false}; - _keys['tab'] = {code:9, shift: false}; - _keys['ctrl'] = {code:17, shift: false}; - _keys['alt'] = {code:18, shift: false}; - _keys['delete'] = {code:46, shift: false}; - _keys['pageup'] = {code:33, shift: false}; - _keys['pagedown'] = {code:34, shift: false}; - // symbols - _keys['='] = {code:187, shift: false}; - _keys['-'] = {code:189, shift: false}; - _keys[']'] = {code:221, shift: false}; - _keys['['] = {code:219, shift: false}; + /** + * this is used for plotting barcharts, this way, we only have to calculate it once. + * @param pos + */ + GraphGroup.prototype.setZeroPosition = function(pos) { + this.zeroPosition = pos; + }; + /** + * set the options of the graph group over the default options. + * @param options + */ + GraphGroup.prototype.setOptions = function(options) { + if (options !== undefined) { + var fields = ['sampling','style','sort','yAxisOrientation','barChart']; + util.selectiveDeepExtend(fields, this.options, options); - var down = function(event) {handleEvent(event,'keydown');}; - var up = function(event) {handleEvent(event,'keyup');}; + util.mergeOptions(this.options, options,'catmullRom'); + util.mergeOptions(this.options, options,'drawPoints'); + util.mergeOptions(this.options, options,'shaded'); - // handle the actualy bound key with the event - var handleEvent = function(event,type) { - if (_bound[type][event.keyCode] !== undefined) { - var bound = _bound[type][event.keyCode]; - for (var i = 0; i < bound.length; i++) { - if (bound[i].shift === undefined) { - bound[i].fn(event); + if (options.catmullRom) { + if (typeof options.catmullRom == 'object') { + if (options.catmullRom.parametrization) { + if (options.catmullRom.parametrization == 'uniform') { + this.options.catmullRom.alpha = 0; } - else if (bound[i].shift == true && event.shiftKey == true) { - bound[i].fn(event); + else if (options.catmullRom.parametrization == 'chordal') { + this.options.catmullRom.alpha = 1.0; } - else if (bound[i].shift == false && event.shiftKey == false) { - bound[i].fn(event); + else { + this.options.catmullRom.parametrization = 'centripetal'; + this.options.catmullRom.alpha = 0.5; } } - - if (preventDefault == true) { - event.preventDefault(); - } } - }; + } + } - // bind a key to a callback - _exportFunctions.bind = function(key, callback, type) { - if (type === undefined) { - type = 'keydown'; - } - if (_keys[key] === undefined) { - throw new Error("unsupported key: " + key); - } - if (_bound[type][_keys[key].code] === undefined) { - _bound[type][_keys[key].code] = []; - } - _bound[type][_keys[key].code].push({fn:callback, shift:_keys[key].shift}); - }; + if (this.options.style == 'line') { + this.type = new Line(this.id, this.options); + } + else if (this.options.style == 'bar') { + this.type = new Bar(this.id, this.options); + } + else if (this.options.style == 'points') { + this.type = new Points(this.id, this.options); + } + }; - // bind all keys to a call back (demo purposes) - _exportFunctions.bindAll = function(callback, type) { - if (type === undefined) { - type = 'keydown'; - } - for (var key in _keys) { - if (_keys.hasOwnProperty(key)) { - _exportFunctions.bind(key,callback,type); - } - } - }; + /** + * this updates the current group class with the latest group dataset entree, used in _updateGroup in linegraph + * @param group + */ + GraphGroup.prototype.update = function(group) { + this.group = group; + this.content = group.content || 'graph'; + this.className = group.className || this.className || "graphGroup" + this.groupsUsingDefaultStyles[0] % 10; + this.visible = group.visible === undefined ? true : group.visible; + this.style = group.style; + this.setOptions(group.options); + }; - // get the key label from an event - _exportFunctions.getKey = function(event) { - for (var key in _keys) { - if (_keys.hasOwnProperty(key)) { - if (event.shiftKey == true && _keys[key].shift == true && event.keyCode == _keys[key].code) { - return key; - } - else if (event.shiftKey == false && _keys[key].shift == false && event.keyCode == _keys[key].code) { - return key; - } - else if (event.keyCode == _keys[key].code && key == 'shift') { - return key; - } - } - } - return "unknown key, currently not supported"; - }; - // unbind either a specific callback from a key or all of them (by leaving callback undefined) - _exportFunctions.unbind = function(key, callback, type) { - if (type === undefined) { - type = 'keydown'; - } - if (_keys[key] === undefined) { - throw new Error("unsupported key: " + key); - } - if (callback !== undefined) { - var newBindings = []; - var bound = _bound[type][_keys[key].code]; - if (bound !== undefined) { - for (var i = 0; i < bound.length; i++) { - if (!(bound[i].fn == callback && bound[i].shift == _keys[key].shift)) { - newBindings.push(_bound[type][_keys[key].code][i]); - } - } - } - _bound[type][_keys[key].code] = newBindings; + /** + * draw the icon for the legend. + * + * @param x + * @param y + * @param JSONcontainer + * @param SVGcontainer + * @param iconWidth + * @param iconHeight + */ + GraphGroup.prototype.drawIcon = function(x, y, JSONcontainer, SVGcontainer, iconWidth, iconHeight) { + var fillHeight = iconHeight * 0.5; + var path, fillPath; + + var outline = DOMutil.getSVGElement("rect", JSONcontainer, SVGcontainer); + outline.setAttributeNS(null, "x", x); + outline.setAttributeNS(null, "y", y - fillHeight); + outline.setAttributeNS(null, "width", iconWidth); + outline.setAttributeNS(null, "height", 2*fillHeight); + outline.setAttributeNS(null, "class", "outline"); + + if (this.options.style == 'line') { + path = DOMutil.getSVGElement("path", JSONcontainer, SVGcontainer); + path.setAttributeNS(null, "class", this.className); + if(this.style !== undefined) { + path.setAttributeNS(null, "style", this.style); + } + + path.setAttributeNS(null, "d", "M" + x + ","+y+" L" + (x + iconWidth) + ","+y+""); + if (this.options.shaded.enabled == true) { + fillPath = DOMutil.getSVGElement("path", JSONcontainer, SVGcontainer); + if (this.options.shaded.orientation == 'top') { + fillPath.setAttributeNS(null, "d", "M"+x+", " + (y - fillHeight) + + "L"+x+","+y+" L"+ (x + iconWidth) + ","+y+" L"+ (x + iconWidth) + "," + (y - fillHeight)); } else { - _bound[type][_keys[key].code] = []; + fillPath.setAttributeNS(null, "d", "M"+x+","+y+" " + + "L"+x+"," + (y + fillHeight) + " " + + "L"+ (x + iconWidth) + "," + (y + fillHeight) + + "L"+ (x + iconWidth) + ","+y); } - }; - - // reset all bound variables. - _exportFunctions.reset = function() { - _bound = {keydown:{}, keyup:{}}; - }; + fillPath.setAttributeNS(null, "class", this.className + " iconFill"); + } - // unbind all listeners and reset all variables. - _exportFunctions.destroy = function() { - _bound = {keydown:{}, keyup:{}}; - container.removeEventListener('keydown', down, true); - container.removeEventListener('keyup', up, true); - }; + if (this.options.drawPoints.enabled == true) { + DOMutil.drawPoint(x + 0.5 * iconWidth,y, this, JSONcontainer, SVGcontainer); + } + } + else { + var barWidth = Math.round(0.3 * iconWidth); + var bar1Height = Math.round(0.4 * iconHeight); + var bar2Height = Math.round(0.75 * iconHeight); - // create listeners. - container.addEventListener('keydown',down,true); - container.addEventListener('keyup',up,true); + var offset = Math.round((iconWidth - (2 * barWidth))/3); - // return the public functions. - return _exportFunctions; + DOMutil.drawBar(x + 0.5*barWidth + offset , y + fillHeight - bar1Height - 1, barWidth, bar1Height, this.className + ' bar', JSONcontainer, SVGcontainer); + DOMutil.drawBar(x + 1.5*barWidth + offset + 2, y + fillHeight - bar2Height - 1, barWidth, bar2Height, this.className + ' bar', JSONcontainer, SVGcontainer); } + }; - return keycharm; - })); + + /** + * return the legend entree for this group. + * + * @param iconWidth + * @param iconHeight + * @returns {{icon: HTMLElement, label: (group.content|*|string), orientation: (.options.yAxisOrientation|*)}} + */ + GraphGroup.prototype.getLegend = function(iconWidth, iconHeight) { + var svg = document.createElementNS('http://www.w3.org/2000/svg',"svg"); + this.drawIcon(0,0.5*iconHeight,[],svg,iconWidth,iconHeight); + return {icon: svg, label: this.content, orientation:this.options.yAxisOrientation}; + } + + GraphGroup.prototype.getYRange = function(groupData) { + return this.type.getYRange(groupData); + } + + GraphGroup.prototype.draw = function(dataset, group, framework) { + this.type.draw(dataset, group, framework); + } + module.exports = GraphGroup; /***/ }, -/* 58 */ +/* 47 */ /***/ function(module, exports, __webpack_require__) { - var __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(global, module) {//! moment.js - //! version : 2.9.0 - //! authors : Tim Wood, Iskren Chernev, Moment.js contributors - //! license : MIT - //! momentjs.com + /** + * Created by Alex on 11/11/2014. + */ + var DOMutil = __webpack_require__(6); + var Points = __webpack_require__(48); - (function (undefined) { - /************************************ - Constants - ************************************/ + function Line(groupId, options) { + this.groupId = groupId; + this.options = options; + } - var moment, - VERSION = '2.9.0', - // the global-scope this is NOT the global object in Node.js - globalScope = (typeof global !== 'undefined' && (typeof window === 'undefined' || window === global.window)) ? global : this, - oldGlobalMoment, - round = Math.round, - hasOwnProperty = Object.prototype.hasOwnProperty, - i, + Line.prototype.getYRange = function(groupData) { + var yMin = groupData[0].y; + var yMax = groupData[0].y; + for (var j = 0; j < groupData.length; j++) { + yMin = yMin > groupData[j].y ? groupData[j].y : yMin; + yMax = yMax < groupData[j].y ? groupData[j].y : yMax; + } + return {min: yMin, max: yMax, yAxisOrientation: this.options.yAxisOrientation}; + }; - YEAR = 0, - MONTH = 1, - DATE = 2, - HOUR = 3, - MINUTE = 4, - SECOND = 5, - MILLISECOND = 6, - // internal storage for locale config files - locales = {}, + /** + * draw a line graph + * + * @param dataset + * @param group + */ + Line.prototype.draw = function (dataset, group, framework) { + if (dataset != null) { + if (dataset.length > 0) { + var path, d; + var svgHeight = Number(framework.svg.style.height.replace('px','')); + path = DOMutil.getSVGElement('path', framework.svgElements, framework.svg); + path.setAttributeNS(null, "class", group.className); + if(group.style !== undefined) { + path.setAttributeNS(null, "style", group.style); + } - // extra moment internal properties (plugins register props here) - momentProperties = [], + // construct path from dataset + if (group.options.catmullRom.enabled == true) { + d = Line._catmullRom(dataset, group); + } + else { + d = Line._linear(dataset); + } - // check for nodeJS - hasModule = (typeof module !== 'undefined' && module && module.exports), + // append with points for fill and finalize the path + if (group.options.shaded.enabled == true) { + var fillPath = DOMutil.getSVGElement('path', framework.svgElements, framework.svg); + var dFill; + if (group.options.shaded.orientation == 'top') { + dFill = 'M' + dataset[0].x + ',' + 0 + ' ' + d + 'L' + dataset[dataset.length - 1].x + ',' + 0; + } + else { + dFill = 'M' + dataset[0].x + ',' + svgHeight + ' ' + d + 'L' + dataset[dataset.length - 1].x + ',' + svgHeight; + } + fillPath.setAttributeNS(null, "class", group.className + " fill"); + if(group.options.shaded.style !== undefined) { + fillPath.setAttributeNS(null, "style", group.options.shaded.style); + } + fillPath.setAttributeNS(null, "d", dFill); + } + // copy properties to path for drawing. + path.setAttributeNS(null, 'd', 'M' + d); - // ASP.NET json date format regex - aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, - aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/, + // draw points + if (group.options.drawPoints.enabled == true) { + Points.draw(dataset, group, framework); + } + } + } + }; - // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html - // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere - isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/, - // format tokens - formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|x|X|zz?|ZZ?|.)/g, - localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, - // parsing token regexes - parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 - parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 - parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999 - parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 - parseTokenDigits = /\d+/, // nonzero number of digits - parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic. - parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z - parseTokenT = /T/i, // T (ISO separator) - parseTokenOffsetMs = /[\+\-]?\d+/, // 1234567890123 - parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 + /** + * This uses an uniform parametrization of the CatmullRom algorithm: + * 'On the Parameterization of Catmull-Rom Curves' by Cem Yuksel et al. + * @param data + * @returns {string} + * @private + */ + Line._catmullRomUniform = function(data) { + // catmull rom + var p0, p1, p2, p3, bp1, bp2; + var d = Math.round(data[0].x) + ',' + Math.round(data[0].y) + ' '; + var normalization = 1/6; + var length = data.length; + for (var i = 0; i < length - 1; i++) { - //strict parsing regexes - parseTokenOneDigit = /\d/, // 0 - 9 - parseTokenTwoDigits = /\d\d/, // 00 - 99 - parseTokenThreeDigits = /\d{3}/, // 000 - 999 - parseTokenFourDigits = /\d{4}/, // 0000 - 9999 - parseTokenSixDigits = /[+-]?\d{6}/, // -999,999 - 999,999 - parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf + p0 = (i == 0) ? data[0] : data[i-1]; + p1 = data[i]; + p2 = data[i+1]; + p3 = (i + 2 < length) ? data[i+2] : p2; - // iso 8601 regex - // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) - isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/, - isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', + // Catmull-Rom to Cubic Bezier conversion matrix + // 0 1 0 0 + // -1/6 1 1/6 0 + // 0 1/6 1 -1/6 + // 0 0 1 0 - isoDates = [ - ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/], - ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/], - ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/], - ['GGGG-[W]WW', /\d{4}-W\d{2}/], - ['YYYY-DDD', /\d{4}-\d{3}/] - ], + // bp0 = { x: p1.x, y: p1.y }; + bp1 = { x: ((-p0.x + 6*p1.x + p2.x) *normalization), y: ((-p0.y + 6*p1.y + p2.y) *normalization)}; + bp2 = { x: (( p1.x + 6*p2.x - p3.x) *normalization), y: (( p1.y + 6*p2.y - p3.y) *normalization)}; + // bp0 = { x: p2.x, y: p2.y }; - // iso time formats and regexes - isoTimes = [ - ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d+/], - ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], - ['HH:mm', /(T| )\d\d:\d\d/], - ['HH', /(T| )\d\d/] - ], + d += 'C' + + bp1.x + ',' + + bp1.y + ' ' + + bp2.x + ',' + + bp2.y + ' ' + + p2.x + ',' + + p2.y + ' '; + } - // timezone chunker '+10:00' > ['10', '00'] or '-1530' > ['-', '15', '30'] - parseTimezoneChunker = /([\+\-]|\d\d)/gi, + return d; + }; - // getter and setter names - proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), - unitMillisecondFactors = { - 'Milliseconds' : 1, - 'Seconds' : 1e3, - 'Minutes' : 6e4, - 'Hours' : 36e5, - 'Days' : 864e5, - 'Months' : 2592e6, - 'Years' : 31536e6 - }, + /** + * This uses either the chordal or centripetal parameterization of the catmull-rom algorithm. + * By default, the centripetal parameterization is used because this gives the nicest results. + * These parameterizations are relatively heavy because the distance between 4 points have to be calculated. + * + * One optimization can be used to reuse distances since this is a sliding window approach. + * @param data + * @param group + * @returns {string} + * @private + */ + Line._catmullRom = function(data, group) { + var alpha = group.options.catmullRom.alpha; + if (alpha == 0 || alpha === undefined) { + return this._catmullRomUniform(data); + } + else { + var p0, p1, p2, p3, bp1, bp2, d1,d2,d3, A, B, N, M; + var d3powA, d2powA, d3pow2A, d2pow2A, d1pow2A, d1powA; + var d = Math.round(data[0].x) + ',' + Math.round(data[0].y) + ' '; + var length = data.length; + for (var i = 0; i < length - 1; i++) { - unitAliases = { - ms : 'millisecond', - s : 'second', - m : 'minute', - h : 'hour', - d : 'day', - D : 'date', - w : 'week', - W : 'isoWeek', - M : 'month', - Q : 'quarter', - y : 'year', - DDD : 'dayOfYear', - e : 'weekday', - E : 'isoWeekday', - gg: 'weekYear', - GG: 'isoWeekYear' - }, + p0 = (i == 0) ? data[0] : data[i-1]; + p1 = data[i]; + p2 = data[i+1]; + p3 = (i + 2 < length) ? data[i+2] : p2; - camelFunctions = { - dayofyear : 'dayOfYear', - isoweekday : 'isoWeekday', - isoweek : 'isoWeek', - weekyear : 'weekYear', - isoweekyear : 'isoWeekYear' - }, + d1 = Math.sqrt(Math.pow(p0.x - p1.x,2) + Math.pow(p0.y - p1.y,2)); + d2 = Math.sqrt(Math.pow(p1.x - p2.x,2) + Math.pow(p1.y - p2.y,2)); + d3 = Math.sqrt(Math.pow(p2.x - p3.x,2) + Math.pow(p2.y - p3.y,2)); - // format function strings - formatFunctions = {}, + // Catmull-Rom to Cubic Bezier conversion matrix - // default relative time thresholds - relativeTimeThresholds = { - 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 - }, + // A = 2d1^2a + 3d1^a * d2^a + d3^2a + // B = 2d3^2a + 3d3^a * d2^a + d2^2a - // tokens to ordinalize and pad - ordinalizeTokens = 'DDD w W M D d'.split(' '), - paddedTokens = 'M D H h m s w W'.split(' '), + // [ 0 1 0 0 ] + // [ -d2^2a /N A/N d1^2a /N 0 ] + // [ 0 d3^2a /M B/M -d2^2a /M ] + // [ 0 0 1 0 ] - formatTokenFunctions = { - M : function () { - return this.month() + 1; - }, - MMM : function (format) { - return this.localeData().monthsShort(this, format); - }, - MMMM : function (format) { - return this.localeData().months(this, format); - }, - D : function () { - return this.date(); - }, - DDD : function () { - return this.dayOfYear(); - }, - d : function () { - return this.day(); - }, - dd : function (format) { - return this.localeData().weekdaysMin(this, format); - }, - ddd : function (format) { - return this.localeData().weekdaysShort(this, format); - }, - dddd : function (format) { - return this.localeData().weekdays(this, format); - }, - w : function () { - return this.week(); - }, - W : function () { - return this.isoWeek(); - }, - YY : function () { - return leftZeroFill(this.year() % 100, 2); - }, - YYYY : function () { - return leftZeroFill(this.year(), 4); - }, - YYYYY : function () { - return leftZeroFill(this.year(), 5); - }, - YYYYYY : function () { - var y = this.year(), sign = y >= 0 ? '+' : '-'; - return sign + leftZeroFill(Math.abs(y), 6); - }, - gg : function () { - return leftZeroFill(this.weekYear() % 100, 2); - }, - gggg : function () { - return leftZeroFill(this.weekYear(), 4); - }, - ggggg : function () { - return leftZeroFill(this.weekYear(), 5); - }, - GG : function () { - return leftZeroFill(this.isoWeekYear() % 100, 2); - }, - GGGG : function () { - return leftZeroFill(this.isoWeekYear(), 4); - }, - GGGGG : function () { - return leftZeroFill(this.isoWeekYear(), 5); - }, - e : function () { - return this.weekday(); - }, - E : function () { - return this.isoWeekday(); - }, - a : function () { - return this.localeData().meridiem(this.hours(), this.minutes(), true); - }, - A : function () { - return this.localeData().meridiem(this.hours(), this.minutes(), false); - }, - H : function () { - return this.hours(); - }, - h : function () { - return this.hours() % 12 || 12; - }, - m : function () { - return this.minutes(); - }, - s : function () { - return this.seconds(); - }, - S : function () { - return toInt(this.milliseconds() / 100); - }, - SS : function () { - return leftZeroFill(toInt(this.milliseconds() / 10), 2); - }, - SSS : function () { - return leftZeroFill(this.milliseconds(), 3); - }, - SSSS : function () { - return leftZeroFill(this.milliseconds(), 3); - }, - Z : function () { - var a = this.utcOffset(), - b = '+'; - if (a < 0) { - a = -a; - b = '-'; - } - return b + leftZeroFill(toInt(a / 60), 2) + ':' + leftZeroFill(toInt(a) % 60, 2); - }, - ZZ : function () { - var a = this.utcOffset(), - b = '+'; - if (a < 0) { - a = -a; - b = '-'; - } - return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2); - }, - z : function () { - return this.zoneAbbr(); - }, - zz : function () { - return this.zoneName(); - }, - x : function () { - return this.valueOf(); - }, - X : function () { - return this.unix(); - }, - Q : function () { - return this.quarter(); - } + d3powA = Math.pow(d3, alpha); + d3pow2A = Math.pow(d3,2*alpha); + d2powA = Math.pow(d2, alpha); + d2pow2A = Math.pow(d2,2*alpha); + d1powA = Math.pow(d1, alpha); + d1pow2A = Math.pow(d1,2*alpha); + + A = 2*d1pow2A + 3*d1powA * d2powA + d2pow2A; + B = 2*d3pow2A + 3*d3powA * d2powA + d2pow2A; + N = 3*d1powA * (d1powA + d2powA); + if (N > 0) {N = 1 / N;} + M = 3*d3powA * (d3powA + d2powA); + if (M > 0) {M = 1 / M;} + + bp1 = { x: ((-d2pow2A * p0.x + A*p1.x + d1pow2A * p2.x) * N), + y: ((-d2pow2A * p0.y + A*p1.y + d1pow2A * p2.y) * N)}; + + bp2 = { x: (( d3pow2A * p1.x + B*p2.x - d2pow2A * p3.x) * M), + y: (( d3pow2A * p1.y + B*p2.y - d2pow2A * p3.y) * M)}; + + if (bp1.x == 0 && bp1.y == 0) {bp1 = p1;} + if (bp2.x == 0 && bp2.y == 0) {bp2 = p2;} + d += 'C' + + bp1.x + ',' + + bp1.y + ' ' + + bp2.x + ',' + + bp2.y + ' ' + + p2.x + ',' + + p2.y + ' '; + } + + return d; + } + }; + + /** + * this generates the SVG path for a linear drawing between datapoints. + * @param data + * @returns {string} + * @private + */ + Line._linear = function(data) { + // linear + var d = ''; + for (var i = 0; i < data.length; i++) { + if (i == 0) { + d += data[i].x + ',' + data[i].y; + } + else { + d += ' ' + data[i].x + ',' + data[i].y; + } + } + return d; + }; + + module.exports = Line; + + +/***/ }, +/* 48 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Created by Alex on 11/11/2014. + */ + var DOMutil = __webpack_require__(6); + + function Points(groupId, options) { + this.groupId = groupId; + this.options = options; + } + + + Points.prototype.getYRange = function(groupData) { + var yMin = groupData[0].y; + var yMax = groupData[0].y; + for (var j = 0; j < groupData.length; j++) { + yMin = yMin > groupData[j].y ? groupData[j].y : yMin; + yMax = yMax < groupData[j].y ? groupData[j].y : yMax; + } + return {min: yMin, max: yMax, yAxisOrientation: this.options.yAxisOrientation}; + }; + + Points.prototype.draw = function(dataset, group, framework, offset) { + Points.draw(dataset, group, framework, offset); + } + + /** + * draw the data points + * + * @param {Array} dataset + * @param {Object} JSONcontainer + * @param {Object} svg | SVG DOM element + * @param {GraphGroup} group + * @param {Number} [offset] + */ + Points.draw = function (dataset, group, framework, offset) { + if (offset === undefined) {offset = 0;} + for (var i = 0; i < dataset.length; i++) { + DOMutil.drawPoint(dataset[i].x + offset, dataset[i].y, group, framework.svgElements, framework.svg); + } + }; + + + module.exports = Points; + +/***/ }, +/* 49 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Created by Alex on 11/11/2014. + */ + var DOMutil = __webpack_require__(6); + var Points = __webpack_require__(48); + + function Bargraph(groupId, options) { + this.groupId = groupId; + this.options = options; + } + + Bargraph.prototype.getYRange = function(groupData) { + if (this.options.barChart.handleOverlap != 'stack') { + var yMin = groupData[0].y; + var yMax = groupData[0].y; + for (var j = 0; j < groupData.length; j++) { + yMin = yMin > groupData[j].y ? groupData[j].y : yMin; + yMax = yMax < groupData[j].y ? groupData[j].y : yMax; + } + return {min: yMin, max: yMax, yAxisOrientation: this.options.yAxisOrientation}; + } + else { + var barCombinedData = []; + for (var j = 0; j < groupData.length; j++) { + barCombinedData.push({ + x: groupData[j].x, + y: groupData[j].y, + groupId: this.groupId + }); + } + return barCombinedData; + } + }; + + + + /** + * draw a bar graph + * + * @param groupIds + * @param processedGroupData + */ + Bargraph.draw = function (groupIds, processedGroupData, framework) { + var combinedData = []; + var intersections = {}; + var coreDistance; + var key, drawData; + var group; + var i,j; + var barPoints = 0; + + // combine all barchart data + for (i = 0; i < groupIds.length; i++) { + group = framework.groups[groupIds[i]]; + if (group.options.style == 'bar') { + if (group.visible == true && (framework.options.groups.visibility[groupIds[i]] === undefined || framework.options.groups.visibility[groupIds[i]] == true)) { + for (j = 0; j < processedGroupData[groupIds[i]].length; j++) { + combinedData.push({ + x: processedGroupData[groupIds[i]][j].x, + y: processedGroupData[groupIds[i]][j].y, + groupId: groupIds[i] + }); + barPoints += 1; + } + } + } + } + + if (barPoints == 0) {return;} + + // sort by time and by group + combinedData.sort(function (a, b) { + if (a.x == b.x) { + return a.groupId - b.groupId; + } else { + return a.x - b.x; + } + }); + + // get intersections + Bargraph._getDataIntersections(intersections, combinedData); + + // plot barchart + for (i = 0; i < combinedData.length; i++) { + group = framework.groups[combinedData[i].groupId]; + var minWidth = 0.1 * group.options.barChart.width; + + key = combinedData[i].x; + var heightOffset = 0; + if (intersections[key] === undefined) { + if (i+1 < combinedData.length) {coreDistance = Math.abs(combinedData[i+1].x - key);} + if (i > 0) {coreDistance = Math.min(coreDistance,Math.abs(combinedData[i-1].x - key));} + drawData = Bargraph._getSafeDrawData(coreDistance, group, minWidth); + } + else { + var nextKey = i + (intersections[key].amount - intersections[key].resolved); + var prevKey = i - (intersections[key].resolved + 1); + if (nextKey < combinedData.length) {coreDistance = Math.abs(combinedData[nextKey].x - key);} + if (prevKey > 0) {coreDistance = Math.min(coreDistance,Math.abs(combinedData[prevKey].x - key));} + drawData = Bargraph._getSafeDrawData(coreDistance, group, minWidth); + intersections[key].resolved += 1; + + if (group.options.barChart.handleOverlap == 'stack') { + heightOffset = intersections[key].accumulated; + intersections[key].accumulated += group.zeroPosition - combinedData[i].y; + } + else if (group.options.barChart.handleOverlap == 'sideBySide') { + drawData.width = drawData.width / intersections[key].amount; + drawData.offset += (intersections[key].resolved) * drawData.width - (0.5*drawData.width * (intersections[key].amount+1)); + if (group.options.barChart.align == 'left') {drawData.offset -= 0.5*drawData.width;} + else if (group.options.barChart.align == 'right') {drawData.offset += 0.5*drawData.width;} + } + } + DOMutil.drawBar(combinedData[i].x + drawData.offset, combinedData[i].y - heightOffset, drawData.width, group.zeroPosition - combinedData[i].y, group.className + ' bar', framework.svgElements, framework.svg); + // draw points + if (group.options.drawPoints.enabled == true) { + DOMutil.drawPoint(combinedData[i].x + drawData.offset, combinedData[i].y, group, framework.svgElements, framework.svg); + } + } + }; + + + /** + * Fill the intersections object with counters of how many datapoints share the same x coordinates + * @param intersections + * @param combinedData + * @private + */ + Bargraph._getDataIntersections = function (intersections, combinedData) { + // get intersections + var coreDistance; + for (var i = 0; i < combinedData.length; i++) { + if (i + 1 < combinedData.length) { + coreDistance = Math.abs(combinedData[i + 1].x - combinedData[i].x); + } + if (i > 0) { + coreDistance = Math.min(coreDistance, Math.abs(combinedData[i - 1].x - combinedData[i].x)); + } + if (coreDistance == 0) { + if (intersections[combinedData[i].x] === undefined) { + intersections[combinedData[i].x] = {amount: 0, resolved: 0, accumulated: 0}; + } + intersections[combinedData[i].x].amount += 1; + } + } + }; + + + /** + * Get the width and offset for bargraphs based on the coredistance between datapoints + * + * @param coreDistance + * @param group + * @param minWidth + * @returns {{width: Number, offset: Number}} + * @private + */ + Bargraph._getSafeDrawData = function (coreDistance, group, minWidth) { + var width, offset; + if (coreDistance < group.options.barChart.width && coreDistance > 0) { + width = coreDistance < minWidth ? minWidth : coreDistance; + + offset = 0; // recalculate offset with the new width; + if (group.options.barChart.align == 'left') { + offset -= 0.5 * coreDistance; + } + else if (group.options.barChart.align == 'right') { + offset += 0.5 * coreDistance; + } + } + else { + // default settings + width = group.options.barChart.width; + offset = 0; + if (group.options.barChart.align == 'left') { + offset -= 0.5 * group.options.barChart.width; + } + else if (group.options.barChart.align == 'right') { + offset += 0.5 * group.options.barChart.width; + } + } + + return {width: width, offset: offset}; + }; + + Bargraph.getStackedBarYRange = function(barCombinedData, groupRanges, groupIds, groupLabel, orientation) { + if (barCombinedData.length > 0) { + // sort by time and by group + barCombinedData.sort(function (a, b) { + if (a.x == b.x) { + return a.groupId - b.groupId; + } else { + return a.x - b.x; + } + }); + var intersections = {}; + + Bargraph._getDataIntersections(intersections, barCombinedData); + groupRanges[groupLabel] = Bargraph._getStackedBarYRange(intersections, barCombinedData); + groupRanges[groupLabel].yAxisOrientation = orientation; + groupIds.push(groupLabel); + } + } + + Bargraph._getStackedBarYRange = function (intersections, combinedData) { + var key; + var yMin = combinedData[0].y; + var yMax = combinedData[0].y; + for (var i = 0; i < combinedData.length; i++) { + key = combinedData[i].x; + if (intersections[key] === undefined) { + yMin = yMin > combinedData[i].y ? combinedData[i].y : yMin; + yMax = yMax < combinedData[i].y ? combinedData[i].y : yMax; + } + else { + intersections[key].accumulated += combinedData[i].y; + } + } + for (var xpos in intersections) { + if (intersections.hasOwnProperty(xpos)) { + yMin = yMin > intersections[xpos].accumulated ? intersections[xpos].accumulated : yMin; + yMax = yMax < intersections[xpos].accumulated ? intersections[xpos].accumulated : yMax; + } + } + + return {min: yMin, max: yMax}; + }; + + module.exports = Bargraph; + +/***/ }, +/* 50 */ +/***/ function(module, exports, __webpack_require__) { + + var util = __webpack_require__(1); + var DOMutil = __webpack_require__(6); + var Component = __webpack_require__(23); + + /** + * Legend for Graph2d + */ + function Legend(body, options, side, linegraphOptions) { + this.body = body; + this.defaultOptions = { + enabled: true, + icons: true, + iconSize: 20, + iconSpacing: 6, + left: { + visible: true, + position: 'top-left' // top/bottom - left,center,right + }, + right: { + visible: true, + position: 'top-left' // top/bottom - left,center,right + } + } + this.side = side; + this.options = util.extend({},this.defaultOptions); + this.linegraphOptions = linegraphOptions; + + this.svgElements = {}; + this.dom = {}; + this.groups = {}; + this.amountOfGroups = 0; + this._create(); + + this.setOptions(options); + } + + Legend.prototype = new Component(); + + Legend.prototype.clear = function() { + this.groups = {}; + this.amountOfGroups = 0; + } + + Legend.prototype.addGroup = function(label, graphOptions) { + + if (!this.groups.hasOwnProperty(label)) { + this.groups[label] = graphOptions; + } + this.amountOfGroups += 1; + }; + + Legend.prototype.updateGroup = function(label, graphOptions) { + this.groups[label] = graphOptions; + }; + + Legend.prototype.removeGroup = function(label) { + if (this.groups.hasOwnProperty(label)) { + delete this.groups[label]; + this.amountOfGroups -= 1; + } + }; + + Legend.prototype._create = function() { + this.dom.frame = document.createElement('div'); + this.dom.frame.className = 'legend'; + this.dom.frame.style.position = "absolute"; + this.dom.frame.style.top = "10px"; + this.dom.frame.style.display = "block"; + + this.dom.textArea = document.createElement('div'); + this.dom.textArea.className = 'legendText'; + this.dom.textArea.style.position = "relative"; + this.dom.textArea.style.top = "0px"; + + this.svg = document.createElementNS('http://www.w3.org/2000/svg',"svg"); + this.svg.style.position = 'absolute'; + this.svg.style.top = 0 +'px'; + this.svg.style.width = this.options.iconSize + 5 + 'px'; + this.svg.style.height = '100%'; + + this.dom.frame.appendChild(this.svg); + this.dom.frame.appendChild(this.dom.textArea); + }; + + /** + * Hide the component from the DOM + */ + Legend.prototype.hide = function() { + // remove the frame containing the items + if (this.dom.frame.parentNode) { + this.dom.frame.parentNode.removeChild(this.dom.frame); + } + }; + + /** + * Show the component in the DOM (when not already visible). + * @return {Boolean} changed + */ + Legend.prototype.show = function() { + // show frame containing the items + if (!this.dom.frame.parentNode) { + this.body.dom.center.appendChild(this.dom.frame); + } + }; + + Legend.prototype.setOptions = function(options) { + var fields = ['enabled','orientation','icons','left','right']; + util.selectiveDeepExtend(fields, this.options, options); + }; + + Legend.prototype.redraw = function() { + var activeGroups = 0; + for (var groupId in this.groups) { + if (this.groups.hasOwnProperty(groupId)) { + if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) { + activeGroups++; + } + } + } + + if (this.options[this.side].visible == false || this.amountOfGroups == 0 || this.options.enabled == false || activeGroups == 0) { + this.hide(); + } + else { + this.show(); + if (this.options[this.side].position == 'top-left' || this.options[this.side].position == 'bottom-left') { + this.dom.frame.style.left = '4px'; + this.dom.frame.style.textAlign = "left"; + this.dom.textArea.style.textAlign = "left"; + this.dom.textArea.style.left = (this.options.iconSize + 15) + 'px'; + this.dom.textArea.style.right = ''; + this.svg.style.left = 0 +'px'; + this.svg.style.right = ''; + } + else { + this.dom.frame.style.right = '4px'; + this.dom.frame.style.textAlign = "right"; + this.dom.textArea.style.textAlign = "right"; + this.dom.textArea.style.right = (this.options.iconSize + 15) + 'px'; + this.dom.textArea.style.left = ''; + this.svg.style.right = 0 +'px'; + this.svg.style.left = ''; + } + + if (this.options[this.side].position == 'top-left' || this.options[this.side].position == 'top-right') { + this.dom.frame.style.top = 4 - Number(this.body.dom.center.style.top.replace("px","")) + 'px'; + this.dom.frame.style.bottom = ''; + } + else { + var scrollableHeight = this.body.domProps.center.height - this.body.domProps.centerContainer.height; + this.dom.frame.style.bottom = 4 + scrollableHeight + Number(this.body.dom.center.style.top.replace("px","")) + 'px'; + this.dom.frame.style.top = ''; + } + + if (this.options.icons == false) { + this.dom.frame.style.width = this.dom.textArea.offsetWidth + 10 + 'px'; + this.dom.textArea.style.right = ''; + this.dom.textArea.style.left = ''; + this.svg.style.width = '0px'; + } + else { + this.dom.frame.style.width = this.options.iconSize + 15 + this.dom.textArea.offsetWidth + 10 + 'px' + this.drawLegendIcons(); + } + + var content = ''; + for (var groupId in this.groups) { + if (this.groups.hasOwnProperty(groupId)) { + if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) { + content += this.groups[groupId].content + '
'; + } + } + } + this.dom.textArea.innerHTML = content; + this.dom.textArea.style.lineHeight = ((0.75 * this.options.iconSize) + this.options.iconSpacing) + 'px'; + } + }; + + Legend.prototype.drawLegendIcons = function() { + if (this.dom.frame.parentNode) { + DOMutil.prepareElements(this.svgElements); + var padding = window.getComputedStyle(this.dom.frame).paddingTop; + var iconOffset = Number(padding.replace('px','')); + var x = iconOffset; + var iconWidth = this.options.iconSize; + var iconHeight = 0.75 * this.options.iconSize; + var y = iconOffset + 0.5 * iconHeight + 3; + + this.svg.style.width = iconWidth + 5 + iconOffset + 'px'; + + for (var groupId in this.groups) { + if (this.groups.hasOwnProperty(groupId)) { + if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) { + this.groups[groupId].drawIcon(x, y, this.svgElements, this.svg, iconWidth, iconHeight); + y += iconHeight + this.options.iconSpacing; + } + } + } + + DOMutil.cleanupElements(this.svgElements); + } + }; + + module.exports = Legend; + + +/***/ }, +/* 51 */ +/***/ function(module, exports, __webpack_require__) { + + var Emitter = __webpack_require__(11); + var Hammer = __webpack_require__(19); + var keycharm = __webpack_require__(36); + var util = __webpack_require__(1); + var hammerUtil = __webpack_require__(22); + var DataSet = __webpack_require__(7); + var DataView = __webpack_require__(9); + var dotparser = __webpack_require__(52); + var gephiParser = __webpack_require__(53); + var Groups = __webpack_require__(54); + var Images = __webpack_require__(55); + var Node = __webpack_require__(56); + var Edge = __webpack_require__(57); + var Popup = __webpack_require__(58); + var MixinLoader = __webpack_require__(59); + var Activator = __webpack_require__(35); + var locales = __webpack_require__(70); + + // Load custom shapes into CanvasRenderingContext2D + __webpack_require__(71); + + /** + * @constructor Network + * Create a network visualization, displaying nodes and edges. + * + * @param {Element} container The DOM element in which the Network will + * be created. Normally a div element. + * @param {Object} data An object containing parameters + * {Array} nodes + * {Array} edges + * @param {Object} options Options + */ + function Network (container, data, options) { + if (!(this instanceof Network)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } + + this._determineBrowserMethod(); + this._initializeMixinLoaders(); + + // create variables and set default values + this.containerElement = container; + + // render and calculation settings + this.renderRefreshRate = 60; // hz (fps) + this.renderTimestep = 1000 / this.renderRefreshRate; // ms -- saves calculation later on + this.renderTime = 0; // measured time it takes to render a frame + this.physicsTime = 0; // measured time it takes to render a frame + this.runDoubleSpeed = false; + this.physicsDiscreteStepsize = 0.50; // discrete stepsize of the simulation + + this.initializing = true; + + this.triggerFunctions = {add:null,edit:null,editEdge:null,connect:null,del:null}; + + // set constant values + this.defaultOptions = { + nodes: { + mass: 1, + radiusMin: 10, + radiusMax: 30, + radius: 10, + shape: 'ellipse', + image: undefined, + widthMin: 16, // px + widthMax: 64, // px + fontColor: 'black', + fontSize: 14, // px + fontFace: 'verdana', + fontFill: undefined, + fontStrokeWidth: 0, // px + fontStrokeColor: 'white', + level: -1, + color: { + border: '#2B7CE9', + background: '#97C2FC', + highlight: { + border: '#2B7CE9', + background: '#D2E5FF' }, + hover: { + border: '#2B7CE9', + background: '#D2E5FF' + } + }, + group: undefined, + borderWidth: 1, + borderWidthSelected: undefined + }, + edges: { + widthMin: 1, // + widthMax: 15,// + width: 1, + widthSelectionMultiplier: 2, + hoverWidth: 1.5, + style: 'line', + color: { + color:'#848484', + highlight:'#848484', + hover: '#848484' + }, + fontColor: '#343434', + fontSize: 14, // px + fontFace: 'arial', + fontFill: 'white', + fontStrokeWidth: 0, // px + fontStrokeColor: 'white', + labelAlignment:'horizontal', + arrowScaleFactor: 1, + dash: { + length: 10, + gap: 5, + altLength: undefined + }, + inheritColor: "from" // to, from, false, true (== from) + }, + configurePhysics:false, + physics: { + barnesHut: { + enabled: true, + thetaInverted: 1 / 0.5, // inverted to save time during calculation + gravitationalConstant: -2000, + centralGravity: 0.3, + springLength: 95, + springConstant: 0.04, + damping: 0.09 + }, + repulsion: { + centralGravity: 0.0, + springLength: 200, + springConstant: 0.05, + nodeDistance: 100, + damping: 0.09 + }, + hierarchicalRepulsion: { + enabled: false, + centralGravity: 0.0, + springLength: 100, + springConstant: 0.01, + nodeDistance: 150, + damping: 0.09 + }, + damping: null, + centralGravity: null, + springLength: null, + springConstant: null + }, + clustering: { // Per Node in Cluster = PNiC + enabled: false, // (Boolean) | global on/off switch for clustering. + initialMaxNodes: 100, // (# nodes) | if the initial amount of nodes is larger than this, we cluster until the total number is less than this threshold. + clusterThreshold:500, // (# nodes) | during calculate forces, we check if the total number of nodes is larger than this. If it is, cluster until reduced to reduceToNodes + reduceToNodes:300, // (# nodes) | during calculate forces, we check if the total number of nodes is larger than clusterThreshold. If it is, cluster until reduced to this + chainThreshold: 0.4, // (% of all drawn nodes)| maximum percentage of allowed chainnodes (long strings of connected nodes) within all nodes. (lower means less chains). + clusterEdgeThreshold: 20, // (px) | edge length threshold. if smaller, this node is clustered. + sectorThreshold: 100, // (# nodes in cluster) | cluster size threshold. If larger, expanding in own sector. + screenSizeThreshold: 0.2, // (% of canvas) | relative size threshold. If the width or height of a clusternode takes up this much of the screen, decluster node. + fontSizeMultiplier: 4.0, // (px PNiC) | how much the cluster font size grows per node in cluster (in px). + maxFontSize: 1000, + forceAmplification: 0.1, // (multiplier PNiC) | factor of increase fo the repulsion force of a cluster (per node in cluster). + distanceAmplification: 0.1, // (multiplier PNiC) | factor how much the repulsion distance of a cluster increases (per node in cluster). + edgeGrowth: 20, // (px PNiC) | amount of clusterSize connected to the edge is multiplied with this and added to edgeLength. + nodeScaling: {width: 1, // (px PNiC) | growth of the width per node in cluster. + height: 1, // (px PNiC) | growth of the height per node in cluster. + radius: 1}, // (px PNiC) | growth of the radius per node in cluster. + maxNodeSizeIncrements: 600, // (# increments) | max growth of the width per node in cluster. + activeAreaBoxSize: 80, // (px) | box area around the curser where clusters are popped open. + clusterLevelDifference: 2 + }, + navigation: { + enabled: false + }, + keyboard: { + enabled: false, + speed: {x: 10, y: 10, zoom: 0.02} + }, + dataManipulation: { + enabled: false, + initiallyVisible: false + }, + hierarchicalLayout: { + enabled:false, + levelSeparation: 150, + nodeSpacing: 100, + direction: "UD", // UD, DU, LR, RL + layout: "hubsize" // hubsize, directed + }, + freezeForStabilization: false, + smoothCurves: { + enabled: true, + dynamic: true, + type: "continuous", + roundness: 0.5 + }, + maxVelocity: 30, + minVelocity: 0.1, // px/s + stabilize: true, // stabilize before displaying the network + stabilizationIterations: 1000, // maximum number of iteration to stabilize + zoomExtentOnStabilize: true, + locale: 'en', + locales: locales, + tooltip: { + delay: 300, + fontColor: 'black', + fontSize: 14, // px + fontFace: 'verdana', + color: { + border: '#666', + background: '#FFFFC6' + } + }, + dragNetwork: true, + dragNodes: true, + zoomable: true, + hover: false, + hideEdgesOnDrag: false, + hideNodesOnDrag: false, + width : '100%', + height : '100%', + selectable: true + }; + this.constants = util.extend({}, this.defaultOptions); + this.pixelRatio = 1; + + + this.hoverObj = {nodes:{},edges:{}}; + this.controlNodesActive = false; + this.navigationHammers = {existing:[], _new: []}; + + // animation properties + this.animationSpeed = 1/this.renderRefreshRate; + this.animationEasingFunction = "easeInOutQuint"; + this.easingTime = 0; + this.sourceScale = 0; + this.targetScale = 0; + this.sourceTranslation = 0; + this.targetTranslation = 0; + this.lockedOnNodeId = null; + this.lockedOnNodeOffset = null; + this.touchTime = 0; + + // Node variables + var network = this; + this.groups = new Groups(); // object with groups + this.images = new Images(); // object with images + this.images.setOnloadCallback(function (status) { + network._redraw(); + }); + + // keyboard navigation variables + this.xIncrement = 0; + this.yIncrement = 0; + this.zoomIncrement = 0; - deprecations = {}, + // loading all the mixins: + // load the force calculation functions, grouped under the physics system. + this._loadPhysicsSystem(); + // create a frame and canvas + this._create(); + // load the sector system. (mandatory, fully integrated with Network) + this._loadSectorSystem(); + // load the cluster system. (mandatory, even when not using the cluster system, there are function calls to it) + this._loadClusterSystem(); + // load the selection system. (mandatory, required by Network) + this._loadSelectionSystem(); + // load the selection system. (mandatory, required by Network) + this._loadHierarchySystem(); - lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin'], - updateInProgress = false; + // apply options + this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2); + this._setScale(1); + this.setOptions(options); - // Pick the first defined of two or three arguments. dfl comes from - // default. - function dfl(a, b, c) { - 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'); - } - } + // other vars + this.freezeSimulation = false;// freeze the simulation + this.cachedFunctions = {}; + this.startedStabilization = false; + this.stabilized = false; + this.stabilizationIterations = null; + this.draggingNodes = false; - function hasOwnProp(a, b) { - return hasOwnProperty.call(a, b); - } + // containers for nodes and edges + this.calculationNodes = {}; + this.calculationNodeIndices = []; + this.nodeIndices = []; // array with all the indices of the nodes. Used to speed up forces calculation + this.nodes = {}; // object with Node objects + this.edges = {}; // object with Edge objects - function defaultParsingFlags() { - // We need to deep clone this object, and es5 standard is not very - // helpful. - return { - empty : false, - unusedTokens : [], - unusedInput : [], - overflow : -2, - charsLeftOver : 0, - nullInput : false, - invalidMonth : null, - invalidFormat : false, - userInvalidated : false, - iso: false - }; - } + // position and scale variables and objects + this.canvasTopLeft = {"x": 0,"y": 0}; // coordinates of the top left of the canvas. they will be set during _redraw. + this.canvasBottomRight = {"x": 0,"y": 0}; // coordinates of the bottom right of the canvas. they will be set during _redraw + this.pointerPosition = {"x": 0,"y": 0}; // coordinates of the bottom right of the canvas. they will be set during _redraw + this.areaCenter = {}; // object with x and y elements used for determining the center of the zoom action + this.scale = 1; // defining the global scale variable in the constructor + this.previousScale = this.scale; // this is used to check if the zoom operation is zooming in or out - function printMsg(msg) { - if (moment.suppressDeprecationWarnings === false && - typeof console !== 'undefined' && console.warn) { - console.warn('Deprecation warning: ' + msg); - } - } + // datasets or dataviews + this.nodesData = null; // A DataSet or DataView + this.edgesData = null; // A DataSet or DataView - function deprecate(msg, fn) { - var firstTime = true; - return extend(function () { - if (firstTime) { - printMsg(msg); - firstTime = false; - } - return fn.apply(this, arguments); - }, fn); + // create event listeners used to subscribe on the DataSets of the nodes and edges + this.nodesListeners = { + 'add': function (event, params) { + network._addNodes(params.items); + network.start(); + }, + 'update': function (event, params) { + network._updateNodes(params.items, params.data); + network.start(); + }, + 'remove': function (event, params) { + network._removeNodes(params.items); + network.start(); + } + }; + this.edgesListeners = { + 'add': function (event, params) { + network._addEdges(params.items); + network.start(); + }, + 'update': function (event, params) { + network._updateEdges(params.items); + network.start(); + }, + 'remove': function (event, params) { + network._removeEdges(params.items); + network.start(); } + }; - function deprecateSimple(name, msg) { - if (!deprecations[name]) { - printMsg(msg); - deprecations[name] = true; - } + // properties for the animation + this.moving = true; + this.timer = undefined; // Scheduling function. Is definded in this.start(); + + // load data (the disable start variable will be the same as the enabled clustering) + this.setData(data,this.constants.clustering.enabled || this.constants.hierarchicalLayout.enabled); + + // hierarchical layout + this.initializing = false; + if (this.constants.hierarchicalLayout.enabled == true) { + this._setupHierarchicalLayout(); + } + else { + // zoom so all data will fit on the screen, if clustering is enabled, we do not want start to be called here. + if (this.constants.stabilize == false) { + this.zoomExtent(undefined, true,this.constants.clustering.enabled); } + } - function padToken(func, count) { - return function (a) { - return leftZeroFill(func.call(this, a), count); - }; + // if clustering is disabled, the simulation will have started in the setData function + if (this.constants.clustering.enabled) { + this.startWithClustering(); + } + } + + // Extend Network with an Emitter mixin + Emitter(Network.prototype); + + /** + * Determine if the browser requires a setTimeout or a requestAnimationFrame. This was required because + * some implementations (safari and IE9) did not support requestAnimationFrame + * @private + */ + Network.prototype._determineBrowserMethod = function() { + var browserType = navigator.userAgent.toLowerCase(); + this.requiresTimeout = false; + if (browserType.indexOf('msie 9.0') != -1) { // IE 9 + this.requiresTimeout = true; + } + else if (browserType.indexOf('safari') != -1) { // safari + if (browserType.indexOf('chrome') <= -1) { + this.requiresTimeout = true; } - function ordinalizeToken(func, period) { - return function (a) { - return this.localeData().ordinal(func.call(this, a), period); - }; + } + } + + + /** + * Get the script path where the vis.js library is located + * + * @returns {string | null} path Path or null when not found. Path does not + * end with a slash. + * @private + */ + Network.prototype._getScriptPath = function() { + var scripts = document.getElementsByTagName( 'script' ); + + // find script named vis.js or vis.min.js + for (var i = 0; i < scripts.length; i++) { + var src = scripts[i].src; + var match = src && /\/?vis(.min)?\.js$/.exec(src); + if (match) { + // return path without the script name + return src.substring(0, src.length - match[0].length); } + } - function monthDiff(a, b) { - // difference in months - var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()), - // b is in (anchor - 1 month, anchor + 1 month) - anchor = a.clone().add(wholeMonthDiff, 'months'), - anchor2, adjust; + return null; + }; - if (b - anchor < 0) { - anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); - // linear across the month - adjust = (b - anchor) / (anchor - anchor2); - } else { - anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); - // linear across the month - adjust = (b - anchor) / (anchor2 - anchor); - } - return -(wholeMonthDiff + adjust); + /** + * Find the center position of the network + * @private + */ + Network.prototype._getRange = function() { + var minY = 1e9, maxY = -1e9, minX = 1e9, maxX = -1e9, node; + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + if (minX > (node.boundingBox.left)) {minX = node.boundingBox.left;} + if (maxX < (node.boundingBox.right)) {maxX = node.boundingBox.right;} + if (minY > (node.boundingBox.bottom)) {minY = node.boundingBox.bottom;} + if (maxY < (node.boundingBox.top)) {maxY = node.boundingBox.top;} } + } + if (minX == 1e9 && maxX == -1e9 && minY == 1e9 && maxY == -1e9) { + minY = 0, maxY = 0, minX = 0, maxX = 0; + } + return {minX: minX, maxX: maxX, minY: minY, maxY: maxY}; + }; - while (ordinalizeTokens.length) { - i = ordinalizeTokens.pop(); - formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i); + + /** + * @param {object} range = {minX: minX, maxX: maxX, minY: minY, maxY: maxY}; + * @returns {{x: number, y: number}} + * @private + */ + Network.prototype._findCenter = function(range) { + return {x: (0.5 * (range.maxX + range.minX)), + y: (0.5 * (range.maxY + range.minY))}; + }; + + + /** + * This function zooms out to fit all data on screen based on amount of nodes + * + * @param {Boolean} [initialZoom] | zoom based on fitted formula or range, true = fitted, default = false; + * @param {Boolean} [disableStart] | If true, start is not called. + */ + Network.prototype.zoomExtent = function(animationOptions, initialZoom, disableStart) { + this._redraw(true); + + if (initialZoom === undefined) { + initialZoom = false; + } + if (disableStart === undefined) { + disableStart = false; + } + if (animationOptions === undefined) { + animationOptions = false; + } + + var range = this._getRange(); + var zoomLevel; + + if (initialZoom == true) { + var numberOfNodes = this.nodeIndices.length; + if (this.constants.smoothCurves == true) { + if (this.constants.clustering.enabled == true && + numberOfNodes >= this.constants.clustering.initialMaxNodes) { + zoomLevel = 49.07548 / (numberOfNodes + 142.05338) + 9.1444e-04; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. + } + else { + zoomLevel = 12.662 / (numberOfNodes + 7.4147) + 0.0964822; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. + } } - while (paddedTokens.length) { - i = paddedTokens.pop(); - formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); + else { + if (this.constants.clustering.enabled == true && + numberOfNodes >= this.constants.clustering.initialMaxNodes) { + zoomLevel = 77.5271985 / (numberOfNodes + 187.266146) + 4.76710517e-05; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. + } + else { + zoomLevel = 30.5062972 / (numberOfNodes + 19.93597763) + 0.08413486; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. + } } - formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); + // correct for larger canvasses. + var factor = Math.min(this.frame.canvas.clientWidth / 600, this.frame.canvas.clientHeight / 600); + zoomLevel *= factor; + } + else { + var xDistance = Math.abs(range.maxX - range.minX) * 1.1; + var yDistance = Math.abs(range.maxY - range.minY) * 1.1; - function meridiemFixWrap(locale, hour, meridiem) { - var isPm; + var xZoomLevel = this.frame.canvas.clientWidth / xDistance; + var yZoomLevel = this.frame.canvas.clientHeight / yDistance; - if (meridiem == null) { - // nothing to do - return hour; - } - if (locale.meridiemHour != null) { - return locale.meridiemHour(hour, meridiem); - } else if (locale.isPM != null) { - // Fallback - isPm = locale.isPM(meridiem); - if (isPm && hour < 12) { - hour += 12; - } - if (!isPm && hour === 12) { - hour = 0; - } - return hour; - } else { - // thie is not supposed to happen - return hour; - } - } + zoomLevel = (xZoomLevel <= yZoomLevel) ? xZoomLevel : yZoomLevel; + } - /************************************ - Constructors - ************************************/ + if (zoomLevel > 1.0) { + zoomLevel = 1.0; + } - function Locale() { - } - // Moment prototype object - function Moment(config, skipOverflow) { - if (skipOverflow !== false) { - checkOverflow(config); - } - copyConfig(this, config); - this._d = new Date(+config._d); - // Prevent infinite loop in case updateOffset creates new moment - // objects. - if (updateInProgress === false) { - updateInProgress = true; - moment.updateOffset(this); - updateInProgress = false; - } + var center = this._findCenter(range); + if (disableStart == false) { + var options = {position: center, scale: zoomLevel, animation: animationOptions}; + this.moveTo(options); + this.moving = true; + this.start(); + } + else { + center.x *= zoomLevel; + center.y *= zoomLevel; + center.x -= 0.5 * this.frame.canvas.clientWidth; + center.y -= 0.5 * this.frame.canvas.clientHeight; + this._setScale(zoomLevel); + this._setTranslation(-center.x,-center.y); + } + }; + + + /** + * Update the this.nodeIndices with the most recent node index list + * @private + */ + Network.prototype._updateNodeIndexList = function() { + this._clearNodeIndexList(); + for (var idx in this.nodes) { + if (this.nodes.hasOwnProperty(idx)) { + this.nodeIndices.push(idx); } + } + }; - // Duration Constructor - function Duration(duration) { - var normalizedInput = normalizeObjectUnits(duration), - years = normalizedInput.year || 0, - quarters = normalizedInput.quarter || 0, - months = normalizedInput.month || 0, - weeks = normalizedInput.week || 0, - days = normalizedInput.day || 0, - hours = normalizedInput.hour || 0, - minutes = normalizedInput.minute || 0, - seconds = normalizedInput.second || 0, - milliseconds = normalizedInput.millisecond || 0; - // representation for dateAddRemove - this._milliseconds = +milliseconds + - seconds * 1e3 + // 1000 - minutes * 6e4 + // 1000 * 60 - hours * 36e5; // 1000 * 60 * 60 - // Because of dateAddRemove treats 24 hours as different from a - // day when working around DST, we need to store them separately - this._days = +days + - weeks * 7; - // It is impossible translate months into days without knowing - // which months you are are talking about, so we have to store - // it separately. - this._months = +months + - quarters * 3 + - years * 12; + /** + * Set nodes and edges, and optionally options as well. + * + * @param {Object} data Object containing parameters: + * {Array | DataSet | DataView} [nodes] Array with nodes + * {Array | DataSet | DataView} [edges] Array with edges + * {String} [dot] String containing data in DOT format + * {String} [gephi] String containing data in gephi JSON format + * {Options} [options] Object with options + * @param {Boolean} [disableStart] | optional: disable the calling of the start function. + */ + Network.prototype.setData = function(data, disableStart) { + if (disableStart === undefined) { + disableStart = false; + } + // we set initializing to true to ensure that the hierarchical layout is not performed until both nodes and edges are added. + this.initializing = true; - this._data = {}; + if (data && data.dot && (data.nodes || data.edges)) { + throw new SyntaxError('Data must contain either parameter "dot" or ' + + ' parameter pair "nodes" and "edges", but not both.'); + } - this._locale = moment.localeData(); + // clean up in case there is anyone in an active mode of the manipulation. This is the same option as bound to the escape button. + if (this.constants.dataManipulation.enabled == true) { + this._createManipulatorBar(); + } - this._bubble(); + // set options + this.setOptions(data && data.options); + // set all data + if (data && data.dot) { + // parse DOT file + if(data && data.dot) { + var dotData = dotparser.DOTToGraph(data.dot); + this.setData(dotData); + return; + } + } + else if (data && data.gephi) { + // parse DOT file + if(data && data.gephi) { + var gephiData = gephiParser.parseGephi(data.gephi); + this.setData(gephiData); + return; + } + } + else { + this._setNodes(data && data.nodes); + this._setEdges(data && data.edges); + } + this._putDataInSector(); + if (disableStart == false) { + if (this.constants.hierarchicalLayout.enabled == true) { + this._resetLevels(); + this._setupHierarchicalLayout(); + } + else { + // find a stable position or start animating to a stable position + if (this.constants.stabilize) { + this._stabilize(); + } } + this.start(); + } + this.initializing = false; + }; - /************************************ - Helpers - ************************************/ + /** + * Set options + * @param {Object} options + */ + Network.prototype.setOptions = function (options) { + if (options) { + var prop; + var fields = ['nodes','edges','smoothCurves','hierarchicalLayout','clustering','navigation', + 'keyboard','dataManipulation','onAdd','onEdit','onEditEdge','onConnect','onDelete','clickToUse' + ]; + // extend all but the values in fields + util.selectiveNotDeepExtend(fields,this.constants, options); + util.selectiveNotDeepExtend(['color'],this.constants.nodes, options.nodes); + util.selectiveNotDeepExtend(['color','length'],this.constants.edges, options.edges); + if (options.physics) { + util.mergeOptions(this.constants.physics, options.physics,'barnesHut'); + util.mergeOptions(this.constants.physics, options.physics,'repulsion'); - function extend(a, b) { - for (var i in b) { - if (hasOwnProp(b, i)) { - a[i] = b[i]; - } + if (options.physics.hierarchicalRepulsion) { + this.constants.hierarchicalLayout.enabled = true; + this.constants.physics.hierarchicalRepulsion.enabled = true; + this.constants.physics.barnesHut.enabled = false; + for (prop in options.physics.hierarchicalRepulsion) { + if (options.physics.hierarchicalRepulsion.hasOwnProperty(prop)) { + this.constants.physics.hierarchicalRepulsion[prop] = options.physics.hierarchicalRepulsion[prop]; + } } + } + } - if (hasOwnProp(b, 'toString')) { - a.toString = b.toString; - } + if (options.onAdd) {this.triggerFunctions.add = options.onAdd;} + if (options.onEdit) {this.triggerFunctions.edit = options.onEdit;} + if (options.onEditEdge) {this.triggerFunctions.editEdge = options.onEditEdge;} + if (options.onConnect) {this.triggerFunctions.connect = options.onConnect;} + if (options.onDelete) {this.triggerFunctions.del = options.onDelete;} + + util.mergeOptions(this.constants, options,'smoothCurves'); + util.mergeOptions(this.constants, options,'hierarchicalLayout'); + util.mergeOptions(this.constants, options,'clustering'); + util.mergeOptions(this.constants, options,'navigation'); + util.mergeOptions(this.constants, options,'keyboard'); + util.mergeOptions(this.constants, options,'dataManipulation'); - if (hasOwnProp(b, 'valueOf')) { - a.valueOf = b.valueOf; - } - return a; + if (options.dataManipulation) { + this.editMode = this.constants.dataManipulation.initiallyVisible; } - 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; + // TODO: work out these options and document them + if (options.edges) { + if (options.edges.color !== undefined) { + if (util.isString(options.edges.color)) { + this.constants.edges.color = {}; + this.constants.edges.color.color = options.edges.color; + this.constants.edges.color.highlight = options.edges.color; + this.constants.edges.color.hover = options.edges.color; } - if (typeof from._locale !== 'undefined') { - to._locale = from._locale; + else { + if (options.edges.color.color !== undefined) {this.constants.edges.color.color = options.edges.color.color;} + if (options.edges.color.highlight !== undefined) {this.constants.edges.color.highlight = options.edges.color.highlight;} + if (options.edges.color.hover !== undefined) {this.constants.edges.color.hover = options.edges.color.hover;} } + this.constants.edges.inheritColor = false; + } - if (momentProperties.length > 0) { - for (i in momentProperties) { - prop = momentProperties[i]; - val = from[prop]; - if (typeof val !== 'undefined') { - to[prop] = val; - } - } + if (!options.edges.fontColor) { + if (options.edges.color !== undefined) { + if (util.isString(options.edges.color)) {this.constants.edges.fontColor = options.edges.color;} + else if (options.edges.color.color !== undefined) {this.constants.edges.fontColor = options.edges.color.color;} } - - return to; + } } - function absRound(number) { - if (number < 0) { - return Math.ceil(number); - } else { - return Math.floor(number); + if (options.nodes) { + if (options.nodes.color) { + var newColorObj = util.parseColor(options.nodes.color); + this.constants.nodes.color.background = newColorObj.background; + this.constants.nodes.color.border = newColorObj.border; + this.constants.nodes.color.highlight.background = newColorObj.highlight.background; + this.constants.nodes.color.highlight.border = newColorObj.highlight.border; + this.constants.nodes.color.hover.background = newColorObj.hover.background; + this.constants.nodes.color.hover.border = newColorObj.hover.border; + } + } + if (options.groups) { + for (var groupname in options.groups) { + if (options.groups.hasOwnProperty(groupname)) { + var group = options.groups[groupname]; + this.groups.add(groupname, group); } + } } - // left zero fill a number - // see http://jsperf.com/left-zero-filling for performance comparison - function leftZeroFill(number, targetLength, forceSign) { - var output = '' + Math.abs(number), - sign = number >= 0; + if (options.tooltip) { + for (prop in options.tooltip) { + if (options.tooltip.hasOwnProperty(prop)) { + this.constants.tooltip[prop] = options.tooltip[prop]; + } + } + if (options.tooltip.color) { + this.constants.tooltip.color = util.parseColor(options.tooltip.color); + } + } - while (output.length < targetLength) { - output = '0' + output; + if ('clickToUse' in options) { + if (options.clickToUse) { + if (!this.activator) { + this.activator = new Activator(this.frame); + this.activator.on('change', this._createKeyBinds.bind(this)); } - return (sign ? (forceSign ? '+' : '') : '-') + output; + } + else { + if (this.activator) { + this.activator.destroy(); + delete this.activator; + } + } } - function positiveMomentsDifference(base, other) { - var res = {milliseconds: 0, months: 0}; + if (options.labels) { + throw new Error('Option "labels" is deprecated. Use options "locale" and "locales" instead.'); + } - 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')); + // (Re)loading the mixins that can be enabled or disabled in the options. + // load the force calculation functions, grouped under the physics system. + this._loadPhysicsSystem(); + // load the navigation system. + this._loadNavigationControls(); + // load the data manipulation system + this._loadManipulationSystem(); + // configure the smooth curves + this._configureSmoothCurves(); - 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; - } + // bind keys. If disabled, this will not do anything; + this._createKeyBinds(); - return res; - } + this.setSize(this.constants.width, this.constants.height); + this.moving = true; + this.start(); + } + }; - // 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, - months = duration._months; - updateOffset = updateOffset == null ? true : updateOffset; + /** + * Create the main frame for the Network. + * This function is executed once when a Network object is created. The frame + * contains a canvas, and this canvas contains all objects like the axis and + * nodes. + * @private + */ + Network.prototype._create = function () { + // remove all elements from the container element. + while (this.containerElement.hasChildNodes()) { + this.containerElement.removeChild(this.containerElement.firstChild); + } - if (milliseconds) { - mom._d.setTime(+mom._d + milliseconds * isAdding); - } - if (days) { - rawSetter(mom, 'Date', rawGetter(mom, 'Date') + days * isAdding); - } - if (months) { - rawMonthSetter(mom, rawGetter(mom, 'Month') + months * isAdding); - } - if (updateOffset) { - moment.updateOffset(mom, days || months); - } - } + this.frame = document.createElement('div'); + this.frame.className = 'vis network-frame'; + this.frame.style.position = 'relative'; + this.frame.style.overflow = 'hidden'; - // check if is an array - function isArray(input) { - return Object.prototype.toString.call(input) === '[object Array]'; - } - function isDate(input) { - return Object.prototype.toString.call(input) === '[object Date]' || - input instanceof Date; - } + ////////////////////////////////////////////////////////////////// - // compare two arrays, return the number of differences - function compareArrays(array1, array2, dontConvert) { - var len = Math.min(array1.length, array2.length), - lengthDiff = Math.abs(array1.length - array2.length), - diffs = 0, - i; - for (i = 0; i < len; i++) { - if ((dontConvert && array1[i] !== array2[i]) || - (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { - diffs++; - } - } - return diffs + lengthDiff; - } + this.frame.canvas = document.createElement("canvas"); + this.frame.canvas.style.position = 'relative'; + this.frame.appendChild(this.frame.canvas); - function normalizeUnits(units) { - if (units) { - var lowered = units.toLowerCase().replace(/(.)s$/, '$1'); - units = unitAliases[units] || camelFunctions[lowered] || lowered; - } - return units; - } + if (!this.frame.canvas.getContext) { + var noCanvas = document.createElement( 'DIV' ); + noCanvas.style.color = 'red'; + noCanvas.style.fontWeight = 'bold' ; + noCanvas.style.padding = '10px'; + noCanvas.innerHTML = 'Error: your browser does not support HTML canvas'; + this.frame.canvas.appendChild(noCanvas); + } + else { + var ctx = this.frame.canvas.getContext("2d"); + this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || + ctx.mozBackingStorePixelRatio || + ctx.msBackingStorePixelRatio || + ctx.oBackingStorePixelRatio || + ctx.backingStorePixelRatio || 1); - function normalizeObjectUnits(inputObject) { - var normalizedInput = {}, - normalizedProp, - prop; + this.frame.canvas.getContext("2d").setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); + } - for (prop in inputObject) { - if (hasOwnProp(inputObject, prop)) { - normalizedProp = normalizeUnits(prop); - if (normalizedProp) { - normalizedInput[normalizedProp] = inputObject[prop]; - } - } - } + ////////////////////////////////////////////////////////////////// - return normalizedInput; - } - function makeList(field) { - var count, setter; + var me = this; + this.drag = {}; + this.pinch = {}; + this.hammer = Hammer(this.frame.canvas, { + prevent_default: true + }); + this.hammer.on('tap', me._onTap.bind(me) ); + this.hammer.on('doubletap', me._onDoubleTap.bind(me) ); + this.hammer.on('hold', me._onHold.bind(me) ); + this.hammer.on('pinch', me._onPinch.bind(me) ); + this.hammer.on('touch', me._onTouch.bind(me) ); + this.hammer.on('dragstart', me._onDragStart.bind(me) ); + this.hammer.on('drag', me._onDrag.bind(me) ); + this.hammer.on('dragend', me._onDragEnd.bind(me) ); + this.hammer.on('mousewheel',me._onMouseWheel.bind(me) ); + this.hammer.on('DOMMouseScroll',me._onMouseWheel.bind(me) ); // for FF + this.hammer.on('mousemove', me._onMouseMoveTitle.bind(me) ); - if (field.indexOf('week') === 0) { - count = 7; - setter = 'day'; - } - else if (field.indexOf('month') === 0) { - count = 12; - setter = 'month'; - } - else { - return; - } + this.hammerFrame = Hammer(this.frame, { + prevent_default: true + }); + this.hammerFrame.on('release', me._onRelease.bind(me) ); - moment[field] = function (format, index) { - var i, getter, - method = moment._locale[field], - results = []; + // add the frame to the container element + this.containerElement.appendChild(this.frame); - if (typeof format === 'number') { - index = format; - format = undefined; - } + }; - getter = function (i) { - var m = moment().utc().set(setter, i); - return method.call(moment._locale, m, format || ''); - }; - if (index != null) { - return getter(index); - } - else { - for (i = 0; i < count; i++) { - results.push(getter(i)); - } - return results; - } - }; - } + /** + * Binding the keys for keyboard navigation. These functions are defined in the NavigationMixin + * @private + */ + Network.prototype._createKeyBinds = function() { + var me = this; + if (this.keycharm !== undefined) { + this.keycharm.destroy(); + } + this.keycharm = keycharm(); - function toInt(argumentForCoercion) { - var coercedNumber = +argumentForCoercion, - value = 0; + this.keycharm.reset(); - if (coercedNumber !== 0 && isFinite(coercedNumber)) { - if (coercedNumber >= 0) { - value = Math.floor(coercedNumber); - } else { - value = Math.ceil(coercedNumber); - } - } + if (this.constants.keyboard.enabled && this.isActive()) { + this.keycharm.bind("up", this._moveUp.bind(me) , "keydown"); + this.keycharm.bind("up", this._yStopMoving.bind(me), "keyup"); + this.keycharm.bind("down", this._moveDown.bind(me) , "keydown"); + this.keycharm.bind("down", this._yStopMoving.bind(me), "keyup"); + this.keycharm.bind("left", this._moveLeft.bind(me) , "keydown"); + this.keycharm.bind("left", this._xStopMoving.bind(me), "keyup"); + this.keycharm.bind("right",this._moveRight.bind(me), "keydown"); + this.keycharm.bind("right",this._xStopMoving.bind(me), "keyup"); + this.keycharm.bind("=", this._zoomIn.bind(me), "keydown"); + this.keycharm.bind("=", this._stopZoom.bind(me), "keyup"); + this.keycharm.bind("num+", this._zoomIn.bind(me), "keydown"); + this.keycharm.bind("num+", this._stopZoom.bind(me), "keyup"); + this.keycharm.bind("num-", this._zoomOut.bind(me), "keydown"); + this.keycharm.bind("num-", this._stopZoom.bind(me), "keyup"); + this.keycharm.bind("-", this._zoomOut.bind(me), "keydown"); + this.keycharm.bind("-", this._stopZoom.bind(me), "keyup"); + this.keycharm.bind("[", this._zoomIn.bind(me), "keydown"); + this.keycharm.bind("[", this._stopZoom.bind(me), "keyup"); + this.keycharm.bind("]", this._zoomOut.bind(me), "keydown"); + this.keycharm.bind("]", this._stopZoom.bind(me), "keyup"); + this.keycharm.bind("pageup",this._zoomIn.bind(me), "keydown"); + this.keycharm.bind("pageup",this._stopZoom.bind(me), "keyup"); + this.keycharm.bind("pagedown",this._zoomOut.bind(me),"keydown"); + this.keycharm.bind("pagedown",this._stopZoom.bind(me), "keyup"); + } - return value; - } + if (this.constants.dataManipulation.enabled == true) { + this.keycharm.bind("esc",this._createManipulatorBar.bind(me)); + this.keycharm.bind("delete",this._deleteSelected.bind(me)); + } + }; - function daysInMonth(year, month) { - return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); - } + /** + * Cleans up all bindings of the network, removing it fully from the memory IF the variable is set to null after calling this function. + * var network = new vis.Network(..); + * network.destroy(); + * network = null; + */ + Network.prototype.destroy = function() { + this.start = function () {}; + this.redraw = function () {}; + this.timer = false; - function weeksInYear(year, dow, doy) { - return weekOfYear(moment([year, 11, 31 + dow - doy]), dow, doy).week; - } + // cleanup physicsConfiguration if it exists + this._cleanupPhysicsConfiguration(); - function daysInYear(year) { - return isLeapYear(year) ? 366 : 365; - } + // remove keybindings + this.keycharm.reset(); - function isLeapYear(year) { - return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; - } + // clear hammer bindings + this.hammer.dispose(); - function checkOverflow(m) { - var overflow; - if (m._a && m._pf.overflow === -2) { - overflow = - m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH : - m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE : - m._a[HOUR] < 0 || m._a[HOUR] > 24 || - (m._a[HOUR] === 24 && (m._a[MINUTE] !== 0 || - m._a[SECOND] !== 0 || - m._a[MILLISECOND] !== 0)) ? HOUR : - m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE : - m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND : - m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND : - -1; + // clear events + this.off(); - if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { - overflow = DATE; - } + this._recursiveDOMDelete(this.containerElement); + } - m._pf.overflow = overflow; - } - } + Network.prototype._recursiveDOMDelete = function(DOMobject) { + while (DOMobject.hasChildNodes() == true) { + this._recursiveDOMDelete(DOMobject.firstChild); + DOMobject.removeChild(DOMobject.firstChild); + } + } - function isValid(m) { - if (m._isValid == null) { - m._isValid = !isNaN(m._d.getTime()) && - m._pf.overflow < 0 && - !m._pf.empty && - !m._pf.invalidMonth && - !m._pf.nullInput && - !m._pf.invalidFormat && - !m._pf.userInvalidated; + /** + * Get the pointer location from a touch location + * @param {{pageX: Number, pageY: Number}} touch + * @return {{x: Number, y: Number}} pointer + * @private + */ + Network.prototype._getPointer = function (touch) { + return { + x: touch.pageX - util.getAbsoluteLeft(this.frame.canvas), + y: touch.pageY - util.getAbsoluteTop(this.frame.canvas) + }; + }; + + /** + * On start of a touch gesture, store the pointer + * @param event + * @private + */ + Network.prototype._onTouch = function (event) { + if (new Date().valueOf() - this.touchTime > 100) { + this.drag.pointer = this._getPointer(event.gesture.center); + this.drag.pinched = false; + this.pinch.scale = this._getScale(); + + // to avoid double fireing of this event because we have two hammer instances. (on canvas and on frame) + this.touchTime = new Date().valueOf(); + + this._handleTouch(this.drag.pointer); + } + }; + + /** + * handle drag start event + * @private + */ + Network.prototype._onDragStart = function (event) { + this._handleDragStart(event); + }; + + + /** + * This function is called by _onDragStart. + * It is separated out because we can then overload it for the datamanipulation system. + * + * @private + */ + Network.prototype._handleDragStart = function(event) { + // in case the touch event was triggered on an external div, do the initial touch now. + if (this.drag.pointer === undefined) { + this._onTouch(event); + } + + var node = this._getNodeAt(this.drag.pointer); + // note: drag.pointer is set in _onTouch to get the initial touch location + + this.drag.dragging = true; + this.drag.selection = []; + this.drag.translation = this._getTranslation(); + this.drag.nodeId = null; + this.draggingNodes = false; - if (m._strict) { - m._isValid = m._isValid && - m._pf.charsLeftOver === 0 && - m._pf.unusedTokens.length === 0 && - m._pf.bigHour === undefined; - } - } - return m._isValid; + if (node != null && this.constants.dragNodes == true) { + this.draggingNodes = true; + this.drag.nodeId = node.id; + // select the clicked node if not yet selected + if (!node.isSelected()) { + this._selectObject(node,false); } - function normalizeLocale(key) { - return key ? key.toLowerCase().replace('_', '-') : key; - } + this.emit("dragStart",{nodeIds:this.getSelection().nodes}); - // 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; + // create an array with the selected nodes and their original location and status + for (var objectId in this.selectionObj.nodes) { + if (this.selectionObj.nodes.hasOwnProperty(objectId)) { + var object = this.selectionObj.nodes[objectId]; + var s = { + id: object.id, + node: object, - 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; - } + // store original x, y, xFixed and yFixed, make the node temporarily Fixed + x: object.x, + y: object.y, + xFixed: object.xFixed, + yFixed: object.yFixed + }; - 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]; - } + object.xFixed = true; + object.yFixed = true; - // Return a moment from input, that is local/utc/utcOffset equivalent to - // model. - function makeAs(input, model) { - var res, diff; - if (model._isUTC) { - res = model.clone(); - diff = (moment.isMoment(input) || isDate(input) ? - +input : +moment(input)) - (+res); - // Use low-level api, because this fn is low-level api. - res._d.setTime(+res._d + diff); - moment.updateOffset(res, false); - return res; - } else { - return moment(input).local(); - } + this.drag.selection.push(s); + } } - - /************************************ - Locale - ************************************/ + } + }; - extend(Locale.prototype, { + /** + * handle drag event + * @private + */ + Network.prototype._onDrag = function (event) { + this._handleOnDrag(event) + }; - set : function (config) { - var prop, i; - for (i in config) { - prop = config[i]; - if (typeof prop === 'function') { - this[i] = prop; - } else { - this['_' + i] = prop; - } - } - // Lenient ordinal parsing accepts just a number in addition to - // number + (possibly) stuff coming from _ordinalParseLenient. - this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + /\d{1,2}/.source); - }, - _months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), - months : function (m) { - return this._months[m.month()]; - }, + /** + * This function is called by _onDrag. + * It is separated out because we can then overload it for the datamanipulation system. + * + * @private + */ + Network.prototype._handleOnDrag = function(event) { + if (this.drag.pinched) { + return; + } - _monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), - monthsShort : function (m) { - return this._monthsShort[m.month()]; - }, + // remove the focus on node if it is focussed on by the focusOnNode + this.releaseNode(); - monthsParse : function (monthName, format, strict) { - var i, mom, regex; + var pointer = this._getPointer(event.gesture.center); + var me = this; + var drag = this.drag; + var selection = drag.selection; + if (selection && selection.length && this.constants.dragNodes == true) { + // calculate delta's and new location + var deltaX = pointer.x - drag.pointer.x; + var deltaY = pointer.y - drag.pointer.y; - if (!this._monthsParse) { - this._monthsParse = []; - this._longMonthsParse = []; - this._shortMonthsParse = []; - } + // update position of all selected nodes + selection.forEach(function (s) { + var node = s.node; - for (i = 0; i < 12; i++) { - // make the regex if we don't have it already - mom = moment.utc([2000, i]); - if (strict && !this._longMonthsParse[i]) { - this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i'); - this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i'); - } - if (!strict && !this._monthsParse[i]) { - regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); - this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) { - return i; - } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) { - return i; - } else if (!strict && this._monthsParse[i].test(monthName)) { - return i; - } - } - }, + if (!s.xFixed) { + node.x = me._XconvertDOMtoCanvas(me._XconvertCanvasToDOM(s.x) + deltaX); + } - _weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), - weekdays : function (m) { - return this._weekdays[m.day()]; - }, + if (!s.yFixed) { + node.y = me._YconvertDOMtoCanvas(me._YconvertCanvasToDOM(s.y) + deltaY); + } + }); - _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 : function (m) { - return this._weekdaysMin[m.day()]; - }, + // start _animationStep if not yet running + if (!this.moving) { + this.moving = true; + this.start(); + } + } + else { + // move the network + if (this.constants.dragNetwork == true) { + // if the drag was not started properly because the click started outside the network div, start it now. + if (this.drag.pointer === undefined) { + this._handleDragStart(event); + return; + } + var diffX = pointer.x - this.drag.pointer.x; + var diffY = pointer.y - this.drag.pointer.y; - weekdaysParse : function (weekdayName) { - var i, mom, regex; + this._setTranslation( + this.drag.translation.x + diffX, + this.drag.translation.y + diffY + ); + this._redraw(); + } + } + }; - if (!this._weekdaysParse) { - this._weekdaysParse = []; - } + /** + * handle drag start event + * @private + */ + Network.prototype._onDragEnd = function (event) { + this._handleDragEnd(event); + }; - for (i = 0; i < 7; i++) { - // make the regex if we don't have it already - if (!this._weekdaysParse[i]) { - mom = moment([2000, 1]).day(i); - regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); - this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (this._weekdaysParse[i].test(weekdayName)) { - return i; - } - } - }, - _longDateFormat : { - LTS : 'h:mm:ss A', - 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]; - if (!output && this._longDateFormat[key.toUpperCase()]) { - output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { - return val.slice(1); - }); - this._longDateFormat[key] = output; - } - return output; - }, + Network.prototype._handleDragEnd = function(event) { + this.drag.dragging = false; + var selection = this.drag.selection; + if (selection && selection.length) { + selection.forEach(function (s) { + // restore original xFixed and yFixed + s.node.xFixed = s.xFixed; + s.node.yFixed = s.yFixed; + }); + this.moving = true; + this.start(); + } + else { + this._redraw(); + } + if (this.draggingNodes == false) { + this.emit("dragEnd",{nodeIds:[]}); + } + else { + this.emit("dragEnd",{nodeIds:this.getSelection().nodes}); + } - isPM : function (input) { - // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays - // Using charAt should be more compatible. - return ((input + '').toLowerCase().charAt(0) === 'p'); - }, + } + /** + * handle tap/click event: select/unselect a node + * @private + */ + Network.prototype._onTap = function (event) { + var pointer = this._getPointer(event.gesture.center); + this.pointerPosition = pointer; + this._handleTap(pointer); - _meridiemParse : /[ap]\.?m?\.?/i, - meridiem : function (hours, minutes, isLower) { - if (hours > 11) { - return isLower ? 'pm' : 'PM'; - } else { - return isLower ? 'am' : 'AM'; - } - }, + }; - _calendar : { - sameDay : '[Today at] LT', - nextDay : '[Tomorrow at] LT', - nextWeek : 'dddd [at] LT', - lastDay : '[Yesterday at] LT', - lastWeek : '[Last] dddd [at] LT', - sameElse : 'L' - }, - calendar : function (key, mom, now) { - var output = this._calendar[key]; - return typeof output === 'function' ? output.apply(mom, [now]) : output; - }, + /** + * handle doubletap event + * @private + */ + Network.prototype._onDoubleTap = function (event) { + var pointer = this._getPointer(event.gesture.center); + this._handleDoubleTap(pointer); + }; - _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' - }, - 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); - }, + /** + * handle long tap event: multi select nodes + * @private + */ + Network.prototype._onHold = function (event) { + var pointer = this._getPointer(event.gesture.center); + this.pointerPosition = pointer; + this._handleOnHold(pointer); + }; - pastFuture : function (diff, output) { - var format = this._relativeTime[diff > 0 ? 'future' : 'past']; - return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); - }, + /** + * handle the release of the screen + * + * @private + */ + Network.prototype._onRelease = function (event) { + var pointer = this._getPointer(event.gesture.center); + this._handleOnRelease(pointer); + }; - ordinal : function (number) { - return this._ordinal.replace('%d', number); - }, - _ordinal : '%d', - _ordinalParse : /\d{1,2}/, + /** + * Handle pinch event + * @param event + * @private + */ + Network.prototype._onPinch = function (event) { + var pointer = this._getPointer(event.gesture.center); - preparse : function (string) { - return string; - }, + this.drag.pinched = true; + if (!('scale' in this.pinch)) { + this.pinch.scale = 1; + } - postformat : function (string) { - return string; - }, + // TODO: enabled moving while pinching? + var scale = this.pinch.scale * event.gesture.scale; + this._zoom(scale, pointer) + }; - week : function (mom) { - return weekOfYear(mom, this._week.dow, this._week.doy).week; - }, + /** + * Zoom the network in or out + * @param {Number} scale a number around 1, and between 0.01 and 10 + * @param {{x: Number, y: Number}} pointer Position on screen + * @return {Number} appliedScale scale is limited within the boundaries + * @private + */ + Network.prototype._zoom = function(scale, pointer) { + if (this.constants.zoomable == true) { + var scaleOld = this._getScale(); + if (scale < 0.00001) { + scale = 0.00001; + } + if (scale > 10) { + scale = 10; + } - _week : { - dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. - }, + var preScaleDragPointer = null; + if (this.drag !== undefined) { + if (this.drag.dragging == true) { + preScaleDragPointer = this.DOMtoCanvas(this.drag.pointer); + } + } + // + this.frame.canvas.clientHeight / 2 + var translation = this._getTranslation(); - firstDayOfWeek : function () { - return this._week.dow; - }, + var scaleFrac = scale / scaleOld; + var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac; + var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac; - firstDayOfYear : function () { - return this._week.doy; - }, + this.areaCenter = {"x" : this._XconvertDOMtoCanvas(pointer.x), + "y" : this._YconvertDOMtoCanvas(pointer.y)}; - _invalidDate: 'Invalid date', - invalidDate: function () { - return this._invalidDate; - } - }); + this._setScale(scale); + this._setTranslation(tx, ty); + this.updateClustersDefault(); - /************************************ - Formatting - ************************************/ + if (preScaleDragPointer != null) { + var postScaleDragPointer = this.canvasToDOM(preScaleDragPointer); + this.drag.pointer.x = postScaleDragPointer.x; + this.drag.pointer.y = postScaleDragPointer.y; + } + this._redraw(); - function removeFormattingTokens(input) { - if (input.match(/\[[\s\S]/)) { - return input.replace(/^\[|\]$/g, ''); - } - return input.replace(/\\/g, ''); + if (scaleOld < scale) { + this.emit("zoom", {direction:"+"}); + } + else { + this.emit("zoom", {direction:"-"}); } - function makeFormatFunction(format) { - var array = format.match(formattingTokens), i, length; + return scale; + } + }; - for (i = 0, length = array.length; i < length; i++) { - if (formatTokenFunctions[array[i]]) { - array[i] = formatTokenFunctions[array[i]]; - } else { - array[i] = removeFormattingTokens(array[i]); - } - } - return function (mom) { - var output = ''; - for (i = 0; i < length; i++) { - output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; - } - return output; - }; + /** + * Event handler for mouse wheel event, used to zoom the timeline + * See http://adomas.org/javascript-mouse-wheel/ + * https://github.com/EightMedia/hammer.js/issues/256 + * @param {MouseEvent} event + * @private + */ + Network.prototype._onMouseWheel = function(event) { + // retrieve delta + var delta = 0; + if (event.wheelDelta) { /* IE/Opera. */ + delta = event.wheelDelta/120; + } else if (event.detail) { /* Mozilla case. */ + // In Mozilla, sign of delta is different than in IE. + // Also, delta is multiple of 3. + delta = -event.detail/3; + } + + // If delta is nonzero, handle it. + // Basically, delta is now positive if wheel was scrolled up, + // and negative, if wheel was scrolled down. + if (delta) { + + // calculate the new scale + var scale = this._getScale(); + var zoom = delta / 10; + if (delta < 0) { + zoom = zoom / (1 - zoom); } + scale *= (1 + zoom); - // format date using native date object - function formatMoment(m, format) { - if (!m.isValid()) { - return m.localeData().invalidDate(); - } - - format = expandFormat(format, m.localeData()); + // calculate the pointer location + var gesture = hammerUtil.fakeGesture(this, event); + var pointer = this._getPointer(gesture.center); - if (!formatFunctions[format]) { - formatFunctions[format] = makeFormatFunction(format); - } + // apply the new scale + this._zoom(scale, pointer); + } - return formatFunctions[format](m); - } + // Prevent default actions caused by mouse wheel. + event.preventDefault(); + }; - function expandFormat(format, locale) { - var i = 5; - function replaceLongDateFormatTokens(input) { - return locale.longDateFormat(input) || input; - } + /** + * Mouse move handler for checking whether the title moves over a node with a title. + * @param {Event} event + * @private + */ + Network.prototype._onMouseMoveTitle = function (event) { + var gesture = hammerUtil.fakeGesture(this, event); + var pointer = this._getPointer(gesture.center); - localFormattingTokens.lastIndex = 0; - while (i >= 0 && localFormattingTokens.test(format)) { - format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); - localFormattingTokens.lastIndex = 0; - i -= 1; - } + // check if the previously selected node is still selected + if (this.popupObj) { + this._checkHidePopup(pointer); + } - return format; - } + // start a timeout that will check if the mouse is positioned above + // an element + var me = this; + var checkShow = function() { + me._checkShowPopup(pointer); + }; + if (this.popupTimer) { + clearInterval(this.popupTimer); // stop any running calculationTimer + } + if (!this.drag.dragging) { + this.popupTimer = setTimeout(checkShow, this.constants.tooltip.delay); + } - /************************************ - Parsing - ************************************/ + /** + * Adding hover highlights + */ + if (this.constants.hover == true) { + // removing all hover highlights + for (var edgeId in this.hoverObj.edges) { + if (this.hoverObj.edges.hasOwnProperty(edgeId)) { + this.hoverObj.edges[edgeId].hover = false; + delete this.hoverObj.edges[edgeId]; + } + } + // adding hover highlights + var obj = this._getNodeAt(pointer); + if (obj == null) { + obj = this._getEdgeAt(pointer); + } + if (obj != null) { + this._hoverObject(obj); + } - // get the regex to find the next token - function getParseRegexForToken(token, config) { - var a, strict = config._strict; - switch (token) { - case 'Q': - return parseTokenOneDigit; - case 'DDDD': - return parseTokenThreeDigits; - case 'YYYY': - case 'GGGG': - case 'gggg': - return strict ? parseTokenFourDigits : parseTokenOneToFourDigits; - case 'Y': - case 'G': - case 'g': - return parseTokenSignedNumber; - case 'YYYYYY': - case 'YYYYY': - case 'GGGGG': - case 'ggggg': - return strict ? parseTokenSixDigits : parseTokenOneToSixDigits; - case 'S': - if (strict) { - return parseTokenOneDigit; - } - /* falls through */ - case 'SS': - if (strict) { - return parseTokenTwoDigits; - } - /* falls through */ - case 'SSS': - if (strict) { - return parseTokenThreeDigits; - } - /* falls through */ - case 'DDD': - return parseTokenOneToThreeDigits; - case 'MMM': - case 'MMMM': - case 'dd': - case 'ddd': - case 'dddd': - return parseTokenWord; - case 'a': - case 'A': - return config._locale._meridiemParse; - case 'x': - return parseTokenOffsetMs; - case 'X': - return parseTokenTimestampMs; - case 'Z': - case 'ZZ': - return parseTokenTimezone; - case 'T': - return parseTokenT; - case 'SSSS': - return parseTokenDigits; - case 'MM': - case 'DD': - case 'YY': - case 'GG': - case 'gg': - case 'HH': - case 'hh': - case 'mm': - case 'ss': - case 'ww': - case 'WW': - return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits; - case 'M': - case 'D': - case 'd': - case 'H': - case 'h': - case 'm': - case 's': - case 'w': - case 'W': - case 'e': - case 'E': - return parseTokenOneOrTwoDigits; - case 'Do': - return strict ? config._locale._ordinalParse : config._locale._ordinalParseLenient; - default : - a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), 'i')); - return a; + // removing all node hover highlights except for the selected one. + for (var nodeId in this.hoverObj.nodes) { + if (this.hoverObj.nodes.hasOwnProperty(nodeId)) { + if (obj instanceof Node && obj.id != nodeId || obj instanceof Edge || obj == null) { + this._blurObject(this.hoverObj.nodes[nodeId]); + delete this.hoverObj.nodes[nodeId]; } + } } + this.redraw(); + } + }; - function utcOffsetFromString(string) { - string = string || ''; - var possibleTzMatches = (string.match(parseTokenTimezone) || []), - tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [], - parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0], - minutes = +(parts[1] * 60) + toInt(parts[2]); + /** + * Check if there is an element on the given position in the network + * (a node or edge). If so, and if this element has a title, + * show a popup window with its title. + * + * @param {{x:Number, y:Number}} pointer + * @private + */ + Network.prototype._checkShowPopup = function (pointer) { + var obj = { + left: this._XconvertDOMtoCanvas(pointer.x), + top: this._YconvertDOMtoCanvas(pointer.y), + right: this._XconvertDOMtoCanvas(pointer.x), + bottom: this._YconvertDOMtoCanvas(pointer.y) + }; - return parts[0] === '+' ? minutes : -minutes; - } + var id; + var lastPopupNode = this.popupObj; + var nodeUnderCursor = false; - // function to convert string input to date - function addTimeToArrayFromToken(token, input, config) { - var a, datePartArray = config._a; + if (this.popupObj == undefined) { + // search the nodes for overlap, select the top one in case of multiple nodes + var nodes = this.nodes; + var overlappingNodes = []; + for (id in nodes) { + if (nodes.hasOwnProperty(id)) { + var node = nodes[id]; + if (node.isOverlappingWith(obj)) { + if (node.getTitle() !== undefined) { + overlappingNodes.push(id); + } + } + } + } - switch (token) { - // QUARTER - case 'Q': - if (input != null) { - datePartArray[MONTH] = (toInt(input) - 1) * 3; - } - break; - // MONTH - case 'M' : // fall through to MM - case 'MM' : - if (input != null) { - datePartArray[MONTH] = toInt(input) - 1; - } - break; - case 'MMM' : // fall through to MMMM - case 'MMMM' : - a = config._locale.monthsParse(input, token, config._strict); - // if we didn't find a month name, mark the date as invalid. - if (a != null) { - datePartArray[MONTH] = a; - } else { - config._pf.invalidMonth = input; - } - break; - // DAY OF MONTH - case 'D' : // fall through to DD - case 'DD' : - if (input != null) { - datePartArray[DATE] = toInt(input); - } - break; - case 'Do' : - if (input != null) { - datePartArray[DATE] = toInt(parseInt( - input.match(/\d{1,2}/)[0], 10)); - } - break; - // DAY OF YEAR - case 'DDD' : // fall through to DDDD - case 'DDDD' : - if (input != null) { - config._dayOfYear = toInt(input); - } + if (overlappingNodes.length > 0) { + // if there are overlapping nodes, select the last one, this is the + // one which is drawn on top of the others + this.popupObj = this.nodes[overlappingNodes[overlappingNodes.length - 1]]; + // if you hover over a node, the title of the edge is not supposed to be shown. + nodeUnderCursor = true; + } + } - break; - // YEAR - case 'YY' : - datePartArray[YEAR] = moment.parseTwoDigitYear(input); - break; - case 'YYYY' : - case 'YYYYY' : - case 'YYYYYY' : - datePartArray[YEAR] = toInt(input); - break; - // AM / PM - case 'a' : // fall through to A - case 'A' : - config._meridiem = input; - // config._isPm = config._locale.isPM(input); - break; - // HOUR - case 'h' : // fall through to hh - case 'hh' : - config._pf.bigHour = true; - /* falls through */ - case 'H' : // fall through to HH - case 'HH' : - datePartArray[HOUR] = toInt(input); - break; - // MINUTE - case 'm' : // fall through to mm - case 'mm' : - datePartArray[MINUTE] = toInt(input); - break; - // SECOND - case 's' : // fall through to ss - case 'ss' : - datePartArray[SECOND] = toInt(input); - break; - // MILLISECOND - case 'S' : - case 'SS' : - case 'SSS' : - case 'SSSS' : - datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000); - break; - // UNIX OFFSET (MILLISECONDS) - case 'x': - config._d = new Date(toInt(input)); - break; - // UNIX TIMESTAMP WITH MS - case 'X': - config._d = new Date(parseFloat(input) * 1000); - break; - // TIMEZONE - case 'Z' : // fall through to ZZ - case 'ZZ' : - config._useUTC = true; - config._tzm = utcOffsetFromString(input); - break; - // WEEKDAY - human - case 'dd': - case 'ddd': - case 'dddd': - 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 || {}; - config._w['d'] = a; - } else { - config._pf.invalidWeekday = input; - } - break; - // WEEK, WEEK DAY - numeric - case 'w': - case 'ww': - case 'W': - case 'WW': - case 'd': - case 'e': - case 'E': - token = token.substr(0, 1); - /* falls through */ - case 'gggg': - case 'GGGG': - case 'GGGGG': - token = token.substr(0, 2); - if (input) { - config._w = config._w || {}; - config._w[token] = toInt(input); - } - break; - case 'gg': - case 'GG': - config._w = config._w || {}; - config._w[token] = moment.parseTwoDigitYear(input); + if (this.popupObj === undefined && nodeUnderCursor == false) { + // search the edges for overlap + var edges = this.edges; + var overlappingEdges = []; + for (id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + if (edge.connected && (edge.getTitle() !== undefined) && + edge.isOverlappingWith(obj)) { + overlappingEdges.push(id); } + } } - function dayOfYearFromWeekInfo(config) { - var w, weekYear, week, weekday, dow, doy, temp; - - w = config._w; - if (w.GG != null || w.W != null || w.E != null) { - dow = 1; - doy = 4; + if (overlappingEdges.length > 0) { + this.popupObj = this.edges[overlappingEdges[overlappingEdges.length - 1]]; + } + } - // TODO: We need to take the current isoWeekYear, but that depends on - // how we interpret now (local, utc, fixed offset). So create - // a now version of current config (take local/utc/offset flags, and - // create now). - weekYear = dfl(w.GG, config._a[YEAR], weekOfYear(moment(), 1, 4).year); - week = dfl(w.W, 1); - weekday = dfl(w.E, 1); - } else { - dow = config._locale._week.dow; - doy = config._locale._week.doy; + if (this.popupObj) { + // show popup message window + if (this.popupObj != lastPopupNode) { + var me = this; + if (!me.popup) { + me.popup = new Popup(me.frame, me.constants.tooltip); + } - weekYear = dfl(w.gg, config._a[YEAR], weekOfYear(moment(), dow, doy).year); - week = dfl(w.w, 1); + // adjust a small offset such that the mouse cursor is located in the + // bottom left location of the popup, and you can easily move over the + // popup area + me.popup.setPosition(pointer.x - 3, pointer.y - 3); + me.popup.setText(me.popupObj.getTitle()); + me.popup.show(); + } + } + else { + if (this.popup) { + this.popup.hide(); + } + } + }; - if (w.d != null) { - // weekday -- low day numbers are considered next week - weekday = w.d; - if (weekday < dow) { - ++week; - } - } else if (w.e != null) { - // local weekday -- counting starts from begining of week - weekday = w.e + dow; - } else { - // default to begining of week - weekday = dow; - } - } - temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow); - config._a[YEAR] = temp.year; - config._dayOfYear = temp.dayOfYear; + /** + * Check if the popup must be hided, which is the case when the mouse is no + * longer hovering on the object + * @param {{x:Number, y:Number}} pointer + * @private + */ + Network.prototype._checkHidePopup = function (pointer) { + if (!this.popupObj || !this._getNodeAt(pointer) ) { + this.popupObj = undefined; + if (this.popup) { + this.popup.hide(); } + } + }; - // convert an array to a date. - // the array should mirror the parameters below - // note: all values past the year are optional and will default to the lowest possible value. - // [year, month, day , hour, minute, second, millisecond] - function dateFromConfig(config) { - var i, date, input = [], currentDate, yearToUse; - - if (config._d) { - return; - } - currentDate = currentDateArray(config); + /** + * Set a new size for the network + * @param {string} width Width in pixels or percentage (for example '800px' + * or '50%') + * @param {string} height Height in pixels or percentage (for example '400px' + * or '30%') + */ + Network.prototype.setSize = function(width, height) { + var emitEvent = false; + var oldWidth = this.frame.canvas.width; + var oldHeight = this.frame.canvas.height; + if (width != this.constants.width || height != this.constants.height || this.frame.style.width != width || this.frame.style.height != height) { + this.frame.style.width = width; + this.frame.style.height = height; - //compute day of the year from weeks and weekdays - if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { - dayOfYearFromWeekInfo(config); - } + this.frame.canvas.style.width = '100%'; + this.frame.canvas.style.height = '100%'; - //if the day of the year is set, figure out what it is - if (config._dayOfYear) { - yearToUse = dfl(config._a[YEAR], currentDate[YEAR]); + this.frame.canvas.width = this.frame.canvas.clientWidth * this.pixelRatio; + this.frame.canvas.height = this.frame.canvas.clientHeight * this.pixelRatio; - if (config._dayOfYear > daysInYear(yearToUse)) { - config._pf._overflowDayOfYear = true; - } + this.constants.width = width; + this.constants.height = height; - date = makeUTCDate(yearToUse, 0, config._dayOfYear); - config._a[MONTH] = date.getUTCMonth(); - config._a[DATE] = date.getUTCDate(); - } + emitEvent = true; + } + else { + // this would adapt the width of the canvas to the width from 100% if and only if + // there is a change. - // Default to current date. - // * if no year, month, day of month are given, default to today - // * if day of month is given, default month and year - // * if month is given, default only year - // * if year is given, don't default anything - for (i = 0; i < 3 && config._a[i] == null; ++i) { - config._a[i] = input[i] = currentDate[i]; - } + if (this.frame.canvas.width != this.frame.canvas.clientWidth * this.pixelRatio) { + this.frame.canvas.width = this.frame.canvas.clientWidth * this.pixelRatio; + emitEvent = true; + } + if (this.frame.canvas.height != this.frame.canvas.clientHeight * this.pixelRatio) { + this.frame.canvas.height = this.frame.canvas.clientHeight * this.pixelRatio; + emitEvent = true; + } + } - // Zero out whatever was not defaulted, including time - for (; i < 7; i++) { - config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; - } + if (emitEvent == true) { + this.emit('resize', {width:this.frame.canvas.width * this.pixelRatio,height:this.frame.canvas.height * this.pixelRatio, oldWidth: oldWidth * this.pixelRatio, oldHeight: oldHeight * this.pixelRatio}); + } + }; - // Check for 24:00:00.000 - if (config._a[HOUR] === 24 && - config._a[MINUTE] === 0 && - config._a[SECOND] === 0 && - config._a[MILLISECOND] === 0) { - config._nextDay = true; - config._a[HOUR] = 0; - } + /** + * Set a data set with nodes for the network + * @param {Array | DataSet | DataView} nodes The data containing the nodes. + * @private + */ + Network.prototype._setNodes = function(nodes) { + var oldNodesData = this.nodesData; - config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input); - // Apply timezone offset from input. The actual utcOffset can be changed - // with parseZone. - if (config._tzm != null) { - config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); - } + if (nodes instanceof DataSet || nodes instanceof DataView) { + this.nodesData = nodes; + } + else if (Array.isArray(nodes)) { + this.nodesData = new DataSet(); + this.nodesData.add(nodes); + } + else if (!nodes) { + this.nodesData = new DataSet(); + } + else { + throw new TypeError('Array or DataSet expected'); + } - if (config._nextDay) { - config._a[HOUR] = 24; - } - } + if (oldNodesData) { + // unsubscribe from old dataset + util.forEach(this.nodesListeners, function (callback, event) { + oldNodesData.off(event, callback); + }); + } - function dateFromObject(config) { - var normalizedInput; + // remove drawn nodes + this.nodes = {}; - if (config._d) { - return; - } + if (this.nodesData) { + // subscribe to new dataset + var me = this; + util.forEach(this.nodesListeners, function (callback, event) { + me.nodesData.on(event, callback); + }); - normalizedInput = normalizeObjectUnits(config._i); - config._a = [ - normalizedInput.year, - normalizedInput.month, - normalizedInput.day || normalizedInput.date, - normalizedInput.hour, - normalizedInput.minute, - normalizedInput.second, - normalizedInput.millisecond - ]; + // draw all new nodes + var ids = this.nodesData.getIds(); + this._addNodes(ids); + } + this._updateSelection(); + }; - dateFromConfig(config); + /** + * Add nodes + * @param {Number[] | String[]} ids + * @private + */ + Network.prototype._addNodes = function(ids) { + var id; + for (var i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + var data = this.nodesData.get(id); + var node = new Node(data, this.images, this.groups, this.constants); + this.nodes[id] = node; // note: this may replace an existing node + if ((node.xFixed == false || node.yFixed == false) && (node.x === null || node.y === null)) { + var radius = 10 * 0.1*ids.length + 10; + var angle = 2 * Math.PI * Math.random(); + if (node.xFixed == false) {node.x = radius * Math.cos(angle);} + if (node.yFixed == false) {node.y = radius * Math.sin(angle);} } + this.moving = true; + } - function currentDateArray(config) { - var now = new Date(); - if (config._useUTC) { - return [ - now.getUTCFullYear(), - now.getUTCMonth(), - now.getUTCDate() - ]; - } else { - return [now.getFullYear(), now.getMonth(), now.getDate()]; - } + this._updateNodeIndexList(); + if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { + this._resetLevels(); + this._setupHierarchicalLayout(); + } + this._updateCalculationNodes(); + this._reconnectEdges(); + this._updateValueRange(this.nodes); + this.updateLabels(); + }; + + /** + * Update existing nodes, or create them when not yet existing + * @param {Number[] | String[]} ids + * @private + */ + Network.prototype._updateNodes = function(ids,changedData) { + var nodes = this.nodes; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + var node = nodes[id]; + var data = changedData[i]; + if (node) { + // update node + node.setProperties(data, this.constants); + } + else { + // create node + node = new Node(properties, this.images, this.groups, this.constants); + nodes[id] = node; } + } + this.moving = true; + if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { + this._resetLevels(); + this._setupHierarchicalLayout(); + } + this._updateNodeIndexList(); + this._updateValueRange(nodes); + }; - // date from string and format string - function makeDateFromStringAndFormat(config) { - if (config._f === moment.ISO_8601) { - parseISO(config); - return; - } + /** + * Remove existing nodes. If nodes do not exist, the method will just ignore it. + * @param {Number[] | String[]} ids + * @private + */ + Network.prototype._removeNodes = function(ids) { + var nodes = this.nodes; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + delete nodes[id]; + } + this._updateNodeIndexList(); + if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { + this._resetLevels(); + this._setupHierarchicalLayout(); + } + this._updateCalculationNodes(); + this._reconnectEdges(); + this._updateSelection(); + this._updateValueRange(nodes); + }; - config._a = []; - config._pf.empty = true; + /** + * Load edges by reading the data table + * @param {Array | DataSet | DataView} edges The data containing the edges. + * @private + * @private + */ + Network.prototype._setEdges = function(edges) { + var oldEdgesData = this.edgesData; - // This array is used to make a Date, either with `new Date` or `Date.UTC` - var string = '' + config._i, - i, parsedInput, tokens, token, skipped, - stringLength = string.length, - totalParsedInputLength = 0; + if (edges instanceof DataSet || edges instanceof DataView) { + this.edgesData = edges; + } + else if (Array.isArray(edges)) { + this.edgesData = new DataSet(); + this.edgesData.add(edges); + } + else if (!edges) { + this.edgesData = new DataSet(); + } + else { + throw new TypeError('Array or DataSet expected'); + } - tokens = expandFormat(config._f, config._locale).match(formattingTokens) || []; + if (oldEdgesData) { + // unsubscribe from old dataset + util.forEach(this.edgesListeners, function (callback, event) { + oldEdgesData.off(event, callback); + }); + } - for (i = 0; i < tokens.length; i++) { - token = tokens[i]; - parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; - if (parsedInput) { - skipped = string.substr(0, string.indexOf(parsedInput)); - if (skipped.length > 0) { - config._pf.unusedInput.push(skipped); - } - string = string.slice(string.indexOf(parsedInput) + parsedInput.length); - totalParsedInputLength += parsedInput.length; - } - // don't parse if it's not a known token - if (formatTokenFunctions[token]) { - if (parsedInput) { - config._pf.empty = false; - } - else { - config._pf.unusedTokens.push(token); - } - addTimeToArrayFromToken(token, parsedInput, config); - } - else if (config._strict && !parsedInput) { - config._pf.unusedTokens.push(token); - } - } + // remove drawn edges + this.edges = {}; - // add remaining unparsed input length to the string - config._pf.charsLeftOver = stringLength - totalParsedInputLength; - if (string.length > 0) { - config._pf.unusedInput.push(string); - } + if (this.edgesData) { + // subscribe to new dataset + var me = this; + util.forEach(this.edgesListeners, function (callback, event) { + me.edgesData.on(event, callback); + }); - // clear _12h flag if hour is <= 12 - if (config._pf.bigHour === true && config._a[HOUR] <= 12) { - config._pf.bigHour = undefined; - } - // handle meridiem - config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], - config._meridiem); - dateFromConfig(config); - checkOverflow(config); - } + // draw all new nodes + var ids = this.edgesData.getIds(); + this._addEdges(ids); + } - function unescapeFormat(s) { - return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { - return p1 || p2 || p3 || p4; - }); - } + this._reconnectEdges(); + }; - // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript - function regexpEscape(s) { - return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); - } + /** + * Add edges + * @param {Number[] | String[]} ids + * @private + */ + Network.prototype._addEdges = function (ids) { + var edges = this.edges, + edgesData = this.edgesData; - // date from string and array of format strings - function makeDateFromStringAndArray(config) { - var tempConfig, - bestMoment, + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; - scoreToBeat, - i, - currentScore; + var oldEdge = edges[id]; + if (oldEdge) { + oldEdge.disconnect(); + } - if (config._f.length === 0) { - config._pf.invalidFormat = true; - config._d = new Date(NaN); - return; - } + var data = edgesData.get(id, {"showInternalIds" : true}); + edges[id] = new Edge(data, this, this.constants); + } + this.moving = true; + this._updateValueRange(edges); + this._createBezierNodes(); + this._updateCalculationNodes(); + if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { + this._resetLevels(); + this._setupHierarchicalLayout(); + } + }; - for (i = 0; i < config._f.length; i++) { - currentScore = 0; - tempConfig = copyConfig({}, config); - if (config._useUTC != null) { - tempConfig._useUTC = config._useUTC; - } - tempConfig._pf = defaultParsingFlags(); - tempConfig._f = config._f[i]; - makeDateFromStringAndFormat(tempConfig); + /** + * Update existing edges, or create them when not yet existing + * @param {Number[] | String[]} ids + * @private + */ + Network.prototype._updateEdges = function (ids) { + var edges = this.edges, + edgesData = this.edgesData; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; - if (!isValid(tempConfig)) { - continue; - } + var data = edgesData.get(id); + var edge = edges[id]; + if (edge) { + // update edge + edge.disconnect(); + edge.setProperties(data, this.constants); + edge.connect(); + } + else { + // create edge + edge = new Edge(data, this, this.constants); + this.edges[id] = edge; + } + } - // if there is any input that was not parsed add a penalty for that format - currentScore += tempConfig._pf.charsLeftOver; + this._createBezierNodes(); + if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { + this._resetLevels(); + this._setupHierarchicalLayout(); + } + this.moving = true; + this._updateValueRange(edges); + }; - //or tokens - currentScore += tempConfig._pf.unusedTokens.length * 10; + /** + * Remove existing edges. Non existing ids will be ignored + * @param {Number[] | String[]} ids + * @private + */ + Network.prototype._removeEdges = function (ids) { + var edges = this.edges; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + var edge = edges[id]; + if (edge) { + if (edge.via != null) { + delete this.sectors['support']['nodes'][edge.via.id]; + } + edge.disconnect(); + delete edges[id]; + } + } - tempConfig._pf.score = currentScore; + this.moving = true; + this._updateValueRange(edges); + if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { + this._resetLevels(); + this._setupHierarchicalLayout(); + } + this._updateCalculationNodes(); + }; - if (scoreToBeat == null || currentScore < scoreToBeat) { - scoreToBeat = currentScore; - bestMoment = tempConfig; - } - } + /** + * Reconnect all edges + * @private + */ + Network.prototype._reconnectEdges = function() { + var id, + nodes = this.nodes, + edges = this.edges; + for (id in nodes) { + if (nodes.hasOwnProperty(id)) { + nodes[id].edges = []; + nodes[id].dynamicEdges = []; + } + } - extend(config, bestMoment || tempConfig); + for (id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + edge.from = null; + edge.to = null; + edge.connect(); } + } + }; - // date from iso format - function parseISO(config) { - var i, l, - string = config._i, - match = isoRegex.exec(string); + /** + * Update the values of all object in the given array according to the current + * value range of the objects in the array. + * @param {Object} obj An object containing a set of Edges or Nodes + * The objects must have a method getValue() and + * setValueRange(min, max). + * @private + */ + Network.prototype._updateValueRange = function(obj) { + var id; - if (match) { - config._pf.iso = true; - for (i = 0, l = isoDates.length; i < l; i++) { - if (isoDates[i][1].exec(string)) { - // match[5] should be 'T' or undefined - config._f = isoDates[i][0] + (match[6] || ' '); - break; - } - } - for (i = 0, l = isoTimes.length; i < l; i++) { - if (isoTimes[i][1].exec(string)) { - config._f += isoTimes[i][0]; - break; - } - } - if (string.match(parseTokenTimezone)) { - config._f += 'Z'; - } - makeDateFromStringAndFormat(config); - } else { - config._isValid = false; - } + // determine the range of the objects + var valueMin = undefined; + var valueMax = undefined; + for (id in obj) { + if (obj.hasOwnProperty(id)) { + var value = obj[id].getValue(); + if (value !== undefined) { + valueMin = (valueMin === undefined) ? value : Math.min(value, valueMin); + valueMax = (valueMax === undefined) ? value : Math.max(value, valueMax); + } } + } - // date from iso format or fallback - function makeDateFromString(config) { - parseISO(config); - if (config._isValid === false) { - delete config._isValid; - moment.createFromInputFallback(config); - } + // adjust the range of all objects + if (valueMin !== undefined && valueMax !== undefined) { + for (id in obj) { + if (obj.hasOwnProperty(id)) { + obj[id].setValueRange(valueMin, valueMax); + } } + } + }; + + /** + * Redraw the network with the current data + * chart will be resized too. + */ + Network.prototype.redraw = function() { + this.setSize(this.constants.width, this.constants.height); + this._redraw(); + }; + + /** + * Redraw the network with the current data + * @param hidden | used to get the first estimate of the node sizes. only the nodes are drawn after which they are quickly drawn over. + * @private + */ + Network.prototype._redraw = function(hidden) { + var ctx = this.frame.canvas.getContext('2d'); + + ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); + + // clear the canvas + var w = this.frame.canvas.width * this.pixelRatio; + var h = this.frame.canvas.height * this.pixelRatio; + ctx.clearRect(0, 0, w, h); + + // set scaling and translation + ctx.save(); + ctx.translate(this.translation.x, this.translation.y); + ctx.scale(this.scale, this.scale); - function map(arr, fn) { - var res = [], i; - for (i = 0; i < arr.length; ++i) { - res.push(fn(arr[i], i)); - } - return res; - } + this.canvasTopLeft = { + "x": this._XconvertDOMtoCanvas(0), + "y": this._YconvertDOMtoCanvas(0) + }; + this.canvasBottomRight = { + "x": this._XconvertDOMtoCanvas(this.frame.canvas.clientWidth * this.pixelRatio), + "y": this._YconvertDOMtoCanvas(this.frame.canvas.clientHeight * this.pixelRatio) + }; - function makeDateFromInput(config) { - var input = config._i, matched; - if (input === undefined) { - config._d = new Date(); - } 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 = map(input.slice(0), function (obj) { - return parseInt(obj, 10); - }); - dateFromConfig(config); - } else if (typeof(input) === 'object') { - dateFromObject(config); - } else if (typeof(input) === 'number') { - // from milliseconds - config._d = new Date(input); - } else { - moment.createFromInputFallback(config); - } + if (!(hidden == true)) { + this._doInAllSectors("_drawAllSectorNodes", ctx); + if (this.drag.dragging == false || this.drag.dragging === undefined || this.constants.hideEdgesOnDrag == false) { + this._doInAllSectors("_drawEdges", ctx); } + } - function makeDate(y, m, d, h, M, s, ms) { - //can't just apply() to create a date: - //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply - var date = new Date(y, m, d, h, M, s, ms); + if (this.drag.dragging == false || this.drag.dragging === undefined || this.constants.hideNodesOnDrag == false) { + this._doInAllSectors("_drawNodes",ctx,false); + } - //the date constructor doesn't accept years < 1970 - if (y < 1970) { - date.setFullYear(y); - } - return date; + if (!(hidden == true)) { + if (this.controlNodesActive == true) { + this._doInAllSectors("_drawControlNodes", ctx); } + } - function makeUTCDate(y) { - var date = new Date(Date.UTC.apply(null, arguments)); - if (y < 1970) { - date.setUTCFullYear(y); - } - return date; - } + // this._doInSupportSector("_drawNodes",ctx,true); + // this._drawTree(ctx,"#F00F0F"); - function parseWeekday(input, locale) { - if (typeof input === 'string') { - if (!isNaN(input)) { - input = parseInt(input, 10); - } - else { - input = locale.weekdaysParse(input); - if (typeof input !== 'number') { - return null; - } - } - } - return input; - } + // restore original scaling and translation + ctx.restore(); - /************************************ - Relative Time - ************************************/ + if (hidden == true) { + ctx.clearRect(0, 0, w, h); + } + }; + /** + * Set the translation of the network + * @param {Number} offsetX Horizontal offset + * @param {Number} offsetY Vertical offset + * @private + */ + Network.prototype._setTranslation = function(offsetX, offsetY) { + if (this.translation === undefined) { + this.translation = { + x: 0, + y: 0 + }; + } - // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize - function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { - return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); - } + if (offsetX !== undefined) { + this.translation.x = offsetX; + } + if (offsetY !== undefined) { + this.translation.y = offsetY; + } - 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')), + this.emit('viewChanged'); + }; - 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.d && ['dd', days] || - months === 1 && ['M'] || - months < relativeTimeThresholds.M && ['MM', months] || - years === 1 && ['y'] || ['yy', years]; + /** + * Get the translation of the network + * @return {Object} translation An object with parameters x and y, both a number + * @private + */ + Network.prototype._getTranslation = function() { + return { + x: this.translation.x, + y: this.translation.y + }; + }; - args[2] = withoutSuffix; - args[3] = +posNegDuration > 0; - args[4] = locale; - return substituteTimeAgo.apply({}, args); - } + /** + * Scale the network + * @param {Number} scale Scaling factor 1.0 is unscaled + * @private + */ + Network.prototype._setScale = function(scale) { + this.scale = scale; + }; + /** + * Get the current scale of the network + * @return {Number} scale Scaling factor 1.0 is unscaled + * @private + */ + Network.prototype._getScale = function() { + return this.scale; + }; - /************************************ - Week of Year - ************************************/ + /** + * Convert the X coordinate in DOM-space (coordinate point in browser relative to the container div) to + * the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon) + * @param {number} x + * @returns {number} + * @private + */ + Network.prototype._XconvertDOMtoCanvas = function(x) { + return (x - this.translation.x) / this.scale; + }; + /** + * Convert the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to + * the X coordinate in DOM-space (coordinate point in browser relative to the container div) + * @param {number} x + * @returns {number} + * @private + */ + Network.prototype._XconvertCanvasToDOM = function(x) { + return x * this.scale + this.translation.x; + }; - // firstDayOfWeek 0 = sun, 6 = sat - // the day of the week that starts the week - // (usually sunday or monday) - // firstDayOfWeekOfYear 0 = sun, 6 = sat - // the first week is the week that contains the first - // of this day of the week - // (eg. ISO weeks use thursday (4)) - function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { - var end = firstDayOfWeekOfYear - firstDayOfWeek, - daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), - adjustedMoment; + /** + * Convert the Y coordinate in DOM-space (coordinate point in browser relative to the container div) to + * the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon) + * @param {number} y + * @returns {number} + * @private + */ + Network.prototype._YconvertDOMtoCanvas = function(y) { + return (y - this.translation.y) / this.scale; + }; + /** + * Convert the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to + * the Y coordinate in DOM-space (coordinate point in browser relative to the container div) + * @param {number} y + * @returns {number} + * @private + */ + Network.prototype._YconvertCanvasToDOM = function(y) { + return y * this.scale + this.translation.y ; + }; - if (daysToDayOfWeek > end) { - daysToDayOfWeek -= 7; - } - if (daysToDayOfWeek < end - 7) { - daysToDayOfWeek += 7; - } + /** + * + * @param {object} pos = {x: number, y: number} + * @returns {{x: number, y: number}} + * @constructor + */ + Network.prototype.canvasToDOM = function (pos) { + return {x: this._XconvertCanvasToDOM(pos.x), y: this._YconvertCanvasToDOM(pos.y)}; + }; - adjustedMoment = moment(mom).add(daysToDayOfWeek, 'd'); - return { - week: Math.ceil(adjustedMoment.dayOfYear() / 7), - year: adjustedMoment.year() - }; - } + /** + * + * @param {object} pos = {x: number, y: number} + * @returns {{x: number, y: number}} + * @constructor + */ + Network.prototype.DOMtoCanvas = function (pos) { + return {x: this._XconvertDOMtoCanvas(pos.x), y: this._YconvertDOMtoCanvas(pos.y)}; + }; - //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday - function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { - var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear; + /** + * Redraw all nodes + * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); + * @param {CanvasRenderingContext2D} ctx + * @param {Boolean} [alwaysShow] + * @private + */ + Network.prototype._drawNodes = function(ctx,alwaysShow) { + if (alwaysShow === undefined) { + alwaysShow = false; + } - d = d === 0 ? 7 : d; - weekday = weekday != null ? weekday : firstDayOfWeek; - daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0); - dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; + // first draw the unselected nodes + var nodes = this.nodes; + var selected = []; - return { - year: dayOfYear > 0 ? year : year - 1, - dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear - }; + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + nodes[id].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight); + if (nodes[id].isSelected()) { + selected.push(id); + } + else { + if (nodes[id].inArea() || alwaysShow) { + nodes[id].draw(ctx); + } + } } + } - /************************************ - Top Level Functions - ************************************/ + // draw the selected nodes on top + for (var s = 0, sMax = selected.length; s < sMax; s++) { + if (nodes[selected[s]].inArea() || alwaysShow) { + nodes[selected[s]].draw(ctx); + } + } + }; - function makeMoment(config) { - var input = config._i, - format = config._f, - res; + /** + * Redraw all edges + * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); + * @param {CanvasRenderingContext2D} ctx + * @private + */ + Network.prototype._drawEdges = function(ctx) { + var edges = this.edges; + for (var id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + edge.setScale(this.scale); + if (edge.connected) { + edges[id].draw(ctx); + } + } + } + }; - config._locale = config._locale || moment.localeData(config._l); + /** + * Redraw all edges + * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); + * @param {CanvasRenderingContext2D} ctx + * @private + */ + Network.prototype._drawControlNodes = function(ctx) { + var edges = this.edges; + for (var id in edges) { + if (edges.hasOwnProperty(id)) { + edges[id]._drawControlNodes(ctx); + } + } + }; - if (input === null || (format === undefined && input === '')) { - return moment.invalid({nullInput: true}); - } + /** + * Find a stable position for all nodes + * @private + */ + Network.prototype._stabilize = function() { + if (this.constants.freezeForStabilization == true) { + this._freezeDefinedNodes(); + } - if (typeof input === 'string') { - config._i = input = config._locale.preparse(input); - } + // find stable position + var count = 0; + while (this.moving && count < this.constants.stabilizationIterations) { + this._physicsTick(); + count++; + } - if (moment.isMoment(input)) { - return new Moment(input, true); - } else if (format) { - if (isArray(format)) { - makeDateFromStringAndArray(config); - } else { - makeDateFromStringAndFormat(config); - } - } else { - makeDateFromInput(config); - } + if (this.constants.zoomExtentOnStabilize == true) { + this.zoomExtent(undefined, false, true); + } - res = new Moment(config); - if (res._nextDay) { - // Adding is smart enough around DST - res.add(1, 'd'); - res._nextDay = undefined; - } + if (this.constants.freezeForStabilization == true) { + this._restoreFrozenNodes(); + } + }; - return res; + /** + * When initializing and stabilizing, we can freeze nodes with a predefined position. This greatly speeds up stabilization + * because only the supportnodes for the smoothCurves have to settle. + * + * @private + */ + Network.prototype._freezeDefinedNodes = function() { + var nodes = this.nodes; + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + if (nodes[id].x != null && nodes[id].y != null) { + nodes[id].fixedData.x = nodes[id].xFixed; + nodes[id].fixedData.y = nodes[id].yFixed; + nodes[id].xFixed = true; + nodes[id].yFixed = true; + } } + } + }; - moment = function (input, format, locale, strict) { - var c; + /** + * Unfreezes the nodes that have been frozen by _freezeDefinedNodes. + * + * @private + */ + Network.prototype._restoreFrozenNodes = function() { + var nodes = this.nodes; + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + if (nodes[id].fixedData.x != null) { + nodes[id].xFixed = nodes[id].fixedData.x; + nodes[id].yFixed = nodes[id].fixedData.y; + } + } + } + }; - if (typeof(locale) === 'boolean') { - strict = locale; - locale = undefined; - } - // object construction must be done this way. - // https://github.com/moment/moment/issues/1423 - c = {}; - c._isAMomentObject = true; - c._i = input; - c._f = format; - c._l = locale; - c._strict = strict; - c._isUTC = false; - c._pf = defaultParsingFlags(); - return makeMoment(c); - }; + /** + * Check if any of the nodes is still moving + * @param {number} vmin the minimum velocity considered as 'moving' + * @return {boolean} true if moving, false if non of the nodes is moving + * @private + */ + Network.prototype._isMoving = function(vmin) { + var nodes = this.nodes; + for (var id in nodes) { + if (nodes.hasOwnProperty(id) && nodes[id].isMoving(vmin)) { + return true; + } + } + return false; + }; - 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 + (config._useUTC ? ' UTC' : '')); - } - ); + /** + * /** + * Perform one discrete step for all nodes + * + * @private + */ + Network.prototype._discreteStepNodes = function() { + var interval = this.physicsDiscreteStepsize; + var nodes = this.nodes; + var nodeId; + var nodesPresent = false; - // 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. - // - // moments should either be an array of moment objects or an array, whose - // first element is an array of moment objects. - function pickBy(fn, moments) { - var res, i; - if (moments.length === 1 && isArray(moments[0])) { - moments = moments[0]; - } - if (!moments.length) { - return moment(); - } - res = moments[0]; - for (i = 1; i < moments.length; ++i) { - if (moments[i][fn](res)) { - res = moments[i]; - } - } - return res; + if (this.constants.maxVelocity > 0) { + for (nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + nodes[nodeId].discreteStepLimited(interval, this.constants.maxVelocity); + nodesPresent = true; + } + } + } + else { + for (nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + nodes[nodeId].discreteStep(interval); + nodesPresent = true; + } + } + } + + if (nodesPresent == true) { + var vminCorrected = this.constants.minVelocity / Math.max(this.scale,0.05); + if (vminCorrected > 0.5*this.constants.maxVelocity) { + return true; + } + else { + return this._isMoving(vminCorrected); } + } + return false; + }; - moment.min = function () { - var args = [].slice.call(arguments, 0); - return pickBy('isBefore', args); - }; + Network.prototype._revertPhysicsState = function() { + var nodes = this.nodes; + for (var nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + nodes[nodeId].revertPosition(); + } + } + } - moment.max = function () { - var args = [].slice.call(arguments, 0); + Network.prototype._revertPhysicsTick = function() { + this._doInAllActiveSectors("_revertPhysicsState"); + if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { + this._doInSupportSector("_revertPhysicsState"); + } + } - return pickBy('isAfter', args); - }; + /** + * A single simulation step (or "tick") in the physics simulation + * + * @private + */ + Network.prototype._physicsTick = function() { + if (!this.freezeSimulation) { + if (this.moving == true) { + var mainMovingStatus = false; + var supportMovingStatus = false; - // creating with utc - moment.utc = function (input, format, locale, strict) { - var c; + this._doInAllActiveSectors("_initializeForceCalculation"); + var mainMoving = this._doInAllActiveSectors("_discreteStepNodes"); + if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { + supportMovingStatus = this._doInSupportSector("_discreteStepNodes"); + } - if (typeof(locale) === 'boolean') { - strict = locale; - locale = undefined; - } - // object construction must be done this way. - // https://github.com/moment/moment/issues/1423 - c = {}; - c._isAMomentObject = true; - c._useUTC = true; - c._isUTC = true; - c._l = locale; - c._i = input; - c._f = format; - c._strict = strict; - c._pf = defaultParsingFlags(); + // gather movement data from all sectors, if one moves, we are NOT stabilzied + for (var i = 0; i < mainMoving.length; i++) {mainMovingStatus = mainMoving[0] || mainMovingStatus;} - return makeMoment(c).utc(); - }; + // determine if the network has stabilzied + this.moving = mainMovingStatus || supportMovingStatus; - // creating with unix timestamp (in seconds) - moment.unix = function (input) { - return moment(input * 1000); - }; + if (this.moving == false) { + this._revertPhysicsTick(); + } + else { + // this is here to ensure that there is no start event when the network is already stable. + if (this.startedStabilization == false) { + this.emit("startStabilization"); + this.startedStabilization = true; + } + } - // duration - moment.duration = function (input, key) { - var duration = input, - // matching against regexp is expensive, do it on demand - match = null, - sign, - ret, - parseIso, - diffRes; + this.stabilizationIterations++; + } + } + }; - if (moment.isDuration(input)) { - duration = { - ms: input._milliseconds, - d: input._days, - M: input._months - }; - } else if (typeof input === 'number') { - duration = {}; - if (key) { - duration[key] = input; - } else { - duration.milliseconds = input; - } - } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) { - sign = (match[1] === '-') ? -1 : 1; - duration = { - y: 0, - d: toInt(match[DATE]) * sign, - h: toInt(match[HOUR]) * sign, - m: toInt(match[MINUTE]) * sign, - s: toInt(match[SECOND]) * sign, - ms: toInt(match[MILLISECOND]) * sign - }; - } else if (!!(match = isoDurationRegex.exec(input))) { - sign = (match[1] === '-') ? -1 : 1; - parseIso = function (inp) { - // We'd normally use ~~inp for this, but unfortunately it also - // converts floats to ints. - // inp may be undefined, so careful calling replace on it. - var res = inp && parseFloat(inp.replace(',', '.')); - // apply sign while we're at it - return (isNaN(res) ? 0 : res) * sign; - }; - duration = { - y: parseIso(match[2]), - M: parseIso(match[3]), - d: parseIso(match[4]), - h: parseIso(match[5]), - m: parseIso(match[6]), - s: parseIso(match[7]), - w: parseIso(match[8]) - }; - } else if (duration == null) {// checks for null or undefined - duration = {}; - } 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; - } + /** + * This function runs one step of the animation. It calls an x amount of physics ticks and one render tick. + * It reschedules itself at the beginning of the function + * + * @private + */ + Network.prototype._animationStep = function() { + // reset the timer so a new scheduled animation step can be set + this.timer = undefined; - ret = new Duration(duration); + // handle the keyboad movement + this._handleNavigation(); - if (moment.isDuration(input) && hasOwnProp(input, '_locale')) { - ret._locale = input._locale; - } + var startTime = Date.now(); + this._physicsTick(); + var physicsTime = Date.now() - startTime; - return ret; - }; + // run double speed if it is a little graph + if ((this.renderTimestep - this.renderTime > 2 * physicsTime || this.runDoubleSpeed == true) && this.moving == true) { + this._physicsTick(); - // version number - moment.version = VERSION; + // this makes sure there is no jitter. The decision is taken once to run it at double speed. + if (this.renderTime != 0) { + this.runDoubleSpeed = true + } + } - // default format - moment.defaultFormat = isoFormat; + var renderStartTime = Date.now(); + this._redraw(); + this.renderTime = Date.now() - renderStartTime; - // constant that refers to the ISO standard - moment.ISO_8601 = function () {}; + // this schedules a new animation step + this.start(); + }; - // Plugins that add properties should also add the key here (null value), - // so we can properly clone ourselves. - moment.momentProperties = momentProperties; + if (typeof window !== 'undefined') { + window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || + window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; + } - // This function will be called whenever a moment is mutated. - // It is intended to keep the offset in sync with the timezone. - moment.updateOffset = function () {}; + /** + * Schedule a animation step with the refreshrate interval. + */ + Network.prototype.start = function() { + if (this.moving == true || this.xIncrement != 0 || this.yIncrement != 0 || this.zoomIncrement != 0) { + if (!this.timer) { + if (this.requiresTimeout == true) { + this.timer = window.setTimeout(this._animationStep.bind(this), this.renderTimestep); // wait this.renderTimeStep milliseconds and perform the animation step function + } + else { + this.timer = window.requestAnimationFrame(this._animationStep.bind(this)); // wait this.renderTimeStep milliseconds and perform the animation step function + } + } + } + else { + this._redraw(); + // this check is to ensure that the network does not emit these events if it was already stabilized and setOptions is called (setting moving to true and calling start()) + if (this.stabilizationIterations > 1) { + // trigger the "stabilized" event. + // The event is triggered on the next tick, to prevent the case that + // it is fired while initializing the Network, in which case you would not + // be able to catch it + var me = this; + var params = { + iterations: me.stabilizationIterations + }; + this.stabilizationIterations = 0; + this.startedStabilization = false; + setTimeout(function () { + me.emit("stabilized", params); + }, 0); + } + else { + this.stabilizationIterations = 0; + } + } + }; - // This function allows you to set a threshold for relative time strings - moment.relativeTimeThreshold = function (threshold, limit) { - if (relativeTimeThresholds[threshold] === undefined) { - return false; - } - if (limit === undefined) { - return relativeTimeThresholds[threshold]; - } - relativeTimeThresholds[threshold] = limit; - return true; + + /** + * Move the network according to the keyboard presses. + * + * @private + */ + Network.prototype._handleNavigation = function() { + if (this.xIncrement != 0 || this.yIncrement != 0) { + var translation = this._getTranslation(); + this._setTranslation(translation.x+this.xIncrement, translation.y+this.yIncrement); + } + if (this.zoomIncrement != 0) { + var center = { + x: this.frame.canvas.clientWidth / 2, + y: this.frame.canvas.clientHeight / 2 }; + this._zoom(this.scale*(1 + this.zoomIncrement), center); + } + }; - 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 - // 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); - } + /** + * Freeze the _animationStep + */ + Network.prototype.toggleFreeze = function() { + if (this.freezeSimulation == false) { + this.freezeSimulation = true; + } + else { + this.freezeSimulation = false; + this.start(); + } + }; - if (data) { - moment.duration._locale = moment._locale = data; - } + + /** + * This function cleans the support nodes if they are not needed and adds them when they are. + * + * @param {boolean} [disableStart] + * @private + */ + Network.prototype._configureSmoothCurves = function(disableStart) { + if (disableStart === undefined) { + disableStart = true; + } + if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { + this._createBezierNodes(); + // cleanup unused support nodes + for (var nodeId in this.sectors['support']['nodes']) { + if (this.sectors['support']['nodes'].hasOwnProperty(nodeId)) { + if (this.edges[this.sectors['support']['nodes'][nodeId].parentEdgeId] === undefined) { + delete this.sectors['support']['nodes'][nodeId]; } + } + } + } + else { + // delete the support nodes + this.sectors['support']['nodes'] = {}; + for (var edgeId in this.edges) { + if (this.edges.hasOwnProperty(edgeId)) { + this.edges[edgeId].via = null; + } + } + } - 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); + this._updateCalculationNodes(); + if (!disableStart) { + this.moving = true; + this.start(); + } + }; - // backwards compat for now: also set the locale - moment.locale(name); - return locales[name]; - } else { - // useful for testing - delete locales[name]; - return null; + /** + * Bezier curves require an anchor point to calculate the smooth flow. These points are nodes. These nodes are invisible but + * are used for the force calculation. + * + * @private + */ + Network.prototype._createBezierNodes = function() { + if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { + for (var edgeId in this.edges) { + if (this.edges.hasOwnProperty(edgeId)) { + var edge = this.edges[edgeId]; + if (edge.via == null) { + var nodeId = "edgeId:".concat(edge.id); + this.sectors['support']['nodes'][nodeId] = new Node( + {id:nodeId, + mass:1, + shape:'circle', + image:"", + internalMultiplier:1 + },{},{},this.constants); + edge.via = this.sectors['support']['nodes'][nodeId]; + edge.via.parentEdgeId = edge.id; + edge.positionBezierNode(); } - }; + } + } + } + }; - moment.langData = deprecate( - 'moment.langData is deprecated. Use moment.localeData instead.', - function (key) { - return moment.localeData(key); - } - ); + /** + * load the functions that load the mixins into the prototype. + * + * @private + */ + Network.prototype._initializeMixinLoaders = function () { + for (var mixin in MixinLoader) { + if (MixinLoader.hasOwnProperty(mixin)) { + Network.prototype[mixin] = MixinLoader[mixin]; + } + } + }; - // returns locale data - moment.localeData = function (key) { - var locale; + /** + * Load the XY positions of the nodes into the dataset. + */ + Network.prototype.storePosition = function() { + console.log("storePosition is depricated: use .storePositions() from now on.") + this.storePositions(); + }; - if (key && key._locale && key._locale._abbr) { - key = key._locale._abbr; - } + /** + * Load the XY positions of the nodes into the dataset. + */ + Network.prototype.storePositions = function() { + var dataArray = []; + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + var node = this.nodes[nodeId]; + var allowedToMoveX = !this.nodes.xFixed; + var allowedToMoveY = !this.nodes.yFixed; + if (this.nodesData._data[nodeId].x != Math.round(node.x) || this.nodesData._data[nodeId].y != Math.round(node.y)) { + dataArray.push({id:nodeId,x:Math.round(node.x),y:Math.round(node.y),allowedToMoveX:allowedToMoveX,allowedToMoveY:allowedToMoveY}); + } + } + } + this.nodesData.update(dataArray); + }; - if (!key) { - return moment._locale; + /** + * Return the positions of the nodes. + */ + Network.prototype.getPositions = function(ids) { + var dataArray = {}; + if (ids !== undefined) { + if (Array.isArray(ids) == true) { + for (var i = 0; i < ids.length; i++) { + if (this.nodes[ids[i]] !== undefined) { + var node = this.nodes[ids[i]]; + dataArray[ids[i]] = {x: Math.round(node.x), y: Math.round(node.y)}; } + } + } + else { + if (this.nodes[ids] !== undefined) { + var node = this.nodes[ids]; + dataArray[ids] = {x: Math.round(node.x), y: Math.round(node.y)}; + } + } + } + else { + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + var node = this.nodes[nodeId]; + dataArray[nodeId] = {x: Math.round(node.x), y: Math.round(node.y)}; + } + } + } + return dataArray; + }; - if (!isArray(key)) { - //short-circuit everything else - locale = loadLocale(key); - if (locale) { - return locale; - } - key = [key]; - } - return chooseLocale(key); - }; - // compare moment object - moment.isMoment = function (obj) { - return obj instanceof Moment || - (obj != null && hasOwnProp(obj, '_isAMomentObject')); - }; + /** + * Center a node in view. + * + * @param {Number} nodeId + * @param {Number} [options] + */ + Network.prototype.focusOnNode = function (nodeId, options) { + if (this.nodes.hasOwnProperty(nodeId)) { + if (options === undefined) { + options = {}; + } + var nodePosition = {x: this.nodes[nodeId].x, y: this.nodes[nodeId].y}; + options.position = nodePosition; + options.lockedOnNode = nodeId; - // for typechecking Duration objects - moment.isDuration = function (obj) { - return obj instanceof Duration; - }; + this.moveTo(options) + } + else { + console.log("This nodeId cannot be found."); + } + }; + + /** + * + * @param {Object} options | options.offset = {x:Number, y:Number} // offset from the center in DOM pixels + * | options.scale = Number // scale to move to + * | options.position = {x:Number, y:Number} // position to move to + * | options.animation = {duration:Number, easingFunction:String} || Boolean // position to move to + */ + Network.prototype.moveTo = function (options) { + if (options === undefined) { + options = {}; + return; + } + if (options.offset === undefined) {options.offset = {x: 0, y: 0}; } + if (options.offset.x === undefined) {options.offset.x = 0; } + if (options.offset.y === undefined) {options.offset.y = 0; } + if (options.scale === undefined) {options.scale = this._getScale(); } + if (options.position === undefined) {options.position = this._getTranslation();} + if (options.animation === undefined) {options.animation = {duration:0}; } + if (options.animation === false ) {options.animation = {duration:0}; } + if (options.animation === true ) {options.animation = {}; } + if (options.animation.duration === undefined) {options.animation.duration = 1000; } // default duration + if (options.animation.easingFunction === undefined) {options.animation.easingFunction = "easeInOutQuad"; } // default easing function - for (i = lists.length - 1; i >= 0; --i) { - makeList(lists[i]); - } + this.animateView(options); + }; - moment.normalizeUnits = function (units) { - return normalizeUnits(units); - }; + /** + * + * @param {Object} options | options.offset = {x:Number, y:Number} // offset from the center in DOM pixels + * | options.time = Number // animation time in milliseconds + * | options.scale = Number // scale to animate to + * | options.position = {x:Number, y:Number} // position to animate to + * | options.easingFunction = String // linear, easeInQuad, easeOutQuad, easeInOutQuad, + * // easeInCubic, easeOutCubic, easeInOutCubic, + * // easeInQuart, easeOutQuart, easeInOutQuart, + * // easeInQuint, easeOutQuint, easeInOutQuint + */ + Network.prototype.animateView = function (options) { + if (options === undefined) { + options = {}; + return; + } - moment.invalid = function (flags) { - var m = moment.utc(NaN); - if (flags != null) { - extend(m._pf, flags); - } - else { - m._pf.userInvalidated = true; - } + // release if something focussed on the node + this.releaseNode(); + if (options.locked == true) { + this.lockedOnNodeId = options.lockedOnNode; + this.lockedOnNodeOffset = options.offset; + } - return m; - }; + // forcefully complete the old animation if it was still running + if (this.easingTime != 0) { + this._transitionRedraw(1); // by setting easingtime to 1, we finish the animation. + } - moment.parseZone = function () { - return moment.apply(null, arguments).parseZone(); - }; + this.sourceScale = this._getScale(); + this.sourceTranslation = this._getTranslation(); + this.targetScale = options.scale; - moment.parseTwoDigitYear = function (input) { - return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); - }; + // set the scale so the viewCenter is based on the correct zoom level. This is overridden in the transitionRedraw + // but at least then we'll have the target transition + this._setScale(this.targetScale); + var viewCenter = this.DOMtoCanvas({x: 0.5 * this.frame.canvas.clientWidth, y: 0.5 * this.frame.canvas.clientHeight}); + var distanceFromCenter = { // offset from view, distance view has to change by these x and y to center the node + x: viewCenter.x - options.position.x, + y: viewCenter.y - options.position.y + }; + this.targetTranslation = { + x: this.sourceTranslation.x + distanceFromCenter.x * this.targetScale + options.offset.x, + y: this.sourceTranslation.y + distanceFromCenter.y * this.targetScale + options.offset.y + }; - moment.isDate = isDate; + // if the time is set to 0, don't do an animation + if (options.animation.duration == 0) { + if (this.lockedOnNodeId != null) { + this._classicRedraw = this._redraw; + this._redraw = this._lockedRedraw; + } + else { + this._setScale(this.targetScale); + this._setTranslation(this.targetTranslation.x, this.targetTranslation.y); + this._redraw(); + } + } + else { + this.animationSpeed = 1 / (this.renderRefreshRate * options.animation.duration * 0.001) || 1 / this.renderRefreshRate; + this.animationEasingFunction = options.animation.easingFunction; + this._classicRedraw = this._redraw; + this._redraw = this._transitionRedraw; + this._redraw(); + this.moving = true; + this.start(); + } + }; - /************************************ - Moment Prototype - ************************************/ + /** + * used to animate smoothly by hijacking the redraw function. + * @private + */ + Network.prototype._lockedRedraw = function () { + var nodePosition = {x: this.nodes[this.lockedOnNodeId].x, y: this.nodes[this.lockedOnNodeId].y}; + var viewCenter = this.DOMtoCanvas({x: 0.5 * this.frame.canvas.clientWidth, y: 0.5 * this.frame.canvas.clientHeight}); + var distanceFromCenter = { // offset from view, distance view has to change by these x and y to center the node + x: viewCenter.x - nodePosition.x, + y: viewCenter.y - nodePosition.y + }; + var sourceTranslation = this._getTranslation(); + var targetTranslation = { + x: sourceTranslation.x + distanceFromCenter.x * this.scale + this.lockedOnNodeOffset.x, + y: sourceTranslation.y + distanceFromCenter.y * this.scale + this.lockedOnNodeOffset.y + }; + this._setTranslation(targetTranslation.x,targetTranslation.y); + this._classicRedraw(); + } - extend(moment.fn = Moment.prototype, { + Network.prototype.releaseNode = function () { + if (this.lockedOnNodeId != null) { + this._redraw = this._classicRedraw; + this.lockedOnNodeId = null; + this.lockedOnNodeOffset = null; + } + } - clone : function () { - return moment(this); - }, + /** + * + * @param easingTime + * @private + */ + Network.prototype._transitionRedraw = function (easingTime) { + this.easingTime = easingTime || this.easingTime + this.animationSpeed; + this.easingTime += this.animationSpeed; - valueOf : function () { - return +this._d - ((this._offset || 0) * 60000); - }, + var progress = util.easingFunctions[this.animationEasingFunction](this.easingTime); - unix : function () { - return Math.floor(+this / 1000); - }, + this._setScale(this.sourceScale + (this.targetScale - this.sourceScale) * progress); + this._setTranslation( + this.sourceTranslation.x + (this.targetTranslation.x - this.sourceTranslation.x) * progress, + this.sourceTranslation.y + (this.targetTranslation.y - this.sourceTranslation.y) * progress + ); - toString : function () { - return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); - }, + this._classicRedraw(); + this.moving = true; - toDate : function () { - return this._offset ? new Date(+this) : this._d; - }, + // cleanup + if (this.easingTime >= 1.0) { + this.easingTime = 0; + if (this.lockedOnNodeId != null) { + this._redraw = this._lockedRedraw; + } + else { + this._redraw = this._classicRedraw; + } + this.emit("animationFinished"); + } + }; - toISOString : function () { - var m = moment(this).utc(); - if (0 < m.year() && m.year() <= 9999) { - if ('function' === typeof Date.prototype.toISOString) { - // native implementation is ~50x faster, use it when we can - return this.toDate().toISOString(); - } else { - return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); - } - } else { - return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); - } - }, + Network.prototype._classicRedraw = function () { + // placeholder function to be overloaded by animations; + }; - toArray : function () { - var m = this; - return [ - m.year(), - m.month(), - m.date(), - m.hours(), - m.minutes(), - m.seconds(), - m.milliseconds() - ]; - }, + /** + * Returns true when the Network is active. + * @returns {boolean} + */ + Network.prototype.isActive = function () { + return !this.activator || this.activator.active; + }; - isValid : function () { - return isValid(this); - }, - isDSTShifted : function () { - if (this._a) { - return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0; - } + /** + * Sets the scale + * @returns {Number} + */ + Network.prototype.setScale = function () { + return this._setScale(); + }; - return false; - }, - parsingFlags : function () { - return extend({}, this._pf); - }, + /** + * Returns the scale + * @returns {Number} + */ + Network.prototype.getScale = function () { + return this._getScale(); + }; - invalidAt: function () { - return this._pf.overflow; - }, - utc : function (keepLocalTime) { - return this.utcOffset(0, keepLocalTime); - }, + /** + * Returns the scale + * @returns {Number} + */ + Network.prototype.getCenterCoordinates = function () { + return this.DOMtoCanvas({x: 0.5 * this.frame.canvas.clientWidth, y: 0.5 * this.frame.canvas.clientHeight}); + }; - local : function (keepLocalTime) { - if (this._isUTC) { - this.utcOffset(0, keepLocalTime); - this._isUTC = false; - if (keepLocalTime) { - this.subtract(this._dateUtcOffset(), 'm'); - } - } - return this; - }, + Network.prototype.getBoundingBox = function(nodeId) { + if (this.nodes[nodeId] !== undefined) { + return this.nodes[nodeId].boundingBox; + } + } - format : function (inputString) { - var output = formatMoment(this, inputString || moment.defaultFormat); - return this.localeData().postformat(output); - }, + module.exports = Network; - add : createAdder(1, 'add'), - subtract : createAdder(-1, 'subtract'), +/***/ }, +/* 52 */ +/***/ function(module, exports, __webpack_require__) { - diff : function (input, units, asFloat) { - var that = makeAs(input, this), - zoneDiff = (that.utcOffset() - this.utcOffset()) * 6e4, - anchor, diff, output, daysAdjust; + /** + * Parse a text source containing data in DOT language into a JSON object. + * The object contains two lists: one with nodes and one with edges. + * + * DOT language reference: http://www.graphviz.org/doc/info/lang.html + * + * @param {String} data Text containing a graph in DOT-notation + * @return {Object} graph An object containing two parameters: + * {Object[]} nodes + * {Object[]} edges + */ + function parseDOT (data) { + dot = data; + return parseGraph(); + } - units = normalizeUnits(units); + // token types enumeration + var TOKENTYPE = { + NULL : 0, + DELIMITER : 1, + IDENTIFIER: 2, + UNKNOWN : 3 + }; - if (units === 'year' || units === 'month' || units === 'quarter') { - output = monthDiff(this, that); - if (units === 'quarter') { - output = output / 3; - } else if (units === 'year') { - output = output / 12; - } - } else { - diff = this - that; - output = units === 'second' ? diff / 1e3 : // 1000 - units === 'minute' ? diff / 6e4 : // 1000 * 60 - units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 - units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst - units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst - diff; - } - return asFloat ? output : absRound(output); - }, + // map with all delimiters + var DELIMITERS = { + '{': true, + '}': true, + '[': true, + ']': true, + ';': true, + '=': true, + ',': true, - from : function (time, withoutSuffix) { - return moment.duration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix); - }, + '->': true, + '--': true + }; - fromNow : function (withoutSuffix) { - return this.from(moment(), withoutSuffix); - }, + var dot = ''; // current dot file + var index = 0; // current index in dot file + var c = ''; // current token character in expr + var token = ''; // current token + var tokenType = TOKENTYPE.NULL; // type of the token - calendar : function (time) { - // We want to compare the start of today, vs this. - // Getting start-of-today depends on whether we're locat/utc/offset - // or not. - var now = time || moment(), - sod = makeAs(now, this).startOf('day'), - diff = this.diff(sod, 'days', true), - format = diff < -6 ? 'sameElse' : - diff < -1 ? 'lastWeek' : - diff < 0 ? 'lastDay' : - diff < 1 ? 'sameDay' : - diff < 2 ? 'nextDay' : - diff < 7 ? 'nextWeek' : 'sameElse'; - return this.format(this.localeData().calendar(format, this, moment(now))); - }, + /** + * Get the first character from the dot file. + * The character is stored into the char c. If the end of the dot file is + * reached, the function puts an empty string in c. + */ + function first() { + index = 0; + c = dot.charAt(0); + } - isLeapYear : function () { - return isLeapYear(this.year()); - }, + /** + * Get the next character from the dot file. + * The character is stored into the char c. If the end of the dot file is + * reached, the function puts an empty string in c. + */ + function next() { + index++; + c = dot.charAt(index); + } - isDST : function () { - return (this.utcOffset() > this.clone().month(0).utcOffset() || - this.utcOffset() > this.clone().month(5).utcOffset()); - }, + /** + * Preview the next character from the dot file. + * @return {String} cNext + */ + function nextPreview() { + return dot.charAt(index + 1); + } - day : function (input) { - var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); - if (input != null) { - input = parseWeekday(input, this.localeData()); - return this.add(input - day, 'd'); - } else { - return day; - } - }, + /** + * Test whether given character is alphabetic or numeric + * @param {String} c + * @return {Boolean} isAlphaNumeric + */ + var regexAlphaNumeric = /[a-zA-Z_0-9.:#]/; + function isAlphaNumeric(c) { + return regexAlphaNumeric.test(c); + } - month : makeAccessor('Month', true), + /** + * Merge all properties of object b into object b + * @param {Object} a + * @param {Object} b + * @return {Object} a + */ + function merge (a, b) { + if (!a) { + a = {}; + } - startOf : function (units) { - units = normalizeUnits(units); - // the following switch intentionally omits break keywords - // to utilize falling through the cases. - switch (units) { - case 'year': - this.month(0); - /* falls through */ - case 'quarter': - case 'month': - this.date(1); - /* falls through */ - case 'week': - case 'isoWeek': - case 'day': - this.hours(0); - /* falls through */ - case 'hour': - this.minutes(0); - /* falls through */ - case 'minute': - this.seconds(0); - /* falls through */ - case 'second': - this.milliseconds(0); - /* falls through */ - } + if (b) { + for (var name in b) { + if (b.hasOwnProperty(name)) { + a[name] = b[name]; + } + } + } + return a; + } - // weeks are a special case - if (units === 'week') { - this.weekday(0); - } else if (units === 'isoWeek') { - this.isoWeekday(1); - } + /** + * Set a value in an object, where the provided parameter name can be a + * path with nested parameters. For example: + * + * var obj = {a: 2}; + * setValue(obj, 'b.c', 3); // obj = {a: 2, b: {c: 3}} + * + * @param {Object} obj + * @param {String} path A parameter name or dot-separated parameter path, + * like "color.highlight.border". + * @param {*} value + */ + function setValue(obj, path, value) { + var keys = path.split('.'); + var o = obj; + while (keys.length) { + var key = keys.shift(); + if (keys.length) { + // this isn't the end point + if (!o[key]) { + o[key] = {}; + } + o = o[key]; + } + else { + // this is the end point + o[key] = value; + } + } + } - // quarters are also special - if (units === 'quarter') { - this.month(Math.floor(this.month() / 3) * 3); - } + /** + * Add a node to a graph object. If there is already a node with + * the same id, their attributes will be merged. + * @param {Object} graph + * @param {Object} node + */ + function addNode(graph, node) { + var i, len; + var current = null; - return this; - }, + // find root graph (in case of subgraph) + var graphs = [graph]; // list with all graphs from current graph to root graph + var root = graph; + while (root.parent) { + graphs.push(root.parent); + root = root.parent; + } - endOf: function (units) { - units = normalizeUnits(units); - if (units === undefined || units === 'millisecond') { - return this; - } - return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms'); - }, + // find existing node (at root level) by its id + if (root.nodes) { + for (i = 0, len = root.nodes.length; i < len; i++) { + if (node.id === root.nodes[i].id) { + current = root.nodes[i]; + break; + } + } + } - isAfter: function (input, units) { - var inputMs; - units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); - if (units === 'millisecond') { - input = moment.isMoment(input) ? input : moment(input); - return +this > +input; - } else { - inputMs = moment.isMoment(input) ? +input : +moment(input); - return inputMs < +this.clone().startOf(units); - } - }, + if (!current) { + // this is a new node + current = { + id: node.id + }; + if (graph.node) { + // clone default attributes + current.attr = merge(current.attr, graph.node); + } + } - isBefore: function (input, units) { - var inputMs; - units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); - if (units === 'millisecond') { - input = moment.isMoment(input) ? input : moment(input); - return +this < +input; - } else { - inputMs = moment.isMoment(input) ? +input : +moment(input); - return +this.clone().endOf(units) < inputMs; - } - }, + // add node to this (sub)graph and all its parent graphs + for (i = graphs.length - 1; i >= 0; i--) { + var g = graphs[i]; - isBetween: function (from, to, units) { - return this.isAfter(from, units) && this.isBefore(to, units); - }, + if (!g.nodes) { + g.nodes = []; + } + if (g.nodes.indexOf(current) == -1) { + g.nodes.push(current); + } + } - isSame: function (input, units) { - var inputMs; - units = normalizeUnits(units || 'millisecond'); - if (units === 'millisecond') { - input = moment.isMoment(input) ? input : moment(input); - return +this === +input; - } else { - inputMs = +moment(input); - return +(this.clone().startOf(units)) <= inputMs && inputMs <= +(this.clone().endOf(units)); - } - }, + // merge attributes + if (node.attr) { + current.attr = merge(current.attr, node.attr); + } + } - min: deprecate( - '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; - } - ), + /** + * Add an edge to a graph object + * @param {Object} graph + * @param {Object} edge + */ + function addEdge(graph, edge) { + if (!graph.edges) { + graph.edges = []; + } + graph.edges.push(edge); + if (graph.edge) { + var attr = merge({}, graph.edge); // clone default attributes + edge.attr = merge(attr, edge.attr); // merge attributes + } + } - max: deprecate( - '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; - } - ), + /** + * Create an edge to a graph object + * @param {Object} graph + * @param {String | Number | Object} from + * @param {String | Number | Object} to + * @param {String} type + * @param {Object | null} attr + * @return {Object} edge + */ + function createEdge(graph, from, to, type, attr) { + var edge = { + from: from, + to: to, + type: type + }; - zone : deprecate( - 'moment().zone is deprecated, use moment().utcOffset instead. ' + - 'https://github.com/moment/moment/issues/1779', - function (input, keepLocalTime) { - if (input != null) { - if (typeof input !== 'string') { - input = -input; - } + if (graph.edge) { + edge.attr = merge({}, graph.edge); // clone default attributes + } + edge.attr = merge(edge.attr || {}, attr); // merge attributes - this.utcOffset(input, keepLocalTime); + return edge; + } - return this; - } else { - return -this.utcOffset(); - } - } - ), + /** + * Get next token in the current dot file. + * The token and token type are available as token and tokenType + */ + function getToken() { + tokenType = TOKENTYPE.NULL; + token = ''; - // keepLocalTime = true means only change the timezone, without - // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]--> - // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset - // +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. - utcOffset : function (input, keepLocalTime) { - var offset = this._offset || 0, - localAdjust; - if (input != null) { - if (typeof input === 'string') { - input = utcOffsetFromString(input); - } - if (Math.abs(input) < 16) { - input = input * 60; - } - if (!this._isUTC && keepLocalTime) { - localAdjust = this._dateUtcOffset(); - } - this._offset = input; - this._isUTC = true; - if (localAdjust != null) { - this.add(localAdjust, 'm'); - } - if (offset !== input) { - if (!keepLocalTime || this._changeInProgress) { - addOrSubtractDurationFromMoment(this, - moment.duration(input - offset, 'm'), 1, false); - } else if (!this._changeInProgress) { - this._changeInProgress = true; - moment.updateOffset(this, true); - this._changeInProgress = null; - } - } + // skip over whitespaces + while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter + next(); + } - return this; - } else { - return this._isUTC ? offset : this._dateUtcOffset(); - } - }, + do { + var isComment = false; - isLocal : function () { - return !this._isUTC; - }, + // skip comment + if (c == '#') { + // find the previous non-space character + var i = index - 1; + while (dot.charAt(i) == ' ' || dot.charAt(i) == '\t') { + i--; + } + if (dot.charAt(i) == '\n' || dot.charAt(i) == '') { + // the # is at the start of a line, this is indeed a line comment + while (c != '' && c != '\n') { + next(); + } + isComment = true; + } + } + if (c == '/' && nextPreview() == '/') { + // skip line comment + while (c != '' && c != '\n') { + next(); + } + isComment = true; + } + if (c == '/' && nextPreview() == '*') { + // skip block comment + while (c != '') { + if (c == '*' && nextPreview() == '/') { + // end of block comment found. skip these last two characters + next(); + next(); + break; + } + else { + next(); + } + } + isComment = true; + } - isUtcOffset : function () { - return this._isUTC; - }, + // skip over whitespaces + while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter + next(); + } + } + while (isComment); - isUtc : function () { - return this._isUTC && this._offset === 0; - }, + // check for end of dot file + if (c == '') { + // token is still empty + tokenType = TOKENTYPE.DELIMITER; + return; + } - zoneAbbr : function () { - return this._isUTC ? 'UTC' : ''; - }, + // check for delimiters consisting of 2 characters + var c2 = c + nextPreview(); + if (DELIMITERS[c2]) { + tokenType = TOKENTYPE.DELIMITER; + token = c2; + next(); + next(); + return; + } - zoneName : function () { - return this._isUTC ? 'Coordinated Universal Time' : ''; - }, + // check for delimiters consisting of 1 character + if (DELIMITERS[c]) { + tokenType = TOKENTYPE.DELIMITER; + token = c; + next(); + return; + } - parseZone : function () { - if (this._tzm) { - this.utcOffset(this._tzm); - } else if (typeof this._i === 'string') { - this.utcOffset(utcOffsetFromString(this._i)); - } - return this; - }, + // check for an identifier (number or string) + // TODO: more precise parsing of numbers/strings (and the port separator ':') + if (isAlphaNumeric(c) || c == '-') { + token += c; + next(); - hasAlignedHourOffset : function (input) { - if (!input) { - input = 0; - } - else { - input = moment(input).utcOffset(); - } + while (isAlphaNumeric(c)) { + token += c; + next(); + } + if (token == 'false') { + token = false; // convert to boolean + } + else if (token == 'true') { + token = true; // convert to boolean + } + else if (!isNaN(Number(token))) { + token = Number(token); // convert to number + } + tokenType = TOKENTYPE.IDENTIFIER; + return; + } - return (this.utcOffset() - input) % 60 === 0; - }, + // check for a string enclosed by double quotes + if (c == '"') { + next(); + while (c != '' && (c != '"' || (c == '"' && nextPreview() == '"'))) { + token += c; + if (c == '"') { // skip the escape character + next(); + } + next(); + } + if (c != '"') { + throw newSyntaxError('End of string " expected'); + } + next(); + tokenType = TOKENTYPE.IDENTIFIER; + return; + } - daysInMonth : function () { - return daysInMonth(this.year(), this.month()); - }, + // something unknown is found, wrong characters, a syntax error + tokenType = TOKENTYPE.UNKNOWN; + while (c != '') { + token += c; + next(); + } + throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"'); + } - dayOfYear : function (input) { - var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; - return input == null ? dayOfYear : this.add((input - dayOfYear), 'd'); - }, + /** + * Parse a graph. + * @returns {Object} graph + */ + function parseGraph() { + var graph = {}; - quarter : function (input) { - return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3); - }, + first(); + getToken(); - weekYear : function (input) { - var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year; - return input == null ? year : this.add((input - year), 'y'); - }, + // optional strict keyword + if (token == 'strict') { + graph.strict = true; + getToken(); + } - isoWeekYear : function (input) { - var year = weekOfYear(this, 1, 4).year; - return input == null ? year : this.add((input - year), 'y'); - }, + // graph or digraph keyword + if (token == 'graph' || token == 'digraph') { + graph.type = token; + getToken(); + } - week : function (input) { - var week = this.localeData().week(this); - return input == null ? week : this.add((input - week) * 7, 'd'); - }, + // optional graph id + if (tokenType == TOKENTYPE.IDENTIFIER) { + graph.id = token; + getToken(); + } - isoWeek : function (input) { - var week = weekOfYear(this, 1, 4).week; - return input == null ? week : this.add((input - week) * 7, 'd'); - }, + // open angle bracket + if (token != '{') { + throw newSyntaxError('Angle bracket { expected'); + } + getToken(); - weekday : function (input) { - var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; - return input == null ? weekday : this.add(input - weekday, 'd'); - }, + // statements + parseStatements(graph); - isoWeekday : function (input) { - // behaves the same as moment#day except - // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) - // as a setter, sunday should belong to the previous week. - return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); - }, + // close angle bracket + if (token != '}') { + throw newSyntaxError('Angle bracket } expected'); + } + getToken(); - isoWeeksInYear : function () { - return weeksInYear(this.year(), 1, 4); - }, + // end of file + if (token !== '') { + throw newSyntaxError('End of file expected'); + } + getToken(); - weeksInYear : function () { - var weekInfo = this.localeData()._week; - return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); - }, + // remove temporary default properties + delete graph.node; + delete graph.edge; + delete graph.graph; - get : function (units) { - units = normalizeUnits(units); - return this[units](); - }, + return graph; + } - set : function (units, value) { - var unit; - if (typeof units === 'object') { - for (unit in units) { - this.set(unit, units[unit]); - } - } - else { - units = normalizeUnits(units); - if (typeof this[units] === 'function') { - this[units](value); - } - } - return this; - }, + /** + * Parse a list with statements. + * @param {Object} graph + */ + function parseStatements (graph) { + while (token !== '' && token != '}') { + parseStatement(graph); + if (token == ';') { + getToken(); + } + } + } - // If passed a locale key, it will set the locale for this - // instance. Otherwise, it will return the locale configuration - // variables for this instance. - locale : function (key) { - var newLocaleData; + /** + * Parse a single statement. Can be a an attribute statement, node + * statement, a series of node statements and edge statements, or a + * parameter. + * @param {Object} graph + */ + function parseStatement(graph) { + // parse subgraph + var subgraph = parseSubgraph(graph); + if (subgraph) { + // edge statements + parseEdge(graph, subgraph); - if (key === undefined) { - return this._locale._abbr; - } else { - newLocaleData = moment.localeData(key); - if (newLocaleData != null) { - this._locale = newLocaleData; - } - return this; - } - }, + return; + } - lang : deprecate( - 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', - function (key) { - if (key === undefined) { - return this.localeData(); - } else { - return this.locale(key); - } - } - ), + // parse an attribute statement + var attr = parseAttributeStatement(graph); + if (attr) { + return; + } - localeData : function () { - return this._locale; - }, + // parse node + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier expected'); + } + var id = token; // id can be a string or a number + getToken(); + + if (token == '=') { + // id statement + getToken(); + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier expected'); + } + graph[id] = token; + getToken(); + // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] " + } + else { + parseNodeStatement(graph, id); + } + } - _dateUtcOffset : function () { - // On Firefox.24 Date#getTimezoneOffset returns a floating point. - // https://github.com/moment/moment/pull/1871 - return -Math.round(this._d.getTimezoneOffset() / 15) * 15; - } + /** + * Parse a subgraph + * @param {Object} graph parent graph object + * @return {Object | null} subgraph + */ + function parseSubgraph (graph) { + var subgraph = null; - }); + // optional subgraph keyword + if (token == 'subgraph') { + subgraph = {}; + subgraph.type = 'subgraph'; + getToken(); - function rawMonthSetter(mom, value) { - var dayOfMonth; + // optional graph id + if (tokenType == TOKENTYPE.IDENTIFIER) { + subgraph.id = token; + getToken(); + } + } - // TODO: Move this out of here! - if (typeof value === 'string') { - value = mom.localeData().monthsParse(value); - // TODO: Another silent failure? - if (typeof value !== 'number') { - return mom; - } - } + // open angle bracket + if (token == '{') { + getToken(); - dayOfMonth = Math.min(mom.date(), - daysInMonth(mom.year(), value)); - mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); - return mom; + if (!subgraph) { + subgraph = {}; } + subgraph.parent = graph; + subgraph.node = graph.node; + subgraph.edge = graph.edge; + subgraph.graph = graph.graph; - function rawGetter(mom, unit) { - return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit](); - } + // statements + parseStatements(subgraph); - function rawSetter(mom, unit, value) { - if (unit === 'Month') { - return rawMonthSetter(mom, value); - } else { - return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); - } + // close angle bracket + if (token != '}') { + throw newSyntaxError('Angle bracket } expected'); } + getToken(); - function makeAccessor(unit, keepTime) { - return function (value) { - if (value != null) { - rawSetter(this, unit, value); - moment.updateOffset(this, keepTime); - return this; - } else { - return rawGetter(this, unit); - } - }; + // remove temporary default properties + delete subgraph.node; + delete subgraph.edge; + delete subgraph.graph; + delete subgraph.parent; + + // register at the parent graph + if (!graph.subgraphs) { + graph.subgraphs = []; } + graph.subgraphs.push(subgraph); + } - moment.fn.millisecond = moment.fn.milliseconds = makeAccessor('Milliseconds', false); - moment.fn.second = moment.fn.seconds = makeAccessor('Seconds', false); - moment.fn.minute = moment.fn.minutes = makeAccessor('Minutes', false); - // Setting the hour should keep the time, because the user explicitly - // specified which hour he wants. So trying to maintain the same hour (in - // a new timezone) makes sense. Adding/subtracting hours does not follow - // this rule. - 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.year = makeAccessor('FullYear', true); - moment.fn.years = deprecate('years accessor is deprecated. Use year instead.', makeAccessor('FullYear', true)); + return subgraph; + } - // add plural methods - moment.fn.days = moment.fn.day; - moment.fn.months = moment.fn.month; - moment.fn.weeks = moment.fn.week; - moment.fn.isoWeeks = moment.fn.isoWeek; - moment.fn.quarters = moment.fn.quarter; + /** + * parse an attribute statement like "node [shape=circle fontSize=16]". + * Available keywords are 'node', 'edge', 'graph'. + * The previous list with default attributes will be replaced + * @param {Object} graph + * @returns {String | null} keyword Returns the name of the parsed attribute + * (node, edge, graph), or null if nothing + * is parsed. + */ + function parseAttributeStatement (graph) { + // attribute statements + if (token == 'node') { + getToken(); - // add aliased format methods - moment.fn.toJSON = moment.fn.toISOString; + // node attributes + graph.node = parseAttributeList(); + return 'node'; + } + else if (token == 'edge') { + getToken(); - // alias isUtc for dev-friendliness - moment.fn.isUTC = moment.fn.isUtc; + // edge attributes + graph.edge = parseAttributeList(); + return 'edge'; + } + else if (token == 'graph') { + getToken(); - /************************************ - Duration Prototype - ************************************/ + // graph attributes + graph.graph = parseAttributeList(); + return 'graph'; + } + return null; + } - function daysToYears (days) { - // 400 years have 146097 days (taking into account leap year rules) - return days * 400 / 146097; - } + /** + * parse a node statement + * @param {Object} graph + * @param {String | Number} id + */ + function parseNodeStatement(graph, id) { + // node statement + var node = { + id: id + }; + var attr = parseAttributeList(); + if (attr) { + node.attr = attr; + } + addNode(graph, node); - function yearsToDays (years) { - // years * 365 + absRound(years / 4) - - // absRound(years / 100) + absRound(years / 400); - return years * 146097 / 400; + // edge statements + parseEdge(graph, id); + } + + /** + * Parse an edge or a series of edges + * @param {Object} graph + * @param {String | Number} from Id of the from node + */ + function parseEdge(graph, from) { + while (token == '->' || token == '--') { + var to; + var type = token; + getToken(); + + var subgraph = parseSubgraph(graph); + if (subgraph) { + to = subgraph; + } + else { + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier or subgraph expected'); + } + to = token; + addNode(graph, { + id: to + }); + getToken(); } - extend(moment.duration.fn = Duration.prototype, { + // parse edge attributes + var attr = parseAttributeList(); - _bubble : function () { - var milliseconds = this._milliseconds, - days = this._days, - months = this._months, - data = this._data, - seconds, minutes, hours, years = 0; + // create edge + var edge = createEdge(graph, from, to, type, attr); + addEdge(graph, edge); - // The following code bubbles up values, see the tests for - // examples of what that means. - data.milliseconds = milliseconds % 1000; + from = to; + } + } - seconds = absRound(milliseconds / 1000); - data.seconds = seconds % 60; + /** + * Parse a set with attributes, + * for example [label="1.000", shape=solid] + * @return {Object | null} attr + */ + function parseAttributeList() { + var attr = null; - minutes = absRound(seconds / 60); - data.minutes = minutes % 60; + while (token == '[') { + getToken(); + attr = {}; + while (token !== '' && token != ']') { + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Attribute name expected'); + } + var name = token; - hours = absRound(minutes / 60); - data.hours = hours % 24; + getToken(); + if (token != '=') { + throw newSyntaxError('Equal sign = expected'); + } + getToken(); - days += absRound(hours / 24); + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Attribute value expected'); + } + var value = token; + setValue(attr, name, value); // name can be a path - // Accurately convert days to years, assume start from year 0. - years = absRound(daysToYears(days)); - days -= absRound(yearsToDays(years)); + getToken(); + if (token ==',') { + getToken(); + } + } - // 30 days to a month - // TODO (iskren): Use anchor date (like 1st Jan) to compute this. - months += absRound(days / 30); - days %= 30; + if (token != ']') { + throw newSyntaxError('Bracket ] expected'); + } + getToken(); + } - // 12 months -> 1 year - years += absRound(months / 12); - months %= 12; + return attr; + } - data.days = days; - data.months = months; - data.years = years; - }, + /** + * Create a syntax error with extra information on current token and index. + * @param {String} message + * @returns {SyntaxError} err + */ + function newSyntaxError(message) { + return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ')'); + } - abs : function () { - this._milliseconds = Math.abs(this._milliseconds); - this._days = Math.abs(this._days); - this._months = Math.abs(this._months); + /** + * Chop off text after a maximum length + * @param {String} text + * @param {Number} maxLength + * @returns {String} + */ + function chop (text, maxLength) { + return (text.length <= maxLength) ? text : (text.substr(0, 27) + '...'); + } - 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); + /** + * Execute a function fn for each pair of elements in two arrays + * @param {Array | *} array1 + * @param {Array | *} array2 + * @param {function} fn + */ + function forEach2(array1, array2, fn) { + if (Array.isArray(array1)) { + array1.forEach(function (elem1) { + if (Array.isArray(array2)) { + array2.forEach(function (elem2) { + fn(elem1, elem2); + }); + } + else { + fn(elem1, array2); + } + }); + } + else { + if (Array.isArray(array2)) { + array2.forEach(function (elem2) { + fn(array1, elem2); + }); + } + else { + fn(array1, array2); + } + } + } - return this; - }, + /** + * Convert a string containing a graph in DOT language into a map containing + * with nodes and edges in the format of graph. + * @param {String} data Text containing a graph in DOT-notation + * @return {Object} graphData + */ + function DOTToGraph (data) { + // parse the DOT file + var dotData = parseDOT(data); + var graphData = { + nodes: [], + edges: [], + options: {} + }; - weeks : function () { - return absRound(this.days() / 7); - }, + // copy the nodes + if (dotData.nodes) { + dotData.nodes.forEach(function (dotNode) { + var graphNode = { + id: dotNode.id, + label: String(dotNode.label || dotNode.id) + }; + merge(graphNode, dotNode.attr); + if (graphNode.image) { + graphNode.shape = 'image'; + } + graphData.nodes.push(graphNode); + }); + } - valueOf : function () { - return this._milliseconds + - this._days * 864e5 + - (this._months % 12) * 2592e6 + - toInt(this._months / 12) * 31536e6; - }, + // copy the edges + if (dotData.edges) { + /** + * Convert an edge in DOT format to an edge with VisGraph format + * @param {Object} dotEdge + * @returns {Object} graphEdge + */ + var convertEdge = function (dotEdge) { + var graphEdge = { + from: dotEdge.from, + to: dotEdge.to + }; + merge(graphEdge, dotEdge.attr); + graphEdge.style = (dotEdge.type == '->') ? 'arrow' : 'line'; + return graphEdge; + } - humanize : function (withSuffix) { - var output = relativeTime(this, !withSuffix, this.localeData()); + dotData.edges.forEach(function (dotEdge) { + var from, to; + if (dotEdge.from instanceof Object) { + from = dotEdge.from.nodes; + } + else { + from = { + id: dotEdge.from + } + } - if (withSuffix) { - output = this.localeData().pastFuture(+this, output); - } + if (dotEdge.to instanceof Object) { + to = dotEdge.to.nodes; + } + else { + to = { + id: dotEdge.to + } + } - return this.localeData().postformat(output); - }, + if (dotEdge.from instanceof Object && dotEdge.from.edges) { + dotEdge.from.edges.forEach(function (subEdge) { + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); + } - add : function (input, val) { - // supports only 2.0-style add(1, 's') or add(moment) - var dur = moment.duration(input, val); + forEach2(from, to, function (from, to) { + var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr); + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); - this._milliseconds += dur._milliseconds; - this._days += dur._days; - this._months += dur._months; + if (dotEdge.to instanceof Object && dotEdge.to.edges) { + dotEdge.to.edges.forEach(function (subEdge) { + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); + } + }); + } - this._bubble(); + // copy the options + if (dotData.attr) { + graphData.options = dotData.attr; + } - return this; - }, + return graphData; + } - subtract : function (input, val) { - var dur = moment.duration(input, val); + // exports + exports.parseDOT = parseDOT; + exports.DOTToGraph = DOTToGraph; - this._milliseconds -= dur._milliseconds; - this._days -= dur._days; - this._months -= dur._months; - this._bubble(); +/***/ }, +/* 53 */ +/***/ function(module, exports, __webpack_require__) { + + + function parseGephi(gephiJSON, options) { + var edges = []; + var nodes = []; + this.options = { + edges: { + inheritColor: true + }, + nodes: { + allowedToMove: false, + parseColor: false + } + }; + + if (options !== undefined) { + this.options.nodes['allowedToMove'] = options.allowedToMove | false; + this.options.nodes['parseColor'] = options.parseColor | false; + this.options.edges['inheritColor'] = options.inheritColor | true; + } + + var gEdges = gephiJSON.edges; + var gNodes = gephiJSON.nodes; + for (var i = 0; i < gEdges.length; i++) { + var edge = {}; + var gEdge = gEdges[i]; + edge['id'] = gEdge.id; + edge['from'] = gEdge.source; + edge['to'] = gEdge.target; + edge['attributes'] = gEdge.attributes; + // edge['value'] = gEdge.attributes !== undefined ? gEdge.attributes.Weight : undefined; + // edge['width'] = edge['value'] !== undefined ? undefined : edgegEdge.size; + edge['color'] = gEdge.color; + edge['inheritColor'] = edge['color'] !== undefined ? false : this.options.inheritColor; + edges.push(edge); + } + + for (var i = 0; i < gNodes.length; i++) { + var node = {}; + var gNode = gNodes[i]; + node['id'] = gNode.id; + node['attributes'] = gNode.attributes; + node['x'] = gNode.x; + node['y'] = gNode.y; + node['label'] = gNode.label; + if (this.options.nodes.parseColor == true) { + node['color'] = gNode.color; + } + else { + node['color'] = gNode.color !== undefined ? {background:gNode.color, border:gNode.color} : undefined; + } + node['radius'] = gNode.size; + node['allowedToMoveX'] = this.options.nodes.allowedToMove; + node['allowedToMoveY'] = this.options.nodes.allowedToMove; + nodes.push(node); + } - return this; - }, + return {nodes:nodes, edges:edges}; + } - get : function (units) { - units = normalizeUnits(units); - return this[units.toLowerCase() + 's'](); - }, + exports.parseGephi = parseGephi; - as : function (units) { - var days, months; - units = normalizeUnits(units); +/***/ }, +/* 54 */ +/***/ function(module, exports, __webpack_require__) { - if (units === 'month' || units === 'year') { - days = this._days + this._milliseconds / 864e5; - months = this._months + daysToYears(days) * 12; - return units === 'month' ? months : months / 12; - } else { - // handle milliseconds separately because of floating point math errors (issue #1867) - days = this._days + Math.round(yearsToDays(this._months / 12)); - switch (units) { - case 'week': return days / 7 + this._milliseconds / 6048e5; - case 'day': return days + this._milliseconds / 864e5; - case 'hour': return days * 24 + this._milliseconds / 36e5; - case 'minute': return days * 24 * 60 + this._milliseconds / 6e4; - case 'second': return days * 24 * 60 * 60 + this._milliseconds / 1000; - // Math.floor prevents floating point math errors here - case 'millisecond': return Math.floor(days * 24 * 60 * 60 * 1000) + this._milliseconds; - default: throw new Error('Unknown unit ' + units); - } - } - }, + var util = __webpack_require__(1); - lang : moment.fn.lang, - locale : moment.fn.locale, + /** + * @class Groups + * This class can store groups and properties specific for groups. + */ + function Groups() { + this.clear(); + this.defaultIndex = 0; + } - toIsoString : deprecate( - 'toIsoString() is deprecated. Please use toISOString() instead ' + - '(notice the capitals)', - function () { - return this.toISOString(); - } - ), - 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()), - days = Math.abs(this.days()), - hours = Math.abs(this.hours()), - minutes = Math.abs(this.minutes()), - seconds = Math.abs(this.seconds() + this.milliseconds() / 1000); + /** + * default constants for group colors + */ + Groups.DEFAULT = [ + {border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}, hover: {border: "#2B7CE9", background: "#D2E5FF"}}, // blue + {border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}, hover: {border: "#FFA500", background: "#FFFFA3"}}, // yellow + {border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}, hover: {border: "#FA0A10", background: "#FFAFB1"}}, // red + {border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}, hover: {border: "#41A906", background: "#A1EC76"}}, // green + {border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}, hover: {border: "#E129F0", background: "#F0B3F5"}}, // magenta + {border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}, hover: {border: "#7C29F0", background: "#D3BDF0"}}, // purple + {border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}, hover: {border: "#C37F00", background: "#FFCA66"}}, // orange + {border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}, hover: {border: "#4220FB", background: "#9B9BFD"}}, // darkblue + {border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}, hover: {border: "#FD5A77", background: "#FFD1D9"}}, // pink + {border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}, hover: {border: "#4AD63A", background: "#E6FFE3"}} // mint + ]; - if (!this.asSeconds()) { - // this is the same as C#'s (Noda) and python (isodate)... - // but not other JS (goog.date) - return 'P0D'; - } - return (this.asSeconds() < 0 ? '-' : '') + - 'P' + - (years ? years + 'Y' : '') + - (months ? months + 'M' : '') + - (days ? days + 'D' : '') + - ((hours || minutes || seconds) ? 'T' : '') + - (hours ? hours + 'H' : '') + - (minutes ? minutes + 'M' : '') + - (seconds ? seconds + 'S' : ''); - }, + /** + * Clear all groups + */ + Groups.prototype.clear = function () { + this.groups = {}; + this.groups.length = function() + { + var i = 0; + for ( var p in this ) { + if (this.hasOwnProperty(p)) { + i++; + } + } + return i; + } + }; - localeData : function () { - return this._locale; - }, - toJSON : function () { - return this.toISOString(); - } - }); + /** + * get group properties of a groupname. If groupname is not found, a new group + * is added. + * @param {*} groupname Can be a number, string, Date, etc. + * @return {Object} group The created group, containing all group properties + */ + Groups.prototype.get = function (groupname) { + var group = this.groups[groupname]; + if (group == undefined) { + // create new group + var index = this.defaultIndex % Groups.DEFAULT.length; + this.defaultIndex++; + group = {}; + group.color = Groups.DEFAULT[index]; + this.groups[groupname] = group; + } - moment.duration.fn.toString = moment.duration.fn.toISOString; + return group; + }; - function makeDurationGetter(name) { - moment.duration.fn[name] = function () { - return this._data[name]; - }; - } + /** + * Add a custom group style + * @param {String} groupname + * @param {Object} style An object containing borderColor, + * backgroundColor, etc. + * @return {Object} group The created group object + */ + Groups.prototype.add = function (groupname, style) { + this.groups[groupname] = style; + return style; + }; - for (i in unitMillisecondFactors) { - if (hasOwnProp(unitMillisecondFactors, i)) { - makeDurationGetter(i.toLowerCase()); - } - } + module.exports = Groups; - 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.as('M'); - }; - moment.duration.fn.asYears = function () { - return this.as('y'); - }; - /************************************ - Default Locale - ************************************/ +/***/ }, +/* 55 */ +/***/ function(module, exports, __webpack_require__) { + /** + * @class Images + * This class loads images and keeps them stored. + */ + function Images() { + this.images = {}; + this.imageBroken = {}; + this.callback = undefined; + } - // Set default locale, other locale will inherit from English. - moment.locale('en', { - ordinalParse: /\d{1,2}(th|st|nd|rd)/, - ordinal : function (number) { - var b = number % 10, - output = (toInt(number % 100 / 10) === 1) ? 'th' : - (b === 1) ? 'st' : - (b === 2) ? 'nd' : - (b === 3) ? 'rd' : 'th'; - return number + output; - } - }); + /** + * Set an onload callback function. This will be called each time an image + * is loaded + * @param {function} callback + */ + Images.prototype.setOnloadCallback = function(callback) { + this.callback = callback; + }; - /* EMBED_LOCALES */ + /** + * + * @param {string} url Url of the image + * @param {string} url Url of an image to use if the url image is not found + * @return {Image} img The image object + */ + Images.prototype.load = function(url, brokenUrl) { + var img = this.images[url]; // make a pointer + if (img === undefined) { + // create the image + var me = this; + img = new Image(); + img.onload = function () { + // IE11 fix -- thanks dponch! + if (this.width == 0) { + document.body.appendChild(this); + this.width = this.offsetWidth; + this.height = this.offsetHeight; + document.body.removeChild(this); + } - /************************************ - Exposing Moment - ************************************/ + if (me.callback) { + me.images[url] = img; + me.callback(this); + } + }; - function makeGlobal(shouldDeprecate) { - /*global ender:false */ - if (typeof ender !== 'undefined') { - return; + img.onerror = function () { + if (brokenUrl === undefined) { + console.error("Could not load image:", url); + delete this.src; + if (me.callback) { + me.callback(this); } - oldGlobalMoment = globalScope.moment; - if (shouldDeprecate) { - globalScope.moment = deprecate( - 'Accessing Moment through the global scope is ' + - 'deprecated, and will be removed in an upcoming ' + - 'release.', - moment); - } else { - globalScope.moment = moment; + } + else if (me.imageBroken[url] === true) { + console.error("Could not load brokenImage:", brokenUrl); + delete this.src; + if (me.callback) { + me.callback(this); } - } + } + else { + this.src = brokenUrl; + me.imageBroken[url] = true; + } + }; - // CommonJS module is defined - if (hasModule) { - module.exports = moment; - } else if (true) { - !(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) { - if (module.config && module.config() && module.config().noGlobal === true) { - // release the global variable - globalScope.moment = oldGlobalMoment; - } + img.src = url; + } + + return img; + }; + + module.exports = Images; - return moment; - }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - makeGlobal(true); - } else { - makeGlobal(); - } - }).call(this); - - /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()), __webpack_require__(71)(module))) /***/ }, -/* 59 */ +/* 56 */ /***/ function(module, exports, __webpack_require__) { - var __WEBPACK_AMD_DEFINE_RESULT__;/*! Hammer.JS - v1.1.3 - 2014-05-20 - * http://eightmedia.github.io/hammer.js - * - * Copyright (c) 2014 Jorik Tangelder ; - * Licensed under the MIT license */ - - (function(window, undefined) { - 'use strict'; + var util = __webpack_require__(1); /** - * @main - * @module hammer + * @class Node + * A node. A node can be connected to other nodes via one or multiple edges. + * @param {object} properties An object containing properties for the node. All + * properties are optional, except for the id. + * {number} id Id of the node. Required + * {string} label Text label for the node + * {number} x Horizontal position of the node + * {number} y Vertical position of the node + * {string} shape Node shape, available: + * "database", "circle", "ellipse", + * "box", "image", "text", "dot", + * "star", "triangle", "triangleDown", + * "square" + * {string} image An image url + * {string} title An title text, can be HTML + * {anytype} group A group name or number + * @param {Network.Images} imagelist A list with images. Only needed + * when the node has an image + * @param {Network.Groups} grouplist A list with groups. Needed for + * retrieving group properties + * @param {Object} constants An object with default values for + * example for the color * - * @class Hammer - * @static */ + function Node(properties, imagelist, grouplist, networkConstants) { + var constants = util.selectiveBridgeObject(['nodes'],networkConstants); + this.options = constants.nodes; - /** - * Hammer, use this to create instances - * ```` - * var hammertime = new Hammer(myElement); - * ```` - * - * @method Hammer - * @param {HTMLElement} element - * @param {Object} [options={}] - * @return {Hammer.Instance} - */ - var Hammer = function Hammer(element, options) { - return new Hammer.Instance(element, options || {}); - }; + this.selected = false; + this.hover = false; - /** - * version, as defined in package.json - * the value will be set at each build - * @property VERSION - * @final - * @type {String} - */ - Hammer.VERSION = '1.1.3'; + this.edges = []; // all edges connected to this node + this.dynamicEdges = []; + this.reroutedEdges = {}; - /** - * default settings. - * more settings are defined per gesture at `/gestures`. Each gesture can be disabled/enabled - * by setting it's name (like `swipe`) to false. - * You can set the defaults for all instances by changing this object before creating an instance. - * @example - * ```` - * Hammer.defaults.drag = false; - * Hammer.defaults.behavior.touchAction = 'pan-y'; - * delete Hammer.defaults.behavior.userSelect; - * ```` - * @property defaults - * @type {Object} - */ - Hammer.defaults = { - /** - * this setting object adds styles and attributes to the element to prevent the browser from doing - * its native behavior. The css properties are auto prefixed for the browsers when needed. - * @property defaults.behavior - * @type {Object} - */ - behavior: { - /** - * Disables text selection to improve the dragging gesture. When the value is `none` it also sets - * `onselectstart=false` for IE on the element. Mainly for desktop browsers. - * @property defaults.behavior.userSelect - * @type {String} - * @default 'none' - */ - userSelect: 'none', + this.fontDrawThreshold = 3; - /** - * Specifies whether and how a given region can be manipulated by the user (for instance, by panning or zooming). - * Used by Chrome 35> and IE10>. By default this makes the element blocking any touch event. - * @property defaults.behavior.touchAction - * @type {String} - * @default: 'pan-y' - */ - touchAction: 'pan-y', + // set defaults for the properties + this.id = undefined; + this.allowedToMoveX = false; + this.allowedToMoveY = false; + this.xFixed = false; + this.yFixed = false; + this.horizontalAlignLeft = true; // these are for the navigation controls + this.verticalAlignTop = true; // these are for the navigation controls + this.baseRadiusValue = networkConstants.nodes.radius; + this.radiusFixed = false; + this.level = -1; + this.preassignedLevel = false; + this.hierarchyEnumerated = false; + this.labelDimensions = {top:0, left:0, width:0, height:0, yLine:0}; // could be cached + this.boundingBox = {top:0, left:0, right:0, bottom:0}; - /** - * Disables the default callout shown when you touch and hold a touch target. - * On iOS, when you touch and hold a touch target such as a link, Safari displays - * a callout containing information about the link. This property allows you to disable that callout. - * @property defaults.behavior.touchCallout - * @type {String} - * @default 'none' - */ - touchCallout: 'none', + this.imagelist = imagelist; + this.grouplist = grouplist; - /** - * Specifies whether zooming is enabled. Used by IE10> - * @property defaults.behavior.contentZooming - * @type {String} - * @default 'none' - */ - contentZooming: 'none', + // physics properties + this.fx = 0.0; // external force x + this.fy = 0.0; // external force y + this.vx = 0.0; // velocity x + this.vy = 0.0; // velocity y + this.x = null; + this.y = null; - /** - * Specifies that an entire element should be draggable instead of its contents. - * Mainly for desktop browsers. - * @property defaults.behavior.userDrag - * @type {String} - * @default 'none' - */ - userDrag: 'none', + // used for reverting to previous position on stabilization + this.previousState = {vx:0,vy:0,x:0,y:0}; - /** - * Overrides the highlight color shown when the user taps a link or a JavaScript - * clickable element in Safari on iPhone. This property obeys the alpha value, if specified. - * - * If you don't specify an alpha value, Safari on iPhone applies a default alpha value - * to the color. To disable tap highlighting, set the alpha value to 0 (invisible). - * If you set the alpha value to 1.0 (opaque), the element is not visible when tapped. - * @property defaults.behavior.tapHighlightColor - * @type {String} - * @default 'rgba(0,0,0,0)' - */ - tapHighlightColor: 'rgba(0,0,0,0)' - } + this.damping = networkConstants.physics.damping; // written every time gravity is calculated + this.fixedData = {x:null,y:null}; + + this.setProperties(properties, constants); + + // creating the variables for clustering + this.resetCluster(); + this.dynamicEdgesLength = 0; + this.clusterSession = 0; + this.clusterSizeWidthFactor = networkConstants.clustering.nodeScaling.width; + this.clusterSizeHeightFactor = networkConstants.clustering.nodeScaling.height; + this.clusterSizeRadiusFactor = networkConstants.clustering.nodeScaling.radius; + this.maxNodeSizeIncrements = networkConstants.clustering.maxNodeSizeIncrements; + this.growthIndicator = 0; + + // variables to tell the node about the network. + this.networkScaleInv = 1; + this.networkScale = 1; + this.canvasTopLeft = {"x": -300, "y": -300}; + this.canvasBottomRight = {"x": 300, "y": 300}; + this.parentEdgeId = null; + } + + + /** + * Revert the position and velocity of the previous step. + */ + Node.prototype.revertPosition = function() { + this.x = this.previousState.x; + this.y = this.previousState.y; + this.vx = this.previousState.vx; + this.vy = this.previousState.vy; + } + + + /** + * (re)setting the clustering variables and objects + */ + Node.prototype.resetCluster = function() { + // clustering variables + this.formationScale = undefined; // this is used to determine when to open the cluster + this.clusterSize = 1; // this signifies the total amount of nodes in this cluster + this.containedNodes = {}; + this.containedEdges = {}; + this.clusterSessions = []; }; /** - * hammer document where the base events are added at - * @property DOCUMENT - * @type {HTMLElement} - * @default window.document + * Attach a edge to the node + * @param {Edge} edge */ - Hammer.DOCUMENT = document; + Node.prototype.attachEdge = function(edge) { + if (this.edges.indexOf(edge) == -1) { + this.edges.push(edge); + } + if (this.dynamicEdges.indexOf(edge) == -1) { + this.dynamicEdges.push(edge); + } + this.dynamicEdgesLength = this.dynamicEdges.length; + }; /** - * detect support for pointer events - * @property HAS_POINTEREVENTS - * @type {Boolean} + * Detach a edge from the node + * @param {Edge} edge */ - Hammer.HAS_POINTEREVENTS = navigator.pointerEnabled || navigator.msPointerEnabled; + Node.prototype.detachEdge = function(edge) { + var index = this.edges.indexOf(edge); + if (index != -1) { + this.edges.splice(index, 1); + } + index = this.dynamicEdges.indexOf(edge); + if (index != -1) { + this.dynamicEdges.splice(index, 1); + } + this.dynamicEdgesLength = this.dynamicEdges.length; + }; + /** - * detect support for touch events - * @property HAS_TOUCHEVENTS - * @type {Boolean} + * Set or overwrite properties for the node + * @param {Object} properties an object with properties + * @param {Object} constants and object with default, global properties */ - Hammer.HAS_TOUCHEVENTS = ('ontouchstart' in window); + Node.prototype.setProperties = function(properties, constants) { + if (!properties) { + return; + } + + var fields = ['borderWidth','borderWidthSelected','shape','image','brokenImage','radius','fontColor', + 'fontSize','fontFace','fontFill','fontStrokeWidth','fontStrokeColor','group','mass' + ]; + util.selectiveDeepExtend(fields, this.options, properties); + + // basic properties + if (properties.id !== undefined) {this.id = properties.id;} + if (properties.label !== undefined) {this.label = properties.label; this.originalLabel = properties.label;} + if (properties.title !== undefined) {this.title = properties.title;} + if (properties.x !== undefined) {this.x = properties.x;} + if (properties.y !== undefined) {this.y = properties.y;} + if (properties.value !== undefined) {this.value = properties.value;} + if (properties.level !== undefined) {this.level = properties.level; this.preassignedLevel = true;} + + // navigation controls properties + if (properties.horizontalAlignLeft !== undefined) {this.horizontalAlignLeft = properties.horizontalAlignLeft;} + if (properties.verticalAlignTop !== undefined) {this.verticalAlignTop = properties.verticalAlignTop;} + if (properties.triggerFunction !== undefined) {this.triggerFunction = properties.triggerFunction;} + + if (this.id === undefined) { + throw "Node must have an id"; + } + + // copy group properties + if (typeof this.options.group === 'number' || (typeof this.options.group === 'string' && this.options.group != '')) { + var groupObj = this.grouplist.get(this.options.group); + util.deepExtend(this.options, groupObj); + // the color object needs to be completely defined. Since groups can partially overwrite the colors, we parse it again, just in case. + this.options.color = util.parseColor(this.options.color); + } + + // individual shape properties + if (properties.radius !== undefined) {this.baseRadiusValue = this.options.radius;} + if (properties.color !== undefined) {this.options.color = util.parseColor(properties.color);} + if (this.options.image !== undefined && this.options.image!= "") { + if (this.imagelist) { + this.imageObj = this.imagelist.load(this.options.image, this.options.brokenImage); + } + else { + throw "No imagelist provided"; + } + } + + if (properties.allowedToMoveX !== undefined) { + this.xFixed = !properties.allowedToMoveX; + this.allowedToMoveX = properties.allowedToMoveX; + } + else if (properties.x !== undefined && this.allowedToMoveX == false) { + this.xFixed = true; + } + + + if (properties.allowedToMoveY !== undefined) { + this.yFixed = !properties.allowedToMoveY; + this.allowedToMoveY = properties.allowedToMoveY; + } + else if (properties.y !== undefined && this.allowedToMoveY == false) { + this.yFixed = true; + } + + this.radiusFixed = this.radiusFixed || (properties.radius !== undefined); + + if (this.options.shape === 'image' || this.options.shape === 'circularImage') { + this.options.radiusMin = constants.nodes.widthMin; + this.options.radiusMax = constants.nodes.widthMax; + } + + // choose draw method depending on the shape + switch (this.options.shape) { + case 'database': this.draw = this._drawDatabase; this.resize = this._resizeDatabase; break; + case 'box': this.draw = this._drawBox; this.resize = this._resizeBox; break; + case 'circle': this.draw = this._drawCircle; this.resize = this._resizeCircle; break; + case 'ellipse': this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break; + // TODO: add diamond shape + case 'image': this.draw = this._drawImage; this.resize = this._resizeImage; break; + case 'circularImage': this.draw = this._drawCircularImage; this.resize = this._resizeCircularImage; break; + case 'text': this.draw = this._drawText; this.resize = this._resizeText; break; + case 'dot': this.draw = this._drawDot; this.resize = this._resizeShape; break; + case 'square': this.draw = this._drawSquare; this.resize = this._resizeShape; break; + case 'triangle': this.draw = this._drawTriangle; this.resize = this._resizeShape; break; + case 'triangleDown': this.draw = this._drawTriangleDown; this.resize = this._resizeShape; break; + case 'star': this.draw = this._drawStar; this.resize = this._resizeShape; break; + default: this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break; + } + // reset the size of the node, this can be changed + this._reset(); + + }; /** - * detect mobile browsers - * @property IS_MOBILE - * @type {Boolean} + * select this node */ - Hammer.IS_MOBILE = /mobile|tablet|ip(ad|hone|od)|android|silk/i.test(navigator.userAgent); + Node.prototype.select = function() { + this.selected = true; + this._reset(); + }; /** - * detect if we want to support mouseevents at all - * @property NO_MOUSEEVENTS - * @type {Boolean} + * unselect this node */ - Hammer.NO_MOUSEEVENTS = (Hammer.HAS_TOUCHEVENTS && Hammer.IS_MOBILE) || Hammer.HAS_POINTEREVENTS; + Node.prototype.unselect = function() { + this.selected = false; + this._reset(); + }; + /** - * interval in which Hammer recalculates current velocity/direction/angle in ms - * @property CALCULATE_INTERVAL - * @type {Number} - * @default 25 + * Reset the calculated size of the node, forces it to recalculate its size */ - Hammer.CALCULATE_INTERVAL = 25; + Node.prototype.clearSizeCache = function() { + this._reset(); + }; /** - * eventtypes per touchevent (start, move, end) are filled by `Event.determineEventTypes` on `setup` - * the object contains the DOM event names per type (`EVENT_START`, `EVENT_MOVE`, `EVENT_END`) - * @property EVENT_TYPES + * Reset the calculated size of the node, forces it to recalculate its size * @private - * @writeOnce - * @type {Object} */ - var EVENT_TYPES = {}; + Node.prototype._reset = function() { + this.width = undefined; + this.height = undefined; + }; /** - * direction strings, for safe comparisons - * @property DIRECTION_DOWN|LEFT|UP|RIGHT - * @final - * @type {String} - * @default 'down' 'left' 'up' 'right' + * get the title of this node. + * @return {string} title The title of the node, or undefined when no title + * has been set. */ - var DIRECTION_DOWN = Hammer.DIRECTION_DOWN = 'down'; - var DIRECTION_LEFT = Hammer.DIRECTION_LEFT = 'left'; - var DIRECTION_UP = Hammer.DIRECTION_UP = 'up'; - var DIRECTION_RIGHT = Hammer.DIRECTION_RIGHT = 'right'; + Node.prototype.getTitle = function() { + return typeof this.title === "function" ? this.title() : this.title; + }; /** - * pointertype strings, for safe comparisons - * @property POINTER_MOUSE|TOUCH|PEN - * @final - * @type {String} - * @default 'mouse' 'touch' 'pen' + * Calculate the distance to the border of the Node + * @param {CanvasRenderingContext2D} ctx + * @param {Number} angle Angle in radians + * @returns {number} distance Distance to the border in pixels */ - var POINTER_MOUSE = Hammer.POINTER_MOUSE = 'mouse'; - var POINTER_TOUCH = Hammer.POINTER_TOUCH = 'touch'; - var POINTER_PEN = Hammer.POINTER_PEN = 'pen'; + Node.prototype.distanceToBorder = function (ctx, angle) { + var borderWidth = 1; - /** - * eventtypes - * @property EVENT_START|MOVE|END|RELEASE|TOUCH - * @final - * @type {String} - * @default 'start' 'change' 'move' 'end' 'release' 'touch' - */ - var EVENT_START = Hammer.EVENT_START = 'start'; - var EVENT_MOVE = Hammer.EVENT_MOVE = 'move'; - var EVENT_END = Hammer.EVENT_END = 'end'; - var EVENT_RELEASE = Hammer.EVENT_RELEASE = 'release'; - var EVENT_TOUCH = Hammer.EVENT_TOUCH = 'touch'; + if (!this.width) { + this.resize(ctx); + } - /** - * if the window events are set... - * @property READY - * @writeOnce - * @type {Boolean} - * @default false - */ - Hammer.READY = false; + switch (this.options.shape) { + case 'circle': + case 'dot': + return this.options.radius+ borderWidth; - /** - * plugins namespace - * @property plugins - * @type {Object} - */ - Hammer.plugins = Hammer.plugins || {}; + case 'ellipse': + var a = this.width / 2; + var b = this.height / 2; + var w = (Math.sin(angle) * a); + var h = (Math.cos(angle) * b); + return a * b / Math.sqrt(w * w + h * h); + + // TODO: implement distanceToBorder for database + // TODO: implement distanceToBorder for triangle + // TODO: implement distanceToBorder for triangleDown + + case 'box': + case 'image': + case 'text': + default: + if (this.width) { + return Math.min( + Math.abs(this.width / 2 / Math.cos(angle)), + Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth; + // TODO: reckon with border radius too in case of box + } + else { + return 0; + } + + } + // TODO: implement calculation of distance to border for all shapes + }; /** - * gestures namespace - * see `/gestures` for the definitions - * @property gestures - * @type {Object} + * Set forces acting on the node + * @param {number} fx Force in horizontal direction + * @param {number} fy Force in vertical direction */ - Hammer.gestures = Hammer.gestures || {}; + Node.prototype._setForce = function(fx, fy) { + this.fx = fx; + this.fy = fy; + }; /** - * setup events to detect gestures on the document - * this function is called when creating an new instance + * Add forces acting on the node + * @param {number} fx Force in horizontal direction + * @param {number} fy Force in vertical direction * @private */ - function setup() { - if(Hammer.READY) { - return; - } - - // find what eventtypes we add listeners to - Event.determineEventTypes(); - - // Register all gestures inside Hammer.gestures - Utils.each(Hammer.gestures, function(gesture) { - Detection.register(gesture); - }); - - // Add touch events on the document - Event.onTouch(Hammer.DOCUMENT, EVENT_MOVE, Detection.detect); - Event.onTouch(Hammer.DOCUMENT, EVENT_END, Detection.detect); + Node.prototype._addForce = function(fx, fy) { + this.fx += fx; + this.fy += fy; + }; - // Hammer is ready...! - Hammer.READY = true; + /** + * Store the state before the next step + */ + Node.prototype.storeState = function() { + this.previousState.x = this.x; + this.previousState.y = this.y; + this.previousState.vx = this.vx; + this.previousState.vy = this.vy; } /** - * @module hammer - * - * @class Utils - * @static + * Perform one discrete step for the node + * @param {number} interval Time interval in seconds */ - var Utils = Hammer.utils = { - /** - * extend method, could also be used for cloning when `dest` is an empty object. - * changes the dest object - * @method extend - * @param {Object} dest - * @param {Object} src - * @param {Boolean} [merge=false] do a merge - * @return {Object} dest - */ - extend: function extend(dest, src, merge) { - for(var key in src) { - if(!src.hasOwnProperty(key) || (dest[key] !== undefined && merge)) { - continue; - } - dest[key] = src[key]; - } - return dest; - }, - - /** - * simple addEventListener wrapper - * @method on - * @param {HTMLElement} element - * @param {String} type - * @param {Function} handler - */ - on: function on(element, type, handler) { - element.addEventListener(type, handler, false); - }, + Node.prototype.discreteStep = function(interval) { + this.storeState(); + if (!this.xFixed) { + var dx = this.damping * this.vx; // damping force + var ax = (this.fx - dx) / this.options.mass; // acceleration + this.vx += ax * interval; // velocity + this.x += this.vx * interval; // position + } + else { + this.fx = 0; + this.vx = 0; + } - /** - * simple removeEventListener wrapper - * @method off - * @param {HTMLElement} element - * @param {String} type - * @param {Function} handler - */ - off: function off(element, type, handler) { - element.removeEventListener(type, handler, false); - }, + if (!this.yFixed) { + var dy = this.damping * this.vy; // damping force + var ay = (this.fy - dy) / this.options.mass; // acceleration + this.vy += ay * interval; // velocity + this.y += this.vy * interval; // position + } + else { + this.fy = 0; + this.vy = 0; + } + }; - /** - * forEach over arrays and objects - * @method each - * @param {Object|Array} obj - * @param {Function} iterator - * @param {any} iterator.item - * @param {Number} iterator.index - * @param {Object|Array} iterator.obj the source object - * @param {Object} context value to use as `this` in the iterator - */ - each: function each(obj, iterator, context) { - var i, len; - // native forEach on arrays - if('forEach' in obj) { - obj.forEach(iterator, context); - // arrays - } else if(obj.length !== undefined) { - for(i = 0, len = obj.length; i < len; i++) { - if(iterator.call(context, obj[i], i, obj) === false) { - return; - } - } - // objects - } else { - for(i in obj) { - if(obj.hasOwnProperty(i) && - iterator.call(context, obj[i], i, obj) === false) { - return; - } - } - } - }, - /** - * find if a string contains the string using indexOf - * @method inStr - * @param {String} src - * @param {String} find - * @return {Boolean} found - */ - inStr: function inStr(src, find) { - return src.indexOf(find) > -1; - }, + /** + * Perform one discrete step for the node + * @param {number} interval Time interval in seconds + * @param {number} maxVelocity The speed limit imposed on the velocity + */ + Node.prototype.discreteStepLimited = function(interval, maxVelocity) { + this.storeState(); + if (!this.xFixed) { + var dx = this.damping * this.vx; // damping force + var ax = (this.fx - dx) / this.options.mass; // acceleration + this.vx += ax * interval; // velocity + this.vx = (Math.abs(this.vx) > maxVelocity) ? ((this.vx > 0) ? maxVelocity : -maxVelocity) : this.vx; + this.x += this.vx * interval; // position + } + else { + this.fx = 0; + this.vx = 0; + } - /** - * find if a array contains the object using indexOf or a simple polyfill - * @method inArray - * @param {String} src - * @param {String} find - * @return {Boolean|Number} false when not found, or the index - */ - inArray: function inArray(src, find) { - if(src.indexOf) { - var index = src.indexOf(find); - return (index === -1) ? false : index; - } else { - for(var i = 0, len = src.length; i < len; i++) { - if(src[i] === find) { - return i; - } - } - return false; - } - }, + if (!this.yFixed) { + var dy = this.damping * this.vy; // damping force + var ay = (this.fy - dy) / this.options.mass; // acceleration + this.vy += ay * interval; // velocity + this.vy = (Math.abs(this.vy) > maxVelocity) ? ((this.vy > 0) ? maxVelocity : -maxVelocity) : this.vy; + this.y += this.vy * interval; // position + } + else { + this.fy = 0; + this.vy = 0; + } + }; - /** - * convert an array-like object (`arguments`, `touchlist`) to an array - * @method toArray - * @param {Object} obj - * @return {Array} - */ - toArray: function toArray(obj) { - return Array.prototype.slice.call(obj, 0); - }, + /** + * Check if this node has a fixed x and y position + * @return {boolean} true if fixed, false if not + */ + Node.prototype.isFixed = function() { + return (this.xFixed && this.yFixed); + }; - /** - * find if a node is in the given parent - * @method hasParent - * @param {HTMLElement} node - * @param {HTMLElement} parent - * @return {Boolean} found - */ - hasParent: function hasParent(node, parent) { - while(node) { - if(node == parent) { - return true; - } - node = node.parentNode; - } - return false; - }, + /** + * Check if this node is moving + * @param {number} vmin the minimum velocity considered as "moving" + * @return {boolean} true if moving, false if it has no velocity + */ + Node.prototype.isMoving = function(vmin) { + var velocity = Math.sqrt(Math.pow(this.vx,2) + Math.pow(this.vy,2)); + // this.velocity = Math.sqrt(Math.pow(this.vx,2) + Math.pow(this.vy,2)) + return (velocity > vmin); + }; - /** - * get the center of all the touches - * @method getCenter - * @param {Array} touches - * @return {Object} center contains `pageX`, `pageY`, `clientX` and `clientY` properties - */ - getCenter: function getCenter(touches) { - var pageX = [], - pageY = [], - clientX = [], - clientY = [], - min = Math.min, - max = Math.max; + /** + * check if this node is selecte + * @return {boolean} selected True if node is selected, else false + */ + Node.prototype.isSelected = function() { + return this.selected; + }; - // no need to loop when only one touch - if(touches.length === 1) { - return { - pageX: touches[0].pageX, - pageY: touches[0].pageY, - clientX: touches[0].clientX, - clientY: touches[0].clientY - }; - } + /** + * Retrieve the value of the node. Can be undefined + * @return {Number} value + */ + Node.prototype.getValue = function() { + return this.value; + }; - Utils.each(touches, function(touch) { - pageX.push(touch.pageX); - pageY.push(touch.pageY); - clientX.push(touch.clientX); - clientY.push(touch.clientY); - }); + /** + * Calculate the distance from the nodes location to the given location (x,y) + * @param {Number} x + * @param {Number} y + * @return {Number} value + */ + Node.prototype.getDistance = function(x, y) { + var dx = this.x - x, + dy = this.y - y; + return Math.sqrt(dx * dx + dy * dy); + }; - return { - pageX: (min.apply(Math, pageX) + max.apply(Math, pageX)) / 2, - pageY: (min.apply(Math, pageY) + max.apply(Math, pageY)) / 2, - clientX: (min.apply(Math, clientX) + max.apply(Math, clientX)) / 2, - clientY: (min.apply(Math, clientY) + max.apply(Math, clientY)) / 2 - }; - }, - /** - * calculate the velocity between two points. unit is in px per ms. - * @method getVelocity - * @param {Number} deltaTime - * @param {Number} deltaX - * @param {Number} deltaY - * @return {Object} velocity `x` and `y` - */ - getVelocity: function getVelocity(deltaTime, deltaX, deltaY) { - return { - x: Math.abs(deltaX / deltaTime) || 0, - y: Math.abs(deltaY / deltaTime) || 0 - }; - }, + /** + * Adjust the value range of the node. The node will adjust it's radius + * based on its value. + * @param {Number} min + * @param {Number} max + */ + Node.prototype.setValueRange = function(min, max) { + if (!this.radiusFixed && this.value !== undefined) { + if (max == min) { + this.options.radius= (this.options.radiusMin + this.options.radiusMax) / 2; + } + else { + var scale = (this.options.radiusMax - this.options.radiusMin) / (max - min); + this.options.radius= (this.value - min) * scale + this.options.radiusMin; + } + } + this.baseRadiusValue = this.options.radius; + }; - /** - * calculate the angle between two coordinates - * @method getAngle - * @param {Touch} touch1 - * @param {Touch} touch2 - * @return {Number} angle - */ - getAngle: function getAngle(touch1, touch2) { - var x = touch2.clientX - touch1.clientX, - y = touch2.clientY - touch1.clientY; + /** + * Draw this node in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + */ + Node.prototype.draw = function(ctx) { + throw "Draw method not initialized for node"; + }; - return Math.atan2(y, x) * 180 / Math.PI; - }, + /** + * Recalculate the size of this node in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + */ + Node.prototype.resize = function(ctx) { + throw "Resize method not initialized for node"; + }; - /** - * do a small comparision to get the direction between two touches. - * @method getDirection - * @param {Touch} touch1 - * @param {Touch} touch2 - * @return {String} direction matches `DIRECTION_LEFT|RIGHT|UP|DOWN` - */ - getDirection: function getDirection(touch1, touch2) { - var x = Math.abs(touch1.clientX - touch2.clientX), - y = Math.abs(touch1.clientY - touch2.clientY); + /** + * Check if this object is overlapping with the provided object + * @param {Object} obj an object with parameters left, top, right, bottom + * @return {boolean} True if location is located on node + */ + Node.prototype.isOverlappingWith = function(obj) { + return (this.left < obj.right && + this.left + this.width > obj.left && + this.top < obj.bottom && + this.top + this.height > obj.top); + }; - if(x >= y) { - return touch1.clientX - touch2.clientX > 0 ? DIRECTION_LEFT : DIRECTION_RIGHT; - } - return touch1.clientY - touch2.clientY > 0 ? DIRECTION_UP : DIRECTION_DOWN; - }, + Node.prototype._resizeImage = function (ctx) { + // TODO: pre calculate the image size - /** - * calculate the distance between two touches - * @method getDistance - * @param {Touch}touch1 - * @param {Touch} touch2 - * @return {Number} distance - */ - getDistance: function getDistance(touch1, touch2) { - var x = touch2.clientX - touch1.clientX, - y = touch2.clientY - touch1.clientY; + if (!this.width || !this.height) { // undefined or 0 + var width, height; + if (this.value) { + this.options.radius= this.baseRadiusValue; + var scale = this.imageObj.height / this.imageObj.width; + if (scale !== undefined) { + width = this.options.radius|| this.imageObj.width; + height = this.options.radius* scale || this.imageObj.height; + } + else { + width = 0; + height = 0; + } + } + else { + width = this.imageObj.width; + height = this.imageObj.height; + } + this.width = width; + this.height = height; - return Math.sqrt((x * x) + (y * y)); - }, + this.growthIndicator = 0; + if (this.width > 0 && this.height > 0) { + this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; + this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; + this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor; + this.growthIndicator = this.width - width; + } + } + }; - /** - * calculate the scale factor between two touchLists - * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out - * @method getScale - * @param {Array} start array of touches - * @param {Array} end array of touches - * @return {Number} scale - */ - getScale: function getScale(start, end) { - // need two fingers... - if(start.length >= 2 && end.length >= 2) { - return this.getDistance(end[0], end[1]) / this.getDistance(start[0], start[1]); - } - return 1; - }, + Node.prototype._drawImageAtPosition = function (ctx) { + if (this.imageObj.width != 0 ) { + // draw the shade + if (this.clusterSize > 1) { + var lineWidth = ((this.clusterSize > 1) ? 10 : 0.0); + lineWidth *= this.networkScaleInv; + lineWidth = Math.min(0.2 * this.width,lineWidth); - /** - * calculate the rotation degrees between two touchLists - * @method getRotation - * @param {Array} start array of touches - * @param {Array} end array of touches - * @return {Number} rotation - */ - getRotation: function getRotation(start, end) { - // need two fingers - if(start.length >= 2 && end.length >= 2) { - return this.getAngle(end[1], end[0]) - this.getAngle(start[1], start[0]); - } - return 0; - }, + ctx.globalAlpha = 0.5; + ctx.drawImage(this.imageObj, this.left - lineWidth, this.top - lineWidth, this.width + 2*lineWidth, this.height + 2*lineWidth); + } - /** - * find out if the direction is vertical * - * @method isVertical - * @param {String} direction matches `DIRECTION_UP|DOWN` - * @return {Boolean} is_vertical - */ - isVertical: function isVertical(direction) { - return direction == DIRECTION_UP || direction == DIRECTION_DOWN; - }, + // draw the image + ctx.globalAlpha = 1.0; + ctx.drawImage(this.imageObj, this.left, this.top, this.width, this.height); + } + }; - /** - * set css properties with their prefixes - * @param {HTMLElement} element - * @param {String} prop - * @param {String} value - * @param {Boolean} [toggle=true] - * @return {Boolean} - */ - setPrefixedCss: function setPrefixedCss(element, prop, value, toggle) { - var prefixes = ['', 'Webkit', 'Moz', 'O', 'ms']; - prop = Utils.toCamelCase(prop); + Node.prototype._drawImageLabel = function (ctx) { + var yLabel; + var offset = 0; + + if (this.height){ + offset = this.height / 2; + var labelDimensions = this.getTextSize(ctx); + + if (labelDimensions.lineCount >= 1){ + offset += labelDimensions.height / 2; + offset += 3; + } + } + + yLabel = this.y + offset; - for(var i = 0; i < prefixes.length; i++) { - var p = prop; - // prefixes - if(prefixes[i]) { - p = prefixes[i] + p.slice(0, 1).toUpperCase() + p.slice(1); - } + this._label(ctx, this.label, this.x, yLabel, undefined); + }; - // test the style - if(p in element.style) { - element.style[p] = (toggle == null || toggle) && value || ''; - break; - } - } - }, + Node.prototype._drawImage = function (ctx) { + this._resizeImage(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; - /** - * toggle browser default behavior by setting css properties. - * `userSelect='none'` also sets `element.onselectstart` to false - * `userDrag='none'` also sets `element.ondragstart` to false - * - * @method toggleBehavior - * @param {HtmlElement} element - * @param {Object} props - * @param {Boolean} [toggle=true] - */ - toggleBehavior: function toggleBehavior(element, props, toggle) { - if(!props || !element || !element.style) { - return; - } + this._drawImageAtPosition(ctx); - // set the css properties - Utils.each(props, function(value, prop) { - Utils.setPrefixedCss(element, prop, value, toggle); - }); + this.boundingBox.top = this.top; + this.boundingBox.left = this.left; + this.boundingBox.right = this.left + this.width; + this.boundingBox.bottom = this.top + this.height; - var falseFn = toggle && function() { - return false; - }; + this._drawImageLabel(ctx); + this.boundingBox.left = Math.min(this.boundingBox.left, this.labelDimensions.left); + this.boundingBox.right = Math.max(this.boundingBox.right, this.labelDimensions.left + this.labelDimensions.width); + this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelDimensions.height); + }; - // also the disable onselectstart - if(props.userSelect == 'none') { - element.onselectstart = falseFn; - } - // and disable ondragstart - if(props.userDrag == 'none') { - element.ondragstart = falseFn; - } - }, + Node.prototype._resizeCircularImage = function (ctx) { + if(!this.imageObj.src || !this.imageObj.width || !this.imageObj.height){ + if (!this.width) { + var diameter = this.options.radius * 2; + this.width = diameter; + this.height = diameter; - /** - * convert a string with underscores to camelCase - * so prevent_default becomes preventDefault - * @param {String} str - * @return {String} camelCaseStr - */ - toCamelCase: function toCamelCase(str) { - return str.replace(/[_-]([a-z])/g, function(s) { - return s[1].toUpperCase(); - }); + // scaling used for clustering + //this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor; + //this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor; + this.options.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor; + this.growthIndicator = this.options.radius- 0.5*diameter; + this._swapToImageResizeWhenImageLoaded = true; + } + } + else { + if (this._swapToImageResizeWhenImageLoaded) { + this.width = 0; + this.height = 0; + delete this._swapToImageResizeWhenImageLoaded; } + this._resizeImage(ctx); + } + }; + Node.prototype._drawCircularImage = function (ctx) { + this._resizeCircularImage(ctx); - /** - * @module hammer - */ - /** - * @class Event - * @static - */ - var Event = Hammer.event = { - /** - * when touch events have been fired, this is true - * this is used to stop mouse events - * @property prevent_mouseevents - * @private - * @type {Boolean} - */ - preventMouseEvents: false, + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + var centerX = this.left + (this.width / 2); + var centerY = this.top + (this.height / 2); + var radius = Math.abs(this.height / 2); - /** - * if EVENT_START has been fired - * @property started - * @private - * @type {Boolean} - */ - started: false, + this._drawRawCircle(ctx, centerX, centerY, radius); - /** - * when the mouse is hold down, this is true - * @property should_detect - * @private - * @type {Boolean} - */ - shouldDetect: false, + ctx.save(); + ctx.circle(this.x, this.y, radius); + ctx.stroke(); + ctx.clip(); - /** - * simple event binder with a hook and support for multiple types - * @method on - * @param {HTMLElement} element - * @param {String} type - * @param {Function} handler - * @param {Function} [hook] - * @param {Object} hook.type - */ - on: function on(element, type, handler, hook) { - var types = type.split(' '); - Utils.each(types, function(type) { - Utils.on(element, type, handler); - hook && hook(type); - }); - }, + this._drawImageAtPosition(ctx); - /** - * simple event unbinder with a hook and support for multiple types - * @method off - * @param {HTMLElement} element - * @param {String} type - * @param {Function} handler - * @param {Function} [hook] - * @param {Object} hook.type - */ - off: function off(element, type, handler, hook) { - var types = type.split(' '); - Utils.each(types, function(type) { - Utils.off(element, type, handler); - hook && hook(type); - }); - }, + ctx.restore(); - /** - * the core touch event handler. - * this finds out if we should to detect gestures - * @method onTouch - * @param {HTMLElement} element - * @param {String} eventType matches `EVENT_START|MOVE|END` - * @param {Function} handler - * @return onTouchHandler {Function} the core event handler - */ - onTouch: function onTouch(element, eventType, handler) { - var self = this; + this.boundingBox.top = this.y - this.options.radius; + this.boundingBox.left = this.x - this.options.radius; + this.boundingBox.right = this.x + this.options.radius; + this.boundingBox.bottom = this.y + this.options.radius; - var onTouchHandler = function onTouchHandler(ev) { - var srcType = ev.type.toLowerCase(), - isPointer = Hammer.HAS_POINTEREVENTS, - isMouse = Utils.inStr(srcType, 'mouse'), - triggerType; + this._drawImageLabel(ctx); + + this.boundingBox.left = Math.min(this.boundingBox.left, this.labelDimensions.left); + this.boundingBox.right = Math.max(this.boundingBox.right, this.labelDimensions.left + this.labelDimensions.width); + this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelDimensions.height); + }; - // if we are in a mouseevent, but there has been a touchevent triggered in this session - // we want to do nothing. simply break out of the event. - if(isMouse && self.preventMouseEvents) { - return; + Node.prototype._resizeBox = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + this.width = textSize.width + 2 * margin; + this.height = textSize.height + 2 * margin; - // mousebutton must be down - } else if(isMouse && eventType == EVENT_START && ev.button === 0) { - self.preventMouseEvents = false; - self.shouldDetect = true; - } else if(isPointer && eventType == EVENT_START) { - self.shouldDetect = (ev.buttons === 1 || PointerEvent.matchType(POINTER_TOUCH, ev)); - // just a valid start event, but no mouse - } else if(!isMouse && eventType == EVENT_START) { - self.preventMouseEvents = true; - self.shouldDetect = true; - } + this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor; + this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor; + this.growthIndicator = this.width - (textSize.width + 2 * margin); + // this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor; - // update the pointer event before entering the detection - if(isPointer && eventType != EVENT_END) { - PointerEvent.updatePointer(eventType, ev); - } + } + }; + + Node.prototype._drawBox = function (ctx) { + this._resizeBox(ctx); + + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + var clusterLineWidth = 2.5; + var borderWidth = this.options.borderWidth; + var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; + + ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; + + // draw the outer border + if (this.clusterSize > 1) { + ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.networkScaleInv; + ctx.lineWidth = Math.min(this.width,ctx.lineWidth); - // we are in a touch/down state, so allowed detection of gestures - if(self.shouldDetect) { - triggerType = self.doDetect.call(self, ev, eventType, element, handler); - } + ctx.roundRect(this.left-2*ctx.lineWidth, this.top-2*ctx.lineWidth, this.width+4*ctx.lineWidth, this.height+4*ctx.lineWidth, this.options.radius); + ctx.stroke(); + } + ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.networkScaleInv; + ctx.lineWidth = Math.min(this.width,ctx.lineWidth); - // ...and we are done with the detection - // so reset everything to start each detection totally fresh - if(triggerType == EVENT_END) { - self.preventMouseEvents = false; - self.shouldDetect = false; - PointerEvent.reset(); - // update the pointerevent object after the detection - } + ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; - if(isPointer && eventType == EVENT_END) { - PointerEvent.updatePointer(eventType, ev); - } - }; + ctx.roundRect(this.left, this.top, this.width, this.height, this.options.radius); + ctx.fill(); + ctx.stroke(); - this.on(element, EVENT_TYPES[eventType], onTouchHandler); - return onTouchHandler; - }, + this.boundingBox.top = this.top; + this.boundingBox.left = this.left; + this.boundingBox.right = this.left + this.width; + this.boundingBox.bottom = this.top + this.height; - /** - * the core detection method - * this finds out what hammer-touch-events to trigger - * @method doDetect - * @param {Object} ev - * @param {String} eventType matches `EVENT_START|MOVE|END` - * @param {HTMLElement} element - * @param {Function} handler - * @return {String} triggerType matches `EVENT_START|MOVE|END` - */ - doDetect: function doDetect(ev, eventType, element, handler) { - var touchList = this.getTouchList(ev, eventType); - var touchListLength = touchList.length; - var triggerType = eventType; - var triggerChange = touchList.trigger; // used by fakeMultitouch plugin - var changedLength = touchListLength; + this._label(ctx, this.label, this.x, this.y); + }; - // at each touchstart-like event we want also want to trigger a TOUCH event... - if(eventType == EVENT_START) { - triggerChange = EVENT_TOUCH; - // ...the same for a touchend-like event - } else if(eventType == EVENT_END) { - triggerChange = EVENT_RELEASE; - // keep track of how many touches have been removed - changedLength = touchList.length - ((ev.changedTouches) ? ev.changedTouches.length : 1); - } + Node.prototype._resizeDatabase = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + var size = textSize.width + 2 * margin; + this.width = size; + this.height = size; - // after there are still touches on the screen, - // we just want to trigger a MOVE event. so change the START or END to a MOVE - // but only after detection has been started, the first time we actualy want a START - if(changedLength > 0 && this.started) { - triggerType = EVENT_MOVE; - } + // scaling used for clustering + this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; + this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; + this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor; + this.growthIndicator = this.width - size; + } + }; - // detection has been started, we keep track of this, see above - this.started = true; + Node.prototype._drawDatabase = function (ctx) { + this._resizeDatabase(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; - // generate some event data, some basic information - var evData = this.collectEventData(element, triggerType, touchList, ev); + var clusterLineWidth = 2.5; + var borderWidth = this.options.borderWidth; + var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; - // trigger the triggerType event before the change (TOUCH, RELEASE) events - // but the END event should be at last - if(eventType != EVENT_END) { - handler.call(Detection, evData); - } + ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; - // trigger a change (TOUCH, RELEASE) event, this means the length of the touches changed - if(triggerChange) { - evData.changedLength = changedLength; - evData.eventType = triggerChange; + // draw the outer border + if (this.clusterSize > 1) { + ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.networkScaleInv; + ctx.lineWidth = Math.min(this.width,ctx.lineWidth); - handler.call(Detection, evData); + ctx.database(this.x - this.width/2 - 2*ctx.lineWidth, this.y - this.height*0.5 - 2*ctx.lineWidth, this.width + 4*ctx.lineWidth, this.height + 4*ctx.lineWidth); + ctx.stroke(); + } + ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.networkScaleInv; + ctx.lineWidth = Math.min(this.width,ctx.lineWidth); - evData.eventType = triggerType; - delete evData.changedLength; - } + ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; + ctx.database(this.x - this.width/2, this.y - this.height*0.5, this.width, this.height); + ctx.fill(); + ctx.stroke(); - // trigger the END event - if(triggerType == EVENT_END) { - handler.call(Detection, evData); + this.boundingBox.top = this.top; + this.boundingBox.left = this.left; + this.boundingBox.right = this.left + this.width; + this.boundingBox.bottom = this.top + this.height; - // ...and we are done with the detection - // so reset everything to start each detection totally fresh - this.started = false; - } + this._label(ctx, this.label, this.x, this.y); + }; - return triggerType; - }, - /** - * we have different events for each device/browser - * determine what we need and set them in the EVENT_TYPES constant - * the `onTouch` method is bind to these properties. - * @method determineEventTypes - * @return {Object} events - */ - determineEventTypes: function determineEventTypes() { - var types; - if(Hammer.HAS_POINTEREVENTS) { - if(window.PointerEvent) { - types = [ - 'pointerdown', - 'pointermove', - 'pointerup pointercancel lostpointercapture' - ]; - } else { - types = [ - 'MSPointerDown', - 'MSPointerMove', - 'MSPointerUp MSPointerCancel MSLostPointerCapture' - ]; - } - } else if(Hammer.NO_MOUSEEVENTS) { - types = [ - 'touchstart', - 'touchmove', - 'touchend touchcancel' - ]; - } else { - types = [ - 'touchstart mousedown', - 'touchmove mousemove', - 'touchend touchcancel mouseup' - ]; - } + Node.prototype._resizeCircle = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + var diameter = Math.max(textSize.width, textSize.height) + 2 * margin; + this.options.radius = diameter / 2; - EVENT_TYPES[EVENT_START] = types[0]; - EVENT_TYPES[EVENT_MOVE] = types[1]; - EVENT_TYPES[EVENT_END] = types[2]; - return EVENT_TYPES; - }, + this.width = diameter; + this.height = diameter; - /** - * create touchList depending on the event - * @method getTouchList - * @param {Object} ev - * @param {String} eventType - * @return {Array} touches - */ - getTouchList: function getTouchList(ev, eventType) { - // get the fake pointerEvent touchlist - if(Hammer.HAS_POINTEREVENTS) { - return PointerEvent.getTouchList(); - } + // scaling used for clustering + // this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor; + // this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor; + this.options.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor; + this.growthIndicator = this.options.radius- 0.5*diameter; + } + }; - // get the touchlist - if(ev.touches) { - if(eventType == EVENT_MOVE) { - return ev.touches; - } + Node.prototype._drawRawCircle = function (ctx, x, y, radius) { + var clusterLineWidth = 2.5; + var borderWidth = this.options.borderWidth; + var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; + + ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; - var identifiers = []; - var concat = [].concat(Utils.toArray(ev.touches), Utils.toArray(ev.changedTouches)); - var touchList = []; + // draw the outer border + if (this.clusterSize > 1) { + ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.networkScaleInv; + ctx.lineWidth = Math.min(this.width,ctx.lineWidth); - Utils.each(concat, function(touch) { - if(Utils.inArray(identifiers, touch.identifier) === false) { - touchList.push(touch); - } - identifiers.push(touch.identifier); - }); + ctx.circle(x, y, radius+2*ctx.lineWidth); + ctx.stroke(); + } + ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.networkScaleInv; + ctx.lineWidth = Math.min(this.width,ctx.lineWidth); - return touchList; - } + ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; + ctx.circle(this.x, this.y, radius); + ctx.fill(); + ctx.stroke(); + }; - // make fake touchList from mouse position - ev.identifier = 1; - return [ev]; - }, + Node.prototype._drawCircle = function (ctx) { + this._resizeCircle(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; - /** - * collect basic event data - * @method collectEventData - * @param {HTMLElement} element - * @param {String} eventType matches `EVENT_START|MOVE|END` - * @param {Array} touches - * @param {Object} ev - * @return {Object} ev - */ - collectEventData: function collectEventData(element, eventType, touches, ev) { - // find out pointerType - var pointerType = POINTER_TOUCH; - if(Utils.inStr(ev.type, 'mouse') || PointerEvent.matchType(POINTER_MOUSE, ev)) { - pointerType = POINTER_MOUSE; - } else if(PointerEvent.matchType(POINTER_PEN, ev)) { - pointerType = POINTER_PEN; - } + this._drawRawCircle(ctx, this.x, this.y, this.options.radius); - return { - center: Utils.getCenter(touches), - timeStamp: Date.now(), - target: ev.target, - touches: touches, - eventType: eventType, - pointerType: pointerType, - srcEvent: ev, + this.boundingBox.top = this.y - this.options.radius; + this.boundingBox.left = this.x - this.options.radius; + this.boundingBox.right = this.x + this.options.radius; + this.boundingBox.bottom = this.y + this.options.radius; - /** - * prevent the browser default actions - * mostly used to disable scrolling of the browser - */ - preventDefault: function() { - var srcEvent = this.srcEvent; - srcEvent.preventManipulation && srcEvent.preventManipulation(); - srcEvent.preventDefault && srcEvent.preventDefault(); - }, + this._label(ctx, this.label, this.x, this.y); + }; - /** - * stop bubbling the event up to its parents - */ - stopPropagation: function() { - this.srcEvent.stopPropagation(); - }, + Node.prototype._resizeEllipse = function (ctx) { + if (!this.width) { + var textSize = this.getTextSize(ctx); - /** - * immediately stop gesture detection - * might be useful after a swipe was detected - * @return {*} - */ - stopDetect: function() { - return Detection.stopDetect(); - } - }; + this.width = textSize.width * 1.5; + this.height = textSize.height * 2; + if (this.width < this.height) { + this.width = this.height; } + var defaultSize = this.width; + + // scaling used for clustering + this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; + this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; + this.options.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor; + this.growthIndicator = this.width - defaultSize; + } }; + Node.prototype._drawEllipse = function (ctx) { + this._resizeEllipse(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; - /** - * @module hammer - * - * @class PointerEvent - * @static - */ - var PointerEvent = Hammer.PointerEvent = { - /** - * holds all pointers, by `identifier` - * @property pointers - * @type {Object} - */ - pointers: {}, + var clusterLineWidth = 2.5; + var borderWidth = this.options.borderWidth; + var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; - /** - * get the pointers as an array - * @method getTouchList - * @return {Array} touchlist - */ - getTouchList: function getTouchList() { - var touchlist = []; - // we can use forEach since pointerEvents only is in IE10 - Utils.each(this.pointers, function(pointer) { - touchlist.push(pointer); - }); - return touchlist; - }, + ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; - /** - * update the position of a pointer - * @method updatePointer - * @param {String} eventType matches `EVENT_START|MOVE|END` - * @param {Object} pointerEvent - */ - updatePointer: function updatePointer(eventType, pointerEvent) { - if(eventType == EVENT_END || (eventType != EVENT_END && pointerEvent.buttons !== 1)) { - delete this.pointers[pointerEvent.pointerId]; - } else { - pointerEvent.identifier = pointerEvent.pointerId; - this.pointers[pointerEvent.pointerId] = pointerEvent; - } - }, + // draw the outer border + if (this.clusterSize > 1) { + ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.networkScaleInv; + ctx.lineWidth = Math.min(this.width,ctx.lineWidth); - /** - * check if ev matches pointertype - * @method matchType - * @param {String} pointerType matches `POINTER_MOUSE|TOUCH|PEN` - * @param {PointerEvent} ev - */ - matchType: function matchType(pointerType, ev) { - if(!ev.pointerType) { - return false; - } + ctx.ellipse(this.left-2*ctx.lineWidth, this.top-2*ctx.lineWidth, this.width+4*ctx.lineWidth, this.height+4*ctx.lineWidth); + ctx.stroke(); + } + ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.networkScaleInv; + ctx.lineWidth = Math.min(this.width,ctx.lineWidth); - var pt = ev.pointerType, - types = {}; + ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; - types[POINTER_MOUSE] = (pt === (ev.MSPOINTER_TYPE_MOUSE || POINTER_MOUSE)); - types[POINTER_TOUCH] = (pt === (ev.MSPOINTER_TYPE_TOUCH || POINTER_TOUCH)); - types[POINTER_PEN] = (pt === (ev.MSPOINTER_TYPE_PEN || POINTER_PEN)); - return types[pointerType]; - }, + ctx.ellipse(this.left, this.top, this.width, this.height); + ctx.fill(); + ctx.stroke(); - /** - * reset the stored pointers - * @method reset - */ - reset: function resetList() { - this.pointers = {}; - } - }; + this.boundingBox.top = this.top; + this.boundingBox.left = this.left; + this.boundingBox.right = this.left + this.width; + this.boundingBox.bottom = this.top + this.height; + this._label(ctx, this.label, this.x, this.y); + }; - /** - * @module hammer - * - * @class Detection - * @static - */ - var Detection = Hammer.detection = { - // contains all registred Hammer.gestures in the correct order - gestures: [], + Node.prototype._drawDot = function (ctx) { + this._drawShape(ctx, 'circle'); + }; - // data of the current Hammer.gesture detection session - current: null, + Node.prototype._drawTriangle = function (ctx) { + this._drawShape(ctx, 'triangle'); + }; - // the previous Hammer.gesture session data - // is a full clone of the previous gesture.current object - previous: null, + Node.prototype._drawTriangleDown = function (ctx) { + this._drawShape(ctx, 'triangleDown'); + }; - // when this becomes true, no gestures are fired - stopped: false, + Node.prototype._drawSquare = function (ctx) { + this._drawShape(ctx, 'square'); + }; - /** - * start Hammer.gesture detection - * @method startDetect - * @param {Hammer.Instance} inst - * @param {Object} eventData - */ - startDetect: function startDetect(inst, eventData) { - // already busy with a Hammer.gesture detection on an element - if(this.current) { - return; - } + Node.prototype._drawStar = function (ctx) { + this._drawShape(ctx, 'star'); + }; - this.stopped = false; + Node.prototype._resizeShape = function (ctx) { + if (!this.width) { + this.options.radius= this.baseRadiusValue; + var size = 2 * this.options.radius; + this.width = size; + this.height = size; - // holds current session - this.current = { - inst: inst, // reference to HammerInstance we're working for - startEvent: Utils.extend({}, eventData), // start eventData for distances, timing etc - lastEvent: false, // last eventData - lastCalcEvent: false, // last eventData for calculations. - futureCalcEvent: false, // last eventData for calculations. - lastCalcData: {}, // last lastCalcData - name: '' // current gesture we're in/detected, can be 'tap', 'hold' etc - }; + // scaling used for clustering + this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; + this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; + this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor; + this.growthIndicator = this.width - size; + } + }; - this.detect(eventData); - }, + Node.prototype._drawShape = function (ctx, shape) { + this._resizeShape(ctx); - /** - * Hammer.gesture detection - * @method detect - * @param {Object} eventData - * @return {any} - */ - detect: function detect(eventData) { - if(!this.current || this.stopped) { - return; - } + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; - // extend event data with calculations about scale, distance etc - eventData = this.extendEventData(eventData); + var clusterLineWidth = 2.5; + var borderWidth = this.options.borderWidth; + var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; + var radiusMultiplier = 2; - // hammer instance and instance options - var inst = this.current.inst, - instOptions = inst.options; + // choose draw method depending on the shape + switch (shape) { + case 'dot': radiusMultiplier = 2; break; + case 'square': radiusMultiplier = 2; break; + case 'triangle': radiusMultiplier = 3; break; + case 'triangleDown': radiusMultiplier = 3; break; + case 'star': radiusMultiplier = 4; break; + } - // call Hammer.gesture handlers - Utils.each(this.gestures, function triggerGesture(gesture) { - // only when the instance options have enabled this gesture - if(!this.stopped && inst.enabled && instOptions[gesture.name]) { - gesture.handler.call(gesture, eventData, inst); - } - }, this); + ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; + // draw the outer border + if (this.clusterSize > 1) { + ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.networkScaleInv; + ctx.lineWidth = Math.min(this.width,ctx.lineWidth); - // store as previous event event - if(this.current) { - this.current.lastEvent = eventData; - } + ctx[shape](this.x, this.y, this.options.radius+ radiusMultiplier * ctx.lineWidth); + ctx.stroke(); + } + ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.networkScaleInv; + ctx.lineWidth = Math.min(this.width,ctx.lineWidth); - if(eventData.eventType == EVENT_END) { - this.stopDetect(); - } + ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; + ctx[shape](this.x, this.y, this.options.radius); + ctx.fill(); + ctx.stroke(); - return eventData; - }, + this.boundingBox.top = this.y - this.options.radius; + this.boundingBox.left = this.x - this.options.radius; + this.boundingBox.right = this.x + this.options.radius; + this.boundingBox.bottom = this.y + this.options.radius; - /** - * clear the Hammer.gesture vars - * this is called on endDetect, but can also be used when a final Hammer.gesture has been detected - * to stop other Hammer.gestures from being fired - * @method stopDetect - */ - stopDetect: function stopDetect() { - // clone current data to the store as the previous gesture - // used for the double tap gesture, since this is an other gesture detect session - this.previous = Utils.extend({}, this.current); + if (this.label) { + this._label(ctx, this.label, this.x, this.y + this.height / 2, undefined, 'hanging',true); + this.boundingBox.left = Math.min(this.boundingBox.left, this.labelDimensions.left); + this.boundingBox.right = Math.max(this.boundingBox.right, this.labelDimensions.left + this.labelDimensions.width); + this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelDimensions.height); + } + }; - // reset the current - this.current = null; - this.stopped = true; - }, + Node.prototype._resizeText = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + this.width = textSize.width + 2 * margin; + this.height = textSize.height + 2 * margin; - /** - * calculate velocity, angle and direction - * @method getVelocityData - * @param {Object} ev - * @param {Object} center - * @param {Number} deltaTime - * @param {Number} deltaX - * @param {Number} deltaY - */ - getCalculatedData: function getCalculatedData(ev, center, deltaTime, deltaX, deltaY) { - var cur = this.current, - recalc = false, - calcEv = cur.lastCalcEvent, - calcData = cur.lastCalcData; + // scaling used for clustering + this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; + this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; + this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor; + this.growthIndicator = this.width - (textSize.width + 2 * margin); + } + }; - if(calcEv && ev.timeStamp - calcEv.timeStamp > Hammer.CALCULATE_INTERVAL) { - center = calcEv.center; - deltaTime = ev.timeStamp - calcEv.timeStamp; - deltaX = ev.center.clientX - calcEv.center.clientX; - deltaY = ev.center.clientY - calcEv.center.clientY; - recalc = true; - } + Node.prototype._drawText = function (ctx) { + this._resizeText(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; - if(ev.eventType == EVENT_TOUCH || ev.eventType == EVENT_RELEASE) { - cur.futureCalcEvent = ev; - } + this._label(ctx, this.label, this.x, this.y); - if(!cur.lastCalcEvent || recalc) { - calcData.velocity = Utils.getVelocity(deltaTime, deltaX, deltaY); - calcData.angle = Utils.getAngle(center, ev.center); - calcData.direction = Utils.getDirection(center, ev.center); + this.boundingBox.top = this.top; + this.boundingBox.left = this.left; + this.boundingBox.right = this.left + this.width; + this.boundingBox.bottom = this.top + this.height; + }; - cur.lastCalcEvent = cur.futureCalcEvent || ev; - cur.futureCalcEvent = ev; - } - ev.velocityX = calcData.velocity.x; - ev.velocityY = calcData.velocity.y; - ev.interimAngle = calcData.angle; - ev.interimDirection = calcData.direction; - }, + Node.prototype._label = function (ctx, text, x, y, align, baseline, labelUnderNode) { + if (text && Number(this.options.fontSize) * this.networkScale > this.fontDrawThreshold) { + ctx.font = (this.selected ? "bold " : "") + this.options.fontSize + "px " + this.options.fontFace; - /** - * extend eventData for Hammer.gestures - * @method extendEventData - * @param {Object} ev - * @return {Object} ev - */ - extendEventData: function extendEventData(ev) { - var cur = this.current, - startEv = cur.startEvent, - lastEv = cur.lastEvent || startEv; + var lines = text.split('\n'); + var lineCount = lines.length; + var fontSize = Number(this.options.fontSize); + var yLine = y + (1 - lineCount) / 2 * fontSize; + if (labelUnderNode == true) { + yLine = y + (1 - lineCount) / (2 * fontSize); + } - // update the start touchlist to calculate the scale/rotation - if(ev.eventType == EVENT_TOUCH || ev.eventType == EVENT_RELEASE) { - startEv.touches = []; - Utils.each(ev.touches, function(touch) { - startEv.touches.push({ - clientX: touch.clientX, - clientY: touch.clientY - }); - }); - } + // font fill from edges now for nodes! + var width = ctx.measureText(lines[0]).width; + for (var i = 1; i < lineCount; i++) { + var lineWidth = ctx.measureText(lines[i]).width; + width = lineWidth > width ? lineWidth : width; + } + var height = this.options.fontSize * lineCount; + var left = x - width / 2; + var top = y - height / 2; + if (baseline == "hanging") { + top += 0.5 * fontSize; + top += 4; // distance from node, required because we use hanging. Hanging has less difference between browsers + yLine += 4; // distance from node + } + this.labelDimensions = {top:top,left:left,width:width,height:height,yLine:yLine}; - var deltaTime = ev.timeStamp - startEv.timeStamp, - deltaX = ev.center.clientX - startEv.center.clientX, - deltaY = ev.center.clientY - startEv.center.clientY; + // create the fontfill background + if (this.options.fontFill !== undefined && this.options.fontFill !== null && this.options.fontFill !== "none") { + ctx.fillStyle = this.options.fontFill; + ctx.fillRect(left, top, width, height); + } - this.getCalculatedData(ev, lastEv.center, deltaTime, deltaX, deltaY); + // draw text + ctx.fillStyle = this.options.fontColor || "black"; + ctx.textAlign = align || "center"; + ctx.textBaseline = baseline || "middle"; + if (this.options.fontStrokeWidth > 0){ + ctx.lineWidth = this.options.fontStrokeWidth; + ctx.strokeStyle = this.options.fontStrokeColor; + ctx.lineJoin = 'round'; + } + for (var i = 0; i < lineCount; i++) { + if(this.options.fontStrokeWidth){ + ctx.strokeText(lines[i], x, yLine); + } + ctx.fillText(lines[i], x, yLine); + yLine += fontSize; + } + } + }; - Utils.extend(ev, { - startEvent: startEv, - deltaTime: deltaTime, - deltaX: deltaX, - deltaY: deltaY, + Node.prototype.getTextSize = function(ctx) { + if (this.label !== undefined) { + ctx.font = (this.selected ? "bold " : "") + this.options.fontSize + "px " + this.options.fontFace; - distance: Utils.getDistance(startEv.center, ev.center), - angle: Utils.getAngle(startEv.center, ev.center), - direction: Utils.getDirection(startEv.center, ev.center), - scale: Utils.getScale(startEv.touches, ev.touches), - rotation: Utils.getRotation(startEv.touches, ev.touches) - }); + var lines = this.label.split('\n'), + height = (Number(this.options.fontSize) + 4) * lines.length, + width = 0; - return ev; - }, + for (var i = 0, iMax = lines.length; i < iMax; i++) { + width = Math.max(width, ctx.measureText(lines[i]).width); + } - /** - * register new gesture - * @method register - * @param {Object} gesture object, see `gestures/` for documentation - * @return {Array} gestures - */ - register: function register(gesture) { - // add an enable gesture options if there is no given - var options = gesture.defaults || {}; - if(options[gesture.name] === undefined) { - options[gesture.name] = true; - } + return {"width": width, "height": height, lineCount: lines.length}; + } + else { + return {"width": 0, "height": 0, lineCount: 0}; + } + }; - // extend Hammer default options with the Hammer.gesture options - Utils.extend(Hammer.defaults, options, true); + /** + * this is used to determine if a node is visible at all. this is used to determine when it needs to be drawn. + * there is a safety margin of 0.3 * width; + * + * @returns {boolean} + */ + Node.prototype.inArea = function() { + if (this.width !== undefined) { + return (this.x + this.width *this.networkScaleInv >= this.canvasTopLeft.x && + this.x - this.width *this.networkScaleInv < this.canvasBottomRight.x && + this.y + this.height*this.networkScaleInv >= this.canvasTopLeft.y && + this.y - this.height*this.networkScaleInv < this.canvasBottomRight.y); + } + else { + return true; + } + }; - // set its index - gesture.index = gesture.index || 1000; + /** + * checks if the core of the node is in the display area, this is used for opening clusters around zoom + * @returns {boolean} + */ + Node.prototype.inView = function() { + return (this.x >= this.canvasTopLeft.x && + this.x < this.canvasBottomRight.x && + this.y >= this.canvasTopLeft.y && + this.y < this.canvasBottomRight.y); + }; - // add Hammer.gesture to the list - this.gestures.push(gesture); + /** + * This allows the zoom level of the network to influence the rendering + * We store the inverted scale and the coordinates of the top left, and bottom right points of the canvas + * + * @param scale + * @param canvasTopLeft + * @param canvasBottomRight + */ + Node.prototype.setScaleAndPos = function(scale,canvasTopLeft,canvasBottomRight) { + this.networkScaleInv = 1.0/scale; + this.networkScale = scale; + this.canvasTopLeft = canvasTopLeft; + this.canvasBottomRight = canvasBottomRight; + }; - // sort the list by index - this.gestures.sort(function(a, b) { - if(a.index < b.index) { - return -1; - } - if(a.index > b.index) { - return 1; - } - return 0; - }); - return this.gestures; - } + /** + * This allows the zoom level of the network to influence the rendering + * + * @param scale + */ + Node.prototype.setScale = function(scale) { + this.networkScaleInv = 1.0/scale; + this.networkScale = scale; }; + /** - * @module hammer + * set the velocity at 0. Is called when this node is contained in another during clustering */ + Node.prototype.clearVelocity = function() { + this.vx = 0; + this.vy = 0; + }; + /** - * create new hammer instance - * all methods should return the instance itself, so it is chainable. + * Basic preservation of (kinectic) energy * - * @class Instance - * @constructor - * @param {HTMLElement} element - * @param {Object} [options={}] options are merged with `Hammer.defaults` - * @return {Hammer.Instance} + * @param massBeforeClustering */ - Hammer.Instance = function(element, options) { - var self = this; - - // setup HammerJS window events and register all gestures - // this also sets up the default options - setup(); + Node.prototype.updateVelocity = function(massBeforeClustering) { + var energyBefore = this.vx * this.vx * massBeforeClustering; + //this.vx = (this.vx < 0) ? -Math.sqrt(energyBefore/this.options.mass) : Math.sqrt(energyBefore/this.options.mass); + this.vx = Math.sqrt(energyBefore/this.options.mass); + energyBefore = this.vy * this.vy * massBeforeClustering; + //this.vy = (this.vy < 0) ? -Math.sqrt(energyBefore/this.options.mass) : Math.sqrt(energyBefore/this.options.mass); + this.vy = Math.sqrt(energyBefore/this.options.mass); + }; - /** - * @property element - * @type {HTMLElement} - */ - this.element = element; + module.exports = Node; - /** - * @property enabled - * @type {Boolean} - * @protected - */ - this.enabled = true; - /** - * options, merged with the defaults - * options with an _ are converted to camelCase - * @property options - * @type {Object} - */ - Utils.each(options, function(value, name) { - delete options[name]; - options[Utils.toCamelCase(name)] = value; - }); +/***/ }, +/* 57 */ +/***/ function(module, exports, __webpack_require__) { - this.options = Utils.extend(Utils.extend({}, Hammer.defaults), options || {}); + var util = __webpack_require__(1); + var Node = __webpack_require__(56); - // add some css to the element to prevent the browser from doing its native behavoir - if(this.options.behavior) { - Utils.toggleBehavior(this.element, this.options.behavior, true); - } + /** + * @class Edge + * + * A edge connects two nodes + * @param {Object} properties Object with properties. Must contain + * At least properties from and to. + * Available properties: from (number), + * to (number), label (string, color (string), + * width (number), style (string), + * length (number), title (string) + * @param {Network} network A Network object, used to find and edge to + * nodes. + * @param {Object} constants An object with default values for + * example for the color + */ + function Edge (properties, network, networkConstants) { + if (!network) { + throw "No network provided"; + } + var fields = ['edges','physics']; + var constants = util.selectiveBridgeObject(fields,networkConstants); + this.options = constants.edges; + this.physics = constants.physics; + this.options['smoothCurves'] = networkConstants['smoothCurves']; - /** - * event start handler on the element to start the detection - * @property eventStartHandler - * @type {Object} - */ - this.eventStartHandler = Event.onTouch(element, EVENT_START, function(ev) { - if(self.enabled && ev.eventType == EVENT_START) { - Detection.startDetect(self, ev); - } else if(ev.eventType == EVENT_TOUCH) { - Detection.detect(ev); - } - }); - /** - * keep a list of user event handlers which needs to be removed when calling 'dispose' - * @property eventHandlers - * @type {Array} - */ - this.eventHandlers = []; - }; + this.network = network; - Hammer.Instance.prototype = { - /** - * bind events to the instance - * @method on - * @chainable - * @param {String} gestures multiple gestures by splitting with a space - * @param {Function} handler - * @param {Object} handler.ev event object - */ - on: function onEvent(gestures, handler) { - var self = this; - Event.on(self.element, gestures, handler, function(type) { - self.eventHandlers.push({ gesture: type, handler: handler }); - }); - return self; - }, + // initialize variables + this.id = undefined; + this.fromId = undefined; + this.toId = undefined; + this.title = undefined; + this.widthSelected = this.options.width * this.options.widthSelectionMultiplier; + this.value = undefined; + this.selected = false; + this.hover = false; + this.labelDimensions = {top:0,left:0,width:0,height:0,yLine:0}; // could be cached + this.dirtyLabel = true; - /** - * unbind events to the instance - * @method off - * @chainable - * @param {String} gestures - * @param {Function} handler - */ - off: function offEvent(gestures, handler) { - var self = this; + this.from = null; // a node + this.to = null; // a node + this.via = null; // a temp node - Event.off(self.element, gestures, handler, function(type) { - var index = Utils.inArray({ gesture: type, handler: handler }); - if(index !== false) { - self.eventHandlers.splice(index, 1); - } - }); - return self; - }, + this.fromBackup = null; // used to clean up after reconnect + this.toBackup = null;; // used to clean up after reconnect - /** - * trigger gesture event - * @method trigger - * @chainable - * @param {String} gesture - * @param {Object} [eventData] - */ - trigger: function triggerEvent(gesture, eventData) { - // optional - if(!eventData) { - eventData = {}; - } + // we use this to be able to reconnect the edge to a cluster if its node is put into a cluster + // by storing the original information we can revert to the original connection when the cluser is opened. + this.originalFromId = []; + this.originalToId = []; - // create DOM event - var event = Hammer.DOCUMENT.createEvent('Event'); - event.initEvent(gesture, true, true); - event.gesture = eventData; + this.connected = false; - // trigger on the target if it is in the instance element, - // this is for event delegation tricks - var element = this.element; - if(Utils.hasParent(eventData.target, element)) { - element = eventData.target; - } + this.widthFixed = false; + this.lengthFixed = false; - element.dispatchEvent(event); - return this; - }, + this.setProperties(properties); - /** - * enable of disable hammer.js detection - * @method enable - * @chainable - * @param {Boolean} state - */ - enable: function enable(state) { - this.enabled = state; - return this; - }, + this.controlNodesEnabled = false; + this.controlNodes = {from:null, to:null, positions:{}}; + this.connectedNode = null; + } - /** - * dispose this hammer instance - * @method dispose - * @return {Null} - */ - dispose: function dispose() { - var i, eh; + /** + * Set or overwrite properties for the edge + * @param {Object} properties an object with properties + * @param {Object} constants and object with default, global properties + */ + Edge.prototype.setProperties = function(properties) { + if (!properties) { + return; + } - // undo all changes made by stop_browser_behavior - Utils.toggleBehavior(this.element, this.options.behavior, false); + var fields = ['style','fontSize','fontFace','fontColor','fontFill','fontStrokeWidth','fontStrokeColor','width', + 'widthSelectionMultiplier','hoverWidth','arrowScaleFactor','dash','inheritColor','labelAlignment' + ]; + util.selectiveDeepExtend(fields, this.options, properties); - // unbind all custom event handlers - for(i = -1; (eh = this.eventHandlers[++i]);) { - Utils.off(this.element, eh.gesture, eh.handler); - } + if (properties.from !== undefined) {this.fromId = properties.from;} + if (properties.to !== undefined) {this.toId = properties.to;} - this.eventHandlers = []; + if (properties.id !== undefined) {this.id = properties.id;} + if (properties.label !== undefined) {this.label = properties.label; this.dirtyLabel = true;} - // unbind the start event listener - Event.off(this.element, EVENT_TYPES[EVENT_START], this.eventStartHandler); + if (properties.title !== undefined) {this.title = properties.title;} + if (properties.value !== undefined) {this.value = properties.value;} + if (properties.length !== undefined) {this.physics.springLength = properties.length;} - return null; + if (properties.color !== undefined) { + this.options.inheritColor = false; + if (util.isString(properties.color)) { + this.options.color.color = properties.color; + this.options.color.highlight = properties.color; } - }; + else { + if (properties.color.color !== undefined) {this.options.color.color = properties.color.color;} + if (properties.color.highlight !== undefined) {this.options.color.highlight = properties.color.highlight;} + if (properties.color.hover !== undefined) {this.options.color.hover = properties.color.hover;} + } + } + // A node is connected when it has a from and to node. + this.connect(); + + this.widthFixed = this.widthFixed || (properties.width !== undefined); + this.lengthFixed = this.lengthFixed || (properties.length !== undefined); + + this.widthSelected = this.options.width* this.options.widthSelectionMultiplier; + + // set draw method based on style + switch (this.options.style) { + case 'line': this.draw = this._drawLine; break; + case 'arrow': this.draw = this._drawArrow; break; + case 'arrow-center': this.draw = this._drawArrowCenter; break; + case 'dash-line': this.draw = this._drawDashLine; break; + default: this.draw = this._drawLine; break; + } + + }; /** - * @module gestures - */ - /** - * Move with x fingers (default 1) around on the page. - * Preventing the default browser behavior is a good way to improve feel and working. - * ```` - * hammertime.on("drag", function(ev) { - * console.log(ev); - * ev.gesture.preventDefault(); - * }); - * ```` - * - * @class Drag - * @static - */ - /** - * @event drag - * @param {Object} ev - */ - /** - * @event dragstart - * @param {Object} ev + * Connect an edge to its nodes */ + Edge.prototype.connect = function () { + this.disconnect(); + + this.from = this.network.nodes[this.fromId] || null; + this.to = this.network.nodes[this.toId] || null; + this.connected = (this.from && this.to); + + if (this.connected) { + this.from.attachEdge(this); + this.to.attachEdge(this); + } + else { + if (this.from) { + this.from.detachEdge(this); + } + if (this.to) { + this.to.detachEdge(this); + } + } + }; + /** - * @event dragend - * @param {Object} ev + * Disconnect an edge from its nodes */ + Edge.prototype.disconnect = function () { + if (this.from) { + this.from.detachEdge(this); + this.from = null; + } + if (this.to) { + this.to.detachEdge(this); + this.to = null; + } + + this.connected = false; + }; + /** - * @event drapleft - * @param {Object} ev + * get the title of this edge. + * @return {string} title The title of the edge, or undefined when no title + * has been set. */ + Edge.prototype.getTitle = function() { + return typeof this.title === "function" ? this.title() : this.title; + }; + + /** - * @event dragright - * @param {Object} ev + * Retrieve the value of the edge. Can be undefined + * @return {Number} value */ + Edge.prototype.getValue = function() { + return this.value; + }; + /** - * @event dragup - * @param {Object} ev + * Adjust the value range of the edge. The edge will adjust it's width + * based on its value. + * @param {Number} min + * @param {Number} max */ + Edge.prototype.setValueRange = function(min, max) { + if (!this.widthFixed && this.value !== undefined) { + var scale = (this.options.widthMax - this.options.widthMin) / (max - min); + this.options.width= (this.value - min) * scale + this.options.widthMin; + this.widthSelected = this.options.width* this.options.widthSelectionMultiplier; + } + }; + /** - * @event dragdown - * @param {Object} ev + * Redraw a edge + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx */ + Edge.prototype.draw = function(ctx) { + throw "Method draw not initialized in edge"; + }; /** - * @param {String} name + * Check if this object is overlapping with the provided object + * @param {Object} obj an object with parameters left, top + * @return {boolean} True if location is located on the edge */ - (function(name) { - var triggered = false; - - function dragGesture(ev, inst) { - var cur = Detection.current; - - // max touches - if(inst.options.dragMaxTouches > 0 && - ev.touches.length > inst.options.dragMaxTouches) { - return; - } - - switch(ev.eventType) { - case EVENT_START: - triggered = false; - break; - - case EVENT_MOVE: - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(ev.distance < inst.options.dragMinDistance && - cur.name != name) { - return; - } + Edge.prototype.isOverlappingWith = function(obj) { + if (this.connected) { + var distMax = 10; + var xFrom = this.from.x; + var yFrom = this.from.y; + var xTo = this.to.x; + var yTo = this.to.y; + var xObj = obj.left; + var yObj = obj.top; - var startCenter = cur.startEvent.center; + var dist = this._getDistanceToEdge(xFrom, yFrom, xTo, yTo, xObj, yObj); - // we are dragging! - if(cur.name != name) { - cur.name = name; - if(inst.options.dragDistanceCorrection && ev.distance > 0) { - // When a drag is triggered, set the event center to dragMinDistance pixels from the original event center. - // Without this correction, the dragged distance would jumpstart at dragMinDistance pixels instead of at 0. - // It might be useful to save the original start point somewhere - var factor = Math.abs(inst.options.dragMinDistance / ev.distance); - startCenter.pageX += ev.deltaX * factor; - startCenter.pageY += ev.deltaY * factor; - startCenter.clientX += ev.deltaX * factor; - startCenter.clientY += ev.deltaY * factor; + return (dist < distMax); + } + else { + return false + } + }; - // recalculate event data using new start point - ev = Detection.extendEventData(ev); - } - } + Edge.prototype._getColor = function() { + var colorObj = this.options.color; + if (this.options.inheritColor == "to") { + colorObj = { + highlight: this.to.options.color.highlight.border, + hover: this.to.options.color.hover.border, + color: this.to.options.color.border + }; + } + else if (this.options.inheritColor == "from" || this.options.inheritColor == true) { + colorObj = { + highlight: this.from.options.color.highlight.border, + hover: this.from.options.color.hover.border, + color: this.from.options.color.border + }; + } - // lock drag to axis? - if(cur.lastEvent.dragLockToAxis || - ( inst.options.dragLockToAxis && - inst.options.dragLockMinDistance <= ev.distance - )) { - ev.dragLockToAxis = true; - } + if (this.selected == true) {return colorObj.highlight;} + else if (this.hover == true) {return colorObj.hover;} + else {return colorObj.color;} + }; - // keep direction on the axis that the drag gesture started on - var lastDirection = cur.lastEvent.direction; - if(ev.dragLockToAxis && lastDirection !== ev.direction) { - if(Utils.isVertical(lastDirection)) { - ev.direction = (ev.deltaY < 0) ? DIRECTION_UP : DIRECTION_DOWN; - } else { - ev.direction = (ev.deltaX < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT; - } - } - // first time, trigger dragstart event - if(!triggered) { - inst.trigger(name + 'start', ev); - triggered = true; - } + /** + * Redraw a edge as a line + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private + */ + Edge.prototype._drawLine = function(ctx) { + // set style + ctx.strokeStyle = this._getColor(); + ctx.lineWidth = this._getLineWidth(); - // trigger events - inst.trigger(name, ev); - inst.trigger(name + ev.direction, ev); + if (this.from != this.to) { + // draw line + var via = this._line(ctx); - var isVertical = Utils.isVertical(ev.direction); + // draw label + var point; + if (this.label) { + if (this.options.smoothCurves.enabled == true && via != null) { + var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); + var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); + point = {x:midpointX, y:midpointY}; + } + else { + point = this._pointOnLine(0.5); + } + this._label(ctx, this.label, point.x, point.y); + } + } + else { + var x, y; + var radius = this.physics.springLength / 4; + var node = this.from; + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width / 2; + y = node.y - radius; + } + else { + x = node.x + radius; + y = node.y - node.height / 2; + } + this._circle(ctx, x, y, radius); + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); + } + }; - // block the browser events - if((inst.options.dragBlockVertical && isVertical) || - (inst.options.dragBlockHorizontal && !isVertical)) { - ev.preventDefault(); - } - break; + /** + * Get the line width of the edge. Depends on width and whether one of the + * connected nodes is selected. + * @return {Number} width + * @private + */ + Edge.prototype._getLineWidth = function() { + if (this.selected == true) { + return Math.max(Math.min(this.widthSelected, this.options.widthMax), 0.3*this.networkScaleInv); + } + else { + if (this.hover == true) { + return Math.max(Math.min(this.options.hoverWidth, this.options.widthMax), 0.3*this.networkScaleInv); + } + else { + return Math.max(this.options.width, 0.3*this.networkScaleInv); + } + } + }; - case EVENT_RELEASE: - if(triggered && ev.changedLength <= inst.options.dragMaxTouches) { - inst.trigger(name + 'end', ev); - triggered = false; - } - break; + Edge.prototype._getViaCoordinates = function () { + if (this.options.smoothCurves.dynamic == true && this.options.smoothCurves.enabled == true ) { + return this.via; + } + else if (this.options.smoothCurves.enabled == false) { + return {x:0,y:0}; + } + else { + var xVia = null; + var yVia = null; + var factor = this.options.smoothCurves.roundness; + var type = this.options.smoothCurves.type; - case EVENT_END: - triggered = false; - break; + var dx = Math.abs(this.from.x - this.to.x); + var dy = Math.abs(this.from.y - this.to.y); + if (type == 'discrete' || type == 'diagonalCross') { + if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { + if (this.from.y > this.to.y) { + if (this.from.x < this.to.x) { + xVia = this.from.x + factor * dy; + yVia = this.from.y - factor * dy; + } + else if (this.from.x > this.to.x) { + xVia = this.from.x - factor * dy; + yVia = this.from.y - factor * dy; + } + } + else if (this.from.y < this.to.y) { + if (this.from.x < this.to.x) { + xVia = this.from.x + factor * dy; + yVia = this.from.y + factor * dy; + } + else if (this.from.x > this.to.x) { + xVia = this.from.x - factor * dy; + yVia = this.from.y + factor * dy; + } + } + if (type == "discrete") { + xVia = dx < factor * dy ? this.from.x : xVia; + } + } + else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { + if (this.from.y > this.to.y) { + if (this.from.x < this.to.x) { + xVia = this.from.x + factor * dx; + yVia = this.from.y - factor * dx; + } + else if (this.from.x > this.to.x) { + xVia = this.from.x - factor * dx; + yVia = this.from.y - factor * dx; + } + } + else if (this.from.y < this.to.y) { + if (this.from.x < this.to.x) { + xVia = this.from.x + factor * dx; + yVia = this.from.y + factor * dx; + } + else if (this.from.x > this.to.x) { + xVia = this.from.x - factor * dx; + yVia = this.from.y + factor * dx; + } + } + if (type == "discrete") { + yVia = dy < factor * dx ? this.from.y : yVia; } + } + } + else if (type == "straightCross") { + if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { // up - down + xVia = this.from.x; + if (this.from.y < this.to.y) { + yVia = this.to.y - (1 - factor) * dy; + } + else { + yVia = this.to.y + (1 - factor) * dy; + } + } + else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { // left - right + if (this.from.x < this.to.x) { + xVia = this.to.x - (1 - factor) * dx; + } + else { + xVia = this.to.x + (1 - factor) * dx; + } + yVia = this.from.y; + } + } + else if (type == 'horizontal') { + if (this.from.x < this.to.x) { + xVia = this.to.x - (1 - factor) * dx; + } + else { + xVia = this.to.x + (1 - factor) * dx; + } + yVia = this.from.y; + } + else if (type == 'vertical') { + xVia = this.from.x; + if (this.from.y < this.to.y) { + yVia = this.to.y - (1 - factor) * dy; + } + else { + yVia = this.to.y + (1 - factor) * dy; + } + } + else { // continuous + if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { + if (this.from.y > this.to.y) { + if (this.from.x < this.to.x) { + // console.log(1) + xVia = this.from.x + factor * dy; + yVia = this.from.y - factor * dy; + xVia = this.to.x < xVia ? this.to.x : xVia; + } + else if (this.from.x > this.to.x) { + // console.log(2) + xVia = this.from.x - factor * dy; + yVia = this.from.y - factor * dy; + xVia = this.to.x > xVia ? this.to.x : xVia; + } + } + else if (this.from.y < this.to.y) { + if (this.from.x < this.to.x) { + // console.log(3) + xVia = this.from.x + factor * dy; + yVia = this.from.y + factor * dy; + xVia = this.to.x < xVia ? this.to.x : xVia; + } + else if (this.from.x > this.to.x) { + // console.log(4, this.from.x, this.to.x) + xVia = this.from.x - factor * dy; + yVia = this.from.y + factor * dy; + xVia = this.to.x > xVia ? this.to.x : xVia; + } + } + } + else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { + if (this.from.y > this.to.y) { + if (this.from.x < this.to.x) { + // console.log(5) + xVia = this.from.x + factor * dx; + yVia = this.from.y - factor * dx; + yVia = this.to.y > yVia ? this.to.y : yVia; + } + else if (this.from.x > this.to.x) { + // console.log(6) + xVia = this.from.x - factor * dx; + yVia = this.from.y - factor * dx; + yVia = this.to.y > yVia ? this.to.y : yVia; + } + } + else if (this.from.y < this.to.y) { + if (this.from.x < this.to.x) { + // console.log(7) + xVia = this.from.x + factor * dx; + yVia = this.from.y + factor * dx; + yVia = this.to.y < yVia ? this.to.y : yVia; + } + else if (this.from.x > this.to.x) { + // console.log(8) + xVia = this.from.x - factor * dx; + yVia = this.from.y + factor * dx; + yVia = this.to.y < yVia ? this.to.y : yVia; + } + } + } } - Hammer.gestures.Drag = { - name: name, - index: 50, - handler: dragGesture, - defaults: { - /** - * minimal movement that have to be made before the drag event gets triggered - * @property dragMinDistance - * @type {Number} - * @default 10 - */ - dragMinDistance: 10, - - /** - * Set dragDistanceCorrection to true to make the starting point of the drag - * be calculated from where the drag was triggered, not from where the touch started. - * Useful to avoid a jerk-starting drag, which can make fine-adjustments - * through dragging difficult, and be visually unappealing. - * @property dragDistanceCorrection - * @type {Boolean} - * @default true - */ - dragDistanceCorrection: true, - - /** - * set 0 for unlimited, but this can conflict with transform - * @property dragMaxTouches - * @type {Number} - * @default 1 - */ - dragMaxTouches: 1, - - /** - * prevent default browser behavior when dragging occurs - * be careful with it, it makes the element a blocking element - * when you are using the drag gesture, it is a good practice to set this true - * @property dragBlockHorizontal - * @type {Boolean} - * @default false - */ - dragBlockHorizontal: false, - - /** - * same as `dragBlockHorizontal`, but for vertical movement - * @property dragBlockVertical - * @type {Boolean} - * @default false - */ - dragBlockVertical: false, - - /** - * dragLockToAxis keeps the drag gesture on the axis that it started on, - * It disallows vertical directions if the initial direction was horizontal, and vice versa. - * @property dragLockToAxis - * @type {Boolean} - * @default false - */ - dragLockToAxis: false, - /** - * drag lock only kicks in when distance > dragLockMinDistance - * This way, locking occurs only when the distance has become large enough to reliably determine the direction - * @property dragLockMinDistance - * @type {Number} - * @default 25 - */ - dragLockMinDistance: 25 - } - }; - })('drag'); + return {x: xVia, y: yVia}; + } + }; /** - * @module gestures - */ - /** - * trigger a simple gesture event, so you can do anything in your handler. - * only usable if you know what your doing... - * - * @class Gesture - * @static - */ - /** - * @event gesture - * @param {Object} ev + * Draw a line between two nodes + * @param {CanvasRenderingContext2D} ctx + * @private */ - Hammer.gestures.Gesture = { - name: 'gesture', - index: 1337, - handler: function releaseGesture(ev, inst) { - inst.trigger(this.name, ev); + Edge.prototype._line = function (ctx) { + // draw a straight line + ctx.beginPath(); + ctx.moveTo(this.from.x, this.from.y); + if (this.options.smoothCurves.enabled == true) { + if (this.options.smoothCurves.dynamic == false) { + var via = this._getViaCoordinates(); + if (via.x == null) { + ctx.lineTo(this.to.x, this.to.y); + ctx.stroke(); + return null; + } + else { + // this.via.x = via.x; + // this.via.y = via.y; + ctx.quadraticCurveTo(via.x,via.y,this.to.x, this.to.y); + ctx.stroke(); + return via; + } + } + else { + ctx.quadraticCurveTo(this.via.x,this.via.y,this.to.x, this.to.y); + ctx.stroke(); + return this.via; } + } + else { + ctx.lineTo(this.to.x, this.to.y); + ctx.stroke(); + return null; + } }; /** - * @module gestures - */ - /** - * Touch stays at the same place for x time - * - * @class Hold - * @static - */ - /** - * @event hold - * @param {Object} ev + * Draw a line from a node to itself, a circle + * @param {CanvasRenderingContext2D} ctx + * @param {Number} x + * @param {Number} y + * @param {Number} radius + * @private */ + Edge.prototype._circle = function (ctx, x, y, radius) { + // draw a circle + ctx.beginPath(); + ctx.arc(x, y, radius, 0, 2 * Math.PI, false); + ctx.stroke(); + }; /** - * @param {String} name + * Draw label with white background and with the middle at (x, y) + * @param {CanvasRenderingContext2D} ctx + * @param {String} text + * @param {Number} x + * @param {Number} y + * @private */ - (function(name) { - var timer; - - function holdGesture(ev, inst) { - var options = inst.options, - current = Detection.current; - - switch(ev.eventType) { - case EVENT_START: - clearTimeout(timer); - - // set the gesture so we can check in the timeout if it still is - current.name = name; + Edge.prototype._label = function (ctx, text, x, y) { + if (text) { + ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") + + this.options.fontSize + "px " + this.options.fontFace; + var yLine; - // set timer and if after the timeout it still is hold, - // we trigger the hold event - timer = setTimeout(function() { - if(current && current.name == name) { - inst.trigger(name, ev); - } - }, options.holdTimeout); - break; + if (this.dirtyLabel == true) { + var lines = String(text).split('\n'); + var lineCount = lines.length; + var fontSize = Number(this.options.fontSize); + yLine = y + (1 - lineCount) / 2 * fontSize; - case EVENT_MOVE: - if(ev.distance > options.holdThreshold) { - clearTimeout(timer); - } - break; + var width = ctx.measureText(lines[0]).width; + for (var i = 1; i < lineCount; i++) { + var lineWidth = ctx.measureText(lines[i]).width; + width = lineWidth > width ? lineWidth : width; + } + var height = this.options.fontSize * lineCount; + var left = x - width / 2; + var top = y - height / 2; - case EVENT_RELEASE: - clearTimeout(timer); - break; - } + // cache + this.labelDimensions = {top:top,left:left,width:width,height:height,yLine:yLine}; } - Hammer.gestures.Hold = { - name: name, - index: 10, - defaults: { - /** - * @property holdTimeout - * @type {Number} - * @default 500 - */ - holdTimeout: 500, + var yLine = this.labelDimensions.yLine; + + ctx.save(); + + if (this.options.labelAlignment != "horizontal"){ + ctx.translate(x, yLine); + this._rotateForLabelAlignment(ctx); + x = 0; + yLine = 0; + } - /** - * movement allowed while holding - * @property holdThreshold - * @type {Number} - * @default 2 - */ - holdThreshold: 2 - }, - handler: holdGesture - }; - })('hold'); + + this._drawLabelRect(ctx); + this._drawLabelText(ctx,x,yLine, lines, lineCount, fontSize); + + ctx.restore(); + } + }; /** - * @module gestures - */ - /** - * when a touch is being released from the page - * - * @class Release - * @static + * Rotates the canvas so the text is most readable + * @param {CanvasRenderingContext2D} ctx + * @private */ + Edge.prototype._rotateForLabelAlignment = function(ctx) { + var dy = this.from.y - this.to.y; + var dx = this.from.x - this.to.x; + var angleInDegrees = Math.atan2(dy, dx); + + // rotate so label it is readable + if((angleInDegrees < -1 && dx < 0) || (angleInDegrees > 0 && dx < 0)){ + angleInDegrees = angleInDegrees + Math.PI; + } + + ctx.rotate(angleInDegrees); + }; + /** - * @event release - * @param {Object} ev + * Draws the label rectangle + * @param {CanvasRenderingContext2D} ctx + * @param {String} labelAlignment + * @private */ - Hammer.gestures.Release = { - name: 'release', - index: Infinity, - handler: function releaseGesture(ev, inst) { - if(ev.eventType == EVENT_RELEASE) { - inst.trigger(this.name, ev); - } + Edge.prototype._drawLabelRect = function(ctx) { + if (this.options.fontFill !== undefined && this.options.fontFill !== null && this.options.fontFill !== "none") { + ctx.fillStyle = this.options.fontFill; + + var lineMargin = 2; + + if (this.options.labelAlignment == 'line-center') { + ctx.fillRect(-this.labelDimensions.width * 0.5, -this.labelDimensions.height * 0.5, this.labelDimensions.width, this.labelDimensions.height); + } + else if (this.options.labelAlignment == 'line-above') { + ctx.fillRect(-this.labelDimensions.width * 0.5, -(this.labelDimensions.height + lineMargin), this.labelDimensions.width, this.labelDimensions.height); + } + else if (this.options.labelAlignment == 'line-below') { + ctx.fillRect(-this.labelDimensions.width * 0.5, lineMargin, this.labelDimensions.width, this.labelDimensions.height); } + else { + ctx.fillRect(this.labelDimensions.left, this.labelDimensions.top, this.labelDimensions.width, this.labelDimensions.height); + } + } }; /** - * @module gestures - */ - /** - * triggers swipe events when the end velocity is above the threshold - * for best usage, set `preventDefault` (on the drag gesture) to `true` - * ```` - * hammertime.on("dragleft swipeleft", function(ev) { - * console.log(ev); - * ev.gesture.preventDefault(); - * }); - * ```` - * - * @class Swipe - * @static - */ - /** - * @event swipe - * @param {Object} ev - */ - /** - * @event swipeleft - * @param {Object} ev - */ - /** - * @event swiperight - * @param {Object} ev - */ - /** - * @event swipeup - * @param {Object} ev + * Draws the label text + * @param {CanvasRenderingContext2D} ctx + * @param {Number} x + * @param {Number} yLine + * @param {Array} lines + * @param {Number} lineCount + * @param {Number} fontSize + * @private */ + Edge.prototype._drawLabelText = function(ctx, x, yLine, lines, lineCount, fontSize) { + // draw text + ctx.fillStyle = this.options.fontColor || "black"; + ctx.textAlign = "center"; + + // check for label alignment + if (this.options.labelAlignment != 'horizontal') { + var lineMargin = 2; + if (this.options.labelAlignment == 'line-above') { + ctx.textBaseline = "alphabetic"; + yLine -= 2 * lineMargin; // distance from edge, required because we use alphabetic. Alphabetic has less difference between browsers + } + else if (this.options.labelAlignment == 'line-below') { + ctx.textBaseline = "hanging"; + yLine += 2 * lineMargin;// distance from edge, required because we use hanging. Hanging has less difference between browsers + } + else { + ctx.textBaseline = "middle"; + } + } + else { + ctx.textBaseline = "middle"; + } + + // check for strokeWidth + if (this.options.fontStrokeWidth > 0){ + ctx.lineWidth = this.options.fontStrokeWidth; + ctx.strokeStyle = this.options.fontStrokeColor; + ctx.lineJoin = 'round'; + } + for (var i = 0; i < lineCount; i++) { + if(this.options.fontStrokeWidth > 0){ + ctx.strokeText(lines[i], x, yLine); + } + ctx.fillText(lines[i], x, yLine); + yLine += fontSize; + } + }; + /** - * @event swipedown - * @param {Object} ev + * Redraw a edge as a dashed line + * Draw this edge in the given canvas + * @author David Jordan + * @date 2012-08-08 + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private */ - Hammer.gestures.Swipe = { - name: 'swipe', - index: 40, - defaults: { - /** - * @property swipeMinTouches - * @type {Number} - * @default 1 - */ - swipeMinTouches: 1, - - /** - * @property swipeMaxTouches - * @type {Number} - * @default 1 - */ - swipeMaxTouches: 1, + Edge.prototype._drawDashLine = function(ctx) { + // set style + ctx.strokeStyle = this._getColor(); + ctx.lineWidth = this._getLineWidth(); - /** - * horizontal swipe velocity - * @property swipeVelocityX - * @type {Number} - * @default 0.6 - */ - swipeVelocityX: 0.6, + var via = null; + // only firefox and chrome support this method, else we use the legacy one. + if (ctx.setLineDash !== undefined) { + ctx.save(); + // configure the dash pattern + var pattern = [0]; + if (this.options.dash.length !== undefined && this.options.dash.gap !== undefined) { + pattern = [this.options.dash.length,this.options.dash.gap]; + } + else { + pattern = [5,5]; + } - /** - * vertical swipe velocity - * @property swipeVelocityY - * @type {Number} - * @default 0.6 - */ - swipeVelocityY: 0.6 - }, + // set dash settings for chrome or firefox + ctx.setLineDash(pattern); + ctx.lineDashOffset = 0; - handler: function swipeGesture(ev, inst) { - if(ev.eventType == EVENT_RELEASE) { - var touches = ev.touches.length, - options = inst.options; + // draw the line + via = this._line(ctx); - // max touches - if(touches < options.swipeMinTouches || - touches > options.swipeMaxTouches) { - return; - } + // restore the dash settings. + ctx.setLineDash([0]); + ctx.lineDashOffset = 0; + ctx.restore(); + } + else { // unsupporting smooth lines + // draw dashed line + ctx.beginPath(); + ctx.lineCap = 'round'; + if (this.options.dash.altLength !== undefined) //If an alt dash value has been set add to the array this value + { + ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, + [this.options.dash.length,this.options.dash.gap,this.options.dash.altLength,this.options.dash.gap]); + } + else if (this.options.dash.length !== undefined && this.options.dash.gap !== undefined) //If a dash and gap value has been set add to the array this value + { + ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, + [this.options.dash.length,this.options.dash.gap]); + } + else //If all else fails draw a line + { + ctx.moveTo(this.from.x, this.from.y); + ctx.lineTo(this.to.x, this.to.y); + } + ctx.stroke(); + } - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(ev.velocityX > options.swipeVelocityX || - ev.velocityY > options.swipeVelocityY) { - // trigger swipe events - inst.trigger(this.name, ev); - inst.trigger(this.name + ev.direction, ev); - } - } + // draw label + if (this.label) { + var point; + if (this.options.smoothCurves.enabled == true && via != null) { + var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); + var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); + point = {x:midpointX, y:midpointY}; + } + else { + point = this._pointOnLine(0.5); } + this._label(ctx, this.label, point.x, point.y); + } }; /** - * @module gestures - */ - /** - * Single tap and a double tap on a place - * - * @class Tap - * @static - */ - /** - * @event tap - * @param {Object} ev + * Get a point on a line + * @param {Number} percentage. Value between 0 (line start) and 1 (line end) + * @return {Object} point + * @private */ + Edge.prototype._pointOnLine = function (percentage) { + return { + x: (1 - percentage) * this.from.x + percentage * this.to.x, + y: (1 - percentage) * this.from.y + percentage * this.to.y + } + }; + /** - * @event doubletap - * @param {Object} ev + * Get a point on a circle + * @param {Number} x + * @param {Number} y + * @param {Number} radius + * @param {Number} percentage. Value between 0 (line start) and 1 (line end) + * @return {Object} point + * @private */ + Edge.prototype._pointOnCircle = function (x, y, radius, percentage) { + var angle = (percentage - 3/8) * 2 * Math.PI; + return { + x: x + radius * Math.cos(angle), + y: y - radius * Math.sin(angle) + } + }; /** - * @param {String} name + * Redraw a edge as a line with an arrow halfway the line + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private */ - (function(name) { - var hasMoved = false; - - function tapGesture(ev, inst) { - var options = inst.options, - current = Detection.current, - prev = Detection.previous, - sincePrev, - didDoubleTap; - - switch(ev.eventType) { - case EVENT_START: - hasMoved = false; - break; + Edge.prototype._drawArrowCenter = function(ctx) { + var point; + // set style + ctx.strokeStyle = this._getColor(); + ctx.fillStyle = ctx.strokeStyle; + ctx.lineWidth = this._getLineWidth(); - case EVENT_MOVE: - hasMoved = hasMoved || (ev.distance > options.tapMaxDistance); - break; + if (this.from != this.to) { + // draw line + var via = this._line(ctx); - case EVENT_END: - if(!Utils.inStr(ev.srcEvent.type, 'cancel') && ev.deltaTime < options.tapMaxTime && !hasMoved) { - // previous gesture, for the double tap since these are two different gesture detections - sincePrev = prev && prev.lastEvent && ev.timeStamp - prev.lastEvent.timeStamp; - didDoubleTap = false; + var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; + // draw an arrow halfway the line + if (this.options.smoothCurves.enabled == true && via != null) { + var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); + var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); + point = {x:midpointX, y:midpointY}; + } + else { + point = this._pointOnLine(0.5); + } - // check if double tap - if(prev && prev.name == name && - (sincePrev && sincePrev < options.doubleTapInterval) && - ev.distance < options.doubleTapDistance) { - inst.trigger('doubletap', ev); - didDoubleTap = true; - } + ctx.arrow(point.x, point.y, angle, length); + ctx.fill(); + ctx.stroke(); - // do a single tap - if(!didDoubleTap || options.tapAlways) { - current.name = name; - inst.trigger(current.name, ev); - } - } - break; - } + // draw label + if (this.label) { + this._label(ctx, this.label, point.x, point.y); + } + } + else { + // draw circle + var x, y; + var radius = 0.25 * Math.max(100,this.physics.springLength); + var node = this.from; + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width * 0.5; + y = node.y - radius; + } + else { + x = node.x + radius; + y = node.y - node.height * 0.5; } + this._circle(ctx, x, y, radius); - Hammer.gestures.Tap = { - name: name, - index: 100, - handler: tapGesture, - defaults: { - /** - * max time of a tap, this is for the slow tappers - * @property tapMaxTime - * @type {Number} - * @default 250 - */ - tapMaxTime: 250, + // draw all arrows + var angle = 0.2 * Math.PI; + var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; + point = this._pointOnCircle(x, y, radius, 0.5); + ctx.arrow(point.x, point.y, angle, length); + ctx.fill(); + ctx.stroke(); - /** - * max distance of movement of a tap, this is for the slow tappers - * @property tapMaxDistance - * @type {Number} - * @default 10 - */ - tapMaxDistance: 10, + // draw label + if (this.label) { + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); + } + } + }; - /** - * always trigger the `tap` event, even while double-tapping - * @property tapAlways - * @type {Boolean} - * @default true - */ - tapAlways: true, + Edge.prototype._pointOnBezier = function(t) { + var via = this._getViaCoordinates(); - /** - * max distance between two taps - * @property doubleTapDistance - * @type {Number} - * @default 20 - */ - doubleTapDistance: 20, + var x = Math.pow(1-t,2)*this.from.x + (2*t*(1 - t))*via.x + Math.pow(t,2)*this.to.x; + var y = Math.pow(1-t,2)*this.from.y + (2*t*(1 - t))*via.y + Math.pow(t,2)*this.to.y; - /** - * max time between two taps - * @property doubleTapInterval - * @type {Number} - * @default 300 - */ - doubleTapInterval: 300 - } - }; - })('tap'); + return {x:x,y:y}; + } /** - * @module gestures - */ - /** - * when a touch is being touched at the page + * This function uses binary search to look for the point where the bezier curve crosses the border of the node. * - * @class Touch - * @static - */ - /** - * @event touch - * @param {Object} ev + * @param from + * @param ctx + * @returns {*} + * @private */ - Hammer.gestures.Touch = { - name: 'touch', - index: -Infinity, - defaults: { - /** - * call preventDefault at touchstart, and makes the element blocking by disabling the scrolling of the page, - * but it improves gestures like transforming and dragging. - * be careful with using this, it can be very annoying for users to be stuck on the page - * @property preventDefault - * @type {Boolean} - * @default false - */ - preventDefault: false, - - /** - * disable mouse events, so only touch (or pen!) input triggers events - * @property preventMouse - * @type {Boolean} - * @default false - */ - preventMouse: false - }, - handler: function touchGesture(ev, inst) { - if(inst.options.preventMouse && ev.pointerType == POINTER_MOUSE) { - ev.stopDetect(); - return; - } + Edge.prototype._findBorderPosition = function(from,ctx) { + var maxIterations = 10; + var iteration = 0; + var low = 0; + var high = 1; + var pos,angle,distanceToBorder, distanceToNodes, difference; + var threshold = 0.2; + var node = this.to; + if (from == true) { + node = this.from; + } - if(inst.options.preventDefault) { - ev.preventDefault(); - } + while (low <= high && iteration < maxIterations) { + var middle = (low + high) * 0.5; - if(ev.eventType == EVENT_TOUCH) { - inst.trigger('touch', ev); - } + pos = this._pointOnBezier(middle); + angle = Math.atan2((node.y - pos.y), (node.x - pos.x)); + distanceToBorder = node.distanceToBorder(ctx,angle); + distanceToNodes = Math.sqrt(Math.pow(pos.x-node.x,2) + Math.pow(pos.y-node.y,2)); + difference = distanceToBorder - distanceToNodes; + if (Math.abs(difference) < threshold) { + break; // found + } + else if (difference < 0) { // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node. + if (from == false) { + low = middle; + } + else { + high = middle; + } + } + else { + if (from == false) { + high = middle; + } + else { + low = middle; + } } - }; - /** - * @module gestures - */ - /** - * User want to scale or rotate with 2 fingers - * Preventing the default browser behavior is a good way to improve feel and working. This can be done with the - * `preventDefault` option. - * - * @class Transform - * @static - */ - /** - * @event transform - * @param {Object} ev - */ - /** - * @event transformstart - * @param {Object} ev - */ - /** - * @event transformend - * @param {Object} ev - */ - /** - * @event pinchin - * @param {Object} ev - */ - /** - * @event pinchout - * @param {Object} ev - */ - /** - * @event rotate - * @param {Object} ev - */ + iteration++; + } + pos.t = middle; + + return pos; + }; /** - * @param {String} name + * Redraw a edge as a line with an arrow + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private */ - (function(name) { - var triggered = false; - - function transformGesture(ev, inst) { - switch(ev.eventType) { - case EVENT_START: - triggered = false; - break; - - case EVENT_MOVE: - // at least multitouch - if(ev.touches.length < 2) { - return; - } - - var scaleThreshold = Math.abs(1 - ev.scale); - var rotationThreshold = Math.abs(ev.rotation); - - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(scaleThreshold < inst.options.transformMinScale && - rotationThreshold < inst.options.transformMinRotation) { - return; - } + Edge.prototype._drawArrow = function(ctx) { + // set style + ctx.strokeStyle = this._getColor(); + ctx.fillStyle = ctx.strokeStyle; + ctx.lineWidth = this._getLineWidth(); - // we are transforming! - Detection.current.name = name; + // set vars + var angle, length, arrowPos; - // first time, trigger dragstart event - if(!triggered) { - inst.trigger(name + 'start', ev); - triggered = true; - } + // if not connected to itself + if (this.from != this.to) { + // draw line + this._line(ctx); - inst.trigger(name, ev); // basic transform event + // draw arrow head + if (this.options.smoothCurves.enabled == true) { + var via = this._getViaCoordinates(); + arrowPos = this._findBorderPosition(false, ctx); + var guidePos = this._pointOnBezier(Math.max(0.0, arrowPos.t - 0.1)) + angle = Math.atan2((arrowPos.y - guidePos.y), (arrowPos.x - guidePos.x)); + } + else { + angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var dx = (this.to.x - this.from.x); + var dy = (this.to.y - this.from.y); + var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); + var toBorderDist = this.to.distanceToBorder(ctx, angle); + var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; - // trigger rotate event - if(rotationThreshold > inst.options.transformMinRotation) { - inst.trigger('rotate', ev); - } + arrowPos = {}; + arrowPos.x = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x; + arrowPos.y = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y; + } - // trigger pinch event - if(scaleThreshold > inst.options.transformMinScale) { - inst.trigger('pinch', ev); - inst.trigger('pinch' + (ev.scale < 1 ? 'in' : 'out'), ev); - } - break; + // draw arrow at the end of the line + length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; + ctx.arrow(arrowPos.x,arrowPos.y, angle, length); + ctx.fill(); + ctx.stroke(); - case EVENT_RELEASE: - if(triggered && ev.changedLength < 2) { - inst.trigger(name + 'end', ev); - triggered = false; - } - break; - } + // draw label + if (this.label) { + var point; + if (this.options.smoothCurves.enabled == true && via != null) { + point = this._pointOnBezier(0.5); + } + else { + point = this._pointOnLine(0.5); + } + this._label(ctx, this.label, point.x, point.y); } + } + else { + // draw circle + var node = this.from; + var x, y, arrow; + var radius = 0.25 * Math.max(100,this.physics.springLength); + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width * 0.5; + y = node.y - radius; + arrow = { + x: x, + y: node.y, + angle: 0.9 * Math.PI + }; + } + else { + x = node.x + radius; + y = node.y - node.height * 0.5; + arrow = { + x: node.x, + y: y, + angle: 0.6 * Math.PI + }; + } + ctx.beginPath(); + // TODO: similarly, for a line without arrows, draw to the border of the nodes instead of the center + ctx.arc(x, y, radius, 0, 2 * Math.PI, false); + ctx.stroke(); - Hammer.gestures.Transform = { - name: name, - index: 45, - defaults: { - /** - * minimal scale factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1 - * @property transformMinScale - * @type {Number} - * @default 0.01 - */ - transformMinScale: 0.01, - - /** - * rotation in degrees - * @property transformMinRotation - * @type {Number} - * @default 1 - */ - transformMinRotation: 1 - }, + // draw all arrows + var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; + ctx.arrow(arrow.x, arrow.y, arrow.angle, length); + ctx.fill(); + ctx.stroke(); - handler: transformGesture - }; - })('transform'); + // draw label + if (this.label) { + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); + } + } + }; /** - * @module hammer + * Calculate the distance between a point (x3,y3) and a line segment from + * (x1,y1) to (x2,y2). + * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment + * @param {number} x1 + * @param {number} y1 + * @param {number} x2 + * @param {number} y2 + * @param {number} x3 + * @param {number} y3 + * @private */ + Edge.prototype._getDistanceToEdge = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point + var returnValue = 0; + if (this.from != this.to) { + if (this.options.smoothCurves.enabled == true) { + var xVia, yVia; + if (this.options.smoothCurves.enabled == true && this.options.smoothCurves.dynamic == true) { + xVia = this.via.x; + yVia = this.via.y; + } + else { + var via = this._getViaCoordinates(); + xVia = via.x; + yVia = via.y; + } + var minDistance = 1e9; + var distance; + var i,t,x,y, lastX, lastY; + for (i = 0; i < 10; i++) { + t = 0.1*i; + x = Math.pow(1-t,2)*x1 + (2*t*(1 - t))*xVia + Math.pow(t,2)*x2; + y = Math.pow(1-t,2)*y1 + (2*t*(1 - t))*yVia + Math.pow(t,2)*y2; + if (i > 0) { + distance = this._getDistanceToLine(lastX,lastY,x,y, x3,y3); + minDistance = distance < minDistance ? distance : minDistance; + } + lastX = x; lastY = y; + } + returnValue = minDistance; + } + else { + returnValue = this._getDistanceToLine(x1,y1,x2,y2,x3,y3); + } + } + else { + var x, y, dx, dy; + var radius = 0.25 * this.physics.springLength; + var node = this.from; + if (node.width > node.height) { + x = node.x + 0.5 * node.width; + y = node.y - radius; + } + else { + x = node.x + radius; + y = node.y - 0.5 * node.height; + } + dx = x - x3; + dy = y - y3; + returnValue = Math.abs(Math.sqrt(dx*dx + dy*dy) - radius); + } - // AMD export - if(true) { - !(__WEBPACK_AMD_DEFINE_RESULT__ = function() { - return Hammer; - }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - // commonjs export - } else if(typeof module !== 'undefined' && module.exports) { - module.exports = Hammer; - // browser export - } else { - window.Hammer = Hammer; - } - - })(window); + if (this.labelDimensions.left < x3 && + this.labelDimensions.left + this.labelDimensions.width > x3 && + this.labelDimensions.top < y3 && + this.labelDimensions.top + this.labelDimensions.height > y3) { + return 0; + } + else { + return returnValue; + } + }; -/***/ }, -/* 60 */ -/***/ function(module, exports, __webpack_require__) { + Edge.prototype._getDistanceToLine = function(x1,y1,x2,y2,x3,y3) { + var px = x2-x1, + py = y2-y1, + something = px*px + py*py, + u = ((x3 - x1) * px + (y3 - y1) * py) / something; - /** - * Creation of the ClusterMixin var. - * - * This contains all the functions the Network object can use to employ clustering - */ + if (u > 1) { + u = 1; + } + else if (u < 0) { + u = 0; + } - /** - * This is only called in the constructor of the network object - * - */ - exports.startWithClustering = function() { - // cluster if the data set is big - this.clusterToFit(this.constants.clustering.initialMaxNodes, true); + var x = x1 + u * px, + y = y1 + u * py, + dx = x - x3, + dy = y - y3; - // updates the lables after clustering - this.updateLabels(); + //# Note: If the actual distance does not matter, + //# if you only want to compare what this function + //# returns to other results of this function, you + //# can just return the squared distance instead + //# (i.e. remove the sqrt) to gain a little performance - // this is called here because if clusterin is disabled, the start and stabilize are called in - // the setData function. - if (this.stabilize) { - this._stabilize(); - } - this.start(); + return Math.sqrt(dx*dx + dy*dy); }; /** - * This function clusters until the initialMaxNodes has been reached + * This allows the zoom level of the network to influence the rendering * - * @param {Number} maxNumberOfNodes - * @param {Boolean} reposition + * @param scale */ - exports.clusterToFit = function(maxNumberOfNodes, reposition) { - var numberOfNodes = this.nodeIndices.length; + Edge.prototype.setScale = function(scale) { + this.networkScaleInv = 1.0/scale; + }; - var maxLevels = 50; - var level = 0; - // we first cluster the hubs, then we pull in the outliers, repeat - while (numberOfNodes > maxNumberOfNodes && level < maxLevels) { - if (level % 3 == 0) { - this.forceAggregateHubs(true); - this.normalizeClusterLevels(); - } - else { - this.increaseClusterLevel(); // this also includes a cluster normalization - } + Edge.prototype.select = function() { + this.selected = true; + }; - numberOfNodes = this.nodeIndices.length; - level += 1; - } + Edge.prototype.unselect = function() { + this.selected = false; + }; - // after the clustering we reposition the nodes to reduce the initial chaos - if (level > 0 && reposition == true) { - this.repositionNodes(); + Edge.prototype.positionBezierNode = function() { + if (this.via !== null && this.from !== null && this.to !== null) { + this.via.x = 0.5 * (this.from.x + this.to.x); + this.via.y = 0.5 * (this.from.y + this.to.y); + } + else if (this.via !== null) { + this.via.x = 0; + this.via.y = 0; } - this._updateCalculationNodes(); }; /** - * This function can be called to open up a specific cluster. It is only called by - * It will unpack the cluster back one level. - * - * @param node | Node object: cluster to open. + * This function draws the control nodes for the manipulator. + * In order to enable this, only set the this.controlNodesEnabled to true. + * @param ctx */ - exports.openCluster = function(node) { - var isMovingBeforeClustering = this.moving; - if (node.clusterSize > this.constants.clustering.sectorThreshold && this._nodeInActiveArea(node) && - !(this._sector() == "default" && this.nodeIndices.length == 1)) { - // this loads a new sector, loads the nodes and edges and nodeIndices of it. - this._addSector(node); - var level = 0; + Edge.prototype._drawControlNodes = function(ctx) { + if (this.controlNodesEnabled == true) { + if (this.controlNodes.from === null && this.controlNodes.to === null) { + var nodeIdFrom = "edgeIdFrom:".concat(this.id); + var nodeIdTo = "edgeIdTo:".concat(this.id); + var constants = { + nodes:{group:'', radius:7, borderWidth:2, borderWidthSelected: 2}, + physics:{damping:0}, + clustering: {maxNodeSizeIncrements: 0 ,nodeScaling: {width:0, height: 0, radius:0}} + }; + this.controlNodes.from = new Node( + {id:nodeIdFrom, + shape:'dot', + color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}} + },{},{},constants); + this.controlNodes.to = new Node( + {id:nodeIdTo, + shape:'dot', + color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}} + },{},{},constants); + } - // we decluster until we reach a decent number of nodes - while ((this.nodeIndices.length < this.constants.clustering.initialMaxNodes) && (level < 10)) { - this.decreaseClusterLevel(); - level += 1; + this.controlNodes.positions = {}; + if (this.controlNodes.from.selected == false) { + this.controlNodes.positions.from = this.getControlNodeFromPosition(ctx); + this.controlNodes.from.x = this.controlNodes.positions.from.x; + this.controlNodes.from.y = this.controlNodes.positions.from.y; + } + if (this.controlNodes.to.selected == false) { + this.controlNodes.positions.to = this.getControlNodeToPosition(ctx); + this.controlNodes.to.x = this.controlNodes.positions.to.x; + this.controlNodes.to.y = this.controlNodes.positions.to.y; } + this.controlNodes.from.draw(ctx); + this.controlNodes.to.draw(ctx); } else { - this._expandClusterNode(node,false,true); - - // update the index list, dynamic edges and labels - this._updateNodeIndexList(); - this._updateDynamicEdges(); - this._updateCalculationNodes(); - this.updateLabels(); - } - - // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded - if (this.moving != isMovingBeforeClustering) { - this.start(); + this.controlNodes = {from:null, to:null, positions:{}}; } }; - /** - * This calls the updateClustes with default arguments + * Enable control nodes. + * @private */ - exports.updateClustersDefault = function() { - if (this.constants.clustering.enabled == true) { - this.updateClusters(0,false,false); - } + Edge.prototype._enableControlNodes = function() { + this.fromBackup = this.from; + this.toBackup = this.to; + this.controlNodesEnabled = true; }; - /** - * This function can be called to increase the cluster level. This means that the nodes with only one edge connection will - * be clustered with their connected node. This can be repeated as many times as needed. - * This can be called externally (by a keybind for instance) to reduce the complexity of big datasets. + * disable control nodes and remove from dynamicEdges from old node + * @private */ - exports.increaseClusterLevel = function() { - this.updateClusters(-1,false,true); - }; - + Edge.prototype._disableControlNodes = function() { + this.fromId = this.from.id; + this.toId = this.to.id; + if (this.fromId != this.fromBackup.id) { // from was changed, remove edge from old 'from' node dynamic edges + this.fromBackup.detachEdge(this); + } + else if (this.toId != this.toBackup.id) { // to was changed, remove edge from old 'to' node dynamic edges + this.toBackup.detachEdge(this); + } - /** - * This function can be called to decrease the cluster level. This means that the nodes with only one edge connection will - * be unpacked if they are a cluster. This can be repeated as many times as needed. - * This can be called externally (by a key-bind for instance) to look into clusters without zooming. - */ - exports.decreaseClusterLevel = function() { - this.updateClusters(1,false,true); + this.fromBackup = null; + this.toBackup = null; + this.controlNodesEnabled = false; }; /** - * This is the main clustering function. It clusters and declusters on zoom or forced - * This function clusters on zoom, it can be called with a predefined zoom direction - * If out, check if we can form clusters, if in, check if we can open clusters. - * This function is only called from _zoom() - * - * @param {Number} zoomDirection | -1 / 0 / +1 for zoomOut / determineByZoom / zoomIn - * @param {Boolean} recursive | enabled or disable recursive calling of the opening of clusters - * @param {Boolean} force | enabled or disable forcing - * @param {Boolean} doNotStart | if true do not call start - * + * This checks if one of the control nodes is selected and if so, returns the control node object. Else it returns null. + * @param x + * @param y + * @returns {null} + * @private */ - exports.updateClusters = function(zoomDirection,recursive,force,doNotStart) { - var isMovingBeforeClustering = this.moving; - var amountOfNodes = this.nodeIndices.length; - - // on zoom out collapse the sector if the scale is at the level the sector was made - if (this.previousScale > this.scale && zoomDirection == 0) { - this._collapseSector(); - } - - // check if we zoom in or out - if (this.previousScale > this.scale || zoomDirection == -1) { // zoom out - // forming clusters when forced pulls outliers in. When not forced, the edge length of the - // outer nodes determines if it is being clustered - this._formClusters(force); - } - else if (this.previousScale < this.scale || zoomDirection == 1) { // zoom in - if (force == true) { - // _openClusters checks for each node if the formationScale of the cluster is smaller than - // the current scale and if so, declusters. When forced, all clusters are reduced by one step - this._openClusters(recursive,force); - } - else { - // if a cluster takes up a set percentage of the active window - this._openClustersBySize(); - } - } - this._updateNodeIndexList(); - - // if a cluster was NOT formed and the user zoomed out, we try clustering by hubs - if (this.nodeIndices.length == amountOfNodes && (this.previousScale > this.scale || zoomDirection == -1)) { - this._aggregateHubs(force); - this._updateNodeIndexList(); - } + Edge.prototype._getSelectedControlNode = function(x,y) { + var positions = this.controlNodes.positions; + var fromDistance = Math.sqrt(Math.pow(x - positions.from.x,2) + Math.pow(y - positions.from.y,2)); + var toDistance = Math.sqrt(Math.pow(x - positions.to.x ,2) + Math.pow(y - positions.to.y ,2)); - // we now reduce chains. - if (this.previousScale > this.scale || zoomDirection == -1) { // zoom out - this.handleChains(); - this._updateNodeIndexList(); + if (fromDistance < 15) { + this.connectedNode = this.from; + this.from = this.controlNodes.from; + return this.controlNodes.from; } - - this.previousScale = this.scale; - - // rest of the update the index list, dynamic edges and labels - this._updateDynamicEdges(); - this.updateLabels(); - - // if a cluster was formed, we increase the clusterSession - if (this.nodeIndices.length < amountOfNodes) { // this means a clustering operation has taken place - this.clusterSession += 1; - // if clusters have been made, we normalize the cluster level - this.normalizeClusterLevels(); + else if (toDistance < 15) { + this.connectedNode = this.to; + this.to = this.controlNodes.to; + return this.controlNodes.to; } - - if (doNotStart == false || doNotStart === undefined) { - // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded - if (this.moving != isMovingBeforeClustering) { - this.start(); - } + else { + return null; } - - this._updateCalculationNodes(); }; - /** - * This function handles the chains. It is called on every updateClusters(). - */ - exports.handleChains = function() { - // after clustering we check how many chains there are - var chainPercentage = this._getChainFraction(); - if (chainPercentage > this.constants.clustering.chainThreshold) { - this._reduceAmountOfChains(1 - this.constants.clustering.chainThreshold / chainPercentage) - - } - }; /** - * this functions starts clustering by hubs - * The minimum hub threshold is set globally - * + * this resets the control nodes to their original position. * @private */ - exports._aggregateHubs = function(force) { - this._getHubSize(); - this._formClustersByHub(force,false); + Edge.prototype._restoreControlNodes = function() { + if (this.controlNodes.from.selected == true) { + this.from = this.connectedNode; + this.connectedNode = null; + this.controlNodes.from.unselect(); + } + else if (this.controlNodes.to.selected == true) { + this.to = this.connectedNode; + this.connectedNode = null; + this.controlNodes.to.unselect(); + } }; - /** - * This function is fired by keypress. It forces hubs to form. + * this calculates the position of the control nodes on the edges of the parent nodes. * + * @param ctx + * @returns {x: *, y: *} */ - exports.forceAggregateHubs = function(doNotStart) { - var isMovingBeforeClustering = this.moving; - var amountOfNodes = this.nodeIndices.length; - - this._aggregateHubs(true); - - // update the index list, dynamic edges and labels - this._updateNodeIndexList(); - this._updateDynamicEdges(); - this.updateLabels(); - - // if a cluster was formed, we increase the clusterSession - if (this.nodeIndices.length != amountOfNodes) { - this.clusterSession += 1; + Edge.prototype.getControlNodeFromPosition = function(ctx) { + // draw arrow head + var controlnodeFromPos; + if (this.options.smoothCurves.enabled == true) { + controlnodeFromPos = this._findBorderPosition(true, ctx); } + else { + var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var dx = (this.to.x - this.from.x); + var dy = (this.to.y - this.from.y); + var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); - if (doNotStart == false || doNotStart === undefined) { - // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded - if (this.moving != isMovingBeforeClustering) { - this.start(); - } + var fromBorderDist = this.from.distanceToBorder(ctx, angle + Math.PI); + var fromBorderPoint = (edgeSegmentLength - fromBorderDist) / edgeSegmentLength; + controlnodeFromPos = {}; + controlnodeFromPos.x = (fromBorderPoint) * this.from.x + (1 - fromBorderPoint) * this.to.x; + controlnodeFromPos.y = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y; } + + return controlnodeFromPos; }; /** - * If a cluster takes up more than a set percentage of the screen, open the cluster + * this calculates the position of the control nodes on the edges of the parent nodes. * - * @private + * @param ctx + * @returns {{from: {x: number, y: number}, to: {x: *, y: *}}} */ - exports._openClustersBySize = function() { - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - var node = this.nodes[nodeId]; - if (node.inView() == true) { - if ((node.width*this.scale > this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientWidth) || - (node.height*this.scale > this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientHeight)) { - this.openCluster(node); - } - } - } + Edge.prototype.getControlNodeToPosition = function(ctx) { + // draw arrow head + var controlnodeFromPos,controlnodeToPos; + if (this.options.smoothCurves.enabled == true) { + controlnodeToPos = this._findBorderPosition(false, ctx); } - }; - + else { + var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var dx = (this.to.x - this.from.x); + var dy = (this.to.y - this.from.y); + var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); + var toBorderDist = this.to.distanceToBorder(ctx, angle); + var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; - /** - * This function loops over all nodes in the nodeIndices list. For each node it checks if it is a cluster and if it - * has to be opened based on the current zoom level. - * - * @private - */ - exports._openClusters = function(recursive,force) { - for (var i = 0; i < this.nodeIndices.length; i++) { - var node = this.nodes[this.nodeIndices[i]]; - this._expandClusterNode(node,recursive,force); - this._updateCalculationNodes(); + controlnodeToPos = {}; + controlnodeToPos.x = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x; + controlnodeToPos.y = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y; } + + return controlnodeToPos; }; + module.exports = Edge; + +/***/ }, +/* 58 */ +/***/ function(module, exports, __webpack_require__) { + /** - * This function checks if a node has to be opened. This is done by checking the zoom level. - * If the node contains child nodes, this function is recursively called on the child nodes as well. - * This recursive behaviour is optional and can be set by the recursive argument. - * - * @param {Node} parentNode | to check for cluster and expand - * @param {Boolean} recursive | enabled or disable recursive calling - * @param {Boolean} force | enabled or disable forcing - * @param {Boolean} [openAll] | This will recursively force all nodes in the parent to be released - * @private + * Popup is a class to create a popup window with some text + * @param {Element} container The container object. + * @param {Number} [x] + * @param {Number} [y] + * @param {String} [text] + * @param {Object} [style] An object containing borderColor, + * backgroundColor, etc. */ - exports._expandClusterNode = function(parentNode, recursive, force, openAll) { - // first check if node is a cluster - if (parentNode.clusterSize > 1) { - // this means that on a double tap event or a zoom event, the cluster fully unpacks if it is smaller than 20 - if (parentNode.clusterSize < this.constants.clustering.sectorThreshold) { - openAll = true; - } - recursive = openAll ? true : recursive; - - // if the last child has been added on a smaller scale than current scale decluster - if (parentNode.formationScale < this.scale || force == true) { - // we will check if any of the contained child nodes should be removed from the cluster - for (var containedNodeId in parentNode.containedNodes) { - if (parentNode.containedNodes.hasOwnProperty(containedNodeId)) { - var childNode = parentNode.containedNodes[containedNodeId]; + function Popup(container, x, y, text, style) { + if (container) { + this.container = container; + } + else { + this.container = document.body; + } - // force expand will expand the largest cluster size clusters. Since we cluster from outside in, we assume that - // the largest cluster is the one that comes from outside - if (force == true) { - if (childNode.clusterSession == parentNode.clusterSessions[parentNode.clusterSessions.length-1] - || openAll) { - this._expelChildFromParent(parentNode,containedNodeId,recursive,force,openAll); - } - } - else { - if (this._nodeInActiveArea(parentNode)) { - this._expelChildFromParent(parentNode,containedNodeId,recursive,force,openAll); - } - } + // x, y and text are optional, see if a style object was passed in their place + if (style === undefined) { + if (typeof x === "object") { + style = x; + x = undefined; + } else if (typeof text === "object") { + style = text; + text = undefined; + } else { + // for backwards compatibility, in case clients other than Network are creating Popup directly + style = { + fontColor: 'black', + fontSize: 14, // px + fontFace: 'verdana', + color: { + border: '#666', + background: '#FFFFC6' } } } } - }; - - /** - * ONLY CALLED FROM _expandClusterNode - * - * This function will expel a child_node from a parent_node. This is to de-cluster the node. This function will remove - * the child node from the parent contained_node object and put it back into the global nodes object. - * The same holds for the edge that was connected to the child node. It is moved back into the global edges object. - * - * @param {Node} parentNode | the parent node - * @param {String} containedNodeId | child_node id as it is contained in the containedNodes object of the parent node - * @param {Boolean} recursive | This will also check if the child needs to be expanded. - * With force and recursive both true, the entire cluster is unpacked - * @param {Boolean} force | This will disregard the zoom level and will expel this child from the parent - * @param {Boolean} openAll | This will recursively force all nodes in the parent to be released - * @private - */ - exports._expelChildFromParent = function(parentNode, containedNodeId, recursive, force, openAll) { - var childNode = parentNode.containedNodes[containedNodeId]; - - // if child node has been added on smaller scale than current, kick out - if (childNode.formationScale < this.scale || force == true) { - // unselect all selected items - this._unselectAll(); - // put the child node back in the global nodes object - this.nodes[containedNodeId] = childNode; + this.x = 0; + this.y = 0; + this.padding = 5; - // release the contained edges from this childNode back into the global edges - this._releaseContainedEdges(parentNode,childNode); + if (x !== undefined && y !== undefined ) { + this.setPosition(x, y); + } + if (text !== undefined) { + this.setText(text); + } - // reconnect rerouted edges to the childNode - this._connectEdgeBackToChild(parentNode,childNode); + // create the frame + this.frame = document.createElement("div"); + var styleAttr = this.frame.style; + styleAttr.position = "absolute"; + styleAttr.visibility = "hidden"; + styleAttr.border = "1px solid " + style.color.border; + styleAttr.color = style.fontColor; + styleAttr.fontSize = style.fontSize + "px"; + styleAttr.fontFamily = style.fontFace; + styleAttr.padding = this.padding + "px"; + styleAttr.backgroundColor = style.color.background; + styleAttr.borderRadius = "3px"; + styleAttr.MozBorderRadius = "3px"; + styleAttr.WebkitBorderRadius = "3px"; + styleAttr.boxShadow = "3px 3px 10px rgba(128, 128, 128, 0.5)"; + styleAttr.whiteSpace = "nowrap"; + this.container.appendChild(this.frame); + } - // validate all edges in dynamicEdges - this._validateEdges(parentNode); + /** + * @param {number} x Horizontal position of the popup window + * @param {number} y Vertical position of the popup window + */ + Popup.prototype.setPosition = function(x, y) { + this.x = parseInt(x); + this.y = parseInt(y); + }; - // undo the changes from the clustering operation on the parent node - parentNode.options.mass -= childNode.options.mass; - parentNode.clusterSize -= childNode.clusterSize; - parentNode.options.fontSize = Math.min(this.constants.clustering.maxFontSize, this.constants.nodes.fontSize + this.constants.clustering.fontSizeMultiplier*(parentNode.clusterSize-1)); - parentNode.dynamicEdgesLength = parentNode.dynamicEdges.length; + /** + * Set the content for the popup window. This can be HTML code or text. + * @param {string | Element} content + */ + Popup.prototype.setText = function(content) { + if (content instanceof Element) { + this.frame.innerHTML = ''; + this.frame.appendChild(content); + } + else { + this.frame.innerHTML = content; // string containing text or HTML + } + }; - // place the child node near the parent, not at the exact same location to avoid chaos in the system - childNode.x = parentNode.x + parentNode.growthIndicator * (0.5 - Math.random()); - childNode.y = parentNode.y + parentNode.growthIndicator * (0.5 - Math.random()); + /** + * Show the popup window + * @param {boolean} show Optional. Show or hide the window + */ + Popup.prototype.show = function (show) { + if (show === undefined) { + show = true; + } - // remove node from the list - delete parentNode.containedNodes[containedNodeId]; + if (show) { + var height = this.frame.clientHeight; + var width = this.frame.clientWidth; + var maxHeight = this.frame.parentNode.clientHeight; + var maxWidth = this.frame.parentNode.clientWidth; - // check if there are other childs with this clusterSession in the parent. - var othersPresent = false; - for (var childNodeId in parentNode.containedNodes) { - if (parentNode.containedNodes.hasOwnProperty(childNodeId)) { - if (parentNode.containedNodes[childNodeId].clusterSession == childNode.clusterSession) { - othersPresent = true; - break; - } - } + var top = (this.y - height); + if (top + height + this.padding > maxHeight) { + top = maxHeight - height - this.padding; } - // if there are no others, remove the cluster session from the list - if (othersPresent == false) { - parentNode.clusterSessions.pop(); + if (top < this.padding) { + top = this.padding; } - this._repositionBezierNodes(childNode); - // this._repositionBezierNodes(parentNode); + var left = this.x; + if (left + width + this.padding > maxWidth) { + left = maxWidth - width - this.padding; + } + if (left < this.padding) { + left = this.padding; + } - // remove the clusterSession from the child node - childNode.clusterSession = 0; + this.frame.style.left = left + "px"; + this.frame.style.top = top + "px"; + this.frame.style.visibility = "visible"; + } + else { + this.hide(); + } + }; - // recalculate the size of the node on the next time the node is rendered - parentNode.clearSizeCache(); + /** + * Hide the popup window + */ + Popup.prototype.hide = function () { + this.frame.style.visibility = "hidden"; + }; - // restart the simulation to reorganise all nodes - this.moving = true; - } + module.exports = Popup; - // check if a further expansion step is possible if recursivity is enabled - if (recursive == true) { - this._expandClusterNode(childNode,recursive,force,openAll); + +/***/ }, +/* 59 */ +/***/ function(module, exports, __webpack_require__) { + + var PhysicsMixin = __webpack_require__(60); + var ClusterMixin = __webpack_require__(64); + var SectorsMixin = __webpack_require__(65); + var SelectionMixin = __webpack_require__(66); + var ManipulationMixin = __webpack_require__(67); + var NavigationMixin = __webpack_require__(68); + var HierarchicalLayoutMixin = __webpack_require__(69); + + /** + * Load a mixin into the network object + * + * @param {Object} sourceVariable | this object has to contain functions. + * @private + */ + exports._loadMixin = function (sourceVariable) { + for (var mixinFunction in sourceVariable) { + if (sourceVariable.hasOwnProperty(mixinFunction)) { + this[mixinFunction] = sourceVariable[mixinFunction]; + } } }; /** - * position the bezier nodes at the center of the edges + * removes a mixin from the network object. * - * @param node + * @param {Object} sourceVariable | this object has to contain functions. * @private */ - exports._repositionBezierNodes = function(node) { - for (var i = 0; i < node.dynamicEdges.length; i++) { - node.dynamicEdges[i].positionBezierNode(); + exports._clearMixin = function (sourceVariable) { + for (var mixinFunction in sourceVariable) { + if (sourceVariable.hasOwnProperty(mixinFunction)) { + this[mixinFunction] = undefined; + } } }; /** - * This function checks if any nodes at the end of their trees have edges below a threshold length - * This function is called only from updateClusters() - * forceLevelCollapse ignores the length of the edge and collapses one level - * This means that a node with only one edge will be clustered with its connected node + * Mixin the physics system and initialize the parameters required. * * @private - * @param {Boolean} force */ - exports._formClusters = function(force) { - if (force == false) { - this._formClustersByZoom(); + exports._loadPhysicsSystem = function () { + this._loadMixin(PhysicsMixin); + this._loadSelectedForceSolver(); + if (this.constants.configurePhysics == true) { + this._loadPhysicsConfiguration(); } else { - this._forceClustersByZoom(); + this._cleanupPhysicsConfiguration(); } }; /** - * This function handles the clustering by zooming out, this is based on a minimum edge distance + * Mixin the cluster system and initialize the parameters required. * * @private */ - exports._formClustersByZoom = function() { - var dx,dy,length, - minLength = this.constants.clustering.clusterEdgeThreshold/this.scale; + exports._loadClusterSystem = function () { + this.clusterSession = 0; + this.hubThreshold = 5; + this._loadMixin(ClusterMixin); + }; - // check if any edges are shorter than minLength and start the clustering - // the clustering favours the node with the larger mass - for (var edgeId in this.edges) { - if (this.edges.hasOwnProperty(edgeId)) { - var edge = this.edges[edgeId]; - if (edge.connected) { - if (edge.toId != edge.fromId) { - dx = (edge.to.x - edge.from.x); - dy = (edge.to.y - edge.from.y); - length = Math.sqrt(dx * dx + dy * dy); + /** + * Mixin the sector system and initialize the parameters required + * + * @private + */ + exports._loadSectorSystem = function () { + this.sectors = {}; + this.activeSector = ["default"]; + this.sectors["active"] = {}; + this.sectors["active"]["default"] = {"nodes": {}, + "edges": {}, + "nodeIndices": [], + "formationScale": 1.0, + "drawingNode": undefined }; + this.sectors["frozen"] = {}; + this.sectors["support"] = {"nodes": {}, + "edges": {}, + "nodeIndices": [], + "formationScale": 1.0, + "drawingNode": undefined }; - if (length < minLength) { - // first check which node is larger - var parentNode = edge.from; - var childNode = edge.to; - if (edge.to.options.mass > edge.from.options.mass) { - parentNode = edge.to; - childNode = edge.from; - } + this.nodeIndices = this.sectors["active"]["default"]["nodeIndices"]; // the node indices list is used to speed up the computation of the repulsion fields - if (childNode.dynamicEdgesLength == 1) { - this._addToCluster(parentNode,childNode,false); - } - else if (parentNode.dynamicEdgesLength == 1) { - this._addToCluster(childNode,parentNode,false); - } - } - } - } - } - } + this._loadMixin(SectorsMixin); }; + /** - * This function forces the network to cluster all nodes with only one connecting edge to their - * connected node. + * Mixin the selection system and initialize the parameters required * * @private */ - exports._forceClustersByZoom = function() { - for (var nodeId in this.nodes) { - // another node could have absorbed this child. - if (this.nodes.hasOwnProperty(nodeId)) { - var childNode = this.nodes[nodeId]; - - // the edges can be swallowed by another decrease - if (childNode.dynamicEdgesLength == 1 && childNode.dynamicEdges.length != 0) { - var edge = childNode.dynamicEdges[0]; - var parentNode = (edge.toId == childNode.id) ? this.nodes[edge.fromId] : this.nodes[edge.toId]; + exports._loadSelectionSystem = function () { + this.selectionObj = {nodes: {}, edges: {}}; - // group to the largest node - if (childNode.id != parentNode.id) { - if (parentNode.options.mass > childNode.options.mass) { - this._addToCluster(parentNode,childNode,true); - } - else { - this._addToCluster(childNode,parentNode,true); - } - } - } - } - } + this._loadMixin(SelectionMixin); }; /** - * To keep the nodes of roughly equal size we normalize the cluster levels. - * This function clusters a node to its smallest connected neighbour. + * Mixin the navigationUI (User Interface) system and initialize the parameters required * - * @param node * @private */ - exports._clusterToSmallestNeighbour = function(node) { - var smallestNeighbour = -1; - var smallestNeighbourNode = null; - for (var i = 0; i < node.dynamicEdges.length; i++) { - if (node.dynamicEdges[i] !== undefined) { - var neighbour = null; - if (node.dynamicEdges[i].fromId != node.id) { - neighbour = node.dynamicEdges[i].from; + exports._loadManipulationSystem = function () { + // reset global variables -- these are used by the selection of nodes and edges. + this.blockConnectingEdgeSelection = false; + this.forceAppendSelection = false; + + if (this.constants.dataManipulation.enabled == true) { + // load the manipulator HTML elements. All styling done in css. + if (this.manipulationDiv === undefined) { + this.manipulationDiv = document.createElement('div'); + this.manipulationDiv.className = 'network-manipulationDiv'; + if (this.editMode == true) { + this.manipulationDiv.style.display = "block"; } - else if (node.dynamicEdges[i].toId != node.id) { - neighbour = node.dynamicEdges[i].to; + else { + this.manipulationDiv.style.display = "none"; } + this.frame.appendChild(this.manipulationDiv); + } - - if (neighbour != null && smallestNeighbour > neighbour.clusterSessions.length) { - smallestNeighbour = neighbour.clusterSessions.length; - smallestNeighbourNode = neighbour; + if (this.editModeDiv === undefined) { + this.editModeDiv = document.createElement('div'); + this.editModeDiv.className = 'network-manipulation-editMode'; + if (this.editMode == true) { + this.editModeDiv.style.display = "none"; } + else { + this.editModeDiv.style.display = "block"; + } + this.frame.appendChild(this.editModeDiv); + } + + if (this.closeDiv === undefined) { + this.closeDiv = document.createElement('div'); + this.closeDiv.className = 'network-manipulation-closeDiv'; + this.closeDiv.style.display = this.manipulationDiv.style.display; + this.frame.appendChild(this.closeDiv); } + + // load the manipulation functions + this._loadMixin(ManipulationMixin); + + // create the manipulator toolbar + this._createManipulatorBar(); } + else { + if (this.manipulationDiv !== undefined) { + // removes all the bindings and overloads + this._createManipulatorBar(); - if (neighbour != null && this.nodes[neighbour.id] !== undefined) { - this._addToCluster(neighbour, node, true); + // remove the manipulation divs + this.frame.removeChild(this.manipulationDiv); + this.frame.removeChild(this.editModeDiv); + this.frame.removeChild(this.closeDiv); + + this.manipulationDiv = undefined; + this.editModeDiv = undefined; + this.closeDiv = undefined; + // remove the mixin functions + this._clearMixin(ManipulationMixin); + } } }; /** - * This function forms clusters from hubs, it loops over all nodes + * Mixin the navigation (User Interface) system and initialize the parameters required * - * @param {Boolean} force | Disregard zoom level - * @param {Boolean} onlyEqual | This only clusters a hub with a specific number of edges * @private */ - exports._formClustersByHub = function(force, onlyEqual) { - // we loop over all nodes in the list - for (var nodeId in this.nodes) { - // we check if it is still available since it can be used by the clustering in this loop - if (this.nodes.hasOwnProperty(nodeId)) { - this._formClusterFromHub(this.nodes[nodeId],force,onlyEqual); - } + exports._loadNavigationControls = function () { + this._loadMixin(NavigationMixin); + // the clean function removes the button divs, this is done to remove the bindings. + this._cleanNavigation(); + if (this.constants.navigation.enabled == true) { + this._loadNavigationElements(); } }; + /** - * This function forms a cluster from a specific preselected hub node + * Mixin the hierarchical layout system. * - * @param {Node} hubNode | the node we will cluster as a hub - * @param {Boolean} force | Disregard zoom level - * @param {Boolean} onlyEqual | This only clusters a hub with a specific number of edges - * @param {Number} [absorptionSizeOffset] | * @private */ - exports._formClusterFromHub = function(hubNode, force, onlyEqual, absorptionSizeOffset) { - if (absorptionSizeOffset === undefined) { - absorptionSizeOffset = 0; - } - // we decide if the node is a hub - if ((hubNode.dynamicEdgesLength >= this.hubThreshold && onlyEqual == false) || - (hubNode.dynamicEdgesLength == this.hubThreshold && onlyEqual == true)) { - // initialize variables - var dx,dy,length; - var minLength = this.constants.clustering.clusterEdgeThreshold/this.scale; - var allowCluster = false; + exports._loadHierarchySystem = function () { + this._loadMixin(HierarchicalLayoutMixin); + }; - // we create a list of edges because the dynamicEdges change over the course of this loop - var edgesIdarray = []; - var amountOfInitialEdges = hubNode.dynamicEdges.length; - for (var j = 0; j < amountOfInitialEdges; j++) { - edgesIdarray.push(hubNode.dynamicEdges[j].id); - } - // if the hub clustering is not forces, we check if one of the edges connected - // to a cluster is small enough based on the constants.clustering.clusterEdgeThreshold - if (force == false) { - allowCluster = false; - for (j = 0; j < amountOfInitialEdges; j++) { - var edge = this.edges[edgesIdarray[j]]; - if (edge !== undefined) { - if (edge.connected) { - if (edge.toId != edge.fromId) { - dx = (edge.to.x - edge.from.x); - dy = (edge.to.y - edge.from.y); - length = Math.sqrt(dx * dx + dy * dy); +/***/ }, +/* 60 */ +/***/ function(module, exports, __webpack_require__) { - if (length < minLength) { - allowCluster = true; - break; - } - } - } - } - } - } + var util = __webpack_require__(1); + var RepulsionMixin = __webpack_require__(61); + var HierarchialRepulsionMixin = __webpack_require__(62); + var BarnesHutMixin = __webpack_require__(63); - // start the clustering if allowed - if ((!force && allowCluster) || force) { - // we loop over all edges INITIALLY connected to this hub - for (j = 0; j < amountOfInitialEdges; j++) { - edge = this.edges[edgesIdarray[j]]; - // the edge can be clustered by this function in a previous loop - if (edge !== undefined) { - var childNode = this.nodes[(edge.fromId == hubNode.id) ? edge.toId : edge.fromId]; - // we do not want hubs to merge with other hubs nor do we want to cluster itself. - if ((childNode.dynamicEdges.length <= (this.hubThreshold + absorptionSizeOffset)) && - (childNode.id != hubNode.id)) { - this._addToCluster(hubNode,childNode,force); - } - } - } - } - } + /** + * Toggling barnes Hut calculation on and off. + * + * @private + */ + exports._toggleBarnesHut = function () { + this.constants.physics.barnesHut.enabled = !this.constants.physics.barnesHut.enabled; + this._loadSelectedForceSolver(); + this.moving = true; + this.start(); }; - /** - * This function adds the child node to the parent node, creating a cluster if it is not already. + * This loads the node force solver based on the barnes hut or repulsion algorithm * - * @param {Node} parentNode | this is the node that will house the child node - * @param {Node} childNode | this node will be deleted from the global this.nodes and stored in the parent node - * @param {Boolean} force | true will only update the remainingEdges at the very end of the clustering, ensuring single level collapse * @private */ - exports._addToCluster = function(parentNode, childNode, force) { - // join child node in the parent node - parentNode.containedNodes[childNode.id] = childNode; - - // manage all the edges connected to the child and parent nodes - for (var i = 0; i < childNode.dynamicEdges.length; i++) { - var edge = childNode.dynamicEdges[i]; - if (edge.toId == parentNode.id || edge.fromId == parentNode.id) { // edge connected to parentNode - this._addToContainedEdges(parentNode,childNode,edge); - } - else { - this._connectEdgeToCluster(parentNode,childNode,edge); - } - } - // a contained node has no dynamic edges. - childNode.dynamicEdges = []; - - // remove circular edges from clusters - this._containCircularEdgesFromNode(parentNode,childNode); - - - // remove the childNode from the global nodes object - delete this.nodes[childNode.id]; + exports._loadSelectedForceSolver = function () { + // this overloads the this._calculateNodeForces + if (this.constants.physics.barnesHut.enabled == true) { + this._clearMixin(RepulsionMixin); + this._clearMixin(HierarchialRepulsionMixin); - // update the properties of the child and parent - var massBefore = parentNode.options.mass; - childNode.clusterSession = this.clusterSession; - parentNode.options.mass += childNode.options.mass; - parentNode.clusterSize += childNode.clusterSize; - parentNode.options.fontSize = Math.min(this.constants.clustering.maxFontSize, this.constants.nodes.fontSize + this.constants.clustering.fontSizeMultiplier*parentNode.clusterSize); + this.constants.physics.centralGravity = this.constants.physics.barnesHut.centralGravity; + this.constants.physics.springLength = this.constants.physics.barnesHut.springLength; + this.constants.physics.springConstant = this.constants.physics.barnesHut.springConstant; + this.constants.physics.damping = this.constants.physics.barnesHut.damping; - // keep track of the clustersessions so we can open the cluster up as it has been formed. - if (parentNode.clusterSessions[parentNode.clusterSessions.length - 1] != this.clusterSession) { - parentNode.clusterSessions.push(this.clusterSession); + this._loadMixin(BarnesHutMixin); } + else if (this.constants.physics.hierarchicalRepulsion.enabled == true) { + this._clearMixin(BarnesHutMixin); + this._clearMixin(RepulsionMixin); - // forced clusters only open from screen size and double tap - if (force == true) { - // parentNode.formationScale = Math.pow(1 - (1.0/11.0),this.clusterSession+3); - parentNode.formationScale = 0; + this.constants.physics.centralGravity = this.constants.physics.hierarchicalRepulsion.centralGravity; + this.constants.physics.springLength = this.constants.physics.hierarchicalRepulsion.springLength; + this.constants.physics.springConstant = this.constants.physics.hierarchicalRepulsion.springConstant; + this.constants.physics.damping = this.constants.physics.hierarchicalRepulsion.damping; + + this._loadMixin(HierarchialRepulsionMixin); } else { - parentNode.formationScale = this.scale; // The latest child has been added on this scale - } - - // recalculate the size of the node on the next time the node is rendered - parentNode.clearSizeCache(); - - // set the pop-out scale for the childnode - parentNode.containedNodes[childNode.id].formationScale = parentNode.formationScale; - - // nullify the movement velocity of the child, this is to avoid hectic behaviour - childNode.clearVelocity(); + this._clearMixin(BarnesHutMixin); + this._clearMixin(HierarchialRepulsionMixin); + this.barnesHutTree = undefined; - // the mass has altered, preservation of energy dictates the velocity to be updated - parentNode.updateVelocity(massBefore); + this.constants.physics.centralGravity = this.constants.physics.repulsion.centralGravity; + this.constants.physics.springLength = this.constants.physics.repulsion.springLength; + this.constants.physics.springConstant = this.constants.physics.repulsion.springConstant; + this.constants.physics.damping = this.constants.physics.repulsion.damping; - // restart the simulation to reorganise all nodes - this.moving = true; + this._loadMixin(RepulsionMixin); + } }; - /** - * This function will apply the changes made to the remainingEdges during the formation of the clusters. - * This is a seperate function to allow for level-wise collapsing of the node barnesHutTree. - * It has to be called if a level is collapsed. It is called by _formClusters(). + * Before calculating the forces, we check if we need to cluster to keep up performance and we check + * if there is more than one node. If it is just one node, we dont calculate anything. + * * @private */ - exports._updateDynamicEdges = function() { - for (var i = 0; i < this.nodeIndices.length; i++) { - var node = this.nodes[this.nodeIndices[i]]; - node.dynamicEdgesLength = node.dynamicEdges.length; - - // this corrects for multiple edges pointing at the same other node - var correction = 0; - if (node.dynamicEdgesLength > 1) { - for (var j = 0; j < node.dynamicEdgesLength - 1; j++) { - var edgeToId = node.dynamicEdges[j].toId; - var edgeFromId = node.dynamicEdges[j].fromId; - for (var k = j+1; k < node.dynamicEdgesLength; k++) { - if ((node.dynamicEdges[k].toId == edgeToId && node.dynamicEdges[k].fromId == edgeFromId) || - (node.dynamicEdges[k].fromId == edgeToId && node.dynamicEdges[k].toId == edgeFromId)) { - correction += 1; - } - } - } + exports._initializeForceCalculation = function () { + // stop calculation if there is only one node + if (this.nodeIndices.length == 1) { + this.nodes[this.nodeIndices[0]]._setForce(0, 0); + } + else { + // if there are too many nodes on screen, we cluster without repositioning + if (this.nodeIndices.length > this.constants.clustering.clusterThreshold && this.constants.clustering.enabled == true) { + this.clusterToFit(this.constants.clustering.reduceToNodes, false); } - node.dynamicEdgesLength -= correction; + + // we now start the force calculation + this._calculateForces(); } }; /** - * This adds an edge from the childNode to the contained edges of the parent node - * - * @param parentNode | Node object - * @param childNode | Node object - * @param edge | Edge object + * Calculate the external forces acting on the nodes + * Forces are caused by: edges, repulsing forces between nodes, gravity * @private */ - exports._addToContainedEdges = function(parentNode, childNode, edge) { - // create an array object if it does not yet exist for this childNode - if (!(parentNode.containedEdges.hasOwnProperty(childNode.id))) { - parentNode.containedEdges[childNode.id] = [] - } - // add this edge to the list - parentNode.containedEdges[childNode.id].push(edge); + exports._calculateForces = function () { + // Gravity is required to keep separated groups from floating off + // the forces are reset to zero in this loop by using _setForce instead + // of _addForce - // remove the edge from the global edges object - delete this.edges[edge.id]; + this._calculateGravitationalForces(); + this._calculateNodeForces(); - // remove the edge from the parent object - for (var i = 0; i < parentNode.dynamicEdges.length; i++) { - if (parentNode.dynamicEdges[i].id == edge.id) { - parentNode.dynamicEdges.splice(i,1); - break; + if (this.constants.physics.springConstant > 0) { + if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { + this._calculateSpringForcesWithSupport(); + } + else { + if (this.constants.physics.hierarchicalRepulsion.enabled == true) { + this._calculateHierarchicalSpringForces(); + } + else { + this._calculateSpringForces(); + } } } }; + /** - * This function connects an edge that was connected to a child node to the parent node. - * It keeps track of which nodes it has been connected to with the originalId array. + * Smooth curves are created by adding invisible nodes in the center of the edges. These nodes are also + * handled in the calculateForces function. We then use a quadratic curve with the center node as control. + * This function joins the datanodes and invisible (called support) nodes into one object. + * We do this so we do not contaminate this.nodes with the support nodes. * - * @param {Node} parentNode | Node object - * @param {Node} childNode | Node object - * @param {Edge} edge | Edge object * @private */ - exports._connectEdgeToCluster = function(parentNode, childNode, edge) { - // handle circular edges - if (edge.toId == edge.fromId) { - this._addToContainedEdges(parentNode, childNode, edge); - } - else { - if (edge.toId == childNode.id) { // edge connected to other node on the "to" side - edge.originalToId.push(childNode.id); - edge.to = parentNode; - edge.toId = parentNode.id; - } - else { // edge connected to other node with the "from" side + exports._updateCalculationNodes = function () { + if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { + this.calculationNodes = {}; + this.calculationNodeIndices = []; - edge.originalFromId.push(childNode.id); - edge.from = parentNode; - edge.fromId = parentNode.id; + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + this.calculationNodes[nodeId] = this.nodes[nodeId]; + } + } + var supportNodes = this.sectors['support']['nodes']; + for (var supportNodeId in supportNodes) { + if (supportNodes.hasOwnProperty(supportNodeId)) { + if (this.edges.hasOwnProperty(supportNodes[supportNodeId].parentEdgeId)) { + this.calculationNodes[supportNodeId] = supportNodes[supportNodeId]; + } + else { + supportNodes[supportNodeId]._setForce(0, 0); + } + } } - this._addToReroutedEdges(parentNode,childNode,edge); + for (var idx in this.calculationNodes) { + if (this.calculationNodes.hasOwnProperty(idx)) { + this.calculationNodeIndices.push(idx); + } + } + } + else { + this.calculationNodes = this.nodes; + this.calculationNodeIndices = this.nodeIndices; } }; /** - * If a node is connected to itself, a circular edge is drawn. When clustering we want to contain - * these edges inside of the cluster. + * this function applies the central gravity effect to keep groups from floating off * - * @param parentNode - * @param childNode * @private */ - exports._containCircularEdgesFromNode = function(parentNode, childNode) { - // manage all the edges connected to the child and parent nodes - for (var i = 0; i < parentNode.dynamicEdges.length; i++) { - var edge = parentNode.dynamicEdges[i]; - // handle circular edges - if (edge.toId == edge.fromId) { - this._addToContainedEdges(parentNode, childNode, edge); + exports._calculateGravitationalForces = function () { + var dx, dy, distance, node, i; + var nodes = this.calculationNodes; + var gravity = this.constants.physics.centralGravity; + var gravityForce = 0; + + for (i = 0; i < this.calculationNodeIndices.length; i++) { + node = nodes[this.calculationNodeIndices[i]]; + node.damping = this.constants.physics.damping; // possibly add function to alter damping properties of clusters. + // gravity does not apply when we are in a pocket sector + if (this._sector() == "default" && gravity != 0) { + dx = -node.x; + dy = -node.y; + distance = Math.sqrt(dx * dx + dy * dy); + + gravityForce = (distance == 0) ? 0 : (gravity / distance); + node.fx = dx * gravityForce; + node.fy = dy * gravityForce; + } + else { + node.fx = 0; + node.fy = 0; } } }; + + /** - * This adds an edge from the childNode to the rerouted edges of the parent node + * this function calculates the effects of the springs in the case of unsmooth curves. * - * @param parentNode | Node object - * @param childNode | Node object - * @param edge | Edge object * @private */ - exports._addToReroutedEdges = function(parentNode, childNode, edge) { - // create an array object if it does not yet exist for this childNode - // we store the edge in the rerouted edges so we can restore it when the cluster pops open - if (!(parentNode.reroutedEdges.hasOwnProperty(childNode.id))) { - parentNode.reroutedEdges[childNode.id] = []; - } - parentNode.reroutedEdges[childNode.id].push(edge); + exports._calculateSpringForces = function () { + var edgeLength, edge, edgeId; + var dx, dy, fx, fy, springForce, distance; + var edges = this.edges; - // this edge becomes part of the dynamicEdges of the cluster node - parentNode.dynamicEdges.push(edge); - }; + // forces caused by the edges, modelled as springs + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.connected) { + // only calculate forces if nodes are in the same sector + if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { + edgeLength = edge.physics.springLength; + // this implies that the edges between big clusters are longer + edgeLength += (edge.to.clusterSize + edge.from.clusterSize - 2) * this.constants.clustering.edgeGrowth; + dx = (edge.from.x - edge.to.x); + dy = (edge.from.y - edge.to.y); + distance = Math.sqrt(dx * dx + dy * dy); + if (distance == 0) { + distance = 0.01; + } - /** - * This function connects an edge that was connected to a cluster node back to the child node. - * - * @param parentNode | Node object - * @param childNode | Node object - * @private - */ - exports._connectEdgeBackToChild = function(parentNode, childNode) { - if (parentNode.reroutedEdges.hasOwnProperty(childNode.id)) { - for (var i = 0; i < parentNode.reroutedEdges[childNode.id].length; i++) { - var edge = parentNode.reroutedEdges[childNode.id][i]; - if (edge.originalFromId[edge.originalFromId.length-1] == childNode.id) { - edge.originalFromId.pop(); - edge.fromId = childNode.id; - edge.from = childNode; - } - else { - edge.originalToId.pop(); - edge.toId = childNode.id; - edge.to = childNode; - } + // the 1/distance is so the fx and fy can be calculated without sine or cosine. + springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance; - // append this edge to the list of edges connecting to the childnode - childNode.dynamicEdges.push(edge); + fx = dx * springForce; + fy = dy * springForce; - // remove the edge from the parent object - for (var j = 0; j < parentNode.dynamicEdges.length; j++) { - if (parentNode.dynamicEdges[j].id == edge.id) { - parentNode.dynamicEdges.splice(j,1); - break; + edge.from.fx += fx; + edge.from.fy += fy; + edge.to.fx -= fx; + edge.to.fy -= fy; } } } - // remove the entry from the rerouted edges - delete parentNode.reroutedEdges[childNode.id]; } }; + + /** - * When loops are clustered, an edge can be both in the rerouted array and the contained array. - * This function is called last to verify that all edges in dynamicEdges are in fact connected to the - * parentNode + * This function calculates the springforces on the nodes, accounting for the support nodes. * - * @param parentNode | Node object * @private */ - exports._validateEdges = function(parentNode) { - for (var i = 0; i < parentNode.dynamicEdges.length; i++) { - var edge = parentNode.dynamicEdges[i]; - if (parentNode.id != edge.toId && parentNode.id != edge.fromId) { - parentNode.dynamicEdges.splice(i,1); + exports._calculateSpringForcesWithSupport = function () { + var edgeLength, edge, edgeId, combinedClusterSize; + var edges = this.edges; + + // forces caused by the edges, modelled as springs + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.connected) { + // only calculate forces if nodes are in the same sector + if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { + if (edge.via != null) { + var node1 = edge.to; + var node2 = edge.via; + var node3 = edge.from; + + edgeLength = edge.physics.springLength; + + combinedClusterSize = node1.clusterSize + node3.clusterSize - 2; + + // this implies that the edges between big clusters are longer + edgeLength += combinedClusterSize * this.constants.clustering.edgeGrowth; + this._calculateSpringForce(node1, node2, 0.5 * edgeLength); + this._calculateSpringForce(node2, node3, 0.5 * edgeLength); + } + } + } } } }; /** - * This function released the contained edges back into the global domain and puts them back into the - * dynamic edges of both parent and child. + * This is the code actually performing the calculation for the function above. It is split out to avoid repetition. * - * @param {Node} parentNode | - * @param {Node} childNode | + * @param node1 + * @param node2 + * @param edgeLength * @private */ - exports._releaseContainedEdges = function(parentNode, childNode) { - for (var i = 0; i < parentNode.containedEdges[childNode.id].length; i++) { - var edge = parentNode.containedEdges[childNode.id][i]; + exports._calculateSpringForce = function (node1, node2, edgeLength) { + var dx, dy, fx, fy, springForce, distance; - // put the edge back in the global edges object - this.edges[edge.id] = edge; + dx = (node1.x - node2.x); + dy = (node1.y - node2.y); + distance = Math.sqrt(dx * dx + dy * dy); - // put the edge back in the dynamic edges of the child and parent - childNode.dynamicEdges.push(edge); - parentNode.dynamicEdges.push(edge); + if (distance == 0) { + distance = 0.01; } - // remove the entry from the contained edges - delete parentNode.containedEdges[childNode.id]; - }; + // the 1/distance is so the fx and fy can be calculated without sine or cosine. + springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance; + fx = dx * springForce; + fy = dy * springForce; + node1.fx += fx; + node1.fy += fy; + node2.fx -= fx; + node2.fy -= fy; + }; - // ------------------- UTILITY FUNCTIONS ---------------------------- // + exports._cleanupPhysicsConfiguration = function() { + if (this.physicsConfiguration !== undefined) { + while (this.physicsConfiguration.hasChildNodes()) { + this.physicsConfiguration.removeChild(this.physicsConfiguration.firstChild); + } + this.physicsConfiguration.parentNode.removeChild(this.physicsConfiguration); + this.physicsConfiguration = undefined; + } + } /** - * This updates the node labels for all nodes (for debugging purposes) + * Load the HTML for the physics config and bind it + * @private */ - exports.updateLabels = function() { - var nodeId; - // update node labels - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - var node = this.nodes[nodeId]; - if (node.clusterSize > 1) { - node.label = "[".concat(String(node.clusterSize),"]"); - } - } - } - - // update node labels - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - if (node.clusterSize == 1) { - if (node.originalLabel !== undefined) { - node.label = node.originalLabel; - } - else { - node.label = String(node.id); - } - } - } - } + exports._loadPhysicsConfiguration = function () { + if (this.physicsConfiguration === undefined) { + this.backupConstants = {}; + util.deepExtend(this.backupConstants,this.constants); - // /* Debug Override */ - // for (nodeId in this.nodes) { - // if (this.nodes.hasOwnProperty(nodeId)) { - // node = this.nodes[nodeId]; - // node.label = String(node.level); - // } - // } + var hierarchicalLayoutDirections = ["LR", "RL", "UD", "DU"]; + this.physicsConfiguration = document.createElement('div'); + this.physicsConfiguration.className = "PhysicsConfiguration"; + this.physicsConfiguration.innerHTML = '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
Simulation Mode:
Barnes HutRepulsionHierarchical
' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
Options:
' + this.containerElement.parentElement.insertBefore(this.physicsConfiguration, this.containerElement); + this.optionsDiv = document.createElement("div"); + this.optionsDiv.style.fontSize = "14px"; + this.optionsDiv.style.fontFamily = "verdana"; + this.containerElement.parentElement.insertBefore(this.optionsDiv, this.containerElement); - }; + var rangeElement; + rangeElement = document.getElementById('graph_BH_gc'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_gc', -1, "physics_barnesHut_gravitationalConstant"); + rangeElement = document.getElementById('graph_BH_cg'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_cg', 1, "physics_centralGravity"); + rangeElement = document.getElementById('graph_BH_sc'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_sc', 1, "physics_springConstant"); + rangeElement = document.getElementById('graph_BH_sl'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_sl', 1, "physics_springLength"); + rangeElement = document.getElementById('graph_BH_damp'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_damp', 1, "physics_damping"); + rangeElement = document.getElementById('graph_R_nd'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_nd', 1, "physics_repulsion_nodeDistance"); + rangeElement = document.getElementById('graph_R_cg'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_cg', 1, "physics_centralGravity"); + rangeElement = document.getElementById('graph_R_sc'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_sc', 1, "physics_springConstant"); + rangeElement = document.getElementById('graph_R_sl'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_sl', 1, "physics_springLength"); + rangeElement = document.getElementById('graph_R_damp'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_damp', 1, "physics_damping"); - /** - * We want to keep the cluster level distribution rather small. This means we do not want unclustered nodes - * if the rest of the nodes are already a few cluster levels in. - * To fix this we use this function. It determines the min and max cluster level and sends nodes that have not - * clustered enough to the clusterToSmallestNeighbours function. - */ - exports.normalizeClusterLevels = function() { - var maxLevel = 0; - var minLevel = 1e9; - var clusterLevel = 0; - var nodeId; + rangeElement = document.getElementById('graph_H_nd'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_nd', 1, "physics_hierarchicalRepulsion_nodeDistance"); + rangeElement = document.getElementById('graph_H_cg'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_cg', 1, "physics_centralGravity"); + rangeElement = document.getElementById('graph_H_sc'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_sc', 1, "physics_springConstant"); + rangeElement = document.getElementById('graph_H_sl'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_sl', 1, "physics_springLength"); + rangeElement = document.getElementById('graph_H_damp'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_damp', 1, "physics_damping"); + rangeElement = document.getElementById('graph_H_direction'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_direction', hierarchicalLayoutDirections, "hierarchicalLayout_direction"); + rangeElement = document.getElementById('graph_H_levsep'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_levsep', 1, "hierarchicalLayout_levelSeparation"); + rangeElement = document.getElementById('graph_H_nspac'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_nspac', 1, "hierarchicalLayout_nodeSpacing"); - // we loop over all nodes in the list - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - clusterLevel = this.nodes[nodeId].clusterSessions.length; - if (maxLevel < clusterLevel) {maxLevel = clusterLevel;} - if (minLevel > clusterLevel) {minLevel = clusterLevel;} + var radioButton1 = document.getElementById("graph_physicsMethod1"); + var radioButton2 = document.getElementById("graph_physicsMethod2"); + var radioButton3 = document.getElementById("graph_physicsMethod3"); + radioButton2.checked = true; + if (this.constants.physics.barnesHut.enabled) { + radioButton1.checked = true; + } + if (this.constants.hierarchicalLayout.enabled) { + radioButton3.checked = true; } - } - if (maxLevel - minLevel > this.constants.clustering.clusterLevelDifference) { - var amountOfNodes = this.nodeIndices.length; - var targetLevel = maxLevel - this.constants.clustering.clusterLevelDifference; - // we loop over all nodes in the list - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - if (this.nodes[nodeId].clusterSessions.length < targetLevel) { - this._clusterToSmallestNeighbour(this.nodes[nodeId]); - } - } + var graph_toggleSmooth = document.getElementById("graph_toggleSmooth"); + var graph_repositionNodes = document.getElementById("graph_repositionNodes"); + var graph_generateOptions = document.getElementById("graph_generateOptions"); + + graph_toggleSmooth.onclick = graphToggleSmoothCurves.bind(this); + graph_repositionNodes.onclick = graphRepositionNodes.bind(this); + graph_generateOptions.onclick = graphGenerateOptions.bind(this); + if (this.constants.smoothCurves == true && this.constants.dynamicSmoothCurves == false) { + graph_toggleSmooth.style.background = "#A4FF56"; } - this._updateNodeIndexList(); - this._updateDynamicEdges(); - // if a cluster was formed, we increase the clusterSession - if (this.nodeIndices.length != amountOfNodes) { - this.clusterSession += 1; + else { + graph_toggleSmooth.style.background = "#FF8532"; } - } - }; + switchConfigurations.apply(this); + + radioButton1.onchange = switchConfigurations.bind(this); + radioButton2.onchange = switchConfigurations.bind(this); + radioButton3.onchange = switchConfigurations.bind(this); + } + }; /** - * This function determines if the cluster we want to decluster is in the active area - * this means around the zoom center + * This overwrites the this.constants. * - * @param {Node} node - * @returns {boolean} + * @param constantsVariableName + * @param value * @private */ - exports._nodeInActiveArea = function(node) { - return ( - Math.abs(node.x - this.areaCenter.x) <= this.constants.clustering.activeAreaBoxSize/this.scale - && - Math.abs(node.y - this.areaCenter.y) <= this.constants.clustering.activeAreaBoxSize/this.scale - ) + exports._overWriteGraphConstants = function (constantsVariableName, value) { + var nameArray = constantsVariableName.split("_"); + if (nameArray.length == 1) { + this.constants[nameArray[0]] = value; + } + else if (nameArray.length == 2) { + this.constants[nameArray[0]][nameArray[1]] = value; + } + else if (nameArray.length == 3) { + this.constants[nameArray[0]][nameArray[1]][nameArray[2]] = value; + } }; /** - * This is an adaptation of the original repositioning function. This is called if the system is clustered initially - * It puts large clusters away from the center and randomizes the order. - * + * this function is bound to the toggle smooth curves button. That is also why it is not in the prototype. */ - exports.repositionNodes = function() { - for (var i = 0; i < this.nodeIndices.length; i++) { - var node = this.nodes[this.nodeIndices[i]]; - if ((node.xFixed == false || node.yFixed == false)) { - var radius = 10 * 0.1*this.nodeIndices.length * Math.min(100,node.options.mass); - var angle = 2 * Math.PI * Math.random(); - if (node.xFixed == false) {node.x = radius * Math.cos(angle);} - if (node.yFixed == false) {node.y = radius * Math.sin(angle);} - this._repositionBezierNodes(node); - } - } - }; + function graphToggleSmoothCurves () { + this.constants.smoothCurves.enabled = !this.constants.smoothCurves.enabled; + var graph_toggleSmooth = document.getElementById("graph_toggleSmooth"); + if (this.constants.smoothCurves.enabled == true) {graph_toggleSmooth.style.background = "#A4FF56";} + else {graph_toggleSmooth.style.background = "#FF8532";} + this._configureSmoothCurves(false); + } /** - * We determine how many connections denote an important hub. - * We take the mean + 2*std as the important hub size. (Assuming a normal distribution of data, ~2.2%) + * this function is used to scramble the nodes * - * @private */ - exports._getHubSize = function() { - var average = 0; - var averageSquared = 0; - var hubCounter = 0; - var largestHub = 0; - - for (var i = 0; i < this.nodeIndices.length; i++) { - - var node = this.nodes[this.nodeIndices[i]]; - if (node.dynamicEdgesLength > largestHub) { - largestHub = node.dynamicEdgesLength; + function graphRepositionNodes () { + for (var nodeId in this.calculationNodes) { + if (this.calculationNodes.hasOwnProperty(nodeId)) { + this.calculationNodes[nodeId].vx = 0; this.calculationNodes[nodeId].vy = 0; + this.calculationNodes[nodeId].fx = 0; this.calculationNodes[nodeId].fy = 0; } - average += node.dynamicEdgesLength; - averageSquared += Math.pow(node.dynamicEdgesLength,2); - hubCounter += 1; } - average = average / hubCounter; - averageSquared = averageSquared / hubCounter; - - var variance = averageSquared - Math.pow(average,2); - - var standardDeviation = Math.sqrt(variance); - - this.hubThreshold = Math.floor(average + 2*standardDeviation); - - // always have at least one to cluster - if (this.hubThreshold > largestHub) { - this.hubThreshold = largestHub; + if (this.constants.hierarchicalLayout.enabled == true) { + this._setupHierarchicalLayout(); + showValueOfRange.call(this, 'graph_H_nd', 1, "physics_hierarchicalRepulsion_nodeDistance"); + showValueOfRange.call(this, 'graph_H_cg', 1, "physics_centralGravity"); + showValueOfRange.call(this, 'graph_H_sc', 1, "physics_springConstant"); + showValueOfRange.call(this, 'graph_H_sl', 1, "physics_springLength"); + showValueOfRange.call(this, 'graph_H_damp', 1, "physics_damping"); } - - // console.log("average",average,"averageSQ",averageSquared,"var",variance,"std",standardDeviation); - // console.log("hubThreshold:",this.hubThreshold); - }; - + else { + this.repositionNodes(); + } + this.moving = true; + this.start(); + } /** - * We reduce the amount of "extension nodes" or chains. These are not quickly clustered with the outliers and hubs methods - * with this amount we can cluster specifically on these chains. - * - * @param {Number} fraction | between 0 and 1, the percentage of chains to reduce - * @private + * this is used to generate an options file from the playing with physics system. */ - exports._reduceAmountOfChains = function(fraction) { - this.hubThreshold = 2; - var reduceAmount = Math.floor(this.nodeIndices.length * fraction); - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - if (this.nodes[nodeId].dynamicEdgesLength == 2 && this.nodes[nodeId].dynamicEdges.length >= 2) { - if (reduceAmount > 0) { - this._formClusterFromHub(this.nodes[nodeId],true,true,1); - reduceAmount -= 1; + function graphGenerateOptions () { + var options = "No options are required, default values used."; + var optionsSpecific = []; + var radioButton1 = document.getElementById("graph_physicsMethod1"); + var radioButton2 = document.getElementById("graph_physicsMethod2"); + if (radioButton1.checked == true) { + if (this.constants.physics.barnesHut.gravitationalConstant != this.backupConstants.physics.barnesHut.gravitationalConstant) {optionsSpecific.push("gravitationalConstant: " + this.constants.physics.barnesHut.gravitationalConstant);} + if (this.constants.physics.centralGravity != this.backupConstants.physics.barnesHut.centralGravity) {optionsSpecific.push("centralGravity: " + this.constants.physics.centralGravity);} + if (this.constants.physics.springLength != this.backupConstants.physics.barnesHut.springLength) {optionsSpecific.push("springLength: " + this.constants.physics.springLength);} + if (this.constants.physics.springConstant != this.backupConstants.physics.barnesHut.springConstant) {optionsSpecific.push("springConstant: " + this.constants.physics.springConstant);} + if (this.constants.physics.damping != this.backupConstants.physics.barnesHut.damping) {optionsSpecific.push("damping: " + this.constants.physics.damping);} + if (optionsSpecific.length != 0) { + options = "var options = {"; + options += "physics: {barnesHut: {"; + for (var i = 0; i < optionsSpecific.length; i++) { + options += optionsSpecific[i]; + if (i < optionsSpecific.length - 1) { + options += ", " } } + options += '}}' + } + if (this.constants.smoothCurves.enabled != this.backupConstants.smoothCurves.enabled) { + if (optionsSpecific.length == 0) {options = "var options = {";} + else {options += ", "} + options += "smoothCurves: " + this.constants.smoothCurves.enabled; + } + if (options != "No options are required, default values used.") { + options += '};' } } - }; - - /** - * We get the amount of "extension nodes" or chains. These are not quickly clustered with the outliers and hubs methods - * with this amount we can cluster specifically on these chains. - * - * @private - */ - exports._getChainFraction = function() { - var chains = 0; - var total = 0; - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - if (this.nodes[nodeId].dynamicEdgesLength == 2 && this.nodes[nodeId].dynamicEdges.length >= 2) { - chains += 1; + else if (radioButton2.checked == true) { + options = "var options = {"; + options += "physics: {barnesHut: {enabled: false}"; + if (this.constants.physics.repulsion.nodeDistance != this.backupConstants.physics.repulsion.nodeDistance) {optionsSpecific.push("nodeDistance: " + this.constants.physics.repulsion.nodeDistance);} + if (this.constants.physics.centralGravity != this.backupConstants.physics.repulsion.centralGravity) {optionsSpecific.push("centralGravity: " + this.constants.physics.centralGravity);} + if (this.constants.physics.springLength != this.backupConstants.physics.repulsion.springLength) {optionsSpecific.push("springLength: " + this.constants.physics.springLength);} + if (this.constants.physics.springConstant != this.backupConstants.physics.repulsion.springConstant) {optionsSpecific.push("springConstant: " + this.constants.physics.springConstant);} + if (this.constants.physics.damping != this.backupConstants.physics.repulsion.damping) {optionsSpecific.push("damping: " + this.constants.physics.damping);} + if (optionsSpecific.length != 0) { + options += ", repulsion: {"; + for (var i = 0; i < optionsSpecific.length; i++) { + options += optionsSpecific[i]; + if (i < optionsSpecific.length - 1) { + options += ", " + } } - total += 1; + options += '}}' + } + if (optionsSpecific.length == 0) {options += "}"} + if (this.constants.smoothCurves != this.backupConstants.smoothCurves) { + options += ", smoothCurves: " + this.constants.smoothCurves; } + options += '};' + } + else { + options = "var options = {"; + if (this.constants.physics.hierarchicalRepulsion.nodeDistance != this.backupConstants.physics.hierarchicalRepulsion.nodeDistance) {optionsSpecific.push("nodeDistance: " + this.constants.physics.hierarchicalRepulsion.nodeDistance);} + if (this.constants.physics.centralGravity != this.backupConstants.physics.hierarchicalRepulsion.centralGravity) {optionsSpecific.push("centralGravity: " + this.constants.physics.centralGravity);} + if (this.constants.physics.springLength != this.backupConstants.physics.hierarchicalRepulsion.springLength) {optionsSpecific.push("springLength: " + this.constants.physics.springLength);} + if (this.constants.physics.springConstant != this.backupConstants.physics.hierarchicalRepulsion.springConstant) {optionsSpecific.push("springConstant: " + this.constants.physics.springConstant);} + if (this.constants.physics.damping != this.backupConstants.physics.hierarchicalRepulsion.damping) {optionsSpecific.push("damping: " + this.constants.physics.damping);} + if (optionsSpecific.length != 0) { + options += "physics: {hierarchicalRepulsion: {"; + for (var i = 0; i < optionsSpecific.length; i++) { + options += optionsSpecific[i]; + if (i < optionsSpecific.length - 1) { + options += ", "; + } + } + options += '}},'; + } + options += 'hierarchicalLayout: {'; + optionsSpecific = []; + if (this.constants.hierarchicalLayout.direction != this.backupConstants.hierarchicalLayout.direction) {optionsSpecific.push("direction: " + this.constants.hierarchicalLayout.direction);} + if (Math.abs(this.constants.hierarchicalLayout.levelSeparation) != this.backupConstants.hierarchicalLayout.levelSeparation) {optionsSpecific.push("levelSeparation: " + this.constants.hierarchicalLayout.levelSeparation);} + if (this.constants.hierarchicalLayout.nodeSpacing != this.backupConstants.hierarchicalLayout.nodeSpacing) {optionsSpecific.push("nodeSpacing: " + this.constants.hierarchicalLayout.nodeSpacing);} + if (optionsSpecific.length != 0) { + for (var i = 0; i < optionsSpecific.length; i++) { + options += optionsSpecific[i]; + if (i < optionsSpecific.length - 1) { + options += ", " + } + } + options += '}' + } + else { + options += "enabled:true}"; + } + options += '};' } - return chains/total; - }; - - -/***/ }, -/* 61 */ -/***/ function(module, exports, __webpack_require__) { - var util = __webpack_require__(1); - var Node = __webpack_require__(40); - /** - * Creation of the SectorMixin var. - * - * This contains all the functions the Network object can use to employ the sector system. - * The sector system is always used by Network, though the benefits only apply to the use of clustering. - * If clustering is not used, there is no overhead except for a duplicate object with references to nodes and edges. - */ + this.optionsDiv.innerHTML = options; + } /** - * This function is only called by the setData function of the Network object. - * This loads the global references into the active sector. This initializes the sector. + * this is used to switch between barnesHut, repulsion and hierarchical. * - * @private */ - exports._putDataInSector = function() { - this.sectors["active"][this._sector()].nodes = this.nodes; - this.sectors["active"][this._sector()].edges = this.edges; - this.sectors["active"][this._sector()].nodeIndices = this.nodeIndices; - }; + function switchConfigurations () { + var ids = ["graph_BH_table", "graph_R_table", "graph_H_table"]; + var radioButton = document.querySelector('input[name="graph_physicsMethod"]:checked').value; + var tableId = "graph_" + radioButton + "_table"; + var table = document.getElementById(tableId); + table.style.display = "block"; + for (var i = 0; i < ids.length; i++) { + if (ids[i] != tableId) { + table = document.getElementById(ids[i]); + table.style.display = "none"; + } + } + this._restoreNodes(); + if (radioButton == "R") { + this.constants.hierarchicalLayout.enabled = false; + this.constants.physics.hierarchicalRepulsion.enabled = false; + this.constants.physics.barnesHut.enabled = false; + } + else if (radioButton == "H") { + if (this.constants.hierarchicalLayout.enabled == false) { + this.constants.hierarchicalLayout.enabled = true; + this.constants.physics.hierarchicalRepulsion.enabled = true; + this.constants.physics.barnesHut.enabled = false; + this.constants.smoothCurves.enabled = false; + this._setupHierarchicalLayout(); + } + } + else { + this.constants.hierarchicalLayout.enabled = false; + this.constants.physics.hierarchicalRepulsion.enabled = false; + this.constants.physics.barnesHut.enabled = true; + } + this._loadSelectedForceSolver(); + var graph_toggleSmooth = document.getElementById("graph_toggleSmooth"); + if (this.constants.smoothCurves.enabled == true) {graph_toggleSmooth.style.background = "#A4FF56";} + else {graph_toggleSmooth.style.background = "#FF8532";} + this.moving = true; + this.start(); + } /** - * /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the supplied (active) sector. If a type is defined, do the specific type + * this generates the ranges depending on the iniital values. * - * @param {String} sectorId - * @param {String} [sectorType] | "active" or "frozen" - * @private + * @param id + * @param map + * @param constantsVariableName */ - exports._switchToSector = function(sectorId, sectorType) { - if (sectorType === undefined || sectorType == "active") { - this._switchToActiveSector(sectorId); + function showValueOfRange (id,map,constantsVariableName) { + var valueId = id + "_value"; + var rangeValue = document.getElementById(id).value; + + if (Array.isArray(map)) { + document.getElementById(valueId).value = map[parseInt(rangeValue)]; + this._overWriteGraphConstants(constantsVariableName,map[parseInt(rangeValue)]); } else { - this._switchToFrozenSector(sectorId); + document.getElementById(valueId).value = parseInt(map) * parseFloat(rangeValue); + this._overWriteGraphConstants(constantsVariableName, parseInt(map) * parseFloat(rangeValue)); } - }; + if (constantsVariableName == "hierarchicalLayout_direction" || + constantsVariableName == "hierarchicalLayout_levelSeparation" || + constantsVariableName == "hierarchicalLayout_nodeSpacing") { + this._setupHierarchicalLayout(); + } + this.moving = true; + this.start(); + } - /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the supplied active sector. - * - * @param sectorId - * @private - */ - exports._switchToActiveSector = function(sectorId) { - this.nodeIndices = this.sectors["active"][sectorId]["nodeIndices"]; - this.nodes = this.sectors["active"][sectorId]["nodes"]; - this.edges = this.sectors["active"][sectorId]["edges"]; - }; - /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the supplied active sector. - * - * @private - */ - exports._switchToSupportSector = function() { - this.nodeIndices = this.sectors["support"]["nodeIndices"]; - this.nodes = this.sectors["support"]["nodes"]; - this.edges = this.sectors["support"]["edges"]; - }; +/***/ }, +/* 61 */ +/***/ function(module, exports, __webpack_require__) { /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the supplied frozen sector. + * Calculate the forces the nodes apply on each other based on a repulsion field. + * This field is linearly approximated. * - * @param sectorId * @private */ - exports._switchToFrozenSector = function(sectorId) { - this.nodeIndices = this.sectors["frozen"][sectorId]["nodeIndices"]; - this.nodes = this.sectors["frozen"][sectorId]["nodes"]; - this.edges = this.sectors["frozen"][sectorId]["edges"]; - }; + exports._calculateNodeForces = function () { + var dx, dy, angle, distance, fx, fy, combinedClusterSize, + repulsingForce, node1, node2, i, j; + var nodes = this.calculationNodes; + var nodeIndices = this.calculationNodeIndices; - /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the currently active sector. - * - * @private - */ - exports._loadLatestSector = function() { - this._switchToSector(this._sector()); + // approximation constants + var a_base = -2 / 3; + var b = 4 / 3; + + // repulsing forces between nodes + var nodeDistance = this.constants.physics.repulsion.nodeDistance; + var minimumDistance = nodeDistance; + + // we loop from i over all but the last entree in the array + // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j + for (i = 0; i < nodeIndices.length - 1; i++) { + node1 = nodes[nodeIndices[i]]; + for (j = i + 1; j < nodeIndices.length; j++) { + node2 = nodes[nodeIndices[j]]; + combinedClusterSize = node1.clusterSize + node2.clusterSize - 2; + + dx = node2.x - node1.x; + dy = node2.y - node1.y; + distance = Math.sqrt(dx * dx + dy * dy); + + // same condition as BarnesHut, making sure nodes are never 100% overlapping. + if (distance == 0) { + distance = 0.1*Math.random(); + dx = distance; + } + + minimumDistance = (combinedClusterSize == 0) ? nodeDistance : (nodeDistance * (1 + combinedClusterSize * this.constants.clustering.distanceAmplification)); + var a = a_base / minimumDistance; + if (distance < 2 * minimumDistance) { + if (distance < 0.5 * minimumDistance) { + repulsingForce = 1.0; + } + else { + repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)) + } + + // amplify the repulsion for clusters. + repulsingForce *= (combinedClusterSize == 0) ? 1 : 1 + combinedClusterSize * this.constants.clustering.forceAmplification; + repulsingForce = repulsingForce / Math.max(distance,0.01*minimumDistance); + + fx = dx * repulsingForce; + fy = dy * repulsingForce; + node1.fx -= fx; + node1.fy -= fy; + node2.fx += fx; + node2.fy += fy; + + } + } + } }; +/***/ }, +/* 62 */ +/***/ function(module, exports, __webpack_require__) { + /** - * This function returns the currently active sector Id + * Calculate the forces the nodes apply on eachother based on a repulsion field. + * This field is linearly approximated. * - * @returns {String} * @private */ - exports._sector = function() { - return this.activeSector[this.activeSector.length-1]; + exports._calculateNodeForces = function () { + var dx, dy, distance, fx, fy, + repulsingForce, node1, node2, i, j; + + var nodes = this.calculationNodes; + var nodeIndices = this.calculationNodeIndices; + + // repulsing forces between nodes + var nodeDistance = this.constants.physics.hierarchicalRepulsion.nodeDistance; + + // we loop from i over all but the last entree in the array + // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j + for (i = 0; i < nodeIndices.length - 1; i++) { + node1 = nodes[nodeIndices[i]]; + for (j = i + 1; j < nodeIndices.length; j++) { + node2 = nodes[nodeIndices[j]]; + + // nodes only affect nodes on their level + if (node1.level == node2.level) { + + dx = node2.x - node1.x; + dy = node2.y - node1.y; + distance = Math.sqrt(dx * dx + dy * dy); + + + var steepness = 0.05; + if (distance < nodeDistance) { + repulsingForce = -Math.pow(steepness*distance,2) + Math.pow(steepness*nodeDistance,2); + } + else { + repulsingForce = 0; + } + // normalize force with + if (distance == 0) { + distance = 0.01; + } + else { + repulsingForce = repulsingForce / distance; + } + fx = dx * repulsingForce; + fy = dy * repulsingForce; + + node1.fx -= fx; + node1.fy -= fy; + node2.fx += fx; + node2.fy += fy; + } + } + } }; /** - * This function returns the previously active sector Id + * this function calculates the effects of the springs in the case of unsmooth curves. * - * @returns {String} * @private */ - exports._previousSector = function() { - if (this.activeSector.length > 1) { - return this.activeSector[this.activeSector.length-2]; - } - else { - throw new TypeError('there are not enough sectors in the this.activeSector array.'); - } - }; + exports._calculateHierarchicalSpringForces = function () { + var edgeLength, edge, edgeId; + var dx, dy, fx, fy, springForce, distance; + var edges = this.edges; + var nodes = this.calculationNodes; + var nodeIndices = this.calculationNodeIndices; - /** - * We add the active sector at the end of the this.activeSector array - * This ensures it is the currently active sector returned by _sector() and it reaches the top - * of the activeSector stack. When we reverse our steps we move from the end to the beginning of this stack. - * - * @param newId - * @private - */ - exports._setActiveSector = function(newId) { - this.activeSector.push(newId); - }; + for (var i = 0; i < nodeIndices.length; i++) { + var node1 = nodes[nodeIndices[i]]; + node1.springFx = 0; + node1.springFy = 0; + } - /** - * We remove the currently active sector id from the active sector stack. This happens when - * we reactivate the previously active sector - * - * @private - */ - exports._forgetLastSector = function() { - this.activeSector.pop(); - }; + // forces caused by the edges, modelled as springs + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.connected) { + // only calculate forces if nodes are in the same sector + if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { + edgeLength = edge.physics.springLength; + // this implies that the edges between big clusters are longer + edgeLength += (edge.to.clusterSize + edge.from.clusterSize - 2) * this.constants.clustering.edgeGrowth; - /** - * This function creates a new active sector with the supplied newId. This newId - * is the expanding node id. - * - * @param {String} newId | Id of the new active sector - * @private - */ - exports._createNewSector = function(newId) { - // create the new sector - this.sectors["active"][newId] = {"nodes":{}, - "edges":{}, - "nodeIndices":[], - "formationScale": this.scale, - "drawingNode": undefined}; + dx = (edge.from.x - edge.to.x); + dy = (edge.from.y - edge.to.y); + distance = Math.sqrt(dx * dx + dy * dy); - // create the new sector render node. This gives visual feedback that you are in a new sector. - this.sectors["active"][newId]['drawingNode'] = new Node( - {id:newId, - color: { - background: "#eaefef", - border: "495c5e" - } - },{},{},this.constants); - this.sectors["active"][newId]['drawingNode'].clusterSize = 2; - }; + if (distance == 0) { + distance = 0.01; + } + // the 1/distance is so the fx and fy can be calculated without sine or cosine. + springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance; - /** - * This function removes the currently active sector. This is called when we create a new - * active sector. - * - * @param {String} sectorId | Id of the active sector that will be removed - * @private - */ - exports._deleteActiveSector = function(sectorId) { - delete this.sectors["active"][sectorId]; - }; + fx = dx * springForce; + fy = dy * springForce; - /** - * This function removes the currently active sector. This is called when we reactivate - * the previously active sector. - * - * @param {String} sectorId | Id of the active sector that will be removed - * @private - */ - exports._deleteFrozenSector = function(sectorId) { - delete this.sectors["frozen"][sectorId]; - }; + if (edge.to.level != edge.from.level) { + edge.to.springFx -= fx; + edge.to.springFy -= fy; + edge.from.springFx += fx; + edge.from.springFy += fy; + } + else { + var factor = 0.5; + edge.to.fx -= factor*fx; + edge.to.fy -= factor*fy; + edge.from.fx += factor*fx; + edge.from.fy += factor*fy; + } + } + } + } + } - /** - * Freezing an active sector means moving it from the "active" object to the "frozen" object. - * We copy the references, then delete the active entree. - * - * @param sectorId - * @private - */ - exports._freezeSector = function(sectorId) { - // we move the set references from the active to the frozen stack. - this.sectors["frozen"][sectorId] = this.sectors["active"][sectorId]; + // normalize spring forces + var springForce = 1; + var springFx, springFy; + for (i = 0; i < nodeIndices.length; i++) { + var node = nodes[nodeIndices[i]]; + springFx = Math.min(springForce,Math.max(-springForce,node.springFx)); + springFy = Math.min(springForce,Math.max(-springForce,node.springFy)); - // we have moved the sector data into the frozen set, we now remove it from the active set - this._deleteActiveSector(sectorId); - }; + node.fx += springFx; + node.fy += springFy; + } + // retain energy balance + var totalFx = 0; + var totalFy = 0; + for (i = 0; i < nodeIndices.length; i++) { + var node = nodes[nodeIndices[i]]; + totalFx += node.fx; + totalFy += node.fy; + } + var correctionFx = totalFx / nodeIndices.length; + var correctionFy = totalFy / nodeIndices.length; - /** - * This is the reverse operation of _freezeSector. Activating means moving the sector from the "frozen" - * object to the "active" object. - * - * @param sectorId - * @private - */ - exports._activateSector = function(sectorId) { - // we move the set references from the frozen to the active stack. - this.sectors["active"][sectorId] = this.sectors["frozen"][sectorId]; + for (i = 0; i < nodeIndices.length; i++) { + var node = nodes[nodeIndices[i]]; + node.fx -= correctionFx; + node.fy -= correctionFy; + } - // we have moved the sector data into the active set, we now remove it from the frozen stack - this._deleteFrozenSector(sectorId); }; +/***/ }, +/* 63 */ +/***/ function(module, exports, __webpack_require__) { /** - * This function merges the data from the currently active sector with a frozen sector. This is used - * in the process of reverting back to the previously active sector. - * The data that is placed in the frozen (the previously active) sector is the node that has been removed from it - * upon the creation of a new active sector. + * This function calculates the forces the nodes apply on eachother based on a gravitational model. + * The Barnes Hut method is used to speed up this N-body simulation. * - * @param sectorId * @private */ - exports._mergeThisWithFrozen = function(sectorId) { - // copy all nodes - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - this.sectors["frozen"][sectorId]["nodes"][nodeId] = this.nodes[nodeId]; - } - } + exports._calculateNodeForces = function() { + if (this.constants.physics.barnesHut.gravitationalConstant != 0) { + var node; + var nodes = this.calculationNodes; + var nodeIndices = this.calculationNodeIndices; + var nodeCount = nodeIndices.length; - // copy all edges (if not fully clustered, else there are no edges) - for (var edgeId in this.edges) { - if (this.edges.hasOwnProperty(edgeId)) { - this.sectors["frozen"][sectorId]["edges"][edgeId] = this.edges[edgeId]; - } - } + this._formBarnesHutTree(nodes,nodeIndices); - // merge the nodeIndices - for (var i = 0; i < this.nodeIndices.length; i++) { - this.sectors["frozen"][sectorId]["nodeIndices"].push(this.nodeIndices[i]); + var barnesHutTree = this.barnesHutTree; + + // place the nodes one by one recursively + for (var i = 0; i < nodeCount; i++) { + node = nodes[nodeIndices[i]]; + if (node.options.mass > 0) { + // starting with root is irrelevant, it never passes the BarnesHut condition + this._getForceContribution(barnesHutTree.root.children.NW,node); + this._getForceContribution(barnesHutTree.root.children.NE,node); + this._getForceContribution(barnesHutTree.root.children.SW,node); + this._getForceContribution(barnesHutTree.root.children.SE,node); + } + } } }; /** - * This clusters the sector to one cluster. It was a single cluster before this process started so - * we revert to that state. The clusterToFit function with a maximum size of 1 node does this. + * This function traverses the barnesHutTree. It checks when it can approximate distant nodes with their center of mass. + * If a region contains a single node, we check if it is not itself, then we apply the force. * + * @param parentBranch + * @param node * @private */ - exports._collapseThisToSingleCluster = function() { - this.clusterToFit(1,false); - }; + exports._getForceContribution = function(parentBranch,node) { + // we get no force contribution from an empty region + if (parentBranch.childrenCount > 0) { + var dx,dy,distance; + + // get the distance from the center of mass to the node. + dx = parentBranch.centerOfMass.x - node.x; + dy = parentBranch.centerOfMass.y - node.y; + distance = Math.sqrt(dx * dx + dy * dy); + // BarnesHut condition + // original condition : s/d < thetaInverted = passed === d/s > 1/theta = passed + // calcSize = 1/s --> d * 1/s > 1/theta = passed + if (distance * parentBranch.calcSize > this.constants.physics.barnesHut.thetaInverted) { + // duplicate code to reduce function calls to speed up program + if (distance == 0) { + distance = 0.1*Math.random(); + dx = distance; + } + var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.options.mass / (distance * distance * distance); + var fx = dx * gravityForce; + var fy = dy * gravityForce; + node.fx += fx; + node.fy += fy; + } + else { + // Did not pass the condition, go into children if available + if (parentBranch.childrenCount == 4) { + this._getForceContribution(parentBranch.children.NW,node); + this._getForceContribution(parentBranch.children.NE,node); + this._getForceContribution(parentBranch.children.SW,node); + this._getForceContribution(parentBranch.children.SE,node); + } + else { // parentBranch must have only one node, if it was empty we wouldnt be here + if (parentBranch.children.data.id != node.id) { // if it is not self + // duplicate code to reduce function calls to speed up program + if (distance == 0) { + distance = 0.5*Math.random(); + dx = distance; + } + var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.options.mass / (distance * distance * distance); + var fx = dx * gravityForce; + var fy = dy * gravityForce; + node.fx += fx; + node.fy += fy; + } + } + } + } + }; /** - * We create a new active sector from the node that we want to open. + * This function constructs the barnesHut tree recursively. It creates the root, splits it and starts placing the nodes. * - * @param node + * @param nodes + * @param nodeIndices * @private */ - exports._addSector = function(node) { - // this is the currently active sector - var sector = this._sector(); - - // // this should allow me to select nodes from a frozen set. - // if (this.sectors['active'][sector]["nodes"].hasOwnProperty(node.id)) { - // console.log("the node is part of the active sector"); - // } - // else { - // console.log("I dont know what the fuck happened!!"); - // } + exports._formBarnesHutTree = function(nodes,nodeIndices) { + var node; + var nodeCount = nodeIndices.length; - // when we switch to a new sector, we remove the node that will be expanded from the current nodes list. - delete this.nodes[node.id]; + var minX = Number.MAX_VALUE, + minY = Number.MAX_VALUE, + maxX =-Number.MAX_VALUE, + maxY =-Number.MAX_VALUE; - var unqiueIdentifier = util.randomUUID(); + // get the range of the nodes + for (var i = 0; i < nodeCount; i++) { + var x = nodes[nodeIndices[i]].x; + var y = nodes[nodeIndices[i]].y; + if (nodes[nodeIndices[i]].options.mass > 0) { + if (x < minX) { minX = x; } + if (x > maxX) { maxX = x; } + if (y < minY) { minY = y; } + if (y > maxY) { maxY = y; } + } + } + // make the range a square + var sizeDiff = Math.abs(maxX - minX) - Math.abs(maxY - minY); // difference between X and Y + if (sizeDiff > 0) {minY -= 0.5 * sizeDiff; maxY += 0.5 * sizeDiff;} // xSize > ySize + else {minX += 0.5 * sizeDiff; maxX -= 0.5 * sizeDiff;} // xSize < ySize - // we fully freeze the currently active sector - this._freezeSector(sector); - // we create a new active sector. This sector has the Id of the node to ensure uniqueness - this._createNewSector(unqiueIdentifier); + var minimumTreeSize = 1e-5; + var rootSize = Math.max(minimumTreeSize,Math.abs(maxX - minX)); + var halfRootSize = 0.5 * rootSize; + var centerX = 0.5 * (minX + maxX), centerY = 0.5 * (minY + maxY); - // we add the active sector to the sectors array to be able to revert these steps later on - this._setActiveSector(unqiueIdentifier); + // construct the barnesHutTree + var barnesHutTree = { + root:{ + centerOfMass: {x:0, y:0}, + mass:0, + range: { + minX: centerX-halfRootSize,maxX:centerX+halfRootSize, + minY: centerY-halfRootSize,maxY:centerY+halfRootSize + }, + size: rootSize, + calcSize: 1 / rootSize, + children: { data:null}, + maxWidth: 0, + level: 0, + childrenCount: 4 + } + }; + this._splitBranch(barnesHutTree.root); - // we redirect the global references to the new sector's references. this._sector() now returns unqiueIdentifier - this._switchToSector(this._sector()); + // place the nodes one by one recursively + for (i = 0; i < nodeCount; i++) { + node = nodes[nodeIndices[i]]; + if (node.options.mass > 0) { + this._placeInTree(barnesHutTree.root,node); + } + } - // finally we add the node we removed from our previous active sector to the new active sector - this.nodes[node.id] = node; + // make global + this.barnesHutTree = barnesHutTree }; /** - * We close the sector that is currently open and revert back to the one before. - * If the active sector is the "default" sector, nothing happens. + * this updates the mass of a branch. this is increased by adding a node. * + * @param parentBranch + * @param node * @private */ - exports._collapseSector = function() { - // the currently active sector - var sector = this._sector(); - - // we cannot collapse the default sector - if (sector != "default") { - if ((this.nodeIndices.length == 1) || - (this.sectors["active"][sector]["drawingNode"].width*this.scale < this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientWidth) || - (this.sectors["active"][sector]["drawingNode"].height*this.scale < this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientHeight)) { - var previousSector = this._previousSector(); - - // we collapse the sector back to a single cluster - this._collapseThisToSingleCluster(); - - // we move the remaining nodes, edges and nodeIndices to the previous sector. - // This previous sector is the one we will reactivate - this._mergeThisWithFrozen(previousSector); - - // the previously active (frozen) sector now has all the data from the currently active sector. - // we can now delete the active sector. - this._deleteActiveSector(sector); - - // we activate the previously active (and currently frozen) sector. - this._activateSector(previousSector); + exports._updateBranchMass = function(parentBranch, node) { + var totalMass = parentBranch.mass + node.options.mass; + var totalMassInv = 1/totalMass; - // we load the references from the newly active sector into the global references - this._switchToSector(previousSector); + parentBranch.centerOfMass.x = parentBranch.centerOfMass.x * parentBranch.mass + node.x * node.options.mass; + parentBranch.centerOfMass.x *= totalMassInv; - // we forget the previously active sector because we reverted to the one before - this._forgetLastSector(); + parentBranch.centerOfMass.y = parentBranch.centerOfMass.y * parentBranch.mass + node.y * node.options.mass; + parentBranch.centerOfMass.y *= totalMassInv; - // finally, we update the node index list. - this._updateNodeIndexList(); + parentBranch.mass = totalMass; + var biggestSize = Math.max(Math.max(node.height,node.radius),node.width); + parentBranch.maxWidth = (parentBranch.maxWidth < biggestSize) ? biggestSize : parentBranch.maxWidth; - // we refresh the list with calulation nodes and calculation node indices. - this._updateCalculationNodes(); - } - } }; /** - * This runs a function in all active sectors. This is used in _redraw() and the _initializeForceCalculation(). + * determine in which branch the node will be placed. * - * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors - * | we dont pass the function itself because then the "this" is the window object - * | instead of the Network object - * @param {*} [argument] | Optional: arguments to pass to the runFunction + * @param parentBranch + * @param node + * @param skipMassUpdate * @private */ - exports._doInAllActiveSectors = function(runFunction,argument) { - var returnValues = []; - if (argument === undefined) { - for (var sector in this.sectors["active"]) { - if (this.sectors["active"].hasOwnProperty(sector)) { - // switch the global references to those of this sector - this._switchToActiveSector(sector); - returnValues.push( this[runFunction]() ); - } + exports._placeInTree = function(parentBranch,node,skipMassUpdate) { + if (skipMassUpdate != true || skipMassUpdate === undefined) { + // update the mass of the branch. + this._updateBranchMass(parentBranch,node); + } + + if (parentBranch.children.NW.range.maxX > node.x) { // in NW or SW + if (parentBranch.children.NW.range.maxY > node.y) { // in NW + this._placeInRegion(parentBranch,node,"NW"); + } + else { // in SW + this._placeInRegion(parentBranch,node,"SW"); } } - else { - for (var sector in this.sectors["active"]) { - if (this.sectors["active"].hasOwnProperty(sector)) { - // switch the global references to those of this sector - this._switchToActiveSector(sector); - var args = Array.prototype.splice.call(arguments, 1); - if (args.length > 1) { - returnValues.push( this[runFunction](args[0],args[1]) ); - } - else { - returnValues.push( this[runFunction](argument) ); - } - } + else { // in NE or SE + if (parentBranch.children.NW.range.maxY > node.y) { // in NE + this._placeInRegion(parentBranch,node,"NE"); + } + else { // in SE + this._placeInRegion(parentBranch,node,"SE"); } } - // we revert the global references back to our active sector - this._loadLatestSector(); - return returnValues; }; /** - * This runs a function in all active sectors. This is used in _redraw() and the _initializeForceCalculation(). + * actually place the node in a region (or branch) * - * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors - * | we dont pass the function itself because then the "this" is the window object - * | instead of the Network object - * @param {*} [argument] | Optional: arguments to pass to the runFunction + * @param parentBranch + * @param node + * @param region * @private */ - exports._doInSupportSector = function(runFunction,argument) { - var returnValues = false; - if (argument === undefined) { - this._switchToSupportSector(); - returnValues = this[runFunction](); - } - else { - this._switchToSupportSector(); - var args = Array.prototype.splice.call(arguments, 1); - if (args.length > 1) { - returnValues = this[runFunction](args[0],args[1]); - } - else { - returnValues = this[runFunction](argument); - } - } - // we revert the global references back to our active sector - this._loadLatestSector(); - return returnValues; + exports._placeInRegion = function(parentBranch,node,region) { + switch (parentBranch.children[region].childrenCount) { + case 0: // place node here + parentBranch.children[region].children.data = node; + parentBranch.children[region].childrenCount = 1; + this._updateBranchMass(parentBranch.children[region],node); + break; + case 1: // convert into children + // if there are two nodes exactly overlapping (on init, on opening of cluster etc.) + // we move one node a pixel and we do not put it in the tree. + if (parentBranch.children[region].children.data.x == node.x && + parentBranch.children[region].children.data.y == node.y) { + node.x += Math.random(); + node.y += Math.random(); + } + else { + this._splitBranch(parentBranch.children[region]); + this._placeInTree(parentBranch.children[region],node); + } + break; + case 4: // place in branch + this._placeInTree(parentBranch.children[region],node); + break; + } }; /** - * This runs a function in all frozen sectors. This is used in the _redraw(). + * this function splits a branch into 4 sub branches. If the branch contained a node, we place it in the subbranch + * after the split is complete. * - * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors - * | we don't pass the function itself because then the "this" is the window object - * | instead of the Network object - * @param {*} [argument] | Optional: arguments to pass to the runFunction + * @param parentBranch * @private */ - exports._doInAllFrozenSectors = function(runFunction,argument) { - if (argument === undefined) { - for (var sector in this.sectors["frozen"]) { - if (this.sectors["frozen"].hasOwnProperty(sector)) { - // switch the global references to those of this sector - this._switchToFrozenSector(sector); - this[runFunction](); - } - } + exports._splitBranch = function(parentBranch) { + // if the branch is shaded with a node, replace the node in the new subset. + var containedNode = null; + if (parentBranch.childrenCount == 1) { + containedNode = parentBranch.children.data; + parentBranch.mass = 0; parentBranch.centerOfMass.x = 0; parentBranch.centerOfMass.y = 0; } - else { - for (var sector in this.sectors["frozen"]) { - if (this.sectors["frozen"].hasOwnProperty(sector)) { - // switch the global references to those of this sector - this._switchToFrozenSector(sector); - var args = Array.prototype.splice.call(arguments, 1); - if (args.length > 1) { - this[runFunction](args[0],args[1]); - } - else { - this[runFunction](argument); - } - } - } + parentBranch.childrenCount = 4; + parentBranch.children.data = null; + this._insertRegion(parentBranch,"NW"); + this._insertRegion(parentBranch,"NE"); + this._insertRegion(parentBranch,"SW"); + this._insertRegion(parentBranch,"SE"); + + if (containedNode != null) { + this._placeInTree(parentBranch,containedNode); } - this._loadLatestSector(); }; /** - * This runs a function in all sectors. This is used in the _redraw(). + * This function subdivides the region into four new segments. + * Specifically, this inserts a single new segment. + * It fills the children section of the parentBranch * - * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors - * | we don't pass the function itself because then the "this" is the window object - * | instead of the Network object - * @param {*} [argument] | Optional: arguments to pass to the runFunction + * @param parentBranch + * @param region + * @param parentRange * @private */ - exports._doInAllSectors = function(runFunction,argument) { - var args = Array.prototype.splice.call(arguments, 1); - if (argument === undefined) { - this._doInAllActiveSectors(runFunction); - this._doInAllFrozenSectors(runFunction); - } - else { - if (args.length > 1) { - this._doInAllActiveSectors(runFunction,args[0],args[1]); - this._doInAllFrozenSectors(runFunction,args[0],args[1]); - } - else { - this._doInAllActiveSectors(runFunction,argument); - this._doInAllFrozenSectors(runFunction,argument); - } + exports._insertRegion = function(parentBranch, region) { + var minX,maxX,minY,maxY; + var childSize = 0.5 * parentBranch.size; + switch (region) { + case "NW": + minX = parentBranch.range.minX; + maxX = parentBranch.range.minX + childSize; + minY = parentBranch.range.minY; + maxY = parentBranch.range.minY + childSize; + break; + case "NE": + minX = parentBranch.range.minX + childSize; + maxX = parentBranch.range.maxX; + minY = parentBranch.range.minY; + maxY = parentBranch.range.minY + childSize; + break; + case "SW": + minX = parentBranch.range.minX; + maxX = parentBranch.range.minX + childSize; + minY = parentBranch.range.minY + childSize; + maxY = parentBranch.range.maxY; + break; + case "SE": + minX = parentBranch.range.minX + childSize; + maxX = parentBranch.range.maxX; + minY = parentBranch.range.minY + childSize; + maxY = parentBranch.range.maxY; + break; } + + + parentBranch.children[region] = { + centerOfMass:{x:0,y:0}, + mass:0, + range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY}, + size: 0.5 * parentBranch.size, + calcSize: 2 * parentBranch.calcSize, + children: {data:null}, + maxWidth: 0, + level: parentBranch.level+1, + childrenCount: 0 + }; }; /** - * This clears the nodeIndices list. We cannot use this.nodeIndices = [] because we would break the link with the - * active sector. Thus we clear the nodeIndices in the active sector, then reconnect the this.nodeIndices to it. + * This function is for debugging purposed, it draws the tree. * + * @param ctx + * @param color * @private */ - exports._clearNodeIndexList = function() { - var sector = this._sector(); - this.sectors["active"][sector]["nodeIndices"] = []; - this.nodeIndices = this.sectors["active"][sector]["nodeIndices"]; + exports._drawTree = function(ctx,color) { + if (this.barnesHutTree !== undefined) { + + ctx.lineWidth = 1; + + this._drawBranch(this.barnesHutTree.root,ctx,color); + } }; /** - * Draw the encompassing sector node + * This function is for debugging purposes. It draws the branches recursively. * + * @param branch * @param ctx - * @param sectorType + * @param color * @private */ - exports._drawSectorNodes = function(ctx,sectorType) { - var minY = 1e9, maxY = -1e9, minX = 1e9, maxX = -1e9, node; - for (var sector in this.sectors[sectorType]) { - if (this.sectors[sectorType].hasOwnProperty(sector)) { - if (this.sectors[sectorType][sector]["drawingNode"] !== undefined) { - - this._switchToSector(sector,sectorType); + exports._drawBranch = function(branch,ctx,color) { + if (color === undefined) { + color = "#FF0000"; + } - minY = 1e9; maxY = -1e9; minX = 1e9; maxX = -1e9; - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - node.resize(ctx); - if (minX > node.x - 0.5 * node.width) {minX = node.x - 0.5 * node.width;} - if (maxX < node.x + 0.5 * node.width) {maxX = node.x + 0.5 * node.width;} - if (minY > node.y - 0.5 * node.height) {minY = node.y - 0.5 * node.height;} - if (maxY < node.y + 0.5 * node.height) {maxY = node.y + 0.5 * node.height;} - } - } - node = this.sectors[sectorType][sector]["drawingNode"]; - node.x = 0.5 * (maxX + minX); - node.y = 0.5 * (maxY + minY); - node.width = 2 * (node.x - minX); - node.height = 2 * (node.y - minY); - node.options.radius = Math.sqrt(Math.pow(0.5*node.width,2) + Math.pow(0.5*node.height,2)); - node.setScale(this.scale); - node._drawCircle(ctx); - } - } + if (branch.childrenCount == 4) { + this._drawBranch(branch.children.NW,ctx); + this._drawBranch(branch.children.NE,ctx); + this._drawBranch(branch.children.SE,ctx); + this._drawBranch(branch.children.SW,ctx); } - }; + ctx.strokeStyle = color; + ctx.beginPath(); + ctx.moveTo(branch.range.minX,branch.range.minY); + ctx.lineTo(branch.range.maxX,branch.range.minY); + ctx.stroke(); - exports._drawAllSectorNodes = function(ctx) { - this._drawSectorNodes(ctx,"frozen"); - this._drawSectorNodes(ctx,"active"); - this._loadLatestSector(); + ctx.beginPath(); + ctx.moveTo(branch.range.maxX,branch.range.minY); + ctx.lineTo(branch.range.maxX,branch.range.maxY); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(branch.range.maxX,branch.range.maxY); + ctx.lineTo(branch.range.minX,branch.range.maxY); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(branch.range.minX,branch.range.maxY); + ctx.lineTo(branch.range.minX,branch.range.minY); + ctx.stroke(); + + /* + if (branch.mass > 0) { + ctx.circle(branch.centerOfMass.x, branch.centerOfMass.y, 3*branch.mass); + ctx.stroke(); + } + */ }; /***/ }, -/* 62 */ +/* 64 */ /***/ function(module, exports, __webpack_require__) { - var Node = __webpack_require__(40); - /** - * This function can be called from the _doInAllSectors function + * Creation of the ClusterMixin var. * - * @param object - * @param overlappingNodes - * @private + * This contains all the functions the Network object can use to employ clustering */ - exports._getNodesOverlappingWith = function(object, overlappingNodes) { - var nodes = this.nodes; - for (var nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - if (nodes[nodeId].isOverlappingWith(object)) { - overlappingNodes.push(nodeId); - } - } - } - }; /** - * retrieve all nodes overlapping with given object - * @param {Object} object An object with parameters left, top, right, bottom - * @return {Number[]} An array with id's of the overlapping nodes - * @private - */ - exports._getAllNodesOverlappingWith = function (object) { - var overlappingNodes = []; - this._doInAllActiveSectors("_getNodesOverlappingWith",object,overlappingNodes); - return overlappingNodes; - }; + * This is only called in the constructor of the network object + * + */ + exports.startWithClustering = function() { + // cluster if the data set is big + this.clusterToFit(this.constants.clustering.initialMaxNodes, true); + // updates the lables after clustering + this.updateLabels(); + + // this is called here because if clusterin is disabled, the start and stabilize are called in + // the setData function. + if (this.stabilize) { + this._stabilize(); + } + this.start(); + }; /** - * Return a position object in canvasspace from a single point in screenspace + * This function clusters until the initialMaxNodes has been reached * - * @param pointer - * @returns {{left: number, top: number, right: number, bottom: number}} - * @private + * @param {Number} maxNumberOfNodes + * @param {Boolean} reposition */ - exports._pointerToPositionObject = function(pointer) { - var x = this._XconvertDOMtoCanvas(pointer.x); - var y = this._YconvertDOMtoCanvas(pointer.y); + exports.clusterToFit = function(maxNumberOfNodes, reposition) { + var numberOfNodes = this.nodeIndices.length; - return { - left: x, - top: y, - right: x, - bottom: y - }; - }; + var maxLevels = 50; + var level = 0; + + // we first cluster the hubs, then we pull in the outliers, repeat + while (numberOfNodes > maxNumberOfNodes && level < maxLevels) { + if (level % 3 == 0) { + this.forceAggregateHubs(true); + this.normalizeClusterLevels(); + } + else { + this.increaseClusterLevel(); // this also includes a cluster normalization + } + + numberOfNodes = this.nodeIndices.length; + level += 1; + } + // after the clustering we reposition the nodes to reduce the initial chaos + if (level > 0 && reposition == true) { + this.repositionNodes(); + } + this._updateCalculationNodes(); + }; /** - * Get the top node at the a specific point (like a click) + * This function can be called to open up a specific cluster. It is only called by + * It will unpack the cluster back one level. * - * @param {{x: Number, y: Number}} pointer - * @return {Node | null} node - * @private + * @param node | Node object: cluster to open. */ - exports._getNodeAt = function (pointer) { - // we first check if this is an navigation controls element - var positionObject = this._pointerToPositionObject(pointer); - var overlappingNodes = this._getAllNodesOverlappingWith(positionObject); + exports.openCluster = function(node) { + var isMovingBeforeClustering = this.moving; + if (node.clusterSize > this.constants.clustering.sectorThreshold && this._nodeInActiveArea(node) && + !(this._sector() == "default" && this.nodeIndices.length == 1)) { + // this loads a new sector, loads the nodes and edges and nodeIndices of it. + this._addSector(node); + var level = 0; + + // we decluster until we reach a decent number of nodes + while ((this.nodeIndices.length < this.constants.clustering.initialMaxNodes) && (level < 10)) { + this.decreaseClusterLevel(); + level += 1; + } - // if there are overlapping nodes, select the last one, this is the - // one which is drawn on top of the others - if (overlappingNodes.length > 0) { - return this.nodes[overlappingNodes[overlappingNodes.length - 1]]; } else { - return null; + this._expandClusterNode(node,false,true); + + // update the index list, dynamic edges and labels + this._updateNodeIndexList(); + this._updateDynamicEdges(); + this._updateCalculationNodes(); + this.updateLabels(); + } + + // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded + if (this.moving != isMovingBeforeClustering) { + this.start(); } }; /** - * retrieve all edges overlapping with given object, selector is around center - * @param {Object} object An object with parameters left, top, right, bottom - * @return {Number[]} An array with id's of the overlapping nodes - * @private + * This calls the updateClustes with default arguments */ - exports._getEdgesOverlappingWith = function (object, overlappingEdges) { - var edges = this.edges; - for (var edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - if (edges[edgeId].isOverlappingWith(object)) { - overlappingEdges.push(edgeId); - } - } + exports.updateClustersDefault = function() { + if (this.constants.clustering.enabled == true) { + this.updateClusters(0,false,false); } }; /** - * retrieve all nodes overlapping with given object - * @param {Object} object An object with parameters left, top, right, bottom - * @return {Number[]} An array with id's of the overlapping nodes - * @private + * This function can be called to increase the cluster level. This means that the nodes with only one edge connection will + * be clustered with their connected node. This can be repeated as many times as needed. + * This can be called externally (by a keybind for instance) to reduce the complexity of big datasets. */ - exports._getAllEdgesOverlappingWith = function (object) { - var overlappingEdges = []; - this._doInAllActiveSectors("_getEdgesOverlappingWith",object,overlappingEdges); - return overlappingEdges; + exports.increaseClusterLevel = function() { + this.updateClusters(-1,false,true); }; + /** - * Place holder. To implement change the _getNodeAt to a _getObjectAt. Have the _getObjectAt call - * _getNodeAt and _getEdgesAt, then priortize the selection to user preferences. + * This function can be called to decrease the cluster level. This means that the nodes with only one edge connection will + * be unpacked if they are a cluster. This can be repeated as many times as needed. + * This can be called externally (by a key-bind for instance) to look into clusters without zooming. + */ + exports.decreaseClusterLevel = function() { + this.updateClusters(1,false,true); + }; + + + /** + * This is the main clustering function. It clusters and declusters on zoom or forced + * This function clusters on zoom, it can be called with a predefined zoom direction + * If out, check if we can form clusters, if in, check if we can open clusters. + * This function is only called from _zoom() + * + * @param {Number} zoomDirection | -1 / 0 / +1 for zoomOut / determineByZoom / zoomIn + * @param {Boolean} recursive | enabled or disable recursive calling of the opening of clusters + * @param {Boolean} force | enabled or disable forcing + * @param {Boolean} doNotStart | if true do not call start * - * @param pointer - * @returns {null} - * @private */ - exports._getEdgeAt = function(pointer) { - var positionObject = this._pointerToPositionObject(pointer); - var overlappingEdges = this._getAllEdgesOverlappingWith(positionObject); + exports.updateClusters = function(zoomDirection,recursive,force,doNotStart) { + var isMovingBeforeClustering = this.moving; + var amountOfNodes = this.nodeIndices.length; - if (overlappingEdges.length > 0) { - return this.edges[overlappingEdges[overlappingEdges.length - 1]]; + // on zoom out collapse the sector if the scale is at the level the sector was made + if (this.previousScale > this.scale && zoomDirection == 0) { + this._collapseSector(); } - else { - return null; + + // check if we zoom in or out + if (this.previousScale > this.scale || zoomDirection == -1) { // zoom out + // forming clusters when forced pulls outliers in. When not forced, the edge length of the + // outer nodes determines if it is being clustered + this._formClusters(force); + } + else if (this.previousScale < this.scale || zoomDirection == 1) { // zoom in + if (force == true) { + // _openClusters checks for each node if the formationScale of the cluster is smaller than + // the current scale and if so, declusters. When forced, all clusters are reduced by one step + this._openClusters(recursive,force); + } + else { + // if a cluster takes up a set percentage of the active window + this._openClustersBySize(); + } + } + this._updateNodeIndexList(); + + // if a cluster was NOT formed and the user zoomed out, we try clustering by hubs + if (this.nodeIndices.length == amountOfNodes && (this.previousScale > this.scale || zoomDirection == -1)) { + this._aggregateHubs(force); + this._updateNodeIndexList(); + } + + // we now reduce chains. + if (this.previousScale > this.scale || zoomDirection == -1) { // zoom out + this.handleChains(); + this._updateNodeIndexList(); + } + + this.previousScale = this.scale; + + // rest of the update the index list, dynamic edges and labels + this._updateDynamicEdges(); + this.updateLabels(); + + // if a cluster was formed, we increase the clusterSession + if (this.nodeIndices.length < amountOfNodes) { // this means a clustering operation has taken place + this.clusterSession += 1; + // if clusters have been made, we normalize the cluster level + this.normalizeClusterLevels(); + } + + if (doNotStart == false || doNotStart === undefined) { + // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded + if (this.moving != isMovingBeforeClustering) { + this.start(); + } } + + this._updateCalculationNodes(); }; + /** + * This function handles the chains. It is called on every updateClusters(). + */ + exports.handleChains = function() { + // after clustering we check how many chains there are + var chainPercentage = this._getChainFraction(); + if (chainPercentage > this.constants.clustering.chainThreshold) { + this._reduceAmountOfChains(1 - this.constants.clustering.chainThreshold / chainPercentage) + + } + }; /** - * Add object to the selection array. + * this functions starts clustering by hubs + * The minimum hub threshold is set globally * - * @param obj * @private */ - exports._addToSelection = function(obj) { - if (obj instanceof Node) { - this.selectionObj.nodes[obj.id] = obj; - } - else { - this.selectionObj.edges[obj.id] = obj; - } + exports._aggregateHubs = function(force) { + this._getHubSize(); + this._formClustersByHub(force,false); }; + /** - * Add object to the selection array. + * This function is fired by keypress. It forces hubs to form. * - * @param obj - * @private */ - exports._addToHover = function(obj) { - if (obj instanceof Node) { - this.hoverObj.nodes[obj.id] = obj; + exports.forceAggregateHubs = function(doNotStart) { + var isMovingBeforeClustering = this.moving; + var amountOfNodes = this.nodeIndices.length; + + this._aggregateHubs(true); + + // update the index list, dynamic edges and labels + this._updateNodeIndexList(); + this._updateDynamicEdges(); + this.updateLabels(); + + // if a cluster was formed, we increase the clusterSession + if (this.nodeIndices.length != amountOfNodes) { + this.clusterSession += 1; } - else { - this.hoverObj.edges[obj.id] = obj; + + if (doNotStart == false || doNotStart === undefined) { + // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded + if (this.moving != isMovingBeforeClustering) { + this.start(); + } + } + }; + + /** + * If a cluster takes up more than a set percentage of the screen, open the cluster + * + * @private + */ + exports._openClustersBySize = function() { + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + var node = this.nodes[nodeId]; + if (node.inView() == true) { + if ((node.width*this.scale > this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientWidth) || + (node.height*this.scale > this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientHeight)) { + this.openCluster(node); + } + } + } } }; /** - * Remove a single option from selection. + * This function loops over all nodes in the nodeIndices list. For each node it checks if it is a cluster and if it + * has to be opened based on the current zoom level. * - * @param {Object} obj * @private */ - exports._removeFromSelection = function(obj) { - if (obj instanceof Node) { - delete this.selectionObj.nodes[obj.id]; - } - else { - delete this.selectionObj.edges[obj.id]; + exports._openClusters = function(recursive,force) { + for (var i = 0; i < this.nodeIndices.length; i++) { + var node = this.nodes[this.nodeIndices[i]]; + this._expandClusterNode(node,recursive,force); + this._updateCalculationNodes(); } }; /** - * Unselect all. The selectionObj is useful for this. + * This function checks if a node has to be opened. This is done by checking the zoom level. + * If the node contains child nodes, this function is recursively called on the child nodes as well. + * This recursive behaviour is optional and can be set by the recursive argument. * - * @param {Boolean} [doNotTrigger] | ignore trigger + * @param {Node} parentNode | to check for cluster and expand + * @param {Boolean} recursive | enabled or disable recursive calling + * @param {Boolean} force | enabled or disable forcing + * @param {Boolean} [openAll] | This will recursively force all nodes in the parent to be released * @private */ - exports._unselectAll = function(doNotTrigger) { - if (doNotTrigger === undefined) { - doNotTrigger = false; - } - for(var nodeId in this.selectionObj.nodes) { - if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { - this.selectionObj.nodes[nodeId].unselect(); - } - } - for(var edgeId in this.selectionObj.edges) { - if(this.selectionObj.edges.hasOwnProperty(edgeId)) { - this.selectionObj.edges[edgeId].unselect(); + exports._expandClusterNode = function(parentNode, recursive, force, openAll) { + // first check if node is a cluster + if (parentNode.clusterSize > 1) { + // this means that on a double tap event or a zoom event, the cluster fully unpacks if it is smaller than 20 + if (parentNode.clusterSize < this.constants.clustering.sectorThreshold) { + openAll = true; } - } + recursive = openAll ? true : recursive; - this.selectionObj = {nodes:{},edges:{}}; + // if the last child has been added on a smaller scale than current scale decluster + if (parentNode.formationScale < this.scale || force == true) { + // we will check if any of the contained child nodes should be removed from the cluster + for (var containedNodeId in parentNode.containedNodes) { + if (parentNode.containedNodes.hasOwnProperty(containedNodeId)) { + var childNode = parentNode.containedNodes[containedNodeId]; - if (doNotTrigger == false) { - this.emit('select', this.getSelection()); + // force expand will expand the largest cluster size clusters. Since we cluster from outside in, we assume that + // the largest cluster is the one that comes from outside + if (force == true) { + if (childNode.clusterSession == parentNode.clusterSessions[parentNode.clusterSessions.length-1] + || openAll) { + this._expelChildFromParent(parentNode,containedNodeId,recursive,force,openAll); + } + } + else { + if (this._nodeInActiveArea(parentNode)) { + this._expelChildFromParent(parentNode,containedNodeId,recursive,force,openAll); + } + } + } + } + } } }; /** - * Unselect all clusters. The selectionObj is useful for this. + * ONLY CALLED FROM _expandClusterNode * - * @param {Boolean} [doNotTrigger] | ignore trigger + * This function will expel a child_node from a parent_node. This is to de-cluster the node. This function will remove + * the child node from the parent contained_node object and put it back into the global nodes object. + * The same holds for the edge that was connected to the child node. It is moved back into the global edges object. + * + * @param {Node} parentNode | the parent node + * @param {String} containedNodeId | child_node id as it is contained in the containedNodes object of the parent node + * @param {Boolean} recursive | This will also check if the child needs to be expanded. + * With force and recursive both true, the entire cluster is unpacked + * @param {Boolean} force | This will disregard the zoom level and will expel this child from the parent + * @param {Boolean} openAll | This will recursively force all nodes in the parent to be released * @private */ - exports._unselectClusters = function(doNotTrigger) { - if (doNotTrigger === undefined) { - doNotTrigger = false; - } + exports._expelChildFromParent = function(parentNode, containedNodeId, recursive, force, openAll) { + var childNode = parentNode.containedNodes[containedNodeId]; - for (var nodeId in this.selectionObj.nodes) { - if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { - if (this.selectionObj.nodes[nodeId].clusterSize > 1) { - this.selectionObj.nodes[nodeId].unselect(); - this._removeFromSelection(this.selectionObj.nodes[nodeId]); + // if child node has been added on smaller scale than current, kick out + if (childNode.formationScale < this.scale || force == true) { + // unselect all selected items + this._unselectAll(); + + // put the child node back in the global nodes object + this.nodes[containedNodeId] = childNode; + + // release the contained edges from this childNode back into the global edges + this._releaseContainedEdges(parentNode,childNode); + + // reconnect rerouted edges to the childNode + this._connectEdgeBackToChild(parentNode,childNode); + + // validate all edges in dynamicEdges + this._validateEdges(parentNode); + + // undo the changes from the clustering operation on the parent node + parentNode.options.mass -= childNode.options.mass; + parentNode.clusterSize -= childNode.clusterSize; + parentNode.options.fontSize = Math.min(this.constants.clustering.maxFontSize, this.constants.nodes.fontSize + this.constants.clustering.fontSizeMultiplier*(parentNode.clusterSize-1)); + parentNode.dynamicEdgesLength = parentNode.dynamicEdges.length; + + // place the child node near the parent, not at the exact same location to avoid chaos in the system + childNode.x = parentNode.x + parentNode.growthIndicator * (0.5 - Math.random()); + childNode.y = parentNode.y + parentNode.growthIndicator * (0.5 - Math.random()); + + // remove node from the list + delete parentNode.containedNodes[containedNodeId]; + + // check if there are other childs with this clusterSession in the parent. + var othersPresent = false; + for (var childNodeId in parentNode.containedNodes) { + if (parentNode.containedNodes.hasOwnProperty(childNodeId)) { + if (parentNode.containedNodes[childNodeId].clusterSession == childNode.clusterSession) { + othersPresent = true; + break; + } } } + // if there are no others, remove the cluster session from the list + if (othersPresent == false) { + parentNode.clusterSessions.pop(); + } + + this._repositionBezierNodes(childNode); + // this._repositionBezierNodes(parentNode); + + // remove the clusterSession from the child node + childNode.clusterSession = 0; + + // recalculate the size of the node on the next time the node is rendered + parentNode.clearSizeCache(); + + // restart the simulation to reorganise all nodes + this.moving = true; } - if (doNotTrigger == false) { - this.emit('select', this.getSelection()); + // check if a further expansion step is possible if recursivity is enabled + if (recursive == true) { + this._expandClusterNode(childNode,recursive,force,openAll); } }; /** - * return the number of selected nodes + * position the bezier nodes at the center of the edges * - * @returns {number} + * @param node * @private */ - exports._getSelectedNodeCount = function() { - var count = 0; - for (var nodeId in this.selectionObj.nodes) { - if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { - count += 1; - } + exports._repositionBezierNodes = function(node) { + for (var i = 0; i < node.dynamicEdges.length; i++) { + node.dynamicEdges[i].positionBezierNode(); } - return count; }; + /** - * return the selected node + * This function checks if any nodes at the end of their trees have edges below a threshold length + * This function is called only from updateClusters() + * forceLevelCollapse ignores the length of the edge and collapses one level + * This means that a node with only one edge will be clustered with its connected node * - * @returns {number} * @private + * @param {Boolean} force */ - exports._getSelectedNode = function() { - for (var nodeId in this.selectionObj.nodes) { - if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { - return this.selectionObj.nodes[nodeId]; - } + exports._formClusters = function(force) { + if (force == false) { + this._formClustersByZoom(); + } + else { + this._forceClustersByZoom(); } - return null; }; + /** - * return the selected edge + * This function handles the clustering by zooming out, this is based on a minimum edge distance * - * @returns {number} * @private */ - exports._getSelectedEdge = function() { - for (var edgeId in this.selectionObj.edges) { - if (this.selectionObj.edges.hasOwnProperty(edgeId)) { - return this.selectionObj.edges[edgeId]; + exports._formClustersByZoom = function() { + var dx,dy,length, + minLength = this.constants.clustering.clusterEdgeThreshold/this.scale; + + // check if any edges are shorter than minLength and start the clustering + // the clustering favours the node with the larger mass + for (var edgeId in this.edges) { + if (this.edges.hasOwnProperty(edgeId)) { + var edge = this.edges[edgeId]; + if (edge.connected) { + if (edge.toId != edge.fromId) { + dx = (edge.to.x - edge.from.x); + dy = (edge.to.y - edge.from.y); + length = Math.sqrt(dx * dx + dy * dy); + + + if (length < minLength) { + // first check which node is larger + var parentNode = edge.from; + var childNode = edge.to; + if (edge.to.options.mass > edge.from.options.mass) { + parentNode = edge.to; + childNode = edge.from; + } + + if (childNode.dynamicEdgesLength == 1) { + this._addToCluster(parentNode,childNode,false); + } + else if (parentNode.dynamicEdgesLength == 1) { + this._addToCluster(childNode,parentNode,false); + } + } + } + } } } - return null; }; - /** - * return the number of selected edges + * This function forces the network to cluster all nodes with only one connecting edge to their + * connected node. * - * @returns {number} * @private */ - exports._getSelectedEdgeCount = function() { - var count = 0; - for (var edgeId in this.selectionObj.edges) { - if (this.selectionObj.edges.hasOwnProperty(edgeId)) { - count += 1; + exports._forceClustersByZoom = function() { + for (var nodeId in this.nodes) { + // another node could have absorbed this child. + if (this.nodes.hasOwnProperty(nodeId)) { + var childNode = this.nodes[nodeId]; + + // the edges can be swallowed by another decrease + if (childNode.dynamicEdgesLength == 1 && childNode.dynamicEdges.length != 0) { + var edge = childNode.dynamicEdges[0]; + var parentNode = (edge.toId == childNode.id) ? this.nodes[edge.fromId] : this.nodes[edge.toId]; + + // group to the largest node + if (childNode.id != parentNode.id) { + if (parentNode.options.mass > childNode.options.mass) { + this._addToCluster(parentNode,childNode,true); + } + else { + this._addToCluster(childNode,parentNode,true); + } + } + } } } - return count; }; /** - * return the number of selected objects. + * To keep the nodes of roughly equal size we normalize the cluster levels. + * This function clusters a node to its smallest connected neighbour. * - * @returns {number} + * @param node * @private */ - exports._getSelectedObjectCount = function() { - var count = 0; - for(var nodeId in this.selectionObj.nodes) { - if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { - count += 1; + exports._clusterToSmallestNeighbour = function(node) { + var smallestNeighbour = -1; + var smallestNeighbourNode = null; + for (var i = 0; i < node.dynamicEdges.length; i++) { + if (node.dynamicEdges[i] !== undefined) { + var neighbour = null; + if (node.dynamicEdges[i].fromId != node.id) { + neighbour = node.dynamicEdges[i].from; + } + else if (node.dynamicEdges[i].toId != node.id) { + neighbour = node.dynamicEdges[i].to; + } + + + if (neighbour != null && smallestNeighbour > neighbour.clusterSessions.length) { + smallestNeighbour = neighbour.clusterSessions.length; + smallestNeighbourNode = neighbour; + } } } - for(var edgeId in this.selectionObj.edges) { - if(this.selectionObj.edges.hasOwnProperty(edgeId)) { - count += 1; - } + + if (neighbour != null && this.nodes[neighbour.id] !== undefined) { + this._addToCluster(neighbour, node, true); } - return count; }; + /** - * Check if anything is selected + * This function forms clusters from hubs, it loops over all nodes * - * @returns {boolean} + * @param {Boolean} force | Disregard zoom level + * @param {Boolean} onlyEqual | This only clusters a hub with a specific number of edges * @private */ - exports._selectionIsEmpty = function() { - for(var nodeId in this.selectionObj.nodes) { - if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { - return false; - } - } - for(var edgeId in this.selectionObj.edges) { - if(this.selectionObj.edges.hasOwnProperty(edgeId)) { - return false; + exports._formClustersByHub = function(force, onlyEqual) { + // we loop over all nodes in the list + for (var nodeId in this.nodes) { + // we check if it is still available since it can be used by the clustering in this loop + if (this.nodes.hasOwnProperty(nodeId)) { + this._formClusterFromHub(this.nodes[nodeId],force,onlyEqual); } } - return true; }; - /** - * check if one of the selected nodes is a cluster. + * This function forms a cluster from a specific preselected hub node * - * @returns {boolean} + * @param {Node} hubNode | the node we will cluster as a hub + * @param {Boolean} force | Disregard zoom level + * @param {Boolean} onlyEqual | This only clusters a hub with a specific number of edges + * @param {Number} [absorptionSizeOffset] | * @private */ - exports._clusterInSelection = function() { - for(var nodeId in this.selectionObj.nodes) { - if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { - if (this.selectionObj.nodes[nodeId].clusterSize > 1) { - return true; + exports._formClusterFromHub = function(hubNode, force, onlyEqual, absorptionSizeOffset) { + if (absorptionSizeOffset === undefined) { + absorptionSizeOffset = 0; + } + // we decide if the node is a hub + if ((hubNode.dynamicEdgesLength >= this.hubThreshold && onlyEqual == false) || + (hubNode.dynamicEdgesLength == this.hubThreshold && onlyEqual == true)) { + // initialize variables + var dx,dy,length; + var minLength = this.constants.clustering.clusterEdgeThreshold/this.scale; + var allowCluster = false; + + // we create a list of edges because the dynamicEdges change over the course of this loop + var edgesIdarray = []; + var amountOfInitialEdges = hubNode.dynamicEdges.length; + for (var j = 0; j < amountOfInitialEdges; j++) { + edgesIdarray.push(hubNode.dynamicEdges[j].id); + } + + // if the hub clustering is not forces, we check if one of the edges connected + // to a cluster is small enough based on the constants.clustering.clusterEdgeThreshold + if (force == false) { + allowCluster = false; + for (j = 0; j < amountOfInitialEdges; j++) { + var edge = this.edges[edgesIdarray[j]]; + if (edge !== undefined) { + if (edge.connected) { + if (edge.toId != edge.fromId) { + dx = (edge.to.x - edge.from.x); + dy = (edge.to.y - edge.from.y); + length = Math.sqrt(dx * dx + dy * dy); + + if (length < minLength) { + allowCluster = true; + break; + } + } + } + } + } + } + + // start the clustering if allowed + if ((!force && allowCluster) || force) { + // we loop over all edges INITIALLY connected to this hub + for (j = 0; j < amountOfInitialEdges; j++) { + edge = this.edges[edgesIdarray[j]]; + // the edge can be clustered by this function in a previous loop + if (edge !== undefined) { + var childNode = this.nodes[(edge.fromId == hubNode.id) ? edge.toId : edge.fromId]; + // we do not want hubs to merge with other hubs nor do we want to cluster itself. + if ((childNode.dynamicEdges.length <= (this.hubThreshold + absorptionSizeOffset)) && + (childNode.id != hubNode.id)) { + this._addToCluster(hubNode,childNode,force); + } + } } } } - return false; }; + + /** - * select the edges connected to the node that is being selected + * This function adds the child node to the parent node, creating a cluster if it is not already. * - * @param {Node} node + * @param {Node} parentNode | this is the node that will house the child node + * @param {Node} childNode | this node will be deleted from the global this.nodes and stored in the parent node + * @param {Boolean} force | true will only update the remainingEdges at the very end of the clustering, ensuring single level collapse * @private */ - exports._selectConnectedEdges = function(node) { - for (var i = 0; i < node.dynamicEdges.length; i++) { - var edge = node.dynamicEdges[i]; - edge.select(); - this._addToSelection(edge); + exports._addToCluster = function(parentNode, childNode, force) { + // join child node in the parent node + parentNode.containedNodes[childNode.id] = childNode; + + // manage all the edges connected to the child and parent nodes + for (var i = 0; i < childNode.dynamicEdges.length; i++) { + var edge = childNode.dynamicEdges[i]; + if (edge.toId == parentNode.id || edge.fromId == parentNode.id) { // edge connected to parentNode + this._addToContainedEdges(parentNode,childNode,edge); + } + else { + this._connectEdgeToCluster(parentNode,childNode,edge); + } } - }; + // a contained node has no dynamic edges. + childNode.dynamicEdges = []; - /** - * select the edges connected to the node that is being selected - * - * @param {Node} node - * @private - */ - exports._hoverConnectedEdges = function(node) { - for (var i = 0; i < node.dynamicEdges.length; i++) { - var edge = node.dynamicEdges[i]; - edge.hover = true; - this._addToHover(edge); + // remove circular edges from clusters + this._containCircularEdgesFromNode(parentNode,childNode); + + + // remove the childNode from the global nodes object + delete this.nodes[childNode.id]; + + // update the properties of the child and parent + var massBefore = parentNode.options.mass; + childNode.clusterSession = this.clusterSession; + parentNode.options.mass += childNode.options.mass; + parentNode.clusterSize += childNode.clusterSize; + parentNode.options.fontSize = Math.min(this.constants.clustering.maxFontSize, this.constants.nodes.fontSize + this.constants.clustering.fontSizeMultiplier*parentNode.clusterSize); + + // keep track of the clustersessions so we can open the cluster up as it has been formed. + if (parentNode.clusterSessions[parentNode.clusterSessions.length - 1] != this.clusterSession) { + parentNode.clusterSessions.push(this.clusterSession); + } + + // forced clusters only open from screen size and double tap + if (force == true) { + // parentNode.formationScale = Math.pow(1 - (1.0/11.0),this.clusterSession+3); + parentNode.formationScale = 0; + } + else { + parentNode.formationScale = this.scale; // The latest child has been added on this scale } + + // recalculate the size of the node on the next time the node is rendered + parentNode.clearSizeCache(); + + // set the pop-out scale for the childnode + parentNode.containedNodes[childNode.id].formationScale = parentNode.formationScale; + + // nullify the movement velocity of the child, this is to avoid hectic behaviour + childNode.clearVelocity(); + + // the mass has altered, preservation of energy dictates the velocity to be updated + parentNode.updateVelocity(massBefore); + + // restart the simulation to reorganise all nodes + this.moving = true; }; /** - * unselect the edges connected to the node that is being selected - * - * @param {Node} node + * This function will apply the changes made to the remainingEdges during the formation of the clusters. + * This is a seperate function to allow for level-wise collapsing of the node barnesHutTree. + * It has to be called if a level is collapsed. It is called by _formClusters(). * @private */ - exports._unselectConnectedEdges = function(node) { - for (var i = 0; i < node.dynamicEdges.length; i++) { - var edge = node.dynamicEdges[i]; - edge.unselect(); - this._removeFromSelection(edge); + exports._updateDynamicEdges = function() { + for (var i = 0; i < this.nodeIndices.length; i++) { + var node = this.nodes[this.nodeIndices[i]]; + node.dynamicEdgesLength = node.dynamicEdges.length; + + // this corrects for multiple edges pointing at the same other node + var correction = 0; + if (node.dynamicEdgesLength > 1) { + for (var j = 0; j < node.dynamicEdgesLength - 1; j++) { + var edgeToId = node.dynamicEdges[j].toId; + var edgeFromId = node.dynamicEdges[j].fromId; + for (var k = j+1; k < node.dynamicEdgesLength; k++) { + if ((node.dynamicEdges[k].toId == edgeToId && node.dynamicEdges[k].fromId == edgeFromId) || + (node.dynamicEdges[k].fromId == edgeToId && node.dynamicEdges[k].toId == edgeFromId)) { + correction += 1; + } + } + } + } + node.dynamicEdgesLength -= correction; } }; - - /** - * This is called when someone clicks on a node. either select or deselect it. - * If there is an existing selection and we don't want to append to it, clear the existing selection + * This adds an edge from the childNode to the contained edges of the parent node * - * @param {Node || Edge} object - * @param {Boolean} append - * @param {Boolean} [doNotTrigger] | ignore trigger + * @param parentNode | Node object + * @param childNode | Node object + * @param edge | Edge object * @private */ - exports._selectObject = function(object, append, doNotTrigger, highlightEdges, overrideSelectable) { - if (doNotTrigger === undefined) { - doNotTrigger = false; - } - if (highlightEdges === undefined) { - highlightEdges = true; + exports._addToContainedEdges = function(parentNode, childNode, edge) { + // create an array object if it does not yet exist for this childNode + if (!(parentNode.containedEdges.hasOwnProperty(childNode.id))) { + parentNode.containedEdges[childNode.id] = [] } + // add this edge to the list + parentNode.containedEdges[childNode.id].push(edge); - if (this._selectionIsEmpty() == false && append == false && this.forceAppendSelection == false) { - this._unselectAll(true); - } + // remove the edge from the global edges object + delete this.edges[edge.id]; - // selectable allows the object to be selected. Override can be used if needed to bypass this. - if (object.selected == false && (this.constants.selectable == true || overrideSelectable)) { - object.select(); - this._addToSelection(object); - if (object instanceof Node && this.blockConnectingEdgeSelection == false && highlightEdges == true) { - this._selectConnectedEdges(object); + // remove the edge from the parent object + for (var i = 0; i < parentNode.dynamicEdges.length; i++) { + if (parentNode.dynamicEdges[i].id == edge.id) { + parentNode.dynamicEdges.splice(i,1); + break; } } - // do not select the object if selectable is false, only add it to selection to allow drag to work - else if (object.selected == false) { - this._addToSelection(object); - doNotTrigger = true; - } - else { - object.unselect(); - this._removeFromSelection(object); - } - - if (doNotTrigger == false) { - this.emit('select', this.getSelection()); - } }; - /** - * This is called when someone clicks on a node. either select or deselect it. - * If there is an existing selection and we don't want to append to it, clear the existing selection + * This function connects an edge that was connected to a child node to the parent node. + * It keeps track of which nodes it has been connected to with the originalId array. * - * @param {Node || Edge} object + * @param {Node} parentNode | Node object + * @param {Node} childNode | Node object + * @param {Edge} edge | Edge object * @private */ - exports._blurObject = function(object) { - if (object.hover == true) { - object.hover = false; - this.emit("blurNode",{node:object.id}); + exports._connectEdgeToCluster = function(parentNode, childNode, edge) { + // handle circular edges + if (edge.toId == edge.fromId) { + this._addToContainedEdges(parentNode, childNode, edge); + } + else { + if (edge.toId == childNode.id) { // edge connected to other node on the "to" side + edge.originalToId.push(childNode.id); + edge.to = parentNode; + edge.toId = parentNode.id; + } + else { // edge connected to other node with the "from" side + + edge.originalFromId.push(childNode.id); + edge.from = parentNode; + edge.fromId = parentNode.id; + } + + this._addToReroutedEdges(parentNode,childNode,edge); } }; + /** - * This is called when someone clicks on a node. either select or deselect it. - * If there is an existing selection and we don't want to append to it, clear the existing selection + * If a node is connected to itself, a circular edge is drawn. When clustering we want to contain + * these edges inside of the cluster. * - * @param {Node || Edge} object + * @param parentNode + * @param childNode * @private */ - exports._hoverObject = function(object) { - if (object.hover == false) { - object.hover = true; - this._addToHover(object); - if (object instanceof Node) { - this.emit("hoverNode",{node:object.id}); + exports._containCircularEdgesFromNode = function(parentNode, childNode) { + // manage all the edges connected to the child and parent nodes + for (var i = 0; i < parentNode.dynamicEdges.length; i++) { + var edge = parentNode.dynamicEdges[i]; + // handle circular edges + if (edge.toId == edge.fromId) { + this._addToContainedEdges(parentNode, childNode, edge); } } - if (object instanceof Node) { - this._hoverConnectedEdges(object); - } }; /** - * handles the selection part of the touch, only for navigation controls elements; - * Touch is triggered before tap, also before hold. Hold triggers after a while. - * This is the most responsive solution + * This adds an edge from the childNode to the rerouted edges of the parent node * - * @param {Object} pointer + * @param parentNode | Node object + * @param childNode | Node object + * @param edge | Edge object * @private */ - exports._handleTouch = function(pointer) { - }; + exports._addToReroutedEdges = function(parentNode, childNode, edge) { + // create an array object if it does not yet exist for this childNode + // we store the edge in the rerouted edges so we can restore it when the cluster pops open + if (!(parentNode.reroutedEdges.hasOwnProperty(childNode.id))) { + parentNode.reroutedEdges[childNode.id] = []; + } + parentNode.reroutedEdges[childNode.id].push(edge); + + // this edge becomes part of the dynamicEdges of the cluster node + parentNode.dynamicEdges.push(edge); + }; + /** - * handles the selection part of the tap; + * This function connects an edge that was connected to a cluster node back to the child node. * - * @param {Object} pointer + * @param parentNode | Node object + * @param childNode | Node object * @private */ - exports._handleTap = function(pointer) { - var node = this._getNodeAt(pointer); - if (node != null) { - this._selectObject(node, false); - } - else { - var edge = this._getEdgeAt(pointer); - if (edge != null) { - this._selectObject(edge, false); - } - else { - this._unselectAll(); + exports._connectEdgeBackToChild = function(parentNode, childNode) { + if (parentNode.reroutedEdges.hasOwnProperty(childNode.id)) { + for (var i = 0; i < parentNode.reroutedEdges[childNode.id].length; i++) { + var edge = parentNode.reroutedEdges[childNode.id][i]; + if (edge.originalFromId[edge.originalFromId.length-1] == childNode.id) { + edge.originalFromId.pop(); + edge.fromId = childNode.id; + edge.from = childNode; + } + else { + edge.originalToId.pop(); + edge.toId = childNode.id; + edge.to = childNode; + } + + // append this edge to the list of edges connecting to the childnode + childNode.dynamicEdges.push(edge); + + // remove the edge from the parent object + for (var j = 0; j < parentNode.dynamicEdges.length; j++) { + if (parentNode.dynamicEdges[j].id == edge.id) { + parentNode.dynamicEdges.splice(j,1); + break; + } + } } + // remove the entry from the rerouted edges + delete parentNode.reroutedEdges[childNode.id]; } - var properties = this.getSelection(); - properties['pointer'] = { - DOM: {x: pointer.x, y: pointer.y}, - canvas: {x: this._XconvertDOMtoCanvas(pointer.x), y: this._YconvertDOMtoCanvas(pointer.y)} - } - this.emit("click", properties); - this._redraw(); }; /** - * handles the selection part of the double tap and opens a cluster if needed + * When loops are clustered, an edge can be both in the rerouted array and the contained array. + * This function is called last to verify that all edges in dynamicEdges are in fact connected to the + * parentNode * - * @param {Object} pointer + * @param parentNode | Node object * @private */ - exports._handleDoubleTap = function(pointer) { - var node = this._getNodeAt(pointer); - if (node != null && node !== undefined) { - // we reset the areaCenter here so the opening of the node will occur - this.areaCenter = {"x" : this._XconvertDOMtoCanvas(pointer.x), - "y" : this._YconvertDOMtoCanvas(pointer.y)}; - this.openCluster(node); - } - var properties = this.getSelection(); - properties['pointer'] = { - DOM: {x: pointer.x, y: pointer.y}, - canvas: {x: this._XconvertDOMtoCanvas(pointer.x), y: this._YconvertDOMtoCanvas(pointer.y)} + exports._validateEdges = function(parentNode) { + for (var i = 0; i < parentNode.dynamicEdges.length; i++) { + var edge = parentNode.dynamicEdges[i]; + if (parentNode.id != edge.toId && parentNode.id != edge.fromId) { + parentNode.dynamicEdges.splice(i,1); + } } - this.emit("doubleClick", properties); }; /** - * Handle the onHold selection part + * This function released the contained edges back into the global domain and puts them back into the + * dynamic edges of both parent and child. * - * @param pointer + * @param {Node} parentNode | + * @param {Node} childNode | * @private */ - exports._handleOnHold = function(pointer) { - var node = this._getNodeAt(pointer); - if (node != null) { - this._selectObject(node,true); - } - else { - var edge = this._getEdgeAt(pointer); - if (edge != null) { - this._selectObject(edge,true); - } + exports._releaseContainedEdges = function(parentNode, childNode) { + for (var i = 0; i < parentNode.containedEdges[childNode.id].length; i++) { + var edge = parentNode.containedEdges[childNode.id][i]; + + // put the edge back in the global edges object + this.edges[edge.id] = edge; + + // put the edge back in the dynamic edges of the child and parent + childNode.dynamicEdges.push(edge); + parentNode.dynamicEdges.push(edge); } - this._redraw(); + // remove the entry from the contained edges + delete parentNode.containedEdges[childNode.id]; + }; - /** - * handle the onRelease event. These functions are here for the navigation controls module - * and data manipulation module. - * - * @private - */ - exports._handleOnRelease = function(pointer) { - this._manipulationReleaseOverload(pointer); - this._navigationReleaseOverload(pointer); - }; - exports._manipulationReleaseOverload = function (pointer) {}; - exports._navigationReleaseOverload = function (pointer) {}; - /** - * - * retrieve the currently selected objects - * @return {{nodes: Array., edges: Array.}} selection - */ - exports.getSelection = function() { - var nodeIds = this.getSelectedNodes(); - var edgeIds = this.getSelectedEdges(); - return {nodes:nodeIds, edges:edgeIds}; - }; + // ------------------- UTILITY FUNCTIONS ---------------------------- // + /** - * - * retrieve the currently selected nodes - * @return {String[]} selection An array with the ids of the - * selected nodes. + * This updates the node labels for all nodes (for debugging purposes) */ - exports.getSelectedNodes = function() { - var idArray = []; - if (this.constants.selectable == true) { - for (var nodeId in this.selectionObj.nodes) { - if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { - idArray.push(nodeId); + exports.updateLabels = function() { + var nodeId; + // update node labels + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + var node = this.nodes[nodeId]; + if (node.clusterSize > 1) { + node.label = "[".concat(String(node.clusterSize),"]"); } } } - return idArray + + // update node labels + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + if (node.clusterSize == 1) { + if (node.originalLabel !== undefined) { + node.label = node.originalLabel; + } + else { + node.label = String(node.id); + } + } + } + } + + // /* Debug Override */ + // for (nodeId in this.nodes) { + // if (this.nodes.hasOwnProperty(nodeId)) { + // node = this.nodes[nodeId]; + // node.label = String(node.level); + // } + // } + }; + /** - * - * retrieve the currently selected edges - * @return {Array} selection An array with the ids of the - * selected nodes. + * We want to keep the cluster level distribution rather small. This means we do not want unclustered nodes + * if the rest of the nodes are already a few cluster levels in. + * To fix this we use this function. It determines the min and max cluster level and sends nodes that have not + * clustered enough to the clusterToSmallestNeighbours function. */ - exports.getSelectedEdges = function() { - var idArray = []; - if (this.constants.selectable == true) { - for (var edgeId in this.selectionObj.edges) { - if (this.selectionObj.edges.hasOwnProperty(edgeId)) { - idArray.push(edgeId); + exports.normalizeClusterLevels = function() { + var maxLevel = 0; + var minLevel = 1e9; + var clusterLevel = 0; + var nodeId; + + // we loop over all nodes in the list + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + clusterLevel = this.nodes[nodeId].clusterSessions.length; + if (maxLevel < clusterLevel) {maxLevel = clusterLevel;} + if (minLevel > clusterLevel) {minLevel = clusterLevel;} + } + } + + if (maxLevel - minLevel > this.constants.clustering.clusterLevelDifference) { + var amountOfNodes = this.nodeIndices.length; + var targetLevel = maxLevel - this.constants.clustering.clusterLevelDifference; + // we loop over all nodes in the list + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + if (this.nodes[nodeId].clusterSessions.length < targetLevel) { + this._clusterToSmallestNeighbour(this.nodes[nodeId]); + } } } + this._updateNodeIndexList(); + this._updateDynamicEdges(); + // if a cluster was formed, we increase the clusterSession + if (this.nodeIndices.length != amountOfNodes) { + this.clusterSession += 1; + } } - return idArray; }; + /** - * select zero or more nodes DEPRICATED - * @param {Number[] | String[]} selection An array with the ids of the - * selected nodes. + * This function determines if the cluster we want to decluster is in the active area + * this means around the zoom center + * + * @param {Node} node + * @returns {boolean} + * @private */ - exports.setSelection = function() { - console.log("setSelection is deprecated. Please use selectNodes instead.") + exports._nodeInActiveArea = function(node) { + return ( + Math.abs(node.x - this.areaCenter.x) <= this.constants.clustering.activeAreaBoxSize/this.scale + && + Math.abs(node.y - this.areaCenter.y) <= this.constants.clustering.activeAreaBoxSize/this.scale + ) }; /** - * select zero or more nodes with the option to highlight edges - * @param {Number[] | String[]} selection An array with the ids of the - * selected nodes. - * @param {boolean} [highlightEdges] + * This is an adaptation of the original repositioning function. This is called if the system is clustered initially + * It puts large clusters away from the center and randomizes the order. + * */ - exports.selectNodes = function(selection, highlightEdges) { - var i, iMax, id; - - if (!selection || (selection.length == undefined)) - throw 'Selection must be an array with ids'; - - // first unselect any selected node - this._unselectAll(true); - - for (i = 0, iMax = selection.length; i < iMax; i++) { - id = selection[i]; - - var node = this.nodes[id]; - if (!node) { - throw new RangeError('Node with id "' + id + '" not found'); + exports.repositionNodes = function() { + for (var i = 0; i < this.nodeIndices.length; i++) { + var node = this.nodes[this.nodeIndices[i]]; + if ((node.xFixed == false || node.yFixed == false)) { + var radius = 10 * 0.1*this.nodeIndices.length * Math.min(100,node.options.mass); + var angle = 2 * Math.PI * Math.random(); + if (node.xFixed == false) {node.x = radius * Math.cos(angle);} + if (node.yFixed == false) {node.y = radius * Math.sin(angle);} + this._repositionBezierNodes(node); } - this._selectObject(node,true,true,highlightEdges,true); } - this.redraw(); }; /** - * select zero or more edges - * @param {Number[] | String[]} selection An array with the ids of the - * selected nodes. + * We determine how many connections denote an important hub. + * We take the mean + 2*std as the important hub size. (Assuming a normal distribution of data, ~2.2%) + * + * @private */ - exports.selectEdges = function(selection) { - var i, iMax, id; + exports._getHubSize = function() { + var average = 0; + var averageSquared = 0; + var hubCounter = 0; + var largestHub = 0; - if (!selection || (selection.length == undefined)) - throw 'Selection must be an array with ids'; + for (var i = 0; i < this.nodeIndices.length; i++) { - // first unselect any selected node - this._unselectAll(true); + var node = this.nodes[this.nodeIndices[i]]; + if (node.dynamicEdgesLength > largestHub) { + largestHub = node.dynamicEdgesLength; + } + average += node.dynamicEdgesLength; + averageSquared += Math.pow(node.dynamicEdgesLength,2); + hubCounter += 1; + } + average = average / hubCounter; + averageSquared = averageSquared / hubCounter; - for (i = 0, iMax = selection.length; i < iMax; i++) { - id = selection[i]; + var variance = averageSquared - Math.pow(average,2); - var edge = this.edges[id]; - if (!edge) { - throw new RangeError('Edge with id "' + id + '" not found'); - } - this._selectObject(edge,true,true,false,true); + var standardDeviation = Math.sqrt(variance); + + this.hubThreshold = Math.floor(average + 2*standardDeviation); + + // always have at least one to cluster + if (this.hubThreshold > largestHub) { + this.hubThreshold = largestHub; } - this.redraw(); + + // console.log("average",average,"averageSQ",averageSquared,"var",variance,"std",standardDeviation); + // console.log("hubThreshold:",this.hubThreshold); }; + /** - * Validate the selection: remove ids of nodes which no longer exist + * We reduce the amount of "extension nodes" or chains. These are not quickly clustered with the outliers and hubs methods + * with this amount we can cluster specifically on these chains. + * + * @param {Number} fraction | between 0 and 1, the percentage of chains to reduce * @private */ - exports._updateSelection = function () { - for(var nodeId in this.selectionObj.nodes) { - if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { - if (!this.nodes.hasOwnProperty(nodeId)) { - delete this.selectionObj.nodes[nodeId]; + exports._reduceAmountOfChains = function(fraction) { + this.hubThreshold = 2; + var reduceAmount = Math.floor(this.nodeIndices.length * fraction); + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + if (this.nodes[nodeId].dynamicEdgesLength == 2 && this.nodes[nodeId].dynamicEdges.length >= 2) { + if (reduceAmount > 0) { + this._formClusterFromHub(this.nodes[nodeId],true,true,1); + reduceAmount -= 1; + } } } } - for(var edgeId in this.selectionObj.edges) { - if(this.selectionObj.edges.hasOwnProperty(edgeId)) { - if (!this.edges.hasOwnProperty(edgeId)) { - delete this.selectionObj.edges[edgeId]; + }; + + /** + * We get the amount of "extension nodes" or chains. These are not quickly clustered with the outliers and hubs methods + * with this amount we can cluster specifically on these chains. + * + * @private + */ + exports._getChainFraction = function() { + var chains = 0; + var total = 0; + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + if (this.nodes[nodeId].dynamicEdgesLength == 2 && this.nodes[nodeId].dynamicEdges.length >= 2) { + chains += 1; } + total += 1; } } + return chains/total; }; /***/ }, -/* 63 */ +/* 65 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); - var Node = __webpack_require__(40); - var Edge = __webpack_require__(37); + var Node = __webpack_require__(56); /** - * clears the toolbar div element of children + * Creation of the SectorMixin var. * - * @private - */ - exports._clearManipulatorBar = function() { - this._recursiveDOMDelete(this.manipulationDiv); - this.manipulationDOM = {}; - - this._manipulationReleaseOverload = function () {}; - delete this.sectors['support']['nodes']['targetNode']; - delete this.sectors['support']['nodes']['targetViaNode']; - this.controlNodesActive = false; - this.freezeSimulation = false; - }; + * This contains all the functions the Network object can use to employ the sector system. + * The sector system is always used by Network, though the benefits only apply to the use of clustering. + * If clustering is not used, there is no overhead except for a duplicate object with references to nodes and edges. + */ /** - * Manipulation UI temporarily overloads certain functions to extend or replace them. To be able to restore - * these functions to their original functionality, we saved them in this.cachedFunctions. - * This function restores these functions to their original function. + * This function is only called by the setData function of the Network object. + * This loads the global references into the active sector. This initializes the sector. * * @private */ - exports._restoreOverloadedFunctions = function() { - for (var functionName in this.cachedFunctions) { - if (this.cachedFunctions.hasOwnProperty(functionName)) { - this[functionName] = this.cachedFunctions[functionName]; - delete this.cachedFunctions[functionName]; - } - } + exports._putDataInSector = function() { + this.sectors["active"][this._sector()].nodes = this.nodes; + this.sectors["active"][this._sector()].edges = this.edges; + this.sectors["active"][this._sector()].nodeIndices = this.nodeIndices; }; + /** - * Enable or disable edit-mode. + * /** + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the supplied (active) sector. If a type is defined, do the specific type * + * @param {String} sectorId + * @param {String} [sectorType] | "active" or "frozen" * @private */ - exports._toggleEditMode = function() { - this.editMode = !this.editMode; - var toolbar = this.manipulationDiv; - var closeDiv = this.closeDiv; - var editModeDiv = this.editModeDiv; - if (this.editMode == true) { - toolbar.style.display="block"; - closeDiv.style.display="block"; - editModeDiv.style.display="none"; - closeDiv.onclick = this._toggleEditMode.bind(this); + exports._switchToSector = function(sectorId, sectorType) { + if (sectorType === undefined || sectorType == "active") { + this._switchToActiveSector(sectorId); } else { - toolbar.style.display="none"; - closeDiv.style.display="none"; - editModeDiv.style.display="block"; - closeDiv.onclick = null; + this._switchToFrozenSector(sectorId); } - this._createManipulatorBar() }; + /** - * main function, creates the main toolbar. Removes functions bound to the select event. Binds all the buttons of the toolbar. + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the supplied active sector. * + * @param sectorId * @private */ - exports._createManipulatorBar = function() { - // remove bound functions - if (this.boundFunction) { - this.off('select', this.boundFunction); - } - - var locale = this.constants.locales[this.constants.locale]; - - if (this.edgeBeingEdited !== undefined) { - this.edgeBeingEdited._disableControlNodes(); - this.edgeBeingEdited = undefined; - this.selectedControlNode = null; - this.controlNodesActive = false; - this._redraw(); - } - - // restore overloaded functions - this._restoreOverloadedFunctions(); - - // resume calculation - this.freezeSimulation = false; - - // reset global variables - this.blockConnectingEdgeSelection = false; - this.forceAppendSelection = false; - this.manipulationDOM = {}; - - if (this.editMode == true) { - while (this.manipulationDiv.hasChildNodes()) { - this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); - } - - this.manipulationDOM['addNodeSpan'] = document.createElement('span'); - this.manipulationDOM['addNodeSpan'].className = 'network-manipulationUI add'; - this.manipulationDOM['addNodeLabelSpan'] = document.createElement('span'); - this.manipulationDOM['addNodeLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['addNodeLabelSpan'].innerHTML = locale['addNode']; - this.manipulationDOM['addNodeSpan'].appendChild(this.manipulationDOM['addNodeLabelSpan']); - - this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); - this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; - - this.manipulationDOM['addEdgeSpan'] = document.createElement('span'); - this.manipulationDOM['addEdgeSpan'].className = 'network-manipulationUI connect'; - this.manipulationDOM['addEdgeLabelSpan'] = document.createElement('span'); - this.manipulationDOM['addEdgeLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['addEdgeLabelSpan'].innerHTML = locale['addEdge']; - this.manipulationDOM['addEdgeSpan'].appendChild(this.manipulationDOM['addEdgeLabelSpan']); - - this.manipulationDiv.appendChild(this.manipulationDOM['addNodeSpan']); - this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); - this.manipulationDiv.appendChild(this.manipulationDOM['addEdgeSpan']); + exports._switchToActiveSector = function(sectorId) { + this.nodeIndices = this.sectors["active"][sectorId]["nodeIndices"]; + this.nodes = this.sectors["active"][sectorId]["nodes"]; + this.edges = this.sectors["active"][sectorId]["edges"]; + }; - if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) { - this.manipulationDOM['seperatorLineDiv2'] = document.createElement('div'); - this.manipulationDOM['seperatorLineDiv2'].className = 'network-seperatorLine'; - this.manipulationDOM['editNodeSpan'] = document.createElement('span'); - this.manipulationDOM['editNodeSpan'].className = 'network-manipulationUI edit'; - this.manipulationDOM['editNodeLabelSpan'] = document.createElement('span'); - this.manipulationDOM['editNodeLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['editNodeLabelSpan'].innerHTML = locale['editNode']; - this.manipulationDOM['editNodeSpan'].appendChild(this.manipulationDOM['editNodeLabelSpan']); + /** + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the supplied active sector. + * + * @private + */ + exports._switchToSupportSector = function() { + this.nodeIndices = this.sectors["support"]["nodeIndices"]; + this.nodes = this.sectors["support"]["nodes"]; + this.edges = this.sectors["support"]["edges"]; + }; - this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv2']); - this.manipulationDiv.appendChild(this.manipulationDOM['editNodeSpan']); - } - else if (this._getSelectedEdgeCount() == 1 && this._getSelectedNodeCount() == 0) { - this.manipulationDOM['seperatorLineDiv3'] = document.createElement('div'); - this.manipulationDOM['seperatorLineDiv3'].className = 'network-seperatorLine'; - this.manipulationDOM['editEdgeSpan'] = document.createElement('span'); - this.manipulationDOM['editEdgeSpan'].className = 'network-manipulationUI edit'; - this.manipulationDOM['editEdgeLabelSpan'] = document.createElement('span'); - this.manipulationDOM['editEdgeLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['editEdgeLabelSpan'].innerHTML = locale['editEdge']; - this.manipulationDOM['editEdgeSpan'].appendChild(this.manipulationDOM['editEdgeLabelSpan']); + /** + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the supplied frozen sector. + * + * @param sectorId + * @private + */ + exports._switchToFrozenSector = function(sectorId) { + this.nodeIndices = this.sectors["frozen"][sectorId]["nodeIndices"]; + this.nodes = this.sectors["frozen"][sectorId]["nodes"]; + this.edges = this.sectors["frozen"][sectorId]["edges"]; + }; - this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv3']); - this.manipulationDiv.appendChild(this.manipulationDOM['editEdgeSpan']); - } - if (this._selectionIsEmpty() == false) { - this.manipulationDOM['seperatorLineDiv4'] = document.createElement('div'); - this.manipulationDOM['seperatorLineDiv4'].className = 'network-seperatorLine'; - this.manipulationDOM['deleteSpan'] = document.createElement('span'); - this.manipulationDOM['deleteSpan'].className = 'network-manipulationUI delete'; - this.manipulationDOM['deleteLabelSpan'] = document.createElement('span'); - this.manipulationDOM['deleteLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['deleteLabelSpan'].innerHTML = locale['del']; - this.manipulationDOM['deleteSpan'].appendChild(this.manipulationDOM['deleteLabelSpan']); + /** + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the currently active sector. + * + * @private + */ + exports._loadLatestSector = function() { + this._switchToSector(this._sector()); + }; - this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv4']); - this.manipulationDiv.appendChild(this.manipulationDOM['deleteSpan']); - } + /** + * This function returns the currently active sector Id + * + * @returns {String} + * @private + */ + exports._sector = function() { + return this.activeSector[this.activeSector.length-1]; + }; - // bind the icons - this.manipulationDOM['addNodeSpan'].onclick = this._createAddNodeToolbar.bind(this); - this.manipulationDOM['addEdgeSpan'].onclick = this._createAddEdgeToolbar.bind(this); - if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) { - this.manipulationDOM['editNodeSpan'].onclick = this._editNode.bind(this); - } - else if (this._getSelectedEdgeCount() == 1 && this._getSelectedNodeCount() == 0) { - this.manipulationDOM['editEdgeSpan'].onclick = this._createEditEdgeToolbar.bind(this); - } - if (this._selectionIsEmpty() == false) { - this.manipulationDOM['deleteSpan'].onclick = this._deleteSelected.bind(this); - } - this.closeDiv.onclick = this._toggleEditMode.bind(this); - var me = this; - this.boundFunction = me._createManipulatorBar; - this.on('select', this.boundFunction); + /** + * This function returns the previously active sector Id + * + * @returns {String} + * @private + */ + exports._previousSector = function() { + if (this.activeSector.length > 1) { + return this.activeSector[this.activeSector.length-2]; } else { - while (this.editModeDiv.hasChildNodes()) { - this.editModeDiv.removeChild(this.editModeDiv.firstChild); - } - - this.manipulationDOM['editModeSpan'] = document.createElement('span'); - this.manipulationDOM['editModeSpan'].className = 'network-manipulationUI edit editmode'; - this.manipulationDOM['editModeLabelSpan'] = document.createElement('span'); - this.manipulationDOM['editModeLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['editModeLabelSpan'].innerHTML = locale['edit']; - this.manipulationDOM['editModeSpan'].appendChild(this.manipulationDOM['editModeLabelSpan']); - - this.editModeDiv.appendChild(this.manipulationDOM['editModeSpan']); - - this.manipulationDOM['editModeSpan'].onclick = this._toggleEditMode.bind(this); + throw new TypeError('there are not enough sectors in the this.activeSector array.'); } }; - /** - * Create the toolbar for adding Nodes + * We add the active sector at the end of the this.activeSector array + * This ensures it is the currently active sector returned by _sector() and it reaches the top + * of the activeSector stack. When we reverse our steps we move from the end to the beginning of this stack. * + * @param newId * @private */ - exports._createAddNodeToolbar = function() { - // clear the toolbar - this._clearManipulatorBar(); - if (this.boundFunction) { - this.off('select', this.boundFunction); - } - - var locale = this.constants.locales[this.constants.locale]; - - this.manipulationDOM = {}; - this.manipulationDOM['backSpan'] = document.createElement('span'); - this.manipulationDOM['backSpan'].className = 'network-manipulationUI back'; - this.manipulationDOM['backLabelSpan'] = document.createElement('span'); - this.manipulationDOM['backLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['backLabelSpan'].innerHTML = locale['back']; - this.manipulationDOM['backSpan'].appendChild(this.manipulationDOM['backLabelSpan']); - - this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); - this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; - - this.manipulationDOM['descriptionSpan'] = document.createElement('span'); - this.manipulationDOM['descriptionSpan'].className = 'network-manipulationUI none'; - this.manipulationDOM['descriptionLabelSpan'] = document.createElement('span'); - this.manipulationDOM['descriptionLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['descriptionLabelSpan'].innerHTML = locale['addDescription']; - this.manipulationDOM['descriptionSpan'].appendChild(this.manipulationDOM['descriptionLabelSpan']); - - this.manipulationDiv.appendChild(this.manipulationDOM['backSpan']); - this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); - this.manipulationDiv.appendChild(this.manipulationDOM['descriptionSpan']); + exports._setActiveSector = function(newId) { + this.activeSector.push(newId); + }; - // bind the icon - this.manipulationDOM['backSpan'].onclick = this._createManipulatorBar.bind(this); - // we use the boundFunction so we can reference it when we unbind it from the "select" event. - var me = this; - this.boundFunction = me._addNode; - this.on('select', this.boundFunction); + /** + * We remove the currently active sector id from the active sector stack. This happens when + * we reactivate the previously active sector + * + * @private + */ + exports._forgetLastSector = function() { + this.activeSector.pop(); }; /** - * create the toolbar to connect nodes + * This function creates a new active sector with the supplied newId. This newId + * is the expanding node id. * + * @param {String} newId | Id of the new active sector * @private */ - exports._createAddEdgeToolbar = function() { - // clear the toolbar - this._clearManipulatorBar(); - this._unselectAll(true); - this.freezeSimulation = true; + exports._createNewSector = function(newId) { + // create the new sector + this.sectors["active"][newId] = {"nodes":{}, + "edges":{}, + "nodeIndices":[], + "formationScale": this.scale, + "drawingNode": undefined}; - if (this.boundFunction) { - this.off('select', this.boundFunction); - } + // create the new sector render node. This gives visual feedback that you are in a new sector. + this.sectors["active"][newId]['drawingNode'] = new Node( + {id:newId, + color: { + background: "#eaefef", + border: "495c5e" + } + },{},{},this.constants); + this.sectors["active"][newId]['drawingNode'].clusterSize = 2; + }; - var locale = this.constants.locales[this.constants.locale]; - this._unselectAll(); - this.forceAppendSelection = false; - this.blockConnectingEdgeSelection = true; + /** + * This function removes the currently active sector. This is called when we create a new + * active sector. + * + * @param {String} sectorId | Id of the active sector that will be removed + * @private + */ + exports._deleteActiveSector = function(sectorId) { + delete this.sectors["active"][sectorId]; + }; - this.manipulationDOM = {}; - this.manipulationDOM['backSpan'] = document.createElement('span'); - this.manipulationDOM['backSpan'].className = 'network-manipulationUI back'; - this.manipulationDOM['backLabelSpan'] = document.createElement('span'); - this.manipulationDOM['backLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['backLabelSpan'].innerHTML = locale['back']; - this.manipulationDOM['backSpan'].appendChild(this.manipulationDOM['backLabelSpan']); - this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); - this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; + /** + * This function removes the currently active sector. This is called when we reactivate + * the previously active sector. + * + * @param {String} sectorId | Id of the active sector that will be removed + * @private + */ + exports._deleteFrozenSector = function(sectorId) { + delete this.sectors["frozen"][sectorId]; + }; - this.manipulationDOM['descriptionSpan'] = document.createElement('span'); - this.manipulationDOM['descriptionSpan'].className = 'network-manipulationUI none'; - this.manipulationDOM['descriptionLabelSpan'] = document.createElement('span'); - this.manipulationDOM['descriptionLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['descriptionLabelSpan'].innerHTML = locale['edgeDescription']; - this.manipulationDOM['descriptionSpan'].appendChild(this.manipulationDOM['descriptionLabelSpan']); - this.manipulationDiv.appendChild(this.manipulationDOM['backSpan']); - this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); - this.manipulationDiv.appendChild(this.manipulationDOM['descriptionSpan']); + /** + * Freezing an active sector means moving it from the "active" object to the "frozen" object. + * We copy the references, then delete the active entree. + * + * @param sectorId + * @private + */ + exports._freezeSector = function(sectorId) { + // we move the set references from the active to the frozen stack. + this.sectors["frozen"][sectorId] = this.sectors["active"][sectorId]; - // bind the icon - this.manipulationDOM['backSpan'].onclick = this._createManipulatorBar.bind(this); + // we have moved the sector data into the frozen set, we now remove it from the active set + this._deleteActiveSector(sectorId); + }; - // we use the boundFunction so we can reference it when we unbind it from the "select" event. - var me = this; - this.boundFunction = me._handleConnect; - this.on('select', this.boundFunction); - // temporarily overload functions - this.cachedFunctions["_handleTouch"] = this._handleTouch; - this.cachedFunctions["_manipulationReleaseOverload"] = this._manipulationReleaseOverload; - this.cachedFunctions["_handleDragStart"] = this._handleDragStart; - this.cachedFunctions["_handleDragEnd"] = this._handleDragEnd; - this._handleTouch = this._handleConnect; - this._manipulationReleaseOverload = function () {}; - this._handleDragStart = function () {}; - this._handleDragEnd = this._finishConnect; + /** + * This is the reverse operation of _freezeSector. Activating means moving the sector from the "frozen" + * object to the "active" object. + * + * @param sectorId + * @private + */ + exports._activateSector = function(sectorId) { + // we move the set references from the frozen to the active stack. + this.sectors["active"][sectorId] = this.sectors["frozen"][sectorId]; - // redraw to show the unselect - this._redraw(); + // we have moved the sector data into the active set, we now remove it from the frozen stack + this._deleteFrozenSector(sectorId); }; + /** - * create the toolbar to edit edges + * This function merges the data from the currently active sector with a frozen sector. This is used + * in the process of reverting back to the previously active sector. + * The data that is placed in the frozen (the previously active) sector is the node that has been removed from it + * upon the creation of a new active sector. * + * @param sectorId * @private */ - exports._createEditEdgeToolbar = function() { - // clear the toolbar - this._clearManipulatorBar(); - this.controlNodesActive = true; - - if (this.boundFunction) { - this.off('select', this.boundFunction); + exports._mergeThisWithFrozen = function(sectorId) { + // copy all nodes + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + this.sectors["frozen"][sectorId]["nodes"][nodeId] = this.nodes[nodeId]; + } } - this.edgeBeingEdited = this._getSelectedEdge(); - this.edgeBeingEdited._enableControlNodes(); - - var locale = this.constants.locales[this.constants.locale]; - - this.manipulationDOM = {}; - this.manipulationDOM['backSpan'] = document.createElement('span'); - this.manipulationDOM['backSpan'].className = 'network-manipulationUI back'; - this.manipulationDOM['backLabelSpan'] = document.createElement('span'); - this.manipulationDOM['backLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['backLabelSpan'].innerHTML = locale['back']; - this.manipulationDOM['backSpan'].appendChild(this.manipulationDOM['backLabelSpan']); - - this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); - this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; - - this.manipulationDOM['descriptionSpan'] = document.createElement('span'); - this.manipulationDOM['descriptionSpan'].className = 'network-manipulationUI none'; - this.manipulationDOM['descriptionLabelSpan'] = document.createElement('span'); - this.manipulationDOM['descriptionLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['descriptionLabelSpan'].innerHTML = locale['editEdgeDescription']; - this.manipulationDOM['descriptionSpan'].appendChild(this.manipulationDOM['descriptionLabelSpan']); - - this.manipulationDiv.appendChild(this.manipulationDOM['backSpan']); - this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); - this.manipulationDiv.appendChild(this.manipulationDOM['descriptionSpan']); - - // bind the icon - this.manipulationDOM['backSpan'].onclick = this._createManipulatorBar.bind(this); - - // temporarily overload functions - this.cachedFunctions["_handleTouch"] = this._handleTouch; - this.cachedFunctions["_manipulationReleaseOverload"] = this._manipulationReleaseOverload; - this.cachedFunctions["_handleTap"] = this._handleTap; - this.cachedFunctions["_handleDragStart"] = this._handleDragStart; - this.cachedFunctions["_handleOnDrag"] = this._handleOnDrag; - this._handleTouch = this._selectControlNode; - this._handleTap = function () {}; - this._handleOnDrag = this._controlNodeDrag; - this._handleDragStart = function () {} - this._manipulationReleaseOverload = this._releaseControlNode; + // copy all edges (if not fully clustered, else there are no edges) + for (var edgeId in this.edges) { + if (this.edges.hasOwnProperty(edgeId)) { + this.sectors["frozen"][sectorId]["edges"][edgeId] = this.edges[edgeId]; + } + } - // redraw to show the unselect - this._redraw(); + // merge the nodeIndices + for (var i = 0; i < this.nodeIndices.length; i++) { + this.sectors["frozen"][sectorId]["nodeIndices"].push(this.nodeIndices[i]); + } }; /** - * the function bound to the selection event. It checks if you want to connect a cluster and changes the description - * to walk the user through the process. + * This clusters the sector to one cluster. It was a single cluster before this process started so + * we revert to that state. The clusterToFit function with a maximum size of 1 node does this. * * @private */ - exports._selectControlNode = function(pointer) { - this.edgeBeingEdited.controlNodes.from.unselect(); - this.edgeBeingEdited.controlNodes.to.unselect(); - this.selectedControlNode = this.edgeBeingEdited._getSelectedControlNode(this._XconvertDOMtoCanvas(pointer.x),this._YconvertDOMtoCanvas(pointer.y)); - if (this.selectedControlNode !== null) { - this.selectedControlNode.select(); - this.freezeSimulation = true; - } - this._redraw(); + exports._collapseThisToSingleCluster = function() { + this.clusterToFit(1,false); }; /** - * the function bound to the selection event. It checks if you want to connect a cluster and changes the description - * to walk the user through the process. + * We create a new active sector from the node that we want to open. * + * @param node * @private */ - exports._controlNodeDrag = function(event) { - var pointer = this._getPointer(event.gesture.center); - if (this.selectedControlNode !== null && this.selectedControlNode !== undefined) { - this.selectedControlNode.x = this._XconvertDOMtoCanvas(pointer.x); - this.selectedControlNode.y = this._YconvertDOMtoCanvas(pointer.y); - } - this._redraw(); - }; + exports._addSector = function(node) { + // this is the currently active sector + var sector = this._sector(); + + // // this should allow me to select nodes from a frozen set. + // if (this.sectors['active'][sector]["nodes"].hasOwnProperty(node.id)) { + // console.log("the node is part of the active sector"); + // } + // else { + // console.log("I dont know what the fuck happened!!"); + // } + + // when we switch to a new sector, we remove the node that will be expanded from the current nodes list. + delete this.nodes[node.id]; + + var unqiueIdentifier = util.randomUUID(); + + // we fully freeze the currently active sector + this._freezeSector(sector); + + // we create a new active sector. This sector has the Id of the node to ensure uniqueness + this._createNewSector(unqiueIdentifier); + + // we add the active sector to the sectors array to be able to revert these steps later on + this._setActiveSector(unqiueIdentifier); + // we redirect the global references to the new sector's references. this._sector() now returns unqiueIdentifier + this._switchToSector(this._sector()); - /** - * - * @param pointer - * @private - */ - exports._releaseControlNode = function(pointer) { - var newNode = this._getNodeAt(pointer); - if (newNode !== null) { - if (this.edgeBeingEdited.controlNodes.from.selected == true) { - this.edgeBeingEdited._restoreControlNodes(); - this._editEdge(newNode.id, this.edgeBeingEdited.to.id); - this.edgeBeingEdited.controlNodes.from.unselect(); - } - if (this.edgeBeingEdited.controlNodes.to.selected == true) { - this.edgeBeingEdited._restoreControlNodes(); - this._editEdge(this.edgeBeingEdited.from.id, newNode.id); - this.edgeBeingEdited.controlNodes.to.unselect(); - } - } - else { - this.edgeBeingEdited._restoreControlNodes(); - } - this.freezeSimulation = false; - this._redraw(); + // finally we add the node we removed from our previous active sector to the new active sector + this.nodes[node.id] = node; }; + /** - * the function bound to the selection event. It checks if you want to connect a cluster and changes the description - * to walk the user through the process. + * We close the sector that is currently open and revert back to the one before. + * If the active sector is the "default" sector, nothing happens. * * @private */ - exports._handleConnect = function(pointer) { - if (this._getSelectedNodeCount() == 0) { - var node = this._getNodeAt(pointer); + exports._collapseSector = function() { + // the currently active sector + var sector = this._sector(); - if (node != null) { - if (node.clusterSize > 1) { - alert(this.constants.locales[this.constants.locale]['createEdgeError']) - } - else { - this._selectObject(node,false); - var supportNodes = this.sectors['support']['nodes']; + // we cannot collapse the default sector + if (sector != "default") { + if ((this.nodeIndices.length == 1) || + (this.sectors["active"][sector]["drawingNode"].width*this.scale < this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientWidth) || + (this.sectors["active"][sector]["drawingNode"].height*this.scale < this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientHeight)) { + var previousSector = this._previousSector(); - // create a node the temporary line can look at - supportNodes['targetNode'] = new Node({id:'targetNode'},{},{},this.constants); - var targetNode = supportNodes['targetNode']; - targetNode.x = node.x; - targetNode.y = node.y; + // we collapse the sector back to a single cluster + this._collapseThisToSingleCluster(); - // create a temporary edge - this.edges['connectionEdge'] = new Edge({id:"connectionEdge",from:node.id,to:targetNode.id}, this, this.constants); - var connectionEdge = this.edges['connectionEdge']; - connectionEdge.from = node; - connectionEdge.connected = true; - connectionEdge.options.smoothCurves = {enabled: true, - dynamic: false, - type: "continuous", - roundness: 0.5 - }; - connectionEdge.selected = true; - connectionEdge.to = targetNode; + // we move the remaining nodes, edges and nodeIndices to the previous sector. + // This previous sector is the one we will reactivate + this._mergeThisWithFrozen(previousSector); - this.cachedFunctions["_handleOnDrag"] = this._handleOnDrag; - this._handleOnDrag = function(event) { - var pointer = this._getPointer(event.gesture.center); - var connectionEdge = this.edges['connectionEdge']; - connectionEdge.to.x = this._XconvertDOMtoCanvas(pointer.x); - connectionEdge.to.y = this._YconvertDOMtoCanvas(pointer.y); - }; + // the previously active (frozen) sector now has all the data from the currently active sector. + // we can now delete the active sector. + this._deleteActiveSector(sector); - this.moving = true; - this.start(); - } - } - } - }; + // we activate the previously active (and currently frozen) sector. + this._activateSector(previousSector); - exports._finishConnect = function(event) { - if (this._getSelectedNodeCount() == 1) { - var pointer = this._getPointer(event.gesture.center); - // restore the drag function - this._handleOnDrag = this.cachedFunctions["_handleOnDrag"]; - delete this.cachedFunctions["_handleOnDrag"]; + // we load the references from the newly active sector into the global references + this._switchToSector(previousSector); - // remember the edge id - var connectFromId = this.edges['connectionEdge'].fromId; + // we forget the previously active sector because we reverted to the one before + this._forgetLastSector(); - // remove the temporary nodes and edge - delete this.edges['connectionEdge']; - delete this.sectors['support']['nodes']['targetNode']; - delete this.sectors['support']['nodes']['targetViaNode']; + // finally, we update the node index list. + this._updateNodeIndexList(); - var node = this._getNodeAt(pointer); - if (node != null) { - if (node.clusterSize > 1) { - alert(this.constants.locales[this.constants.locale]["createEdgeError"]) - } - else { - this._createEdge(connectFromId,node.id); - this._createManipulatorBar(); - } + // we refresh the list with calulation nodes and calculation node indices. + this._updateCalculationNodes(); } - this._unselectAll(); } }; /** - * Adds a node on the specified location + * This runs a function in all active sectors. This is used in _redraw() and the _initializeForceCalculation(). + * + * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors + * | we dont pass the function itself because then the "this" is the window object + * | instead of the Network object + * @param {*} [argument] | Optional: arguments to pass to the runFunction + * @private */ - exports._addNode = function() { - if (this._selectionIsEmpty() && this.editMode == true) { - var positionObject = this._pointerToPositionObject(this.pointerPosition); - var defaultData = {id:util.randomUUID(),x:positionObject.left,y:positionObject.top,label:"new",allowedToMoveX:true,allowedToMoveY:true}; - if (this.triggerFunctions.add) { - if (this.triggerFunctions.add.length == 2) { - var me = this; - this.triggerFunctions.add(defaultData, function(finalizedData) { - me.nodesData.add(finalizedData); - me._createManipulatorBar(); - me.moving = true; - me.start(); - }); - } - else { - throw new Error('The function for add does not support two arguments (data,callback)'); - this._createManipulatorBar(); - this.moving = true; - this.start(); + exports._doInAllActiveSectors = function(runFunction,argument) { + var returnValues = []; + if (argument === undefined) { + for (var sector in this.sectors["active"]) { + if (this.sectors["active"].hasOwnProperty(sector)) { + // switch the global references to those of this sector + this._switchToActiveSector(sector); + returnValues.push( this[runFunction]() ); } } - else { - this.nodesData.add(defaultData); - this._createManipulatorBar(); - this.moving = true; - this.start(); + } + else { + for (var sector in this.sectors["active"]) { + if (this.sectors["active"].hasOwnProperty(sector)) { + // switch the global references to those of this sector + this._switchToActiveSector(sector); + var args = Array.prototype.splice.call(arguments, 1); + if (args.length > 1) { + returnValues.push( this[runFunction](args[0],args[1]) ); + } + else { + returnValues.push( this[runFunction](argument) ); + } + } } } + // we revert the global references back to our active sector + this._loadLatestSector(); + return returnValues; }; /** - * connect two nodes with a new edge. + * This runs a function in all active sectors. This is used in _redraw() and the _initializeForceCalculation(). * + * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors + * | we dont pass the function itself because then the "this" is the window object + * | instead of the Network object + * @param {*} [argument] | Optional: arguments to pass to the runFunction * @private */ - exports._createEdge = function(sourceNodeId,targetNodeId) { - if (this.editMode == true) { - var defaultData = {from:sourceNodeId, to:targetNodeId}; - if (this.triggerFunctions.connect) { - if (this.triggerFunctions.connect.length == 2) { - var me = this; - this.triggerFunctions.connect(defaultData, function(finalizedData) { - me.edgesData.add(finalizedData); - me.moving = true; - me.start(); - }); - } - else { - throw new Error('The function for connect does not support two arguments (data,callback)'); - this.moving = true; - this.start(); - } + exports._doInSupportSector = function(runFunction,argument) { + var returnValues = false; + if (argument === undefined) { + this._switchToSupportSector(); + returnValues = this[runFunction](); + } + else { + this._switchToSupportSector(); + var args = Array.prototype.splice.call(arguments, 1); + if (args.length > 1) { + returnValues = this[runFunction](args[0],args[1]); } else { - this.edgesData.add(defaultData); - this.moving = true; - this.start(); + returnValues = this[runFunction](argument); } } + // we revert the global references back to our active sector + this._loadLatestSector(); + return returnValues; }; + /** - * connect two nodes with a new edge. + * This runs a function in all frozen sectors. This is used in the _redraw(). * + * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors + * | we don't pass the function itself because then the "this" is the window object + * | instead of the Network object + * @param {*} [argument] | Optional: arguments to pass to the runFunction * @private */ - exports._editEdge = function(sourceNodeId,targetNodeId) { - if (this.editMode == true) { - var defaultData = {id: this.edgeBeingEdited.id, from:sourceNodeId, to:targetNodeId}; - if (this.triggerFunctions.editEdge) { - if (this.triggerFunctions.editEdge.length == 2) { - var me = this; - this.triggerFunctions.editEdge(defaultData, function(finalizedData) { - me.edgesData.update(finalizedData); - me.moving = true; - me.start(); - }); - } - else { - throw new Error('The function for edit does not support two arguments (data, callback)'); - this.moving = true; - this.start(); + exports._doInAllFrozenSectors = function(runFunction,argument) { + if (argument === undefined) { + for (var sector in this.sectors["frozen"]) { + if (this.sectors["frozen"].hasOwnProperty(sector)) { + // switch the global references to those of this sector + this._switchToFrozenSector(sector); + this[runFunction](); } } - else { - this.edgesData.update(defaultData); - this.moving = true; - this.start(); + } + else { + for (var sector in this.sectors["frozen"]) { + if (this.sectors["frozen"].hasOwnProperty(sector)) { + // switch the global references to those of this sector + this._switchToFrozenSector(sector); + var args = Array.prototype.splice.call(arguments, 1); + if (args.length > 1) { + this[runFunction](args[0],args[1]); + } + else { + this[runFunction](argument); + } + } } } + this._loadLatestSector(); }; + /** - * Create the toolbar to edit the selected node. The label and the color can be changed. Other colors are derived from the chosen color. + * This runs a function in all sectors. This is used in the _redraw(). * + * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors + * | we don't pass the function itself because then the "this" is the window object + * | instead of the Network object + * @param {*} [argument] | Optional: arguments to pass to the runFunction * @private */ - exports._editNode = function() { - if (this.triggerFunctions.edit && this.editMode == true) { - var node = this._getSelectedNode(); - var data = {id:node.id, - label: node.label, - group: node.options.group, - shape: node.options.shape, - color: { - background:node.options.color.background, - border:node.options.color.border, - highlight: { - background:node.options.color.highlight.background, - border:node.options.color.highlight.border - } - }}; - if (this.triggerFunctions.edit.length == 2) { - var me = this; - this.triggerFunctions.edit(data, function (finalizedData) { - me.nodesData.update(finalizedData); - me._createManipulatorBar(); - me.moving = true; - me.start(); - }); + exports._doInAllSectors = function(runFunction,argument) { + var args = Array.prototype.splice.call(arguments, 1); + if (argument === undefined) { + this._doInAllActiveSectors(runFunction); + this._doInAllFrozenSectors(runFunction); + } + else { + if (args.length > 1) { + this._doInAllActiveSectors(runFunction,args[0],args[1]); + this._doInAllFrozenSectors(runFunction,args[0],args[1]); } else { - throw new Error('The function for edit does not support two arguments (data, callback)'); + this._doInAllActiveSectors(runFunction,argument); + this._doInAllFrozenSectors(runFunction,argument); } } - else { - throw new Error('No edit function has been bound to this button'); - } }; + /** + * This clears the nodeIndices list. We cannot use this.nodeIndices = [] because we would break the link with the + * active sector. Thus we clear the nodeIndices in the active sector, then reconnect the this.nodeIndices to it. + * + * @private + */ + exports._clearNodeIndexList = function() { + var sector = this._sector(); + this.sectors["active"][sector]["nodeIndices"] = []; + this.nodeIndices = this.sectors["active"][sector]["nodeIndices"]; + }; /** - * delete everything in the selection + * Draw the encompassing sector node * + * @param ctx + * @param sectorType * @private */ - exports._deleteSelected = function() { - if (!this._selectionIsEmpty() && this.editMode == true) { - if (!this._clusterInSelection()) { - var selectedNodes = this.getSelectedNodes(); - var selectedEdges = this.getSelectedEdges(); - if (this.triggerFunctions.del) { - var me = this; - var data = {nodes: selectedNodes, edges: selectedEdges}; - if (this.triggerFunctions.del.length == 2) { - this.triggerFunctions.del(data, function (finalizedData) { - me.edgesData.remove(finalizedData.edges); - me.nodesData.remove(finalizedData.nodes); - me._unselectAll(); - me.moving = true; - me.start(); - }); - } - else { - throw new Error('The function for delete does not support two arguments (data, callback)') + exports._drawSectorNodes = function(ctx,sectorType) { + var minY = 1e9, maxY = -1e9, minX = 1e9, maxX = -1e9, node; + for (var sector in this.sectors[sectorType]) { + if (this.sectors[sectorType].hasOwnProperty(sector)) { + if (this.sectors[sectorType][sector]["drawingNode"] !== undefined) { + + this._switchToSector(sector,sectorType); + + minY = 1e9; maxY = -1e9; minX = 1e9; maxX = -1e9; + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + node.resize(ctx); + if (minX > node.x - 0.5 * node.width) {minX = node.x - 0.5 * node.width;} + if (maxX < node.x + 0.5 * node.width) {maxX = node.x + 0.5 * node.width;} + if (minY > node.y - 0.5 * node.height) {minY = node.y - 0.5 * node.height;} + if (maxY < node.y + 0.5 * node.height) {maxY = node.y + 0.5 * node.height;} + } } + node = this.sectors[sectorType][sector]["drawingNode"]; + node.x = 0.5 * (maxX + minX); + node.y = 0.5 * (maxY + minY); + node.width = 2 * (node.x - minX); + node.height = 2 * (node.y - minY); + node.options.radius = Math.sqrt(Math.pow(0.5*node.width,2) + Math.pow(0.5*node.height,2)); + node.setScale(this.scale); + node._drawCircle(ctx); } - else { - this.edgesData.remove(selectedEdges); - this.nodesData.remove(selectedNodes); - this._unselectAll(); - this.moving = true; - this.start(); - } - } - else { - alert(this.constants.locales[this.constants.locale]["deleteClusterError"]); } } }; + exports._drawAllSectorNodes = function(ctx) { + this._drawSectorNodes(ctx,"frozen"); + this._drawSectorNodes(ctx,"active"); + this._loadLatestSector(); + }; + /***/ }, -/* 64 */ +/* 66 */ /***/ function(module, exports, __webpack_require__) { - var util = __webpack_require__(1); - var Hammer = __webpack_require__(45); + var Node = __webpack_require__(56); - exports._cleanNavigation = function() { - // clean hammer bindings - if (this.navigationHammers.existing.length != 0) { - for (var i = 0; i < this.navigationHammers.existing.length; i++) { - this.navigationHammers.existing[i].dispose(); + /** + * This function can be called from the _doInAllSectors function + * + * @param object + * @param overlappingNodes + * @private + */ + exports._getNodesOverlappingWith = function(object, overlappingNodes) { + var nodes = this.nodes; + for (var nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + if (nodes[nodeId].isOverlappingWith(object)) { + overlappingNodes.push(nodeId); + } } - this.navigationHammers.existing = []; } + }; - this._navigationReleaseOverload = function () {}; - - // clean up previous navigation items - if (this.navigationDivs && this.navigationDivs['wrapper'] && this.navigationDivs['wrapper'].parentNode) { - this.navigationDivs['wrapper'].parentNode.removeChild(this.navigationDivs['wrapper']); - } + /** + * retrieve all nodes overlapping with given object + * @param {Object} object An object with parameters left, top, right, bottom + * @return {Number[]} An array with id's of the overlapping nodes + * @private + */ + exports._getAllNodesOverlappingWith = function (object) { + var overlappingNodes = []; + this._doInAllActiveSectors("_getNodesOverlappingWith",object,overlappingNodes); + return overlappingNodes; }; + /** - * Creation of the navigation controls nodes. They are drawn over the rest of the nodes and are not affected by scale and translation - * they have a triggerFunction which is called on click. If the position of the navigation controls is dependent - * on this.frame.canvas.clientWidth or this.frame.canvas.clientHeight, we flag horizontalAlignLeft and verticalAlignTop false. - * This means that the location will be corrected by the _relocateNavigation function on a size change of the canvas. + * Return a position object in canvasspace from a single point in screenspace * + * @param pointer + * @returns {{left: number, top: number, right: number, bottom: number}} * @private */ - exports._loadNavigationElements = function() { - this._cleanNavigation(); + exports._pointerToPositionObject = function(pointer) { + var x = this._XconvertDOMtoCanvas(pointer.x); + var y = this._YconvertDOMtoCanvas(pointer.y); - this.navigationDivs = {}; - var navigationDivs = ['up','down','left','right','zoomIn','zoomOut','zoomExtends']; - var navigationDivActions = ['_moveUp','_moveDown','_moveLeft','_moveRight','_zoomIn','_zoomOut','_zoomExtent']; + return { + left: x, + top: y, + right: x, + bottom: y + }; + }; - this.navigationDivs['wrapper'] = document.createElement('div'); - this.frame.appendChild(this.navigationDivs['wrapper']); - for (var i = 0; i < navigationDivs.length; i++) { - this.navigationDivs[navigationDivs[i]] = document.createElement('div'); - this.navigationDivs[navigationDivs[i]].className = 'network-navigation ' + navigationDivs[i]; - this.navigationDivs['wrapper'].appendChild(this.navigationDivs[navigationDivs[i]]); + /** + * Get the top node at the a specific point (like a click) + * + * @param {{x: Number, y: Number}} pointer + * @return {Node | null} node + * @private + */ + exports._getNodeAt = function (pointer) { + // we first check if this is an navigation controls element + var positionObject = this._pointerToPositionObject(pointer); + var overlappingNodes = this._getAllNodesOverlappingWith(positionObject); - var hammer = Hammer(this.navigationDivs[navigationDivs[i]], {prevent_default: true}); - hammer.on('touch', this[navigationDivActions[i]].bind(this)); - this.navigationHammers._new.push(hammer); + // if there are overlapping nodes, select the last one, this is the + // one which is drawn on top of the others + if (overlappingNodes.length > 0) { + return this.nodes[overlappingNodes[overlappingNodes.length - 1]]; + } + else { + return null; } + }; - this._navigationReleaseOverload = this._stopMovement; - this.navigationHammers.existing = this.navigationHammers._new; + /** + * retrieve all edges overlapping with given object, selector is around center + * @param {Object} object An object with parameters left, top, right, bottom + * @return {Number[]} An array with id's of the overlapping nodes + * @private + */ + exports._getEdgesOverlappingWith = function (object, overlappingEdges) { + var edges = this.edges; + for (var edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + if (edges[edgeId].isOverlappingWith(object)) { + overlappingEdges.push(edgeId); + } + } + } + }; + + + /** + * retrieve all nodes overlapping with given object + * @param {Object} object An object with parameters left, top, right, bottom + * @return {Number[]} An array with id's of the overlapping nodes + * @private + */ + exports._getAllEdgesOverlappingWith = function (object) { + var overlappingEdges = []; + this._doInAllActiveSectors("_getEdgesOverlappingWith",object,overlappingEdges); + return overlappingEdges; }; - /** - * this stops all movement induced by the navigation buttons + * Place holder. To implement change the _getNodeAt to a _getObjectAt. Have the _getObjectAt call + * _getNodeAt and _getEdgesAt, then priortize the selection to user preferences. * + * @param pointer + * @returns {null} * @private */ - exports._zoomExtent = function(event) { - this.zoomExtent({duration:700}); - event.stopPropagation(); + exports._getEdgeAt = function(pointer) { + var positionObject = this._pointerToPositionObject(pointer); + var overlappingEdges = this._getAllEdgesOverlappingWith(positionObject); + + if (overlappingEdges.length > 0) { + return this.edges[overlappingEdges[overlappingEdges.length - 1]]; + } + else { + return null; + } }; + /** - * this stops all movement induced by the navigation buttons + * Add object to the selection array. * + * @param obj * @private */ - exports._stopMovement = function() { - this._xStopMoving(); - this._yStopMoving(); - this._stopZoom(); + exports._addToSelection = function(obj) { + if (obj instanceof Node) { + this.selectionObj.nodes[obj.id] = obj; + } + else { + this.selectionObj.edges[obj.id] = obj; + } }; - /** - * move the screen up - * By using the increments, instead of adding a fixed number to the translation, we keep fluent and - * instant movement. The onKeypress event triggers immediately, then pauses, then triggers frequently - * To avoid this behaviour, we do the translation in the start loop. + * Add object to the selection array. * + * @param obj * @private */ - exports._moveUp = function(event) { - this.yIncrement = this.constants.keyboard.speed.y; - this.start(); // if there is no node movement, the calculation wont be done - event.preventDefault(); + exports._addToHover = function(obj) { + if (obj instanceof Node) { + this.hoverObj.nodes[obj.id] = obj; + } + else { + this.hoverObj.edges[obj.id] = obj; + } }; /** - * move the screen down + * Remove a single option from selection. + * + * @param {Object} obj * @private */ - exports._moveDown = function(event) { - this.yIncrement = -this.constants.keyboard.speed.y; - this.start(); // if there is no node movement, the calculation wont be done - event.preventDefault(); + exports._removeFromSelection = function(obj) { + if (obj instanceof Node) { + delete this.selectionObj.nodes[obj.id]; + } + else { + delete this.selectionObj.edges[obj.id]; + } }; - /** - * move the screen left + * Unselect all. The selectionObj is useful for this. + * + * @param {Boolean} [doNotTrigger] | ignore trigger * @private */ - exports._moveLeft = function(event) { - this.xIncrement = this.constants.keyboard.speed.x; - this.start(); // if there is no node movement, the calculation wont be done - event.preventDefault(); - }; + exports._unselectAll = function(doNotTrigger) { + if (doNotTrigger === undefined) { + doNotTrigger = false; + } + for(var nodeId in this.selectionObj.nodes) { + if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { + this.selectionObj.nodes[nodeId].unselect(); + } + } + for(var edgeId in this.selectionObj.edges) { + if(this.selectionObj.edges.hasOwnProperty(edgeId)) { + this.selectionObj.edges[edgeId].unselect(); + } + } + this.selectionObj = {nodes:{},edges:{}}; + + if (doNotTrigger == false) { + this.emit('select', this.getSelection()); + } + }; /** - * move the screen right + * Unselect all clusters. The selectionObj is useful for this. + * + * @param {Boolean} [doNotTrigger] | ignore trigger * @private */ - exports._moveRight = function(event) { - this.xIncrement = -this.constants.keyboard.speed.y; - this.start(); // if there is no node movement, the calculation wont be done - event.preventDefault(); + exports._unselectClusters = function(doNotTrigger) { + if (doNotTrigger === undefined) { + doNotTrigger = false; + } + + for (var nodeId in this.selectionObj.nodes) { + if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { + if (this.selectionObj.nodes[nodeId].clusterSize > 1) { + this.selectionObj.nodes[nodeId].unselect(); + this._removeFromSelection(this.selectionObj.nodes[nodeId]); + } + } + } + + if (doNotTrigger == false) { + this.emit('select', this.getSelection()); + } }; /** - * Zoom in, using the same method as the movement. + * return the number of selected nodes + * + * @returns {number} * @private */ - exports._zoomIn = function(event) { - this.zoomIncrement = this.constants.keyboard.speed.zoom; - this.start(); // if there is no node movement, the calculation wont be done - event.preventDefault(); + exports._getSelectedNodeCount = function() { + var count = 0; + for (var nodeId in this.selectionObj.nodes) { + if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { + count += 1; + } + } + return count; }; - /** - * Zoom out + * return the selected node + * + * @returns {number} * @private */ - exports._zoomOut = function(event) { - this.zoomIncrement = -this.constants.keyboard.speed.zoom; - this.start(); // if there is no node movement, the calculation wont be done - event.preventDefault(); + exports._getSelectedNode = function() { + for (var nodeId in this.selectionObj.nodes) { + if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { + return this.selectionObj.nodes[nodeId]; + } + } + return null; }; - /** - * Stop zooming and unhighlight the zoom controls + * return the selected edge + * + * @returns {number} * @private */ - exports._stopZoom = function(event) { - this.zoomIncrement = 0; - event && event.preventDefault(); + exports._getSelectedEdge = function() { + for (var edgeId in this.selectionObj.edges) { + if (this.selectionObj.edges.hasOwnProperty(edgeId)) { + return this.selectionObj.edges[edgeId]; + } + } + return null; }; /** - * Stop moving in the Y direction and unHighlight the up and down + * return the number of selected edges + * + * @returns {number} * @private */ - exports._yStopMoving = function(event) { - this.yIncrement = 0; - event && event.preventDefault(); + exports._getSelectedEdgeCount = function() { + var count = 0; + for (var edgeId in this.selectionObj.edges) { + if (this.selectionObj.edges.hasOwnProperty(edgeId)) { + count += 1; + } + } + return count; }; /** - * Stop moving in the X direction and unHighlight left and right. + * return the number of selected objects. + * + * @returns {number} * @private */ - exports._xStopMoving = function(event) { - this.xIncrement = 0; - event && event.preventDefault(); - }; - - -/***/ }, -/* 65 */ -/***/ function(module, exports, __webpack_require__) { - - exports._resetLevels = function() { - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - var node = this.nodes[nodeId]; - if (node.preassignedLevel == false) { - node.level = -1; - node.hierarchyEnumerated = false; - } + exports._getSelectedObjectCount = function() { + var count = 0; + for(var nodeId in this.selectionObj.nodes) { + if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { + count += 1; + } + } + for(var edgeId in this.selectionObj.edges) { + if(this.selectionObj.edges.hasOwnProperty(edgeId)) { + count += 1; } } + return count; }; /** - * This is the main function to layout the nodes in a hierarchical way. - * It checks if the node details are supplied correctly + * Check if anything is selected * + * @returns {boolean} * @private */ - exports._setupHierarchicalLayout = function() { - if (this.constants.hierarchicalLayout.enabled == true && this.nodeIndices.length > 0) { - // get the size of the largest hubs and check if the user has defined a level for a node. - var hubsize = 0; - var node, nodeId; - var definedLevel = false; - var undefinedLevel = false; - - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - if (node.level != -1) { - definedLevel = true; - } - else { - undefinedLevel = true; - } - if (hubsize < node.edges.length) { - hubsize = node.edges.length; - } - } + exports._selectionIsEmpty = function() { + for(var nodeId in this.selectionObj.nodes) { + if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { + return false; } - - // if the user defined some levels but not all, alert and run without hierarchical layout - if (undefinedLevel == true && definedLevel == true) { - 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(undefined,true,this.constants.clustering.enabled); - if (!this.constants.clustering.enabled) { - this.start(); - } + } + for(var edgeId in this.selectionObj.edges) { + if(this.selectionObj.edges.hasOwnProperty(edgeId)) { + return false; } - else { - // setup the system to use hierarchical method. - this._changeConstants(); + } + return true; + }; - // define levels if undefined by the users. Based on hubsize - if (undefinedLevel == true) { - if (this.constants.hierarchicalLayout.layout == "hubsize") { - this._determineLevels(hubsize); - } - else { - this._determineLevelsDirected(false); - } + /** + * check if one of the selected nodes is a cluster. + * + * @returns {boolean} + * @private + */ + exports._clusterInSelection = function() { + for(var nodeId in this.selectionObj.nodes) { + if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { + if (this.selectionObj.nodes[nodeId].clusterSize > 1) { + return true; } - // check the distribution of the nodes per level. - var distribution = this._getDistribution(); - - // place the nodes on the canvas. This also stablilizes the system. - this._placeNodesByHierarchy(distribution); - - // start the simulation. - this.start(); } } + return false; }; - /** - * This function places the nodes on the canvas based on the hierarchial distribution. + * select the edges connected to the node that is being selected * - * @param {Object} distribution | obtained by the function this._getDistribution() + * @param {Node} node * @private */ - exports._placeNodesByHierarchy = function(distribution) { - var nodeId, node; - - // start placing all the level 0 nodes first. Then recursively position their branches. - for (var level in distribution) { - if (distribution.hasOwnProperty(level)) { + exports._selectConnectedEdges = function(node) { + for (var i = 0; i < node.dynamicEdges.length; i++) { + var edge = node.dynamicEdges[i]; + edge.select(); + this._addToSelection(edge); + } + }; - for (nodeId in distribution[level].nodes) { - if (distribution[level].nodes.hasOwnProperty(nodeId)) { - node = distribution[level].nodes[nodeId]; - if (this.constants.hierarchicalLayout.direction == "UD" || this.constants.hierarchicalLayout.direction == "DU") { - if (node.xFixed) { - node.x = distribution[level].minPos; - node.xFixed = false; + /** + * select the edges connected to the node that is being selected + * + * @param {Node} node + * @private + */ + exports._hoverConnectedEdges = function(node) { + for (var i = 0; i < node.dynamicEdges.length; i++) { + var edge = node.dynamicEdges[i]; + edge.hover = true; + this._addToHover(edge); + } + }; - distribution[level].minPos += distribution[level].nodeSpacing; - } - } - else { - if (node.yFixed) { - node.y = distribution[level].minPos; - node.yFixed = false; - distribution[level].minPos += distribution[level].nodeSpacing; - } - } - this._placeBranchNodes(node.edges,node.id,distribution,node.level); - } - } - } + /** + * unselect the edges connected to the node that is being selected + * + * @param {Node} node + * @private + */ + exports._unselectConnectedEdges = function(node) { + for (var i = 0; i < node.dynamicEdges.length; i++) { + var edge = node.dynamicEdges[i]; + edge.unselect(); + this._removeFromSelection(edge); } - - // stabilize the system after positioning. This function calls zoomExtent. - this._stabilize(); }; + + /** - * This function get the distribution of levels based on hubsize + * This is called when someone clicks on a node. either select or deselect it. + * If there is an existing selection and we don't want to append to it, clear the existing selection * - * @returns {Object} + * @param {Node || Edge} object + * @param {Boolean} append + * @param {Boolean} [doNotTrigger] | ignore trigger * @private */ - exports._getDistribution = function() { - var distribution = {}; - var nodeId, node, level; - - // we fix Y because the hierarchy is vertical, we fix X so we do not give a node an x position for a second time. - // the fix of X is removed after the x value has been set. - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - node.xFixed = true; - node.yFixed = true; - if (this.constants.hierarchicalLayout.direction == "UD" || this.constants.hierarchicalLayout.direction == "DU") { - node.y = this.constants.hierarchicalLayout.levelSeparation*node.level; - } - else { - node.x = this.constants.hierarchicalLayout.levelSeparation*node.level; - } - if (distribution[node.level] === undefined) { - distribution[node.level] = {amount: 0, nodes: {}, minPos:0, nodeSpacing:0}; - } - distribution[node.level].amount += 1; - distribution[node.level].nodes[nodeId] = node; - } + exports._selectObject = function(object, append, doNotTrigger, highlightEdges, overrideSelectable) { + if (doNotTrigger === undefined) { + doNotTrigger = false; + } + if (highlightEdges === undefined) { + highlightEdges = true; } - // determine the largest amount of nodes of all levels - var maxCount = 0; - for (level in distribution) { - if (distribution.hasOwnProperty(level)) { - if (maxCount < distribution[level].amount) { - maxCount = distribution[level].amount; - } - } + if (this._selectionIsEmpty() == false && append == false && this.forceAppendSelection == false) { + this._unselectAll(true); } - // set the initial position and spacing of each nodes accordingly - for (level in distribution) { - if (distribution.hasOwnProperty(level)) { - distribution[level].nodeSpacing = (maxCount + 1) * this.constants.hierarchicalLayout.nodeSpacing; - distribution[level].nodeSpacing /= (distribution[level].amount + 1); - distribution[level].minPos = distribution[level].nodeSpacing - (0.5 * (distribution[level].amount + 1) * distribution[level].nodeSpacing); + // selectable allows the object to be selected. Override can be used if needed to bypass this. + if (object.selected == false && (this.constants.selectable == true || overrideSelectable)) { + object.select(); + this._addToSelection(object); + if (object instanceof Node && this.blockConnectingEdgeSelection == false && highlightEdges == true) { + this._selectConnectedEdges(object); } } + // do not select the object if selectable is false, only add it to selection to allow drag to work + else if (object.selected == false) { + this._addToSelection(object); + doNotTrigger = true; + } + else { + object.unselect(); + this._removeFromSelection(object); + } - return distribution; + if (doNotTrigger == false) { + this.emit('select', this.getSelection()); + } }; /** - * this function allocates nodes in levels based on the recursive branching from the largest hubs. + * This is called when someone clicks on a node. either select or deselect it. + * If there is an existing selection and we don't want to append to it, clear the existing selection * - * @param hubsize + * @param {Node || Edge} object * @private */ - exports._determineLevels = function(hubsize) { - var nodeId, node; - - // determine hubs - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - if (node.edges.length == hubsize) { - node.level = 0; - } - } + exports._blurObject = function(object) { + if (object.hover == true) { + object.hover = false; + this.emit("blurNode",{node:object.id}); } + }; - // branch from hubs - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - if (node.level == 0) { - this._setLevel(1,node.edges,node.id); - } + /** + * This is called when someone clicks on a node. either select or deselect it. + * If there is an existing selection and we don't want to append to it, clear the existing selection + * + * @param {Node || Edge} object + * @private + */ + exports._hoverObject = function(object) { + if (object.hover == false) { + object.hover = true; + this._addToHover(object); + if (object instanceof Node) { + this.emit("hoverNode",{node:object.id}); } } + if (object instanceof Node) { + this._hoverConnectedEdges(object); + } }; - /** - * this function allocates nodes in levels based on the direction of the edges + * handles the selection part of the touch, only for navigation controls elements; + * Touch is triggered before tap, also before hold. Hold triggers after a while. + * This is the most responsive solution * - * @param hubsize + * @param {Object} pointer * @private */ - exports._determineLevelsDirected = function() { - var nodeId, node, firstNode; - var minLevel = 10000; + exports._handleTouch = function(pointer) { + }; - // set first node to source - firstNode = this.nodes[this.nodeIndices[0]]; - firstNode.level = minLevel; - this._setLevelDirected(minLevel,firstNode.edges,firstNode.id); - // get the minimum level - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - minLevel = node.level < minLevel ? node.level : minLevel; + /** + * handles the selection part of the tap; + * + * @param {Object} pointer + * @private + */ + exports._handleTap = function(pointer) { + var node = this._getNodeAt(pointer); + if (node != null) { + this._selectObject(node, false); + } + else { + var edge = this._getEdgeAt(pointer); + if (edge != null) { + this._selectObject(edge, false); } - } - - // subtract the minimum from the set so we have a range starting from 0 - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - node.level -= minLevel; + else { + this._unselectAll(); } } + var properties = this.getSelection(); + properties['pointer'] = { + DOM: {x: pointer.x, y: pointer.y}, + canvas: {x: this._XconvertDOMtoCanvas(pointer.x), y: this._YconvertDOMtoCanvas(pointer.y)} + } + this.emit("click", properties); + this._redraw(); }; /** - * Since hierarchical layout does not support: - * - smooth curves (based on the physics), - * - clustering (based on dynamic node counts) - * - * We disable both features so there will be no problems. + * handles the selection part of the double tap and opens a cluster if needed * + * @param {Object} pointer * @private */ - exports._changeConstants = function() { - this.constants.clustering.enabled = false; - this.constants.physics.barnesHut.enabled = false; - this.constants.physics.hierarchicalRepulsion.enabled = true; - this._loadSelectedForceSolver(); - if (this.constants.smoothCurves.enabled == true) { - this.constants.smoothCurves.dynamic = false; + exports._handleDoubleTap = function(pointer) { + var node = this._getNodeAt(pointer); + if (node != null && node !== undefined) { + // we reset the areaCenter here so the opening of the node will occur + this.areaCenter = {"x" : this._XconvertDOMtoCanvas(pointer.x), + "y" : this._YconvertDOMtoCanvas(pointer.y)}; + this.openCluster(node); } - this._configureSmoothCurves(); - - var config = this.constants.hierarchicalLayout; - config.levelSeparation = Math.abs(config.levelSeparation); - if (config.direction == "RL" || config.direction == "DU") { - config.levelSeparation *= -1; + var properties = this.getSelection(); + properties['pointer'] = { + DOM: {x: pointer.x, y: pointer.y}, + canvas: {x: this._XconvertDOMtoCanvas(pointer.x), y: this._YconvertDOMtoCanvas(pointer.y)} } + this.emit("doubleClick", properties); + }; - if (config.direction == "RL" || config.direction == "LR") { - if (this.constants.smoothCurves.enabled == true) { - this.constants.smoothCurves.type = "vertical"; - } + + /** + * Handle the onHold selection part + * + * @param pointer + * @private + */ + exports._handleOnHold = function(pointer) { + var node = this._getNodeAt(pointer); + if (node != null) { + this._selectObject(node,true); } else { - if (this.constants.smoothCurves.enabled == true) { - this.constants.smoothCurves.type = "horizontal"; + var edge = this._getEdgeAt(pointer); + if (edge != null) { + this._selectObject(edge,true); } } + this._redraw(); }; /** - * This is a recursively called function to enumerate the branches from the largest hubs and place the nodes - * on a X position that ensures there will be no overlap. + * handle the onRelease event. These functions are here for the navigation controls module + * and data manipulation module. * - * @param edges - * @param parentId - * @param distribution - * @param parentLevel - * @private + * @private */ - exports._placeBranchNodes = function(edges, parentId, distribution, parentLevel) { - for (var i = 0; i < edges.length; i++) { - var childNode = null; - if (edges[i].toId == parentId) { - childNode = edges[i].from; - } - else { - childNode = edges[i].to; - } + exports._handleOnRelease = function(pointer) { + this._manipulationReleaseOverload(pointer); + this._navigationReleaseOverload(pointer); + }; - // if a node is conneceted to another node on the same level (or higher (means lower level))!, this is not handled here. - var nodeMoved = false; - if (this.constants.hierarchicalLayout.direction == "UD" || this.constants.hierarchicalLayout.direction == "DU") { - if (childNode.xFixed && childNode.level > parentLevel) { - childNode.xFixed = false; - childNode.x = distribution[childNode.level].minPos; - nodeMoved = true; - } - } - else { - if (childNode.yFixed && childNode.level > parentLevel) { - childNode.yFixed = false; - childNode.y = distribution[childNode.level].minPos; - nodeMoved = true; - } - } + exports._manipulationReleaseOverload = function (pointer) {}; + exports._navigationReleaseOverload = function (pointer) {}; - if (nodeMoved == true) { - distribution[childNode.level].minPos += distribution[childNode.level].nodeSpacing; - if (childNode.edges.length > 1) { - this._placeBranchNodes(childNode.edges,childNode.id,distribution,childNode.level); + /** + * + * retrieve the currently selected objects + * @return {{nodes: Array., edges: Array.}} selection + */ + exports.getSelection = function() { + var nodeIds = this.getSelectedNodes(); + var edgeIds = this.getSelectedEdges(); + return {nodes:nodeIds, edges:edgeIds}; + }; + + /** + * + * retrieve the currently selected nodes + * @return {String[]} selection An array with the ids of the + * selected nodes. + */ + exports.getSelectedNodes = function() { + var idArray = []; + if (this.constants.selectable == true) { + for (var nodeId in this.selectionObj.nodes) { + if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { + idArray.push(nodeId); } } } + return idArray }; - /** - * this function is called recursively to enumerate the barnches of the largest hubs and give each node a level. * - * @param level - * @param edges - * @param parentId - * @private + * retrieve the currently selected edges + * @return {Array} selection An array with the ids of the + * selected nodes. */ - exports._setLevel = function(level, edges, parentId) { - for (var i = 0; i < edges.length; i++) { - var childNode = null; - if (edges[i].toId == parentId) { - childNode = edges[i].from; - } - else { - childNode = edges[i].to; - } - if (childNode.level == -1 || childNode.level > level) { - childNode.level = level; - if (childNode.edges.length > 1) { - this._setLevel(level+1, childNode.edges, childNode.id); + exports.getSelectedEdges = function() { + var idArray = []; + if (this.constants.selectable == true) { + for (var edgeId in this.selectionObj.edges) { + if (this.selectionObj.edges.hasOwnProperty(edgeId)) { + idArray.push(edgeId); } } } + return idArray; }; /** - * this function is called recursively to enumerate the branched of the first node and give each node a level based on edge direction - * - * @param level - * @param edges - * @param parentId - * @private + * select zero or more nodes DEPRICATED + * @param {Number[] | String[]} selection An array with the ids of the + * selected nodes. */ - exports._setLevelDirected = function(level, edges, parentId) { - this.nodes[parentId].hierarchyEnumerated = true; - var childNode, direction; - for (var i = 0; i < edges.length; i++) { - direction = 1; - if (edges[i].toId == parentId) { - childNode = edges[i].from; - direction = -1; - } - else { - childNode = edges[i].to; - } - if (childNode.level == -1) { - childNode.level = level + direction; + exports.setSelection = function() { + console.log("setSelection is deprecated. Please use selectNodes instead.") + }; + + + /** + * select zero or more nodes with the option to highlight edges + * @param {Number[] | String[]} selection An array with the ids of the + * selected nodes. + * @param {boolean} [highlightEdges] + */ + exports.selectNodes = function(selection, highlightEdges) { + var i, iMax, id; + + if (!selection || (selection.length == undefined)) + throw 'Selection must be an array with ids'; + + // first unselect any selected node + this._unselectAll(true); + + for (i = 0, iMax = selection.length; i < iMax; i++) { + id = selection[i]; + + var node = this.nodes[id]; + if (!node) { + throw new RangeError('Node with id "' + id + '" not found'); } + this._selectObject(node,true,true,highlightEdges,true); } + this.redraw(); + }; - for (var i = 0; i < edges.length; i++) { - if (edges[i].toId == parentId) {childNode = edges[i].from;} - else {childNode = edges[i].to;} - if (childNode.edges.length > 1 && childNode.hierarchyEnumerated === false) { - this._setLevelDirected(childNode.level, childNode.edges, childNode.id); + /** + * select zero or more edges + * @param {Number[] | String[]} selection An array with the ids of the + * selected nodes. + */ + exports.selectEdges = function(selection) { + var i, iMax, id; + + if (!selection || (selection.length == undefined)) + throw 'Selection must be an array with ids'; + + // first unselect any selected node + this._unselectAll(true); + + for (i = 0, iMax = selection.length; i < iMax; i++) { + id = selection[i]; + + var edge = this.edges[id]; + if (!edge) { + throw new RangeError('Edge with id "' + id + '" not found'); } + this._selectObject(edge,true,true,false,true); } + this.redraw(); }; - /** - * Unfix nodes - * + * Validate the selection: remove ids of nodes which no longer exist * @private */ - exports._restoreNodes = function() { - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - this.nodes[nodeId].xFixed = false; - this.nodes[nodeId].yFixed = false; + exports._updateSelection = function () { + for(var nodeId in this.selectionObj.nodes) { + if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { + if (!this.nodes.hasOwnProperty(nodeId)) { + delete this.selectionObj.nodes[nodeId]; + } + } + } + for(var edgeId in this.selectionObj.edges) { + if(this.selectionObj.edges.hasOwnProperty(edgeId)) { + if (!this.edges.hasOwnProperty(edgeId)) { + delete this.selectionObj.edges[edgeId]; + } } } }; /***/ }, -/* 66 */ +/* 67 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); - var RepulsionMixin = __webpack_require__(68); - var HierarchialRepulsionMixin = __webpack_require__(69); - var BarnesHutMixin = __webpack_require__(70); + var Node = __webpack_require__(56); + var Edge = __webpack_require__(57); /** - * Toggling barnes Hut calculation on and off. + * clears the toolbar div element of children * * @private */ - exports._toggleBarnesHut = function () { - this.constants.physics.barnesHut.enabled = !this.constants.physics.barnesHut.enabled; - this._loadSelectedForceSolver(); - this.moving = true; - this.start(); - }; + exports._clearManipulatorBar = function() { + this._recursiveDOMDelete(this.manipulationDiv); + this.manipulationDOM = {}; + this._manipulationReleaseOverload = function () {}; + delete this.sectors['support']['nodes']['targetNode']; + delete this.sectors['support']['nodes']['targetViaNode']; + this.controlNodesActive = false; + this.freezeSimulation = false; + }; /** - * This loads the node force solver based on the barnes hut or repulsion algorithm + * Manipulation UI temporarily overloads certain functions to extend or replace them. To be able to restore + * these functions to their original functionality, we saved them in this.cachedFunctions. + * This function restores these functions to their original function. * * @private */ - exports._loadSelectedForceSolver = function () { - // this overloads the this._calculateNodeForces - if (this.constants.physics.barnesHut.enabled == true) { - this._clearMixin(RepulsionMixin); - this._clearMixin(HierarchialRepulsionMixin); - - this.constants.physics.centralGravity = this.constants.physics.barnesHut.centralGravity; - this.constants.physics.springLength = this.constants.physics.barnesHut.springLength; - this.constants.physics.springConstant = this.constants.physics.barnesHut.springConstant; - this.constants.physics.damping = this.constants.physics.barnesHut.damping; - - this._loadMixin(BarnesHutMixin); + exports._restoreOverloadedFunctions = function() { + for (var functionName in this.cachedFunctions) { + if (this.cachedFunctions.hasOwnProperty(functionName)) { + this[functionName] = this.cachedFunctions[functionName]; + delete this.cachedFunctions[functionName]; + } } - else if (this.constants.physics.hierarchicalRepulsion.enabled == true) { - this._clearMixin(BarnesHutMixin); - this._clearMixin(RepulsionMixin); - - this.constants.physics.centralGravity = this.constants.physics.hierarchicalRepulsion.centralGravity; - this.constants.physics.springLength = this.constants.physics.hierarchicalRepulsion.springLength; - this.constants.physics.springConstant = this.constants.physics.hierarchicalRepulsion.springConstant; - this.constants.physics.damping = this.constants.physics.hierarchicalRepulsion.damping; + }; - this._loadMixin(HierarchialRepulsionMixin); + /** + * Enable or disable edit-mode. + * + * @private + */ + exports._toggleEditMode = function() { + this.editMode = !this.editMode; + var toolbar = this.manipulationDiv; + var closeDiv = this.closeDiv; + var editModeDiv = this.editModeDiv; + if (this.editMode == true) { + toolbar.style.display="block"; + closeDiv.style.display="block"; + editModeDiv.style.display="none"; + closeDiv.onclick = this._toggleEditMode.bind(this); } else { - this._clearMixin(BarnesHutMixin); - this._clearMixin(HierarchialRepulsionMixin); - this.barnesHutTree = undefined; - - this.constants.physics.centralGravity = this.constants.physics.repulsion.centralGravity; - this.constants.physics.springLength = this.constants.physics.repulsion.springLength; - this.constants.physics.springConstant = this.constants.physics.repulsion.springConstant; - this.constants.physics.damping = this.constants.physics.repulsion.damping; - - this._loadMixin(RepulsionMixin); + toolbar.style.display="none"; + closeDiv.style.display="none"; + editModeDiv.style.display="block"; + closeDiv.onclick = null; } + this._createManipulatorBar() }; /** - * Before calculating the forces, we check if we need to cluster to keep up performance and we check - * if there is more than one node. If it is just one node, we dont calculate anything. + * main function, creates the main toolbar. Removes functions bound to the select event. Binds all the buttons of the toolbar. * * @private */ - exports._initializeForceCalculation = function () { - // stop calculation if there is only one node - if (this.nodeIndices.length == 1) { - this.nodes[this.nodeIndices[0]]._setForce(0, 0); + exports._createManipulatorBar = function() { + // remove bound functions + if (this.boundFunction) { + this.off('select', this.boundFunction); } - else { - // if there are too many nodes on screen, we cluster without repositioning - if (this.nodeIndices.length > this.constants.clustering.clusterThreshold && this.constants.clustering.enabled == true) { - this.clusterToFit(this.constants.clustering.reduceToNodes, false); - } - // we now start the force calculation - this._calculateForces(); + var locale = this.constants.locales[this.constants.locale]; + + if (this.edgeBeingEdited !== undefined) { + this.edgeBeingEdited._disableControlNodes(); + this.edgeBeingEdited = undefined; + this.selectedControlNode = null; + this.controlNodesActive = false; + this._redraw(); } - }; + // restore overloaded functions + this._restoreOverloadedFunctions(); - /** - * Calculate the external forces acting on the nodes - * Forces are caused by: edges, repulsing forces between nodes, gravity - * @private - */ - exports._calculateForces = function () { - // Gravity is required to keep separated groups from floating off - // the forces are reset to zero in this loop by using _setForce instead - // of _addForce + // resume calculation + this.freezeSimulation = false; - this._calculateGravitationalForces(); - this._calculateNodeForces(); + // reset global variables + this.blockConnectingEdgeSelection = false; + this.forceAppendSelection = false; + this.manipulationDOM = {}; - if (this.constants.physics.springConstant > 0) { - if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { - this._calculateSpringForcesWithSupport(); - } - else { - if (this.constants.physics.hierarchicalRepulsion.enabled == true) { - this._calculateHierarchicalSpringForces(); - } - else { - this._calculateSpringForces(); - } + if (this.editMode == true) { + while (this.manipulationDiv.hasChildNodes()) { + this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); } - } - }; + this.manipulationDOM['addNodeSpan'] = document.createElement('span'); + this.manipulationDOM['addNodeSpan'].className = 'network-manipulationUI add'; + this.manipulationDOM['addNodeLabelSpan'] = document.createElement('span'); + this.manipulationDOM['addNodeLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['addNodeLabelSpan'].innerHTML = locale['addNode']; + this.manipulationDOM['addNodeSpan'].appendChild(this.manipulationDOM['addNodeLabelSpan']); + + this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); + this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; - /** - * Smooth curves are created by adding invisible nodes in the center of the edges. These nodes are also - * handled in the calculateForces function. We then use a quadratic curve with the center node as control. - * This function joins the datanodes and invisible (called support) nodes into one object. - * We do this so we do not contaminate this.nodes with the support nodes. - * - * @private - */ - exports._updateCalculationNodes = function () { - if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { - this.calculationNodes = {}; - this.calculationNodeIndices = []; + this.manipulationDOM['addEdgeSpan'] = document.createElement('span'); + this.manipulationDOM['addEdgeSpan'].className = 'network-manipulationUI connect'; + this.manipulationDOM['addEdgeLabelSpan'] = document.createElement('span'); + this.manipulationDOM['addEdgeLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['addEdgeLabelSpan'].innerHTML = locale['addEdge']; + this.manipulationDOM['addEdgeSpan'].appendChild(this.manipulationDOM['addEdgeLabelSpan']); - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - this.calculationNodes[nodeId] = this.nodes[nodeId]; - } + this.manipulationDiv.appendChild(this.manipulationDOM['addNodeSpan']); + this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); + this.manipulationDiv.appendChild(this.manipulationDOM['addEdgeSpan']); + + if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) { + this.manipulationDOM['seperatorLineDiv2'] = document.createElement('div'); + this.manipulationDOM['seperatorLineDiv2'].className = 'network-seperatorLine'; + + this.manipulationDOM['editNodeSpan'] = document.createElement('span'); + this.manipulationDOM['editNodeSpan'].className = 'network-manipulationUI edit'; + this.manipulationDOM['editNodeLabelSpan'] = document.createElement('span'); + this.manipulationDOM['editNodeLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['editNodeLabelSpan'].innerHTML = locale['editNode']; + this.manipulationDOM['editNodeSpan'].appendChild(this.manipulationDOM['editNodeLabelSpan']); + + this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv2']); + this.manipulationDiv.appendChild(this.manipulationDOM['editNodeSpan']); } - var supportNodes = this.sectors['support']['nodes']; - for (var supportNodeId in supportNodes) { - if (supportNodes.hasOwnProperty(supportNodeId)) { - if (this.edges.hasOwnProperty(supportNodes[supportNodeId].parentEdgeId)) { - this.calculationNodes[supportNodeId] = supportNodes[supportNodeId]; - } - else { - supportNodes[supportNodeId]._setForce(0, 0); - } - } + else if (this._getSelectedEdgeCount() == 1 && this._getSelectedNodeCount() == 0) { + this.manipulationDOM['seperatorLineDiv3'] = document.createElement('div'); + this.manipulationDOM['seperatorLineDiv3'].className = 'network-seperatorLine'; + + this.manipulationDOM['editEdgeSpan'] = document.createElement('span'); + this.manipulationDOM['editEdgeSpan'].className = 'network-manipulationUI edit'; + this.manipulationDOM['editEdgeLabelSpan'] = document.createElement('span'); + this.manipulationDOM['editEdgeLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['editEdgeLabelSpan'].innerHTML = locale['editEdge']; + this.manipulationDOM['editEdgeSpan'].appendChild(this.manipulationDOM['editEdgeLabelSpan']); + + this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv3']); + this.manipulationDiv.appendChild(this.manipulationDOM['editEdgeSpan']); } + if (this._selectionIsEmpty() == false) { + this.manipulationDOM['seperatorLineDiv4'] = document.createElement('div'); + this.manipulationDOM['seperatorLineDiv4'].className = 'network-seperatorLine'; - for (var idx in this.calculationNodes) { - if (this.calculationNodes.hasOwnProperty(idx)) { - this.calculationNodeIndices.push(idx); - } + this.manipulationDOM['deleteSpan'] = document.createElement('span'); + this.manipulationDOM['deleteSpan'].className = 'network-manipulationUI delete'; + this.manipulationDOM['deleteLabelSpan'] = document.createElement('span'); + this.manipulationDOM['deleteLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['deleteLabelSpan'].innerHTML = locale['del']; + this.manipulationDOM['deleteSpan'].appendChild(this.manipulationDOM['deleteLabelSpan']); + + this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv4']); + this.manipulationDiv.appendChild(this.manipulationDOM['deleteSpan']); + } + + + // bind the icons + this.manipulationDOM['addNodeSpan'].onclick = this._createAddNodeToolbar.bind(this); + this.manipulationDOM['addEdgeSpan'].onclick = this._createAddEdgeToolbar.bind(this); + if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) { + this.manipulationDOM['editNodeSpan'].onclick = this._editNode.bind(this); + } + else if (this._getSelectedEdgeCount() == 1 && this._getSelectedNodeCount() == 0) { + this.manipulationDOM['editEdgeSpan'].onclick = this._createEditEdgeToolbar.bind(this); + } + if (this._selectionIsEmpty() == false) { + this.manipulationDOM['deleteSpan'].onclick = this._deleteSelected.bind(this); } + this.closeDiv.onclick = this._toggleEditMode.bind(this); + + var me = this; + this.boundFunction = me._createManipulatorBar; + this.on('select', this.boundFunction); } else { - this.calculationNodes = this.nodes; - this.calculationNodeIndices = this.nodeIndices; + while (this.editModeDiv.hasChildNodes()) { + this.editModeDiv.removeChild(this.editModeDiv.firstChild); + } + + this.manipulationDOM['editModeSpan'] = document.createElement('span'); + this.manipulationDOM['editModeSpan'].className = 'network-manipulationUI edit editmode'; + this.manipulationDOM['editModeLabelSpan'] = document.createElement('span'); + this.manipulationDOM['editModeLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['editModeLabelSpan'].innerHTML = locale['edit']; + this.manipulationDOM['editModeSpan'].appendChild(this.manipulationDOM['editModeLabelSpan']); + + this.editModeDiv.appendChild(this.manipulationDOM['editModeSpan']); + + this.manipulationDOM['editModeSpan'].onclick = this._toggleEditMode.bind(this); } }; + /** - * this function applies the central gravity effect to keep groups from floating off + * Create the toolbar for adding Nodes * * @private */ - exports._calculateGravitationalForces = function () { - var dx, dy, distance, node, i; - var nodes = this.calculationNodes; - var gravity = this.constants.physics.centralGravity; - var gravityForce = 0; + exports._createAddNodeToolbar = function() { + // clear the toolbar + this._clearManipulatorBar(); + if (this.boundFunction) { + this.off('select', this.boundFunction); + } - for (i = 0; i < this.calculationNodeIndices.length; i++) { - node = nodes[this.calculationNodeIndices[i]]; - node.damping = this.constants.physics.damping; // possibly add function to alter damping properties of clusters. - // gravity does not apply when we are in a pocket sector - if (this._sector() == "default" && gravity != 0) { - dx = -node.x; - dy = -node.y; - distance = Math.sqrt(dx * dx + dy * dy); + var locale = this.constants.locales[this.constants.locale]; - gravityForce = (distance == 0) ? 0 : (gravity / distance); - node.fx = dx * gravityForce; - node.fy = dy * gravityForce; - } - else { - node.fx = 0; - node.fy = 0; - } - } - }; + this.manipulationDOM = {}; + this.manipulationDOM['backSpan'] = document.createElement('span'); + this.manipulationDOM['backSpan'].className = 'network-manipulationUI back'; + this.manipulationDOM['backLabelSpan'] = document.createElement('span'); + this.manipulationDOM['backLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['backLabelSpan'].innerHTML = locale['back']; + this.manipulationDOM['backSpan'].appendChild(this.manipulationDOM['backLabelSpan']); + + this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); + this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; + + this.manipulationDOM['descriptionSpan'] = document.createElement('span'); + this.manipulationDOM['descriptionSpan'].className = 'network-manipulationUI none'; + this.manipulationDOM['descriptionLabelSpan'] = document.createElement('span'); + this.manipulationDOM['descriptionLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['descriptionLabelSpan'].innerHTML = locale['addDescription']; + this.manipulationDOM['descriptionSpan'].appendChild(this.manipulationDOM['descriptionLabelSpan']); + this.manipulationDiv.appendChild(this.manipulationDOM['backSpan']); + this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); + this.manipulationDiv.appendChild(this.manipulationDOM['descriptionSpan']); + + // bind the icon + this.manipulationDOM['backSpan'].onclick = this._createManipulatorBar.bind(this); + // we use the boundFunction so we can reference it when we unbind it from the "select" event. + var me = this; + this.boundFunction = me._addNode; + this.on('select', this.boundFunction); + }; /** - * this function calculates the effects of the springs in the case of unsmooth curves. + * create the toolbar to connect nodes * * @private */ - exports._calculateSpringForces = function () { - var edgeLength, edge, edgeId; - var dx, dy, fx, fy, springForce, distance; - var edges = this.edges; + exports._createAddEdgeToolbar = function() { + // clear the toolbar + this._clearManipulatorBar(); + this._unselectAll(true); + this.freezeSimulation = true; - // forces caused by the edges, modelled as springs - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.connected) { - // only calculate forces if nodes are in the same sector - if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { - edgeLength = edge.physics.springLength; - // this implies that the edges between big clusters are longer - edgeLength += (edge.to.clusterSize + edge.from.clusterSize - 2) * this.constants.clustering.edgeGrowth; + if (this.boundFunction) { + this.off('select', this.boundFunction); + } - dx = (edge.from.x - edge.to.x); - dy = (edge.from.y - edge.to.y); - distance = Math.sqrt(dx * dx + dy * dy); + var locale = this.constants.locales[this.constants.locale]; - if (distance == 0) { - distance = 0.01; - } + this._unselectAll(); + this.forceAppendSelection = false; + this.blockConnectingEdgeSelection = true; - // the 1/distance is so the fx and fy can be calculated without sine or cosine. - springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance; + this.manipulationDOM = {}; + this.manipulationDOM['backSpan'] = document.createElement('span'); + this.manipulationDOM['backSpan'].className = 'network-manipulationUI back'; + this.manipulationDOM['backLabelSpan'] = document.createElement('span'); + this.manipulationDOM['backLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['backLabelSpan'].innerHTML = locale['back']; + this.manipulationDOM['backSpan'].appendChild(this.manipulationDOM['backLabelSpan']); - fx = dx * springForce; - fy = dy * springForce; + this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); + this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; - edge.from.fx += fx; - edge.from.fy += fy; - edge.to.fx -= fx; - edge.to.fy -= fy; - } - } - } - } - }; + this.manipulationDOM['descriptionSpan'] = document.createElement('span'); + this.manipulationDOM['descriptionSpan'].className = 'network-manipulationUI none'; + this.manipulationDOM['descriptionLabelSpan'] = document.createElement('span'); + this.manipulationDOM['descriptionLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['descriptionLabelSpan'].innerHTML = locale['edgeDescription']; + this.manipulationDOM['descriptionSpan'].appendChild(this.manipulationDOM['descriptionLabelSpan']); + + this.manipulationDiv.appendChild(this.manipulationDOM['backSpan']); + this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); + this.manipulationDiv.appendChild(this.manipulationDOM['descriptionSpan']); + + // bind the icon + this.manipulationDOM['backSpan'].onclick = this._createManipulatorBar.bind(this); + // we use the boundFunction so we can reference it when we unbind it from the "select" event. + var me = this; + this.boundFunction = me._handleConnect; + this.on('select', this.boundFunction); + // temporarily overload functions + this.cachedFunctions["_handleTouch"] = this._handleTouch; + this.cachedFunctions["_manipulationReleaseOverload"] = this._manipulationReleaseOverload; + this.cachedFunctions["_handleDragStart"] = this._handleDragStart; + this.cachedFunctions["_handleDragEnd"] = this._handleDragEnd; + this._handleTouch = this._handleConnect; + this._manipulationReleaseOverload = function () {}; + this._handleDragStart = function () {}; + this._handleDragEnd = this._finishConnect; + // redraw to show the unselect + this._redraw(); + }; /** - * This function calculates the springforces on the nodes, accounting for the support nodes. + * create the toolbar to edit edges * * @private */ - exports._calculateSpringForcesWithSupport = function () { - var edgeLength, edge, edgeId, combinedClusterSize; - var edges = this.edges; + exports._createEditEdgeToolbar = function() { + // clear the toolbar + this._clearManipulatorBar(); + this.controlNodesActive = true; - // forces caused by the edges, modelled as springs - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.connected) { - // only calculate forces if nodes are in the same sector - if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { - if (edge.via != null) { - var node1 = edge.to; - var node2 = edge.via; - var node3 = edge.from; + if (this.boundFunction) { + this.off('select', this.boundFunction); + } - edgeLength = edge.physics.springLength; + this.edgeBeingEdited = this._getSelectedEdge(); + this.edgeBeingEdited._enableControlNodes(); - combinedClusterSize = node1.clusterSize + node3.clusterSize - 2; + var locale = this.constants.locales[this.constants.locale]; - // this implies that the edges between big clusters are longer - edgeLength += combinedClusterSize * this.constants.clustering.edgeGrowth; - this._calculateSpringForce(node1, node2, 0.5 * edgeLength); - this._calculateSpringForce(node2, node3, 0.5 * edgeLength); - } - } - } - } - } + this.manipulationDOM = {}; + this.manipulationDOM['backSpan'] = document.createElement('span'); + this.manipulationDOM['backSpan'].className = 'network-manipulationUI back'; + this.manipulationDOM['backLabelSpan'] = document.createElement('span'); + this.manipulationDOM['backLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['backLabelSpan'].innerHTML = locale['back']; + this.manipulationDOM['backSpan'].appendChild(this.manipulationDOM['backLabelSpan']); + + this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); + this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; + + this.manipulationDOM['descriptionSpan'] = document.createElement('span'); + this.manipulationDOM['descriptionSpan'].className = 'network-manipulationUI none'; + this.manipulationDOM['descriptionLabelSpan'] = document.createElement('span'); + this.manipulationDOM['descriptionLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['descriptionLabelSpan'].innerHTML = locale['editEdgeDescription']; + this.manipulationDOM['descriptionSpan'].appendChild(this.manipulationDOM['descriptionLabelSpan']); + + this.manipulationDiv.appendChild(this.manipulationDOM['backSpan']); + this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); + this.manipulationDiv.appendChild(this.manipulationDOM['descriptionSpan']); + + // bind the icon + this.manipulationDOM['backSpan'].onclick = this._createManipulatorBar.bind(this); + + // temporarily overload functions + this.cachedFunctions["_handleTouch"] = this._handleTouch; + this.cachedFunctions["_manipulationReleaseOverload"] = this._manipulationReleaseOverload; + this.cachedFunctions["_handleTap"] = this._handleTap; + this.cachedFunctions["_handleDragStart"] = this._handleDragStart; + this.cachedFunctions["_handleOnDrag"] = this._handleOnDrag; + this._handleTouch = this._selectControlNode; + this._handleTap = function () {}; + this._handleOnDrag = this._controlNodeDrag; + this._handleDragStart = function () {} + this._manipulationReleaseOverload = this._releaseControlNode; + + // redraw to show the unselect + this._redraw(); }; /** - * This is the code actually performing the calculation for the function above. It is split out to avoid repetition. + * the function bound to the selection event. It checks if you want to connect a cluster and changes the description + * to walk the user through the process. * - * @param node1 - * @param node2 - * @param edgeLength * @private */ - exports._calculateSpringForce = function (node1, node2, edgeLength) { - var dx, dy, fx, fy, springForce, distance; - - dx = (node1.x - node2.x); - dy = (node1.y - node2.y); - distance = Math.sqrt(dx * dx + dy * dy); - - if (distance == 0) { - distance = 0.01; + exports._selectControlNode = function(pointer) { + this.edgeBeingEdited.controlNodes.from.unselect(); + this.edgeBeingEdited.controlNodes.to.unselect(); + this.selectedControlNode = this.edgeBeingEdited._getSelectedControlNode(this._XconvertDOMtoCanvas(pointer.x),this._YconvertDOMtoCanvas(pointer.y)); + if (this.selectedControlNode !== null) { + this.selectedControlNode.select(); + this.freezeSimulation = true; } + this._redraw(); + }; - // the 1/distance is so the fx and fy can be calculated without sine or cosine. - springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance; - - fx = dx * springForce; - fy = dy * springForce; - node1.fx += fx; - node1.fy += fy; - node2.fx -= fx; - node2.fy -= fy; + /** + * the function bound to the selection event. It checks if you want to connect a cluster and changes the description + * to walk the user through the process. + * + * @private + */ + exports._controlNodeDrag = function(event) { + var pointer = this._getPointer(event.gesture.center); + if (this.selectedControlNode !== null && this.selectedControlNode !== undefined) { + this.selectedControlNode.x = this._XconvertDOMtoCanvas(pointer.x); + this.selectedControlNode.y = this._YconvertDOMtoCanvas(pointer.y); + } + this._redraw(); }; - exports._cleanupPhysicsConfiguration = function() { - if (this.physicsConfiguration !== undefined) { - while (this.physicsConfiguration.hasChildNodes()) { - this.physicsConfiguration.removeChild(this.physicsConfiguration.firstChild); + /** + * + * @param pointer + * @private + */ + exports._releaseControlNode = function(pointer) { + var newNode = this._getNodeAt(pointer); + if (newNode !== null) { + if (this.edgeBeingEdited.controlNodes.from.selected == true) { + this.edgeBeingEdited._restoreControlNodes(); + this._editEdge(newNode.id, this.edgeBeingEdited.to.id); + this.edgeBeingEdited.controlNodes.from.unselect(); + } + if (this.edgeBeingEdited.controlNodes.to.selected == true) { + this.edgeBeingEdited._restoreControlNodes(); + this._editEdge(this.edgeBeingEdited.from.id, newNode.id); + this.edgeBeingEdited.controlNodes.to.unselect(); } - - this.physicsConfiguration.parentNode.removeChild(this.physicsConfiguration); - this.physicsConfiguration = undefined; } - } + else { + this.edgeBeingEdited._restoreControlNodes(); + } + this.freezeSimulation = false; + this._redraw(); + }; /** - * Load the HTML for the physics config and bind it + * the function bound to the selection event. It checks if you want to connect a cluster and changes the description + * to walk the user through the process. + * * @private */ - exports._loadPhysicsConfiguration = function () { - if (this.physicsConfiguration === undefined) { - this.backupConstants = {}; - util.deepExtend(this.backupConstants,this.constants); + exports._handleConnect = function(pointer) { + if (this._getSelectedNodeCount() == 0) { + var node = this._getNodeAt(pointer); - var hierarchicalLayoutDirections = ["LR", "RL", "UD", "DU"]; - this.physicsConfiguration = document.createElement('div'); - this.physicsConfiguration.className = "PhysicsConfiguration"; - this.physicsConfiguration.innerHTML = '' + - '' + - '' + - '' + - '' + - '' + - '' + - '
Simulation Mode:
Barnes HutRepulsionHierarchical
' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '
Options:
' - this.containerElement.parentElement.insertBefore(this.physicsConfiguration, this.containerElement); - this.optionsDiv = document.createElement("div"); - this.optionsDiv.style.fontSize = "14px"; - this.optionsDiv.style.fontFamily = "verdana"; - this.containerElement.parentElement.insertBefore(this.optionsDiv, this.containerElement); + if (node != null) { + if (node.clusterSize > 1) { + alert(this.constants.locales[this.constants.locale]['createEdgeError']) + } + else { + this._selectObject(node,false); + var supportNodes = this.sectors['support']['nodes']; - var rangeElement; - rangeElement = document.getElementById('graph_BH_gc'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_gc', -1, "physics_barnesHut_gravitationalConstant"); - rangeElement = document.getElementById('graph_BH_cg'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_cg', 1, "physics_centralGravity"); - rangeElement = document.getElementById('graph_BH_sc'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_sc', 1, "physics_springConstant"); - rangeElement = document.getElementById('graph_BH_sl'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_sl', 1, "physics_springLength"); - rangeElement = document.getElementById('graph_BH_damp'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_damp', 1, "physics_damping"); + // create a node the temporary line can look at + supportNodes['targetNode'] = new Node({id:'targetNode'},{},{},this.constants); + var targetNode = supportNodes['targetNode']; + targetNode.x = node.x; + targetNode.y = node.y; - rangeElement = document.getElementById('graph_R_nd'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_nd', 1, "physics_repulsion_nodeDistance"); - rangeElement = document.getElementById('graph_R_cg'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_cg', 1, "physics_centralGravity"); - rangeElement = document.getElementById('graph_R_sc'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_sc', 1, "physics_springConstant"); - rangeElement = document.getElementById('graph_R_sl'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_sl', 1, "physics_springLength"); - rangeElement = document.getElementById('graph_R_damp'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_damp', 1, "physics_damping"); + // create a temporary edge + this.edges['connectionEdge'] = new Edge({id:"connectionEdge",from:node.id,to:targetNode.id}, this, this.constants); + var connectionEdge = this.edges['connectionEdge']; + connectionEdge.from = node; + connectionEdge.connected = true; + connectionEdge.options.smoothCurves = {enabled: true, + dynamic: false, + type: "continuous", + roundness: 0.5 + }; + connectionEdge.selected = true; + connectionEdge.to = targetNode; - rangeElement = document.getElementById('graph_H_nd'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_nd', 1, "physics_hierarchicalRepulsion_nodeDistance"); - rangeElement = document.getElementById('graph_H_cg'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_cg', 1, "physics_centralGravity"); - rangeElement = document.getElementById('graph_H_sc'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_sc', 1, "physics_springConstant"); - rangeElement = document.getElementById('graph_H_sl'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_sl', 1, "physics_springLength"); - rangeElement = document.getElementById('graph_H_damp'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_damp', 1, "physics_damping"); - rangeElement = document.getElementById('graph_H_direction'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_direction', hierarchicalLayoutDirections, "hierarchicalLayout_direction"); - rangeElement = document.getElementById('graph_H_levsep'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_levsep', 1, "hierarchicalLayout_levelSeparation"); - rangeElement = document.getElementById('graph_H_nspac'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_nspac', 1, "hierarchicalLayout_nodeSpacing"); + this.cachedFunctions["_handleOnDrag"] = this._handleOnDrag; + this._handleOnDrag = function(event) { + var pointer = this._getPointer(event.gesture.center); + var connectionEdge = this.edges['connectionEdge']; + connectionEdge.to.x = this._XconvertDOMtoCanvas(pointer.x); + connectionEdge.to.y = this._YconvertDOMtoCanvas(pointer.y); + }; - var radioButton1 = document.getElementById("graph_physicsMethod1"); - var radioButton2 = document.getElementById("graph_physicsMethod2"); - var radioButton3 = document.getElementById("graph_physicsMethod3"); - radioButton2.checked = true; - if (this.constants.physics.barnesHut.enabled) { - radioButton1.checked = true; + this.moving = true; + this.start(); + } } - if (this.constants.hierarchicalLayout.enabled) { - radioButton3.checked = true; + } + }; + + exports._finishConnect = function(event) { + if (this._getSelectedNodeCount() == 1) { + var pointer = this._getPointer(event.gesture.center); + // restore the drag function + this._handleOnDrag = this.cachedFunctions["_handleOnDrag"]; + delete this.cachedFunctions["_handleOnDrag"]; + + // remember the edge id + var connectFromId = this.edges['connectionEdge'].fromId; + + // remove the temporary nodes and edge + delete this.edges['connectionEdge']; + delete this.sectors['support']['nodes']['targetNode']; + delete this.sectors['support']['nodes']['targetViaNode']; + + var node = this._getNodeAt(pointer); + if (node != null) { + if (node.clusterSize > 1) { + alert(this.constants.locales[this.constants.locale]["createEdgeError"]) + } + else { + this._createEdge(connectFromId,node.id); + this._createManipulatorBar(); + } } + this._unselectAll(); + } + }; - var graph_toggleSmooth = document.getElementById("graph_toggleSmooth"); - var graph_repositionNodes = document.getElementById("graph_repositionNodes"); - var graph_generateOptions = document.getElementById("graph_generateOptions"); - graph_toggleSmooth.onclick = graphToggleSmoothCurves.bind(this); - graph_repositionNodes.onclick = graphRepositionNodes.bind(this); - graph_generateOptions.onclick = graphGenerateOptions.bind(this); - if (this.constants.smoothCurves == true && this.constants.dynamicSmoothCurves == false) { - graph_toggleSmooth.style.background = "#A4FF56"; + /** + * Adds a node on the specified location + */ + exports._addNode = function() { + if (this._selectionIsEmpty() && this.editMode == true) { + var positionObject = this._pointerToPositionObject(this.pointerPosition); + var defaultData = {id:util.randomUUID(),x:positionObject.left,y:positionObject.top,label:"new",allowedToMoveX:true,allowedToMoveY:true}; + if (this.triggerFunctions.add) { + if (this.triggerFunctions.add.length == 2) { + var me = this; + this.triggerFunctions.add(defaultData, function(finalizedData) { + me.nodesData.add(finalizedData); + me._createManipulatorBar(); + me.moving = true; + me.start(); + }); + } + else { + throw new Error('The function for add does not support two arguments (data,callback)'); + this._createManipulatorBar(); + this.moving = true; + this.start(); + } } else { - graph_toggleSmooth.style.background = "#FF8532"; + this.nodesData.add(defaultData); + this._createManipulatorBar(); + this.moving = true; + this.start(); } - - - switchConfigurations.apply(this); - - radioButton1.onchange = switchConfigurations.bind(this); - radioButton2.onchange = switchConfigurations.bind(this); - radioButton3.onchange = switchConfigurations.bind(this); } }; + /** - * This overwrites the this.constants. + * connect two nodes with a new edge. * - * @param constantsVariableName - * @param value * @private */ - exports._overWriteGraphConstants = function (constantsVariableName, value) { - var nameArray = constantsVariableName.split("_"); - if (nameArray.length == 1) { - this.constants[nameArray[0]] = value; - } - else if (nameArray.length == 2) { - this.constants[nameArray[0]][nameArray[1]] = value; - } - else if (nameArray.length == 3) { - this.constants[nameArray[0]][nameArray[1]][nameArray[2]] = value; + exports._createEdge = function(sourceNodeId,targetNodeId) { + if (this.editMode == true) { + var defaultData = {from:sourceNodeId, to:targetNodeId}; + if (this.triggerFunctions.connect) { + if (this.triggerFunctions.connect.length == 2) { + var me = this; + this.triggerFunctions.connect(defaultData, function(finalizedData) { + me.edgesData.add(finalizedData); + me.moving = true; + me.start(); + }); + } + else { + throw new Error('The function for connect does not support two arguments (data,callback)'); + this.moving = true; + this.start(); + } + } + else { + this.edgesData.add(defaultData); + this.moving = true; + this.start(); + } } }; - /** - * this function is bound to the toggle smooth curves button. That is also why it is not in the prototype. + * connect two nodes with a new edge. + * + * @private */ - function graphToggleSmoothCurves () { - this.constants.smoothCurves.enabled = !this.constants.smoothCurves.enabled; - var graph_toggleSmooth = document.getElementById("graph_toggleSmooth"); - if (this.constants.smoothCurves.enabled == true) {graph_toggleSmooth.style.background = "#A4FF56";} - else {graph_toggleSmooth.style.background = "#FF8532";} - - this._configureSmoothCurves(false); - } + exports._editEdge = function(sourceNodeId,targetNodeId) { + if (this.editMode == true) { + var defaultData = {id: this.edgeBeingEdited.id, from:sourceNodeId, to:targetNodeId}; + if (this.triggerFunctions.editEdge) { + if (this.triggerFunctions.editEdge.length == 2) { + var me = this; + this.triggerFunctions.editEdge(defaultData, function(finalizedData) { + me.edgesData.update(finalizedData); + me.moving = true; + me.start(); + }); + } + else { + throw new Error('The function for edit does not support two arguments (data, callback)'); + this.moving = true; + this.start(); + } + } + else { + this.edgesData.update(defaultData); + this.moving = true; + this.start(); + } + } + }; /** - * this function is used to scramble the nodes + * Create the toolbar to edit the selected node. The label and the color can be changed. Other colors are derived from the chosen color. * + * @private */ - function graphRepositionNodes () { - for (var nodeId in this.calculationNodes) { - if (this.calculationNodes.hasOwnProperty(nodeId)) { - this.calculationNodes[nodeId].vx = 0; this.calculationNodes[nodeId].vy = 0; - this.calculationNodes[nodeId].fx = 0; this.calculationNodes[nodeId].fy = 0; + exports._editNode = function() { + if (this.triggerFunctions.edit && this.editMode == true) { + var node = this._getSelectedNode(); + var data = {id:node.id, + label: node.label, + group: node.options.group, + shape: node.options.shape, + color: { + background:node.options.color.background, + border:node.options.color.border, + highlight: { + background:node.options.color.highlight.background, + border:node.options.color.highlight.border + } + }}; + if (this.triggerFunctions.edit.length == 2) { + var me = this; + this.triggerFunctions.edit(data, function (finalizedData) { + me.nodesData.update(finalizedData); + me._createManipulatorBar(); + me.moving = true; + me.start(); + }); + } + else { + throw new Error('The function for edit does not support two arguments (data, callback)'); } - } - if (this.constants.hierarchicalLayout.enabled == true) { - this._setupHierarchicalLayout(); - showValueOfRange.call(this, 'graph_H_nd', 1, "physics_hierarchicalRepulsion_nodeDistance"); - showValueOfRange.call(this, 'graph_H_cg', 1, "physics_centralGravity"); - showValueOfRange.call(this, 'graph_H_sc', 1, "physics_springConstant"); - showValueOfRange.call(this, 'graph_H_sl', 1, "physics_springLength"); - showValueOfRange.call(this, 'graph_H_damp', 1, "physics_damping"); } else { - this.repositionNodes(); + throw new Error('No edit function has been bound to this button'); } - this.moving = true; - this.start(); - } + }; + + + /** - * this is used to generate an options file from the playing with physics system. + * delete everything in the selection + * + * @private */ - function graphGenerateOptions () { - var options = "No options are required, default values used."; - var optionsSpecific = []; - var radioButton1 = document.getElementById("graph_physicsMethod1"); - var radioButton2 = document.getElementById("graph_physicsMethod2"); - if (radioButton1.checked == true) { - if (this.constants.physics.barnesHut.gravitationalConstant != this.backupConstants.physics.barnesHut.gravitationalConstant) {optionsSpecific.push("gravitationalConstant: " + this.constants.physics.barnesHut.gravitationalConstant);} - if (this.constants.physics.centralGravity != this.backupConstants.physics.barnesHut.centralGravity) {optionsSpecific.push("centralGravity: " + this.constants.physics.centralGravity);} - if (this.constants.physics.springLength != this.backupConstants.physics.barnesHut.springLength) {optionsSpecific.push("springLength: " + this.constants.physics.springLength);} - if (this.constants.physics.springConstant != this.backupConstants.physics.barnesHut.springConstant) {optionsSpecific.push("springConstant: " + this.constants.physics.springConstant);} - if (this.constants.physics.damping != this.backupConstants.physics.barnesHut.damping) {optionsSpecific.push("damping: " + this.constants.physics.damping);} - if (optionsSpecific.length != 0) { - options = "var options = {"; - options += "physics: {barnesHut: {"; - for (var i = 0; i < optionsSpecific.length; i++) { - options += optionsSpecific[i]; - if (i < optionsSpecific.length - 1) { - options += ", " - } - } - options += '}}' - } - if (this.constants.smoothCurves.enabled != this.backupConstants.smoothCurves.enabled) { - if (optionsSpecific.length == 0) {options = "var options = {";} - else {options += ", "} - options += "smoothCurves: " + this.constants.smoothCurves.enabled; - } - if (options != "No options are required, default values used.") { - options += '};' - } - } - else if (radioButton2.checked == true) { - options = "var options = {"; - options += "physics: {barnesHut: {enabled: false}"; - if (this.constants.physics.repulsion.nodeDistance != this.backupConstants.physics.repulsion.nodeDistance) {optionsSpecific.push("nodeDistance: " + this.constants.physics.repulsion.nodeDistance);} - if (this.constants.physics.centralGravity != this.backupConstants.physics.repulsion.centralGravity) {optionsSpecific.push("centralGravity: " + this.constants.physics.centralGravity);} - if (this.constants.physics.springLength != this.backupConstants.physics.repulsion.springLength) {optionsSpecific.push("springLength: " + this.constants.physics.springLength);} - if (this.constants.physics.springConstant != this.backupConstants.physics.repulsion.springConstant) {optionsSpecific.push("springConstant: " + this.constants.physics.springConstant);} - if (this.constants.physics.damping != this.backupConstants.physics.repulsion.damping) {optionsSpecific.push("damping: " + this.constants.physics.damping);} - if (optionsSpecific.length != 0) { - options += ", repulsion: {"; - for (var i = 0; i < optionsSpecific.length; i++) { - options += optionsSpecific[i]; - if (i < optionsSpecific.length - 1) { - options += ", " + exports._deleteSelected = function() { + if (!this._selectionIsEmpty() && this.editMode == true) { + if (!this._clusterInSelection()) { + var selectedNodes = this.getSelectedNodes(); + var selectedEdges = this.getSelectedEdges(); + if (this.triggerFunctions.del) { + var me = this; + var data = {nodes: selectedNodes, edges: selectedEdges}; + if (this.triggerFunctions.del.length == 2) { + this.triggerFunctions.del(data, function (finalizedData) { + me.edgesData.remove(finalizedData.edges); + me.nodesData.remove(finalizedData.nodes); + me._unselectAll(); + me.moving = true; + me.start(); + }); } - } - options += '}}' - } - if (optionsSpecific.length == 0) {options += "}"} - if (this.constants.smoothCurves != this.backupConstants.smoothCurves) { - options += ", smoothCurves: " + this.constants.smoothCurves; - } - options += '};' - } - else { - options = "var options = {"; - if (this.constants.physics.hierarchicalRepulsion.nodeDistance != this.backupConstants.physics.hierarchicalRepulsion.nodeDistance) {optionsSpecific.push("nodeDistance: " + this.constants.physics.hierarchicalRepulsion.nodeDistance);} - if (this.constants.physics.centralGravity != this.backupConstants.physics.hierarchicalRepulsion.centralGravity) {optionsSpecific.push("centralGravity: " + this.constants.physics.centralGravity);} - if (this.constants.physics.springLength != this.backupConstants.physics.hierarchicalRepulsion.springLength) {optionsSpecific.push("springLength: " + this.constants.physics.springLength);} - if (this.constants.physics.springConstant != this.backupConstants.physics.hierarchicalRepulsion.springConstant) {optionsSpecific.push("springConstant: " + this.constants.physics.springConstant);} - if (this.constants.physics.damping != this.backupConstants.physics.hierarchicalRepulsion.damping) {optionsSpecific.push("damping: " + this.constants.physics.damping);} - if (optionsSpecific.length != 0) { - options += "physics: {hierarchicalRepulsion: {"; - for (var i = 0; i < optionsSpecific.length; i++) { - options += optionsSpecific[i]; - if (i < optionsSpecific.length - 1) { - options += ", "; + else { + throw new Error('The function for delete does not support two arguments (data, callback)') } } - options += '}},'; - } - options += 'hierarchicalLayout: {'; - optionsSpecific = []; - if (this.constants.hierarchicalLayout.direction != this.backupConstants.hierarchicalLayout.direction) {optionsSpecific.push("direction: " + this.constants.hierarchicalLayout.direction);} - if (Math.abs(this.constants.hierarchicalLayout.levelSeparation) != this.backupConstants.hierarchicalLayout.levelSeparation) {optionsSpecific.push("levelSeparation: " + this.constants.hierarchicalLayout.levelSeparation);} - if (this.constants.hierarchicalLayout.nodeSpacing != this.backupConstants.hierarchicalLayout.nodeSpacing) {optionsSpecific.push("nodeSpacing: " + this.constants.hierarchicalLayout.nodeSpacing);} - if (optionsSpecific.length != 0) { - for (var i = 0; i < optionsSpecific.length; i++) { - options += optionsSpecific[i]; - if (i < optionsSpecific.length - 1) { - options += ", " - } + else { + this.edgesData.remove(selectedEdges); + this.nodesData.remove(selectedNodes); + this._unselectAll(); + this.moving = true; + this.start(); } - options += '}' } else { - options += "enabled:true}"; + alert(this.constants.locales[this.constants.locale]["deleteClusterError"]); } - options += '};' } + }; - this.optionsDiv.innerHTML = options; - } +/***/ }, +/* 68 */ +/***/ function(module, exports, __webpack_require__) { - /** - * this is used to switch between barnesHut, repulsion and hierarchical. - * - */ - function switchConfigurations () { - var ids = ["graph_BH_table", "graph_R_table", "graph_H_table"]; - var radioButton = document.querySelector('input[name="graph_physicsMethod"]:checked').value; - var tableId = "graph_" + radioButton + "_table"; - var table = document.getElementById(tableId); - table.style.display = "block"; - for (var i = 0; i < ids.length; i++) { - if (ids[i] != tableId) { - table = document.getElementById(ids[i]); - table.style.display = "none"; - } - } - this._restoreNodes(); - if (radioButton == "R") { - this.constants.hierarchicalLayout.enabled = false; - this.constants.physics.hierarchicalRepulsion.enabled = false; - this.constants.physics.barnesHut.enabled = false; - } - else if (radioButton == "H") { - if (this.constants.hierarchicalLayout.enabled == false) { - this.constants.hierarchicalLayout.enabled = true; - this.constants.physics.hierarchicalRepulsion.enabled = true; - this.constants.physics.barnesHut.enabled = false; - this.constants.smoothCurves.enabled = false; - this._setupHierarchicalLayout(); + var util = __webpack_require__(1); + var Hammer = __webpack_require__(19); + + exports._cleanNavigation = function() { + // clean hammer bindings + if (this.navigationHammers.existing.length != 0) { + for (var i = 0; i < this.navigationHammers.existing.length; i++) { + this.navigationHammers.existing[i].dispose(); } + this.navigationHammers.existing = []; } - else { - this.constants.hierarchicalLayout.enabled = false; - this.constants.physics.hierarchicalRepulsion.enabled = false; - this.constants.physics.barnesHut.enabled = true; - } - this._loadSelectedForceSolver(); - var graph_toggleSmooth = document.getElementById("graph_toggleSmooth"); - if (this.constants.smoothCurves.enabled == true) {graph_toggleSmooth.style.background = "#A4FF56";} - else {graph_toggleSmooth.style.background = "#FF8532";} - this.moving = true; - this.start(); - } + this._navigationReleaseOverload = function () {}; + + // clean up previous navigation items + if (this.navigationDivs && this.navigationDivs['wrapper'] && this.navigationDivs['wrapper'].parentNode) { + this.navigationDivs['wrapper'].parentNode.removeChild(this.navigationDivs['wrapper']); + } + }; /** - * this generates the ranges depending on the iniital values. + * Creation of the navigation controls nodes. They are drawn over the rest of the nodes and are not affected by scale and translation + * they have a triggerFunction which is called on click. If the position of the navigation controls is dependent + * on this.frame.canvas.clientWidth or this.frame.canvas.clientHeight, we flag horizontalAlignLeft and verticalAlignTop false. + * This means that the location will be corrected by the _relocateNavigation function on a size change of the canvas. * - * @param id - * @param map - * @param constantsVariableName + * @private */ - function showValueOfRange (id,map,constantsVariableName) { - var valueId = id + "_value"; - var rangeValue = document.getElementById(id).value; + exports._loadNavigationElements = function() { + this._cleanNavigation(); - if (Array.isArray(map)) { - document.getElementById(valueId).value = map[parseInt(rangeValue)]; - this._overWriteGraphConstants(constantsVariableName,map[parseInt(rangeValue)]); - } - else { - document.getElementById(valueId).value = parseInt(map) * parseFloat(rangeValue); - this._overWriteGraphConstants(constantsVariableName, parseInt(map) * parseFloat(rangeValue)); - } + this.navigationDivs = {}; + var navigationDivs = ['up','down','left','right','zoomIn','zoomOut','zoomExtends']; + var navigationDivActions = ['_moveUp','_moveDown','_moveLeft','_moveRight','_zoomIn','_zoomOut','_zoomExtent']; - if (constantsVariableName == "hierarchicalLayout_direction" || - constantsVariableName == "hierarchicalLayout_levelSeparation" || - constantsVariableName == "hierarchicalLayout_nodeSpacing") { - this._setupHierarchicalLayout(); - } - this.moving = true; - this.start(); - } + this.navigationDivs['wrapper'] = document.createElement('div'); + this.frame.appendChild(this.navigationDivs['wrapper']); + + for (var i = 0; i < navigationDivs.length; i++) { + this.navigationDivs[navigationDivs[i]] = document.createElement('div'); + this.navigationDivs[navigationDivs[i]].className = 'network-navigation ' + navigationDivs[i]; + this.navigationDivs['wrapper'].appendChild(this.navigationDivs[navigationDivs[i]]); + var hammer = Hammer(this.navigationDivs[navigationDivs[i]], {prevent_default: true}); + hammer.on('touch', this[navigationDivActions[i]].bind(this)); + this.navigationHammers._new.push(hammer); + } + this._navigationReleaseOverload = this._stopMovement; + this.navigationHammers.existing = this.navigationHammers._new; + }; -/***/ }, -/* 67 */ -/***/ function(module, exports, __webpack_require__) { - function webpackContext(req) { - throw new Error("Cannot find module '" + req + "'."); - } - webpackContext.keys = function() { return []; }; - webpackContext.resolve = webpackContext; - module.exports = webpackContext; - webpackContext.id = 67; + /** + * this stops all movement induced by the navigation buttons + * + * @private + */ + exports._zoomExtent = function(event) { + this.zoomExtent({duration:700}); + event.stopPropagation(); + }; + /** + * this stops all movement induced by the navigation buttons + * + * @private + */ + exports._stopMovement = function() { + this._xStopMoving(); + this._yStopMoving(); + this._stopZoom(); + }; -/***/ }, -/* 68 */ -/***/ function(module, exports, __webpack_require__) { /** - * Calculate the forces the nodes apply on each other based on a repulsion field. - * This field is linearly approximated. + * move the screen up + * By using the increments, instead of adding a fixed number to the translation, we keep fluent and + * instant movement. The onKeypress event triggers immediately, then pauses, then triggers frequently + * To avoid this behaviour, we do the translation in the start loop. * * @private */ - exports._calculateNodeForces = function () { - var dx, dy, angle, distance, fx, fy, combinedClusterSize, - repulsingForce, node1, node2, i, j; + exports._moveUp = function(event) { + this.yIncrement = this.constants.keyboard.speed.y; + this.start(); // if there is no node movement, the calculation wont be done + event.preventDefault(); + }; - var nodes = this.calculationNodes; - var nodeIndices = this.calculationNodeIndices; - // approximation constants - var a_base = -2 / 3; - var b = 4 / 3; + /** + * move the screen down + * @private + */ + exports._moveDown = function(event) { + this.yIncrement = -this.constants.keyboard.speed.y; + this.start(); // if there is no node movement, the calculation wont be done + event.preventDefault(); + }; - // repulsing forces between nodes - var nodeDistance = this.constants.physics.repulsion.nodeDistance; - var minimumDistance = nodeDistance; - // we loop from i over all but the last entree in the array - // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j - for (i = 0; i < nodeIndices.length - 1; i++) { - node1 = nodes[nodeIndices[i]]; - for (j = i + 1; j < nodeIndices.length; j++) { - node2 = nodes[nodeIndices[j]]; - combinedClusterSize = node1.clusterSize + node2.clusterSize - 2; + /** + * move the screen left + * @private + */ + exports._moveLeft = function(event) { + this.xIncrement = this.constants.keyboard.speed.x; + this.start(); // if there is no node movement, the calculation wont be done + event.preventDefault(); + }; + + + /** + * move the screen right + * @private + */ + exports._moveRight = function(event) { + this.xIncrement = -this.constants.keyboard.speed.y; + this.start(); // if there is no node movement, the calculation wont be done + event.preventDefault(); + }; + + + /** + * Zoom in, using the same method as the movement. + * @private + */ + exports._zoomIn = function(event) { + this.zoomIncrement = this.constants.keyboard.speed.zoom; + this.start(); // if there is no node movement, the calculation wont be done + event.preventDefault(); + }; + + + /** + * Zoom out + * @private + */ + exports._zoomOut = function(event) { + this.zoomIncrement = -this.constants.keyboard.speed.zoom; + this.start(); // if there is no node movement, the calculation wont be done + event.preventDefault(); + }; - dx = node2.x - node1.x; - dy = node2.y - node1.y; - distance = Math.sqrt(dx * dx + dy * dy); - // same condition as BarnesHut, making sure nodes are never 100% overlapping. - if (distance == 0) { - distance = 0.1*Math.random(); - dx = distance; - } + /** + * Stop zooming and unhighlight the zoom controls + * @private + */ + exports._stopZoom = function(event) { + this.zoomIncrement = 0; + event && event.preventDefault(); + }; - minimumDistance = (combinedClusterSize == 0) ? nodeDistance : (nodeDistance * (1 + combinedClusterSize * this.constants.clustering.distanceAmplification)); - var a = a_base / minimumDistance; - if (distance < 2 * minimumDistance) { - if (distance < 0.5 * minimumDistance) { - repulsingForce = 1.0; - } - else { - repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)) - } - // amplify the repulsion for clusters. - repulsingForce *= (combinedClusterSize == 0) ? 1 : 1 + combinedClusterSize * this.constants.clustering.forceAmplification; - repulsingForce = repulsingForce / Math.max(distance,0.01*minimumDistance); + /** + * Stop moving in the Y direction and unHighlight the up and down + * @private + */ + exports._yStopMoving = function(event) { + this.yIncrement = 0; + event && event.preventDefault(); + }; - fx = dx * repulsingForce; - fy = dy * repulsingForce; - node1.fx -= fx; - node1.fy -= fy; - node2.fx += fx; - node2.fy += fy; - } - } - } + /** + * Stop moving in the X direction and unHighlight left and right. + * @private + */ + exports._xStopMoving = function(event) { + this.xIncrement = 0; + event && event.preventDefault(); }; @@ -34060,579 +33963,676 @@ return /******/ (function(modules) { // webpackBootstrap /* 69 */ /***/ function(module, exports, __webpack_require__) { + exports._resetLevels = function() { + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + var node = this.nodes[nodeId]; + if (node.preassignedLevel == false) { + node.level = -1; + node.hierarchyEnumerated = false; + } + } + } + }; + /** - * Calculate the forces the nodes apply on eachother based on a repulsion field. - * This field is linearly approximated. + * This is the main function to layout the nodes in a hierarchical way. + * It checks if the node details are supplied correctly * * @private */ - exports._calculateNodeForces = function () { - var dx, dy, distance, fx, fy, - repulsingForce, node1, node2, i, j; - - var nodes = this.calculationNodes; - var nodeIndices = this.calculationNodeIndices; - - // repulsing forces between nodes - var nodeDistance = this.constants.physics.hierarchicalRepulsion.nodeDistance; - - // we loop from i over all but the last entree in the array - // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j - for (i = 0; i < nodeIndices.length - 1; i++) { - node1 = nodes[nodeIndices[i]]; - for (j = i + 1; j < nodeIndices.length; j++) { - node2 = nodes[nodeIndices[j]]; - - // nodes only affect nodes on their level - if (node1.level == node2.level) { + exports._setupHierarchicalLayout = function() { + if (this.constants.hierarchicalLayout.enabled == true && this.nodeIndices.length > 0) { + // get the size of the largest hubs and check if the user has defined a level for a node. + var hubsize = 0; + var node, nodeId; + var definedLevel = false; + var undefinedLevel = false; - dx = node2.x - node1.x; - dy = node2.y - node1.y; - distance = Math.sqrt(dx * dx + dy * dy); + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + if (node.level != -1) { + definedLevel = true; + } + else { + undefinedLevel = true; + } + if (hubsize < node.edges.length) { + hubsize = node.edges.length; + } + } + } + // if the user defined some levels but not all, alert and run without hierarchical layout + if (undefinedLevel == true && definedLevel == true) { + 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(undefined,true,this.constants.clustering.enabled); + if (!this.constants.clustering.enabled) { + this.start(); + } + } + else { + // setup the system to use hierarchical method. + this._changeConstants(); - var steepness = 0.05; - if (distance < nodeDistance) { - repulsingForce = -Math.pow(steepness*distance,2) + Math.pow(steepness*nodeDistance,2); + // define levels if undefined by the users. Based on hubsize + if (undefinedLevel == true) { + if (this.constants.hierarchicalLayout.layout == "hubsize") { + this._determineLevels(hubsize); } else { - repulsingForce = 0; + this._determineLevelsDirected(false); } - // normalize force with - if (distance == 0) { - distance = 0.01; - } - else { - repulsingForce = repulsingForce / distance; - } - fx = dx * repulsingForce; - fy = dy * repulsingForce; - node1.fx -= fx; - node1.fy -= fy; - node2.fx += fx; - node2.fy += fy; } + // check the distribution of the nodes per level. + var distribution = this._getDistribution(); + + // place the nodes on the canvas. This also stablilizes the system. + this._placeNodesByHierarchy(distribution); + + // start the simulation. + this.start(); } } }; /** - * this function calculates the effects of the springs in the case of unsmooth curves. + * This function places the nodes on the canvas based on the hierarchial distribution. * + * @param {Object} distribution | obtained by the function this._getDistribution() * @private */ - exports._calculateHierarchicalSpringForces = function () { - var edgeLength, edge, edgeId; - var dx, dy, fx, fy, springForce, distance; - var edges = this.edges; - - var nodes = this.calculationNodes; - var nodeIndices = this.calculationNodeIndices; - - - for (var i = 0; i < nodeIndices.length; i++) { - var node1 = nodes[nodeIndices[i]]; - node1.springFx = 0; - node1.springFy = 0; - } - - - // forces caused by the edges, modelled as springs - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.connected) { - // only calculate forces if nodes are in the same sector - if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { - edgeLength = edge.physics.springLength; - // this implies that the edges between big clusters are longer - edgeLength += (edge.to.clusterSize + edge.from.clusterSize - 2) * this.constants.clustering.edgeGrowth; - - dx = (edge.from.x - edge.to.x); - dy = (edge.from.y - edge.to.y); - distance = Math.sqrt(dx * dx + dy * dy); - - if (distance == 0) { - distance = 0.01; - } - - // the 1/distance is so the fx and fy can be calculated without sine or cosine. - springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance; - - fx = dx * springForce; - fy = dy * springForce; + exports._placeNodesByHierarchy = function(distribution) { + var nodeId, node; + // start placing all the level 0 nodes first. Then recursively position their branches. + for (var level in distribution) { + if (distribution.hasOwnProperty(level)) { + for (nodeId in distribution[level].nodes) { + if (distribution[level].nodes.hasOwnProperty(nodeId)) { + node = distribution[level].nodes[nodeId]; + if (this.constants.hierarchicalLayout.direction == "UD" || this.constants.hierarchicalLayout.direction == "DU") { + if (node.xFixed) { + node.x = distribution[level].minPos; + node.xFixed = false; - if (edge.to.level != edge.from.level) { - edge.to.springFx -= fx; - edge.to.springFy -= fy; - edge.from.springFx += fx; - edge.from.springFy += fy; + distribution[level].minPos += distribution[level].nodeSpacing; + } } else { - var factor = 0.5; - edge.to.fx -= factor*fx; - edge.to.fy -= factor*fy; - edge.from.fx += factor*fx; - edge.from.fy += factor*fy; + if (node.yFixed) { + node.y = distribution[level].minPos; + node.yFixed = false; + + distribution[level].minPos += distribution[level].nodeSpacing; + } } + this._placeBranchNodes(node.edges,node.id,distribution,node.level); } } } } - // normalize spring forces - var springForce = 1; - var springFx, springFy; - for (i = 0; i < nodeIndices.length; i++) { - var node = nodes[nodeIndices[i]]; - springFx = Math.min(springForce,Math.max(-springForce,node.springFx)); - springFy = Math.min(springForce,Math.max(-springForce,node.springFy)); - - node.fx += springFx; - node.fy += springFy; - } - - // retain energy balance - var totalFx = 0; - var totalFy = 0; - for (i = 0; i < nodeIndices.length; i++) { - var node = nodes[nodeIndices[i]]; - totalFx += node.fx; - totalFy += node.fy; - } - var correctionFx = totalFx / nodeIndices.length; - var correctionFy = totalFy / nodeIndices.length; - - for (i = 0; i < nodeIndices.length; i++) { - var node = nodes[nodeIndices[i]]; - node.fx -= correctionFx; - node.fy -= correctionFy; - } - + // stabilize the system after positioning. This function calls zoomExtent. + this._stabilize(); }; -/***/ }, -/* 70 */ -/***/ function(module, exports, __webpack_require__) { /** - * This function calculates the forces the nodes apply on eachother based on a gravitational model. - * The Barnes Hut method is used to speed up this N-body simulation. + * This function get the distribution of levels based on hubsize * + * @returns {Object} * @private */ - exports._calculateNodeForces = function() { - if (this.constants.physics.barnesHut.gravitationalConstant != 0) { - var node; - var nodes = this.calculationNodes; - var nodeIndices = this.calculationNodeIndices; - var nodeCount = nodeIndices.length; - - this._formBarnesHutTree(nodes,nodeIndices); + exports._getDistribution = function() { + var distribution = {}; + var nodeId, node, level; - var barnesHutTree = this.barnesHutTree; + // we fix Y because the hierarchy is vertical, we fix X so we do not give a node an x position for a second time. + // the fix of X is removed after the x value has been set. + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + node.xFixed = true; + node.yFixed = true; + if (this.constants.hierarchicalLayout.direction == "UD" || this.constants.hierarchicalLayout.direction == "DU") { + node.y = this.constants.hierarchicalLayout.levelSeparation*node.level; + } + else { + node.x = this.constants.hierarchicalLayout.levelSeparation*node.level; + } + if (distribution[node.level] === undefined) { + distribution[node.level] = {amount: 0, nodes: {}, minPos:0, nodeSpacing:0}; + } + distribution[node.level].amount += 1; + distribution[node.level].nodes[nodeId] = node; + } + } - // place the nodes one by one recursively - for (var i = 0; i < nodeCount; i++) { - node = nodes[nodeIndices[i]]; - if (node.options.mass > 0) { - // starting with root is irrelevant, it never passes the BarnesHut condition - this._getForceContribution(barnesHutTree.root.children.NW,node); - this._getForceContribution(barnesHutTree.root.children.NE,node); - this._getForceContribution(barnesHutTree.root.children.SW,node); - this._getForceContribution(barnesHutTree.root.children.SE,node); + // determine the largest amount of nodes of all levels + var maxCount = 0; + for (level in distribution) { + if (distribution.hasOwnProperty(level)) { + if (maxCount < distribution[level].amount) { + maxCount = distribution[level].amount; } } } + + // set the initial position and spacing of each nodes accordingly + for (level in distribution) { + if (distribution.hasOwnProperty(level)) { + distribution[level].nodeSpacing = (maxCount + 1) * this.constants.hierarchicalLayout.nodeSpacing; + distribution[level].nodeSpacing /= (distribution[level].amount + 1); + distribution[level].minPos = distribution[level].nodeSpacing - (0.5 * (distribution[level].amount + 1) * distribution[level].nodeSpacing); + } + } + + return distribution; }; /** - * This function traverses the barnesHutTree. It checks when it can approximate distant nodes with their center of mass. - * If a region contains a single node, we check if it is not itself, then we apply the force. + * this function allocates nodes in levels based on the recursive branching from the largest hubs. * - * @param parentBranch - * @param node + * @param hubsize * @private */ - exports._getForceContribution = function(parentBranch,node) { - // we get no force contribution from an empty region - if (parentBranch.childrenCount > 0) { - var dx,dy,distance; - - // get the distance from the center of mass to the node. - dx = parentBranch.centerOfMass.x - node.x; - dy = parentBranch.centerOfMass.y - node.y; - distance = Math.sqrt(dx * dx + dy * dy); + exports._determineLevels = function(hubsize) { + var nodeId, node; - // BarnesHut condition - // original condition : s/d < thetaInverted = passed === d/s > 1/theta = passed - // calcSize = 1/s --> d * 1/s > 1/theta = passed - if (distance * parentBranch.calcSize > this.constants.physics.barnesHut.thetaInverted) { - // duplicate code to reduce function calls to speed up program - if (distance == 0) { - distance = 0.1*Math.random(); - dx = distance; + // determine hubs + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + if (node.edges.length == hubsize) { + node.level = 0; } - var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.options.mass / (distance * distance * distance); - var fx = dx * gravityForce; - var fy = dy * gravityForce; - node.fx += fx; - node.fy += fy; } - else { - // Did not pass the condition, go into children if available - if (parentBranch.childrenCount == 4) { - this._getForceContribution(parentBranch.children.NW,node); - this._getForceContribution(parentBranch.children.NE,node); - this._getForceContribution(parentBranch.children.SW,node); - this._getForceContribution(parentBranch.children.SE,node); - } - else { // parentBranch must have only one node, if it was empty we wouldnt be here - if (parentBranch.children.data.id != node.id) { // if it is not self - // duplicate code to reduce function calls to speed up program - if (distance == 0) { - distance = 0.5*Math.random(); - dx = distance; - } - var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.options.mass / (distance * distance * distance); - var fx = dx * gravityForce; - var fy = dy * gravityForce; - node.fx += fx; - node.fy += fy; - } + } + + // branch from hubs + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + if (node.level == 0) { + this._setLevel(1,node.edges,node.id); } } } }; + + /** - * This function constructs the barnesHut tree recursively. It creates the root, splits it and starts placing the nodes. + * this function allocates nodes in levels based on the direction of the edges * - * @param nodes - * @param nodeIndices + * @param hubsize * @private */ - exports._formBarnesHutTree = function(nodes,nodeIndices) { - var node; - var nodeCount = nodeIndices.length; + exports._determineLevelsDirected = function() { + var nodeId, node, firstNode; + var minLevel = 10000; - var minX = Number.MAX_VALUE, - minY = Number.MAX_VALUE, - maxX =-Number.MAX_VALUE, - maxY =-Number.MAX_VALUE; + // set first node to source + firstNode = this.nodes[this.nodeIndices[0]]; + firstNode.level = minLevel; + this._setLevelDirected(minLevel,firstNode.edges,firstNode.id); - // get the range of the nodes - for (var i = 0; i < nodeCount; i++) { - var x = nodes[nodeIndices[i]].x; - var y = nodes[nodeIndices[i]].y; - if (nodes[nodeIndices[i]].options.mass > 0) { - if (x < minX) { minX = x; } - if (x > maxX) { maxX = x; } - if (y < minY) { minY = y; } - if (y > maxY) { maxY = y; } + // get the minimum level + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + minLevel = node.level < minLevel ? node.level : minLevel; } } - // make the range a square - var sizeDiff = Math.abs(maxX - minX) - Math.abs(maxY - minY); // difference between X and Y - if (sizeDiff > 0) {minY -= 0.5 * sizeDiff; maxY += 0.5 * sizeDiff;} // xSize > ySize - else {minX += 0.5 * sizeDiff; maxX -= 0.5 * sizeDiff;} // xSize < ySize - - - var minimumTreeSize = 1e-5; - var rootSize = Math.max(minimumTreeSize,Math.abs(maxX - minX)); - var halfRootSize = 0.5 * rootSize; - var centerX = 0.5 * (minX + maxX), centerY = 0.5 * (minY + maxY); - - // construct the barnesHutTree - var barnesHutTree = { - root:{ - centerOfMass: {x:0, y:0}, - mass:0, - range: { - minX: centerX-halfRootSize,maxX:centerX+halfRootSize, - minY: centerY-halfRootSize,maxY:centerY+halfRootSize - }, - size: rootSize, - calcSize: 1 / rootSize, - children: { data:null}, - maxWidth: 0, - level: 0, - childrenCount: 4 - } - }; - this._splitBranch(barnesHutTree.root); - // place the nodes one by one recursively - for (i = 0; i < nodeCount; i++) { - node = nodes[nodeIndices[i]]; - if (node.options.mass > 0) { - this._placeInTree(barnesHutTree.root,node); + // subtract the minimum from the set so we have a range starting from 0 + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + node.level -= minLevel; } } - - // make global - this.barnesHutTree = barnesHutTree }; /** - * this updates the mass of a branch. this is increased by adding a node. + * Since hierarchical layout does not support: + * - smooth curves (based on the physics), + * - clustering (based on dynamic node counts) + * + * We disable both features so there will be no problems. * - * @param parentBranch - * @param node * @private */ - exports._updateBranchMass = function(parentBranch, node) { - var totalMass = parentBranch.mass + node.options.mass; - var totalMassInv = 1/totalMass; - - parentBranch.centerOfMass.x = parentBranch.centerOfMass.x * parentBranch.mass + node.x * node.options.mass; - parentBranch.centerOfMass.x *= totalMassInv; - - parentBranch.centerOfMass.y = parentBranch.centerOfMass.y * parentBranch.mass + node.y * node.options.mass; - parentBranch.centerOfMass.y *= totalMassInv; + exports._changeConstants = function() { + this.constants.clustering.enabled = false; + this.constants.physics.barnesHut.enabled = false; + this.constants.physics.hierarchicalRepulsion.enabled = true; + this._loadSelectedForceSolver(); + if (this.constants.smoothCurves.enabled == true) { + this.constants.smoothCurves.dynamic = false; + } + this._configureSmoothCurves(); - parentBranch.mass = totalMass; - var biggestSize = Math.max(Math.max(node.height,node.radius),node.width); - parentBranch.maxWidth = (parentBranch.maxWidth < biggestSize) ? biggestSize : parentBranch.maxWidth; + var config = this.constants.hierarchicalLayout; + config.levelSeparation = Math.abs(config.levelSeparation); + if (config.direction == "RL" || config.direction == "DU") { + config.levelSeparation *= -1; + } + if (config.direction == "RL" || config.direction == "LR") { + if (this.constants.smoothCurves.enabled == true) { + this.constants.smoothCurves.type = "vertical"; + } + } + else { + if (this.constants.smoothCurves.enabled == true) { + this.constants.smoothCurves.type = "horizontal"; + } + } }; /** - * determine in which branch the node will be placed. + * This is a recursively called function to enumerate the branches from the largest hubs and place the nodes + * on a X position that ensures there will be no overlap. * - * @param parentBranch - * @param node - * @param skipMassUpdate + * @param edges + * @param parentId + * @param distribution + * @param parentLevel * @private */ - exports._placeInTree = function(parentBranch,node,skipMassUpdate) { - if (skipMassUpdate != true || skipMassUpdate === undefined) { - // update the mass of the branch. - this._updateBranchMass(parentBranch,node); - } - - if (parentBranch.children.NW.range.maxX > node.x) { // in NW or SW - if (parentBranch.children.NW.range.maxY > node.y) { // in NW - this._placeInRegion(parentBranch,node,"NW"); + exports._placeBranchNodes = function(edges, parentId, distribution, parentLevel) { + for (var i = 0; i < edges.length; i++) { + var childNode = null; + if (edges[i].toId == parentId) { + childNode = edges[i].from; } - else { // in SW - this._placeInRegion(parentBranch,node,"SW"); + else { + childNode = edges[i].to; } - } - else { // in NE or SE - if (parentBranch.children.NW.range.maxY > node.y) { // in NE - this._placeInRegion(parentBranch,node,"NE"); + + // if a node is conneceted to another node on the same level (or higher (means lower level))!, this is not handled here. + var nodeMoved = false; + if (this.constants.hierarchicalLayout.direction == "UD" || this.constants.hierarchicalLayout.direction == "DU") { + if (childNode.xFixed && childNode.level > parentLevel) { + childNode.xFixed = false; + childNode.x = distribution[childNode.level].minPos; + nodeMoved = true; + } } - else { // in SE - this._placeInRegion(parentBranch,node,"SE"); + else { + if (childNode.yFixed && childNode.level > parentLevel) { + childNode.yFixed = false; + childNode.y = distribution[childNode.level].minPos; + nodeMoved = true; + } + } + + if (nodeMoved == true) { + distribution[childNode.level].minPos += distribution[childNode.level].nodeSpacing; + if (childNode.edges.length > 1) { + this._placeBranchNodes(childNode.edges,childNode.id,distribution,childNode.level); + } } } }; /** - * actually place the node in a region (or branch) + * this function is called recursively to enumerate the barnches of the largest hubs and give each node a level. * - * @param parentBranch - * @param node - * @param region + * @param level + * @param edges + * @param parentId * @private */ - exports._placeInRegion = function(parentBranch,node,region) { - switch (parentBranch.children[region].childrenCount) { - case 0: // place node here - parentBranch.children[region].children.data = node; - parentBranch.children[region].childrenCount = 1; - this._updateBranchMass(parentBranch.children[region],node); - break; - case 1: // convert into children - // if there are two nodes exactly overlapping (on init, on opening of cluster etc.) - // we move one node a pixel and we do not put it in the tree. - if (parentBranch.children[region].children.data.x == node.x && - parentBranch.children[region].children.data.y == node.y) { - node.x += Math.random(); - node.y += Math.random(); - } - else { - this._splitBranch(parentBranch.children[region]); - this._placeInTree(parentBranch.children[region],node); + exports._setLevel = function(level, edges, parentId) { + for (var i = 0; i < edges.length; i++) { + var childNode = null; + if (edges[i].toId == parentId) { + childNode = edges[i].from; + } + else { + childNode = edges[i].to; + } + if (childNode.level == -1 || childNode.level > level) { + childNode.level = level; + if (childNode.edges.length > 1) { + this._setLevel(level+1, childNode.edges, childNode.id); } - break; - case 4: // place in branch - this._placeInTree(parentBranch.children[region],node); - break; + } } }; /** - * this function splits a branch into 4 sub branches. If the branch contained a node, we place it in the subbranch - * after the split is complete. + * this function is called recursively to enumerate the branched of the first node and give each node a level based on edge direction * - * @param parentBranch + * @param level + * @param edges + * @param parentId * @private */ - exports._splitBranch = function(parentBranch) { - // if the branch is shaded with a node, replace the node in the new subset. - var containedNode = null; - if (parentBranch.childrenCount == 1) { - containedNode = parentBranch.children.data; - parentBranch.mass = 0; parentBranch.centerOfMass.x = 0; parentBranch.centerOfMass.y = 0; + exports._setLevelDirected = function(level, edges, parentId) { + this.nodes[parentId].hierarchyEnumerated = true; + var childNode, direction; + for (var i = 0; i < edges.length; i++) { + direction = 1; + if (edges[i].toId == parentId) { + childNode = edges[i].from; + direction = -1; + } + else { + childNode = edges[i].to; + } + if (childNode.level == -1) { + childNode.level = level + direction; + } } - parentBranch.childrenCount = 4; - parentBranch.children.data = null; - this._insertRegion(parentBranch,"NW"); - this._insertRegion(parentBranch,"NE"); - this._insertRegion(parentBranch,"SW"); - this._insertRegion(parentBranch,"SE"); - if (containedNode != null) { - this._placeInTree(parentBranch,containedNode); + for (var i = 0; i < edges.length; i++) { + if (edges[i].toId == parentId) {childNode = edges[i].from;} + else {childNode = edges[i].to;} + + if (childNode.edges.length > 1 && childNode.hierarchyEnumerated === false) { + this._setLevelDirected(childNode.level, childNode.edges, childNode.id); + } } }; /** - * This function subdivides the region into four new segments. - * Specifically, this inserts a single new segment. - * It fills the children section of the parentBranch + * Unfix nodes * - * @param parentBranch - * @param region - * @param parentRange * @private */ - exports._insertRegion = function(parentBranch, region) { - var minX,maxX,minY,maxY; - var childSize = 0.5 * parentBranch.size; - switch (region) { - case "NW": - minX = parentBranch.range.minX; - maxX = parentBranch.range.minX + childSize; - minY = parentBranch.range.minY; - maxY = parentBranch.range.minY + childSize; - break; - case "NE": - minX = parentBranch.range.minX + childSize; - maxX = parentBranch.range.maxX; - minY = parentBranch.range.minY; - maxY = parentBranch.range.minY + childSize; - break; - case "SW": - minX = parentBranch.range.minX; - maxX = parentBranch.range.minX + childSize; - minY = parentBranch.range.minY + childSize; - maxY = parentBranch.range.maxY; - break; - case "SE": - minX = parentBranch.range.minX + childSize; - maxX = parentBranch.range.maxX; - minY = parentBranch.range.minY + childSize; - maxY = parentBranch.range.maxY; - break; + exports._restoreNodes = function() { + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + this.nodes[nodeId].xFixed = false; + this.nodes[nodeId].yFixed = false; + } } + }; - parentBranch.children[region] = { - centerOfMass:{x:0,y:0}, - mass:0, - range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY}, - size: 0.5 * parentBranch.size, - calcSize: 2 * parentBranch.calcSize, - children: {data:null}, - maxWidth: 0, - level: parentBranch.level+1, - childrenCount: 0 - }; +/***/ }, +/* 70 */ +/***/ function(module, exports, __webpack_require__) { + + // English + exports['en'] = { + edit: 'Edit', + del: 'Delete selected', + back: 'Back', + addNode: 'Add Node', + addEdge: 'Add Edge', + editNode: 'Edit Node', + editEdge: 'Edit Edge', + addDescription: 'Click in an empty space to place a new node.', + edgeDescription: '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'] = { + edit: 'Wijzigen', + del: 'Selectie verwijderen', + back: 'Terug', + addNode: 'Node toevoegen', + addEdge: 'Link toevoegen', + editNode: 'Node wijzigen', + editEdge: 'Link wijzigen', + addDescription: 'Klik op een leeg gebied om een nieuwe node te maken.', + edgeDescription: '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']; + +/***/ }, +/* 71 */ +/***/ function(module, exports, __webpack_require__) { /** - * This function is for debugging purposed, it draws the tree. - * - * @param ctx - * @param color - * @private + * Canvas shapes used by Network */ - exports._drawTree = function(ctx,color) { - if (this.barnesHutTree !== undefined) { + if (typeof CanvasRenderingContext2D !== 'undefined') { - ctx.lineWidth = 1; + /** + * Draw a circle shape + */ + CanvasRenderingContext2D.prototype.circle = function(x, y, r) { + this.beginPath(); + this.arc(x, y, r, 0, 2*Math.PI, false); + }; - this._drawBranch(this.barnesHutTree.root,ctx,color); - } - }; + /** + * Draw a square shape + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r size, width and height of the square + */ + CanvasRenderingContext2D.prototype.square = function(x, y, r) { + this.beginPath(); + this.rect(x - r, y - r, r * 2, r * 2); + }; + /** + * Draw a triangle shape + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r radius, half the length of the sides of the triangle + */ + CanvasRenderingContext2D.prototype.triangle = function(x, y, r) { + // http://en.wikipedia.org/wiki/Equilateral_triangle + this.beginPath(); - /** - * This function is for debugging purposes. It draws the branches recursively. - * - * @param branch - * @param ctx - * @param color - * @private - */ - exports._drawBranch = function(branch,ctx,color) { - if (color === undefined) { - color = "#FF0000"; - } + var s = r * 2; + var s2 = s / 2; + var ir = Math.sqrt(3) / 6 * s; // radius of inner circle + var h = Math.sqrt(s * s - s2 * s2); // height - if (branch.childrenCount == 4) { - this._drawBranch(branch.children.NW,ctx); - this._drawBranch(branch.children.NE,ctx); - this._drawBranch(branch.children.SE,ctx); - this._drawBranch(branch.children.SW,ctx); - } - ctx.strokeStyle = color; - ctx.beginPath(); - ctx.moveTo(branch.range.minX,branch.range.minY); - ctx.lineTo(branch.range.maxX,branch.range.minY); - ctx.stroke(); + this.moveTo(x, y - (h - ir)); + this.lineTo(x + s2, y + ir); + this.lineTo(x - s2, y + ir); + this.lineTo(x, y - (h - ir)); + this.closePath(); + }; - ctx.beginPath(); - ctx.moveTo(branch.range.maxX,branch.range.minY); - ctx.lineTo(branch.range.maxX,branch.range.maxY); - ctx.stroke(); + /** + * Draw a triangle shape in downward orientation + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r radius + */ + CanvasRenderingContext2D.prototype.triangleDown = function(x, y, r) { + // http://en.wikipedia.org/wiki/Equilateral_triangle + this.beginPath(); - ctx.beginPath(); - ctx.moveTo(branch.range.maxX,branch.range.maxY); - ctx.lineTo(branch.range.minX,branch.range.maxY); - ctx.stroke(); + var s = r * 2; + var s2 = s / 2; + var ir = Math.sqrt(3) / 6 * s; // radius of inner circle + var h = Math.sqrt(s * s - s2 * s2); // height - ctx.beginPath(); - ctx.moveTo(branch.range.minX,branch.range.maxY); - ctx.lineTo(branch.range.minX,branch.range.minY); - ctx.stroke(); + this.moveTo(x, y + (h - ir)); + this.lineTo(x + s2, y - ir); + this.lineTo(x - s2, y - ir); + this.lineTo(x, y + (h - ir)); + this.closePath(); + }; - /* - if (branch.mass > 0) { - ctx.circle(branch.centerOfMass.x, branch.centerOfMass.y, 3*branch.mass); - ctx.stroke(); - } + /** + * Draw a star shape, a star with 5 points + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r radius, half the length of the sides of the triangle */ - }; + CanvasRenderingContext2D.prototype.star = function(x, y, r) { + // http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/ + this.beginPath(); + for (var n = 0; n < 10; n++) { + var radius = (n % 2 === 0) ? r * 1.3 : r * 0.5; + this.lineTo( + x + radius * Math.sin(n * 2 * Math.PI / 10), + y - radius * Math.cos(n * 2 * Math.PI / 10) + ); + } -/***/ }, -/* 71 */ -/***/ function(module, exports, __webpack_require__) { + this.closePath(); + }; - module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - module.children = []; - module.webpackPolyfill = 1; - } - return module; + /** + * http://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas + */ + CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) { + var r2d = Math.PI/180; + if( w - ( 2 * r ) < 0 ) { r = ( w / 2 ); } //ensure that the radius isn't too large for x + if( h - ( 2 * r ) < 0 ) { r = ( h / 2 ); } //ensure that the radius isn't too large for y + this.beginPath(); + this.moveTo(x+r,y); + this.lineTo(x+w-r,y); + this.arc(x+w-r,y+r,r,r2d*270,r2d*360,false); + this.lineTo(x+w,y+h-r); + this.arc(x+w-r,y+h-r,r,0,r2d*90,false); + this.lineTo(x+r,y+h); + this.arc(x+r,y+h-r,r,r2d*90,r2d*180,false); + this.lineTo(x,y+r); + this.arc(x+r,y+r,r,r2d*180,r2d*270,false); + }; + + /** + * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + */ + CanvasRenderingContext2D.prototype.ellipse = function(x, y, w, h) { + var kappa = .5522848, + ox = (w / 2) * kappa, // control point offset horizontal + oy = (h / 2) * kappa, // control point offset vertical + xe = x + w, // x-end + ye = y + h, // y-end + xm = x + w / 2, // x-middle + ym = y + h / 2; // y-middle + + this.beginPath(); + this.moveTo(x, ym); + this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + }; + + + + /** + * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + */ + CanvasRenderingContext2D.prototype.database = function(x, y, w, h) { + var f = 1/3; + var wEllipse = w; + var hEllipse = h * f; + + var kappa = .5522848, + ox = (wEllipse / 2) * kappa, // control point offset horizontal + oy = (hEllipse / 2) * kappa, // control point offset vertical + xe = x + wEllipse, // x-end + ye = y + hEllipse, // y-end + xm = x + wEllipse / 2, // x-middle + ym = y + hEllipse / 2, // y-middle + ymb = y + (h - hEllipse/2), // y-midlle, bottom ellipse + yeb = y + h; // y-end, bottom ellipse + + this.beginPath(); + this.moveTo(xe, ym); + + this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + + this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + + this.lineTo(xe, ymb); + + this.bezierCurveTo(xe, ymb + oy, xm + ox, yeb, xm, yeb); + this.bezierCurveTo(xm - ox, yeb, x, ymb + oy, x, ymb); + + this.lineTo(x, ym); + }; + + + /** + * Draw an arrow point (no line) + */ + CanvasRenderingContext2D.prototype.arrow = function(x, y, angle, length) { + // tail + var xt = x - length * Math.cos(angle); + var yt = y - length * Math.sin(angle); + + // inner tail + // TODO: allow to customize different shapes + var xi = x - length * 0.9 * Math.cos(angle); + var yi = y - length * 0.9 * Math.sin(angle); + + // left + var xl = xt + length / 3 * Math.cos(angle + 0.5 * Math.PI); + var yl = yt + length / 3 * Math.sin(angle + 0.5 * Math.PI); + + // right + var xr = xt + length / 3 * Math.cos(angle - 0.5 * Math.PI); + var yr = yt + length / 3 * Math.sin(angle - 0.5 * Math.PI); + + this.beginPath(); + this.moveTo(x, y); + this.lineTo(xl, yl); + this.lineTo(xi, yi); + this.lineTo(xr, yr); + this.closePath(); + }; + + /** + * Sets up the dashedLine functionality for drawing + * Original code came from http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas + * @author David Jordan + * @date 2012-08-08 + */ + CanvasRenderingContext2D.prototype.dashedLine = function(x,y,x2,y2,dashArray){ + if (!dashArray) dashArray=[10,5]; + if (dashLength==0) dashLength = 0.001; // Hack for Safari + var dashCount = dashArray.length; + this.moveTo(x, y); + var dx = (x2-x), dy = (y2-y); + var slope = dy/dx; + var distRemaining = Math.sqrt( dx*dx + dy*dy ); + var dashIndex=0, draw=true; + while (distRemaining>=0.1){ + var dashLength = dashArray[dashIndex++%dashCount]; + if (dashLength > distRemaining) dashLength = distRemaining; + var xStep = Math.sqrt( dashLength*dashLength / (1 + slope*slope) ); + if (dx<0) xStep = -xStep; + x += xStep; + y += slope*xStep; + this[draw ? 'lineTo' : 'moveTo'](x,y); + distRemaining -= dashLength; + draw = !draw; + } + }; + + // TODO: add diamond shape } diff --git a/dist/vis.min.css b/dist/vis.min.css index a390c40d..8478b04b 100644 --- a/dist/vis.min.css +++ b/dist/vis.min.css @@ -1 +1 @@ -.vis .overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10}.vis-active{box-shadow:0 0 10px #86d5f8}.vis [class*=span]{min-height:0;width:auto}.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;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%;overflow:visible}.vis.timeline .axis{position:absolute;width:100%;height:0;left:0;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:2}.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.background{overflow:hidden;border:none;background-color:rgba(213,221,246,.4);box-sizing:border-box;padding:0;margin:0}.vis.timeline .item.range .content{position:relative;display:inline-block;max-width:100%;overflow:hidden}.vis.timeline .item.background .content{position:absolute;display:inline-block;overflow:hidden;max-width:100%;margin:5px}.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}.vis.timeline .item.range .drag-right{position:absolute;width:24px;height:100%;top:0;right:-4px;cursor:e-resize}.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;border-left: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;border: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;border:0;visibility:hidden;width:auto}.vis.timeline .dataaxis .yAxis.title{position:absolute;color:#4d4d4d;white-space:nowrap;bottom:20px;text-align:center}.vis.timeline .dataaxis .yAxis.title.measure{padding:0;margin:0;visibility:hidden;width:auto}.vis.timeline .dataaxis .yAxis.title.left{bottom:0;-webkit-transform-origin:left top;-moz-transform-origin:left top;-ms-transform-origin:left top;-o-transform-origin:left top;transform-origin:left bottom;-webkit-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-ms-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)}.vis.timeline .dataaxis .yAxis.title.right{bottom:0;-webkit-transform-origin:right bottom;-moz-transform-origin:right bottom;-ms-transform-origin:right bottom;-o-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.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);position:absolute;left:0;top:0;width:100%;height:30px}div.network-manipulation-editMode{position:absolute;left:0;top:0;height:30px;margin-top:20px}div.network-manipulation-closeDiv{position:absolute;right:0;top:0;width:30px;height:30px;background-position:20px 3px;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}div.network-manipulation-closeDiv:hover{opacity:.6}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_wrapper{position:absolute;left:0;top:0;width:100%;height:100%}div.network-navigation{width:34px;height:34px;-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 .overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10}.vis-active{box-shadow:0 0 10px #86d5f8}.vis [class*=span]{min-height:0;width:auto}.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;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%;overflow:visible}.vis.timeline .axis{position:absolute;width:100%;height:0;left:0;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:2}.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.background{overflow:hidden;border:none;background-color:rgba(213,221,246,.4);box-sizing:border-box;padding:0;margin:0}.vis.timeline .item.range .content{position:relative;display:inline-block;max-width:100%;overflow:hidden}.vis.timeline .item.background .content{position:absolute;display:inline-block;overflow:hidden;max-width:100%;margin:5px}.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}.vis.timeline .item.range .drag-right{position:absolute;width:24px;height:100%;top:0;right:-4px;cursor:e-resize}.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;border-left: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;border: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;border:0;visibility:hidden;width:auto}.vis.timeline .dataaxis .yAxis.title{position:absolute;color:#4d4d4d;white-space:nowrap;bottom:20px;text-align:center}.vis.timeline .dataaxis .yAxis.title.measure{padding:0;margin:0;visibility:hidden;width:auto}.vis.timeline .dataaxis .yAxis.title.left{bottom:0;-webkit-transform-origin:left top;-moz-transform-origin:left top;-ms-transform-origin:left top;-o-transform-origin:left top;transform-origin:left bottom;-webkit-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-ms-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)}.vis.timeline .dataaxis .yAxis.title.right{bottom:0;-webkit-transform-origin:right bottom;-moz-transform-origin:right bottom;-ms-transform-origin:right bottom;-o-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.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);position:absolute;left:0;top:0;width:100%;height:30px}div.network-manipulation-editMode{position:absolute;left:0;top:0;height:30px;margin-top:20px}div.network-manipulation-closeDiv{position:absolute;right:0;top:0;width:30px;height:30px;background-position:20px 3px;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}div.network-manipulation-closeDiv:hover{opacity:.6}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_wrapper{position:absolute;left:0;top:0;width:100%;height:100%}div.network-navigation{width:34px;height:34px;-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/lib/network/Edge.js b/lib/network/Edge.js index 4991fe1c..2735ebf9 100644 --- a/lib/network/Edge.js +++ b/lib/network/Edge.js @@ -1164,7 +1164,7 @@ Edge.prototype.positionBezierNode = function() { this.via.x = 0.5 * (this.from.x + this.to.x); this.via.y = 0.5 * (this.from.y + this.to.y); } - else { + else if (this.via !== null) { this.via.x = 0; this.via.y = 0; } diff --git a/lib/network/Network.js b/lib/network/Network.js index 139aab32..3b813974 100644 --- a/lib/network/Network.js +++ b/lib/network/Network.js @@ -45,7 +45,7 @@ function Network (container, data, options) { this.renderRefreshRate = 60; // hz (fps) this.renderTimestep = 1000 / this.renderRefreshRate; // ms -- saves calculation later on this.renderTime = 0; // measured time it takes to render a frame - this.physicsTime = 0; // measured time it takes to render a frame + this.physicsTime = 0; // measured time it takes to render a frame this.runDoubleSpeed = false; this.physicsDiscreteStepsize = 0.50; // discrete stepsize of the simulation From 22abb8635c38e895f6f32c364e8ec38bd0422aac Mon Sep 17 00:00:00 2001 From: jos Date: Fri, 16 Jan 2015 15:47:40 +0100 Subject: [PATCH 02/16] Updated version number to 3.9.1-SNAPSHOT --- bower.json | 2 +- dist/vis.js | 3840 +++++++++++++++++++++++++---------------------- dist/vis.map | 2 +- dist/vis.min.js | 16 +- package.json | 2 +- 5 files changed, 2086 insertions(+), 1776 deletions(-) diff --git a/bower.json b/bower.json index 7cc52380..7e67ff5d 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "vis", - "version": "3.9.0", + "version": "3.9.1-SNAPSHOT", "main": ["dist/vis.min.js", "dist/vis.min.css"], "description": "A dynamic, browser-based visualization library.", "homepage": "http://visjs.org/", diff --git a/dist/vis.js b/dist/vis.js index 506f99f1..61c06c80 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -4,7 +4,7 @@ * * A dynamic, browser-based visualization library. * - * @version 3.9.0 + * @version 3.9.1-SNAPSHOT * @date 2015-01-16 * * @license @@ -27385,2168 +27385,2470 @@ return /******/ (function(modules) { // webpackBootstrap /* 59 */ /***/ function(module, exports, __webpack_require__) { - var __WEBPACK_AMD_DEFINE_RESULT__;/*! Hammer.JS - v1.1.3 - 2014-05-20 - * http://eightmedia.github.io/hammer.js + var __WEBPACK_AMD_DEFINE_RESULT__;/*! Hammer.JS - v2.0.4 - 2014-09-28 + * http://hammerjs.github.io/ * - * Copyright (c) 2014 Jorik Tangelder ; + * Copyright (c) 2014 Jorik Tangelder; * Licensed under the MIT license */ - - (function(window, undefined) { + (function(window, document, exportName, undefined) { 'use strict'; + var VENDOR_PREFIXES = ['', 'webkit', 'moz', 'MS', 'ms', 'o']; + var TEST_ELEMENT = document.createElement('div'); + + var TYPE_FUNCTION = 'function'; + + var round = Math.round; + var abs = Math.abs; + var now = Date.now; + /** - * @main - * @module hammer - * - * @class Hammer - * @static + * set a timeout with a given scope + * @param {Function} fn + * @param {Number} timeout + * @param {Object} context + * @returns {number} */ + function setTimeoutContext(fn, timeout, context) { + return setTimeout(bindFn(fn, context), timeout); + } /** - * Hammer, use this to create instances - * ```` - * var hammertime = new Hammer(myElement); - * ```` - * - * @method Hammer - * @param {HTMLElement} element - * @param {Object} [options={}] - * @return {Hammer.Instance} + * if the argument is an array, we want to execute the fn on each entry + * if it aint an array we don't want to do a thing. + * this is used by all the methods that accept a single and array argument. + * @param {*|Array} arg + * @param {String} fn + * @param {Object} [context] + * @returns {Boolean} */ - var Hammer = function Hammer(element, options) { - return new Hammer.Instance(element, options || {}); - }; + function invokeArrayArg(arg, fn, context) { + if (Array.isArray(arg)) { + each(arg, context[fn], context); + return true; + } + return false; + } /** - * version, as defined in package.json - * the value will be set at each build - * @property VERSION - * @final - * @type {String} + * walk objects and arrays + * @param {Object} obj + * @param {Function} iterator + * @param {Object} context */ - Hammer.VERSION = '1.1.3'; + function each(obj, iterator, context) { + var i; + + if (!obj) { + return; + } + + if (obj.forEach) { + obj.forEach(iterator, context); + } else if (obj.length !== undefined) { + i = 0; + while (i < obj.length) { + iterator.call(context, obj[i], i, obj); + i++; + } + } else { + for (i in obj) { + obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj); + } + } + } /** - * default settings. - * more settings are defined per gesture at `/gestures`. Each gesture can be disabled/enabled - * by setting it's name (like `swipe`) to false. - * You can set the defaults for all instances by changing this object before creating an instance. - * @example - * ```` - * Hammer.defaults.drag = false; - * Hammer.defaults.behavior.touchAction = 'pan-y'; - * delete Hammer.defaults.behavior.userSelect; - * ```` - * @property defaults - * @type {Object} + * extend object. + * means that properties in dest will be overwritten by the ones in src. + * @param {Object} dest + * @param {Object} src + * @param {Boolean} [merge] + * @returns {Object} dest */ - Hammer.defaults = { - /** - * this setting object adds styles and attributes to the element to prevent the browser from doing - * its native behavior. The css properties are auto prefixed for the browsers when needed. - * @property defaults.behavior - * @type {Object} - */ - behavior: { - /** - * Disables text selection to improve the dragging gesture. When the value is `none` it also sets - * `onselectstart=false` for IE on the element. Mainly for desktop browsers. - * @property defaults.behavior.userSelect - * @type {String} - * @default 'none' - */ - userSelect: 'none', - - /** - * Specifies whether and how a given region can be manipulated by the user (for instance, by panning or zooming). - * Used by Chrome 35> and IE10>. By default this makes the element blocking any touch event. - * @property defaults.behavior.touchAction - * @type {String} - * @default: 'pan-y' - */ - touchAction: 'pan-y', + function extend(dest, src, merge) { + var keys = Object.keys(src); + var i = 0; + while (i < keys.length) { + if (!merge || (merge && dest[keys[i]] === undefined)) { + dest[keys[i]] = src[keys[i]]; + } + i++; + } + return dest; + } - /** - * Disables the default callout shown when you touch and hold a touch target. - * On iOS, when you touch and hold a touch target such as a link, Safari displays - * a callout containing information about the link. This property allows you to disable that callout. - * @property defaults.behavior.touchCallout - * @type {String} - * @default 'none' - */ - touchCallout: 'none', + /** + * merge the values from src in the dest. + * means that properties that exist in dest will not be overwritten by src + * @param {Object} dest + * @param {Object} src + * @returns {Object} dest + */ + function merge(dest, src) { + return extend(dest, src, true); + } - /** - * Specifies whether zooming is enabled. Used by IE10> - * @property defaults.behavior.contentZooming - * @type {String} - * @default 'none' - */ - contentZooming: 'none', + /** + * simple class inheritance + * @param {Function} child + * @param {Function} base + * @param {Object} [properties] + */ + function inherit(child, base, properties) { + var baseP = base.prototype, + childP; - /** - * Specifies that an entire element should be draggable instead of its contents. - * Mainly for desktop browsers. - * @property defaults.behavior.userDrag - * @type {String} - * @default 'none' - */ - userDrag: 'none', + childP = child.prototype = Object.create(baseP); + childP.constructor = child; + childP._super = baseP; - /** - * Overrides the highlight color shown when the user taps a link or a JavaScript - * clickable element in Safari on iPhone. This property obeys the alpha value, if specified. - * - * If you don't specify an alpha value, Safari on iPhone applies a default alpha value - * to the color. To disable tap highlighting, set the alpha value to 0 (invisible). - * If you set the alpha value to 1.0 (opaque), the element is not visible when tapped. - * @property defaults.behavior.tapHighlightColor - * @type {String} - * @default 'rgba(0,0,0,0)' - */ - tapHighlightColor: 'rgba(0,0,0,0)' + if (properties) { + extend(childP, properties); } - }; + } /** - * hammer document where the base events are added at - * @property DOCUMENT - * @type {HTMLElement} - * @default window.document + * simple function bind + * @param {Function} fn + * @param {Object} context + * @returns {Function} */ - Hammer.DOCUMENT = document; + function bindFn(fn, context) { + return function boundFn() { + return fn.apply(context, arguments); + }; + } /** - * detect support for pointer events - * @property HAS_POINTEREVENTS - * @type {Boolean} + * let a boolean value also be a function that must return a boolean + * this first item in args will be used as the context + * @param {Boolean|Function} val + * @param {Array} [args] + * @returns {Boolean} */ - Hammer.HAS_POINTEREVENTS = navigator.pointerEnabled || navigator.msPointerEnabled; + function boolOrFn(val, args) { + if (typeof val == TYPE_FUNCTION) { + return val.apply(args ? args[0] || undefined : undefined, args); + } + return val; + } /** - * detect support for touch events - * @property HAS_TOUCHEVENTS - * @type {Boolean} + * use the val2 when val1 is undefined + * @param {*} val1 + * @param {*} val2 + * @returns {*} */ - Hammer.HAS_TOUCHEVENTS = ('ontouchstart' in window); + function ifUndefined(val1, val2) { + return (val1 === undefined) ? val2 : val1; + } /** - * detect mobile browsers - * @property IS_MOBILE - * @type {Boolean} + * addEventListener with multiple events at once + * @param {EventTarget} target + * @param {String} types + * @param {Function} handler */ - Hammer.IS_MOBILE = /mobile|tablet|ip(ad|hone|od)|android|silk/i.test(navigator.userAgent); + function addEventListeners(target, types, handler) { + each(splitStr(types), function(type) { + target.addEventListener(type, handler, false); + }); + } /** - * detect if we want to support mouseevents at all - * @property NO_MOUSEEVENTS - * @type {Boolean} + * removeEventListener with multiple events at once + * @param {EventTarget} target + * @param {String} types + * @param {Function} handler */ - Hammer.NO_MOUSEEVENTS = (Hammer.HAS_TOUCHEVENTS && Hammer.IS_MOBILE) || Hammer.HAS_POINTEREVENTS; + function removeEventListeners(target, types, handler) { + each(splitStr(types), function(type) { + target.removeEventListener(type, handler, false); + }); + } /** - * interval in which Hammer recalculates current velocity/direction/angle in ms - * @property CALCULATE_INTERVAL - * @type {Number} - * @default 25 + * find if a node is in the given parent + * @method hasParent + * @param {HTMLElement} node + * @param {HTMLElement} parent + * @return {Boolean} found */ - Hammer.CALCULATE_INTERVAL = 25; + function hasParent(node, parent) { + while (node) { + if (node == parent) { + return true; + } + node = node.parentNode; + } + return false; + } /** - * eventtypes per touchevent (start, move, end) are filled by `Event.determineEventTypes` on `setup` - * the object contains the DOM event names per type (`EVENT_START`, `EVENT_MOVE`, `EVENT_END`) - * @property EVENT_TYPES - * @private - * @writeOnce - * @type {Object} + * small indexOf wrapper + * @param {String} str + * @param {String} find + * @returns {Boolean} found */ - var EVENT_TYPES = {}; + function inStr(str, find) { + return str.indexOf(find) > -1; + } /** - * direction strings, for safe comparisons - * @property DIRECTION_DOWN|LEFT|UP|RIGHT - * @final - * @type {String} - * @default 'down' 'left' 'up' 'right' + * split string on whitespace + * @param {String} str + * @returns {Array} words */ - var DIRECTION_DOWN = Hammer.DIRECTION_DOWN = 'down'; - var DIRECTION_LEFT = Hammer.DIRECTION_LEFT = 'left'; - var DIRECTION_UP = Hammer.DIRECTION_UP = 'up'; - var DIRECTION_RIGHT = Hammer.DIRECTION_RIGHT = 'right'; + function splitStr(str) { + return str.trim().split(/\s+/g); + } /** - * pointertype strings, for safe comparisons - * @property POINTER_MOUSE|TOUCH|PEN - * @final - * @type {String} - * @default 'mouse' 'touch' 'pen' + * find if a array contains the object using indexOf or a simple polyFill + * @param {Array} src + * @param {String} find + * @param {String} [findByKey] + * @return {Boolean|Number} false when not found, or the index */ - var POINTER_MOUSE = Hammer.POINTER_MOUSE = 'mouse'; - var POINTER_TOUCH = Hammer.POINTER_TOUCH = 'touch'; - var POINTER_PEN = Hammer.POINTER_PEN = 'pen'; + function inArray(src, find, findByKey) { + if (src.indexOf && !findByKey) { + return src.indexOf(find); + } else { + var i = 0; + while (i < src.length) { + if ((findByKey && src[i][findByKey] == find) || (!findByKey && src[i] === find)) { + return i; + } + i++; + } + return -1; + } + } /** - * eventtypes - * @property EVENT_START|MOVE|END|RELEASE|TOUCH - * @final - * @type {String} - * @default 'start' 'change' 'move' 'end' 'release' 'touch' + * convert array-like objects to real arrays + * @param {Object} obj + * @returns {Array} */ - var EVENT_START = Hammer.EVENT_START = 'start'; - var EVENT_MOVE = Hammer.EVENT_MOVE = 'move'; - var EVENT_END = Hammer.EVENT_END = 'end'; - var EVENT_RELEASE = Hammer.EVENT_RELEASE = 'release'; - var EVENT_TOUCH = Hammer.EVENT_TOUCH = 'touch'; + function toArray(obj) { + return Array.prototype.slice.call(obj, 0); + } /** - * if the window events are set... - * @property READY - * @writeOnce - * @type {Boolean} - * @default false + * unique array with objects based on a key (like 'id') or just by the array's value + * @param {Array} src [{id:1},{id:2},{id:1}] + * @param {String} [key] + * @param {Boolean} [sort=False] + * @returns {Array} [{id:1},{id:2}] */ - Hammer.READY = false; + function uniqueArray(src, key, sort) { + var results = []; + var values = []; + var i = 0; + + while (i < src.length) { + var val = key ? src[i][key] : src[i]; + if (inArray(values, val) < 0) { + results.push(src[i]); + } + values[i] = val; + i++; + } + + if (sort) { + if (!key) { + results = results.sort(); + } else { + results = results.sort(function sortUniqueArray(a, b) { + return a[key] > b[key]; + }); + } + } + + return results; + } /** - * plugins namespace - * @property plugins - * @type {Object} + * get the prefixed property + * @param {Object} obj + * @param {String} property + * @returns {String|Undefined} prefixed */ - Hammer.plugins = Hammer.plugins || {}; + function prefixed(obj, property) { + var prefix, prop; + var camelProp = property[0].toUpperCase() + property.slice(1); + + var i = 0; + while (i < VENDOR_PREFIXES.length) { + prefix = VENDOR_PREFIXES[i]; + prop = (prefix) ? prefix + camelProp : property; + + if (prop in obj) { + return prop; + } + i++; + } + return undefined; + } /** - * gestures namespace - * see `/gestures` for the definitions - * @property gestures - * @type {Object} + * get a unique id + * @returns {number} uniqueId */ - Hammer.gestures = Hammer.gestures || {}; + var _uniqueId = 1; + function uniqueId() { + return _uniqueId++; + } /** - * setup events to detect gestures on the document - * this function is called when creating an new instance - * @private + * get the window object of an element + * @param {HTMLElement} element + * @returns {DocumentView|Window} */ - function setup() { - if(Hammer.READY) { - return; - } + function getWindowForElement(element) { + var doc = element.ownerDocument; + return (doc.defaultView || doc.parentWindow); + } - // find what eventtypes we add listeners to - Event.determineEventTypes(); + var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i; - // Register all gestures inside Hammer.gestures - Utils.each(Hammer.gestures, function(gesture) { - Detection.register(gesture); - }); + var SUPPORT_TOUCH = ('ontouchstart' in window); + var SUPPORT_POINTER_EVENTS = prefixed(window, 'PointerEvent') !== undefined; + var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent); - // Add touch events on the document - Event.onTouch(Hammer.DOCUMENT, EVENT_MOVE, Detection.detect); - Event.onTouch(Hammer.DOCUMENT, EVENT_END, Detection.detect); + var INPUT_TYPE_TOUCH = 'touch'; + var INPUT_TYPE_PEN = 'pen'; + var INPUT_TYPE_MOUSE = 'mouse'; + var INPUT_TYPE_KINECT = 'kinect'; - // Hammer is ready...! - Hammer.READY = true; - } + var COMPUTE_INTERVAL = 25; + + var INPUT_START = 1; + var INPUT_MOVE = 2; + var INPUT_END = 4; + var INPUT_CANCEL = 8; + + var DIRECTION_NONE = 1; + var DIRECTION_LEFT = 2; + var DIRECTION_RIGHT = 4; + var DIRECTION_UP = 8; + var DIRECTION_DOWN = 16; + + var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT; + var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN; + var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL; + + var PROPS_XY = ['x', 'y']; + var PROPS_CLIENT_XY = ['clientX', 'clientY']; /** - * @module hammer - * - * @class Utils - * @static + * create new input type manager + * @param {Manager} manager + * @param {Function} callback + * @returns {Input} + * @constructor */ - var Utils = Hammer.utils = { - /** - * extend method, could also be used for cloning when `dest` is an empty object. - * changes the dest object - * @method extend - * @param {Object} dest - * @param {Object} src - * @param {Boolean} [merge=false] do a merge - * @return {Object} dest - */ - extend: function extend(dest, src, merge) { - for(var key in src) { - if(!src.hasOwnProperty(key) || (dest[key] !== undefined && merge)) { - continue; - } - dest[key] = src[key]; + function Input(manager, callback) { + var self = this; + this.manager = manager; + this.callback = callback; + this.element = manager.element; + this.target = manager.options.inputTarget; + + // smaller wrapper around the handler, for the scope and the enabled state of the manager, + // so when disabled the input events are completely bypassed. + this.domHandler = function(ev) { + if (boolOrFn(manager.options.enable, [manager])) { + self.handler(ev); } - return dest; - }, + }; - /** - * simple addEventListener wrapper - * @method on - * @param {HTMLElement} element - * @param {String} type - * @param {Function} handler - */ - on: function on(element, type, handler) { - element.addEventListener(type, handler, false); - }, + this.init(); - /** - * simple removeEventListener wrapper - * @method off - * @param {HTMLElement} element - * @param {String} type - * @param {Function} handler - */ - off: function off(element, type, handler) { - element.removeEventListener(type, handler, false); - }, + } + Input.prototype = { /** - * forEach over arrays and objects - * @method each - * @param {Object|Array} obj - * @param {Function} iterator - * @param {any} iterator.item - * @param {Number} iterator.index - * @param {Object|Array} iterator.obj the source object - * @param {Object} context value to use as `this` in the iterator + * should handle the inputEvent data and trigger the callback + * @virtual */ - each: function each(obj, iterator, context) { - var i, len; - - // native forEach on arrays - if('forEach' in obj) { - obj.forEach(iterator, context); - // arrays - } else if(obj.length !== undefined) { - for(i = 0, len = obj.length; i < len; i++) { - if(iterator.call(context, obj[i], i, obj) === false) { - return; - } - } - // objects - } else { - for(i in obj) { - if(obj.hasOwnProperty(i) && - iterator.call(context, obj[i], i, obj) === false) { - return; - } - } - } - }, + handler: function() { }, /** - * find if a string contains the string using indexOf - * @method inStr - * @param {String} src - * @param {String} find - * @return {Boolean} found + * bind the events */ - inStr: function inStr(src, find) { - return src.indexOf(find) > -1; + init: function() { + this.evEl && addEventListeners(this.element, this.evEl, this.domHandler); + this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler); + this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler); }, /** - * find if a array contains the object using indexOf or a simple polyfill - * @method inArray - * @param {String} src - * @param {String} find - * @return {Boolean|Number} false when not found, or the index + * unbind the events */ - inArray: function inArray(src, find) { - if(src.indexOf) { - var index = src.indexOf(find); - return (index === -1) ? false : index; - } else { - for(var i = 0, len = src.length; i < len; i++) { - if(src[i] === find) { - return i; - } - } - return false; - } - }, + destroy: function() { + this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler); + this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler); + this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler); + } + }; - /** - * convert an array-like object (`arguments`, `touchlist`) to an array - * @method toArray - * @param {Object} obj - * @return {Array} - */ - toArray: function toArray(obj) { - return Array.prototype.slice.call(obj, 0); - }, + /** + * create new input type manager + * called by the Manager constructor + * @param {Hammer} manager + * @returns {Input} + */ + function createInputInstance(manager) { + var Type; + var inputClass = manager.options.inputClass; - /** - * find if a node is in the given parent - * @method hasParent - * @param {HTMLElement} node - * @param {HTMLElement} parent - * @return {Boolean} found - */ - hasParent: function hasParent(node, parent) { - while(node) { - if(node == parent) { - return true; - } - node = node.parentNode; - } - return false; - }, + if (inputClass) { + Type = inputClass; + } else if (SUPPORT_POINTER_EVENTS) { + Type = PointerEventInput; + } else if (SUPPORT_ONLY_TOUCH) { + Type = TouchInput; + } else if (!SUPPORT_TOUCH) { + Type = MouseInput; + } else { + Type = TouchMouseInput; + } + return new (Type)(manager, inputHandler); + } - /** - * get the center of all the touches - * @method getCenter - * @param {Array} touches - * @return {Object} center contains `pageX`, `pageY`, `clientX` and `clientY` properties - */ - getCenter: function getCenter(touches) { - var pageX = [], - pageY = [], - clientX = [], - clientY = [], - min = Math.min, - max = Math.max; - - // no need to loop when only one touch - if(touches.length === 1) { - return { - pageX: touches[0].pageX, - pageY: touches[0].pageY, - clientX: touches[0].clientX, - clientY: touches[0].clientY - }; - } + /** + * handle input events + * @param {Manager} manager + * @param {String} eventType + * @param {Object} input + */ + function inputHandler(manager, eventType, input) { + var pointersLen = input.pointers.length; + var changedPointersLen = input.changedPointers.length; + var isFirst = (eventType & INPUT_START && (pointersLen - changedPointersLen === 0)); + var isFinal = (eventType & (INPUT_END | INPUT_CANCEL) && (pointersLen - changedPointersLen === 0)); - Utils.each(touches, function(touch) { - pageX.push(touch.pageX); - pageY.push(touch.pageY); - clientX.push(touch.clientX); - clientY.push(touch.clientY); - }); + input.isFirst = !!isFirst; + input.isFinal = !!isFinal; - return { - pageX: (min.apply(Math, pageX) + max.apply(Math, pageX)) / 2, - pageY: (min.apply(Math, pageY) + max.apply(Math, pageY)) / 2, - clientX: (min.apply(Math, clientX) + max.apply(Math, clientX)) / 2, - clientY: (min.apply(Math, clientY) + max.apply(Math, clientY)) / 2 + if (isFirst) { + manager.session = {}; + } + + // source event is the normalized value of the domEvents + // like 'touchstart, mouseup, pointerdown' + input.eventType = eventType; + + // compute scale, rotation etc + computeInputData(manager, input); + + // emit secret event + manager.emit('hammer.input', input); + + manager.recognize(input); + manager.session.prevInput = input; + } + + /** + * extend the data with some usable properties like scale, rotate, velocity etc + * @param {Object} manager + * @param {Object} input + */ + function computeInputData(manager, input) { + var session = manager.session; + var pointers = input.pointers; + var pointersLength = pointers.length; + + // store the first input to calculate the distance and direction + if (!session.firstInput) { + session.firstInput = simpleCloneInputData(input); + } + + // to compute scale and rotation we need to store the multiple touches + if (pointersLength > 1 && !session.firstMultiple) { + session.firstMultiple = simpleCloneInputData(input); + } else if (pointersLength === 1) { + session.firstMultiple = false; + } + + var firstInput = session.firstInput; + var firstMultiple = session.firstMultiple; + var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center; + + var center = input.center = getCenter(pointers); + input.timeStamp = now(); + input.deltaTime = input.timeStamp - firstInput.timeStamp; + + input.angle = getAngle(offsetCenter, center); + input.distance = getDistance(offsetCenter, center); + + computeDeltaXY(session, input); + input.offsetDirection = getDirection(input.deltaX, input.deltaY); + + input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1; + input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0; + + computeIntervalInputData(session, input); + + // find the correct target + var target = manager.element; + if (hasParent(input.srcEvent.target, target)) { + target = input.srcEvent.target; + } + input.target = target; + } + + function computeDeltaXY(session, input) { + var center = input.center; + var offset = session.offsetDelta || {}; + var prevDelta = session.prevDelta || {}; + var prevInput = session.prevInput || {}; + + if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) { + prevDelta = session.prevDelta = { + x: prevInput.deltaX || 0, + y: prevInput.deltaY || 0 }; - }, - /** - * calculate the velocity between two points. unit is in px per ms. - * @method getVelocity - * @param {Number} deltaTime - * @param {Number} deltaX - * @param {Number} deltaY - * @return {Object} velocity `x` and `y` - */ - getVelocity: function getVelocity(deltaTime, deltaX, deltaY) { - return { - x: Math.abs(deltaX / deltaTime) || 0, - y: Math.abs(deltaY / deltaTime) || 0 + offset = session.offsetDelta = { + x: center.x, + y: center.y }; - }, + } - /** - * calculate the angle between two coordinates - * @method getAngle - * @param {Touch} touch1 - * @param {Touch} touch2 - * @return {Number} angle - */ - getAngle: function getAngle(touch1, touch2) { - var x = touch2.clientX - touch1.clientX, - y = touch2.clientY - touch1.clientY; + input.deltaX = prevDelta.x + (center.x - offset.x); + input.deltaY = prevDelta.y + (center.y - offset.y); + } - return Math.atan2(y, x) * 180 / Math.PI; - }, + /** + * velocity is calculated every x ms + * @param {Object} session + * @param {Object} input + */ + function computeIntervalInputData(session, input) { + var last = session.lastInterval || input, + deltaTime = input.timeStamp - last.timeStamp, + velocity, velocityX, velocityY, direction; - /** - * do a small comparision to get the direction between two touches. - * @method getDirection - * @param {Touch} touch1 - * @param {Touch} touch2 - * @return {String} direction matches `DIRECTION_LEFT|RIGHT|UP|DOWN` - */ - getDirection: function getDirection(touch1, touch2) { - var x = Math.abs(touch1.clientX - touch2.clientX), - y = Math.abs(touch1.clientY - touch2.clientY); + if (input.eventType != INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) { + var deltaX = last.deltaX - input.deltaX; + var deltaY = last.deltaY - input.deltaY; - if(x >= y) { - return touch1.clientX - touch2.clientX > 0 ? DIRECTION_LEFT : DIRECTION_RIGHT; - } - return touch1.clientY - touch2.clientY > 0 ? DIRECTION_UP : DIRECTION_DOWN; - }, + var v = getVelocity(deltaTime, deltaX, deltaY); + velocityX = v.x; + velocityY = v.y; + velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y; + direction = getDirection(deltaX, deltaY); - /** - * calculate the distance between two touches - * @method getDistance - * @param {Touch}touch1 - * @param {Touch} touch2 - * @return {Number} distance - */ - getDistance: function getDistance(touch1, touch2) { - var x = touch2.clientX - touch1.clientX, - y = touch2.clientY - touch1.clientY; + session.lastInterval = input; + } else { + // use latest velocity info if it doesn't overtake a minimum period + velocity = last.velocity; + velocityX = last.velocityX; + velocityY = last.velocityY; + direction = last.direction; + } - return Math.sqrt((x * x) + (y * y)); - }, + input.velocity = velocity; + input.velocityX = velocityX; + input.velocityY = velocityY; + input.direction = direction; + } - /** - * calculate the scale factor between two touchLists - * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out - * @method getScale - * @param {Array} start array of touches - * @param {Array} end array of touches - * @return {Number} scale - */ - getScale: function getScale(start, end) { - // need two fingers... - if(start.length >= 2 && end.length >= 2) { - return this.getDistance(end[0], end[1]) / this.getDistance(start[0], start[1]); - } - return 1; - }, + /** + * create a simple clone from the input used for storage of firstInput and firstMultiple + * @param {Object} input + * @returns {Object} clonedInputData + */ + function simpleCloneInputData(input) { + // make a simple copy of the pointers because we will get a reference if we don't + // we only need clientXY for the calculations + var pointers = []; + var i = 0; + while (i < input.pointers.length) { + pointers[i] = { + clientX: round(input.pointers[i].clientX), + clientY: round(input.pointers[i].clientY) + }; + i++; + } - /** - * calculate the rotation degrees between two touchLists - * @method getRotation - * @param {Array} start array of touches - * @param {Array} end array of touches - * @return {Number} rotation - */ - getRotation: function getRotation(start, end) { - // need two fingers - if(start.length >= 2 && end.length >= 2) { - return this.getAngle(end[1], end[0]) - this.getAngle(start[1], start[0]); - } - return 0; - }, + return { + timeStamp: now(), + pointers: pointers, + center: getCenter(pointers), + deltaX: input.deltaX, + deltaY: input.deltaY + }; + } - /** - * find out if the direction is vertical * - * @method isVertical - * @param {String} direction matches `DIRECTION_UP|DOWN` - * @return {Boolean} is_vertical - */ - isVertical: function isVertical(direction) { - return direction == DIRECTION_UP || direction == DIRECTION_DOWN; - }, + /** + * get the center of all the pointers + * @param {Array} pointers + * @return {Object} center contains `x` and `y` properties + */ + function getCenter(pointers) { + var pointersLength = pointers.length; - /** - * set css properties with their prefixes - * @param {HTMLElement} element - * @param {String} prop - * @param {String} value - * @param {Boolean} [toggle=true] - * @return {Boolean} - */ - setPrefixedCss: function setPrefixedCss(element, prop, value, toggle) { - var prefixes = ['', 'Webkit', 'Moz', 'O', 'ms']; - prop = Utils.toCamelCase(prop); - - for(var i = 0; i < prefixes.length; i++) { - var p = prop; - // prefixes - if(prefixes[i]) { - p = prefixes[i] + p.slice(0, 1).toUpperCase() + p.slice(1); - } + // no need to loop when only one touch + if (pointersLength === 1) { + return { + x: round(pointers[0].clientX), + y: round(pointers[0].clientY) + }; + } - // test the style - if(p in element.style) { - element.style[p] = (toggle == null || toggle) && value || ''; - break; - } - } - }, + var x = 0, y = 0, i = 0; + while (i < pointersLength) { + x += pointers[i].clientX; + y += pointers[i].clientY; + i++; + } - /** - * toggle browser default behavior by setting css properties. - * `userSelect='none'` also sets `element.onselectstart` to false - * `userDrag='none'` also sets `element.ondragstart` to false - * - * @method toggleBehavior - * @param {HtmlElement} element - * @param {Object} props - * @param {Boolean} [toggle=true] - */ - toggleBehavior: function toggleBehavior(element, props, toggle) { - if(!props || !element || !element.style) { - return; - } + return { + x: round(x / pointersLength), + y: round(y / pointersLength) + }; + } - // set the css properties - Utils.each(props, function(value, prop) { - Utils.setPrefixedCss(element, prop, value, toggle); - }); + /** + * calculate the velocity between two points. unit is in px per ms. + * @param {Number} deltaTime + * @param {Number} x + * @param {Number} y + * @return {Object} velocity `x` and `y` + */ + function getVelocity(deltaTime, x, y) { + return { + x: x / deltaTime || 0, + y: y / deltaTime || 0 + }; + } - var falseFn = toggle && function() { - return false; - }; + /** + * get the direction between two points + * @param {Number} x + * @param {Number} y + * @return {Number} direction + */ + function getDirection(x, y) { + if (x === y) { + return DIRECTION_NONE; + } - // also the disable onselectstart - if(props.userSelect == 'none') { - element.onselectstart = falseFn; - } - // and disable ondragstart - if(props.userDrag == 'none') { - element.ondragstart = falseFn; - } - }, + if (abs(x) >= abs(y)) { + return x > 0 ? DIRECTION_LEFT : DIRECTION_RIGHT; + } + return y > 0 ? DIRECTION_UP : DIRECTION_DOWN; + } - /** - * convert a string with underscores to camelCase - * so prevent_default becomes preventDefault - * @param {String} str - * @return {String} camelCaseStr - */ - toCamelCase: function toCamelCase(str) { - return str.replace(/[_-]([a-z])/g, function(s) { - return s[1].toUpperCase(); - }); + /** + * calculate the absolute distance between two points + * @param {Object} p1 {x, y} + * @param {Object} p2 {x, y} + * @param {Array} [props] containing x and y keys + * @return {Number} distance + */ + function getDistance(p1, p2, props) { + if (!props) { + props = PROPS_XY; } - }; + var x = p2[props[0]] - p1[props[0]], + y = p2[props[1]] - p1[props[1]]; + return Math.sqrt((x * x) + (y * y)); + } /** - * @module hammer + * calculate the angle between two coordinates + * @param {Object} p1 + * @param {Object} p2 + * @param {Array} [props] containing x and y keys + * @return {Number} angle */ + function getAngle(p1, p2, props) { + if (!props) { + props = PROPS_XY; + } + var x = p2[props[0]] - p1[props[0]], + y = p2[props[1]] - p1[props[1]]; + return Math.atan2(y, x) * 180 / Math.PI; + } + /** - * @class Event - * @static + * calculate the rotation degrees between two pointersets + * @param {Array} start array of pointers + * @param {Array} end array of pointers + * @return {Number} rotation */ - var Event = Hammer.event = { - /** - * when touch events have been fired, this is true - * this is used to stop mouse events - * @property prevent_mouseevents - * @private - * @type {Boolean} - */ - preventMouseEvents: false, + function getRotation(start, end) { + return getAngle(end[1], end[0], PROPS_CLIENT_XY) - getAngle(start[1], start[0], PROPS_CLIENT_XY); + } - /** - * if EVENT_START has been fired - * @property started - * @private - * @type {Boolean} - */ - started: false, + /** + * calculate the scale factor between two pointersets + * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out + * @param {Array} start array of pointers + * @param {Array} end array of pointers + * @return {Number} scale + */ + function getScale(start, end) { + return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY); + } - /** - * when the mouse is hold down, this is true - * @property should_detect - * @private - * @type {Boolean} - */ - shouldDetect: false, + var MOUSE_INPUT_MAP = { + mousedown: INPUT_START, + mousemove: INPUT_MOVE, + mouseup: INPUT_END + }; - /** - * simple event binder with a hook and support for multiple types - * @method on - * @param {HTMLElement} element - * @param {String} type - * @param {Function} handler - * @param {Function} [hook] - * @param {Object} hook.type - */ - on: function on(element, type, handler, hook) { - var types = type.split(' '); - Utils.each(types, function(type) { - Utils.on(element, type, handler); - hook && hook(type); - }); - }, + var MOUSE_ELEMENT_EVENTS = 'mousedown'; + var MOUSE_WINDOW_EVENTS = 'mousemove mouseup'; - /** - * simple event unbinder with a hook and support for multiple types - * @method off - * @param {HTMLElement} element - * @param {String} type - * @param {Function} handler - * @param {Function} [hook] - * @param {Object} hook.type - */ - off: function off(element, type, handler, hook) { - var types = type.split(' '); - Utils.each(types, function(type) { - Utils.off(element, type, handler); - hook && hook(type); - }); - }, + /** + * Mouse events input + * @constructor + * @extends Input + */ + function MouseInput() { + this.evEl = MOUSE_ELEMENT_EVENTS; + this.evWin = MOUSE_WINDOW_EVENTS; + this.allow = true; // used by Input.TouchMouse to disable mouse events + this.pressed = false; // mousedown state + + Input.apply(this, arguments); + } + + inherit(MouseInput, Input, { /** - * the core touch event handler. - * this finds out if we should to detect gestures - * @method onTouch - * @param {HTMLElement} element - * @param {String} eventType matches `EVENT_START|MOVE|END` - * @param {Function} handler - * @return onTouchHandler {Function} the core event handler + * handle mouse events + * @param {Object} ev */ - onTouch: function onTouch(element, eventType, handler) { - var self = this; + handler: function MEhandler(ev) { + var eventType = MOUSE_INPUT_MAP[ev.type]; - var onTouchHandler = function onTouchHandler(ev) { - var srcType = ev.type.toLowerCase(), - isPointer = Hammer.HAS_POINTEREVENTS, - isMouse = Utils.inStr(srcType, 'mouse'), - triggerType; + // on start we want to have the left mouse button down + if (eventType & INPUT_START && ev.button === 0) { + this.pressed = true; + } - // if we are in a mouseevent, but there has been a touchevent triggered in this session - // we want to do nothing. simply break out of the event. - if(isMouse && self.preventMouseEvents) { - return; + if (eventType & INPUT_MOVE && ev.which !== 1) { + eventType = INPUT_END; + } - // mousebutton must be down - } else if(isMouse && eventType == EVENT_START && ev.button === 0) { - self.preventMouseEvents = false; - self.shouldDetect = true; - } else if(isPointer && eventType == EVENT_START) { - self.shouldDetect = (ev.buttons === 1 || PointerEvent.matchType(POINTER_TOUCH, ev)); - // just a valid start event, but no mouse - } else if(!isMouse && eventType == EVENT_START) { - self.preventMouseEvents = true; - self.shouldDetect = true; - } + // mouse must be down, and mouse events are allowed (see the TouchMouse input) + if (!this.pressed || !this.allow) { + return; + } - // update the pointer event before entering the detection - if(isPointer && eventType != EVENT_END) { - PointerEvent.updatePointer(eventType, ev); - } + if (eventType & INPUT_END) { + this.pressed = false; + } - // we are in a touch/down state, so allowed detection of gestures - if(self.shouldDetect) { - triggerType = self.doDetect.call(self, ev, eventType, element, handler); - } + this.callback(this.manager, eventType, { + pointers: [ev], + changedPointers: [ev], + pointerType: INPUT_TYPE_MOUSE, + srcEvent: ev + }); + } + }); - // ...and we are done with the detection - // so reset everything to start each detection totally fresh - if(triggerType == EVENT_END) { - self.preventMouseEvents = false; - self.shouldDetect = false; - PointerEvent.reset(); - // update the pointerevent object after the detection - } + var POINTER_INPUT_MAP = { + pointerdown: INPUT_START, + pointermove: INPUT_MOVE, + pointerup: INPUT_END, + pointercancel: INPUT_CANCEL, + pointerout: INPUT_CANCEL + }; - if(isPointer && eventType == EVENT_END) { - PointerEvent.updatePointer(eventType, ev); - } - }; + // in IE10 the pointer types is defined as an enum + var IE10_POINTER_TYPE_ENUM = { + 2: INPUT_TYPE_TOUCH, + 3: INPUT_TYPE_PEN, + 4: INPUT_TYPE_MOUSE, + 5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816 + }; - this.on(element, EVENT_TYPES[eventType], onTouchHandler); - return onTouchHandler; - }, + var POINTER_ELEMENT_EVENTS = 'pointerdown'; + var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel'; + // IE10 has prefixed support, and case-sensitive + if (window.MSPointerEvent) { + POINTER_ELEMENT_EVENTS = 'MSPointerDown'; + POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel'; + } + + /** + * Pointer events input + * @constructor + * @extends Input + */ + function PointerEventInput() { + this.evEl = POINTER_ELEMENT_EVENTS; + this.evWin = POINTER_WINDOW_EVENTS; + + Input.apply(this, arguments); + + this.store = (this.manager.session.pointerEvents = []); + } + + inherit(PointerEventInput, Input, { /** - * the core detection method - * this finds out what hammer-touch-events to trigger - * @method doDetect + * handle mouse events * @param {Object} ev - * @param {String} eventType matches `EVENT_START|MOVE|END` - * @param {HTMLElement} element - * @param {Function} handler - * @return {String} triggerType matches `EVENT_START|MOVE|END` */ - doDetect: function doDetect(ev, eventType, element, handler) { - var touchList = this.getTouchList(ev, eventType); - var touchListLength = touchList.length; - var triggerType = eventType; - var triggerChange = touchList.trigger; // used by fakeMultitouch plugin - var changedLength = touchListLength; + handler: function PEhandler(ev) { + var store = this.store; + var removePointer = false; + + var eventTypeNormalized = ev.type.toLowerCase().replace('ms', ''); + var eventType = POINTER_INPUT_MAP[eventTypeNormalized]; + var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType; - // at each touchstart-like event we want also want to trigger a TOUCH event... - if(eventType == EVENT_START) { - triggerChange = EVENT_TOUCH; - // ...the same for a touchend-like event - } else if(eventType == EVENT_END) { - triggerChange = EVENT_RELEASE; + var isTouch = (pointerType == INPUT_TYPE_TOUCH); - // keep track of how many touches have been removed - changedLength = touchList.length - ((ev.changedTouches) ? ev.changedTouches.length : 1); + // get index of the event in the store + var storeIndex = inArray(store, ev.pointerId, 'pointerId'); + + // start and mouse must be down + if (eventType & INPUT_START && (ev.button === 0 || isTouch)) { + if (storeIndex < 0) { + store.push(ev); + storeIndex = store.length - 1; + } + } else if (eventType & (INPUT_END | INPUT_CANCEL)) { + removePointer = true; } - // after there are still touches on the screen, - // we just want to trigger a MOVE event. so change the START or END to a MOVE - // but only after detection has been started, the first time we actualy want a START - if(changedLength > 0 && this.started) { - triggerType = EVENT_MOVE; + // it not found, so the pointer hasn't been down (so it's probably a hover) + if (storeIndex < 0) { + return; } - // detection has been started, we keep track of this, see above - this.started = true; + // update the event in the store + store[storeIndex] = ev; - // generate some event data, some basic information - var evData = this.collectEventData(element, triggerType, touchList, ev); + this.callback(this.manager, eventType, { + pointers: store, + changedPointers: [ev], + pointerType: pointerType, + srcEvent: ev + }); - // trigger the triggerType event before the change (TOUCH, RELEASE) events - // but the END event should be at last - if(eventType != EVENT_END) { - handler.call(Detection, evData); + if (removePointer) { + // remove from the store + store.splice(storeIndex, 1); } + } + }); - // trigger a change (TOUCH, RELEASE) event, this means the length of the touches changed - if(triggerChange) { - evData.changedLength = changedLength; - evData.eventType = triggerChange; + var SINGLE_TOUCH_INPUT_MAP = { + touchstart: INPUT_START, + touchmove: INPUT_MOVE, + touchend: INPUT_END, + touchcancel: INPUT_CANCEL + }; + + var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart'; + var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel'; + + /** + * Touch events input + * @constructor + * @extends Input + */ + function SingleTouchInput() { + this.evTarget = SINGLE_TOUCH_TARGET_EVENTS; + this.evWin = SINGLE_TOUCH_WINDOW_EVENTS; + this.started = false; + + Input.apply(this, arguments); + } - handler.call(Detection, evData); + inherit(SingleTouchInput, Input, { + handler: function TEhandler(ev) { + var type = SINGLE_TOUCH_INPUT_MAP[ev.type]; - evData.eventType = triggerType; - delete evData.changedLength; + // should we handle the touch events? + if (type === INPUT_START) { + this.started = true; } - // trigger the END event - if(triggerType == EVENT_END) { - handler.call(Detection, evData); + if (!this.started) { + return; + } - // ...and we are done with the detection - // so reset everything to start each detection totally fresh + var touches = normalizeSingleTouches.call(this, ev, type); + + // when done, reset the started state + if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) { this.started = false; } - return triggerType; - }, + this.callback(this.manager, type, { + pointers: touches[0], + changedPointers: touches[1], + pointerType: INPUT_TYPE_TOUCH, + srcEvent: ev + }); + } + }); - /** - * we have different events for each device/browser - * determine what we need and set them in the EVENT_TYPES constant - * the `onTouch` method is bind to these properties. - * @method determineEventTypes - * @return {Object} events - */ - determineEventTypes: function determineEventTypes() { - var types; - if(Hammer.HAS_POINTEREVENTS) { - if(window.PointerEvent) { - types = [ - 'pointerdown', - 'pointermove', - 'pointerup pointercancel lostpointercapture' - ]; - } else { - types = [ - 'MSPointerDown', - 'MSPointerMove', - 'MSPointerUp MSPointerCancel MSLostPointerCapture' - ]; - } - } else if(Hammer.NO_MOUSEEVENTS) { - types = [ - 'touchstart', - 'touchmove', - 'touchend touchcancel' - ]; - } else { - types = [ - 'touchstart mousedown', - 'touchmove mousemove', - 'touchend touchcancel mouseup' - ]; - } + /** + * @this {TouchInput} + * @param {Object} ev + * @param {Number} type flag + * @returns {undefined|Array} [all, changed] + */ + function normalizeSingleTouches(ev, type) { + var all = toArray(ev.touches); + var changed = toArray(ev.changedTouches); - EVENT_TYPES[EVENT_START] = types[0]; - EVENT_TYPES[EVENT_MOVE] = types[1]; - EVENT_TYPES[EVENT_END] = types[2]; - return EVENT_TYPES; - }, + if (type & (INPUT_END | INPUT_CANCEL)) { + all = uniqueArray(all.concat(changed), 'identifier', true); + } - /** - * create touchList depending on the event - * @method getTouchList - * @param {Object} ev - * @param {String} eventType - * @return {Array} touches - */ - getTouchList: function getTouchList(ev, eventType) { - // get the fake pointerEvent touchlist - if(Hammer.HAS_POINTEREVENTS) { - return PointerEvent.getTouchList(); + return [all, changed]; + } + + var TOUCH_INPUT_MAP = { + touchstart: INPUT_START, + touchmove: INPUT_MOVE, + touchend: INPUT_END, + touchcancel: INPUT_CANCEL + }; + + var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel'; + + /** + * Multi-user touch events input + * @constructor + * @extends Input + */ + function TouchInput() { + this.evTarget = TOUCH_TARGET_EVENTS; + this.targetIds = {}; + + Input.apply(this, arguments); + } + + inherit(TouchInput, Input, { + handler: function MTEhandler(ev) { + var type = TOUCH_INPUT_MAP[ev.type]; + var touches = getTouches.call(this, ev, type); + if (!touches) { + return; } - // get the touchlist - if(ev.touches) { - if(eventType == EVENT_MOVE) { - return ev.touches; - } + this.callback(this.manager, type, { + pointers: touches[0], + changedPointers: touches[1], + pointerType: INPUT_TYPE_TOUCH, + srcEvent: ev + }); + } + }); - var identifiers = []; - var concat = [].concat(Utils.toArray(ev.touches), Utils.toArray(ev.changedTouches)); - var touchList = []; + /** + * @this {TouchInput} + * @param {Object} ev + * @param {Number} type flag + * @returns {undefined|Array} [all, changed] + */ + function getTouches(ev, type) { + var allTouches = toArray(ev.touches); + var targetIds = this.targetIds; - Utils.each(concat, function(touch) { - if(Utils.inArray(identifiers, touch.identifier) === false) { - touchList.push(touch); - } - identifiers.push(touch.identifier); - }); + // when there is only one touch, the process can be simplified + if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) { + targetIds[allTouches[0].identifier] = true; + return [allTouches, allTouches]; + } + + var i, + targetTouches, + changedTouches = toArray(ev.changedTouches), + changedTargetTouches = [], + target = this.target; + + // get target touches from touches + targetTouches = allTouches.filter(function(touch) { + return hasParent(touch.target, target); + }); - return touchList; + // collect touches + if (type === INPUT_START) { + i = 0; + while (i < targetTouches.length) { + targetIds[targetTouches[i].identifier] = true; + i++; } + } - // make fake touchList from mouse position - ev.identifier = 1; - return [ev]; - }, + // filter changed touches to only contain touches that exist in the collected target ids + i = 0; + while (i < changedTouches.length) { + if (targetIds[changedTouches[i].identifier]) { + changedTargetTouches.push(changedTouches[i]); + } + // cleanup removed touches + if (type & (INPUT_END | INPUT_CANCEL)) { + delete targetIds[changedTouches[i].identifier]; + } + i++; + } + + if (!changedTargetTouches.length) { + return; + } + + return [ + // merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel' + uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true), + changedTargetTouches + ]; + } + + /** + * Combined touch and mouse input + * + * Touch has a higher priority then mouse, and while touching no mouse events are allowed. + * This because touch devices also emit mouse events while doing a touch. + * + * @constructor + * @extends Input + */ + function TouchMouseInput() { + Input.apply(this, arguments); + + var handler = bindFn(this.handler, this); + this.touch = new TouchInput(this.manager, handler); + this.mouse = new MouseInput(this.manager, handler); + } + + inherit(TouchMouseInput, Input, { /** - * collect basic event data - * @method collectEventData - * @param {HTMLElement} element - * @param {String} eventType matches `EVENT_START|MOVE|END` - * @param {Array} touches - * @param {Object} ev - * @return {Object} ev + * handle mouse and touch events + * @param {Hammer} manager + * @param {String} inputEvent + * @param {Object} inputData */ - collectEventData: function collectEventData(element, eventType, touches, ev) { - // find out pointerType - var pointerType = POINTER_TOUCH; - if(Utils.inStr(ev.type, 'mouse') || PointerEvent.matchType(POINTER_MOUSE, ev)) { - pointerType = POINTER_MOUSE; - } else if(PointerEvent.matchType(POINTER_PEN, ev)) { - pointerType = POINTER_PEN; + handler: function TMEhandler(manager, inputEvent, inputData) { + var isTouch = (inputData.pointerType == INPUT_TYPE_TOUCH), + isMouse = (inputData.pointerType == INPUT_TYPE_MOUSE); + + // when we're in a touch event, so block all upcoming mouse events + // most mobile browser also emit mouseevents, right after touchstart + if (isTouch) { + this.mouse.allow = false; + } else if (isMouse && !this.mouse.allow) { + return; } - return { - center: Utils.getCenter(touches), - timeStamp: Date.now(), - target: ev.target, - touches: touches, - eventType: eventType, - pointerType: pointerType, - srcEvent: ev, - - /** - * prevent the browser default actions - * mostly used to disable scrolling of the browser - */ - preventDefault: function() { - var srcEvent = this.srcEvent; - srcEvent.preventManipulation && srcEvent.preventManipulation(); - srcEvent.preventDefault && srcEvent.preventDefault(); - }, + // reset the allowMouse when we're done + if (inputEvent & (INPUT_END | INPUT_CANCEL)) { + this.mouse.allow = true; + } - /** - * stop bubbling the event up to its parents - */ - stopPropagation: function() { - this.srcEvent.stopPropagation(); - }, + this.callback(manager, inputEvent, inputData); + }, - /** - * immediately stop gesture detection - * might be useful after a swipe was detected - * @return {*} - */ - stopDetect: function() { - return Detection.stopDetect(); - } - }; + /** + * remove the event listeners + */ + destroy: function destroy() { + this.touch.destroy(); + this.mouse.destroy(); } - }; + }); + + var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction'); + var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined; + // magical touchAction value + var TOUCH_ACTION_COMPUTE = 'compute'; + var TOUCH_ACTION_AUTO = 'auto'; + var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented + var TOUCH_ACTION_NONE = 'none'; + var TOUCH_ACTION_PAN_X = 'pan-x'; + var TOUCH_ACTION_PAN_Y = 'pan-y'; /** - * @module hammer - * - * @class PointerEvent - * @static + * Touch Action + * sets the touchAction property or uses the js alternative + * @param {Manager} manager + * @param {String} value + * @constructor */ - var PointerEvent = Hammer.PointerEvent = { + function TouchAction(manager, value) { + this.manager = manager; + this.set(value); + } + + TouchAction.prototype = { /** - * holds all pointers, by `identifier` - * @property pointers - * @type {Object} + * set the touchAction value on the element or enable the polyfill + * @param {String} value */ - pointers: {}, + set: function(value) { + // find out the touch-action by the event handlers + if (value == TOUCH_ACTION_COMPUTE) { + value = this.compute(); + } + + if (NATIVE_TOUCH_ACTION) { + this.manager.element.style[PREFIXED_TOUCH_ACTION] = value; + } + this.actions = value.toLowerCase().trim(); + }, /** - * get the pointers as an array - * @method getTouchList - * @return {Array} touchlist + * just re-set the touchAction value */ - getTouchList: function getTouchList() { - var touchlist = []; - // we can use forEach since pointerEvents only is in IE10 - Utils.each(this.pointers, function(pointer) { - touchlist.push(pointer); - }); - return touchlist; + update: function() { + this.set(this.manager.options.touchAction); }, /** - * update the position of a pointer - * @method updatePointer - * @param {String} eventType matches `EVENT_START|MOVE|END` - * @param {Object} pointerEvent + * compute the value for the touchAction property based on the recognizer's settings + * @returns {String} value */ - updatePointer: function updatePointer(eventType, pointerEvent) { - if(eventType == EVENT_END || (eventType != EVENT_END && pointerEvent.buttons !== 1)) { - delete this.pointers[pointerEvent.pointerId]; - } else { - pointerEvent.identifier = pointerEvent.pointerId; - this.pointers[pointerEvent.pointerId] = pointerEvent; - } + compute: function() { + var actions = []; + each(this.manager.recognizers, function(recognizer) { + if (boolOrFn(recognizer.options.enable, [recognizer])) { + actions = actions.concat(recognizer.getTouchAction()); + } + }); + return cleanTouchActions(actions.join(' ')); }, /** - * check if ev matches pointertype - * @method matchType - * @param {String} pointerType matches `POINTER_MOUSE|TOUCH|PEN` - * @param {PointerEvent} ev + * this method is called on each input cycle and provides the preventing of the browser behavior + * @param {Object} input */ - matchType: function matchType(pointerType, ev) { - if(!ev.pointerType) { - return false; + preventDefaults: function(input) { + // not needed with native support for the touchAction property + if (NATIVE_TOUCH_ACTION) { + return; + } + + var srcEvent = input.srcEvent; + var direction = input.offsetDirection; + + // if the touch action did prevented once this session + if (this.manager.session.prevented) { + srcEvent.preventDefault(); + return; } - var pt = ev.pointerType, - types = {}; + var actions = this.actions; + var hasNone = inStr(actions, TOUCH_ACTION_NONE); + var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y); + var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X); - types[POINTER_MOUSE] = (pt === (ev.MSPOINTER_TYPE_MOUSE || POINTER_MOUSE)); - types[POINTER_TOUCH] = (pt === (ev.MSPOINTER_TYPE_TOUCH || POINTER_TOUCH)); - types[POINTER_PEN] = (pt === (ev.MSPOINTER_TYPE_PEN || POINTER_PEN)); - return types[pointerType]; + if (hasNone || + (hasPanY && direction & DIRECTION_HORIZONTAL) || + (hasPanX && direction & DIRECTION_VERTICAL)) { + return this.preventSrc(srcEvent); + } }, /** - * reset the stored pointers - * @method reset + * call preventDefault to prevent the browser's default behavior (scrolling in most cases) + * @param {Object} srcEvent */ - reset: function resetList() { - this.pointers = {}; + preventSrc: function(srcEvent) { + this.manager.session.prevented = true; + srcEvent.preventDefault(); } }; + /** + * when the touchActions are collected they are not a valid value, so we need to clean things up. * + * @param {String} actions + * @returns {*} + */ + function cleanTouchActions(actions) { + // none + if (inStr(actions, TOUCH_ACTION_NONE)) { + return TOUCH_ACTION_NONE; + } + + var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X); + var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y); + + // pan-x and pan-y can be combined + if (hasPanX && hasPanY) { + return TOUCH_ACTION_PAN_X + ' ' + TOUCH_ACTION_PAN_Y; + } + + // pan-x OR pan-y + if (hasPanX || hasPanY) { + return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y; + } + + // manipulation + if (inStr(actions, TOUCH_ACTION_MANIPULATION)) { + return TOUCH_ACTION_MANIPULATION; + } + + return TOUCH_ACTION_AUTO; + } /** - * @module hammer - * - * @class Detection - * @static + * Recognizer flow explained; * + * All recognizers have the initial state of POSSIBLE when a input session starts. + * The definition of a input session is from the first input until the last input, with all it's movement in it. * + * Example session for mouse-input: mousedown -> mousemove -> mouseup + * + * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed + * which determines with state it should be. + * + * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to + * POSSIBLE to give it another change on the next cycle. + * + * Possible + * | + * +-----+---------------+ + * | | + * +-----+-----+ | + * | | | + * Failed Cancelled | + * +-------+------+ + * | | + * Recognized Began + * | + * Changed + * | + * Ended/Recognized + */ + var STATE_POSSIBLE = 1; + var STATE_BEGAN = 2; + var STATE_CHANGED = 4; + var STATE_ENDED = 8; + var STATE_RECOGNIZED = STATE_ENDED; + var STATE_CANCELLED = 16; + var STATE_FAILED = 32; + + /** + * Recognizer + * Every recognizer needs to extend from this class. + * @constructor + * @param {Object} options */ - var Detection = Hammer.detection = { - // contains all registred Hammer.gestures in the correct order - gestures: [], + function Recognizer(options) { + this.id = uniqueId(); - // data of the current Hammer.gesture detection session - current: null, + this.manager = null; + this.options = merge(options || {}, this.defaults); - // the previous Hammer.gesture session data - // is a full clone of the previous gesture.current object - previous: null, + // default is enable true + this.options.enable = ifUndefined(this.options.enable, true); - // when this becomes true, no gestures are fired - stopped: false, + this.state = STATE_POSSIBLE; + this.simultaneous = {}; + this.requireFail = []; + } + + Recognizer.prototype = { /** - * start Hammer.gesture detection - * @method startDetect - * @param {Hammer.Instance} inst - * @param {Object} eventData + * @virtual + * @type {Object} */ - startDetect: function startDetect(inst, eventData) { - // already busy with a Hammer.gesture detection on an element - if(this.current) { - return; + defaults: {}, + + /** + * set options + * @param {Object} options + * @return {Recognizer} + */ + set: function(options) { + extend(this.options, options); + + // also update the touchAction, in case something changed about the directions/enabled state + this.manager && this.manager.touchAction.update(); + return this; + }, + + /** + * recognize simultaneous with an other recognizer. + * @param {Recognizer} otherRecognizer + * @returns {Recognizer} this + */ + recognizeWith: function(otherRecognizer) { + if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) { + return this; } - this.stopped = false; + var simultaneous = this.simultaneous; + otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this); + if (!simultaneous[otherRecognizer.id]) { + simultaneous[otherRecognizer.id] = otherRecognizer; + otherRecognizer.recognizeWith(this); + } + return this; + }, - // holds current session - this.current = { - inst: inst, // reference to HammerInstance we're working for - startEvent: Utils.extend({}, eventData), // start eventData for distances, timing etc - lastEvent: false, // last eventData - lastCalcEvent: false, // last eventData for calculations. - futureCalcEvent: false, // last eventData for calculations. - lastCalcData: {}, // last lastCalcData - name: '' // current gesture we're in/detected, can be 'tap', 'hold' etc - }; + /** + * drop the simultaneous link. it doesnt remove the link on the other recognizer. + * @param {Recognizer} otherRecognizer + * @returns {Recognizer} this + */ + dropRecognizeWith: function(otherRecognizer) { + if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) { + return this; + } + + otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this); + delete this.simultaneous[otherRecognizer.id]; + return this; + }, + + /** + * recognizer can only run when an other is failing + * @param {Recognizer} otherRecognizer + * @returns {Recognizer} this + */ + requireFailure: function(otherRecognizer) { + if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) { + return this; + } - this.detect(eventData); + var requireFail = this.requireFail; + otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this); + if (inArray(requireFail, otherRecognizer) === -1) { + requireFail.push(otherRecognizer); + otherRecognizer.requireFailure(this); + } + return this; }, /** - * Hammer.gesture detection - * @method detect - * @param {Object} eventData - * @return {any} + * drop the requireFailure link. it does not remove the link on the other recognizer. + * @param {Recognizer} otherRecognizer + * @returns {Recognizer} this */ - detect: function detect(eventData) { - if(!this.current || this.stopped) { - return; - } - - // extend event data with calculations about scale, distance etc - eventData = this.extendEventData(eventData); - - // hammer instance and instance options - var inst = this.current.inst, - instOptions = inst.options; - - // call Hammer.gesture handlers - Utils.each(this.gestures, function triggerGesture(gesture) { - // only when the instance options have enabled this gesture - if(!this.stopped && inst.enabled && instOptions[gesture.name]) { - gesture.handler.call(gesture, eventData, inst); - } - }, this); - - // store as previous event event - if(this.current) { - this.current.lastEvent = eventData; + dropRequireFailure: function(otherRecognizer) { + if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) { + return this; } - if(eventData.eventType == EVENT_END) { - this.stopDetect(); + otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this); + var index = inArray(this.requireFail, otherRecognizer); + if (index > -1) { + this.requireFail.splice(index, 1); } + return this; + }, - return eventData; + /** + * has require failures boolean + * @returns {boolean} + */ + hasRequireFailures: function() { + return this.requireFail.length > 0; }, /** - * clear the Hammer.gesture vars - * this is called on endDetect, but can also be used when a final Hammer.gesture has been detected - * to stop other Hammer.gestures from being fired - * @method stopDetect + * if the recognizer can recognize simultaneous with an other recognizer + * @param {Recognizer} otherRecognizer + * @returns {Boolean} */ - stopDetect: function stopDetect() { - // clone current data to the store as the previous gesture - // used for the double tap gesture, since this is an other gesture detect session - this.previous = Utils.extend({}, this.current); - - // reset the current - this.current = null; - this.stopped = true; + canRecognizeWith: function(otherRecognizer) { + return !!this.simultaneous[otherRecognizer.id]; }, /** - * calculate velocity, angle and direction - * @method getVelocityData - * @param {Object} ev - * @param {Object} center - * @param {Number} deltaTime - * @param {Number} deltaX - * @param {Number} deltaY + * You should use `tryEmit` instead of `emit` directly to check + * that all the needed recognizers has failed before emitting. + * @param {Object} input */ - getCalculatedData: function getCalculatedData(ev, center, deltaTime, deltaX, deltaY) { - var cur = this.current, - recalc = false, - calcEv = cur.lastCalcEvent, - calcData = cur.lastCalcData; + emit: function(input) { + var self = this; + var state = this.state; - if(calcEv && ev.timeStamp - calcEv.timeStamp > Hammer.CALCULATE_INTERVAL) { - center = calcEv.center; - deltaTime = ev.timeStamp - calcEv.timeStamp; - deltaX = ev.center.clientX - calcEv.center.clientX; - deltaY = ev.center.clientY - calcEv.center.clientY; - recalc = true; + function emit(withState) { + self.manager.emit(self.options.event + (withState ? stateStr(state) : ''), input); } - if(ev.eventType == EVENT_TOUCH || ev.eventType == EVENT_RELEASE) { - cur.futureCalcEvent = ev; + // 'panstart' and 'panmove' + if (state < STATE_ENDED) { + emit(true); } - if(!cur.lastCalcEvent || recalc) { - calcData.velocity = Utils.getVelocity(deltaTime, deltaX, deltaY); - calcData.angle = Utils.getAngle(center, ev.center); - calcData.direction = Utils.getDirection(center, ev.center); + emit(); // simple 'eventName' events - cur.lastCalcEvent = cur.futureCalcEvent || ev; - cur.futureCalcEvent = ev; + // panend and pancancel + if (state >= STATE_ENDED) { + emit(true); } - - ev.velocityX = calcData.velocity.x; - ev.velocityY = calcData.velocity.y; - ev.interimAngle = calcData.angle; - ev.interimDirection = calcData.direction; }, /** - * extend eventData for Hammer.gestures - * @method extendEventData - * @param {Object} ev - * @return {Object} ev + * Check that all the require failure recognizers has failed, + * if true, it emits a gesture event, + * otherwise, setup the state to FAILED. + * @param {Object} input */ - extendEventData: function extendEventData(ev) { - var cur = this.current, - startEv = cur.startEvent, - lastEv = cur.lastEvent || startEv; - - // update the start touchlist to calculate the scale/rotation - if(ev.eventType == EVENT_TOUCH || ev.eventType == EVENT_RELEASE) { - startEv.touches = []; - Utils.each(ev.touches, function(touch) { - startEv.touches.push({ - clientX: touch.clientX, - clientY: touch.clientY - }); - }); + tryEmit: function(input) { + if (this.canEmit()) { + return this.emit(input); } + // it's failing anyway + this.state = STATE_FAILED; + }, - var deltaTime = ev.timeStamp - startEv.timeStamp, - deltaX = ev.center.clientX - startEv.center.clientX, - deltaY = ev.center.clientY - startEv.center.clientY; - - this.getCalculatedData(ev, lastEv.center, deltaTime, deltaX, deltaY); + /** + * can we emit? + * @returns {boolean} + */ + canEmit: function() { + var i = 0; + while (i < this.requireFail.length) { + if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) { + return false; + } + i++; + } + return true; + }, - Utils.extend(ev, { - startEvent: startEv, + /** + * update the recognizer + * @param {Object} inputData + */ + recognize: function(inputData) { + // make a new copy of the inputData + // so we can change the inputData without messing up the other recognizers + var inputDataClone = extend({}, inputData); + + // is is enabled and allow recognizing? + if (!boolOrFn(this.options.enable, [this, inputDataClone])) { + this.reset(); + this.state = STATE_FAILED; + return; + } - deltaTime: deltaTime, - deltaX: deltaX, - deltaY: deltaY, + // reset when we've reached the end + if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) { + this.state = STATE_POSSIBLE; + } - distance: Utils.getDistance(startEv.center, ev.center), - angle: Utils.getAngle(startEv.center, ev.center), - direction: Utils.getDirection(startEv.center, ev.center), - scale: Utils.getScale(startEv.touches, ev.touches), - rotation: Utils.getRotation(startEv.touches, ev.touches) - }); + this.state = this.process(inputDataClone); - return ev; + // the recognizer has recognized a gesture + // so trigger an event + if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) { + this.tryEmit(inputDataClone); + } }, /** - * register new gesture - * @method register - * @param {Object} gesture object, see `gestures/` for documentation - * @return {Array} gestures + * return the state of the recognizer + * the actual recognizing happens in this method + * @virtual + * @param {Object} inputData + * @returns {Const} STATE */ - register: function register(gesture) { - // add an enable gesture options if there is no given - var options = gesture.defaults || {}; - if(options[gesture.name] === undefined) { - options[gesture.name] = true; - } + process: function(inputData) { }, // jshint ignore:line - // extend Hammer default options with the Hammer.gesture options - Utils.extend(Hammer.defaults, options, true); - - // set its index - gesture.index = gesture.index || 1000; - - // add Hammer.gesture to the list - this.gestures.push(gesture); + /** + * return the preferred touch-action + * @virtual + * @returns {Array} + */ + getTouchAction: function() { }, - // sort the list by index - this.gestures.sort(function(a, b) { - if(a.index < b.index) { - return -1; - } - if(a.index > b.index) { - return 1; - } - return 0; - }); + /** + * called when the gesture isn't allowed to recognize + * like when another is being recognized or it is disabled + * @virtual + */ + reset: function() { } + }; - return this.gestures; + /** + * get a usable string, used as event postfix + * @param {Const} state + * @returns {String} state + */ + function stateStr(state) { + if (state & STATE_CANCELLED) { + return 'cancel'; + } else if (state & STATE_ENDED) { + return 'end'; + } else if (state & STATE_CHANGED) { + return 'move'; + } else if (state & STATE_BEGAN) { + return 'start'; } - }; + return ''; + } + /** + * direction cons to string + * @param {Const} direction + * @returns {String} + */ + function directionStr(direction) { + if (direction == DIRECTION_DOWN) { + return 'down'; + } else if (direction == DIRECTION_UP) { + return 'up'; + } else if (direction == DIRECTION_LEFT) { + return 'left'; + } else if (direction == DIRECTION_RIGHT) { + return 'right'; + } + return ''; + } /** - * @module hammer + * get a recognizer by name if it is bound to a manager + * @param {Recognizer|String} otherRecognizer + * @param {Recognizer} recognizer + * @returns {Recognizer} */ + function getRecognizerByNameIfManager(otherRecognizer, recognizer) { + var manager = recognizer.manager; + if (manager) { + return manager.get(otherRecognizer); + } + return otherRecognizer; + } /** - * create new hammer instance - * all methods should return the instance itself, so it is chainable. - * - * @class Instance + * This recognizer is just used as a base for the simple attribute recognizers. * @constructor - * @param {HTMLElement} element - * @param {Object} [options={}] options are merged with `Hammer.defaults` - * @return {Hammer.Instance} + * @extends Recognizer */ - Hammer.Instance = function(element, options) { - var self = this; - - // setup HammerJS window events and register all gestures - // this also sets up the default options - setup(); + function AttrRecognizer() { + Recognizer.apply(this, arguments); + } + inherit(AttrRecognizer, Recognizer, { /** - * @property element - * @type {HTMLElement} + * @namespace + * @memberof AttrRecognizer */ - this.element = element; + defaults: { + /** + * @type {Number} + * @default 1 + */ + pointers: 1 + }, /** - * @property enabled - * @type {Boolean} - * @protected + * Used to check if it the recognizer receives valid input, like input.distance > 10. + * @memberof AttrRecognizer + * @param {Object} input + * @returns {Boolean} recognized */ - this.enabled = true; + attrTest: function(input) { + var optionPointers = this.options.pointers; + return optionPointers === 0 || input.pointers.length === optionPointers; + }, /** - * options, merged with the defaults - * options with an _ are converted to camelCase - * @property options - * @type {Object} + * Process the input and return the state for the recognizer + * @memberof AttrRecognizer + * @param {Object} input + * @returns {*} State */ - Utils.each(options, function(value, name) { - delete options[name]; - options[Utils.toCamelCase(name)] = value; - }); - - this.options = Utils.extend(Utils.extend({}, Hammer.defaults), options || {}); - - // add some css to the element to prevent the browser from doing its native behavoir - if(this.options.behavior) { - Utils.toggleBehavior(this.element, this.options.behavior, true); + process: function(input) { + var state = this.state; + var eventType = input.eventType; + + var isRecognized = state & (STATE_BEGAN | STATE_CHANGED); + var isValid = this.attrTest(input); + + // on cancel input and we've recognized before, return STATE_CANCELLED + if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) { + return state | STATE_CANCELLED; + } else if (isRecognized || isValid) { + if (eventType & INPUT_END) { + return state | STATE_ENDED; + } else if (!(state & STATE_BEGAN)) { + return STATE_BEGAN; + } + return state | STATE_CHANGED; + } + return STATE_FAILED; } + }); - /** - * event start handler on the element to start the detection - * @property eventStartHandler - * @type {Object} - */ - this.eventStartHandler = Event.onTouch(element, EVENT_START, function(ev) { - if(self.enabled && ev.eventType == EVENT_START) { - Detection.startDetect(self, ev); - } else if(ev.eventType == EVENT_TOUCH) { - Detection.detect(ev); - } - }); + /** + * Pan + * Recognized when the pointer is down and moved in the allowed direction. + * @constructor + * @extends AttrRecognizer + */ + function PanRecognizer() { + AttrRecognizer.apply(this, arguments); - /** - * keep a list of user event handlers which needs to be removed when calling 'dispose' - * @property eventHandlers - * @type {Array} - */ - this.eventHandlers = []; - }; + this.pX = null; + this.pY = null; + } - Hammer.Instance.prototype = { + inherit(PanRecognizer, AttrRecognizer, { /** - * bind events to the instance - * @method on - * @chainable - * @param {String} gestures multiple gestures by splitting with a space - * @param {Function} handler - * @param {Object} handler.ev event object + * @namespace + * @memberof PanRecognizer */ - on: function onEvent(gestures, handler) { - var self = this; - Event.on(self.element, gestures, handler, function(type) { - self.eventHandlers.push({ gesture: type, handler: handler }); - }); - return self; + defaults: { + event: 'pan', + threshold: 10, + pointers: 1, + direction: DIRECTION_ALL }, - /** - * unbind events to the instance - * @method off - * @chainable - * @param {String} gestures - * @param {Function} handler - */ - off: function offEvent(gestures, handler) { - var self = this; + getTouchAction: function() { + var direction = this.options.direction; + var actions = []; + if (direction & DIRECTION_HORIZONTAL) { + actions.push(TOUCH_ACTION_PAN_Y); + } + if (direction & DIRECTION_VERTICAL) { + actions.push(TOUCH_ACTION_PAN_X); + } + return actions; + }, - Event.off(self.element, gestures, handler, function(type) { - var index = Utils.inArray({ gesture: type, handler: handler }); - if(index !== false) { - self.eventHandlers.splice(index, 1); + directionTest: function(input) { + var options = this.options; + var hasMoved = true; + var distance = input.distance; + var direction = input.direction; + var x = input.deltaX; + var y = input.deltaY; + + // lock to axis? + if (!(direction & options.direction)) { + if (options.direction & DIRECTION_HORIZONTAL) { + direction = (x === 0) ? DIRECTION_NONE : (x < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT; + hasMoved = x != this.pX; + distance = Math.abs(input.deltaX); + } else { + direction = (y === 0) ? DIRECTION_NONE : (y < 0) ? DIRECTION_UP : DIRECTION_DOWN; + hasMoved = y != this.pY; + distance = Math.abs(input.deltaY); } - }); - return self; + } + input.direction = direction; + return hasMoved && distance > options.threshold && direction & options.direction; }, - /** - * trigger gesture event - * @method trigger - * @chainable - * @param {String} gesture - * @param {Object} [eventData] - */ - trigger: function triggerEvent(gesture, eventData) { - // optional - if(!eventData) { - eventData = {}; - } + attrTest: function(input) { + return AttrRecognizer.prototype.attrTest.call(this, input) && + (this.state & STATE_BEGAN || (!(this.state & STATE_BEGAN) && this.directionTest(input))); + }, - // create DOM event - var event = Hammer.DOCUMENT.createEvent('Event'); - event.initEvent(gesture, true, true); - event.gesture = eventData; + emit: function(input) { + this.pX = input.deltaX; + this.pY = input.deltaY; - // trigger on the target if it is in the instance element, - // this is for event delegation tricks - var element = this.element; - if(Utils.hasParent(eventData.target, element)) { - element = eventData.target; + var direction = directionStr(input.direction); + if (direction) { + this.manager.emit(this.options.event + direction, input); } - element.dispatchEvent(event); - return this; - }, + this._super.emit.call(this, input); + } + }); + + /** + * Pinch + * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out). + * @constructor + * @extends AttrRecognizer + */ + function PinchRecognizer() { + AttrRecognizer.apply(this, arguments); + } + inherit(PinchRecognizer, AttrRecognizer, { /** - * enable of disable hammer.js detection - * @method enable - * @chainable - * @param {Boolean} state + * @namespace + * @memberof PinchRecognizer */ - enable: function enable(state) { - this.enabled = state; - return this; + defaults: { + event: 'pinch', + threshold: 0, + pointers: 2 }, - /** - * dispose this hammer instance - * @method dispose - * @return {Null} - */ - dispose: function dispose() { - var i, eh; + getTouchAction: function() { + return [TOUCH_ACTION_NONE]; + }, - // undo all changes made by stop_browser_behavior - Utils.toggleBehavior(this.element, this.options.behavior, false); + attrTest: function(input) { + return this._super.attrTest.call(this, input) && + (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN); + }, - // unbind all custom event handlers - for(i = -1; (eh = this.eventHandlers[++i]);) { - Utils.off(this.element, eh.gesture, eh.handler); + emit: function(input) { + this._super.emit.call(this, input); + if (input.scale !== 1) { + var inOut = input.scale < 1 ? 'in' : 'out'; + this.manager.emit(this.options.event + inOut, input); } - - this.eventHandlers = []; - - // unbind the start event listener - Event.off(this.element, EVENT_TYPES[EVENT_START], this.eventStartHandler); - - return null; } - }; - + }); /** - * @module gestures - */ - /** - * Move with x fingers (default 1) around on the page. - * Preventing the default browser behavior is a good way to improve feel and working. - * ```` - * hammertime.on("drag", function(ev) { - * console.log(ev); - * ev.gesture.preventDefault(); - * }); - * ```` - * - * @class Drag - * @static - */ - /** - * @event drag - * @param {Object} ev - */ - /** - * @event dragstart - * @param {Object} ev - */ - /** - * @event dragend - * @param {Object} ev - */ - /** - * @event drapleft - * @param {Object} ev - */ - /** - * @event dragright - * @param {Object} ev - */ - /** - * @event dragup - * @param {Object} ev - */ - /** - * @event dragdown - * @param {Object} ev + * Press + * Recognized when the pointer is down for x ms without any movement. + * @constructor + * @extends Recognizer */ + function PressRecognizer() { + Recognizer.apply(this, arguments); - /** - * @param {String} name - */ - (function(name) { - var triggered = false; + this._timer = null; + this._input = null; + } + + inherit(PressRecognizer, Recognizer, { + /** + * @namespace + * @memberof PressRecognizer + */ + defaults: { + event: 'press', + pointers: 1, + time: 500, // minimal time of the pointer to be pressed + threshold: 5 // a minimal movement is ok, but keep it low + }, + + getTouchAction: function() { + return [TOUCH_ACTION_AUTO]; + }, + + process: function(input) { + var options = this.options; + var validPointers = input.pointers.length === options.pointers; + var validMovement = input.distance < options.threshold; + var validTime = input.deltaTime > options.time; + + this._input = input; + + // we only allow little movement + // and we've reached an end event, so a tap is possible + if (!validMovement || !validPointers || (input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime)) { + this.reset(); + } else if (input.eventType & INPUT_START) { + this.reset(); + this._timer = setTimeoutContext(function() { + this.state = STATE_RECOGNIZED; + this.tryEmit(); + }, options.time, this); + } else if (input.eventType & INPUT_END) { + return STATE_RECOGNIZED; + } + return STATE_FAILED; + }, - function dragGesture(ev, inst) { - var cur = Detection.current; + reset: function() { + clearTimeout(this._timer); + }, - // max touches - if(inst.options.dragMaxTouches > 0 && - ev.touches.length > inst.options.dragMaxTouches) { + emit: function(input) { + if (this.state !== STATE_RECOGNIZED) { return; } - switch(ev.eventType) { - case EVENT_START: - triggered = false; - break; - - case EVENT_MOVE: - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(ev.distance < inst.options.dragMinDistance && - cur.name != name) { - return; - } + if (input && (input.eventType & INPUT_END)) { + this.manager.emit(this.options.event + 'up', input); + } else { + this._input.timeStamp = now(); + this.manager.emit(this.options.event, this._input); + } + } + }); - var startCenter = cur.startEvent.center; - - // we are dragging! - if(cur.name != name) { - cur.name = name; - if(inst.options.dragDistanceCorrection && ev.distance > 0) { - // When a drag is triggered, set the event center to dragMinDistance pixels from the original event center. - // Without this correction, the dragged distance would jumpstart at dragMinDistance pixels instead of at 0. - // It might be useful to save the original start point somewhere - var factor = Math.abs(inst.options.dragMinDistance / ev.distance); - startCenter.pageX += ev.deltaX * factor; - startCenter.pageY += ev.deltaY * factor; - startCenter.clientX += ev.deltaX * factor; - startCenter.clientY += ev.deltaY * factor; - - // recalculate event data using new start point - ev = Detection.extendEventData(ev); - } - } + /** + * Rotate + * Recognized when two or more pointer are moving in a circular motion. + * @constructor + * @extends AttrRecognizer + */ + function RotateRecognizer() { + AttrRecognizer.apply(this, arguments); + } - // lock drag to axis? - if(cur.lastEvent.dragLockToAxis || - ( inst.options.dragLockToAxis && - inst.options.dragLockMinDistance <= ev.distance - )) { - ev.dragLockToAxis = true; - } + inherit(RotateRecognizer, AttrRecognizer, { + /** + * @namespace + * @memberof RotateRecognizer + */ + defaults: { + event: 'rotate', + threshold: 0, + pointers: 2 + }, - // keep direction on the axis that the drag gesture started on - var lastDirection = cur.lastEvent.direction; - if(ev.dragLockToAxis && lastDirection !== ev.direction) { - if(Utils.isVertical(lastDirection)) { - ev.direction = (ev.deltaY < 0) ? DIRECTION_UP : DIRECTION_DOWN; - } else { - ev.direction = (ev.deltaX < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT; - } - } + getTouchAction: function() { + return [TOUCH_ACTION_NONE]; + }, - // first time, trigger dragstart event - if(!triggered) { - inst.trigger(name + 'start', ev); - triggered = true; - } + attrTest: function(input) { + return this._super.attrTest.call(this, input) && + (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN); + } + }); - // trigger events - inst.trigger(name, ev); - inst.trigger(name + ev.direction, ev); + /** + * Swipe + * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction. + * @constructor + * @extends AttrRecognizer + */ + function SwipeRecognizer() { + AttrRecognizer.apply(this, arguments); + } - var isVertical = Utils.isVertical(ev.direction); + inherit(SwipeRecognizer, AttrRecognizer, { + /** + * @namespace + * @memberof SwipeRecognizer + */ + defaults: { + event: 'swipe', + threshold: 10, + velocity: 0.65, + direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL, + pointers: 1 + }, - // block the browser events - if((inst.options.dragBlockVertical && isVertical) || - (inst.options.dragBlockHorizontal && !isVertical)) { - ev.preventDefault(); - } - break; + getTouchAction: function() { + return PanRecognizer.prototype.getTouchAction.call(this); + }, - case EVENT_RELEASE: - if(triggered && ev.changedLength <= inst.options.dragMaxTouches) { - inst.trigger(name + 'end', ev); - triggered = false; - } - break; + attrTest: function(input) { + var direction = this.options.direction; + var velocity; - case EVENT_END: - triggered = false; - break; + if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) { + velocity = input.velocity; + } else if (direction & DIRECTION_HORIZONTAL) { + velocity = input.velocityX; + } else if (direction & DIRECTION_VERTICAL) { + velocity = input.velocityY; } - } - Hammer.gestures.Drag = { - name: name, - index: 50, - handler: dragGesture, - defaults: { - /** - * minimal movement that have to be made before the drag event gets triggered - * @property dragMinDistance - * @type {Number} - * @default 10 - */ - dragMinDistance: 10, - - /** - * Set dragDistanceCorrection to true to make the starting point of the drag - * be calculated from where the drag was triggered, not from where the touch started. - * Useful to avoid a jerk-starting drag, which can make fine-adjustments - * through dragging difficult, and be visually unappealing. - * @property dragDistanceCorrection - * @type {Boolean} - * @default true - */ - dragDistanceCorrection: true, - - /** - * set 0 for unlimited, but this can conflict with transform - * @property dragMaxTouches - * @type {Number} - * @default 1 - */ - dragMaxTouches: 1, - - /** - * prevent default browser behavior when dragging occurs - * be careful with it, it makes the element a blocking element - * when you are using the drag gesture, it is a good practice to set this true - * @property dragBlockHorizontal - * @type {Boolean} - * @default false - */ - dragBlockHorizontal: false, - - /** - * same as `dragBlockHorizontal`, but for vertical movement - * @property dragBlockVertical - * @type {Boolean} - * @default false - */ - dragBlockVertical: false, - - /** - * dragLockToAxis keeps the drag gesture on the axis that it started on, - * It disallows vertical directions if the initial direction was horizontal, and vice versa. - * @property dragLockToAxis - * @type {Boolean} - * @default false - */ - dragLockToAxis: false, - - /** - * drag lock only kicks in when distance > dragLockMinDistance - * This way, locking occurs only when the distance has become large enough to reliably determine the direction - * @property dragLockMinDistance - * @type {Number} - * @default 25 - */ - dragLockMinDistance: 25 + return this._super.attrTest.call(this, input) && + direction & input.direction && + input.distance > this.options.threshold && + abs(velocity) > this.options.velocity && input.eventType & INPUT_END; + }, + + emit: function(input) { + var direction = directionStr(input.direction); + if (direction) { + this.manager.emit(this.options.event + direction, input); } - }; - })('drag'); - /** - * @module gestures - */ - /** - * trigger a simple gesture event, so you can do anything in your handler. - * only usable if you know what your doing... - * - * @class Gesture - * @static - */ - /** - * @event gesture - * @param {Object} ev - */ - Hammer.gestures.Gesture = { - name: 'gesture', - index: 1337, - handler: function releaseGesture(ev, inst) { - inst.trigger(this.name, ev); + this.manager.emit(this.options.event, input); } - }; + }); /** - * @module gestures - */ - /** - * Touch stays at the same place for x time + * A tap is ecognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur + * between the given interval and position. The delay option can be used to recognize multi-taps without firing + * a single tap. * - * @class Hold - * @static - */ - /** - * @event hold - * @param {Object} ev + * The eventData from the emitted event contains the property `tapCount`, which contains the amount of + * multi-taps being recognized. + * @constructor + * @extends Recognizer */ + function TapRecognizer() { + Recognizer.apply(this, arguments); - /** - * @param {String} name - */ - (function(name) { - var timer; + // previous time and center, + // used for tap counting + this.pTime = false; + this.pCenter = false; + + this._timer = null; + this._input = null; + this.count = 0; + } - function holdGesture(ev, inst) { - var options = inst.options, - current = Detection.current; + inherit(TapRecognizer, Recognizer, { + /** + * @namespace + * @memberof PinchRecognizer + */ + defaults: { + event: 'tap', + pointers: 1, + taps: 1, + interval: 300, // max time between the multi-tap taps + time: 250, // max time of the pointer to be down (like finger on the screen) + threshold: 2, // a minimal movement is ok, but keep it low + posThreshold: 10 // a multi-tap can be a bit off the initial position + }, - switch(ev.eventType) { - case EVENT_START: - clearTimeout(timer); + getTouchAction: function() { + return [TOUCH_ACTION_MANIPULATION]; + }, - // set the gesture so we can check in the timeout if it still is - current.name = name; + process: function(input) { + var options = this.options; - // set timer and if after the timeout it still is hold, - // we trigger the hold event - timer = setTimeout(function() { - if(current && current.name == name) { - inst.trigger(name, ev); - } - }, options.holdTimeout); - break; + var validPointers = input.pointers.length === options.pointers; + var validMovement = input.distance < options.threshold; + var validTouchTime = input.deltaTime < options.time; - case EVENT_MOVE: - if(ev.distance > options.holdThreshold) { - clearTimeout(timer); - } - break; + this.reset(); - case EVENT_RELEASE: - clearTimeout(timer); - break; + if ((input.eventType & INPUT_START) && (this.count === 0)) { + return this.failTimeout(); } - } - Hammer.gestures.Hold = { - name: name, - index: 10, - defaults: { - /** - * @property holdTimeout - * @type {Number} - * @default 500 - */ - holdTimeout: 500, - - /** - * movement allowed while holding - * @property holdThreshold - * @type {Number} - * @default 2 - */ - holdThreshold: 2 - }, - handler: holdGesture - }; - })('hold'); + // we only allow little movement + // and we've reached an end event, so a tap is possible + if (validMovement && validTouchTime && validPointers) { + if (input.eventType != INPUT_END) { + return this.failTimeout(); + } - /** - * @module gestures - */ - /** - * when a touch is being released from the page - * - * @class Release - * @static - */ - /** - * @event release - * @param {Object} ev - */ - Hammer.gestures.Release = { - name: 'release', - index: Infinity, - handler: function releaseGesture(ev, inst) { - if(ev.eventType == EVENT_RELEASE) { - inst.trigger(this.name, ev); + var validInterval = this.pTime ? (input.timeStamp - this.pTime < options.interval) : true; + var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold; + + this.pTime = input.timeStamp; + this.pCenter = input.center; + + if (!validMultiTap || !validInterval) { + this.count = 1; + } else { + this.count += 1; + } + + this._input = input; + + // if tap count matches we have recognized it, + // else it has began recognizing... + var tapCount = this.count % options.taps; + if (tapCount === 0) { + // no failing requirements, immediately trigger the tap event + // or wait as long as the multitap interval to trigger + if (!this.hasRequireFailures()) { + return STATE_RECOGNIZED; + } else { + this._timer = setTimeoutContext(function() { + this.state = STATE_RECOGNIZED; + this.tryEmit(); + }, options.interval, this); + return STATE_BEGAN; + } + } + } + return STATE_FAILED; + }, + + failTimeout: function() { + this._timer = setTimeoutContext(function() { + this.state = STATE_FAILED; + }, this.options.interval, this); + return STATE_FAILED; + }, + + reset: function() { + clearTimeout(this._timer); + }, + + emit: function() { + if (this.state == STATE_RECOGNIZED ) { + this._input.tapCount = this.count; + this.manager.emit(this.options.event, this._input); } } - }; + }); /** - * @module gestures - */ - /** - * triggers swipe events when the end velocity is above the threshold - * for best usage, set `preventDefault` (on the drag gesture) to `true` - * ```` - * hammertime.on("dragleft swipeleft", function(ev) { - * console.log(ev); - * ev.gesture.preventDefault(); - * }); - * ```` - * - * @class Swipe - * @static - */ - /** - * @event swipe - * @param {Object} ev - */ - /** - * @event swipeleft - * @param {Object} ev - */ - /** - * @event swiperight - * @param {Object} ev + * Simple way to create an manager with a default set of recognizers. + * @param {HTMLElement} element + * @param {Object} [options] + * @constructor */ + function Hammer(element, options) { + options = options || {}; + options.recognizers = ifUndefined(options.recognizers, Hammer.defaults.preset); + return new Manager(element, options); + } + /** - * @event swipeup - * @param {Object} ev + * @const {string} */ + Hammer.VERSION = '2.0.4'; + /** - * @event swipedown - * @param {Object} ev + * default settings + * @namespace */ - Hammer.gestures.Swipe = { - name: 'swipe', - index: 40, - defaults: { + Hammer.defaults = { + /** + * set if DOM events are being triggered. + * But this is slower and unused by simple implementations, so disabled by default. + * @type {Boolean} + * @default false + */ + domEvents: false, + + /** + * The value for the touchAction property/fallback. + * When set to `compute` it will magically set the correct value based on the added recognizers. + * @type {String} + * @default compute + */ + touchAction: TOUCH_ACTION_COMPUTE, + + /** + * @type {Boolean} + * @default true + */ + enable: true, + + /** + * EXPERIMENTAL FEATURE -- can be removed/changed + * Change the parent input target element. + * If Null, then it is being set the to main element. + * @type {Null|EventTarget} + * @default null + */ + inputTarget: null, + + /** + * force an input class + * @type {Null|Function} + * @default null + */ + inputClass: null, + + /** + * Default recognizer setup when calling `Hammer()` + * When creating a new Manager these will be skipped. + * @type {Array} + */ + preset: [ + // RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...] + [RotateRecognizer, { enable: false }], + [PinchRecognizer, { enable: false }, ['rotate']], + [SwipeRecognizer,{ direction: DIRECTION_HORIZONTAL }], + [PanRecognizer, { direction: DIRECTION_HORIZONTAL }, ['swipe']], + [TapRecognizer], + [TapRecognizer, { event: 'doubletap', taps: 2 }, ['tap']], + [PressRecognizer] + ], + + /** + * Some CSS properties can be used to improve the working of Hammer. + * Add them to this method and they will be set when creating a new Manager. + * @namespace + */ + cssProps: { /** - * @property swipeMinTouches - * @type {Number} - * @default 1 + * Disables text selection to improve the dragging gesture. Mainly for desktop browsers. + * @type {String} + * @default 'none' */ - swipeMinTouches: 1, + userSelect: 'none', /** - * @property swipeMaxTouches - * @type {Number} - * @default 1 + * Disable the Windows Phone grippers when pressing an element. + * @type {String} + * @default 'none' */ - swipeMaxTouches: 1, + touchSelect: 'none', /** - * horizontal swipe velocity - * @property swipeVelocityX - * @type {Number} - * @default 0.6 + * Disables the default callout shown when you touch and hold a touch target. + * On iOS, when you touch and hold a touch target such as a link, Safari displays + * a callout containing information about the link. This property allows you to disable that callout. + * @type {String} + * @default 'none' */ - swipeVelocityX: 0.6, + touchCallout: 'none', /** - * vertical swipe velocity - * @property swipeVelocityY - * @type {Number} - * @default 0.6 + * Specifies whether zooming is enabled. Used by IE10> + * @type {String} + * @default 'none' */ - swipeVelocityY: 0.6 - }, - - handler: function swipeGesture(ev, inst) { - if(ev.eventType == EVENT_RELEASE) { - var touches = ev.touches.length, - options = inst.options; + contentZooming: 'none', - // max touches - if(touches < options.swipeMinTouches || - touches > options.swipeMaxTouches) { - return; - } + /** + * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers. + * @type {String} + * @default 'none' + */ + userDrag: 'none', - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(ev.velocityX > options.swipeVelocityX || - ev.velocityY > options.swipeVelocityY) { - // trigger swipe events - inst.trigger(this.name, ev); - inst.trigger(this.name + ev.direction, ev); - } - } + /** + * Overrides the highlight color shown when the user taps a link or a JavaScript + * clickable element in iOS. This property obeys the alpha value, if specified. + * @type {String} + * @default 'rgba(0,0,0,0)' + */ + tapHighlightColor: 'rgba(0,0,0,0)' } }; - /** - * @module gestures - */ - /** - * Single tap and a double tap on a place - * - * @class Tap - * @static - */ - /** - * @event tap - * @param {Object} ev - */ - /** - * @event doubletap - * @param {Object} ev - */ + var STOP = 1; + var FORCED_STOP = 2; /** - * @param {String} name + * Manager + * @param {HTMLElement} element + * @param {Object} [options] + * @constructor */ - (function(name) { - var hasMoved = false; + function Manager(element, options) { + options = options || {}; - function tapGesture(ev, inst) { - var options = inst.options, - current = Detection.current, - prev = Detection.previous, - sincePrev, - didDoubleTap; + this.options = merge(options, Hammer.defaults); + this.options.inputTarget = this.options.inputTarget || element; - switch(ev.eventType) { - case EVENT_START: - hasMoved = false; - break; + this.handlers = {}; + this.session = {}; + this.recognizers = []; - case EVENT_MOVE: - hasMoved = hasMoved || (ev.distance > options.tapMaxDistance); - break; + this.element = element; + this.input = createInputInstance(this); + this.touchAction = new TouchAction(this, this.options.touchAction); - case EVENT_END: - if(!Utils.inStr(ev.srcEvent.type, 'cancel') && ev.deltaTime < options.tapMaxTime && !hasMoved) { - // previous gesture, for the double tap since these are two different gesture detections - sincePrev = prev && prev.lastEvent && ev.timeStamp - prev.lastEvent.timeStamp; - didDoubleTap = false; - - // check if double tap - if(prev && prev.name == name && - (sincePrev && sincePrev < options.doubleTapInterval) && - ev.distance < options.doubleTapDistance) { - inst.trigger('doubletap', ev); - didDoubleTap = true; - } + toggleCssProps(this, true); - // do a single tap - if(!didDoubleTap || options.tapAlways) { - current.name = name; - inst.trigger(current.name, ev); - } - } - break; + each(options.recognizers, function(item) { + var recognizer = this.add(new (item[0])(item[1])); + item[2] && recognizer.recognizeWith(item[2]); + item[3] && recognizer.requireFailure(item[3]); + }, this); + } + + Manager.prototype = { + /** + * set options + * @param {Object} options + * @returns {Manager} + */ + set: function(options) { + extend(this.options, options); + + // Options that need a little more setup + if (options.touchAction) { + this.touchAction.update(); } - } + if (options.inputTarget) { + // Clean up existing event listeners and reinitialize + this.input.destroy(); + this.input.target = options.inputTarget; + this.input.init(); + } + return this; + }, - Hammer.gestures.Tap = { - name: name, - index: 100, - handler: tapGesture, - defaults: { - /** - * max time of a tap, this is for the slow tappers - * @property tapMaxTime - * @type {Number} - * @default 250 - */ - tapMaxTime: 250, - - /** - * max distance of movement of a tap, this is for the slow tappers - * @property tapMaxDistance - * @type {Number} - * @default 10 - */ - tapMaxDistance: 10, - - /** - * always trigger the `tap` event, even while double-tapping - * @property tapAlways - * @type {Boolean} - * @default true - */ - tapAlways: true, - - /** - * max distance between two taps - * @property doubleTapDistance - * @type {Number} - * @default 20 - */ - doubleTapDistance: 20, - - /** - * max time between two taps - * @property doubleTapInterval - * @type {Number} - * @default 300 - */ - doubleTapInterval: 300 + /** + * stop recognizing for this session. + * This session will be discarded, when a new [input]start event is fired. + * When forced, the recognizer cycle is stopped immediately. + * @param {Boolean} [force] + */ + stop: function(force) { + this.session.stopped = force ? FORCED_STOP : STOP; + }, + + /** + * run the recognizers! + * called by the inputHandler function on every movement of the pointers (touches) + * it walks through all the recognizers and tries to detect the gesture that is being made + * @param {Object} inputData + */ + recognize: function(inputData) { + var session = this.session; + if (session.stopped) { + return; } - }; - })('tap'); - /** - * @module gestures - */ - /** - * when a touch is being touched at the page - * - * @class Touch - * @static - */ - /** - * @event touch - * @param {Object} ev - */ - Hammer.gestures.Touch = { - name: 'touch', - index: -Infinity, - defaults: { - /** - * call preventDefault at touchstart, and makes the element blocking by disabling the scrolling of the page, - * but it improves gestures like transforming and dragging. - * be careful with using this, it can be very annoying for users to be stuck on the page - * @property preventDefault - * @type {Boolean} - * @default false - */ - preventDefault: false, + // run the touch-action polyfill + this.touchAction.preventDefaults(inputData); - /** - * disable mouse events, so only touch (or pen!) input triggers events - * @property preventMouse - * @type {Boolean} - * @default false - */ - preventMouse: false + var recognizer; + var recognizers = this.recognizers; + + // this holds the recognizer that is being recognized. + // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED + // if no recognizer is detecting a thing, it is set to `null` + var curRecognizer = session.curRecognizer; + + // reset when the last recognizer is recognized + // or when we're in a new session + if (!curRecognizer || (curRecognizer && curRecognizer.state & STATE_RECOGNIZED)) { + curRecognizer = session.curRecognizer = null; + } + + var i = 0; + while (i < recognizers.length) { + recognizer = recognizers[i]; + + // find out if we are allowed try to recognize the input for this one. + // 1. allow if the session is NOT forced stopped (see the .stop() method) + // 2. allow if we still haven't recognized a gesture in this session, or the this recognizer is the one + // that is being recognized. + // 3. allow if the recognizer is allowed to run simultaneous with the current recognized recognizer. + // this can be setup with the `recognizeWith()` method on the recognizer. + if (session.stopped !== FORCED_STOP && ( // 1 + !curRecognizer || recognizer == curRecognizer || // 2 + recognizer.canRecognizeWith(curRecognizer))) { // 3 + recognizer.recognize(inputData); + } else { + recognizer.reset(); + } + + // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the + // current active recognizer. but only if we don't already have an active recognizer + if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) { + curRecognizer = session.curRecognizer = recognizer; + } + i++; + } }, - handler: function touchGesture(ev, inst) { - if(inst.options.preventMouse && ev.pointerType == POINTER_MOUSE) { - ev.stopDetect(); - return; + + /** + * get a recognizer by its event name. + * @param {Recognizer|String} recognizer + * @returns {Recognizer|Null} + */ + get: function(recognizer) { + if (recognizer instanceof Recognizer) { + return recognizer; } - if(inst.options.preventDefault) { - ev.preventDefault(); + var recognizers = this.recognizers; + for (var i = 0; i < recognizers.length; i++) { + if (recognizers[i].options.event == recognizer) { + return recognizers[i]; + } } + return null; + }, - if(ev.eventType == EVENT_TOUCH) { - inst.trigger('touch', ev); + /** + * add a recognizer to the manager + * existing recognizers with the same event name will be removed + * @param {Recognizer} recognizer + * @returns {Recognizer|Manager} + */ + add: function(recognizer) { + if (invokeArrayArg(recognizer, 'add', this)) { + return this; } - } - }; - /** - * @module gestures - */ - /** - * User want to scale or rotate with 2 fingers - * Preventing the default browser behavior is a good way to improve feel and working. This can be done with the - * `preventDefault` option. - * - * @class Transform - * @static - */ - /** - * @event transform - * @param {Object} ev - */ - /** - * @event transformstart - * @param {Object} ev - */ - /** - * @event transformend - * @param {Object} ev - */ - /** - * @event pinchin - * @param {Object} ev - */ - /** - * @event pinchout - * @param {Object} ev - */ - /** - * @event rotate - * @param {Object} ev - */ + // remove existing + var existing = this.get(recognizer.options.event); + if (existing) { + this.remove(existing); + } - /** - * @param {String} name - */ - (function(name) { - var triggered = false; + this.recognizers.push(recognizer); + recognizer.manager = this; - function transformGesture(ev, inst) { - switch(ev.eventType) { - case EVENT_START: - triggered = false; - break; + this.touchAction.update(); + return recognizer; + }, - case EVENT_MOVE: - // at least multitouch - if(ev.touches.length < 2) { - return; - } + /** + * remove a recognizer by name or instance + * @param {Recognizer|String} recognizer + * @returns {Manager} + */ + remove: function(recognizer) { + if (invokeArrayArg(recognizer, 'remove', this)) { + return this; + } - var scaleThreshold = Math.abs(1 - ev.scale); - var rotationThreshold = Math.abs(ev.rotation); + var recognizers = this.recognizers; + recognizer = this.get(recognizer); + recognizers.splice(inArray(recognizers, recognizer), 1); - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(scaleThreshold < inst.options.transformMinScale && - rotationThreshold < inst.options.transformMinRotation) { - return; - } + this.touchAction.update(); + return this; + }, - // we are transforming! - Detection.current.name = name; + /** + * bind event + * @param {String} events + * @param {Function} handler + * @returns {EventEmitter} this + */ + on: function(events, handler) { + var handlers = this.handlers; + each(splitStr(events), function(event) { + handlers[event] = handlers[event] || []; + handlers[event].push(handler); + }); + return this; + }, - // first time, trigger dragstart event - if(!triggered) { - inst.trigger(name + 'start', ev); - triggered = true; - } + /** + * unbind event, leave emit blank to remove all handlers + * @param {String} events + * @param {Function} [handler] + * @returns {EventEmitter} this + */ + off: function(events, handler) { + var handlers = this.handlers; + each(splitStr(events), function(event) { + if (!handler) { + delete handlers[event]; + } else { + handlers[event].splice(inArray(handlers[event], handler), 1); + } + }); + return this; + }, - inst.trigger(name, ev); // basic transform event + /** + * emit event to the listeners + * @param {String} event + * @param {Object} data + */ + emit: function(event, data) { + // we also want to trigger dom events + if (this.options.domEvents) { + triggerDomEvent(event, data); + } - // trigger rotate event - if(rotationThreshold > inst.options.transformMinRotation) { - inst.trigger('rotate', ev); - } + // no handlers, so skip it all + var handlers = this.handlers[event] && this.handlers[event].slice(); + if (!handlers || !handlers.length) { + return; + } - // trigger pinch event - if(scaleThreshold > inst.options.transformMinScale) { - inst.trigger('pinch', ev); - inst.trigger('pinch' + (ev.scale < 1 ? 'in' : 'out'), ev); - } - break; + data.type = event; + data.preventDefault = function() { + data.srcEvent.preventDefault(); + }; - case EVENT_RELEASE: - if(triggered && ev.changedLength < 2) { - inst.trigger(name + 'end', ev); - triggered = false; - } - break; + var i = 0; + while (i < handlers.length) { + handlers[i](data); + i++; } - } + }, - Hammer.gestures.Transform = { - name: name, - index: 45, - defaults: { - /** - * minimal scale factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1 - * @property transformMinScale - * @type {Number} - * @default 0.01 - */ - transformMinScale: 0.01, - - /** - * rotation in degrees - * @property transformMinRotation - * @type {Number} - * @default 1 - */ - transformMinRotation: 1 - }, + /** + * destroy the manager and unbinds all events + * it doesn't unbind dom events, that is the user own responsibility + */ + destroy: function() { + this.element && toggleCssProps(this, false); - handler: transformGesture - }; - })('transform'); + this.handlers = {}; + this.session = {}; + this.input.destroy(); + this.element = null; + } + }; + + /** + * add/remove the css properties as defined in manager.options.cssProps + * @param {Manager} manager + * @param {Boolean} add + */ + function toggleCssProps(manager, add) { + var element = manager.element; + each(manager.options.cssProps, function(value, name) { + element.style[prefixed(element.style, name)] = add ? value : ''; + }); + } /** - * @module hammer + * trigger dom event + * @param {String} event + * @param {Object} data */ + function triggerDomEvent(event, data) { + var gestureEvent = document.createEvent('Event'); + gestureEvent.initEvent(event, true, true); + gestureEvent.gesture = data; + data.target.dispatchEvent(gestureEvent); + } - // AMD export - if(true) { + extend(Hammer, { + INPUT_START: INPUT_START, + INPUT_MOVE: INPUT_MOVE, + INPUT_END: INPUT_END, + INPUT_CANCEL: INPUT_CANCEL, + + STATE_POSSIBLE: STATE_POSSIBLE, + STATE_BEGAN: STATE_BEGAN, + STATE_CHANGED: STATE_CHANGED, + STATE_ENDED: STATE_ENDED, + STATE_RECOGNIZED: STATE_RECOGNIZED, + STATE_CANCELLED: STATE_CANCELLED, + STATE_FAILED: STATE_FAILED, + + DIRECTION_NONE: DIRECTION_NONE, + DIRECTION_LEFT: DIRECTION_LEFT, + DIRECTION_RIGHT: DIRECTION_RIGHT, + DIRECTION_UP: DIRECTION_UP, + DIRECTION_DOWN: DIRECTION_DOWN, + DIRECTION_HORIZONTAL: DIRECTION_HORIZONTAL, + DIRECTION_VERTICAL: DIRECTION_VERTICAL, + DIRECTION_ALL: DIRECTION_ALL, + + Manager: Manager, + Input: Input, + TouchAction: TouchAction, + + TouchInput: TouchInput, + MouseInput: MouseInput, + PointerEventInput: PointerEventInput, + TouchMouseInput: TouchMouseInput, + SingleTouchInput: SingleTouchInput, + + Recognizer: Recognizer, + AttrRecognizer: AttrRecognizer, + Tap: TapRecognizer, + Pan: PanRecognizer, + Swipe: SwipeRecognizer, + Pinch: PinchRecognizer, + Rotate: RotateRecognizer, + Press: PressRecognizer, + + on: addEventListeners, + off: removeEventListeners, + each: each, + merge: merge, + extend: extend, + inherit: inherit, + bindFn: bindFn, + prefixed: prefixed + }); + + if ("function" == TYPE_FUNCTION && __webpack_require__(72)) { !(__WEBPACK_AMD_DEFINE_RESULT__ = function() { return Hammer; }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - // commonjs export - } else if(typeof module !== 'undefined' && module.exports) { + } else if (typeof module != 'undefined' && module.exports) { module.exports = Hammer; - // browser export } else { - window.Hammer = Hammer; + window[exportName] = Hammer; } - })(window); + })(window, document, 'Hammer'); + /***/ }, /* 60 */ @@ -34636,6 +34938,14 @@ return /******/ (function(modules) { // webpackBootstrap } +/***/ }, +/* 72 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(__webpack_amd_options__) {module.exports = __webpack_amd_options__; + + /* WEBPACK VAR INJECTION */}.call(exports, {})) + /***/ } /******/ ]) }); diff --git a/dist/vis.map b/dist/vis.map index ea23db01..8981ec42 100644 --- a/dist/vis.map +++ b/dist/vis.map @@ -1 +1 @@ -{"version":3,"file":"vis.map","sources":["./dist/vis.js"],"names":["root","factory","exports","module","define","amd","this","modules","__webpack_require__","moduleId","installedModules","id","loaded","call","m","c","p","util","DOMutil","DataSet","DataView","Queue","Graph3d","graph3d","Camera","Filter","Point2d","Point3d","Slider","StepNumber","Timeline","Graph2d","timeline","DateUtil","DataStep","Range","stack","TimeStep","components","items","Item","BackgroundItem","BoxItem","PointItem","RangeItem","Component","CurrentTime","CustomTime","DataAxis","GraphGroup","Group","BackgroundGroup","ItemSet","Legend","LineGraph","TimeAxis","Network","network","Edge","Groups","Images","Node","Popup","dotparser","gephiParser","Graph","Error","moment","hammer","isNumber","object","Number","isString","String","isDate","Date","match","ASPDateRegex","exec","isNaN","parse","isDataTable","google","visualization","DataTable","randomUUID","S4","Math","floor","random","toString","extend","a","i","len","arguments","length","other","prop","hasOwnProperty","selectiveExtend","props","Array","isArray","selectiveDeepExtend","b","TypeError","constructor","Object","undefined","deepExtend","selectiveNotDeepExtend","indexOf","equalArray","convert","type","Boolean","valueOf","isMoment","toDate","getType","toISOString","value","getAbsoluteLeft","elem","getBoundingClientRect","left","window","pageXOffset","getAbsoluteTop","top","pageYOffset","addClassName","className","classes","split","push","join","removeClassName","index","splice","forEach","callback","toArray","array","updateProperty","key","addEventListener","element","action","listener","useCapture","navigator","userAgent","attachEvent","removeEventListener","detachEvent","preventDefault","event","returnValue","getTarget","target","srcElement","nodeType","parentNode","option","asBoolean","defaultValue","asNumber","asString","asSize","asElement","hexToRGB","hex","shorthandRegex","replace","r","g","result","parseInt","RGBToHex","red","green","blue","slice","parseColor","color","isValidRGB","rgb","substr","isValidHex","hsv","hexToHSV","lighterColorHSV","h","s","v","min","darkerColorHSV","darkerColorHex","HSVToHex","lighterColorHex","background","border","highlight","hover","RGBToHSV","minRGB","maxRGB","max","d","hue","saturation","cssUtil","cssText","styles","style","trim","parts","keys","map","addCssText","currentStyles","newStyles","removeCssText","removeStyles","HSVToRGB","f","q","t","isOk","test","selectiveBridgeObject","fields","referenceObject","objectTo","create","bridgeObject","mergeOptions","mergeTarget","options","enabled","binarySearchCustom","orderedItems","searchFunction","field","field2","maxIterations","iteration","low","high","middle","item","searchResult","binarySearchValue","sidePreference","prevValue","nextValue","easeInOutQuad","start","end","duration","change","easingFunctions","linear","easeInQuad","easeOutQuad","easeInCubic","easeOutCubic","easeInOutCubic","easeInQuart","easeOutQuart","easeInOutQuart","easeInQuint","easeOutQuint","easeInOutQuint","prepareElements","JSONcontainer","elementType","redundant","used","cleanupElements","removeChild","getSVGElement","svgContainer","shift","document","createElementNS","appendChild","getDOMElement","DOMContainer","insertBefore","createElement","drawPoint","x","y","group","point","drawPoints","setAttributeNS","size","drawBar","width","height","rect","data","_options","_data","_fieldId","fieldId","_type","_subscribers","add","setOptions","prototype","queue","_queue","destroy","on","subscribers","subscribe","off","filter","unsubscribe","_trigger","params","senderId","concat","subscriber","addedIds","me","_addItem","columns","_getColumnNames","row","rows","getNumberOfRows","col","cols","getValue","update","updatedIds","updatedData","addOrUpdate","_updateItem","get","ids","firstType","returnType","allowedValues","itemId","_getItem","order","_sort","_filterFields","_appendRow","getIds","getDataSet","mappedItems","filteredItem","name","sort","av","bv","remove","removedId","removedIds","_remove","clear","maxField","itemField","minField","distinct","values","fieldType","count","exists","types","raw","converted","JSON","stringify","dataTable","getNumberOfColumns","getColumnId","getColumnLabel","addRow","setValue","_ids","_onEvent","apply","setData","viewOptions","getArguments","defaultFilter","dataSet","added","updated","removed","delay","Infinity","_timeout","_extended","_flushIfNeeded","flush","methods","original","method","args","fn","context","entry","clearTimeout","setTimeout","container","SyntaxError","containerElement","margin","defaultXCenter","defaultYCenter","xLabel","yLabel","zLabel","passValueFn","xValueLabel","yValueLabel","zValueLabel","filterLabel","legendLabel","STYLE","DOT","showPerspective","showGrid","keepAspectRatio","showShadow","showGrayBottom","showTooltip","verticalRatio","animationInterval","animationPreload","camera","eye","dataPoints","colX","colY","colZ","colValue","colFilter","xMin","xStep","xMax","yMin","yStep","yMax","zMin","zStep","zMax","valueMin","valueMax","xBarWidth","yBarWidth","colorAxis","colorGrid","colorDot","colorDotBorder","getMouseX","clientX","targetTouches","getMouseY","clientY","Emitter","_setScale","scale","z","xCenter","yCenter","zCenter","setArmLocation","_convert3Dto2D","point3d","translation","_convertPointToTranslation","_convertTranslationToScreen","ax","ay","az","cx","getCameraLocation","cy","cz","sinTx","sin","getCameraRotation","cosTx","cos","sinTy","cosTy","sinTz","cosTz","dx","dy","dz","bx","by","ex","ey","ez","getArmLength","xcenter","frame","canvas","clientWidth","ycenter","_setBackgroundColor","backgroundColor","fill","stroke","strokeWidth","borderColor","borderWidth","borderStyle","BAR","BARCOLOR","BARSIZE","DOTLINE","DOTCOLOR","DOTSIZE","GRID","LINE","SURFACE","_getStyleNumber","styleName","_determineColumnIndexes","counter","column","getDistinctValues","distinctValues","getColumnRange","minMax","_dataInitialize","rawData","_onChange","dataFilter","setOnLoadCallback","redraw","withBars","defaultXBarWidth","dataX","defaultYBarWidth","dataY","xRange","defaultXMin","defaultXMax","defaultXStep","yRange","defaultYMin","defaultYMax","defaultYStep","zRange","defaultZMin","defaultZMax","defaultZStep","valueRange","defaultValueMin","defaultValueMax","_getDataPoints","obj","sortNumber","dataMatrix","xIndex","yIndex","trans","screen","bottom","pointRight","pointTop","pointCross","hasChildNodes","firstChild","position","overflow","noCanvas","fontWeight","padding","innerHTML","onmousedown","_onMouseDown","ontouchstart","_onTouchStart","onmousewheel","_onWheel","ontooltip","_onTooltip","onkeydown","setSize","_resizeCanvas","clientHeight","animationStart","slider","play","animationStop","stop","_resizeCenter","charAt","parseFloat","setCameraPosition","pos","horizontal","vertical","setArmRotation","distance","setArmLength","getCameraPosition","getArmRotation","_readData","_redrawFilter","animationAutoStart","cameraPosition","styleNumber","tooltip","showAnimationControls","_redrawSlider","_redrawClear","_redrawAxis","_redrawDataGrid","_redrawDataLine","_redrawDataBar","_redrawDataDot","_redrawInfo","_redrawLegend","ctx","getContext","clearRect","widthMin","widthMax","dotSize","right","lineWidth","font","ymin","ymax","_hsv2rgb","strokeStyle","beginPath","moveTo","lineTo","strokeRect","fillStyle","closePath","gridLineLen","step","getCurrent","next","textAlign","textBaseline","fillText","label","visible","setValues","setPlayInterval","onchange","getIndex","selectValue","setOnChangeCallback","lineStyle","getLabel","getSelectedValue","from","to","prettyStep","text","xText","yText","zText","offset","xOffset","yOffset","xMin2d","xMax2d","gridLenX","gridLenY","textMargin","armAngle","H","S","V","R","G","B","C","Hi","X","abs","cross","topSideVisible","zAvg","transBottom","dist","sortDepth","aDiff","subtract","bDiff","crossproduct","crossProduct","radius","arc","PI","j","surface","corners","xWidth","yWidth","surfaces","center","avg","transCenter","diff","leftButtonDown","_onMouseUp","which","button","touchDown","startMouseX","startMouseY","startStart","startEnd","startArmRotation","cursor","onmousemove","_onMouseMove","onmouseup","diffX","diffY","horizontalNew","verticalNew","snapAngle","snapValue","round","parameters","emit","boundingRect","mouseX","mouseY","tooltipTimeout","_hideTooltip","dataPoint","_dataPointFromXY","_showTooltip","ontouchmove","_onTouchMove","ontouchend","_onTouchEnd","delta","wheelDelta","detail","oldLength","newLength","_insideTriangle","triangle","sign","as","bs","cs","distMax","closestDataPoint","closestDist","triangle1","triangle2","distX","distY","sqrt","content","line","dot","dom","borderRadius","boxShadow","borderLeft","contentWidth","offsetWidth","contentHeight","offsetHeight","lineHeight","dotWidth","dotHeight","armLocation","armRotation","armLength","cameraLocation","cameraRotation","calculateCameraOrientation","rot","graph","onLoadCallback","loadInBackground","isLoaded","getLoadedProgress","getColumn","getValues","dataView","progress","sub","sum","prev","bar","MozBorderRadius","slide","onclick","togglePlay","onChangeCallback","playTimeout","playInterval","playLoop","setIndex","playNext","interval","clearInterval","getPlayInterval","setPlayLoop","doLoop","onChange","indexToLeft","startClientX","startSlideX","leftToIndex","_start","_end","_step","precision","_current","setRange","setStep","calculatePrettyStep","log10","log","LN10","step1","pow","step2","step5","toPrecision","getStep","groups","forthArgument","defaultOptions","autoResize","orientation","maxHeight","minHeight","_create","body","domProps","emitter","bind","hiddenDates","snap","toScreen","_toScreen","toGlobalScreen","_toGlobalScreen","toTime","_toTime","toGlobalTime","_toGlobalTime","range","timeAxis","currentTime","customTime","itemSet","itemsData","groupsData","setGroups","setItems","Core","newDataSet","initialLoad","dataRange","_getDataRange","setWindow","animate","fit","setSelection","focus","getSelection","itemData","e","getItemRange","dataset","minItem","maxStartItem","maxEndItem","linegraph","getLegend","groupId","isGroupVisible","visibility","convertHiddenOptions","repeat","dateItem","updateHiddenDates","centerContainer","totalRange","pixelTime","startDate","endDate","_d","runUntil","clone","day","dayOfYear","year","dayOffset","date","month","console","removeDuplicates","startHidden","isHidden","endHidden","rangeStart","rangeEnd","hidden","startToFront","endToFront","_applyRange","safeDates","printDates","dates","stepOverHiddenDates","timeStep","previousTime","stepInHidden","currentValue","current","newValue","switchedYear","switchedMonth","switchedDay","time","conversion","getHiddenDurationBetween","correctTimeForHidden","hiddenDuration","totalDuration","partialDuration","accumulatedHiddenDuration","getAccumulatedHiddenDuration","newTime","getHiddenDurationBefore","timeOffset","requiredDuration","previousPoint","snapAwayFromHidden","direction","correctionEnabled","minimumStep","containerHeight","customRange","alignZeros","autoScale","stepIndex","marginStart","marginEnd","deadSpace","majorSteps","minorSteps","setMinimumStep","setFirst","safeSize","minimumStepValue","orderOfMagnitude","minorStepIdx","magnitudefactor","solutionFound","stepSize","niceStart","niceEnd","roundToMinor","marginRange","rounded","hasNext","previous","decimals","exp","cnt","isMajor","now","hours","minutes","seconds","milliseconds","deltaDifference","scaleOffset","moveable","zoomable","zoomMin","zoomMax","touch","animateTimer","_onDragStart","_onDrag","_onDragEnd","_onHold","_onMouseWheel","_onTouch","_onPinch","validateDirection","getPointer","pageX","pageY","hammerUtil","byUser","_cancelAnimation","initStart","initEnd","initTime","anyChanged","dragging","done","changed","newStart","newEnd","getRange","totalHidden","previousDelta","allowDragging","gesture","deltaX","deltaY","diffRange","safeStart","safeEnd","fakeGesture","pointer","pointerDate","_pointerToDate","zoom","touches","centerDate","hiddenDurationBefore","hiddenDurationAfter","move","EPSILON","orderByStart","orderByEnd","aTime","bTime","force","iMax","axis","collidingItem","jj","collision","nostack","subgroups","newTop","subgroup","format","FORMAT","minorLabels","millisecond","second","minute","hour","weekday","majorLabels","setFormat","defaultFormat","first","setFullYear","getFullYear","setMonth","setDate","setHours","setMinutes","setSeconds","setMilliseconds","getMilliseconds","getSeconds","getMinutes","getHours","getDate","getMonth","setScale","newScale","newStep","setAutoScale","enable","stepYear","stepMonth","stepDay","stepHour","stepMinute","stepSecond","stepMillisecond","getLabelMinor","getLabelMajor","getClassName","even","today","isSame","currentWeek","currentMonth","currentYear","locale","lang","toLowerCase","_isResized","resized","_previousWidth","_previousHeight","showCurrentTime","locales","parent","backgroundVertical","title","toUpperCase","substring","currentTimeTimer","setCurrentTime","getCurrentTime","showCustomTime","eventParams","Hammer","drag","prevent_default","setCustomTime","getCustomTime","stopPropagation","svg","linegraphOptions","showMinorLabels","showMajorLabels","icons","majorLinesOffset","minorLinesOffset","labelOffsetX","labelOffsetY","iconWidth","linegraphSVG","DOMelements","lines","labels","conversionFactor","minWidth","stepPixels","stepPixelsForced","zeroCrossing","lineOffset","master","svgElements","iconsRemoved","amountOfGroups","lineContainer","scrollTop","addGroup","graphOptions","updateGroup","removeGroup","hide","show","display","_redrawGroupIcons","iconHeight","iconOffset","drawIcon","_cleanupIcons","backgroundHorizontal","activeGroups","_calculateCharSize","minorLabelHeight","minorCharHeight","majorLabelHeight","majorCharHeight","minorLineWidth","minorLineHeight","majorLineWidth","majorLineHeight","_redrawLabels","_redrawTitle","amountOfSteps","stepDifference","zeroStepDifference","valueAtZero","marginStartPos","maxLabelSize","_redrawLabel","_redrawLine","titleWidth","titleCharHeight","convertValue","invertedValue","convertedValue","characterHeight","largestWidth","majorCharWidth","minorCharWidth","textMinor","createTextNode","measureCharMinor","textMajor","measureCharMajor","textTitle","measureCharTitle","titleCharWidth","groupsUsingDefaultStyles","usingDefaultStyle","zeroPosition","Line","Bar","Points","setZeroPosition","catmullRom","parametrization","alpha","SVGcontainer","path","fillPath","fillHeight","outline","shaded","barWidth","bar1Height","bar2Height","icon","yAxisOrientation","getYRange","groupData","draw","framework","subgroupIndex","subgroupOrderer","subgroupOrder","visibleItems","byStart","byEnd","checkRangedItems","inner","foreground","marker","Element","getLabelWidth","restack","_updateVisibleItems","markerHeight","lastMarkerHeight","dirty","displayed","_calculateHeight","offsetTop","offsetLeft","ii","repositionY","resetSubgroups","labelSet","setParent","orderSubgroups","_checkIfVisible","sortArray","sortField","removeFromDataSet","removeItem","startArray","endArray","oldVisibleItems","visibleItemsLookup","lowerBound","upperBound","_checkIfVisibleWithReference","initialPosByStart","_traceVisible","initialPosByEnd","repositionX","initialPos","breakCondition","isVisible","align","groupOrder","selectable","editable","updateTime","onAdd","onUpdate","onMove","onRemove","onMoving","itemOptions","itemListeners","_onAdd","_onUpdate","_onRemove","groupListeners","_onAddGroups","_onUpdateGroups","_onRemoveGroups","groupIds","selection","stackDirty","touchParams","UNGROUPED","BACKGROUND","box","_updateUngrouped","backgroundGroup","_onSelectItem","_onMultiSelectItem","_onAddItem","addCallback","Function","markDirty","unselect","select","getVisibleItems","rawVisibleItems","_deselect","_orderGroups","visibleInterval","zoomed","lastVisibleInterval","lastWidth","firstGroup","_firstGroup","firstMargin","nonFirstMargin","groupMargin","groupResized","firstGroupIndex","firstGroupId","ungrouped","_getGroupId","getLabelSet","oldItemsData","getItems","_order","getGroups","_getType","_removeItem","groupOptions","oldGroupId","oldGroup","_constructByEndArray","itemFromTarget","selected","dragLeftItem","dragRightItem","initialX","itemProps","newProps","initial","groupFromTarget","_updateItemProps","_moveToGroup","changes","ctrlKey","srcEvent","shiftKey","oldSelection","newSelection","xAbs","newItem","_getItemRange","_item","itemSetFromTarget","side","iconSize","iconSpacing","textArea","scrollableHeight","drawLegendIcons","getComputedStyle","paddingTop","defaultGroup","sampling","graphHeight","barChart","handleOverlap","dataAxis","legend","abortedGraphUpdate","updateSVGheight","updateSVGheightOnResize","lastStart","COUNTER","BarGraphFunctions","yAxisLeft","yAxisRight","legendLeft","legendRight","_updateAllGroupData","_updateGroup","groupsContent","ungroupedCounter","forceGraphUpdate","_updateGraph","rangePerPixelInv","preprocessedGroupData","processedGroupData","groupRanges","changeCalled","minDate","maxDate","_getRelevantData","_applySampling","_convertXcoordinates","_getYRanges","_updateYAxis","MAX_CYCLES","_convertYcoordinates","dataContainer","guess","increment","amountOfPoints","xDistance","pointsPerPixel","ceil","sampledData","barCombinedDataLeft","barCombinedDataRight","getStackedBarYRange","minVal","maxVal","yAxisLeftUsed","yAxisRightUsed","minLeft","minRight","maxLeft","maxRight","ignore","_toggleAxisVisiblity","drawIcons","axisUsed","datapoints","xValue","yValue","extractedData","svgHeight","majorTexts","minorTexts","lineTop","parentChanged","foregroundNextSibling","nextSibling","backgroundNextSibling","_repaintLabels","timeLabelsize","cur","prevLine","xPrev","xFirstMajorLabel","_repaintMinorText","_repaintMajorText","_repaintMajorLine","_repaintMinorLine","leftTime","leftText","widthText","arr","pop","childNodes","nodeValue","_repaintDeleteButton","anchor","deleteButton","_updateContents","template","_updateTitle","removeAttribute","_updateDataAttributes","dataAttributes","attributes","setAttribute","_updateStyle","emptyContent","baseClassName","onTop","itemSubgroup","itemSetHeight","marginLeft","maxWidth","_repaintDragLeft","_repaintDragRight","contentLeft","parentWidth","boxWidth","dragLeft","dragRight","_determineBrowserMethod","_initializeMixinLoaders","renderRefreshRate","renderTimestep","renderTime","physicsTime","runDoubleSpeed","physicsDiscreteStepsize","initializing","triggerFunctions","edit","editEdge","connect","del","nodes","mass","radiusMin","radiusMax","shape","image","fontColor","fontSize","fontFace","fontFill","fontStrokeWidth","fontStrokeColor","level","borderWidthSelected","edges","widthSelectionMultiplier","hoverWidth","labelAlignment","arrowScaleFactor","dash","gap","altLength","inheritColor","configurePhysics","physics","barnesHut","thetaInverted","gravitationalConstant","centralGravity","springLength","springConstant","damping","repulsion","nodeDistance","hierarchicalRepulsion","clustering","initialMaxNodes","clusterThreshold","reduceToNodes","chainThreshold","clusterEdgeThreshold","sectorThreshold","screenSizeThreshold","fontSizeMultiplier","maxFontSize","forceAmplification","distanceAmplification","edgeGrowth","nodeScaling","maxNodeSizeIncrements","activeAreaBoxSize","clusterLevelDifference","navigation","keyboard","speed","dataManipulation","initiallyVisible","hierarchicalLayout","levelSeparation","nodeSpacing","layout","freezeForStabilization","smoothCurves","dynamic","roundness","maxVelocity","minVelocity","stabilize","stabilizationIterations","zoomExtentOnStabilize","dragNetwork","dragNodes","hideEdgesOnDrag","hideNodesOnDrag","constants","pixelRatio","hoverObj","controlNodesActive","navigationHammers","existing","_new","animationSpeed","animationEasingFunction","easingTime","sourceScale","targetScale","sourceTranslation","targetTranslation","lockedOnNodeId","lockedOnNodeOffset","touchTime","images","setOnloadCallback","_redraw","xIncrement","yIncrement","zoomIncrement","_loadPhysicsSystem","_loadSectorSystem","_loadClusterSystem","_loadSelectionSystem","_loadHierarchySystem","_setTranslation","freezeSimulation","cachedFunctions","startedStabilization","stabilized","draggingNodes","calculationNodes","calculationNodeIndices","nodeIndices","canvasTopLeft","canvasBottomRight","pointerPosition","areaCenter","previousScale","nodesData","edgesData","nodesListeners","_addNodes","_updateNodes","_removeNodes","edgesListeners","_addEdges","_updateEdges","_removeEdges","moving","timer","_setupHierarchicalLayout","zoomExtent","startWithClustering","keycharm","MixinLoader","Activator","browserType","requiresTimeout","_getScriptPath","scripts","getElementsByTagName","src","_getRange","node","minY","maxY","minX","maxX","nodeId","boundingBox","_findCenter","animationOptions","initialZoom","disableStart","zoomLevel","numberOfNodes","factor","yDistance","xZoomLevel","yZoomLevel","animation","_updateNodeIndexList","_clearNodeIndexList","idx","_createManipulatorBar","dotData","DOTToGraph","gephi","gephiData","parseGephi","_setNodes","_setEdges","_putDataInSector","_resetLevels","_stabilize","onEdit","onEditEdge","onConnect","onDelete","editMode","newColorObj","groupname","clickToUse","activator","_createKeyBinds","_loadNavigationControls","_loadManipulationSystem","_configureSmoothCurves","devicePixelRatio","webkitBackingStorePixelRatio","mozBackingStorePixelRatio","msBackingStorePixelRatio","oBackingStorePixelRatio","backingStorePixelRatio","setTransform","pinch","_onTap","_onDoubleTap","_onMouseMoveTitle","hammerFrame","_onRelease","reset","isActive","_moveUp","_yStopMoving","_moveDown","_moveLeft","_xStopMoving","_moveRight","_zoomIn","_stopZoom","_zoomOut","_deleteSelected","_cleanupPhysicsConfiguration","dispose","_recursiveDOMDelete","DOMobject","_getPointer","pinched","_getScale","_handleTouch","_handleDragStart","_getNodeAt","_getTranslation","isSelected","_selectObject","nodeIds","objectId","selectionObj","xFixed","yFixed","_handleOnDrag","releaseNode","_XconvertDOMtoCanvas","_XconvertCanvasToDOM","_YconvertDOMtoCanvas","_YconvertCanvasToDOM","_handleDragEnd","_handleTap","_handleDoubleTap","_handleOnHold","_handleOnRelease","_zoom","scaleOld","preScaleDragPointer","DOMtoCanvas","scaleFrac","tx","ty","updateClustersDefault","postScaleDragPointer","canvasToDOM","popupObj","_checkHidePopup","checkShow","_checkShowPopup","popupTimer","edgeId","_getEdgeAt","_hoverObject","_blurObject","lastPopupNode","nodeUnderCursor","overlappingNodes","isOverlappingWith","getTitle","overlappingEdges","edge","connected","popup","setPosition","setText","emitEvent","oldWidth","oldHeight","oldNodesData","_updateSelection","angle","_updateCalculationNodes","_reconnectEdges","_updateValueRange","updateLabels","changedData","setProperties","properties","oldEdgesData","oldEdge","disconnect","showInternalIds","_createBezierNodes","via","sectors","dynamicEdges","setValueRange","w","save","translate","_doInAllSectors","restore","offsetX","offsetY","_drawNodes","alwaysShow","setScaleAndPos","inArea","sMax","_drawEdges","_drawControlNodes","_freezeDefinedNodes","_physicsTick","_restoreFrozenNodes","fixedData","_isMoving","vmin","isMoving","_discreteStepNodes","nodesPresent","discreteStepLimited","discreteStep","vminCorrected","_revertPhysicsState","revertPosition","_revertPhysicsTick","_doInAllActiveSectors","_doInSupportSector","mainMovingStatus","supportMovingStatus","mainMoving","_animationStep","_handleNavigation","startTime","renderStartTime","requestAnimationFrame","mozRequestAnimationFrame","webkitRequestAnimationFrame","msRequestAnimationFrame","iterations","toggleFreeze","parentEdgeId","internalMultiplier","positionBezierNode","mixin","storePosition","storePositions","dataArray","allowedToMoveX","allowedToMoveY","getPositions","focusOnNode","nodePosition","lockedOnNode","easingFunction","animateView","locked","_transitionRedraw","viewCenter","distanceFromCenter","_classicRedraw","_lockedRedraw","active","getScale","getCenterCoordinates","getBoundingBox","networkConstants","fromId","toId","widthSelected","labelDimensions","yLine","dirtyLabel","fromBackup","toBackup","originalFromId","originalToId","widthFixed","lengthFixed","controlNodesEnabled","controlNodes","positions","connectedNode","_drawLine","_drawArrow","_drawArrowCenter","_drawDashLine","attachEdge","detachEdge","xFrom","yFrom","xTo","yTo","xObj","yObj","_getDistanceToEdge","_getColor","colorObj","_getLineWidth","_line","midpointX","midpointY","_pointOnLine","_label","resize","_circle","_pointOnCircle","networkScaleInv","_getViaCoordinates","xVia","yVia","quadraticCurveTo","lineCount","measureText","_rotateForLabelAlignment","_drawLabelRect","_drawLabelText","angleInDegrees","atan2","rotate","lineMargin","fillRect","lineJoin","strokeText","setLineDash","pattern","lineDashOffset","lineCap","dashedLine","percentage","arrow","_pointOnBezier","_findBorderPosition","distanceToBorder","distanceToNodes","difference","threshold","arrowPos","guidePos","edgeSegmentLength","toBorderDist","toBorderPoint","x1","y1","x2","y2","x3","y3","lastX","lastY","minDistance","_getDistanceToLine","px","py","something","u","nodeIdFrom","nodeIdTo","getControlNodeFromPosition","getControlNodeToPosition","_enableControlNodes","_disableControlNodes","_getSelectedControlNode","fromDistance","toDistance","_restoreControlNodes","controlnodeFromPos","fromBorderDist","fromBorderPoint","controlnodeToPos","defaultIndex","DEFAULT","imageBroken","load","url","brokenUrl","img","Image","onload","onerror","error","imagelist","grouplist","reroutedEdges","fontDrawThreshold","horizontalAlignLeft","verticalAlignTop","baseRadiusValue","radiusFixed","preassignedLevel","hierarchyEnumerated","fx","fy","vx","vy","previousState","resetCluster","dynamicEdgesLength","clusterSession","clusterSizeWidthFactor","clusterSizeHeightFactor","clusterSizeRadiusFactor","growthIndicator","networkScale","formationScale","clusterSize","containedNodes","containedEdges","clusterSessions","originalLabel","triggerFunction","groupObj","imageObj","brokenImage","_drawDatabase","_resizeDatabase","_drawBox","_resizeBox","_drawCircle","_resizeCircle","_drawEllipse","_resizeEllipse","_drawImage","_resizeImage","_drawCircularImage","_resizeCircularImage","_drawText","_resizeText","_drawDot","_resizeShape","_drawSquare","_drawTriangle","_drawTriangleDown","_drawStar","_reset","clearSizeCache","_setForce","_addForce","storeState","isFixed","velocity","getDistance","_drawImageAtPosition","globalAlpha","drawImage","_drawImageLabel","getTextSize","_swapToImageResizeWhenImageLoaded","diameter","centerX","centerY","_drawRawCircle","circle","clip","textSize","clusterLineWidth","selectionLineWidth","roundRect","database","defaultSize","ellipse","_drawShape","radiusMultiplier","baseline","labelUnderNode","inView","clearVelocity","updateVelocity","massBeforeClustering","energyBefore","styleAttr","fontFamily","WebkitBorderRadius","whiteSpace","parseDOT","parseGraph","nextPreview","isAlphaNumeric","regexAlphaNumeric","merge","o","addNode","graphs","attr","addEdge","createEdge","getToken","tokenType","TOKENTYPE","NULL","token","isComment","DELIMITER","c2","DELIMITERS","IDENTIFIER","newSyntaxError","UNKNOWN","chop","strict","parseStatements","parseStatement","subgraph","parseSubgraph","parseEdge","parseAttributeStatement","parseNodeStatement","subgraphs","parseAttributeList","message","maxLength","forEach2","array1","array2","elem1","elem2","graphData","dotNode","graphNode","convertEdge","dotEdge","graphEdge","subEdge","{","}","[","]",";","=",",","->","--","gephiJSON","allowedToMove","gEdges","gNodes","gEdge","source","gNode","leftContainer","rightContainer","shadowTop","shadowBottom","shadowTopLeft","shadowBottomLeft","shadowTopRight","shadowBottomRight","_redrawTimer","listeners","events","scrollTopMin","redrawCount","_initAutoResize","component","_stopAutoResize","what","getWindow","borderRootHeight","borderRootWidth","autoHeight","centerWidth","_updateScrollTop","visibilityTop","visibilityBottom","MAX_REDRAWS","repaint","_startAutoResize","_onResize","lastHeight","watchTimer","setInterval","initialScrollTop","oldScrollTop","_getScrollTop","newScrollTop","_setScrollTop","eventType","getTouchList","collectEventData","custom","back","editNode","addDescription","edgeDescription","editEdgeDescription","createEdgeError","deleteClusterError","CanvasRenderingContext2D","square","s2","ir","triangleDown","star","n","r2d","kappa","ox","oy","xe","ye","xm","ym","bezierCurveTo","wEllipse","hEllipse","ymb","yeb","xt","yt","xi","yi","xl","yl","xr","yr","dashArray","dashLength","dashCount","slope","distRemaining","dashIndex","_catmullRom","_linear","dFill","_catmullRomUniform","p0","p1","p2","p3","bp1","bp2","normalization","d1","d2","d3","A","N","M","d3powA","d2powA","d3pow2A","d2pow2A","d1pow2A","d1powA","Bargraph","barCombinedData","coreDistance","drawData","combinedData","intersections","barPoints","_getDataIntersections","heightOffset","_getSafeDrawData","nextKey","amount","resolved","prevKey","accumulated","groupLabel","_getStackedBarYRange","xpos","PhysicsMixin","ClusterMixin","SectorsMixin","SelectionMixin","ManipulationMixin","NavigationMixin","HierarchicalLayoutMixin","_loadMixin","sourceVariable","mixinFunction","_clearMixin","_loadSelectedForceSolver","_loadPhysicsConfiguration","hubThreshold","activeSector","drawingNode","blockConnectingEdgeSelection","forceAppendSelection","manipulationDiv","editModeDiv","closeDiv","_cleanNavigation","_loadNavigationElements","overlay","_onTapOverlay","windowHammer","_hasParent","deactivate","escListener","activate","unbind","_callbacks","once","self","removeListener","removeAllListeners","callbacks","cb","hasListeners","__WEBPACK_AMD_DEFINE_FACTORY__","__WEBPACK_AMD_DEFINE_ARRAY__","__WEBPACK_AMD_DEFINE_RESULT__","_exportFunctions","_bound","keydown","keyup","_keys","fromCharCode","code","down","handleEvent","up","keyCode","bound","bindAll","getKey","newBindings","global","dfl","hasOwnProp","defaultParsingFlags","empty","unusedTokens","unusedInput","charsLeftOver","nullInput","invalidMonth","invalidFormat","userInvalidated","iso","printMsg","msg","suppressDeprecationWarnings","warn","deprecate","firstTime","deprecateSimple","deprecations","padToken","func","leftZeroFill","ordinalizeToken","period","localeData","ordinal","monthDiff","anchor2","adjust","wholeMonthDiff","meridiemFixWrap","meridiem","isPm","meridiemHour","isPM","Locale","Moment","config","skipOverflow","checkOverflow","copyConfig","updateInProgress","updateOffset","Duration","normalizedInput","normalizeObjectUnits","years","quarters","quarter","months","weeks","week","days","_milliseconds","_days","_months","_locale","_bubble","val","_isAMomentObject","_i","_f","_l","_strict","_tzm","_isUTC","_offset","_pf","momentProperties","absRound","number","targetLength","forceSign","output","positiveMomentsDifference","base","res","isAfter","momentsDifference","makeAs","isBefore","createAdder","dur","tmp","addOrSubtractDurationFromMoment","mom","isAdding","setTime","rawSetter","rawGetter","rawMonthSetter","input","compareArrays","dontConvert","lengthDiff","diffs","toInt","normalizeUnits","units","lowered","unitAliases","camelFunctions","inputObject","normalizedProp","makeList","setter","getter","results","utc","set","argumentForCoercion","coercedNumber","isFinite","daysInMonth","UTC","getUTCDate","weeksInYear","dow","doy","weekOfYear","daysInYear","isLeapYear","_a","MONTH","DATE","YEAR","HOUR","MINUTE","SECOND","MILLISECOND","_overflowDayOfYear","isValid","_isValid","getTime","bigHour","normalizeLocale","chooseLocale","names","loadLocale","oldLocale","hasModule","model","local","removeFormattingTokens","makeFormatFunction","formattingTokens","formatTokenFunctions","formatMoment","expandFormat","formatFunctions","invalidDate","replaceLongDateFormatTokens","longDateFormat","localFormattingTokens","lastIndex","getParseRegexForToken","parseTokenOneDigit","parseTokenThreeDigits","parseTokenFourDigits","parseTokenOneToFourDigits","parseTokenSignedNumber","parseTokenSixDigits","parseTokenOneToSixDigits","parseTokenTwoDigits","parseTokenOneToThreeDigits","parseTokenWord","_meridiemParse","parseTokenOffsetMs","parseTokenTimestampMs","parseTokenTimezone","parseTokenT","parseTokenDigits","parseTokenOneOrTwoDigits","_ordinalParse","_ordinalParseLenient","RegExp","regexpEscape","unescapeFormat","utcOffsetFromString","string","possibleTzMatches","tzChunk","parseTimezoneChunker","addTimeToArrayFromToken","datePartArray","monthsParse","_dayOfYear","parseTwoDigitYear","_meridiem","_useUTC","weekdaysParse","_w","invalidWeekday","dayOfYearFromWeekInfo","weekYear","temp","GG","W","E","_week","gg","dayOfYearFromWeeks","dateFromConfig","currentDate","yearToUse","currentDateArray","makeUTCDate","getUTCMonth","_nextDay","makeDate","setUTCMinutes","getUTCMinutes","dateFromObject","getUTCFullYear","makeDateFromStringAndFormat","ISO_8601","parseISO","parsedInput","tokens","skipped","stringLength","totalParsedInputLength","matched","p4","makeDateFromStringAndArray","tempConfig","bestMoment","scoreToBeat","currentScore","NaN","score","l","isoRegex","isoDates","isoTimes","makeDateFromString","createFromInputFallback","makeDateFromInput","aspNetJsonRegex","ms","setUTCFullYear","parseWeekday","substituteTimeAgo","withoutSuffix","isFuture","relativeTime","posNegDuration","relativeTimeThresholds","firstDayOfWeek","firstDayOfWeekOfYear","adjustedMoment","daysToDayOfWeek","daysToAdd","getUTCDay","makeMoment","invalid","preparse","pickBy","moments","dayOfMonth","unit","makeAccessor","keepTime","daysToYears","yearsToDays","makeDurationGetter","makeGlobal","shouldDeprecate","ender","oldGlobalMoment","globalScope","VERSION","aspNetTimeSpanJsonRegex","isoDurationRegex","isoFormat","unitMillisecondFactors","Milliseconds","Seconds","Minutes","Hours","Days","Months","Years","D","Q","DDD","dayofyear","isoweekday","isoweek","weekyear","isoweekyear","ordinalizeTokens","paddedTokens","MMM","monthsShort","MMMM","dd","weekdaysMin","ddd","weekdaysShort","dddd","weekdays","isoWeek","YY","YYYY","YYYYY","YYYYYY","gggg","ggggg","isoWeekYear","GGGG","GGGGG","isoWeekday","SS","SSS","SSSS","Z","utcOffset","ZZ","zoneAbbr","zz","zoneName","unix","lists","DDDD","_monthsShort","monthName","regex","_monthsParse","_longMonthsParse","_shortMonthsParse","_weekdays","_weekdaysShort","_weekdaysMin","weekdayName","_weekdaysParse","_longDateFormat","LTS","LT","L","LL","LLL","LLLL","isLower","_calendar","sameDay","nextDay","nextWeek","lastDay","lastWeek","sameElse","calendar","_relativeTime","future","past","mm","hh","MM","yy","pastFuture","_ordinal","postformat","firstDayOfYear","_invalidDate","ret","parseIso","diffRes","isDuration","inp","version","relativeTimeThreshold","limit","defineLocale","_abbr","abbr","langData","flags","parseZone","isDSTShifted","parsingFlags","invalidAt","keepLocalTime","_dateUtcOffset","inputString","asFloat","that","zoneDiff","humanize","fromNow","sod","startOf","isDST","getDay","endOf","inputMs","isBetween","zone","localAdjust","_changeInProgress","isLocal","isUtcOffset","isUtc","hasAlignedHourOffset","isoWeeksInYear","weekInfo","newLocaleData","getTimezoneOffset","isoWeeks","toJSON","isUTC","withSuffix","toIsoString","asSeconds","asMilliseconds","asMinutes","asHours","asDays","asWeeks","asMonths","asYears","ordinalParse","require","noGlobal","setup","READY","Event","determineEventTypes","Utils","each","gestures","Detection","register","onTouch","DOCUMENT","EVENT_MOVE","detect","EVENT_END","Instance","defaults","behavior","userSelect","touchAction","touchCallout","contentZooming","userDrag","tapHighlightColor","HAS_POINTEREVENTS","pointerEnabled","msPointerEnabled","HAS_TOUCHEVENTS","IS_MOBILE","NO_MOUSEEVENTS","CALCULATE_INTERVAL","EVENT_TYPES","DIRECTION_DOWN","DIRECTION_LEFT","DIRECTION_UP","DIRECTION_RIGHT","POINTER_MOUSE","POINTER_TOUCH","POINTER_PEN","EVENT_START","EVENT_RELEASE","EVENT_TOUCH","plugins","utils","dest","handler","iterator","inStr","find","inArray","hasParent","getCenter","getVelocity","deltaTime","getAngle","touch1","touch2","getDirection","getRotation","isVertical","setPrefixedCss","toggle","prefixes","toCamelCase","toggleBehavior","falseFn","onselectstart","ondragstart","str","preventMouseEvents","started","shouldDetect","hook","onTouchHandler","ev","triggerType","srcType","isPointer","isMouse","buttons","PointerEvent","matchType","updatePointer","doDetect","touchList","touchListLength","triggerChange","trigger","changedLength","changedTouches","evData","identifiers","identifier","pointerType","timeStamp","preventManipulation","stopDetect","pointers","touchlist","pointerEvent","pointerId","pt","MSPOINTER_TYPE_MOUSE","MSPOINTER_TYPE_TOUCH","MSPOINTER_TYPE_PEN","detection","stopped","startDetect","inst","eventData","startEvent","lastEvent","lastCalcEvent","futureCalcEvent","lastCalcData","extendEventData","instOptions","getCalculatedData","recalc","calcEv","calcData","velocityX","velocityY","interimAngle","interimDirection","startEv","lastEv","rotation","eventStartHandler","eventHandlers","createEvent","initEvent","dispatchEvent","state","eh","dragGesture","dragMaxTouches","triggered","dragMinDistance","startCenter","dragDistanceCorrection","dragLockToAxis","dragLockMinDistance","lastDirection","dragBlockVertical","dragBlockHorizontal","Drag","Gesture","holdGesture","holdTimeout","holdThreshold","Hold","Release","Swipe","swipeMinTouches","swipeMaxTouches","swipeVelocityX","swipeVelocityY","tapGesture","sincePrev","didDoubleTap","hasMoved","tapMaxDistance","tapMaxTime","doubleTapInterval","doubleTapDistance","tapAlways","Tap","Touch","preventMouse","transformGesture","scaleThreshold","rotationThreshold","transformMinScale","transformMinRotation","Transform","clusterToFit","maxNumberOfNodes","reposition","maxLevels","forceAggregateHubs","normalizeClusterLevels","increaseClusterLevel","repositionNodes","openCluster","isMovingBeforeClustering","_nodeInActiveArea","_sector","_addSector","decreaseClusterLevel","_expandClusterNode","_updateDynamicEdges","updateClusters","zoomDirection","recursive","doNotStart","amountOfNodes","_collapseSector","_formClusters","_openClusters","_openClustersBySize","_aggregateHubs","handleChains","chainPercentage","_getChainFraction","_reduceAmountOfChains","_getHubSize","_formClustersByHub","openAll","containedNodeId","childNode","_expelChildFromParent","_unselectAll","_releaseContainedEdges","_connectEdgeBackToChild","_validateEdges","othersPresent","childNodeId","_repositionBezierNodes","_formClustersByZoom","_forceClustersByZoom","minLength","_addToCluster","_clusterToSmallestNeighbour","smallestNeighbour","smallestNeighbourNode","neighbour","onlyEqual","_formClusterFromHub","hubNode","absorptionSizeOffset","allowCluster","edgesIdarray","amountOfInitialEdges","_addToContainedEdges","_connectEdgeToCluster","_containCircularEdgesFromNode","massBefore","correction","edgeToId","edgeFromId","k","_addToReroutedEdges","maxLevel","minLevel","clusterLevel","targetLevel","average","averageSquared","hubCounter","largestHub","variance","standardDeviation","fraction","reduceAmount","chains","total","_switchToSector","sectorId","sectorType","_switchToActiveSector","_switchToFrozenSector","_switchToSupportSector","_loadLatestSector","_previousSector","_setActiveSector","newId","_forgetLastSector","_createNewSector","_deleteActiveSector","_deleteFrozenSector","_freezeSector","_activateSector","_mergeThisWithFrozen","_collapseThisToSingleCluster","sector","unqiueIdentifier","previousSector","runFunction","argument","returnValues","_doInAllFrozenSectors","_drawSectorNodes","_drawAllSectorNodes","_getNodesOverlappingWith","_getAllNodesOverlappingWith","_pointerToPositionObject","positionObject","_getEdgesOverlappingWith","_getAllEdgesOverlappingWith","_addToSelection","_addToHover","_removeFromSelection","doNotTrigger","_unselectClusters","_getSelectedNodeCount","_getSelectedNode","_getSelectedEdge","_getSelectedEdgeCount","_getSelectedObjectCount","_selectionIsEmpty","_clusterInSelection","_selectConnectedEdges","_hoverConnectedEdges","_unselectConnectedEdges","append","highlightEdges","overrideSelectable","DOM","_manipulationReleaseOverload","_navigationReleaseOverload","getSelectedNodes","edgeIds","getSelectedEdges","idArray","selectNodes","RangeError","selectEdges","_clearManipulatorBar","manipulationDOM","_restoreOverloadedFunctions","functionName","_toggleEditMode","toolbar","boundFunction","edgeBeingEdited","selectedControlNode","_createAddNodeToolbar","_createAddEdgeToolbar","_editNode","_createEditEdgeToolbar","_addNode","_handleConnect","_finishConnect","_selectControlNode","_controlNodeDrag","_releaseControlNode","newNode","_editEdge","alert","supportNodes","targetNode","connectionEdge","connectFromId","_createEdge","defaultData","finalizedData","sourceNodeId","targetNodeId","selectedNodes","selectedEdges","navigationDivs","navigationDivActions","_stopMovement","_zoomExtent","hubsize","definedLevel","undefinedLevel","_changeConstants","_determineLevels","_determineLevelsDirected","distribution","_getDistribution","_placeNodesByHierarchy","minPos","_placeBranchNodes","maxCount","_setLevel","firstNode","_setLevelDirected","parentId","parentLevel","nodeMoved","_restoreNodes","graphToggleSmoothCurves","graph_toggleSmooth","getElementById","graphRepositionNodes","showValueOfRange","graphGenerateOptions","optionsSpecific","radioButton1","radioButton2","checked","backupConstants","optionsDiv","switchConfigurations","radioButton","querySelector","tableId","table","constantsVariableName","valueId","rangeValue","_overWriteGraphConstants","RepulsionMixin","HierarchialRepulsionMixin","BarnesHutMixin","_toggleBarnesHut","barnesHutTree","_initializeForceCalculation","_calculateForces","_calculateGravitationalForces","_calculateNodeForces","_calculateSpringForcesWithSupport","_calculateHierarchicalSpringForces","_calculateSpringForces","supportNodeId","gravity","gravityForce","edgeLength","springForce","combinedClusterSize","node1","node2","node3","_calculateSpringForce","physicsConfiguration","hierarchicalLayoutDirections","parentElement","rangeElement","radioButton3","graph_repositionNodes","graph_generateOptions","dynamicSmoothCurves","nameArray","webpackContext","req","resolve","repulsingForce","a_base","minimumDistance","steepness","springFx","springFy","totalFx","totalFy","correctionFx","correctionFy","nodeCount","_formBarnesHutTree","_getForceContribution","children","NW","NE","SW","SE","parentBranch","childrenCount","centerOfMass","calcSize","MAX_VALUE","sizeDiff","minimumTreeSize","rootSize","halfRootSize","_splitBranch","_placeInTree","_updateBranchMass","totalMass","totalMassInv","biggestSize","skipMassUpdate","_placeInRegion","region","containedNode","_insertRegion","childSize","_drawTree","_drawBranch","branch","webpackPolyfill","paths"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"vis.map","sources":["./dist/vis.js"],"names":["root","factory","exports","module","define","amd","this","modules","__webpack_require__","moduleId","installedModules","id","loaded","call","m","c","p","util","DOMutil","DataSet","DataView","Queue","Graph3d","graph3d","Camera","Filter","Point2d","Point3d","Slider","StepNumber","Timeline","Graph2d","timeline","DateUtil","DataStep","Range","stack","TimeStep","components","items","Item","BackgroundItem","BoxItem","PointItem","RangeItem","Component","CurrentTime","CustomTime","DataAxis","GraphGroup","Group","BackgroundGroup","ItemSet","Legend","LineGraph","TimeAxis","Network","network","Edge","Groups","Images","Node","Popup","dotparser","gephiParser","Graph","Error","moment","hammer","isNumber","object","Number","isString","String","isDate","Date","match","ASPDateRegex","exec","isNaN","parse","isDataTable","google","visualization","DataTable","randomUUID","S4","Math","floor","random","toString","extend","a","i","len","arguments","length","other","prop","hasOwnProperty","selectiveExtend","props","Array","isArray","selectiveDeepExtend","b","TypeError","constructor","Object","undefined","deepExtend","selectiveNotDeepExtend","indexOf","equalArray","convert","type","Boolean","valueOf","isMoment","toDate","getType","toISOString","value","getAbsoluteLeft","elem","getBoundingClientRect","left","window","pageXOffset","getAbsoluteTop","top","pageYOffset","addClassName","className","classes","split","push","join","removeClassName","index","splice","forEach","callback","toArray","array","updateProperty","key","addEventListener","element","action","listener","useCapture","navigator","userAgent","attachEvent","removeEventListener","detachEvent","preventDefault","event","returnValue","getTarget","target","srcElement","nodeType","parentNode","option","asBoolean","defaultValue","asNumber","asString","asSize","asElement","hexToRGB","hex","shorthandRegex","replace","r","g","result","parseInt","RGBToHex","red","green","blue","slice","parseColor","color","isValidRGB","rgb","substr","isValidHex","hsv","hexToHSV","lighterColorHSV","h","s","v","min","darkerColorHSV","darkerColorHex","HSVToHex","lighterColorHex","background","border","highlight","hover","RGBToHSV","minRGB","maxRGB","max","d","hue","saturation","cssUtil","cssText","styles","style","trim","parts","keys","map","addCssText","currentStyles","newStyles","removeCssText","removeStyles","HSVToRGB","f","q","t","isOk","test","selectiveBridgeObject","fields","referenceObject","objectTo","create","bridgeObject","mergeOptions","mergeTarget","options","enabled","binarySearchCustom","orderedItems","searchFunction","field","field2","maxIterations","iteration","low","high","middle","item","searchResult","binarySearchValue","sidePreference","prevValue","nextValue","easeInOutQuad","start","end","duration","change","easingFunctions","linear","easeInQuad","easeOutQuad","easeInCubic","easeOutCubic","easeInOutCubic","easeInQuart","easeOutQuart","easeInOutQuart","easeInQuint","easeOutQuint","easeInOutQuint","prepareElements","JSONcontainer","elementType","redundant","used","cleanupElements","removeChild","getSVGElement","svgContainer","shift","document","createElementNS","appendChild","getDOMElement","DOMContainer","insertBefore","createElement","drawPoint","x","y","group","point","drawPoints","setAttributeNS","size","drawBar","width","height","rect","data","_options","_data","_fieldId","fieldId","_type","_subscribers","add","setOptions","prototype","queue","_queue","destroy","on","subscribers","subscribe","off","filter","unsubscribe","_trigger","params","senderId","concat","subscriber","addedIds","me","_addItem","columns","_getColumnNames","row","rows","getNumberOfRows","col","cols","getValue","update","updatedIds","updatedData","addOrUpdate","_updateItem","get","ids","firstType","returnType","allowedValues","itemId","_getItem","order","_sort","_filterFields","_appendRow","getIds","getDataSet","mappedItems","filteredItem","name","sort","av","bv","remove","removedId","removedIds","_remove","clear","maxField","itemField","minField","distinct","values","fieldType","count","exists","types","raw","converted","JSON","stringify","dataTable","getNumberOfColumns","getColumnId","getColumnLabel","addRow","setValue","_ids","_onEvent","apply","setData","viewOptions","getArguments","defaultFilter","dataSet","added","updated","removed","delay","Infinity","_timeout","_extended","_flushIfNeeded","flush","methods","original","method","args","fn","context","entry","clearTimeout","setTimeout","container","SyntaxError","containerElement","margin","defaultXCenter","defaultYCenter","xLabel","yLabel","zLabel","passValueFn","xValueLabel","yValueLabel","zValueLabel","filterLabel","legendLabel","STYLE","DOT","showPerspective","showGrid","keepAspectRatio","showShadow","showGrayBottom","showTooltip","verticalRatio","animationInterval","animationPreload","camera","eye","dataPoints","colX","colY","colZ","colValue","colFilter","xMin","xStep","xMax","yMin","yStep","yMax","zMin","zStep","zMax","valueMin","valueMax","xBarWidth","yBarWidth","colorAxis","colorGrid","colorDot","colorDotBorder","getMouseX","clientX","targetTouches","getMouseY","clientY","Emitter","_setScale","scale","z","xCenter","yCenter","zCenter","setArmLocation","_convert3Dto2D","point3d","translation","_convertPointToTranslation","_convertTranslationToScreen","ax","ay","az","cx","getCameraLocation","cy","cz","sinTx","sin","getCameraRotation","cosTx","cos","sinTy","cosTy","sinTz","cosTz","dx","dy","dz","bx","by","ex","ey","ez","getArmLength","xcenter","frame","canvas","clientWidth","ycenter","_setBackgroundColor","backgroundColor","fill","stroke","strokeWidth","borderColor","borderWidth","borderStyle","BAR","BARCOLOR","BARSIZE","DOTLINE","DOTCOLOR","DOTSIZE","GRID","LINE","SURFACE","_getStyleNumber","styleName","_determineColumnIndexes","counter","column","getDistinctValues","distinctValues","getColumnRange","minMax","_dataInitialize","rawData","_onChange","dataFilter","setOnLoadCallback","redraw","withBars","defaultXBarWidth","dataX","defaultYBarWidth","dataY","xRange","defaultXMin","defaultXMax","defaultXStep","yRange","defaultYMin","defaultYMax","defaultYStep","zRange","defaultZMin","defaultZMax","defaultZStep","valueRange","defaultValueMin","defaultValueMax","_getDataPoints","obj","sortNumber","dataMatrix","xIndex","yIndex","trans","screen","bottom","pointRight","pointTop","pointCross","hasChildNodes","firstChild","position","overflow","noCanvas","fontWeight","padding","innerHTML","onmousedown","_onMouseDown","ontouchstart","_onTouchStart","onmousewheel","_onWheel","ontooltip","_onTooltip","onkeydown","setSize","_resizeCanvas","clientHeight","animationStart","slider","play","animationStop","stop","_resizeCenter","charAt","parseFloat","setCameraPosition","pos","horizontal","vertical","setArmRotation","distance","setArmLength","getCameraPosition","getArmRotation","_readData","_redrawFilter","animationAutoStart","cameraPosition","styleNumber","tooltip","showAnimationControls","_redrawSlider","_redrawClear","_redrawAxis","_redrawDataGrid","_redrawDataLine","_redrawDataBar","_redrawDataDot","_redrawInfo","_redrawLegend","ctx","getContext","clearRect","widthMin","widthMax","dotSize","right","lineWidth","font","ymin","ymax","_hsv2rgb","strokeStyle","beginPath","moveTo","lineTo","strokeRect","fillStyle","closePath","gridLineLen","step","getCurrent","next","textAlign","textBaseline","fillText","label","visible","setValues","setPlayInterval","onchange","getIndex","selectValue","setOnChangeCallback","lineStyle","getLabel","getSelectedValue","from","to","prettyStep","text","xText","yText","zText","offset","xOffset","yOffset","xMin2d","xMax2d","gridLenX","gridLenY","textMargin","armAngle","H","S","V","R","G","B","C","Hi","X","abs","cross","topSideVisible","zAvg","transBottom","dist","sortDepth","aDiff","subtract","bDiff","crossproduct","crossProduct","radius","arc","PI","j","surface","corners","xWidth","yWidth","surfaces","center","avg","transCenter","diff","leftButtonDown","_onMouseUp","which","button","touchDown","startMouseX","startMouseY","startStart","startEnd","startArmRotation","cursor","onmousemove","_onMouseMove","onmouseup","diffX","diffY","horizontalNew","verticalNew","snapAngle","snapValue","round","parameters","emit","boundingRect","mouseX","mouseY","tooltipTimeout","_hideTooltip","dataPoint","_dataPointFromXY","_showTooltip","ontouchmove","_onTouchMove","ontouchend","_onTouchEnd","delta","wheelDelta","detail","oldLength","newLength","_insideTriangle","triangle","sign","as","bs","cs","distMax","closestDataPoint","closestDist","triangle1","triangle2","distX","distY","sqrt","content","line","dot","dom","borderRadius","boxShadow","borderLeft","contentWidth","offsetWidth","contentHeight","offsetHeight","lineHeight","dotWidth","dotHeight","armLocation","armRotation","armLength","cameraLocation","cameraRotation","calculateCameraOrientation","rot","graph","onLoadCallback","loadInBackground","isLoaded","getLoadedProgress","getColumn","getValues","dataView","progress","sub","sum","prev","bar","MozBorderRadius","slide","onclick","togglePlay","onChangeCallback","playTimeout","playInterval","playLoop","setIndex","playNext","interval","clearInterval","getPlayInterval","setPlayLoop","doLoop","onChange","indexToLeft","startClientX","startSlideX","leftToIndex","_start","_end","_step","precision","_current","setRange","setStep","calculatePrettyStep","log10","log","LN10","step1","pow","step2","step5","toPrecision","getStep","groups","forthArgument","defaultOptions","autoResize","orientation","maxHeight","minHeight","_create","body","domProps","emitter","bind","hiddenDates","snap","toScreen","_toScreen","toGlobalScreen","_toGlobalScreen","toTime","_toTime","toGlobalTime","_toGlobalTime","range","timeAxis","currentTime","customTime","itemSet","itemsData","groupsData","setGroups","setItems","Core","newDataSet","initialLoad","dataRange","_getDataRange","setWindow","animate","fit","setSelection","focus","getSelection","itemData","e","getItemRange","dataset","minItem","maxStartItem","maxEndItem","linegraph","getLegend","groupId","isGroupVisible","visibility","convertHiddenOptions","repeat","dateItem","updateHiddenDates","centerContainer","totalRange","pixelTime","startDate","endDate","_d","runUntil","clone","day","dayOfYear","year","dayOffset","date","month","console","removeDuplicates","startHidden","isHidden","endHidden","rangeStart","rangeEnd","hidden","startToFront","endToFront","_applyRange","safeDates","printDates","dates","stepOverHiddenDates","timeStep","previousTime","stepInHidden","currentValue","current","newValue","switchedYear","switchedMonth","switchedDay","time","conversion","getHiddenDurationBetween","correctTimeForHidden","hiddenDuration","totalDuration","partialDuration","accumulatedHiddenDuration","getAccumulatedHiddenDuration","newTime","getHiddenDurationBefore","timeOffset","requiredDuration","previousPoint","snapAwayFromHidden","direction","correctionEnabled","minimumStep","containerHeight","customRange","alignZeros","autoScale","stepIndex","marginStart","marginEnd","deadSpace","majorSteps","minorSteps","setMinimumStep","setFirst","safeSize","minimumStepValue","orderOfMagnitude","minorStepIdx","magnitudefactor","solutionFound","stepSize","niceStart","niceEnd","roundToMinor","marginRange","rounded","hasNext","previous","decimals","exp","cnt","isMajor","now","hours","minutes","seconds","milliseconds","deltaDifference","scaleOffset","moveable","zoomable","zoomMin","zoomMax","touch","animateTimer","_onDragStart","_onDrag","_onDragEnd","_onHold","_onMouseWheel","_onTouch","_onPinch","validateDirection","getPointer","pageX","pageY","hammerUtil","byUser","_cancelAnimation","initStart","initEnd","initTime","anyChanged","dragging","done","changed","newStart","newEnd","getRange","totalHidden","previousDelta","allowDragging","gesture","deltaX","deltaY","diffRange","safeStart","safeEnd","fakeGesture","pointer","pointerDate","_pointerToDate","zoom","touches","centerDate","hiddenDurationBefore","hiddenDurationAfter","move","EPSILON","orderByStart","orderByEnd","aTime","bTime","force","iMax","axis","collidingItem","jj","collision","nostack","subgroups","newTop","subgroup","format","FORMAT","minorLabels","millisecond","second","minute","hour","weekday","majorLabels","setFormat","defaultFormat","first","setFullYear","getFullYear","setMonth","setDate","setHours","setMinutes","setSeconds","setMilliseconds","getMilliseconds","getSeconds","getMinutes","getHours","getDate","getMonth","setScale","newScale","newStep","setAutoScale","enable","stepYear","stepMonth","stepDay","stepHour","stepMinute","stepSecond","stepMillisecond","getLabelMinor","getLabelMajor","getClassName","even","today","isSame","currentWeek","currentMonth","currentYear","locale","lang","toLowerCase","_isResized","resized","_previousWidth","_previousHeight","showCurrentTime","locales","parent","backgroundVertical","title","toUpperCase","substring","currentTimeTimer","setCurrentTime","getCurrentTime","showCustomTime","eventParams","Hammer","drag","prevent_default","setCustomTime","getCustomTime","stopPropagation","svg","linegraphOptions","showMinorLabels","showMajorLabels","icons","majorLinesOffset","minorLinesOffset","labelOffsetX","labelOffsetY","iconWidth","linegraphSVG","DOMelements","lines","labels","conversionFactor","minWidth","stepPixels","stepPixelsForced","zeroCrossing","lineOffset","master","svgElements","iconsRemoved","amountOfGroups","lineContainer","scrollTop","addGroup","graphOptions","updateGroup","removeGroup","hide","show","display","_redrawGroupIcons","iconHeight","iconOffset","drawIcon","_cleanupIcons","backgroundHorizontal","activeGroups","_calculateCharSize","minorLabelHeight","minorCharHeight","majorLabelHeight","majorCharHeight","minorLineWidth","minorLineHeight","majorLineWidth","majorLineHeight","_redrawLabels","_redrawTitle","amountOfSteps","stepDifference","zeroStepDifference","valueAtZero","marginStartPos","maxLabelSize","_redrawLabel","_redrawLine","titleWidth","titleCharHeight","convertValue","invertedValue","convertedValue","characterHeight","largestWidth","majorCharWidth","minorCharWidth","textMinor","createTextNode","measureCharMinor","textMajor","measureCharMajor","textTitle","measureCharTitle","titleCharWidth","groupsUsingDefaultStyles","usingDefaultStyle","zeroPosition","Line","Bar","Points","setZeroPosition","catmullRom","parametrization","alpha","SVGcontainer","path","fillPath","fillHeight","outline","shaded","barWidth","bar1Height","bar2Height","icon","yAxisOrientation","getYRange","groupData","draw","framework","subgroupIndex","subgroupOrderer","subgroupOrder","visibleItems","byStart","byEnd","checkRangedItems","inner","foreground","marker","Element","getLabelWidth","restack","_updateVisibleItems","markerHeight","lastMarkerHeight","dirty","displayed","_calculateHeight","offsetTop","offsetLeft","ii","repositionY","resetSubgroups","labelSet","setParent","orderSubgroups","_checkIfVisible","sortArray","sortField","removeFromDataSet","removeItem","startArray","endArray","oldVisibleItems","visibleItemsLookup","lowerBound","upperBound","_checkIfVisibleWithReference","initialPosByStart","_traceVisible","initialPosByEnd","repositionX","initialPos","breakCondition","isVisible","align","groupOrder","selectable","editable","updateTime","onAdd","onUpdate","onMove","onRemove","onMoving","itemOptions","itemListeners","_onAdd","_onUpdate","_onRemove","groupListeners","_onAddGroups","_onUpdateGroups","_onRemoveGroups","groupIds","selection","stackDirty","touchParams","UNGROUPED","BACKGROUND","box","_updateUngrouped","backgroundGroup","_onSelectItem","_onMultiSelectItem","_onAddItem","addCallback","Function","markDirty","unselect","select","getVisibleItems","rawVisibleItems","_deselect","_orderGroups","visibleInterval","zoomed","lastVisibleInterval","lastWidth","firstGroup","_firstGroup","firstMargin","nonFirstMargin","groupMargin","groupResized","firstGroupIndex","firstGroupId","ungrouped","_getGroupId","getLabelSet","oldItemsData","getItems","_order","getGroups","_getType","_removeItem","groupOptions","oldGroupId","oldGroup","_constructByEndArray","itemFromTarget","selected","dragLeftItem","dragRightItem","initialX","itemProps","newProps","initial","groupFromTarget","_updateItemProps","_moveToGroup","changes","ctrlKey","srcEvent","shiftKey","oldSelection","newSelection","xAbs","newItem","_getItemRange","_item","itemSetFromTarget","side","iconSize","iconSpacing","textArea","scrollableHeight","drawLegendIcons","getComputedStyle","paddingTop","defaultGroup","sampling","graphHeight","barChart","handleOverlap","dataAxis","legend","abortedGraphUpdate","updateSVGheight","updateSVGheightOnResize","lastStart","COUNTER","BarGraphFunctions","yAxisLeft","yAxisRight","legendLeft","legendRight","_updateAllGroupData","_updateGroup","groupsContent","ungroupedCounter","forceGraphUpdate","_updateGraph","rangePerPixelInv","preprocessedGroupData","processedGroupData","groupRanges","changeCalled","minDate","maxDate","_getRelevantData","_applySampling","_convertXcoordinates","_getYRanges","_updateYAxis","MAX_CYCLES","_convertYcoordinates","dataContainer","guess","increment","amountOfPoints","xDistance","pointsPerPixel","ceil","sampledData","barCombinedDataLeft","barCombinedDataRight","getStackedBarYRange","minVal","maxVal","yAxisLeftUsed","yAxisRightUsed","minLeft","minRight","maxLeft","maxRight","ignore","_toggleAxisVisiblity","drawIcons","axisUsed","datapoints","xValue","yValue","extractedData","svgHeight","majorTexts","minorTexts","lineTop","parentChanged","foregroundNextSibling","nextSibling","backgroundNextSibling","_repaintLabels","timeLabelsize","cur","prevLine","xPrev","xFirstMajorLabel","_repaintMinorText","_repaintMajorText","_repaintMajorLine","_repaintMinorLine","leftTime","leftText","widthText","arr","pop","childNodes","nodeValue","_repaintDeleteButton","anchor","deleteButton","_updateContents","template","_updateTitle","removeAttribute","_updateDataAttributes","dataAttributes","attributes","setAttribute","_updateStyle","emptyContent","baseClassName","onTop","itemSubgroup","itemSetHeight","marginLeft","maxWidth","_repaintDragLeft","_repaintDragRight","contentLeft","parentWidth","boxWidth","dragLeft","dragRight","_determineBrowserMethod","_initializeMixinLoaders","renderRefreshRate","renderTimestep","renderTime","physicsTime","runDoubleSpeed","physicsDiscreteStepsize","initializing","triggerFunctions","edit","editEdge","connect","del","nodes","mass","radiusMin","radiusMax","shape","image","fontColor","fontSize","fontFace","fontFill","fontStrokeWidth","fontStrokeColor","level","borderWidthSelected","edges","widthSelectionMultiplier","hoverWidth","labelAlignment","arrowScaleFactor","dash","gap","altLength","inheritColor","configurePhysics","physics","barnesHut","thetaInverted","gravitationalConstant","centralGravity","springLength","springConstant","damping","repulsion","nodeDistance","hierarchicalRepulsion","clustering","initialMaxNodes","clusterThreshold","reduceToNodes","chainThreshold","clusterEdgeThreshold","sectorThreshold","screenSizeThreshold","fontSizeMultiplier","maxFontSize","forceAmplification","distanceAmplification","edgeGrowth","nodeScaling","maxNodeSizeIncrements","activeAreaBoxSize","clusterLevelDifference","navigation","keyboard","speed","dataManipulation","initiallyVisible","hierarchicalLayout","levelSeparation","nodeSpacing","layout","freezeForStabilization","smoothCurves","dynamic","roundness","maxVelocity","minVelocity","stabilize","stabilizationIterations","zoomExtentOnStabilize","dragNetwork","dragNodes","hideEdgesOnDrag","hideNodesOnDrag","constants","pixelRatio","hoverObj","controlNodesActive","navigationHammers","existing","_new","animationSpeed","animationEasingFunction","easingTime","sourceScale","targetScale","sourceTranslation","targetTranslation","lockedOnNodeId","lockedOnNodeOffset","touchTime","images","setOnloadCallback","_redraw","xIncrement","yIncrement","zoomIncrement","_loadPhysicsSystem","_loadSectorSystem","_loadClusterSystem","_loadSelectionSystem","_loadHierarchySystem","_setTranslation","freezeSimulation","cachedFunctions","startedStabilization","stabilized","draggingNodes","calculationNodes","calculationNodeIndices","nodeIndices","canvasTopLeft","canvasBottomRight","pointerPosition","areaCenter","previousScale","nodesData","edgesData","nodesListeners","_addNodes","_updateNodes","_removeNodes","edgesListeners","_addEdges","_updateEdges","_removeEdges","moving","timer","_setupHierarchicalLayout","zoomExtent","startWithClustering","keycharm","MixinLoader","Activator","browserType","requiresTimeout","_getScriptPath","scripts","getElementsByTagName","src","_getRange","node","minY","maxY","minX","maxX","nodeId","boundingBox","_findCenter","animationOptions","initialZoom","disableStart","zoomLevel","numberOfNodes","factor","yDistance","xZoomLevel","yZoomLevel","animation","_updateNodeIndexList","_clearNodeIndexList","idx","_createManipulatorBar","dotData","DOTToGraph","gephi","gephiData","parseGephi","_setNodes","_setEdges","_putDataInSector","_resetLevels","_stabilize","onEdit","onEditEdge","onConnect","onDelete","editMode","newColorObj","groupname","clickToUse","activator","_createKeyBinds","_loadNavigationControls","_loadManipulationSystem","_configureSmoothCurves","devicePixelRatio","webkitBackingStorePixelRatio","mozBackingStorePixelRatio","msBackingStorePixelRatio","oBackingStorePixelRatio","backingStorePixelRatio","setTransform","pinch","_onTap","_onDoubleTap","_onMouseMoveTitle","hammerFrame","_onRelease","reset","isActive","_moveUp","_yStopMoving","_moveDown","_moveLeft","_xStopMoving","_moveRight","_zoomIn","_stopZoom","_zoomOut","_deleteSelected","_cleanupPhysicsConfiguration","dispose","_recursiveDOMDelete","DOMobject","_getPointer","pinched","_getScale","_handleTouch","_handleDragStart","_getNodeAt","_getTranslation","isSelected","_selectObject","nodeIds","objectId","selectionObj","xFixed","yFixed","_handleOnDrag","releaseNode","_XconvertDOMtoCanvas","_XconvertCanvasToDOM","_YconvertDOMtoCanvas","_YconvertCanvasToDOM","_handleDragEnd","_handleTap","_handleDoubleTap","_handleOnHold","_handleOnRelease","_zoom","scaleOld","preScaleDragPointer","DOMtoCanvas","scaleFrac","tx","ty","updateClustersDefault","postScaleDragPointer","canvasToDOM","popupObj","_checkHidePopup","checkShow","_checkShowPopup","popupTimer","edgeId","_getEdgeAt","_hoverObject","_blurObject","lastPopupNode","nodeUnderCursor","overlappingNodes","isOverlappingWith","getTitle","overlappingEdges","edge","connected","popup","setPosition","setText","emitEvent","oldWidth","oldHeight","oldNodesData","_updateSelection","angle","_updateCalculationNodes","_reconnectEdges","_updateValueRange","updateLabels","changedData","setProperties","properties","oldEdgesData","oldEdge","disconnect","showInternalIds","_createBezierNodes","via","sectors","dynamicEdges","setValueRange","w","save","translate","_doInAllSectors","restore","offsetX","offsetY","_drawNodes","alwaysShow","setScaleAndPos","inArea","sMax","_drawEdges","_drawControlNodes","_freezeDefinedNodes","_physicsTick","_restoreFrozenNodes","fixedData","_isMoving","vmin","isMoving","_discreteStepNodes","nodesPresent","discreteStepLimited","discreteStep","vminCorrected","_revertPhysicsState","revertPosition","_revertPhysicsTick","_doInAllActiveSectors","_doInSupportSector","mainMovingStatus","supportMovingStatus","mainMoving","_animationStep","_handleNavigation","startTime","renderStartTime","requestAnimationFrame","mozRequestAnimationFrame","webkitRequestAnimationFrame","msRequestAnimationFrame","iterations","toggleFreeze","parentEdgeId","internalMultiplier","positionBezierNode","mixin","storePosition","storePositions","dataArray","allowedToMoveX","allowedToMoveY","getPositions","focusOnNode","nodePosition","lockedOnNode","easingFunction","animateView","locked","_transitionRedraw","viewCenter","distanceFromCenter","_classicRedraw","_lockedRedraw","active","getScale","getCenterCoordinates","getBoundingBox","networkConstants","fromId","toId","widthSelected","labelDimensions","yLine","dirtyLabel","fromBackup","toBackup","originalFromId","originalToId","widthFixed","lengthFixed","controlNodesEnabled","controlNodes","positions","connectedNode","_drawLine","_drawArrow","_drawArrowCenter","_drawDashLine","attachEdge","detachEdge","xFrom","yFrom","xTo","yTo","xObj","yObj","_getDistanceToEdge","_getColor","colorObj","_getLineWidth","_line","midpointX","midpointY","_pointOnLine","_label","resize","_circle","_pointOnCircle","networkScaleInv","_getViaCoordinates","xVia","yVia","quadraticCurveTo","lineCount","measureText","_rotateForLabelAlignment","_drawLabelRect","_drawLabelText","angleInDegrees","atan2","rotate","lineMargin","fillRect","lineJoin","strokeText","setLineDash","pattern","lineDashOffset","lineCap","dashedLine","percentage","arrow","_pointOnBezier","_findBorderPosition","distanceToBorder","distanceToNodes","difference","threshold","arrowPos","guidePos","edgeSegmentLength","toBorderDist","toBorderPoint","x1","y1","x2","y2","x3","y3","lastX","lastY","minDistance","_getDistanceToLine","px","py","something","u","nodeIdFrom","nodeIdTo","getControlNodeFromPosition","getControlNodeToPosition","_enableControlNodes","_disableControlNodes","_getSelectedControlNode","fromDistance","toDistance","_restoreControlNodes","controlnodeFromPos","fromBorderDist","fromBorderPoint","controlnodeToPos","defaultIndex","DEFAULT","imageBroken","load","url","brokenUrl","img","Image","onload","onerror","error","imagelist","grouplist","reroutedEdges","fontDrawThreshold","horizontalAlignLeft","verticalAlignTop","baseRadiusValue","radiusFixed","preassignedLevel","hierarchyEnumerated","fx","fy","vx","vy","previousState","resetCluster","dynamicEdgesLength","clusterSession","clusterSizeWidthFactor","clusterSizeHeightFactor","clusterSizeRadiusFactor","growthIndicator","networkScale","formationScale","clusterSize","containedNodes","containedEdges","clusterSessions","originalLabel","triggerFunction","groupObj","imageObj","brokenImage","_drawDatabase","_resizeDatabase","_drawBox","_resizeBox","_drawCircle","_resizeCircle","_drawEllipse","_resizeEllipse","_drawImage","_resizeImage","_drawCircularImage","_resizeCircularImage","_drawText","_resizeText","_drawDot","_resizeShape","_drawSquare","_drawTriangle","_drawTriangleDown","_drawStar","_reset","clearSizeCache","_setForce","_addForce","storeState","isFixed","velocity","getDistance","_drawImageAtPosition","globalAlpha","drawImage","_drawImageLabel","getTextSize","_swapToImageResizeWhenImageLoaded","diameter","centerX","centerY","_drawRawCircle","circle","clip","textSize","clusterLineWidth","selectionLineWidth","roundRect","database","defaultSize","ellipse","_drawShape","radiusMultiplier","baseline","labelUnderNode","inView","clearVelocity","updateVelocity","massBeforeClustering","energyBefore","styleAttr","fontFamily","WebkitBorderRadius","whiteSpace","parseDOT","parseGraph","nextPreview","isAlphaNumeric","regexAlphaNumeric","merge","o","addNode","graphs","attr","addEdge","createEdge","getToken","tokenType","TOKENTYPE","NULL","token","isComment","DELIMITER","c2","DELIMITERS","IDENTIFIER","newSyntaxError","UNKNOWN","chop","strict","parseStatements","parseStatement","subgraph","parseSubgraph","parseEdge","parseAttributeStatement","parseNodeStatement","subgraphs","parseAttributeList","message","maxLength","forEach2","array1","array2","elem1","elem2","graphData","dotNode","graphNode","convertEdge","dotEdge","graphEdge","subEdge","{","}","[","]",";","=",",","->","--","gephiJSON","allowedToMove","gEdges","gNodes","gEdge","source","gNode","leftContainer","rightContainer","shadowTop","shadowBottom","shadowTopLeft","shadowBottomLeft","shadowTopRight","shadowBottomRight","_redrawTimer","listeners","events","scrollTopMin","redrawCount","_initAutoResize","component","_stopAutoResize","what","getWindow","borderRootHeight","borderRootWidth","autoHeight","centerWidth","_updateScrollTop","visibilityTop","visibilityBottom","MAX_REDRAWS","repaint","_startAutoResize","_onResize","lastHeight","watchTimer","setInterval","initialScrollTop","oldScrollTop","_getScrollTop","newScrollTop","_setScrollTop","eventType","getTouchList","collectEventData","custom","back","editNode","addDescription","edgeDescription","editEdgeDescription","createEdgeError","deleteClusterError","CanvasRenderingContext2D","square","s2","ir","triangleDown","star","n","r2d","kappa","ox","oy","xe","ye","xm","ym","bezierCurveTo","wEllipse","hEllipse","ymb","yeb","xt","yt","xi","yi","xl","yl","xr","yr","dashArray","dashLength","dashCount","slope","distRemaining","dashIndex","_catmullRom","_linear","dFill","_catmullRomUniform","p0","p1","p2","p3","bp1","bp2","normalization","d1","d2","d3","A","N","M","d3powA","d2powA","d3pow2A","d2pow2A","d1pow2A","d1powA","Bargraph","barCombinedData","coreDistance","drawData","combinedData","intersections","barPoints","_getDataIntersections","heightOffset","_getSafeDrawData","nextKey","amount","resolved","prevKey","accumulated","groupLabel","_getStackedBarYRange","xpos","PhysicsMixin","ClusterMixin","SectorsMixin","SelectionMixin","ManipulationMixin","NavigationMixin","HierarchicalLayoutMixin","_loadMixin","sourceVariable","mixinFunction","_clearMixin","_loadSelectedForceSolver","_loadPhysicsConfiguration","hubThreshold","activeSector","drawingNode","blockConnectingEdgeSelection","forceAppendSelection","manipulationDiv","editModeDiv","closeDiv","_cleanNavigation","_loadNavigationElements","overlay","_onTapOverlay","windowHammer","_hasParent","deactivate","escListener","activate","unbind","_callbacks","once","self","removeListener","removeAllListeners","callbacks","cb","hasListeners","__WEBPACK_AMD_DEFINE_FACTORY__","__WEBPACK_AMD_DEFINE_ARRAY__","__WEBPACK_AMD_DEFINE_RESULT__","_exportFunctions","_bound","keydown","keyup","_keys","fromCharCode","code","down","handleEvent","up","keyCode","bound","bindAll","getKey","newBindings","global","dfl","hasOwnProp","defaultParsingFlags","empty","unusedTokens","unusedInput","charsLeftOver","nullInput","invalidMonth","invalidFormat","userInvalidated","iso","printMsg","msg","suppressDeprecationWarnings","warn","deprecate","firstTime","deprecateSimple","deprecations","padToken","func","leftZeroFill","ordinalizeToken","period","localeData","ordinal","monthDiff","anchor2","adjust","wholeMonthDiff","meridiemFixWrap","meridiem","isPm","meridiemHour","isPM","Locale","Moment","config","skipOverflow","checkOverflow","copyConfig","updateInProgress","updateOffset","Duration","normalizedInput","normalizeObjectUnits","years","quarters","quarter","months","weeks","week","days","_milliseconds","_days","_months","_locale","_bubble","val","_isAMomentObject","_i","_f","_l","_strict","_tzm","_isUTC","_offset","_pf","momentProperties","absRound","number","targetLength","forceSign","output","positiveMomentsDifference","base","res","isAfter","momentsDifference","makeAs","isBefore","createAdder","dur","tmp","addOrSubtractDurationFromMoment","mom","isAdding","setTime","rawSetter","rawGetter","rawMonthSetter","input","compareArrays","dontConvert","lengthDiff","diffs","toInt","normalizeUnits","units","lowered","unitAliases","camelFunctions","inputObject","normalizedProp","makeList","setter","getter","results","utc","set","argumentForCoercion","coercedNumber","isFinite","daysInMonth","UTC","getUTCDate","weeksInYear","dow","doy","weekOfYear","daysInYear","isLeapYear","_a","MONTH","DATE","YEAR","HOUR","MINUTE","SECOND","MILLISECOND","_overflowDayOfYear","isValid","_isValid","getTime","bigHour","normalizeLocale","chooseLocale","names","loadLocale","oldLocale","hasModule","model","local","removeFormattingTokens","makeFormatFunction","formattingTokens","formatTokenFunctions","formatMoment","expandFormat","formatFunctions","invalidDate","replaceLongDateFormatTokens","longDateFormat","localFormattingTokens","lastIndex","getParseRegexForToken","parseTokenOneDigit","parseTokenThreeDigits","parseTokenFourDigits","parseTokenOneToFourDigits","parseTokenSignedNumber","parseTokenSixDigits","parseTokenOneToSixDigits","parseTokenTwoDigits","parseTokenOneToThreeDigits","parseTokenWord","_meridiemParse","parseTokenOffsetMs","parseTokenTimestampMs","parseTokenTimezone","parseTokenT","parseTokenDigits","parseTokenOneOrTwoDigits","_ordinalParse","_ordinalParseLenient","RegExp","regexpEscape","unescapeFormat","utcOffsetFromString","string","possibleTzMatches","tzChunk","parseTimezoneChunker","addTimeToArrayFromToken","datePartArray","monthsParse","_dayOfYear","parseTwoDigitYear","_meridiem","_useUTC","weekdaysParse","_w","invalidWeekday","dayOfYearFromWeekInfo","weekYear","temp","GG","W","E","_week","gg","dayOfYearFromWeeks","dateFromConfig","currentDate","yearToUse","currentDateArray","makeUTCDate","getUTCMonth","_nextDay","makeDate","setUTCMinutes","getUTCMinutes","dateFromObject","getUTCFullYear","makeDateFromStringAndFormat","ISO_8601","parseISO","parsedInput","tokens","skipped","stringLength","totalParsedInputLength","matched","p4","makeDateFromStringAndArray","tempConfig","bestMoment","scoreToBeat","currentScore","NaN","score","l","isoRegex","isoDates","isoTimes","makeDateFromString","createFromInputFallback","makeDateFromInput","aspNetJsonRegex","ms","setUTCFullYear","parseWeekday","substituteTimeAgo","withoutSuffix","isFuture","relativeTime","posNegDuration","relativeTimeThresholds","firstDayOfWeek","firstDayOfWeekOfYear","adjustedMoment","daysToDayOfWeek","daysToAdd","getUTCDay","makeMoment","invalid","preparse","pickBy","moments","dayOfMonth","unit","makeAccessor","keepTime","daysToYears","yearsToDays","makeDurationGetter","makeGlobal","shouldDeprecate","ender","oldGlobalMoment","globalScope","VERSION","aspNetTimeSpanJsonRegex","isoDurationRegex","isoFormat","unitMillisecondFactors","Milliseconds","Seconds","Minutes","Hours","Days","Months","Years","D","Q","DDD","dayofyear","isoweekday","isoweek","weekyear","isoweekyear","ordinalizeTokens","paddedTokens","MMM","monthsShort","MMMM","dd","weekdaysMin","ddd","weekdaysShort","dddd","weekdays","isoWeek","YY","YYYY","YYYYY","YYYYYY","gggg","ggggg","isoWeekYear","GGGG","GGGGG","isoWeekday","SS","SSS","SSSS","Z","utcOffset","ZZ","zoneAbbr","zz","zoneName","unix","lists","DDDD","_monthsShort","monthName","regex","_monthsParse","_longMonthsParse","_shortMonthsParse","_weekdays","_weekdaysShort","_weekdaysMin","weekdayName","_weekdaysParse","_longDateFormat","LTS","LT","L","LL","LLL","LLLL","isLower","_calendar","sameDay","nextDay","nextWeek","lastDay","lastWeek","sameElse","calendar","_relativeTime","future","past","mm","hh","MM","yy","pastFuture","_ordinal","postformat","firstDayOfYear","_invalidDate","ret","parseIso","diffRes","isDuration","inp","version","relativeTimeThreshold","limit","defineLocale","_abbr","abbr","langData","flags","parseZone","isDSTShifted","parsingFlags","invalidAt","keepLocalTime","_dateUtcOffset","inputString","asFloat","that","zoneDiff","humanize","fromNow","sod","startOf","isDST","getDay","endOf","inputMs","isBetween","zone","localAdjust","_changeInProgress","isLocal","isUtcOffset","isUtc","hasAlignedHourOffset","isoWeeksInYear","weekInfo","newLocaleData","getTimezoneOffset","isoWeeks","toJSON","isUTC","withSuffix","toIsoString","asSeconds","asMilliseconds","asMinutes","asHours","asDays","asWeeks","asMonths","asYears","ordinalParse","require","noGlobal","exportName","setTimeoutContext","timeout","bindFn","invokeArrayArg","arg","each","iterator","dest","inherit","child","childP","baseP","_super","boolOrFn","TYPE_FUNCTION","ifUndefined","val1","val2","addEventListeners","handler","splitStr","removeEventListeners","hasParent","inStr","str","find","inArray","findByKey","uniqueArray","prefixed","property","prefix","camelProp","VENDOR_PREFIXES","uniqueId","_uniqueId","getWindowForElement","doc","ownerDocument","defaultView","parentWindow","Input","manager","inputTarget","domHandler","ev","init","createInputInstance","Type","inputClass","SUPPORT_POINTER_EVENTS","PointerEventInput","SUPPORT_ONLY_TOUCH","TouchInput","SUPPORT_TOUCH","TouchMouseInput","MouseInput","inputHandler","pointersLen","pointers","changedPointersLen","changedPointers","isFirst","INPUT_START","isFinal","INPUT_END","INPUT_CANCEL","session","computeInputData","recognize","prevInput","pointersLength","firstInput","simpleCloneInputData","firstMultiple","offsetCenter","getCenter","timeStamp","deltaTime","getAngle","computeDeltaXY","offsetDirection","getDirection","rotation","getRotation","computeIntervalInputData","offsetDelta","prevDelta","velocityX","velocityY","last","lastInterval","COMPUTE_INTERVAL","getVelocity","DIRECTION_NONE","DIRECTION_LEFT","DIRECTION_RIGHT","DIRECTION_UP","DIRECTION_DOWN","PROPS_XY","PROPS_CLIENT_XY","evEl","MOUSE_ELEMENT_EVENTS","evWin","MOUSE_WINDOW_EVENTS","allow","pressed","POINTER_ELEMENT_EVENTS","POINTER_WINDOW_EVENTS","store","pointerEvents","SingleTouchInput","evTarget","SINGLE_TOUCH_TARGET_EVENTS","SINGLE_TOUCH_WINDOW_EVENTS","started","normalizeSingleTouches","all","changedTouches","TOUCH_TARGET_EVENTS","targetIds","getTouches","allTouches","INPUT_MOVE","identifier","changedTargetTouches","mouse","TouchAction","cleanTouchActions","actions","TOUCH_ACTION_NONE","hasPanX","TOUCH_ACTION_PAN_X","hasPanY","TOUCH_ACTION_PAN_Y","TOUCH_ACTION_MANIPULATION","TOUCH_ACTION_AUTO","Recognizer","defaults","state","STATE_POSSIBLE","simultaneous","requireFail","stateStr","STATE_CANCELLED","STATE_ENDED","STATE_CHANGED","STATE_BEGAN","directionStr","getRecognizerByNameIfManager","otherRecognizer","recognizer","AttrRecognizer","PanRecognizer","pX","pY","PinchRecognizer","PressRecognizer","_timer","_input","RotateRecognizer","SwipeRecognizer","TapRecognizer","pTime","pCenter","recognizers","preset","Manager","handlers","touchAction","toggleCssProps","recognizeWith","requireFailure","cssProps","triggerDomEvent","gestureEvent","createEvent","initEvent","dispatchEvent","TEST_ELEMENT","MOBILE_REGEX","INPUT_TYPE_TOUCH","INPUT_TYPE_PEN","INPUT_TYPE_MOUSE","INPUT_TYPE_KINECT","DIRECTION_HORIZONTAL","DIRECTION_VERTICAL","DIRECTION_ALL","MOUSE_INPUT_MAP","mousedown","mousemove","mouseup","pointerType","POINTER_INPUT_MAP","pointerdown","pointermove","pointerup","pointercancel","pointerout","IE10_POINTER_TYPE_ENUM",2,3,4,5,"MSPointerEvent","removePointer","eventTypeNormalized","isTouch","storeIndex","pointerId","SINGLE_TOUCH_INPUT_MAP","touchstart","touchmove","touchend","touchcancel","TOUCH_INPUT_MAP","inputEvent","inputData","isMouse","PREFIXED_TOUCH_ACTION","NATIVE_TOUCH_ACTION","TOUCH_ACTION_COMPUTE","compute","getTouchAction","preventDefaults","prevented","hasNone","preventSrc","STATE_RECOGNIZED","STATE_FAILED","dropRecognizeWith","dropRequireFailure","hasRequireFailures","canRecognizeWith","withState","tryEmit","canEmit","inputDataClone","process","attrTest","optionPointers","isRecognized","directionTest","hasMoved","inOut","validPointers","validMovement","validTime","taps","posThreshold","validTouchTime","failTimeout","validInterval","validMultiTap","tapCount","domEvents","userSelect","touchSelect","touchCallout","contentZooming","userDrag","tapHighlightColor","STOP","FORCED_STOP","stopped","curRecognizer","Tap","Pan","Swipe","Pinch","Rotate","Press","clusterToFit","maxNumberOfNodes","reposition","maxLevels","forceAggregateHubs","normalizeClusterLevels","increaseClusterLevel","repositionNodes","openCluster","isMovingBeforeClustering","_nodeInActiveArea","_sector","_addSector","decreaseClusterLevel","_expandClusterNode","_updateDynamicEdges","updateClusters","zoomDirection","recursive","doNotStart","amountOfNodes","_collapseSector","_formClusters","_openClusters","_openClustersBySize","_aggregateHubs","handleChains","chainPercentage","_getChainFraction","_reduceAmountOfChains","_getHubSize","_formClustersByHub","openAll","containedNodeId","childNode","_expelChildFromParent","_unselectAll","_releaseContainedEdges","_connectEdgeBackToChild","_validateEdges","othersPresent","childNodeId","_repositionBezierNodes","_formClustersByZoom","_forceClustersByZoom","minLength","_addToCluster","_clusterToSmallestNeighbour","smallestNeighbour","smallestNeighbourNode","neighbour","onlyEqual","_formClusterFromHub","hubNode","absorptionSizeOffset","allowCluster","edgesIdarray","amountOfInitialEdges","_addToContainedEdges","_connectEdgeToCluster","_containCircularEdgesFromNode","massBefore","correction","edgeToId","edgeFromId","k","_addToReroutedEdges","maxLevel","minLevel","clusterLevel","targetLevel","average","averageSquared","hubCounter","largestHub","variance","standardDeviation","fraction","reduceAmount","chains","total","_switchToSector","sectorId","sectorType","_switchToActiveSector","_switchToFrozenSector","_switchToSupportSector","_loadLatestSector","_previousSector","_setActiveSector","newId","_forgetLastSector","_createNewSector","_deleteActiveSector","_deleteFrozenSector","_freezeSector","_activateSector","_mergeThisWithFrozen","_collapseThisToSingleCluster","sector","unqiueIdentifier","previousSector","runFunction","argument","returnValues","_doInAllFrozenSectors","_drawSectorNodes","_drawAllSectorNodes","_getNodesOverlappingWith","_getAllNodesOverlappingWith","_pointerToPositionObject","positionObject","_getEdgesOverlappingWith","_getAllEdgesOverlappingWith","_addToSelection","_addToHover","_removeFromSelection","doNotTrigger","_unselectClusters","_getSelectedNodeCount","_getSelectedNode","_getSelectedEdge","_getSelectedEdgeCount","_getSelectedObjectCount","_selectionIsEmpty","_clusterInSelection","_selectConnectedEdges","_hoverConnectedEdges","_unselectConnectedEdges","append","highlightEdges","overrideSelectable","DOM","_manipulationReleaseOverload","_navigationReleaseOverload","getSelectedNodes","edgeIds","getSelectedEdges","idArray","selectNodes","RangeError","selectEdges","_clearManipulatorBar","manipulationDOM","_restoreOverloadedFunctions","functionName","_toggleEditMode","toolbar","boundFunction","edgeBeingEdited","selectedControlNode","_createAddNodeToolbar","_createAddEdgeToolbar","_editNode","_createEditEdgeToolbar","_addNode","_handleConnect","_finishConnect","_selectControlNode","_controlNodeDrag","_releaseControlNode","newNode","_editEdge","alert","supportNodes","targetNode","connectionEdge","connectFromId","_createEdge","defaultData","finalizedData","sourceNodeId","targetNodeId","selectedNodes","selectedEdges","navigationDivs","navigationDivActions","_stopMovement","_zoomExtent","hubsize","definedLevel","undefinedLevel","_changeConstants","_determineLevels","_determineLevelsDirected","distribution","_getDistribution","_placeNodesByHierarchy","minPos","_placeBranchNodes","maxCount","_setLevel","firstNode","_setLevelDirected","parentId","parentLevel","nodeMoved","_restoreNodes","graphToggleSmoothCurves","graph_toggleSmooth","getElementById","graphRepositionNodes","showValueOfRange","graphGenerateOptions","optionsSpecific","radioButton1","radioButton2","checked","backupConstants","optionsDiv","switchConfigurations","radioButton","querySelector","tableId","table","constantsVariableName","valueId","rangeValue","_overWriteGraphConstants","RepulsionMixin","HierarchialRepulsionMixin","BarnesHutMixin","_toggleBarnesHut","barnesHutTree","_initializeForceCalculation","_calculateForces","_calculateGravitationalForces","_calculateNodeForces","_calculateSpringForcesWithSupport","_calculateHierarchicalSpringForces","_calculateSpringForces","supportNodeId","gravity","gravityForce","edgeLength","springForce","combinedClusterSize","node1","node2","node3","_calculateSpringForce","physicsConfiguration","hierarchicalLayoutDirections","parentElement","rangeElement","radioButton3","graph_repositionNodes","graph_generateOptions","dynamicSmoothCurves","nameArray","webpackContext","req","resolve","repulsingForce","a_base","minimumDistance","steepness","springFx","springFy","totalFx","totalFy","correctionFx","correctionFy","nodeCount","_formBarnesHutTree","_getForceContribution","children","NW","NE","SW","SE","parentBranch","childrenCount","centerOfMass","calcSize","MAX_VALUE","sizeDiff","minimumTreeSize","rootSize","halfRootSize","_splitBranch","_placeInTree","_updateBranchMass","totalMass","totalMassInv","biggestSize","skipMassUpdate","_placeInRegion","region","containedNode","_insertRegion","childSize","_drawTree","_drawBranch","branch","webpackPolyfill","paths","__webpack_amd_options__"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAyBA,cAEA,SAA2CA,EAAMC,GAC1B,gBAAZC,UAA0C,gBAAXC,QACxCA,OAAOD,QAAUD,IACQ,kBAAXG,SAAyBA,OAAOC,IAC9CD,OAAOH,GACmB,gBAAZC,SACdA,QAAa,IAAID,IAEjBD,EAAU,IAAIC,KACbK,KAAM,WACT,MAAgB,UAAUC,GAKhB,QAASC,GAAoBC,GAG5B,GAAGC,EAAiBD,GACnB,MAAOC,GAAiBD,GAAUP,OAGnC,IAAIC,GAASO,EAAiBD,IAC7BP,WACAS,GAAIF,EACJG,QAAQ,EAUT,OANAL,GAAQE,GAAUI,KAAKV,EAAOD,QAASC,EAAQA,EAAOD,QAASM,GAG/DL,EAAOS,QAAS,EAGTT,EAAOD,QAvBf,GAAIQ,KAqCJ,OATAF,GAAoBM,EAAIP,EAGxBC,EAAoBO,EAAIL,EAGxBF,EAAoBQ,EAAI,GAGjBR,EAAoB,KAK/B,SAASL,EAAQD,EAASM,GAG9BN,EAAQe,KAAOT,EAAoB,GACnCN,EAAQgB,QAAUV,EAAoB,GAGtCN,EAAQiB,QAAUX,EAAoB,GACtCN,EAAQkB,SAAWZ,EAAoB,GACvCN,EAAQmB,MAAQb,EAAoB,GAGpCN,EAAQoB,QAAUd,EAAoB,GACtCN,EAAQqB,SACNC,OAAQhB,EAAoB,GAC5BiB,OAAQjB,EAAoB,GAC5BkB,QAASlB,EAAoB,GAC7BmB,QAASnB,EAAoB,IAC7BoB,OAAQpB,EAAoB,IAC5BqB,WAAYrB,EAAoB,KAIlCN,EAAQ4B,SAAWtB,EAAoB,IACvCN,EAAQ6B,QAAUvB,EAAoB,IACtCN,EAAQ8B,UACNC,SAAUzB,EAAoB,IAC9B0B,SAAU1B,EAAoB,IAC9B2B,MAAO3B,EAAoB,IAC3B4B,MAAO5B,EAAoB,IAC3B6B,SAAU7B,EAAoB,IAE9B8B,YACEC,OACEC,KAAMhC,EAAoB,IAC1BiC,eAAgBjC,EAAoB,IACpCkC,QAASlC,EAAoB,IAC7BmC,UAAWnC,EAAoB,IAC/BoC,UAAWpC,EAAoB,KAGjCqC,UAAWrC,EAAoB,IAC/BsC,YAAatC,EAAoB,IACjCuC,WAAYvC,EAAoB,IAChCwC,SAAUxC,EAAoB,IAC9ByC,WAAYzC,EAAoB,IAChC0C,MAAO1C,EAAoB,IAC3B2C,gBAAiB3C,EAAoB,IACrC4C,QAAS5C,EAAoB,IAC7B6C,OAAQ7C,EAAoB,IAC5B8C,UAAW9C,EAAoB,IAC/B+C,SAAU/C,EAAoB,MAKlCN,EAAQsD,QAAUhD,EAAoB,IACtCN,EAAQuD,SACNC,KAAMlD,EAAoB,IAC1BmD,OAAQnD,EAAoB,IAC5BoD,OAAQpD,EAAoB,IAC5BqD,KAAMrD,EAAoB,IAC1BsD,MAAOtD,EAAoB,IAC3BuD,UAAWvD,EAAoB,IAC/BwD,YAAaxD,EAAoB,KAInCN,EAAQ+D,MAAQ,WACd,KAAM,IAAIC,OAAM,+EAIlBhE,EAAQiE,OAAS3D,EAAoB,IACrCN,EAAQkE,OAAS5D,EAAoB,KAKjC,SAASL,EAAQD,EAASM,GAM9B,GAAI2D,GAAS3D,EAAoB,GAOjCN,GAAQmE,SAAW,SAASC,GAC1B,MAAQA,aAAkBC,SAA2B,gBAAVD,IAQ7CpE,EAAQsE,SAAW,SAASF,GAC1B,MAAQA,aAAkBG,SAA2B,gBAAVH,IAQ7CpE,EAAQwE,OAAS,SAASJ,GACxB,GAAIA,YAAkBK,MACpB,OAAO,CAEJ,IAAIzE,EAAQsE,SAASF,GAAS,CAEjC,GAAIM,GAAQC,EAAaC,KAAKR,EAC9B,IAAIM,EACF,OAAO,CAEJ,KAAKG,MAAMJ,KAAKK,MAAMV,IACzB,OAAO,EAIX,OAAO,GAQTpE,EAAQ+E,YAAc,SAASX,GAC7B,MAA4B,mBAAb,SACVY,OAAoB,eACpBA,OAAOC,cAAuB,WAC9Bb,YAAkBY,QAAOC,cAAcC,WAQ9ClF,EAAQmF,WAAa,WACnB,GAAIC,GAAK,WACP,MAAOC,MAAKC,MACQ,MAAhBD,KAAKE,UACPC,SAAS,IAGb,OACIJ,KAAOA,IAAO,IACVA,IAAO,IACPA,IAAO,IACPA,IAAO,IACPA,IAAOA,IAAOA,KAWxBpF,EAAQyF,OAAS,SAAUC,GACzB,IAAK,GAAIC,GAAI,EAAGC,EAAMC,UAAUC,OAAYF,EAAJD,EAASA,IAAK,CACpD,GAAII,GAAQF,UAAUF,EACtB,KAAK,GAAIK,KAAQD,GACXA,EAAME,eAAeD,KACvBN,EAAEM,GAAQD,EAAMC,IAKtB,MAAON,IAWT1F,EAAQkG,gBAAkB,SAAUC,EAAOT,GACzC,IAAKU,MAAMC,QAAQF,GACjB,KAAM,IAAInC,OAAM,uDAGlB,KAAK,GAAI2B,GAAI,EAAGA,EAAIE,UAAUC,OAAQH,IAGpC,IAAK,GAFDI,GAAQF,UAAUF,GAEb7E,EAAI,EAAGA,EAAIqF,EAAML,OAAQhF,IAAK,CACrC,GAAIkF,GAAOG,EAAMrF,EACbiF,GAAME,eAAeD,KACvBN,EAAEM,GAAQD,EAAMC,IAItB,MAAON,IAWT1F,EAAQsG,oBAAsB,SAAUH,EAAOT,EAAGa,GAEhD,GAAIH,MAAMC,QAAQE,GAChB,KAAM,IAAIC,WAAU,yCAEtB,KAAK,GAAIb,GAAI,EAAGA,EAAIE,UAAUC,OAAQH,IAEpC,IAAK,GADDI,GAAQF,UAAUF,GACb7E,EAAI,EAAGA,EAAIqF,EAAML,OAAQhF,IAAK,CACrC,GAAIkF,GAAOG,EAAMrF,EACjB,IAAIiF,EAAME,eAAeD,GACvB,GAAIO,EAAEP,IAASO,EAAEP,GAAMS,cAAgBC,OACrBC,SAAZjB,EAAEM,KACJN,EAAEM,OAEAN,EAAEM,GAAMS,cAAgBC,OAC1B1G,EAAQ4G,WAAWlB,EAAEM,GAAOO,EAAEP,IAG9BN,EAAEM,GAAQO,EAAEP,OAET,CAAA,GAAII,MAAMC,QAAQE,EAAEP,IACzB,KAAM,IAAIQ,WAAU,yCAEpBd,GAAEM,GAAQO,EAAEP,IAMpB,MAAON,IAWT1F,EAAQ6G,uBAAyB,SAAUV,EAAOT,EAAGa,GAEnD,GAAIH,MAAMC,QAAQE,GAChB,KAAM,IAAIC,WAAU,yCAEtB,KAAK,GAAIR,KAAQO,GACf,GAAIA,EAAEN,eAAeD,IACQ,IAAvBG,EAAMW,QAAQd,GAChB,GAAIO,EAAEP,IAASO,EAAEP,GAAMS,cAAgBC,OACrBC,SAAZjB,EAAEM,KACJN,EAAEM,OAEAN,EAAEM,GAAMS,cAAgBC,OAC1B1G,EAAQ4G,WAAWlB,EAAEM,GAAOO,EAAEP,IAG9BN,EAAEM,GAAQO,EAAEP,OAET,CAAA,GAAII,MAAMC,QAAQE,EAAEP,IACzB,KAAM,IAAIQ,WAAU,yCAEpBd,GAAEM,GAAQO,EAAEP,GAKpB,MAAON,IAST1F,EAAQ4G,WAAa,SAASlB,EAAGa,GAE/B,GAAIH,MAAMC,QAAQE,GAChB,KAAM,IAAIC,WAAU,yCAGtB,KAAK,GAAIR,KAAQO,GACf,GAAIA,EAAEN,eAAeD,GACnB,GAAIO,EAAEP,IAASO,EAAEP,GAAMS,cAAgBC,OACrBC,SAAZjB,EAAEM,KACJN,EAAEM,OAEAN,EAAEM,GAAMS,cAAgBC,OAC1B1G,EAAQ4G,WAAWlB,EAAEM,GAAOO,EAAEP,IAG9BN,EAAEM,GAAQO,EAAEP,OAET,CAAA,GAAII,MAAMC,QAAQE,EAAEP,IACzB,KAAM,IAAIQ,WAAU,yCAEpBd,GAAEM,GAAQO,EAAEP,GAIlB,MAAON,IAUT1F,EAAQ+G,WAAa,SAAUrB,EAAGa,GAChC,GAAIb,EAAEI,QAAUS,EAAET,OAAQ,OAAO,CAEjC,KAAK,GAAIH,GAAI,EAAGC,EAAMF,EAAEI,OAAYF,EAAJD,EAASA,IACvC,GAAID,EAAEC,IAAMY,EAAEZ,GAAI,OAAO,CAG3B,QAAO,GAYT3F,EAAQgH,QAAU,SAAS5C,EAAQ6C,GACjC,GAAIvC,EAEJ,IAAeiC,SAAXvC,EACF,MAAOuC,OAET,IAAe,OAAXvC,EACF,MAAO,KAGT,KAAK6C,EACH,MAAO7C,EAET,IAAsB,gBAAT6C,MAAwBA,YAAgB1C,SACnD,KAAM,IAAIP,OAAM,wBAIlB,QAAQiD,GACN,IAAK,UACL,IAAK,UACH,MAAOC,SAAQ9C,EAEjB,KAAK,SACL,IAAK,SACH,MAAOC,QAAOD,EAAO+C,UAEvB,KAAK,SACL,IAAK,SACH,MAAO5C,QAAOH,EAEhB,KAAK,OACH,GAAIpE,EAAQmE,SAASC,GACnB,MAAO,IAAIK,MAAKL,EAElB,IAAIA,YAAkBK,MACpB,MAAO,IAAIA,MAAKL,EAAO+C,UAEpB,IAAIlD,EAAOmD,SAAShD,GACvB,MAAO,IAAIK,MAAKL,EAAO+C,UAEzB,IAAInH,EAAQsE,SAASF,GAEnB,MADAM,GAAQC,EAAaC,KAAKR,GACtBM,EAEK,GAAID,MAAKJ,OAAOK,EAAM,KAGtBT,EAAOG,GAAQiD,QAIxB,MAAM,IAAIrD,OACN,iCAAmChE,EAAQsH,QAAQlD,GAC/C,gBAGZ,KAAK,SACH,GAAIpE,EAAQmE,SAASC,GACnB,MAAOH,GAAOG,EAEhB,IAAIA,YAAkBK,MACpB,MAAOR,GAAOG,EAAO+C,UAElB,IAAIlD,EAAOmD,SAAShD,GACvB,MAAOH,GAAOG,EAEhB,IAAIpE,EAAQsE,SAASF,GAEnB,MADAM,GAAQC,EAAaC,KAAKR,GAGjBH,EAFLS,EAEYL,OAAOK,EAAM,IAGbN,EAIhB,MAAM,IAAIJ,OACN,iCAAmChE,EAAQsH,QAAQlD,GAC/C,gBAGZ,KAAK,UACH,GAAIpE,EAAQmE,SAASC,GACnB,MAAO,IAAIK,MAAKL,EAEb,IAAIA,YAAkBK,MACzB,MAAOL,GAAOmD,aAEX,IAAItD,EAAOmD,SAAShD,GACvB,MAAOA,GAAOiD,SAASE,aAEpB,IAAIvH,EAAQsE,SAASF,GAExB,MADAM,GAAQC,EAAaC,KAAKR,GACtBM,EAEK,GAAID,MAAKJ,OAAOK,EAAM,KAAK6C,cAG3B,GAAI9C,MAAKL,GAAQmD,aAI1B,MAAM,IAAIvD,OACN,iCAAmChE,EAAQsH,QAAQlD,GAC/C,mBAGZ,KAAK,UACH,GAAIpE,EAAQmE,SAASC,GACnB,MAAO,SAAWA,EAAS,IAExB,IAAIA,YAAkBK,MACzB,MAAO,SAAWL,EAAO+C,UAAY,IAElC,IAAInH,EAAQsE,SAASF,GAAS,CACjCM,EAAQC,EAAaC,KAAKR,EAC1B,IAAIoD,EAQJ,OALEA,GAFE9C,EAEM,GAAID,MAAKJ,OAAOK,EAAM,KAAKyC,UAG3B,GAAI1C,MAAKL,GAAQ+C,UAEpB,SAAWK,EAAQ,KAG1B,KAAM,IAAIxD,OACN,iCAAmChE,EAAQsH,QAAQlD,GAC/C,mBAGZ,SACE,KAAM,IAAIJ,OAAM,iBAAmBiD,EAAO,MAOhD,IAAItC,GAAe,qBAOnB3E,GAAQsH,QAAU,SAASlD,GACzB,GAAI6C,SAAc7C,EAElB,OAAY,UAAR6C,EACY,MAAV7C,EACK,OAELA,YAAkB8C,SACb,UAEL9C,YAAkBC,QACb,SAELD,YAAkBG,QACb,SAEL6B,MAAMC,QAAQjC,GACT,QAELA,YAAkBK,MACb,OAEF,SAEQ,UAARwC,EACA,SAEQ,WAARA,EACA,UAEQ,UAARA,EACA,SAGFA,GASTjH,EAAQyH,gBAAkB,SAASC,GACjC,MAAOA,GAAKC,wBAAwBC,KAAOC,OAAOC,aASpD9H,EAAQ+H,eAAiB,SAASL,GAChC,MAAOA,GAAKC,wBAAwBK,IAAMH,OAAOI,aAQnDjI,EAAQkI,aAAe,SAASR,EAAMS,GACpC,GAAIC,GAAUV,EAAKS,UAAUE,MAAM,IACD,KAA9BD,EAAQtB,QAAQqB,KAClBC,EAAQE,KAAKH,GACbT,EAAKS,UAAYC,EAAQG,KAAK,OASlCvI,EAAQwI,gBAAkB,SAASd,EAAMS,GACvC,GAAIC,GAAUV,EAAKS,UAAUE,MAAM,KAC/BI,EAAQL,EAAQtB,QAAQqB,EACf,KAATM,IACFL,EAAQM,OAAOD,EAAO,GACtBf,EAAKS,UAAYC,EAAQG,KAAK,OAalCvI,EAAQ2I,QAAU,SAASvE,EAAQwE,GACjC,GAAIjD,GACAC,CACJ,IAAIQ,MAAMC,QAAQjC,GAEhB,IAAKuB,EAAI,EAAGC,EAAMxB,EAAO0B,OAAYF,EAAJD,EAASA,IACxCiD,EAASxE,EAAOuB,GAAIA,EAAGvB,OAKzB,KAAKuB,IAAKvB,GACJA,EAAO6B,eAAeN,IACxBiD,EAASxE,EAAOuB,GAAIA,EAAGvB,IAY/BpE,EAAQ6I,QAAU,SAASzE,GACzB,GAAI0E,KAEJ,KAAK,GAAI9C,KAAQ5B,GACXA,EAAO6B,eAAeD,IAAO8C,EAAMR,KAAKlE,EAAO4B,GAGrD,OAAO8C,IAUT9I,EAAQ+I,eAAiB,SAAS3E,EAAQ4E,EAAKxB,GAC7C,MAAIpD,GAAO4E,KAASxB,GAClBpD,EAAO4E,GAAOxB,GACP,IAGA,GAYXxH,EAAQiJ,iBAAmB,SAASC,EAASC,EAAQC,EAAUC,GACzDH,EAAQD,kBACStC,SAAf0C,IACFA,GAAa,GAEA,eAAXF,GAA2BG,UAAUC,UAAUzC,QAAQ,YAAc,IACvEqC,EAAS,kBAGXD,EAAQD,iBAAiBE,EAAQC,EAAUC,IAE3CH,EAAQM,YAAY,KAAOL,EAAQC,IAWvCpJ,EAAQyJ,oBAAsB,SAASP,EAASC,EAAQC,EAAUC,GAC5DH,EAAQO,qBAES9C,SAAf0C,IACFA,GAAa,GAEA,eAAXF,GAA2BG,UAAUC,UAAUzC,QAAQ,YAAc,IACvEqC,EAAS,kBAGXD,EAAQO,oBAAoBN,EAAQC,EAAUC,IAG9CH,EAAQQ,YAAY,KAAOP,EAAQC,IAOvCpJ,EAAQ2J,eAAiB,SAAUC,GAC5BA,IACHA,EAAQ/B,OAAO+B,OAEbA,EAAMD,eACRC,EAAMD,iBAGNC,EAAMC,aAAc,GASxB7J,EAAQ8J,UAAY,SAASF,GAEtBA,IACHA,EAAQ/B,OAAO+B,MAGjB,IAAIG,EAcJ,OAZIH,GAAMG,OACRA,EAASH,EAAMG,OAERH,EAAMI,aACbD,EAASH,EAAMI,YAGMrD,QAAnBoD,EAAOE,UAA4C,GAAnBF,EAAOE,WAEzCF,EAASA,EAAOG,YAGXH,GAGT/J,EAAQmK,UAQRnK,EAAQmK,OAAOC,UAAY,SAAU5C,EAAO6C,GAK1C,MAJoB,kBAAT7C,KACTA,EAAQA,KAGG,MAATA,EACe,GAATA,EAGH6C,GAAgB,MASzBrK,EAAQmK,OAAOG,SAAW,SAAU9C,EAAO6C,GAKzC,MAJoB,kBAAT7C,KACTA,EAAQA,KAGG,MAATA,EACKnD,OAAOmD,IAAU6C,GAAgB,KAGnCA,GAAgB,MASzBrK,EAAQmK,OAAOI,SAAW,SAAU/C,EAAO6C,GAKzC,MAJoB,kBAAT7C,KACTA,EAAQA,KAGG,MAATA,EACKjD,OAAOiD,GAGT6C,GAAgB,MASzBrK,EAAQmK,OAAOK,OAAS,SAAUhD,EAAO6C,GAKvC,MAJoB,kBAAT7C,KACTA,EAAQA,KAGNxH,EAAQsE,SAASkD,GACZA,EAEAxH,EAAQmE,SAASqD,GACjBA,EAAQ,KAGR6C,GAAgB,MAU3BrK,EAAQmK,OAAOM,UAAY,SAAUjD,EAAO6C,GAK1C,MAJoB,kBAAT7C,KACTA,EAAQA,KAGHA,GAAS6C,GAAgB,MASlCrK,EAAQ0K,SAAW,SAASC,GAE1B,GAAIC,GAAiB,kCACrBD,GAAMA,EAAIE,QAAQD,EAAgB,SAAShK,EAAGkK,EAAGC,EAAGxE,GAChD,MAAOuE,GAAIA,EAAIC,EAAIA,EAAIxE,EAAIA,GAE/B,IAAIyE,GAAS,4CAA4CpG,KAAK+F,EAC9D,OAAOK,IACHF,EAAGG,SAASD,EAAO,GAAI,IACvBD,EAAGE,SAASD,EAAO,GAAI,IACvBzE,EAAG0E,SAASD,EAAO,GAAI,KACvB,MAWNhL,EAAQkL,SAAW,SAASC,EAAIC,EAAMC,GACpC,MAAO,MAAQ,GAAK,KAAOF,GAAO,KAAOC,GAAS,GAAKC,GAAM7F,SAAS,IAAI8F,MAAM,IASlFtL,EAAQuL,WAAa,SAASC,GAC5B,GAAI3K,EACJ,IAAIb,EAAQsE,SAASkH,GAAQ,CAC3B,GAAIxL,EAAQyL,WAAWD,GAAQ,CAC7B,GAAIE,GAAMF,EAAMG,OAAO,GAAGA,OAAO,EAAEH,EAAM1F,OAAO,GAAGuC,MAAM,IACzDmD,GAAQxL,EAAQkL,SAASQ,EAAI,GAAGA,EAAI,GAAGA,EAAI,IAE7C,GAAI1L,EAAQ4L,WAAWJ,GAAQ,CAC7B,GAAIK,GAAM7L,EAAQ8L,SAASN,GACvBO,GAAmBC,EAAEH,EAAIG,EAAEC,EAAU,IAARJ,EAAII,EAASC,EAAE7G,KAAK8G,IAAI,EAAU,KAARN,EAAIK,IAC3DE,GAAmBJ,EAAEH,EAAIG,EAAEC,EAAE5G,KAAK8G,IAAI,EAAU,KAARN,EAAIK,GAAUA,EAAQ,GAANL,EAAIK,GAC5DG,EAAkBrM,EAAQsM,SAASF,EAAeJ,EAAGI,EAAeJ,EAAGI,EAAeF,GACtFK,EAAkBvM,EAAQsM,SAASP,EAAgBC,EAAED,EAAgBE,EAAEF,EAAgBG,EAE3FrL,IACE2L,WAAYhB,EACZiB,OAAOJ,EACPK,WACEF,WAAWD,EACXE,OAAOJ,GAETM,OACEH,WAAWD,EACXE,OAAOJ,QAKXxL,IACE2L,WAAWhB,EACXiB,OAAOjB,EACPkB,WACEF,WAAWhB,EACXiB,OAAOjB,GAETmB,OACEH,WAAWhB,EACXiB,OAAOjB,QAMb3K,MACAA,EAAE2L,WAAahB,EAAMgB,YAAc,QACnC3L,EAAE4L,OAASjB,EAAMiB,QAAU5L,EAAE2L,WAEzBxM,EAAQsE,SAASkH,EAAMkB,WACzB7L,EAAE6L,WACAD,OAAQjB,EAAMkB,UACdF,WAAYhB,EAAMkB,YAIpB7L,EAAE6L,aACF7L,EAAE6L,UAAUF,WAAahB,EAAMkB,WAAalB,EAAMkB,UAAUF,YAAc3L,EAAE2L,WAC5E3L,EAAE6L,UAAUD,OAASjB,EAAMkB,WAAalB,EAAMkB,UAAUD,QAAU5L,EAAE4L,QAGlEzM,EAAQsE,SAASkH,EAAMmB,OACzB9L,EAAE8L,OACAF,OAAQjB,EAAMmB,MACdH,WAAYhB,EAAMmB,QAIpB9L,EAAE8L,SACF9L,EAAE8L,MAAMH,WAAahB,EAAMmB,OAASnB,EAAMmB,MAAMH,YAAc3L,EAAE2L,WAChE3L,EAAE8L,MAAMF,OAASjB,EAAMmB,OAASnB,EAAMmB,MAAMF,QAAU5L,EAAE4L,OAI5D,OAAO5L,IAYTb,EAAQ4M,SAAW,SAASzB,EAAIC,EAAMC,GACpCF,GAAQ,IAAKC,GAAY,IAAKC,GAAU,GACxC,IAAIwB,GAASxH,KAAK8G,IAAIhB,EAAI9F,KAAK8G,IAAIf,EAAMC,IACrCyB,EAASzH,KAAK0H,IAAI5B,EAAI9F,KAAK0H,IAAI3B,EAAMC,GAGzC,IAAIwB,GAAUC,EACZ,OAAQd,EAAE,EAAEC,EAAE,EAAEC,EAAEW,EAIpB,IAAIG,GAAK7B,GAAK0B,EAAUzB,EAAMC,EAASA,GAAMwB,EAAU1B,EAAIC,EAAQC,EAAKF,EACpEa,EAAKb,GAAK0B,EAAU,EAAMxB,GAAMwB,EAAU,EAAI,EAC9CI,EAAM,IAAIjB,EAAIgB,GAAGF,EAASD,IAAS,IACnCK,GAAcJ,EAASD,GAAQC,EAC/BtF,EAAQsF,CACZ,QAAQd,EAAEiB,EAAIhB,EAAEiB,EAAWhB,EAAE1E,GAG/B,IAAI2F,IAEF9E,MAAO,SAAU+E,GACf,GAAIC,KAWJ,OATAD,GAAQ/E,MAAM,KAAKM,QAAQ,SAAU2E,GACnC,GAAoB,IAAhBA,EAAMC,OAAc,CACtB,GAAIC,GAAQF,EAAMjF,MAAM,KACpBW,EAAMwE,EAAM,GAAGD,OACf/F,EAAQgG,EAAM,GAAGD,MACrBF,GAAOrE,GAAOxB,KAIX6F,GAIT9E,KAAM,SAAU8E,GACd,MAAO3G,QAAO+G,KAAKJ,GACdK,IAAI,SAAU1E,GACb,MAAOA,GAAM,KAAOqE,EAAOrE,KAE5BT,KAAK,OASdvI,GAAQ2N,WAAa,SAAUzE,EAASkE,GACtC,GAAIQ,GAAgBT,EAAQ9E,MAAMa,EAAQoE,MAAMF,SAC5CS,EAAYV,EAAQ9E,MAAM+E,GAC1BC,EAASrN,EAAQyF,OAAOmI,EAAeC,EAE3C3E,GAAQoE,MAAMF,QAAUD,EAAQ5E,KAAK8E,IAQvCrN,EAAQ8N,cAAgB,SAAU5E,EAASkE,GACzC,GAAIC,GAASF,EAAQ9E,MAAMa,EAAQoE,MAAMF,SACrCW,EAAeZ,EAAQ9E,MAAM+E,EAEjC,KAAK,GAAIpE,KAAO+E,GACVA,EAAa9H,eAAe+C,UACvBqE,GAAOrE,EAIlBE,GAAQoE,MAAMF,QAAUD,EAAQ5E,KAAK8E,IAWvCrN,EAAQgO,SAAW,SAAShC,EAAGC,EAAGC,GAChC,GAAIpB,GAAGC,EAAGxE,EAENZ,EAAIN,KAAKC,MAAU,EAAJ0G,GACfiC,EAAQ,EAAJjC,EAAQrG,EACZ7E,EAAIoL,GAAK,EAAID,GACbiC,EAAIhC,GAAK,EAAI+B,EAAIhC,GACjBkC,EAAIjC,GAAK,GAAK,EAAI+B,GAAKhC,EAE3B,QAAQtG,EAAI,GACV,IAAK,GAAGmF,EAAIoB,EAAGnB,EAAIoD,EAAG5H,EAAIzF,CAAG,MAC7B,KAAK,GAAGgK,EAAIoD,EAAGnD,EAAImB,EAAG3F,EAAIzF,CAAG,MAC7B,KAAK,GAAGgK,EAAIhK,EAAGiK,EAAImB,EAAG3F,EAAI4H,CAAG,MAC7B,KAAK,GAAGrD,EAAIhK,EAAGiK,EAAImD,EAAG3H,EAAI2F,CAAG,MAC7B,KAAK,GAAGpB,EAAIqD,EAAGpD,EAAIjK,EAAGyF,EAAI2F,CAAG,MAC7B,KAAK,GAAGpB,EAAIoB,EAAGnB,EAAIjK,EAAGyF,EAAI2H,EAG5B,OAAQpD,EAAEzF,KAAKC,MAAU,IAAJwF,GAAUC,EAAE1F,KAAKC,MAAU,IAAJyF,GAAUxE,EAAElB,KAAKC,MAAU,IAAJiB,KAGrEvG,EAAQsM,SAAW,SAASN,EAAGC,EAAGC,GAChC,GAAIR,GAAM1L,EAAQgO,SAAShC,EAAGC,EAAGC,EACjC,OAAOlM,GAAQkL,SAASQ,EAAIZ,EAAGY,EAAIX,EAAGW,EAAInF,IAG5CvG,EAAQ8L,SAAW,SAASnB,GAC1B,GAAIe,GAAM1L,EAAQ0K,SAASC,EAC3B,OAAO3K,GAAQ4M,SAASlB,EAAIZ,EAAGY,EAAIX,EAAGW,EAAInF,IAG5CvG,EAAQ4L,WAAa,SAASjB,GAC5B,GAAIyD,GAAO,qCAAqCC,KAAK1D,EACrD,OAAOyD,IAGTpO,EAAQyL,WAAa,SAASC,GAC5BA,EAAMA,EAAIb,QAAQ,IAAI,GACtB,IAAIuD,GAAO,wCAAwCC,KAAK3C,EACxD,OAAO0C,IAUTpO,EAAQsO,sBAAwB,SAASC,EAAQC,GAC/C,GAA8B,gBAAnBA,GAA6B,CAEtC,IAAK,GADDC,GAAW/H,OAAOgI,OAAOF,GACpB7I,EAAI,EAAGA,EAAI4I,EAAOzI,OAAQH,IAC7B6I,EAAgBvI,eAAesI,EAAO5I,KACC,gBAA9B6I,GAAgBD,EAAO5I,MAChC8I,EAASF,EAAO5I,IAAM3F,EAAQ2O,aAAaH,EAAgBD,EAAO5I,KAIxE,OAAO8I,GAGP,MAAO,OAWXzO,EAAQ2O,aAAe,SAASH,GAC9B,GAA8B,gBAAnBA,GAA6B,CACtC,GAAIC,GAAW/H,OAAOgI,OAAOF,EAC7B,KAAK,GAAI7I,KAAK6I,GACRA,EAAgBvI,eAAeN,IACA,gBAAtB6I,GAAgB7I,KACzB8I,EAAS9I,GAAK3F,EAAQ2O,aAAaH,EAAgB7I,IAIzD,OAAO8I,GAGP,MAAO,OAcXzO,EAAQ4O,aAAe,SAAUC,EAAaC,EAAS3E,GACrD,GAAwBxD,SAApBmI,EAAQ3E,GACV,GAA8B,iBAAnB2E,GAAQ3E,GACjB0E,EAAY1E,GAAQ4E,QAAUD,EAAQ3E,OAEnC,CACH0E,EAAY1E,GAAQ4E,SAAU,CAC9B,KAAK,GAAI/I,KAAQ8I,GAAQ3E,GACnB2E,EAAQ3E,GAAQlE,eAAeD,KACjC6I,EAAY1E,GAAQnE,GAAQ8I,EAAQ3E,GAAQnE,MAmBtDhG,EAAQgP,mBAAqB,SAASC,EAAcC,EAAgBC,EAAOC,GAMzE,IALA,GAAIC,GAAgB,IAChBC,EAAY,EACZC,EAAM,EACNC,EAAOP,EAAanJ,OAAS,EAEnB0J,GAAPD,GAA2BF,EAAZC,GAA2B,CAC/C,GAAIG,GAASpK,KAAKC,OAAOiK,EAAMC,GAAQ,GAEnCE,EAAOT,EAAaQ,GACpBjI,EAAoBb,SAAXyI,EAAwBM,EAAKP,GAASO,EAAKP,GAAOC,GAE3DO,EAAeT,EAAe1H,EAClC,IAAoB,GAAhBmI,EACF,MAAOF,EAEgB,KAAhBE,EACPJ,EAAME,EAAS,EAGfD,EAAOC,EAAS,EAGlBH,IAGF,MAAO,IAeTtP,EAAQ4P,kBAAoB,SAASX,EAAclF,EAAQoF,EAAOU,GAOhE,IANA,GAIIC,GAAWtI,EAAOuI,EAAWN,EAJ7BJ,EAAgB,IAChBC,EAAY,EACZC,EAAM,EACNC,EAAOP,EAAanJ,OAAS,EAGnB0J,GAAPD,GAA2BF,EAAZC,GAA2B,CAO/C,GALAG,EAASpK,KAAKC,MAAM,IAAKkK,EAAKD,IAC9BO,EAAYb,EAAa5J,KAAK0H,IAAI,EAAE0C,EAAS,IAAIN,GACjD3H,EAAYyH,EAAaQ,GAAQN,GACjCY,EAAYd,EAAa5J,KAAK8G,IAAI8C,EAAanJ,OAAO,EAAE2J,EAAS,IAAIN,GAEjE3H,GAASuC,EACX,MAAO0F,EAEJ,IAAgB1F,EAAZ+F,GAAsBtI,EAAQuC,EACrC,MAAyB,UAAlB8F,EAA6BxK,KAAK0H,IAAI,EAAE0C,EAAS,GAAKA,CAE1D,IAAY1F,EAARvC,GAAkBuI,EAAYhG,EACrC,MAAyB,UAAlB8F,EAA6BJ,EAASpK,KAAK8G,IAAI8C,EAAanJ,OAAO,EAAE2J,EAAS,EAGzE1F,GAARvC,EACF+H,EAAME,EAAS,EAGfD,EAAOC,EAAS,EAGpBH,IAIF,MAAO,IAYTtP,EAAQgQ,cAAgB,SAAU7B,EAAG8B,EAAOC,EAAKC,GAC/C,GAAIC,GAASF,EAAMD,CAEnB,OADA9B,IAAKgC,EAAS,EACN,EAAJhC,EAAciC,EAAO,EAAEjC,EAAEA,EAAI8B,GACjC9B,KACQiC,EAAO,GAAKjC,GAAGA,EAAE,GAAK,GAAK8B,IAUrCjQ,EAAQqQ,iBAENC,OAAQ,SAAUnC,GAChB,MAAOA,IAGToC,WAAY,SAAUpC,GACpB,MAAOA,GAAIA,GAGbqC,YAAa,SAAUrC,GACrB,MAAOA,IAAK,EAAIA,IAGlB6B,cAAe,SAAU7B,GACvB,MAAW,GAAJA,EAAS,EAAIA,EAAIA,EAAI,IAAM,EAAI,EAAIA,GAAKA,GAGjDsC,YAAa,SAAUtC,GACrB,MAAOA,GAAIA,EAAIA,GAGjBuC,aAAc,SAAUvC,GACtB,QAAUA,EAAKA,EAAIA,EAAI,GAGzBwC,eAAgB,SAAUxC,GACxB,MAAW,GAAJA,EAAS,EAAIA,EAAIA,EAAIA,GAAKA,EAAI,IAAM,EAAIA,EAAI,IAAM,EAAIA,EAAI,GAAK,GAGxEyC,YAAa,SAAUzC,GACrB,MAAOA,GAAIA,EAAIA,EAAIA,GAGrB0C,aAAc,SAAU1C,GACtB,MAAO,MAAOA,EAAKA,EAAIA,EAAIA,GAG7B2C,eAAgB,SAAU3C,GACxB,MAAW,GAAJA,EAAS,EAAIA,EAAIA,EAAIA,EAAIA,EAAI,EAAI,IAAOA,EAAKA,EAAIA,EAAIA,GAG9D4C,YAAa,SAAU5C,GACrB,MAAOA,GAAIA,EAAIA,EAAIA,EAAIA,GAGzB6C,aAAc,SAAU7C,GACtB,MAAO,KAAOA,EAAKA,EAAIA,EAAIA,EAAIA,GAGjC8C,eAAgB,SAAU9C,GACxB,MAAW,GAAJA,EAAS,GAAKA,EAAIA,EAAIA,EAAIA,EAAIA,EAAI,EAAI,KAAQA,EAAKA,EAAIA,EAAIA,EAAIA,KAMtE,SAASlO,EAAQD,GASrBA,EAAQkR,gBAAkB,SAASC,GAEjC,IAAK,GAAIC,KAAeD,GAClBA,EAAclL,eAAemL,KAC/BD,EAAcC,GAAaC,UAAYF,EAAcC,GAAaE,KAClEH,EAAcC,GAAaE,UAYjCtR,EAAQuR,gBAAkB,SAASJ,GAEjC,IAAK,GAAIC,KAAeD,GACtB,GAAIA,EAAclL,eAAemL,IAC3BD,EAAcC,GAAaC,UAAW,CACxC,IAAK,GAAI1L,GAAI,EAAGA,EAAIwL,EAAcC,GAAaC,UAAUvL,OAAQH,IAC/DwL,EAAcC,GAAaC,UAAU1L,GAAGuE,WAAWsH,YAAYL,EAAcC,GAAaC,UAAU1L,GAEtGwL,GAAcC,GAAaC,eAgBnCrR,EAAQyR,cAAgB,SAAUL,EAAaD,EAAeO,GAC5D,GAAIxI,EAqBJ,OAnBIiI,GAAclL,eAAemL,GAE3BD,EAAcC,GAAaC,UAAUvL,OAAS,GAChDoD,EAAUiI,EAAcC,GAAaC,UAAU,GAC/CF,EAAcC,GAAaC,UAAUM,UAIrCzI,EAAU0I,SAASC,gBAAgB,6BAA8BT,GACjEM,EAAaI,YAAY5I,KAK3BA,EAAU0I,SAASC,gBAAgB,6BAA8BT,GACjED,EAAcC,IAAgBE,QAAUD,cACxCK,EAAaI,YAAY5I,IAE3BiI,EAAcC,GAAaE,KAAKhJ,KAAKY,GAC9BA,GAcTlJ,EAAQ+R,cAAgB,SAAUX,EAAaD,EAAea,EAAcC,GAC1E,GAAI/I,EA+BJ,OA7BIiI,GAAclL,eAAemL,GAE3BD,EAAcC,GAAaC,UAAUvL,OAAS,GAChDoD,EAAUiI,EAAcC,GAAaC,UAAU,GAC/CF,EAAcC,GAAaC,UAAUM,UAIrCzI,EAAU0I,SAASM,cAAcd,GACZzK,SAAjBsL,EACFD,EAAaC,aAAa/I,EAAS+I,GAGnCD,EAAaF,YAAY5I,KAM7BA,EAAU0I,SAASM,cAAcd,GACjCD,EAAcC,IAAgBE,QAAUD,cACnB1K,SAAjBsL,EACFD,EAAaC,aAAa/I,EAAS+I,GAGnCD,EAAaF,YAAY5I,IAG7BiI,EAAcC,GAAaE,KAAKhJ,KAAKY,GAC9BA,GAkBTlJ,EAAQmS,UAAY,SAASC,EAAGC,EAAGC,EAAOnB,EAAeO,GACvD,GAAIa,EAmBJ,OAlBsC,UAAlCD,EAAMxD,QAAQ0D,WAAWlF,OAC3BiF,EAAQvS,EAAQyR,cAAc,SAASN,EAAcO,GACrDa,EAAME,eAAe,KAAM,KAAML,GACjCG,EAAME,eAAe,KAAM,KAAMJ,GACjCE,EAAME,eAAe,KAAM,IAAK,GAAMH,EAAMxD,QAAQ0D,WAAWE,QAG/DH,EAAQvS,EAAQyR,cAAc,OAAON,EAAcO,GACnDa,EAAME,eAAe,KAAM,IAAKL,EAAI,GAAIE,EAAMxD,QAAQ0D,WAAWE,MACjEH,EAAME,eAAe,KAAM,IAAKJ,EAAI,GAAIC,EAAMxD,QAAQ0D,WAAWE,MACjEH,EAAME,eAAe,KAAM,QAASH,EAAMxD,QAAQ0D,WAAWE,MAC7DH,EAAME,eAAe,KAAM,SAAUH,EAAMxD,QAAQ0D,WAAWE,OAGzB/L,SAApC2L,EAAMxD,QAAQ0D,WAAWnF,QAC1BkF,EAAME,eAAe,KAAM,QAASH,EAAMA,MAAMxD,QAAQ0D,WAAWnF,QAErEkF,EAAME,eAAe,KAAM,QAASH,EAAMnK,UAAY,UAC/CoK,GAUTvS,EAAQ2S,QAAU,SAAUP,EAAGC,EAAGO,EAAOC,EAAQ1K,EAAWgJ,EAAeO,GACzE,GAAc,GAAVmB,EAAa,CACF,EAATA,IACFA,GAAU,GACVR,GAAKQ,EAEP,IAAIC,GAAO9S,EAAQyR,cAAc,OAAON,EAAeO,EACvDoB,GAAKL,eAAe,KAAM,IAAKL,EAAI,GAAMQ,GACzCE,EAAKL,eAAe,KAAM,IAAKJ,GAC/BS,EAAKL,eAAe,KAAM,QAASG,GACnCE,EAAKL,eAAe,KAAM,SAAUI,GACpCC,EAAKL,eAAe,KAAM,QAAStK,MAMnC,SAASlI,EAAQD,EAASM,GAgD9B,QAASW,GAAS8R,EAAMjE,GActB,IAZIiE,GAAS3M,MAAMC,QAAQ0M,IAAUhS,EAAKgE,YAAYgO,KACpDjE,EAAUiE,EACVA,EAAO,MAGT3S,KAAK4S,SAAWlE,MAChB1O,KAAK6S,SACL7S,KAAK8S,SAAW9S,KAAK4S,SAASG,SAAW,KACzC/S,KAAKgT,SAIDhT,KAAK4S,SAAS/L,KAChB,IAAK,GAAIkI,KAAS/O,MAAK4S,SAAS/L,KAC9B,GAAI7G,KAAK4S,SAAS/L,KAAKhB,eAAekJ,GAAQ,CAC5C,GAAI3H,GAAQpH,KAAK4S,SAAS/L,KAAKkI,EAE7B/O,MAAKgT,MAAMjE,GADA,QAAT3H,GAA4B,WAATA,GAA+B,WAATA,EACvB,OAGAA,EAO5B,GAAIpH,KAAK4S,SAAShM,QAChB,KAAM,IAAIhD,OAAM,sDAGlB5D,MAAKiT,gBAGDN,GACF3S,KAAKkT,IAAIP,GAGX3S,KAAKmT,WAAWzE,GAtFlB,GAAI/N,GAAOT,EAAoB,GAC3Ba,EAAQb,EAAoB,EAiGhCW,GAAQuS,UAAUD,WAAa,SAASzE,GAClCA,GAA6BnI,SAAlBmI,EAAQ2E,QACjB3E,EAAQ2E,SAAU,EAEhBrT,KAAKsT,SACPtT,KAAKsT,OAAOC,gBACLvT,MAAKsT,SAKTtT,KAAKsT,SACRtT,KAAKsT,OAASvS,EAAMsE,OAAOrF,MACzByK,SAAU,MAAO,SAAU,aAIF,gBAAlBiE,GAAQ2E,OACjBrT,KAAKsT,OAAOH,WAAWzE,EAAQ2E,UAevCxS,EAAQuS,UAAUI,GAAK,SAAShK,EAAOhB,GACrC,GAAIiL,GAAczT,KAAKiT,aAAazJ,EAC/BiK,KACHA,KACAzT,KAAKiT,aAAazJ,GAASiK,GAG7BA,EAAYvL,MACVM,SAAUA,KAKd3H,EAAQuS,UAAUM,UAAY7S,EAAQuS,UAAUI,GAOhD3S,EAAQuS,UAAUO,IAAM,SAASnK,EAAOhB,GACtC,GAAIiL,GAAczT,KAAKiT,aAAazJ,EAChCiK,KACFzT,KAAKiT,aAAazJ,GAASiK,EAAYG,OAAO,SAAU5K,GACtD,MAAQA,GAASR,UAAYA,MAMnC3H,EAAQuS,UAAUS,YAAchT,EAAQuS,UAAUO,IASlD9S,EAAQuS,UAAUU,SAAW,SAAUtK,EAAOuK,EAAQC,GACpD,GAAa,KAATxK,EACF,KAAM,IAAI5F,OAAM,yBAGlB,IAAI6P,KACAjK,KAASxJ,MAAKiT,eAChBQ,EAAcA,EAAYQ,OAAOjU,KAAKiT,aAAazJ,KAEjD,KAAOxJ,MAAKiT,eACdQ,EAAcA,EAAYQ,OAAOjU,KAAKiT,aAAa,MAGrD,KAAK,GAAI1N,GAAI,EAAGA,EAAIkO,EAAY/N,OAAQH,IAAK,CAC3C,GAAI2O,GAAaT,EAAYlO,EACzB2O,GAAW1L,UACb0L,EAAW1L,SAASgB,EAAOuK,EAAQC,GAAY,QAYrDnT,EAAQuS,UAAUF,IAAM,SAAUP,EAAMqB,GACtC,GACI3T,GADA8T,KAEAC,EAAKpU,IAET,IAAIgG,MAAMC,QAAQ0M,GAEhB,IAAK,GAAIpN,GAAI,EAAGC,EAAMmN,EAAKjN,OAAYF,EAAJD,EAASA,IAC1ClF,EAAK+T,EAAGC,SAAS1B,EAAKpN,IACtB4O,EAASjM,KAAK7H,OAGb,IAAIM,EAAKgE,YAAYgO,GAGxB,IAAK,GADD2B,GAAUtU,KAAKuU,gBAAgB5B,GAC1B6B,EAAM,EAAGC,EAAO9B,EAAK+B,kBAAyBD,EAAND,EAAYA,IAAO,CAElE,IAAK,GADDlF,MACKqF,EAAM,EAAGC,EAAON,EAAQ5O,OAAckP,EAAND,EAAYA,IAAO,CAC1D,GAAI5F,GAAQuF,EAAQK,EACpBrF,GAAKP,GAAS4D,EAAKkC,SAASL,EAAKG,GAGnCtU,EAAK+T,EAAGC,SAAS/E,GACjB6E,EAASjM,KAAK7H,OAGb,CAAA,KAAIsS,YAAgBrM,SAMvB,KAAM,IAAI1C,OAAM,mBAJhBvD,GAAK+T,EAAGC,SAAS1B,GACjBwB,EAASjM,KAAK7H,GAUhB,MAJI8T,GAASzO,QACX1F,KAAK8T,SAAS,OAAQ7R,MAAOkS,GAAWH,GAGnCG,GASTtT,EAAQuS,UAAU0B,OAAS,SAAUnC,EAAMqB,GACzC,GAAIG,MACAY,KACAC,KACAZ,EAAKpU,KACL+S,EAAUqB,EAAGtB,SAEbmC,EAAc,SAAU3F,GAC1B,GAAIjP,GAAKiP,EAAKyD,EACVqB,GAAGvB,MAAMxS,IAEXA,EAAK+T,EAAGc,YAAY5F,GACpByF,EAAW7M,KAAK7H,GAChB2U,EAAY9M,KAAKoH,KAIjBjP,EAAK+T,EAAGC,SAAS/E,GACjB6E,EAASjM,KAAK7H,IAIlB,IAAI2F,MAAMC,QAAQ0M,GAEhB,IAAK,GAAIpN,GAAI,EAAGC,EAAMmN,EAAKjN,OAAYF,EAAJD,EAASA,IAC1C0P,EAAYtC,EAAKpN,QAGhB,IAAI5E,EAAKgE,YAAYgO,GAGxB,IAAK,GADD2B,GAAUtU,KAAKuU,gBAAgB5B,GAC1B6B,EAAM,EAAGC,EAAO9B,EAAK+B,kBAAyBD,EAAND,EAAYA,IAAO,CAElE,IAAK,GADDlF,MACKqF,EAAM,EAAGC,EAAON,EAAQ5O,OAAckP,EAAND,EAAYA,IAAO,CAC1D,GAAI5F,GAAQuF,EAAQK,EACpBrF,GAAKP,GAAS4D,EAAKkC,SAASL,EAAKG,GAGnCM,EAAY3F,OAGX,CAAA,KAAIqD,YAAgBrM,SAKvB,KAAM,IAAI1C,OAAM,mBAHhBqR,GAAYtC,GAad,MAPIwB,GAASzO,QACX1F,KAAK8T,SAAS,OAAQ7R,MAAOkS,GAAWH,GAEtCe,EAAWrP,QACb1F,KAAK8T,SAAS,UAAW7R,MAAO8S,EAAYpC,KAAMqC,GAAchB,GAG3DG,EAASF,OAAOc,IAsCzBlU,EAAQuS,UAAU+B,IAAM,WACtB,GAGI9U,GAAI+U,EAAK1G,EAASiE,EAHlByB,EAAKpU,KAILqV,EAAY1U,EAAKuG,QAAQzB,UAAU,GACtB,WAAb4P,GAAsC,UAAbA,GAE3BhV,EAAKoF,UAAU,GACfiJ,EAAUjJ,UAAU,GACpBkN,EAAOlN,UAAU,IAEG,SAAb4P,GAEPD,EAAM3P,UAAU,GAChBiJ,EAAUjJ,UAAU,GACpBkN,EAAOlN,UAAU,KAIjBiJ,EAAUjJ,UAAU,GACpBkN,EAAOlN,UAAU,GAInB,IAAI6P,EACJ,IAAI5G,GAAWA,EAAQ4G,WAAY,CACjC,GAAIC,IAAiB,YAAa,QAAS,SAG3C,IAFAD,EAA0D,IAA7CC,EAAc7O,QAAQgI,EAAQ4G,YAAoB,QAAU5G,EAAQ4G,WAE7E3C,GAAS2C,GAAc3U,EAAKuG,QAAQyL,GACtC,KAAM,IAAI/O,OAAM,6BAA+BjD,EAAKuG,QAAQyL,GAAQ,sDACVjE,EAAQ7H,KAAO,IAE3E,IAAkB,aAAdyO,IAA8B3U,EAAKgE,YAAYgO,GACjD,KAAM,IAAI/O,OAAM,6EAKlB0R,GADO3C,GAC6B,aAAtBhS,EAAKuG,QAAQyL,GAAwB,YAGtC,OAIf,IAEgBrD,GAAMkG,EAAQjQ,EAAGC,EAF7BqB,EAAO6H,GAAWA,EAAQ7H,MAAQ7G,KAAK4S,SAAS/L,KAChD+M,EAASlF,GAAWA,EAAQkF,OAC5B3R,IAGJ,IAAUsE,QAANlG,EAEFiP,EAAO8E,EAAGqB,SAASpV,EAAIwG,GACnB+M,IAAWA,EAAOtE,KACpBA,EAAO,UAGN,IAAW/I,QAAP6O,EAEP,IAAK7P,EAAI,EAAGC,EAAM4P,EAAI1P,OAAYF,EAAJD,EAASA,IACrC+J,EAAO8E,EAAGqB,SAASL,EAAI7P,GAAIsB,KACtB+M,GAAUA,EAAOtE,KACpBrN,EAAMiG,KAAKoH,OAMf,KAAKkG,IAAUxV,MAAK6S,MACd7S,KAAK6S,MAAMhN,eAAe2P,KAC5BlG,EAAO8E,EAAGqB,SAASD,EAAQ3O,KACtB+M,GAAUA,EAAOtE,KACpBrN,EAAMiG,KAAKoH,GAYnB,IALIZ,GAAWA,EAAQgH,OAAenP,QAANlG,GAC9BL,KAAK2V,MAAM1T,EAAOyM,EAAQgH,OAIxBhH,GAAWA,EAAQP,OAAQ,CAC7B,GAAIA,GAASO,EAAQP,MACrB,IAAU5H,QAANlG,EACFiP,EAAOtP,KAAK4V,cAActG,EAAMnB,OAGhC,KAAK5I,EAAI,EAAGC,EAAMvD,EAAMyD,OAAYF,EAAJD,EAASA,IACvCtD,EAAMsD,GAAKvF,KAAK4V,cAAc3T,EAAMsD,GAAI4I,GAM9C,GAAkB,aAAdmH,EAA2B,CAC7B,GAAIhB,GAAUtU,KAAKuU,gBAAgB5B,EACnC,IAAUpM,QAANlG,EAEF+T,EAAGyB,WAAWlD,EAAM2B,EAAShF,OAI7B,KAAK/J,EAAI,EAAGA,EAAItD,EAAMyD,OAAQH,IAC5B6O,EAAGyB,WAAWlD,EAAM2B,EAASrS,EAAMsD,GAGvC,OAAOoN,GAEJ,GAAkB,UAAd2C,EAAwB,CAC/B,GAAI1K,KACJ,KAAKrF,EAAI,EAAGA,EAAItD,EAAMyD,OAAQH,IAC5BqF,EAAO3I,EAAMsD,GAAGlF,IAAM4B,EAAMsD,EAE9B,OAAOqF,GAIP,GAAUrE,QAANlG,EAEF,MAAOiP,EAIP,IAAIqD,EAAM,CAER,IAAKpN,EAAI,EAAGC,EAAMvD,EAAMyD,OAAYF,EAAJD,EAASA,IACvCoN,EAAKzK,KAAKjG,EAAMsD,GAElB,OAAOoN,GAIP,MAAO1Q,IAcfpB,EAAQuS,UAAU0C,OAAS,SAAUpH,GACnC,GAIInJ,GACAC,EACAnF,EACAiP,EACArN,EARA0Q,EAAO3S,KAAK6S,MACZe,EAASlF,GAAWA,EAAQkF,OAC5B8B,EAAQhH,GAAWA,EAAQgH,MAC3B7O,EAAO6H,GAAWA,EAAQ7H,MAAQ7G,KAAK4S,SAAS/L,KAMhDuO,IAEJ,IAAIxB,EAEF,GAAI8B,EAAO,CAETzT,IACA,KAAK5B,IAAMsS,GACLA,EAAK9M,eAAexF,KACtBiP,EAAOtP,KAAKyV,SAASpV,EAAIwG,GACrB+M,EAAOtE,IACTrN,EAAMiG,KAAKoH,GAOjB,KAFAtP,KAAK2V,MAAM1T,EAAOyT,GAEbnQ,EAAI,EAAGC,EAAMvD,EAAMyD,OAAYF,EAAJD,EAASA,IACvC6P,EAAI7P,GAAKtD,EAAMsD,GAAGvF,KAAK8S,cAKzB,KAAKzS,IAAMsS,GACLA,EAAK9M,eAAexF,KACtBiP,EAAOtP,KAAKyV,SAASpV,EAAIwG,GACrB+M,EAAOtE,IACT8F,EAAIlN,KAAKoH,EAAKtP,KAAK8S,gBAQ3B,IAAI4C,EAAO,CAETzT,IACA,KAAK5B,IAAMsS,GACLA,EAAK9M,eAAexF,IACtB4B,EAAMiG,KAAKyK,EAAKtS,GAMpB,KAFAL,KAAK2V,MAAM1T,EAAOyT,GAEbnQ,EAAI,EAAGC,EAAMvD,EAAMyD,OAAYF,EAAJD,EAASA,IACvC6P,EAAI7P,GAAKtD,EAAMsD,GAAGvF,KAAK8S,cAKzB,KAAKzS,IAAMsS,GACLA,EAAK9M,eAAexF,KACtBiP,EAAOqD,EAAKtS,GACZ+U,EAAIlN,KAAKoH,EAAKtP,KAAK8S,WAM3B,OAAOsC,IAOTvU,EAAQuS,UAAU2C,WAAa,WAC7B,MAAO/V,OAaTa,EAAQuS,UAAU7K,QAAU,SAAUC,EAAUkG,GAC9C,GAGIY,GACAjP,EAJAuT,EAASlF,GAAWA,EAAQkF,OAC5B/M,EAAO6H,GAAWA,EAAQ7H,MAAQ7G,KAAK4S,SAAS/L,KAChD8L,EAAO3S,KAAK6S,KAIhB,IAAInE,GAAWA,EAAQgH,MAIrB,IAAK,GAFDzT,GAAQjC,KAAKmV,IAAIzG,GAEZnJ,EAAI,EAAGC,EAAMvD,EAAMyD,OAAYF,EAAJD,EAASA,IAC3C+J,EAAOrN,EAAMsD,GACblF,EAAKiP,EAAKtP,KAAK8S,UACftK,EAAS8G,EAAMjP,OAKjB,KAAKA,IAAMsS,GACLA,EAAK9M,eAAexF,KACtBiP,EAAOtP,KAAKyV,SAASpV,EAAIwG,KACpB+M,GAAUA,EAAOtE,KACpB9G,EAAS8G,EAAMjP,KAkBzBQ,EAAQuS,UAAU9F,IAAM,SAAU9E,EAAUkG,GAC1C,GAIIY,GAJAsE,EAASlF,GAAWA,EAAQkF,OAC5B/M,EAAO6H,GAAWA,EAAQ7H,MAAQ7G,KAAK4S,SAAS/L,KAChDmP,KACArD,EAAO3S,KAAK6S,KAIhB,KAAK,GAAIxS,KAAMsS,GACTA,EAAK9M,eAAexF,KACtBiP,EAAOtP,KAAKyV,SAASpV,EAAIwG,KACpB+M,GAAUA,EAAOtE,KACpB0G,EAAY9N,KAAKM,EAAS8G,EAAMjP,IAUtC,OAJIqO,IAAWA,EAAQgH,OACrB1V,KAAK2V,MAAMK,EAAatH,EAAQgH,OAG3BM,GAUTnV,EAAQuS,UAAUwC,cAAgB,SAAUtG,EAAMnB,GAChD,GAAI8H,KAEJ,KAAK,GAAIlH,KAASO,GACZA,EAAKzJ,eAAekJ,IAAoC,IAAzBZ,EAAOzH,QAAQqI,KAChDkH,EAAalH,GAASO,EAAKP,GAI/B,OAAOkH,IASTpV,EAAQuS,UAAUuC,MAAQ,SAAU1T,EAAOyT,GACzC,GAAI/U,EAAKuD,SAASwR,GAAQ,CAExB,GAAIQ,GAAOR,CACXzT,GAAMkU,KAAK,SAAU7Q,EAAGa,GACtB,GAAIiQ,GAAK9Q,EAAE4Q,GACPG,EAAKlQ,EAAE+P,EACX,OAAQE,GAAKC,EAAM,EAAWA,EAALD,EAAW,GAAK,QAGxC,CAAA,GAAqB,kBAAVV,GAOd,KAAM,IAAItP,WAAU,uCALpBnE,GAAMkU,KAAKT,KAgBf7U,EAAQuS,UAAUkD,OAAS,SAAUjW,EAAI2T,GACvC,GACIzO,GAAGC,EAAK+Q,EADRC,IAGJ,IAAIxQ,MAAMC,QAAQ5F,GAChB,IAAKkF,EAAI,EAAGC,EAAMnF,EAAGqF,OAAYF,EAAJD,EAASA,IACpCgR,EAAYvW,KAAKyW,QAAQpW,EAAGkF,IACX,MAAbgR,GACFC,EAAWtO,KAAKqO,OAKpBA,GAAYvW,KAAKyW,QAAQpW,GACR,MAAbkW,GACFC,EAAWtO,KAAKqO,EAQpB,OAJIC,GAAW9Q,QACb1F,KAAK8T,SAAS,UAAW7R,MAAOuU,GAAaxC,GAGxCwC,GAST3V,EAAQuS,UAAUqD,QAAU,SAAUpW,GACpC,GAAIM,EAAKoD,SAAS1D,IAAOM,EAAKuD,SAAS7D,IACrC,GAAIL,KAAK6S,MAAMxS,GAEb,aADOL,MAAK6S,MAAMxS,GACXA,MAGN,IAAIA,YAAciG,QAAQ,CAC7B,GAAIkP,GAASnV,EAAGL,KAAK8S,SACrB,IAAI0C,GAAUxV,KAAK6S,MAAM2C,GAEvB,aADOxV,MAAK6S,MAAM2C,GACXA,EAGX,MAAO,OAQT3U,EAAQuS,UAAUsD,MAAQ,SAAU1C,GAClC,GAAIoB,GAAM9O,OAAO+G,KAAKrN,KAAK6S,MAM3B,OAJA7S,MAAK6S,SAEL7S,KAAK8T,SAAS,UAAW7R,MAAOmT,GAAMpB,GAE/BoB,GAQTvU,EAAQuS,UAAUzG,IAAM,SAAUoC,GAChC,GAAI4D,GAAO3S,KAAK6S,MACZlG,EAAM,KACNgK,EAAW,IAEf,KAAK,GAAItW,KAAMsS,GACb,GAAIA,EAAK9M,eAAexF,GAAK,CAC3B,GAAIiP,GAAOqD,EAAKtS,GACZuW,EAAYtH,EAAKP,EACJ,OAAb6H,KAAuBjK,GAAOiK,EAAYD,KAC5ChK,EAAM2C,EACNqH,EAAWC,GAKjB,MAAOjK,IAQT9L,EAAQuS,UAAUrH,IAAM,SAAUgD,GAChC,GAAI4D,GAAO3S,KAAK6S,MACZ9G,EAAM,KACN8K,EAAW,IAEf,KAAK,GAAIxW,KAAMsS,GACb,GAAIA,EAAK9M,eAAexF,GAAK,CAC3B,GAAIiP,GAAOqD,EAAKtS,GACZuW,EAAYtH,EAAKP,EACJ,OAAb6H,KAAuB7K,GAAmB8K,EAAZD,KAChC7K,EAAMuD,EACNuH,EAAWD,GAKjB,MAAO7K,IAUTlL,EAAQuS,UAAU0D,SAAW,SAAU/H,GACrC,GAIIxJ,GAJAoN,EAAO3S,KAAK6S,MACZkE,KACAC,EAAYhX,KAAK4S,SAAS/L,MAAQ7G,KAAK4S,SAAS/L,KAAKkI,IAAU,KAC/DkI,EAAQ,CAGZ,KAAK,GAAIrR,KAAQ+M,GACf,GAAIA,EAAK9M,eAAeD,GAAO,CAC7B,GAAI0J,GAAOqD,EAAK/M,GACZwB,EAAQkI,EAAKP,GACbmI,GAAS,CACb,KAAK3R,EAAI,EAAO0R,EAAJ1R,EAAWA,IACrB,GAAIwR,EAAOxR,IAAM6B,EAAO,CACtB8P,GAAS,CACT,OAGCA,GAAqB3Q,SAAVa,IACd2P,EAAOE,GAAS7P,EAChB6P,KAKN,GAAID,EACF,IAAKzR,EAAI,EAAGA,EAAIwR,EAAOrR,OAAQH,IAC7BwR,EAAOxR,GAAK5E,EAAKiG,QAAQmQ,EAAOxR,GAAIyR,EAIxC,OAAOD,IASTlW,EAAQuS,UAAUiB,SAAW,SAAU/E,GACrC,GAAIjP,GAAKiP,EAAKtP,KAAK8S,SAEnB,IAAUvM,QAANlG,GAEF,GAAIL,KAAK6S,MAAMxS,GAEb,KAAM,IAAIuD,OAAM,iCAAmCvD,EAAK,uBAK1DA,GAAKM,EAAKoE,aACVuK,EAAKtP,KAAK8S,UAAYzS,CAGxB,IAAIuM,KACJ,KAAK,GAAImC,KAASO,GAChB,GAAIA,EAAKzJ,eAAekJ,GAAQ,CAC9B,GAAIiI,GAAYhX,KAAKgT,MAAMjE,EAC3BnC,GAAEmC,GAASpO,EAAKiG,QAAQ0I,EAAKP,GAAQiI,GAKzC,MAFAhX,MAAK6S,MAAMxS,GAAMuM,EAEVvM,GAUTQ,EAAQuS,UAAUqC,SAAW,SAAUpV,EAAI8W,GACzC,GAAIpI,GAAO3H,EAGPgQ,EAAMpX,KAAK6S,MAAMxS,EACrB,KAAK+W,EACH,MAAO,KAIT,IAAIC,KACJ,IAAIF,EACF,IAAKpI,IAASqI,GACRA,EAAIvR,eAAekJ,KACrB3H,EAAQgQ,EAAIrI,GACZsI,EAAUtI,GAASpO,EAAKiG,QAAQQ,EAAO+P,EAAMpI,SAMjD,KAAKA,IAASqI,GACRA,EAAIvR,eAAekJ,KACrB3H,EAAQgQ,EAAIrI,GACZsI,EAAUtI,GAAS3H,EAIzB,OAAOiQ,IAWTxW,EAAQuS,UAAU8B,YAAc,SAAU5F,GACxC,GAAIjP,GAAKiP,EAAKtP,KAAK8S,SACnB,IAAUvM,QAANlG,EACF,KAAM,IAAIuD,OAAM,6CAA+C0T,KAAKC,UAAUjI,GAAQ,IAExF,IAAI1C,GAAI5M,KAAK6S,MAAMxS,EACnB,KAAKuM,EAEH,KAAM,IAAIhJ,OAAM,uCAAyCvD,EAAK,SAIhE,KAAK,GAAI0O,KAASO,GAChB,GAAIA,EAAKzJ,eAAekJ,GAAQ,CAC9B,GAAIiI,GAAYhX,KAAKgT,MAAMjE,EAC3BnC,GAAEmC,GAASpO,EAAKiG,QAAQ0I,EAAKP,GAAQiI,GAIzC,MAAO3W,IASTQ,EAAQuS,UAAUmB,gBAAkB,SAAUiD,GAE5C,IAAK,GADDlD,MACKK,EAAM,EAAGC,EAAO4C,EAAUC,qBAA4B7C,EAAND,EAAYA,IACnEL,EAAQK,GAAO6C,EAAUE,YAAY/C,IAAQ6C,EAAUG,eAAehD,EAExE,OAAOL,IAUTzT,EAAQuS,UAAUyC,WAAa,SAAU2B,EAAWlD,EAAShF,GAG3D,IAAK,GAFDkF,GAAMgD,EAAUI,SAEXjD,EAAM,EAAGC,EAAON,EAAQ5O,OAAckP,EAAND,EAAYA,IAAO,CAC1D,GAAI5F,GAAQuF,EAAQK,EACpB6C,GAAUK,SAASrD,EAAKG,EAAKrF,EAAKP,MAItClP,EAAOD,QAAUiB,GAKb,SAAShB,EAAQD,EAASM,GAe9B,QAASY,GAAU6R,EAAMjE,GACvB1O,KAAK6S,MAAQ,KACb7S,KAAK8X,QACL9X,KAAK4S,SAAWlE,MAChB1O,KAAK8S,SAAW,KAChB9S,KAAKiT,eAEL,IAAImB,GAAKpU,IACTA,MAAKgJ,SAAW,WACdoL,EAAG2D,SAASC,MAAM5D,EAAI3O,YAGxBzF,KAAKiY,QAAQtF,GAzBf,GAAIhS,GAAOT,EAAoB,GAC3BW,EAAUX,EAAoB,EAkClCY,GAASsS,UAAU6E,QAAU,SAAUtF,GACrC,GAAIyC,GAAK7P,EAAGC,CAEZ,IAAIxF,KAAK6S,MAAO,CAEV7S,KAAK6S,MAAMgB,aACb7T,KAAK6S,MAAMgB,YAAY,IAAK7T,KAAKgJ,UAInCoM,IACA,KAAK,GAAI/U,KAAML,MAAK8X,KACd9X,KAAK8X,KAAKjS,eAAexF,IAC3B+U,EAAIlN,KAAK7H,EAGbL,MAAK8X,QACL9X,KAAK8T,SAAS,UAAW7R,MAAOmT,IAKlC,GAFApV,KAAK6S,MAAQF,EAET3S,KAAK6S,MAAO,CAQd,IANA7S,KAAK8S,SAAW9S,KAAK4S,SAASG,SACzB/S,KAAK6S,OAAS7S,KAAK6S,MAAMnE,SAAW1O,KAAK6S,MAAMnE,QAAQqE,SACxD,KAGJqC,EAAMpV,KAAK6S,MAAMiD,QAAQlC,OAAQ5T,KAAK4S,UAAY5S,KAAK4S,SAASgB,SAC3DrO,EAAI,EAAGC,EAAM4P,EAAI1P,OAAYF,EAAJD,EAASA,IACrClF,EAAK+U,EAAI7P,GACTvF,KAAK8X,KAAKzX,IAAM,CAElBL,MAAK8T,SAAS,OAAQ7R,MAAOmT,IAGzBpV,KAAK6S,MAAMW,IACbxT,KAAK6S,MAAMW,GAAG,IAAKxT,KAAKgJ,YAuC9BlI,EAASsS,UAAU+B,IAAM,WACvB,GAGIC,GAAK1G,EAASiE,EAHdyB,EAAKpU,KAILqV,EAAY1U,EAAKuG,QAAQzB,UAAU,GACtB,WAAb4P,GAAsC,UAAbA,GAAsC,SAAbA,GAEpDD,EAAM3P,UAAU,GAChBiJ,EAAUjJ,UAAU,GACpBkN,EAAOlN,UAAU,KAIjBiJ,EAAUjJ,UAAU,GACpBkN,EAAOlN,UAAU,GAInB,IAAIyS,GAAcvX,EAAK0E,UAAWrF,KAAK4S,SAAUlE,EAG7C1O,MAAK4S,SAASgB,QAAUlF,GAAWA,EAAQkF,SAC7CsE,EAAYtE,OAAS,SAAUtE,GAC7B,MAAO8E,GAAGxB,SAASgB,OAAOtE,IAASZ,EAAQkF,OAAOtE,IAKtD,IAAI6I,KAOJ,OANW5R,SAAP6O,GACF+C,EAAajQ,KAAKkN,GAEpB+C,EAAajQ,KAAKgQ,GAClBC,EAAajQ,KAAKyK,GAEX3S,KAAK6S,OAAS7S,KAAK6S,MAAMsC,IAAI6C,MAAMhY,KAAK6S,MAAOsF,IAWxDrX,EAASsS,UAAU0C,OAAS,SAAUpH,GACpC,GAAI0G,EAEJ,IAAIpV,KAAK6S,MAAO,CACd,GACIe,GADAwE,EAAgBpY,KAAK4S,SAASgB,MAK9BA,GAFAlF,GAAWA,EAAQkF,OACjBwE,EACO,SAAU9I,GACjB,MAAO8I,GAAc9I,IAASZ,EAAQkF,OAAOtE,IAItCZ,EAAQkF,OAIVwE,EAGXhD,EAAMpV,KAAK6S,MAAMiD,QACflC,OAAQA,EACR8B,MAAOhH,GAAWA,EAAQgH,YAI5BN,KAGF,OAAOA,IAQTtU,EAASsS,UAAU2C,WAAa,WAE9B,IADA,GAAIsC,GAAUrY,KACPqY,YAAmBvX,IACxBuX,EAAUA,EAAQxF,KAEpB,OAAOwF,IAAW,MAYpBvX,EAASsS,UAAU2E,SAAW,SAAUvO,EAAOuK,EAAQC,GACrD,GAAIzO,GAAGC,EAAKnF,EAAIiP,EACZ8F,EAAMrB,GAAUA,EAAO9R,MACvB0Q,EAAO3S,KAAK6S,MACZyF,KACAC,KACAC,IAEJ,IAAIpD,GAAOzC,EAAM,CACf,OAAQnJ,GACN,IAAK,MAEH,IAAKjE,EAAI,EAAGC,EAAM4P,EAAI1P,OAAYF,EAAJD,EAASA,IACrClF,EAAK+U,EAAI7P,GACT+J,EAAOtP,KAAKmV,IAAI9U,GACZiP,IACFtP,KAAK8X,KAAKzX,IAAM,EAChBiY,EAAMpQ,KAAK7H,GAIf,MAEF,KAAK,SAGH,IAAKkF,EAAI,EAAGC,EAAM4P,EAAI1P,OAAYF,EAAJD,EAASA,IACrClF,EAAK+U,EAAI7P,GACT+J,EAAOtP,KAAKmV,IAAI9U,GAEZiP,EACEtP,KAAK8X,KAAKzX,GACZkY,EAAQrQ,KAAK7H,IAGbL,KAAK8X,KAAKzX,IAAM,EAChBiY,EAAMpQ,KAAK7H,IAITL,KAAK8X,KAAKzX,WACLL,MAAK8X,KAAKzX,GACjBmY,EAAQtQ,KAAK7H,GAQnB,MAEF,KAAK,SAEH,IAAKkF,EAAI,EAAGC,EAAM4P,EAAI1P,OAAYF,EAAJD,EAASA,IACrClF,EAAK+U,EAAI7P,GACLvF,KAAK8X,KAAKzX,WACLL,MAAK8X,KAAKzX,GACjBmY,EAAQtQ,KAAK7H,IAOjBiY,EAAM5S,QACR1F,KAAK8T,SAAS,OAAQ7R,MAAOqW,GAAQtE,GAEnCuE,EAAQ7S,QACV1F,KAAK8T,SAAS,UAAW7R,MAAOsW,GAAUvE,GAExCwE,EAAQ9S,QACV1F,KAAK8T,SAAS,UAAW7R,MAAOuW,GAAUxE,KAMhDlT,EAASsS,UAAUI,GAAK3S,EAAQuS,UAAUI,GAC1C1S,EAASsS,UAAUO,IAAM9S,EAAQuS,UAAUO,IAC3C7S,EAASsS,UAAUU,SAAWjT,EAAQuS,UAAUU,SAGhDhT,EAASsS,UAAUM,UAAY5S,EAASsS,UAAUI,GAClD1S,EAASsS,UAAUS,YAAc/S,EAASsS,UAAUO,IAEpD9T,EAAOD,QAAUkB,GAIb,SAASjB,GAeb,QAASkB,GAAM2N,GAEb1O,KAAKyY,MAAQ,KACbzY,KAAK2M,IAAM+L,IAGX1Y,KAAKsT,UACLtT,KAAK2Y,SAAW,KAChB3Y,KAAK4Y,UAAY,KAEjB5Y,KAAKmT,WAAWzE,GAgBlB3N,EAAMqS,UAAUD,WAAa,SAAUzE,GACjCA,GAAoC,mBAAlBA,GAAQ+J,QAC5BzY,KAAKyY,MAAQ/J,EAAQ+J,OAEnB/J,GAAkC,mBAAhBA,GAAQ/B,MAC5B3M,KAAK2M,IAAM+B,EAAQ/B,KAGrB3M,KAAK6Y,kBAsBP9X,EAAMsE,OAAS,SAAUrB,EAAQ0K,GAC/B,GAAI2E,GAAQ,GAAItS,GAAM2N,EAEtB,IAAqBnI,SAAjBvC,EAAO8U,MACT,KAAM,IAAIlV,OAAM,6CAElBI,GAAO8U,MAAQ,WACbzF,EAAMyF,QAGR,IAAIC,KACF7C,KAAM,QACN8C,SAAUzS,QAGZ,IAAImI,GAAWA,EAAQjE,QACrB,IAAK,GAAIlF,GAAI,EAAGA,EAAImJ,EAAQjE,QAAQ/E,OAAQH,IAAK,CAC/C,GAAI2Q,GAAOxH,EAAQjE,QAAQlF,EAC3BwT,GAAQ7Q,MACNgO,KAAMA,EACN8C,SAAUhV,EAAOkS,KAEnB7C,EAAM5I,QAAQzG,EAAQkS,GAS1B,MALA7C,GAAMuF,WACJ5U,OAAQA,EACR+U,QAASA,GAGJ1F,GAOTtS,EAAMqS,UAAUG,QAAU,WAGxB,GAFAvT,KAAK8Y,QAED9Y,KAAK4Y,UAAW,CAGlB,IAAK,GAFD5U,GAAShE,KAAK4Y,UAAU5U,OACxB+U,EAAU/Y,KAAK4Y,UAAUG,QACpBxT,EAAI,EAAGA,EAAIwT,EAAQrT,OAAQH,IAAK,CACvC,GAAI0T,GAASF,EAAQxT,EACjB0T,GAAOD,SACThV,EAAOiV,EAAO/C,MAAQ+C,EAAOD,eAGtBhV,GAAOiV,EAAO/C,MAGzBlW,KAAK4Y,UAAY,OASrB7X,EAAMqS,UAAU3I,QAAU,SAASzG,EAAQiV,GACzC,GAAI7E,GAAKpU,KACLgZ,EAAWhV,EAAOiV,EACtB,KAAKD,EACH,KAAM,IAAIpV,OAAM,UAAYqV,EAAS,aAGvCjV,GAAOiV,GAAU,WAGf,IAAK,GADDC,MACK3T,EAAI,EAAGA,EAAIE,UAAUC,OAAQH,IACpC2T,EAAK3T,GAAKE,UAAUF,EAItB6O,GAAGf,OACD6F,KAAMA,EACNC,GAAIH,EACJI,QAASpZ,SASfe,EAAMqS,UAAUC,MAAQ,SAASgG,GAE7BrZ,KAAKsT,OAAOpL,KADO,kBAAVmR,IACSF,GAAIE,GAGLA,GAGnBrZ,KAAK6Y,kBAOP9X,EAAMqS,UAAUyF,eAAiB,WAQ/B,GANI7Y,KAAKsT,OAAO5N,OAAS1F,KAAK2M,KAC5B3M,KAAK8Y,QAIPQ,aAAatZ,KAAK2Y,UACd3Y,KAAKqT,MAAM3N,OAAS,GAA2B,gBAAf1F,MAAKyY,MAAoB,CAC3D,GAAIrE,GAAKpU,IACTA,MAAK2Y,SAAWY,WAAW,WACzBnF,EAAG0E,SACF9Y,KAAKyY,SAOZ1X,EAAMqS,UAAU0F,MAAQ,WACtB,KAAO9Y,KAAKsT,OAAO5N,OAAS,GAAG,CAC7B,GAAI2T,GAAQrZ,KAAKsT,OAAO/B,OACxB8H,GAAMF,GAAGnB,MAAMqB,EAAMD,SAAWC,EAAMF,GAAIE,EAAMH,YAIpDrZ,EAAOD,QAAUmB,GAKb,SAASlB,EAAQD,EAASM,GAwB9B,QAASc,GAAQwY,EAAW7G,EAAMjE,GAChC,KAAM1O,eAAgBgB,IACpB,KAAM,IAAIyY,aAAY,mDAIxBzZ,MAAK0Z,iBAAmBF,EACxBxZ,KAAKwS,MAAQ,QACbxS,KAAKyS,OAAS,QACdzS,KAAK2Z,OAAS,GACd3Z,KAAK4Z,eAAiB,MACtB5Z,KAAK6Z,eAAiB,MAEtB7Z,KAAK8Z,OAAS,IACd9Z,KAAK+Z,OAAS,IACd/Z,KAAKga,OAAS,GAEd,IAAIC,GAAc,SAASnO,GAAK,MAAOA,GACvC9L,MAAKka,YAAcD,EACnBja,KAAKma,YAAcF,EACnBja,KAAKoa,YAAcH,EAEnBja,KAAKqa,YAAc,OACnBra,KAAKsa,YAAc,QAEnBta,KAAKkN,MAAQlM,EAAQuZ,MAAMC,IAC3Bxa,KAAKya,iBAAkB,EACvBza,KAAK0a,UAAW,EAChB1a,KAAK2a,iBAAkB,EACvB3a,KAAK4a,YAAa,EAClB5a,KAAK6a,gBAAiB,EACtB7a,KAAK8a,aAAc,EACnB9a,KAAK+a,cAAgB,GAErB/a,KAAKgb,kBAAoB,IACzBhb,KAAKib,kBAAmB,EAExBjb,KAAKkb,OAAS,GAAIha,GAClBlB,KAAKmb,IAAM,GAAI9Z,GAAQ,EAAG,EAAG,IAE7BrB,KAAKwX,UAAY,KACjBxX,KAAKob,WAAa,KAGlBpb,KAAKqb,KAAO9U,OACZvG,KAAKsb,KAAO/U,OACZvG,KAAKub,KAAOhV,OACZvG,KAAKwb,SAAWjV,OAChBvG,KAAKyb,UAAYlV,OAEjBvG,KAAK0b,KAAO,EACZ1b,KAAK2b,MAAQpV,OACbvG,KAAK4b,KAAO,EACZ5b,KAAK6b,KAAO,EACZ7b,KAAK8b,MAAQvV,OACbvG,KAAK+b,KAAO,EACZ/b,KAAKgc,KAAO,EACZhc,KAAKic,MAAQ1V,OACbvG,KAAKkc,KAAO,EACZlc,KAAKmc,SAAW,EAChBnc,KAAKoc,SAAW,EAChBpc,KAAKqc,UAAY,EACjBrc,KAAKsc,UAAY,EAIjBtc,KAAKuc,UAAY,UACjBvc,KAAKwc,UAAY,UACjBxc,KAAKyc,SAAW,UAChBzc,KAAK0c,eAAiB,UAGtB1c,KAAKsO,SAGLtO,KAAKmT,WAAWzE,GAGZiE,GACF3S,KAAKiY,QAAQtF,GAknEjB,QAASgK,GAAWnT,GAClB,MAAI,WAAaA,GAAcA,EAAMoT,QAC9BpT,EAAMqT,cAAc,IAAMrT,EAAMqT,cAAc,GAAGD,SAAW,EAQrE,QAASE,GAAWtT,GAClB,MAAI,WAAaA,GAAcA,EAAMuT,QAC9BvT,EAAMqT,cAAc,IAAMrT,EAAMqT,cAAc,GAAGE,SAAW,EAnuErE,GAAIC,GAAU9c,EAAoB,IAC9BW,EAAUX,EAAoB,GAC9BY,EAAWZ,EAAoB,GAC/BS,EAAOT,EAAoB,GAC3BmB,EAAUnB,EAAoB,IAC9BkB,EAAUlB,EAAoB,GAC9BgB,EAAShB,EAAoB,GAC7BiB,EAASjB,EAAoB,GAC7BoB,EAASpB,EAAoB,IAC7BqB,EAAarB,EAAoB,GAiGrC8c,GAAQhc,EAAQoS,WAKhBpS,EAAQoS,UAAU6J,UAAY,WAC5Bjd,KAAKkd,MAAQ,GAAI7b,GAAQ,GAAKrB,KAAK4b,KAAO5b,KAAK0b,MAC7C,GAAK1b,KAAK+b,KAAO/b,KAAK6b,MACtB,GAAK7b,KAAKkc,KAAOlc,KAAKgc,OAGpBhc,KAAK2a,kBACH3a,KAAKkd,MAAMlL,EAAIhS,KAAKkd,MAAMjL,EAE5BjS,KAAKkd,MAAMjL,EAAIjS,KAAKkd,MAAMlL,EAI1BhS,KAAKkd,MAAMlL,EAAIhS,KAAKkd,MAAMjL,GAK9BjS,KAAKkd,MAAMC,GAAKnd,KAAK+a,cAIrB/a,KAAKkd,MAAM9V,MAAQ,GAAKpH,KAAKoc,SAAWpc,KAAKmc,SAG7C,IAAIiB,IAAWpd,KAAK4b,KAAO5b,KAAK0b,MAAQ,EAAI1b,KAAKkd,MAAMlL,EACnDqL,GAAWrd,KAAK+b,KAAO/b,KAAK6b,MAAQ,EAAI7b,KAAKkd,MAAMjL,EACnDqL,GAAWtd,KAAKkc,KAAOlc,KAAKgc,MAAQ,EAAIhc,KAAKkd,MAAMC,CACvDnd,MAAKkb,OAAOqC,eAAeH,EAASC,EAASC,IAU/Ctc,EAAQoS,UAAUoK,eAAiB,SAASC,GAC1C,GAAIC,GAAc1d,KAAK2d,2BAA2BF,EAClD,OAAOzd,MAAK4d,4BAA4BF,IAW1C1c,EAAQoS,UAAUuK,2BAA6B,SAASF,GACtD,GAAII,GAAKJ,EAAQzL,EAAIhS,KAAKkd,MAAMlL,EAC9B8L,EAAKL,EAAQxL,EAAIjS,KAAKkd,MAAMjL,EAC5B8L,EAAKN,EAAQN,EAAInd,KAAKkd,MAAMC,EAE5Ba,EAAKhe,KAAKkb,OAAO+C,oBAAoBjM,EACrCkM,EAAKle,KAAKkb,OAAO+C,oBAAoBhM,EACrCkM,EAAKne,KAAKkb,OAAO+C,oBAAoBd,EAGrCiB,EAAQnZ,KAAKoZ,IAAIre,KAAKkb,OAAOoD,oBAAoBtM,GACjDuM,EAAQtZ,KAAKuZ,IAAIxe,KAAKkb,OAAOoD,oBAAoBtM,GACjDyM,EAAQxZ,KAAKoZ,IAAIre,KAAKkb,OAAOoD,oBAAoBrM,GACjDyM,EAAQzZ,KAAKuZ,IAAIxe,KAAKkb,OAAOoD,oBAAoBrM,GACjD0M,EAAQ1Z,KAAKoZ,IAAIre,KAAKkb,OAAOoD,oBAAoBnB,GACjDyB,EAAQ3Z,KAAKuZ,IAAIxe,KAAKkb,OAAOoD,oBAAoBnB,GAGjD0B,EAAKH,GAASC,GAASb,EAAKI,GAAMU,GAASf,EAAKG,IAAOS,GAASV,EAAKI,GACrEW,EAAKV,GAASM,GAASX,EAAKI,GAAMM,GAASE,GAASb,EAAKI,GAAMU,GAASf,EAAKG,KAAQO,GAASK,GAASd,EAAKI,GAAMS,GAASd,EAAGG,IAC9He,EAAKR,GAASG,GAASX,EAAKI,GAAMM,GAASE,GAASb,EAAKI,GAAMU,GAASf,EAAKG,KAAQI,GAASQ,GAASd,EAAKI,GAAMS,GAASd,EAAGG,GAEhI,OAAO,IAAI3c,GAAQwd,EAAIC,EAAIC,IAU7B/d,EAAQoS,UAAUwK,4BAA8B,SAASF,GACvD,GAQIsB,GACAC,EATAC,EAAKlf,KAAKmb,IAAInJ,EAChBmN,EAAKnf,KAAKmb,IAAIlJ,EACdmN,EAAKpf,KAAKmb,IAAIgC,EACd0B,EAAKnB,EAAY1L,EACjB8M,EAAKpB,EAAYzL,EACjB8M,EAAKrB,EAAYP,CAgBnB,OAXInd,MAAKya,iBACPuE,GAAMH,EAAKK,IAAOE,EAAKL,GACvBE,GAAMH,EAAKK,IAAOC,EAAKL,KAGvBC,EAAKH,IAAOO,EAAKpf,KAAKkb,OAAOmE,gBAC7BJ,EAAKH,IAAOM,EAAKpf,KAAKkb,OAAOmE,iBAKxB,GAAIje,GACTpB,KAAKsf,QAAUN,EAAKhf,KAAKuf,MAAMC,OAAOC,YACtCzf,KAAK0f,QAAUT,EAAKjf,KAAKuf,MAAMC,OAAOC,cAO1Cze,EAAQoS,UAAUuM,oBAAsB,SAASC,GAC/C,GAAIC,GAAO,QACPC,EAAS,OACTC,EAAc,CAElB,IAAgC,gBAAtB,GACRF,EAAOD,EACPE,EAAS,OACTC,EAAc,MAEX,IAAgC,gBAAtB,GACgBxZ,SAAzBqZ,EAAgBC,OAAuBA,EAAOD,EAAgBC,MACnCtZ,SAA3BqZ,EAAgBE,SAAyBA,EAASF,EAAgBE,QAClCvZ,SAAhCqZ,EAAgBG,cAA2BA,EAAcH,EAAgBG,iBAE1E,IAAyBxZ,SAApBqZ,EAIR,KAAM,qCAGR5f,MAAKuf,MAAMrS,MAAM0S,gBAAkBC,EACnC7f,KAAKuf,MAAMrS,MAAM8S,YAAcF,EAC/B9f,KAAKuf,MAAMrS,MAAM+S,YAAcF,EAAc,KAC7C/f,KAAKuf,MAAMrS,MAAMgT,YAAc,SAKjClf,EAAQuZ,OACN4F,IAAK,EACLC,SAAU,EACVC,QAAS,EACT7F,IAAM,EACN8F,QAAU,EACVC,SAAU,EACVC,QAAS,EACTC,KAAO,EACPC,KAAM,EACNC,QAAU,GASZ3f,EAAQoS,UAAUwN,gBAAkB,SAASC,GAC3C,OAAQA,GACN,IAAK,MAAW,MAAO7f,GAAQuZ,MAAMC,GACrC,KAAK,WAAa,MAAOxZ,GAAQuZ,MAAM+F,OACvC,KAAK,YAAe,MAAOtf,GAAQuZ,MAAMgG,QACzC,KAAK,WAAa,MAAOvf,GAAQuZ,MAAMiG,OACvC,KAAK,OAAW,MAAOxf,GAAQuZ,MAAMmG,IACrC,KAAK,OAAW,MAAO1f,GAAQuZ,MAAMkG,IACrC,KAAK,UAAa,MAAOzf,GAAQuZ,MAAMoG,OACvC,KAAK,MAAW,MAAO3f,GAAQuZ,MAAM4F,GACrC,KAAK,YAAe,MAAOnf,GAAQuZ,MAAM6F,QACzC,KAAK,WAAa,MAAOpf,GAAQuZ,MAAM8F,QAGzC,MAAO,IAQTrf,EAAQoS,UAAU0N,wBAA0B,SAASnO,GACnD,GAAI3S,KAAKkN,QAAUlM,EAAQuZ,MAAMC,KAC/Bxa,KAAKkN,QAAUlM,EAAQuZ,MAAM+F,SAC7BtgB,KAAKkN,QAAUlM,EAAQuZ,MAAMmG,MAC7B1gB,KAAKkN,QAAUlM,EAAQuZ,MAAMkG,MAC7BzgB,KAAKkN,QAAUlM,EAAQuZ,MAAMoG,SAC7B3gB,KAAKkN,QAAUlM,EAAQuZ,MAAM4F,IAE7BngB,KAAKqb,KAAO,EACZrb,KAAKsb,KAAO,EACZtb,KAAKub,KAAO,EACZvb,KAAKwb,SAAWjV,OAEZoM,EAAK8E,qBAAuB,IAC9BzX,KAAKyb,UAAY,OAGhB,CAAA,GAAIzb,KAAKkN,QAAUlM,EAAQuZ,MAAMgG,UACpCvgB,KAAKkN,QAAUlM,EAAQuZ,MAAMiG,SAC7BxgB,KAAKkN,QAAUlM,EAAQuZ,MAAM6F,UAC7BpgB,KAAKkN,QAAUlM,EAAQuZ,MAAM8F,QAY7B,KAAM,kBAAoBrgB,KAAKkN,MAAQ,GAVvClN,MAAKqb,KAAO,EACZrb,KAAKsb,KAAO,EACZtb,KAAKub,KAAO,EACZvb,KAAKwb,SAAW,EAEZ7I,EAAK8E,qBAAuB,IAC9BzX,KAAKyb,UAAY,KAQvBza,EAAQoS,UAAUsB,gBAAkB,SAAS/B,GAC3C,MAAOA,GAAKjN,QAId1E,EAAQoS,UAAUqE,mBAAqB,SAAS9E,GAC9C,GAAIoO,GAAU,CACd,KAAK,GAAIC,KAAUrO,GAAK,GAClBA,EAAK,GAAG9M,eAAemb,IACzBD,GAGJ,OAAOA,IAIT/f,EAAQoS,UAAU6N,kBAAoB,SAAStO,EAAMqO,GAEnD,IAAK,GADDE,MACK3b,EAAI,EAAGA,EAAIoN,EAAKjN,OAAQH,IACgB,IAA3C2b,EAAexa,QAAQiM,EAAKpN,GAAGyb,KACjCE,EAAehZ,KAAKyK,EAAKpN,GAAGyb,GAGhC,OAAOE,IAITlgB,EAAQoS,UAAU+N,eAAiB,SAASxO,EAAKqO,GAE/C,IAAK,GADDI,IAAUrV,IAAI4G,EAAK,GAAGqO,GAAQrU,IAAIgG,EAAK,GAAGqO,IACrCzb,EAAI,EAAGA,EAAIoN,EAAKjN,OAAQH,IAC3B6b,EAAOrV,IAAM4G,EAAKpN,GAAGyb,KAAWI,EAAOrV,IAAM4G,EAAKpN,GAAGyb,IACrDI,EAAOzU,IAAMgG,EAAKpN,GAAGyb,KAAWI,EAAOzU,IAAMgG,EAAKpN,GAAGyb,GAE3D,OAAOI,IASTpgB,EAAQoS,UAAUiO,gBAAkB,SAAUC,GAC5C,GAAIlN,GAAKpU,IAOT,IAJIA,KAAKqY,SACPrY,KAAKqY,QAAQ1E,IAAI,IAAK3T,KAAKuhB,WAGbhb,SAAZ+a,EAAJ,CAGItb,MAAMC,QAAQqb,KAChBA,EAAU,GAAIzgB,GAAQygB,GAGxB,IAAI3O,EACJ,MAAI2O,YAAmBzgB,IAAWygB,YAAmBxgB,IAInD,KAAM,IAAI8C,OAAM,uCAGlB,IANE+O,EAAO2O,EAAQnM,MAME,GAAfxC,EAAKjN,OAAT,CAGA1F,KAAKqY,QAAUiJ,EACfthB,KAAKwX,UAAY7E,EAGjB3S,KAAKuhB,UAAY,WACfnN,EAAG6D,QAAQ7D,EAAGiE,UAEhBrY,KAAKqY,QAAQ7E,GAAG,IAAKxT,KAAKuhB,WAS1BvhB,KAAKqb,KAAO,IACZrb,KAAKsb,KAAO,IACZtb,KAAKub,KAAO,IACZvb,KAAKwb,SAAW,QAChBxb,KAAKyb,UAAY,SAKb9I,EAAK,GAAG9M,eAAe,WACDU,SAApBvG,KAAKwhB,aACPxhB,KAAKwhB,WAAa,GAAIrgB,GAAOmgB,EAASthB,KAAKyb,UAAWzb,MACtDA,KAAKwhB,WAAWC,kBAAkB,WAAYrN,EAAGsN,WAKrD,IAAIC,GAAW3hB,KAAKkN,OAASlM,EAAQuZ,MAAM4F,KACzCngB,KAAKkN,OAASlM,EAAQuZ,MAAM6F,UAC5BpgB,KAAKkN,OAASlM,EAAQuZ,MAAM8F,OAG9B,IAAIsB,EAAU,CACZ,GAA8Bpb,SAA1BvG,KAAK4hB,iBACP5hB,KAAKqc,UAAYrc,KAAK4hB,qBAEnB,CACH,GAAIC,GAAQ7hB,KAAKihB,kBAAkBtO,EAAK3S,KAAKqb,KAC7Crb,MAAKqc,UAAawF,EAAM,GAAKA,EAAM,IAAO,EAG5C,GAA8Btb,SAA1BvG,KAAK8hB,iBACP9hB,KAAKsc,UAAYtc,KAAK8hB,qBAEnB,CACH,GAAIC,GAAQ/hB,KAAKihB,kBAAkBtO,EAAK3S,KAAKsb,KAC7Ctb,MAAKsc,UAAayF,EAAM,GAAKA,EAAM,IAAO,GAK9C,GAAIC,GAAShiB,KAAKmhB,eAAexO,EAAK3S,KAAKqb,KACvCsG,KACFK,EAAOjW,KAAO/L,KAAKqc,UAAY,EAC/B2F,EAAOrV,KAAO3M,KAAKqc,UAAY,GAEjCrc,KAAK0b,KAA6BnV,SAArBvG,KAAKiiB,YAA6BjiB,KAAKiiB,YAAcD,EAAOjW,IACzE/L,KAAK4b,KAA6BrV,SAArBvG,KAAKkiB,YAA6BliB,KAAKkiB,YAAcF,EAAOrV,IACrE3M,KAAK4b,MAAQ5b,KAAK0b,OAAM1b,KAAK4b,KAAO5b,KAAK0b,KAAO,GACpD1b,KAAK2b,MAA+BpV,SAAtBvG,KAAKmiB,aAA8BniB,KAAKmiB,cAAgBniB,KAAK4b,KAAK5b,KAAK0b,MAAM,CAE3F,IAAI0G,GAASpiB,KAAKmhB,eAAexO,EAAK3S,KAAKsb,KACvCqG;IACFS,EAAOrW,KAAO/L,KAAKsc,UAAY,EAC/B8F,EAAOzV,KAAO3M,KAAKsc,UAAY,GAEjCtc,KAAK6b,KAA6BtV,SAArBvG,KAAKqiB,YAA6BriB,KAAKqiB,YAAcD,EAAOrW,IACzE/L,KAAK+b,KAA6BxV,SAArBvG,KAAKsiB,YAA6BtiB,KAAKsiB,YAAcF,EAAOzV,IACrE3M,KAAK+b,MAAQ/b,KAAK6b,OAAM7b,KAAK+b,KAAO/b,KAAK6b,KAAO,GACpD7b,KAAK8b,MAA+BvV,SAAtBvG,KAAKuiB,aAA8BviB,KAAKuiB,cAAgBviB,KAAK+b,KAAK/b,KAAK6b,MAAM,CAE3F,IAAI2G,GAASxiB,KAAKmhB,eAAexO,EAAK3S,KAAKub,KAM3C,IALAvb,KAAKgc,KAA6BzV,SAArBvG,KAAKyiB,YAA6BziB,KAAKyiB,YAAcD,EAAOzW,IACzE/L,KAAKkc,KAA6B3V,SAArBvG,KAAK0iB,YAA6B1iB,KAAK0iB,YAAcF,EAAO7V,IACrE3M,KAAKkc,MAAQlc,KAAKgc,OAAMhc,KAAKkc,KAAOlc,KAAKgc,KAAO,GACpDhc,KAAKic,MAA+B1V,SAAtBvG,KAAK2iB,aAA8B3iB,KAAK2iB,cAAgB3iB,KAAKkc,KAAKlc,KAAKgc,MAAM,EAErEzV,SAAlBvG,KAAKwb,SAAwB,CAC/B,GAAIoH,GAAa5iB,KAAKmhB,eAAexO,EAAK3S,KAAKwb,SAC/Cxb,MAAKmc,SAAqC5V,SAAzBvG,KAAK6iB,gBAAiC7iB,KAAK6iB,gBAAkBD,EAAW7W,IACzF/L,KAAKoc,SAAqC7V,SAAzBvG,KAAK8iB,gBAAiC9iB,KAAK8iB,gBAAkBF,EAAWjW,IACrF3M,KAAKoc,UAAYpc,KAAKmc,WAAUnc,KAAKoc,SAAWpc,KAAKmc,SAAW,GAItEnc,KAAKid,eAUPjc,EAAQoS,UAAU2P,eAAiB,SAAUpQ,GAE3C,GAAIX,GAAGC,EAAG1M,EAAG4X,EAAG6F,EAAK7Q,EAEjBiJ,IAEJ,IAAIpb,KAAKkN,QAAUlM,EAAQuZ,MAAMkG,MAC/BzgB,KAAKkN,QAAUlM,EAAQuZ,MAAMoG,QAAS,CAKtC,GAAIkB,MACAE,IACJ,KAAKxc,EAAI,EAAGA,EAAIvF,KAAK0U,gBAAgB/B,GAAOpN,IAC1CyM,EAAIW,EAAKpN,GAAGvF,KAAKqb,OAAS,EAC1BpJ,EAAIU,EAAKpN,GAAGvF,KAAKsb,OAAS,EAED,KAArBuG,EAAMnb,QAAQsL,IAChB6P,EAAM3Z,KAAK8J,GAEY,KAArB+P,EAAMrb,QAAQuL,IAChB8P,EAAM7Z,KAAK+J,EAIf,IAAIgR,GAAa,SAAU3d,EAAGa,GAC5B,MAAOb,GAAIa,EAEb0b,GAAM1L,KAAK8M,GACXlB,EAAM5L,KAAK8M,EAGX,IAAIC,KACJ,KAAK3d,EAAI,EAAGA,EAAIoN,EAAKjN,OAAQH,IAAK,CAChCyM,EAAIW,EAAKpN,GAAGvF,KAAKqb,OAAS,EAC1BpJ,EAAIU,EAAKpN,GAAGvF,KAAKsb,OAAS,EAC1B6B,EAAIxK,EAAKpN,GAAGvF,KAAKub,OAAS,CAE1B,IAAI4H,GAAStB,EAAMnb,QAAQsL,GACvBoR,EAASrB,EAAMrb,QAAQuL,EAEA1L,UAAvB2c,EAAWC,KACbD,EAAWC,MAGb,IAAI1F,GAAU,GAAIpc,EAClBoc,GAAQzL,EAAIA,EACZyL,EAAQxL,EAAIA,EACZwL,EAAQN,EAAIA,EAEZ6F,KACAA,EAAI7Q,MAAQsL,EACZuF,EAAIK,MAAQ9c,OACZyc,EAAIM,OAAS/c,OACbyc,EAAIO,OAAS,GAAIliB,GAAQ2Q,EAAGC,EAAGjS,KAAKgc,MAEpCkH,EAAWC,GAAQC,GAAUJ,EAE7B5H,EAAWlT,KAAK8a,GAIlB,IAAKhR,EAAI,EAAGA,EAAIkR,EAAWxd,OAAQsM,IACjC,IAAKC,EAAI,EAAGA,EAAIiR,EAAWlR,GAAGtM,OAAQuM,IAChCiR,EAAWlR,GAAGC,KAChBiR,EAAWlR,GAAGC,GAAGuR,WAAcxR,EAAIkR,EAAWxd,OAAO,EAAKwd,EAAWlR,EAAE,GAAGC,GAAK1L,OAC/E2c,EAAWlR,GAAGC,GAAGwR,SAAcxR,EAAIiR,EAAWlR,GAAGtM,OAAO,EAAKwd,EAAWlR,GAAGC,EAAE,GAAK1L,OAClF2c,EAAWlR,GAAGC,GAAGyR,WACd1R,EAAIkR,EAAWxd,OAAO,GAAKuM,EAAIiR,EAAWlR,GAAGtM,OAAO,EACnDwd,EAAWlR,EAAE,GAAGC,EAAE,GAClB1L,YAOV,KAAKhB,EAAI,EAAGA,EAAIoN,EAAKjN,OAAQH,IAC3B4M,EAAQ,GAAI9Q,GACZ8Q,EAAMH,EAAIW,EAAKpN,GAAGvF,KAAKqb,OAAS,EAChClJ,EAAMF,EAAIU,EAAKpN,GAAGvF,KAAKsb,OAAS,EAChCnJ,EAAMgL,EAAIxK,EAAKpN,GAAGvF,KAAKub,OAAS,EAEVhV,SAAlBvG,KAAKwb,WACPrJ,EAAM/K,MAAQuL,EAAKpN,GAAGvF,KAAKwb,WAAa,GAG1CwH,KACAA,EAAI7Q,MAAQA,EACZ6Q,EAAIO,OAAS,GAAIliB,GAAQ8Q,EAAMH,EAAGG,EAAMF,EAAGjS,KAAKgc,MAChDgH,EAAIK,MAAQ9c,OACZyc,EAAIM,OAAS/c,OAEb6U,EAAWlT,KAAK8a,EAIpB,OAAO5H,IASTpa,EAAQoS,UAAU9E,OAAS,WAEzB,KAAOtO,KAAK0Z,iBAAiBiK,iBAC3B3jB,KAAK0Z,iBAAiBtI,YAAYpR,KAAK0Z,iBAAiBkK,WAG1D5jB,MAAKuf,MAAQ/N,SAASM,cAAc,OACpC9R,KAAKuf,MAAMrS,MAAM2W,SAAW,WAC5B7jB,KAAKuf,MAAMrS,MAAM4W,SAAW,SAG5B9jB,KAAKuf,MAAMC,OAAShO,SAASM,cAAe,UAC5C9R,KAAKuf,MAAMC,OAAOtS,MAAM2W,SAAW,WACnC7jB,KAAKuf,MAAM7N,YAAY1R,KAAKuf,MAAMC,OAGhC,IAAIuE,GAAWvS,SAASM,cAAe,MACvCiS,GAAS7W,MAAM9B,MAAQ,MACvB2Y,EAAS7W,MAAM8W,WAAc,OAC7BD,EAAS7W,MAAM+W,QAAW,OAC1BF,EAASG,UAAa,mDACtBlkB,KAAKuf,MAAMC,OAAO9N,YAAYqS,GAGhC/jB,KAAKuf,MAAM3L,OAASpC,SAASM,cAAe,OAC5C9R,KAAKuf,MAAM3L,OAAO1G,MAAM2W,SAAW,WACnC7jB,KAAKuf,MAAM3L,OAAO1G,MAAMqW,OAAS,MACjCvjB,KAAKuf,MAAM3L,OAAO1G,MAAM1F,KAAO,MAC/BxH,KAAKuf,MAAM3L,OAAO1G,MAAMsF,MAAQ,OAChCxS,KAAKuf,MAAM7N,YAAY1R,KAAKuf,MAAM3L,OAGlC,IAAIQ,GAAKpU,KACLmkB,EAAc,SAAU3a,GAAQ4K,EAAGgQ,aAAa5a,IAChD6a,EAAe,SAAU7a,GAAQ4K,EAAGkQ,cAAc9a,IAClD+a,EAAe,SAAU/a,GAAQ4K,EAAGoQ,SAAShb,IAC7Cib,EAAY,SAAUjb,GAAQ4K,EAAGsQ,WAAWlb,GAGhD7I,GAAKkI,iBAAiB7I,KAAKuf,MAAMC,OAAQ,UAAWmF,WACpDhkB,EAAKkI,iBAAiB7I,KAAKuf,MAAMC,OAAQ,YAAa2E,GACtDxjB,EAAKkI,iBAAiB7I,KAAKuf,MAAMC,OAAQ,aAAc6E,GACvD1jB,EAAKkI,iBAAiB7I,KAAKuf,MAAMC,OAAQ,aAAc+E,GACvD5jB,EAAKkI,iBAAiB7I,KAAKuf,MAAMC,OAAQ,YAAaiF,GAGtDzkB,KAAK0Z,iBAAiBhI,YAAY1R,KAAKuf,QAWzCve,EAAQoS,UAAUwR,QAAU,SAASpS,EAAOC,GAC1CzS,KAAKuf,MAAMrS,MAAMsF,MAAQA,EACzBxS,KAAKuf,MAAMrS,MAAMuF,OAASA,EAE1BzS,KAAK6kB,iBAMP7jB,EAAQoS,UAAUyR,cAAgB,WAChC7kB,KAAKuf,MAAMC,OAAOtS,MAAMsF,MAAQ,OAChCxS,KAAKuf,MAAMC,OAAOtS,MAAMuF,OAAS,OAEjCzS,KAAKuf,MAAMC,OAAOhN,MAAQxS,KAAKuf,MAAMC,OAAOC,YAC5Czf,KAAKuf,MAAMC,OAAO/M,OAASzS,KAAKuf,MAAMC,OAAOsF,aAG7C9kB,KAAKuf,MAAM3L,OAAO1G,MAAMsF,MAASxS,KAAKuf,MAAMC,OAAOC,YAAc,GAAU,MAM7Eze,EAAQoS,UAAU2R,eAAiB,WACjC,IAAK/kB,KAAKuf,MAAM3L,SAAW5T,KAAKuf,MAAM3L,OAAOoR,OAC3C,KAAM,wBAERhlB,MAAKuf,MAAM3L,OAAOoR,OAAOC,QAO3BjkB,EAAQoS,UAAU8R,cAAgB,WAC3BllB,KAAKuf,MAAM3L,QAAW5T,KAAKuf,MAAM3L,OAAOoR,QAE7ChlB,KAAKuf,MAAM3L,OAAOoR,OAAOG,QAU3BnkB,EAAQoS,UAAUgS,cAAgB,WAG9BplB,KAAKsf,QAD0D,MAA7Dtf,KAAK4Z,eAAeyL,OAAOrlB,KAAK4Z,eAAelU,OAAO,GAEtD4f,WAAWtlB,KAAK4Z,gBAAkB,IAChC5Z,KAAKuf,MAAMC,OAAOC,YAGP6F,WAAWtlB,KAAK4Z,gBAK/B5Z,KAAK0f,QAD0D,MAA7D1f,KAAK6Z,eAAewL,OAAOrlB,KAAK6Z,eAAenU,OAAO,GAEtD4f,WAAWtlB,KAAK6Z,gBAAkB,KAC/B7Z,KAAKuf,MAAMC,OAAOsF,aAAe9kB,KAAKuf,MAAM3L,OAAOkR,cAGzCQ,WAAWtlB,KAAK6Z,iBAoBnC7Y,EAAQoS,UAAUmS,kBAAoB,SAASC,GACjCjf,SAARif,IAImBjf,SAAnBif,EAAIC,YAA6Clf,SAAjBif,EAAIE,UACtC1lB,KAAKkb,OAAOyK,eAAeH,EAAIC,WAAYD,EAAIE,UAG5Bnf,SAAjBif,EAAII,UACN5lB,KAAKkb,OAAO2K,aAAaL,EAAII,UAG/B5lB,KAAK0hB,WASP1gB,EAAQoS,UAAU0S,kBAAoB,WACpC,GAAIN,GAAMxlB,KAAKkb,OAAO6K,gBAEtB,OADAP,GAAII,SAAW5lB,KAAKkb,OAAOmE,eACpBmG,GAMTxkB,EAAQoS,UAAU4S,UAAY,SAASrT,GAErC3S,KAAKqhB,gBAAgB1O,EAAM3S,KAAKkN,OAK9BlN,KAAKob,WAFHpb,KAAKwhB,WAEWxhB,KAAKwhB,WAAWuB,iBAIhB/iB,KAAK+iB,eAAe/iB,KAAKwX,WAI7CxX,KAAKimB,iBAOPjlB,EAAQoS,UAAU6E,QAAU,SAAUtF,GACpC3S,KAAKgmB,UAAUrT,GACf3S,KAAK0hB,SAGD1hB,KAAKkmB,oBAAsBlmB,KAAKwhB,YAClCxhB,KAAK+kB,kBAQT/jB,EAAQoS,UAAUD,WAAa,SAAUzE,GACvC,GAAIyX,GAAiB5f,MAIrB,IAFAvG,KAAKklB,gBAEW3e,SAAZmI,EAAuB,CAkBzB,GAhBsBnI,SAAlBmI,EAAQ8D,QAA2BxS,KAAKwS,MAAQ9D,EAAQ8D,OACrCjM,SAAnBmI,EAAQ+D,SAA2BzS,KAAKyS,OAAS/D,EAAQ+D,QAErClM,SAApBmI,EAAQ0O,UAA2Bpd,KAAK4Z,eAAiBlL,EAAQ0O,SAC7C7W,SAApBmI,EAAQ2O,UAA2Brd,KAAK6Z,eAAiBnL,EAAQ2O,SAEzC9W,SAAxBmI,EAAQ2L,cAA+Bra,KAAKqa,YAAc3L,EAAQ2L,aAC1C9T,SAAxBmI,EAAQ4L,cAA+Bta,KAAKsa,YAAc5L,EAAQ4L,aAC/C/T,SAAnBmI,EAAQoL,SAA0B9Z,KAAK8Z,OAASpL,EAAQoL,QACrCvT,SAAnBmI,EAAQqL,SAA0B/Z,KAAK+Z,OAASrL,EAAQqL,QACrCxT,SAAnBmI,EAAQsL,SAA0Bha,KAAKga,OAAStL,EAAQsL,QAEhCzT,SAAxBmI,EAAQwL,cAA+Bla,KAAKka,YAAcxL,EAAQwL,aAC1C3T,SAAxBmI,EAAQyL,cAA+Bna,KAAKma,YAAczL,EAAQyL,aAC1C5T,SAAxBmI,EAAQ0L,cAA+Bpa,KAAKoa,YAAc1L,EAAQ0L,aAEhD7T,SAAlBmI,EAAQxB,MAAqB,CAC/B,GAAIkZ,GAAcpmB,KAAK4gB,gBAAgBlS,EAAQxB,MAC3B,MAAhBkZ,IACFpmB,KAAKkN,MAAQkZ,GAGQ7f,SAArBmI,EAAQgM,WAA6B1a,KAAK0a,SAAWhM,EAAQgM,UACjCnU,SAA5BmI,EAAQ+L,kBAAiCza,KAAKya,gBAAkB/L,EAAQ+L,iBACjDlU,SAAvBmI,EAAQkM,aAA6B5a,KAAK4a,WAAalM,EAAQkM,YAC3CrU,SAApBmI,EAAQ2X,UAA6BrmB,KAAK8a,YAAcpM,EAAQ2X,SAC9B9f,SAAlCmI,EAAQ4X,wBAAqCtmB,KAAKsmB,sBAAwB5X,EAAQ4X,uBACtD/f,SAA5BmI,EAAQiM,kBAAiC3a,KAAK2a,gBAAkBjM,EAAQiM,iBAC9CpU,SAA1BmI,EAAQqM,gBAA+B/a,KAAK+a,cAAgBrM,EAAQqM,eAEtCxU,SAA9BmI,EAAQsM,oBAAiChb,KAAKgb,kBAAoBtM,EAAQsM,mBAC7CzU,SAA7BmI,EAAQuM,mBAAiCjb,KAAKib,iBAAmBvM,EAAQuM,kBAC1C1U,SAA/BmI,EAAQwX,qBAAiClmB,KAAKkmB,mBAAqBxX,EAAQwX,oBAErD3f,SAAtBmI,EAAQ2N,YAAyBrc,KAAK4hB,iBAAmBlT,EAAQ2N,WAC3C9V,SAAtBmI,EAAQ4N,YAAyBtc,KAAK8hB,iBAAmBpT,EAAQ4N,WAEhD/V,SAAjBmI,EAAQgN,OAAoB1b,KAAKiiB,YAAcvT,EAAQgN,MACrCnV,SAAlBmI,EAAQiN,QAAqB3b,KAAKmiB,aAAezT,EAAQiN,OACxCpV,SAAjBmI,EAAQkN,OAAoB5b,KAAKkiB,YAAcxT,EAAQkN,MACtCrV,SAAjBmI,EAAQmN,OAAoB7b,KAAKqiB,YAAc3T,EAAQmN,MACrCtV,SAAlBmI,EAAQoN,QAAqB9b,KAAKuiB,aAAe7T,EAAQoN,OACxCvV,SAAjBmI,EAAQqN,OAAoB/b,KAAKsiB,YAAc5T,EAAQqN,MACtCxV,SAAjBmI,EAAQsN,OAAoBhc,KAAKyiB,YAAc/T,EAAQsN,MACrCzV,SAAlBmI,EAAQuN,QAAqBjc,KAAK2iB,aAAejU,EAAQuN,OACxC1V,SAAjBmI,EAAQwN,OAAoBlc,KAAK0iB,YAAchU,EAAQwN,MAClC3V,SAArBmI,EAAQyN,WAAwBnc,KAAK6iB,gBAAkBnU,EAAQyN,UAC1C5V,SAArBmI,EAAQ0N,WAAwBpc,KAAK8iB,gBAAkBpU,EAAQ0N,UAEpC7V,SAA3BmI,EAAQyX,iBAA8BA,EAAiBzX,EAAQyX,gBAE5C5f,SAAnB4f,GACFnmB,KAAKkb,OAAOyK,eAAeQ,EAAeV,WAAYU,EAAeT,UACrE1lB,KAAKkb,OAAO2K,aAAaM,EAAeP,YAGxC5lB,KAAKkb,OAAOyK,eAAe,EAAK,IAChC3lB,KAAKkb,OAAO2K,aAAa,MAI7B7lB,KAAK2f,oBAAoBjR,GAAWA,EAAQkR,iBAE5C5f,KAAK4kB,QAAQ5kB,KAAKwS,MAAOxS,KAAKyS,QAG1BzS,KAAKwX,WACPxX,KAAKiY,QAAQjY,KAAKwX,WAIhBxX,KAAKkmB,oBAAsBlmB,KAAKwhB,YAClCxhB,KAAK+kB,kBAOT/jB,EAAQoS,UAAUsO,OAAS,WACzB,GAAwBnb,SAApBvG,KAAKob,WACP,KAAM,mCAGRpb,MAAK6kB,gBACL7kB,KAAKolB,gBACLplB,KAAKumB,gBACLvmB,KAAKwmB,eACLxmB,KAAKymB,cAEDzmB,KAAKkN,QAAUlM,EAAQuZ,MAAMkG,MAC/BzgB,KAAKkN,QAAUlM,EAAQuZ,MAAMoG,QAC7B3gB,KAAK0mB,kBAEE1mB,KAAKkN,QAAUlM,EAAQuZ,MAAMmG,KACpC1gB,KAAK2mB,kBAEE3mB,KAAKkN,QAAUlM,EAAQuZ,MAAM4F,KACpCngB,KAAKkN,QAAUlM,EAAQuZ,MAAM6F,UAC7BpgB,KAAKkN,QAAUlM,EAAQuZ,MAAM8F,QAC7BrgB,KAAK4mB,iBAIL5mB,KAAK6mB,iBAGP7mB,KAAK8mB,cACL9mB,KAAK+mB,iBAMP/lB,EAAQoS,UAAUoT,aAAe,WAC/B,GAAIhH,GAASxf,KAAKuf,MAAMC,OACpBwH,EAAMxH,EAAOyH,WAAW,KAE5BD,GAAIE,UAAU,EAAG,EAAG1H,EAAOhN,MAAOgN,EAAO/M,SAO3CzR,EAAQoS,UAAU2T,cAAgB,WAChC,GAAI9U,EAEJ,IAAIjS,KAAKkN,QAAUlM,EAAQuZ,MAAMgG,UAC/BvgB,KAAKkN,QAAUlM,EAAQuZ,MAAMiG,QAAS,CAEtC,GAEI2G,GAAUC,EAFVC,EAAmC,IAAzBrnB,KAAKuf,MAAME,WAGrBzf,MAAKkN,QAAUlM,EAAQuZ,MAAMiG,SAC/B2G,EAAWE,EAAU,EACrBD,EAAWC,EAAU,EAAc,EAAVA,IAGzBF,EAAW,GACXC,EAAW,GAGb,IAAI3U,GAASxN,KAAK0H,IAA8B,IAA1B3M,KAAKuf,MAAMuF,aAAqB,KAClDld,EAAM5H,KAAK2Z,OACX2N,EAAQtnB,KAAKuf,MAAME,YAAczf,KAAK2Z,OACtCnS,EAAO8f,EAAQF,EACf7D,EAAS3b,EAAM6K,EAGrB,GAAI+M,GAASxf,KAAKuf,MAAMC,OACpBwH,EAAMxH,EAAOyH,WAAW,KAI5B,IAHAD,EAAIO,UAAY,EAChBP,EAAIQ,KAAO,aAEPxnB,KAAKkN,QAAUlM,EAAQuZ,MAAMgG,SAAU,CAEzC,GAAIkH,GAAO,EACPC,EAAOjV,CACX,KAAKR,EAAIwV,EAAUC,EAAJzV,EAAUA,IAAK,CAC5B,GAAIpE,IAAKoE,EAAIwV,IAASC,EAAOD,GAGzB5a,EAAU,IAAJgB,EACNzC,EAAQpL,KAAK2nB,SAAS9a,EAAK,EAAG,EAElCma,GAAIY,YAAcxc,EAClB4b,EAAIa,YACJb,EAAIc,OAAOtgB,EAAMI,EAAMqK,GACvB+U,EAAIe,OAAOT,EAAO1f,EAAMqK,GACxB+U,EAAIlH,SAGNkH,EAAIY,YAAe5nB,KAAKuc,UACxByK,EAAIgB,WAAWxgB,EAAMI,EAAKwf,EAAU3U,GAiBtC,GAdIzS,KAAKkN,QAAUlM,EAAQuZ,MAAMiG,UAE/BwG,EAAIY,YAAe5nB,KAAKuc,UACxByK,EAAIiB,UAAajoB,KAAKyc,SACtBuK,EAAIa,YACJb,EAAIc,OAAOtgB,EAAMI,GACjBof,EAAIe,OAAOT,EAAO1f,GAClBof,EAAIe,OAAOT,EAAQF,EAAWD,EAAU5D,GACxCyD,EAAIe,OAAOvgB,EAAM+b,GACjByD,EAAIkB,YACJlB,EAAInH,OACJmH,EAAIlH,UAGF9f,KAAKkN,QAAUlM,EAAQuZ,MAAMgG,UAC/BvgB,KAAKkN,QAAUlM,EAAQuZ,MAAMiG,QAAS,CAEtC,GAAI2H,GAAc,EACdC,EAAO,GAAI7mB,GAAWvB,KAAKmc,SAAUnc,KAAKoc,UAAWpc,KAAKoc,SAASpc,KAAKmc,UAAU,GAAG,EAKzF,KAJAiM,EAAKvY,QACDuY,EAAKC,aAAeroB,KAAKmc,UAC3BiM,EAAKE,QAECF,EAAKtY,OACXmC,EAAIsR,GAAU6E,EAAKC,aAAeroB,KAAKmc,WAAanc,KAAKoc,SAAWpc,KAAKmc,UAAY1J,EAErFuU,EAAIa,YACJb,EAAIc,OAAOtgB,EAAO2gB,EAAalW,GAC/B+U,EAAIe,OAAOvgB,EAAMyK,GACjB+U,EAAIlH,SAEJkH,EAAIuB,UAAY,QAChBvB,EAAIwB,aAAe,SACnBxB,EAAIiB,UAAYjoB,KAAKuc,UACrByK,EAAIyB,SAASL,EAAKC,aAAc7gB,EAAO,EAAI2gB,EAAalW,GAExDmW,EAAKE,MAGPtB,GAAIuB,UAAY,QAChBvB,EAAIwB,aAAe,KACnB,IAAIE,GAAQ1oB,KAAKsa,WACjB0M,GAAIyB,SAASC,EAAOpB,EAAO/D,EAASvjB,KAAK2Z,UAO7C3Y,EAAQoS,UAAU6S,cAAgB,WAGhC,GAFAjmB,KAAKuf,MAAM3L,OAAOsQ,UAAY,GAE1BlkB,KAAKwhB,WAAY,CACnB,GAAI9S,IACFia,QAAW3oB,KAAKsmB,uBAEdtB,EAAS,GAAI1jB,GAAOtB,KAAKuf,MAAM3L,OAAQlF,EAC3C1O,MAAKuf,MAAM3L,OAAOoR,OAASA,EAG3BhlB,KAAKuf,MAAM3L,OAAO1G,MAAM+W,QAAU,OAGlCe,EAAO4D,UAAU5oB,KAAKwhB,WAAWzK,QACjCiO,EAAO6D,gBAAgB7oB,KAAKgb,kBAG5B,IAAI5G,GAAKpU,KACL8oB,EAAW,WACb,GAAIzgB,GAAQ2c,EAAO+D,UAEnB3U,GAAGoN,WAAWwH,YAAY3gB,GAC1B+L,EAAGgH,WAAahH,EAAGoN,WAAWuB,iBAE9B3O,EAAGsN,SAELsD,GAAOiE,oBAAoBH,OAG3B9oB,MAAKuf,MAAM3L,OAAOoR,OAASze,QAO/BvF,EAAQoS,UAAUmT,cAAgB,WACEhgB,SAA7BvG,KAAKuf,MAAM3L,OAAOoR,QACrBhlB,KAAKuf,MAAM3L,OAAOoR,OAAOtD,UAQ7B1gB,EAAQoS,UAAU0T,YAAc,WAC9B,GAAI9mB,KAAKwhB,WAAY,CACnB,GAAIhC,GAASxf,KAAKuf,MAAMC,OACpBwH,EAAMxH,EAAOyH,WAAW,KAE5BD,GAAIQ,KAAO,aACXR,EAAIkC,UAAY,OAChBlC,EAAIiB,UAAY,OAChBjB,EAAIuB,UAAY,OAChBvB,EAAIwB,aAAe,KAEnB,IAAIxW,GAAIhS,KAAK2Z,OACT1H,EAAIjS,KAAK2Z,MACbqN,GAAIyB,SAASzoB,KAAKwhB,WAAW2H,WAAa,KAAOnpB,KAAKwhB,WAAW4H,mBAAoBpX,EAAGC,KAQ5FjR,EAAQoS,UAAUqT,YAAc,WAC9B,GAEE4C,GAAMC,EAAIlB,EAAMmB,EAChBC,EAAMC,EAAOC,EAAOC,EACpBC,EAAQC,EAASC,EACjBC,EAAQC,EALNxK,EAASxf,KAAKuf,MAAMC,OACtBwH,EAAMxH,EAAOyH,WAAW,KAQ1BD,GAAIQ,KAAO,GAAKxnB,KAAKkb,OAAOmE,eAAiB,UAG7C,IAAI4K,GAAW,KAAQjqB,KAAKkd,MAAMlL,EAC9BkY,EAAW,KAAQlqB,KAAKkd,MAAMjL,EAC9BkY,EAAa,EAAInqB,KAAKkb,OAAOmE,eAC7B+K,EAAWpqB,KAAKkb,OAAO6K,iBAAiBN,UAU5C,KAPAuB,EAAIO,UAAY,EAChBgC,EAAoChjB,SAAtBvG,KAAKmiB,aACnBiG,EAAO,GAAI7mB,GAAWvB,KAAK0b,KAAM1b,KAAK4b,KAAM5b,KAAK2b,MAAO4N,GACxDnB,EAAKvY,QACDuY,EAAKC,aAAeroB,KAAK0b,MAC3B0M,EAAKE,QAECF,EAAKtY,OAAO,CAClB,GAAIkC,GAAIoW,EAAKC,YAETroB,MAAK0a,UACP2O,EAAOrpB,KAAKwd,eAAe,GAAInc,GAAQ2Q,EAAGhS,KAAK6b,KAAM7b,KAAKgc,OAC1DsN,EAAKtpB,KAAKwd,eAAe,GAAInc,GAAQ2Q,EAAGhS,KAAK+b,KAAM/b,KAAKgc,OACxDgL,EAAIY,YAAc5nB,KAAKwc,UACvBwK,EAAIa,YACJb,EAAIc,OAAOuB,EAAKrX,EAAGqX,EAAKpX,GACxB+U,EAAIe,OAAOuB,EAAGtX,EAAGsX,EAAGrX,GACpB+U,EAAIlH,WAGJuJ,EAAOrpB,KAAKwd,eAAe,GAAInc,GAAQ2Q,EAAGhS,KAAK6b,KAAM7b,KAAKgc,OAC1DsN,EAAKtpB,KAAKwd,eAAe,GAAInc,GAAQ2Q,EAAGhS,KAAK6b,KAAKoO,EAAUjqB,KAAKgc,OACjEgL,EAAIY,YAAc5nB,KAAKuc,UACvByK,EAAIa,YACJb,EAAIc,OAAOuB,EAAKrX,EAAGqX,EAAKpX,GACxB+U,EAAIe,OAAOuB,EAAGtX,EAAGsX,EAAGrX,GACpB+U,EAAIlH,SAEJuJ,EAAOrpB,KAAKwd,eAAe,GAAInc,GAAQ2Q,EAAGhS,KAAK+b,KAAM/b,KAAKgc,OAC1DsN,EAAKtpB,KAAKwd,eAAe,GAAInc,GAAQ2Q,EAAGhS,KAAK+b,KAAKkO,EAAUjqB,KAAKgc,OACjEgL,EAAIY,YAAc5nB,KAAKuc,UACvByK,EAAIa,YACJb,EAAIc,OAAOuB,EAAKrX,EAAGqX,EAAKpX,GACxB+U,EAAIe,OAAOuB,EAAGtX,EAAGsX,EAAGrX,GACpB+U,EAAIlH,UAGN4J,EAASzkB,KAAKuZ,IAAI4L,GAAY,EAAKpqB,KAAK6b,KAAO7b,KAAK+b,KACpDyN,EAAOxpB,KAAKwd,eAAe,GAAInc,GAAQ2Q,EAAG0X,EAAO1pB,KAAKgc,OAClD/W,KAAKuZ,IAAe,EAAX4L,GAAgB,GAC3BpD,EAAIuB,UAAY,SAChBvB,EAAIwB,aAAe,MACnBgB,EAAKvX,GAAKkY,GAEHllB,KAAKoZ,IAAe,EAAX+L,GAAgB,GAChCpD,EAAIuB,UAAY,QAChBvB,EAAIwB,aAAe,WAGnBxB,EAAIuB,UAAY,OAChBvB,EAAIwB,aAAe,UAErBxB,EAAIiB,UAAYjoB,KAAKuc,UACrByK,EAAIyB,SAAS,KAAOzoB,KAAKka,YAAYkO,EAAKC,cAAgB,KAAMmB,EAAKxX,EAAGwX,EAAKvX,GAE7EmW,EAAKE,OAWP,IAPAtB,EAAIO,UAAY,EAChBgC,EAAoChjB,SAAtBvG,KAAKuiB,aACnB6F,EAAO,GAAI7mB,GAAWvB,KAAK6b,KAAM7b,KAAK+b,KAAM/b,KAAK8b,MAAOyN,GACxDnB,EAAKvY,QACDuY,EAAKC,aAAeroB,KAAK6b,MAC3BuM,EAAKE,QAECF,EAAKtY,OACP9P,KAAK0a,UACP2O,EAAOrpB,KAAKwd,eAAe,GAAInc,GAAQrB,KAAK0b,KAAM0M,EAAKC,aAAcroB,KAAKgc,OAC1EsN,EAAKtpB,KAAKwd,eAAe,GAAInc,GAAQrB,KAAK4b,KAAMwM,EAAKC,aAAcroB,KAAKgc,OACxEgL,EAAIY,YAAc5nB,KAAKwc,UACvBwK,EAAIa,YACJb,EAAIc,OAAOuB,EAAKrX,EAAGqX,EAAKpX,GACxB+U,EAAIe,OAAOuB,EAAGtX,EAAGsX,EAAGrX,GACpB+U,EAAIlH,WAGJuJ,EAAOrpB,KAAKwd,eAAe,GAAInc,GAAQrB,KAAK0b,KAAM0M,EAAKC,aAAcroB,KAAKgc,OAC1EsN,EAAKtpB,KAAKwd,eAAe,GAAInc,GAAQrB,KAAK0b,KAAKwO,EAAU9B,EAAKC,aAAcroB,KAAKgc,OACjFgL,EAAIY,YAAc5nB,KAAKuc,UACvByK,EAAIa,YACJb,EAAIc,OAAOuB,EAAKrX,EAAGqX,EAAKpX,GACxB+U,EAAIe,OAAOuB,EAAGtX,EAAGsX,EAAGrX,GACpB+U,EAAIlH,SAEJuJ,EAAOrpB,KAAKwd,eAAe,GAAInc,GAAQrB,KAAK4b,KAAMwM,EAAKC,aAAcroB,KAAKgc,OAC1EsN,EAAKtpB,KAAKwd,eAAe,GAAInc,GAAQrB,KAAK4b,KAAKsO,EAAU9B,EAAKC,aAAcroB,KAAKgc,OACjFgL,EAAIY,YAAc5nB,KAAKuc,UACvByK,EAAIa,YACJb,EAAIc,OAAOuB,EAAKrX,EAAGqX,EAAKpX,GACxB+U,EAAIe,OAAOuB,EAAGtX,EAAGsX,EAAGrX,GACpB+U,EAAIlH,UAGN2J,EAASxkB,KAAKoZ,IAAI+L,GAAa,EAAKpqB,KAAK0b,KAAO1b,KAAK4b,KACrD4N,EAAOxpB,KAAKwd,eAAe,GAAInc,GAAQooB,EAAOrB,EAAKC,aAAcroB,KAAKgc,OAClE/W,KAAKuZ,IAAe,EAAX4L,GAAgB,GAC3BpD,EAAIuB,UAAY,SAChBvB,EAAIwB,aAAe,MACnBgB,EAAKvX,GAAKkY,GAEHllB,KAAKoZ,IAAe,EAAX+L,GAAgB,GAChCpD,EAAIuB,UAAY,QAChBvB,EAAIwB,aAAe,WAGnBxB,EAAIuB,UAAY,OAChBvB,EAAIwB,aAAe,UAErBxB,EAAIiB,UAAYjoB,KAAKuc,UACrByK,EAAIyB,SAAS,KAAOzoB,KAAKma,YAAYiO,EAAKC,cAAgB,KAAMmB,EAAKxX,EAAGwX,EAAKvX,GAE7EmW,EAAKE,MAaP,KATAtB,EAAIO,UAAY,EAChBgC,EAAoChjB,SAAtBvG,KAAK2iB,aACnByF,EAAO,GAAI7mB,GAAWvB,KAAKgc,KAAMhc,KAAKkc,KAAMlc,KAAKic,MAAOsN,GACxDnB,EAAKvY,QACDuY,EAAKC,aAAeroB,KAAKgc,MAC3BoM,EAAKE,OAEPmB,EAASxkB,KAAKuZ,IAAI4L,GAAa,EAAKpqB,KAAK0b,KAAO1b,KAAK4b,KACrD8N,EAASzkB,KAAKoZ,IAAI+L,GAAa,EAAKpqB,KAAK6b,KAAO7b,KAAK+b,MAC7CqM,EAAKtY,OAEXuZ,EAAOrpB,KAAKwd,eAAe,GAAInc,GAAQooB,EAAOC,EAAOtB,EAAKC,eAC1DrB,EAAIY,YAAc5nB,KAAKuc,UACvByK,EAAIa,YACJb,EAAIc,OAAOuB,EAAKrX,EAAGqX,EAAKpX,GACxB+U,EAAIe,OAAOsB,EAAKrX,EAAImY,EAAYd,EAAKpX,GACrC+U,EAAIlH,SAEJkH,EAAIuB,UAAY,QAChBvB,EAAIwB,aAAe,SACnBxB,EAAIiB,UAAYjoB,KAAKuc,UACrByK,EAAIyB,SAASzoB,KAAKoa,YAAYgO,EAAKC,cAAgB,IAAKgB,EAAKrX,EAAI,EAAGqX,EAAKpX,GAEzEmW,EAAKE,MAEPtB,GAAIO,UAAY,EAChB8B,EAAOrpB,KAAKwd,eAAe,GAAInc,GAAQooB,EAAOC,EAAO1pB,KAAKgc,OAC1DsN,EAAKtpB,KAAKwd,eAAe,GAAInc,GAAQooB,EAAOC,EAAO1pB,KAAKkc,OACxD8K,EAAIY,YAAc5nB,KAAKuc,UACvByK,EAAIa,YACJb,EAAIc,OAAOuB,EAAKrX,EAAGqX,EAAKpX,GACxB+U,EAAIe,OAAOuB,EAAGtX,EAAGsX,EAAGrX,GACpB+U,EAAIlH,SAGJkH,EAAIO,UAAY,EAEhBwC,EAAS/pB,KAAKwd,eAAe,GAAInc,GAAQrB,KAAK0b,KAAM1b,KAAK6b,KAAM7b,KAAKgc,OACpEgO,EAAShqB,KAAKwd,eAAe,GAAInc,GAAQrB,KAAK4b,KAAM5b,KAAK6b,KAAM7b,KAAKgc,OACpEgL,EAAIY,YAAc5nB,KAAKuc,UACvByK,EAAIa,YACJb,EAAIc,OAAOiC,EAAO/X,EAAG+X,EAAO9X,GAC5B+U,EAAIe,OAAOiC,EAAOhY,EAAGgY,EAAO/X,GAC5B+U,EAAIlH,SAEJiK,EAAS/pB,KAAKwd,eAAe,GAAInc,GAAQrB,KAAK0b,KAAM1b,KAAK+b,KAAM/b,KAAKgc,OACpEgO,EAAShqB,KAAKwd,eAAe,GAAInc,GAAQrB,KAAK4b,KAAM5b,KAAK+b,KAAM/b,KAAKgc,OACpEgL,EAAIY,YAAc5nB,KAAKuc,UACvByK,EAAIa,YACJb,EAAIc,OAAOiC,EAAO/X,EAAG+X,EAAO9X,GAC5B+U,EAAIe,OAAOiC,EAAOhY,EAAGgY,EAAO/X,GAC5B+U,EAAIlH,SAGJkH,EAAIO,UAAY,EAEhB8B,EAAOrpB,KAAKwd,eAAe,GAAInc,GAAQrB,KAAK0b,KAAM1b,KAAK6b,KAAM7b,KAAKgc,OAClEsN,EAAKtpB,KAAKwd,eAAe,GAAInc,GAAQrB,KAAK0b,KAAM1b,KAAK+b,KAAM/b,KAAKgc,OAChEgL,EAAIY,YAAc5nB,KAAKuc,UACvByK,EAAIa,YACJb,EAAIc,OAAOuB,EAAKrX,EAAGqX,EAAKpX,GACxB+U,EAAIe,OAAOuB,EAAGtX,EAAGsX,EAAGrX,GACpB+U,EAAIlH,SAEJuJ,EAAOrpB,KAAKwd,eAAe,GAAInc,GAAQrB,KAAK4b,KAAM5b,KAAK6b,KAAM7b,KAAKgc,OAClEsN,EAAKtpB,KAAKwd,eAAe,GAAInc,GAAQrB,KAAK4b,KAAM5b,KAAK+b,KAAM/b,KAAKgc,OAChEgL,EAAIY,YAAc5nB,KAAKuc,UACvByK,EAAIa,YACJb,EAAIc,OAAOuB,EAAKrX,EAAGqX,EAAKpX,GACxB+U,EAAIe,OAAOuB,EAAGtX,EAAGsX,EAAGrX,GACpB+U,EAAIlH,QAGJ,IAAIhG,GAAS9Z,KAAK8Z,MACdA,GAAOpU,OAAS,IAClBokB,EAAU,GAAM9pB,KAAKkd,MAAMjL,EAC3BwX,GAASzpB,KAAK0b,KAAO1b,KAAK4b,MAAQ,EAClC8N,EAASzkB,KAAKuZ,IAAI4L,GAAY,EAAKpqB,KAAK6b,KAAOiO,EAAS9pB,KAAK+b,KAAO+N,EACpEN,EAAOxpB,KAAKwd,eAAe,GAAInc,GAAQooB,EAAOC,EAAO1pB,KAAKgc,OACtD/W,KAAKuZ,IAAe,EAAX4L,GAAgB,GAC3BpD,EAAIuB,UAAY,SAChBvB,EAAIwB,aAAe,OAEZvjB,KAAKoZ,IAAe,EAAX+L,GAAgB,GAChCpD,EAAIuB,UAAY,QAChBvB,EAAIwB,aAAe,WAGnBxB,EAAIuB,UAAY,OAChBvB,EAAIwB,aAAe,UAErBxB,EAAIiB,UAAYjoB,KAAKuc,UACrByK,EAAIyB,SAAS3O,EAAQ0P,EAAKxX,EAAGwX,EAAKvX,GAIpC,IAAI8H,GAAS/Z,KAAK+Z,MACdA,GAAOrU,OAAS,IAClBmkB,EAAU,GAAM7pB,KAAKkd,MAAMlL,EAC3ByX,EAASxkB,KAAKoZ,IAAI+L,GAAa,EAAKpqB,KAAK0b,KAAOmO,EAAU7pB,KAAK4b,KAAOiO,EACtEH,GAAS1pB,KAAK6b,KAAO7b,KAAK+b,MAAQ,EAClCyN,EAAOxpB,KAAKwd,eAAe,GAAInc,GAAQooB,EAAOC,EAAO1pB,KAAKgc,OACtD/W,KAAKuZ,IAAe,EAAX4L,GAAgB,GAC3BpD,EAAIuB,UAAY,SAChBvB,EAAIwB,aAAe,OAEZvjB,KAAKoZ,IAAe,EAAX+L,GAAgB,GAChCpD,EAAIuB,UAAY,QAChBvB,EAAIwB,aAAe,WAGnBxB,EAAIuB,UAAY,OAChBvB,EAAIwB,aAAe,UAErBxB,EAAIiB,UAAYjoB,KAAKuc,UACrByK,EAAIyB,SAAS1O,EAAQyP,EAAKxX,EAAGwX,EAAKvX,GAIpC,IAAI+H,GAASha,KAAKga,MACdA,GAAOtU,OAAS,IAClBkkB,EAAS,GACTH,EAASxkB,KAAKuZ,IAAI4L,GAAa,EAAKpqB,KAAK0b,KAAO1b,KAAK4b,KACrD8N,EAASzkB,KAAKoZ,IAAI+L,GAAa,EAAKpqB,KAAK6b,KAAO7b,KAAK+b,KACrD4N,GAAS3pB,KAAKgc,KAAOhc,KAAKkc,MAAQ,EAClCsN,EAAOxpB,KAAKwd,eAAe,GAAInc,GAAQooB,EAAOC,EAAOC,IACrD3C,EAAIuB,UAAY,QAChBvB,EAAIwB,aAAe,SACnBxB,EAAIiB,UAAYjoB,KAAKuc,UACrByK,EAAIyB,SAASzO,EAAQwP,EAAKxX,EAAI4X,EAAQJ,EAAKvX,KAU/CjR,EAAQoS,UAAUuU,SAAW,SAAS0C,EAAGC,EAAGC,GAC1C,GAAIC,GAAGC,EAAGC,EAAGC,EAAGC,EAAIC,CAMpB,QAJAF,EAAIJ,EAAID,EACRM,EAAK3lB,KAAKC,MAAMmlB,EAAE,IAClBQ,EAAIF,GAAK,EAAI1lB,KAAK6lB,IAAMT,EAAE,GAAM,EAAK,IAE7BO,GACN,IAAK,GAAGJ,EAAIG,EAAGF,EAAII,EAAGH,EAAI,CAAG,MAC7B,KAAK,GAAGF,EAAIK,EAAGJ,EAAIE,EAAGD,EAAI,CAAG,MAC7B,KAAK,GAAGF,EAAI,EAAGC,EAAIE,EAAGD,EAAIG,CAAG,MAC7B,KAAK,GAAGL,EAAI,EAAGC,EAAII,EAAGH,EAAIC,CAAG,MAC7B,KAAK,GAAGH,EAAIK,EAAGJ,EAAI,EAAGC,EAAIC,CAAG,MAC7B,KAAK,GAAGH,EAAIG,EAAGF,EAAI,EAAGC,EAAIG,CAAG,MAE7B,SAASL,EAAI,EAAGC,EAAI,EAAGC,EAAI,EAG7B,MAAO,OAAS7f,SAAW,IAAF2f,GAAS,IAAM3f,SAAW,IAAF4f,GAAS,IAAM5f,SAAW,IAAF6f,GAAS,KAQpF1pB,EAAQoS,UAAUsT,gBAAkB,WAClC,GAEEvU,GAAOmV,EAAO1f,EAAKmjB,EACnBxlB,EACAylB,EAAgB/C,EAAWL,EAAaL,EACxC3b,EAAGC,EAAGC,EAAGmf,EALPzL,EAASxf,KAAKuf,MAAMC,OACtBwH,EAAMxH,EAAOyH,WAAW,KAO1B,MAAwB1gB,SAApBvG,KAAKob,YAA4Bpb,KAAKob,WAAW1V,QAAU,GAA/D,CAIA,IAAKH,EAAI,EAAGA,EAAIvF,KAAKob,WAAW1V,OAAQH,IAAK,CAC3C,GAAI8d,GAAQrjB,KAAK2d,2BAA2B3d,KAAKob,WAAW7V,GAAG4M,OAC3DmR,EAAStjB,KAAK4d,4BAA4ByF,EAE9CrjB,MAAKob,WAAW7V,GAAG8d,MAAQA,EAC3BrjB,KAAKob,WAAW7V,GAAG+d,OAASA,CAG5B,IAAI4H,GAAclrB,KAAK2d,2BAA2B3d,KAAKob,WAAW7V,GAAGge,OACrEvjB,MAAKob,WAAW7V,GAAG4lB,KAAOnrB,KAAKya,gBAAkByQ,EAAYxlB,UAAYwlB,EAAY/N,EAIvF,GAAIiO,GAAY,SAAU9lB,EAAGa,GAC3B,MAAOA,GAAEglB,KAAO7lB,EAAE6lB,KAIpB,IAFAnrB,KAAKob,WAAWjF,KAAKiV,GAEjBprB,KAAKkN,QAAUlM,EAAQuZ,MAAMoG,SAC/B,IAAKpb,EAAI,EAAGA,EAAIvF,KAAKob,WAAW1V,OAAQH,IAMtC,GALA4M,EAAQnS,KAAKob,WAAW7V,GACxB+hB,EAAQtnB,KAAKob,WAAW7V,GAAGie,WAC3B5b,EAAQ5H,KAAKob,WAAW7V,GAAGke,SAC3BsH,EAAQ/qB,KAAKob,WAAW7V,GAAGme,WAEbnd,SAAV4L,GAAiC5L,SAAV+gB,GAA+B/gB,SAARqB,GAA+BrB,SAAVwkB,EAAqB,CAE1F,GAAI/qB,KAAK6a,gBAAkB7a,KAAK4a,WAAY,CAK1C,GAAIyQ,GAAQhqB,EAAQiqB,SAASP,EAAM1H,MAAOlR,EAAMkR,OAC5CkI,EAAQlqB,EAAQiqB,SAAS1jB,EAAIyb,MAAOiE,EAAMjE,OAC1CmI,EAAenqB,EAAQoqB,aAAaJ,EAAOE,GAC3C/lB,EAAMgmB,EAAa9lB,QAGvBslB,GAAkBQ,EAAarO,EAAI,MAGnC6N,IAAiB,CAGfA,IAEFC,GAAQ9Y,EAAMA,MAAMgL,EAAImK,EAAMnV,MAAMgL,EAAIvV,EAAIuK,MAAMgL,EAAI4N,EAAM5Y,MAAMgL,GAAK,EACvEvR,EAAoE,KAA/D,GAAKqf,EAAOjrB,KAAKgc,MAAQhc,KAAKkd,MAAMC,EAAKnd,KAAK+a,eACnDlP,EAAI,EAEA7L,KAAK4a,YACP9O,EAAI7G,KAAK8G,IAAI,EAAKyf,EAAaxZ,EAAIxM,EAAO,EAAG,GAC7CyiB,EAAYjoB,KAAK2nB,SAAS/b,EAAGC,EAAGC,GAChC8b,EAAcK,IAGdnc,EAAI,EACJmc,EAAYjoB,KAAK2nB,SAAS/b,EAAGC,EAAGC,GAChC8b,EAAc5nB,KAAKuc,aAIrB0L,EAAY,OACZL,EAAc5nB,KAAKuc,WAErBgL,EAAY,GAEZP,EAAIO,UAAYA,EAChBP,EAAIiB,UAAYA,EAChBjB,EAAIY,YAAcA,EAClBZ,EAAIa,YACJb,EAAIc,OAAO3V,EAAMmR,OAAOtR,EAAGG,EAAMmR,OAAOrR,GACxC+U,EAAIe,OAAOT,EAAMhE,OAAOtR,EAAGsV,EAAMhE,OAAOrR,GACxC+U,EAAIe,OAAOgD,EAAMzH,OAAOtR,EAAG+Y,EAAMzH,OAAOrR,GACxC+U,EAAIe,OAAOngB,EAAI0b,OAAOtR,EAAGpK,EAAI0b,OAAOrR,GACpC+U,EAAIkB,YACJlB,EAAInH,OACJmH,EAAIlH,cAKR,KAAKva,EAAI,EAAGA,EAAIvF,KAAKob,WAAW1V,OAAQH,IACtC4M,EAAQnS,KAAKob,WAAW7V,GACxB+hB,EAAQtnB,KAAKob,WAAW7V,GAAGie,WAC3B5b,EAAQ5H,KAAKob,WAAW7V,GAAGke,SAEbld,SAAV4L,IAEAoV,EADEvnB,KAAKya,gBACK,GAAKtI,EAAMkR,MAAMlG,EAGjB,IAAMnd,KAAKmb,IAAIgC,EAAInd,KAAKkb,OAAOmE,iBAIjC9Y,SAAV4L,GAAiC5L,SAAV+gB,IAEzB2D,GAAQ9Y,EAAMA,MAAMgL,EAAImK,EAAMnV,MAAMgL,GAAK,EACzCvR,EAAoE,KAA/D,GAAKqf,EAAOjrB,KAAKgc,MAAQhc,KAAKkd,MAAMC,EAAKnd,KAAK+a,eAEnDiM,EAAIO,UAAYA,EAChBP,EAAIY,YAAc5nB,KAAK2nB,SAAS/b,EAAG,EAAG,GACtCob,EAAIa,YACJb,EAAIc,OAAO3V,EAAMmR,OAAOtR,EAAGG,EAAMmR,OAAOrR,GACxC+U,EAAIe,OAAOT,EAAMhE,OAAOtR,EAAGsV,EAAMhE,OAAOrR,GACxC+U,EAAIlH,UAGQvZ,SAAV4L,GAA+B5L,SAARqB,IAEzBqjB,GAAQ9Y,EAAMA,MAAMgL,EAAIvV,EAAIuK,MAAMgL,GAAK,EACvCvR,EAAoE,KAA/D,GAAKqf,EAAOjrB,KAAKgc,MAAQhc,KAAKkd,MAAMC,EAAKnd,KAAK+a,eAEnDiM,EAAIO,UAAYA,EAChBP,EAAIY,YAAc5nB,KAAK2nB,SAAS/b,EAAG,EAAG,GACtCob,EAAIa,YACJb,EAAIc,OAAO3V,EAAMmR,OAAOtR,EAAGG,EAAMmR,OAAOrR,GACxC+U,EAAIe,OAAOngB,EAAI0b,OAAOtR,EAAGpK,EAAI0b,OAAOrR,GACpC+U,EAAIlH,YAWZ9e,EAAQoS,UAAUyT,eAAiB,WACjC,GAEIthB,GAFAia,EAASxf,KAAKuf,MAAMC,OACpBwH,EAAMxH,EAAOyH,WAAW,KAG5B,MAAwB1gB,SAApBvG,KAAKob,YAA4Bpb,KAAKob,WAAW1V,QAAU,GAA/D,CAIA,IAAKH,EAAI,EAAGA,EAAIvF,KAAKob,WAAW1V,OAAQH,IAAK,CAC3C,GAAI8d,GAAQrjB,KAAK2d,2BAA2B3d,KAAKob,WAAW7V,GAAG4M,OAC3DmR,EAAStjB,KAAK4d,4BAA4ByF,EAC9CrjB,MAAKob,WAAW7V,GAAG8d,MAAQA,EAC3BrjB,KAAKob,WAAW7V,GAAG+d,OAASA,CAG5B,IAAI4H,GAAclrB,KAAK2d,2BAA2B3d,KAAKob,WAAW7V,GAAGge,OACrEvjB,MAAKob,WAAW7V,GAAG4lB,KAAOnrB,KAAKya,gBAAkByQ,EAAYxlB,UAAYwlB,EAAY/N,EAIvF,GAAIiO,GAAY,SAAU9lB,EAAGa,GAC3B,MAAOA,GAAEglB,KAAO7lB,EAAE6lB,KAEpBnrB,MAAKob,WAAWjF,KAAKiV,EAGrB,IAAI/D,GAAmC,IAAzBrnB,KAAKuf,MAAME,WACzB,KAAKla,EAAI,EAAGA,EAAIvF,KAAKob,WAAW1V,OAAQH,IAAK,CAC3C,GAAI4M,GAAQnS,KAAKob,WAAW7V,EAE5B,IAAIvF,KAAKkN,QAAUlM,EAAQuZ,MAAM+F,QAAS,CAGxC,GAAI+I,GAAOrpB,KAAKwd,eAAerL,EAAMoR,OACrCyD,GAAIO,UAAY,EAChBP,EAAIY,YAAc5nB,KAAKwc,UACvBwK,EAAIa,YACJb,EAAIc,OAAOuB,EAAKrX,EAAGqX,EAAKpX,GACxB+U,EAAIe,OAAO5V,EAAMmR,OAAOtR,EAAGG,EAAMmR,OAAOrR,GACxC+U,EAAIlH,SAIN,GAAIxN,EAEFA,GADEtS,KAAKkN,QAAUlM,EAAQuZ,MAAMiG,QACxB6G,EAAQ,EAAI,EAAEA,GAAWlV,EAAMA,MAAM/K,MAAQpH,KAAKmc,WAAanc,KAAKoc,SAAWpc,KAAKmc,UAGpFkL,CAGT,IAAIqE,EAEFA,GADE1rB,KAAKya,gBACEnI,GAAQH,EAAMkR,MAAMlG,EAGpB7K,IAAStS,KAAKmb,IAAIgC,EAAInd,KAAKkb,OAAOmE,gBAEhC,EAATqM,IACFA,EAAS,EAGX,IAAI7e,GAAKzB,EAAO4U,CACZhgB,MAAKkN,QAAUlM,EAAQuZ,MAAMgG,UAE/B1T,EAAqE,KAA9D,GAAKsF,EAAMA,MAAM/K,MAAQpH,KAAKmc,UAAYnc,KAAKkd,MAAM9V,OAC5DgE,EAAQpL,KAAK2nB,SAAS9a,EAAK,EAAG,GAC9BmT,EAAchgB,KAAK2nB,SAAS9a,EAAK,EAAG,KAE7B7M,KAAKkN,QAAUlM,EAAQuZ,MAAMiG,SACpCpV,EAAQpL,KAAKyc,SACbuD,EAAchgB,KAAK0c,iBAInB7P,EAA+E,KAAxE,GAAKsF,EAAMA,MAAMgL,EAAInd,KAAKgc,MAAQhc,KAAKkd,MAAMC,EAAKnd,KAAK+a,eAC9D3P,EAAQpL,KAAK2nB,SAAS9a,EAAK,EAAG,GAC9BmT,EAAchgB,KAAK2nB,SAAS9a,EAAK,EAAG,KAItCma,EAAIO,UAAY,EAChBP,EAAIY,YAAc5H,EAClBgH,EAAIiB,UAAY7c,EAChB4b,EAAIa,YACJb,EAAI2E,IAAIxZ,EAAMmR,OAAOtR,EAAGG,EAAMmR,OAAOrR,EAAGyZ,EAAQ,EAAW,EAARzmB,KAAK2mB,IAAM,GAC9D5E,EAAInH,OACJmH,EAAIlH,YAQR9e,EAAQoS,UAAUwT,eAAiB,WACjC,GAEIrhB,GAAGsmB,EAAGC,EAASC,EAFfvM,EAASxf,KAAKuf,MAAMC,OACpBwH,EAAMxH,EAAOyH,WAAW,KAG5B,MAAwB1gB,SAApBvG,KAAKob,YAA4Bpb,KAAKob,WAAW1V,QAAU,GAA/D,CAIA,IAAKH,EAAI,EAAGA,EAAIvF,KAAKob,WAAW1V,OAAQH,IAAK,CAC3C,GAAI8d,GAAQrjB,KAAK2d,2BAA2B3d,KAAKob,WAAW7V,GAAG4M,OAC3DmR,EAAStjB,KAAK4d,4BAA4ByF,EAC9CrjB,MAAKob,WAAW7V,GAAG8d,MAAQA,EAC3BrjB,KAAKob,WAAW7V,GAAG+d,OAASA,CAG5B,IAAI4H,GAAclrB,KAAK2d,2BAA2B3d,KAAKob,WAAW7V,GAAGge,OACrEvjB,MAAKob,WAAW7V,GAAG4lB,KAAOnrB,KAAKya,gBAAkByQ,EAAYxlB,UAAYwlB,EAAY/N,EAIvF,GAAIiO,GAAY,SAAU9lB,EAAGa,GAC3B,MAAOA,GAAEglB,KAAO7lB,EAAE6lB,KAEpBnrB,MAAKob,WAAWjF,KAAKiV,EAGrB,IAAIY,GAAShsB,KAAKqc,UAAY,EAC1B4P,EAASjsB,KAAKsc,UAAY,CAC9B,KAAK/W,EAAI,EAAGA,EAAIvF,KAAKob,WAAW1V,OAAQH,IAAK,CAC3C,GAGIsH,GAAKzB,EAAO4U,EAHZ7N,EAAQnS,KAAKob,WAAW7V,EAIxBvF,MAAKkN,QAAUlM,EAAQuZ,MAAM6F,UAE/BvT,EAAqE,KAA9D,GAAKsF,EAAMA,MAAM/K,MAAQpH,KAAKmc,UAAYnc,KAAKkd,MAAM9V,OAC5DgE,EAAQpL,KAAK2nB,SAAS9a,EAAK,EAAG,GAC9BmT,EAAchgB,KAAK2nB,SAAS9a,EAAK,EAAG,KAE7B7M,KAAKkN,QAAUlM,EAAQuZ,MAAM8F,SACpCjV,EAAQpL,KAAKyc,SACbuD,EAAchgB,KAAK0c,iBAInB7P,EAA+E,KAAxE,GAAKsF,EAAMA,MAAMgL,EAAInd,KAAKgc,MAAQhc,KAAKkd,MAAMC,EAAKnd,KAAK+a,eAC9D3P,EAAQpL,KAAK2nB,SAAS9a,EAAK,EAAG,GAC9BmT,EAAchgB,KAAK2nB,SAAS9a,EAAK,EAAG,KAIlC7M,KAAKkN,QAAUlM,EAAQuZ,MAAM8F,UAC/B2L,EAAUhsB,KAAKqc,UAAY,IAAOlK,EAAMA,MAAM/K,MAAQpH,KAAKmc,WAAanc,KAAKoc,SAAWpc,KAAKmc,UAAY,GAAM,IAC/G8P,EAAUjsB,KAAKsc,UAAY,IAAOnK,EAAMA,MAAM/K,MAAQpH,KAAKmc,WAAanc,KAAKoc,SAAWpc,KAAKmc,UAAY,GAAM,IAIjH,IAAI/H,GAAKpU,KACLyd,EAAUtL,EAAMA,MAChBvK,IACDuK,MAAO,GAAI9Q,GAAQoc,EAAQzL,EAAIga,EAAQvO,EAAQxL,EAAIga,EAAQxO,EAAQN,KACnEhL,MAAO,GAAI9Q,GAAQoc,EAAQzL,EAAIga,EAAQvO,EAAQxL,EAAIga,EAAQxO,EAAQN,KACnEhL,MAAO,GAAI9Q,GAAQoc,EAAQzL,EAAIga,EAAQvO,EAAQxL,EAAIga,EAAQxO,EAAQN,KACnEhL,MAAO,GAAI9Q,GAAQoc,EAAQzL,EAAIga,EAAQvO,EAAQxL,EAAIga,EAAQxO,EAAQN,KAElEoG,IACDpR,MAAO,GAAI9Q,GAAQoc,EAAQzL,EAAIga,EAAQvO,EAAQxL,EAAIga,EAAQjsB,KAAKgc,QAChE7J,MAAO,GAAI9Q,GAAQoc,EAAQzL,EAAIga,EAAQvO,EAAQxL,EAAIga,EAAQjsB,KAAKgc,QAChE7J,MAAO,GAAI9Q,GAAQoc,EAAQzL,EAAIga,EAAQvO,EAAQxL,EAAIga,EAAQjsB,KAAKgc,QAChE7J,MAAO,GAAI9Q,GAAQoc,EAAQzL,EAAIga,EAAQvO,EAAQxL,EAAIga,EAAQjsB,KAAKgc,OAInEpU,GAAIW,QAAQ,SAAUya,GACpBA,EAAIM,OAASlP,EAAGoJ,eAAewF,EAAI7Q,SAErCoR,EAAOhb,QAAQ,SAAUya,GACvBA,EAAIM,OAASlP,EAAGoJ,eAAewF,EAAI7Q,QAIrC,IAAI+Z,KACDH,QAASnkB,EAAKukB,OAAQ9qB,EAAQ+qB,IAAI7I,EAAO,GAAGpR,MAAOoR,EAAO,GAAGpR,SAC7D4Z,SAAUnkB,EAAI,GAAIA,EAAI,GAAI2b,EAAO,GAAIA,EAAO,IAAK4I,OAAQ9qB,EAAQ+qB,IAAI7I,EAAO,GAAGpR,MAAOoR,EAAO,GAAGpR,SAChG4Z,SAAUnkB,EAAI,GAAIA,EAAI,GAAI2b,EAAO,GAAIA,EAAO,IAAK4I,OAAQ9qB,EAAQ+qB,IAAI7I,EAAO,GAAGpR,MAAOoR,EAAO,GAAGpR,SAChG4Z,SAAUnkB,EAAI,GAAIA,EAAI,GAAI2b,EAAO,GAAIA,EAAO,IAAK4I,OAAQ9qB,EAAQ+qB,IAAI7I,EAAO,GAAGpR,MAAOoR,EAAO,GAAGpR,SAChG4Z,SAAUnkB,EAAI,GAAIA,EAAI,GAAI2b,EAAO,GAAIA,EAAO,IAAK4I,OAAQ9qB,EAAQ+qB,IAAI7I,EAAO,GAAGpR,MAAOoR,EAAO,GAAGpR,QAKnG,KAHAA,EAAM+Z,SAAWA,EAGZL,EAAI,EAAGA,EAAIK,EAASxmB,OAAQmmB,IAAK,CACpCC,EAAUI,EAASL,EACnB,IAAIQ,GAAcrsB,KAAK2d,2BAA2BmO,EAAQK,OAC1DL,GAAQX,KAAOnrB,KAAKya,gBAAkB4R,EAAY3mB,UAAY2mB,EAAYlP,EAwB5E,IAjBA+O,EAAS/V,KAAK,SAAU7Q,EAAGa,GACzB,GAAImmB,GAAOnmB,EAAEglB,KAAO7lB,EAAE6lB,IACtB,OAAImB,GAAaA,EAGbhnB,EAAEymB,UAAYnkB,EAAY,EAC1BzB,EAAE4lB,UAAYnkB,EAAY,GAGvB,IAITof,EAAIO,UAAY,EAChBP,EAAIY,YAAc5H,EAClBgH,EAAIiB,UAAY7c,EAEXygB,EAAI,EAAGA,EAAIK,EAASxmB,OAAQmmB,IAC/BC,EAAUI,EAASL,GACnBE,EAAUD,EAAQC,QAClB/E,EAAIa,YACJb,EAAIc,OAAOiE,EAAQ,GAAGzI,OAAOtR,EAAG+Z,EAAQ,GAAGzI,OAAOrR,GAClD+U,EAAIe,OAAOgE,EAAQ,GAAGzI,OAAOtR,EAAG+Z,EAAQ,GAAGzI,OAAOrR,GAClD+U,EAAIe,OAAOgE,EAAQ,GAAGzI,OAAOtR,EAAG+Z,EAAQ,GAAGzI,OAAOrR,GAClD+U,EAAIe,OAAOgE,EAAQ,GAAGzI,OAAOtR,EAAG+Z,EAAQ,GAAGzI,OAAOrR,GAClD+U,EAAIe,OAAOgE,EAAQ,GAAGzI,OAAOtR,EAAG+Z,EAAQ,GAAGzI,OAAOrR,GAClD+U,EAAInH,OACJmH,EAAIlH,YAUV9e,EAAQoS,UAAUuT,gBAAkB,WAClC,GAEExU,GAAO5M,EAFLia,EAASxf,KAAKuf,MAAMC,OACtBwH,EAAMxH,EAAOyH,WAAW,KAG1B,MAAwB1gB,SAApBvG,KAAKob,YAA4Bpb,KAAKob,WAAW1V,QAAU,GAA/D,CAIA,IAAKH,EAAI,EAAGA,EAAIvF,KAAKob,WAAW1V,OAAQH,IAAK,CAC3C,GAAI8d,GAAQrjB,KAAK2d,2BAA2B3d,KAAKob,WAAW7V,GAAG4M,OAC3DmR,EAAStjB,KAAK4d,4BAA4ByF,EAE9CrjB,MAAKob,WAAW7V,GAAG8d,MAAQA,EAC3BrjB,KAAKob,WAAW7V,GAAG+d,OAASA,EAc9B,IAVItjB,KAAKob,WAAW1V,OAAS,IAC3ByM,EAAQnS,KAAKob,WAAW,GAExB4L,EAAIO,UAAY,EAChBP,EAAIY,YAAc,OAClBZ,EAAIa,YACJb,EAAIc,OAAO3V,EAAMmR,OAAOtR,EAAGG,EAAMmR,OAAOrR,IAIrC1M,EAAI,EAAGA,EAAIvF,KAAKob,WAAW1V,OAAQH,IACtC4M,EAAQnS,KAAKob,WAAW7V,GACxByhB,EAAIe,OAAO5V,EAAMmR,OAAOtR,EAAGG,EAAMmR,OAAOrR,EAItCjS,MAAKob,WAAW1V,OAAS,GAC3BshB,EAAIlH,WASR9e,EAAQoS,UAAUgR,aAAe,SAAS5a,GAWxC,GAVAA,EAAQA,GAAS/B,OAAO+B,MAIpBxJ,KAAKusB,gBACPvsB,KAAKwsB,WAAWhjB,GAIlBxJ,KAAKusB,eAAiB/iB,EAAMijB,MAAyB,IAAhBjjB,EAAMijB,MAAiC,IAAjBjjB,EAAMkjB,OAC5D1sB,KAAKusB,gBAAmBvsB,KAAK2sB,UAAlC,CAGA3sB,KAAK4sB,YAAcjQ,EAAUnT,GAC7BxJ,KAAK6sB,YAAc/P,EAAUtT,GAE7BxJ,KAAK8sB,WAAa,GAAIzoB,MAAKrE,KAAK6P,OAChC7P,KAAK+sB,SAAW,GAAI1oB,MAAKrE,KAAK8P,KAC9B9P,KAAKgtB,iBAAmBhtB,KAAKkb,OAAO6K,iBAEpC/lB,KAAKuf,MAAMrS,MAAM+f,OAAS,MAK1B,IAAI7Y,GAAKpU,IACTA,MAAKktB,YAAc,SAAU1jB,GAAQ4K,EAAG+Y,aAAa3jB,IACrDxJ,KAAKotB,UAAc,SAAU5jB,GAAQ4K,EAAGoY,WAAWhjB,IACnD7I,EAAKkI,iBAAiB2I,SAAU,YAAa4C,EAAG8Y,aAChDvsB,EAAKkI,iBAAiB2I,SAAU,UAAW4C,EAAGgZ,WAC9CzsB,EAAK4I,eAAeC,KAStBxI,EAAQoS,UAAU+Z,aAAe,SAAU3jB,GACzCA,EAAQA,GAAS/B,OAAO+B,KAGxB,IAAI6jB,GAAQ/H,WAAW3I,EAAUnT,IAAUxJ,KAAK4sB,YAC5CU,EAAQhI,WAAWxI,EAAUtT,IAAUxJ,KAAK6sB,YAE5CU,EAAgBvtB,KAAKgtB,iBAAiBvH,WAAa4H,EAAQ,IAC3DG,EAAcxtB,KAAKgtB,iBAAiBtH,SAAW4H,EAAQ,IAEvDG,EAAY,EACZC,EAAYzoB,KAAKoZ,IAAIoP,EAAY,IAAM,EAAIxoB,KAAK2mB,GAIhD3mB,MAAK6lB,IAAI7lB,KAAKoZ,IAAIkP,IAAkBG,IACtCH,EAAgBtoB,KAAK0oB,MAAOJ,EAAgBtoB,KAAK2mB,IAAO3mB,KAAK2mB,GAAK,MAEhE3mB,KAAK6lB,IAAI7lB,KAAKuZ,IAAI+O,IAAkBG,IACtCH,GAAiBtoB,KAAK0oB,MAAOJ,EAAetoB,KAAK2mB,GAAK,IAAQ,IAAO3mB,KAAK2mB,GAAK,MAI7E3mB,KAAK6lB,IAAI7lB,KAAKoZ,IAAImP,IAAgBE,IACpCF,EAAcvoB,KAAK0oB,MAAOH,EAAcvoB,KAAK2mB,IAAO3mB,KAAK2mB,IAEvD3mB,KAAK6lB,IAAI7lB,KAAKuZ,IAAIgP,IAAgBE,IACpCF,GAAevoB,KAAK0oB,MAAOH,EAAavoB,KAAK2mB,GAAK,IAAQ,IAAO3mB,KAAK2mB,IAGxE5rB,KAAKkb,OAAOyK,eAAe4H,EAAeC,GAC1CxtB,KAAK0hB,QAGL,IAAIkM,GAAa5tB,KAAK8lB,mBACtB9lB,MAAK6tB,KAAK,uBAAwBD,GAElCjtB,EAAK4I,eAAeC,IAStBxI,EAAQoS,UAAUoZ,WAAa,SAAUhjB,GACvCxJ,KAAKuf,MAAMrS,MAAM+f,OAAS,OAC1BjtB,KAAKusB,gBAAiB,EAGtB5rB,EAAK0I,oBAAoBmI,SAAU,YAAaxR,KAAKktB,aACrDvsB,EAAK0I,oBAAoBmI,SAAU,UAAaxR,KAAKotB,WACrDzsB,EAAK4I,eAAeC,IAOtBxI,EAAQoS,UAAUsR,WAAa,SAAUlb,GACvC,GAAIiP,GAAQ,IACRqV,EAAe9tB,KAAKuf,MAAMhY,wBAC1BwmB,EAASpR,EAAUnT,GAASskB,EAAatmB,KACzCwmB,EAASlR,EAAUtT,GAASskB,EAAalmB,GAE7C,IAAK5H,KAAK8a,YAAV,CASA,GALI9a,KAAKiuB,gBACP3U,aAAatZ,KAAKiuB,gBAIhBjuB,KAAKusB,eAEP,WADAvsB,MAAKkuB,cAIP,IAAIluB,KAAKqmB,SAAWrmB,KAAKqmB,QAAQ8H,UAAW,CAE1C,GAAIA,GAAYnuB,KAAKouB,iBAAiBL,EAAQC,EAC1CG,KAAcnuB,KAAKqmB,QAAQ8H,YAEzBA,EACFnuB,KAAKquB,aAAaF,GAGlBnuB,KAAKkuB,oBAIN,CAEH,GAAI9Z,GAAKpU,IACTA,MAAKiuB,eAAiB1U,WAAW,WAC/BnF,EAAG6Z,eAAiB,IAGpB,IAAIE,GAAY/Z,EAAGga,iBAAiBL,EAAQC,EACxCG,IACF/Z,EAAGia,aAAaF,IAEjB1V,MAOPzX,EAAQoS,UAAUkR,cAAgB,SAAS9a,GACzCxJ,KAAK2sB,WAAY,CAEjB,IAAIvY,GAAKpU,IACTA,MAAKsuB,YAAc,SAAU9kB,GAAQ4K,EAAGma,aAAa/kB,IACrDxJ,KAAKwuB,WAAc,SAAUhlB,GAAQ4K,EAAGqa,YAAYjlB,IACpD7I,EAAKkI,iBAAiB2I,SAAU,YAAa4C,EAAGka,aAChD3tB,EAAKkI,iBAAiB2I,SAAU,WAAY4C,EAAGoa,YAE/CxuB,KAAKokB,aAAa5a,IAMpBxI,EAAQoS,UAAUmb,aAAe,SAAS/kB,GACxCxJ,KAAKmtB,aAAa3jB,IAMpBxI,EAAQoS,UAAUqb,YAAc,SAASjlB,GACvCxJ,KAAK2sB,WAAY,EAEjBhsB,EAAK0I,oBAAoBmI,SAAU,YAAaxR,KAAKsuB,aACrD3tB,EAAK0I,oBAAoBmI,SAAU,WAAcxR,KAAKwuB,YAEtDxuB,KAAKwsB,WAAWhjB,IASlBxI,EAAQoS,UAAUoR,SAAW,SAAShb,GAC/BA,IACHA,EAAQ/B,OAAO+B,MAGjB,IAAIklB,GAAQ,CAYZ,IAXIllB,EAAMmlB,WACRD,EAAQllB,EAAMmlB,WAAW,IAChBnlB,EAAMolB,SAGfF,GAASllB,EAAMolB,OAAO,GAMpBF,EAAO,CACT,GAAIG,GAAY7uB,KAAKkb,OAAOmE,eACxByP,EAAYD,GAAa,EAAIH,EAAQ,GAEzC1uB,MAAKkb,OAAO2K,aAAaiJ,GACzB9uB,KAAK0hB,SAEL1hB,KAAKkuB,eAIP,GAAIN,GAAa5tB,KAAK8lB,mBACtB9lB,MAAK6tB,KAAK,uBAAwBD,GAKlCjtB,EAAK4I,eAAeC,IAUtBxI,EAAQoS,UAAU2b,gBAAkB,SAAU5c,EAAO6c,GAKnD,QAASC,GAAMjd,GACb,MAAOA,GAAI,EAAI,EAAQ,EAAJA,EAAQ,GAAK,EALlC,GAAI1M,GAAI0pB,EAAS,GACf7oB,EAAI6oB,EAAS,GACbvuB,EAAIuuB,EAAS,GAMXE,EAAKD,GAAM9oB,EAAE6L,EAAI1M,EAAE0M,IAAMG,EAAMF,EAAI3M,EAAE2M,IAAM9L,EAAE8L,EAAI3M,EAAE2M,IAAME,EAAMH,EAAI1M,EAAE0M,IACrEmd,EAAKF,GAAMxuB,EAAEuR,EAAI7L,EAAE6L,IAAMG,EAAMF,EAAI9L,EAAE8L,IAAMxR,EAAEwR,EAAI9L,EAAE8L,IAAME,EAAMH,EAAI7L,EAAE6L,IACrEod,EAAKH,GAAM3pB,EAAE0M,EAAIvR,EAAEuR,IAAMG,EAAMF,EAAIxR,EAAEwR,IAAM3M,EAAE2M,EAAIxR,EAAEwR,IAAME,EAAMH,EAAIvR,EAAEuR,GAGzE,SAAc,GAANkd,GAAiB,GAANC,GAAWD,GAAMC,GAC3B,GAANA,GAAiB,GAANC,GAAWD,GAAMC,GACtB,GAANF,GAAiB,GAANE,GAAWF,GAAME,IAUjCpuB,EAAQoS,UAAUgb,iBAAmB,SAAUpc,EAAGC,GAChD,GAAI1M,GACF8pB,EAAU,IACVlB,EAAY,KACZmB,EAAmB,KACnBC,EAAc,KACdpD,EAAS,GAAI/qB,GAAQ4Q,EAAGC,EAE1B,IAAIjS,KAAKkN,QAAUlM,EAAQuZ,MAAM4F,KAC/BngB,KAAKkN,QAAUlM,EAAQuZ,MAAM6F,UAC7BpgB,KAAKkN,QAAUlM,EAAQuZ,MAAM8F,QAE7B,IAAK9a,EAAIvF,KAAKob,WAAW1V,OAAS,EAAGH,GAAK,EAAGA,IAAK,CAChD4oB,EAAYnuB,KAAKob,WAAW7V,EAC5B,IAAI2mB,GAAYiC,EAAUjC,QAC1B,IAAIA,EACF,IAAK,GAAIrgB,GAAIqgB,EAASxmB,OAAS,EAAGmG,GAAK,EAAGA,IAAK,CAE7C,GAAIigB,GAAUI,EAASrgB,GACnBkgB,EAAUD,EAAQC,QAClByD,GAAazD,EAAQ,GAAGzI,OAAQyI,EAAQ,GAAGzI,OAAQyI,EAAQ,GAAGzI,QAC9DmM,GAAa1D,EAAQ,GAAGzI,OAAQyI,EAAQ,GAAGzI,OAAQyI,EAAQ,GAAGzI,OAClE,IAAItjB,KAAK+uB,gBAAgB5C,EAAQqD,IAC/BxvB,KAAK+uB,gBAAgB5C,EAAQsD,GAE7B,MAAOtB,QAQf,KAAK5oB,EAAI,EAAGA,EAAIvF,KAAKob,WAAW1V,OAAQH,IAAK,CAC3C4oB,EAAYnuB,KAAKob,WAAW7V,EAC5B,IAAI4M,GAAQgc,EAAU7K,MACtB,IAAInR,EAAO,CACT,GAAIud,GAAQzqB,KAAK6lB,IAAI9Y,EAAIG,EAAMH,GAC3B2d,EAAQ1qB,KAAK6lB,IAAI7Y,EAAIE,EAAMF,GAC3BkZ,EAAQlmB,KAAK2qB,KAAKF,EAAQA,EAAQC,EAAQA,IAEzB,OAAhBJ,GAA+BA,EAAPpE,IAA8BkE,EAAPlE,IAClDoE,EAAcpE,EACdmE,EAAmBnB,IAO3B,MAAOmB,IAQTtuB,EAAQoS,UAAUib,aAAe,SAAUF,GACzC,GAAI0B,GAASC,EAAMC,CAEd/vB,MAAKqmB,SAiCRwJ,EAAU7vB,KAAKqmB,QAAQ2J,IAAIH,QAC3BC,EAAQ9vB,KAAKqmB,QAAQ2J,IAAIF,KACzBC,EAAQ/vB,KAAKqmB,QAAQ2J,IAAID,MAlCzBF,EAAUre,SAASM,cAAc,OACjC+d,EAAQ3iB,MAAM2W,SAAW,WACzBgM,EAAQ3iB,MAAM+W,QAAU,OACxB4L,EAAQ3iB,MAAMb,OAAS,oBACvBwjB,EAAQ3iB,MAAM9B,MAAQ,UACtBykB,EAAQ3iB,MAAMd,WAAa,wBAC3ByjB,EAAQ3iB,MAAM+iB,aAAe,MAC7BJ,EAAQ3iB,MAAMgjB,UAAY,qCAE1BJ,EAAOte,SAASM,cAAc,OAC9Bge,EAAK5iB,MAAM2W,SAAW,WACtBiM,EAAK5iB,MAAMuF,OAAS,OACpBqd,EAAK5iB,MAAMsF,MAAQ,IACnBsd,EAAK5iB,MAAMijB,WAAa,oBAExBJ,EAAMve,SAASM,cAAc,OAC7Bie,EAAI7iB,MAAM2W,SAAW,WACrBkM,EAAI7iB,MAAMuF,OAAS,IACnBsd,EAAI7iB,MAAMsF,MAAQ,IAClBud,EAAI7iB,MAAMb,OAAS,oBACnB0jB,EAAI7iB,MAAM+iB,aAAe,MAEzBjwB,KAAKqmB,SACH8H,UAAW,KACX6B,KACEH,QAASA,EACTC,KAAMA,EACNC,IAAKA,KAUX/vB,KAAKkuB,eAELluB,KAAKqmB,QAAQ8H,UAAYA,EAEvB0B,EAAQ3L,UADsB,kBAArBlkB,MAAK8a,YACM9a,KAAK8a,YAAYqT,EAAUhc,OAG3B,6BACMgc,EAAUhc,MAAMH,EAAI,gCACpBmc,EAAUhc,MAAMF,EAAI,gCACpBkc,EAAUhc,MAAMgL,EAAI,qBAIhD0S,EAAQ3iB,MAAM1F,KAAQ,IACtBqoB,EAAQ3iB,MAAMtF,IAAQ,IACtB5H,KAAKuf,MAAM7N,YAAYme,GACvB7vB,KAAKuf,MAAM7N,YAAYoe,GACvB9vB,KAAKuf,MAAM7N,YAAYqe,EAGvB,IAAIK,GAAgBP,EAAQQ,YACxBC,EAAkBT,EAAQU,aAC1BC,EAAgBV,EAAKS,aACrBE,EAAcV,EAAIM,YAClBK,EAAgBX,EAAIQ,aAEpB/oB,EAAO2mB,EAAU7K,OAAOtR,EAAIoe,EAAe,CAC/C5oB,GAAOvC,KAAK8G,IAAI9G,KAAK0H,IAAInF,EAAM,IAAKxH,KAAKuf,MAAME,YAAc,GAAK2Q,GAElEN,EAAK5iB,MAAM1F,KAAS2mB,EAAU7K,OAAOtR,EAAI,KACzC8d,EAAK5iB,MAAMtF,IAAUumB,EAAU7K,OAAOrR,EAAIue,EAAc,KACxDX,EAAQ3iB,MAAM1F,KAAQA,EAAO,KAC7BqoB,EAAQ3iB,MAAMtF,IAASumB,EAAU7K,OAAOrR,EAAIue,EAAaF,EAAiB,KAC1EP,EAAI7iB,MAAM1F,KAAW2mB,EAAU7K,OAAOtR,EAAIye,EAAW,EAAK,KAC1DV,EAAI7iB,MAAMtF,IAAWumB,EAAU7K,OAAOrR,EAAIye,EAAY,EAAK,MAO7D1vB,EAAQoS,UAAU8a,aAAe,WAC/B,GAAIluB,KAAKqmB,QAAS,CAChBrmB,KAAKqmB,QAAQ8H,UAAY,IAEzB,KAAK,GAAIvoB,KAAQ5F,MAAKqmB,QAAQ2J,IAC5B,GAAIhwB,KAAKqmB,QAAQ2J,IAAInqB,eAAeD,GAAO,CACzC,GAAI0B,GAAOtH,KAAKqmB,QAAQ2J,IAAIpqB,EACxB0B,IAAQA,EAAKwC,YACfxC,EAAKwC,WAAWsH,YAAY9J,MA8BtCzH,EAAOD,QAAUoB,GAKb,SAASnB,EAAQD,EAASM,GAc9B,QAASgB,KACPlB,KAAK2wB,YAAc,GAAItvB,GACvBrB,KAAK4wB,eACL5wB,KAAK4wB,YAAYnL,WAAa,EAC9BzlB,KAAK4wB,YAAYlL,SAAW,EAC5B1lB,KAAK6wB,UAAY,IAEjB7wB,KAAK8wB,eAAiB,GAAIzvB,GAC1BrB,KAAK+wB,eAAkB,GAAI1vB,GAAQ,GAAI4D,KAAK2mB,GAAI,EAAG,GAEnD5rB,KAAKgxB,6BAtBP,GAAI3vB,GAAUnB,EAAoB,GA+BlCgB,GAAOkS,UAAUmK,eAAiB,SAASvL,EAAGC,EAAGkL,GAC/Cnd,KAAK2wB,YAAY3e,EAAIA,EACrBhS,KAAK2wB,YAAY1e,EAAIA,EACrBjS,KAAK2wB,YAAYxT,EAAIA,EAErBnd,KAAKgxB,8BAWP9vB,EAAOkS,UAAUuS,eAAiB,SAASF,EAAYC,GAClCnf,SAAfkf,IACFzlB,KAAK4wB,YAAYnL,WAAaA,GAGflf,SAAbmf,IACF1lB,KAAK4wB,YAAYlL,SAAWA,EACxB1lB,KAAK4wB,YAAYlL,SAAW,IAAG1lB,KAAK4wB,YAAYlL,SAAW,GAC3D1lB,KAAK4wB,YAAYlL,SAAW,GAAIzgB,KAAK2mB,KAAI5rB,KAAK4wB,YAAYlL,SAAW,GAAIzgB,KAAK2mB,MAGjErlB,SAAfkf,GAAyClf,SAAbmf,IAC9B1lB,KAAKgxB,8BAQT9vB,EAAOkS,UAAU2S,eAAiB,WAChC,GAAIkL,KAIJ,OAHAA,GAAIxL,WAAazlB,KAAK4wB,YAAYnL,WAClCwL,EAAIvL,SAAW1lB,KAAK4wB,YAAYlL,SAEzBuL,GAOT/vB,EAAOkS,UAAUyS,aAAe,SAASngB,GACxBa,SAAXb,IAGJ1F,KAAK6wB,UAAYnrB,EAKb1F,KAAK6wB,UAAY,MAAM7wB,KAAK6wB,UAAY,KACxC7wB,KAAK6wB,UAAY,IAAK7wB,KAAK6wB,UAAY,GAE3C7wB,KAAKgxB,+BAOP9vB,EAAOkS,UAAUiM,aAAe,WAC9B,MAAOrf,MAAK6wB,WAOd3vB,EAAOkS,UAAU6K,kBAAoB,WACnC,MAAOje,MAAK8wB,gBAOd5vB,EAAOkS,UAAUkL,kBAAoB,WACnC,MAAOte,MAAK+wB,gBAOd7vB,EAAOkS,UAAU4d,2BAA6B,WAE5ChxB,KAAK8wB,eAAe9e,EAAIhS,KAAK2wB,YAAY3e,EAAIhS,KAAK6wB,UAAY5rB,KAAKoZ,IAAIre,KAAK4wB,YAAYnL,YAAcxgB,KAAKuZ,IAAIxe,KAAK4wB,YAAYlL,UAChI1lB,KAAK8wB,eAAe7e,EAAIjS,KAAK2wB,YAAY1e,EAAIjS,KAAK6wB,UAAY5rB,KAAKuZ,IAAIxe,KAAK4wB,YAAYnL,YAAcxgB,KAAKuZ,IAAIxe,KAAK4wB,YAAYlL,UAChI1lB,KAAK8wB,eAAe3T,EAAInd,KAAK2wB,YAAYxT,EAAInd,KAAK6wB,UAAY5rB,KAAKoZ,IAAIre,KAAK4wB,YAAYlL,UAGxF1lB,KAAK+wB,eAAe/e,EAAI/M,KAAK2mB,GAAG,EAAI5rB,KAAK4wB,YAAYlL,SACrD1lB,KAAK+wB,eAAe9e,EAAI,EACxBjS,KAAK+wB,eAAe5T,GAAKnd,KAAK4wB,YAAYnL,YAG5C5lB,EAAOD,QAAUsB,GAIb,SAASrB,EAAQD,EAASM,GAW9B,QAASiB,GAAQwR,EAAMqO,EAAQkQ,GAC7BlxB,KAAK2S,KAAOA,EACZ3S,KAAKghB,OAASA,EACdhhB,KAAKkxB,MAAQA,EAEblxB,KAAKqI,MAAQ9B,OACbvG,KAAKoH,MAAQb,OAGbvG,KAAK+W,OAASma,EAAMjQ,kBAAkBtO,EAAKwC,MAAOnV,KAAKghB,QAGvDhhB,KAAK+W,OAAOZ,KAAK,SAAU7Q,EAAGa,GAC5B,MAAOb,GAAIa,EAAI,EAAQA,EAAJb,EAAQ,GAAK,IAG9BtF,KAAK+W,OAAOrR,OAAS,GACvB1F,KAAKgpB,YAAY,GAInBhpB,KAAKob,cAELpb,KAAKM,QAAS,EACdN,KAAKmxB,eAAiB5qB,OAElB2qB,EAAMjW,kBACRjb,KAAKM,QAAS,EACdN,KAAKoxB,oBAGLpxB,KAAKM,QAAS,EAxClB,GAAIQ,GAAWZ,EAAoB,EAiDnCiB,GAAOiS,UAAUie,SAAW,WAC1B,MAAOrxB,MAAKM,QAQda,EAAOiS,UAAUke,kBAAoB,WAInC,IAHA,GAAI9rB,GAAMxF,KAAK+W,OAAOrR,OAElBH,EAAI,EACDvF,KAAKob,WAAW7V,IACrBA,GAGF,OAAON,MAAK0oB,MAAMpoB,EAAIC,EAAM,MAQ9BrE,EAAOiS,UAAU+V,SAAW,WAC1B,MAAOnpB,MAAKkxB,MAAM7W,aAQpBlZ,EAAOiS,UAAUme,UAAY,WAC3B,MAAOvxB,MAAKghB,QAOd7f,EAAOiS,UAAUgW,iBAAmB,WAClC,MAAmB7iB,UAAfvG,KAAKqI,MACA9B,OAEFvG,KAAK+W,OAAO/W,KAAKqI,QAO1BlH,EAAOiS,UAAUoe,UAAY,WAC3B,MAAOxxB,MAAK+W,QAQd5V,EAAOiS,UAAUyB,SAAW,SAASxM,GACnC,GAAIA,GAASrI,KAAK+W,OAAOrR,OACvB,KAAM,2BAER,OAAO1F,MAAK+W,OAAO1O,IASrBlH,EAAOiS,UAAU2P,eAAiB,SAAS1a,GAIzC,GAHc9B,SAAV8B,IACFA,EAAQrI,KAAKqI,OAED9B,SAAV8B,EACF,QAEF,IAAI+S,EACJ,IAAIpb,KAAKob,WAAW/S,GAClB+S,EAAapb,KAAKob,WAAW/S,OAE1B,CACH,GAAIwF,KACJA,GAAEmT,OAAShhB,KAAKghB,OAChBnT,EAAEzG,MAAQpH,KAAK+W,OAAO1O,EAEtB,IAAIopB,GAAW,GAAI3wB,GAASd,KAAK2S,MAAMiB,OAAQ,SAAUtE,GAAO,MAAQA,GAAKzB,EAAEmT,SAAWnT,EAAEzG,SAAW+N,KACvGiG,GAAapb,KAAKkxB,MAAMnO,eAAe0O,GAEvCzxB,KAAKob,WAAW/S,GAAS+S,EAG3B,MAAOA,IAQTja,EAAOiS,UAAUqO,kBAAoB,SAASjZ,GAC5CxI,KAAKmxB,eAAiB3oB,GASxBrH,EAAOiS,UAAU4V,YAAc,SAAS3gB,GACtC,GAAIA,GAASrI,KAAK+W,OAAOrR,OACvB,KAAM,2BAER1F,MAAKqI,MAAQA,EACbrI,KAAKoH,MAAQpH,KAAK+W,OAAO1O,IAO3BlH,EAAOiS,UAAUge,iBAAmB,SAAS/oB,GAC7B9B,SAAV8B,IACFA,EAAQ,EAEV,IAAIkX,GAAQvf,KAAKkxB,MAAM3R,KAEvB,IAAIlX,EAAQrI,KAAK+W,OAAOrR,OAAQ,CAC9B,CAAqB1F,KAAK+iB,eAAe1a,GAIlB9B,SAAnBgZ,EAAMmS,WACRnS,EAAMmS,SAAWlgB,SAASM,cAAc,OACxCyN,EAAMmS,SAASxkB,MAAM2W,SAAW,WAChCtE,EAAMmS,SAASxkB,MAAM9B,MAAQ,OAC7BmU,EAAM7N,YAAY6N,EAAMmS,UAE1B,IAAIA,GAAW1xB,KAAKsxB,mBACpB/R,GAAMmS,SAASxN,UAAY,wBAA0BwN,EAAW,IAEhEnS,EAAMmS,SAASxkB,MAAMqW,OAAS,OAC9BhE,EAAMmS,SAASxkB,MAAM1F,KAAO,MAE5B,IAAI4M,GAAKpU,IACTuZ,YAAW,WAAYnF,EAAGgd,iBAAiB/oB,EAAM,IAAM,IACvDrI,KAAKM,QAAS,MAGdN,MAAKM,QAAS,EAGSiG,SAAnBgZ,EAAMmS,WACRnS,EAAMnO,YAAYmO,EAAMmS,UACxBnS,EAAMmS,SAAWnrB,QAGfvG,KAAKmxB,gBACPnxB,KAAKmxB;EAIXtxB,EAAOD,QAAUuB,GAKb,SAAStB,GAOb,QAASuB,GAAS4Q,EAAGC,GACnBjS,KAAKgS,EAAUzL,SAANyL,EAAkBA,EAAI,EAC/BhS,KAAKiS,EAAU1L,SAAN0L,EAAkBA,EAAI,EAGjCpS,EAAOD,QAAUwB,GAKb,SAASvB,GAQb,QAASwB,GAAQ2Q,EAAGC,EAAGkL,GACrBnd,KAAKgS,EAAUzL,SAANyL,EAAkBA,EAAI,EAC/BhS,KAAKiS,EAAU1L,SAAN0L,EAAkBA,EAAI,EAC/BjS,KAAKmd,EAAU5W,SAAN4W,EAAkBA,EAAI,EASjC9b,EAAQiqB,SAAW,SAAShmB,EAAGa,GAC7B,GAAIwrB,GAAM,GAAItwB,EAId,OAHAswB,GAAI3f,EAAI1M,EAAE0M,EAAI7L,EAAE6L,EAChB2f,EAAI1f,EAAI3M,EAAE2M,EAAI9L,EAAE8L,EAChB0f,EAAIxU,EAAI7X,EAAE6X,EAAIhX,EAAEgX,EACTwU,GASTtwB,EAAQ6R,IAAM,SAAS5N,EAAGa,GACxB,GAAIyrB,GAAM,GAAIvwB,EAId,OAHAuwB,GAAI5f,EAAI1M,EAAE0M,EAAI7L,EAAE6L,EAChB4f,EAAI3f,EAAI3M,EAAE2M,EAAI9L,EAAE8L,EAChB2f,EAAIzU,EAAI7X,EAAE6X,EAAIhX,EAAEgX,EACTyU,GASTvwB,EAAQ+qB,IAAM,SAAS9mB,EAAGa,GACxB,MAAO,IAAI9E,IACFiE,EAAE0M,EAAI7L,EAAE6L,GAAK,GACb1M,EAAE2M,EAAI9L,EAAE8L,GAAK,GACb3M,EAAE6X,EAAIhX,EAAEgX,GAAK,IAWxB9b,EAAQoqB,aAAe,SAASnmB,EAAGa,GACjC,GAAIqlB,GAAe,GAAInqB,EAMvB,OAJAmqB,GAAaxZ,EAAI1M,EAAE2M,EAAI9L,EAAEgX,EAAI7X,EAAE6X,EAAIhX,EAAE8L,EACrCuZ,EAAavZ,EAAI3M,EAAE6X,EAAIhX,EAAE6L,EAAI1M,EAAE0M,EAAI7L,EAAEgX,EACrCqO,EAAarO,EAAI7X,EAAE0M,EAAI7L,EAAE8L,EAAI3M,EAAE2M,EAAI9L,EAAE6L,EAE9BwZ,GAQTnqB,EAAQ+R,UAAU1N,OAAS,WACzB,MAAOT,MAAK2qB,KACJ5vB,KAAKgS,EAAIhS,KAAKgS,EACdhS,KAAKiS,EAAIjS,KAAKiS,EACdjS,KAAKmd,EAAInd,KAAKmd,IAIxBtd,EAAOD,QAAUyB,GAKb,SAASxB,EAAQD,EAASM,GAa9B,QAASoB,GAAOkY,EAAW9K,GACzB,GAAkBnI,SAAdiT,EACF,KAAM,qCAKR,IAHAxZ,KAAKwZ,UAAYA,EACjBxZ,KAAK2oB,QAAWja,GAA8BnI,QAAnBmI,EAAQia,QAAwBja,EAAQia,SAAU,EAEzE3oB,KAAK2oB,QAAS,CAChB3oB,KAAKuf,MAAQ/N,SAASM,cAAc,OAEpC9R,KAAKuf,MAAMrS,MAAMsF,MAAQ,OACzBxS,KAAKuf,MAAMrS,MAAM2W,SAAW,WAC5B7jB,KAAKwZ,UAAU9H,YAAY1R,KAAKuf,OAEhCvf,KAAKuf,MAAMsS,KAAOrgB,SAASM,cAAc,SACzC9R,KAAKuf,MAAMsS,KAAKhrB,KAAO,SACvB7G,KAAKuf,MAAMsS,KAAKzqB,MAAQ,OACxBpH,KAAKuf,MAAM7N,YAAY1R,KAAKuf,MAAMsS,MAElC7xB,KAAKuf,MAAM0F,KAAOzT,SAASM,cAAc,SACzC9R,KAAKuf,MAAM0F,KAAKpe,KAAO,SACvB7G,KAAKuf,MAAM0F,KAAK7d,MAAQ,OACxBpH,KAAKuf,MAAM7N,YAAY1R,KAAKuf,MAAM0F,MAElCjlB,KAAKuf,MAAM+I,KAAO9W,SAASM,cAAc,SACzC9R,KAAKuf,MAAM+I,KAAKzhB,KAAO,SACvB7G,KAAKuf,MAAM+I,KAAKlhB,MAAQ,OACxBpH,KAAKuf,MAAM7N,YAAY1R,KAAKuf,MAAM+I,MAElCtoB,KAAKuf,MAAMuS,IAAMtgB,SAASM,cAAc,SACxC9R,KAAKuf,MAAMuS,IAAIjrB,KAAO,SACtB7G,KAAKuf,MAAMuS,IAAI5kB,MAAM2W,SAAW,WAChC7jB,KAAKuf,MAAMuS,IAAI5kB,MAAMb,OAAS,gBAC9BrM,KAAKuf,MAAMuS,IAAI5kB,MAAMsF,MAAQ,QAC7BxS,KAAKuf,MAAMuS,IAAI5kB,MAAMuF,OAAS,MAC9BzS,KAAKuf,MAAMuS,IAAI5kB,MAAM+iB,aAAe,MACpCjwB,KAAKuf,MAAMuS,IAAI5kB,MAAM6kB,gBAAkB,MACvC/xB,KAAKuf,MAAMuS,IAAI5kB,MAAMb,OAAS,oBAC9BrM,KAAKuf,MAAMuS,IAAI5kB,MAAM0S,gBAAkB,UACvC5f,KAAKuf,MAAM7N,YAAY1R,KAAKuf,MAAMuS,KAElC9xB,KAAKuf,MAAMyS,MAAQxgB,SAASM,cAAc,SAC1C9R,KAAKuf,MAAMyS,MAAMnrB,KAAO,SACxB7G,KAAKuf,MAAMyS,MAAM9kB,MAAMyM,OAAS,MAChC3Z,KAAKuf,MAAMyS,MAAM5qB,MAAQ,IACzBpH,KAAKuf,MAAMyS,MAAM9kB,MAAM2W,SAAW,WAClC7jB,KAAKuf,MAAMyS,MAAM9kB,MAAM1F,KAAO,SAC9BxH,KAAKuf,MAAM7N,YAAY1R,KAAKuf,MAAMyS,MAGlC,IAAI5d,GAAKpU,IACTA,MAAKuf,MAAMyS,MAAM7N,YAAc,SAAU3a,GAAQ4K,EAAGgQ,aAAa5a,IACjExJ,KAAKuf,MAAMsS,KAAKI,QAAU,SAAUzoB,GAAQ4K,EAAGyd,KAAKroB,IACpDxJ,KAAKuf,MAAM0F,KAAKgN,QAAU,SAAUzoB,GAAQ4K,EAAG8d,WAAW1oB,IAC1DxJ,KAAKuf,MAAM+I,KAAK2J,QAAU,SAAUzoB,GAAQ4K,EAAGkU,KAAK9e,IAGtDxJ,KAAKmyB,iBAAmB5rB,OAExBvG,KAAK+W,UACL/W,KAAKqI,MAAQ9B,OAEbvG,KAAKoyB,YAAc7rB,OACnBvG,KAAKqyB,aAAe,IACpBryB,KAAKsyB,UAAW,EA3ElB,GAAI3xB,GAAOT,EAAoB,EAiF/BoB,GAAO8R,UAAUye,KAAO,WACtB,GAAIxpB,GAAQrI,KAAK+oB,UACb1gB,GAAQ,IACVA,IACArI,KAAKuyB,SAASlqB,KAOlB/G,EAAO8R,UAAUkV,KAAO,WACtB,GAAIjgB,GAAQrI,KAAK+oB,UACb1gB,GAAQrI,KAAK+W,OAAOrR,OAAS,IAC/B2C,IACArI,KAAKuyB,SAASlqB,KAOlB/G,EAAO8R,UAAUof,SAAW,WAC1B,GAAI3iB,GAAQ,GAAIxL,MAEZgE,EAAQrI,KAAK+oB,UACb1gB,GAAQrI,KAAK+W,OAAOrR,OAAS,GAC/B2C,IACArI,KAAKuyB,SAASlqB,IAEPrI,KAAKsyB,WAEZjqB,EAAQ,EACRrI,KAAKuyB,SAASlqB,GAGhB,IAAIyH,GAAM,GAAIzL,MACVioB,EAAQxc,EAAMD,EAId4iB,EAAWxtB,KAAK0H,IAAI3M,KAAKqyB,aAAe/F,EAAM,GAG9ClY,EAAKpU,IACTA,MAAKoyB,YAAc7Y,WAAW,WAAYnF,EAAGoe,YAAcC,IAM7DnxB,EAAO8R,UAAU8e,WAAa,WACH3rB,SAArBvG,KAAKoyB,YACPpyB,KAAKilB,OAELjlB,KAAKmlB,QAOT7jB,EAAO8R,UAAU6R,KAAO,WAElBjlB,KAAKoyB,cAETpyB,KAAKwyB,WAEDxyB,KAAKuf,QACPvf,KAAKuf,MAAM0F,KAAK7d,MAAQ,UAO5B9F,EAAO8R,UAAU+R,KAAO,WACtBuN,cAAc1yB,KAAKoyB,aACnBpyB,KAAKoyB,YAAc7rB,OAEfvG,KAAKuf,QACPvf,KAAKuf,MAAM0F,KAAK7d,MAAQ,SAQ5B9F,EAAO8R,UAAU6V,oBAAsB,SAASzgB,GAC9CxI,KAAKmyB,iBAAmB3pB,GAO1BlH,EAAO8R,UAAUyV,gBAAkB,SAAS4J,GAC1CzyB,KAAKqyB,aAAeI,GAOtBnxB,EAAO8R,UAAUuf,gBAAkB,WACjC,MAAO3yB,MAAKqyB,cASd/wB,EAAO8R,UAAUwf,YAAc,SAASC,GACtC7yB,KAAKsyB,SAAWO,GAOlBvxB,EAAO8R,UAAU0f,SAAW,WACIvsB,SAA1BvG,KAAKmyB,kBACPnyB,KAAKmyB,oBAOT7wB,EAAO8R,UAAUsO,OAAS,WACxB,GAAI1hB,KAAKuf,MAAO,CAEdvf,KAAKuf,MAAMuS,IAAI5kB,MAAMtF,IAAO5H,KAAKuf,MAAMuF,aAAa,EAChD9kB,KAAKuf,MAAMuS,IAAIvB,aAAa,EAAK,KACrCvwB,KAAKuf,MAAMuS,IAAI5kB,MAAMsF,MAASxS,KAAKuf,MAAME,YACrCzf,KAAKuf,MAAMsS,KAAKpS,YAChBzf,KAAKuf,MAAM0F,KAAKxF,YAChBzf,KAAKuf,MAAM+I,KAAK7I,YAAc,GAAO,IAGzC,IAAIjY,GAAOxH,KAAK+yB,YAAY/yB,KAAKqI,MACjCrI,MAAKuf,MAAMyS,MAAM9kB,MAAM1F,KAAO,EAAS,OAS3ClG,EAAO8R,UAAUwV,UAAY,SAAS7R,GACpC/W,KAAK+W,OAASA,EAEV/W,KAAK+W,OAAOrR,OAAS,EACvB1F,KAAKuyB,SAAS,GAEdvyB,KAAKqI,MAAQ9B,QAOjBjF,EAAO8R,UAAUmf,SAAW,SAASlqB,GACnC,KAAIA,EAAQrI,KAAK+W,OAAOrR,QAOtB,KAAM,2BANN1F,MAAKqI,MAAQA,EAEbrI,KAAK0hB,SACL1hB,KAAK8yB,YAWTxxB,EAAO8R,UAAU2V,SAAW,WAC1B,MAAO/oB,MAAKqI,OAQd/G,EAAO8R,UAAU+B,IAAM,WACrB,MAAOnV,MAAK+W,OAAO/W,KAAKqI,QAI1B/G,EAAO8R,UAAUgR,aAAe,SAAS5a,GAEvC,GAAI+iB,GAAiB/iB,EAAMijB,MAAyB,IAAhBjjB,EAAMijB,MAAiC,IAAjBjjB,EAAMkjB,MAChE,IAAKH,EAAL,CAEAvsB,KAAKgzB,aAAexpB,EAAMoT,QAC1B5c,KAAKizB,YAAc3N,WAAWtlB,KAAKuf,MAAMyS,MAAM9kB,MAAM1F,MAErDxH,KAAKuf,MAAMrS,MAAM+f,OAAS,MAK1B,IAAI7Y,GAAKpU,IACTA,MAAKktB,YAAc,SAAU1jB,GAAQ4K,EAAG+Y,aAAa3jB,IACrDxJ,KAAKotB,UAAc,SAAU5jB,GAAQ4K,EAAGoY,WAAWhjB,IACnD7I,EAAKkI,iBAAiB2I,SAAU,YAAaxR,KAAKktB,aAClDvsB,EAAKkI,iBAAiB2I,SAAU,UAAaxR,KAAKotB,WAClDzsB,EAAK4I,eAAeC,KAItBlI,EAAO8R,UAAU8f,YAAc,SAAU1rB,GACvC,GAAIgL,GAAQ8S,WAAWtlB,KAAKuf,MAAMuS,IAAI5kB,MAAMsF,OACxCxS,KAAKuf,MAAMyS,MAAMvS,YAAc,GAC/BzN,EAAIxK,EAAO,EAEXa,EAAQpD,KAAK0oB,MAAM3b,EAAIQ,GAASxS,KAAK+W,OAAOrR,OAAO,GAIvD,OAHY,GAAR2C,IAAWA,EAAQ,GACnBA,EAAQrI,KAAK+W,OAAOrR,OAAO,IAAG2C,EAAQrI,KAAK+W,OAAOrR,OAAO,GAEtD2C,GAGT/G,EAAO8R,UAAU2f,YAAc,SAAU1qB,GACvC,GAAImK,GAAQ8S,WAAWtlB,KAAKuf,MAAMuS,IAAI5kB,MAAMsF,OACxCxS,KAAKuf,MAAMyS,MAAMvS,YAAc,GAE/BzN,EAAI3J,GAASrI,KAAK+W,OAAOrR,OAAO,GAAK8M,EACrChL,EAAOwK,EAAI,CAEf,OAAOxK,IAKTlG,EAAO8R,UAAU+Z,aAAe,SAAU3jB,GACxC,GAAI8iB,GAAO9iB,EAAMoT,QAAU5c,KAAKgzB,aAC5BhhB,EAAIhS,KAAKizB,YAAc3G,EAEvBjkB,EAAQrI,KAAKkzB,YAAYlhB,EAE7BhS,MAAKuyB,SAASlqB,GAEd1H,EAAK4I,kBAIPjI,EAAO8R,UAAUoZ,WAAa,WAC5BxsB,KAAKuf,MAAMrS,MAAM+f,OAAS,OAG1BtsB,EAAK0I,oBAAoBmI,SAAU,YAAaxR,KAAKktB,aACrDvsB,EAAK0I,oBAAoBmI,SAAU,UAAWxR,KAAKotB,WAEnDzsB,EAAK4I,kBAGP1J,EAAOD,QAAU0B,GAKb,SAASzB,GA2Bb,QAAS0B,GAAWsO,EAAOC,EAAKsY,EAAMmB,GAEpCvpB,KAAKmzB,OAAS,EACdnzB,KAAKozB,KAAO,EACZpzB,KAAKqzB,MAAQ,EACbrzB,KAAKupB,YAAa,EAClBvpB,KAAKszB,UAAY,EAEjBtzB,KAAKuzB,SAAW,EAChBvzB,KAAKwzB,SAAS3jB,EAAOC,EAAKsY,EAAMmB,GAYlChoB,EAAW6R,UAAUogB,SAAW,SAAS3jB,EAAOC,EAAKsY,EAAMmB,GACzDvpB,KAAKmzB,OAAStjB,EAAQA,EAAQ,EAC9B7P,KAAKozB,KAAOtjB,EAAMA,EAAM,EAExB9P,KAAKyzB,QAAQrL,EAAMmB,IASrBhoB,EAAW6R,UAAUqgB,QAAU,SAASrL,EAAMmB,GAC/BhjB,SAAT6hB,GAA8B,GAARA,IAGP7hB,SAAfgjB,IACFvpB,KAAKupB,WAAaA,GAGlBvpB,KAAKqzB,MADHrzB,KAAKupB,cAAe,EACThoB,EAAWmyB,oBAAoBtL,GAE/BA,IAUjB7mB,EAAWmyB,oBAAsB,SAAUtL,GACzC,GAAIuL,GAAQ,SAAU3hB,GAAI,MAAO/M,MAAK2uB,IAAI5hB,GAAK/M,KAAK4uB,MAGhDC,EAAQ7uB,KAAK8uB,IAAI,GAAI9uB,KAAK0oB,MAAMgG,EAAMvL,KACtC4L,EAAQ,EAAI/uB,KAAK8uB,IAAI,GAAI9uB,KAAK0oB,MAAMgG,EAAMvL,EAAO,KACjD6L,EAAQ,EAAIhvB,KAAK8uB,IAAI,GAAI9uB,KAAK0oB,MAAMgG,EAAMvL,EAAO,KAGjDmB,EAAauK,CASjB,OARI7uB,MAAK6lB,IAAIkJ,EAAQ5L,IAASnjB,KAAK6lB,IAAIvB,EAAanB,KAAOmB,EAAayK,GACpE/uB,KAAK6lB,IAAImJ,EAAQ7L,IAASnjB,KAAK6lB,IAAIvB,EAAanB,KAAOmB,EAAa0K,GAGtD,GAAd1K,IACFA,EAAa,GAGRA,GAOThoB,EAAW6R,UAAUiV,WAAa,WAChC,MAAO/C,YAAWtlB,KAAKuzB,SAASW,YAAYl0B,KAAKszB,aAOnD/xB,EAAW6R,UAAU+gB,QAAU,WAC7B,MAAOn0B,MAAKqzB,OAOd9xB,EAAW6R,UAAUvD,MAAQ,WAC3B7P,KAAKuzB,SAAWvzB,KAAKmzB,OAASnzB,KAAKmzB,OAASnzB,KAAKqzB,OAMnD9xB,EAAW6R,UAAUkV,KAAO,WAC1BtoB,KAAKuzB,UAAYvzB,KAAKqzB,OAOxB9xB,EAAW6R,UAAUtD,IAAM,WACzB,MAAQ9P,MAAKuzB,SAAWvzB,KAAKozB,MAG/BvzB,EAAOD,QAAU2B,GAKb,SAAS1B,EAAQD,EAASM,GAuB9B,QAASsB,GAAUgY,EAAWvX,EAAOmyB,EAAQ1lB,GAC3C,KAAM1O,eAAgBwB,IACpB,KAAM,IAAIiY,aAAY,mDAIxB,MAAMzT,MAAMC,QAAQmuB,IAAWA,YAAkBvzB,KAAYuzB,YAAkB9tB,QAAQ,CACrF,GAAI+tB,GAAgB3lB,CACpBA,GAAU0lB,EACVA,EAASC,EAGX,GAAIjgB,GAAKpU,IACTA,MAAKs0B,gBACHzkB,MAAO,KACPC,IAAO,KAEPykB,YAAY,EAEZC,YAAa,SACbhiB,MAAO,KACPC,OAAQ,KACRgiB,UAAW,KACXC,UAAW,MAEb10B,KAAK0O,QAAU/N,EAAK6F,cAAexG,KAAKs0B,gBAGxCt0B,KAAK20B,QAAQnb,GAGbxZ,KAAKgC,cAELhC,KAAK40B,MACH5E,IAAKhwB,KAAKgwB,IACV6E,SAAU70B,KAAK+F,MACf+uB,SACEthB,GAAIxT,KAAKwT,GAAGuhB,KAAK/0B,MACjB2T,IAAK3T,KAAK2T,IAAIohB,KAAK/0B,MACnB6tB,KAAM7tB,KAAK6tB,KAAKkH,KAAK/0B,OAEvBg1B,eACAr0B,MACEs0B,KAAM,KACNC,SAAU9gB,EAAG+gB,UAAUJ,KAAK3gB,GAC5BghB,eAAgBhhB,EAAGihB,gBAAgBN,KAAK3gB,GACxCkhB,OAAQlhB,EAAGmhB,QAAQR,KAAK3gB,GACxBohB,aAAephB,EAAGqhB,cAAcV,KAAK3gB,KAKzCpU,KAAK01B,MAAQ,GAAI7zB,GAAM7B,KAAK40B,MAC5B50B,KAAKgC,WAAWkG,KAAKlI,KAAK01B,OAC1B11B,KAAK40B,KAAKc,MAAQ11B,KAAK01B,MAGvB11B,KAAK21B,SAAW,GAAI1yB,GAASjD,KAAK40B,MAClC50B,KAAKgC,WAAWkG,KAAKlI,KAAK21B,UAC1B31B,KAAK40B,KAAKj0B,KAAKs0B,KAAOj1B,KAAK21B,SAASV,KAAKF,KAAK/0B,KAAK21B,UAGnD31B,KAAK41B,YAAc,GAAIpzB,GAAYxC,KAAK40B,MACxC50B,KAAKgC,WAAWkG,KAAKlI,KAAK41B,aAI1B51B,KAAK61B,WAAa,GAAIpzB,GAAWzC,KAAK40B,MACtC50B,KAAKgC,WAAWkG,KAAKlI,KAAK61B,YAG1B71B,KAAK81B,QAAU,GAAIhzB,GAAQ9C,KAAK40B,MAChC50B,KAAKgC,WAAWkG,KAAKlI,KAAK81B,SAE1B91B,KAAK+1B,UAAY,KACjB/1B,KAAKg2B,WAAa,KAGdtnB,GACF1O,KAAKmT,WAAWzE,GAId0lB,GACFp0B,KAAKi2B,UAAU7B,GAIbnyB,EACFjC,KAAKk2B,SAASj0B,GAGdjC,KAAK0hB,SAjHT,GAEI/gB,IAFUT,EAAoB,IACrBA,EAAoB,IACtBA,EAAoB,IAC3BW,EAAUX,EAAoB,GAC9BY,EAAWZ,EAAoB,GAC/B2B,EAAQ3B,EAAoB,IAC5Bi2B,EAAOj2B,EAAoB,IAC3B+C,EAAW/C,EAAoB,IAC/BsC,EAActC,EAAoB,IAClCuC,EAAavC,EAAoB,IACjC4C,EAAU5C,EAAoB,GA4GlCsB,GAAS4R,UAAY,GAAI+iB,GAMzB30B,EAAS4R,UAAU8iB,SAAW,SAASj0B,GACrC,GAGIm0B,GAHAC,EAAiC,MAAlBr2B,KAAK+1B,SAwBxB,IAhBEK,EAJGn0B,EAGIA,YAAiBpB,IAAWoB,YAAiBnB,GACvCmB,EAIA,GAAIpB,GAAQoB,GACvB4E,MACEgJ,MAAO,OACPC,IAAK,UAVI,KAgBf9P,KAAK+1B,UAAYK,EACjBp2B,KAAK81B,SAAW91B,KAAK81B,QAAQI,SAASE,GAElCC,EACF,GAA0B9vB,QAAtBvG,KAAK0O,QAAQmB,OAA0CtJ,QAApBvG,KAAK0O,QAAQoB,IAAkB,CACpE,GAA0BvJ,QAAtBvG,KAAK0O,QAAQmB,OAA0CtJ,QAApBvG,KAAK0O,QAAQoB,IAClD,GAAIwmB,GAAYt2B,KAAKu2B,eAGvB,IAAI1mB,GAA8BtJ,QAAtBvG,KAAK0O,QAAQmB,MAAqB7P,KAAK0O,QAAQmB,MAAQymB,EAAUzmB,MACzEC,EAA4BvJ,QAApBvG,KAAK0O,QAAQoB,IAAqB9P,KAAK0O,QAAQoB,IAAQwmB,EAAUxmB,GAE7E9P,MAAKw2B,UAAU3mB,EAAOC,GAAM2mB,SAAS,QAGrCz2B,MAAK02B,KAAKD,SAAS,KASzBj1B,EAAS4R,UAAU6iB,UAAY,SAAS7B,GAEtC,GAAIgC,EAKFA,GAJGhC,EAGIA,YAAkBvzB,IAAWuzB,YAAkBtzB,GACzCszB,EAIA,GAAIvzB,GAAQuzB,GAPZ,KAUfp0B,KAAKg2B,WAAaI,EAClBp2B,KAAK81B,QAAQG,UAAUG,IAmBzB50B,EAAS4R,UAAUujB,aAAe,SAASvhB,EAAK1G,GAC9C1O,KAAK81B,SAAW91B,KAAK81B,QAAQa,aAAavhB,GAEtC1G,GAAWA,EAAQkoB,OACrB52B,KAAK42B,MAAMxhB,EAAK1G,IAQpBlN,EAAS4R,UAAUyjB,aAAe,WAChC,MAAO72B,MAAK81B,SAAW91B,KAAK81B,QAAQe,oBAetCr1B,EAAS4R,UAAUwjB,MAAQ,SAASv2B,EAAIqO,GACtC,GAAK1O,KAAK+1B,WAAmBxvB,QAANlG,EAAvB,CAEA,GAAI+U,GAAMpP,MAAMC,QAAQ5F,GAAMA,GAAMA,GAGhC01B,EAAY/1B,KAAK+1B,UAAUhgB,aAAaZ,IAAIC,GAC9CvO,MACEgJ,MAAO,OACPC,IAAK,UAKLD,EAAQ,KACRC,EAAM,IAcV,IAbAimB,EAAUxtB,QAAQ,SAAUuuB,GAC1B,GAAIjrB,GAAIirB,EAASjnB,MAAM9I,UACnBgwB,EAAI,OAASD,GAAWA,EAAShnB,IAAI/I,UAAY+vB,EAASjnB,MAAM9I,WAEtD,OAAV8I,GAAsBA,EAAJhE,KACpBgE,EAAQhE,IAGE,OAARiE,GAAgBinB,EAAIjnB,KACtBA,EAAMinB,KAII,OAAVlnB,GAA0B,OAARC,EAAc,CAElC,GAAIT,IAAUQ,EAAQC,GAAO,EACzB2iB,EAAWxtB,KAAK0H,IAAK3M,KAAK01B,MAAM5lB,IAAM9P,KAAK01B,MAAM7lB,MAAwB,KAAfC,EAAMD,IAEhE4mB,EAAW/nB,GAA+BnI,SAApBmI,EAAQ+nB,QAAyB/nB,EAAQ+nB,SAAU,CAC7Ez2B,MAAK01B,MAAMlC,SAASnkB,EAASojB,EAAW,EAAGpjB,EAASojB,EAAW,EAAGgE,MAUtEj1B,EAAS4R,UAAU4jB,aAAe,WAEhC,GAAIC,GAAUj3B,KAAK+1B,UAAUhgB,aAC3BhK,EAAM,KACNY,EAAM,IAER,IAAIsqB,EAAS,CAEX,GAAIC,GAAUD,EAAQlrB,IAAI,QAC1BA,GAAMmrB,EAAUv2B,EAAKiG,QAAQswB,EAAQrnB,MAAO,QAAQ9I,UAAY,IAKhE,IAAIowB,GAAeF,EAAQtqB,IAAI,QAC3BwqB,KACFxqB,EAAMhM,EAAKiG,QAAQuwB,EAAatnB,MAAO,QAAQ9I,UAEjD,IAAIqwB,GAAaH,EAAQtqB,IAAI,MACzByqB,KAEAzqB,EADS,MAAPA,EACIhM,EAAKiG,QAAQwwB,EAAWtnB,IAAK,QAAQ/I,UAGrC9B,KAAK0H,IAAIA,EAAKhM,EAAKiG,QAAQwwB,EAAWtnB,IAAK,QAAQ/I,YAK/D,OACEgF,IAAa,MAAPA,EAAe,GAAI1H,MAAK0H,GAAO,KACrCY,IAAa,MAAPA,EAAe,GAAItI,MAAKsI,GAAO,OAKzC9M,EAAOD,QAAU4B,GAKb,SAAS3B,EAAQD,EAASM,GAsB9B,QAASuB,GAAS+X,EAAWvX,EAAOmyB,EAAQ1lB,GAE1C,KAAM1I,MAAMC,QAAQmuB,IAAWA,YAAkBvzB,KAAYuzB,YAAkB9tB,QAAQ,CACrF,GAAI+tB,GAAgB3lB,CACpBA,GAAU0lB,EACVA,EAASC,EAGX,GAAIjgB,GAAKpU,IACTA,MAAKs0B,gBACHzkB,MAAO,KACPC,IAAO,KAEPykB,YAAY,EAEZC,YAAa,SACbhiB,MAAO,KACPC,OAAQ,KACRgiB,UAAW,KACXC,UAAW,MAEb10B,KAAK0O,QAAU/N,EAAK6F,cAAexG,KAAKs0B,gBAGxCt0B,KAAK20B,QAAQnb,GAGbxZ,KAAKgC,cAELhC,KAAK40B,MACH5E,IAAKhwB,KAAKgwB,IACV6E,SAAU70B,KAAK+F,MACf+uB,SACEthB,GAAIxT,KAAKwT,GAAGuhB,KAAK/0B,MACjB2T,IAAK3T,KAAK2T,IAAIohB,KAAK/0B,MACnB6tB,KAAM7tB,KAAK6tB,KAAKkH,KAAK/0B,OAEvBg1B,eACAr0B,MACEs0B,KAAM,KACNC,SAAU9gB,EAAG+gB,UAAUJ,KAAK3gB,GAC5BghB,eAAgBhhB,EAAGihB,gBAAgBN,KAAK3gB,GACxCkhB,OAAQlhB,EAAGmhB,QAAQR,KAAK3gB,GACxBohB,aAAephB,EAAGqhB,cAAcV,KAAK3gB,KAKzCpU,KAAK01B,MAAQ,GAAI7zB,GAAM7B,KAAK40B,MAC5B50B,KAAKgC,WAAWkG,KAAKlI,KAAK01B,OAC1B11B,KAAK40B,KAAKc,MAAQ11B,KAAK01B,MAGvB11B,KAAK21B,SAAW,GAAI1yB,GAASjD,KAAK40B,MAClC50B,KAAKgC,WAAWkG,KAAKlI,KAAK21B,UAC1B31B,KAAK40B,KAAKj0B,KAAKs0B,KAAOj1B,KAAK21B,SAASV,KAAKF,KAAK/0B,KAAK21B,UAGnD31B,KAAK41B,YAAc,GAAIpzB,GAAYxC,KAAK40B,MACxC50B,KAAKgC,WAAWkG,KAAKlI,KAAK41B,aAI1B51B,KAAK61B,WAAa,GAAIpzB,GAAWzC,KAAK40B,MACtC50B,KAAKgC,WAAWkG,KAAKlI,KAAK61B,YAG1B71B,KAAKq3B,UAAY,GAAIr0B,GAAUhD,KAAK40B,MACpC50B,KAAKgC,WAAWkG,KAAKlI,KAAKq3B,WAE1Br3B,KAAK+1B,UAAY,KACjB/1B,KAAKg2B,WAAa,KAGdtnB,GACF1O,KAAKmT,WAAWzE,GAId0lB,GACFp0B,KAAKi2B,UAAU7B,GAIbnyB,EACFjC,KAAKk2B,SAASj0B,GAGdjC,KAAK0hB,SA5GT,GAEI/gB,IAFUT,EAAoB,IACrBA,EAAoB,IACtBA,EAAoB,IAC3BW,EAAUX,EAAoB,GAC9BY,EAAWZ,EAAoB,GAC/B2B,EAAQ3B,EAAoB,IAC5Bi2B,EAAOj2B,EAAoB,IAC3B+C,EAAW/C,EAAoB,IAC/BsC,EAActC,EAAoB,IAClCuC,EAAavC,EAAoB,IACjC8C,EAAY9C,EAAoB,GAuGpCuB,GAAQ2R,UAAY,GAAI+iB,GAMxB10B,EAAQ2R,UAAU8iB,SAAW,SAASj0B,GACpC,GAGIm0B,GAHAC,EAAiC,MAAlBr2B,KAAK+1B,SAwBxB,IAhBEK,EAJGn0B,EAGIA,YAAiBpB,IAAWoB,YAAiBnB,GACvCmB,EAIA,GAAIpB,GAAQoB,GACvB4E,MACEgJ,MAAO,OACPC,IAAK,UAVI,KAgBf9P,KAAK+1B,UAAYK,EACjBp2B,KAAKq3B,WAAar3B,KAAKq3B,UAAUnB,SAASE,GAEtCC,EACF,GAA0B9vB,QAAtBvG,KAAK0O,QAAQmB,OAA0CtJ,QAApBvG,KAAK0O,QAAQoB,IAAkB,CACpE,GAAID,GAA8BtJ,QAAtBvG,KAAK0O,QAAQmB,MAAqB7P,KAAK0O,QAAQmB,MAAQ,KAC/DC,EAA4BvJ,QAApBvG,KAAK0O,QAAQoB,IAAqB9P,KAAK0O,QAAQoB,IAAM,IAEjE9P,MAAKw2B,UAAU3mB,EAAOC,GAAM2mB,SAAS,QAGrCz2B,MAAK02B,KAAKD,SAAS,KASzBh1B,EAAQ2R,UAAU6iB,UAAY,SAAS7B,GAErC,GAAIgC,EAKFA,GAJGhC,EAGIA,YAAkBvzB,IAAWuzB,YAAkBtzB,GACzCszB,EAIA,GAAIvzB,GAAQuzB,GAPZ,KAUfp0B,KAAKg2B,WAAaI,EAClBp2B,KAAKq3B,UAAUpB,UAAUG,IAS3B30B,EAAQ2R,UAAUkkB,UAAY,SAASC,EAAS/kB,EAAOC,GAGrD,MAFelM,UAAXiM,IAAuBA,EAAS,IACrBjM,SAAXkM,IAAuBA,EAAS,IACGlM,SAAnCvG,KAAKq3B,UAAUjD,OAAOmD,GACjBv3B,KAAKq3B,UAAUjD,OAAOmD,GAASD,UAAU9kB,EAAMC,GAG/C,qBAAwB8kB,GASnC91B,EAAQ2R,UAAUokB,eAAiB,SAASD,GAC1C,MAAuChxB,UAAnCvG,KAAKq3B,UAAUjD,OAAOmD,GAChBv3B,KAAKq3B,UAAUjD,OAAOmD,GAAS5O,UAAkEpiB,SAAtDvG,KAAKq3B,UAAU3oB,QAAQ0lB,OAAOqD,WAAWF,IAA+E,GAArDv3B,KAAKq3B,UAAU3oB,QAAQ0lB,OAAOqD,WAAWF,KAGxJ,GAWX91B,EAAQ2R,UAAU4jB,aAAe,WAC/B,GAAIjrB,GAAM,KACNY,EAAM,IAGV,KAAK,GAAI4qB,KAAWv3B,MAAKq3B,UAAUjD,OACjC,GAAIp0B,KAAKq3B,UAAUjD,OAAOvuB,eAAe0xB,IACO,GAA1Cv3B,KAAKq3B,UAAUjD,OAAOmD,GAAS5O,QACjC,IAAK,GAAIpjB,GAAI,EAAGA,EAAIvF,KAAKq3B,UAAUjD,OAAOmD,GAASxB,UAAUrwB,OAAQH,IAAK,CACxE,GAAI+J,GAAOtP,KAAKq3B,UAAUjD,OAAOmD,GAASxB,UAAUxwB,GAChD6B,EAAQzG,EAAKiG,QAAQ0I,EAAK0C,EAAG,QAAQjL,SACzCgF,GAAa,MAAPA,EAAc3E,EAAQ2E,EAAM3E,EAAQA,EAAQ2E,EAClDY,EAAa,MAAPA,EAAcvF,EAAcA,EAANuF,EAAcvF,EAAQuF,EAM1D,OACEZ,IAAa,MAAPA,EAAe,GAAI1H,MAAK0H,GAAO,KACrCY,IAAa,MAAPA,EAAe,GAAItI,MAAKsI,GAAO,OAMzC9M,EAAOD,QAAU6B,GAKb,SAAS5B,EAAQD,EAASM,GAK9B,GAAI2D,GAAS3D,EAAoB,GAQjCN,GAAQ83B,qBAAuB,SAAS9C,EAAMI,GAE5C,GADAJ,EAAKI,eACDA,GACgC,GAA9BhvB,MAAMC,QAAQ+uB,GAAsB,CACtC,IAAK,GAAIzvB,GAAI,EAAGA,EAAIyvB,EAAYtvB,OAAQH,IACtC,GAA8BgB,SAA1ByuB,EAAYzvB,GAAGoyB,OAAsB,CACvC,GAAIC,KACJA,GAAS/nB,MAAQhM,EAAOmxB,EAAYzvB,GAAGsK,OAAO5I,SAASF,UACvD6wB,EAAS9nB,IAAMjM,EAAOmxB,EAAYzvB,GAAGuK,KAAK7I,SAASF,UACnD6tB,EAAKI,YAAY9sB,KAAK0vB,GAG1BhD,EAAKI,YAAY7e,KAAK,SAAU7Q,EAAGa,GACjC,MAAOb,GAAEuK,MAAQ1J,EAAE0J,UAY3BjQ,EAAQi4B,kBAAoB,SAAUjD,EAAMI,GAC1C,GAAIA,GAAuDzuB,SAAxCquB,EAAKC,SAASiD,gBAAgBtlB,MAAqB,CACpE5S,EAAQ83B,qBAAqB9C,EAAMI,EAQnC,KAAK,GANDnlB,GAAQhM,EAAO+wB,EAAKc,MAAM7lB,OAC1BC,EAAMjM,EAAO+wB,EAAKc,MAAM5lB,KAExBioB,EAAcnD,EAAKc,MAAM5lB,IAAM8kB,EAAKc,MAAM7lB,MAC1CmoB,EAAYD,EAAanD,EAAKC,SAASiD,gBAAgBtlB,MAElDjN,EAAI,EAAGA,EAAIyvB,EAAYtvB,OAAQH,IACtC,GAA8BgB,SAA1ByuB,EAAYzvB,GAAGoyB,OAAsB,CACvC,GAAIM,GAAYp0B,EAAOmxB,EAAYzvB,GAAGsK,OAClCqoB,EAAUr0B,EAAOmxB,EAAYzvB,GAAGuK,IAEpC,IAAoB,gBAAhBmoB,EAAUE,GACZ,KAAM,IAAIv0B,OAAM,qCAAuCoxB,EAAYzvB,GAAGsK,MAExE,IAAkB,gBAAdqoB,EAAQC,GACV,KAAM,IAAIv0B,OAAM,mCAAqCoxB,EAAYzvB,GAAGuK,IAGtE,IAAIC,GAAWmoB,EAAUD,CACzB,IAAIloB,GAAY,EAAIioB,EAAW,CAE7B,GAAIpO,GAAS,EACTwO,EAAWtoB,EAAIuoB,OACnB,QAAQrD,EAAYzvB,GAAGoyB,QACrB,IAAK,QACCM,EAAUK,OAASJ,EAAQI,QAC7B1O,EAAS,GAEXqO,EAAUM,UAAU1oB,EAAM0oB,aAC1BN,EAAUO,KAAK3oB,EAAM2oB,QACrBP,EAAU3M,SAAS,EAAE,QAErB4M,EAAQK,UAAU1oB,EAAM0oB,aACxBL,EAAQM,KAAK3oB,EAAM2oB,QACnBN,EAAQ5M,SAAS,EAAI1B,EAAO,QAE5BwO,EAASllB,IAAI,EAAG,QAChB,MACF,KAAK,SACH,GAAIulB,GAAYP,EAAQ5L,KAAK2L,EAAU,QACnCK,EAAML,EAAUK,KAGpBL,GAAUS,KAAK7oB,EAAM6oB,QACrBT,EAAUU,MAAM9oB,EAAM8oB,SACtBV,EAAUO,KAAK3oB,EAAM2oB,QACrBN,EAAUD,EAAUI,QAGpBJ,EAAUK,IAAIA,GACdJ,EAAQI,IAAIA,GACZJ,EAAQhlB,IAAIulB,EAAU,QAEtBR,EAAU3M,SAAS,EAAE,SACrB4M,EAAQ5M,SAAS,EAAE,SAEnB8M,EAASllB,IAAI,EAAG,QAChB,MACF,KAAK,UACC+kB,EAAUU,SAAWT,EAAQS,UAC/B/O,EAAS,GAEXqO,EAAUU,MAAM9oB,EAAM8oB,SACtBV,EAAUO,KAAK3oB,EAAM2oB,QACrBP,EAAU3M,SAAS,EAAE,UAErB4M,EAAQS,MAAM9oB,EAAM8oB,SACpBT,EAAQM,KAAK3oB,EAAM2oB,QACnBN,EAAQ5M,SAAS,EAAE,UACnB4M,EAAQhlB,IAAI0W,EAAO,UAEnBwO,EAASllB,IAAI,EAAG,SAChB,MACF,KAAK,SACC+kB,EAAUO,QAAUN,EAAQM,SAC9B5O,EAAS,GAEXqO,EAAUO,KAAK3oB,EAAM2oB,QACrBP,EAAU3M,SAAS,EAAE,SACrB4M,EAAQM,KAAK3oB,EAAM2oB,QACnBN,EAAQ5M,SAAS,EAAE,SACnB4M,EAAQhlB,IAAI0W,EAAO,SAEnBwO,EAASllB,IAAI,EAAG,QAChB,MACF,SAEE,WADA0lB,SAAQhF,IAAI,2EAA4EoB,EAAYzvB,GAAGoyB,QAG3G,KAAmBS,EAAZH,GAEL,OADArD,EAAKI,YAAY9sB,MAAM2H,MAAOooB,EAAUlxB,UAAW+I,IAAKooB,EAAQnxB,YACxDiuB,EAAYzvB,GAAGoyB,QACrB,IAAK,QACHM,EAAU/kB,IAAI,EAAG,QACjBglB,EAAQhlB,IAAI,EAAG,OACf,MACF,KAAK,SACH+kB,EAAU/kB,IAAI,EAAG,SACjBglB,EAAQhlB,IAAI,EAAG,QACf,MACF,KAAK,UACH+kB,EAAU/kB,IAAI,EAAG,UACjBglB,EAAQhlB,IAAI,EAAG,SACf,MACF,KAAK,SACH+kB,EAAU/kB,IAAI,EAAG,KACjBglB,EAAQhlB,IAAI,EAAG,IACf,MACF,SAEE,WADA0lB,SAAQhF,IAAI,2EAA4EoB,EAAYzvB,GAAGoyB,QAI7G/C,EAAKI,YAAY9sB,MAAM2H,MAAOooB,EAAUlxB,UAAW+I,IAAKooB,EAAQnxB,aAKtEnH,EAAQi5B,iBAAiBjE,EAEzB,IAAIkE,GAAcl5B,EAAQm5B,SAASnE,EAAKc,MAAM7lB,MAAO+kB,EAAKI,aACtDgE,EAAYp5B,EAAQm5B,SAASnE,EAAKc,MAAM5lB,IAAI8kB,EAAKI,aACjDiE,EAAarE,EAAKc,MAAM7lB,MACxBqpB,EAAWtE,EAAKc,MAAM5lB,GACA,IAAtBgpB,EAAYK,SAAiBF,EAAwC,GAA3BrE,EAAKc,MAAM0D,aAAuBN,EAAYb,UAAY,EAAIa,EAAYZ,QAAU,GAC1G,GAApBc,EAAUG,SAAmBD,EAAsC,GAAzBtE,EAAKc,MAAM2D,WAAuBL,EAAUf,UAAY,EAAMe,EAAUd,QAAU,IACtG,GAAtBY,EAAYK,QAAsC,GAApBH,EAAUG,SAC1CvE,EAAKc,MAAM4D,YAAYL,EAAYC,KAYzCt5B,EAAQi5B,iBAAmB,SAASjE,GAGlC,IAAK,GAFDI,GAAcJ,EAAKI,YACnBuE,KACKh0B,EAAI,EAAGA,EAAIyvB,EAAYtvB,OAAQH,IACtC,IAAK,GAAIsmB,GAAI,EAAGA,EAAImJ,EAAYtvB,OAAQmmB,IAClCtmB,GAAKsmB,GAA8B,GAAzBmJ,EAAYnJ,GAAGvV,QAA2C,GAAzB0e,EAAYzvB,GAAG+Q,SAExD0e,EAAYnJ,GAAGhc,OAASmlB,EAAYzvB,GAAGsK,OAASmlB,EAAYnJ,GAAG/b,KAAOklB,EAAYzvB,GAAGuK,IACvFklB,EAAYnJ,GAAGvV,QAAS,EAGjB0e,EAAYnJ,GAAGhc,OAASmlB,EAAYzvB,GAAGsK,OAASmlB,EAAYnJ,GAAGhc,OAASmlB,EAAYzvB,GAAGuK,KAC9FklB,EAAYzvB,GAAGuK,IAAMklB,EAAYnJ,GAAG/b,IACpCklB,EAAYnJ,GAAGvV,QAAS,GAGjB0e,EAAYnJ,GAAG/b,KAAOklB,EAAYzvB,GAAGsK,OAASmlB,EAAYnJ,GAAG/b,KAAOklB,EAAYzvB,GAAGuK,MAC1FklB,EAAYzvB,GAAGsK,MAAQmlB,EAAYnJ,GAAGhc,MACtCmlB,EAAYnJ,GAAGvV,QAAS,GAMhC,KAAK,GAAI/Q,GAAI,EAAGA,EAAIyvB,EAAYtvB,OAAQH,IAClCyvB,EAAYzvB,GAAG+Q,UAAW,GAC5BijB,EAAUrxB,KAAK8sB,EAAYzvB,GAI/BqvB,GAAKI,YAAcuE,EACnB3E,EAAKI,YAAY7e,KAAK,SAAU7Q,EAAGa,GACjC,MAAOb,GAAEuK,MAAQ1J,EAAE0J,SAIvBjQ,EAAQ45B,WAAa,SAASC,GAC5B,IAAK,GAAIl0B,GAAG,EAAGA,EAAIk0B,EAAM/zB,OAAQH,IAC/BqzB,QAAQhF,IAAIruB,EAAG,GAAIlB,MAAKo1B,EAAMl0B,GAAGsK,OAAO,GAAIxL,MAAKo1B,EAAMl0B,GAAGuK,KAAM2pB,EAAMl0B,GAAGsK,MAAO4pB,EAAMl0B,GAAGuK,IAAK2pB,EAAMl0B,GAAG+Q,SAS3G1W,EAAQ85B,oBAAsB,SAASC,EAAUC,GAG/C,IAAK,GAFDC,IAAe,EACfC,EAAeH,EAASI,QAAQhzB,UAC3BxB,EAAI,EAAGA,EAAIo0B,EAAS3E,YAAYtvB,OAAQH,IAAK,CACpD,GAAI0yB,GAAY0B,EAAS3E,YAAYzvB,GAAGsK,MACpCqoB,EAAUyB,EAAS3E,YAAYzvB,GAAGuK,GACtC,IAAIgqB,GAAgB7B,GAA4BC,EAAf4B,EAAwB,CACvDD,GAAe,CACf,QAIJ,GAAoB,GAAhBA,GAAwBC,EAAeH,EAASvG,KAAKrsB,WAAa+yB,GAAgBF,EAAc,CAClG,GAAIlqB,GAAY7L,EAAO+1B,GACnBI,EAAWn2B,EAAOq0B,EAElBxoB,GAAU8oB,QAAUwB,EAASxB,OAASmB,EAASM,cAAe,EACzDvqB,EAAUipB,SAAWqB,EAASrB,QAAUgB,EAASO,eAAgB,EACjExqB,EAAU6oB,aAAeyB,EAASzB,cAAcoB,EAASQ,aAAc,GAEhFR,EAASI,QAAUC,EAAS/yB,WAmChCrH,EAAQs1B,SAAW,SAASiB,EAAMiE,EAAM5nB,GACtC,GAAoC,GAAhC2jB,EAAKvB,KAAKI,YAAYtvB,OAAa,CACrC,GAAI20B,GAAalE,EAAKT,MAAM2E,WAAW7nB,EACvC,QAAQ4nB,EAAKrzB,UAAYszB,EAAWzQ,QAAUyQ,EAAWnd,MAGzD,GAAIic,GAASv5B,EAAQm5B,SAASqB,EAAMjE,EAAKvB,KAAKI,YACzB,IAAjBmE,EAAOA,SACTiB,EAAOjB,EAAOlB,UAGhB,IAAIloB,GAAWnQ,EAAQ06B,yBAAyBnE,EAAKvB,KAAKI,YAAamB,EAAKT,MAAM7lB,MAAOsmB,EAAKT,MAAM5lB,IACpGsqB,GAAOx6B,EAAQ26B,qBAAqBpE,EAAKvB,KAAKI,YAAamB,EAAKT,MAAO0E,EAEvE,IAAIC,GAAalE,EAAKT,MAAM2E,WAAW7nB,EAAOzC,EAC9C,QAAQqqB,EAAKrzB,UAAYszB,EAAWzQ,QAAUyQ,EAAWnd,OAa7Dtd,EAAQ01B,OAAS,SAASa,EAAMnkB,EAAGQ,GACjC,GAAoC,GAAhC2jB,EAAKvB,KAAKI,YAAYtvB,OAAa,CACrC,GAAI20B,GAAalE,EAAKT,MAAM2E,WAAW7nB,EACvC,OAAO,IAAInO,MAAK2N,EAAIqoB,EAAWnd,MAAQmd,EAAWzQ,QAGlD,GAAI4Q,GAAiB56B,EAAQ06B,yBAAyBnE,EAAKvB,KAAKI,YAAamB,EAAKT,MAAM7lB,MAAOsmB,EAAKT,MAAM5lB,KACtG2qB,EAAgBtE,EAAKT,MAAM5lB,IAAMqmB,EAAKT,MAAM7lB,MAAQ2qB,EACpDE,EAAkBD,EAAgBzoB,EAAIQ,EACtCmoB,EAA4B/6B,EAAQg7B,6BAA6BzE,EAAKvB,KAAKI,YAAamB,EAAKT,MAAOgF,GAEpGG,EAAU,GAAIx2B,MAAKs2B,EAA4BD,EAAkBvE,EAAKT,MAAM7lB,MAChF,OAAOgrB,IAYXj7B,EAAQ06B,yBAA2B,SAAStF,EAAanlB,EAAOC,GAE9D,IAAK,GADDC,GAAW,EACNxK,EAAI,EAAGA,EAAIyvB,EAAYtvB,OAAQH,IAAK,CAC3C,GAAI0yB,GAAYjD,EAAYzvB,GAAGsK,MAC3BqoB,EAAUlD,EAAYzvB,GAAGuK,GAEzBmoB,IAAapoB,GAAmBC,EAAVooB,IACxBnoB,GAAYmoB,EAAUD,GAG1B,MAAOloB,IAWTnQ,EAAQ26B,qBAAuB,SAASvF,EAAaU,EAAO0E,GAG1D,MAFAA,GAAOv2B,EAAOu2B,GAAMnzB,SAASF,UAC7BqzB,GAAQx6B,EAAQk7B,wBAAwB9F,EAAYU,EAAM0E,IAI5Dx6B,EAAQk7B,wBAA0B,SAAS9F,EAAaU,EAAO0E,GAC7D,GAAIW,GAAa,CACjBX,GAAOv2B,EAAOu2B,GAAMnzB,SAASF,SAE7B,KAAK,GAAIxB,GAAI,EAAGA,EAAIyvB,EAAYtvB,OAAQH,IAAK,CAC3C,GAAI0yB,GAAYjD,EAAYzvB,GAAGsK,MAC3BqoB,EAAUlD,EAAYzvB,GAAGuK,GAEzBmoB,IAAavC,EAAM7lB,OAASqoB,EAAUxC,EAAM5lB,KAC1CsqB,GAAQlC,IACV6C,GAAe7C,EAAUD,GAI/B,MAAO8C,IAWTn7B,EAAQg7B,6BAA+B,SAAS5F,EAAaU,EAAOsF,GAKlE,IAAK,GAJDR,GAAiB,EACjBzqB,EAAW,EACXkrB,EAAgBvF,EAAM7lB,MAEjBtK,EAAI,EAAGA,EAAIyvB,EAAYtvB,OAAQH,IAAK,CAC3C,GAAI0yB,GAAYjD,EAAYzvB,GAAGsK,MAC3BqoB,EAAUlD,EAAYzvB,GAAGuK,GAE7B,IAAImoB,GAAavC,EAAM7lB,OAASqoB,EAAUxC,EAAM5lB,IAAK,CAGnD,GAFAC,GAAYkoB,EAAYgD,EACxBA,EAAgB/C,EACZnoB,GAAYirB,EACd,KAGAR,IAAkBtC,EAAUD,GAKlC,MAAOuC,IAaT56B,EAAQs7B,mBAAqB,SAASlG,EAAaoF,EAAMe,EAAWC,GAClE,GAAIrC,GAAWn5B,EAAQm5B,SAASqB,EAAMpF,EACtC,OAAuB,IAAnB+D,EAASI,OACK,EAAZgC,EACuB,GAArBC,EACKrC,EAASd,WAAac,EAASb,QAAUkC,GAAQ,EAGjDrB,EAASd,UAAY,EAIL,GAArBmD,EACKrC,EAASb,SAAWkC,EAAOrB,EAASd,WAAa,EAGjDc,EAASb,QAAU,EAKvBkC,GAaXx6B,EAAQm5B,SAAW,SAASqB,EAAMpF,GAChC,IAAK,GAAIzvB,GAAI,EAAGA,EAAIyvB,EAAYtvB,OAAQH,IAAK,CAC3C,GAAI0yB,GAAYjD,EAAYzvB,GAAGsK,MAC3BqoB,EAAUlD,EAAYzvB,GAAGuK,GAE7B,IAAIsqB,GAAQnC,GAAoBC,EAAPkC,EACvB,OAAQjB,QAAQ,EAAMlB,UAAWA,EAAWC,QAASA,GAIzD,OAAQiB,QAAQ,EAAOlB,UAAWA,EAAWC,QAASA,KAKpD,SAASr4B,GA4Bb,QAAS+B,GAASiO,EAAOC,EAAKurB,EAAaC,EAAiBC,EAAaC,GAEvEx7B,KAAK+5B,QAAU,EAEf/5B,KAAKy7B,WAAY,EACjBz7B,KAAK07B,UAAY,EACjB17B,KAAKooB,KAAO,EACZpoB,KAAKkd,MAAQ,EAEbld,KAAK27B,YACL37B,KAAK47B,UACL57B,KAAK67B,UAAY,EAEjB77B,KAAK87B,YAAc,EAAO,EAAM,EAAI,IACpC97B,KAAK+7B,YAAc,IAAO,GAAM,EAAI,GAEpC/7B,KAAKw7B,WAAaA,EAElBx7B,KAAKwzB,SAAS3jB,EAAOC,EAAKurB,EAAaC,EAAiBC,GAe1D35B,EAASwR,UAAUogB,SAAW,SAAS3jB,EAAOC,EAAKurB,EAAaC,EAAiBC,GAC/Ev7B,KAAKmzB,OAA6B5sB,SAApBg1B,EAAYxvB,IAAoB8D,EAAQ0rB,EAAYxvB,IAClE/L,KAAKozB,KAA2B7sB,SAApBg1B,EAAY5uB,IAAoBmD,EAAMyrB,EAAY5uB,IAE1D3M,KAAKmzB,QAAUnzB,KAAKozB,OACtBpzB,KAAKmzB,QAAU,IACfnzB,KAAKozB,MAAQ,GAGO,GAAlBpzB,KAAKy7B,WACPz7B,KAAKg8B,eAAeX,EAAaC,GAGnCt7B,KAAKi8B,SAASV,IAOhB35B,EAASwR,UAAU4oB,eAAiB,SAASX,EAAaC,GAExD,GAAIhpB,GAAOtS,KAAKozB,KAAOpzB,KAAKmzB,OACxB+I,EAAkB,IAAP5pB,EACX6pB,EAAmBd,GAAea,EAAWZ,GAC7Cc,EAAmBn3B,KAAK0oB,MAAM1oB,KAAK2uB,IAAIsI,GAAUj3B,KAAK4uB,MAEtDwI,EAAe,GACfC,EAAkBr3B,KAAK8uB,IAAI,GAAGqI,GAE9BvsB,EAAQ,CACW,GAAnBusB,IACFvsB,EAAQusB,EAIV,KAAK,GADDG,IAAgB,EACXh3B,EAAIsK,EAAO5K,KAAK6lB,IAAIvlB,IAAMN,KAAK6lB,IAAIsR,GAAmB72B,IAAK,CAClE+2B,EAAkBr3B,KAAK8uB,IAAI,GAAGxuB,EAC9B,KAAK,GAAIsmB,GAAI,EAAGA,EAAI7rB,KAAK+7B,WAAWr2B,OAAQmmB,IAAK,CAC/C,GAAI2Q,GAAWF,EAAkBt8B,KAAK+7B,WAAWlQ,EACjD,IAAI2Q,GAAYL,EAAkB,CAChCI,GAAgB,EAChBF,EAAexQ,CACf,QAGJ,GAAqB,GAAjB0Q,EACF,MAGJv8B,KAAK07B,UAAYW,EACjBr8B,KAAKkd,MAAQof,EACbt8B,KAAKooB,KAAOkU,EAAkBt8B,KAAK+7B,WAAWM,IAShDz6B,EAASwR,UAAU6oB,SAAW,SAASV,GACjBh1B,SAAhBg1B,IACFA,KAGF,IAAIkB,GAAgCl2B,SAApBg1B,EAAYxvB,IAAoB/L,KAAKmzB,OAAuB,EAAbnzB,KAAKkd,MAAYld,KAAK+7B,WAAW/7B,KAAK07B,WAAcH,EAAYxvB,IAC3H2wB,EAA8Bn2B,SAApBg1B,EAAY5uB,IAAoB3M,KAAKozB,KAAQpzB,KAAKkd,MAAQld,KAAK+7B,WAAW/7B,KAAK07B,WAAcH,EAAY5uB,GAEvH3M,MAAK47B,UAAgCr1B,SAApBg1B,EAAY5uB,IAAoB3M,KAAK28B,aAAaD,GAAWnB,EAAY5uB,IAC1F3M,KAAK27B,YAAkCp1B,SAApBg1B,EAAYxvB,IAAoB/L,KAAK28B,aAAaF,GAAalB,EAAYxvB,IAGvE,GAAnB/L,KAAKw7B,aAAuBx7B,KAAK47B,UAAY57B,KAAK27B,aAAe37B,KAAKooB,MAAQ,IAChFpoB,KAAK47B,WAAa57B,KAAK47B,UAAY57B,KAAKooB,MAG1CpoB,KAAK67B,UAAY77B,KAAK28B,aAAaD,GAAWA,EAAU18B,KAAK28B,aAAaF,GAAaA,EACvFz8B,KAAK48B,YAAc58B,KAAK47B,UAAY57B,KAAK27B,YAGzC37B,KAAK+5B,QAAU/5B,KAAK47B,WAGtBh6B,EAASwR,UAAUupB,aAAe,SAASv1B,GACzC,GAAIy1B,GAAUz1B,EAASA,GAASpH,KAAKkd,MAAQld,KAAK+7B,WAAW/7B,KAAK07B,WAClE,OAAIt0B,IAASpH,KAAKkd,MAAQld,KAAK+7B,WAAW/7B,KAAK07B,YAAc,GAAO17B,KAAKkd,MAAQld,KAAK+7B,WAAW/7B,KAAK07B,WAC7FmB,EAAW78B,KAAKkd,MAAQld,KAAK+7B,WAAW/7B,KAAK07B,WAG7CmB,GASXj7B,EAASwR,UAAU0pB,QAAU,WAC3B,MAAQ98B,MAAK+5B,SAAW/5B,KAAK27B,aAM/B/5B,EAASwR,UAAUkV,KAAO,WACxB,GAAIuJ,GAAO7xB,KAAK+5B,OAChB/5B,MAAK+5B,SAAW/5B,KAAKooB,KAGjBpoB,KAAK+5B,SAAWlI,IAClB7xB,KAAK+5B,QAAU/5B,KAAKozB,OAOxBxxB,EAASwR,UAAU2pB,SAAW,WAC5B/8B,KAAK+5B,SAAW/5B,KAAKooB,KACrBpoB,KAAK47B,WAAa57B,KAAKooB,KACvBpoB,KAAK48B,YAAc58B,KAAK47B,UAAY57B,KAAK27B,aAS3C/5B,EAASwR,UAAUiV,WAAa,SAAS2U,GAEvC,GAAIjD,GAAW90B,KAAK6lB,IAAI9qB,KAAK+5B,SAAW/5B,KAAKooB,KAAO,EAAK,EAAIpoB,KAAK+5B,QAC9D7F,EAAc,GAAKjwB,OAAO81B,GAAS7F,YAAY,EAGnD,IAAgB3tB,SAAby2B,GAA2Bv4B,MAAMR,OAAO+4B,KAqCzC,GAAgC,IAA5B9I,EAAYxtB,QAAQ,MAA0C,IAA5BwtB,EAAYxtB,QAAQ,KAExD,IAAK,GAAInB,GAAI2uB,EAAYxuB,OAAS,EAAGH,EAAI,EAAGA,IAAK,CAC/C,GAAsB,KAAlB2uB,EAAY3uB,GAGX,CAAA,GAAsB,KAAlB2uB,EAAY3uB,IAA+B,KAAlB2uB,EAAY3uB,GAAW,CACvD2uB,EAAcA,EAAYhpB,MAAM,EAAG3F,EACnC,OAGA,MAPA2uB,EAAcA,EAAYhpB,MAAM,EAAG3F,QAzCY,CAErD,GAAI03B,GAAM,GACN50B,EAAQ6rB,EAAYxtB,QAAQ,IAoBhC,IAnBY,IAAT2B,IAED40B,EAAM/I,EAAYhpB,MAAM7C,GAExB6rB,EAAcA,EAAYhpB,MAAM,EAAG7C,IAErCA,EAAQpD,KAAK0H,IAAIunB,EAAYxtB,QAAQ,KAAMwtB,EAAYxtB,QAAQ,MAClD,KAAV2B,GAEe,IAAb20B,IACD9I,GAAe,KAGjB7rB,EAAQ6rB,EAAYxuB,OAASs3B,GAEV,IAAbA,IAEN30B,GAAS20B,EAAW,GAEnB30B,EAAQ6rB,EAAYxuB,OAErB,IAAI,GAAIw3B,GAAM70B,EAAQ6rB,EAAYxuB,OAAQw3B,EAAM,EAAGA,IACjDhJ,GAAe,QAKjBA,GAAcA,EAAYhpB,MAAM,EAAG7C,EAGrC6rB,IAAe+I,EAoBjB,MAAO/I,IAWTtyB,EAASwR,UAAU6hB,KAAO,aAS1BrzB,EAASwR,UAAU+pB,QAAU,WAC3B,MAAQn9B,MAAK+5B,SAAW/5B,KAAKkd,MAAQld,KAAK87B,WAAW97B,KAAK07B,aAAe,GAG3E77B,EAAOD,QAAUgC,GAKb,SAAS/B,EAAQD,EAASM,GAgB9B,QAAS2B,GAAM+yB,EAAMlmB,GACnB,GAAI0uB,GAAMv5B,IAASw5B,MAAM,GAAGC,QAAQ,GAAGC,QAAQ,GAAGC,aAAa,EAC/Dx9B,MAAK6P,MAAQutB,EAAI/E,QAAQnlB,IAAI,GAAI,QAAQnM,UACzC/G,KAAK8P,IAAMstB,EAAI/E,QAAQnlB,IAAI,EAAG,QAAQnM,UAEtC/G,KAAK40B,KAAOA,EACZ50B,KAAKy9B,gBAAkB,EACvBz9B,KAAK09B,YAAc,EACnB19B,KAAKo5B,cAAe,EACpBp5B,KAAKq5B,YAAa,EAGlBr5B,KAAKs0B,gBACHzkB,MAAO,KACPC,IAAK,KACLqrB,UAAW,aACXwC,UAAU,EACVC,UAAU,EACV7xB,IAAK,KACLY,IAAK,KACLkxB,QAAS,GACTC,QAAS,UAEX99B,KAAK0O,QAAU/N,EAAK0E,UAAWrF,KAAKs0B,gBAEpCt0B,KAAK+F,OACHg4B,UAEF/9B,KAAKg+B,aAAe,KAGpBh+B,KAAK40B,KAAKE,QAAQthB,GAAG,YAAaxT,KAAKi+B,aAAalJ,KAAK/0B,OACzDA,KAAK40B,KAAKE,QAAQthB,GAAG,OAAaxT,KAAKk+B,QAAQnJ,KAAK/0B,OACpDA,KAAK40B,KAAKE,QAAQthB,GAAG,UAAaxT,KAAKm+B,WAAWpJ,KAAK/0B,OAGvDA,KAAK40B,KAAKE,QAAQthB,GAAG,OAAQxT,KAAKo+B,QAAQrJ,KAAK/0B,OAG/CA,KAAK40B,KAAKE,QAAQthB,GAAG,aAAmBxT,KAAKq+B,cAActJ,KAAK/0B,OAChEA,KAAK40B,KAAKE,QAAQthB,GAAG,iBAAmBxT,KAAKq+B,cAActJ,KAAK/0B,OAGhEA,KAAK40B,KAAKE,QAAQthB,GAAG,QAASxT,KAAKs+B,SAASvJ,KAAK/0B,OACjDA,KAAK40B,KAAKE,QAAQthB,GAAG,QAASxT,KAAKu+B,SAASxJ,KAAK/0B,OAEjDA,KAAKmT,WAAWzE,GAsClB,QAAS8vB,GAAmBrD,GAC1B,GAAiB,cAAbA,GAA0C,YAAbA,EAC/B,KAAM,IAAI/0B,WAAU,sBAAwB+0B,EAAY,yCAgf5D,QAASsD,GAAYV,EAAOj1B,GAC1B,OACEkJ,EAAG+rB,EAAMW,MAAQ/9B,EAAK0G,gBAAgByB,GACtCmJ,EAAG8rB,EAAMY,MAAQh+B,EAAKgH,eAAemB,IAvlBzC,GAAInI,GAAOT,EAAoB,GAC3B0+B,EAAa1+B,EAAoB,IACjC2D,EAAS3D,EAAoB,IAC7BqC,EAAYrC,EAAoB,IAChCyB,EAAWzB,EAAoB,GA2DnC2B,GAAMuR,UAAY,GAAI7Q,GAkBtBV,EAAMuR,UAAUD,WAAa,SAAUzE,GACrC,GAAIA,EAAS,CAEX,GAAIP,IAAU,YAAa,MAAO,MAAO,UAAW,UAAW,WAAY,WAAY,WAAY,cACnGxN,GAAKmF,gBAAgBqI,EAAQnO,KAAK0O,QAASA,IAEvC,SAAWA,IAAW,OAASA,KAEjC1O,KAAKwzB,SAAS9kB,EAAQmB,MAAOnB,EAAQoB,OA4B3CjO,EAAMuR,UAAUogB,SAAW,SAAS3jB,EAAOC,EAAK2mB,EAASoI,GACnDA,KAAW,IACbA,GAAS,EAEX,IAAI1L,GAAkB5sB,QAATsJ,EAAqBlP,EAAKiG,QAAQiJ,EAAO,QAAQ9I,UAAY,KACtEqsB,EAAgB7sB,QAAPuJ,EAAqBnP,EAAKiG,QAAQkJ,EAAK,QAAQ/I,UAAc,IAG1E,IAFA/G,KAAK8+B,mBAEDrI,EAAS,CACX,GAAIriB,GAAKpU,KACL++B,EAAY/+B,KAAK6P,MACjBmvB,EAAUh/B,KAAK8P,IACfC,EAA8B,gBAAZ0mB,GAAuBA,EAAU,IACnDwI,GAAW,GAAI56B,OAAO0C,UACtBm4B,GAAa,EAEb5W,EAAO,WACT,IAAKlU,EAAGrO,MAAMg4B,MAAMoB,SAAU,CAC5B,GAAI/B,IAAM,GAAI/4B,OAAO0C,UACjBqzB,EAAOgD,EAAM6B,EACbG,EAAOhF,EAAOrqB,EACdlE,EAAKuzB,GAAmB,OAAXjM,EAAmBA,EAASxyB,EAAKiP,cAAcwqB,EAAM2E,EAAW5L,EAAQpjB,GACrFgnB,EAAKqI,GAAiB,OAAThM,EAAmBA,EAASzyB,EAAKiP,cAAcwqB,EAAM4E,EAAS5L,EAAMrjB,EAErFsvB,GAAUjrB,EAAGklB,YAAYztB,EAAGkrB,GAC5Bp1B,EAASk2B,kBAAkBzjB,EAAGwgB,KAAMxgB,EAAG1F,QAAQsmB,aAC/CkK,EAAaA,GAAcG,EACvBA,GACFjrB,EAAGwgB,KAAKE,QAAQjH,KAAK,eAAgBhe,MAAO,GAAIxL,MAAK+P,EAAGvE,OAAQC,IAAK,GAAIzL,MAAK+P,EAAGtE,KAAM+uB,OAAOA,IAG5FO,EACEF,GACF9qB,EAAGwgB,KAAKE,QAAQjH,KAAK,gBAAiBhe,MAAO,GAAIxL,MAAK+P,EAAGvE,OAAQC,IAAK,GAAIzL,MAAK+P,EAAGtE,KAAM+uB,OAAOA,IAMjGzqB,EAAG4pB,aAAezkB,WAAW+O,EAAM,KAKzC,OAAOA,KAGP,GAAI+W,GAAUr/B,KAAKs5B,YAAYnG,EAAQC,EAEvC,IADAzxB,EAASk2B,kBAAkB73B,KAAK40B,KAAM50B,KAAK0O,QAAQsmB,aAC/CqK,EAAS,CACX,GAAItrB,IAAUlE,MAAO,GAAIxL,MAAKrE,KAAK6P,OAAQC,IAAK,GAAIzL,MAAKrE,KAAK8P,KAAM+uB,OAAOA,EAC3E7+B,MAAK40B,KAAKE,QAAQjH,KAAK,cAAe9Z,GACtC/T,KAAK40B,KAAKE,QAAQjH,KAAK,eAAgB9Z,KAS7ClS,EAAMuR,UAAU0rB,iBAAmB,WAC7B9+B,KAAKg+B,eACP1kB,aAAatZ,KAAKg+B,cAClBh+B,KAAKg+B,aAAe,OAaxBn8B,EAAMuR,UAAUkmB,YAAc,SAASzpB,EAAOC,GAC5C,GAIIwc,GAJAgT,EAAqB,MAATzvB,EAAiBlP,EAAKiG,QAAQiJ,EAAO,QAAQ9I,UAAY/G,KAAK6P,MAC1E0vB,EAAmB,MAAPzvB,EAAiBnP,EAAKiG,QAAQkJ,EAAK,QAAQ/I,UAAc/G,KAAK8P,IAC1EnD,EAA2B,MAApB3M,KAAK0O,QAAQ/B,IAAehM,EAAKiG,QAAQ5G,KAAK0O,QAAQ/B,IAAK,QAAQ5F,UAAY,KACtFgF,EAA2B,MAApB/L,KAAK0O,QAAQ3C,IAAepL,EAAKiG,QAAQ5G,KAAK0O,QAAQ3C,IAAK,QAAQhF,UAAY,IAI1F,IAAItC,MAAM66B,IAA0B,OAAbA,EACrB,KAAM,IAAI17B,OAAM,kBAAoBiM,EAAQ,IAE9C,IAAIpL,MAAM86B,IAAsB,OAAXA,EACnB,KAAM,IAAI37B,OAAM,gBAAkBkM,EAAM,IAyC1C,IArCawvB,EAATC,IACFA,EAASD,GAIC,OAARvzB,GACaA,EAAXuzB,IACFhT,EAAQvgB,EAAMuzB,EACdA,GAAYhT,EACZiT,GAAUjT,EAGC,MAAP3f,GACE4yB,EAAS5yB,IACX4yB,EAAS5yB,IAOL,OAARA,GACE4yB,EAAS5yB,IACX2f,EAAQiT,EAAS5yB,EACjB2yB,GAAYhT,EACZiT,GAAUjT,EAGC,MAAPvgB,GACaA,EAAXuzB,IACFA,EAAWvzB,IAOU,OAAzB/L,KAAK0O,QAAQmvB,QAAkB,CACjC,GAAIA,GAAUvY,WAAWtlB,KAAK0O,QAAQmvB,QACxB,GAAVA,IACFA,EAAU,GAEcA,EAArB0B,EAASD,IACPt/B,KAAK8P,IAAM9P,KAAK6P,QAAWguB,GAE9ByB,EAAWt/B,KAAK6P,MAChB0vB,EAASv/B,KAAK8P,MAIdwc,EAAQuR,GAAW0B,EAASD,GAC5BA,GAAYhT,EAAO,EACnBiT,GAAUjT,EAAO,IAMvB,GAA6B,OAAzBtsB,KAAK0O,QAAQovB,QAAkB,CACjC,GAAIA,GAAUxY,WAAWtlB,KAAK0O,QAAQovB,QACxB,GAAVA,IACFA,EAAU,GAEPyB,EAASD,EAAYxB,IACnB99B,KAAK8P,IAAM9P,KAAK6P,QAAWiuB,GAE9BwB,EAAWt/B,KAAK6P,MAChB0vB,EAASv/B,KAAK8P,MAIdwc,EAASiT,EAASD,EAAYxB,EAC9BwB,GAAYhT,EAAO,EACnBiT,GAAUjT,EAAO,IAKvB,GAAI+S,GAAWr/B,KAAK6P,OAASyvB,GAAYt/B,KAAK8P,KAAOyvB,CAUrD,OAPOD,IAAYt/B,KAAK6P,OAASyvB,GAAct/B,KAAK8P,KAASyvB,GAAYv/B,KAAK6P,OAAS0vB,GAAYv/B,KAAK8P,KACjG9P,KAAK6P,OAASyvB,GAAYt/B,KAAK6P,OAAS0vB,GAAcv/B,KAAK8P,KAAOwvB,GAAct/B,KAAK8P,KAAOyvB,GACjGv/B,KAAK40B,KAAKE,QAAQjH,KAAK,oBAGzB7tB,KAAK6P,MAAQyvB,EACbt/B,KAAK8P,IAAMyvB,EACJF,GAOTx9B,EAAMuR,UAAUosB,SAAW,WACzB,OACE3vB,MAAO7P,KAAK6P,MACZC,IAAK9P,KAAK8P,MAUdjO,EAAMuR,UAAUinB,WAAa,SAAU7nB,EAAOitB,GAC5C,MAAO59B,GAAMw4B,WAAWr6B,KAAK6P,MAAO7P,KAAK8P,IAAK0C,EAAOitB,IAWvD59B,EAAMw4B,WAAa,SAAUxqB,EAAOC,EAAK0C,EAAOitB,GAI9C,MAHoBl5B,UAAhBk5B,IACFA,EAAc,GAEH,GAATjtB,GAAe1C,EAAMD,GAAS,GAE9B+Z,OAAQ/Z,EACRqN,MAAO1K,GAAS1C,EAAMD,EAAQ4vB,KAK9B7V,OAAQ,EACR1M,MAAO,IAUbrb,EAAMuR,UAAU6qB,aAAe,WAC7Bj+B,KAAKy9B,gBAAkB,EACvBz9B,KAAK0/B,cAAgB,EAEhB1/B,KAAK0O,QAAQivB,UAIb39B,KAAK+F,MAAMg4B,MAAM4B,gBAEtB3/B,KAAK+F,MAAMg4B,MAAMluB,MAAQ7P,KAAK6P,MAC9B7P,KAAK+F,MAAMg4B,MAAMjuB,IAAM9P,KAAK8P,IAC5B9P,KAAK+F,MAAMg4B,MAAMoB,UAAW,EAExBn/B,KAAK40B,KAAK5E,IAAItwB,OAChBM,KAAK40B,KAAK5E,IAAItwB,KAAKwN,MAAM+f,OAAS,UAStCprB,EAAMuR,UAAU8qB,QAAU,SAAU10B,GAElC,GAAKxJ,KAAK0O,QAAQivB,UAGb39B,KAAK+F,MAAMg4B,MAAM4B,cAAtB,CAEA,GAAIxE,GAAYn7B,KAAK0O,QAAQysB,SAC7BqD,GAAkBrD,EAElB,IAAIzM,GAAsB,cAAbyM,EAA6B3xB,EAAMo2B,QAAQC,OAASr2B,EAAMo2B,QAAQE,MAC/EpR,IAAS1uB,KAAKy9B,eACd,IAAIhL,GAAYzyB,KAAK+F,MAAMg4B,MAAMjuB,IAAM9P,KAAK+F,MAAMg4B,MAAMluB,MAGpDE,EAAWpO,EAAS24B,yBAAyBt6B,KAAK40B,KAAKI,YAAah1B,KAAK6P,MAAO7P,KAAK8P,IACzF2iB,IAAY1iB,CAEZ,IAAIyC,GAAsB,cAAb2oB,EAA6Bn7B,KAAK40B,KAAKC,SAAS1I,OAAO3Z,MAAQxS,KAAK40B,KAAKC,SAAS1I,OAAO1Z,OAClGstB,GAAarR,EAAQlc,EAAQigB,EAC7B6M,EAAWt/B,KAAK+F,MAAMg4B,MAAMluB,MAAQkwB,EACpCR,EAASv/B,KAAK+F,MAAMg4B,MAAMjuB,IAAMiwB,EAIhCC,EAAYr+B,EAASu5B,mBAAmBl7B,KAAK40B,KAAKI,YAAasK,EAAUt/B,KAAK0/B,cAAchR,GAAO,GACnGuR,EAAUt+B,EAASu5B,mBAAmBl7B,KAAK40B,KAAKI,YAAauK,EAAQv/B,KAAK0/B,cAAchR,GAAO,EACnG,IAAIsR,GAAaV,GAAYW,GAAWV,EAKtC,MAJAv/B,MAAKy9B,iBAAmB/O,EACxB1uB,KAAK+F,MAAMg4B,MAAMluB,MAAQmwB,EACzBhgC,KAAK+F,MAAMg4B,MAAMjuB,IAAMmwB,MACvBjgC,MAAKk+B,QAAQ10B,EAIfxJ,MAAK0/B,cAAgBhR,EACrB1uB,KAAKs5B,YAAYgG,EAAUC,GAG3Bv/B,KAAK40B,KAAKE,QAAQjH,KAAK,eACrBhe,MAAO,GAAIxL,MAAKrE,KAAK6P,OACrBC,IAAO,GAAIzL,MAAKrE,KAAK8P,KACrB+uB,QAAQ,MASZh9B,EAAMuR,UAAU+qB,WAAa,WAEtBn+B,KAAK0O,QAAQivB,UAIb39B,KAAK+F,MAAMg4B,MAAM4B,gBAEtB3/B,KAAK+F,MAAMg4B,MAAMoB,UAAW,EACxBn/B,KAAK40B,KAAK5E,IAAItwB,OAChBM,KAAK40B,KAAK5E,IAAItwB,KAAKwN,MAAM+f,OAAS,QAIpCjtB,KAAK40B,KAAKE,QAAQjH,KAAK,gBACrBhe,MAAO,GAAIxL,MAAKrE,KAAK6P,OACrBC,IAAO,GAAIzL,MAAKrE,KAAK8P,KACrB+uB,QAAQ,MAUZh9B,EAAMuR,UAAUirB,cAAgB,SAAS70B,GAEvC,GAAMxJ,KAAK0O,QAAQkvB,UAAY59B,KAAK0O,QAAQivB,SAA5C,CAGA,GAAIjP,GAAQ,CAYZ,IAXIllB,EAAMmlB,WACRD,EAAQllB,EAAMmlB,WAAa,IAClBnlB,EAAMolB,SAGfF,GAASllB,EAAMolB,OAAS,GAMtBF,EAAO,CAKT,GAAIxR,EAEFA,GADU,EAARwR,EACM,EAAKA,EAAQ,EAGb,GAAK,EAAKA,EAAQ,EAI5B,IAAIkR,GAAUhB,EAAWsB,YAAYlgC,KAAMwJ,GACvC22B,EAAU1B,EAAWmB,EAAQzT,OAAQnsB,KAAK40B,KAAK5E,IAAI7D,QACnDiU,EAAcpgC,KAAKqgC,eAAeF,EAEtCngC,MAAKsgC,KAAKpjB,EAAOkjB,EAAa1R,GAKhCllB,EAAMD,mBAOR1H,EAAMuR,UAAUkrB,SAAW,WACzBt+B,KAAK+F,MAAMg4B,MAAMluB,MAAQ7P,KAAK6P,MAC9B7P,KAAK+F,MAAMg4B,MAAMjuB,IAAM9P,KAAK8P,IAC5B9P,KAAK+F,MAAMg4B,MAAM4B,eAAgB,EACjC3/B,KAAK+F,MAAMg4B,MAAM5R,OAAS,KAC1BnsB,KAAK09B,YAAc,EACnB19B,KAAKy9B,gBAAkB,GAOzB57B,EAAMuR,UAAUgrB,QAAU,WACxBp+B,KAAK+F,MAAMg4B,MAAM4B,eAAgB,GAQnC99B,EAAMuR,UAAUmrB,SAAW,SAAU/0B,GAEnC,GAAMxJ,KAAK0O,QAAQkvB,UAAY59B,KAAK0O,QAAQivB,WAE5C39B,KAAK+F,MAAMg4B,MAAM4B,eAAgB,EAE7Bn2B,EAAMo2B,QAAQW,QAAQ76B,OAAS,GAAG,CAC/B1F,KAAK+F,MAAMg4B,MAAM5R,SACpBnsB,KAAK+F,MAAMg4B,MAAM5R,OAASsS,EAAWj1B,EAAMo2B,QAAQzT,OAAQnsB,KAAK40B,KAAK5E,IAAI7D,QAG3E,IAAIjP,GAAQ,GAAK1T,EAAMo2B,QAAQ1iB,MAAQld,KAAK09B,aACxC8C,EAAaxgC,KAAKqgC,eAAergC,KAAK+F,MAAMg4B,MAAM5R,QAElDqO,EAAiB74B,EAAS24B,yBAAyBt6B,KAAK40B,KAAKI,YAAah1B,KAAK6P,MAAO7P,KAAK8P,KAC3F2wB,EAAuB9+B,EAASm5B,wBAAwB96B,KAAK40B,KAAKI,YAAah1B,KAAMwgC,GACrFE,EAAsBlG,EAAiBiG,EAGvCnB,EAAYkB,EAAaC,GAAyBzgC,KAAK+F,MAAMg4B,MAAMluB,OAAS2wB,EAAaC,IAAyBvjB,EAClHqiB,EAAUiB,EAAaE,GAAwB1gC,KAAK+F,MAAMg4B,MAAMjuB,KAAO0wB,EAAaE,IAAwBxjB,CAGhHld,MAAKo5B,aAAe,EAAIlc,EAAQ,GAAI,GAAQ,EAC5Cld,KAAKq5B,WAAanc,EAAQ,EAAI,GAAI,GAAQ,CAE1C,IAAI8iB,GAAYr+B,EAASu5B,mBAAmBl7B,KAAK40B,KAAKI,YAAasK,EAAU,EAAIpiB,GAAO,GACpF+iB,EAAUt+B,EAASu5B,mBAAmBl7B,KAAK40B,KAAKI,YAAauK,EAAQriB,EAAQ,GAAG,IAChF8iB,GAAaV,GAAYW,GAAWV,KACtCv/B,KAAK+F,MAAMg4B,MAAMluB,MAAQmwB,EACzBhgC,KAAK+F,MAAMg4B,MAAMjuB,IAAMmwB,EACvBjgC,KAAK09B,YAAc,EAAIl0B,EAAMo2B,QAAQ1iB,MACrCoiB,EAAWU,EACXT,EAASU,GAGXjgC,KAAKwzB,SAAS8L,EAAUC,GAAQ,GAAO,GAEvCv/B,KAAKo5B,cAAe,EACpBp5B,KAAKq5B,YAAa,IAUtBx3B,EAAMuR,UAAUitB,eAAiB,SAAUF,GACzC,GAAI9F,GACAc,EAAYn7B,KAAK0O,QAAQysB,SAI7B,IAFAqD,EAAkBrD,GAED,cAAbA,EACF,MAAOn7B,MAAK40B,KAAKj0B,KAAK20B,OAAO6K,EAAQnuB,GAAGjL,SAGxC,IAAI0L,GAASzS,KAAK40B,KAAKC,SAAS1I,OAAO1Z,MAEvC,OADA4nB,GAAar6B,KAAKq6B,WAAW5nB,GACtB0tB,EAAQluB,EAAIooB,EAAWnd,MAAQmd,EAAWzQ,QA4BrD/nB,EAAMuR,UAAUktB,KAAO,SAASpjB,EAAOiP,EAAQuC,GAE/B,MAAVvC,IACFA,GAAUnsB,KAAK6P,MAAQ7P,KAAK8P,KAAO,EAGrC,IAAI0qB,GAAiB74B,EAAS24B,yBAAyBt6B,KAAK40B,KAAKI,YAAah1B,KAAK6P,MAAO7P,KAAK8P,KAC3F2wB,EAAuB9+B,EAASm5B,wBAAwB96B,KAAK40B,KAAKI,YAAah1B,KAAMmsB,GACrFuU,EAAsBlG,EAAiBiG,EAGvCnB,EAAYnT,EAAOsU,GAAyBzgC,KAAK6P,OAASsc,EAAOsU,IAAyBvjB,EAC1FqiB,EAAYpT,EAAOuU,GAAwB1gC,KAAK8P,KAAOqc,EAAOuU,IAAwBxjB,CAG1Fld,MAAKo5B,aAAe1K,EAAQ,GAAI,GAAQ,EACxC1uB,KAAKq5B,YAAc3K,EAAS,GAAI,GAAQ,CACxC,IAAIsR,GAAYr+B,EAASu5B,mBAAmBl7B,KAAK40B,KAAKI,YAAasK,EAAU5Q,GAAO,GAChFuR,EAAUt+B,EAASu5B,mBAAmBl7B,KAAK40B,KAAKI,YAAauK,GAAS7Q,GAAO,IAC7EsR,GAAaV,GAAYW,GAAWV,KACtCD,EAAWU,EACXT,EAASU,GAGXjgC,KAAKwzB,SAAS8L,EAAUC,GAAQ,GAAO,GAEvCv/B,KAAKo5B,cAAe,EACpBp5B,KAAKq5B,YAAa,GAWpBx3B,EAAMuR,UAAUutB,KAAO,SAASjS,GAE9B,GAAIpC,GAAQtsB,KAAK8P,IAAM9P,KAAK6P,MAGxByvB,EAAWt/B,KAAK6P,MAAQyc,EAAOoC,EAC/B6Q,EAASv/B,KAAK8P,IAAMwc,EAAOoC,CAI/B1uB,MAAK6P,MAAQyvB,EACbt/B,KAAK8P,IAAMyvB,GAOb19B,EAAMuR,UAAU0U,OAAS,SAASA,GAChC,GAAIqE,IAAUnsB,KAAK6P,MAAQ7P,KAAK8P,KAAO,EAEnCwc,EAAOH,EAASrE,EAGhBwX,EAAWt/B,KAAK6P,MAAQyc,EACxBiT,EAASv/B,KAAK8P,IAAMwc,CAExBtsB,MAAKwzB,SAAS8L,EAAUC,IAG1B1/B,EAAOD,QAAUiC,GAKb,SAAShC,EAAQD,GAGrB,GAAIghC,GAAU,IAMdhhC,GAAQihC,aAAe,SAAS5+B,GAC9BA,EAAMkU,KAAK,SAAU7Q,EAAGa,GACtB,MAAOb,GAAEqN,KAAK9C,MAAQ1J,EAAEwM,KAAK9C,SASjCjQ,EAAQkhC,WAAa,SAAS7+B,GAC5BA,EAAMkU,KAAK,SAAU7Q,EAAGa,GACtB,GAAI46B,GAAS,OAASz7B,GAAEqN,KAAQrN,EAAEqN,KAAK7C,IAAMxK,EAAEqN,KAAK9C,MAChDmxB,EAAS,OAAS76B,GAAEwM,KAAQxM,EAAEwM,KAAK7C,IAAM3J,EAAEwM,KAAK9C,KAEpD,OAAOkxB,GAAQC,KAenBphC,EAAQkC,MAAQ,SAASG,EAAO0X,EAAQsnB,GACtC,GAAI17B,GAAG27B,CAEP,IAAID,EAEF,IAAK17B,EAAI,EAAG27B,EAAOj/B,EAAMyD,OAAYw7B,EAAJ37B,EAAUA,IACzCtD,EAAMsD,GAAGqC,IAAM,IAKnB,KAAKrC,EAAI,EAAG27B,EAAOj/B,EAAMyD,OAAYw7B,EAAJ37B,EAAUA,IAAK,CAC9C,GAAI+J,GAAOrN,EAAMsD,EACjB,IAAI+J,EAAKxN,OAAsB,OAAbwN,EAAK1H,IAAc,CAEnC0H,EAAK1H,IAAM+R,EAAOwnB,IAElB,GAAG,CAID,IAAK,GADDC,GAAgB,KACXvV,EAAI,EAAGwV,EAAKp/B,EAAMyD,OAAY27B,EAAJxV,EAAQA,IAAK,CAC9C,GAAIlmB,GAAQ1D,EAAM4pB,EAClB,IAAkB,OAAdlmB,EAAMiC,KAAgBjC,IAAU2J,GAAQ3J,EAAM7D,OAASlC,EAAQ0hC,UAAUhyB,EAAM3J,EAAOgU,EAAOrK,MAAO,CACtG8xB,EAAgBz7B,CAChB,QAIiB,MAAjBy7B,IAEF9xB,EAAK1H,IAAMw5B,EAAcx5B,IAAMw5B,EAAc3uB,OAASkH,EAAOrK,KAAKoW,gBAE7D0b,MAafxhC,EAAQ2hC,QAAU,SAASt/B,EAAO0X,EAAQ6nB,GACxC,GAAIj8B,GAAG27B,EAAMO,CAGb,KAAKl8B,EAAI,EAAG27B,EAAOj/B,EAAMyD,OAAYw7B,EAAJ37B,EAAUA,IACzC,GAA+BgB,SAA3BtE,EAAMsD,GAAGoN,KAAK+uB,SAAwB,CACxCD,EAAS9nB,EAAOwnB,IAChB,KAAK,GAAIO,KAAYF,GACfA,EAAU37B,eAAe67B,IACQ,GAA/BF,EAAUE,GAAU/Y,SAAmB6Y,EAAUE,GAAUr5B,MAAQm5B,EAAUv/B,EAAMsD,GAAGoN,KAAK+uB,UAAUr5B,QACvGo5B,GAAUD,EAAUE,GAAUjvB,OAASkH,EAAOrK,KAAKoW,SAIzDzjB,GAAMsD,GAAGqC,IAAM65B,MAGfx/B,GAAMsD,GAAGqC,IAAM+R,EAAOwnB,MAe5BvhC,EAAQ0hC,UAAY,SAASh8B,EAAGa,EAAGwT,GACjC,MAASrU,GAAEkC,KAAOmS,EAAO8L,WAAamb,EAAkBz6B,EAAEqB,KAAOrB,EAAEqM,OAC9DlN,EAAEkC,KAAOlC,EAAEkN,MAAQmH,EAAO8L,WAAamb,EAAWz6B,EAAEqB,MACpDlC,EAAEsC,IAAM+R,EAAO+L,SAAWkb,EAAyBz6B,EAAEyB,IAAMzB,EAAEsM,QAC7DnN,EAAEsC,IAAMtC,EAAEmN,OAASkH,EAAO+L,SAAWkb,EAAaz6B,EAAEyB,MAMvD,SAAS/H,EAAQD,EAASM,GAgC9B,QAAS6B,GAAS8N,EAAOC,EAAKurB,EAAarG,GAEzCh1B,KAAK+5B,QAAU,GAAI11B,MACnBrE,KAAKmzB,OAAS,GAAI9uB,MAClBrE,KAAKozB,KAAO,GAAI/uB,MAEhBrE,KAAKy7B,WAAa,EAClBz7B,KAAKkd,MAAQ,MACbld,KAAKooB,KAAO,EAGZpoB,KAAKwzB,SAAS3jB,EAAOC,EAAKurB,GAG1Br7B,KAAKm6B,aAAc,EACnBn6B,KAAKk6B,eAAgB,EACrBl6B,KAAKi6B,cAAe,EACpBj6B,KAAKg1B,YAAcA,EACCzuB,SAAhByuB,IACFh1B,KAAKg1B,gBAGPh1B,KAAK2hC,OAAS5/B,EAAS6/B,OApDzB,GAAI/9B,GAAS3D,EAAoB,IAC7ByB,EAAWzB,EAAoB,IAC/BS,EAAOT,EAAoB,EAsD/B6B,GAAS6/B,QACPC,aACEC,YAAY,MACZC,OAAY,IACZC,OAAY,QACZC,KAAY,QACZC,QAAY,QACZ5J,IAAY,IACZK,MAAY,MACZH,KAAY,QAEd2J,aACEL,YAAY,WACZC,OAAY,eACZC,OAAY,aACZC,KAAY,aACZC,QAAY,YACZ5J,IAAY,YACZK,MAAY,OACZH,KAAY,KAUhBz2B,EAASqR,UAAUgvB,UAAY,SAAUT,GACvC,GAAIU,GAAgB1hC,EAAK6F,cAAezE,EAAS6/B,OACjD5hC,MAAK2hC,OAAShhC,EAAK6F,WAAW67B,EAAeV,IAa/C5/B,EAASqR,UAAUogB,SAAW,SAAS3jB,EAAOC,EAAKurB,GACjD,KAAMxrB,YAAiBxL,OAAWyL,YAAezL,OAC/C,KAAO,+CAGTrE,MAAKmzB,OAAmB5sB,QAATsJ,EAAsB,GAAIxL,MAAKwL,EAAM9I,WAAa,GAAI1C,MACrErE,KAAKozB,KAAe7sB,QAAPuJ,EAAoB,GAAIzL,MAAKyL,EAAI/I,WAAa,GAAI1C,MAE3DrE,KAAKy7B,WACPz7B,KAAKg8B,eAAeX,IAOxBt5B,EAASqR,UAAUkvB,MAAQ,WACzBtiC,KAAK+5B,QAAU,GAAI11B,MAAKrE,KAAKmzB,OAAOpsB,WACpC/G,KAAK28B,gBAOP56B,EAASqR,UAAUupB,aAAe,WAIhC,OAAQ38B,KAAKkd,OACX,IAAK,OACHld,KAAK+5B,QAAQwI,YAAYviC,KAAKooB,KAAOnjB,KAAKC,MAAMlF,KAAK+5B,QAAQyI,cAAgBxiC,KAAKooB,OAClFpoB,KAAK+5B,QAAQ0I,SAAS,EACxB,KAAK,QAAgBziC,KAAK+5B,QAAQ2I,QAAQ,EAC1C,KAAK,MACL,IAAK,UAAgB1iC,KAAK+5B,QAAQ4I,SAAS,EAC3C,KAAK,OAAgB3iC,KAAK+5B,QAAQ6I,WAAW,EAC7C,KAAK,SAAgB5iC,KAAK+5B,QAAQ8I,WAAW,EAC7C,KAAK,SAAgB7iC,KAAK+5B,QAAQ+I,gBAAgB,GAIpD,GAAiB,GAAb9iC,KAAKooB,KAEP,OAAQpoB,KAAKkd,OACX,IAAK,cAAgBld,KAAK+5B,QAAQ+I,gBAAgB9iC,KAAK+5B,QAAQgJ,kBAAoB/iC,KAAK+5B,QAAQgJ,kBAAoB/iC,KAAKooB,KAAQ,MACjI,KAAK,SAAgBpoB,KAAK+5B,QAAQ8I,WAAW7iC,KAAK+5B,QAAQiJ,aAAehjC,KAAK+5B,QAAQiJ,aAAehjC,KAAKooB,KAAO,MACjH,KAAK,SAAgBpoB,KAAK+5B,QAAQ6I,WAAW5iC,KAAK+5B,QAAQkJ,aAAejjC,KAAK+5B,QAAQkJ,aAAejjC,KAAKooB,KAAO,MACjH,KAAK,OAAgBpoB,KAAK+5B,QAAQ4I,SAAS3iC,KAAK+5B,QAAQmJ,WAAaljC,KAAK+5B,QAAQmJ,WAAaljC,KAAKooB,KAAO,MAC3G,KAAK,UACL,IAAK,MAAgBpoB,KAAK+5B,QAAQ2I,QAAS1iC,KAAK+5B,QAAQoJ,UAAU,GAAMnjC,KAAK+5B,QAAQoJ,UAAU,GAAKnjC,KAAKooB,KAAO,EAAI,MACpH,KAAK,QAAgBpoB,KAAK+5B,QAAQ0I,SAASziC,KAAK+5B,QAAQqJ,WAAapjC,KAAK+5B,QAAQqJ,WAAapjC,KAAKooB,KAAQ,MAC5G,KAAK,OAAgBpoB,KAAK+5B,QAAQwI,YAAYviC,KAAK+5B,QAAQyI,cAAgBxiC,KAAK+5B,QAAQyI,cAAgBxiC,KAAKooB,QAUnHrmB,EAASqR,UAAU0pB,QAAU,WAC3B,MAAQ98B,MAAK+5B,QAAQhzB,WAAa/G,KAAKozB,KAAKrsB,WAM9ChF,EAASqR,UAAUkV,KAAO,WACxB,GAAIuJ,GAAO7xB,KAAK+5B,QAAQhzB,SAIxB,IAAI/G,KAAK+5B,QAAQqJ,WAAa,EAC5B,OAAQpjC,KAAKkd,OACX,IAAK,cAEHld,KAAK+5B,QAAU,GAAI11B,MAAKrE,KAAK+5B,QAAQhzB,UAAY/G,KAAKooB,KAAO,MAC/D,KAAK,SAAgBpoB,KAAK+5B,QAAU,GAAI11B,MAAKrE,KAAK+5B,QAAQhzB,UAAwB,IAAZ/G,KAAKooB,KAAc,MACzF,KAAK,SAAgBpoB,KAAK+5B,QAAU,GAAI11B,MAAKrE,KAAK+5B,QAAQhzB,UAAwB,IAAZ/G,KAAKooB,KAAc,GAAK,MAC9F,KAAK,OACHpoB,KAAK+5B,QAAU,GAAI11B,MAAKrE,KAAK+5B,QAAQhzB,UAAwB,IAAZ/G,KAAKooB,KAAc,GAAK,GAEzE,IAAIxc,GAAI5L,KAAK+5B,QAAQmJ,UACrBljC,MAAK+5B,QAAQ4I,SAAS/2B,EAAKA,EAAI5L,KAAKooB,KACpC,MACF,KAAK,UACL,IAAK,MAAgBpoB,KAAK+5B,QAAQ2I,QAAQ1iC,KAAK+5B,QAAQoJ,UAAYnjC,KAAKooB,KAAO;KAC/E,KAAK,QAAgBpoB,KAAK+5B,QAAQ0I,SAASziC,KAAK+5B,QAAQqJ,WAAapjC,KAAKooB,KAAO,MACjF,KAAK,OAAgBpoB,KAAK+5B,QAAQwI,YAAYviC,KAAK+5B,QAAQyI,cAAgBxiC,KAAKooB,UAKlF,QAAQpoB,KAAKkd,OACX,IAAK,cAAgBld,KAAK+5B,QAAU,GAAI11B,MAAKrE,KAAK+5B,QAAQhzB,UAAY/G,KAAKooB,KAAO,MAClF,KAAK,SAAgBpoB,KAAK+5B,QAAQ8I,WAAW7iC,KAAK+5B,QAAQiJ,aAAehjC,KAAKooB,KAAO,MACrF,KAAK,SAAgBpoB,KAAK+5B,QAAQ6I,WAAW5iC,KAAK+5B,QAAQkJ,aAAejjC,KAAKooB,KAAO,MACrF,KAAK,OAAgBpoB,KAAK+5B,QAAQ4I,SAAS3iC,KAAK+5B,QAAQmJ,WAAaljC,KAAKooB,KAAO,MACjF,KAAK,UACL,IAAK,MAAgBpoB,KAAK+5B,QAAQ2I,QAAQ1iC,KAAK+5B,QAAQoJ,UAAYnjC,KAAKooB,KAAO,MAC/E,KAAK,QAAgBpoB,KAAK+5B,QAAQ0I,SAASziC,KAAK+5B,QAAQqJ,WAAapjC,KAAKooB,KAAO,MACjF,KAAK,OAAgBpoB,KAAK+5B,QAAQwI,YAAYviC,KAAK+5B,QAAQyI,cAAgBxiC,KAAKooB,MAKpF,GAAiB,GAAbpoB,KAAKooB,KAEP,OAAQpoB,KAAKkd,OACX,IAAK,cAAmBld,KAAK+5B,QAAQgJ,kBAAoB/iC,KAAKooB,MAAMpoB,KAAK+5B,QAAQ+I,gBAAgB,EAAK,MACtG,KAAK,SAAmB9iC,KAAK+5B,QAAQiJ,aAAehjC,KAAKooB,MAAMpoB,KAAK+5B,QAAQ8I,WAAW,EAAK,MAC5F,KAAK,SAAmB7iC,KAAK+5B,QAAQkJ,aAAejjC,KAAKooB,MAAMpoB,KAAK+5B,QAAQ6I,WAAW,EAAK,MAC5F,KAAK,OAAmB5iC,KAAK+5B,QAAQmJ,WAAaljC,KAAKooB,MAAMpoB,KAAK+5B,QAAQ4I,SAAS,EAAK,MACxF,KAAK,UACL,IAAK,MAAmB3iC,KAAK+5B,QAAQoJ,UAAYnjC,KAAKooB,KAAK,GAAGpoB,KAAK+5B,QAAQ2I,QAAQ,EAAI,MACvF,KAAK,QAAmB1iC,KAAK+5B,QAAQqJ,WAAapjC,KAAKooB,MAAMpoB,KAAK+5B,QAAQ0I,SAAS,EAAK,MACxF,KAAK,QAMLziC,KAAK+5B,QAAQhzB,WAAa8qB,IAC5B7xB,KAAK+5B,QAAU,GAAI11B,MAAKrE,KAAKozB,KAAKrsB,YAGpCpF,EAAS+3B,oBAAoB15B,KAAM6xB,IAQrC9vB,EAASqR,UAAUiV,WAAa,WAC9B,MAAOroB,MAAK+5B,SAcdh4B,EAASqR,UAAUiwB,SAAW,SAASC,EAAUC,GAC/CvjC,KAAKkd,MAAQomB,EAETC,EAAU,IACZvjC,KAAKooB,KAAOmb,GAGdvjC,KAAKy7B,WAAY,GAOnB15B,EAASqR,UAAUowB,aAAe,SAAUC,GAC1CzjC,KAAKy7B,UAAYgI,GAQnB1hC,EAASqR,UAAU4oB,eAAiB,SAASX,GAC3C,GAAmB90B,QAAf80B,EAAJ,CAMA,GAAIqI,GAAiB,QACjBC,EAAiB,OACjBC,EAAiB,MACjBC,EAAiB,KACjBC,EAAiB,IACjBC,EAAiB,IACjBC,EAAiB,CAGR,KAATN,EAAgBrI,IAAqBr7B,KAAKkd,MAAQ,OAAeld,KAAKooB,KAAO,KACpE,IAATsb,EAAerI,IAAsBr7B,KAAKkd,MAAQ,OAAeld,KAAKooB,KAAO,KACpE,IAATsb,EAAerI,IAAsBr7B,KAAKkd,MAAQ,OAAeld,KAAKooB,KAAO,KACpE,GAATsb,EAAcrI,IAAuBr7B,KAAKkd,MAAQ,OAAeld,KAAKooB,KAAO,IACpE,GAATsb,EAAcrI,IAAuBr7B,KAAKkd,MAAQ,OAAeld,KAAKooB,KAAO,IACpE,EAATsb,EAAarI,IAAwBr7B,KAAKkd,MAAQ,OAAeld,KAAKooB,KAAO,GAC7Esb,EAAWrI,IAA0Br7B,KAAKkd,MAAQ,OAAeld,KAAKooB,KAAO,GACnE,EAAVub,EAActI,IAAuBr7B,KAAKkd,MAAQ,QAAeld,KAAKooB,KAAO,GAC7Eub,EAAYtI,IAAyBr7B,KAAKkd,MAAQ,QAAeld,KAAKooB,KAAO,GACrE,EAARwb,EAAYvI,IAAyBr7B,KAAKkd,MAAQ,MAAeld,KAAKooB,KAAO,GACrE,EAARwb,EAAYvI,IAAyBr7B,KAAKkd,MAAQ,MAAeld,KAAKooB,KAAO,GAC7Ewb,EAAUvI,IAA2Br7B,KAAKkd,MAAQ,MAAeld,KAAKooB,KAAO,GAC7Ewb,EAAQ,EAAIvI,IAAyBr7B,KAAKkd,MAAQ,UAAeld,KAAKooB,KAAO,GACpE,EAATyb,EAAaxI,IAAwBr7B,KAAKkd,MAAQ,OAAeld,KAAKooB,KAAO,GAC7Eyb,EAAWxI,IAA0Br7B,KAAKkd,MAAQ,OAAeld,KAAKooB,KAAO,GAClE,GAAX0b,EAAgBzI,IAAqBr7B,KAAKkd,MAAQ,SAAeld,KAAKooB,KAAO,IAClE,GAAX0b,EAAgBzI,IAAqBr7B,KAAKkd,MAAQ,SAAeld,KAAKooB,KAAO,IAClE,EAAX0b,EAAezI,IAAsBr7B,KAAKkd,MAAQ,SAAeld,KAAKooB,KAAO,GAC7E0b,EAAazI,IAAwBr7B,KAAKkd,MAAQ,SAAeld,KAAKooB,KAAO,GAClE,GAAX2b,EAAgB1I,IAAqBr7B,KAAKkd,MAAQ,SAAeld,KAAKooB,KAAO,IAClE,GAAX2b,EAAgB1I,IAAqBr7B,KAAKkd,MAAQ,SAAeld,KAAKooB,KAAO,IAClE,EAAX2b,EAAe1I,IAAsBr7B,KAAKkd,MAAQ,SAAeld,KAAKooB,KAAO,GAC7E2b,EAAa1I,IAAwBr7B,KAAKkd,MAAQ,SAAeld,KAAKooB,KAAO,GAC7D,IAAhB4b,EAAsB3I,IAAer7B,KAAKkd,MAAQ,cAAeld,KAAKooB,KAAO,KAC7D,IAAhB4b,EAAsB3I,IAAer7B,KAAKkd,MAAQ,cAAeld,KAAKooB,KAAO,KAC7D,GAAhB4b,EAAqB3I,IAAgBr7B,KAAKkd,MAAQ,cAAeld,KAAKooB,KAAO,IAC7D,GAAhB4b,EAAqB3I,IAAgBr7B,KAAKkd,MAAQ,cAAeld,KAAKooB,KAAO,IAC7D,EAAhB4b,EAAoB3I,IAAiBr7B,KAAKkd,MAAQ,cAAeld,KAAKooB,KAAO,GAC7E4b,EAAkB3I,IAAmBr7B,KAAKkd,MAAQ,cAAeld,KAAKooB,KAAO,KASnFrmB,EAASqR,UAAU6hB,KAAO,SAASyD,GACjC,GAAIL,GAAQ,GAAIh0B,MAAKq0B,EAAK3xB,UAE1B,IAAkB,QAAd/G,KAAKkd,MAAiB,CACxB,GAAIsb,GAAOH,EAAMmK,cAAgBv9B,KAAK0oB,MAAM0K,EAAM+K,WAAa,GAC/D/K,GAAMkK,YAAYt9B,KAAK0oB,MAAM6K,EAAOx4B,KAAKooB,MAAQpoB,KAAKooB,MACtDiQ,EAAMoK,SAAS,GACfpK,EAAMqK,QAAQ,GACdrK,EAAMsK,SAAS,GACftK,EAAMuK,WAAW,GACjBvK,EAAMwK,WAAW,GACjBxK,EAAMyK,gBAAgB,OAEnB,IAAkB,SAAd9iC,KAAKkd,MACRmb,EAAM8K,UAAY,IACpB9K,EAAMqK,QAAQ,GACdrK,EAAMoK,SAASpK,EAAM+K,WAAa,IAIlC/K,EAAMqK,QAAQ,GAGhBrK,EAAMsK,SAAS,GACftK,EAAMuK,WAAW,GACjBvK,EAAMwK,WAAW,GACjBxK,EAAMyK,gBAAgB,OAEnB,IAAkB,OAAd9iC,KAAKkd,MAAgB,CAE5B,OAAQld,KAAKooB,MACX,IAAK,GACL,IAAK,GACHiQ,EAAMsK,SAA6C,GAApC19B,KAAK0oB,MAAM0K,EAAM6K,WAAa,IAAW,MAC1D,SACE7K,EAAMsK,SAA6C,GAApC19B,KAAK0oB,MAAM0K,EAAM6K,WAAa,KAEjD7K,EAAMuK,WAAW,GACjBvK,EAAMwK,WAAW,GACjBxK,EAAMyK,gBAAgB,OAEnB,IAAkB,WAAd9iC,KAAKkd,MAAoB,CAEhC,OAAQld,KAAKooB,MACX,IAAK,GACL,IAAK,GACHiQ,EAAMsK,SAA6C,GAApC19B,KAAK0oB,MAAM0K,EAAM6K,WAAa,IAAW,MAC1D,SACE7K,EAAMsK,SAA4C,EAAnC19B,KAAK0oB,MAAM0K,EAAM6K,WAAa,IAEjD7K,EAAMuK,WAAW,GACjBvK,EAAMwK,WAAW,GACjBxK,EAAMyK,gBAAgB,OAEnB,IAAkB,QAAd9iC,KAAKkd,MAAiB,CAC7B,OAAQld,KAAKooB,MACX,IAAK,GACHiQ,EAAMuK,WAAiD,GAAtC39B,KAAK0oB,MAAM0K,EAAM4K,aAAe,IAAW,MAC9D,SACE5K,EAAMuK,WAAiD,GAAtC39B,KAAK0oB,MAAM0K,EAAM4K,aAAe,KAErD5K,EAAMwK,WAAW,GACjBxK,EAAMyK,gBAAgB,OACjB,IAAkB,UAAd9iC,KAAKkd,MAAmB,CAEjC,OAAQld,KAAKooB,MACX,IAAK,IACL,IAAK,IACHiQ,EAAMuK,WAAgD,EAArC39B,KAAK0oB,MAAM0K,EAAM4K,aAAe,IACjD5K,EAAMwK,WAAW,EACjB,MACF,KAAK,GACHxK,EAAMwK,WAAiD,GAAtC59B,KAAK0oB,MAAM0K,EAAM2K,aAAe,IAAW,MAC9D,SACE3K,EAAMwK,WAAiD,GAAtC59B,KAAK0oB,MAAM0K,EAAM2K,aAAe,KAErD3K,EAAMyK,gBAAgB,OAEnB,IAAkB,UAAd9iC,KAAKkd,MAEZ,OAAQld,KAAKooB,MACX,IAAK,IACL,IAAK,IACHiQ,EAAMwK,WAAgD,EAArC59B,KAAK0oB,MAAM0K,EAAM2K,aAAe,IACjD3K,EAAMyK,gBAAgB,EACtB,MACF,KAAK,GACHzK,EAAMyK,gBAA6D,IAA7C79B,KAAK0oB,MAAM0K,EAAM0K,kBAAoB,KAAe,MAC5E,SACE1K,EAAMyK,gBAA4D,IAA5C79B,KAAK0oB,MAAM0K,EAAM0K,kBAAoB,UAG5D,IAAkB,eAAd/iC,KAAKkd,MAAwB,CACpC,GAAIkL,GAAOpoB,KAAKooB,KAAO,EAAIpoB,KAAKooB,KAAO,EAAI,CAC3CiQ,GAAMyK,gBAAgB79B,KAAK0oB,MAAM0K,EAAM0K,kBAAoB3a,GAAQA,GAGrE,MAAOiQ,IAQTt2B,EAASqR,UAAU+pB,QAAU,WAC3B,GAAyB,GAArBn9B,KAAKi6B,aAEP,OADAj6B,KAAKi6B,cAAe,EACZj6B,KAAKkd,OACX,IAAK,OACL,IAAK,QACL,IAAK,UACL,IAAK,MACL,IAAK,OACL,IAAK,SACL,IAAK,SACL,IAAK,cACH,OAAO,CACT,SACE,OAAO,MAGR,IAA0B,GAAtBld,KAAKk6B,cAEZ,OADAl6B,KAAKk6B,eAAgB,EACbl6B,KAAKkd,OACX,IAAK,UACL,IAAK,MACL,IAAK,OACL,IAAK,SACL,IAAK,SACL,IAAK,cACH,OAAO,CACT,SACE,OAAO,MAGR,IAAwB,GAApBld,KAAKm6B,YAEZ,OADAn6B,KAAKm6B,aAAc,EACXn6B,KAAKkd,OACX,IAAK,cACL,IAAK,SACL,IAAK,SACL,IAAK,OACH,OAAO,CACT,SACE,OAAO,EAIb,OAAQld,KAAKkd,OACX,IAAK,cACH,MAA0C,IAAlCld,KAAK+5B,QAAQgJ,iBACvB,KAAK,SACH,MAAqC,IAA7B/iC,KAAK+5B,QAAQiJ,YACvB,KAAK,SACH,MAAmC,IAA3BhjC,KAAK+5B,QAAQmJ,YAAkD,GAA7BljC,KAAK+5B,QAAQkJ,YACzD,KAAK,OACH,MAAmC,IAA3BjjC,KAAK+5B,QAAQmJ,UACvB,KAAK,UACL,IAAK,MACH,MAAkC,IAA1BljC,KAAK+5B,QAAQoJ,SACvB,KAAK,QACH,MAAmC,IAA3BnjC,KAAK+5B,QAAQqJ,UACvB,KAAK,OACH,OAAO,CACT,SACE,OAAO,IAWbrhC,EAASqR,UAAU6wB,cAAgB,SAASvL,GAC9BnyB,QAARmyB,IACFA,EAAO14B,KAAK+5B,QAGd,IAAI4H,GAAS3hC,KAAK2hC,OAAOE,YAAY7hC,KAAKkd,MAC1C,OAAQykB,IAAUA,EAAOj8B,OAAS,EAAK7B,EAAO60B,GAAMiJ,OAAOA,GAAU,IASvE5/B,EAASqR,UAAU8wB,cAAgB,SAASxL,GAC9BnyB,QAARmyB,IACFA,EAAO14B,KAAK+5B,QAGd,IAAI4H,GAAS3hC,KAAK2hC,OAAOQ,YAAYniC,KAAKkd,MAC1C,OAAQykB,IAAUA,EAAOj8B,OAAS,EAAK7B,EAAO60B,GAAMiJ,OAAOA,GAAU,IAGvE5/B,EAASqR,UAAU+wB,aAAe,WAKhC,QAASC,GAAKh9B,GACZ,MAAQA,GAAQghB,EAAO,GAAK,EAAK,QAAU,OAG7C,QAASic,GAAM3L,GACb,MAAIA,GAAK4L,OAAO,GAAIjgC,MAAQ,OACnB,SAELq0B,EAAK4L,OAAOzgC,IAASqP,IAAI,EAAG,OAAQ,OAC/B,YAELwlB,EAAK4L,OAAOzgC,IAASqP,IAAI,GAAI,OAAQ,OAChC,aAEF,GAGT,QAASqxB,GAAY7L,GACnB,MAAOA,GAAK4L,OAAO,GAAIjgC,MAAQ,QAAU,gBAAkB,GAG7D,QAASmgC,GAAa9L,GACpB,MAAOA,GAAK4L,OAAO,GAAIjgC,MAAQ,SAAW,iBAAmB,GAG/D,QAASogC,GAAY/L,GACnB,MAAOA,GAAK4L,OAAO,GAAIjgC,MAAQ,QAAU,gBAAkB,GA9B7D,GAAI7D,GAAIqD,EAAO7D,KAAK+5B,SAChBrB,EAAOl4B,EAAEkkC,OAASlkC,EAAEkkC,OAAO,MAAQlkC,EAAEmkC,KAAK,MAC1Cvc,EAAOpoB,KAAKooB,IA+BhB,QAAQpoB,KAAKkd,OACX,IAAK,cACH,MAAOknB,GAAK1L,EAAK8E,gBAAgBrwB,MAEnC,KAAK,SACH,MAAOi3B,GAAK1L,EAAK6E,WAAWpwB,MAE9B,KAAK,SACH,MAAOi3B,GAAK1L,EAAK4E,WAAWnwB,MAE9B,KAAK,OACH,GAAIkwB,GAAQ3E,EAAK2E,OAIjB,OAHiB,IAAbr9B,KAAKooB,OACPiV,EAAQA,EAAQ,KAAOA,EAAQ,IAE1BA,EAAQ,IAAMgH,EAAM3L,GAAQ0L,EAAK1L,EAAK2E,QAE/C,KAAK,UACH,MAAO3E,GAAKiJ,OAAO,QAAQiD,cACvBP,EAAM3L,GAAQ6L,EAAY7L,GAAQ0L,EAAK1L,EAAKA,OAElD,KAAK,MACH,GAAIJ,GAAMI,EAAKA,OACXC,EAAQD,EAAKiJ,OAAO,QAAQiD,aAChC,OAAO,MAAQtM,EAAM,IAAMK,EAAQ6L,EAAa9L,GAAQ0L,EAAK9L,EAAM,EAErE,KAAK,QACH,MAAOI,GAAKiJ,OAAO,QAAQiD,cACvBJ,EAAa9L,GAAQ0L,EAAK1L,EAAKC,QAErC,KAAK,OACH,GAAIH,GAAOE,EAAKF,MAChB,OAAO,OAASA,EAAOiM,EAAY/L,GAAO0L,EAAK5L,EAEjD,SACE,MAAO,KAIb34B,EAAOD,QAAUmC,GAKb,SAASlC,GAOb,QAAS0C,KACPvC,KAAK0O,QAAU,KACf1O,KAAK+F,MAAQ,KAQfxD,EAAU6Q,UAAUD,WAAa,SAASzE,GACpCA,GACF/N,KAAK0E,OAAOrF,KAAK0O,QAASA,IAQ9BnM,EAAU6Q,UAAUsO,OAAS,WAE3B,OAAO,GAMTnf,EAAU6Q,UAAUG,QAAU,aAU9BhR,EAAU6Q,UAAUyxB,WAAa,WAC/B,GAAIC,GAAW9kC,KAAK+F,MAAMg/B,iBAAmB/kC,KAAK+F,MAAMyM,OACpDxS,KAAK+F,MAAMi/B,kBAAoBhlC,KAAK+F,MAAM0M,MAK9C,OAHAzS,MAAK+F,MAAMg/B,eAAiB/kC,KAAK+F,MAAMyM,MACvCxS,KAAK+F,MAAMi/B,gBAAkBhlC,KAAK+F,MAAM0M,OAEjCqyB,GAGTjlC,EAAOD,QAAU2C,GAKb,SAAS1C,EAAQD,EAASM,GAe9B,QAASsC,GAAaoyB,EAAMlmB,GAC1B1O,KAAK40B,KAAOA,EAGZ50B,KAAKs0B,gBACH2Q,iBAAiB,EAEjBC,QAASA,EACTR,OAAQ,MAEV1kC,KAAK0O,QAAU/N,EAAK0E,UAAWrF,KAAKs0B,gBACpCt0B,KAAK4pB,OAAS,EAEd5pB,KAAK20B,UAEL30B,KAAKmT,WAAWzE,GA5BlB,GAAI/N,GAAOT,EAAoB,GAC3BqC,EAAYrC,EAAoB,IAChC2D,EAAS3D,EAAoB,IAC7BglC,EAAUhlC,EAAoB,GA4BlCsC,GAAY4Q,UAAY,GAAI7Q,GAM5BC,EAAY4Q,UAAUuhB,QAAU,WAC9B,GAAI7C,GAAMtgB,SAASM,cAAc,MACjCggB,GAAI/pB,UAAY,cAChB+pB,EAAI5kB,MAAM2W,SAAW,WACrBiO,EAAI5kB,MAAMtF,IAAM,MAChBkqB,EAAI5kB,MAAMuF,OAAS,OAEnBzS,KAAK8xB,IAAMA,GAMbtvB,EAAY4Q,UAAUG,QAAU,WAC9BvT,KAAK0O,QAAQu2B,iBAAkB,EAC/BjlC,KAAK0hB,SAEL1hB,KAAK40B,KAAO,MAQdpyB,EAAY4Q,UAAUD,WAAa,SAASzE,GACtCA,GAEF/N,EAAKmF,iBAAiB,kBAAmB,SAAU,WAAY9F,KAAK0O,QAASA,IAQjFlM,EAAY4Q,UAAUsO,OAAS,WAC7B,GAAI1hB,KAAK0O,QAAQu2B,gBAAiB,CAChC,GAAIE,GAASnlC,KAAK40B,KAAK5E,IAAIoV,kBACvBplC,MAAK8xB,IAAIhoB,YAAcq7B,IAErBnlC,KAAK8xB,IAAIhoB,YACX9J,KAAK8xB,IAAIhoB,WAAWsH,YAAYpR,KAAK8xB,KAEvCqT,EAAOzzB,YAAY1R,KAAK8xB,KAExB9xB,KAAK6P,QAGP,IAAIutB,GAAM,GAAI/4B,OAAK,GAAIA,OAAO0C,UAAY/G,KAAK4pB,QAC3C5X,EAAIhS,KAAK40B,KAAKj0B,KAAKu0B,SAASkI,GAE5BsH,EAAS1kC,KAAK0O,QAAQw2B,QAAQllC,KAAK0O,QAAQg2B,QAC3CW,EAAQX,EAAO3K,QAAU,IAAM2K,EAAOtK,KAAO,KAAOv2B,EAAOu5B,GAAKuE,OAAO,8BAC3E0D,GAAQA,EAAMhgB,OAAO,GAAGigB,cAAgBD,EAAME,UAAU,GAExDvlC,KAAK8xB,IAAI5kB,MAAM1F,KAAOwK,EAAI,KAC1BhS,KAAK8xB,IAAIuT,MAAQA,MAIbrlC,MAAK8xB,IAAIhoB,YACX9J,KAAK8xB,IAAIhoB,WAAWsH,YAAYpR,KAAK8xB,KAEvC9xB,KAAKmlB,MAGP,QAAO,GAMT3iB,EAAY4Q,UAAUvD,MAAQ,WAG5B,QAASiF,KACPV,EAAG+Q,MAGH,IAAIjI,GAAQ9I,EAAGwgB,KAAKc,MAAM2E,WAAWjmB,EAAGwgB,KAAKC,SAAS1I,OAAO3Z,OAAO0K,MAChEuV,EAAW,EAAIvV,EAAQ,EACZ,IAAXuV,IAAiBA,EAAW,IAC5BA,EAAW,MAAMA,EAAW,KAEhCre,EAAGsN,SAGHtN,EAAGoxB,iBAAmBjsB,WAAWzE,EAAQ2d,GAd3C,GAAIre,GAAKpU,IAiBT8U,MAMFtS,EAAY4Q,UAAU+R,KAAO,WACG5e,SAA1BvG,KAAKwlC,mBACPlsB,aAAatZ,KAAKwlC,wBACXxlC,MAAKwlC,mBAUhBhjC,EAAY4Q,UAAUqyB,eAAiB,SAASrL,GAC9C,GAAIrsB,GAAIpN,EAAKiG,QAAQwzB,EAAM,QAAQrzB,UAC/Bq2B,GAAM,GAAI/4B,OAAO0C,SACrB/G,MAAK4pB,OAAS7b,EAAIqvB,EAClBp9B,KAAK0hB,UAOPlf,EAAY4Q,UAAUsyB,eAAiB,WACrC,MAAO,IAAIrhC,OAAK,GAAIA,OAAO0C,UAAY/G,KAAK4pB,SAG9C/pB,EAAOD,QAAU4C,GAKb,SAAS3C,EAAQD,EAASM,GAiB9B,QAASuC,GAAYmyB,EAAMlmB,GACzB1O,KAAK40B,KAAOA,EAGZ50B,KAAKs0B,gBACHqR,gBAAgB,EAChBT,QAASA,EACTR,OAAQ,MAEV1kC,KAAK0O,QAAU/N,EAAK0E,UAAWrF,KAAKs0B,gBAEpCt0B,KAAK61B,WAAa,GAAIxxB,MACtBrE,KAAK4lC,eAGL5lC,KAAK20B,UAEL30B,KAAKmT,WAAWzE,GAhClB,GAAIm3B,GAAS3lC,EAAoB,IAC7BS,EAAOT,EAAoB,GAC3BqC,EAAYrC,EAAoB,IAChC2D,EAAS3D,EAAoB,IAC7BglC,EAAUhlC,EAAoB,GA+BlCuC,GAAW2Q,UAAY,GAAI7Q,GAO3BE,EAAW2Q,UAAUD,WAAa,SAASzE,GACrCA,GAEF/N,EAAKmF,iBAAiB,iBAAkB,SAAU,WAAY9F,KAAK0O,QAASA,IAQhFjM,EAAW2Q,UAAUuhB,QAAU,WAC7B,GAAI7C,GAAMtgB,SAASM,cAAc,MACjCggB,GAAI/pB,UAAY,aAChB+pB,EAAI5kB,MAAM2W,SAAW,WACrBiO,EAAI5kB,MAAMtF,IAAM,MAChBkqB,EAAI5kB,MAAMuF,OAAS,OACnBzS,KAAK8xB,IAAMA,CAEX,IAAIgU,GAAOt0B,SAASM,cAAc,MAClCg0B,GAAK54B,MAAM2W,SAAW,WACtBiiB,EAAK54B,MAAMtF,IAAM,MACjBk+B,EAAK54B,MAAM1F,KAAO,QAClBs+B,EAAK54B,MAAMuF,OAAS,OACpBqzB,EAAK54B,MAAMsF,MAAQ,OACnBsf,EAAIpgB,YAAYo0B,GAGhB9lC,KAAK8D,OAAS+hC,EAAO/T,GACnBiU,iBAAiB,IAEnB/lC,KAAK8D,OAAO0P,GAAG,YAAaxT,KAAKi+B,aAAalJ,KAAK/0B,OACnDA,KAAK8D,OAAO0P,GAAG,OAAaxT,KAAKk+B,QAAQnJ,KAAK/0B,OAC9CA,KAAK8D,OAAO0P,GAAG,UAAaxT,KAAKm+B,WAAWpJ,KAAK/0B,QAMnDyC,EAAW2Q,UAAUG,QAAU,WAC7BvT,KAAK0O,QAAQi3B,gBAAiB,EAC9B3lC,KAAK0hB,SAEL1hB,KAAK8D,OAAO2/B,QAAO,GACnBzjC,KAAK8D,OAAS,KAEd9D,KAAK40B,KAAO,MAOdnyB,EAAW2Q,UAAUsO,OAAS,WAC5B,GAAI1hB,KAAK0O,QAAQi3B,eAAgB,CAC/B,GAAIR,GAASnlC,KAAK40B,KAAK5E,IAAIoV,kBACvBplC,MAAK8xB,IAAIhoB,YAAcq7B,IAErBnlC,KAAK8xB,IAAIhoB,YACX9J,KAAK8xB,IAAIhoB,WAAWsH,YAAYpR,KAAK8xB,KAEvCqT,EAAOzzB,YAAY1R,KAAK8xB,KAG1B,IAAI9f,GAAIhS,KAAK40B,KAAKj0B,KAAKu0B,SAASl1B,KAAK61B,YAEjC6O,EAAS1kC,KAAK0O,QAAQw2B,QAAQllC,KAAK0O,QAAQg2B,QAC3CW,EAAQX,EAAOtK,KAAO,KAAOv2B,EAAO7D,KAAK61B,YAAY8L,OAAO,8BAChE0D,GAAQA,EAAMhgB,OAAO,GAAGigB,cAAgBD,EAAME,UAAU,GAExDvlC,KAAK8xB,IAAI5kB,MAAM1F,KAAOwK,EAAI,KAC1BhS,KAAK8xB,IAAIuT,MAAQA,MAIbrlC,MAAK8xB,IAAIhoB,YACX9J,KAAK8xB,IAAIhoB,WAAWsH,YAAYpR,KAAK8xB,IAIzC,QAAO,GAOTrvB,EAAW2Q,UAAU4yB,cAAgB,SAAS5L,GAC5Cp6B,KAAK61B,WAAal1B,EAAKiG,QAAQwzB,EAAM,QACrCp6B,KAAK0hB,UAOPjf,EAAW2Q,UAAU6yB,cAAgB,WACnC,MAAO,IAAI5hC,MAAKrE,KAAK61B,WAAW9uB,YAQlCtE,EAAW2Q,UAAU6qB,aAAe,SAASz0B,GAC3CxJ,KAAK4lC,YAAYzG,UAAW,EAC5Bn/B,KAAK4lC,YAAY/P,WAAa71B,KAAK61B,WAEnCrsB,EAAM08B,kBACN18B,EAAMD,kBAQR9G,EAAW2Q,UAAU8qB,QAAU,SAAU10B,GACvC,GAAKxJ,KAAK4lC,YAAYzG,SAAtB,CAEA,GAAIU,GAASr2B,EAAMo2B,QAAQC,OACvB7tB,EAAIhS,KAAK40B,KAAKj0B,KAAKu0B,SAASl1B,KAAK4lC,YAAY/P,YAAcgK,EAC3DzF,EAAOp6B,KAAK40B,KAAKj0B,KAAK20B,OAAOtjB,EAEjChS,MAAKgmC,cAAc5L,GAGnBp6B,KAAK40B,KAAKE,QAAQjH,KAAK,cACrBuM,KAAM,GAAI/1B,MAAKrE,KAAK61B,WAAW9uB,aAGjCyC,EAAM08B,kBACN18B,EAAMD,mBAQR9G,EAAW2Q,UAAU+qB,WAAa,SAAU30B,GACrCxJ,KAAK4lC,YAAYzG,WAGtBn/B,KAAK40B,KAAKE,QAAQjH,KAAK,eACrBuM,KAAM,GAAI/1B,MAAKrE,KAAK61B,WAAW9uB,aAGjCyC,EAAM08B,kBACN18B,EAAMD,mBAGR1J,EAAOD,QAAU6C,GAKb,SAAS5C,EAAQD,EAASM,GAe9B,QAASwC,GAAUkyB,EAAMlmB,EAASy3B,EAAKC,GACrCpmC,KAAKK,GAAKM,EAAKoE,aACf/E,KAAK40B,KAAOA,EAEZ50B,KAAKs0B,gBACHE,YAAa,OACb6R,iBAAiB,EACjBC,iBAAiB,EACjBC,OAAO,EACPC,iBAAkB,EAClBC,iBAAkB,EAClBC,aAAc,GACdC,aAAc,EACdC,UAAW,GACXp0B,MAAO,OACPmW,SAAS,EACT6S,YAAY,EACZD,aACE/zB,MAAOuE,IAAIxF,OAAWoG,IAAIpG,QAC1B+gB,OAAQvb,IAAIxF,OAAWoG,IAAIpG,SAE7B8+B,OACE79B,MAAOgiB,KAAKjjB,QACZ+gB,OAAQkC,KAAKjjB,SAEfo7B,QACEn6B,MAAOw1B,SAAUz2B,QACjB+gB,OAAQ0V,SAAUz2B,UAItBvG,KAAKomC,iBAAmBA,EACxBpmC,KAAK6mC,aAAeV,EACpBnmC,KAAK+F,SACL/F,KAAK8mC,aACHC,SACAC,UACA3B,UAGFrlC,KAAKgwB,OAELhwB,KAAK01B,OAAS7lB,MAAM,EAAGC,IAAI,GAE3B9P,KAAK0O,QAAU/N,EAAK0E,UAAWrF,KAAKs0B,gBACpCt0B,KAAKinC,iBAAmB,EAExBjnC,KAAKmT,WAAWzE,GAChB1O,KAAKwS,MAAQvO,QAAQ,GAAKjE,KAAK0O,QAAQ8D,OAAO/H,QAAQ,KAAK,KAC3DzK,KAAKknC,SAAWlnC,KAAKwS,MACrBxS,KAAKyS,OAASzS,KAAK6mC,aAAatW,aAChCvwB,KAAKm5B,QAAS,EAEdn5B,KAAKmnC,WAAa,GAClBnnC,KAAKonC,iBAAmB,GACxBpnC,KAAKqnC,aAAe,GAEpBrnC,KAAKsnC,WAAa,EAClBtnC,KAAKunC,QAAS,EACdvnC,KAAKwnC,eACLxnC,KAAKynC,cAAe,EAGpBznC,KAAKo0B,UACLp0B,KAAK0nC,eAAiB,EAGtB1nC,KAAK20B,SAEL,IAAIvgB,GAAKpU,IACTA,MAAK40B,KAAKE,QAAQthB,GAAG,eAAgB,WACnCY,EAAG4b,IAAI2X,cAAcz6B,MAAMtF,IAAMwM,EAAGwgB,KAAKC,SAAS+S,UAAY,OApFlE,GAAIjnC,GAAOT,EAAoB,GAC3BU,EAAUV,EAAoB,GAC9BqC,EAAYrC,EAAoB,IAChC0B,EAAW1B,EAAoB,GAqFnCwC,GAAS0Q,UAAY,GAAI7Q,GAGzBG,EAAS0Q,UAAUy0B,SAAW,SAASnf,EAAOof,GACvC9nC,KAAKo0B,OAAOvuB,eAAe6iB,KAC9B1oB,KAAKo0B,OAAO1L,GAASof,GAEvB9nC,KAAK0nC,gBAAkB,GAGzBhlC,EAAS0Q,UAAU20B,YAAc,SAASrf,EAAOof,GAC/C9nC,KAAKo0B,OAAO1L,GAASof,GAGvBplC,EAAS0Q,UAAU40B,YAAc,SAAStf,GACpC1oB,KAAKo0B,OAAOvuB,eAAe6iB,WACtB1oB,MAAKo0B,OAAO1L,GACnB1oB,KAAK0nC,gBAAkB,IAK3BhlC,EAAS0Q,UAAUD,WAAa,SAAUzE,GACxC,GAAIA,EAAS,CACX,GAAIgT,IAAS,CACT1hB,MAAK0O,QAAQ8lB,aAAe9lB,EAAQ8lB,aAAuCjuB,SAAxBmI,EAAQ8lB,cAC7D9S,GAAS,EAEX,IAAIvT,IACF,cACA,kBACA,kBACA,QACA,mBACA,mBACA,eACA,eACA,YACA,QACA,UACA,cACA,QACA,SACA,aAEFxN,GAAKmF,gBAAgBqI,EAAQnO,KAAK0O,QAASA,GAE3C1O,KAAKknC,SAAWjjC,QAAQ,GAAKjE,KAAK0O,QAAQ8D,OAAO/H,QAAQ,KAAK,KAEhD,GAAViX,GAAkB1hB,KAAKgwB,IAAIzQ,QAC7Bvf,KAAKioC,OACLjoC,KAAKkoC,UASXxlC,EAAS0Q,UAAUuhB,QAAU,WAC3B30B,KAAKgwB,IAAIzQ,MAAQ/N,SAASM,cAAc,OACxC9R,KAAKgwB,IAAIzQ,MAAMrS,MAAMsF,MAAQxS,KAAK0O,QAAQ8D,MAC1CxS,KAAKgwB,IAAIzQ,MAAMrS,MAAMuF,OAASzS,KAAKyS,OAEnCzS,KAAKgwB,IAAI2X,cAAgBn2B,SAASM,cAAc,OAChD9R,KAAKgwB,IAAI2X,cAAcz6B,MAAMsF,MAAQ,OACrCxS,KAAKgwB,IAAI2X,cAAcz6B,MAAMuF,OAASzS,KAAKyS,OAC3CzS,KAAKgwB,IAAI2X,cAAcz6B,MAAM2W,SAAW,WAGxC7jB,KAAKmmC,IAAM30B,SAASC,gBAAgB,6BAA6B,OACjEzR,KAAKmmC,IAAIj5B,MAAM2W,SAAW,WAC1B7jB,KAAKmmC,IAAIj5B,MAAMtF,IAAM,MACrB5H,KAAKmmC,IAAIj5B,MAAMuF,OAAS,OACxBzS,KAAKmmC,IAAIj5B,MAAMsF,MAAQ,OACvBxS,KAAKmmC,IAAIj5B,MAAMi7B,QAAU,QACzBnoC,KAAKgwB,IAAIzQ,MAAM7N,YAAY1R,KAAKmmC,MAGlCzjC,EAAS0Q,UAAUg1B,kBAAoB,WACrCxnC,EAAQkQ,gBAAgB9Q,KAAKwnC,YAE7B,IAAIx1B,GACA40B,EAAY5mC,KAAK0O,QAAQk4B,UACzByB,EAAa,GACbC,EAAa,EACbr2B,EAAIq2B,EAAa,GAAMD,CAGzBr2B,GAD8B,QAA5BhS,KAAK0O,QAAQ8lB,YACX8T,EAGAtoC,KAAKwS,MAAQo0B,EAAY0B,CAG/B,KAAK,GAAI/Q,KAAWv3B,MAAKo0B,OACnBp0B,KAAKo0B,OAAOvuB,eAAe0xB,KACO,GAAhCv3B,KAAKo0B,OAAOmD,GAAS5O,SAAkEpiB,SAA9CvG,KAAKomC,iBAAiB3O,WAAWF,IAAuE,GAA7Cv3B,KAAKomC,iBAAiB3O,WAAWF,KACvIv3B,KAAKo0B,OAAOmD,GAASgR,SAASv2B,EAAGC,EAAGjS,KAAKwnC,YAAaxnC,KAAKmmC,IAAKS,EAAWyB,GAC3Ep2B,GAAKo2B,EAAaC,GAKxB1nC,GAAQuQ,gBAAgBnR,KAAKwnC,aAC7BxnC,KAAKynC,cAAe,GAGtB/kC,EAAS0Q,UAAUo1B,cAAgB,WACR,GAArBxoC,KAAKynC,eACP7mC,EAAQkQ,gBAAgB9Q,KAAKwnC,aAC7B5mC,EAAQuQ,gBAAgBnR,KAAKwnC,aAC7BxnC,KAAKynC,cAAe,IAOxB/kC,EAAS0Q,UAAU80B,KAAO,WACxBloC,KAAKm5B,QAAS,EACTn5B,KAAKgwB,IAAIzQ,MAAMzV,aACc,QAA5B9J,KAAK0O,QAAQ8lB,YACfx0B,KAAK40B,KAAK5E,IAAIxoB,KAAKkK,YAAY1R,KAAKgwB,IAAIzQ,OAGxCvf,KAAK40B,KAAK5E,IAAI1I,MAAM5V,YAAY1R,KAAKgwB,IAAIzQ,QAIxCvf,KAAKgwB,IAAI2X,cAAc79B,YAC1B9J,KAAK40B,KAAK5E,IAAIyY,qBAAqB/2B,YAAY1R,KAAKgwB,IAAI2X,gBAO5DjlC,EAAS0Q,UAAU60B,KAAO,WACxBjoC,KAAKm5B,QAAS,EACVn5B,KAAKgwB,IAAIzQ,MAAMzV,YACjB9J,KAAKgwB,IAAIzQ,MAAMzV,WAAWsH,YAAYpR,KAAKgwB,IAAIzQ,OAG7Cvf,KAAKgwB,IAAI2X,cAAc79B,YACzB9J,KAAKgwB,IAAI2X,cAAc79B,WAAWsH,YAAYpR,KAAKgwB,IAAI2X,gBAU3DjlC,EAAS0Q,UAAUogB,SAAW,SAAU3jB,EAAOC,GAC1B,GAAf9P,KAAKunC,QAA8C,GAA3BvnC,KAAK0O,QAAQ8sB,YAA2C,IAArBx7B,KAAKqnC,cAC9Dx3B,EAAQ,IACVA,EAAQ,GAGZ7P,KAAK01B,MAAM7lB,MAAQA,EACnB7P,KAAK01B,MAAM5lB,IAAMA,GAOnBpN,EAAS0Q,UAAUsO,OAAS,WAC1B,GAAIojB,IAAU,EACV4D,EAAe,CAGnB1oC,MAAKgwB,IAAI2X,cAAcz6B,MAAMtF,IAAM5H,KAAK40B,KAAKC,SAAS+S,UAAY,IAElE,KAAK,GAAIrQ,KAAWv3B,MAAKo0B,OACnBp0B,KAAKo0B,OAAOvuB,eAAe0xB,KACO,GAAhCv3B,KAAKo0B,OAAOmD,GAAS5O,SAAkEpiB,SAA9CvG,KAAKomC,iBAAiB3O,WAAWF,IAAuE,GAA7Cv3B,KAAKomC,iBAAiB3O,WAAWF,IACvImR,IAIN,IAA2B,GAAvB1oC,KAAK0nC,gBAAuC,GAAhBgB,EAC9B1oC,KAAKioC,WAEF,CACHjoC,KAAKkoC,OACLloC,KAAKyS,OAASxO,OAAOjE,KAAK6mC,aAAa35B,MAAMuF,OAAOhI,QAAQ,KAAK,KAGjEzK,KAAKgwB,IAAI2X,cAAcz6B,MAAMuF,OAASzS,KAAKyS,OAAS,KACpDzS,KAAKwS,MAAgC,GAAxBxS,KAAK0O,QAAQia,QAAkB1kB,QAAQ,GAAKjE,KAAK0O,QAAQ8D,OAAO/H,QAAQ,KAAK,KAAO,CAEjG,IAAI1E,GAAQ/F,KAAK+F,MACbwZ,EAAQvf,KAAKgwB,IAAIzQ,KAGrBA,GAAMxX,UAAY,WAGlB/H,KAAK2oC,oBAEL,IAAInU,GAAcx0B,KAAK0O,QAAQ8lB,YAC3B6R,EAAkBrmC,KAAK0O,QAAQ23B,gBAC/BC,EAAkBtmC,KAAK0O,QAAQ43B,eAGnCvgC,GAAM6iC,iBAAmBvC,EAAkBtgC,EAAM8iC,gBAAkB,EACnE9iC,EAAM+iC,iBAAmBxC,EAAkBvgC,EAAMgjC,gBAAkB,EAEnEhjC,EAAMijC,eAAiBhpC,KAAK40B,KAAK5E,IAAIyY,qBAAqBpY,YAAcrwB,KAAKsnC,WAAatnC,KAAKwS,MAAQ,EAAIxS,KAAK0O,QAAQ+3B,iBACxH1gC,EAAMkjC,gBAAkB,EACxBljC,EAAMmjC,eAAiBlpC,KAAK40B,KAAK5E,IAAIyY,qBAAqBpY,YAAcrwB,KAAKsnC,WAAatnC,KAAKwS,MAAQ,EAAIxS,KAAK0O,QAAQ83B,iBACxHzgC,EAAMojC,gBAAkB,EAGL,QAAf3U,GACFjV,EAAMrS,MAAMtF,IAAM,IAClB2X,EAAMrS,MAAM1F,KAAO,IACnB+X,EAAMrS,MAAMqW,OAAS,GACrBhE,EAAMrS,MAAMsF,MAAQxS,KAAKwS,MAAQ,KACjC+M,EAAMrS,MAAMuF,OAASzS,KAAKyS,OAAS,KACnCzS,KAAK+F,MAAMyM,MAAQxS,KAAK40B,KAAKC,SAASrtB,KAAKgL,MAC3CxS,KAAK+F,MAAM0M,OAASzS,KAAK40B,KAAKC,SAASrtB,KAAKiL,SAG5C8M,EAAMrS,MAAMtF,IAAM,GAClB2X,EAAMrS,MAAMqW,OAAS,IACrBhE,EAAMrS,MAAM1F,KAAO,IACnB+X,EAAMrS,MAAMsF,MAAQxS,KAAKwS,MAAQ,KACjC+M,EAAMrS,MAAMuF,OAASzS,KAAKyS,OAAS,KACnCzS,KAAK+F,MAAMyM,MAAQxS,KAAK40B,KAAKC,SAASvN,MAAM9U,MAC5CxS,KAAK+F,MAAM0M,OAASzS,KAAK40B,KAAKC,SAASvN,MAAM7U,QAG/CqyB,EAAU9kC,KAAKopC,gBACftE,EAAU9kC,KAAK6kC,cAAgBC,EAEL,GAAtB9kC,KAAK0O,QAAQ63B,MACfvmC,KAAKooC,oBAGLpoC,KAAKwoC,gBAGPxoC,KAAKqpC,aAAa7U,GAEpB,MAAOsQ,IAOTpiC,EAAS0Q,UAAUg2B,cAAgB,WACjC,GAAItE,IAAU,CACdlkC,GAAQkQ,gBAAgB9Q,KAAK8mC,YAAYC,OACzCnmC,EAAQkQ,gBAAgB9Q,KAAK8mC,YAAYE,OAEzC,IAAIxS,GAAcx0B,KAAK0O,QAAqB,YAGxC2sB,EAAcr7B,KAAKunC,OAASvnC,KAAK+F,MAAMgjC,iBAAmB,GAAK/oC,KAAKonC,iBAEpEhf,EAAO,GAAIxmB,GACb5B,KAAK01B,MAAM7lB,MACX7P,KAAK01B,MAAM5lB,IACXurB,EACAr7B,KAAKgwB,IAAIzQ,MAAMgR,aACfvwB,KAAK0O,QAAQ6sB,YAAYv7B,KAAK0O,QAAQ8lB,aACvB,GAAfx0B,KAAKunC,QAAmBvnC,KAAK0O,QAAQ8sB,WAGvCx7B,MAAKooB,KAAOA,CAGZ,IAAI+e,IAAcnnC,KAAKgwB,IAAIzQ,MAAMgR,aAAgBnI,EAAKyT,WAAa77B,KAAKgwB,IAAIzQ,MAAMgR,aAAenI,EAAKwU,gBAAoBxU,EAAKwU,YAAcxU,EAAKyT,WAAazT,EAAKA,KAEpKpoB,MAAKmnC,WAAaA,CAElB,IAAImC,GAAgBtpC,KAAKyS,OAAS00B,EAC9BoC,EAAiB,CAGrB,IAAmB,GAAfvpC,KAAKunC,OAAiB,CACxBJ,EAAannC,KAAKonC,iBAClBmC,EAAiBtkC,KAAK0oB,MAAO3tB,KAAKgwB,IAAIzQ,MAAMgR,aAAe4W,EAAcmC,EACzE,KAAK,GAAI/jC,GAAI,EAAO,GAAMgkC,EAAVhkC,EAA0BA,IACxC6iB,EAAK2U,UAIP,IAFAuM,EAAgBtpC,KAAKyS,OAAS00B,EAEL,IAArBnnC,KAAKqnC,cAAiD,GAA3BrnC,KAAK0O,QAAQ8sB,WAAoB,CAC9D,GAAIgO,GAAsBphB,EAAKwT,UAAYxT,EAAKA,KAAQpoB,KAAKqnC,YAC7D,IAAImC,EAAqB,EACvB,IAAK,GAAIjkC,GAAI,EAAOikC,EAAJjkC,EAAwBA,IAAM6iB,EAAKE,WAEhD,IAAyB,EAArBkhB,EACP,IAAK,GAAIjkC,GAAI,GAAQikC,EAALjkC,EAAyBA,IAAM6iB,EAAK2U,gBAKxDuM,IAAiB,GAInBtpC,MAAKypC,YAAcrhB,EAAKwT,SACxB,IAMIoB,GANA0M,EAAiB,EAGjB/8B,EAAM,CAI8BpG,UAArCvG,KAAK0O,QAAQizB,OAAOnN,KACrBwI,EAAWh9B,KAAK0O,QAAQizB,OAAOnN,GAAawI,UAG9Ch9B,KAAK2pC,aAAe,CAEpB,KADA,GAAI13B,GAAI,EACDtF,EAAM1H,KAAK0oB,MAAM2b,IAAgB,CACtClhB,EAAKE,OACLrW,EAAIhN,KAAK0oB,MAAMhhB,EAAMw6B,GACrBuC,EAAiB/8B,EAAMw6B,CACvB,IAAIhK,GAAU/U,EAAK+U,WAEfn9B,KAAK0O,QAAyB,iBAAgB,GAAXyuB,GAAmC,GAAfn9B,KAAKunC,QAAsD,GAAnCvnC,KAAK0O,QAAyB,kBAC/G1O,KAAK4pC,aAAa33B,EAAI,EAAGmW,EAAKC,WAAW2U,GAAWxI,EAAa,cAAex0B,KAAK+F,MAAM8iC,iBAGzF1L,GAAWn9B,KAAK0O,QAAyB,iBAAoB,GAAf1O,KAAKunC,QAChB,GAAnCvnC,KAAK0O,QAAyB,iBAA6B,GAAf1O,KAAKunC,QAA8B,GAAXpK,GAClElrB,GAAK,GACPjS,KAAK4pC,aAAa33B,EAAI,EAAGmW,EAAKC,WAAW2U,GAAWxI,EAAa,cAAex0B,KAAK+F,MAAMgjC,iBAE7F/oC,KAAK6pC,YAAY53B,EAAGuiB,EAAa,wBAAyBx0B,KAAK0O,QAAQ83B,iBAAkBxmC,KAAK+F,MAAMmjC,iBAGpGlpC,KAAK6pC,YAAY53B,EAAGuiB,EAAa,wBAAyBx0B,KAAK0O,QAAQ+3B,iBAAkBzmC,KAAK+F,MAAMijC,gBAGnF,GAAfhpC,KAAKunC,QAAkC,GAAhBnf,EAAK2R,UAC9B/5B,KAAKqnC,aAAe16B,GAGtBA,IAIA3M,KAAKinC,iBADY,GAAfjnC,KAAKunC,OACiBt1B,GAAKjS,KAAKypC,YAAcrhB,EAAK2R,SAG7B/5B,KAAKgwB,IAAIzQ,MAAMgR,aAAenI,EAAKwU,WAI7D,IAAIkN,GAAa,CACuBvjC,UAApCvG,KAAK0O,QAAQ22B,MAAM7Q,IAAuEjuB,SAAzCvG,KAAK0O,QAAQ22B,MAAM7Q,GAAahL,OACnFsgB,EAAa9pC,KAAK+F,MAAMgkC,gBAE1B,IAAIngB,GAA+B,GAAtB5pB,KAAK0O,QAAQ63B,MAAgBthC,KAAK0H,IAAI3M,KAAK0O,QAAQk4B,UAAWkD,GAAc9pC,KAAK0O,QAAQg4B,aAAe,GAAKoD,EAAa9pC,KAAK0O,QAAQg4B,aAAe,EA0BnK,OAvBI1mC,MAAK2pC,aAAgB3pC,KAAKwS,MAAQoX,GAAmC,GAAxB5pB,KAAK0O,QAAQia,SAC5D3oB,KAAKwS,MAAQxS,KAAK2pC,aAAe/f,EACjC5pB,KAAK0O,QAAQ8D,MAAQxS,KAAKwS,MAAQ,KAClC5R,EAAQuQ,gBAAgBnR,KAAK8mC,YAAYC,OACzCnmC,EAAQuQ,gBAAgBnR,KAAK8mC,YAAYE,QACzChnC,KAAK0hB,SACLojB,GAAU,GAGH9kC,KAAK2pC,aAAgB3pC,KAAKwS,MAAQoX,GAAmC,GAAxB5pB,KAAK0O,QAAQia,SAAmB3oB,KAAKwS,MAAQxS,KAAKknC,UACtGlnC,KAAKwS,MAAQvN,KAAK0H,IAAI3M,KAAKknC,SAASlnC,KAAK2pC,aAAe/f,GACxD5pB,KAAK0O,QAAQ8D,MAAQxS,KAAKwS,MAAQ,KAClC5R,EAAQuQ,gBAAgBnR,KAAK8mC,YAAYC,OACzCnmC,EAAQuQ,gBAAgBnR,KAAK8mC,YAAYE,QACzChnC,KAAK0hB,SACLojB,GAAU,IAGVlkC,EAAQuQ,gBAAgBnR,KAAK8mC,YAAYC,OACzCnmC,EAAQuQ,gBAAgBnR,KAAK8mC,YAAYE,QACzClC,GAAU,GAGLA,GAGTpiC,EAAS0Q,UAAU42B,aAAe,SAAU5iC,GAC1C,GAAI6iC,GAAgBjqC,KAAKypC,YAAcriC,EACnC8iC,EAAiBD,EAAgBjqC,KAAKinC,gBAC1C,OAAOiD,IAYTxnC,EAAS0Q,UAAUw2B,aAAe,SAAU33B,EAAGuX,EAAMgL,EAAazsB,EAAWoiC,GAE3E,GAAIzhB,GAAQ9nB,EAAQ+Q,cAAc,MAAM3R,KAAK8mC,YAAYE,OAAQhnC,KAAKgwB,IAAIzQ,MAC1EmJ,GAAM3gB,UAAYA,EAClB2gB,EAAMxE,UAAYsF,EACC,QAAfgL,GACF9L,EAAMxb,MAAM1F,KAAO,IAAMxH,KAAK0O,QAAQg4B,aAAe,KACrDhe,EAAMxb,MAAMqb,UAAY,UAGxBG,EAAMxb,MAAMoa,MAAQ,IAAMtnB,KAAK0O,QAAQg4B,aAAe,KACtDhe,EAAMxb,MAAMqb,UAAY,QAG1BG,EAAMxb,MAAMtF,IAAMqK,EAAI,GAAMk4B,EAAkBnqC,KAAK0O,QAAQi4B,aAAe,KAE1End,GAAQ,EAER,IAAI4gB,GAAenlC,KAAK0H,IAAI3M,KAAK+F,MAAMskC,eAAerqC,KAAK+F,MAAMukC,eAC7DtqC,MAAK2pC,aAAengB,EAAK9jB,OAAS0kC,IACpCpqC,KAAK2pC,aAAengB,EAAK9jB,OAAS0kC,IAYtC1nC,EAAS0Q,UAAUy2B,YAAc,SAAU53B,EAAGuiB,EAAazsB,EAAW6hB,EAAQpX,GAC5E,GAAmB,GAAfxS,KAAKunC,OAAgB,CACvB,GAAIzX,GAAOlvB,EAAQ+Q,cAAc,MAAM3R,KAAK8mC,YAAYC,MAAO/mC,KAAKgwB,IAAI2X,cACxE7X,GAAK/nB,UAAYA,EACjB+nB,EAAK5L,UAAY,GAEE,QAAfsQ,EACF1E,EAAK5iB,MAAM1F,KAAQxH,KAAKwS,MAAQoX,EAAU,KAG1CkG,EAAK5iB,MAAMoa,MAAStnB,KAAKwS,MAAQoX,EAAU,KAG7CkG,EAAK5iB,MAAMsF,MAAQA,EAAQ,KAC3Bsd,EAAK5iB,MAAMtF,IAAMqK,EAAI,OASzBvP,EAAS0Q,UAAUi2B,aAAe,SAAU7U,GAI1C,GAHA5zB,EAAQkQ,gBAAgB9Q,KAAK8mC,YAAYzB,OAGD9+B,SAApCvG,KAAK0O,QAAQ22B,MAAM7Q,IAAuEjuB,SAAzCvG,KAAK0O,QAAQ22B,MAAM7Q,GAAahL,KAAoB,CACvG,GAAI6b,GAAQzkC,EAAQ+Q,cAAc,MAAO3R,KAAK8mC,YAAYzB,MAAOrlC,KAAKgwB,IAAIzQ,MAC1E8lB,GAAMt9B,UAAY,eAAiBysB,EACnC6Q,EAAMnhB,UAAYlkB,KAAK0O,QAAQ22B,MAAM7Q,GAAahL,KAGJjjB,SAA1CvG,KAAK0O,QAAQ22B,MAAM7Q,GAAatnB,OAClCvM,EAAK4M,WAAW83B,EAAOrlC,KAAK0O,QAAQ22B,MAAM7Q,GAAatnB,OAGtC,QAAfsnB,EACF6Q,EAAMn4B,MAAM1F,KAAOxH,KAAK+F,MAAMgkC,gBAAkB,KAGhD1E,EAAMn4B,MAAMoa,MAAQtnB,KAAK+F,MAAMgkC,gBAAkB,KAGnD1E,EAAMn4B,MAAMsF,MAAQxS,KAAKyS,OAAS,KAIpC7R,EAAQuQ,gBAAgBnR,KAAK8mC,YAAYzB,QAW3C3iC,EAAS0Q,UAAUu1B,mBAAqB,WAEtC,KAAM,mBAAqB3oC,MAAK+F,OAAQ,CACtC,GAAIwkC,GAAY/4B,SAASg5B,eAAe,KACpCC,EAAmBj5B,SAASM,cAAc,MAC9C24B,GAAiB1iC,UAAY,sBAC7B0iC,EAAiB/4B,YAAY64B,GAC7BvqC,KAAKgwB,IAAIzQ,MAAM7N,YAAY+4B,GAE3BzqC,KAAK+F,MAAM8iC,gBAAkB4B,EAAiB3lB,aAC9C9kB,KAAK+F,MAAMukC,eAAiBG,EAAiBhrB,YAE7Czf,KAAKgwB,IAAIzQ,MAAMnO,YAAYq5B,GAG7B,KAAM,mBAAqBzqC,MAAK+F,OAAQ,CACtC,GAAI2kC,GAAYl5B,SAASg5B,eAAe,KACpCG,EAAmBn5B,SAASM,cAAc,MAC9C64B,GAAiB5iC,UAAY,sBAC7B4iC,EAAiBj5B,YAAYg5B,GAC7B1qC,KAAKgwB,IAAIzQ,MAAM7N,YAAYi5B,GAE3B3qC,KAAK+F,MAAMgjC,gBAAkB4B,EAAiB7lB,aAC9C9kB,KAAK+F,MAAMskC,eAAiBM,EAAiBlrB,YAE7Czf,KAAKgwB,IAAIzQ,MAAMnO,YAAYu5B,GAG7B,KAAM,mBAAqB3qC,MAAK+F,OAAQ,CACtC,GAAI6kC,GAAYp5B,SAASg5B,eAAe,KACpCK,EAAmBr5B,SAASM,cAAc,MAC9C+4B,GAAiB9iC,UAAY,sBAC7B8iC,EAAiBn5B,YAAYk5B,GAC7B5qC,KAAKgwB,IAAIzQ,MAAM7N,YAAYm5B,GAE3B7qC,KAAK+F,MAAMgkC,gBAAkBc,EAAiB/lB,aAC9C9kB,KAAK+F,MAAM+kC,eAAiBD,EAAiBprB,YAE7Czf,KAAKgwB,IAAIzQ,MAAMnO,YAAYy5B,KAU/BnoC,EAAS0Q,UAAU6hB,KAAO,SAASyD,GACjC,MAAO14B,MAAKooB,KAAK6M,KAAKyD,IAGxB74B,EAAOD,QAAU8C,GAKb,SAAS7C,EAAQD,EAASM,GAkB9B,QAASyC,GAAYuP,EAAOqlB,EAAS7oB,EAASq8B,GAC5C/qC,KAAKK,GAAKk3B,CACV,IAAIppB,IAAU,WAAW,QAAQ,OAAO,mBAAmB,WAAW,aAAa,SAAS,aAC5FnO,MAAK0O,QAAU/N,EAAKuN,sBAAsBC,EAAOO,GACjD1O,KAAKgrC,kBAAwCzkC,SAApB2L,EAAMnK,UAC/B/H,KAAK+qC,yBAA2BA,EAChC/qC,KAAKirC,aAAe,EACpBjrC,KAAK8U,OAAO5C,GACkB,GAA1BlS,KAAKgrC,oBACPhrC,KAAK+qC,yBAAyB,IAAM,GAEtC/qC,KAAK+1B,aACL/1B,KAAK2oB,QAA4BpiB,SAAlB2L,EAAMyW,SAAwB,EAAOzW,EAAMyW,QA5B5D,GAAIhoB,GAAOT,EAAoB,GAC3BU,EAAUV,EAAoB,GAC9BgrC,EAAOhrC,EAAoB,IAC3BirC,EAAMjrC,EAAoB,IAC1BkrC,EAASlrC,EAAoB,GAgCjCyC,GAAWyQ,UAAU8iB,SAAW,SAASj0B,GAC1B,MAATA,GACFjC,KAAK+1B,UAAY9zB,EACQ,GAArBjC,KAAK0O,QAAQyH,MACfnW,KAAK+1B,UAAU5f,KAAK,SAAU7Q,EAAEa,GAAI,MAAOb,GAAE0M,EAAI7L,EAAE6L,KAIrDhS,KAAK+1B,cASTpzB,EAAWyQ,UAAUi4B,gBAAkB,SAAS7lB,GAC9CxlB,KAAKirC,aAAezlB,GAQtB7iB,EAAWyQ,UAAUD,WAAa,SAASzE,GACzC,GAAgBnI,SAAZmI,EAAuB,CACzB,GAAIP,IAAU,WAAW,QAAQ,OAAO,mBAAmB,WAC3DxN,GAAKuF,oBAAoBiI,EAAQnO,KAAK0O,QAASA,GAE/C/N,EAAK6N,aAAaxO,KAAK0O,QAASA,EAAQ,cACxC/N,EAAK6N,aAAaxO,KAAK0O,QAASA,EAAQ,cACxC/N,EAAK6N,aAAaxO,KAAK0O,QAASA,EAAQ,UAEpCA,EAAQ48B,YACuB,gBAAtB58B,GAAQ48B,YACb58B,EAAQ48B,WAAWC,kBACqB,WAAtC78B,EAAQ48B,WAAWC,gBACrBvrC,KAAK0O,QAAQ48B,WAAWE,MAAQ,EAEa,WAAtC98B,EAAQ48B,WAAWC,gBAC1BvrC,KAAK0O,QAAQ48B,WAAWE,MAAQ,GAGhCxrC,KAAK0O,QAAQ48B,WAAWC,gBAAkB,cAC1CvrC,KAAK0O,QAAQ48B,WAAWE,MAAQ,KAOhB,QAAtBxrC,KAAK0O,QAAQxB,MACflN,KAAK6G,KAAO,GAAIqkC,GAAKlrC,KAAKK,GAAIL,KAAK0O,SAEN,OAAtB1O,KAAK0O,QAAQxB,MACpBlN,KAAK6G,KAAO,GAAIskC,GAAInrC,KAAKK,GAAIL,KAAK0O,SAEL,UAAtB1O,KAAK0O,QAAQxB,QACpBlN,KAAK6G,KAAO,GAAIukC,GAAOprC,KAAKK,GAAIL,KAAK0O,WASzC/L,EAAWyQ,UAAU0B,OAAS,SAAS5C,GACrClS,KAAKkS,MAAQA,EACblS,KAAK6vB,QAAU3d,EAAM2d,SAAW,QAChC7vB,KAAK+H,UAAYmK,EAAMnK,WAAa/H,KAAK+H,WAAa,aAAe/H,KAAK+qC,yBAAyB,GAAK,GACxG/qC,KAAK2oB,QAA4BpiB,SAAlB2L,EAAMyW,SAAwB,EAAOzW,EAAMyW,QAC1D3oB,KAAKkN,MAAQgF,EAAMhF,MACnBlN,KAAKmT,WAAWjB,EAAMxD,UAcxB/L,EAAWyQ,UAAUm1B,SAAW,SAASv2B,EAAGC,EAAGlB,EAAe06B,EAAc7E,EAAWyB,GACrF,GACIqD,GAAMC,EADNC,EAA0B,GAAbvD,EAGbwD,EAAUjrC,EAAQyQ,cAAc,OAAQN,EAAe06B,EAO3D,IANAI,EAAQx5B,eAAe,KAAM,IAAKL,GAClC65B,EAAQx5B,eAAe,KAAM,IAAKJ,EAAI25B,GACtCC,EAAQx5B,eAAe,KAAM,QAASu0B,GACtCiF,EAAQx5B,eAAe,KAAM,SAAU,EAAEu5B,GACzCC,EAAQx5B,eAAe,KAAM,QAAS,WAEZ,QAAtBrS,KAAK0O,QAAQxB,MACfw+B,EAAO9qC,EAAQyQ,cAAc,OAAQN,EAAe06B,GACpDC,EAAKr5B,eAAe,KAAM,QAASrS,KAAK+H,WACtBxB,SAAfvG,KAAKkN,OACNw+B,EAAKr5B,eAAe,KAAM,QAASrS,KAAKkN,OAG1Cw+B,EAAKr5B,eAAe,KAAM,IAAK,IAAML,EAAI,IAAIC,EAAE,MAAQD,EAAI40B,GAAa,IAAI30B,GACzC,GAA/BjS,KAAK0O,QAAQo9B,OAAOn9B,UACtBg9B,EAAW/qC,EAAQyQ,cAAc,OAAQN,EAAe06B,GACjB,OAAnCzrC,KAAK0O,QAAQo9B,OAAOtX,YACtBmX,EAASt5B,eAAe,KAAM,IAAK,IAAIL,EAAE,MAAQC,EAAI25B,GACnD,IAAI55B,EAAE,IAAIC,EAAE,MAAOD,EAAI40B,GAAa,IAAI30B,EAAE,MAAOD,EAAI40B,GAAa,KAAO30B,EAAI25B,IAG/ED,EAASt5B,eAAe,KAAM,IAAK,IAAIL,EAAE,IAAIC,EAAE,KACzCD,EAAE,KAAOC,EAAI25B,GAAc,MACzB55B,EAAI40B,GAAa,KAAO30B,EAAI25B,GAClC,KAAM55B,EAAI40B,GAAa,IAAI30B,GAE/B05B,EAASt5B,eAAe,KAAM,QAASrS,KAAK+H,UAAY,cAGnB,GAAnC/H,KAAK0O,QAAQ0D,WAAWzD,SAC1B/N,EAAQmR,UAAUC,EAAI,GAAM40B,EAAU30B,EAAGjS,KAAM+Q,EAAe06B,OAG7D,CACH,GAAIM,GAAW9mC,KAAK0oB,MAAM,GAAMiZ,GAC5BoF,EAAa/mC,KAAK0oB,MAAM,GAAM0a,GAC9B4D,EAAahnC,KAAK0oB,MAAM,IAAO0a,GAE/Bze,EAAS3kB,KAAK0oB,OAAOiZ,EAAa,EAAImF,GAAW,EAErDnrC,GAAQ2R,QAAQP,EAAI,GAAI+5B,EAAWniB,EAAY3X,EAAI25B,EAAaI,EAAa,EAAGD,EAAUC,EAAYhsC,KAAK+H,UAAY,OAAQgJ,EAAe06B,GAC9I7qC,EAAQ2R,QAAQP,EAAI,IAAI+5B,EAAWniB,EAAS,EAAG3X,EAAI25B,EAAaK,EAAa,EAAGF,EAAUE,EAAYjsC,KAAK+H,UAAY,OAAQgJ,EAAe06B,KAYlJ9oC,EAAWyQ,UAAUkkB,UAAY,SAASsP,EAAWyB,GACnD,GAAIlC,GAAM30B,SAASC,gBAAgB,6BAA6B,MAEhE,OADAzR,MAAKuoC,SAAS,EAAE,GAAIF,KAAclC,EAAIS,EAAUyB,IACxC6D,KAAM/F,EAAKzd,MAAO1oB,KAAK6vB,QAAS2E,YAAYx0B,KAAK0O,QAAQy9B,mBAGnExpC,EAAWyQ,UAAUg5B,UAAY,SAASC,GACxC,MAAOrsC,MAAK6G,KAAKulC,UAAUC,IAG7B1pC,EAAWyQ,UAAUk5B,KAAO,SAASrV,EAAS/kB,EAAOq6B,GACnDvsC,KAAK6G,KAAKylC,KAAKrV,EAAS/kB,EAAOq6B,IAIjC1sC,EAAOD,QAAU+C,GAKb,SAAS9C,EAAQD,EAASM,GAY9B,QAAS0C,GAAO20B,EAAS5kB,EAAMmjB,GAC7B91B,KAAKu3B,QAAUA,EACfv3B,KAAKwhC,aACLxhC,KAAKwsC,cAAgB,EACrBxsC,KAAKysC,gBAAkB95B,GAAQA,EAAK+5B,cACpC1sC,KAAK81B,QAAUA,EAEf91B,KAAKgwB,OACLhwB,KAAK+F,OACH2iB,OACElW,MAAO,EACPC,OAAQ,IAGZzS,KAAK+H,UAAY,KAEjB/H,KAAKiC,SACLjC,KAAK2sC,gBACL3sC,KAAK6O,cACH+9B,WACAC,UAEF7sC,KAAK8sC,kBAAmB,CACxB,IAAI14B,GAAKpU,IACTA,MAAK81B,QAAQlB,KAAKE,QAAQthB,GAAG,mBAAoB,WAC/CY,EAAG04B,kBAAmB,IAGxB9sC,KAAK20B,UAEL30B,KAAKiY,QAAQtF,GAxCf,CAAA,GAAIhS,GAAOT,EAAoB,GAC3B4B,EAAQ5B,EAAoB,GAChBA,GAAoB,IA6CpC0C,EAAMwQ,UAAUuhB,QAAU,WACxB,GAAIjM,GAAQlX,SAASM,cAAc,MACnC4W,GAAM3gB,UAAY,SAClB/H,KAAKgwB,IAAItH,MAAQA,CAEjB,IAAIqkB,GAAQv7B,SAASM,cAAc,MACnCi7B,GAAMhlC,UAAY,QAClB2gB,EAAMhX,YAAYq7B,GAClB/sC,KAAKgwB,IAAI+c,MAAQA,CAEjB,IAAIC,GAAax7B,SAASM,cAAc,MACxCk7B,GAAWjlC,UAAY,QACvBilC,EAAW,kBAAoBhtC,KAC/BA,KAAKgwB,IAAIgd,WAAaA,EAEtBhtC,KAAKgwB,IAAI5jB,WAAaoF,SAASM,cAAc,OAC7C9R,KAAKgwB,IAAI5jB,WAAWrE,UAAY,QAEhC/H,KAAKgwB,IAAImR,KAAO3vB,SAASM,cAAc,OACvC9R,KAAKgwB,IAAImR,KAAKp5B,UAAY,QAK1B/H,KAAKgwB,IAAIid,OAASz7B,SAASM,cAAc,OACzC9R,KAAKgwB,IAAIid,OAAO//B,MAAMuqB,WAAa,SACnCz3B,KAAKgwB,IAAIid,OAAO/oB,UAAY,IAC5BlkB,KAAKgwB,IAAI5jB,WAAWsF,YAAY1R,KAAKgwB,IAAIid,SAO3CrqC,EAAMwQ,UAAU6E,QAAU,SAAStF,GAEjC,GAAIkd,GAAUld,GAAQA,EAAKkd,OACvBA,aAAmBqd,SACrBltC,KAAKgwB,IAAI+c,MAAMr7B,YAAYme,GAG3B7vB,KAAKgwB,IAAI+c,MAAM7oB,UADI3d,SAAZspB,GAAqC,OAAZA,EACLA,EAGA7vB,KAAKu3B,SAAW,GAI7Cv3B,KAAKgwB,IAAItH,MAAM2c,MAAQ1yB,GAAQA,EAAK0yB,OAAS,GAExCrlC,KAAKgwB,IAAI+c,MAAMnpB,WAIlBjjB,EAAKyH,gBAAgBpI,KAAKgwB,IAAI+c,MAAO,UAHrCpsC,EAAKmH,aAAa9H,KAAKgwB,IAAI+c,MAAO,SAOpC,IAAIhlC,GAAY4K,GAAQA,EAAK5K,WAAa,IACtCA,IAAa/H,KAAK+H,YAChB/H,KAAK+H,YACPpH,EAAKyH,gBAAgBpI,KAAKgwB,IAAItH,MAAO1oB,KAAK+H,WAC1CpH,EAAKyH,gBAAgBpI,KAAKgwB,IAAIgd,WAAYhtC,KAAK+H,WAC/CpH,EAAKyH,gBAAgBpI,KAAKgwB,IAAI5jB,WAAYpM,KAAK+H,WAC/CpH,EAAKyH,gBAAgBpI,KAAKgwB,IAAImR,KAAMnhC,KAAK+H,YAE3CpH,EAAKmH,aAAa9H,KAAKgwB,IAAItH,MAAO3gB,GAClCpH,EAAKmH,aAAa9H,KAAKgwB,IAAIgd,WAAYjlC,GACvCpH,EAAKmH,aAAa9H,KAAKgwB,IAAI5jB,WAAYrE,GACvCpH,EAAKmH,aAAa9H,KAAKgwB,IAAImR,KAAMp5B,GACjC/H,KAAK+H,UAAYA,GAIf/H,KAAKkN,QACPvM,EAAK+M,cAAc1N,KAAKgwB,IAAItH,MAAO1oB,KAAKkN,OACxClN,KAAKkN,MAAQ,MAEXyF,GAAQA,EAAKzF,QACfvM,EAAK4M,WAAWvN,KAAKgwB,IAAItH,MAAO/V,EAAKzF,OACrClN,KAAKkN,MAAQyF,EAAKzF,QAQtBtK,EAAMwQ,UAAU+5B,cAAgB,WAC9B,MAAOntC,MAAK+F,MAAM2iB,MAAMlW,OAW1B5P,EAAMwQ,UAAUsO,OAAS,SAASgU,EAAO/b,EAAQyzB,GAC/C,GAAItI,IAAU,CAEd9kC,MAAK2sC,aAAe3sC,KAAKqtC,oBAAoBrtC,KAAK6O,aAAc7O,KAAK2sC,aAAcjX,EAInF,IAAI4X,GAAettC,KAAKgwB,IAAIid,OAAOnoB,YAC/BwoB,IAAgBttC,KAAKutC,mBACvBvtC,KAAKutC,iBAAmBD,EAExB3sC,EAAK4H,QAAQvI,KAAKiC,MAAO,SAAUqN,GACjCA,EAAKk+B,OAAQ,EACTl+B,EAAKm+B,WAAWn+B,EAAKoS,WAG3B0rB,GAAU,GAIRptC,KAAK81B,QAAQpnB,QAAQ5M,MACvBA,EAAMA,MAAM9B,KAAK2sC,aAAchzB,EAAQyzB,GAGvCtrC,EAAMy/B,QAAQvhC,KAAK2sC,aAAchzB,EAAQ3Z,KAAKwhC,UAIhD,IAAI/uB,GAASzS,KAAK0tC,iBAAiB/zB,GAG/BqzB,EAAahtC,KAAKgwB,IAAIgd,UAC1BhtC,MAAK4H,IAAMolC,EAAWW,UACtB3tC,KAAKwH,KAAOwlC,EAAWY,WACvB5tC,KAAKwS,MAAQw6B,EAAW3c,YACxByU,EAAUnkC,EAAKgI,eAAe3I,KAAM,SAAUyS,IAAWqyB,EAGzDA,EAAUnkC,EAAKgI,eAAe3I,KAAK+F,MAAM2iB,MAAO,QAAS1oB,KAAKgwB,IAAI+c,MAAMttB,cAAgBqlB,EACxFA,EAAUnkC,EAAKgI,eAAe3I,KAAK+F,MAAM2iB,MAAO,SAAU1oB,KAAKgwB,IAAI+c,MAAMjoB,eAAiBggB,EAG1F9kC,KAAKgwB,IAAI5jB,WAAWc,MAAMuF,OAAUA,EAAS,KAC7CzS,KAAKgwB,IAAIgd,WAAW9/B,MAAMuF,OAAUA,EAAS,KAC7CzS,KAAKgwB,IAAItH,MAAMxb,MAAMuF,OAASA,EAAS,IAGvC,KAAK,GAAIlN,GAAI,EAAGsoC,EAAK7tC,KAAK2sC,aAAajnC,OAAYmoC,EAAJtoC,EAAQA,IAAK,CAC1D,GAAI+J,GAAOtP,KAAK2sC,aAAapnC,EAC7B+J,GAAKw+B,YAAYn0B,GAGnB,MAAOmrB,IASTliC,EAAMwQ,UAAUs6B,iBAAmB,SAAU/zB,GAE3C,GAAIlH,GACAk6B,EAAe3sC,KAAK2sC,YAGxB3sC,MAAK+tC,gBACL,IAAI35B,GAAKpU,IACT,IAAI2sC,EAAajnC,OAAQ,CACvB,GAAIqG,GAAM4gC,EAAa,GAAG/kC,IACtB+E,EAAMggC,EAAa,GAAG/kC,IAAM+kC,EAAa,GAAGl6B,MAahD,IAZA9R,EAAK4H,QAAQokC,EAAc,SAAUr9B,GACnCvD,EAAM9G,KAAK8G,IAAIA,EAAKuD,EAAK1H,KACzB+E,EAAM1H,KAAK0H,IAAIA,EAAM2C,EAAK1H,IAAM0H,EAAKmD,QACVlM,SAAvB+I,EAAKqD,KAAK+uB,WACZttB,EAAGotB,UAAUlyB,EAAKqD,KAAK+uB,UAAUjvB,OAASxN,KAAK0H,IAAIyH,EAAGotB,UAAUlyB,EAAKqD,KAAK+uB,UAAUjvB,OAAOnD,EAAKmD,QAChG2B,EAAGotB,UAAUlyB,EAAKqD,KAAK+uB,UAAU/Y,SAAU,KAO3C5c,EAAM4N,EAAOwnB,KAAM,CAErB,GAAIvX,GAAS7d,EAAM4N,EAAOwnB,IAC1Bx0B,IAAOid,EACPjpB,EAAK4H,QAAQokC,EAAc,SAAUr9B,GACnCA,EAAK1H,KAAOgiB,IAGhBnX,EAAS9F,EAAMgN,EAAOrK,KAAKoW,SAAW,MAGtCjT,GAASkH,EAAOwnB,KAAOxnB,EAAOrK,KAAKoW,QAIrC,OAFAjT,GAASxN,KAAK0H,IAAI8F,EAAQzS,KAAK+F,MAAM2iB,MAAMjW,SAQ7C7P,EAAMwQ,UAAU80B,KAAO,WAChBloC,KAAKgwB,IAAItH,MAAM5e,YAClB9J,KAAK81B,QAAQ9F,IAAIge,SAASt8B,YAAY1R,KAAKgwB,IAAItH,OAG5C1oB,KAAKgwB,IAAIgd,WAAWljC,YACvB9J,KAAK81B,QAAQ9F,IAAIgd,WAAWt7B,YAAY1R,KAAKgwB,IAAIgd,YAG9ChtC,KAAKgwB,IAAI5jB,WAAWtC,YACvB9J,KAAK81B,QAAQ9F,IAAI5jB,WAAWsF,YAAY1R,KAAKgwB,IAAI5jB,YAG9CpM,KAAKgwB,IAAImR,KAAKr3B,YACjB9J,KAAK81B,QAAQ9F,IAAImR,KAAKzvB,YAAY1R,KAAKgwB,IAAImR,OAO/Cv+B,EAAMwQ,UAAU60B,KAAO,WACrB,GAAIvf,GAAQ1oB,KAAKgwB,IAAItH,KACjBA,GAAM5e,YACR4e,EAAM5e,WAAWsH,YAAYsX,EAG/B,IAAIskB,GAAahtC,KAAKgwB,IAAIgd,UACtBA,GAAWljC,YACbkjC,EAAWljC,WAAWsH,YAAY47B,EAGpC,IAAI5gC,GAAapM,KAAKgwB,IAAI5jB,UACtBA,GAAWtC,YACbsC,EAAWtC,WAAWsH,YAAYhF,EAGpC,IAAI+0B,GAAOnhC,KAAKgwB,IAAImR,IAChBA,GAAKr3B,YACPq3B,EAAKr3B,WAAWsH,YAAY+vB,IAQhCv+B,EAAMwQ,UAAUF,IAAM,SAAS5D,GAc7B,GAbAtP,KAAKiC,MAAMqN,EAAKjP,IAAMiP,EACtBA,EAAK2+B,UAAUjuC,MAGYuG,SAAvB+I,EAAKqD,KAAK+uB,WAC+Bn7B,SAAvCvG,KAAKwhC,UAAUlyB,EAAKqD,KAAK+uB,YAC3B1hC,KAAKwhC,UAAUlyB,EAAKqD,KAAK+uB,WAAajvB,OAAO,EAAGkW,SAAS,EAAOtgB,MAAMrI,KAAKwsC,cAAevqC,UAC1FjC,KAAKwsC,iBAEPxsC,KAAKwhC,UAAUlyB,EAAKqD,KAAK+uB,UAAUz/B,MAAMiG,KAAKoH,IAEhDtP,KAAKkuC,iBAEkC,IAAnCluC,KAAK2sC,aAAajmC,QAAQ4I,GAAa,CACzC,GAAIomB,GAAQ11B,KAAK81B,QAAQlB,KAAKc,KAC9B11B,MAAKmuC,gBAAgB7+B,EAAMtP,KAAK2sC,aAAcjX,KAIlD9yB,EAAMwQ,UAAU86B,eAAiB,WAC/B,GAA6B3nC,SAAzBvG,KAAKysC,gBAA+B,CACtC,GAAI2B,KACJ,IAAmC,gBAAxBpuC,MAAKysC,gBAA6B,CAC3C,IAAK,GAAI/K,KAAY1hC,MAAKwhC,UACxB4M,EAAUlmC,MAAMw5B,SAAUA,EAAU2M,UAAWruC,KAAKwhC,UAAUE,GAAUz/B,MAAM,GAAG0Q,KAAK3S,KAAKysC,kBAE7F2B,GAAUj4B,KAAK,SAAU7Q,EAAGa,GAC1B,MAAOb,GAAE+oC,UAAYloC,EAAEkoC,gBAGtB,IAAmC,kBAAxBruC,MAAKysC,gBAA+B,CAClD,IAAK,GAAI/K,KAAY1hC,MAAKwhC,UACxB4M,EAAUlmC,KAAKlI,KAAKwhC,UAAUE,GAAUz/B,MAAM,GAAG0Q,KAEnDy7B,GAAUj4B,KAAKnW,KAAKysC,iBAGtB,GAAI2B,EAAU1oC,OAAS,EACrB,IAAK,GAAIH,GAAI,EAAGA,EAAI6oC,EAAU1oC,OAAQH,IACpCvF,KAAKwhC,UAAU4M,EAAU7oC,GAAGm8B,UAAUr5B,MAAQ9C,IAMtD3C,EAAMwQ,UAAU26B,eAAiB,WAC/B,IAAK,GAAIrM,KAAY1hC,MAAKwhC,UACpBxhC,KAAKwhC,UAAU37B,eAAe67B,KAChC1hC,KAAKwhC,UAAUE,GAAU/Y,SAAU,IASzC/lB,EAAMwQ,UAAUkD,OAAS,SAAShH,SACzBtP,MAAKiC,MAAMqN,EAAKjP,IACvBiP,EAAK2+B,UAAU,KAGf,IAAI5lC,GAAQrI,KAAK2sC,aAAajmC,QAAQ4I,EACzB,KAATjH,GAAarI,KAAK2sC,aAAarkC,OAAOD,EAAO,IAUnDzF,EAAMwQ,UAAUk7B,kBAAoB,SAASh/B,GAC3CtP,KAAK81B,QAAQyY,WAAWj/B,EAAKjP,KAO/BuC,EAAMwQ,UAAUsC,MAAQ,WAKtB,IAAK,GAJDhN,GAAQ/H,EAAK8H,QAAQzI,KAAKiC,OAC1BusC,KACAC,KAEKlpC,EAAI,EAAGA,EAAImD,EAAMhD,OAAQH,IACNgB,SAAtBmC,EAAMnD,GAAGoN,KAAK7C,KAChB2+B,EAASvmC,KAAKQ,EAAMnD,IAEtBipC,EAAWtmC,KAAKQ,EAAMnD,GAExBvF,MAAK6O,cACH+9B,QAAS4B,EACT3B,MAAO4B,GAGT3sC,EAAM++B,aAAa7gC,KAAK6O,aAAa+9B,SACrC9qC,EAAMg/B,WAAW9gC,KAAK6O,aAAag+B,QAYrCjqC,EAAMwQ,UAAUi6B,oBAAsB,SAASx+B,EAAc6/B,EAAiBhZ,GAC5E,GAKIpmB,GAAM/J,EALNonC,KACAgC,KACAlc,GAAYiD,EAAM5lB,IAAM4lB,EAAM7lB,OAAS,EACvC++B,EAAalZ,EAAM7lB,MAAQ4iB,EAC3Boc,EAAanZ,EAAM5lB,IAAM2iB,EAIzB3jB,EAAiB,SAAU1H,GAC7B,MAAiBwnC,GAARxnC,EAA6B,GACpBynC,GAATznC,EAA8B,EACA,EAMzC,IAAIsnC,EAAgBhpC,OAAS,EAC3B,IAAKH,EAAI,EAAGA,EAAImpC,EAAgBhpC,OAAQH,IACtCvF,KAAK8uC,6BAA6BJ,EAAgBnpC,GAAIonC,EAAcgC,EAAoBjZ,EAK5F,IAAIqZ,GAAoBpuC,EAAKiO,mBAAmBC,EAAa+9B,QAAS99B,EAAgB,OAAO,QAS7F,IANA9O,KAAKgvC,cAAcD,EAAmBlgC,EAAa+9B,QAASD,EAAcgC,EAAoB,SAAUr/B,GACtG,MAAQA,GAAKqD,KAAK9C,MAAQ++B,GAAct/B,EAAKqD,KAAK9C,MAAQg/B,IAK/B,GAAzB7uC,KAAK8sC,iBAEP,IADA9sC,KAAK8sC,kBAAmB,EACnBvnC,EAAI,EAAGA,EAAIsJ,EAAag+B,MAAMnnC,OAAQH,IACzCvF,KAAK8uC,6BAA6BjgC,EAAag+B,MAAMtnC,GAAIonC,EAAcgC,EAAoBjZ,OAG1F,CAEH,GAAIuZ,GAAkBtuC,EAAKiO,mBAAmBC,EAAag+B,MAAO/9B,EAAgB,OAAO,MAGzF9O,MAAKgvC,cAAcC,EAAiBpgC,EAAag+B,MAAOF,EAAcgC,EAAoB,SAAUr/B,GAClG,MAAQA,GAAKqD,KAAK7C,IAAM8+B,GAAct/B,EAAKqD,KAAK7C,IAAM++B,IAM1D,IAAKtpC,EAAI,EAAGA,EAAIonC,EAAajnC,OAAQH,IACnC+J,EAAOq9B,EAAapnC,GACf+J,EAAKm+B,WAAWn+B,EAAK44B,OAE1B54B,EAAK4/B,aAgBP,OAAOvC,IAGT/pC,EAAMwQ,UAAU47B,cAAgB,SAAUG,EAAYltC,EAAO0qC,EAAcgC,EAAoBS,GAC7F,GAAI9/B,GACA/J,CAEJ,IAAkB,IAAd4pC,EAAkB,CACpB,IAAK5pC,EAAI4pC,EAAY5pC,GAAK,IACxB+J,EAAOrN,EAAMsD,IACT6pC,EAAe9/B,IAFQ/J,IAMWgB,SAAhCooC,EAAmBr/B,EAAKjP,MAC1BsuC,EAAmBr/B,EAAKjP,KAAM,EAC9BssC,EAAazkC,KAAKoH,GAKxB;IAAK/J,EAAI4pC,EAAa,EAAG5pC,EAAItD,EAAMyD,SACjC4J,EAAOrN,EAAMsD,IACT6pC,EAAe9/B,IAFsB/J,IAMHgB,SAAhCooC,EAAmBr/B,EAAKjP,MAC1BsuC,EAAmBr/B,EAAKjP,KAAM,EAC9BssC,EAAazkC,KAAKoH,MAmB5B1M,EAAMwQ,UAAU+6B,gBAAkB,SAAS7+B,EAAMq9B,EAAcjX,GACvDpmB,EAAK+/B,UAAU3Z,IACZpmB,EAAKm+B,WAAWn+B,EAAK44B,OAE1B54B,EAAK4/B,cACLvC,EAAazkC,KAAKoH,IAGdA,EAAKm+B,WAAWn+B,EAAK24B,QAgB/BrlC,EAAMwQ,UAAU07B,6BAA+B,SAASx/B,EAAMq9B,EAAcgC,EAAoBjZ,GAC1FpmB,EAAK+/B,UAAU3Z,GACmBnvB,SAAhCooC,EAAmBr/B,EAAKjP,MAC1BsuC,EAAmBr/B,EAAKjP,KAAM,EAC9BssC,EAAazkC,KAAKoH,IAIhBA,EAAKm+B,WAAWn+B,EAAK24B,QAM7BpoC,EAAOD,QAAUgD,GAKb,SAAS/C,EAAQD,EAASM,GAW9B,QAAS2C,GAAiB00B,EAAS5kB,EAAMmjB,GACvClzB,EAAMrC,KAAKP,KAAMu3B,EAAS5kB,EAAMmjB,GAEhC91B,KAAKwS,MAAQ,EACbxS,KAAKyS,OAAS,EACdzS,KAAK4H,IAAM,EACX5H,KAAKwH,KAAO,EAfd,GACI5E,IADO1C,EAAoB,GACnBA,EAAoB,IAiBhC2C,GAAgBuQ,UAAY9M,OAAOgI,OAAO1L,EAAMwQ,WAShDvQ,EAAgBuQ,UAAUsO,OAAS,SAASgU,EAAO/b,GACjD,GAAImrB,IAAU,CAEd9kC,MAAK2sC,aAAe3sC,KAAKqtC,oBAAoBrtC,KAAK6O,aAAc7O,KAAK2sC,aAAcjX,GAGnF11B,KAAKwS,MAAQxS,KAAKgwB,IAAI5jB,WAAWikB,YAGjCrwB,KAAKgwB,IAAI5jB,WAAWc,MAAMuF,OAAU,GAGpC,KAAK,GAAIlN,GAAI,EAAGsoC,EAAK7tC,KAAK2sC,aAAajnC,OAAYmoC,EAAJtoC,EAAQA,IAAK,CAC1D,GAAI+J,GAAOtP,KAAK2sC,aAAapnC,EAC7B+J,GAAKw+B,YAAYn0B,GAGnB,MAAOmrB,IAMTjiC,EAAgBuQ,UAAU80B,KAAO,WAC1BloC,KAAKgwB,IAAI5jB,WAAWtC,YACvB9J,KAAK81B,QAAQ9F,IAAI5jB,WAAWsF,YAAY1R,KAAKgwB,IAAI5jB,aAIrDvM,EAAOD,QAAUiD,GAKb,SAAShD,EAAQD,EAASM,GA2B9B,QAAS4C,GAAQ8xB,EAAMlmB,GACrB1O,KAAK40B,KAAOA,EAEZ50B,KAAKs0B,gBACHztB,KAAM,KACN2tB,YAAa,SACb8a,MAAO,OACPxtC,OAAO,EACPytC,WAAY,KAEZC,YAAY,EACZC,UACEC,YAAY,EACZ3H,aAAa,EACb70B,KAAK,EACLoD,QAAQ,GAGVq5B,MAAO,SAAUrgC,EAAM9G,GACrBA,EAAS8G,IAEXsgC,SAAU,SAAUtgC,EAAM9G,GACxBA,EAAS8G,IAEXugC,OAAQ,SAAUvgC,EAAM9G,GACtBA,EAAS8G,IAEXwgC,SAAU,SAAUxgC,EAAM9G,GACxBA,EAAS8G,IAEXygC,SAAU,SAAUzgC,EAAM9G,GACxBA,EAAS8G,IAGXqK,QACErK,MACEmW,WAAY,GACZC,SAAU,IAEZyb,KAAM,IAERld,QAAS,GAIXjkB,KAAK0O,QAAU/N,EAAK0E,UAAWrF,KAAKs0B,gBAGpCt0B,KAAKgwC,aACHnpC,MAAOgJ,MAAO,OAAQC,IAAK,SAG7B9P,KAAKq6B,YACHnF,SAAUN,EAAKj0B,KAAKu0B,SACpBI,OAAQV,EAAKj0B,KAAK20B,QAEpBt1B,KAAKgwB,OACLhwB,KAAK+F,SACL/F,KAAK8D,OAAS,IAEd,IAAIsQ,GAAKpU,IACTA,MAAK+1B,UAAY,KACjB/1B,KAAKg2B,WAAa,KAGlBh2B,KAAKiwC,eACH/8B,IAAO,SAAU1J,EAAOuK,GACtBK,EAAG87B,OAAOn8B,EAAO9R,QAEnB6S,OAAU,SAAUtL,EAAOuK,GACzBK,EAAG+7B,UAAUp8B,EAAO9R,QAEtBqU,OAAU,SAAU9M,EAAOuK,GACzBK,EAAGg8B,UAAUr8B,EAAO9R,SAKxBjC,KAAKqwC,gBACHn9B,IAAO,SAAU1J,EAAOuK,GACtBK,EAAGk8B,aAAav8B,EAAO9R,QAEzB6S,OAAU,SAAUtL,EAAOuK,GACzBK,EAAGm8B,gBAAgBx8B,EAAO9R,QAE5BqU,OAAU,SAAU9M,EAAOuK,GACzBK,EAAGo8B,gBAAgBz8B,EAAO9R,SAI9BjC,KAAKiC,SACLjC,KAAKo0B,UACLp0B,KAAKywC,YAELzwC,KAAK0wC,aACL1wC,KAAK2wC,YAAa,EAElB3wC,KAAK4wC,eAGL5wC,KAAK20B,UAEL30B,KAAKmT,WAAWzE,GA/HlB,GAAIm3B,GAAS3lC,EAAoB,IAC7BS,EAAOT,EAAoB,GAC3BW,EAAUX,EAAoB,GAC9BY,EAAWZ,EAAoB,GAC/BqC,EAAYrC,EAAoB,IAChC0C,EAAQ1C,EAAoB,IAC5B2C,EAAkB3C,EAAoB,IACtCkC,EAAUlC,EAAoB,IAC9BmC,EAAYnC,EAAoB,IAChCoC,EAAYpC,EAAoB,IAChCiC,EAAiBjC,EAAoB,IAGrC2wC,EAAY,gBACZC,EAAa,gBAoHjBhuC,GAAQsQ,UAAY,GAAI7Q,GAGxBO,EAAQqU,OACN/K,WAAYjK,EACZ4uC,IAAK3uC,EACLszB,MAAOpzB,EACP6P,MAAO9P,GAMTS,EAAQsQ,UAAUuhB,QAAU,WAC1B,GAAIpV,GAAQ/N,SAASM,cAAc,MACnCyN,GAAMxX,UAAY,UAClBwX,EAAM,oBAAsBvf,KAC5BA,KAAKgwB,IAAIzQ,MAAQA,CAGjB,IAAInT,GAAaoF,SAASM,cAAc,MACxC1F,GAAWrE,UAAY,aACvBwX,EAAM7N,YAAYtF,GAClBpM,KAAKgwB,IAAI5jB,WAAaA,CAGtB,IAAI4gC,GAAax7B,SAASM,cAAc,MACxCk7B,GAAWjlC,UAAY,aACvBwX,EAAM7N,YAAYs7B,GAClBhtC,KAAKgwB,IAAIgd,WAAaA,CAGtB,IAAI7L,GAAO3vB,SAASM,cAAc,MAClCqvB,GAAKp5B,UAAY,OACjB/H,KAAKgwB,IAAImR,KAAOA,CAGhB,IAAI6M,GAAWx8B,SAASM,cAAc,MACtCk8B,GAASjmC,UAAY,WACrB/H,KAAKgwB,IAAIge,SAAWA,EAGpBhuC,KAAKgxC,kBAGL,IAAIC,GAAkB,GAAIpuC,GAAgBiuC,EAAY,KAAM9wC,KAC5DixC,GAAgB/I,OAChBloC,KAAKo0B,OAAO0c,GAAcG,EAM1BjxC,KAAK8D,OAAS+hC,EAAO7lC,KAAK40B,KAAK5E,IAAI8H,iBACjCvuB,gBAAgB,IAIlBvJ,KAAK8D,OAAO0P,GAAG,QAAaxT,KAAKs+B,SAASvJ,KAAK/0B,OAC/CA,KAAK8D,OAAO0P,GAAG,YAAaxT,KAAKi+B,aAAalJ,KAAK/0B,OACnDA,KAAK8D,OAAO0P,GAAG,OAAaxT,KAAKk+B,QAAQnJ,KAAK/0B,OAC9CA,KAAK8D,OAAO0P,GAAG,UAAaxT,KAAKm+B,WAAWpJ,KAAK/0B,OAGjDA,KAAK8D,OAAO0P,GAAG,MAAQxT,KAAKkxC,cAAcnc,KAAK/0B,OAG/CA,KAAK8D,OAAO0P,GAAG,OAAQxT,KAAKmxC,mBAAmBpc,KAAK/0B,OAGpDA,KAAK8D,OAAO0P,GAAG,YAAaxT,KAAKoxC,WAAWrc,KAAK/0B,OAGjDA,KAAKkoC,QAmEPplC,EAAQsQ,UAAUD,WAAa,SAASzE,GACtC,GAAIA,EAAS,CAEX,GAAIP,IAAU,OAAQ,QAAS,cAAe,UAAW,QAAS,aAAc,aAAc,iBAAkB,WAAW,OAC3HxN,GAAKmF,gBAAgBqI,EAAQnO,KAAK0O,QAASA,GAEvC,UAAYA,KACgB,gBAAnBA,GAAQiL,QACjB3Z,KAAK0O,QAAQiL,OAAOwnB,KAAOzyB,EAAQiL,OACnC3Z,KAAK0O,QAAQiL,OAAOrK,KAAKmW,WAAa/W,EAAQiL,OAC9C3Z,KAAK0O,QAAQiL,OAAOrK,KAAKoW,SAAWhX,EAAQiL,QAEX,gBAAnBjL,GAAQiL,SACtBhZ,EAAKmF,iBAAiB,QAAS9F,KAAK0O,QAAQiL,OAAQjL,EAAQiL,QACxD,QAAUjL,GAAQiL,SACe,gBAAxBjL,GAAQiL,OAAOrK,MACxBtP,KAAK0O,QAAQiL,OAAOrK,KAAKmW,WAAa/W,EAAQiL,OAAOrK,KACrDtP,KAAK0O,QAAQiL,OAAOrK,KAAKoW,SAAWhX,EAAQiL,OAAOrK,MAEb,gBAAxBZ,GAAQiL,OAAOrK,MAC7B3O,EAAKmF,iBAAiB,aAAc,YAAa9F,KAAK0O,QAAQiL,OAAOrK,KAAMZ,EAAQiL,OAAOrK,SAM9F,YAAcZ,KACgB,iBAArBA,GAAQ+gC,UACjBzvC,KAAK0O,QAAQ+gC,SAASC,WAAchhC,EAAQ+gC,SAC5CzvC,KAAK0O,QAAQ+gC,SAAS1H,YAAcr5B,EAAQ+gC,SAC5CzvC,KAAK0O,QAAQ+gC,SAASv8B,IAAcxE,EAAQ+gC,SAC5CzvC,KAAK0O,QAAQ+gC,SAASn5B,OAAc5H,EAAQ+gC,UAET,gBAArB/gC,GAAQ+gC,UACtB9uC,EAAKmF,iBAAiB,aAAc,cAAe,MAAO,UAAW9F,KAAK0O,QAAQ+gC,SAAU/gC,EAAQ+gC,UAKxG,IAAI4B,GAAc,SAAWn7B,GAC3B,GAAIiD,GAAKzK,EAAQwH,EACjB,IAAIiD,EAAI,CACN,KAAMA,YAAcm4B,WAClB,KAAM,IAAI1tC,OAAM,UAAYsS,EAAO,uBAAyBA,EAAO,mBAErElW,MAAK0O,QAAQwH,GAAQiD,IAEtB4b,KAAK/0B,OACP,QAAS,WAAY,WAAY,SAAU,YAAYuI,QAAQ8oC,GAGhErxC,KAAKuxC,cAOTzuC,EAAQsQ,UAAUm+B,UAAY,WAC5BvxC,KAAKywC,YACLzwC,KAAK2wC,YAAa,GAMpB7tC,EAAQsQ,UAAUG,QAAU,WAC1BvT,KAAKioC,OACLjoC,KAAKk2B,SAAS,MACdl2B,KAAKi2B,UAAU,MAEfj2B,KAAK8D,OAAS,KAEd9D,KAAK40B,KAAO,KACZ50B,KAAKq6B,WAAa,MAMpBv3B,EAAQsQ,UAAU60B,KAAO,WAEnBjoC,KAAKgwB,IAAIzQ,MAAMzV,YACjB9J,KAAKgwB,IAAIzQ,MAAMzV,WAAWsH,YAAYpR,KAAKgwB,IAAIzQ,OAI7Cvf,KAAKgwB,IAAImR,KAAKr3B,YAChB9J,KAAKgwB,IAAImR,KAAKr3B,WAAWsH,YAAYpR,KAAKgwB,IAAImR,MAI5CnhC,KAAKgwB,IAAIge,SAASlkC,YACpB9J,KAAKgwB,IAAIge,SAASlkC,WAAWsH,YAAYpR,KAAKgwB,IAAIge,WAQtDlrC,EAAQsQ,UAAU80B,KAAO,WAElBloC,KAAKgwB,IAAIzQ,MAAMzV,YAClB9J,KAAK40B,KAAK5E,IAAI7D,OAAOza,YAAY1R,KAAKgwB,IAAIzQ,OAIvCvf,KAAKgwB,IAAImR,KAAKr3B,YACjB9J,KAAK40B,KAAK5E,IAAIoV,mBAAmB1zB,YAAY1R,KAAKgwB,IAAImR,MAInDnhC,KAAKgwB,IAAIge,SAASlkC,YACrB9J,KAAK40B,KAAK5E,IAAIxoB,KAAKkK,YAAY1R,KAAKgwB,IAAIge,WAW5ClrC,EAAQsQ,UAAUujB,aAAe,SAASvhB,GACxC,GAAI7P,GAAGsoC,EAAIxtC,EAAIiP,CAMf,KAJW/I,QAAP6O,IAAkBA,MACjBpP,MAAMC,QAAQmP,KAAMA,GAAOA,IAG3B7P,EAAI,EAAGsoC,EAAK7tC,KAAK0wC,UAAUhrC,OAAYmoC,EAAJtoC,EAAQA,IAC9ClF,EAAKL,KAAK0wC,UAAUnrC,GACpB+J,EAAOtP,KAAKiC,MAAM5B,GACdiP,GAAMA,EAAKkiC,UAKjB,KADAxxC,KAAK0wC,aACAnrC,EAAI,EAAGsoC,EAAKz4B,EAAI1P,OAAYmoC,EAAJtoC,EAAQA,IACnClF,EAAK+U,EAAI7P,GACT+J,EAAOtP,KAAKiC,MAAM5B,GACdiP,IACFtP,KAAK0wC,UAAUxoC,KAAK7H,GACpBiP,EAAKmiC,WASX3uC,EAAQsQ,UAAUyjB,aAAe,WAC/B,MAAO72B,MAAK0wC,UAAUz8B,YAOxBnR,EAAQsQ,UAAUs+B,gBAAkB,WAClC,GAAIhc,GAAQ11B,KAAK40B,KAAKc,MAAM8J,WACxBh4B,EAAQxH,KAAK40B,KAAKj0B,KAAKu0B,SAASQ,EAAM7lB,OACtCyX,EAAQtnB,KAAK40B,KAAKj0B,KAAKu0B,SAASQ,EAAM5lB,KAEtCsF,IACJ,KAAK,GAAImiB,KAAWv3B,MAAKo0B,OACvB,GAAIp0B,KAAKo0B,OAAOvuB,eAAe0xB,GAM7B,IAAK,GALDrlB,GAAQlS,KAAKo0B,OAAOmD,GACpBoa,EAAkBz/B,EAAMy6B,aAInBpnC,EAAI,EAAGA,EAAIosC,EAAgBjsC,OAAQH,IAAK,CAC/C,GAAI+J,GAAOqiC,EAAgBpsC,EAEtB+J,GAAK9H,KAAO8f,GAAWhY,EAAK9H,KAAO8H,EAAKkD,MAAQhL,GACnD4N,EAAIlN,KAAKoH,EAAKjP,IAMtB,MAAO+U,IAQTtS,EAAQsQ,UAAUw+B,UAAY,SAASvxC,GAErC,IAAK,GADDqwC,GAAY1wC,KAAK0wC,UACZnrC,EAAI,EAAGsoC,EAAK6C,EAAUhrC,OAAYmoC,EAAJtoC,EAAQA,IAC7C,GAAImrC,EAAUnrC,IAAMlF,EAAI,CACtBqwC,EAAUpoC,OAAO/C,EAAG,EACpB,SASNzC,EAAQsQ,UAAUsO,OAAS,WACzB,GAAI/H,GAAS3Z,KAAK0O,QAAQiL,OACtB+b,EAAQ11B,KAAK40B,KAAKc,MAClBtrB,EAASzJ,EAAKoJ,OAAOK,OACrBsE,EAAU1O,KAAK0O,QACf8lB,EAAc9lB,EAAQ8lB,YACtBsQ,GAAU,EACVvlB,EAAQvf,KAAKgwB,IAAIzQ,MACjBkwB,EAAW/gC,EAAQ+gC,SAASC,YAAchhC,EAAQ+gC,SAAS1H,WAG/D/nC,MAAK+F,MAAM6B,IAAM5H,KAAK40B,KAAKC,SAASjtB,IAAI6K,OAASzS,KAAK40B,KAAKC,SAASxoB,OAAOzE,IAC3E5H,KAAK+F,MAAMyB,KAAOxH,KAAK40B,KAAKC,SAASrtB,KAAKgL,MAAQxS,KAAK40B,KAAKC,SAASxoB,OAAO7E,KAG5E+X,EAAMxX,UAAY,WAAa0nC,EAAW,YAAc,IAGxD3K,EAAU9kC,KAAK6xC,gBAAkB/M,CAIjC,IAAIgN,GAAkBpc,EAAM5lB,IAAM4lB,EAAM7lB,MACpCkiC,EAAUD,GAAmB9xC,KAAKgyC,qBAAyBhyC,KAAK+F,MAAMyM,OAASxS,KAAK+F,MAAMksC,SAC1FF,KAAQ/xC,KAAK2wC,YAAa,GAC9B3wC,KAAKgyC,oBAAsBF,EAC3B9xC,KAAK+F,MAAMksC,UAAYjyC,KAAK+F,MAAMyM,KAElC,IAAI46B,GAAUptC,KAAK2wC,WACfuB,EAAalyC,KAAKmyC,cAClBC,GACF9iC,KAAMqK,EAAOrK,KACb6xB,KAAMxnB,EAAOwnB,MAEXkR,GACF/iC,KAAMqK,EAAOrK,KACb6xB,KAAMxnB,EAAOrK,KAAKoW,SAAW,GAE3BjT,EAAS,EACTiiB,EAAY/a,EAAOwnB,KAAOxnB,EAAOrK,KAAKoW,QA+B1C,OA5BA1lB,MAAKo0B,OAAO0c,GAAYpvB,OAAOgU,EAAO2c,EAAgBjF,GAGtDzsC,EAAK4H,QAAQvI,KAAKo0B,OAAQ,SAAUliB,GAClC,GAAIogC,GAAepgC,GAASggC,EAAcE,EAAcC,EACpDE,EAAergC,EAAMwP,OAAOgU,EAAO4c,EAAalF,EACpDtI,GAAUyN,GAAgBzN,EAC1BryB,GAAUP,EAAMO,SAElBA,EAASxN,KAAK0H,IAAI8F,EAAQiiB,GAC1B10B,KAAK2wC,YAAa,EAGlBpxB,EAAMrS,MAAMuF,OAAUrI,EAAOqI,GAG7BzS,KAAK+F,MAAMyM,MAAQ+M,EAAM8Q,YACzBrwB,KAAK+F,MAAM0M,OAASA,EAGpBzS,KAAKgwB,IAAImR,KAAKj0B,MAAMtF,IAAMwC,EAAuB,OAAfoqB,EAC7Bx0B,KAAK40B,KAAKC,SAASjtB,IAAI6K,OAASzS,KAAK40B,KAAKC,SAASxoB,OAAOzE,IAC1D5H,KAAK40B,KAAKC,SAASjtB,IAAI6K,OAASzS,KAAK40B,KAAKC,SAASiD,gBAAgBrlB,QACxEzS,KAAKgwB,IAAImR,KAAKj0B,MAAM1F,KAAO,IAG3Bs9B,EAAU9kC,KAAK6kC,cAAgBC,GAUjChiC,EAAQsQ,UAAU++B,YAAc,WAC9B,GAAIK,GAA+C,OAA5BxyC,KAAK0O,QAAQ8lB,YAAwB,EAAKx0B,KAAKywC,SAAS/qC,OAAS,EACpF+sC,EAAezyC,KAAKywC,SAAS+B,GAC7BN,EAAalyC,KAAKo0B,OAAOqe,IAAiBzyC,KAAKo0B,OAAOyc,EAE1D,OAAOqB,IAAc,MAQvBpvC,EAAQsQ,UAAU49B,iBAAmB,WACnC,CAAA,GAEI1hC,GAAMkG,EAFNk9B,EAAY1yC,KAAKo0B,OAAOyc,EACX7wC,MAAKo0B,OAAO0c,GAG7B,GAAI9wC,KAAKg2B,YAEP,GAAI0c,EAAW,CACbA,EAAUzK,aACHjoC,MAAKo0B,OAAOyc,EAEnB,KAAKr7B,IAAUxV,MAAKiC,MAClB,GAAIjC,KAAKiC,MAAM4D,eAAe2P,GAAS,CACrClG,EAAOtP,KAAKiC,MAAMuT,GAClBlG,EAAK61B,QAAU71B,EAAK61B,OAAO7uB,OAAOhH,EAClC,IAAIioB,GAAUv3B,KAAK2yC,YAAYrjC,EAAKqD,MAChCT,EAAQlS,KAAKo0B,OAAOmD,EACxBrlB,IAASA,EAAMgB,IAAI5D,IAASA,EAAK24B,aAOvC,KAAKyK,EAAW,CACd,GAAIryC,GAAK,KACLsS,EAAO,IACX+/B,GAAY,GAAI9vC,GAAMvC,EAAIsS,EAAM3S,MAChCA,KAAKo0B,OAAOyc,GAAa6B,CAEzB,KAAKl9B,IAAUxV,MAAKiC,MACdjC,KAAKiC,MAAM4D,eAAe2P,KAC5BlG,EAAOtP,KAAKiC,MAAMuT,GAClBk9B,EAAUx/B,IAAI5D,GAIlBojC,GAAUxK,SAShBplC,EAAQsQ,UAAUw/B,YAAc,WAC9B,MAAO5yC,MAAKgwB,IAAIge,UAOlBlrC,EAAQsQ,UAAU8iB,SAAW,SAASj0B,GACpC,GACImT,GADAhB,EAAKpU,KAEL6yC,EAAe7yC,KAAK+1B,SAGxB,IAAK9zB,EAGA,CAAA,KAAIA,YAAiBpB,IAAWoB,YAAiBnB,IAIpD,KAAM,IAAIsF,WAAU,kDAHpBpG,MAAK+1B,UAAY9zB,MAHjBjC,MAAK+1B,UAAY,IAoBnB,IAXI8c,IAEFlyC,EAAK4H,QAAQvI,KAAKiwC,cAAe,SAAUznC,EAAUgB,GACnDqpC,EAAal/B,IAAInK,EAAOhB,KAI1B4M,EAAMy9B,EAAa/8B,SACnB9V,KAAKowC,UAAUh7B,IAGbpV,KAAK+1B,UAAW,CAElB,GAAI11B,GAAKL,KAAKK,EACdM,GAAK4H,QAAQvI,KAAKiwC,cAAe,SAAUznC,EAAUgB,GACnD4K,EAAG2hB,UAAUviB,GAAGhK,EAAOhB,EAAUnI,KAInC+U,EAAMpV,KAAK+1B,UAAUjgB,SACrB9V,KAAKkwC,OAAO96B,GAGZpV,KAAKgxC,qBAQTluC,EAAQsQ,UAAU0/B,SAAW,WAC3B,MAAO9yC,MAAK+1B,WAOdjzB,EAAQsQ,UAAU6iB,UAAY,SAAS7B,GACrC,GACIhf,GADAhB,EAAKpU,IAgBT,IAZIA,KAAKg2B,aACPr1B,EAAK4H,QAAQvI,KAAKqwC,eAAgB,SAAU7nC,EAAUgB,GACpD4K,EAAG4hB,WAAWniB,YAAYrK,EAAOhB,KAInC4M,EAAMpV,KAAKg2B,WAAWlgB,SACtB9V,KAAKg2B,WAAa,KAClBh2B,KAAKwwC,gBAAgBp7B,IAIlBgf,EAGA,CAAA,KAAIA,YAAkBvzB,IAAWuzB,YAAkBtzB,IAItD,KAAM,IAAIsF,WAAU,kDAHpBpG,MAAKg2B,WAAa5B,MAHlBp0B,MAAKg2B,WAAa,IASpB,IAAIh2B,KAAKg2B,WAAY,CAEnB,GAAI31B,GAAKL,KAAKK,EACdM,GAAK4H,QAAQvI,KAAKqwC,eAAgB,SAAU7nC,EAAUgB,GACpD4K,EAAG4hB,WAAWxiB,GAAGhK,EAAOhB,EAAUnI,KAIpC+U,EAAMpV,KAAKg2B,WAAWlgB,SACtB9V,KAAKswC,aAAal7B,GAIpBpV,KAAKgxC,mBAGLhxC,KAAK+yC,SAEL/yC,KAAK40B,KAAKE,QAAQjH,KAAK,UAAWxa,OAAO,KAO3CvQ,EAAQsQ,UAAU4/B,UAAY,WAC5B,MAAOhzC,MAAKg2B,YAOdlzB,EAAQsQ,UAAUm7B,WAAa,SAASluC,GACtC,GAAIiP,GAAOtP,KAAK+1B,UAAU5gB,IAAI9U,GAC1B42B,EAAUj3B,KAAK+1B,UAAUhgB,YAEzBzG,IAEFtP,KAAK0O,QAAQohC,SAASxgC,EAAM,SAAUA,GAChCA,GAGF2nB,EAAQ3gB,OAAOjW,MAYvByC,EAAQsQ,UAAU6/B,SAAW,SAAUnc,GACrC,MAAOA,GAASjwB,MAAQ7G,KAAK0O,QAAQ7H,OAASiwB,EAAShnB,IAAM,QAAU,QAUzEhN,EAAQsQ,UAAUu/B,YAAc,SAAU7b,GACxC,GAAIjwB,GAAO7G,KAAKizC,SAASnc,EACzB,OAAY,cAARjwB,GAA0CN,QAAlBuwB,EAAS5kB,MAC7B4+B,EAGC9wC,KAAKg2B,WAAac,EAAS5kB,MAAQ2+B,GAS9C/tC,EAAQsQ,UAAU+8B,UAAY,SAAS/6B,GACrC,GAAIhB,GAAKpU,IAEToV,GAAI7M,QAAQ,SAAUlI,GACpB,GAAIy2B,GAAW1iB,EAAG2hB,UAAU5gB,IAAI9U,EAAI+T,EAAG47B,aACnC1gC,EAAO8E,EAAGnS,MAAM5B,GAChBwG,EAAOuN,EAAG6+B,SAASnc,GAEnBzwB,EAAcvD,EAAQqU,MAAMtQ,EAchC,IAZIyI,IAEGjJ,GAAiBiJ,YAAgBjJ,GAMpC+N,EAAGc,YAAY5F,EAAMwnB,IAJrB1iB,EAAG8+B,YAAY5jC,GACfA,EAAO,QAONA,EAAM,CAET,IAAIjJ,EAKC,KAEG,IAAID,WAFK,iBAARS,EAEa,4HAIA,sBAAwBA,EAAO,IAVnDyI,GAAO,GAAIjJ,GAAYywB,EAAU1iB,EAAGimB,WAAYjmB,EAAG1F,SACnDY,EAAKjP,GAAKA,EACV+T,EAAGC,SAAS/E,MAalBtP,KAAK+yC,SACL/yC,KAAK2wC,YAAa,EAClB3wC,KAAK40B,KAAKE,QAAQjH,KAAK,UAAWxa,OAAO,KAQ3CvQ,EAAQsQ,UAAU88B,OAASptC,EAAQsQ,UAAU+8B,UAO7CrtC,EAAQsQ,UAAUg9B,UAAY,SAASh7B,GACrC,GAAI6B,GAAQ,EACR7C,EAAKpU,IACToV,GAAI7M,QAAQ,SAAUlI,GACpB,GAAIiP,GAAO8E,EAAGnS,MAAM5B,EAChBiP,KACF2H,IACA7C,EAAG8+B,YAAY5jC,MAIf2H,IAEFjX,KAAK+yC,SACL/yC,KAAK2wC,YAAa,EAClB3wC,KAAK40B,KAAKE,QAAQjH,KAAK,UAAWxa,OAAO,MAQ7CvQ,EAAQsQ,UAAU2/B,OAAS,WAGzBpyC,EAAK4H,QAAQvI,KAAKo0B,OAAQ,SAAUliB,GAClCA,EAAMwD,WASV5S,EAAQsQ,UAAUm9B,gBAAkB,SAASn7B,GAC3CpV,KAAKswC,aAAal7B,IAQpBtS,EAAQsQ,UAAUk9B,aAAe,SAASl7B,GACxC,GAAIhB,GAAKpU,IAEToV,GAAI7M,QAAQ,SAAUlI,GACpB,GAAIgsC,GAAYj4B,EAAG4hB,WAAW7gB,IAAI9U,GAC9B6R,EAAQkC,EAAGggB,OAAO/zB,EAEtB,IAAK6R,EA6BHA,EAAM+F,QAAQo0B,OA7BJ,CAEV,GAAIhsC,GAAMwwC,GAAaxwC,GAAMywC,EAC3B,KAAM,IAAIltC,OAAM,qBAAuBvD,EAAK,qBAG9C,IAAI8yC,GAAe7sC,OAAOgI,OAAO8F,EAAG1F,QACpC/N,GAAK0E,OAAO8tC,GACV1gC,OAAQ,OAGVP,EAAQ,GAAItP,GAAMvC,EAAIgsC,EAAWj4B,GACjCA,EAAGggB,OAAO/zB,GAAM6R,CAGhB,KAAK,GAAIsD,KAAUpB,GAAGnS,MACpB,GAAImS,EAAGnS,MAAM4D,eAAe2P,GAAS,CACnC,GAAIlG,GAAO8E,EAAGnS,MAAMuT,EAChBlG,GAAKqD,KAAKT,OAAS7R,GACrB6R,EAAMgB,IAAI5D,GAKhB4C,EAAMwD,QACNxD,EAAMg2B,UAQVloC,KAAK40B,KAAKE,QAAQjH,KAAK,UAAWxa,OAAO,KAQ3CvQ,EAAQsQ,UAAUo9B,gBAAkB,SAASp7B,GAC3C,GAAIgf,GAASp0B,KAAKo0B,MAClBhf,GAAI7M,QAAQ,SAAUlI,GACpB,GAAI6R,GAAQkiB,EAAO/zB,EAEf6R,KACFA,EAAM+1B,aACC7T,GAAO/zB,MAIlBL,KAAKuxC,YAELvxC,KAAK40B,KAAKE,QAAQjH,KAAK,UAAWxa,OAAO,KAQ3CvQ,EAAQsQ,UAAUy+B,aAAe,WAC/B,GAAI7xC,KAAKg2B,WAAY,CAEnB,GAAIya,GAAWzwC,KAAKg2B,WAAWlgB,QAC7BJ,MAAO1V,KAAK0O,QAAQ6gC,aAGlBlQ,GAAW1+B,EAAKgG,WAAW8pC,EAAUzwC,KAAKywC,SAC9C,IAAIpR,EAAS,CAEX,GAAIjL,GAASp0B,KAAKo0B,MAClBqc,GAASloC,QAAQ,SAAUgvB,GACzBnD,EAAOmD,GAAS0Q,SAIlBwI,EAASloC,QAAQ,SAAUgvB,GACzBnD,EAAOmD,GAAS2Q,SAGlBloC,KAAKywC,SAAWA,EAGlB,MAAOpR,GAGP,OAAO,GASXv8B,EAAQsQ,UAAUiB,SAAW,SAAS/E,GACpCtP,KAAKiC,MAAMqN,EAAKjP,IAAMiP,CAGtB,IAAIioB,GAAUv3B,KAAK2yC,YAAYrjC,EAAKqD,MAChCT,EAAQlS,KAAKo0B,OAAOmD,EACpBrlB,IAAOA,EAAMgB,IAAI5D,IASvBxM,EAAQsQ,UAAU8B,YAAc,SAAS5F,EAAMwnB,GAC7C,GAAIsc,GAAa9jC,EAAKqD,KAAKT,KAM3B,IAHA5C,EAAK2I,QAAQ6e,GAGTsc,GAAc9jC,EAAKqD,KAAKT,MAAO,CACjC,GAAImhC,GAAWrzC,KAAKo0B,OAAOgf,EACvBC,IAAUA,EAAS/8B,OAAOhH,EAE9B,IAAIioB,GAAUv3B,KAAK2yC,YAAYrjC,EAAKqD,MAChCT,EAAQlS,KAAKo0B,OAAOmD,EACpBrlB,IAAOA,EAAMgB,IAAI5D,KAUzBxM,EAAQsQ,UAAU8/B,YAAc,SAAS5jC,GAEvCA,EAAK24B,aAGEjoC,MAAKiC,MAAMqN,EAAKjP,GAGvB,IAAIgI,GAAQrI,KAAK0wC,UAAUhqC,QAAQ4I,EAAKjP,GAC3B,KAATgI,GAAarI,KAAK0wC,UAAUpoC,OAAOD,EAAO,GAG9CiH,EAAK61B,QAAU71B,EAAK61B,OAAO7uB,OAAOhH,IASpCxM,EAAQsQ,UAAUkgC,qBAAuB,SAAS5qC,GAGhD,IAAK,GAFD+lC,MAEKlpC,EAAI,EAAGA,EAAImD,EAAMhD,OAAQH,IAC5BmD,EAAMnD,YAAcjD,IACtBmsC,EAASvmC,KAAKQ,EAAMnD,GAGxB,OAAOkpC,IAYT3rC,EAAQsQ,UAAUkrB,SAAW,SAAU90B,GAErCxJ,KAAK4wC,YAAYthC,KAAOxM,EAAQywC,eAAe/pC,IAQjD1G,EAAQsQ,UAAU6qB,aAAe,SAAUz0B,GACzC,GAAKxJ,KAAK0O,QAAQ+gC,SAASC,YAAe1vC,KAAK0O,QAAQ+gC,SAAS1H,YAAhE,CAIA,GAEIhiC,GAFAuJ,EAAOtP,KAAK4wC,YAAYthC,MAAQ,KAChC8E,EAAKpU,IAGT,IAAIsP,GAAQA,EAAKkkC,SAAU,CACzB,GAAIC,GAAejqC,EAAMG,OAAO8pC,aAC5BC,EAAgBlqC,EAAMG,OAAO+pC,aAE7BD,IACF1tC,GACEuJ,KAAMmkC,EACNE,SAAUnqC,EAAMo2B,QAAQzT,OAAOvP,SAG7BxI,EAAG1F,QAAQ+gC,SAASC,aACtB3pC,EAAM8J,MAAQP,EAAKqD,KAAK9C,MAAM9I,WAE5BqN,EAAG1F,QAAQ+gC,SAAS1H,aAClB,SAAWz4B,GAAKqD,OAAM5M,EAAMmM,MAAQ5C,EAAKqD,KAAKT,OAGpDlS,KAAK4wC,YAAYgD,WAAa7tC,IAEvB2tC,GACP3tC,GACEuJ,KAAMokC,EACNC,SAAUnqC,EAAMo2B,QAAQzT,OAAOvP,SAG7BxI,EAAG1F,QAAQ+gC,SAASC,aACtB3pC,EAAM+J,IAAMR,EAAKqD,KAAK7C,IAAI/I,WAExBqN,EAAG1F,QAAQ+gC,SAAS1H,aAClB,SAAWz4B,GAAKqD,OAAM5M,EAAMmM,MAAQ5C,EAAKqD,KAAKT,OAGpDlS,KAAK4wC,YAAYgD,WAAa7tC,IAG9B/F,KAAK4wC,YAAYgD,UAAY5zC,KAAK62B,eAAevpB,IAAI,SAAUjN,GAC7D,GAAIiP,GAAO8E,EAAGnS,MAAM5B,GAChB0F,GACFuJ,KAAMA,EACNqkC,SAAUnqC,EAAMo2B,QAAQzT,OAAOvP,QAWjC,OARIxI,GAAG1F,QAAQ+gC,SAASC,aAClB,SAAWpgC,GAAKqD,OAAM5M,EAAM8J,MAAQP,EAAKqD,KAAK9C,MAAM9I,WACpD,OAASuI,GAAKqD,OAAQ5M,EAAM+J,IAAMR,EAAKqD,KAAK7C,IAAI/I,YAElDqN,EAAG1F,QAAQ+gC,SAAS1H,aAClB,SAAWz4B,GAAKqD,OAAM5M,EAAMmM,MAAQ5C,EAAKqD,KAAKT,OAG7CnM,IAIXyD,EAAM08B,qBASVpjC,EAAQsQ,UAAU8qB,QAAU,SAAU10B,GAGpC,GAFAA,EAAMD,iBAEFvJ,KAAK4wC,YAAYgD,UAAW,CAC9B,GAAIx/B,GAAKpU,KACLi1B,EAAOj1B,KAAK40B,KAAKj0B,KAAKs0B,MAAQ,KAC9BpL,EAAU7pB,KAAK40B,KAAK5E,IAAItwB,KAAKkuC,WAAa5tC,KAAK40B,KAAKC,SAASrtB,KAAKgL,KAGtExS,MAAK4wC,YAAYgD,UAAUrrC,QAAQ,SAAUxC,GAC3C,GAAI8tC,MACA9Z,EAAU3lB,EAAGwgB,KAAKj0B,KAAK20B,OAAO9rB,EAAMo2B,QAAQzT,OAAOvP,QAAUiN,GAC7DiqB,EAAU1/B,EAAGwgB,KAAKj0B,KAAK20B,OAAOvvB,EAAM4tC,SAAW9pB,GAC/CD,EAASmQ,EAAU+Z,CAEvB,IAAI,SAAW/tC,GAAO,CACpB,GAAI8J,GAAQ,GAAIxL,MAAK0B,EAAM8J,MAAQ+Z,EACnCiqB,GAAShkC,MAAQolB,EAAOA,EAAKplB,GAASA,EAGxC,GAAI,OAAS9J,GAAO,CAClB,GAAI+J,GAAM,GAAIzL,MAAK0B,EAAM+J,IAAM8Z,EAC/BiqB,GAAS/jC,IAAMmlB,EAAOA,EAAKnlB,GAAOA,EAGpC,GAAI,SAAW/J,GAAO,CAEpB,GAAImM,GAAQpP,EAAQixC,gBAAgBvqC,EACpCqqC,GAAS3hC,MAAQA,GAASA,EAAMqlB,QAIlC,GAAIT,GAAWn2B,EAAK0E,UAAWU,EAAMuJ,KAAKqD,KAAMkhC,EAChDz/B,GAAG1F,QAAQqhC,SAASjZ,EAAU,SAAUA,GAClCA,GACF1iB,EAAG4/B,iBAAiBjuC,EAAMuJ,KAAMwnB,OAKtC92B,KAAK2wC,YAAa,EAClB3wC,KAAK40B,KAAKE,QAAQjH,KAAK,UAEvBrkB,EAAM08B,oBAUVpjC,EAAQsQ,UAAU4gC,iBAAmB,SAAS1kC,EAAMvJ,GAE9C,SAAWA,KAAOuJ,EAAKqD,KAAK9C,MAAQ9J,EAAM8J,OAC1C,OAAS9J,KAASuJ,EAAKqD,KAAK7C,IAAQ/J,EAAM+J,KAC1C,SAAW/J,IAASuJ,EAAKqD,KAAKT,OAASnM,EAAMmM,OAC/ClS,KAAKi0C,aAAa3kC,EAAMvJ,EAAMmM,QAUlCpP,EAAQsQ,UAAU6gC,aAAe,SAAS3kC,EAAMioB,GAC9C,GAAIrlB,GAAQlS,KAAKo0B,OAAOmD,EACxB,IAAIrlB,GAASA,EAAMqlB,SAAWjoB,EAAKqD,KAAKT,MAAO,CAC7C,GAAImhC,GAAW/jC,EAAK61B,MACpBkO,GAAS/8B,OAAOhH,GAChB+jC,EAAS39B,QACTxD,EAAMgB,IAAI5D,GACV4C,EAAMwD,QAENpG,EAAKqD,KAAKT,MAAQA,EAAMqlB,UAS5Bz0B,EAAQsQ,UAAU+qB,WAAa,SAAU30B,GAGvC,GAFAA,EAAMD,iBAEFvJ,KAAK4wC,YAAYgD,UAAW,CAE9B,GAAIM,MACA9/B,EAAKpU,KACLi3B,EAAUj3B,KAAK+1B,UAAUhgB,aAEzB69B,EAAY5zC,KAAK4wC,YAAYgD,SACjC5zC,MAAK4wC,YAAYgD,UAAY,KAC7BA,EAAUrrC,QAAQ,SAAUxC,GAC1B,GAAI1F,GAAK0F,EAAMuJ,KAAKjP,GAChBy2B,EAAW1iB,EAAG2hB,UAAU5gB,IAAI9U,EAAI+T,EAAG47B,aAEnC3Q,GAAU,CACV,UAAWt5B,GAAMuJ,KAAKqD,OACxB0sB,EAAWt5B,EAAM8J,OAAS9J,EAAMuJ,KAAKqD,KAAK9C,MAAM9I,UAChD+vB,EAASjnB,MAAQlP,EAAKiG,QAAQb,EAAMuJ,KAAKqD,KAAK9C,MACtConB,EAAQrkB,SAAS/L,MAAQowB,EAAQrkB,SAAS/L,KAAKgJ,OAAS,SAE9D,OAAS9J,GAAMuJ,KAAKqD,OACtB0sB,EAAUA,GAAat5B,EAAM+J,KAAO/J,EAAMuJ,KAAKqD,KAAK7C,IAAI/I,UACxD+vB,EAAShnB,IAAMnP,EAAKiG,QAAQb,EAAMuJ,KAAKqD,KAAK7C,IACpCmnB,EAAQrkB,SAAS/L,MAAQowB,EAAQrkB,SAAS/L,KAAKiJ,KAAO,SAE5D,SAAW/J,GAAMuJ,KAAKqD,OACxB0sB,EAAUA,GAAat5B,EAAMmM,OAASnM,EAAMuJ,KAAKqD,KAAKT,MACtD4kB,EAAS5kB,MAAQnM,EAAMuJ,KAAKqD,KAAKT,OAI/BmtB,GACFjrB,EAAG1F,QAAQmhC,OAAO/Y,EAAU,SAAUA,GAChCA,GAEFA,EAASG,EAAQnkB,UAAYzS,EAC7B6zC,EAAQhsC,KAAK4uB,KAIb1iB,EAAG4/B,iBAAiBjuC,EAAMuJ,KAAMvJ,GAEhCqO,EAAGu8B,YAAa,EAChBv8B,EAAGwgB,KAAKE,QAAQjH,KAAK,eAOzBqmB,EAAQxuC,QACVuxB,EAAQniB,OAAOo/B,GAGjB1qC,EAAM08B,oBASVpjC,EAAQsQ,UAAU89B,cAAgB,SAAU1nC,GAC1C,GAAKxJ,KAAK0O,QAAQ8gC,WAAlB,CAEA,GAAI2E,GAAW3qC,EAAMo2B,QAAQwU,UAAY5qC,EAAMo2B,QAAQwU,SAASD,QAC5DE,EAAW7qC,EAAMo2B,QAAQwU,UAAY5qC,EAAMo2B,QAAQwU,SAASC,QAChE,IAAIF,GAAWE,EAEb,WADAr0C,MAAKmxC,mBAAmB3nC,EAI1B,IAAI8qC,GAAet0C,KAAK62B,eAEpBvnB,EAAOxM,EAAQywC,eAAe/pC,GAC9BknC,EAAYphC,GAAQA,EAAKjP,MAC7BL,MAAK22B,aAAa+Z,EAElB,IAAI6D,GAAev0C,KAAK62B,gBAIpB0d,EAAa7uC,OAAS,GAAK4uC,EAAa5uC,OAAS,IACnD1F,KAAK40B,KAAKE,QAAQjH,KAAK,UACrB5rB,MAAOsyC,MAUbzxC,EAAQsQ,UAAUg+B,WAAa,SAAU5nC,GACvC,GAAKxJ,KAAK0O,QAAQ8gC,YACbxvC,KAAK0O,QAAQ+gC,SAASv8B,IAA3B,CAEA,GAAIkB,GAAKpU,KACLi1B,EAAOj1B,KAAK40B,KAAKj0B,KAAKs0B,MAAQ,KAC9B3lB,EAAOxM,EAAQywC,eAAe/pC,EAElC,IAAI8F,EAAM,CAIR,GAAIwnB,GAAW1iB,EAAG2hB,UAAU5gB,IAAI7F,EAAKjP,GACrCL,MAAK0O,QAAQkhC,SAAS9Y,EAAU,SAAUA,GACpCA,GACF1iB,EAAG2hB,UAAUhgB,aAAajB,OAAOgiB,SAIlC,CAEH,GAAI0d,GAAO7zC,EAAK0G,gBAAgBrH,KAAKgwB,IAAIzQ,OACrCvN,EAAIxI,EAAMo2B,QAAQzT,OAAOuS,MAAQ8V,EACjC3kC,EAAQ7P,KAAK40B,KAAKj0B,KAAK20B,OAAOtjB,GAC9ByiC,GACF5kC,MAAOolB,EAAOA,EAAKplB,GAASA,EAC5BggB,QAAS,WAIX,IAA0B,UAAtB7vB,KAAK0O,QAAQ7H,KAAkB,CACjC,GAAIiJ,GAAM9P,KAAK40B,KAAKj0B,KAAK20B,OAAOtjB,EAAIhS,KAAK+F,MAAMyM,MAAQ,EACvDiiC,GAAQ3kC,IAAMmlB,EAAOA,EAAKnlB,GAAOA,EAGnC2kC,EAAQz0C,KAAK+1B,UAAUjjB,UAAYnS,EAAKoE,YAExC,IAAImN,GAAQpP,EAAQixC,gBAAgBvqC,EAChC0I,KACFuiC,EAAQviC,MAAQA,EAAMqlB,SAIxBv3B,KAAK0O,QAAQihC,MAAM8E,EAAS,SAAUnlC,GAChCA,GACF8E,EAAG2hB,UAAUhgB,aAAa7C,IAAI5D,QAYtCxM,EAAQsQ,UAAU+9B,mBAAqB,SAAU3nC,GAC/C,GAAKxJ,KAAK0O,QAAQ8gC,WAAlB,CAEA,GAAIkB,GACAphC,EAAOxM,EAAQywC,eAAe/pC,EAElC,IAAI8F,EAAM,CAERohC,EAAY1wC,KAAK62B,cAEjB,IAAIwd,GAAW7qC,EAAMo2B,QAAQW,QAAQ,IAAM/2B,EAAMo2B,QAAQW,QAAQ,GAAG8T,WAAY,CAChF,IAAIA,EAAU,CAIZ3D,EAAUxoC,KAAKoH,EAAKjP,GACpB,IAAIq1B,GAAQ5yB,EAAQ4xC,cAAc10C,KAAK+1B,UAAU5gB,IAAIu7B,EAAW1wC,KAAKgwC,aAGrEU,KACA,KAAK,GAAIrwC,KAAML,MAAKiC,MAClB,GAAIjC,KAAKiC,MAAM4D,eAAexF,GAAK,CACjC,GAAIs0C,GAAQ30C,KAAKiC,MAAM5B,GACnBwP,EAAQ8kC,EAAMhiC,KAAK9C,MACnBC,EAA0BvJ,SAAnBouC,EAAMhiC,KAAK7C,IAAqB6kC,EAAMhiC,KAAK7C,IAAMD,CAExDA,IAAS6lB,EAAM3pB,KAAO+D,GAAO4lB,EAAM/oB,KACrC+jC,EAAUxoC,KAAKysC,EAAMt0C,SAKxB,CAEH,GAAIgI,GAAQqoC,EAAUhqC,QAAQ4I,EAAKjP,GACtB,KAATgI,EAEFqoC,EAAUxoC,KAAKoH,EAAKjP,IAIpBqwC,EAAUpoC,OAAOD,EAAO,GAI5BrI,KAAK22B,aAAa+Z,GAElB1wC,KAAK40B,KAAKE,QAAQjH,KAAK,UACrB5rB,MAAOjC,KAAK62B,oBAWlB/zB,EAAQ4xC,cAAgB,SAAS3e,GAC/B,GAAIppB,GAAM,KACNZ,EAAM,IAmBV,OAjBAgqB,GAAUxtB,QAAQ,SAAUoK,IACf,MAAP5G,GAAe4G,EAAK9C,MAAQ9D,KAC9BA,EAAM4G,EAAK9C,OAGGtJ,QAAZoM,EAAK7C,KACI,MAAPnD,GAAegG,EAAK7C,IAAMnD,KAC5BA,EAAMgG,EAAK7C,MAIF,MAAPnD,GAAegG,EAAK9C,MAAQlD,KAC9BA,EAAMgG,EAAK9C,UAMf9D,IAAKA,EACLY,IAAKA,IAUT7J,EAAQywC,eAAiB,SAAS/pC,GAEhC,IADA,GAAIG,GAASH,EAAMG,OACZA,GAAQ,CACb,GAAIA,EAAO9D,eAAe,iBACxB,MAAO8D,GAAO,gBAEhBA,GAASA,EAAOG,WAGlB,MAAO,OASThH,EAAQixC,gBAAkB,SAASvqC,GAEjC,IADA,GAAIG,GAASH,EAAMG,OACZA,GAAQ,CACb,GAAIA,EAAO9D,eAAe,kBACxB,MAAO8D,GAAO,iBAEhBA,GAASA,EAAOG,WAGlB,MAAO,OASThH,EAAQ8xC,kBAAoB,SAASprC,GAEnC,IADA,GAAIG,GAASH,EAAMG,OACZA,GAAQ,CACb,GAAIA,EAAO9D,eAAe,oBACxB,MAAO8D,GAAO,mBAEhBA,GAASA,EAAOG,WAGlB,MAAO,OAGTjK,EAAOD,QAAUkD,GAKb,SAASjD,EAAQD,EAASM,GAS9B,QAAS6C,GAAO6xB,EAAMlmB,EAASmmC,EAAMzO,GACnCpmC,KAAK40B,KAAOA,EACZ50B,KAAKs0B,gBACH3lB,SAAS,EACT43B,OAAO,EACPuO,SAAU,GACVC,YAAa,EACbvtC,MACEmhB,SAAS,EACT9E,SAAU,YAEZyD,OACEqB,SAAS,EACT9E,SAAU,aAGd7jB,KAAK60C,KAAOA,EACZ70C,KAAK0O,QAAU/N,EAAK0E,UAAUrF,KAAKs0B,gBACnCt0B,KAAKomC,iBAAmBA,EAExBpmC,KAAKwnC,eACLxnC,KAAKgwB,OACLhwB,KAAKo0B,UACLp0B,KAAK0nC,eAAiB,EACtB1nC,KAAK20B,UAEL30B,KAAKmT,WAAWzE,GAjClB,GAAI/N,GAAOT,EAAoB,GAC3BU,EAAUV,EAAoB,GAC9BqC,EAAYrC,EAAoB,GAkCpC6C,GAAOqQ,UAAY,GAAI7Q,GAEvBQ,EAAOqQ,UAAUsD,MAAQ,WACvB1W,KAAKo0B,UACLp0B,KAAK0nC,eAAiB,GAGxB3kC,EAAOqQ,UAAUy0B,SAAW,SAASnf,EAAOof,GAErC9nC,KAAKo0B,OAAOvuB,eAAe6iB,KAC9B1oB,KAAKo0B,OAAO1L,GAASof,GAEvB9nC,KAAK0nC,gBAAkB,GAGzB3kC,EAAOqQ,UAAU20B,YAAc,SAASrf,EAAOof,GAC7C9nC,KAAKo0B,OAAO1L,GAASof,GAGvB/kC,EAAOqQ,UAAU40B,YAAc,SAAStf,GAClC1oB,KAAKo0B,OAAOvuB,eAAe6iB,WACtB1oB,MAAKo0B,OAAO1L,GACnB1oB,KAAK0nC,gBAAkB,IAI3B3kC,EAAOqQ,UAAUuhB,QAAU,WACzB30B,KAAKgwB,IAAIzQ,MAAQ/N,SAASM,cAAc,OACxC9R,KAAKgwB,IAAIzQ,MAAMxX,UAAY,SAC3B/H,KAAKgwB,IAAIzQ,MAAMrS,MAAM2W,SAAW,WAChC7jB,KAAKgwB,IAAIzQ,MAAMrS,MAAMtF,IAAM,OAC3B5H,KAAKgwB,IAAIzQ,MAAMrS,MAAMi7B,QAAU,QAE/BnoC,KAAKgwB,IAAIglB,SAAWxjC,SAASM,cAAc,OAC3C9R,KAAKgwB,IAAIglB,SAASjtC,UAAY,aAC9B/H,KAAKgwB,IAAIglB,SAAS9nC,MAAM2W,SAAW,WACnC7jB,KAAKgwB,IAAIglB,SAAS9nC,MAAMtF,IAAM,MAE9B5H,KAAKmmC,IAAM30B,SAASC,gBAAgB,6BAA6B,OACjEzR,KAAKmmC,IAAIj5B,MAAM2W,SAAW,WAC1B7jB,KAAKmmC,IAAIj5B,MAAMtF,IAAM,MACrB5H,KAAKmmC,IAAIj5B,MAAMsF,MAAQxS,KAAK0O,QAAQomC,SAAW,EAAI,KACnD90C,KAAKmmC,IAAIj5B,MAAMuF,OAAS,OAExBzS,KAAKgwB,IAAIzQ,MAAM7N,YAAY1R,KAAKmmC,KAChCnmC,KAAKgwB,IAAIzQ,MAAM7N,YAAY1R,KAAKgwB,IAAIglB,WAMtCjyC,EAAOqQ,UAAU60B,KAAO,WAElBjoC,KAAKgwB,IAAIzQ,MAAMzV,YACjB9J,KAAKgwB,IAAIzQ,MAAMzV,WAAWsH,YAAYpR,KAAKgwB,IAAIzQ,QAQnDxc,EAAOqQ,UAAU80B,KAAO,WAEjBloC,KAAKgwB,IAAIzQ,MAAMzV,YAClB9J,KAAK40B,KAAK5E,IAAI7D,OAAOza,YAAY1R,KAAKgwB,IAAIzQ,QAI9Cxc,EAAOqQ,UAAUD,WAAa,SAASzE,GACrC,GAAIP,IAAU,UAAU,cAAc,QAAQ,OAAO,QACrDxN,GAAKuF,oBAAoBiI,EAAQnO,KAAK0O,QAASA,IAGjD3L,EAAOqQ,UAAUsO,OAAS,WACxB,GAAIgnB,GAAe,CACnB,KAAK,GAAInR,KAAWv3B,MAAKo0B,OACnBp0B,KAAKo0B,OAAOvuB,eAAe0xB,KACO,GAAhCv3B,KAAKo0B,OAAOmD,GAAS5O,SAAkEpiB,SAA9CvG,KAAKomC,iBAAiB3O,WAAWF,IAAuE,GAA7Cv3B,KAAKomC,iBAAiB3O,WAAWF,IACvImR,IAKN,IAAuC,GAAnC1oC,KAAK0O,QAAQ1O,KAAK60C,MAAMlsB,SAA2C,GAAvB3oB,KAAK0nC,gBAA+C,GAAxB1nC,KAAK0O,QAAQC,SAAoC,GAAhB+5B,EAC3G1oC,KAAKioC,WAEF,CAqBH,GApBAjoC,KAAKkoC,OACmC,YAApCloC,KAAK0O,QAAQ1O,KAAK60C,MAAMhxB,UAA8D,eAApC7jB,KAAK0O,QAAQ1O,KAAK60C,MAAMhxB,UAC5E7jB,KAAKgwB,IAAIzQ,MAAMrS,MAAM1F,KAAO,MAC5BxH,KAAKgwB,IAAIzQ,MAAMrS,MAAMqb,UAAY,OACjCvoB,KAAKgwB,IAAIglB,SAAS9nC,MAAMqb,UAAY,OACpCvoB,KAAKgwB,IAAIglB,SAAS9nC,MAAM1F,KAAQxH,KAAK0O,QAAQomC,SAAW,GAAM,KAC9D90C,KAAKgwB,IAAIglB,SAAS9nC,MAAMoa,MAAQ,GAChCtnB,KAAKmmC,IAAIj5B,MAAM1F,KAAO,MACtBxH,KAAKmmC,IAAIj5B,MAAMoa,MAAQ,KAGvBtnB,KAAKgwB,IAAIzQ,MAAMrS,MAAMoa,MAAQ,MAC7BtnB,KAAKgwB,IAAIzQ,MAAMrS,MAAMqb,UAAY,QACjCvoB,KAAKgwB,IAAIglB,SAAS9nC,MAAMqb,UAAY,QACpCvoB,KAAKgwB,IAAIglB,SAAS9nC,MAAMoa,MAAStnB,KAAK0O,QAAQomC,SAAW,GAAM,KAC/D90C,KAAKgwB,IAAIglB,SAAS9nC,MAAM1F,KAAO,GAC/BxH,KAAKmmC,IAAIj5B,MAAMoa,MAAQ,MACvBtnB,KAAKmmC,IAAIj5B,MAAM1F,KAAO,IAGgB,YAApCxH,KAAK0O,QAAQ1O,KAAK60C,MAAMhxB,UAA8D,aAApC7jB,KAAK0O,QAAQ1O,KAAK60C,MAAMhxB,SAC5E7jB,KAAKgwB,IAAIzQ,MAAMrS,MAAMtF,IAAM,EAAI3D,OAAOjE,KAAK40B,KAAK5E,IAAI7D,OAAOjf,MAAMtF,IAAI6C,QAAQ,KAAK,KAAO,KACzFzK,KAAKgwB,IAAIzQ,MAAMrS,MAAMqW,OAAS,OAE3B,CACH,GAAI0xB,GAAmBj1C,KAAK40B,KAAKC,SAAS1I,OAAO1Z,OAASzS,KAAK40B,KAAKC,SAASiD,gBAAgBrlB,MAC7FzS,MAAKgwB,IAAIzQ,MAAMrS,MAAMqW,OAAS,EAAI0xB,EAAmBhxC,OAAOjE,KAAK40B,KAAK5E,IAAI7D,OAAOjf,MAAMtF,IAAI6C,QAAQ,KAAK,KAAO,KAC/GzK,KAAKgwB,IAAIzQ,MAAMrS,MAAMtF,IAAM,GAGH,GAAtB5H,KAAK0O,QAAQ63B,OACfvmC,KAAKgwB,IAAIzQ,MAAMrS,MAAMsF,MAAQxS,KAAKgwB,IAAIglB,SAAS3kB,YAAc,GAAK,KAClErwB,KAAKgwB,IAAIglB,SAAS9nC,MAAMoa,MAAQ,GAChCtnB,KAAKgwB,IAAIglB,SAAS9nC,MAAM1F,KAAO,GAC/BxH,KAAKmmC,IAAIj5B,MAAMsF,MAAQ,QAGvBxS,KAAKgwB,IAAIzQ,MAAMrS,MAAMsF,MAAQxS,KAAK0O,QAAQomC,SAAW,GAAK90C,KAAKgwB,IAAIglB,SAAS3kB,YAAc,GAAK,KAC/FrwB,KAAKk1C,kBAGP,IAAIrlB,GAAU,EACd,KAAK,GAAI0H,KAAWv3B,MAAKo0B,OACnBp0B,KAAKo0B,OAAOvuB,eAAe0xB,KACO,GAAhCv3B,KAAKo0B,OAAOmD,GAAS5O,SAAkEpiB,SAA9CvG,KAAKomC,iBAAiB3O,WAAWF,IAAuE,GAA7Cv3B,KAAKomC,iBAAiB3O,WAAWF,KACvI1H,GAAW7vB,KAAKo0B,OAAOmD,GAAS1H,QAAU,UAIhD7vB,MAAKgwB,IAAIglB,SAAS9wB,UAAY2L,EAC9B7vB,KAAKgwB,IAAIglB,SAAS9nC,MAAMsjB,WAAe,IAAOxwB,KAAK0O,QAAQomC,SAAY90C,KAAK0O,QAAQqmC,YAAe,OAIvGhyC,EAAOqQ,UAAU8hC,gBAAkB,WACjC,GAAIl1C,KAAKgwB,IAAIzQ,MAAMzV,WAAY,CAC7BlJ,EAAQkQ,gBAAgB9Q,KAAKwnC,YAC7B,IAAIvjB,GAAUxc,OAAO0tC,iBAAiBn1C,KAAKgwB,IAAIzQ,OAAO61B,WAClD9M,EAAarkC,OAAOggB,EAAQxZ,QAAQ,KAAK,KACzCuH,EAAIs2B,EACJ1B,EAAY5mC,KAAK0O,QAAQomC,SACzBzM,EAAa,IAAOroC,KAAK0O,QAAQomC,SACjC7iC,EAAIq2B,EAAa,GAAMD,EAAa,CAExCroC,MAAKmmC,IAAIj5B,MAAMsF,MAAQo0B,EAAY,EAAI0B,EAAa,IAEpD,KAAK,GAAI/Q,KAAWv3B,MAAKo0B,OACnBp0B,KAAKo0B,OAAOvuB,eAAe0xB,KACO,GAAhCv3B,KAAKo0B,OAAOmD,GAAS5O,SAAkEpiB,SAA9CvG,KAAKomC,iBAAiB3O,WAAWF,IAAuE,GAA7Cv3B,KAAKomC,iBAAiB3O,WAAWF,KACvIv3B,KAAKo0B,OAAOmD,GAASgR,SAASv2B,EAAGC,EAAGjS,KAAKwnC,YAAaxnC,KAAKmmC,IAAKS,EAAWyB,GAC3Ep2B,GAAKo2B,EAAaroC,KAAK0O,QAAQqmC,aAKrCn0C,GAAQuQ,gBAAgBnR,KAAKwnC,eAIjC3nC,EAAOD,QAAUmD,GAKb,SAASlD,EAAQD,EAASM,GAqB9B,QAAS8C,GAAU4xB,EAAMlmB,GACvB1O,KAAKK,GAAKM,EAAKoE,aACf/E,KAAK40B,KAAOA,EAEZ50B,KAAKs0B,gBACH6X,iBAAkB,OAClBkJ,aAAc,UACdl/B,MAAM,EACNm/B,UAAU,EACVC,YAAa,QACbzJ,QACEn9B,SAAS,EACT6lB,YAAa,UAEftnB,MAAO,OACPsoC,UACEhjC,MAAO,GACPijC,cAAe,UACfnG,MAAO,UAEThE,YACE38B,SAAS,EACT48B,gBAAiB,cACjBC,MAAO,IAETp5B,YACEzD,SAAS,EACT2D,KAAM,EACNpF,MAAO,UAETwoC,UACErP,iBAAiB,EACjBC,iBAAiB,EACjBC,OAAO,EACP/zB,MAAO,OACPmW,SAAS,EACT6S,YAAY,EACZD,aACE/zB,MAAOuE,IAAIxF,OAAWoG,IAAIpG,QAC1B+gB,OAAQvb,IAAIxF,OAAWoG,IAAIpG,UAkB/BovC,QACEhnC,SAAS,EACT43B,OAAO,EACP/+B,MACEmhB,SAAS,EACT9E,SAAU,YAEZyD,OACEqB,SAAS,EACT9E,SAAU,cAGduQ,QACEqD,gBAKJz3B,KAAK0O,QAAU/N,EAAK0E,UAAWrF,KAAKs0B,gBACpCt0B,KAAKgwB,OACLhwB,KAAK+F,SACL/F,KAAK8D,OAAS,KACd9D,KAAKo0B,UACLp0B,KAAK41C,oBAAqB,EAC1B51C,KAAK61C,iBAAkB,EACvB71C,KAAK81C,yBAA0B,CAE/B,IAAI1hC,GAAKpU,IACTA,MAAK+1B,UAAY,KACjB/1B,KAAKg2B,WAAa,KAGlBh2B,KAAKiwC,eACH/8B,IAAO,SAAU1J,EAAOuK,GACtBK,EAAG87B,OAAOn8B,EAAO9R,QAEnB6S,OAAU,SAAUtL,EAAOuK,GACzBK,EAAG+7B,UAAUp8B,EAAO9R,QAEtBqU,OAAU,SAAU9M,EAAOuK,GACzBK,EAAGg8B,UAAUr8B,EAAO9R,SAKxBjC,KAAKqwC,gBACHn9B,IAAO,SAAU1J,EAAOuK,GACtBK,EAAGk8B,aAAav8B,EAAO9R,QAEzB6S,OAAU,SAAUtL,EAAOuK,GACzBK,EAAGm8B,gBAAgBx8B,EAAO9R,QAE5BqU,OAAU,SAAU9M,EAAOuK,GACzBK,EAAGo8B,gBAAgBz8B,EAAO9R,SAI9BjC,KAAKiC,SACLjC,KAAK0wC,aACL1wC,KAAK+1C,UAAY/1C,KAAK40B,KAAKc,MAAM7lB,MACjC7P,KAAK4wC,eAEL5wC,KAAKwnC,eACLxnC,KAAKmT,WAAWzE,GAChB1O,KAAK+qC,0BAA4B,GACjC/qC,KAAKg2C,QAAU,EACfh2C,KAAK40B,KAAKE,QAAQthB,GAAG,eAAgB,WACnCY,EAAG2hC,UAAY3hC,EAAGwgB,KAAKc,MAAM7lB,MAC7BuE,EAAG+xB,IAAIj5B,MAAM1F,KAAO7G,EAAKoJ,OAAOK,QAAQgK,EAAGrO,MAAMyM,OACjD4B,EAAGsN,OAAOnhB,KAAK6T,GAAG,KAIpBpU,KAAK20B,UACL30B,KAAKusC,WAAapG,IAAKnmC,KAAKmmC,IAAKqB,YAAaxnC,KAAKwnC,YAAa94B,QAAS1O,KAAK0O,QAAS0lB,OAAQp0B,KAAKo0B,QACpGp0B,KAAK40B,KAAKE,QAAQjH,KAAK,UAvJzB,GAAIltB,GAAOT,EAAoB,GAC3BU,EAAUV,EAAoB,GAC9BW,EAAUX,EAAoB,GAC9BY,EAAWZ,EAAoB,GAC/BqC,EAAYrC,EAAoB,IAChCwC,EAAWxC,EAAoB,IAC/ByC,EAAazC,EAAoB,IACjC6C,EAAS7C,EAAoB,IAC7B+1C,EAAoB/1C,EAAoB,IAExC2wC,EAAY,eAiJhB7tC,GAAUoQ,UAAY,GAAI7Q,GAK1BS,EAAUoQ,UAAUuhB,QAAU,WAC5B,GAAIpV,GAAQ/N,SAASM,cAAc,MACnCyN,GAAMxX,UAAY,YAClB/H,KAAKgwB,IAAIzQ,MAAQA,EAGjBvf,KAAKmmC,IAAM30B,SAASC,gBAAgB,6BAA6B,OACjEzR,KAAKmmC,IAAIj5B,MAAM2W,SAAW,WAC1B7jB,KAAKmmC,IAAIj5B,MAAMuF,QAAU,GAAKzS,KAAK0O,QAAQ6mC,aAAa9qC,QAAQ,KAAK,IAAM,KAC3EzK,KAAKmmC,IAAIj5B,MAAMi7B,QAAU,QACzB5oB,EAAM7N,YAAY1R,KAAKmmC,KAGvBnmC,KAAK0O,QAAQgnC,SAASlhB,YAAc,OACpCx0B,KAAKk2C,UAAY,GAAIxzC,GAAS1C,KAAK40B,KAAM50B,KAAK0O,QAAQgnC,SAAU11C,KAAKmmC,IAAKnmC,KAAK0O,QAAQ0lB,QAEvFp0B,KAAK0O,QAAQgnC,SAASlhB,YAAc,QACpCx0B,KAAKm2C,WAAa,GAAIzzC,GAAS1C,KAAK40B,KAAM50B,KAAK0O,QAAQgnC,SAAU11C,KAAKmmC,IAAKnmC,KAAK0O,QAAQ0lB,cACjFp0B,MAAK0O,QAAQgnC,SAASlhB,YAG7Bx0B,KAAKo2C,WAAa,GAAIrzC,GAAO/C,KAAK40B,KAAM50B,KAAK0O,QAAQinC,OAAQ,OAAQ31C,KAAK0O,QAAQ0lB,QAClFp0B,KAAKq2C,YAAc,GAAItzC,GAAO/C,KAAK40B,KAAM50B,KAAK0O,QAAQinC,OAAQ,QAAS31C,KAAK0O,QAAQ0lB,QAEpFp0B,KAAKkoC,QAOPllC,EAAUoQ,UAAUD,WAAa,SAASzE,GACxC,GAAIA,EAAS,CACX,GAAIP,IAAU,WAAW,eAAe,SAAS,cAAc,mBAAmB,QAAQ,WAAW,WAAW,OAAO,SAC3F5H,UAAxBmI,EAAQ6mC,aAAgDhvC,SAAnBmI,EAAQ+D,QAAsElM,SAA9CvG,KAAK40B,KAAKC,SAASiD,gBAAgBrlB,QAC1GzS,KAAK61C,iBAAkB,EACvB71C,KAAK81C,yBAA0B,GAEsBvvC,SAA9CvG,KAAK40B,KAAKC,SAASiD,gBAAgBrlB,QAAgDlM,SAAxBmI,EAAQ6mC,aACtE1qC,UAAU6D,EAAQ6mC,YAAc,IAAI9qC,QAAQ,KAAK,KAAOzK,KAAK40B,KAAKC,SAASiD,gBAAgBrlB,SAC7FzS,KAAK61C,iBAAkB,GAG3Bl1C,EAAKuF,oBAAoBiI,EAAQnO,KAAK0O,QAASA,GAC/C/N,EAAK6N,aAAaxO,KAAK0O,QAASA,EAAQ,cACxC/N,EAAK6N,aAAaxO,KAAK0O,QAASA,EAAQ,cACxC/N,EAAK6N,aAAaxO,KAAK0O,QAASA,EAAQ,UACxC/N,EAAK6N,aAAaxO,KAAK0O,QAASA,EAAQ,UAEpCA,EAAQ48B,YACuB,gBAAtB58B,GAAQ48B,YACb58B,EAAQ48B,WAAWC,kBACqB,WAAtC78B,EAAQ48B,WAAWC,gBACrBvrC,KAAK0O,QAAQ48B,WAAWE,MAAQ,EAEa,WAAtC98B,EAAQ48B,WAAWC,gBAC1BvrC,KAAK0O,QAAQ48B,WAAWE,MAAQ,GAGhCxrC,KAAK0O,QAAQ48B,WAAWC,gBAAkB,cAC1CvrC,KAAK0O,QAAQ48B,WAAWE,MAAQ,KAMpCxrC,KAAKk2C,WACkB3vC,SAArBmI,EAAQgnC,WACV11C,KAAKk2C,UAAU/iC,WAAWnT,KAAK0O,QAAQgnC,UACvC11C,KAAKm2C,WAAWhjC,WAAWnT,KAAK0O,QAAQgnC,WAIxC11C,KAAKo2C,YACgB7vC,SAAnBmI,EAAQinC,SACV31C,KAAKo2C,WAAWjjC,WAAWnT,KAAK0O,QAAQinC,QACxC31C,KAAKq2C,YAAYljC,WAAWnT,KAAK0O,QAAQinC,SAIzC31C,KAAKo0B,OAAOvuB,eAAegrC,IAC7B7wC,KAAKo0B,OAAOyc,GAAW19B,WAAWzE,GAKlC1O,KAAKgwB,IAAIzQ,OACXvf,KAAK0hB,QAAO,IAOhB1e,EAAUoQ,UAAU60B,KAAO,WAErBjoC,KAAKgwB,IAAIzQ,MAAMzV,YACjB9J,KAAKgwB,IAAIzQ,MAAMzV,WAAWsH,YAAYpR,KAAKgwB,IAAIzQ,QASnDvc,EAAUoQ,UAAU80B,KAAO,WAEpBloC,KAAKgwB,IAAIzQ,MAAMzV,YAClB9J,KAAK40B,KAAK5E,IAAI7D,OAAOza,YAAY1R,KAAKgwB,IAAIzQ,QAS9Cvc,EAAUoQ,UAAU8iB,SAAW,SAASj0B,GACtC,GACEmT,GADEhB,EAAKpU,KAEP6yC,EAAe7yC,KAAK+1B,SAGtB,IAAK9zB,EAGA,CAAA,KAAIA,YAAiBpB,IAAWoB,YAAiBnB,IAIpD,KAAM,IAAIsF,WAAU,kDAHpBpG,MAAK+1B,UAAY9zB,MAHjBjC,MAAK+1B,UAAY,IAoBnB,IAXI8c,IAEFlyC,EAAK4H,QAAQvI,KAAKiwC,cAAe,SAAUznC,EAAUgB,GACnDqpC,EAAal/B,IAAInK,EAAOhB,KAI1B4M,EAAMy9B,EAAa/8B,SACnB9V,KAAKowC,UAAUh7B,IAGbpV,KAAK+1B,UAAW,CAElB,GAAI11B,GAAKL,KAAKK,EACdM,GAAK4H,QAAQvI,KAAKiwC,cAAe,SAAUznC,EAAUgB,GACnD4K,EAAG2hB,UAAUviB,GAAGhK,EAAOhB,EAAUnI,KAInC+U,EAAMpV,KAAK+1B,UAAUjgB,SACrB9V,KAAKkwC,OAAO96B,GAEdpV,KAAKgxC,mBAELhxC,KAAK0hB,QAAO,IAQd1e,EAAUoQ,UAAU6iB,UAAY,SAAS7B,GACvC,GACIhf,GADAhB,EAAKpU,IAgBT,IAZIA,KAAKg2B,aACPr1B,EAAK4H,QAAQvI,KAAKqwC,eAAgB,SAAU7nC,EAAUgB,GACpD4K,EAAG4hB,WAAWniB,YAAYrK,EAAOhB,KAInC4M,EAAMpV,KAAKg2B,WAAWlgB,SACtB9V,KAAKg2B,WAAa,KAClBh2B,KAAKwwC,gBAAgBp7B,IAIlBgf,EAGA,CAAA,KAAIA,YAAkBvzB,IAAWuzB,YAAkBtzB,IAItD,KAAM,IAAIsF,WAAU,kDAHpBpG,MAAKg2B,WAAa5B,MAHlBp0B,MAAKg2B,WAAa,IASpB,IAAIh2B,KAAKg2B,WAAY,CAEnB,GAAI31B,GAAKL,KAAKK,EACdM,GAAK4H,QAAQvI,KAAKqwC,eAAgB,SAAU7nC,EAAUgB,GACpD4K,EAAG4hB,WAAWxiB,GAAGhK,EAAOhB,EAAUnI,KAIpC+U,EAAMpV,KAAKg2B,WAAWlgB,SACtB9V,KAAKswC,aAAal7B,GAEpBpV,KAAKmwC,aASPntC,EAAUoQ,UAAU+8B,UAAY,WAC9BnwC,KAAKgxC,mBACLhxC,KAAKs2C,sBAELt2C,KAAK0hB,QAAO,IAEd1e,EAAUoQ,UAAU88B,OAAkB,SAAU96B,GAAMpV,KAAKmwC,UAAU/6B,IACrEpS,EAAUoQ,UAAUg9B,UAAkB,SAAUh7B,GAAMpV,KAAKmwC,UAAU/6B,IACrEpS,EAAUoQ,UAAUm9B,gBAAmB,SAAUE,GAC/C,IAAK,GAAIlrC,GAAI,EAAGA,EAAIkrC,EAAS/qC,OAAQH,IAAK,CACxC,GAAI2M,GAAQlS,KAAKg2B,WAAW7gB,IAAIs7B,EAASlrC,GACzCvF,MAAKu2C,aAAarkC,EAAOu+B,EAASlrC,IAIpCvF,KAAK0hB,QAAO,IAEd1e,EAAUoQ,UAAUk9B,aAAe,SAAUG,GAAWzwC,KAAKuwC,gBAAgBE,IAQ7EztC,EAAUoQ,UAAUo9B,gBAAkB,SAAUC,GAC9C,IAAK,GAAIlrC,GAAI,EAAGA,EAAIkrC,EAAS/qC,OAAQH,IAC/BvF,KAAKo0B,OAAOvuB,eAAe4qC,EAASlrC,MACmB,SAArDvF,KAAKo0B,OAAOqc,EAASlrC,IAAImJ,QAAQy9B,kBACnCnsC,KAAKm2C,WAAWnO,YAAYyI,EAASlrC,IACrCvF,KAAKq2C,YAAYrO,YAAYyI,EAASlrC,IACtCvF,KAAKq2C,YAAY30B,WAGjB1hB,KAAKk2C,UAAUlO,YAAYyI,EAASlrC,IACpCvF,KAAKo2C,WAAWpO,YAAYyI,EAASlrC,IACrCvF,KAAKo2C,WAAW10B,gBAEX1hB,MAAKo0B,OAAOqc,EAASlrC,IAGhCvF,MAAKgxC,mBAELhxC,KAAK0hB,QAAO,IAWd1e,EAAUoQ,UAAUmjC,aAAe,SAAUrkC,EAAOqlB,GAC7Cv3B,KAAKo0B,OAAOvuB,eAAe0xB,IAY9Bv3B,KAAKo0B,OAAOmD,GAASziB,OAAO5C,GACyB,SAAjDlS,KAAKo0B,OAAOmD,GAAS7oB,QAAQy9B,kBAC/BnsC,KAAKm2C,WAAWpO,YAAYxQ,EAASv3B,KAAKo0B,OAAOmD,IACjDv3B,KAAKq2C,YAAYtO,YAAYxQ,EAASv3B,KAAKo0B,OAAOmD,MAGlDv3B,KAAKk2C,UAAUnO,YAAYxQ,EAASv3B,KAAKo0B,OAAOmD,IAChDv3B,KAAKo2C,WAAWrO,YAAYxQ,EAASv3B,KAAKo0B,OAAOmD,OAlBnDv3B,KAAKo0B,OAAOmD,GAAW,GAAI50B,GAAWuP,EAAOqlB,EAASv3B,KAAK0O,QAAS1O,KAAK+qC,0BACpB,SAAjD/qC,KAAKo0B,OAAOmD,GAAS7oB,QAAQy9B,kBAC/BnsC,KAAKm2C,WAAWtO,SAAStQ,EAASv3B,KAAKo0B,OAAOmD,IAC9Cv3B,KAAKq2C,YAAYxO,SAAStQ,EAASv3B,KAAKo0B,OAAOmD,MAG/Cv3B,KAAKk2C,UAAUrO,SAAStQ,EAASv3B,KAAKo0B,OAAOmD,IAC7Cv3B,KAAKo2C,WAAWvO,SAAStQ,EAASv3B,KAAKo0B,OAAOmD,MAclDv3B,KAAKo2C,WAAW10B,SAChB1hB,KAAKq2C,YAAY30B,UASnB1e,EAAUoQ,UAAUkjC,oBAAsB,WACxC,GAAsB,MAAlBt2C,KAAK+1B,UAAmB,CAC1B,GACIwB,GADAif,IAEJ,KAAKjf,IAAWv3B,MAAKo0B,OACfp0B,KAAKo0B,OAAOvuB,eAAe0xB,KAC7Bif,EAAcjf,MAGlB,KAAK,GAAI/hB,KAAUxV,MAAK+1B,UAAUljB,MAChC,GAAI7S,KAAK+1B,UAAUljB,MAAMhN,eAAe2P,GAAS,CAC/C,GAAIlG,GAAOtP,KAAK+1B,UAAUljB,MAAM2C,EAChC,IAAkCjP,SAA9BiwC,EAAclnC,EAAK4C,OACrB,KAAM,IAAItO,OAAM,4IAElB0L,GAAK0C,EAAIrR,EAAKiG,QAAQ0I,EAAK0C,EAAE,QAC7BwkC,EAAclnC,EAAK4C,OAAOhK,KAAKoH,GAGnC,IAAKioB,IAAWv3B,MAAKo0B,OACfp0B,KAAKo0B,OAAOvuB,eAAe0xB,IAC7Bv3B,KAAKo0B,OAAOmD,GAASrB,SAASsgB,EAAcjf,MAYpDv0B,EAAUoQ,UAAU49B,iBAAmB,WACrC,GAAIhxC,KAAK+1B,WAA+B,MAAlB/1B,KAAK+1B,UAAmB,CAC5C,GAAI0gB,GAAmB,CACvB,KAAK,GAAIjhC,KAAUxV,MAAK+1B,UAAUljB,MAChC,GAAI7S,KAAK+1B,UAAUljB,MAAMhN,eAAe2P,GAAS,CAC/C,GAAIlG,GAAOtP,KAAK+1B,UAAUljB,MAAM2C,EACpBjP,SAAR+I,IACEA,EAAKzJ,eAAe,SACHU,SAAf+I,EAAK4C,QACP5C,EAAK4C,MAAQ2+B,GAIfvhC,EAAK4C,MAAQ2+B,EAEf4F,EAAmBnnC,EAAK4C,OAAS2+B,EAAY4F,EAAmB,EAAIA,GAK1E,GAAwB,GAApBA,QACKz2C,MAAKo0B,OAAOyc,GACnB7wC,KAAKo2C,WAAWpO,YAAY6I,GAC5B7wC,KAAKq2C,YAAYrO,YAAY6I,GAC7B7wC,KAAKk2C,UAAUlO,YAAY6I,GAC3B7wC,KAAKm2C,WAAWnO,YAAY6I,OAEzB,CACH,GAAI3+B,IAAS7R,GAAIwwC,EAAWhhB,QAAS7vB,KAAK0O,QAAQ2mC,aAClDr1C,MAAKu2C,aAAarkC,EAAO2+B,eAIpB7wC,MAAKo0B,OAAOyc,GACnB7wC,KAAKo2C,WAAWpO,YAAY6I,GAC5B7wC,KAAKq2C,YAAYrO,YAAY6I,GAC7B7wC,KAAKk2C,UAAUlO,YAAY6I,GAC3B7wC,KAAKm2C,WAAWnO,YAAY6I,EAG9B7wC,MAAKo2C,WAAW10B,SAChB1hB,KAAKq2C,YAAY30B,UAQnB1e,EAAUoQ,UAAUsO,OAAS,SAASg1B,GACpC,GAAI5R,IAAU,CAGd9kC,MAAK+F,MAAMyM,MAAQxS,KAAKgwB,IAAIzQ,MAAM8Q,YAClCrwB,KAAK+F,MAAM0M,OAASzS,KAAK40B,KAAKC,SAASiD,gBAAgBrlB,OAGhClM,SAAnBvG,KAAKiyC,WAA2BjyC,KAAK+F,MAAMyM,QAC7CkkC,GAAmB,GAIrB5R,EAAU9kC,KAAK6kC,cAAgBC,CAG/B,IAAIgN,GAAkB9xC,KAAK40B,KAAKc,MAAM5lB,IAAM9P,KAAK40B,KAAKc,MAAM7lB,MACxDkiC,EAAUD,GAAmB9xC,KAAKgyC,mBA6BtC,IA5BAhyC,KAAKgyC,oBAAsBF,EAKZ,GAAXhN,IACF9kC,KAAKmmC,IAAIj5B,MAAMsF,MAAQ7R,EAAKoJ,OAAOK,OAAO,EAAEpK,KAAK+F,MAAMyM,OACvDxS,KAAKmmC,IAAIj5B,MAAM1F,KAAO7G,EAAKoJ,OAAOK,QAAQpK,KAAK+F,MAAMyM,QAGN,KAA1CxS,KAAK0O,QAAQ+D,OAAS,IAAI/L,QAAQ,MAA8C,GAAhC1G,KAAK81C,2BACxD91C,KAAK61C,iBAAkB,IAKC,GAAxB71C,KAAK61C,iBACH71C,KAAK0O,QAAQ6mC,aAAev1C,KAAK40B,KAAKC,SAASiD,gBAAgBrlB,OAAS,OAC1EzS,KAAK0O,QAAQ6mC,YAAcv1C,KAAK40B,KAAKC,SAASiD,gBAAgBrlB,OAAS,KACvEzS,KAAKmmC,IAAIj5B,MAAMuF,OAASzS,KAAK40B,KAAKC,SAASiD,gBAAgBrlB,OAAS,MAEtEzS,KAAK61C,iBAAkB,GAGvB71C,KAAKmmC,IAAIj5B,MAAMuF,QAAU,GAAKzS,KAAK0O,QAAQ6mC,aAAa9qC,QAAQ,KAAK,IAAM,KAI9D,GAAXq6B,GAA6B,GAAViN,GAA6C,GAA3B/xC,KAAK41C,oBAAkD,GAApBc,EAC1E5R,EAAU9kC,KAAK22C,gBAAkB7R,MAIjC,IAAsB,GAAlB9kC,KAAK+1C,UAAgB,CACvB,GAAInsB,GAAS5pB,KAAK40B,KAAKc,MAAM7lB,MAAQ7P,KAAK+1C,UACtCrgB,EAAQ11B,KAAK40B,KAAKc,MAAM5lB,IAAM9P,KAAK40B,KAAKc,MAAM7lB,KAClD,IAAwB,GAApB7P,KAAK+F,MAAMyM,MAAY,CACzB,GAAIokC,GAAmB52C,KAAK+F,MAAMyM,MAAMkjB,EACpC7L,EAAUD,EAASgtB,CACvB52C,MAAKmmC,IAAIj5B,MAAM1F,MAASxH,KAAK+F,MAAMyM,MAAQqX,EAAW,MAO5D,MAFA7pB,MAAKo2C,WAAW10B,SAChB1hB,KAAKq2C,YAAY30B,SACVojB,GAQT9hC,EAAUoQ,UAAUujC,aAAe,WAGjC,GADA/1C,EAAQkQ,gBAAgB9Q,KAAKwnC,aACL,GAApBxnC,KAAK+F,MAAMyM,OAAgC,MAAlBxS,KAAK+1B,UAAmB,CACnD,GAAI7jB,GAAO3M,EACPsxC,KACAC,KACAC,KACAC,GAAe,EAGfvG,IACJ,KAAK,GAAIlZ,KAAWv3B,MAAKo0B,OACnBp0B,KAAKo0B,OAAOvuB,eAAe0xB,KAC7BrlB,EAAQlS,KAAKo0B,OAAOmD,GACC,GAAjBrlB,EAAMyW,SAAgEpiB,SAA5CvG,KAAK0O,QAAQ0lB,OAAOqD,WAAWF,IAAqE,GAA3Cv3B,KAAK0O,QAAQ0lB,OAAOqD,WAAWF,IACpHkZ,EAASvoC,KAAKqvB,GAIpB,IAAIkZ,EAAS/qC,OAAS,EAAG,CAEvB,GAAIuxC,GAAUj3C,KAAK40B,KAAKj0B,KAAK60B,cAAcx1B,KAAK40B,KAAKC,SAASn1B,KAAK8S,OAC/D0kC,EAAUl3C,KAAK40B,KAAKj0B,KAAK60B,aAAa,EAAIx1B,KAAK40B,KAAKC,SAASn1B,KAAK8S,OAClEwjB,IAQJ,KANAh2B,KAAKm3C,iBAAiB1G,EAAUza,EAAYihB,EAASC,GAGrDl3C,KAAKo3C,eAAe3G,EAAUza,GAGzBzwB,EAAI,EAAGA,EAAIkrC,EAAS/qC,OAAQH,IAC/BsxC,EAAsBpG,EAASlrC,IAAMvF,KAAKq3C,qBAAqBrhB,EAAWya,EAASlrC,IAIrFvF,MAAKs3C,YAAY7G,EAAUoG,EAAuBE,GAIlDC,EAAeh3C,KAAKu3C,aAAa9G,EAAUsG,EAC3C,IAAIS,GAAa,CACjB,IAAoB,GAAhBR,GAAwBh3C,KAAKg2C,QAAUwB,EAKzC,MAJA52C,GAAQuQ,gBAAgBnR,KAAKwnC,aAC7BxnC,KAAK41C,oBAAqB,EAC1B51C,KAAKg2C,UACLh2C,KAAK40B,KAAKE,QAAQjH,KAAK,WAChB,CAUP,KAPI7tB,KAAKg2C,QAAUwB,GACjB5e,QAAQhF,IAAI,6EAEd5zB,KAAKg2C,QAAU,EACfh2C,KAAK41C,oBAAqB,EAGrBrwC,EAAI,EAAGA,EAAIkrC,EAAS/qC,OAAQH,IAC/B2M,EAAQlS,KAAKo0B,OAAOqc,EAASlrC,IAC7BuxC,EAAmBrG,EAASlrC,IAAMvF,KAAKy3C,qBAAqBzhB,EAAWya,EAASlrC,IAAK2M,EAIvF,KAAK3M,EAAI,EAAGA,EAAIkrC,EAAS/qC,OAAQH,IAC/B2M,EAAQlS,KAAKo0B,OAAOqc,EAASlrC,IACF,OAAvB2M,EAAMxD,QAAQxB,OAChBgF,EAAMo6B,KAAKwK,EAAmBrG,EAASlrC,IAAK2M,EAAOlS,KAAKusC,UAG5D0J;EAAkB3J,KAAKmE,EAAUqG,EAAoB92C,KAAKusC,YAOhE,MADA3rC,GAAQuQ,gBAAgBnR,KAAKwnC,cACtB,GAiBTxkC,EAAUoQ,UAAU+jC,iBAAmB,SAAU1G,EAAUza,EAAYihB,EAASC,GAC9E,GAAIhlC,GAAO3M,EAAGsmB,EAAGvc,CACjB,IAAImhC,EAAS/qC,OAAS,EACpB,IAAKH,EAAI,EAAGA,EAAIkrC,EAAS/qC,OAAQH,IAAK,CACpC2M,EAAQlS,KAAKo0B,OAAOqc,EAASlrC,IAC7BywB,EAAWya,EAASlrC,MACpB,IAAImyC,GAAgB1hB,EAAWya,EAASlrC,GAExC,IAA0B,GAAtB2M,EAAMxD,QAAQyH,KAAc,CAC9B,GAAIwhC,GAAQ1yC,KAAK0H,IAAI,EAAGhM,EAAK6O,kBAAkB0C,EAAM6jB,UAAWkhB,EAAS,IAAK,UAC9E,KAAKprB,EAAI8rB,EAAO9rB,EAAI3Z,EAAM6jB,UAAUrwB,OAAQmmB,IAE1C,GADAvc,EAAO4C,EAAM6jB,UAAUlK,GACVtlB,SAAT+I,EAAoB,CACtB,GAAIA,EAAK0C,EAAIklC,EAAS,CACpBQ,EAAcxvC,KAAKoH,EACnB,OAGAooC,EAAcxvC,KAAKoH,QAMzB,KAAKuc,EAAI,EAAGA,EAAI3Z,EAAM6jB,UAAUrwB,OAAQmmB,IACtCvc,EAAO4C,EAAM6jB,UAAUlK,GACVtlB,SAAT+I,GACEA,EAAK0C,EAAIilC,GAAW3nC,EAAK0C,EAAIklC,GAC/BQ,EAAcxvC,KAAKoH,KAgBjCtM,EAAUoQ,UAAUgkC,eAAiB,SAAU3G,EAAUza,GACvD,GAAI9jB,EACJ,IAAIu+B,EAAS/qC,OAAS,EACpB,IAAK,GAAIH,GAAI,EAAGA,EAAIkrC,EAAS/qC,OAAQH,IAEnC,GADA2M,EAAQlS,KAAKo0B,OAAOqc,EAASlrC,IACC,GAA1B2M,EAAMxD,QAAQ4mC,SAAkB,CAClC,GAAIoC,GAAgB1hB,EAAWya,EAASlrC,GACxC,IAAImyC,EAAchyC,OAAS,EAAG,CAC5B,GAAIkyC,GAAY,EACZC,EAAiBH,EAAchyC,OAI/BoyC,EAAY93C,KAAK40B,KAAKj0B,KAAKy0B,eAAesiB,EAAcA,EAAchyC,OAAS,GAAGsM,GAAKhS,KAAK40B,KAAKj0B,KAAKy0B,eAAesiB,EAAc,GAAG1lC,GACtI+lC,EAAiBF,EAAiBC,CACtCF,GAAY3yC,KAAK8G,IAAI9G,KAAK+yC,KAAK,GAAMH,GAAiB5yC,KAAK0H,IAAI,EAAG1H,KAAK0oB,MAAMoqB,IAG7E,KAAK,GADDE,MACKpsB,EAAI,EAAOgsB,EAAJhsB,EAAoBA,GAAK+rB,EACvCK,EAAY/vC,KAAKwvC,EAAc7rB,GAGjCmK,GAAWya,EAASlrC,IAAM0yC,KAgBpCj1C,EAAUoQ,UAAUkkC,YAAc,SAAU7G,EAAUza,EAAY+gB,GAChE,GAAI1K,GAAWn6B,EAAO3M,EAGlBmJ,EAFAwpC,KACAC,IAEJ,IAAI1H,EAAS/qC,OAAS,EAAG,CACvB,IAAKH,EAAI,EAAGA,EAAIkrC,EAAS/qC,OAAQH,IAC/B8mC,EAAYrW,EAAWya,EAASlrC,IAChCmJ,EAAU1O,KAAKo0B,OAAOqc,EAASlrC,IAAImJ,QAC/B29B,EAAU3mC,OAAS,IACrBwM,EAAQlS,KAAKo0B,OAAOqc,EAASlrC,IAES,SAAlCmJ,EAAQ8mC,SAASC,eAA6C,OAAjB/mC,EAAQxB,MACvB,QAA5BwB,EAAQy9B,iBAA6B+L,EAAuBA,EAAoBjkC,OAAO/B,EAAMk6B,UAAUC,IAClE8L,EAAuBA,EAAqBlkC,OAAO/B,EAAMk6B,UAAUC,IAG5G0K,EAAYtG,EAASlrC,IAAM2M,EAAMk6B,UAAUC,EAAUoE,EAASlrC,IAMpE0wC,GAAkBmC,oBAAoBF,EAAsBnB,EAAatG,EAAU,iBAAmB,QACtGwF,EAAkBmC,oBAAoBD,EAAsBpB,EAAatG,EAAU,kBAAmB,WAW1GztC,EAAUoQ,UAAUmkC,aAAe,SAAU9G,EAAUsG,GACrD,GAGoEsB,GAAQC,EAHxExT,GAAU,EACVyT,GAAgB,EAChBC,GAAiB,EACjBC,EAAU,IAAKC,EAAW,IAAKC,EAAU,KAAMC,EAAW,IAE9D,IAAInI,EAAS/qC,OAAS,EAAG,CAEvB,IAAK,GAAIH,GAAI,EAAGA,EAAIkrC,EAAS/qC,OAAQH,IAAK,CACxC,GAAI2M,GAAQlS,KAAKo0B,OAAOqc,EAASlrC,GAC7B2M,IAA2C,SAAlCA,EAAMxD,QAAQy9B,kBACzBoM,GAAgB,EAChBE,EAAU,EACVE,EAAU,GAEHzmC,GAASA,EAAMxD,QAAQy9B,mBAC9BqM,GAAiB,EACjBE,EAAW,EACXE,EAAW,GAKf,IAAK,GAAIrzC,GAAI,EAAGA,EAAIkrC,EAAS/qC,OAAQH,IAC/BwxC,EAAYlxC,eAAe4qC,EAASlrC,KAClCwxC,EAAYtG,EAASlrC,IAAIszC,UAAW,IACtCR,EAAStB,EAAYtG,EAASlrC,IAAIwG,IAClCusC,EAASvB,EAAYtG,EAASlrC,IAAIoH,IAEe,SAA7CoqC,EAAYtG,EAASlrC,IAAI4mC,kBAC3BoM,GAAgB,EAChBE,EAAUA,EAAUJ,EAASA,EAASI,EACtCE,EAAoBL,EAAVK,EAAmBL,EAASK,IAGtCH,GAAiB,EACjBE,EAAWA,EAAWL,EAASA,EAASK,EACxCE,EAAsBN,EAAXM,EAAoBN,EAASM,GAM3B,IAAjBL,GACFv4C,KAAKk2C,UAAU1iB,SAASilB,EAASE,GAEb,GAAlBH,GACFx4C,KAAKm2C,WAAW3iB,SAASklB,EAAUE,GAoCvC,MAjCA9T,GAAU9kC,KAAK84C,qBAAqBP,EAAgBv4C,KAAKk2C,YAAepR,EACxEA,EAAU9kC,KAAK84C,qBAAqBN,EAAgBx4C,KAAKm2C,aAAerR,EAElD,GAAlB0T,GAA2C,GAAjBD,GAC5Bv4C,KAAKk2C,UAAU6C,WAAY,EAC3B/4C,KAAKm2C,WAAW4C,WAAY,IAG5B/4C,KAAKk2C,UAAU6C,WAAY,EAC3B/4C,KAAKm2C,WAAW4C,WAAY,GAE9B/4C,KAAKm2C,WAAW5O,QAAUgR,EACI,GAA1Bv4C,KAAKm2C,WAAW5O,QACWvnC,KAAKk2C,UAAU5O,WAAtB,GAAlBkR,EAAqDx4C,KAAKm2C,WAAW3jC,MAChB,EAEzDsyB,EAAU9kC,KAAKk2C,UAAUx0B,UAAYojB,EACrC9kC,KAAKm2C,WAAW/O,iBAAmBpnC,KAAKk2C,UAAU/O,WAClDnnC,KAAKm2C,WAAW9O,aAAernC,KAAKk2C,UAAU7O,aAC9CvC,EAAU9kC,KAAKm2C,WAAWz0B,UAAYojB,GAGtCA,EAAU9kC,KAAKm2C,WAAWz0B,UAAYojB,EAIE,IAAtC2L,EAAS/pC,QAAQ,mBACnB+pC,EAASnoC,OAAOmoC,EAAS/pC,QAAQ,kBAAkB,GAEV,IAAvC+pC,EAAS/pC,QAAQ,oBACnB+pC,EAASnoC,OAAOmoC,EAAS/pC,QAAQ,mBAAmB,GAG/Co+B,GAYT9hC,EAAUoQ,UAAU0lC,qBAAuB,SAAUE,EAAU7X,GAC7D,GAAI9B,IAAU,CAad,OAZgB,IAAZ2Z,EACE7X,EAAKnR,IAAIzQ,MAAMzV,YAA6B,GAAfq3B,EAAKhI,SACpCgI,EAAK8G,OACL5I,GAAU,GAIP8B,EAAKnR,IAAIzQ,MAAMzV,YAA6B,GAAfq3B,EAAKhI,SACrCgI,EAAK+G,OACL7I,GAAU,GAGPA,GAaTr8B,EAAUoQ,UAAUikC,qBAAuB,SAAU4B,GAKnD,IAAK,GAHDC,GAAQC,EADRC,KAEAlkB,EAAWl1B,KAAK40B,KAAKj0B,KAAKu0B,SAErB3vB,EAAI,EAAGA,EAAI0zC,EAAWvzC,OAAQH,IACrC2zC,EAAShkB,EAAS+jB,EAAW1zC,GAAGyM,GAAKhS,KAAK+F,MAAMyM,MAChD2mC,EAASF,EAAW1zC,GAAG0M,EACvBmnC,EAAclxC,MAAM8J,EAAGknC,EAAQjnC,EAAGknC,GAGpC,OAAOC,IAcTp2C,EAAUoQ,UAAUqkC,qBAAuB,SAAUwB,EAAY/mC,GAC/D,GACIgnC,GAAQC,EADRC,KAEAlkB,EAAWl1B,KAAK40B,KAAKj0B,KAAKu0B,SAC1BiM,EAAOnhC,KAAKk2C,UACZmD,EAAYp1C,OAAOjE,KAAKmmC,IAAIj5B,MAAMuF,OAAOhI,QAAQ,KAAK,IACpB,UAAlCyH,EAAMxD,QAAQy9B,mBAChBhL,EAAOnhC,KAAKm2C,WAGd,KAAK,GAAI5wC,GAAI,EAAGA,EAAI0zC,EAAWvzC,OAAQH,IACrC2zC,EAAShkB,EAAS+jB,EAAW1zC,GAAGyM,GAAKhS,KAAK+F,MAAMyM,MAChD2mC,EAASl0C,KAAK0oB,MAAMwT,EAAK6I,aAAaiP,EAAW1zC,GAAG0M,IACpDmnC,EAAclxC,MAAM8J,EAAGknC,EAAQjnC,EAAGknC,GAKpC,OAFAjnC,GAAMm5B,gBAAgBpmC,KAAK8G,IAAIstC,EAAWlY,EAAK6I,aAAa,KAErDoP,GAITv5C,EAAOD,QAAUoD,GAKb,SAASnD,EAAQD,EAASM,GAgB9B,QAAS+C,GAAU2xB,EAAMlmB,GACvB1O,KAAKgwB,KACHgd,WAAY,KACZjG,SACAuS,cACAC,cACAtoC,WACE81B,SACAuS,cACAC,gBAGJv5C,KAAK+F,OACH2vB,OACE7lB,MAAO,EACPC,IAAK,EACLurB,YAAa,GAEfme,QAAS,GAGXx5C,KAAKs0B,gBACHE,YAAa,SAEb6R,iBAAiB,EACjBC,iBAAiB,EACjB3E,OAAQ,MAEV3hC,KAAK0O,QAAU/N,EAAK0E,UAAWrF,KAAKs0B,gBAEpCt0B,KAAK40B,KAAOA,EAGZ50B,KAAK20B,UAEL30B,KAAKmT,WAAWzE,GAjDlB,GAAI/N,GAAOT,EAAoB,GAC3BqC,EAAYrC,EAAoB,IAChC6B,EAAW7B,EAAoB,IAC/ByB,EAAWzB,EAAoB,IAC/B2D,EAAS3D,EAAoB,GAgDjC+C,GAASmQ,UAAY,GAAI7Q,GAUzBU,EAASmQ,UAAUD,WAAa,SAASzE,GACnCA,IAEF/N,EAAKmF,iBACH,cACA,kBACA,kBACA,cACA,UACC9F,KAAK0O,QAASA,GAIb,UAAYA,KACe,kBAAlB7K,GAAO6gC,OAEhB7gC,EAAO6gC,OAAOh2B,EAAQg2B,QAGtB7gC,EAAO8gC,KAAKj2B,EAAQg2B,WAS5BzhC,EAASmQ,UAAUuhB,QAAU,WAC3B30B,KAAKgwB,IAAIgd,WAAax7B,SAASM,cAAc,OAC7C9R,KAAKgwB,IAAI5jB,WAAaoF,SAASM,cAAc,OAE7C9R,KAAKgwB,IAAIgd,WAAWjlC,UAAY,sBAChC/H,KAAKgwB,IAAI5jB,WAAWrE,UAAY,uBAMlC9E,EAASmQ,UAAUG,QAAU,WAEvBvT,KAAKgwB,IAAIgd,WAAWljC,YACtB9J,KAAKgwB,IAAIgd,WAAWljC,WAAWsH,YAAYpR,KAAKgwB,IAAIgd,YAElDhtC,KAAKgwB,IAAI5jB,WAAWtC,YACtB9J,KAAKgwB,IAAI5jB,WAAWtC,WAAWsH,YAAYpR,KAAKgwB,IAAI5jB,YAGtDpM,KAAK40B,KAAO,MAOd3xB,EAASmQ,UAAUsO,OAAS,WAC1B,GAAIhT,GAAU1O,KAAK0O,QACf3I,EAAQ/F,KAAK+F,MACbinC,EAAahtC,KAAKgwB,IAAIgd,WACtB5gC,EAAapM,KAAKgwB,IAAI5jB,WAGtB+4B,EAAiC,OAAvBz2B,EAAQ8lB,YAAwBx0B,KAAK40B,KAAK5E,IAAIpoB,IAAM5H,KAAK40B,KAAK5E,IAAIzM,OAC5Ek2B,EAAiBzM,EAAWljC,aAAeq7B,CAG/CnlC,MAAK2oC,oBAGL,IACItC,IADcrmC,KAAK0O,QAAQ8lB,YACTx0B,KAAK0O,QAAQ23B,iBAC/BC,EAAkBtmC,KAAK0O,QAAQ43B,eAGnCvgC,GAAM6iC,iBAAmBvC,EAAkBtgC,EAAM8iC,gBAAkB,EACnE9iC,EAAM+iC,iBAAmBxC,EAAkBvgC,EAAMgjC,gBAAkB,EACnEhjC,EAAM0M,OAAS1M,EAAM6iC,iBAAmB7iC,EAAM+iC,iBAC9C/iC,EAAMyM,MAAQw6B,EAAW3c,YAEzBtqB,EAAMkjC,gBAAkBjpC,KAAK40B,KAAKC,SAASn1B,KAAK+S,OAAS1M,EAAM+iC,kBACnC,OAAvBp6B,EAAQ8lB,YAAuBx0B,KAAK40B,KAAKC,SAAStR,OAAO9Q,OAASzS,KAAK40B,KAAKC,SAASjtB,IAAI6K,QAC9F1M,EAAMijC,eAAiB,EACvBjjC,EAAMojC,gBAAkBpjC,EAAMkjC,gBAAkBljC,EAAM+iC,iBACtD/iC,EAAMmjC,eAAiB,CAGvB,IAAIwQ,GAAwB1M,EAAW2M,YACnCC,EAAwBxtC,EAAWutC,WAsBvC,OArBA3M,GAAWljC,YAAckjC,EAAWljC,WAAWsH,YAAY47B,GAC3D5gC,EAAWtC,YAAcsC,EAAWtC,WAAWsH,YAAYhF,GAE3D4gC,EAAW9/B,MAAMuF,OAASzS,KAAK+F,MAAM0M,OAAS,KAE9CzS,KAAK65C,iBAGDH,EACFvU,EAAOtzB,aAAam7B,EAAY0M,GAGhCvU,EAAOzzB,YAAYs7B,GAEjB4M,EACF55C,KAAK40B,KAAK5E,IAAIoV,mBAAmBvzB,aAAazF,EAAYwtC,GAG1D55C,KAAK40B,KAAK5E,IAAIoV,mBAAmB1zB,YAAYtF,GAGxCpM,KAAK6kC,cAAgB4U,GAO9Bx2C,EAASmQ,UAAUymC,eAAiB,WAClC,GAAIrlB,GAAcx0B,KAAK0O,QAAQ8lB,YAG3B3kB,EAAQlP,EAAKiG,QAAQ5G,KAAK40B,KAAKc,MAAM7lB,MAAO,UAC5CC,EAAMnP,EAAKiG,QAAQ5G,KAAK40B,KAAKc,MAAM5lB,IAAK,UACxCgqC,EAAgB95C,KAAK40B,KAAKj0B,KAAK20B,OAA2C,GAAnCt1B,KAAK+F,MAAMukC,gBAAkB,KAASvjC,UAC7Es0B,EAAcye,EAAgBn4C,EAASm5B,wBAAwB96B,KAAK40B,KAAKI,YAAah1B,KAAK40B,KAAKc,MAAOokB,EAC3Gze,IAAer7B,KAAK40B,KAAKj0B,KAAK20B,OAAO,GAAGvuB,SAExC,IAAIqhB,GAAO,GAAIrmB,GAAS,GAAIsC,MAAKwL,GAAQ,GAAIxL,MAAKyL,GAAMurB,EAAar7B,KAAK40B,KAAKI,YAC3Eh1B,MAAK0O,QAAQizB,QACfvZ,EAAKga,UAAUpiC,KAAK0O,QAAQizB,QAE9B3hC,KAAKooB,KAAOA,CAKZ,IAAI4H,GAAMhwB,KAAKgwB,GACfA,GAAI/e,UAAU81B,MAAQ/W,EAAI+W,MAC1B/W,EAAI/e,UAAUqoC,WAAatpB,EAAIspB,WAC/BtpB,EAAI/e,UAAUsoC,WAAavpB,EAAIupB,WAC/BvpB,EAAI+W,SACJ/W,EAAIspB,cACJtpB,EAAIupB,aAEJ,IAAIQ,GAEA5c,EAGA6c,EAGAjyC,EAPAiK,EAAI,EAEJioC,EAAQ,EACRznC,EAAQ,EAER0nC,EAAmB3zC,OACnBoG,EAAM,CAIV,KADAyb,EAAKka,QACEla,EAAK0U,WAAmB,IAANnwB,GACvBA,IAEAotC,EAAM3xB,EAAKC,aACX8U,EAAU/U,EAAK+U,UACfp1B,EAAYqgB,EAAK+b,eAEjB8V,EAAQjoC,EACRA,EAAIhS,KAAK40B,KAAKj0B,KAAKu0B,SAAS6kB,GAC5BvnC,EAAQR,EAAIioC,EACRD,IACFA,EAAS9sC,MAAMsF,MAAQA,EAAQ,MAG7BxS,KAAK0O,QAAQ23B,iBACfrmC,KAAKm6C,kBAAkBnoC,EAAGoW,EAAK6b,gBAAiBzP,EAAazsB,GAG3Do1B,GAAWn9B,KAAK0O,QAAQ43B,iBACtBt0B,EAAI,IACkBzL,QAApB2zC,IACFA,EAAmBloC,GAErBhS,KAAKo6C,kBAAkBpoC,EAAGoW,EAAK8b,gBAAiB1P,EAAazsB,IAE/DiyC,EAAWh6C,KAAKq6C,kBAAkBroC,EAAGwiB,EAAazsB,IAGlDiyC,EAAWh6C,KAAKs6C,kBAAkBtoC,EAAGwiB,EAAazsB,GAGpDqgB,EAAKE,MAIP,IAAItoB,KAAK0O,QAAQ43B,gBAAiB,CAChC,GAAIiU,GAAWv6C,KAAK40B,KAAKj0B,KAAK20B,OAAO,GACjCklB,EAAWpyB,EAAK8b,cAAcqW,GAC9BE,EAAYD,EAAS90C,QAAU1F,KAAK+F,MAAMskC,gBAAkB,IAAM,IAE9C9jC,QAApB2zC,GAA6CA,EAAZO,IACnCz6C,KAAKo6C,kBAAkB,EAAGI,EAAUhmB,EAAazsB,GAKrDpH,EAAK4H,QAAQvI,KAAKgwB,IAAI/e,UAAW,SAAUypC,GACzC,KAAOA,EAAIh1C,QAAQ,CACjB,GAAI4B,GAAOozC,EAAIC,KACXrzC,IAAQA,EAAKwC,YACfxC,EAAKwC,WAAWsH,YAAY9J,OAcpCrE,EAASmQ,UAAU+mC,kBAAoB,SAAUnoC,EAAGwX,EAAMgL,EAAazsB,GAErE,GAAI2gB,GAAQ1oB,KAAKgwB,IAAI/e,UAAUsoC,WAAWhoC,OAE1C,KAAKmX,EAAO,CAEV,GAAImH,GAAUre,SAASg5B,eAAe,GACtC9hB,GAAQlX,SAASM,cAAc,OAC/B4W,EAAMhX,YAAYme,GAClB7vB,KAAKgwB,IAAIgd,WAAWt7B,YAAYgX,GAElC1oB,KAAKgwB,IAAIupB,WAAWrxC,KAAKwgB,GAEzBA,EAAMkyB,WAAW,GAAGC,UAAYrxB,EAEhCd,EAAMxb,MAAMtF,IAAsB,OAAf4sB,EAAyBx0B,KAAK+F,MAAM+iC,iBAAmB,KAAQ,IAClFpgB,EAAMxb,MAAM1F,KAAOwK,EAAI,KACvB0W,EAAM3gB,UAAY,cAAgBA,GAYpC9E,EAASmQ,UAAUgnC,kBAAoB,SAAUpoC,EAAGwX,EAAMgL,EAAazsB,GAErE,GAAI2gB,GAAQ1oB,KAAKgwB,IAAI/e,UAAUqoC,WAAW/nC,OAE1C,KAAKmX,EAAO,CAEV,GAAImH,GAAUre,SAASg5B,eAAehhB,EACtCd,GAAQlX,SAASM,cAAc,OAC/B4W,EAAMhX,YAAYme,GAClB7vB,KAAKgwB,IAAIgd,WAAWt7B,YAAYgX,GAElC1oB,KAAKgwB,IAAIspB,WAAWpxC,KAAKwgB,GAEzBA,EAAMkyB,WAAW,GAAGC,UAAYrxB,EAChCd,EAAM3gB,UAAY,cAAgBA,EAGlC2gB,EAAMxb,MAAMtF,IAAsB,OAAf4sB,EAAwB,IAAOx0B,KAAK+F,MAAM6iC,iBAAoB,KACjFlgB,EAAMxb,MAAM1F,KAAOwK,EAAI,MAWzB/O,EAASmQ,UAAUknC,kBAAoB,SAAUtoC,EAAGwiB,EAAazsB,GAE/D,GAAI+nB,GAAO9vB,KAAKgwB,IAAI/e,UAAU81B,MAAMx1B,OAC/Bue,KAEHA,EAAOte,SAASM,cAAc,OAC9B9R,KAAKgwB,IAAI5jB,WAAWsF,YAAYoe,IAElC9vB,KAAKgwB,IAAI+W,MAAM7+B,KAAK4nB,EAEpB,IAAI/pB,GAAQ/F,KAAK+F,KAYjB,OAVE+pB,GAAK5iB,MAAMtF,IADM,OAAf4sB,EACezuB,EAAM+iC,iBAAmB,KAGzB9oC,KAAK40B,KAAKC,SAASjtB,IAAI6K,OAAS,KAEnDqd,EAAK5iB,MAAMuF,OAAS1M,EAAMkjC,gBAAkB,KAC5CnZ,EAAK5iB,MAAM1F,KAAQwK,EAAIjM,EAAMijC,eAAiB,EAAK,KAEnDlZ,EAAK/nB,UAAY,uBAAyBA,EAEnC+nB,GAWT7sB,EAASmQ,UAAUinC,kBAAoB,SAAUroC,EAAGwiB,EAAazsB,GAE/D,GAAI+nB,GAAO9vB,KAAKgwB,IAAI/e,UAAU81B,MAAMx1B,OAC/Bue,KAEHA,EAAOte,SAASM,cAAc,OAC9B9R,KAAKgwB,IAAI5jB,WAAWsF,YAAYoe,IAElC9vB,KAAKgwB,IAAI+W,MAAM7+B,KAAK4nB,EAEpB,IAAI/pB,GAAQ/F,KAAK+F,KAYjB,OAVE+pB,GAAK5iB,MAAMtF,IADM,OAAf4sB,EACe,IAGAx0B,KAAK40B,KAAKC,SAASjtB,IAAI6K,OAAS,KAEnDqd,EAAK5iB,MAAM1F,KAAQwK,EAAIjM,EAAMmjC,eAAiB,EAAK,KACnDpZ,EAAK5iB,MAAMuF,OAAS1M,EAAMojC,gBAAkB,KAE5CrZ,EAAK/nB,UAAY,uBAAyBA,EAEnC+nB,GAQT7sB,EAASmQ,UAAUu1B,mBAAqB,WAKjC3oC,KAAKgwB,IAAIya,mBACZzqC,KAAKgwB,IAAIya,iBAAmBj5B,SAASM,cAAc,OACnD9R,KAAKgwB,IAAIya,iBAAiB1iC,UAAY,qBACtC/H,KAAKgwB,IAAIya,iBAAiBv9B,MAAM2W,SAAW,WAE3C7jB,KAAKgwB,IAAIya,iBAAiB/4B,YAAYF,SAASg5B,eAAe,MAC9DxqC,KAAKgwB,IAAIgd,WAAWt7B,YAAY1R,KAAKgwB,IAAIya,mBAE3CzqC,KAAK+F,MAAM8iC,gBAAkB7oC,KAAKgwB,IAAIya,iBAAiB3lB,aACvD9kB,KAAK+F,MAAMukC,eAAiBtqC,KAAKgwB,IAAIya,iBAAiBhrB,YAGjDzf,KAAKgwB,IAAI2a,mBACZ3qC,KAAKgwB,IAAI2a,iBAAmBn5B,SAASM,cAAc,OACnD9R,KAAKgwB,IAAI2a,iBAAiB5iC,UAAY,qBACtC/H,KAAKgwB,IAAI2a,iBAAiBz9B,MAAM2W,SAAW,WAE3C7jB,KAAKgwB,IAAI2a,iBAAiBj5B,YAAYF,SAASg5B,eAAe,MAC9DxqC,KAAKgwB,IAAIgd,WAAWt7B,YAAY1R,KAAKgwB,IAAI2a,mBAE3C3qC,KAAK+F,MAAMgjC,gBAAkB/oC,KAAKgwB,IAAI2a,iBAAiB7lB,aACvD9kB,KAAK+F,MAAMskC,eAAiBrqC,KAAKgwB,IAAI2a,iBAAiBlrB,aASxDxc,EAASmQ,UAAU6hB,KAAO,SAASyD,GACjC,MAAO14B,MAAKooB,KAAK6M,KAAKyD,IAGxB74B,EAAOD,QAAUqD,GAKb,SAASpD,EAAQD,EAASM,GAc9B,QAASgC,GAAMyQ,EAAM0nB,EAAY3rB,GAC/B1O,KAAKK,GAAK,KACVL,KAAKmlC,OAAS,KACdnlC,KAAK2S,KAAOA,EACZ3S,KAAKgwB,IAAM,KACXhwB,KAAKq6B,WAAaA,MAClBr6B,KAAK0O,QAAUA,MAEf1O,KAAKwzC,UAAW,EAChBxzC,KAAKytC,WAAY,EACjBztC,KAAKwtC,OAAQ,EAEbxtC,KAAK4H,IAAM,KACX5H,KAAKwH,KAAO,KACZxH,KAAKwS,MAAQ,KACbxS,KAAKyS,OAAS,KA3BhB,GAAIozB,GAAS3lC,EAAoB,IAC7BS,EAAOT,EAAoB,EA6B/BgC,GAAKkR,UAAUtR,OAAQ,EAKvBI,EAAKkR,UAAUq+B,OAAS,WACtBzxC,KAAKwzC,UAAW,EAChBxzC,KAAKwtC,OAAQ,EACTxtC,KAAKytC,WAAWztC,KAAK0hB,UAM3Bxf,EAAKkR,UAAUo+B,SAAW,WACxBxxC,KAAKwzC,UAAW,EAChBxzC,KAAKwtC,OAAQ,EACTxtC,KAAKytC,WAAWztC,KAAK0hB,UAQ3Bxf,EAAKkR,UAAU6E,QAAU,SAAStF,GAChC3S,KAAK2S,KAAOA,EACZ3S,KAAKwtC,OAAQ,EACTxtC,KAAKytC,WAAWztC,KAAK0hB,UAO3Bxf,EAAKkR,UAAU66B,UAAY,SAAS9I,GAC9BnlC,KAAKytC,WACPztC,KAAKioC,OACLjoC,KAAKmlC,OAASA,EACVnlC,KAAKmlC,QACPnlC,KAAKkoC,QAIPloC,KAAKmlC,OAASA,GASlBjjC,EAAKkR,UAAUi8B,UAAY,WAEzB,OAAO,GAOTntC,EAAKkR,UAAU80B,KAAO,WACpB,OAAO,GAOThmC,EAAKkR,UAAU60B,KAAO,WACpB,OAAO,GAMT/lC,EAAKkR,UAAUsO,OAAS,aAOxBxf,EAAKkR,UAAU87B,YAAc,aAO7BhtC,EAAKkR,UAAU06B,YAAc,aAS7B5rC,EAAKkR,UAAU0nC,qBAAuB,SAAUC,GAC9C,GAAI/6C,KAAKwzC,UAAYxzC,KAAK0O,QAAQ+gC,SAASn5B,SAAWtW,KAAKgwB,IAAIgrB,aAAc,CAE3E,GAAI5mC,GAAKpU,KAELg7C,EAAexpC,SAASM,cAAc,MAC1CkpC,GAAajzC,UAAY,SACzBizC,EAAa3V,MAAQ,mBAErBQ,EAAOmV,GACLzxC,gBAAgB,IACfiK,GAAG,MAAO,SAAUhK,GACrB4K,EAAG+wB,OAAOmJ,kBAAkBl6B,GAC5B5K,EAAM08B,oBAGR6U,EAAOrpC,YAAYspC,GACnBh7C,KAAKgwB,IAAIgrB,aAAeA,OAEhBh7C,KAAKwzC,UAAYxzC,KAAKgwB,IAAIgrB,eAE9Bh7C,KAAKgwB,IAAIgrB,aAAalxC,YACxB9J,KAAKgwB,IAAIgrB,aAAalxC,WAAWsH,YAAYpR,KAAKgwB,IAAIgrB,cAExDh7C,KAAKgwB,IAAIgrB,aAAe,OAS5B94C,EAAKkR,UAAU6nC,gBAAkB,SAAUnyC,GACzC,GAAI+mB,EACJ,IAAI7vB,KAAK0O,QAAQwsC,SAAU,CACzB,GAAIpkB,GAAW92B,KAAKmlC,OAAOrP,QAAQC,UAAU5gB,IAAInV,KAAKK,GACtDwvB,GAAU7vB,KAAK0O,QAAQwsC,SAASpkB,OAGhCjH,GAAU7vB,KAAK2S,KAAKkd,OAGtB,IAAGA,IAAY7vB,KAAK6vB,QAAS,CAE3B,GAAIA,YAAmBqd,SACrBpkC,EAAQob,UAAY,GACpBpb,EAAQ4I,YAAYme,OAEjB,IAAetpB,QAAXspB,EACP/mB,EAAQob,UAAY2L,MAGpB,IAAwB,cAAlB7vB,KAAK2S,KAAK9L,MAA8CN,SAAtBvG,KAAK2S,KAAKkd,QAChD,KAAM,IAAIjsB,OAAM,sCAAwC5D,KAAKK,GAIjEL,MAAK6vB,QAAUA,IASnB3tB,EAAKkR,UAAU+nC,aAAe,SAAUryC,GACf,MAAnB9I,KAAK2S,KAAK0yB,MACZv8B,EAAQu8B,MAAQrlC,KAAK2S,KAAK0yB,OAAS,GAGnCv8B,EAAQsyC,gBAAgB,UAS3Bl5C,EAAKkR,UAAUioC,sBAAwB,SAASvyC,GAC/C,GAAI9I,KAAK0O,QAAQ4sC,gBAAkBt7C,KAAK0O,QAAQ4sC,eAAe51C,OAAS,EAAG,CACzE,GAAI61C,KAEJ,IAAIv1C,MAAMC,QAAQjG,KAAK0O,QAAQ4sC,gBAC7BC,EAAav7C,KAAK0O,QAAQ4sC,mBAEvB,CAAA,GAAmC,OAA/Bt7C,KAAK0O,QAAQ4sC,eAIpB,MAHAC,GAAaj1C,OAAO+G,KAAKrN,KAAK2S,MAMhC,IAAK,GAAIpN,GAAI,EAAGA,EAAIg2C,EAAW71C,OAAQH,IAAK,CAC1C,GAAI2Q,GAAOqlC,EAAWh2C,GAClB6B,EAAQpH,KAAK2S,KAAKuD,EAET,OAAT9O,EACF0B,EAAQ0yC,aAAa,QAAUtlC,EAAM9O,GAGrC0B,EAAQsyC,gBAAgB,QAAUllC,MAW1ChU,EAAKkR,UAAUqoC,aAAe,SAAS3yC,GAEjC9I,KAAKkN,QACPvM,EAAK+M,cAAc5E,EAAS9I,KAAKkN,OACjClN,KAAKkN,MAAQ,MAIXlN,KAAK2S,KAAKzF,QACZvM,EAAK4M,WAAWzE,EAAS9I,KAAK2S,KAAKzF,OACnClN,KAAKkN,MAAQlN,KAAK2S,KAAKzF,QAI3BrN,EAAOD,QAAUsC,GAKb,SAASrC,EAAQD,EAASM,GAkB9B,QAASiC,GAAgBwQ,EAAM0nB,EAAY3rB,GASzC,GARA1O,KAAK+F,OACH8pB,SACErd,MAAO,IAGXxS,KAAK8jB,UAAW,EAGZnR,EAAM,CACR,GAAkBpM,QAAdoM,EAAK9C,MACP,KAAM,IAAIjM,OAAM,oCAAsC+O,EAAKtS,GAE7D,IAAgBkG,QAAZoM,EAAK7C,IACP,KAAM,IAAIlM,OAAM,kCAAoC+O,EAAKtS,IAI7D6B,EAAK3B,KAAKP,KAAM2S,EAAM0nB,EAAY3rB,GAElC1O,KAAK07C,cAAe,EApCtB,GACIx5C,IADShC,EAAoB,IACtBA,EAAoB,KAC3B2C,EAAkB3C,EAAoB,IACtCoC,EAAYpC,EAAoB,GAoCpCiC,GAAeiR,UAAY,GAAIlR,GAAM,KAAM,KAAM,MAEjDC,EAAeiR,UAAUuoC,cAAgB,kBACzCx5C,EAAeiR,UAAUtR,OAAQ,EAOjCK,EAAeiR,UAAUi8B,UAAY,SAAS3Z,GAE5C,MAAQ11B,MAAK2S,KAAK9C,MAAQ6lB,EAAM5lB,KAAS9P,KAAK2S,KAAK7C,IAAM4lB,EAAM7lB,OAMjE1N,EAAeiR,UAAUsO,OAAS,WAChC,GAAIsO,GAAMhwB,KAAKgwB,GAuBf,IAtBKA,IAEHhwB,KAAKgwB,OACLA,EAAMhwB,KAAKgwB,IAGXA,EAAI+gB,IAAMv/B,SAASM,cAAc,OAIjCke,EAAIH,QAAUre,SAASM,cAAc,OACrCke,EAAIH,QAAQ9nB,UAAY,UACxBioB,EAAI+gB,IAAIr/B,YAAYse,EAAIH,SAMxB7vB,KAAKwtC,OAAQ,IAIVxtC,KAAKmlC,OACR,KAAM,IAAIvhC,OAAM,yCAElB,KAAKosB,EAAI+gB,IAAIjnC,WAAY,CACvB,GAAIsC,GAAapM,KAAKmlC,OAAOnV,IAAI5jB,UACjC,KAAKA,EACH,KAAM,IAAIxI,OAAM,iEAElBwI,GAAWsF,YAAYse,EAAI+gB,KAQ7B,GANA/wC,KAAKytC,WAAY,EAMbztC,KAAKwtC,MAAO,CACdxtC,KAAKi7C,gBAAgBj7C,KAAKgwB,IAAIH,SAC9B7vB,KAAKm7C,aAAan7C,KAAKgwB,IAAIH,SAC3B7vB,KAAKq7C,sBAAsBr7C,KAAKgwB,IAAIH,SACpC7vB,KAAKy7C,aAAaz7C,KAAKgwB,IAAI+gB,IAG3B,IAAIhpC,IAAa/H,KAAK2S,KAAK5K,UAAa,IAAM/H,KAAK2S,KAAK5K,UAAa,KAChE/H,KAAKwzC,SAAW,YAAc,GACnCxjB,GAAI+gB,IAAIhpC,UAAY/H,KAAK27C,cAAgB5zC,EAGzC/H,KAAK8jB,SAA6D,WAAlDrc,OAAO0tC,iBAAiBnlB,EAAIH,SAAS/L,SAGrD9jB,KAAK+F,MAAM8pB,QAAQrd,MAAQxS,KAAKgwB,IAAIH,QAAQQ,YAC5CrwB,KAAKyS,OAAS,EAEdzS,KAAKwtC,OAAQ,IAQjBrrC,EAAeiR,UAAU80B,KAAO5lC,EAAU8Q,UAAU80B,KAMpD/lC,EAAeiR,UAAU60B,KAAO3lC,EAAU8Q,UAAU60B,KAMpD9lC,EAAeiR,UAAU87B,YAAc5sC,EAAU8Q,UAAU87B,YAM3D/sC,EAAeiR,UAAU06B,YAAc,SAASn0B,GAC9C,GAAIiiC,GAAqC,QAA7B57C,KAAK0O,QAAQ8lB,WACzBx0B,MAAKgwB,IAAIH,QAAQ3iB,MAAMtF,IAAMg0C,EAAQ,GAAK,IAC1C57C,KAAKgwB,IAAIH,QAAQ3iB,MAAMqW,OAASq4B,EAAQ,IAAM,EAC9C,IAAInpC,EAGJ,IAA2BlM,SAAvBvG,KAAK2S,KAAK+uB,SAAwB,CACpC,GAAIma,GAAe77C,KAAK2S,KAAK+uB,SACzBF,EAAYxhC,KAAKmlC,OAAO3D,UACxBgL,EAAgBhL,EAAUqa,GAAcxzC,KAE5C,IAAa,GAATuzC,EAAe,CAEjBnpC,EAASzS,KAAKmlC,OAAO3D,UAAUqa,GAAcppC,OAASkH,EAAOrK,KAAKoW,SAClEjT,GAA2B,GAAjB+5B,EAAqB7yB,EAAOwnB,KAAO,GAAIxnB,EAAOrK,KAAKoW,SAAW,CACxE,IAAI+b,GAASzhC,KAAKmlC,OAAOv9B,GACzB,KAAK,GAAI85B,KAAYF,GACfA,EAAU37B,eAAe67B,IACQ,GAA/BF,EAAUE,GAAU/Y,SAAmB6Y,EAAUE,GAAUr5B,MAAQmkC,IACrE/K,GAAUD,EAAUE,GAAUjvB,OAASkH,EAAOrK,KAAKoW,SAMzD+b,IAA2B,GAAjB+K,EAAqB7yB,EAAOwnB,KAAO,GAAMxnB,EAAOrK,KAAKoW,SAAW,EAC1E1lB,KAAKgwB,IAAI+gB,IAAI7jC,MAAMtF,IAAM65B,EAAS,KAClCzhC,KAAKgwB,IAAI+gB,IAAI7jC,MAAMqW,OAAS,OAGzB,CACH,GAAIke,GAASzhC,KAAKmlC,OAAOv9B,GACzB,KAAK,GAAI85B,KAAYF,GACfA,EAAU37B,eAAe67B,IACQ,GAA/BF,EAAUE,GAAU/Y,SAAmB6Y,EAAUE,GAAUr5B,MAAQmkC,IACrE/K,GAAUD,EAAUE,GAAUjvB,OAASkH,EAAOrK,KAAKoW,SAIzDjT,GAASzS,KAAKmlC,OAAO3D,UAAUqa,GAAcppC,OAASkH,EAAOrK,KAAKoW,SAClE1lB,KAAKgwB,IAAI+gB,IAAI7jC,MAAMtF,IAAM65B,EAAS,KAClCzhC,KAAKgwB,IAAI+gB,IAAI7jC,MAAMqW,OAAS,QAM1BvjB,MAAKmlC,iBAAkBtiC,IAEzB4P,EAASxN,KAAK0H,IAAI3M,KAAKmlC,OAAO1yB,OAC1BzS,KAAKmlC,OAAOrP,QAAQlB,KAAKC,SAAS1I,OAAO1Z,OACzCzS,KAAKmlC,OAAOrP,QAAQlB,KAAKC,SAASiD,gBAAgBrlB,QACtDzS,KAAKgwB,IAAI+gB,IAAI7jC,MAAMtF,IAAMg0C,EAAQ,IAAM,GACvC57C,KAAKgwB,IAAI+gB,IAAI7jC,MAAMqW,OAASq4B,EAAQ,GAAK,MAGzCnpC,EAASzS,KAAKmlC,OAAO1yB,OAErBzS,KAAKgwB,IAAI+gB,IAAI7jC,MAAMtF,IAAM5H,KAAKmlC,OAAOv9B,IAAM,KAC3C5H,KAAKgwB,IAAI+gB,IAAI7jC,MAAMqW,OAAS,GAGhCvjB,MAAKgwB,IAAI+gB,IAAI7jC,MAAMuF,OAASA,EAAS,MAGvC5S,EAAOD,QAAUuC,GAKb,SAAStC,EAAQD,EAASM,GAe9B,QAASkC,GAASuQ,EAAM0nB,EAAY3rB,GAalC,GAZA1O,KAAK+F,OACHgqB,KACEvd,MAAO,EACPC,OAAQ,GAEVqd,MACEtd,MAAO,EACPC,OAAQ,IAKRE,GACgBpM,QAAdoM,EAAK9C,MACP,KAAM,IAAIjM,OAAM,oCAAsC+O,EAI1DzQ,GAAK3B,KAAKP,KAAM2S,EAAM0nB,EAAY3rB,GAhCpC,CAAA,GAAIxM,GAAOhC,EAAoB,GACpBA,GAAoB,GAkC/BkC,EAAQgR,UAAY,GAAIlR,GAAM,KAAM,KAAM,MAO1CE,EAAQgR,UAAUi8B,UAAY,SAAS3Z,GAGrC,GAAIjD,IAAYiD,EAAM5lB,IAAM4lB,EAAM7lB,OAAS,CAC3C,OAAQ7P,MAAK2S,KAAK9C,MAAQ6lB,EAAM7lB,MAAQ4iB,GAAczyB,KAAK2S,KAAK9C,MAAQ6lB,EAAM5lB,IAAM2iB,GAMtFrwB,EAAQgR,UAAUsO,OAAS,WACzB,GAAIsO,GAAMhwB,KAAKgwB,GA6Bf,IA5BKA,IAEHhwB,KAAKgwB,OACLA,EAAMhwB,KAAKgwB,IAGXA,EAAI+gB,IAAMv/B,SAASM,cAAc,OAGjCke,EAAIH,QAAUre,SAASM,cAAc,OACrCke,EAAIH,QAAQ9nB,UAAY,UACxBioB,EAAI+gB,IAAIr/B,YAAYse,EAAIH,SAGxBG,EAAIF,KAAOte,SAASM,cAAc,OAClCke,EAAIF,KAAK/nB,UAAY,OAGrBioB,EAAID,IAAMve,SAASM,cAAc,OACjCke,EAAID,IAAIhoB,UAAY,MAGpBioB,EAAI+gB,IAAI,iBAAmB/wC,KAE3BA,KAAKwtC,OAAQ,IAIVxtC,KAAKmlC,OACR,KAAM,IAAIvhC,OAAM,yCAElB,KAAKosB,EAAI+gB,IAAIjnC,WAAY,CACvB,GAAIkjC,GAAahtC,KAAKmlC,OAAOnV,IAAIgd,UACjC,KAAKA,EAAY,KAAM,IAAIppC,OAAM,iEACjCopC,GAAWt7B,YAAYse,EAAI+gB,KAE7B,IAAK/gB,EAAIF,KAAKhmB,WAAY,CACxB,GAAIsC,GAAapM,KAAKmlC,OAAOnV,IAAI5jB,UACjC,KAAKA,EAAY,KAAM,IAAIxI,OAAM,iEACjCwI,GAAWsF,YAAYse,EAAIF,MAE7B,IAAKE,EAAID,IAAIjmB,WAAY,CACvB,GAAIq3B,GAAOnhC,KAAKmlC,OAAOnV,IAAImR,IAC3B,KAAK/0B,EAAY,KAAM,IAAIxI,OAAM,2DACjCu9B,GAAKzvB,YAAYse,EAAID,KAQvB,GANA/vB,KAAKytC,WAAY,EAMbztC,KAAKwtC,MAAO,CACdxtC,KAAKi7C,gBAAgBj7C,KAAKgwB,IAAIH,SAC9B7vB,KAAKm7C,aAAan7C,KAAKgwB,IAAI+gB,KAC3B/wC,KAAKq7C,sBAAsBr7C,KAAKgwB,IAAI+gB,KACpC/wC,KAAKy7C,aAAaz7C,KAAKgwB,IAAI+gB,IAG3B,IAAIhpC,IAAa/H,KAAK2S,KAAK5K,UAAW,IAAM/H,KAAK2S,KAAK5K,UAAY,KAC7D/H,KAAKwzC,SAAW,YAAc,GACnCxjB,GAAI+gB,IAAIhpC,UAAY,WAAaA,EACjCioB,EAAIF,KAAK/nB,UAAY,YAAcA,EACnCioB,EAAID,IAAIhoB,UAAa,WAAaA,EAGlC/H,KAAK+F,MAAMgqB,IAAItd,OAASud,EAAID,IAAIQ,aAChCvwB,KAAK+F,MAAMgqB,IAAIvd,MAAQwd,EAAID,IAAIM,YAC/BrwB,KAAK+F,MAAM+pB,KAAKtd,MAAQwd,EAAIF,KAAKO,YACjCrwB,KAAKwS,MAAQwd,EAAI+gB,IAAI1gB,YACrBrwB,KAAKyS,OAASud,EAAI+gB,IAAIxgB,aAEtBvwB,KAAKwtC,OAAQ,EAGfxtC,KAAK86C,qBAAqB9qB,EAAI+gB,MAOhC3uC,EAAQgR,UAAU80B,KAAO,WAClBloC,KAAKytC,WACRztC,KAAK0hB,UAOTtf,EAAQgR,UAAU60B,KAAO,WACvB,GAAIjoC,KAAKytC,UAAW,CAClB,GAAIzd,GAAMhwB,KAAKgwB,GAEXA,GAAI+gB,IAAIjnC,YAAckmB,EAAI+gB,IAAIjnC,WAAWsH,YAAY4e,EAAI+gB,KACzD/gB,EAAIF,KAAKhmB,YAAakmB,EAAIF,KAAKhmB,WAAWsH,YAAY4e,EAAIF,MAC1DE,EAAID,IAAIjmB,YAAckmB,EAAID,IAAIjmB,WAAWsH,YAAY4e,EAAID,KAE7D/vB,KAAK4H,IAAM,KACX5H,KAAKwH,KAAO,KAEZxH,KAAKytC,WAAY,IAQrBrrC,EAAQgR,UAAU87B,YAAc,WAC9B,GAAIr/B,GAAQ7P,KAAKq6B,WAAWnF,SAASl1B,KAAK2S,KAAK9C,OAC3Cy/B,EAAQtvC,KAAK0O,QAAQ4gC,MAErByB,EAAM/wC,KAAKgwB,IAAI+gB,IACfjhB,EAAO9vB,KAAKgwB,IAAIF,KAChBC,EAAM/vB,KAAKgwB,IAAID,GAIjB/vB,MAAKwH,KADM,SAAT8nC,EACUz/B,EAAQ7P,KAAKwS,MAET,QAAT88B,EACKz/B,EAIAA,EAAQ7P,KAAKwS,MAAQ,EAInCu+B,EAAI7jC,MAAM1F,KAAOxH,KAAKwH,KAAO,KAG7BsoB,EAAK5iB,MAAM1F,KAAQqI,EAAQ7P,KAAK+F,MAAM+pB,KAAKtd,MAAQ,EAAK,KAGxDud,EAAI7iB,MAAM1F,KAAQqI,EAAQ7P,KAAK+F,MAAMgqB,IAAIvd,MAAQ,EAAK,MAOxDpQ,EAAQgR,UAAU06B,YAAc,WAC9B,GAAItZ,GAAcx0B,KAAK0O,QAAQ8lB,YAC3Buc,EAAM/wC,KAAKgwB,IAAI+gB,IACfjhB,EAAO9vB,KAAKgwB,IAAIF,KAChBC,EAAM/vB,KAAKgwB,IAAID,GAEnB,IAAmB,OAAfyE,EACFuc,EAAI7jC,MAAMtF,KAAW5H,KAAK4H,KAAO,GAAK,KAEtCkoB,EAAK5iB,MAAMtF,IAAS,IACpBkoB,EAAK5iB,MAAMuF,OAAUzS,KAAKmlC,OAAOv9B,IAAM5H,KAAK4H,IAAM,EAAK,KACvDkoB,EAAK5iB,MAAMqW,OAAS,OAEjB,CACH,GAAIu4B,GAAgB97C,KAAKmlC,OAAOrP,QAAQ/vB,MAAM0M,OAC1C+d,EAAasrB,EAAgB97C,KAAKmlC,OAAOv9B,IAAM5H,KAAKmlC,OAAO1yB,OAASzS,KAAK4H,GAE7EmpC,GAAI7jC,MAAMtF,KAAW5H,KAAKmlC,OAAO1yB,OAASzS,KAAK4H,IAAM5H,KAAKyS,QAAU,GAAK,KACzEqd,EAAK5iB,MAAMtF,IAAUk0C,EAAgBtrB,EAAc,KACnDV,EAAK5iB,MAAMqW,OAAS,IAGtBwM,EAAI7iB,MAAMtF,KAAQ5H,KAAK+F,MAAMgqB,IAAItd,OAAS,EAAK,MAGjD5S,EAAOD,QAAUwC,GAKb,SAASvC,EAAQD,EAASM,GAc9B,QAASmC,GAAWsQ,EAAM0nB,EAAY3rB,GAcpC,GAbA1O,KAAK+F,OACHgqB,KACEnoB,IAAK,EACL4K,MAAO,EACPC,OAAQ,GAEVod,SACEpd,OAAQ,EACRspC,WAAY,IAKZppC,GACgBpM,QAAdoM,EAAK9C,MACP,KAAM,IAAIjM,OAAM,oCAAsC+O,EAI1DzQ,GAAK3B,KAAKP,KAAM2S,EAAM0nB,EAAY3rB,GAhCpC,GAAIxM,GAAOhC,EAAoB,GAmC/BmC,GAAU+Q,UAAY,GAAIlR,GAAM,KAAM,KAAM,MAO5CG,EAAU+Q,UAAUi8B,UAAY,SAAS3Z,GAGvC,GAAIjD,IAAYiD,EAAM5lB,IAAM4lB,EAAM7lB,OAAS,CAC3C,OAAQ7P,MAAK2S,KAAK9C,MAAQ6lB,EAAM7lB,MAAQ4iB,GAAczyB,KAAK2S,KAAK9C,MAAQ6lB,EAAM5lB,IAAM2iB,GAMtFpwB,EAAU+Q,UAAUsO,OAAS,WAC3B,GAAIsO,GAAMhwB,KAAKgwB,GA0Bf,IAzBKA,IAEHhwB,KAAKgwB,OACLA,EAAMhwB,KAAKgwB,IAGXA,EAAI7d,MAAQX,SAASM,cAAc,OAInCke,EAAIH,QAAUre,SAASM,cAAc,OACrCke,EAAIH,QAAQ9nB,UAAY,UACxBioB,EAAI7d,MAAMT,YAAYse,EAAIH,SAG1BG,EAAID,IAAMve,SAASM,cAAc,OACjCke,EAAI7d,MAAMT,YAAYse,EAAID,KAG1BC,EAAI7d,MAAM,iBAAmBnS,KAE7BA,KAAKwtC,OAAQ,IAIVxtC,KAAKmlC,OACR,KAAM,IAAIvhC,OAAM,yCAElB,KAAKosB,EAAI7d,MAAMrI,WAAY,CACzB,GAAIkjC,GAAahtC,KAAKmlC,OAAOnV,IAAIgd,UACjC,KAAKA,EACH,KAAM,IAAIppC,OAAM,iEAElBopC,GAAWt7B,YAAYse,EAAI7d,OAQ7B,GANAnS,KAAKytC,WAAY,EAMbztC,KAAKwtC,MAAO,CACdxtC,KAAKi7C,gBAAgBj7C,KAAKgwB,IAAIH,SAC9B7vB,KAAKm7C,aAAan7C,KAAKgwB,IAAI7d,OAC3BnS,KAAKq7C,sBAAsBr7C,KAAKgwB,IAAI7d,OACpCnS,KAAKy7C,aAAaz7C,KAAKgwB,IAAI7d,MAG3B,IAAIpK,IAAa/H,KAAK2S,KAAK5K,UAAW,IAAM/H,KAAK2S,KAAK5K,UAAY,KAC7D/H,KAAKwzC,SAAW,YAAc,GACnCxjB,GAAI7d,MAAMpK,UAAa,aAAeA,EACtCioB,EAAID,IAAIhoB,UAAa,WAAaA,EAGlC/H,KAAKwS,MAAQwd,EAAI7d,MAAMke,YACvBrwB,KAAKyS,OAASud,EAAI7d,MAAMoe,aACxBvwB,KAAK+F,MAAMgqB,IAAIvd,MAAQwd,EAAID,IAAIM,YAC/BrwB,KAAK+F,MAAMgqB,IAAItd,OAASud,EAAID,IAAIQ,aAChCvwB,KAAK+F,MAAM8pB,QAAQpd,OAASud,EAAIH,QAAQU,aAGxCP,EAAIH,QAAQ3iB,MAAM6uC,WAAa,EAAI/7C,KAAK+F,MAAMgqB,IAAIvd,MAAQ,KAG1Dwd,EAAID,IAAI7iB,MAAMtF,KAAQ5H,KAAKyS,OAASzS,KAAK+F,MAAMgqB,IAAItd,QAAU,EAAK,KAClEud,EAAID,IAAI7iB,MAAM1F,KAAQxH,KAAK+F,MAAMgqB,IAAIvd,MAAQ,EAAK,KAElDxS,KAAKwtC,OAAQ,EAGfxtC,KAAK86C,qBAAqB9qB,EAAI7d,QAOhC9P,EAAU+Q,UAAU80B,KAAO,WACpBloC,KAAKytC,WACRztC,KAAK0hB,UAOTrf,EAAU+Q,UAAU60B,KAAO,WACrBjoC,KAAKytC,YACHztC,KAAKgwB,IAAI7d,MAAMrI,YACjB9J,KAAKgwB,IAAI7d,MAAMrI,WAAWsH,YAAYpR,KAAKgwB,IAAI7d,OAGjDnS,KAAK4H,IAAM,KACX5H,KAAKwH,KAAO,KAEZxH,KAAKytC,WAAY,IAQrBprC,EAAU+Q,UAAU87B,YAAc,WAChC,GAAIr/B,GAAQ7P,KAAKq6B,WAAWnF,SAASl1B,KAAK2S,KAAK9C,MAE/C7P,MAAKwH,KAAOqI,EAAQ7P,KAAK+F,MAAMgqB,IAAIvd,MAGnCxS,KAAKgwB,IAAI7d,MAAMjF,MAAM1F,KAAOxH,KAAKwH,KAAO,MAO1CnF,EAAU+Q,UAAU06B,YAAc,WAChC,GAAItZ,GAAcx0B,KAAK0O,QAAQ8lB,YAC3BriB,EAAQnS,KAAKgwB,IAAI7d,KAGnBA,GAAMjF,MAAMtF,IADK,OAAf4sB,EACgBx0B,KAAK4H,IAAM,KAGV5H,KAAKmlC,OAAO1yB,OAASzS,KAAK4H,IAAM5H,KAAKyS,OAAU,MAItE5S,EAAOD,QAAUyC,GAKb,SAASxC,EAAQD,EAASM,GAe9B,QAASoC,GAAWqQ,EAAM0nB,EAAY3rB,GASpC,GARA1O,KAAK+F,OACH8pB,SACErd,MAAO,IAGXxS,KAAK8jB,UAAW,EAGZnR,EAAM,CACR,GAAkBpM,QAAdoM,EAAK9C,MACP,KAAM,IAAIjM,OAAM,oCAAsC+O,EAAKtS,GAE7D,IAAgBkG,QAAZoM,EAAK7C,IACP,KAAM,IAAIlM,OAAM,kCAAoC+O,EAAKtS,IAI7D6B,EAAK3B,KAAKP,KAAM2S,EAAM0nB,EAAY3rB,GA/BpC,GAAIm3B,GAAS3lC,EAAoB,IAC7BgC,EAAOhC,EAAoB,GAiC/BoC,GAAU8Q,UAAY,GAAIlR,GAAM,KAAM,KAAM,MAE5CI,EAAU8Q,UAAUuoC,cAAgB,aAOpCr5C,EAAU8Q,UAAUi8B,UAAY,SAAS3Z,GAEvC,MAAQ11B,MAAK2S,KAAK9C,MAAQ6lB,EAAM5lB,KAAS9P,KAAK2S,KAAK7C,IAAM4lB,EAAM7lB,OAMjEvN,EAAU8Q,UAAUsO,OAAS,WAC3B,GAAIsO,GAAMhwB,KAAKgwB,GAsBf,IArBKA,IAEHhwB,KAAKgwB,OACLA,EAAMhwB,KAAKgwB,IAGXA,EAAI+gB,IAAMv/B,SAASM,cAAc,OAIjCke,EAAIH,QAAUre,SAASM,cAAc,OACrCke,EAAIH,QAAQ9nB,UAAY,UACxBioB,EAAI+gB,IAAIr/B,YAAYse,EAAIH,SAGxBG,EAAI+gB,IAAI,iBAAmB/wC,KAE3BA,KAAKwtC,OAAQ,IAIVxtC,KAAKmlC,OACR,KAAM,IAAIvhC,OAAM,yCAElB,KAAKosB,EAAI+gB,IAAIjnC,WAAY,CACvB,GAAIkjC,GAAahtC,KAAKmlC,OAAOnV,IAAIgd,UACjC,KAAKA,EACH,KAAM,IAAIppC,OAAM,iEAElBopC,GAAWt7B,YAAYse,EAAI+gB,KAQ7B,GANA/wC,KAAKytC,WAAY,EAMbztC,KAAKwtC,MAAO,CACdxtC,KAAKi7C,gBAAgBj7C,KAAKgwB,IAAIH,SAC9B7vB,KAAKm7C,aAAan7C,KAAKgwB,IAAI+gB,KAC3B/wC,KAAKq7C,sBAAsBr7C,KAAKgwB,IAAI+gB,KACpC/wC,KAAKy7C,aAAaz7C,KAAKgwB,IAAI+gB,IAG3B,IAAIhpC,IAAa/H,KAAK2S,KAAK5K,UAAa,IAAM/H,KAAK2S,KAAK5K,UAAa,KAChE/H,KAAKwzC,SAAW,YAAc,GACnCxjB,GAAI+gB,IAAIhpC,UAAY/H,KAAK27C,cAAgB5zC,EAGzC/H,KAAK8jB,SAA6D,WAAlDrc,OAAO0tC,iBAAiBnlB,EAAIH,SAAS/L,SAKrD9jB,KAAKgwB,IAAIH,QAAQ3iB,MAAM8uC,SAAW,OAClCh8C,KAAK+F,MAAM8pB,QAAQrd,MAAQxS,KAAKgwB,IAAIH,QAAQQ,YAC5CrwB,KAAKyS,OAASzS,KAAKgwB,IAAI+gB,IAAIxgB,aAC3BvwB,KAAKgwB,IAAIH,QAAQ3iB,MAAM8uC,SAAW,GAElCh8C,KAAKwtC,OAAQ,EAGfxtC,KAAK86C,qBAAqB9qB,EAAI+gB,KAC9B/wC,KAAKi8C,mBACLj8C,KAAKk8C,qBAOP55C,EAAU8Q,UAAU80B,KAAO,WACpBloC,KAAKytC,WACRztC,KAAK0hB,UAQTpf,EAAU8Q,UAAU60B,KAAO,WACzB,GAAIjoC,KAAKytC,UAAW,CAClB,GAAIsD,GAAM/wC,KAAKgwB,IAAI+gB,GAEfA,GAAIjnC,YACNinC,EAAIjnC,WAAWsH,YAAY2/B,GAG7B/wC,KAAK4H,IAAM,KACX5H,KAAKwH,KAAO,KAEZxH,KAAKytC,WAAY,IAQrBnrC,EAAU8Q,UAAU87B,YAAc,WAChC,GAGIiN,GACA/rB,EAJAgsB,EAAcp8C,KAAKmlC,OAAO3yB,MAC1B3C,EAAQ7P,KAAKq6B,WAAWnF,SAASl1B,KAAK2S,KAAK9C,OAC3CC,EAAM9P,KAAKq6B,WAAWnF,SAASl1B,KAAK2S,KAAK7C,MAKhCssC,EAATvsC,IACFA,GAASusC,GAEPtsC,EAAM,EAAIssC,IACZtsC,EAAM,EAAIssC,EAEZ,IAAIC,GAAWp3C,KAAK0H,IAAImD,EAAMD,EAAO,EAoBrC,QAlBI7P,KAAK8jB,UACP9jB,KAAKwH,KAAOqI,EACZ7P,KAAKwS,MAAQ6pC,EAAWr8C,KAAK+F,MAAM8pB,QAAQrd,MAC3C4d,EAAepwB,KAAK+F,MAAM8pB,QAAQrd,QAOlCxS,KAAKwH,KAAOqI,EACZ7P,KAAKwS,MAAQ6pC,EACbjsB,EAAenrB,KAAK8G,IAAI+D,EAAMD,EAAQ,EAAI7P,KAAK0O,QAAQuV,QAASjkB,KAAK+F,MAAM8pB,QAAQrd,QAGrFxS,KAAKgwB,IAAI+gB,IAAI7jC,MAAM1F,KAAOxH,KAAKwH,KAAO,KACtCxH,KAAKgwB,IAAI+gB,IAAI7jC,MAAMsF,MAAQ6pC,EAAW,KAE9Br8C,KAAK0O,QAAQ4gC,OACnB,IAAK,OACHtvC,KAAKgwB,IAAIH,QAAQ3iB,MAAM1F,KAAO,GAC9B,MAEF,KAAK,QACHxH,KAAKgwB,IAAIH,QAAQ3iB,MAAM1F,KAAOvC,KAAK0H,IAAK0vC,EAAWjsB,EAAe,EAAIpwB,KAAK0O,QAAQuV,QAAU,GAAK,IAClG,MAEF,KAAK,SACHjkB,KAAKgwB,IAAIH,QAAQ3iB,MAAM1F,KAAOvC,KAAK0H,KAAK0vC,EAAWjsB,EAAe,EAAIpwB,KAAK0O,QAAQuV,SAAW,EAAG,GAAK,IACtG,MAEF,SAIMk4B,EAFAn8C,KAAK8jB,SACHhU,EAAM,EACM7K,KAAK0H,KAAKkD,EAAO,IAGhBugB,EAIL,EAARvgB,EACY5K,KAAK8G,KAAK8D,EACnBC,EAAMD,EAAQugB,EAAe,EAAIpwB,KAAK0O,QAAQuV,SAIrC,EAGlBjkB,KAAKgwB,IAAIH,QAAQ3iB,MAAM1F,KAAO20C,EAAc,OAQlD75C,EAAU8Q,UAAU06B,YAAc,WAChC,GAAItZ,GAAcx0B,KAAK0O,QAAQ8lB,YAC3Buc,EAAM/wC,KAAKgwB,IAAI+gB,GAGjBA,GAAI7jC,MAAMtF,IADO,OAAf4sB,EACcx0B,KAAK4H,IAAM,KAGV5H,KAAKmlC,OAAO1yB,OAASzS,KAAK4H,IAAM5H,KAAKyS,OAAU,MAQpEnQ,EAAU8Q,UAAU6oC,iBAAmB,WACrC,GAAIj8C,KAAKwzC,UAAYxzC,KAAK0O,QAAQ+gC,SAASC,aAAe1vC,KAAKgwB,IAAIssB,SAAU,CAE3E,GAAIA,GAAW9qC,SAASM,cAAc,MACtCwqC,GAASv0C,UAAY,YACrBu0C,EAAS7I,aAAezzC,KAGxB6lC,EAAOyW,GACL/yC,gBAAgB,IACfiK,GAAG,OAAQ,cAIdxT,KAAKgwB,IAAI+gB,IAAIr/B,YAAY4qC,GACzBt8C,KAAKgwB,IAAIssB,SAAWA,OAEZt8C,KAAKwzC,UAAYxzC,KAAKgwB,IAAIssB,WAE9Bt8C,KAAKgwB,IAAIssB,SAASxyC,YACpB9J,KAAKgwB,IAAIssB,SAASxyC,WAAWsH,YAAYpR,KAAKgwB,IAAIssB,UAEpDt8C,KAAKgwB,IAAIssB,SAAW,OAQxBh6C,EAAU8Q,UAAU8oC,kBAAoB,WACtC,GAAIl8C,KAAKwzC,UAAYxzC,KAAK0O,QAAQ+gC,SAASC,aAAe1vC,KAAKgwB,IAAIusB,UAAW,CAE5E,GAAIA,GAAY/qC,SAASM,cAAc,MACvCyqC,GAAUx0C,UAAY,aACtBw0C,EAAU7I,cAAgB1zC,KAG1B6lC,EAAO0W,GACLhzC,gBAAgB,IACfiK,GAAG,OAAQ,cAIdxT,KAAKgwB,IAAI+gB,IAAIr/B,YAAY6qC,GACzBv8C,KAAKgwB,IAAIusB,UAAYA,OAEbv8C,KAAKwzC,UAAYxzC,KAAKgwB,IAAIusB,YAE9Bv8C,KAAKgwB,IAAIusB,UAAUzyC,YACrB9J,KAAKgwB,IAAIusB,UAAUzyC,WAAWsH,YAAYpR,KAAKgwB,IAAIusB,WAErDv8C,KAAKgwB,IAAIusB,UAAY,OAIzB18C,EAAOD,QAAU0C,GAKb,SAASzC,EAAQD,EAASM,GAkC9B,QAASgD,GAASsW,EAAW7G,EAAMjE,GACjC,KAAM1O,eAAgBkD,IACpB,KAAM,IAAIuW,aAAY,mDAGxBzZ,MAAKw8C,0BACLx8C,KAAKy8C,0BAGLz8C,KAAK0Z,iBAAmBF,EAGxBxZ,KAAK08C,kBAAoB,GACzB18C,KAAK28C,eAAiB,IAAO38C,KAAK08C,kBAClC18C,KAAK48C,WAAa,EAClB58C,KAAK68C,YAAc,EACnB78C,KAAK88C,gBAAiB,EACtB98C,KAAK+8C,wBAA0B,GAE/B/8C,KAAKg9C,cAAe,EAEpBh9C,KAAKi9C,kBAAoB/pC,IAAI,KAAKgqC,KAAK,KAAKC,SAAS,KAAKC,QAAQ,KAAKC,IAAI,MAG3Er9C,KAAKs0B,gBACHgpB,OACEC,KAAM,EACNC,UAAW,GACXC,UAAW,GACX/xB,OAAQ,GACRgyB,MAAO,UACPC,MAAOp3C,OACP4gB,SAAU,GACVC,SAAU,GACVw2B,UAAW,QACXC,SAAU,GACVC,SAAU,UACVC,SAAUx3C,OACVy3C,gBAAiB,EACjBC,gBAAiB,QACjBC,MAAO,GACP9yC,OACIiB,OAAQ,UACRD,WAAY,UACdE,WACED,OAAQ,UACRD,WAAY,WAEdG,OACEF,OAAQ,UACRD,WAAY,YAGhB8F,MAAO3L,OACP0Z,YAAa,EACbk+B,oBAAqB53C,QAEvB63C,OACEj3B,SAAU,EACVC,SAAU,GACV5U,MAAO,EACP6rC,yBAA0B,EAC1BC,WAAY,IACZpxC,MAAO,OACP9B,OACEA,MAAM,UACNkB,UAAU,UACVC,MAAO,WAETqxC,UAAW,UACXC,SAAU,GACVC,SAAU,QACVC,SAAU,QACVC,gBAAiB,EACjBC,gBAAiB,QACjBM,eAAe,aACfC,iBAAkB,EAClBC,MACE/4C,OAAQ,GACRg5C,IAAK,EACLC,UAAWp4C,QAEbq4C,aAAc,QAEhBC,kBAAiB,EACjBC,SACEC,WACEpwC,SAAS,EACTqwC,cAAe,EACfC,sBAAuB,KACvBC,eAAgB,GAChBC,aAAc,GACdC,eAAgB,IAChBC,QAAS,KAEXC,WACEJ,eAAgB,EAChBC,aAAc,IACdC,eAAgB,IAChBG,aAAc,IACdF,QAAS,KAEXG,uBACE7wC,SAAS,EACTuwC,eAAgB,EAChBC,aAAc,IACdC,eAAgB,IAChBG,aAAc,IACdF,QAAS,KAEXA,QAAS,KACTH,eAAgB,KAChBC,aAAc,KACdC,eAAgB,MAElBK,YACE9wC,SAAS,EACT+wC,gBAAiB,IACjBC,iBAAiB,IACjBC,cAAc,IACdC,eAAgB,GAChBC,qBAAsB,GACtBC,gBAAiB,IACjBC,oBAAqB,GACrBC,mBAAoB,EACpBC,YAAa,IACbC,mBAAoB,GACpBC,sBAAuB,GACvBC,WAAY,GACZC,aAAc9tC,MAAQ,EACRC,OAAQ,EACRiZ,OAAQ,GACtB60B,sBAAuB,IACvBC,kBAAmB,GACnBC,uBAAwB,GAE1BC,YACE/xC,SAAS,GAEXgyC,UACEhyC,SAAS,EACTiyC,OAAQ5uC,EAAG,GAAIC,EAAG,GAAIquB,KAAM,MAE9BugB,kBACElyC,SAAS,EACTmyC,kBAAkB,GAEpBC,oBACEpyC,SAAQ,EACRqyC,gBAAiB,IACjBC,YAAa,IACb9lB,UAAW,KACX+lB,OAAQ,WAEVC,wBAAwB,EACxBC,cACEzyC,SAAS,EACT0yC,SAAS,EACTx6C,KAAM,aACNy6C,UAAW,IAEbC,YAAc,GACdC,YAAc,GACdC,WAAW,EACXC,wBAAyB,IACzBC,uBAAuB,EACvBjd,OAAQ,KACRQ,QAASA,EACT7e,SACE5N,MAAO,IACPmlC,UAAW,QACXC,SAAU,GACVC,SAAU,UACV1yC,OACEiB,OAAQ,OACRD,WAAY,YAGhBw1C,aAAa,EACbC,WAAW,EACXjkB,UAAU,EACVrxB,OAAO,EACPu1C,iBAAiB,EACjBC,iBAAiB,EACjBvvC,MAAQ,OACRC,OAAS,OACT+8B,YAAY,GAEdxvC,KAAKgiD,UAAYrhD,EAAK0E,UAAWrF,KAAKs0B,gBACtCt0B,KAAKiiD,WAAa,EAGlBjiD,KAAKkiD,UAAY5E,SAASc,UAC1Bp+C,KAAKmiD,oBAAqB,EAC1BniD,KAAKoiD,mBAAqBC,YAAaC,SAGvCtiD,KAAKuiD,eAAiB,EAAEviD,KAAK08C,kBAC7B18C,KAAKwiD,wBAA0B,iBAC/BxiD,KAAKyiD,WAAa,EAClBziD,KAAK0iD,YAAc,EACnB1iD,KAAK2iD,YAAc,EACnB3iD,KAAK4iD,kBAAoB,EACzB5iD,KAAK6iD,kBAAoB,EACzB7iD,KAAK8iD,eAAiB,KACtB9iD,KAAK+iD,mBAAqB,KAC1B/iD,KAAKgjD,UAAY,CAGjB,IAAI7/C,GAAUnD,IACdA,MAAKo0B,OAAS,GAAI/wB,GAClBrD,KAAKijD,OAAS,GAAI3/C,GAClBtD,KAAKijD,OAAOC,kBAAkB,WAC5B//C,EAAQggD,YAIVnjD,KAAKojD,WAAa,EAClBpjD,KAAKqjD,WAAa,EAClBrjD,KAAKsjD,cAAgB,EAIrBtjD,KAAKujD,qBAELvjD,KAAK20B,UAEL30B,KAAKwjD,oBAELxjD,KAAKyjD,qBAELzjD,KAAK0jD,uBAEL1jD,KAAK2jD,uBAIL3jD,KAAK4jD,gBAAgB5jD,KAAKuf,MAAME,YAAc,EAAGzf,KAAKuf,MAAMuF,aAAe,GAC3E9kB,KAAKid,UAAU,GACfjd,KAAKmT,WAAWzE,GAGhB1O,KAAK6jD,kBAAmB,EACxB7jD,KAAK8jD,mBACL9jD,KAAK+jD,sBAAuB,EAC5B/jD,KAAKgkD,YAAa,EAClBhkD,KAAK0hD,wBAA0B,KAC/B1hD,KAAKikD,eAAgB,EAGrBjkD,KAAKkkD,oBACLlkD,KAAKmkD,0BACLnkD,KAAKokD,eACLpkD,KAAKs9C,SACLt9C,KAAKo+C,SAGLp+C,KAAKqkD,eAAqBryC,EAAK,EAAEC,EAAK,GACtCjS,KAAKskD,mBAAqBtyC,EAAK,EAAEC,EAAK,GACtCjS,KAAKukD,iBAAmBvyC,EAAK,EAAEC,EAAK,GACpCjS,KAAKwkD,cACLxkD,KAAKkd,MAAQ,EACbld,KAAKykD,cAAgBzkD,KAAKkd,MAG1Bld,KAAK0kD,UAAY,KACjB1kD,KAAK2kD,UAAY,KAGjB3kD,KAAK4kD,gBACH1xC,IAAO,SAAU1J,EAAOuK,GACtB5Q,EAAQ0hD,UAAU9wC,EAAO9R,OACzBkB,EAAQ0M,SAEViF,OAAU,SAAUtL,EAAOuK,GACzB5Q,EAAQ2hD,aAAa/wC,EAAO9R,MAAO8R,EAAOpB,MAC1CxP,EAAQ0M,SAEVyG,OAAU,SAAU9M,EAAOuK,GACzB5Q,EAAQ4hD,aAAahxC,EAAO9R,OAC5BkB,EAAQ0M,UAGZ7P,KAAKglD,gBACH9xC,IAAO,SAAU1J,EAAOuK,GACtB5Q,EAAQ8hD,UAAUlxC,EAAO9R,OACzBkB,EAAQ0M,SAEViF,OAAU,SAAUtL,EAAOuK,GACzB5Q,EAAQ+hD,aAAanxC,EAAO9R,OAC5BkB,EAAQ0M,SAEVyG,OAAU,SAAU9M,EAAOuK,GACzB5Q,EAAQgiD,aAAapxC,EAAO9R,OAC5BkB,EAAQ0M,UAKZ7P,KAAKolD,QAAS,EACdplD,KAAKqlD,MAAQ9+C,OAGbvG,KAAKiY,QAAQtF,EAAK3S,KAAKgiD,UAAUvC,WAAW9wC,SAAW3O,KAAKgiD,UAAUjB,mBAAmBpyC,SAGzF3O,KAAKg9C,cAAe,EAC6B,GAA7Ch9C,KAAKgiD,UAAUjB,mBAAmBpyC,QACpC3O,KAAKslD,2BAI2B,GAA5BtlD,KAAKgiD,UAAUP,WACjBzhD,KAAKulD,WAAWh/C,QAAW,EAAKvG,KAAKgiD,UAAUvC,WAAW9wC,SAK1D3O,KAAKgiD,UAAUvC,WAAW9wC,SAC5B3O,KAAKwlD,sBA/VT,GAAIxoC,GAAU9c,EAAoB,IAC9B2lC,EAAS3lC,EAAoB,IAC7BulD,EAAWvlD,EAAoB,IAC/BS,EAAOT,EAAoB,GAC3B0+B,EAAa1+B,EAAoB,IACjCW,EAAUX,EAAoB,GAC9BY,EAAWZ,EAAoB,GAC/BuD,EAAYvD,EAAoB,IAChCwD,EAAcxD,EAAoB,IAClCmD,EAASnD,EAAoB,IAC7BoD,EAASpD,EAAoB,IAC7BqD,EAAOrD,EAAoB,IAC3BkD,EAAOlD,EAAoB,IAC3BsD,EAAQtD,EAAoB,IAC5BwlD,EAAcxlD,EAAoB,IAClCylD,EAAYzlD,EAAoB,IAChCglC,EAAUhlC,EAAoB,GAGlCA,GAAoB,IAiVpB8c,EAAQ9Z,EAAQkQ,WAOhBlQ,EAAQkQ,UAAUopC,wBAA0B,WAC1C,GAAIoJ,GAAc18C,UAAUC,UAAUy7B,aACtC5kC,MAAK6lD,iBAAkB,EACgB,IAAnCD,EAAYl/C,QAAQ,YACtB1G,KAAK6lD,iBAAkB,EAEiB,IAAjCD,EAAYl/C,QAAQ,WACvBk/C,EAAYl/C,QAAQ,WAAa,KACnC1G,KAAK6lD,iBAAkB,IAa7B3iD,EAAQkQ,UAAU0yC,eAAiB,WAIjC,IAAK,GAHDC,GAAUv0C,SAASw0C,qBAAsB,UAGpCzgD,EAAI,EAAGA,EAAIwgD,EAAQrgD,OAAQH,IAAK,CACvC,GAAI0gD,GAAMF,EAAQxgD,GAAG0gD,IACjB3hD,EAAQ2hD,GAAO,qBAAqBzhD,KAAKyhD,EAC7C,IAAI3hD,EAEF,MAAO2hD,GAAI1gB,UAAU,EAAG0gB,EAAIvgD,OAASpB,EAAM,GAAGoB,QAIlD,MAAO,OAQTxC,EAAQkQ,UAAU8yC,UAAY,WAC5B,GAAsDC,GAAlDC,EAAO,IAAKC,EAAO,KAAMC,EAAO,IAAKC,EAAO,IAChD,KAAK,GAAIC,KAAUxmD,MAAKs9C,MAClBt9C,KAAKs9C,MAAMz3C,eAAe2gD,KAC5BL,EAAOnmD,KAAKs9C,MAAMkJ,GACdF,EAAQH,EAAKM,YAAgB,OAAIH,EAAOH,EAAKM,YAAYj/C,MACzD++C,EAAQJ,EAAKM,YAAiB,QAAIF,EAAOJ,EAAKM,YAAYn/B,OAC1D8+B,EAAQD,EAAKM,YAAkB,SAAIL,EAAOD,EAAKM,YAAYljC,QAC3D8iC,EAAQF,EAAKM,YAAe,MAAIJ,EAAOF,EAAKM,YAAY7+C,KAMhE,OAHY,MAAR0+C,GAAuB,MAARC,GAAwB,KAARH,GAAuB,MAARC,IAChDD,EAAO,EAAGC,EAAO,EAAGC,EAAO,EAAGC,EAAO,IAE/BD,KAAMA,EAAMC,KAAMA,EAAMH,KAAMA,EAAMC,KAAMA,IASpDnjD,EAAQkQ,UAAUszC,YAAc,SAAShxB,GACvC,OAAQ1jB,EAAI,IAAO0jB,EAAM6wB,KAAO7wB,EAAM4wB,MAC9Br0C,EAAI,IAAOyjB,EAAM2wB,KAAO3wB,EAAM0wB,QAUxCljD,EAAQkQ,UAAUmyC,WAAa,SAASoB,EAAkBC,EAAaC,GACrE7mD,KAAKmjD,SAAQ,GAEO58C,SAAhBqgD,IACFA,GAAc,GAEKrgD,SAAjBsgD,IACFA,GAAe,GAEQtgD,SAArBogD,IACFA,GAAmB,EAGrB,IACIG,GADApxB,EAAQ11B,KAAKkmD,WAGjB,IAAmB,GAAfU,EAAqB,CACvB,GAAIG,GAAgB/mD,KAAKokD,YAAY1+C,MAIjCohD,GAH+B,GAA/B9mD,KAAKgiD,UAAUZ,aACwB,GAArCphD,KAAKgiD,UAAUvC,WAAW9wC,SAC5Bo4C,GAAiB/mD,KAAKgiD,UAAUvC,WAAWC,gBAC/B,UAAYqH,EAAgB,WAAa,SAGzC,QAAUA,EAAgB,QAAU,SAIT,GAArC/mD,KAAKgiD,UAAUvC,WAAW9wC,SAC1Bo4C,GAAiB/mD,KAAKgiD,UAAUvC,WAAWC,gBACjC,YAAcqH,EAAgB,YAAc,cAG5C,YAAcA,EAAgB,aAAe,SAK7D,IAAIC,GAAS/hD,KAAK8G,IAAI/L,KAAKuf,MAAMC,OAAOC,YAAc,IAAKzf,KAAKuf,MAAMC,OAAOsF,aAAe,IAC5FgiC,IAAaE,MAEV,CACH,GAAIlP,GAAgD,IAApC7yC,KAAK6lB,IAAI4K,EAAM6wB,KAAO7wB,EAAM4wB,MACxCW,EAAgD,IAApChiD,KAAK6lB,IAAI4K,EAAM2wB,KAAO3wB,EAAM0wB,MAExCc,EAAalnD,KAAKuf,MAAMC,OAAOC,YAAeq4B,EAC9CqP,EAAannD,KAAKuf,MAAMC,OAAOsF,aAAemiC,CAElDH,GAA2BK,GAAdD,EAA4BA,EAAaC,EAGpDL,EAAY,IACdA,EAAY,EAId,IAAI36B,GAASnsB,KAAK0mD,YAAYhxB,EAC9B,IAAoB,GAAhBmxB,EAAuB,CACzB,GAAIn4C,IAAWmV,SAAUsI,EAAQjP,MAAO4pC,EAAWM,UAAWT,EAC9D3mD,MAAK8nB,OAAOpZ,GACZ1O,KAAKolD,QAAS,EACdplD,KAAK6P,YAGLsc,GAAOna,GAAK80C,EACZ36B,EAAOla,GAAK60C,EACZ36B,EAAOna,GAAK,GAAMhS,KAAKuf,MAAMC,OAAOC,YACpC0M,EAAOla,GAAK,GAAMjS,KAAKuf,MAAMC,OAAOsF,aACpC9kB,KAAKid,UAAU6pC,GACf9mD,KAAK4jD,iBAAiBz3B,EAAOna,GAAGma,EAAOla,IAS3C/O,EAAQkQ,UAAUi0C,qBAAuB,WACvCrnD,KAAKsnD,qBACL,KAAK,GAAIC,KAAOvnD,MAAKs9C,MACft9C,KAAKs9C,MAAMz3C,eAAe0hD,IAC5BvnD,KAAKokD,YAAYl8C,KAAKq/C,IAiB5BrkD,EAAQkQ,UAAU6E,QAAU,SAAStF,EAAMk0C,GAOzC,GANqBtgD,SAAjBsgD,IACFA,GAAe,GAGjB7mD,KAAKg9C,cAAe,EAEhBrqC,GAAQA,EAAKod,MAAQpd,EAAK2qC,OAAS3qC,EAAKyrC,OAC1C,KAAM,IAAI3kC,aAAY,iGAYxB,IAP+C,GAA3CzZ,KAAKgiD,UAAUnB,iBAAiBlyC,SAClC3O,KAAKwnD,wBAIPxnD,KAAKmT,WAAWR,GAAQA,EAAKjE,SAEzBiE,GAAQA,EAAKod,KAEf,GAAGpd,GAAQA,EAAKod,IAAK,CACnB,GAAI03B,GAAUhkD,EAAUikD,WAAW/0C,EAAKod,IAExC,YADA/vB,MAAKiY,QAAQwvC,QAIZ,IAAI90C,GAAQA,EAAKg1C,OAEpB,GAAGh1C,GAAQA,EAAKg1C,MAAO,CACrB,GAAIC,GAAYlkD,EAAYmkD,WAAWl1C,EAAKg1C,MAE5C,YADA3nD,MAAKiY,QAAQ2vC,QAKf5nD,MAAK8nD,UAAUn1C,GAAQA,EAAK2qC,OAC5Bt9C,KAAK+nD,UAAUp1C,GAAQA,EAAKyrC,MAE9Bp+C,MAAKgoD,mBACe,GAAhBnB,IAC+C,GAA7C7mD,KAAKgiD,UAAUjB,mBAAmBpyC,SACpC3O,KAAKioD,eACLjoD,KAAKslD,4BAIDtlD,KAAKgiD,UAAUP,WACjBzhD,KAAKkoD,aAGTloD,KAAK6P,SAEP7P,KAAKg9C,cAAe,GAOtB95C,EAAQkQ,UAAUD,WAAa,SAAUzE,GACvC,GAAIA,EAAS,CACX,GAAI9I,GACAuI,GAAU,QAAQ,QAAQ,eAAe,qBAAqB,aAAa,aAC7E,WAAW,mBAAmB,QAAQ,SAAS,aAAa,YAAY,WAAW,aAOrF,IAJAxN,EAAK8F,uBAAuB0H,EAAOnO,KAAKgiD,UAAWtzC,GACnD/N,EAAK8F,wBAAwB,SAASzG,KAAKgiD,UAAU1E,MAAO5uC,EAAQ4uC,OACpE38C,EAAK8F,wBAAwB,QAAQ,UAAUzG,KAAKgiD,UAAU5D,MAAO1vC,EAAQ0vC,OAEzE1vC,EAAQowC,UACVn+C,EAAK6N,aAAaxO,KAAKgiD,UAAUlD,QAASpwC,EAAQowC,QAAQ,aAC1Dn+C,EAAK6N,aAAaxO,KAAKgiD,UAAUlD,QAASpwC,EAAQowC,QAAQ,aAEtDpwC,EAAQowC,QAAQU,uBAAuB,CACzCx/C,KAAKgiD,UAAUjB,mBAAmBpyC,SAAU,EAC5C3O,KAAKgiD,UAAUlD,QAAQU,sBAAsB7wC,SAAU,EACvD3O,KAAKgiD,UAAUlD,QAAQC,UAAUpwC,SAAU,CAC3C;IAAK/I,IAAQ8I,GAAQowC,QAAQU,sBACvB9wC,EAAQowC,QAAQU,sBAAsB35C,eAAeD,KACvD5F,KAAKgiD,UAAUlD,QAAQU,sBAAsB55C,GAAQ8I,EAAQowC,QAAQU,sBAAsB55C,IAkDnG,GA5CI8I,EAAQihC,QAAQ3vC,KAAKi9C,iBAAiB/pC,IAAMxE,EAAQihC,OACpDjhC,EAAQy5C,SAASnoD,KAAKi9C,iBAAiBC,KAAOxuC,EAAQy5C,QACtDz5C,EAAQ05C,aAAapoD,KAAKi9C,iBAAiBE,SAAWzuC,EAAQ05C,YAC9D15C,EAAQ25C,YAAYroD,KAAKi9C,iBAAiBG,QAAU1uC,EAAQ25C,WAC5D35C,EAAQ45C,WAAWtoD,KAAKi9C,iBAAiBI,IAAM3uC,EAAQ45C,UAE3D3nD,EAAK6N,aAAaxO,KAAKgiD,UAAWtzC,EAAQ,gBAC1C/N,EAAK6N,aAAaxO,KAAKgiD,UAAWtzC,EAAQ,sBAC1C/N,EAAK6N,aAAaxO,KAAKgiD,UAAWtzC,EAAQ,cAC1C/N,EAAK6N,aAAaxO,KAAKgiD,UAAWtzC,EAAQ,cAC1C/N,EAAK6N,aAAaxO,KAAKgiD,UAAWtzC,EAAQ,YAC1C/N,EAAK6N,aAAaxO,KAAKgiD,UAAWtzC,EAAQ,oBAGtCA,EAAQmyC,mBACV7gD,KAAKuoD,SAAWvoD,KAAKgiD,UAAUnB,iBAAiBC,kBAK9CpyC,EAAQ0vC,QACkB73C,SAAxBmI,EAAQ0vC,MAAMhzC,QACZzK,EAAKuD,SAASwK,EAAQ0vC,MAAMhzC,QAC9BpL,KAAKgiD,UAAU5D,MAAMhzC,SACrBpL,KAAKgiD,UAAU5D,MAAMhzC,MAAMA,MAAQsD,EAAQ0vC,MAAMhzC,MACjDpL,KAAKgiD,UAAU5D,MAAMhzC,MAAMkB,UAAYoC,EAAQ0vC,MAAMhzC,MACrDpL,KAAKgiD,UAAU5D,MAAMhzC,MAAMmB,MAAQmC,EAAQ0vC,MAAMhzC,QAGf7E,SAA9BmI,EAAQ0vC,MAAMhzC,MAAMA,QAA0BpL,KAAKgiD,UAAU5D,MAAMhzC,MAAMA,MAAQsD,EAAQ0vC,MAAMhzC,MAAMA,OACnE7E,SAAlCmI,EAAQ0vC,MAAMhzC,MAAMkB,YAA0BtM,KAAKgiD,UAAU5D,MAAMhzC,MAAMkB,UAAYoC,EAAQ0vC,MAAMhzC,MAAMkB,WAC3E/F,SAA9BmI,EAAQ0vC,MAAMhzC,MAAMmB,QAA0BvM,KAAKgiD,UAAU5D,MAAMhzC,MAAMmB,MAAQmC,EAAQ0vC,MAAMhzC,MAAMmB,QAE3GvM,KAAKgiD,UAAU5D,MAAMQ,cAAe,GAGjClwC,EAAQ0vC,MAAMR,WACWr3C,SAAxBmI,EAAQ0vC,MAAMhzC,QACZzK,EAAKuD,SAASwK,EAAQ0vC,MAAMhzC,OAAmBpL,KAAKgiD,UAAU5D,MAAMR,UAAYlvC,EAAQ0vC,MAAMhzC,MAC3D7E,SAA9BmI,EAAQ0vC,MAAMhzC,MAAMA,QAAsBpL,KAAKgiD,UAAU5D,MAAMR,UAAYlvC,EAAQ0vC,MAAMhzC,MAAMA,SAK1GsD,EAAQ4uC,OACN5uC,EAAQ4uC,MAAMlyC,MAAO,CACvB,GAAIo9C,GAAc7nD,EAAKwK,WAAWuD,EAAQ4uC,MAAMlyC,MAChDpL,MAAKgiD,UAAU1E,MAAMlyC,MAAMgB,WAAao8C,EAAYp8C,WACpDpM,KAAKgiD,UAAU1E,MAAMlyC,MAAMiB,OAASm8C,EAAYn8C,OAChDrM,KAAKgiD,UAAU1E,MAAMlyC,MAAMkB,UAAUF,WAAao8C,EAAYl8C,UAAUF,WACxEpM,KAAKgiD,UAAU1E,MAAMlyC,MAAMkB,UAAUD,OAASm8C,EAAYl8C,UAAUD,OACpErM,KAAKgiD,UAAU1E,MAAMlyC,MAAMmB,MAAMH,WAAao8C,EAAYj8C,MAAMH,WAChEpM,KAAKgiD,UAAU1E,MAAMlyC,MAAMmB,MAAMF,OAASm8C,EAAYj8C,MAAMF,OAGhE,GAAIqC,EAAQ0lB,OACV,IAAK,GAAIq0B,KAAa/5C,GAAQ0lB,OAC5B,GAAI1lB,EAAQ0lB,OAAOvuB,eAAe4iD,GAAY,CAC5C,GAAIv2C,GAAQxD,EAAQ0lB,OAAOq0B,EAC3BzoD,MAAKo0B,OAAOlhB,IAAIu1C,EAAWv2C,GAKjC,GAAIxD,EAAQ2X,QAAS,CACnB,IAAKzgB,IAAQ8I,GAAQ2X,QACf3X,EAAQ2X,QAAQxgB,eAAeD,KACjC5F,KAAKgiD,UAAU37B,QAAQzgB,GAAQ8I,EAAQ2X,QAAQzgB,GAG/C8I,GAAQ2X,QAAQjb,QAClBpL,KAAKgiD,UAAU37B,QAAQjb,MAAQzK,EAAKwK,WAAWuD,EAAQ2X,QAAQjb,QAmBnE,GAfI,cAAgBsD,KACdA,EAAQg6C,WACL1oD,KAAK2oD,YACR3oD,KAAK2oD,UAAY,GAAIhD,GAAU3lD,KAAKuf,OACpCvf,KAAK2oD,UAAUn1C,GAAG,SAAUxT,KAAK4oD,gBAAgB7zB,KAAK/0B,QAIpDA,KAAK2oD,YACP3oD,KAAK2oD,UAAUp1C,gBACRvT,MAAK2oD,YAKdj6C,EAAQs4B,OACV,KAAM,IAAIpjC,OAAM,6EAMlB5D,MAAKujD,qBAELvjD,KAAK6oD,0BAEL7oD,KAAK8oD,0BAEL9oD,KAAK+oD,yBAIL/oD,KAAK4oD,kBAEL5oD,KAAK4kB,QAAQ5kB,KAAKgiD,UAAUxvC,MAAOxS,KAAKgiD,UAAUvvC,QAClDzS,KAAKolD,QAAS,EACdplD,KAAK6P,UAaT3M,EAAQkQ,UAAUuhB,QAAU,WAE1B,KAAO30B,KAAK0Z,iBAAiBiK,iBAC3B3jB,KAAK0Z,iBAAiBtI,YAAYpR,KAAK0Z,iBAAiBkK,WAe1D,IAZA5jB,KAAKuf,MAAQ/N,SAASM,cAAc,OACpC9R,KAAKuf,MAAMxX,UAAY,oBACvB/H,KAAKuf,MAAMrS,MAAM2W,SAAW,WAC5B7jB,KAAKuf,MAAMrS,MAAM4W,SAAW,SAK5B9jB,KAAKuf,MAAMC,OAAShO,SAASM,cAAc,UAC3C9R,KAAKuf,MAAMC,OAAOtS,MAAM2W,SAAW,WACnC7jB,KAAKuf,MAAM7N,YAAY1R,KAAKuf,MAAMC,QAE7Bxf,KAAKuf,MAAMC,OAAOyH,WAQlB,CACH,GAAID,GAAMhnB,KAAKuf,MAAMC,OAAOyH,WAAW,KACvCjnB,MAAKiiD,YAAcx6C,OAAOuhD,kBAAoB,IAAMhiC,EAAIiiC,8BAC9CjiC,EAAIkiC,2BACJliC,EAAImiC,0BACJniC,EAAIoiC,yBACJpiC,EAAIqiC,wBAA0B,GAExCrpD,KAAKuf,MAAMC,OAAOyH,WAAW,MAAMqiC,aAAatpD,KAAKiiD,WAAY,EAAG,EAAGjiD,KAAKiiD,WAAY,EAAG,OAhB1D,CACjC,GAAIl+B,GAAWvS,SAASM,cAAe,MACvCiS,GAAS7W,MAAM9B,MAAQ,MACvB2Y,EAAS7W,MAAM8W,WAAc,OAC7BD,EAAS7W,MAAM+W,QAAW,OAC1BF,EAASG,UAAa,mDACtBlkB,KAAKuf,MAAMC,OAAO9N,YAAYqS,GAgBhC,GAAI3P,GAAKpU,IACTA,MAAK8lC,QACL9lC,KAAKupD,SACLvpD,KAAK8D,OAAS+hC,EAAO7lC,KAAKuf,MAAMC,QAC9BumB,iBAAiB,IAEnB/lC,KAAK8D,OAAO0P,GAAG,MAAaY,EAAGo1C,OAAOz0B,KAAK3gB,IAC3CpU,KAAK8D,OAAO0P,GAAG,YAAaY,EAAGq1C,aAAa10B,KAAK3gB,IACjDpU,KAAK8D,OAAO0P,GAAG,OAAaY,EAAGgqB,QAAQrJ,KAAK3gB,IAC5CpU,KAAK8D,OAAO0P,GAAG,QAAaY,EAAGmqB,SAASxJ,KAAK3gB,IAC7CpU,KAAK8D,OAAO0P,GAAG,QAAaY,EAAGkqB,SAASvJ,KAAK3gB,IAC7CpU,KAAK8D,OAAO0P,GAAG,YAAaY,EAAG6pB,aAAalJ,KAAK3gB,IACjDpU,KAAK8D,OAAO0P,GAAG,OAAaY,EAAG8pB,QAAQnJ,KAAK3gB,IAC5CpU,KAAK8D,OAAO0P,GAAG,UAAaY,EAAG+pB,WAAWpJ,KAAK3gB,IAC/CpU,KAAK8D,OAAO0P,GAAG,aAAaY,EAAGiqB,cAActJ,KAAK3gB,IAClDpU,KAAK8D,OAAO0P,GAAG,iBAAiBY,EAAGiqB,cAActJ,KAAK3gB,IACtDpU,KAAK8D,OAAO0P,GAAG,YAAaY,EAAGs1C,kBAAkB30B,KAAK3gB,IAEtDpU,KAAK2pD,YAAc9jB,EAAO7lC,KAAKuf,OAC7BwmB,iBAAiB,IAEnB/lC,KAAK2pD,YAAYn2C,GAAG,UAAWY,EAAGw1C,WAAW70B,KAAK3gB,IAGlDpU,KAAK0Z,iBAAiBhI,YAAY1R,KAAKuf,QASzCrc,EAAQkQ,UAAUw1C,gBAAkB,WAClC,GAAIx0C,GAAKpU,IACauG,UAAlBvG,KAAKylD,UACPzlD,KAAKylD,SAASlyC,UAEhBvT,KAAKylD,SAAWA,IAEhBzlD,KAAKylD,SAASoE,QAEV7pD,KAAKgiD,UAAUrB,SAAShyC,SAAW3O,KAAK8pD,aAC1C9pD,KAAKylD,SAAS1wB,KAAK,KAAQ/0B,KAAK+pD,QAAQh1B,KAAK3gB,GAAQ,WACrDpU,KAAKylD,SAAS1wB,KAAK,KAAQ/0B,KAAKgqD,aAAaj1B,KAAK3gB,GAAK,SACvDpU,KAAKylD,SAAS1wB,KAAK,OAAQ/0B,KAAKiqD,UAAUl1B,KAAK3gB,GAAM,WACrDpU,KAAKylD,SAAS1wB,KAAK,OAAQ/0B,KAAKgqD,aAAaj1B,KAAK3gB,GAAK,SACvDpU,KAAKylD,SAAS1wB,KAAK,OAAQ/0B,KAAKkqD,UAAUn1B,KAAK3gB,GAAM,WACrDpU,KAAKylD,SAAS1wB,KAAK,OAAQ/0B,KAAKmqD,aAAap1B,KAAK3gB,GAAK,SACvDpU,KAAKylD,SAAS1wB,KAAK,QAAQ/0B,KAAKoqD,WAAWr1B,KAAK3gB,GAAK,WACrDpU,KAAKylD,SAAS1wB,KAAK,QAAQ/0B,KAAKmqD,aAAap1B,KAAK3gB,GAAK,SACvDpU,KAAKylD,SAAS1wB,KAAK,IAAQ/0B,KAAKqqD,QAAQt1B,KAAK3gB,GAAQ,WACrDpU,KAAKylD,SAAS1wB,KAAK,IAAQ/0B,KAAKsqD,UAAUv1B,KAAK3gB,GAAQ,SACvDpU,KAAKylD,SAAS1wB,KAAK,OAAQ/0B,KAAKqqD,QAAQt1B,KAAK3gB,GAAQ,WACrDpU,KAAKylD,SAAS1wB,KAAK,OAAQ/0B,KAAKsqD,UAAUv1B,KAAK3gB,GAAQ,SACvDpU,KAAKylD,SAAS1wB,KAAK,OAAQ/0B,KAAKuqD,SAASx1B,KAAK3gB,GAAO,WACrDpU,KAAKylD,SAAS1wB,KAAK,OAAQ/0B,KAAKsqD,UAAUv1B,KAAK3gB,GAAQ,SACvDpU,KAAKylD,SAAS1wB,KAAK,IAAQ/0B,KAAKuqD,SAASx1B,KAAK3gB,GAAO,WACrDpU,KAAKylD,SAAS1wB,KAAK,IAAQ/0B,KAAKsqD,UAAUv1B,KAAK3gB,GAAQ,SACvDpU,KAAKylD,SAAS1wB,KAAK,IAAQ/0B,KAAKqqD,QAAQt1B,KAAK3gB,GAAQ,WACrDpU,KAAKylD,SAAS1wB,KAAK,IAAQ/0B,KAAKsqD,UAAUv1B,KAAK3gB,GAAQ,SACvDpU,KAAKylD,SAAS1wB,KAAK,IAAQ/0B,KAAKuqD,SAASx1B,KAAK3gB,GAAO,WACrDpU,KAAKylD,SAAS1wB,KAAK,IAAQ/0B,KAAKsqD,UAAUv1B,KAAK3gB,GAAQ,SACvDpU,KAAKylD,SAAS1wB,KAAK,SAAS/0B,KAAKqqD,QAAQt1B,KAAK3gB,GAAO,WACrDpU,KAAKylD,SAAS1wB,KAAK,SAAS/0B,KAAKsqD,UAAUv1B,KAAK3gB,GAAO,SACvDpU,KAAKylD,SAAS1wB,KAAK,WAAW/0B,KAAKuqD,SAASx1B,KAAK3gB,GAAI,WACrDpU,KAAKylD,SAAS1wB,KAAK,WAAW/0B,KAAKsqD,UAAUv1B,KAAK3gB,GAAK,UAGV,GAA3CpU,KAAKgiD,UAAUnB,iBAAiBlyC,UAClC3O,KAAKylD,SAAS1wB,KAAK,MAAM/0B,KAAKwnD,sBAAsBzyB,KAAK3gB,IACzDpU,KAAKylD,SAAS1wB,KAAK,SAAS/0B,KAAKwqD,gBAAgBz1B,KAAK3gB,MAU1DlR,EAAQkQ,UAAUG,QAAU,WAC1BvT,KAAK6P,MAAQ,aACb7P,KAAK0hB,OAAS,aACd1hB,KAAKqlD,OAAQ,EAGbrlD,KAAKyqD,+BAGLzqD,KAAKylD,SAASoE,QAGd7pD,KAAK8D,OAAO4mD,UAGZ1qD,KAAK2T,MAEL3T,KAAK2qD,oBAAoB3qD,KAAK0Z,mBAGhCxW,EAAQkQ,UAAUu3C,oBAAsB,SAASC,GAC/C,KAAoC,GAA7BA,EAAUjnC,iBACf3jB,KAAK2qD,oBAAoBC,EAAUhnC,YACnCgnC,EAAUx5C,YAAYw5C,EAAUhnC,aAUpC1gB,EAAQkQ,UAAUy3C,YAAc,SAAU9sB,GACxC,OACE/rB,EAAG+rB,EAAMW,MAAQ/9B,EAAK0G,gBAAgBrH,KAAKuf,MAAMC,QACjDvN,EAAG8rB,EAAMY,MAAQh+B,EAAKgH,eAAe3H,KAAKuf,MAAMC,UASpDtc,EAAQkQ,UAAUkrB,SAAW,SAAU90B,IACjC,GAAInF,OAAO0C,UAAY/G,KAAKgjD,UAAY,MAC1ChjD,KAAK8lC,KAAK3F,QAAUngC,KAAK6qD,YAAYrhD,EAAMo2B,QAAQzT,QACnDnsB,KAAK8lC,KAAKglB,SAAU,EACpB9qD,KAAKupD,MAAMrsC,MAAQld,KAAK+qD,YAGxB/qD,KAAKgjD,WAAY,GAAI3+C,OAAO0C,UAE5B/G,KAAKgrD,aAAahrD,KAAK8lC,KAAK3F,WAQhCj9B,EAAQkQ,UAAU6qB,aAAe,SAAUz0B,GACzCxJ,KAAKirD,iBAAiBzhD,IAUxBtG,EAAQkQ,UAAU63C,iBAAmB,SAASzhD,GAElBjD,SAAtBvG,KAAK8lC,KAAK3F,SACZngC,KAAKs+B,SAAS90B,EAGhB,IAAI28C,GAAOnmD,KAAKkrD,WAAWlrD,KAAK8lC,KAAK3F,QASrC,IANAngC,KAAK8lC,KAAK3G,UAAW,EACrBn/B,KAAK8lC,KAAK4K,aACV1wC,KAAK8lC,KAAKpoB,YAAc1d,KAAKmrD,kBAC7BnrD,KAAK8lC,KAAK0gB,OAAS,KACnBxmD,KAAKikD,eAAgB,EAET,MAARkC,GAA4C,GAA5BnmD,KAAKgiD,UAAUH,UAAmB,CACpD7hD,KAAKikD,eAAgB,EACrBjkD,KAAK8lC,KAAK0gB,OAASL,EAAK9lD,GAEnB8lD,EAAKiF,cACRprD,KAAKqrD,cAAclF,GAAK,GAG1BnmD,KAAK6tB,KAAK,aAAay9B,QAAQtrD,KAAK62B,eAAeymB,OAGnD,KAAK,GAAIiO,KAAYvrD,MAAKwrD,aAAalO,MACrC,GAAIt9C,KAAKwrD,aAAalO,MAAMz3C,eAAe0lD,GAAW,CACpD,GAAIvnD,GAAShE,KAAKwrD,aAAalO,MAAMiO,GACjC1/C,GACFxL,GAAI2D,EAAO3D,GACX8lD,KAAMniD,EAGNgO,EAAGhO,EAAOgO,EACVC,EAAGjO,EAAOiO,EACVw5C,OAAQznD,EAAOynD,OACfC,OAAQ1nD,EAAO0nD,OAGjB1nD,GAAOynD,QAAS,EAChBznD,EAAO0nD,QAAS,EAEhB1rD,KAAK8lC,KAAK4K,UAAUxoC,KAAK2D,MAWjC3I,EAAQkQ,UAAU8qB,QAAU,SAAU10B,GACpCxJ,KAAK2rD,cAAcniD,IAUrBtG,EAAQkQ,UAAUu4C,cAAgB,SAASniD,GACzC,IAAIxJ,KAAK8lC,KAAKglB,QAAd,CAKA9qD,KAAK4rD,aAEL,IAAIzrB,GAAUngC,KAAK6qD,YAAYrhD,EAAMo2B,QAAQzT,QACzC/X,EAAKpU,KACL8lC,EAAO9lC,KAAK8lC,KACZ4K,EAAY5K,EAAK4K,SACrB,IAAIA,GAAaA,EAAUhrC,QAAsC,GAA5B1F,KAAKgiD,UAAUH,UAAmB,CAErE,GAAIhiB,GAASM,EAAQnuB,EAAI8zB,EAAK3F,QAAQnuB,EAClC8tB,EAASK,EAAQluB,EAAI6zB,EAAK3F,QAAQluB,CAGtCy+B,GAAUnoC,QAAQ,SAAUsD,GAC1B,GAAIs6C,GAAOt6C,EAAEs6C,IAERt6C,GAAE4/C,SACLtF,EAAKn0C,EAAIoC,EAAGy3C,qBAAqBz3C,EAAG03C,qBAAqBjgD,EAAEmG,GAAK6tB,IAG7Dh0B,EAAE6/C,SACLvF,EAAKl0C,EAAImC,EAAG23C,qBAAqB33C,EAAG43C,qBAAqBngD,EAAEoG,GAAK6tB,MAM/D9/B,KAAKolD,SACRplD,KAAKolD,QAAS,EACdplD,KAAK6P,aAKP,IAAkC,GAA9B7P,KAAKgiD,UAAUJ,YAAqB,CAEtC,GAA0Br7C,SAAtBvG,KAAK8lC,KAAK3F,QAEZ,WADAngC,MAAKirD,iBAAiBzhD,EAGxB,IAAI6jB,GAAQ8S,EAAQnuB,EAAIhS,KAAK8lC,KAAK3F,QAAQnuB,EACtCsb,EAAQ6S,EAAQluB,EAAIjS,KAAK8lC,KAAK3F,QAAQluB,CAE1CjS,MAAK4jD,gBACH5jD,KAAK8lC,KAAKpoB,YAAY1L,EAAIqb,EAC1BrtB,KAAK8lC,KAAKpoB,YAAYzL,EAAIqb,GAE5BttB,KAAKmjD,aASXjgD,EAAQkQ,UAAU+qB,WAAa,SAAU30B,GACvCxJ,KAAKisD,eAAeziD,IAItBtG,EAAQkQ,UAAU64C,eAAiB,WACjCjsD,KAAK8lC,KAAK3G,UAAW,CACrB,IAAIuR,GAAY1wC,KAAK8lC,KAAK4K,SACtBA,IAAaA,EAAUhrC,QACzBgrC,EAAUnoC,QAAQ,SAAUsD,GAE1BA,EAAEs6C,KAAKsF,OAAS5/C,EAAE4/C,OAClB5/C,EAAEs6C,KAAKuF,OAAS7/C,EAAE6/C,SAEpB1rD,KAAKolD,QAAS,EACdplD,KAAK6P,SAGL7P,KAAKmjD,UAEmB,GAAtBnjD,KAAKikD,cACPjkD,KAAK6tB,KAAK,WAAWy9B,aAGrBtrD,KAAK6tB,KAAK,WAAWy9B,QAAQtrD,KAAK62B,eAAeymB,SAQrDp6C,EAAQkQ,UAAUo2C,OAAS,SAAUhgD,GACnC,GAAI22B,GAAUngC,KAAK6qD,YAAYrhD,EAAMo2B,QAAQzT,OAC7CnsB,MAAKukD,gBAAkBpkB,EACvBngC,KAAKksD,WAAW/rB,IASlBj9B,EAAQkQ,UAAUq2C,aAAe,SAAUjgD,GACzC,GAAI22B,GAAUngC,KAAK6qD,YAAYrhD,EAAMo2B,QAAQzT,OAC7CnsB,MAAKmsD,iBAAiBhsB,IAQxBj9B,EAAQkQ,UAAUgrB,QAAU,SAAU50B,GACpC,GAAI22B,GAAUngC,KAAK6qD,YAAYrhD,EAAMo2B,QAAQzT,OAC7CnsB,MAAKukD,gBAAkBpkB,EACvBngC,KAAKosD,cAAcjsB,IAQrBj9B,EAAQkQ,UAAUw2C,WAAa,SAAUpgD,GACvC,GAAI22B,GAAUngC,KAAK6qD,YAAYrhD,EAAMo2B,QAAQzT,OAC7CnsB,MAAKqsD,iBAAiBlsB,IAQxBj9B,EAAQkQ,UAAUmrB,SAAW,SAAU/0B,GACrC,GAAI22B,GAAUngC,KAAK6qD,YAAYrhD,EAAMo2B,QAAQzT,OAE7CnsB,MAAK8lC,KAAKglB,SAAU,EACd,SAAW9qD,MAAKupD,QACpBvpD,KAAKupD,MAAMrsC,MAAQ,EAIrB,IAAIA,GAAQld,KAAKupD,MAAMrsC,MAAQ1T,EAAMo2B,QAAQ1iB,KAC7Cld,MAAKssD,MAAMpvC,EAAOijB,IAUpBj9B,EAAQkQ,UAAUk5C,MAAQ,SAASpvC,EAAOijB,GACxC,GAA+B,GAA3BngC,KAAKgiD,UAAUpkB,SAAkB,CACnC,GAAI2uB,GAAWvsD,KAAK+qD,WACR,MAAR7tC,IACFA,EAAQ,MAENA,EAAQ,KACVA,EAAQ,GAGV,IAAIsvC,GAAsB,IACRjmD,UAAdvG,KAAK8lC,MACmB,GAAtB9lC,KAAK8lC,KAAK3G,WACZqtB,EAAsBxsD,KAAKysD,YAAYzsD,KAAK8lC,KAAK3F,SAIrD,IAAIziB,GAAc1d,KAAKmrD,kBAEnBuB,EAAYxvC,EAAQqvC,EACpBI,GAAM,EAAID,GAAavsB,EAAQnuB,EAAI0L,EAAY1L,EAAI06C,EACnDE,GAAM,EAAIF,GAAavsB,EAAQluB,EAAIyL,EAAYzL,EAAIy6C,CASvD,IAPA1sD,KAAKwkD,YAAcxyC,EAAMhS,KAAK6rD,qBAAqB1rB,EAAQnuB,GACxCC,EAAMjS,KAAK+rD,qBAAqB5rB,EAAQluB,IAE3DjS,KAAKid,UAAUC,GACfld,KAAK4jD,gBAAgB+I,EAAIC,GACzB5sD,KAAK6sD,wBAEsB,MAAvBL,EAA6B,CAC/B,GAAIM,GAAuB9sD,KAAK+sD,YAAYP,EAC5CxsD,MAAK8lC,KAAK3F,QAAQnuB,EAAI86C,EAAqB96C,EAC3ChS,KAAK8lC,KAAK3F,QAAQluB,EAAI66C,EAAqB76C,EAY7C,MATAjS,MAAKmjD,UAEUjmC,EAAXqvC,EACFvsD,KAAK6tB,KAAK,QAASsN,UAAU,MAG7Bn7B,KAAK6tB,KAAK,QAASsN,UAAU,MAGxBje,IAYXha,EAAQkQ,UAAUirB,cAAgB,SAAS70B,GAEzC,GAAIklB,GAAQ,CAYZ,IAXIllB,EAAMmlB,WACRD,EAAQllB,EAAMmlB,WAAW,IAChBnlB,EAAMolB,SAGfF,GAASllB,EAAMolB,OAAO,GAMpBF,EAAO,CAGT,GAAIxR,GAAQld,KAAK+qD,YACbzqB,EAAO5R,EAAQ,EACP,GAARA,IACF4R,GAAe,EAAIA,GAErBpjB,GAAU,EAAIojB,CAGd,IAAIV,GAAUhB,EAAWsB,YAAYlgC,KAAMwJ,GACvC22B,EAAUngC,KAAK6qD,YAAYjrB,EAAQzT,OAGvCnsB,MAAKssD,MAAMpvC,EAAOijB,GAIpB32B,EAAMD,kBASRrG,EAAQkQ,UAAUs2C,kBAAoB,SAAUlgD,GAC9C,GAAIo2B,GAAUhB,EAAWsB,YAAYlgC,KAAMwJ,GACvC22B,EAAUngC,KAAK6qD,YAAYjrB,EAAQzT,OAGnCnsB,MAAKgtD,UACPhtD,KAAKitD,gBAAgB9sB,EAKvB,IAAI/rB,GAAKpU,KACLktD,EAAY,WACd94C,EAAG+4C,gBAAgBhtB,GAarB,IAXIngC,KAAKotD,YACP16B,cAAc1yB,KAAKotD,YAEhBptD,KAAK8lC,KAAK3G,WACbn/B,KAAKotD,WAAa7zC,WAAW2zC,EAAWltD,KAAKgiD,UAAU37B,QAAQ5N,QAOrC,GAAxBzY,KAAKgiD,UAAUz1C,MAAe,CAEhC,IAAK,GAAI8gD,KAAUrtD,MAAKkiD,SAAS9D,MAC3Bp+C,KAAKkiD,SAAS9D,MAAMv4C,eAAewnD,KACrCrtD,KAAKkiD,SAAS9D,MAAMiP,GAAQ9gD,OAAQ,QAC7BvM,MAAKkiD,SAAS9D,MAAMiP,GAK/B,IAAIrqC,GAAMhjB,KAAKkrD,WAAW/qB,EACf,OAAPnd,IACFA,EAAMhjB,KAAKstD,WAAWntB,IAEb,MAAPnd,GACFhjB,KAAKutD,aAAavqC,EAIpB,KAAK,GAAIwjC,KAAUxmD,MAAKkiD,SAAS5E,MAC3Bt9C,KAAKkiD,SAAS5E,MAAMz3C,eAAe2gD,KACjCxjC,YAAezf,IAAQyf,EAAI3iB,IAAMmmD,GAAUxjC,YAAe5f,IAAe,MAAP4f,KACpEhjB,KAAKwtD,YAAYxtD,KAAKkiD,SAAS5E,MAAMkJ,UAC9BxmD,MAAKkiD,SAAS5E,MAAMkJ,GAIjCxmD,MAAK0hB,WAYTxe,EAAQkQ,UAAU+5C,gBAAkB,SAAUhtB,GAC5C,GAOI9/B,GAPA2iB,GACFxb,KAAQxH,KAAK6rD,qBAAqB1rB,EAAQnuB,GAC1CpK,IAAQ5H,KAAK+rD,qBAAqB5rB,EAAQluB,GAC1CqV,MAAQtnB,KAAK6rD,qBAAqB1rB,EAAQnuB,GAC1CuR,OAAQvjB,KAAK+rD,qBAAqB5rB,EAAQluB,IAIxCw7C,EAAgBztD,KAAKgtD,SACrBU,GAAkB,CAEtB,IAAqBnnD,QAAjBvG,KAAKgtD,SAAuB,CAE9B,GAAI1P,GAAQt9C,KAAKs9C,MACbqQ,IACJ,KAAKttD,IAAMi9C,GACT,GAAIA,EAAMz3C,eAAexF,GAAK,CAC5B,GAAI8lD,GAAO7I,EAAMj9C,EACb8lD,GAAKyH,kBAAkB5qC,IACDzc,SAApB4/C,EAAK0H,YACPF,EAAiBzlD,KAAK7H,GAM1BstD,EAAiBjoD,OAAS,IAG5B1F,KAAKgtD,SAAWhtD,KAAKs9C,MAAMqQ,EAAiBA,EAAiBjoD,OAAS,IAEtEgoD,GAAkB,GAItB,GAAsBnnD,SAAlBvG,KAAKgtD,UAA6C,GAAnBU,EAA0B,CAE3D,GAAItP,GAAQp+C,KAAKo+C,MACb0P,IACJ,KAAKztD,IAAM+9C,GACT,GAAIA,EAAMv4C,eAAexF,GAAK,CAC5B,GAAI0tD,GAAO3P,EAAM/9C,EACb0tD,GAAKC,WAAkCznD,SAApBwnD,EAAKF,YACxBE,EAAKH,kBAAkB5qC,IACzB8qC,EAAiB5lD,KAAK7H,GAKxBytD,EAAiBpoD,OAAS,IAC5B1F,KAAKgtD,SAAWhtD,KAAKo+C,MAAM0P,EAAiBA,EAAiBpoD,OAAS,KAI1E,GAAI1F,KAAKgtD,UAEP,GAAIhtD,KAAKgtD,UAAYS,EAAe,CAClC,GAAIr5C,GAAKpU,IACJoU,GAAG65C,QACN75C,EAAG65C,MAAQ,GAAIzqD,GAAM4Q,EAAGmL,MAAOnL,EAAG4tC,UAAU37B,UAM9CjS,EAAG65C,MAAMC,YAAY/tB,EAAQnuB,EAAI,EAAGmuB,EAAQluB,EAAI,GAChDmC,EAAG65C,MAAME,QAAQ/5C,EAAG44C,SAASa,YAC7Bz5C,EAAG65C,MAAM/lB,YAIPloC,MAAKiuD,OACPjuD,KAAKiuD,MAAMhmB,QAYjB/kC,EAAQkQ,UAAU65C,gBAAkB,SAAU9sB,GACvCngC,KAAKgtD,UAAahtD,KAAKkrD,WAAW/qB,KACrCngC,KAAKgtD,SAAWzmD,OACZvG,KAAKiuD,OACPjuD,KAAKiuD,MAAMhmB,SAajB/kC,EAAQkQ,UAAUwR,QAAU,SAASpS,EAAOC,GAC1C,GAAI27C,IAAY,EACZC,EAAWruD,KAAKuf,MAAMC,OAAOhN,MAC7B87C,EAAYtuD,KAAKuf,MAAMC,OAAO/M,MAC9BD,IAASxS,KAAKgiD,UAAUxvC,OAASC,GAAUzS,KAAKgiD,UAAUvvC,QAAUzS,KAAKuf,MAAMrS,MAAMsF,OAASA,GAASxS,KAAKuf,MAAMrS,MAAMuF,QAAUA,GACpIzS,KAAKuf,MAAMrS,MAAMsF,MAAQA,EACzBxS,KAAKuf,MAAMrS,MAAMuF,OAASA,EAE1BzS,KAAKuf,MAAMC,OAAOtS,MAAMsF,MAAQ,OAChCxS,KAAKuf,MAAMC,OAAOtS,MAAMuF,OAAS,OAEjCzS,KAAKuf,MAAMC,OAAOhN,MAAQxS,KAAKuf,MAAMC,OAAOC,YAAczf,KAAKiiD,WAC/DjiD,KAAKuf,MAAMC,OAAO/M,OAASzS,KAAKuf,MAAMC,OAAOsF,aAAe9kB,KAAKiiD,WAEjEjiD,KAAKgiD,UAAUxvC,MAAQA,EACvBxS,KAAKgiD,UAAUvvC,OAASA,EAExB27C,GAAY,IAMRpuD,KAAKuf,MAAMC,OAAOhN,OAASxS,KAAKuf,MAAMC,OAAOC,YAAczf,KAAKiiD,aAClEjiD,KAAKuf,MAAMC,OAAOhN,MAAQxS,KAAKuf,MAAMC,OAAOC,YAAczf,KAAKiiD,WAC/DmM,GAAY,GAEVpuD,KAAKuf,MAAMC,OAAO/M,QAAUzS,KAAKuf,MAAMC,OAAOsF,aAAe9kB,KAAKiiD,aACpEjiD,KAAKuf,MAAMC,OAAO/M,OAASzS,KAAKuf,MAAMC,OAAOsF,aAAe9kB,KAAKiiD,WACjEmM,GAAY,IAIC,GAAbA,GACFpuD,KAAK6tB,KAAK,UAAWrb,MAAMxS,KAAKuf,MAAMC,OAAOhN,MAAQxS,KAAKiiD,WAAWxvC,OAAOzS,KAAKuf,MAAMC,OAAO/M,OAASzS,KAAKiiD,WAAYoM,SAAUA,EAAWruD,KAAKiiD,WAAYqM,UAAWA,EAAYtuD,KAAKiiD,cAS9L/+C,EAAQkQ,UAAU00C,UAAY,SAASxK,GACrC,GAAIiR,GAAevuD,KAAK0kD,SAExB,IAAIpH,YAAiBz8C,IAAWy8C,YAAiBx8C,GAC/Cd,KAAK0kD,UAAYpH,MAEd,IAAIt3C,MAAMC,QAAQq3C,GACrBt9C,KAAK0kD,UAAY,GAAI7jD,GACrBb,KAAK0kD,UAAUxxC,IAAIoqC,OAEhB,CAAA,GAAKA,EAIR,KAAM,IAAIl3C,WAAU,4BAHpBpG,MAAK0kD,UAAY,GAAI7jD,GAgBvB,GAVI0tD,GAEF5tD,EAAK4H,QAAQvI,KAAK4kD,eAAgB,SAAUp8C,EAAUgB,GACpD+kD,EAAa56C,IAAInK,EAAOhB,KAK5BxI,KAAKs9C,SAEDt9C,KAAK0kD,UAAW,CAElB,GAAItwC,GAAKpU,IACTW,GAAK4H,QAAQvI,KAAK4kD,eAAgB,SAAUp8C,EAAUgB,GACpD4K,EAAGswC,UAAUlxC,GAAGhK,EAAOhB,IAIzB,IAAI4M,GAAMpV,KAAK0kD,UAAU5uC,QACzB9V,MAAK6kD,UAAUzvC,GAEjBpV,KAAKwuD,oBAQPtrD,EAAQkQ,UAAUyxC,UAAY,SAASzvC,GAErC,IAAK,GADD/U,GACKkF,EAAI,EAAGC,EAAM4P,EAAI1P,OAAYF,EAAJD,EAASA,IAAK,CAC9ClF,EAAK+U,EAAI7P,EACT,IAAIoN,GAAO3S,KAAK0kD,UAAUvvC,IAAI9U,GAC1B8lD,EAAO,GAAI5iD,GAAKoP,EAAM3S,KAAKijD,OAAQjjD,KAAKo0B,OAAQp0B,KAAKgiD,UAEzD,IADAhiD,KAAKs9C,MAAMj9C,GAAM8lD,IACG,GAAfA,EAAKsF,QAAkC,GAAftF,EAAKuF,QAAgC,OAAXvF,EAAKn0C,GAAyB,OAAXm0C,EAAKl0C,GAAa,CAC1F,GAAIyZ,GAAS,EAAStW,EAAI1P,OAAS,GAC/B+oD,EAAQ,EAAIxpD,KAAK2mB,GAAK3mB,KAAKE,QACZ,IAAfghD,EAAKsF,SAAkBtF,EAAKn0C,EAAI0Z,EAASzmB,KAAKuZ,IAAIiwC,IACnC,GAAftI,EAAKuF,SAAkBvF,EAAKl0C,EAAIyZ,EAASzmB,KAAKoZ,IAAIowC,IAExDzuD,KAAKolD,QAAS,EAGhBplD,KAAKqnD,uBAC4C,GAA7CrnD,KAAKgiD,UAAUjB,mBAAmBpyC,SAAwC,GAArB3O,KAAKg9C,eAC5Dh9C,KAAKioD,eACLjoD,KAAKslD,4BAEPtlD,KAAK0uD,0BACL1uD,KAAK2uD,kBACL3uD,KAAK4uD,kBAAkB5uD,KAAKs9C,OAC5Bt9C,KAAK6uD,gBAQP3rD,EAAQkQ,UAAU0xC,aAAe,SAAS1vC,EAAI05C,GAE5C,IAAK,GADDxR,GAAQt9C,KAAKs9C,MACR/3C,EAAI,EAAGC,EAAM4P,EAAI1P,OAAYF,EAAJD,EAASA,IAAK,CAC9C,GAAIlF,GAAK+U,EAAI7P,GACT4gD,EAAO7I,EAAMj9C,GACbsS,EAAOm8C,EAAYvpD,EACnB4gD,GAEFA,EAAK4I,cAAcp8C,EAAM3S,KAAKgiD,YAI9BmE,EAAO,GAAI5iD,GAAKyrD,WAAYhvD,KAAKijD,OAAQjjD,KAAKo0B,OAAQp0B,KAAKgiD,WAC3D1E,EAAMj9C,GAAM8lD,GAGhBnmD,KAAKolD,QAAS,EACmC,GAA7CplD,KAAKgiD,UAAUjB,mBAAmBpyC,SAAwC,GAArB3O,KAAKg9C,eAC5Dh9C,KAAKioD,eACLjoD,KAAKslD,4BAEPtlD,KAAKqnD,uBACLrnD,KAAK4uD,kBAAkBtR,IAQzBp6C,EAAQkQ,UAAU2xC,aAAe,SAAS3vC,GAExC,IAAK,GADDkoC,GAAQt9C,KAAKs9C,MACR/3C,EAAI,EAAGC,EAAM4P,EAAI1P,OAAYF,EAAJD,EAASA,IAAK,CAC9C,GAAIlF,GAAK+U,EAAI7P,SACN+3C,GAAMj9C,GAEfL,KAAKqnD,uBAC4C,GAA7CrnD,KAAKgiD,UAAUjB,mBAAmBpyC,SAAwC,GAArB3O,KAAKg9C,eAC5Dh9C,KAAKioD,eACLjoD,KAAKslD,4BAEPtlD,KAAK0uD,0BACL1uD,KAAK2uD,kBACL3uD,KAAKwuD,mBACLxuD,KAAK4uD,kBAAkBtR,IASzBp6C,EAAQkQ,UAAU20C,UAAY,SAAS3J,GACrC,GAAI6Q,GAAejvD,KAAK2kD,SAExB,IAAIvG,YAAiBv9C,IAAWu9C,YAAiBt9C,GAC/Cd,KAAK2kD,UAAYvG,MAEd,IAAIp4C,MAAMC,QAAQm4C,GACrBp+C,KAAK2kD,UAAY,GAAI9jD,GACrBb,KAAK2kD,UAAUzxC,IAAIkrC,OAEhB,CAAA,GAAKA,EAIR,KAAM,IAAIh4C,WAAU,4BAHpBpG,MAAK2kD,UAAY,GAAI9jD,GAgBvB,GAVIouD,GAEFtuD,EAAK4H,QAAQvI,KAAKglD,eAAgB,SAAUx8C,EAAUgB,GACpDylD,EAAat7C,IAAInK,EAAOhB,KAK5BxI,KAAKo+C,SAEDp+C,KAAK2kD,UAAW,CAElB,GAAIvwC,GAAKpU,IACTW,GAAK4H,QAAQvI,KAAKglD,eAAgB,SAAUx8C,EAAUgB,GACpD4K,EAAGuwC,UAAUnxC,GAAGhK,EAAOhB,IAIzB,IAAI4M,GAAMpV,KAAK2kD,UAAU7uC,QACzB9V,MAAKilD,UAAU7vC,GAGjBpV,KAAK2uD,mBAQPzrD,EAAQkQ,UAAU6xC,UAAY,SAAU7vC,GAItC,IAAK,GAHDgpC,GAAQp+C,KAAKo+C,MACbuG,EAAY3kD,KAAK2kD,UAEZp/C,EAAI,EAAGC,EAAM4P,EAAI1P,OAAYF,EAAJD,EAASA,IAAK,CAC9C,GAAIlF,GAAK+U,EAAI7P,GAET2pD,EAAU9Q,EAAM/9C,EAChB6uD,IACFA,EAAQC,YAGV,IAAIx8C,GAAOgyC,EAAUxvC,IAAI9U,GAAK+uD,iBAAoB,GAClDhR,GAAM/9C,GAAM,GAAI+C,GAAKuP,EAAM3S,KAAMA,KAAKgiD,WAExChiD,KAAKolD,QAAS,EACdplD,KAAK4uD,kBAAkBxQ,GACvBp+C,KAAKqvD,qBACLrvD,KAAK0uD,0BAC4C,GAA7C1uD,KAAKgiD,UAAUjB,mBAAmBpyC,SAAwC,GAArB3O,KAAKg9C,eAC5Dh9C,KAAKioD,eACLjoD,KAAKslD,6BASTpiD,EAAQkQ,UAAU8xC,aAAe,SAAU9vC,GAGzC,IAAK,GAFDgpC,GAAQp+C,KAAKo+C,MACbuG,EAAY3kD,KAAK2kD,UACZp/C,EAAI,EAAGC,EAAM4P,EAAI1P,OAAYF,EAAJD,EAASA,IAAK,CAC9C,GAAIlF,GAAK+U,EAAI7P,GAEToN,EAAOgyC,EAAUxvC,IAAI9U,GACrB0tD,EAAO3P,EAAM/9C,EACb0tD,IAEFA,EAAKoB,aACLpB,EAAKgB,cAAcp8C,EAAM3S,KAAKgiD,WAC9B+L,EAAK3Q,YAIL2Q,EAAO,GAAI3qD,GAAKuP,EAAM3S,KAAMA,KAAKgiD,WACjChiD,KAAKo+C,MAAM/9C,GAAM0tD,GAIrB/tD,KAAKqvD,qBAC4C,GAA7CrvD,KAAKgiD,UAAUjB,mBAAmBpyC,SAAwC,GAArB3O,KAAKg9C,eAC5Dh9C,KAAKioD,eACLjoD,KAAKslD,4BAEPtlD,KAAKolD,QAAS,EACdplD,KAAK4uD,kBAAkBxQ,IAQzBl7C,EAAQkQ,UAAU+xC,aAAe,SAAU/vC,GAEzC,IAAK,GADDgpC,GAAQp+C,KAAKo+C,MACR74C,EAAI,EAAGC,EAAM4P,EAAI1P,OAAYF,EAAJD,EAASA,IAAK,CAC9C,GAAIlF,GAAK+U,EAAI7P,GACTwoD,EAAO3P,EAAM/9C,EACb0tD,KACc,MAAZA,EAAKuB,WACAtvD,MAAKuvD,QAAiB,QAAS,MAAExB,EAAKuB,IAAIjvD,IAEnD0tD,EAAKoB,mBACE/Q,GAAM/9C,IAIjBL,KAAKolD,QAAS,EACdplD,KAAK4uD,kBAAkBxQ,GAC0B,GAA7Cp+C,KAAKgiD,UAAUjB,mBAAmBpyC,SAAwC,GAArB3O,KAAKg9C,eAC5Dh9C,KAAKioD,eACLjoD,KAAKslD,4BAEPtlD,KAAK0uD,2BAOPxrD,EAAQkQ,UAAUu7C,gBAAkB,WAClC,GAAItuD,GACAi9C,EAAQt9C,KAAKs9C,MACbc,EAAQp+C,KAAKo+C,KACjB,KAAK/9C,IAAMi9C,GACLA,EAAMz3C,eAAexF,KACvBi9C,EAAMj9C,GAAI+9C,SACVd,EAAMj9C,GAAImvD,gBAId,KAAKnvD,IAAM+9C,GACT,GAAIA,EAAMv4C,eAAexF,GAAK,CAC5B,GAAI0tD,GAAO3P,EAAM/9C,EACjB0tD,GAAK1kC,KAAO,KACZ0kC,EAAKzkC,GAAK,KACVykC,EAAK3Q,YAaXl6C,EAAQkQ,UAAUw7C,kBAAoB,SAAS5rC,GAC7C,GAAI3iB,GAGA8b,EAAW5V,OACX6V,EAAW7V,MACf,KAAKlG,IAAM2iB,GACT,GAAIA,EAAInd,eAAexF,GAAK,CAC1B,GAAI+G,GAAQ4b,EAAI3iB,GAAIwU,UACNtO,UAAVa,IACF+U,EAAyB5V,SAAb4V,EAA0B/U,EAAQnC,KAAK8G,IAAI3E,EAAO+U,GAC9DC,EAAyB7V,SAAb6V,EAA0BhV,EAAQnC,KAAK0H,IAAIvF,EAAOgV,IAMpE,GAAiB7V,SAAb4V,GAAuC5V,SAAb6V,EAC5B,IAAK/b,IAAM2iB,GACLA,EAAInd,eAAexF,IACrB2iB,EAAI3iB,GAAIovD,cAActzC,EAAUC,IAUxClZ,EAAQkQ,UAAUsO,OAAS,WACzB1hB,KAAK4kB,QAAQ5kB,KAAKgiD,UAAUxvC,MAAOxS,KAAKgiD,UAAUvvC,QAClDzS,KAAKmjD,WAQPjgD,EAAQkQ,UAAU+vC,QAAU,SAAShqB,GACnC,GAAInS,GAAMhnB,KAAKuf,MAAMC,OAAOyH,WAAW,KAEvCD,GAAIsiC,aAAatpD,KAAKiiD,WAAY,EAAG,EAAGjiD,KAAKiiD,WAAY,EAAG,EAG5D,IAAIyN,GAAI1vD,KAAKuf,MAAMC,OAAOhN,MAASxS,KAAKiiD,WACpCr2C,EAAI5L,KAAKuf,MAAMC,OAAO/M,OAAUzS,KAAKiiD,UACzCj7B,GAAIE,UAAU,EAAG,EAAGwoC,EAAG9jD,GAGvBob,EAAI2oC,OACJ3oC,EAAI4oC,UAAU5vD,KAAK0d,YAAY1L,EAAGhS,KAAK0d,YAAYzL,GACnD+U,EAAI9J,MAAMld,KAAKkd,MAAOld,KAAKkd,OAE3Bld,KAAKqkD,eACHryC,EAAKhS,KAAK6rD,qBAAqB,GAC/B55C,EAAKjS,KAAK+rD,qBAAqB,IAEjC/rD,KAAKskD,mBACHtyC,EAAKhS,KAAK6rD,qBAAqB7rD,KAAKuf,MAAMC,OAAOC,YAAczf,KAAKiiD,YACpEhwC,EAAKjS,KAAK+rD,qBAAqB/rD,KAAKuf,MAAMC,OAAOsF,aAAe9kB,KAAKiiD,aAGvD,GAAV9oB,IACJn5B,KAAK6vD,gBAAgB,sBAAuB7oC,IAClB,GAAtBhnB,KAAK8lC,KAAK3G,UAA4C54B,SAAvBvG,KAAK8lC,KAAK3G,UAA4D,GAAlCn/B,KAAKgiD,UAAUF,kBACpF9hD,KAAK6vD,gBAAgB,aAAc7oC,KAIb,GAAtBhnB,KAAK8lC,KAAK3G,UAA4C54B,SAAvBvG,KAAK8lC,KAAK3G,UAA4D,GAAlCn/B,KAAKgiD,UAAUD,kBACpF/hD,KAAK6vD,gBAAgB,aAAa7oC,GAAI,GAGxB,GAAVmS,GAC2B,GAA3Bn5B,KAAKmiD,oBACPniD,KAAK6vD,gBAAgB,oBAAqB7oC,GAQ9CA,EAAI8oC,UAEU,GAAV32B,GACFnS,EAAIE,UAAU,EAAG,EAAGwoC,EAAG9jD,IAU3B1I,EAAQkQ,UAAUwwC,gBAAkB,SAASmM,EAASC,GAC3BzpD,SAArBvG,KAAK0d,cACP1d,KAAK0d,aACH1L,EAAG,EACHC,EAAG,IAIS1L,SAAZwpD,IACF/vD,KAAK0d,YAAY1L,EAAI+9C,GAEPxpD,SAAZypD,IACFhwD,KAAK0d,YAAYzL,EAAI+9C,GAGvBhwD,KAAK6tB,KAAK,gBAQZ3qB,EAAQkQ,UAAU+3C,gBAAkB,WAClC,OACEn5C,EAAGhS,KAAK0d,YAAY1L,EACpBC,EAAGjS,KAAK0d,YAAYzL,IASxB/O,EAAQkQ,UAAU6J,UAAY,SAASC,GACrCld,KAAKkd,MAAQA,GAQfha,EAAQkQ,UAAU23C,UAAY,WAC5B,MAAO/qD,MAAKkd,OAUdha,EAAQkQ,UAAUy4C,qBAAuB,SAAS75C,GAChD,OAAQA,EAAIhS,KAAK0d,YAAY1L,GAAKhS,KAAKkd,OAUzCha,EAAQkQ,UAAU04C,qBAAuB,SAAS95C,GAChD,MAAOA,GAAIhS,KAAKkd,MAAQld,KAAK0d,YAAY1L,GAU3C9O,EAAQkQ,UAAU24C,qBAAuB,SAAS95C,GAChD,OAAQA,EAAIjS,KAAK0d,YAAYzL,GAAKjS,KAAKkd,OAUzCha,EAAQkQ,UAAU44C,qBAAuB,SAAS/5C,GAChD,MAAOA,GAAIjS,KAAKkd,MAAQld,KAAK0d,YAAYzL,GAU3C/O,EAAQkQ,UAAU25C,YAAc,SAAUvnC,GACxC,OAAQxT,EAAGhS,KAAK8rD,qBAAqBtmC,EAAIxT,GAAIC,EAAGjS,KAAKgsD,qBAAqBxmC,EAAIvT,KAShF/O,EAAQkQ,UAAUq5C,YAAc,SAAUjnC,GACxC,OAAQxT,EAAGhS,KAAK6rD,qBAAqBrmC,EAAIxT,GAAIC,EAAGjS,KAAK+rD,qBAAqBvmC,EAAIvT,KAUhF/O,EAAQkQ,UAAU68C,WAAa,SAASjpC,EAAIkpC,GACvB3pD,SAAf2pD,IACFA,GAAa,EAIf,IAAI5S,GAAQt9C,KAAKs9C,MACb9J,IAEJ,KAAK,GAAInzC,KAAMi9C,GACTA,EAAMz3C,eAAexF,KACvBi9C,EAAMj9C,GAAI8vD,eAAenwD,KAAKkd,MAAMld,KAAKqkD,cAAcrkD,KAAKskD,mBACxDhH,EAAMj9C,GAAI+qD,aACZ5X,EAAStrC,KAAK7H,IAGVi9C,EAAMj9C,GAAI+vD,UAAYF,IACxB5S,EAAMj9C,GAAIisC,KAAKtlB,GAOvB,KAAK,GAAInb,GAAI,EAAGwkD,EAAO7c,EAAS9tC,OAAY2qD,EAAJxkD,EAAUA,KAC5CyxC,EAAM9J,EAAS3nC,IAAIukD,UAAYF,IACjC5S,EAAM9J,EAAS3nC,IAAIygC,KAAKtlB,IAW9B9jB,EAAQkQ,UAAUk9C,WAAa,SAAStpC,GACtC,GAAIo3B,GAAQp+C,KAAKo+C,KACjB,KAAK,GAAI/9C,KAAM+9C,GACb,GAAIA,EAAMv4C,eAAexF,GAAK,CAC5B,GAAI0tD,GAAO3P,EAAM/9C,EACjB0tD,GAAK1qB,SAASrjC,KAAKkd,OACf6wC,EAAKC,WACP5P,EAAM/9C,GAAIisC,KAAKtlB,KAYvB9jB,EAAQkQ,UAAUm9C,kBAAoB,SAASvpC,GAC7C,GAAIo3B,GAAQp+C,KAAKo+C,KACjB,KAAK,GAAI/9C,KAAM+9C,GACTA,EAAMv4C,eAAexF,IACvB+9C,EAAM/9C,GAAIkwD,kBAAkBvpC,IASlC9jB,EAAQkQ,UAAU80C,WAAa,WACgB,GAAzCloD,KAAKgiD,UAAUb,wBACjBnhD,KAAKwwD,qBAKP,KADA,GAAIv5C,GAAQ,EACLjX,KAAKolD,QAAUnuC,EAAQjX,KAAKgiD,UAAUN,yBAC3C1hD,KAAKywD,eACLx5C,GAG0C,IAAxCjX,KAAKgiD,UAAUL,uBACjB3hD,KAAKulD,WAAWh/C,QAAW,GAAO,GAGS,GAAzCvG,KAAKgiD,UAAUb,wBACjBnhD,KAAK0wD,uBAUTxtD,EAAQkQ,UAAUo9C,oBAAsB,WACtC,GAAIlT,GAAQt9C,KAAKs9C,KACjB,KAAK,GAAIj9C,KAAMi9C,GACTA,EAAMz3C,eAAexF,IACJ,MAAfi9C,EAAMj9C,GAAI2R,GAA4B,MAAfsrC,EAAMj9C,GAAI4R,IACnCqrC,EAAMj9C,GAAIswD,UAAU3+C,EAAIsrC,EAAMj9C,GAAIorD,OAClCnO,EAAMj9C,GAAIswD,UAAU1+C,EAAIqrC,EAAMj9C,GAAIqrD,OAClCpO,EAAMj9C,GAAIorD,QAAS,EACnBnO,EAAMj9C,GAAIqrD,QAAS,IAW3BxoD,EAAQkQ,UAAUs9C,oBAAsB,WACtC,GAAIpT,GAAQt9C,KAAKs9C,KACjB,KAAK,GAAIj9C,KAAMi9C,GACTA,EAAMz3C,eAAexF,IACM,MAAzBi9C,EAAMj9C,GAAIswD,UAAU3+C,IACtBsrC,EAAMj9C,GAAIorD,OAASnO,EAAMj9C,GAAIswD,UAAU3+C,EACvCsrC,EAAMj9C,GAAIqrD,OAASpO,EAAMj9C,GAAIswD,UAAU1+C,IAa/C/O,EAAQkQ,UAAUw9C,UAAY,SAASC,GACrC,GAAIvT,GAAQt9C,KAAKs9C,KACjB,KAAK,GAAIj9C,KAAMi9C,GACb,GAAIA,EAAMz3C,eAAexF,IAAOi9C,EAAMj9C,GAAIywD,SAASD,GACjD,OAAO,CAGX,QAAO,GAUT3tD,EAAQkQ,UAAU29C,mBAAqB,WACrC,GAEIvK,GAFA/zB,EAAWzyB,KAAK+8C,wBAChBO,EAAQt9C,KAAKs9C,MAEb0T,GAAe,CAEnB,IAAIhxD,KAAKgiD,UAAUT,YAAc,EAC/B,IAAKiF,IAAUlJ,GACTA,EAAMz3C,eAAe2gD,KACvBlJ,EAAMkJ,GAAQyK,oBAAoBx+B,EAAUzyB,KAAKgiD,UAAUT,aAC3DyP,GAAe,OAKnB,KAAKxK,IAAUlJ,GACTA,EAAMz3C,eAAe2gD,KACvBlJ,EAAMkJ,GAAQ0K,aAAaz+B,GAC3Bu+B,GAAe,EAKrB,IAAoB,GAAhBA,EAAsB,CACxB,GAAIG,GAAgBnxD,KAAKgiD,UAAUR,YAAcv8C,KAAK0H,IAAI3M,KAAKkd,MAAM,IACrE,OAAIi0C,GAAgB,GAAInxD,KAAKgiD,UAAUT,aAC9B,EAGAvhD,KAAK4wD,UAAUO,GAG1B,OAAO,GAITjuD,EAAQkQ,UAAUg+C,oBAAsB,WACtC,GAAI9T,GAAQt9C,KAAKs9C,KACjB,KAAK,GAAIkJ,KAAUlJ,GACbA,EAAMz3C,eAAe2gD,IACvBlJ,EAAMkJ,GAAQ6K,kBAKpBnuD,EAAQkQ,UAAUk+C,mBAAqB,WACrCtxD,KAAKuxD,sBAAsB,uBACgB,GAAvCvxD,KAAKgiD,UAAUZ,aAAazyC,SAA0D,GAAvC3O,KAAKgiD,UAAUZ,aAAaC,SAC7ErhD,KAAKwxD,mBAAmB,wBAS5BtuD,EAAQkQ,UAAUq9C,aAAe,WAC/B,IAAKzwD,KAAK6jD,kBACW,GAAf7jD,KAAKolD,OAAgB,CACvB,GAAIqM,IAAmB,EACnBC,GAAsB,CAE1B1xD,MAAKuxD,sBAAsB,8BAC3B,IAAII,GAAa3xD,KAAKuxD,sBAAsB,qBACD,IAAvCvxD,KAAKgiD,UAAUZ,aAAazyC,SAA0D,GAAvC3O,KAAKgiD,UAAUZ,aAAaC,UAC7EqQ,EAAsB1xD,KAAKwxD,mBAAmB,sBAIhD,KAAK,GAAIjsD,GAAI,EAAGA,EAAIosD,EAAWjsD,OAAQH,IAAMksD,EAAmBE,EAAW,IAAMF,CAGjFzxD,MAAKolD,OAASqM,GAAoBC,EAEf,GAAf1xD,KAAKolD,OACPplD,KAAKsxD,qBAI4B,GAA7BtxD,KAAK+jD,uBACP/jD,KAAK6tB,KAAK,sBACV7tB,KAAK+jD,sBAAuB,GAIhC/jD,KAAK0hD,4BAYXx+C,EAAQkQ,UAAUw+C,eAAiB,WAEjC5xD,KAAKqlD,MAAQ9+C,OAGbvG,KAAK6xD,mBAEL,IAAIC,GAAYztD,KAAK+4B,KACrBp9B,MAAKywD,cACL,IAAI5T,GAAcx4C,KAAK+4B,MAAQ00B,GAG1B9xD,KAAK28C,eAAiB38C,KAAK48C,WAAa,EAAIC,GAAsC,GAAvB78C,KAAK88C,iBAA2C,GAAf98C,KAAKolD,SACpGplD,KAAKywD,eAGkB,GAAnBzwD,KAAK48C,aACP58C,KAAK88C,gBAAiB,GAI1B,IAAIiV,GAAkB1tD,KAAK+4B,KAC3Bp9B,MAAKmjD,UACLnjD,KAAK48C,WAAav4C,KAAK+4B,MAAQ20B,EAG/B/xD,KAAK6P,SAGe,mBAAXpI,UACTA,OAAOuqD,sBAAwBvqD,OAAOuqD,uBAAyBvqD,OAAOwqD,0BACvCxqD,OAAOyqD,6BAA+BzqD,OAAO0qD,yBAM9EjvD,EAAQkQ,UAAUvD,MAAQ,WACxB,GAAmB,GAAf7P,KAAKolD,QAAqC,GAAnBplD,KAAKojD,YAAsC,GAAnBpjD,KAAKqjD,YAAyC,GAAtBrjD,KAAKsjD,cACzEtjD,KAAKqlD,QAENrlD,KAAKqlD,MADqB,GAAxBrlD,KAAK6lD,gBACMp+C,OAAO8R,WAAWvZ,KAAK4xD,eAAe78B,KAAK/0B,MAAOA,KAAK28C,gBAGvDl1C,OAAOuqD,sBAAsBhyD,KAAK4xD,eAAe78B,KAAK/0B,YAOvE,IAFAA,KAAKmjD,UAEDnjD,KAAK0hD,wBAA0B,EAAG,CAKpC,GAAIttC,GAAKpU,KACL+T,GACFq+C,WAAYh+C,EAAGstC,wBAEjB1hD,MAAK0hD,wBAA0B,EAC/B1hD,KAAK+jD,sBAAuB,EAC5BxqC,WAAW,WACTnF,EAAGyZ,KAAK,aAAc9Z,IACrB,OAGH/T,MAAK0hD,wBAA0B,GAWrCx+C,EAAQkQ,UAAUy+C,kBAAoB,WACpC,GAAuB,GAAnB7xD,KAAKojD,YAAsC,GAAnBpjD,KAAKqjD,WAAiB,CAChD,GAAI3lC,GAAc1d,KAAKmrD,iBACvBnrD,MAAK4jD,gBAAgBlmC,EAAY1L,EAAEhS,KAAKojD,WAAY1lC,EAAYzL,EAAEjS,KAAKqjD,YAEzE,GAA0B,GAAtBrjD,KAAKsjD,cAAoB,CAC3B,GAAIn3B,IACFna,EAAGhS,KAAKuf,MAAMC,OAAOC,YAAc,EACnCxN,EAAGjS,KAAKuf,MAAMC,OAAOsF,aAAe,EAEtC9kB,MAAKssD,MAAMtsD,KAAKkd,OAAO,EAAIld,KAAKsjD,eAAgBn3B,KAQpDjpB,EAAQkQ,UAAUi/C,aAAe,WACF,GAAzBryD,KAAK6jD,iBACP7jD,KAAK6jD,kBAAmB,GAGxB7jD,KAAK6jD,kBAAmB,EACxB7jD,KAAK6P,UAWT3M,EAAQkQ,UAAU21C,uBAAyB,SAASlC,GAIlD,GAHqBtgD,SAAjBsgD,IACFA,GAAe,GAE0B,GAAvC7mD,KAAKgiD,UAAUZ,aAAazyC,SAA0D,GAAvC3O,KAAKgiD,UAAUZ,aAAaC,QAAiB,CAC9FrhD,KAAKqvD,oBAEL,KAAK,GAAI7I,KAAUxmD,MAAKuvD,QAAiB,QAAS,MAC5CvvD,KAAKuvD,QAAiB,QAAS,MAAE1pD,eAAe2gD,IACwBjgD,SAAtEvG,KAAKo+C,MAAMp+C,KAAKuvD,QAAiB,QAAS,MAAE/I,GAAQ8L,qBAC/CtyD,MAAKuvD,QAAiB,QAAS,MAAE/I,OAK3C,CAEHxmD,KAAKuvD,QAAiB,QAAS,QAC/B,KAAK,GAAIlC,KAAUrtD,MAAKo+C,MAClBp+C,KAAKo+C,MAAMv4C,eAAewnD,KAC5BrtD,KAAKo+C,MAAMiP,GAAQiC,IAAM,MAM/BtvD,KAAK0uD,0BACA7H,IACH7mD,KAAKolD,QAAS,EACdplD,KAAK6P,UAWT3M,EAAQkQ,UAAUi8C,mBAAqB,WACrC,GAA2C,GAAvCrvD,KAAKgiD,UAAUZ,aAAazyC,SAA0D,GAAvC3O,KAAKgiD,UAAUZ,aAAaC,QAC7E,IAAK,GAAIgM,KAAUrtD,MAAKo+C,MACtB,GAAIp+C,KAAKo+C,MAAMv4C,eAAewnD,GAAS,CACrC,GAAIU,GAAO/tD,KAAKo+C,MAAMiP,EACtB,IAAgB,MAAZU,EAAKuB,IAAa,CACpB,GAAI9I,GAAS,UAAUvyC,OAAO85C,EAAK1tD,GACnCL,MAAKuvD,QAAiB,QAAS,MAAE/I,GAAU,GAAIjjD,IACtClD,GAAGmmD,EACFjJ,KAAK,EACLG,MAAM,SACNC,MAAM,GACN4U,mBAAmB,SACbvyD,KAAKgiD,WACrB+L,EAAKuB,IAAMtvD,KAAKuvD,QAAiB,QAAS,MAAE/I,GAC5CuH,EAAKuB,IAAIgD,aAAevE,EAAK1tD,GAC7B0tD,EAAKyE,wBAYftvD,EAAQkQ,UAAUqpC,wBAA0B,WAC1C,IAAK,GAAIgW,KAAS/M,GACZA,EAAY7/C,eAAe4sD,KAC7BvvD,EAAQkQ,UAAUq/C,GAAS/M,EAAY+M,KAQ7CvvD,EAAQkQ,UAAUs/C,cAAgB,WAChC95B,QAAQhF,IAAI,mEACZ5zB,KAAK2yD,kBAMPzvD,EAAQkQ,UAAUu/C,eAAiB,WACjC,GAAIC,KACJ,KAAK,GAAIpM,KAAUxmD,MAAKs9C,MACtB,GAAIt9C,KAAKs9C,MAAMz3C,eAAe2gD,GAAS,CACrC,GAAIL,GAAOnmD,KAAKs9C,MAAMkJ,GAClBqM,GAAkB7yD,KAAKs9C,MAAMmO,OAC7BqH,GAAkB9yD,KAAKs9C,MAAMoO,QAC7B1rD,KAAK0kD,UAAU7xC,MAAM2zC,GAAQx0C,GAAK/M,KAAK0oB,MAAMw4B,EAAKn0C,IAAMhS,KAAK0kD,UAAU7xC,MAAM2zC,GAAQv0C,GAAKhN,KAAK0oB,MAAMw4B,EAAKl0C,KAC5G2gD,EAAU1qD,MAAM7H,GAAGmmD,EAAOx0C,EAAE/M,KAAK0oB,MAAMw4B,EAAKn0C,GAAGC,EAAEhN,KAAK0oB,MAAMw4B,EAAKl0C,GAAG4gD,eAAeA,EAAeC,eAAeA,IAIvH9yD,KAAK0kD,UAAU5vC,OAAO89C,IAMxB1vD,EAAQkQ,UAAU2/C,aAAe,SAAS39C,GACxC,GAAIw9C,KACJ,IAAYrsD,SAAR6O,GACF,GAA0B,GAAtBpP,MAAMC,QAAQmP,IAChB,IAAK,GAAI7P,GAAI,EAAGA,EAAI6P,EAAI1P,OAAQH,IAC9B,GAA2BgB,SAAvBvG,KAAKs9C,MAAMloC,EAAI7P,IAAmB,CACpC,GAAI4gD,GAAOnmD,KAAKs9C,MAAMloC,EAAI7P,GAC1BqtD,GAAUx9C,EAAI7P,KAAOyM,EAAG/M,KAAK0oB,MAAMw4B,EAAKn0C,GAAIC,EAAGhN,KAAK0oB,MAAMw4B,EAAKl0C,SAKnE,IAAwB1L,SAApBvG,KAAKs9C,MAAMloC,GAAoB,CACjC,GAAI+wC,GAAOnmD,KAAKs9C,MAAMloC,EACtBw9C,GAAUx9C,IAAQpD,EAAG/M,KAAK0oB,MAAMw4B,EAAKn0C,GAAIC,EAAGhN,KAAK0oB,MAAMw4B,EAAKl0C,SAKhE,KAAK,GAAIu0C,KAAUxmD,MAAKs9C,MACtB,GAAIt9C,KAAKs9C,MAAMz3C,eAAe2gD,GAAS,CACrC,GAAIL,GAAOnmD,KAAKs9C,MAAMkJ,EACtBoM,GAAUpM,IAAWx0C,EAAG/M,KAAK0oB,MAAMw4B,EAAKn0C,GAAIC,EAAGhN,KAAK0oB,MAAMw4B,EAAKl0C,IAIrE,MAAO2gD,IAWT1vD,EAAQkQ,UAAU4/C,YAAc,SAAUxM,EAAQ93C,GAChD,GAAI1O,KAAKs9C,MAAMz3C,eAAe2gD,GAAS,CACrBjgD,SAAZmI,IACFA,KAEF,IAAIukD,IAAgBjhD,EAAGhS,KAAKs9C,MAAMkJ,GAAQx0C,EAAGC,EAAGjS,KAAKs9C,MAAMkJ,GAAQv0C,EACnEvD,GAAQmV,SAAWovC,EACnBvkD,EAAQwkD,aAAe1M,EAEvBxmD,KAAK8nB,OAAOpZ,OAGZkqB,SAAQhF,IAAI,iCAWhB1wB,EAAQkQ,UAAU0U,OAAS,SAAUpZ,GACnC,MAAgBnI,UAAZmI,OACFA,OAGwBnI,SAAtBmI,EAAQkb,SAAoClb,EAAQkb,QAAa5X,EAAG,EAAGC,EAAG,IACpD1L,SAAtBmI,EAAQkb,OAAO5X,IAA6BtD,EAAQkb,OAAO5X,EAAK,GAC1CzL,SAAtBmI,EAAQkb,OAAO3X,IAA6BvD,EAAQkb,OAAO3X,EAAK,GAC1C1L,SAAtBmI,EAAQwO,QAAoCxO,EAAQwO,MAAYld,KAAK+qD,aAC/CxkD,SAAtBmI,EAAQmV,WAAoCnV,EAAQmV,SAAY7jB,KAAKmrD,mBAC/C5kD,SAAtBmI,EAAQ04C,YAAoC14C,EAAQ04C,WAAar3C,SAAS,IAC1ErB,EAAQ04C,aAAc,IAAsB14C,EAAQ04C,WAAar3C,SAAS,IAC1ErB,EAAQ04C,aAAc,IAAsB14C,EAAQ04C,cACrB7gD,SAA/BmI,EAAQ04C,UAAUr3C,WAA0BrB,EAAQ04C,UAAUr3C,SAAW,KACpCxJ,SAArCmI,EAAQ04C,UAAU+L,iBAAgCzkD,EAAQ04C,UAAU+L,eAAiB,qBAEzFnzD,MAAKozD,YAAY1kD,KAcnBxL,EAAQkQ,UAAUggD,YAAc,SAAU1kD,GACxC,GAAgBnI,SAAZmI,EAEF,YADAA,KAKF1O,MAAK4rD,cACiB,GAAlBl9C,EAAQ2kD,SACVrzD,KAAK8iD,eAAiBp0C,EAAQwkD,aAC9BlzD,KAAK+iD,mBAAqBr0C,EAAQkb,QAIb,GAAnB5pB,KAAKyiD,YACPziD,KAAKszD,kBAAkB,GAGzBtzD,KAAK0iD,YAAc1iD,KAAK+qD,YACxB/qD,KAAK4iD,kBAAoB5iD,KAAKmrD,kBAC9BnrD,KAAK2iD,YAAcj0C,EAAQwO,MAI3Bld,KAAKid,UAAUjd,KAAK2iD,YACpB,IAAI4Q,GAAavzD,KAAKysD,aAAaz6C,EAAG,GAAMhS,KAAKuf,MAAMC,OAAOC,YAAaxN,EAAG,GAAMjS,KAAKuf,MAAMC,OAAOsF,eAClG0uC,GACFxhD,EAAGuhD,EAAWvhD,EAAItD,EAAQmV,SAAS7R,EACnCC,EAAGshD,EAAWthD,EAAIvD,EAAQmV,SAAS5R,EAErCjS,MAAK6iD,mBACH7wC,EAAGhS,KAAK4iD,kBAAkB5wC,EAAIwhD,EAAmBxhD,EAAIhS,KAAK2iD,YAAcj0C,EAAQkb,OAAO5X,EACvFC,EAAGjS,KAAK4iD,kBAAkB3wC,EAAIuhD,EAAmBvhD,EAAIjS,KAAK2iD,YAAcj0C,EAAQkb,OAAO3X,GAIvD,GAA9BvD,EAAQ04C,UAAUr3C,SACO,MAAvB/P,KAAK8iD,gBACP9iD,KAAKyzD,eAAiBzzD,KAAKmjD,QAC3BnjD,KAAKmjD,QAAUnjD,KAAK0zD,gBAGpB1zD,KAAKid,UAAUjd,KAAK2iD,aACpB3iD,KAAK4jD,gBAAgB5jD,KAAK6iD,kBAAkB7wC,EAAGhS,KAAK6iD,kBAAkB5wC,GACtEjS,KAAKmjD,YAIPnjD,KAAKuiD,eAAiB,GAAKviD,KAAK08C,kBAAoBhuC,EAAQ04C,UAAUr3C,SAAW,OAAU,EAAI/P,KAAK08C,kBACpG18C,KAAKwiD,wBAA0B9zC,EAAQ04C,UAAU+L,eACjDnzD,KAAKyzD,eAAiBzzD,KAAKmjD,QAC3BnjD,KAAKmjD,QAAUnjD,KAAKszD,kBACpBtzD,KAAKmjD,UACLnjD,KAAKolD,QAAS,EACdplD,KAAK6P,UAQT3M,EAAQkQ,UAAUsgD,cAAgB,WAChC,GAAIT,IAAgBjhD,EAAGhS,KAAKs9C,MAAMt9C,KAAK8iD,gBAAgB9wC,EAAGC,EAAGjS,KAAKs9C,MAAMt9C,KAAK8iD,gBAAgB7wC,GACzFshD,EAAavzD,KAAKysD,aAAaz6C,EAAG,GAAMhS,KAAKuf,MAAMC,OAAOC,YAAaxN,EAAG,GAAMjS,KAAKuf,MAAMC,OAAOsF,eAClG0uC,GACFxhD,EAAGuhD,EAAWvhD,EAAIihD,EAAajhD,EAC/BC,EAAGshD,EAAWthD,EAAIghD,EAAahhD,GAE7B2wC,EAAoB5iD,KAAKmrD,kBACzBtI,GACF7wC,EAAG4wC,EAAkB5wC,EAAIwhD,EAAmBxhD,EAAIhS,KAAKkd,MAAQld,KAAK+iD,mBAAmB/wC,EACrFC,EAAG2wC,EAAkB3wC,EAAIuhD,EAAmBvhD,EAAIjS,KAAKkd,MAAQld,KAAK+iD,mBAAmB9wC,EAGvFjS,MAAK4jD,gBAAgBf,EAAkB7wC,EAAE6wC,EAAkB5wC,GAC3DjS,KAAKyzD,kBAGPvwD,EAAQkQ,UAAUw4C,YAAc,WACH,MAAvB5rD,KAAK8iD,iBACP9iD,KAAKmjD,QAAUnjD,KAAKyzD,eACpBzzD,KAAK8iD,eAAiB,KACtB9iD,KAAK+iD,mBAAqB,OAS9B7/C,EAAQkQ,UAAUkgD,kBAAoB,SAAU7Q,GAC9CziD,KAAKyiD,WAAaA,GAAcziD,KAAKyiD,WAAaziD,KAAKuiD,eACvDviD,KAAKyiD,YAAcziD,KAAKuiD,cAExB,IAAI7wB,GAAW/wB,EAAKsP,gBAAgBjQ,KAAKwiD,yBAAyBxiD,KAAKyiD,WAEvEziD,MAAKid,UAAUjd,KAAK0iD,aAAe1iD,KAAK2iD,YAAc3iD,KAAK0iD,aAAehxB,GAC1E1xB,KAAK4jD,gBACH5jD,KAAK4iD,kBAAkB5wC,GAAKhS,KAAK6iD,kBAAkB7wC,EAAIhS,KAAK4iD,kBAAkB5wC,GAAK0f,EACnF1xB,KAAK4iD,kBAAkB3wC,GAAKjS,KAAK6iD,kBAAkB5wC,EAAIjS,KAAK4iD,kBAAkB3wC,GAAKyf,GAGrF1xB,KAAKyzD,iBACLzzD,KAAKolD,QAAS,EAGVplD,KAAKyiD,YAAc,IACrBziD,KAAKyiD,WAAa,EAEhBziD,KAAKmjD,QADoB,MAAvBnjD,KAAK8iD,eACQ9iD,KAAK0zD,cAGL1zD,KAAKyzD,eAEtBzzD,KAAK6tB,KAAK,uBAId3qB,EAAQkQ,UAAUqgD,eAAiB,aAQnCvwD,EAAQkQ,UAAU02C,SAAW,WAC3B,OAAQ9pD,KAAK2oD,WAAa3oD,KAAK2oD,UAAUgL,QAQ3CzwD,EAAQkQ,UAAUiwB,SAAW,WAC3B,MAAOrjC,MAAKid,aAQd/Z,EAAQkQ,UAAUwgD,SAAW,WAC3B,MAAO5zD,MAAK+qD,aAQd7nD,EAAQkQ,UAAUygD,qBAAuB,WACvC,MAAO7zD,MAAKysD,aAAaz6C,EAAG,GAAMhS,KAAKuf,MAAMC,OAAOC,YAAaxN,EAAG,GAAMjS,KAAKuf,MAAMC,OAAOsF,gBAI9F5hB,EAAQkQ,UAAU0gD,eAAiB,SAAStN,GAC1C,MAA2BjgD,UAAvBvG,KAAKs9C,MAAMkJ,GACNxmD,KAAKs9C,MAAMkJ,GAAQC,YAD5B,QAKF5mD,EAAOD,QAAUsD,GAKb,SAASrD,EAAQD,EAASM,GAoB9B,QAASkD,GAAM4rD,EAAY7rD,EAAS4wD,GAClC,IAAK5wD,EACH,KAAM,qBAER,IAAIgL,IAAU,QAAQ,WAClB6zC,EAAYrhD,EAAKuN,sBAAsBC,EAAO4lD,EAClD/zD,MAAK0O,QAAUszC,EAAU5D,MACzBp+C,KAAK8+C,QAAUkD,EAAUlD,QACzB9+C,KAAK0O,QAAsB,aAAIqlD,EAA+B,aAG9D/zD,KAAKmD,QAAUA,EAGfnD,KAAKK,GAASkG,OACdvG,KAAKg0D,OAASztD,OACdvG,KAAKi0D,KAAS1tD,OACdvG,KAAKqlC,MAAS9+B,OACdvG,KAAKk0D,cAAgBl0D,KAAK0O,QAAQ8D,MAAQxS,KAAK0O,QAAQ2vC,yBACvDr+C,KAAKoH,MAASb,OACdvG,KAAKwzC,UAAW,EAChBxzC,KAAKuM,OAAQ,EACbvM,KAAKm0D,iBAAmBvsD,IAAI,EAAEJ,KAAK,EAAEgL,MAAM,EAAEC,OAAO,EAAE2hD,MAAM,GAC5Dp0D,KAAKq0D,YAAa,EAElBr0D,KAAKqpB,KAAO,KACZrpB,KAAKspB,GAAK,KACVtpB,KAAKsvD,IAAM,KAEXtvD,KAAKs0D,WAAa,KAClBt0D,KAAKu0D,SAAW,KAIhBv0D,KAAKw0D,kBACLx0D,KAAKy0D,gBAELz0D,KAAKguD,WAAY,EAEjBhuD,KAAK00D,YAAc,EACnB10D,KAAK20D,aAAc,EAEnB30D,KAAK+uD,cAAcC,GAEnBhvD,KAAK40D,qBAAsB,EAC3B50D,KAAK60D,cAAgBxrC,KAAK,KAAMC,GAAG,KAAMwrC,cACzC90D,KAAK+0D,cAAgB,KAhEvB,GAAIp0D,GAAOT,EAAoB,GAC3BqD,EAAOrD,EAAoB,GAuE/BkD,GAAKgQ,UAAU27C,cAAgB,SAASC,GACtC,GAAKA,EAAL,CAIA,GAAI7gD,IAAU,QAAQ,WAAW,WAAW,YAAY,WAAW,kBAAkB,kBAAkB,QACrG,2BAA2B,aAAa,mBAAmB,OAAO,eAAe,iBAoCnF,QAlCAxN,EAAKuF,oBAAoBiI,EAAQnO,KAAK0O,QAASsgD,GAEvBzoD,SAApByoD,EAAW3lC,OAA+BrpB,KAAKg0D,OAAShF,EAAW3lC,MACjD9iB,SAAlByoD,EAAW1lC,KAA+BtpB,KAAKi0D,KAAOjF,EAAW1lC,IAE/C/iB,SAAlByoD,EAAW3uD,KAA+BL,KAAKK,GAAK2uD,EAAW3uD,IAC1CkG,SAArByoD,EAAWtmC,QAA+B1oB,KAAK0oB,MAAQsmC,EAAWtmC,MAAO1oB,KAAKq0D,YAAa,GAEtE9tD,SAArByoD,EAAW3pB,QAA6BrlC,KAAKqlC,MAAQ2pB,EAAW3pB,OAC3C9+B,SAArByoD,EAAW5nD,QAA6BpH,KAAKoH,MAAQ4nD,EAAW5nD,OAC1Cb,SAAtByoD,EAAWtpD,SAA6B1F,KAAK8+C,QAAQK,aAAe6P,EAAWtpD,QAE1Da,SAArByoD,EAAW5jD,QACbpL,KAAK0O,QAAQkwC,cAAe,EACxBj+C,EAAKuD,SAAS8qD,EAAW5jD,QAC3BpL,KAAK0O,QAAQtD,MAAMA,MAAQ4jD,EAAW5jD,MACtCpL,KAAK0O,QAAQtD,MAAMkB,UAAY0iD,EAAW5jD,QAGX7E,SAA3ByoD,EAAW5jD,MAAMA,QAA0BpL,KAAK0O,QAAQtD,MAAMA,MAAQ4jD,EAAW5jD,MAAMA,OACxD7E,SAA/ByoD,EAAW5jD,MAAMkB,YAA0BtM,KAAK0O,QAAQtD,MAAMkB,UAAY0iD,EAAW5jD,MAAMkB,WAChE/F,SAA3ByoD,EAAW5jD,MAAMmB,QAA0BvM,KAAK0O,QAAQtD,MAAMmB,MAAQyiD,EAAW5jD,MAAMmB,SAK/FvM,KAAKo9C,UAELp9C,KAAK00D,WAAa10D,KAAK00D,YAAoCnuD,SAArByoD,EAAWx8C,MACjDxS,KAAK20D,YAAc30D,KAAK20D,aAAsCpuD,SAAtByoD,EAAWtpD,OAEnD1F,KAAKk0D,cAAgBl0D,KAAK0O,QAAQ8D,MAAOxS,KAAK0O,QAAQ2vC,yBAG9Cr+C,KAAK0O,QAAQxB,OACnB,IAAK,OAAiBlN,KAAKssC,KAAOtsC,KAAKg1D,SAAW,MAClD,KAAK,QAAiBh1D,KAAKssC,KAAOtsC,KAAKi1D,UAAY,MACnD,KAAK,eAAiBj1D,KAAKssC,KAAOtsC,KAAKk1D,gBAAkB,MACzD,KAAK,YAAiBl1D,KAAKssC,KAAOtsC,KAAKm1D,aAAe,MACtD,SAAsBn1D,KAAKssC,KAAOtsC,KAAKg1D,aAQ3C5xD,EAAKgQ,UAAUgqC,QAAU,WACvBp9C,KAAKmvD,aAELnvD,KAAKqpB,KAAOrpB,KAAKmD,QAAQm6C,MAAMt9C,KAAKg0D,SAAW,KAC/Ch0D,KAAKspB,GAAKtpB,KAAKmD,QAAQm6C,MAAMt9C,KAAKi0D,OAAS,KAC3Cj0D,KAAKguD,UAAahuD,KAAKqpB,MAAQrpB,KAAKspB,GAEhCtpB,KAAKguD,WACPhuD,KAAKqpB,KAAK+rC,WAAWp1D,MACrBA,KAAKspB,GAAG8rC,WAAWp1D,QAGfA,KAAKqpB,MACPrpB,KAAKqpB,KAAKgsC,WAAWr1D,MAEnBA,KAAKspB,IACPtpB,KAAKspB,GAAG+rC,WAAWr1D,QAQzBoD,EAAKgQ,UAAU+7C,WAAa,WACtBnvD,KAAKqpB,OACPrpB,KAAKqpB,KAAKgsC,WAAWr1D,MACrBA,KAAKqpB,KAAO,MAEVrpB,KAAKspB,KACPtpB,KAAKspB,GAAG+rC,WAAWr1D,MACnBA,KAAKspB,GAAK,MAGZtpB,KAAKguD,WAAY;EAQnB5qD,EAAKgQ,UAAUy6C,SAAW,WACxB,MAA6B,kBAAf7tD,MAAKqlC,MAAuBrlC,KAAKqlC,QAAUrlC,KAAKqlC,OAQhEjiC,EAAKgQ,UAAUyB,SAAW,WACxB,MAAO7U,MAAKoH,OASdhE,EAAKgQ,UAAUq8C,cAAgB,SAAS1jD,EAAKY,GAC3C,IAAK3M,KAAK00D,YAA6BnuD,SAAfvG,KAAKoH,MAAqB,CAChD,GAAI8V,IAASld,KAAK0O,QAAQ0Y,SAAWpnB,KAAK0O,QAAQyY,WAAaxa,EAAMZ,EACrE/L,MAAK0O,QAAQ8D,OAAQxS,KAAKoH,MAAQ2E,GAAOmR,EAAQld,KAAK0O,QAAQyY,SAC9DnnB,KAAKk0D,cAAgBl0D,KAAK0O,QAAQ8D,MAAOxS,KAAK0O,QAAQ2vC,2BAU1Dj7C,EAAKgQ,UAAUk5B,KAAO,WACpB,KAAM,uCAQRlpC,EAAKgQ,UAAUw6C,kBAAoB,SAAS5qC,GAC1C,GAAIhjB,KAAKguD,UAAW,CAClB,GAAI3+B,GAAU,GACVimC,EAAQt1D,KAAKqpB,KAAKrX,EAClBujD,EAAQv1D,KAAKqpB,KAAKpX,EAClBujD,EAAMx1D,KAAKspB,GAAGtX,EACdyjD,EAAMz1D,KAAKspB,GAAGrX,EACdyjD,EAAO1yC,EAAIxb,KACXmuD,EAAO3yC,EAAIpb,IAEXujB,EAAOnrB,KAAK41D,mBAAmBN,EAAOC,EAAOC,EAAKC,EAAKC,EAAMC,EAEjE,OAAetmC,GAAPlE,EAGR,OAAO,GAIX/nB,EAAKgQ,UAAUyiD,UAAY,WACzB,GAAIC,GAAW91D,KAAK0O,QAAQtD,KAgB5B,OAfiC,MAA7BpL,KAAK0O,QAAQkwC,aACfkX,GACExpD,UAAWtM,KAAKspB,GAAG5a,QAAQtD,MAAMkB,UAAUD,OAC3CE,MAAOvM,KAAKspB,GAAG5a,QAAQtD,MAAMmB,MAAMF,OACnCjB,MAAOpL,KAAKspB,GAAG5a,QAAQtD,MAAMiB,SAGK,QAA7BrM,KAAK0O,QAAQkwC,cAAuD,GAA7B5+C,KAAK0O,QAAQkwC,gBAC3DkX,GACExpD,UAAWtM,KAAKqpB,KAAK3a,QAAQtD,MAAMkB,UAAUD,OAC7CE,MAAOvM,KAAKqpB,KAAK3a,QAAQtD,MAAMmB,MAAMF,OACrCjB,MAAOpL,KAAKqpB,KAAK3a,QAAQtD,MAAMiB,SAId,GAAjBrM,KAAKwzC,SAA4BsiB,EAASxpD,UACvB,GAAdtM,KAAKuM,MAAuBupD,EAASvpD,MACTupD,EAAS1qD,OAWhDhI,EAAKgQ,UAAU4hD,UAAY,SAAShuC,GAKlC,GAHAA,EAAIY,YAAc5nB,KAAK61D,YACvB7uC,EAAIO,UAAcvnB,KAAK+1D,gBAEnB/1D,KAAKqpB,MAAQrpB,KAAKspB,GAAI,CAExB,GAGInX,GAHAm9C,EAAMtvD,KAAKg2D,MAAMhvC,EAIrB,IAAIhnB,KAAK0oB,MAAO,CACd,GAAyC,GAArC1oB,KAAK0O,QAAQ0yC,aAAazyC,SAA0B,MAAP2gD,EAAa,CAC5D,GAAI2G,GAAY,IAAK,IAAKj2D,KAAKqpB,KAAKrX,EAAIs9C,EAAIt9C,GAAK,IAAKhS,KAAKspB,GAAGtX,EAAIs9C,EAAIt9C,IAClEkkD,EAAY,IAAK,IAAKl2D,KAAKqpB,KAAKpX,EAAIq9C,EAAIr9C,GAAK,IAAKjS,KAAKspB,GAAGrX,EAAIq9C,EAAIr9C,GACtEE,IAASH,EAAEikD,EAAWhkD,EAAEikD,OAGxB/jD,GAAQnS,KAAKm2D,aAAa,GAE5Bn2D,MAAKo2D,OAAOpvC,EAAKhnB,KAAK0oB,MAAOvW,EAAMH,EAAGG,EAAMF,QAG3C,CACH,GAAID,GAAGC,EACHyZ,EAAS1rB,KAAK8+C,QAAQK,aAAe,EACrCgH,EAAOnmD,KAAKqpB,IACX88B,GAAK3zC,OACR2zC,EAAKkQ,OAAOrvC,GAEVm/B,EAAK3zC,MAAQ2zC,EAAK1zC,QACpBT,EAAIm0C,EAAKn0C,EAAIm0C,EAAK3zC,MAAQ,EAC1BP,EAAIk0C,EAAKl0C,EAAIyZ,IAGb1Z,EAAIm0C,EAAKn0C,EAAI0Z,EACbzZ,EAAIk0C,EAAKl0C,EAAIk0C,EAAK1zC,OAAS,GAE7BzS,KAAKs2D,QAAQtvC,EAAKhV,EAAGC,EAAGyZ,GACxBvZ,EAAQnS,KAAKu2D,eAAevkD,EAAGC,EAAGyZ,EAAQ,IAC1C1rB,KAAKo2D,OAAOpvC,EAAKhnB,KAAK0oB,MAAOvW,EAAMH,EAAGG,EAAMF,KAUhD7O,EAAKgQ,UAAU2iD,cAAgB,WAC7B,MAAqB,IAAjB/1D,KAAKwzC,SACCvuC,KAAK0H,IAAI1H,KAAK8G,IAAI/L,KAAKk0D,cAAel0D,KAAK0O,QAAQ0Y,UAAW,GAAIpnB,KAAKw2D,iBAG7D,GAAdx2D,KAAKuM,MACAtH,KAAK0H,IAAI1H,KAAK8G,IAAI/L,KAAK0O,QAAQ4vC,WAAYt+C,KAAK0O,QAAQ0Y,UAAW,GAAIpnB,KAAKw2D,iBAG5EvxD,KAAK0H,IAAI3M,KAAK0O,QAAQ8D,MAAO,GAAIxS,KAAKw2D,kBAKnDpzD,EAAKgQ,UAAUqjD,mBAAqB,WAClC,GAAyC,GAArCz2D,KAAK0O,QAAQ0yC,aAAaC,SAAwD,GAArCrhD,KAAK0O,QAAQ0yC,aAAazyC,QACzE,MAAO3O,MAAKsvD,GAET,IAAyC,GAArCtvD,KAAK0O,QAAQ0yC,aAAazyC,QACjC,OAAQqD,EAAE,EAAEC,EAAE,EAGd,IAAIykD,GAAO,KACPC,EAAO,KACP3P,EAAShnD,KAAK0O,QAAQ0yC,aAAaE,UACnCz6C,EAAO7G,KAAK0O,QAAQ0yC,aAAav6C,KAEjCgY,EAAK5Z,KAAK6lB,IAAI9qB,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,GACpC8M,EAAK7Z,KAAK6lB,IAAI9qB,KAAKqpB,KAAKpX,EAAIjS,KAAKspB,GAAGrX,EA2JxC,OA1JY,YAARpL,GAA8B,iBAARA,EACpB5B,KAAK6lB,IAAI9qB,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,GAAK/M,KAAK6lB,IAAI9qB,KAAKqpB,KAAKpX,EAAIjS,KAAKspB,GAAGrX,IACjEjS,KAAKqpB,KAAKpX,EAAIjS,KAAKspB,GAAGrX,EACpBjS,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,GACxB0kD,EAAO12D,KAAKqpB,KAAKrX,EAAIg1C,EAASloC,EAC9B63C,EAAO32D,KAAKqpB,KAAKpX,EAAI+0C,EAASloC,GAEvB9e,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,IAC7B0kD,EAAO12D,KAAKqpB,KAAKrX,EAAIg1C,EAASloC,EAC9B63C,EAAO32D,KAAKqpB,KAAKpX,EAAI+0C,EAASloC,GAGzB9e,KAAKqpB,KAAKpX,EAAIjS,KAAKspB,GAAGrX,IACzBjS,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,GACxB0kD,EAAO12D,KAAKqpB,KAAKrX,EAAIg1C,EAASloC,EAC9B63C,EAAO32D,KAAKqpB,KAAKpX,EAAI+0C,EAASloC,GAEvB9e,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,IAC7B0kD,EAAO12D,KAAKqpB,KAAKrX,EAAIg1C,EAASloC,EAC9B63C,EAAO32D,KAAKqpB,KAAKpX,EAAI+0C,EAASloC,IAGtB,YAARjY,IACF6vD,EAAY1P,EAASloC,EAAdD,EAAmB7e,KAAKqpB,KAAKrX,EAAI0kD,IAGnCzxD,KAAK6lB,IAAI9qB,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,GAAK/M,KAAK6lB,IAAI9qB,KAAKqpB,KAAKpX,EAAIjS,KAAKspB,GAAGrX,KACtEjS,KAAKqpB,KAAKpX,EAAIjS,KAAKspB,GAAGrX,EACpBjS,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,GACxB0kD,EAAO12D,KAAKqpB,KAAKrX,EAAIg1C,EAASnoC,EAC9B83C,EAAO32D,KAAKqpB,KAAKpX,EAAI+0C,EAASnoC,GAEvB7e,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,IAC7B0kD,EAAO12D,KAAKqpB,KAAKrX,EAAIg1C,EAASnoC,EAC9B83C,EAAO32D,KAAKqpB,KAAKpX,EAAI+0C,EAASnoC,GAGzB7e,KAAKqpB,KAAKpX,EAAIjS,KAAKspB,GAAGrX,IACzBjS,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,GACxB0kD,EAAO12D,KAAKqpB,KAAKrX,EAAIg1C,EAASnoC,EAC9B83C,EAAO32D,KAAKqpB,KAAKpX,EAAI+0C,EAASnoC,GAEvB7e,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,IAC7B0kD,EAAO12D,KAAKqpB,KAAKrX,EAAIg1C,EAASnoC,EAC9B83C,EAAO32D,KAAKqpB,KAAKpX,EAAI+0C,EAASnoC,IAGtB,YAARhY,IACF8vD,EAAY3P,EAASnoC,EAAdC,EAAmB9e,KAAKqpB,KAAKpX,EAAI0kD,IAI7B,iBAAR9vD,EACH5B,KAAK6lB,IAAI9qB,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,GAAK/M,KAAK6lB,IAAI9qB,KAAKqpB,KAAKpX,EAAIjS,KAAKspB,GAAGrX,IACrEykD,EAAO12D,KAAKqpB,KAAKrX,EAEf2kD,EADE32D,KAAKqpB,KAAKpX,EAAIjS,KAAKspB,GAAGrX,EACjBjS,KAAKspB,GAAGrX,GAAK,EAAI+0C,GAAUloC,EAG3B9e,KAAKspB,GAAGrX,GAAK,EAAI+0C,GAAUloC,GAG7B7Z,KAAK6lB,IAAI9qB,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,GAAK/M,KAAK6lB,IAAI9qB,KAAKqpB,KAAKpX,EAAIjS,KAAKspB,GAAGrX,KAExEykD,EADE12D,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,EACjBhS,KAAKspB,GAAGtX,GAAK,EAAIg1C,GAAUnoC,EAG3B7e,KAAKspB,GAAGtX,GAAK,EAAIg1C,GAAUnoC,EAEpC83C,EAAO32D,KAAKqpB,KAAKpX,GAGJ,cAARpL,GAEL6vD,EADE12D,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,EACjBhS,KAAKspB,GAAGtX,GAAK,EAAIg1C,GAAUnoC,EAG3B7e,KAAKspB,GAAGtX,GAAK,EAAIg1C,GAAUnoC,EAEpC83C,EAAO32D,KAAKqpB,KAAKpX,GAEF,YAARpL,GACP6vD,EAAO12D,KAAKqpB,KAAKrX,EAEf2kD,EADE32D,KAAKqpB,KAAKpX,EAAIjS,KAAKspB,GAAGrX,EACjBjS,KAAKspB,GAAGrX,GAAK,EAAI+0C,GAAUloC,EAG3B9e,KAAKspB,GAAGrX,GAAK,EAAI+0C,GAAUloC,GAIhC7Z,KAAK6lB,IAAI9qB,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,GAAK/M,KAAK6lB,IAAI9qB,KAAKqpB,KAAKpX,EAAIjS,KAAKspB,GAAGrX,GACjEjS,KAAKqpB,KAAKpX,EAAIjS,KAAKspB,GAAGrX,EACpBjS,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,GAExB0kD,EAAO12D,KAAKqpB,KAAKrX,EAAIg1C,EAASloC,EAC9B63C,EAAO32D,KAAKqpB,KAAKpX,EAAI+0C,EAASloC,EAC9B43C,EAAO12D,KAAKspB,GAAGtX,EAAI0kD,EAAO12D,KAAKspB,GAAGtX,EAAI0kD,GAE/B12D,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,IAE7B0kD,EAAO12D,KAAKqpB,KAAKrX,EAAIg1C,EAASloC,EAC9B63C,EAAO32D,KAAKqpB,KAAKpX,EAAI+0C,EAASloC,EAC9B43C,EAAO12D,KAAKspB,GAAGtX,EAAI0kD,EAAO12D,KAAKspB,GAAGtX,EAAI0kD,GAGjC12D,KAAKqpB,KAAKpX,EAAIjS,KAAKspB,GAAGrX,IACzBjS,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,GAExB0kD,EAAO12D,KAAKqpB,KAAKrX,EAAIg1C,EAASloC,EAC9B63C,EAAO32D,KAAKqpB,KAAKpX,EAAI+0C,EAASloC,EAC9B43C,EAAO12D,KAAKspB,GAAGtX,EAAI0kD,EAAO12D,KAAKspB,GAAGtX,EAAI0kD,GAE/B12D,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,IAE7B0kD,EAAO12D,KAAKqpB,KAAKrX,EAAIg1C,EAASloC,EAC9B63C,EAAO32D,KAAKqpB,KAAKpX,EAAI+0C,EAASloC,EAC9B43C,EAAO12D,KAAKspB,GAAGtX,EAAI0kD,EAAO12D,KAAKspB,GAAGtX,EAAI0kD,IAInCzxD,KAAK6lB,IAAI9qB,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,GAAK/M,KAAK6lB,IAAI9qB,KAAKqpB,KAAKpX,EAAIjS,KAAKspB,GAAGrX,KACtEjS,KAAKqpB,KAAKpX,EAAIjS,KAAKspB,GAAGrX,EACpBjS,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,GAExB0kD,EAAO12D,KAAKqpB,KAAKrX,EAAIg1C,EAASnoC,EAC9B83C,EAAO32D,KAAKqpB,KAAKpX,EAAI+0C,EAASnoC,EAC9B83C,EAAO32D,KAAKspB,GAAGrX,EAAI0kD,EAAO32D,KAAKspB,GAAGrX,EAAI0kD,GAE/B32D,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,IAE7B0kD,EAAO12D,KAAKqpB,KAAKrX,EAAIg1C,EAASnoC,EAC9B83C,EAAO32D,KAAKqpB,KAAKpX,EAAI+0C,EAASnoC,EAC9B83C,EAAO32D,KAAKspB,GAAGrX,EAAI0kD,EAAO32D,KAAKspB,GAAGrX,EAAI0kD,GAGjC32D,KAAKqpB,KAAKpX,EAAIjS,KAAKspB,GAAGrX,IACzBjS,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,GAExB0kD,EAAO12D,KAAKqpB,KAAKrX,EAAIg1C,EAASnoC,EAC9B83C,EAAO32D,KAAKqpB,KAAKpX,EAAI+0C,EAASnoC,EAC9B83C,EAAO32D,KAAKspB,GAAGrX,EAAI0kD,EAAO32D,KAAKspB,GAAGrX,EAAI0kD,GAE/B32D,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,IAE7B0kD,EAAO12D,KAAKqpB,KAAKrX,EAAIg1C,EAASnoC,EAC9B83C,EAAO32D,KAAKqpB,KAAKpX,EAAI+0C,EAASnoC,EAC9B83C,EAAO32D,KAAKspB,GAAGrX,EAAI0kD,EAAO32D,KAAKspB,GAAGrX,EAAI0kD,MAOtC3kD,EAAG0kD,EAAMzkD,EAAG0kD,IASxBvzD,EAAKgQ,UAAU4iD,MAAQ,SAAUhvC,GAI/B,GAFAA,EAAIa,YACJb,EAAIc,OAAO9nB,KAAKqpB,KAAKrX,EAAGhS,KAAKqpB,KAAKpX,GACO,GAArCjS,KAAK0O,QAAQ0yC,aAAazyC,QAAiB,CAC7C,GAAyC,GAArC3O,KAAK0O,QAAQ0yC,aAAaC,QAAkB,CAC9C,GAAIiO,GAAMtvD,KAAKy2D,oBACf,OAAa,OAATnH,EAAIt9C,GACNgV,EAAIe,OAAO/nB,KAAKspB,GAAGtX,EAAGhS,KAAKspB,GAAGrX,GAC9B+U,EAAIlH,SACG,OAKPkH,EAAI4vC,iBAAiBtH,EAAIt9C,EAAEs9C,EAAIr9C,EAAEjS,KAAKspB,GAAGtX,EAAGhS,KAAKspB,GAAGrX,GACpD+U,EAAIlH,SACGwvC,GAMT,MAFAtoC,GAAI4vC,iBAAiB52D,KAAKsvD,IAAIt9C,EAAEhS,KAAKsvD,IAAIr9C,EAAEjS,KAAKspB,GAAGtX,EAAGhS,KAAKspB,GAAGrX,GAC9D+U,EAAIlH,SACG9f,KAAKsvD,IAMd,MAFAtoC,GAAIe,OAAO/nB,KAAKspB,GAAGtX,EAAGhS,KAAKspB,GAAGrX,GAC9B+U,EAAIlH,SACG,MAYX1c,EAAKgQ,UAAUkjD,QAAU,SAAUtvC,EAAKhV,EAAGC,EAAGyZ,GAE5C1E,EAAIa,YACJb,EAAI2E,IAAI3Z,EAAGC,EAAGyZ,EAAQ,EAAG,EAAIzmB,KAAK2mB,IAAI,GACtC5E,EAAIlH,UAWN1c,EAAKgQ,UAAUgjD,OAAS,SAAUpvC,EAAKwC,EAAMxX,EAAGC,GAC9C,GAAIuX,EAAM,CACRxC,EAAIQ,MAASxnB,KAAKqpB,KAAKmqB,UAAYxzC,KAAKspB,GAAGkqB,SAAY,QAAU,IACjExzC,KAAK0O,QAAQmvC,SAAW,MAAQ79C,KAAK0O,QAAQovC,QAC7C,IAAIsW,EAEJ,IAAuB,GAAnBp0D,KAAKq0D,WAAoB,CAC3B,GAAIttB,GAAQ5iC,OAAOqlB,GAAMvhB,MAAM,MAC3B4uD,EAAY9vB,EAAMrhC,OAClBm4C,EAAW55C,OAAOjE,KAAK0O,QAAQmvC,SACnCuW,GAAQniD,GAAK,EAAI4kD,GAAa,EAAIhZ,CAGlC,KAAK,GADDrrC,GAAQwU,EAAI8vC,YAAY/vB,EAAM,IAAIv0B,MAC7BjN,EAAI,EAAOsxD,EAAJtxD,EAAeA,IAAK,CAClC,GAAIgiB,GAAYP,EAAI8vC,YAAY/vB,EAAMxhC,IAAIiN,KAC1CA,GAAQ+U,EAAY/U,EAAQ+U,EAAY/U,EAE1C,GAAIC,GAASzS,KAAK0O,QAAQmvC,SAAWgZ,EACjCrvD,EAAOwK,EAAIQ,EAAQ,EACnB5K,EAAMqK,EAAIQ,EAAS,CAGvBzS,MAAKm0D,iBAAmBvsD,IAAIA,EAAIJ,KAAKA,EAAKgL,MAAMA,EAAMC,OAAOA,EAAO2hD,MAAMA,GAG/E,GAAIA,GAAQp0D,KAAKm0D,gBAAgBC,KAEjCptC,GAAI2oC,OAE+B,cAA/B3vD,KAAK0O,QAAQ6vC,iBAChBv3B,EAAI4oC,UAAU59C,EAAGoiD,GACjBp0D,KAAK+2D,yBAAyB/vC,GAC9BhV,EAAI,EACJoiD,EAAQ,GAITp0D,KAAKg3D,eAAehwC,GACpBhnB,KAAKi3D,eAAejwC,EAAIhV,EAAEoiD,EAAOrtB,EAAO8vB,EAAWhZ,GAEnD72B,EAAI8oC,YASL1sD,EAAKgQ,UAAU2jD,yBAA2B,SAAS/vC,GAClD,GAAIlI,GAAK9e,KAAKqpB,KAAKpX,EAAIjS,KAAKspB,GAAGrX,EAC3B4M,EAAK7e,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,EAC3BklD,EAAiBjyD,KAAKkyD,MAAMr4C,EAAID,IAGf,GAAjBq4C,GAA4B,EAALr4C,GAAYq4C,EAAiB,GAAU,EAALr4C,KAC5Dq4C,GAAkCjyD,KAAK2mB,IAGxC5E,EAAIowC,OAAOF,IASZ9zD,EAAKgQ,UAAU4jD,eAAiB,SAAShwC,GACxC,GAA8BzgB,SAA1BvG,KAAK0O,QAAQqvC,UAAoD,OAA1B/9C,KAAK0O,QAAQqvC,UAA+C,SAA1B/9C,KAAK0O,QAAQqvC,SAAqB,CAC9G/2B,EAAIiB,UAAYjoB,KAAK0O,QAAQqvC,QAE7B,IAAIsZ,GAAa,CAEoB,gBAA/Br3D,KAAK0O,QAAQ6vC,eACfv3B,EAAIswC,SAAuC,IAA7Bt3D,KAAKm0D,gBAAgB3hD,MAA4C,IAA9BxS,KAAKm0D,gBAAgB1hD,OAAczS,KAAKm0D,gBAAgB3hD,MAAOxS,KAAKm0D,gBAAgB1hD,QAE/F,cAA/BzS,KAAK0O,QAAQ6vC,eACpBv3B,EAAIswC,SAAuC,IAA7Bt3D,KAAKm0D,gBAAgB3hD,QAAexS,KAAKm0D,gBAAgB1hD,OAAS4kD,GAAar3D,KAAKm0D,gBAAgB3hD,MAAOxS,KAAKm0D,gBAAgB1hD,QAExG,cAA/BzS,KAAK0O,QAAQ6vC,eACpBv3B,EAAIswC,SAAuC,IAA7Bt3D,KAAKm0D,gBAAgB3hD,MAAa6kD,EAAYr3D,KAAKm0D,gBAAgB3hD,MAAOxS,KAAKm0D,gBAAgB1hD,QAG7GuU,EAAIswC,SAASt3D,KAAKm0D,gBAAgB3sD,KAAMxH,KAAKm0D,gBAAgBvsD,IAAK5H,KAAKm0D,gBAAgB3hD,MAAOxS,KAAKm0D,gBAAgB1hD,UAezHrP,EAAKgQ,UAAU6jD,eAAiB,SAASjwC,EAAKhV,EAAGoiD,EAAOrtB,EAAO8vB,EAAWhZ,GAMxE,GAJD72B,EAAIiB,UAAYjoB,KAAK0O,QAAQkvC,WAAa,QAC1C52B,EAAIuB,UAAY,SAGoB,cAA/BvoB,KAAK0O,QAAQ6vC,eAAgC,CAC/C,GAAI8Y,GAAa,CACkB,eAA/Br3D,KAAK0O,QAAQ6vC,gBACfv3B,EAAIwB,aAAe,aACnB4rC,GAAS,EAAIiD,GAEyB,cAA/Br3D,KAAK0O,QAAQ6vC,gBACpBv3B,EAAIwB,aAAe,UACnB4rC,GAAS,EAAIiD,GAGbrwC,EAAIwB,aAAe,aAIrBxB,GAAIwB,aAAe,QAIjBxoB,MAAK0O,QAAQsvC,gBAAkB,IACjCh3B,EAAIO,UAAcvnB,KAAK0O,QAAQsvC,gBAC/Bh3B,EAAIY,YAAc5nB,KAAK0O,QAAQuvC,gBAC/Bj3B,EAAIuwC,SAAc,QAErB,KAAK,GAAIhyD,GAAI,EAAOsxD,EAAJtxD,EAAeA,IACzBvF,KAAK0O,QAAQsvC,gBAAkB,GAChCh3B,EAAIwwC,WAAWzwB,EAAMxhC,GAAIyM,EAAGoiD,GAEhCptC,EAAIyB,SAASse,EAAMxhC,GAAIyM,EAAGoiD,GAC1BA,GAASvW,GAaXz6C,EAAKgQ,UAAU+hD,cAAgB,SAASnuC,GAEtCA,EAAIY,YAAc5nB,KAAK61D,YACvB7uC,EAAIO,UAAYvnB,KAAK+1D,eAErB,IAAIzG,GAAM,IAEV,IAAwB/oD,SAApBygB,EAAIywC,YAA2B,CACjCzwC,EAAI2oC,MAEJ,IAAI+H,IAAW,EAEbA,GAD+BnxD,SAA7BvG,KAAK0O,QAAQ+vC,KAAK/4C,QAAkDa,SAA1BvG,KAAK0O,QAAQ+vC,KAAKC,KACnD1+C,KAAK0O,QAAQ+vC,KAAK/4C,OAAO1F,KAAK0O,QAAQ+vC,KAAKC,MAG3C,EAAE,GAIf13B,EAAIywC,YAAYC,GAChB1wC,EAAI2wC,eAAiB,EAGrBrI,EAAMtvD,KAAKg2D,MAAMhvC,GAGjBA,EAAIywC,aAAa,IACjBzwC,EAAI2wC,eAAiB,EACrB3wC,EAAI8oC,cAIJ9oC,GAAIa,YACJb,EAAI4wC,QAAU,QACsBrxD,SAAhCvG,KAAK0O,QAAQ+vC,KAAKE,UAEpB33B,EAAI6wC,WAAW73D,KAAKqpB,KAAKrX,EAAEhS,KAAKqpB,KAAKpX,EAAEjS,KAAKspB,GAAGtX,EAAEhS,KAAKspB,GAAGrX,GACpDjS,KAAK0O,QAAQ+vC,KAAK/4C,OAAO1F,KAAK0O,QAAQ+vC,KAAKC,IAAI1+C,KAAK0O,QAAQ+vC,KAAKE,UAAU3+C,KAAK0O,QAAQ+vC,KAAKC,MAE9Dn4C,SAA7BvG,KAAK0O,QAAQ+vC,KAAK/4C,QAAkDa,SAA1BvG,KAAK0O,QAAQ+vC,KAAKC,IAEnE13B,EAAI6wC,WAAW73D,KAAKqpB,KAAKrX,EAAEhS,KAAKqpB,KAAKpX,EAAEjS,KAAKspB,GAAGtX,EAAEhS,KAAKspB,GAAGrX,GACpDjS,KAAK0O,QAAQ+vC,KAAK/4C,OAAO1F,KAAK0O,QAAQ+vC,KAAKC,OAIhD13B,EAAIc,OAAO9nB,KAAKqpB,KAAKrX,EAAGhS,KAAKqpB,KAAKpX,GAClC+U,EAAIe,OAAO/nB,KAAKspB,GAAGtX,EAAGhS,KAAKspB,GAAGrX,IAEhC+U,EAAIlH,QAIN,IAAI9f,KAAK0oB,MAAO,CACd,GAAIvW,EACJ,IAAyC,GAArCnS,KAAK0O,QAAQ0yC,aAAazyC,SAA0B,MAAP2gD,EAAa,CAC5D,GAAI2G,GAAY,IAAK,IAAKj2D,KAAKqpB,KAAKrX,EAAIs9C,EAAIt9C,GAAK,IAAKhS,KAAKspB,GAAGtX,EAAIs9C,EAAIt9C,IAClEkkD,EAAY,IAAK,IAAKl2D,KAAKqpB,KAAKpX,EAAIq9C,EAAIr9C,GAAK,IAAKjS,KAAKspB,GAAGrX,EAAIq9C,EAAIr9C,GACtEE,IAASH,EAAEikD,EAAWhkD,EAAEikD,OAGxB/jD,GAAQnS,KAAKm2D,aAAa,GAE5Bn2D,MAAKo2D,OAAOpvC,EAAKhnB,KAAK0oB,MAAOvW,EAAMH,EAAGG,EAAMF,KAUhD7O,EAAKgQ,UAAU+iD,aAAe,SAAU2B,GACtC,OACE9lD,GAAI,EAAI8lD,GAAc93D,KAAKqpB,KAAKrX,EAAI8lD,EAAa93D,KAAKspB,GAAGtX,EACzDC,GAAI,EAAI6lD,GAAc93D,KAAKqpB,KAAKpX,EAAI6lD,EAAa93D,KAAKspB,GAAGrX,IAa7D7O,EAAKgQ,UAAUmjD,eAAiB,SAAUvkD,EAAGC,EAAGyZ,EAAQosC,GACtD,GAAIrJ,GAA6B,GAApBqJ,EAAa,EAAE,GAAS7yD,KAAK2mB,EAC1C,QACE5Z,EAAGA,EAAI0Z,EAASzmB,KAAKuZ,IAAIiwC,GACzBx8C,EAAGA,EAAIyZ,EAASzmB,KAAKoZ,IAAIowC,KAW7BrrD,EAAKgQ,UAAU8hD,iBAAmB,SAASluC,GACzC,GAAI7U,EAMJ,IAJA6U,EAAIY,YAAc5nB,KAAK61D,YACvB7uC,EAAIiB,UAAYjB,EAAIY,YACpBZ,EAAIO,UAAYvnB,KAAK+1D,gBAEjB/1D,KAAKqpB,MAAQrpB,KAAKspB,GAAI,CAExB,GAAIgmC,GAAMtvD,KAAKg2D,MAAMhvC,GAEjBynC,EAAQxpD,KAAKkyD,MAAOn3D,KAAKspB,GAAGrX,EAAIjS,KAAKqpB,KAAKpX,EAAKjS,KAAKspB,GAAGtX,EAAIhS,KAAKqpB,KAAKrX,GACrEtM,GAAU,GAAK,EAAI1F,KAAK0O,QAAQ8D,OAASxS,KAAK0O,QAAQ8vC,gBAE1D,IAAyC,GAArCx+C,KAAK0O,QAAQ0yC,aAAazyC,SAA0B,MAAP2gD,EAAa,CAC5D,GAAI2G,GAAY,IAAK,IAAKj2D,KAAKqpB,KAAKrX,EAAIs9C,EAAIt9C,GAAK,IAAKhS,KAAKspB,GAAGtX,EAAIs9C,EAAIt9C,IAClEkkD,EAAY,IAAK,IAAKl2D,KAAKqpB,KAAKpX,EAAIq9C,EAAIr9C,GAAK,IAAKjS,KAAKspB,GAAGrX,EAAIq9C,EAAIr9C,GACtEE,IAASH,EAAEikD,EAAWhkD,EAAEikD,OAGxB/jD,GAAQnS,KAAKm2D,aAAa,GAG5BnvC,GAAI+wC,MAAM5lD,EAAMH,EAAGG,EAAMF,EAAGw8C,EAAO/oD,GACnCshB,EAAInH,OACJmH,EAAIlH,SAGA9f,KAAK0oB,OACP1oB,KAAKo2D,OAAOpvC,EAAKhnB,KAAK0oB,MAAOvW,EAAMH,EAAGG,EAAMF,OAG3C,CAEH,GAAID,GAAGC,EACHyZ,EAAS,IAAOzmB,KAAK0H,IAAI,IAAI3M,KAAK8+C,QAAQK,cAC1CgH,EAAOnmD,KAAKqpB,IACX88B,GAAK3zC,OACR2zC,EAAKkQ,OAAOrvC,GAEVm/B,EAAK3zC,MAAQ2zC,EAAK1zC,QACpBT,EAAIm0C,EAAKn0C,EAAiB,GAAbm0C,EAAK3zC,MAClBP,EAAIk0C,EAAKl0C,EAAIyZ,IAGb1Z,EAAIm0C,EAAKn0C,EAAI0Z,EACbzZ,EAAIk0C,EAAKl0C,EAAkB,GAAdk0C,EAAK1zC,QAEpBzS,KAAKs2D,QAAQtvC,EAAKhV,EAAGC,EAAGyZ,EAGxB,IAAI+iC,GAAQ,GAAMxpD,KAAK2mB,GACnBlmB,GAAU,GAAK,EAAI1F,KAAK0O,QAAQ8D,OAASxS,KAAK0O,QAAQ8vC,gBAC1DrsC,GAAQnS,KAAKu2D,eAAevkD,EAAGC,EAAGyZ,EAAQ,IAC1C1E,EAAI+wC,MAAM5lD,EAAMH,EAAGG,EAAMF,EAAGw8C,EAAO/oD,GACnCshB,EAAInH,OACJmH,EAAIlH,SAGA9f,KAAK0oB,QACPvW,EAAQnS,KAAKu2D,eAAevkD,EAAGC,EAAGyZ,EAAQ,IAC1C1rB,KAAKo2D,OAAOpvC,EAAKhnB,KAAK0oB,MAAOvW,EAAMH,EAAGG,EAAMF,MAKlD7O,EAAKgQ,UAAU4kD,eAAiB,SAASjqD,GACvC,GAAIuhD,GAAMtvD,KAAKy2D,qBAEXzkD,EAAI/M,KAAK8uB,IAAI,EAAEhmB,EAAE,GAAG/N,KAAKqpB,KAAKrX,EAAK,EAAEjE,GAAG,EAAIA,GAAIuhD,EAAIt9C,EAAI/M,KAAK8uB,IAAIhmB,EAAE,GAAG/N,KAAKspB,GAAGtX,EAC9EC,EAAIhN,KAAK8uB,IAAI,EAAEhmB,EAAE,GAAG/N,KAAKqpB,KAAKpX,EAAK,EAAElE,GAAG,EAAIA,GAAIuhD,EAAIr9C,EAAIhN,KAAK8uB,IAAIhmB,EAAE,GAAG/N,KAAKspB,GAAGrX,CAElF,QAAQD,EAAEA,EAAEC,EAAEA,IAWhB7O,EAAKgQ,UAAU6kD,oBAAsB,SAAS5uC,EAAKrC,GACjD,GAIIxB,GAAIipC,EAAMyJ,EAAkBC,EAAiBC,EAJ7CnpD,EAAgB,GAChBC,EAAY,EACZC,EAAM,EACNC,EAAO,EAEPipD,EAAY,GACZlS,EAAOnmD,KAAKspB,EAKhB,KAJY,GAARD,IACF88B,EAAOnmD,KAAKqpB,MAGAja,GAAPD,GAA2BF,EAAZC,GAA2B,CAC/C,GAAIG,GAAwB,IAAdF,EAAMC,EAOpB,IALAoW,EAAMxlB,KAAKg4D,eAAe3oD,GAC1Bo/C,EAAQxpD,KAAKkyD,MAAOhR,EAAKl0C,EAAIuT,EAAIvT,EAAKk0C,EAAKn0C,EAAIwT,EAAIxT,GACnDkmD,EAAmB/R,EAAK+R,iBAAiBlxC,EAAIynC,GAC7C0J,EAAkBlzD,KAAK2qB,KAAK3qB,KAAK8uB,IAAIvO,EAAIxT,EAAEm0C,EAAKn0C,EAAE,GAAK/M,KAAK8uB,IAAIvO,EAAIvT,EAAEk0C,EAAKl0C,EAAE,IAC7EmmD,EAAaF,EAAmBC,EAC5BlzD,KAAK6lB,IAAIstC,GAAcC,EACzB,KAEoB,GAAbD,EACK,GAAR/uC,EACFla,EAAME,EAGND,EAAOC,EAIG,GAARga,EACFja,EAAOC,EAGPF,EAAME,EAIVH,IAIF,MAFAsW,GAAIzX,EAAIsB,EAEDmW,GAUTpiB,EAAKgQ,UAAU6hD,WAAa,SAASjuC,GAEnCA,EAAIY,YAAc5nB,KAAK61D,YACvB7uC,EAAIiB,UAAYjB,EAAIY,YACpBZ,EAAIO,UAAYvnB,KAAK+1D,eAGrB,IAAItH,GAAO/oD,EAAQ4yD,CAGnB,IAAIt4D,KAAKqpB,MAAQrpB,KAAKspB,GAAI,CAKxB,GAHAtpB,KAAKg2D,MAAMhvC,GAG8B,GAArChnB,KAAK0O,QAAQ0yC,aAAazyC,QAAiB,CAC7C,GAAI2gD,GAAMtvD,KAAKy2D,oBACf6B,GAAWt4D,KAAKi4D,qBAAoB,EAAOjxC,EAC3C,IAAIuxC,GAAWv4D,KAAKg4D,eAAe/yD,KAAK0H,IAAI,EAAK2rD,EAASvqD,EAAI,IAC9D0gD,GAAQxpD,KAAKkyD,MAAOmB,EAASrmD,EAAIsmD,EAAStmD,EAAKqmD,EAAStmD,EAAIumD,EAASvmD,OAElE,CACHy8C,EAAQxpD,KAAKkyD,MAAOn3D,KAAKspB,GAAGrX,EAAIjS,KAAKqpB,KAAKpX,EAAKjS,KAAKspB,GAAGtX,EAAIhS,KAAKqpB,KAAKrX,EACrE,IAAI6M,GAAM7e,KAAKspB,GAAGtX,EAAIhS,KAAKqpB,KAAKrX,EAC5B8M,EAAM9e,KAAKspB,GAAGrX,EAAIjS,KAAKqpB,KAAKpX,EAC5BumD,EAAoBvzD,KAAK2qB,KAAK/Q,EAAKA,EAAKC,EAAKA,GAC7C25C,EAAez4D,KAAKspB,GAAG4uC,iBAAiBlxC,EAAKynC,GAC7CiK,GAAiBF,EAAoBC,GAAgBD,CAEzDF,MACAA,EAAStmD,GAAK,EAAI0mD,GAAiB14D,KAAKqpB,KAAKrX,EAAI0mD,EAAgB14D,KAAKspB,GAAGtX,EACzEsmD,EAASrmD,GAAK,EAAIymD,GAAiB14D,KAAKqpB,KAAKpX,EAAIymD,EAAgB14D,KAAKspB,GAAGrX,EAU3E,GANAvM,GAAU,GAAK,EAAI1F,KAAK0O,QAAQ8D,OAASxS,KAAK0O,QAAQ8vC,iBACtDx3B,EAAI+wC,MAAMO,EAAStmD,EAAEsmD,EAASrmD,EAAGw8C,EAAO/oD,GACxCshB,EAAInH,OACJmH,EAAIlH,SAGA9f,KAAK0oB,MAAO,CACd,GAAIvW,EAEFA,GADuC,GAArCnS,KAAK0O,QAAQ0yC,aAAazyC,SAA0B,MAAP2gD,EACvCtvD,KAAKg4D,eAAe,IAGpBh4D,KAAKm2D,aAAa,IAE5Bn2D,KAAKo2D,OAAOpvC,EAAKhnB,KAAK0oB,MAAOvW,EAAMH,EAAGG,EAAMF,QAG3C,CAEH,GACID,GAAGC,EAAG8lD,EADN5R,EAAOnmD,KAAKqpB,KAEZqC,EAAS,IAAOzmB,KAAK0H,IAAI,IAAI3M,KAAK8+C,QAAQK,aACzCgH,GAAK3zC,OACR2zC,EAAKkQ,OAAOrvC,GAEVm/B,EAAK3zC,MAAQ2zC,EAAK1zC,QACpBT,EAAIm0C,EAAKn0C,EAAiB,GAAbm0C,EAAK3zC,MAClBP,EAAIk0C,EAAKl0C,EAAIyZ,EACbqsC,GACE/lD,EAAGA,EACHC,EAAGk0C,EAAKl0C,EACRw8C,MAAO,GAAMxpD,KAAK2mB,MAIpB5Z,EAAIm0C,EAAKn0C,EAAI0Z,EACbzZ,EAAIk0C,EAAKl0C,EAAkB,GAAdk0C,EAAK1zC,OAClBslD,GACE/lD,EAAGm0C,EAAKn0C,EACRC,EAAGA,EACHw8C,MAAO,GAAMxpD,KAAK2mB,KAGtB5E,EAAIa,YAEJb,EAAI2E,IAAI3Z,EAAGC,EAAGyZ,EAAQ,EAAG,EAAIzmB,KAAK2mB,IAAI,GACtC5E,EAAIlH,QAGJ,IAAIpa,IAAU,GAAK,EAAI1F,KAAK0O,QAAQ8D,OAASxS,KAAK0O,QAAQ8vC,gBAC1Dx3B,GAAI+wC,MAAMA,EAAM/lD,EAAG+lD,EAAM9lD,EAAG8lD,EAAMtJ,MAAO/oD,GACzCshB,EAAInH,OACJmH,EAAIlH,SAGA9f,KAAK0oB,QACPvW,EAAQnS,KAAKu2D,eAAevkD,EAAGC,EAAGyZ,EAAQ,IAC1C1rB,KAAKo2D,OAAOpvC,EAAKhnB,KAAK0oB,MAAOvW,EAAMH,EAAGG,EAAMF,MAiBlD7O,EAAKgQ,UAAUwiD,mBAAqB,SAAU+C,EAAGC,EAAIC,EAAGC,EAAIC,EAAGC,GAC7D,GAAIvvD,GAAc,CAClB,IAAIzJ,KAAKqpB,MAAQrpB,KAAKspB,GACpB,GAAyC,GAArCtpB,KAAK0O,QAAQ0yC,aAAazyC,QAAiB,CAC7C,GAAI+nD,GAAMC,CACV,IAAyC,GAArC32D,KAAK0O,QAAQ0yC,aAAazyC,SAAwD,GAArC3O,KAAK0O,QAAQ0yC,aAAaC,QACzEqV,EAAO12D,KAAKsvD,IAAIt9C,EAChB2kD,EAAO32D,KAAKsvD,IAAIr9C,MAEb,CACH,GAAIq9C,GAAMtvD,KAAKy2D,oBACfC,GAAOpH,EAAIt9C,EACX2kD,EAAOrH,EAAIr9C,EAEb,GACI2T,GACArgB,EAAEwI,EAAEiE,EAAEC,EAAGgnD,EAAOC,EAFhBC,EAAc,GAGlB,KAAK5zD,EAAI,EAAO,GAAJA,EAAQA,IAClBwI,EAAI,GAAIxI,EACRyM,EAAI/M,KAAK8uB,IAAI,EAAEhmB,EAAE,GAAG4qD,EAAM,EAAE5qD,GAAG,EAAIA,GAAI2oD,EAAOzxD,KAAK8uB,IAAIhmB,EAAE,GAAG8qD,EAC5D5mD,EAAIhN,KAAK8uB,IAAI,EAAEhmB,EAAE,GAAG6qD,EAAM,EAAE7qD,GAAG,EAAIA,GAAI4oD,EAAO1xD,KAAK8uB,IAAIhmB,EAAE,GAAG+qD,EACxDvzD,EAAI,IACNqgB,EAAW5lB,KAAKo5D,mBAAmBH,EAAMC,EAAMlnD,EAAEC,EAAG8mD,EAAGC,GACvDG,EAAyBA,EAAXvzC,EAAyBA,EAAWuzC,GAEpDF,EAAQjnD,EAAGknD,EAAQjnD,CAErBxI,GAAc0vD,MAGd1vD,GAAczJ,KAAKo5D,mBAAmBT,EAAGC,EAAGC,EAAGC,EAAGC,EAAGC,OAGpD,CACH,GAAIhnD,GAAGC,EAAG4M,EAAIC,EACV4M,EAAS,IAAO1rB,KAAK8+C,QAAQK,aAC7BgH,EAAOnmD,KAAKqpB,IACZ88B,GAAK3zC,MAAQ2zC,EAAK1zC,QACpBT,EAAIm0C,EAAKn0C,EAAI,GAAMm0C,EAAK3zC,MACxBP,EAAIk0C,EAAKl0C,EAAIyZ,IAGb1Z,EAAIm0C,EAAKn0C,EAAI0Z,EACbzZ,EAAIk0C,EAAKl0C,EAAI,GAAMk0C,EAAK1zC,QAE1BoM,EAAK7M,EAAI+mD,EACTj6C,EAAK7M,EAAI+mD,EACTvvD,EAAcxE,KAAK6lB,IAAI7lB,KAAK2qB,KAAK/Q,EAAGA,EAAKC,EAAGA,GAAM4M,GAGpD,MAAI1rB,MAAKm0D,gBAAgB3sD,KAAOuxD,GAC9B/4D,KAAKm0D,gBAAgB3sD,KAAOxH,KAAKm0D,gBAAgB3hD,MAAQumD,GACzD/4D,KAAKm0D,gBAAgBvsD,IAAMoxD,GAC3Bh5D,KAAKm0D,gBAAgBvsD,IAAM5H,KAAKm0D,gBAAgB1hD,OAASumD,EAClD,EAGAvvD,GAIXrG,EAAKgQ,UAAUgmD,mBAAqB,SAAST,EAAGC,EAAGC,EAAGC,EAAGC,EAAGC,GAC1D,GAAIK,GAAKR,EAAGF,EACVW,EAAKR,EAAGF,EACRW,EAAYF,EAAGA,EAAKC,EAAGA,EACvBE,IAAOT,EAAKJ,GAAMU,GAAML,EAAKJ,GAAMU,GAAMC,CAEvCC,GAAI,EACNA,EAAI,EAEO,EAAJA,IACPA,EAAI,EAGN,IAAIxnD,GAAI2mD,EAAKa,EAAIH,EACfpnD,EAAI2mD,EAAKY,EAAIF,EACbz6C,EAAK7M,EAAI+mD,EACTj6C,EAAK7M,EAAI+mD,CAQX,OAAO/zD,MAAK2qB,KAAK/Q,EAAGA,EAAKC,EAAGA,IAQ9B1b,EAAKgQ,UAAUiwB,SAAW,SAASnmB,GACjCld,KAAKw2D,gBAAkB,EAAIt5C,GAI7B9Z,EAAKgQ,UAAUq+B,OAAS,WACtBzxC,KAAKwzC,UAAW,GAGlBpwC,EAAKgQ,UAAUo+B,SAAW,WACxBxxC,KAAKwzC,UAAW,GAGlBpwC,EAAKgQ,UAAUo/C,mBAAqB,WACjB,OAAbxyD,KAAKsvD,KAA8B,OAAdtvD,KAAKqpB,MAA6B,OAAZrpB,KAAKspB,IAClDtpB,KAAKsvD,IAAIt9C,EAAI,IAAOhS,KAAKqpB,KAAKrX,EAAIhS,KAAKspB,GAAGtX,GAC1ChS,KAAKsvD,IAAIr9C,EAAI,IAAOjS,KAAKqpB,KAAKpX,EAAIjS,KAAKspB,GAAGrX,KAG1CjS,KAAKsvD,IAAIt9C,EAAI,EACbhS,KAAKsvD,IAAIr9C,EAAI,IASjB7O,EAAKgQ,UAAUm9C,kBAAoB,SAASvpC,GAC1C,GAAgC,GAA5BhnB,KAAK40D,oBAA6B,CACpC,GAA+B,OAA3B50D,KAAK60D,aAAaxrC,MAA0C,OAAzBrpB,KAAK60D,aAAavrC,GAAa,CACpE,GAAImwC,GAAa,cAAcxlD,OAAOjU,KAAKK,IACvCq5D,EAAW,YAAYzlD,OAAOjU,KAAKK,IACnC2hD,GACY1E,OAAOprC,MAAM,GAAIwZ,OAAO,EAAGzL,YAAY,EAAGk+B,oBAAqB,GAC/DW,SAASO,QAAQ,GACjBI,YAAac,sBAAuB,EAAGD,aAAc9tC,MAAM,EAAGC,OAAQ,EAAGiZ,OAAO,IAEhG1rB,MAAK60D,aAAaxrC,KAAO,GAAI9lB,IAC1BlD,GAAGo5D,EACF/b,MAAM,MACJtyC,OAAOgB,WAAW,UAAWC,OAAO,UAAWC,WAAYF,WAAW,mBAClE41C,GACVhiD,KAAK60D,aAAavrC,GAAK,GAAI/lB,IACxBlD,GAAGq5D,EACFhc,MAAM,MACNtyC,OAAOgB,WAAW,UAAWC,OAAO,UAAWC,WAAYF,WAAW,mBAChE41C,GAGZhiD,KAAK60D,aAAaC,aACqB,GAAnC90D,KAAK60D,aAAaxrC,KAAKmqB,WACzBxzC,KAAK60D,aAAaC,UAAUzrC,KAAOrpB,KAAK25D,2BAA2B3yC,GACnEhnB,KAAK60D,aAAaxrC,KAAKrX,EAAIhS,KAAK60D,aAAaC,UAAUzrC,KAAKrX,EAC5DhS,KAAK60D,aAAaxrC,KAAKpX,EAAIjS,KAAK60D,aAAaC,UAAUzrC,KAAKpX,GAEzB,GAAjCjS,KAAK60D,aAAavrC,GAAGkqB,WACvBxzC,KAAK60D,aAAaC,UAAUxrC,GAAKtpB,KAAK45D,yBAAyB5yC,GAC/DhnB,KAAK60D,aAAavrC,GAAGtX,EAAIhS,KAAK60D,aAAaC,UAAUxrC,GAAGtX,EACxDhS,KAAK60D,aAAavrC,GAAGrX,EAAIjS,KAAK60D,aAAaC,UAAUxrC,GAAGrX,GAG1DjS,KAAK60D,aAAaxrC,KAAKijB,KAAKtlB,GAC5BhnB,KAAK60D,aAAavrC,GAAGgjB,KAAKtlB,OAG1BhnB,MAAK60D,cAAgBxrC,KAAK,KAAMC,GAAG,KAAMwrC,eAQ7C1xD,EAAKgQ,UAAUymD,oBAAsB,WACnC75D,KAAKs0D,WAAat0D,KAAKqpB,KACvBrpB,KAAKu0D,SAAWv0D,KAAKspB,GACrBtpB,KAAK40D,qBAAsB,GAO7BxxD,EAAKgQ,UAAU0mD,qBAAuB,WACpC95D,KAAKg0D,OAASh0D,KAAKqpB,KAAKhpB,GACxBL,KAAKi0D,KAAOj0D,KAAKspB,GAAGjpB,GAChBL,KAAKg0D,QAAUh0D,KAAKs0D,WAAWj0D,GACjCL,KAAKs0D,WAAWe,WAAWr1D,MAEpBA,KAAKi0D,MAAQj0D,KAAKu0D,SAASl0D,IAClCL,KAAKu0D,SAASc,WAAWr1D,MAG3BA,KAAKs0D,WAAa,KAClBt0D,KAAKu0D,SAAW,KAChBv0D,KAAK40D,qBAAsB,GAW7BxxD,EAAKgQ,UAAU2mD,wBAA0B,SAAS/nD,EAAEC,GAClD,GAAI6iD,GAAY90D,KAAK60D,aAAaC,UAC9BkF,EAAe/0D,KAAK2qB,KAAK3qB,KAAK8uB,IAAI/hB,EAAI8iD,EAAUzrC,KAAKrX,EAAE,GAAK/M,KAAK8uB,IAAI9hB,EAAI6iD,EAAUzrC,KAAKpX,EAAE,IAC1FgoD,EAAeh1D,KAAK2qB,KAAK3qB,KAAK8uB,IAAI/hB,EAAI8iD,EAAUxrC,GAAGtX,EAAI,GAAK/M,KAAK8uB,IAAI9hB,EAAI6iD,EAAUxrC,GAAGrX,EAAI,GAE9F,OAAmB,IAAf+nD,GACFh6D,KAAK+0D,cAAgB/0D,KAAKqpB,KAC1BrpB,KAAKqpB,KAAOrpB,KAAK60D,aAAaxrC,KACvBrpB,KAAK60D,aAAaxrC,MAEL,GAAb4wC,GACPj6D,KAAK+0D,cAAgB/0D,KAAKspB,GAC1BtpB,KAAKspB,GAAKtpB,KAAK60D,aAAavrC,GACrBtpB,KAAK60D,aAAavrC,IAGlB,MASXlmB,EAAKgQ,UAAU8mD,qBAAuB,WACG,GAAnCl6D,KAAK60D,aAAaxrC,KAAKmqB,UACzBxzC,KAAKqpB,KAAOrpB,KAAK+0D,cACjB/0D,KAAK+0D,cAAgB,KACrB/0D,KAAK60D,aAAaxrC,KAAKmoB,YAEiB,GAAjCxxC,KAAK60D,aAAavrC,GAAGkqB,WAC5BxzC,KAAKspB,GAAKtpB,KAAK+0D,cACf/0D,KAAK+0D,cAAgB,KACrB/0D,KAAK60D,aAAavrC,GAAGkoB,aAUzBpuC,EAAKgQ,UAAUumD,2BAA6B,SAAS3yC,GAEnD,GAAImzC,EACJ,IAAyC,GAArCn6D,KAAK0O,QAAQ0yC,aAAazyC,QAC5BwrD,EAAqBn6D,KAAKi4D,qBAAoB,EAAMjxC,OAEjD,CACH,GAAIynC,GAAQxpD,KAAKkyD,MAAOn3D,KAAKspB,GAAGrX,EAAIjS,KAAKqpB,KAAKpX,EAAKjS,KAAKspB,GAAGtX,EAAIhS,KAAKqpB,KAAKrX,GACrE6M,EAAM7e,KAAKspB,GAAGtX,EAAIhS,KAAKqpB,KAAKrX,EAC5B8M,EAAM9e,KAAKspB,GAAGrX,EAAIjS,KAAKqpB,KAAKpX,EAC5BumD,EAAoBvzD,KAAK2qB,KAAK/Q,EAAKA,EAAKC,EAAKA,GAE7Cs7C,EAAiBp6D,KAAKqpB,KAAK6uC,iBAAiBlxC,EAAKynC,EAAQxpD,KAAK2mB,IAC9DyuC,GAAmB7B,EAAoB4B,GAAkB5B,CAC7D2B,MACAA,EAAmBnoD,EAAI,EAAoBhS,KAAKqpB,KAAKrX,GAAK,EAAIqoD,GAAmBr6D,KAAKspB,GAAGtX,EACzFmoD,EAAmBloD,EAAI,EAAoBjS,KAAKqpB,KAAKpX,GAAK,EAAIooD,GAAmBr6D,KAAKspB,GAAGrX,EAG3F,MAAOkoD,IAST/2D,EAAKgQ,UAAUwmD,yBAA2B,SAAS5yC,GAEjD,GAAuBszC,EACvB,IAAyC,GAArCt6D,KAAK0O,QAAQ0yC,aAAazyC,QAC5B2rD,EAAmBt6D,KAAKi4D,qBAAoB,EAAOjxC,OAEhD,CACH,GAAIynC,GAAQxpD,KAAKkyD,MAAOn3D,KAAKspB,GAAGrX,EAAIjS,KAAKqpB,KAAKpX,EAAKjS,KAAKspB,GAAGtX,EAAIhS,KAAKqpB,KAAKrX,GACrE6M,EAAM7e,KAAKspB,GAAGtX,EAAIhS,KAAKqpB,KAAKrX,EAC5B8M,EAAM9e,KAAKspB,GAAGrX,EAAIjS,KAAKqpB,KAAKpX,EAC5BumD,EAAoBvzD,KAAK2qB,KAAK/Q,EAAKA,EAAKC,EAAKA,GAC7C25C,EAAez4D,KAAKspB,GAAG4uC,iBAAiBlxC,EAAKynC,GAC7CiK,GAAiBF,EAAoBC,GAAgBD,CAEzD8B,MACAA,EAAiBtoD,GAAK,EAAI0mD,GAAiB14D,KAAKqpB,KAAKrX,EAAI0mD,EAAgB14D,KAAKspB,GAAGtX,EACjFsoD,EAAiBroD,GAAK,EAAIymD,GAAiB14D,KAAKqpB,KAAKpX,EAAIymD,EAAgB14D,KAAKspB,GAAGrX,EAGnF,MAAOqoD,IAGTz6D,EAAOD,QAAUwD,GAIb,SAASvD,EAAQD,EAASM,GAQ9B,QAASmD,KACPrD,KAAK0W,QACL1W,KAAKu6D,aAAe,EARXr6D,EAAoB,EAe/BmD,GAAOm3D,UACJnuD,OAAQ,UAAWD,WAAY,UAAWE,WAAYD,OAAQ,UAAWD,WAAY,WAAYG,OAAQF,OAAQ,UAAWD,WAAY,aACxIC,OAAQ,UAAWD,WAAY,UAAWE,WAAYD,OAAQ,UAAWD,WAAY,WAAYG,OAAQF,OAAQ,UAAWD,WAAY,aACxIC,OAAQ,UAAWD,WAAY,UAAWE,WAAYD,OAAQ,UAAWD,WAAY,WAAYG,OAAQF,OAAQ,UAAWD,WAAY,aACxIC,OAAQ,UAAWD,WAAY,UAAWE,WAAYD,OAAQ,UAAWD,WAAY,WAAYG,OAAQF,OAAQ,UAAWD,WAAY,aACxIC,OAAQ,UAAWD,WAAY,UAAWE,WAAYD,OAAQ,UAAWD,WAAY,WAAYG,OAAQF,OAAQ,UAAWD,WAAY,aACxIC,OAAQ,UAAWD,WAAY,UAAWE,WAAYD,OAAQ,UAAWD,WAAY,WAAYG,OAAQF,OAAQ,UAAWD,WAAY,aACxIC,OAAQ,UAAWD,WAAY,UAAWE,WAAYD,OAAQ,UAAWD,WAAY,WAAYG,OAAQF,OAAQ,UAAWD,WAAY,aACxIC,OAAQ,UAAWD,WAAY,UAAWE,WAAYD,OAAQ,UAAWD,WAAY,WAAYG,OAAQF,OAAQ,UAAWD,WAAY,aACxIC,OAAQ,UAAWD,WAAY,UAAWE,WAAYD,OAAQ,UAAWD,WAAY,WAAYG,OAAQF,OAAQ,UAAWD,WAAY,aACxIC,OAAQ,UAAWD,WAAY,UAAWE,WAAYD,OAAQ,UAAWD,WAAY,WAAYG,OAAQF,OAAQ,UAAWD,WAAY,aAO3I/I,EAAO+P,UAAUsD,MAAQ,WACvB1W,KAAKo0B,UACLp0B,KAAKo0B,OAAO1uB,OAAS,WAEnB,GAAIH,GAAI,CACR,KAAM,GAAI7E,KAAKV,MACTA,KAAK6F,eAAenF,IACtB6E,GAGJ,OAAOA,KAWXlC,EAAO+P,UAAU+B,IAAM,SAAUszC,GAC/B,GAAIv2C,GAAQlS,KAAKo0B,OAAOq0B,EACxB,IAAaliD,QAAT2L,EAAoB,CAEtB,GAAI7J,GAAQrI,KAAKu6D,aAAel3D,EAAOm3D,QAAQ90D,MAC/C1F,MAAKu6D,eACLroD,KACAA,EAAM9G,MAAQ/H,EAAOm3D,QAAQnyD,GAC7BrI,KAAKo0B,OAAOq0B,GAAav2C,EAG3B,MAAOA,IAUT7O,EAAO+P,UAAUF,IAAM,SAAUu1C,EAAWv7C,GAE1C,MADAlN,MAAKo0B,OAAOq0B,GAAav7C,EAClBA,GAGTrN,EAAOD,QAAUyD,GAKb,SAASxD,GAMb,QAASyD,KACPtD,KAAKijD,UACLjjD,KAAKy6D,eACLz6D,KAAKwI,SAAWjC,OAQlBjD,EAAO8P,UAAU8vC,kBAAoB,SAAS16C,GAC5CxI,KAAKwI,SAAWA,GASlBlF,EAAO8P,UAAUsnD,KAAO,SAASC,EAAKC,GACpC,GAAIC,GAAM76D,KAAKijD,OAAO0X,EACtB,IAAYp0D,SAARs0D,EAAmB,CAErB,GAAIzmD,GAAKpU,IACT66D,GAAM,GAAIC,OACVD,EAAIE,OAAS,WAEO,GAAd/6D,KAAKwS,QACPhB,SAASojB,KAAKljB,YAAY1R,MAC1BA,KAAKwS,MAAQxS,KAAKqwB,YAClBrwB,KAAKyS,OAASzS,KAAKuwB,aACnB/e,SAASojB,KAAKxjB,YAAYpR,OAGxBoU,EAAG5L,WACL4L,EAAG6uC,OAAO0X,GAAOE,EACjBzmD,EAAG5L,SAASxI,QAIhB66D,EAAIG,QAAU,WACMz0D,SAAdq0D,GACFhiC,QAAQqiC,MAAM,wBAAyBN,SAChC36D,MAAKimD,IACR7xC,EAAG5L,UACL4L,EAAG5L,SAASxI,OAGPoU,EAAGqmD,YAAYE,MAAS,GAC/B/hC,QAAQqiC,MAAM,8BAA+BL,SACtC56D,MAAKimD,IACR7xC,EAAG5L,UACL4L,EAAG5L,SAASxI,QAIdA,KAAKimD,IAAM2U,EACXxmD,EAAGqmD,YAAYE,IAAO,IAI1BE,EAAI5U,IAAM0U,EAGZ,MAAOE,IAGTh7D,EAAOD,QAAU0D,GAKb,SAASzD,EAAQD,EAASM,GA6B9B,QAASqD,GAAKyrD,EAAYkM,EAAWC,EAAWpH,GAC9C,GAAI/R,GAAYrhD,EAAKuN,uBAAuB,SAAS6lD,EACrD/zD,MAAK0O,QAAUszC,EAAU1E,MAEzBt9C,KAAKwzC,UAAW,EAChBxzC,KAAKuM,OAAQ,EAEbvM,KAAKo+C,SACLp+C,KAAKwvD,gBACLxvD,KAAKo7D,iBAELp7D,KAAKq7D,kBAAoB,EAGzBr7D,KAAKK,GAAKkG,OACVvG,KAAK6yD,gBAAiB,EACtB7yD,KAAK8yD,gBAAiB,EACtB9yD,KAAKyrD,QAAS,EACdzrD,KAAK0rD,QAAS,EACd1rD,KAAKs7D,qBAAsB,EAC3Bt7D,KAAKu7D,kBAAsB,EAC3Bv7D,KAAKw7D,gBAAkBzH,EAAiBzW,MAAM5xB,OAC9C1rB,KAAKy7D,aAAc,EACnBz7D,KAAKk+C,MAAQ,GACbl+C,KAAK07D,kBAAmB,EACxB17D,KAAK27D,qBAAsB,EAC3B37D,KAAKm0D,iBAAmBvsD,IAAI,EAAGJ,KAAK,EAAGgL,MAAM,EAAGC,OAAO,EAAG2hD,MAAM,GAChEp0D,KAAKymD,aAAe7+C,IAAI,EAAGJ,KAAK,EAAG8f,MAAM,EAAG/D,OAAO,GAEnDvjB,KAAKk7D,UAAYA,EACjBl7D,KAAKm7D,UAAYA,EAGjBn7D,KAAK47D,GAAK,EACV57D,KAAK67D,GAAK,EACV77D,KAAK87D,GAAK,EACV97D,KAAK+7D,GAAK,EACV/7D,KAAKgS,EAAI,KACThS,KAAKiS,EAAI,KAGTjS,KAAKg8D,eAAiBF,GAAG,EAAEC,GAAG,EAAE/pD,EAAE,EAAEC,EAAE,GAEtCjS,KAAKq/C,QAAU0U,EAAiBjV,QAAQO,QACxCr/C,KAAK2wD,WAAa3+C,EAAE,KAAKC,EAAE,MAE3BjS,KAAK+uD,cAAcC,EAAYhN,GAG/BhiD,KAAKi8D,eACLj8D,KAAKk8D,mBAAqB,EAC1Bl8D,KAAKm8D,eAAiB,EACtBn8D,KAAKo8D,uBAA0BrI,EAAiBtU,WAAWa,YAAY9tC,MACvExS,KAAKq8D,wBAA0BtI,EAAiBtU,WAAWa,YAAY7tC,OACvEzS,KAAKs8D,wBAA0BvI,EAAiBtU,WAAWa,YAAY50B,OACvE1rB,KAAKugD,sBAAwBwT,EAAiBtU,WAAWc,sBACzDvgD,KAAKu8D,gBAAkB,EAGvBv8D,KAAKw2D,gBAAkB,EACvBx2D,KAAKw8D,aAAe,EACpBx8D,KAAKqkD,eAAiBryC,EAAK,KAAMC,EAAK,MACtCjS,KAAKskD,mBAAqBtyC,EAAM,IAAKC,EAAM,KAC3CjS,KAAKsyD,aAAe,KA1FtB,GAAI3xD,GAAOT,EAAoB,EAiG/BqD,GAAK6P,UAAUi+C,eAAiB,WAC9BrxD,KAAKgS,EAAIhS,KAAKg8D,cAAchqD,EAC5BhS,KAAKiS,EAAIjS,KAAKg8D,cAAc/pD,EAC5BjS,KAAK87D,GAAK97D,KAAKg8D,cAAcF,GAC7B97D,KAAK+7D,GAAK/7D,KAAKg8D,cAAcD,IAO/Bx4D,EAAK6P,UAAU6oD,aAAe,WAE5Bj8D,KAAKy8D,eAAiBl2D,OACtBvG,KAAK08D,YAAc,EACnB18D,KAAK28D,kBACL38D,KAAK48D,kBACL58D,KAAK68D,oBAOPt5D,EAAK6P,UAAUgiD,WAAa,SAASrH,GACH,IAA5B/tD,KAAKo+C,MAAM13C,QAAQqnD,IACrB/tD,KAAKo+C,MAAMl2C,KAAK6lD,GAEqB,IAAnC/tD,KAAKwvD,aAAa9oD,QAAQqnD,IAC5B/tD,KAAKwvD,aAAatnD,KAAK6lD,GAEzB/tD,KAAKk8D,mBAAqBl8D,KAAKwvD,aAAa9pD,QAO9CnC,EAAK6P,UAAUiiD,WAAa,SAAStH,GACnC,GAAI1lD,GAAQrI,KAAKo+C,MAAM13C,QAAQqnD,EAClB,KAAT1lD,GACFrI,KAAKo+C,MAAM91C,OAAOD,EAAO,GAE3BA,EAAQrI,KAAKwvD,aAAa9oD,QAAQqnD,GACrB,IAAT1lD,GACFrI,KAAKwvD,aAAalnD,OAAOD,EAAO,GAElCrI,KAAKk8D,mBAAqBl8D,KAAKwvD,aAAa9pD,QAS9CnC,EAAK6P,UAAU27C,cAAgB,SAASC,EAAYhN,GAClD,GAAKgN,EAAL,CAIA,GAAI7gD,IAAU,cAAc,sBAAsB,QAAQ,QAAQ,cAAc,SAAS,YACvF,WAAW,WAAW,WAAW,kBAAkB,kBAAkB,QAAQ,OAkB/E,IAhBAxN,EAAKuF,oBAAoBiI,EAAQnO,KAAK0O,QAASsgD,GAGzBzoD,SAAlByoD,EAAW3uD,KAA0BL,KAAKK,GAAK2uD,EAAW3uD,IACrCkG,SAArByoD,EAAWtmC,QAA0B1oB,KAAK0oB,MAAQsmC,EAAWtmC,MAAO1oB,KAAK88D,cAAgB9N,EAAWtmC,OAC/EniB,SAArByoD,EAAW3pB,QAA0BrlC,KAAKqlC,MAAQ2pB,EAAW3pB,OAC5C9+B,SAAjByoD,EAAWh9C,IAA0BhS,KAAKgS,EAAIg9C,EAAWh9C,GACxCzL,SAAjByoD,EAAW/8C,IAA0BjS,KAAKiS,EAAI+8C,EAAW/8C,GACpC1L,SAArByoD,EAAW5nD,QAA0BpH,KAAKoH,MAAQ4nD,EAAW5nD,OACxCb,SAArByoD,EAAW9Q,QAA0Bl+C,KAAKk+C,MAAQ8Q,EAAW9Q,MAAOl+C,KAAK07D,kBAAmB,GAGzDn1D,SAAnCyoD,EAAWsM,sBAAoCt7D,KAAKs7D,oBAAsBtM,EAAWsM,qBAClD/0D,SAAnCyoD,EAAWuM,mBAAoCv7D,KAAKu7D,iBAAsBvM,EAAWuM,kBAClDh1D,SAAnCyoD,EAAW+N,kBAAoC/8D,KAAK+8D,gBAAsB/N,EAAW+N,iBAEzEx2D,SAAZvG,KAAKK,GACP,KAAM,sBAIR,IAAkC,gBAAvBL,MAAK0O,QAAQwD,OAAqD,gBAAvBlS,MAAK0O,QAAQwD,OAA4C,IAAtBlS,KAAK0O,QAAQwD,MAAc,CAClH,GAAI8qD,GAAWh9D,KAAKm7D,UAAUhmD,IAAInV,KAAK0O,QAAQwD,MAC/CvR,GAAK6F,WAAWxG,KAAK0O,QAASsuD,GAE9Bh9D,KAAK0O,QAAQtD,MAAQzK,EAAKwK,WAAWnL,KAAK0O,QAAQtD,OAMpD,GAF0B7E,SAAtByoD,EAAWtjC,SAA+B1rB,KAAKw7D,gBAAkBx7D,KAAK0O,QAAQgd,QACzDnlB,SAArByoD,EAAW5jD,QAA+BpL,KAAK0O,QAAQtD,MAAQzK,EAAKwK,WAAW6jD,EAAW5jD,QACnE7E,SAAvBvG,KAAK0O,QAAQivC,OAA4C,IAArB39C,KAAK0O,QAAQivC,MAAY,CAC/D,IAAI39C,KAAKk7D,UAIP,KAAM,uBAHNl7D,MAAKi9D,SAAWj9D,KAAKk7D,UAAUR,KAAK16D,KAAK0O,QAAQivC,MAAO39C,KAAK0O,QAAQwuD,aAgCzE,OAzBkC32D,SAA9ByoD,EAAW6D,gBACb7yD,KAAKyrD,QAAUuD,EAAW6D,eAC1B7yD,KAAK6yD,eAAiB7D,EAAW6D,gBAETtsD,SAAjByoD,EAAWh9C,GAA0C,GAAvBhS,KAAK6yD,iBAC1C7yD,KAAKyrD,QAAS,GAIkBllD,SAA9ByoD,EAAW8D,gBACb9yD,KAAK0rD,QAAUsD,EAAW8D,eAC1B9yD,KAAK8yD,eAAiB9D,EAAW8D,gBAETvsD,SAAjByoD,EAAW/8C,GAA0C,GAAvBjS,KAAK8yD,iBAC1C9yD,KAAK0rD,QAAS,GAGhB1rD,KAAKy7D,YAAcz7D,KAAKy7D,aAAsCl1D,SAAtByoD,EAAWtjC,QAExB,UAAvB1rB,KAAK0O,QAAQgvC,OAA4C,kBAAvB19C,KAAK0O,QAAQgvC,SACjD19C,KAAK0O,QAAQ8uC,UAAYwE,EAAU1E,MAAMn2B,SACzCnnB,KAAK0O,QAAQ+uC,UAAYuE,EAAU1E,MAAMl2B,UAInCpnB,KAAK0O,QAAQgvC,OACnB,IAAK,WAAiB19C,KAAKssC,KAAOtsC,KAAKm9D,cAAen9D,KAAKq2D,OAASr2D,KAAKo9D,eAAiB,MAC1F,KAAK,MAAiBp9D,KAAKssC,KAAOtsC,KAAKq9D,SAAUr9D,KAAKq2D,OAASr2D,KAAKs9D,UAAY,MAChF,KAAK,SAAiBt9D,KAAKssC,KAAOtsC,KAAKu9D,YAAav9D,KAAKq2D,OAASr2D,KAAKw9D,aAAe,MACtF,KAAK,UAAiBx9D,KAAKssC,KAAOtsC,KAAKy9D,aAAcz9D,KAAKq2D,OAASr2D,KAAK09D,cAAgB,MAExF,KAAK,QAAiB19D,KAAKssC,KAAOtsC,KAAK29D,WAAY39D,KAAKq2D,OAASr2D,KAAK49D,YAAc,MACpF,KAAK,gBAAiB59D,KAAKssC,KAAOtsC,KAAK69D,mBAAoB79D,KAAKq2D,OAASr2D,KAAK89D,oBAAsB,MACpG,KAAK,OAAiB99D,KAAKssC,KAAOtsC,KAAK+9D,UAAW/9D,KAAKq2D,OAASr2D,KAAKg+D,WAAa,MAClF,KAAK,MAAiBh+D,KAAKssC,KAAOtsC,KAAKi+D,SAAUj+D,KAAKq2D,OAASr2D,KAAKk+D,YAAc,MAClF,KAAK,SAAiBl+D,KAAKssC,KAAOtsC,KAAKm+D,YAAan+D,KAAKq2D,OAASr2D,KAAKk+D,YAAc,MACrF,KAAK,WAAiBl+D,KAAKssC,KAAOtsC,KAAKo+D,cAAep+D,KAAKq2D,OAASr2D,KAAKk+D,YAAc,MACvF,KAAK,eAAiBl+D,KAAKssC,KAAOtsC,KAAKq+D,kBAAmBr+D,KAAKq2D,OAASr2D,KAAKk+D,YAAc,MAC3F,KAAK,OAAiBl+D,KAAKssC,KAAOtsC,KAAKs+D,UAAWt+D,KAAKq2D,OAASr2D,KAAKk+D,YAAc,MACnF,SAAsBl+D,KAAKssC,KAAOtsC,KAAKy9D,aAAcz9D,KAAKq2D,OAASr2D,KAAK09D,eAG1E19D,KAAKu+D,WAOPh7D,EAAK6P,UAAUq+B,OAAS,WACtBzxC,KAAKwzC,UAAW,EAChBxzC,KAAKu+D,UAMPh7D,EAAK6P,UAAUo+B,SAAW,WACxBxxC,KAAKwzC,UAAW,EAChBxzC,KAAKu+D,UAOPh7D,EAAK6P,UAAUorD,eAAiB,WAC9Bx+D,KAAKu+D,UAOPh7D,EAAK6P,UAAUmrD,OAAS,WACtBv+D,KAAKwS,MAAQjM,OACbvG,KAAKyS,OAASlM,QAQhBhD,EAAK6P,UAAUy6C,SAAW,WACxB,MAA6B,kBAAf7tD,MAAKqlC,MAAuBrlC,KAAKqlC,QAAUrlC,KAAKqlC,OAShE9hC,EAAK6P,UAAU8kD,iBAAmB,SAAUlxC,EAAKynC,GAC/C,GAAIxuC,GAAc,CAMlB,QAJKjgB,KAAKwS,OACRxS,KAAKq2D,OAAOrvC,GAGNhnB,KAAK0O,QAAQgvC,OACnB,IAAK,SACL,IAAK,MACH,MAAO19C,MAAK0O,QAAQgd,OAAQzL,CAE9B,KAAK,UACH,GAAI3a,GAAItF,KAAKwS,MAAQ,EACjBrM,EAAInG,KAAKyS,OAAS,EAClBi9C,EAAKzqD,KAAKoZ,IAAIowC,GAASnpD,EACvBsG,EAAK3G,KAAKuZ,IAAIiwC,GAAStoD,CAC3B,OAAOb,GAAIa,EAAIlB,KAAK2qB,KAAK8/B,EAAIA,EAAI9jD,EAAIA,EAMvC,KAAK,MACL,IAAK,QACL,IAAK,OACL,QACE,MAAI5L,MAAKwS,MACAvN,KAAK8G,IACR9G,KAAK6lB,IAAI9qB,KAAKwS,MAAQ,EAAIvN,KAAKuZ,IAAIiwC,IACnCxpD,KAAK6lB,IAAI9qB,KAAKyS,OAAS,EAAIxN,KAAKoZ,IAAIowC,KAAWxuC,EAI5C,IAYf1c,EAAK6P,UAAUqrD,UAAY,SAAS7C,EAAIC,GACtC77D,KAAK47D,GAAKA,EACV57D,KAAK67D,GAAKA,GASZt4D,EAAK6P,UAAUsrD,UAAY,SAAS9C,EAAIC,GACtC77D,KAAK47D,IAAMA,EACX57D,KAAK67D,IAAMA,GAMbt4D,EAAK6P,UAAUurD,WAAa,WAC1B3+D,KAAKg8D,cAAchqD,EAAIhS,KAAKgS,EAC5BhS,KAAKg8D,cAAc/pD,EAAIjS,KAAKiS,EAC5BjS,KAAKg8D,cAAcF,GAAK97D,KAAK87D,GAC7B97D,KAAKg8D,cAAcD,GAAK/7D,KAAK+7D,IAO/Bx4D,EAAK6P,UAAU89C,aAAe,SAASz+B,GAErC,GADAzyB,KAAK2+D,aACA3+D,KAAKyrD,OAORzrD,KAAK47D,GAAK,EACV57D,KAAK87D,GAAK,MARM,CAChB,GAAIj9C,GAAO7e,KAAKq/C,QAAUr/C,KAAK87D,GAC3Bj+C,GAAQ7d,KAAK47D,GAAK/8C,GAAM7e,KAAK0O,QAAQ6uC,IACzCv9C,MAAK87D,IAAMj+C,EAAK4U,EAChBzyB,KAAKgS,GAAMhS,KAAK87D,GAAKrpC,EAOvB,GAAKzyB,KAAK0rD,OAOR1rD,KAAK67D,GAAK,EACV77D,KAAK+7D,GAAK,MARM,CAChB,GAAIj9C,GAAO9e,KAAKq/C,QAAUr/C,KAAK+7D,GAC3Bj+C,GAAQ9d,KAAK67D,GAAK/8C,GAAM9e,KAAK0O,QAAQ6uC,IACzCv9C,MAAK+7D,IAAMj+C,EAAK2U,EAChBzyB,KAAKiS,GAAMjS,KAAK+7D,GAAKtpC,IAezBlvB,EAAK6P,UAAU69C,oBAAsB,SAASx+B,EAAU8uB,GAEtD,GADAvhD,KAAK2+D,aACA3+D,KAAKyrD,OAQRzrD,KAAK47D,GAAK,EACV57D,KAAK87D,GAAK,MATM,CAChB,GAAIj9C,GAAO7e,KAAKq/C,QAAUr/C,KAAK87D,GAC3Bj+C,GAAQ7d,KAAK47D,GAAK/8C,GAAM7e,KAAK0O,QAAQ6uC,IACzCv9C,MAAK87D,IAAMj+C,EAAK4U,EAChBzyB,KAAK87D,GAAM72D,KAAK6lB,IAAI9qB,KAAK87D,IAAMva,EAAiBvhD,KAAK87D,GAAK,EAAKva,GAAeA,EAAevhD,KAAK87D,GAClG97D,KAAKgS,GAAMhS,KAAK87D,GAAKrpC,EAOvB,GAAKzyB,KAAK0rD,OAQR1rD,KAAK67D,GAAK,EACV77D,KAAK+7D,GAAK,MATM,CAChB,GAAIj9C,GAAO9e,KAAKq/C,QAAUr/C,KAAK+7D,GAC3Bj+C,GAAQ9d,KAAK67D,GAAK/8C,GAAM9e,KAAK0O,QAAQ6uC,IACzCv9C,MAAK+7D,IAAMj+C,EAAK2U,EAChBzyB,KAAK+7D,GAAM92D,KAAK6lB,IAAI9qB,KAAK+7D,IAAMxa,EAAiBvhD,KAAK+7D,GAAK,EAAKxa,GAAeA,EAAevhD,KAAK+7D,GAClG/7D,KAAKiS,GAAMjS,KAAK+7D,GAAKtpC,IAYzBlvB,EAAK6P,UAAUwrD,QAAU,WACvB,MAAQ5+D,MAAKyrD,QAAUzrD,KAAK0rD,QAQ9BnoD,EAAK6P,UAAU09C,SAAW,SAASD,GACjC,GAAIgO,GAAW55D,KAAK2qB,KAAK3qB,KAAK8uB,IAAI/zB,KAAK87D,GAAG,GAAK72D,KAAK8uB,IAAI/zB,KAAK+7D,GAAG,GAEhE,OAAQ8C,GAAWhO,GAOrBttD,EAAK6P,UAAUg4C,WAAa,WAC1B,MAAOprD,MAAKwzC,UAOdjwC,EAAK6P,UAAUyB,SAAW,WACxB,MAAO7U,MAAKoH,OASd7D,EAAK6P,UAAU0rD,YAAc,SAAS9sD,EAAGC,GACvC,GAAI4M,GAAK7e,KAAKgS,EAAIA,EACd8M,EAAK9e,KAAKiS,EAAIA,CAClB,OAAOhN,MAAK2qB,KAAK/Q,EAAKA,EAAKC,EAAKA,IAUlCvb,EAAK6P,UAAUq8C,cAAgB,SAAS1jD,EAAKY,GAC3C,IAAK3M,KAAKy7D,aAA8Bl1D,SAAfvG,KAAKoH,MAC5B,GAAIuF,GAAOZ,EACT/L,KAAK0O,QAAQgd,QAAS1rB,KAAK0O,QAAQ8uC,UAAYx9C,KAAK0O,QAAQ+uC,WAAa,MAEtE,CACH,GAAIvgC,IAASld,KAAK0O,QAAQ+uC,UAAYz9C,KAAK0O,QAAQ8uC,YAAc7wC,EAAMZ,EACvE/L,MAAK0O,QAAQgd,QAAS1rB,KAAKoH,MAAQ2E,GAAOmR,EAAQld,KAAK0O,QAAQ8uC,UAGnEx9C,KAAKw7D,gBAAkBx7D,KAAK0O,QAAQgd,QAQtCnoB,EAAK6P,UAAUk5B,KAAO,WACpB,KAAM,wCAQR/oC,EAAK6P,UAAUijD,OAAS,WACtB,KAAM,0CAQR9yD,EAAK6P,UAAUw6C,kBAAoB,SAAS5qC,GAC1C,MAAQhjB,MAAKwH,KAAoBwb,EAAIsE,OAC7BtnB,KAAKwH,KAAOxH,KAAKwS,MAAQwQ,EAAIxb,MAC7BxH,KAAK4H,IAAoBob,EAAIO,QAC7BvjB,KAAK4H,IAAM5H,KAAKyS,OAASuQ,EAAIpb,KAGvCrE,EAAK6P,UAAUwqD,aAAe,WAG5B,IAAK59D,KAAKwS,QAAUxS,KAAKyS,OAAQ,CAC/B,GAAID,GAAOC,CACX,IAAIzS,KAAKoH,MAAO,CACdpH,KAAK0O,QAAQgd,OAAQ1rB,KAAKw7D,eAC1B,IAAIt+C,GAAQld,KAAKi9D,SAASxqD,OAASzS,KAAKi9D,SAASzqD,KACnCjM,UAAV2W,GACF1K,EAAQxS,KAAK0O,QAAQgd,QAAS1rB,KAAKi9D,SAASzqD,MAC5CC,EAASzS,KAAK0O,QAAQgd,OAAQxO,GAASld,KAAKi9D,SAASxqD,SAGrDD,EAAQ,EACRC,EAAS,OAIXD,GAAQxS,KAAKi9D,SAASzqD,MACtBC,EAASzS,KAAKi9D,SAASxqD,MAEzBzS,MAAKwS,MAASA,EACdxS,KAAKyS,OAASA,EAEdzS,KAAKu8D,gBAAkB,EACnBv8D,KAAKwS,MAAQ,GAAKxS,KAAKyS,OAAS,IAClCzS,KAAKwS,OAAUvN,KAAK8G,IAAI/L,KAAK08D,YAAc,EAAG18D,KAAKugD,uBAA0BvgD,KAAKo8D,uBAClFp8D,KAAKyS,QAAUxN,KAAK8G,IAAI/L,KAAK08D,YAAc,EAAG18D,KAAKugD,uBAAyBvgD,KAAKq8D,wBACjFr8D,KAAK0O,QAAQgd,QAASzmB,KAAK8G,IAAI/L,KAAK08D,YAAc,EAAG18D,KAAKugD,uBAAyBvgD,KAAKs8D,wBACxFt8D,KAAKu8D,gBAAkBv8D,KAAKwS,MAAQA,KAK1CjP,EAAK6P,UAAU2rD,qBAAuB,SAAU/3C,GAC9C,GAA2B,GAAvBhnB,KAAKi9D,SAASzqD,MAAa,CAE7B,GAAIxS,KAAK08D,YAAc,EAAG,CACxB,GAAIn1C,GAAcvnB,KAAK08D,YAAc,EAAK,GAAK,CAC/Cn1C,IAAavnB,KAAKw2D,gBAClBjvC,EAAYtiB,KAAK8G,IAAI,GAAM/L,KAAKwS,MAAM+U,GAEtCP,EAAIg4C,YAAc,GAClBh4C,EAAIi4C,UAAUj/D,KAAKi9D,SAAUj9D,KAAKwH,KAAO+f,EAAWvnB,KAAK4H,IAAM2f,EAAWvnB,KAAKwS,MAAQ,EAAE+U,EAAWvnB,KAAKyS,OAAS,EAAE8U,GAItHP,EAAIg4C,YAAc,EAClBh4C,EAAIi4C,UAAUj/D,KAAKi9D,SAAUj9D,KAAKwH,KAAMxH,KAAK4H,IAAK5H,KAAKwS,MAAOxS,KAAKyS,UAIvElP,EAAK6P,UAAU8rD,gBAAkB,SAAUl4C,GACzC,GAAIjN,GACA6P,EAAS,CAEb,IAAI5pB,KAAKyS,OAAO,CACdmX,EAAS5pB,KAAKyS,OAAS,CACvB,IAAI0hD,GAAkBn0D,KAAKm/D,YAAYn4C,EAEnCmtC,GAAgB0C,WAAa,IAC/BjtC,GAAUuqC,EAAgB1hD,OAAS,EACnCmX,GAAU,GAId7P,EAAS/Z,KAAKiS,EAAI2X,EAElB5pB,KAAKo2D,OAAOpvC,EAAKhnB,KAAK0oB,MAAO1oB,KAAKgS,EAAG+H,EAAQxT,SAG/ChD,EAAK6P,UAAUuqD,WAAa,SAAU32C,GACpChnB,KAAK49D,aAAa52C,GAClBhnB,KAAKwH,KAASxH,KAAKgS,EAAIhS,KAAKwS,MAAQ,EACpCxS,KAAK4H,IAAS5H,KAAKiS,EAAIjS,KAAKyS,OAAS,EAErCzS,KAAK++D,qBAAqB/3C,GAE1BhnB,KAAKymD,YAAY7+C,IAAM5H,KAAK4H,IAC5B5H,KAAKymD,YAAYj/C,KAAOxH,KAAKwH,KAC7BxH,KAAKymD,YAAYn/B,MAAQtnB,KAAKwH,KAAOxH,KAAKwS,MAC1CxS,KAAKymD,YAAYljC,OAASvjB,KAAK4H,IAAM5H,KAAKyS,OAE1CzS,KAAKk/D,gBAAgBl4C,GACrBhnB,KAAKymD,YAAYj/C,KAAOvC,KAAK8G,IAAI/L,KAAKymD,YAAYj/C,KAAMxH,KAAKm0D,gBAAgB3sD,MAC7ExH,KAAKymD,YAAYn/B,MAAQriB,KAAK0H,IAAI3M,KAAKymD,YAAYn/B,MAAOtnB,KAAKm0D,gBAAgB3sD,KAAOxH,KAAKm0D,gBAAgB3hD,OAC3GxS,KAAKymD,YAAYljC,OAASte,KAAK0H,IAAI3M,KAAKymD,YAAYljC,OAAQvjB,KAAKymD,YAAYljC,OAASvjB,KAAKm0D,gBAAgB1hD,SAG7GlP,EAAK6P,UAAU0qD,qBAAuB,SAAU92C,GAC9C,GAAIhnB,KAAKi9D,SAAShX,KAAQjmD,KAAKi9D,SAASzqD,OAAUxS,KAAKi9D,SAASxqD,OAe1DzS,KAAKo/D,oCACPp/D,KAAKwS,MAAQ,EACbxS,KAAKyS,OAAS,QACPzS,MAAKo/D,mCAEdp/D,KAAK49D,aAAa52C,OAnBlB,KAAKhnB,KAAKwS,MAAO,CACf,GAAI6sD,GAAiC,EAAtBr/D,KAAK0O,QAAQgd,MAC5B1rB,MAAKwS,MAAQ6sD,EACbr/D,KAAKyS,OAAS4sD,EAKdr/D,KAAK0O,QAAQgd,QAAuE,GAA7DzmB,KAAK8G,IAAI/L,KAAK08D,YAAc,EAAG18D,KAAKugD,uBAA+BvgD,KAAKs8D,wBAC/Ft8D,KAAKu8D,gBAAkBv8D,KAAK0O,QAAQgd,OAAQ,GAAI2zC,EAChDr/D,KAAKo/D,mCAAoC,IAc/C77D,EAAK6P,UAAUyqD,mBAAqB,SAAU72C,GAC5ChnB,KAAK89D,qBAAqB92C,GAE1BhnB,KAAKwH,KAASxH,KAAKgS,EAAIhS,KAAKwS,MAAQ,EACpCxS,KAAK4H,IAAS5H,KAAKiS,EAAIjS,KAAKyS,OAAS,CAErC,IAAI6sD,GAAUt/D,KAAKwH,KAAQxH,KAAKwS,MAAQ,EACpC+sD,EAAUv/D,KAAK4H,IAAO5H,KAAKyS,OAAS,EACpCiZ,EAASzmB,KAAK6lB,IAAI9qB,KAAKyS,OAAS,EAEpCzS,MAAKw/D,eAAex4C,EAAKs4C,EAASC,EAAS7zC,GAE3C1E,EAAI2oC,OACJ3oC,EAAIy4C,OAAOz/D,KAAKgS,EAAGhS,KAAKiS,EAAGyZ,GAC3B1E,EAAIlH,SACJkH,EAAI04C,OAEJ1/D,KAAK++D,qBAAqB/3C,GAE1BA,EAAI8oC,UAEJ9vD,KAAKymD,YAAY7+C,IAAM5H,KAAKiS,EAAIjS,KAAK0O,QAAQgd,OAC7C1rB,KAAKymD,YAAYj/C,KAAOxH,KAAKgS,EAAIhS,KAAK0O,QAAQgd,OAC9C1rB,KAAKymD,YAAYn/B,MAAQtnB,KAAKgS,EAAIhS,KAAK0O,QAAQgd,OAC/C1rB,KAAKymD,YAAYljC,OAASvjB,KAAKiS,EAAIjS,KAAK0O,QAAQgd,OAEhD1rB,KAAKk/D,gBAAgBl4C,GAErBhnB,KAAKymD,YAAYj/C,KAAOvC,KAAK8G,IAAI/L,KAAKymD,YAAYj/C,KAAMxH,KAAKm0D,gBAAgB3sD,MAC7ExH,KAAKymD,YAAYn/B,MAAQriB,KAAK0H,IAAI3M,KAAKymD,YAAYn/B,MAAOtnB,KAAKm0D,gBAAgB3sD,KAAOxH,KAAKm0D,gBAAgB3hD,OAC3GxS,KAAKymD,YAAYljC,OAASte,KAAK0H,IAAI3M,KAAKymD,YAAYljC,OAAQvjB,KAAKymD,YAAYljC,OAASvjB,KAAKm0D,gBAAgB1hD,SAG7GlP,EAAK6P,UAAUkqD,WAAa,SAAUt2C,GACpC,IAAKhnB,KAAKwS,MAAO,CACf,GAAImH,GAAS,EACTgmD,EAAW3/D,KAAKm/D,YAAYn4C,EAChChnB,MAAKwS,MAAQmtD,EAASntD,MAAQ,EAAImH,EAClC3Z,KAAKyS,OAASktD,EAASltD,OAAS,EAAIkH,EAEpC3Z,KAAKwS,OAAuE,GAA7DvN,KAAK8G,IAAI/L,KAAK08D,YAAc,EAAG18D,KAAKugD,uBAA+BvgD,KAAKo8D,uBACvFp8D,KAAKyS,QAAuE,GAA7DxN,KAAK8G,IAAI/L,KAAK08D,YAAc,EAAG18D,KAAKugD,uBAA+BvgD,KAAKq8D,wBACvFr8D,KAAKu8D,gBAAkBv8D,KAAKwS,OAASmtD,EAASntD,MAAQ,EAAImH,KAM9DpW,EAAK6P,UAAUiqD,SAAW,SAAUr2C,GAClChnB,KAAKs9D,WAAWt2C,GAEhBhnB,KAAKwH,KAAOxH,KAAKgS,EAAIhS,KAAKwS,MAAQ,EAClCxS,KAAK4H,IAAM5H,KAAKiS,EAAIjS,KAAKyS,OAAS,CAElC,IAAImtD,GAAmB,IACnB3/C,EAAcjgB,KAAK0O,QAAQuR,YAC3B4/C,EAAqB7/D,KAAK0O,QAAQyvC,qBAAuB,EAAIn+C,KAAK0O,QAAQuR,WAE9E+G,GAAIY,YAAc5nB,KAAKwzC,SAAWxzC,KAAK0O,QAAQtD,MAAMkB,UAAUD,OAASrM,KAAKuM,MAAQvM,KAAK0O,QAAQtD,MAAMmB,MAAMF,OAASrM,KAAK0O,QAAQtD,MAAMiB,OAGtIrM,KAAK08D,YAAc,IACrB11C,EAAIO,WAAavnB,KAAKwzC,SAAWqsB,EAAqB5/C,IAAiBjgB,KAAK08D,YAAc,EAAKkD,EAAmB,GAClH54C,EAAIO,WAAavnB,KAAKw2D,gBACtBxvC,EAAIO,UAAYtiB,KAAK8G,IAAI/L,KAAKwS,MAAMwU,EAAIO,WAExCP,EAAI84C,UAAU9/D,KAAKwH,KAAK,EAAEwf,EAAIO,UAAWvnB,KAAK4H,IAAI,EAAEof,EAAIO,UAAWvnB,KAAKwS,MAAM,EAAEwU,EAAIO,UAAWvnB,KAAKyS,OAAO,EAAEuU,EAAIO,UAAWvnB,KAAK0O,QAAQgd,QACzI1E,EAAIlH,UAENkH,EAAIO,WAAavnB,KAAKwzC,SAAWqsB,EAAqB5/C,IAAiBjgB,KAAK08D,YAAc,EAAKkD,EAAmB,GAClH54C,EAAIO,WAAavnB,KAAKw2D,gBACtBxvC,EAAIO,UAAYtiB,KAAK8G,IAAI/L,KAAKwS,MAAMwU,EAAIO,WAExCP,EAAIiB,UAAYjoB,KAAKwzC,SAAWxzC,KAAK0O,QAAQtD,MAAMkB,UAAUF,WAAapM,KAAKuM,MAAQvM,KAAK0O,QAAQtD,MAAMmB,MAAMH,WAAapM,KAAK0O,QAAQtD,MAAMgB,WAEhJ4a,EAAI84C,UAAU9/D,KAAKwH,KAAMxH,KAAK4H,IAAK5H,KAAKwS,MAAOxS,KAAKyS,OAAQzS,KAAK0O,QAAQgd,QACzE1E,EAAInH,OACJmH,EAAIlH,SAEJ9f,KAAKymD,YAAY7+C,IAAM5H,KAAK4H,IAC5B5H,KAAKymD,YAAYj/C,KAAOxH,KAAKwH,KAC7BxH,KAAKymD,YAAYn/B,MAAQtnB,KAAKwH,KAAOxH,KAAKwS,MAC1CxS,KAAKymD,YAAYljC,OAASvjB,KAAK4H,IAAM5H,KAAKyS,OAE1CzS,KAAKo2D,OAAOpvC,EAAKhnB,KAAK0oB,MAAO1oB,KAAKgS,EAAGhS,KAAKiS,IAI5C1O,EAAK6P,UAAUgqD,gBAAkB,SAAUp2C,GACzC,IAAKhnB,KAAKwS,MAAO,CACf,GAAImH,GAAS,EACTgmD,EAAW3/D,KAAKm/D,YAAYn4C,GAC5B1U,EAAOqtD,EAASntD,MAAQ,EAAImH,CAChC3Z,MAAKwS,MAAQF,EACbtS,KAAKyS,OAASH,EAGdtS,KAAKwS,OAAUvN,KAAK8G,IAAI/L,KAAK08D,YAAc,EAAG18D,KAAKugD,uBAAyBvgD,KAAKo8D,uBACjFp8D,KAAKyS,QAAUxN,KAAK8G,IAAI/L,KAAK08D,YAAc,EAAG18D,KAAKugD,uBAAyBvgD,KAAKq8D,wBACjFr8D,KAAK0O,QAAQgd,QAASzmB,KAAK8G,IAAI/L,KAAK08D,YAAc,EAAG18D,KAAKugD,uBAAyBvgD,KAAKs8D,wBACxFt8D,KAAKu8D,gBAAkBv8D,KAAKwS,MAAQF,IAIxC/O,EAAK6P,UAAU+pD,cAAgB,SAAUn2C,GACvChnB,KAAKo9D,gBAAgBp2C,GACrBhnB,KAAKwH,KAAOxH,KAAKgS,EAAIhS,KAAKwS,MAAQ,EAClCxS,KAAK4H,IAAM5H,KAAKiS,EAAIjS,KAAKyS,OAAS,CAElC,IAAImtD,GAAmB,IACnB3/C,EAAcjgB,KAAK0O,QAAQuR,YAC3B4/C,EAAqB7/D,KAAK0O,QAAQyvC,qBAAuB,EAAIn+C,KAAK0O,QAAQuR,WAE9E+G;EAAIY,YAAc5nB,KAAKwzC,SAAWxzC,KAAK0O,QAAQtD,MAAMkB,UAAUD,OAASrM,KAAKuM,MAAQvM,KAAK0O,QAAQtD,MAAMmB,MAAMF,OAASrM,KAAK0O,QAAQtD,MAAMiB,OAGtIrM,KAAK08D,YAAc,IACrB11C,EAAIO,WAAavnB,KAAKwzC,SAAWqsB,EAAqB5/C,IAAiBjgB,KAAK08D,YAAc,EAAKkD,EAAmB,GAClH54C,EAAIO,WAAavnB,KAAKw2D,gBACtBxvC,EAAIO,UAAYtiB,KAAK8G,IAAI/L,KAAKwS,MAAMwU,EAAIO,WAExCP,EAAI+4C,SAAS//D,KAAKgS,EAAIhS,KAAKwS,MAAM,EAAI,EAAEwU,EAAIO,UAAWvnB,KAAKiS,EAAgB,GAAZjS,KAAKyS,OAAa,EAAEuU,EAAIO,UAAWvnB,KAAKwS,MAAQ,EAAEwU,EAAIO,UAAWvnB,KAAKyS,OAAS,EAAEuU,EAAIO,WACpJP,EAAIlH,UAENkH,EAAIO,WAAavnB,KAAKwzC,SAAWqsB,EAAqB5/C,IAAiBjgB,KAAK08D,YAAc,EAAKkD,EAAmB,GAClH54C,EAAIO,WAAavnB,KAAKw2D,gBACtBxvC,EAAIO,UAAYtiB,KAAK8G,IAAI/L,KAAKwS,MAAMwU,EAAIO,WAExCP,EAAIiB,UAAYjoB,KAAKwzC,SAAWxzC,KAAK0O,QAAQtD,MAAMkB,UAAUF,WAAapM,KAAKuM,MAAQvM,KAAK0O,QAAQtD,MAAMmB,MAAMH,WAAapM,KAAK0O,QAAQtD,MAAMgB,WAChJ4a,EAAI+4C,SAAS//D,KAAKgS,EAAIhS,KAAKwS,MAAM,EAAGxS,KAAKiS,EAAgB,GAAZjS,KAAKyS,OAAYzS,KAAKwS,MAAOxS,KAAKyS,QAC/EuU,EAAInH,OACJmH,EAAIlH,SAEJ9f,KAAKymD,YAAY7+C,IAAM5H,KAAK4H,IAC5B5H,KAAKymD,YAAYj/C,KAAOxH,KAAKwH,KAC7BxH,KAAKymD,YAAYn/B,MAAQtnB,KAAKwH,KAAOxH,KAAKwS,MAC1CxS,KAAKymD,YAAYljC,OAASvjB,KAAK4H,IAAM5H,KAAKyS,OAE1CzS,KAAKo2D,OAAOpvC,EAAKhnB,KAAK0oB,MAAO1oB,KAAKgS,EAAGhS,KAAKiS,IAI5C1O,EAAK6P,UAAUoqD,cAAgB,SAAUx2C,GACvC,IAAKhnB,KAAKwS,MAAO,CACf,GAAImH,GAAS,EACTgmD,EAAW3/D,KAAKm/D,YAAYn4C,GAC5Bq4C,EAAWp6D,KAAK0H,IAAIgzD,EAASntD,MAAOmtD,EAASltD,QAAU,EAAIkH,CAC/D3Z,MAAK0O,QAAQgd,OAAS2zC,EAAW,EAEjCr/D,KAAKwS,MAAQ6sD,EACbr/D,KAAKyS,OAAS4sD,EAKdr/D,KAAK0O,QAAQgd,QAAuE,GAA7DzmB,KAAK8G,IAAI/L,KAAK08D,YAAc,EAAG18D,KAAKugD,uBAA+BvgD,KAAKs8D,wBAC/Ft8D,KAAKu8D,gBAAkBv8D,KAAK0O,QAAQgd,OAAQ,GAAI2zC,IAIpD97D,EAAK6P,UAAUosD,eAAiB,SAAUx4C,EAAKhV,EAAGC,EAAGyZ,GACnD,GAAIk0C,GAAmB,IACnB3/C,EAAcjgB,KAAK0O,QAAQuR,YAC3B4/C,EAAqB7/D,KAAK0O,QAAQyvC,qBAAuB,EAAIn+C,KAAK0O,QAAQuR,WAE9E+G,GAAIY,YAAc5nB,KAAKwzC,SAAWxzC,KAAK0O,QAAQtD,MAAMkB,UAAUD,OAASrM,KAAKuM,MAAQvM,KAAK0O,QAAQtD,MAAMmB,MAAMF,OAASrM,KAAK0O,QAAQtD,MAAMiB,OAGtIrM,KAAK08D,YAAc,IACrB11C,EAAIO,WAAavnB,KAAKwzC,SAAWqsB,EAAqB5/C,IAAiBjgB,KAAK08D,YAAc,EAAKkD,EAAmB,GAClH54C,EAAIO,WAAavnB,KAAKw2D,gBACtBxvC,EAAIO,UAAYtiB,KAAK8G,IAAI/L,KAAKwS,MAAMwU,EAAIO,WAExCP,EAAIy4C,OAAOztD,EAAGC,EAAGyZ,EAAO,EAAE1E,EAAIO,WAC9BP,EAAIlH,UAENkH,EAAIO,WAAavnB,KAAKwzC,SAAWqsB,EAAqB5/C,IAAiBjgB,KAAK08D,YAAc,EAAKkD,EAAmB,GAClH54C,EAAIO,WAAavnB,KAAKw2D,gBACtBxvC,EAAIO,UAAYtiB,KAAK8G,IAAI/L,KAAKwS,MAAMwU,EAAIO,WAExCP,EAAIiB,UAAYjoB,KAAKwzC,SAAWxzC,KAAK0O,QAAQtD,MAAMkB,UAAUF,WAAapM,KAAKuM,MAAQvM,KAAK0O,QAAQtD,MAAMmB,MAAMH,WAAapM,KAAK0O,QAAQtD,MAAMgB,WAChJ4a,EAAIy4C,OAAOz/D,KAAKgS,EAAGhS,KAAKiS,EAAGyZ,GAC3B1E,EAAInH,OACJmH,EAAIlH,UAGNvc,EAAK6P,UAAUmqD,YAAc,SAAUv2C,GACrChnB,KAAKw9D,cAAcx2C,GACnBhnB,KAAKwH,KAAOxH,KAAKgS,EAAIhS,KAAKwS,MAAQ,EAClCxS,KAAK4H,IAAM5H,KAAKiS,EAAIjS,KAAKyS,OAAS,EAElCzS,KAAKw/D,eAAex4C,EAAKhnB,KAAKgS,EAAGhS,KAAKiS,EAAGjS,KAAK0O,QAAQgd,QAEtD1rB,KAAKymD,YAAY7+C,IAAM5H,KAAKiS,EAAIjS,KAAK0O,QAAQgd,OAC7C1rB,KAAKymD,YAAYj/C,KAAOxH,KAAKgS,EAAIhS,KAAK0O,QAAQgd,OAC9C1rB,KAAKymD,YAAYn/B,MAAQtnB,KAAKgS,EAAIhS,KAAK0O,QAAQgd,OAC/C1rB,KAAKymD,YAAYljC,OAASvjB,KAAKiS,EAAIjS,KAAK0O,QAAQgd,OAEhD1rB,KAAKo2D,OAAOpvC,EAAKhnB,KAAK0oB,MAAO1oB,KAAKgS,EAAGhS,KAAKiS,IAG5C1O,EAAK6P,UAAUsqD,eAAiB,SAAU12C,GACxC,IAAKhnB,KAAKwS,MAAO,CACf,GAAImtD,GAAW3/D,KAAKm/D,YAAYn4C,EAEhChnB,MAAKwS,MAAyB,IAAjBmtD,EAASntD,MACtBxS,KAAKyS,OAA2B,EAAlBktD,EAASltD,OACnBzS,KAAKwS,MAAQxS,KAAKyS,SACpBzS,KAAKwS,MAAQxS,KAAKyS,OAEpB,IAAIutD,GAAchgE,KAAKwS,KAGvBxS,MAAKwS,OAAUvN,KAAK8G,IAAI/L,KAAK08D,YAAc,EAAG18D,KAAKugD,uBAAyBvgD,KAAKo8D,uBACjFp8D,KAAKyS,QAAUxN,KAAK8G,IAAI/L,KAAK08D,YAAc,EAAG18D,KAAKugD,uBAAyBvgD,KAAKq8D,wBACjFr8D,KAAK0O,QAAQgd,QAAUzmB,KAAK8G,IAAI/L,KAAK08D,YAAc,EAAG18D,KAAKugD,uBAAyBvgD,KAAKs8D,wBACzFt8D,KAAKu8D,gBAAkBv8D,KAAKwS,MAAQwtD,IAIxCz8D,EAAK6P,UAAUqqD,aAAe,SAAUz2C,GACtChnB,KAAK09D,eAAe12C,GACpBhnB,KAAKwH,KAAOxH,KAAKgS,EAAIhS,KAAKwS,MAAQ,EAClCxS,KAAK4H,IAAM5H,KAAKiS,EAAIjS,KAAKyS,OAAS,CAElC,IAAImtD,GAAmB,IACnB3/C,EAAcjgB,KAAK0O,QAAQuR,YAC3B4/C,EAAqB7/D,KAAK0O,QAAQyvC,qBAAuB,EAAIn+C,KAAK0O,QAAQuR,WAE9E+G,GAAIY,YAAc5nB,KAAKwzC,SAAWxzC,KAAK0O,QAAQtD,MAAMkB,UAAUD,OAASrM,KAAKuM,MAAQvM,KAAK0O,QAAQtD,MAAMmB,MAAMF,OAASrM,KAAK0O,QAAQtD,MAAMiB,OAGtIrM,KAAK08D,YAAc,IACrB11C,EAAIO,WAAavnB,KAAKwzC,SAAWqsB,EAAqB5/C,IAAiBjgB,KAAK08D,YAAc,EAAKkD,EAAmB,GAClH54C,EAAIO,WAAavnB,KAAKw2D,gBACtBxvC,EAAIO,UAAYtiB,KAAK8G,IAAI/L,KAAKwS,MAAMwU,EAAIO,WAExCP,EAAIi5C,QAAQjgE,KAAKwH,KAAK,EAAEwf,EAAIO,UAAWvnB,KAAK4H,IAAI,EAAEof,EAAIO,UAAWvnB,KAAKwS,MAAM,EAAEwU,EAAIO,UAAWvnB,KAAKyS,OAAO,EAAEuU,EAAIO,WAC/GP,EAAIlH,UAENkH,EAAIO,WAAavnB,KAAKwzC,SAAWqsB,EAAqB5/C,IAAiBjgB,KAAK08D,YAAc,EAAKkD,EAAmB,GAClH54C,EAAIO,WAAavnB,KAAKw2D,gBACtBxvC,EAAIO,UAAYtiB,KAAK8G,IAAI/L,KAAKwS,MAAMwU,EAAIO,WAExCP,EAAIiB,UAAYjoB,KAAKwzC,SAAWxzC,KAAK0O,QAAQtD,MAAMkB,UAAUF,WAAapM,KAAKuM,MAAQvM,KAAK0O,QAAQtD,MAAMmB,MAAMH,WAAapM,KAAK0O,QAAQtD,MAAMgB,WAEhJ4a,EAAIi5C,QAAQjgE,KAAKwH,KAAMxH,KAAK4H,IAAK5H,KAAKwS,MAAOxS,KAAKyS,QAClDuU,EAAInH,OACJmH,EAAIlH,SAEJ9f,KAAKymD,YAAY7+C,IAAM5H,KAAK4H,IAC5B5H,KAAKymD,YAAYj/C,KAAOxH,KAAKwH,KAC7BxH,KAAKymD,YAAYn/B,MAAQtnB,KAAKwH,KAAOxH,KAAKwS,MAC1CxS,KAAKymD,YAAYljC,OAASvjB,KAAK4H,IAAM5H,KAAKyS,OAE1CzS,KAAKo2D,OAAOpvC,EAAKhnB,KAAK0oB,MAAO1oB,KAAKgS,EAAGhS,KAAKiS,IAG5C1O,EAAK6P,UAAU6qD,SAAW,SAAUj3C,GAClChnB,KAAKkgE,WAAWl5C,EAAK,WAGvBzjB,EAAK6P,UAAUgrD,cAAgB,SAAUp3C,GACvChnB,KAAKkgE,WAAWl5C,EAAK,aAGvBzjB,EAAK6P,UAAUirD,kBAAoB,SAAUr3C,GAC3ChnB,KAAKkgE,WAAWl5C,EAAK,iBAGvBzjB,EAAK6P,UAAU+qD,YAAc,SAAUn3C,GACrChnB,KAAKkgE,WAAWl5C,EAAK,WAGvBzjB,EAAK6P,UAAUkrD,UAAY,SAAUt3C,GACnChnB,KAAKkgE,WAAWl5C,EAAK,SAGvBzjB,EAAK6P,UAAU8qD,aAAe,WAC5B,IAAKl+D,KAAKwS,MAAO,CACfxS,KAAK0O,QAAQgd,OAAQ1rB,KAAKw7D,eAC1B,IAAIlpD,GAAO,EAAItS,KAAK0O,QAAQgd,MAC5B1rB,MAAKwS,MAAQF,EACbtS,KAAKyS,OAASH,EAGdtS,KAAKwS,OAAUvN,KAAK8G,IAAI/L,KAAK08D,YAAc,EAAG18D,KAAKugD,uBAAyBvgD,KAAKo8D,uBACjFp8D,KAAKyS,QAAUxN,KAAK8G,IAAI/L,KAAK08D,YAAc,EAAG18D,KAAKugD,uBAAyBvgD,KAAKq8D,wBACjFr8D,KAAK0O,QAAQgd,QAAsE,GAA7DzmB,KAAK8G,IAAI/L,KAAK08D,YAAc,EAAG18D,KAAKugD,uBAA+BvgD,KAAKs8D,wBAC9Ft8D,KAAKu8D,gBAAkBv8D,KAAKwS,MAAQF,IAIxC/O,EAAK6P,UAAU8sD,WAAa,SAAUl5C,EAAK02B,GACzC19C,KAAKk+D,aAAal3C,GAElBhnB,KAAKwH,KAAOxH,KAAKgS,EAAIhS,KAAKwS,MAAQ,EAClCxS,KAAK4H,IAAM5H,KAAKiS,EAAIjS,KAAKyS,OAAS,CAElC,IAAImtD,GAAmB,IACnB3/C,EAAcjgB,KAAK0O,QAAQuR,YAC3B4/C,EAAqB7/D,KAAK0O,QAAQyvC,qBAAuB,EAAIn+C,KAAK0O,QAAQuR,YAC1EkgD,EAAmB,CAGvB,QAAQziB,GACN,IAAK,MAAiByiB,EAAmB,CAAG,MAC5C,KAAK,SAAiBA,EAAmB,CAAG,MAC5C,KAAK,WAAiBA,EAAmB,CAAG,MAC5C,KAAK,eAAiBA,EAAmB,CAAG,MAC5C,KAAK,OAAiBA,EAAmB,EAG3Cn5C,EAAIY,YAAc5nB,KAAKwzC,SAAWxzC,KAAK0O,QAAQtD,MAAMkB,UAAUD,OAASrM,KAAKuM,MAAQvM,KAAK0O,QAAQtD,MAAMmB,MAAMF,OAASrM,KAAK0O,QAAQtD,MAAMiB,OAEtIrM,KAAK08D,YAAc,IACrB11C,EAAIO,WAAavnB,KAAKwzC,SAAWqsB,EAAqB5/C,IAAiBjgB,KAAK08D,YAAc,EAAKkD,EAAmB,GAClH54C,EAAIO,WAAavnB,KAAKw2D,gBACtBxvC,EAAIO,UAAYtiB,KAAK8G,IAAI/L,KAAKwS,MAAMwU,EAAIO,WAExCP,EAAI02B,GAAO19C,KAAKgS,EAAGhS,KAAKiS,EAAGjS,KAAK0O,QAAQgd,OAAQy0C,EAAmBn5C,EAAIO,WACvEP,EAAIlH,UAENkH,EAAIO,WAAavnB,KAAKwzC,SAAWqsB,EAAqB5/C,IAAiBjgB,KAAK08D,YAAc,EAAKkD,EAAmB,GAClH54C,EAAIO,WAAavnB,KAAKw2D,gBACtBxvC,EAAIO,UAAYtiB,KAAK8G,IAAI/L,KAAKwS,MAAMwU,EAAIO,WAExCP,EAAIiB,UAAYjoB,KAAKwzC,SAAWxzC,KAAK0O,QAAQtD,MAAMkB,UAAUF,WAAapM,KAAKuM,MAAQvM,KAAK0O,QAAQtD,MAAMmB,MAAMH,WAAapM,KAAK0O,QAAQtD,MAAMgB,WAChJ4a,EAAI02B,GAAO19C,KAAKgS,EAAGhS,KAAKiS,EAAGjS,KAAK0O,QAAQgd,QACxC1E,EAAInH,OACJmH,EAAIlH,SAEJ9f,KAAKymD,YAAY7+C,IAAM5H,KAAKiS,EAAIjS,KAAK0O,QAAQgd,OAC7C1rB,KAAKymD,YAAYj/C,KAAOxH,KAAKgS,EAAIhS,KAAK0O,QAAQgd,OAC9C1rB,KAAKymD,YAAYn/B,MAAQtnB,KAAKgS,EAAIhS,KAAK0O,QAAQgd,OAC/C1rB,KAAKymD,YAAYljC,OAASvjB,KAAKiS,EAAIjS,KAAK0O,QAAQgd,OAE5C1rB,KAAK0oB,QACP1oB,KAAKo2D,OAAOpvC,EAAKhnB,KAAK0oB,MAAO1oB,KAAKgS,EAAGhS,KAAKiS,EAAIjS,KAAKyS,OAAS,EAAGlM,OAAW,WAAU,GACpFvG,KAAKymD,YAAYj/C,KAAOvC,KAAK8G,IAAI/L,KAAKymD,YAAYj/C,KAAMxH,KAAKm0D,gBAAgB3sD,MAC7ExH,KAAKymD,YAAYn/B,MAAQriB,KAAK0H,IAAI3M,KAAKymD,YAAYn/B,MAAOtnB,KAAKm0D,gBAAgB3sD,KAAOxH,KAAKm0D,gBAAgB3hD,OAC3GxS,KAAKymD,YAAYljC,OAASte,KAAK0H,IAAI3M,KAAKymD,YAAYljC,OAAQvjB,KAAKymD,YAAYljC,OAASvjB,KAAKm0D,gBAAgB1hD,UAI/GlP,EAAK6P,UAAU4qD,YAAc,SAAUh3C,GACrC,IAAKhnB,KAAKwS,MAAO,CACf,GAAImH,GAAS,EACTgmD,EAAW3/D,KAAKm/D,YAAYn4C,EAChChnB,MAAKwS,MAAQmtD,EAASntD,MAAQ,EAAImH,EAClC3Z,KAAKyS,OAASktD,EAASltD,OAAS,EAAIkH,EAGpC3Z,KAAKwS,OAAUvN,KAAK8G,IAAI/L,KAAK08D,YAAc,EAAG18D,KAAKugD,uBAAyBvgD,KAAKo8D,uBACjFp8D,KAAKyS,QAAUxN,KAAK8G,IAAI/L,KAAK08D,YAAc,EAAG18D,KAAKugD,uBAAyBvgD,KAAKq8D,wBACjFr8D,KAAK0O,QAAQgd,QAASzmB,KAAK8G,IAAI/L,KAAK08D,YAAc,EAAG18D,KAAKugD,uBAAyBvgD,KAAKs8D,wBACxFt8D,KAAKu8D,gBAAkBv8D,KAAKwS,OAASmtD,EAASntD,MAAQ,EAAImH,KAI9DpW,EAAK6P,UAAU2qD,UAAY,SAAU/2C,GACnChnB,KAAKg+D,YAAYh3C,GACjBhnB,KAAKwH,KAAOxH,KAAKgS,EAAIhS,KAAKwS,MAAQ,EAClCxS,KAAK4H,IAAM5H,KAAKiS,EAAIjS,KAAKyS,OAAS,EAElCzS,KAAKo2D,OAAOpvC,EAAKhnB,KAAK0oB,MAAO1oB,KAAKgS,EAAGhS,KAAKiS,GAE1CjS,KAAKymD,YAAY7+C,IAAM5H,KAAK4H,IAC5B5H,KAAKymD,YAAYj/C,KAAOxH,KAAKwH,KAC7BxH,KAAKymD,YAAYn/B,MAAQtnB,KAAKwH,KAAOxH,KAAKwS,MAC1CxS,KAAKymD,YAAYljC,OAASvjB,KAAK4H,IAAM5H,KAAKyS,QAI5ClP,EAAK6P,UAAUgjD,OAAS,SAAUpvC,EAAKwC,EAAMxX,EAAGC,EAAGq9B,EAAO8wB,EAAUC,GAClE,GAAI72C,GAAQvlB,OAAOjE,KAAK0O,QAAQmvC,UAAY79C,KAAKw8D,aAAex8D,KAAKq7D,kBAAmB,CACtFr0C,EAAIQ,MAAQxnB,KAAKwzC,SAAW,QAAU,IAAMxzC,KAAK0O,QAAQmvC,SAAW,MAAQ79C,KAAK0O,QAAQovC,QAEzF,IAAI/W,GAAQvd,EAAKvhB,MAAM,MACnB4uD,EAAY9vB,EAAMrhC,OAClBm4C,EAAW55C,OAAOjE,KAAK0O,QAAQmvC,UAC/BuW,EAAQniD,GAAK,EAAI4kD,GAAa,EAAIhZ,CAChB,IAAlBwiB,IACFjM,EAAQniD,GAAK,EAAI4kD,IAAc,EAAIhZ,GAKrC,KAAK,GADDrrC,GAAQwU,EAAI8vC,YAAY/vB,EAAM,IAAIv0B,MAC7BjN,EAAI,EAAOsxD,EAAJtxD,EAAeA,IAAK,CAClC,GAAIgiB,GAAYP,EAAI8vC,YAAY/vB,EAAMxhC,IAAIiN,KAC1CA,GAAQ+U,EAAY/U,EAAQ+U,EAAY/U,EAE1C,GAAIC,GAASzS,KAAK0O,QAAQmvC,SAAWgZ,EACjCrvD,EAAOwK,EAAIQ,EAAQ,EACnB5K,EAAMqK,EAAIQ,EAAS,CACP,YAAZ2tD,IACFx4D,GAAO,GAAMi2C,EACbj2C,GAAO,EACPwsD,GAAS,GAEXp0D,KAAKm0D,iBAAmBvsD,IAAIA,EAAIJ,KAAKA,EAAKgL,MAAMA,EAAMC,OAAOA,EAAO2hD,MAAMA,GAG5C7tD,SAA1BvG,KAAK0O,QAAQqvC,UAAoD,OAA1B/9C,KAAK0O,QAAQqvC,UAA+C,SAA1B/9C,KAAK0O,QAAQqvC,WACxF/2B,EAAIiB,UAAYjoB,KAAK0O,QAAQqvC,SAC7B/2B,EAAIswC,SAAS9vD,EAAMI,EAAK4K,EAAOC,IAIjCuU,EAAIiB,UAAYjoB,KAAK0O,QAAQkvC,WAAa,QAC1C52B,EAAIuB,UAAY+mB,GAAS,SACzBtoB,EAAIwB,aAAe43C,GAAY,SAC3BpgE,KAAK0O,QAAQsvC,gBAAkB,IACjCh3B,EAAIO,UAAcvnB,KAAK0O,QAAQsvC,gBAC/Bh3B,EAAIY,YAAc5nB,KAAK0O,QAAQuvC,gBAC/Bj3B,EAAIuwC,SAAc,QAEpB,KAAK,GAAIhyD,GAAI,EAAOsxD,EAAJtxD,EAAeA,IAC1BvF,KAAK0O,QAAQsvC,iBACdh3B,EAAIwwC,WAAWzwB,EAAMxhC,GAAIyM,EAAGoiD,GAE9BptC,EAAIyB,SAASse,EAAMxhC,GAAIyM,EAAGoiD,GAC1BA,GAASvW,IAMft6C,EAAK6P,UAAU+rD,YAAc,SAASn4C,GACpC,GAAmBzgB,SAAfvG,KAAK0oB,MAAqB,CAC5B1B,EAAIQ,MAAQxnB,KAAKwzC,SAAW,QAAU,IAAMxzC,KAAK0O,QAAQmvC,SAAW,MAAQ79C,KAAK0O,QAAQovC,QAMzF,KAAK,GAJD/W,GAAQ/mC,KAAK0oB,MAAMzgB,MAAM,MACzBwK,GAAUxO,OAAOjE,KAAK0O,QAAQmvC,UAAY,GAAK9W,EAAMrhC,OACrD8M,EAAQ,EAEHjN,EAAI,EAAG27B,EAAO6F,EAAMrhC,OAAYw7B,EAAJ37B,EAAUA,IAC7CiN,EAAQvN,KAAK0H,IAAI6F,EAAOwU,EAAI8vC,YAAY/vB,EAAMxhC,IAAIiN,MAGpD,QAAQA,MAASA,EAAOC,OAAUA,EAAQokD,UAAW9vB,EAAMrhC,QAG3D,OAAQ8M,MAAS,EAAGC,OAAU,EAAGokD,UAAW,IAUhDtzD,EAAK6P,UAAUg9C,OAAS,WACtB,MAAmB7pD,UAAfvG,KAAKwS,MACDxS,KAAKgS,EAAIhS,KAAKwS,MAAOxS,KAAKw2D,iBAAoBx2D,KAAKqkD,cAAcryC,GACjEhS,KAAKgS,EAAIhS,KAAKwS,MAAOxS,KAAKw2D,gBAAoBx2D,KAAKskD,kBAAkBtyC,GACrEhS,KAAKiS,EAAIjS,KAAKyS,OAAOzS,KAAKw2D,iBAAoBx2D,KAAKqkD,cAAcpyC,GACjEjS,KAAKiS,EAAIjS,KAAKyS,OAAOzS,KAAKw2D,gBAAoBx2D,KAAKskD,kBAAkBryC,GAGpE,GAQX1O,EAAK6P,UAAUktD,OAAS,WACtB,MAAQtgE,MAAKgS,GAAKhS,KAAKqkD,cAAcryC,GAC7BhS,KAAKgS,EAAIhS,KAAKskD,kBAAkBtyC,GAChChS,KAAKiS,GAAKjS,KAAKqkD,cAAcpyC,GAC7BjS,KAAKiS,EAAIjS,KAAKskD,kBAAkBryC,GAW1C1O,EAAK6P,UAAU+8C,eAAiB,SAASjzC,EAAMmnC,EAAcC,GAC3DtkD,KAAKw2D,gBAAkB,EAAIt5C,EAC3Bld,KAAKw8D,aAAet/C,EACpBld,KAAKqkD,cAAgBA,EACrBrkD,KAAKskD,kBAAoBA,GAS3B/gD,EAAK6P,UAAUiwB,SAAW,SAASnmB,GACjCld,KAAKw2D,gBAAkB,EAAIt5C,EAC3Bld,KAAKw8D,aAAet/C,GAQtB3Z,EAAK6P,UAAUmtD,cAAgB,WAC7BvgE,KAAK87D,GAAK,EACV97D,KAAK+7D,GAAK,GASZx4D,EAAK6P,UAAUotD,eAAiB,SAASC,GACvC,GAAIC,GAAe1gE,KAAK87D,GAAK97D,KAAK87D,GAAK2E,CAEvCzgE,MAAK87D,GAAK72D,KAAK2qB,KAAK8wC,EAAa1gE,KAAK0O,QAAQ6uC,MAC9CmjB,EAAe1gE,KAAK+7D,GAAK/7D,KAAK+7D,GAAK0E,EAEnCzgE,KAAK+7D,GAAK92D,KAAK2qB,KAAK8wC,EAAa1gE,KAAK0O,QAAQ6uC,OAGhD19C,EAAOD,QAAU2D,GAKb,SAAS1D,GAWb,QAAS2D,GAAMgW,EAAWxH,EAAGC,EAAGuX,EAAMtc,GAElClN,KAAKwZ,UADHA,EACeA,EAGAhI,SAASojB,KAIdruB,SAAV2G,IACe,gBAAN8E,IACT9E,EAAQ8E,EACRA,EAAIzL,QACqB,gBAATijB,IAChBtc,EAAQsc,EACRA,EAAOjjB,QAGP2G,GACE0wC,UAAW,QACXC,SAAU,GACVC,SAAU,UACV1yC,OACEiB,OAAQ,OACRD,WAAY,aAMpBpM,KAAKgS,EAAI,EACThS,KAAKiS,EAAI,EACTjS,KAAKikB,QAAU,EAEL1d,SAANyL,GAAyBzL,SAAN0L,GACrBjS,KAAKkuD,YAAYl8C,EAAGC,GAET1L,SAATijB,GACFxpB,KAAKmuD,QAAQ3kC,GAIfxpB,KAAKuf,MAAQ/N,SAASM,cAAc,MACpC,IAAI6uD,GAAY3gE,KAAKuf,MAAMrS,KAC3ByzD,GAAU98C,SAAW,WACrB88C,EAAUlpC,WAAa,SACvBkpC,EAAUt0D,OAAS,aAAea,EAAM9B,MAAMiB,OAC9Cs0D,EAAUv1D,MAAQ8B,EAAM0wC,UACxB+iB,EAAU9iB,SAAW3wC,EAAM2wC,SAAW,KACtC8iB,EAAUC,WAAa1zD,EAAM4wC,SAC7B6iB,EAAU18C,QAAUjkB,KAAKikB,QAAU,KACnC08C,EAAU/gD,gBAAkB1S,EAAM9B,MAAMgB,WACxCu0D,EAAU1wC,aAAe,MACzB0wC,EAAU5uC,gBAAkB,MAC5B4uC,EAAUE,mBAAqB,MAC/BF,EAAUzwC,UAAY,wCACtBywC,EAAUG,WAAa,SACvB9gE,KAAKwZ,UAAU9H,YAAY1R,KAAKuf,OAOlC/b,EAAM4P,UAAU86C,YAAc,SAASl8C,EAAGC,GACxCjS,KAAKgS,EAAInH,SAASmH,GAClBhS,KAAKiS,EAAIpH,SAASoH,IAOpBzO,EAAM4P,UAAU+6C,QAAU,SAASt+B,GAC7BA,YAAmBqd,UACrBltC,KAAKuf,MAAM2E,UAAY,GACvBlkB,KAAKuf,MAAM7N,YAAYme,IAGvB7vB,KAAKuf,MAAM2E,UAAY2L,GAQ3BrsB,EAAM4P,UAAU80B,KAAO,SAAUA,GAK/B,GAJa3hC,SAAT2hC,IACFA,GAAO,GAGLA,EAAM,CACR,GAAIz1B,GAASzS,KAAKuf,MAAMuF,aACpBtS,EAASxS,KAAKuf,MAAME,YACpBgV,EAAYz0B,KAAKuf,MAAMzV,WAAWgb,aAClCk3B,EAAWh8C,KAAKuf,MAAMzV,WAAW2V,YAEjC7X,EAAO5H,KAAKiS,EAAIQ,CAChB7K,GAAM6K,EAASzS,KAAKikB,QAAUwQ,IAChC7sB,EAAM6sB,EAAYhiB,EAASzS,KAAKikB,SAE9Brc,EAAM5H,KAAKikB,UACbrc,EAAM5H,KAAKikB,QAGb,IAAIzc,GAAOxH,KAAKgS,CACZxK,GAAOgL,EAAQxS,KAAKikB,QAAU+3B,IAChCx0C,EAAOw0C,EAAWxpC,EAAQxS,KAAKikB,SAE7Bzc,EAAOxH,KAAKikB,UACdzc,EAAOxH,KAAKikB,SAGdjkB,KAAKuf,MAAMrS,MAAM1F,KAAOA,EAAO,KAC/BxH,KAAKuf,MAAMrS,MAAMtF,IAAMA,EAAM,KAC7B5H,KAAKuf,MAAMrS,MAAMuqB,WAAa,cAG9Bz3B,MAAKioC,QAOTzkC,EAAM4P,UAAU60B,KAAO,WACrBjoC,KAAKuf,MAAMrS,MAAMuqB,WAAa,UAGhC53B,EAAOD,QAAU4D,GAKb,SAAS3D,EAAQD,GAarB,QAASmhE,GAAUpuD,GAEjB,MADAod,GAAMpd,EACCquD,IAoCT,QAAS1+B,KACPj6B,EAAQ,EACR5H,EAAIsvB,EAAI1K,OAAO,GAQjB,QAASiD,KACPjgB,IACA5H,EAAIsvB,EAAI1K,OAAOhd,GAOjB,QAAS44D,KACP,MAAOlxC,GAAI1K,OAAOhd,EAAQ,GAS5B,QAAS64D,GAAezgE,GACtB,MAAO0gE,GAAkBlzD,KAAKxN,GAShC,QAAS2gE,GAAO97D,EAAGa,GAKjB,GAJKb,IACHA,MAGEa,EACF,IAAK,GAAI+P,KAAQ/P,GACXA,EAAEN,eAAeqQ,KACnB5Q,EAAE4Q,GAAQ/P,EAAE+P,GAIlB,OAAO5Q,GAeT,QAASuS,GAASmL,EAAK0oB,EAAMtkC,GAG3B,IAFA,GAAIiG,GAAOq+B,EAAKzjC,MAAM,KAClBo5D,EAAIr+C,EACD3V,EAAK3H,QAAQ,CAClB,GAAIkD,GAAMyE,EAAKkE,OACXlE,GAAK3H,QAEF27D,EAAEz4D,KACLy4D,EAAEz4D,OAEJy4D,EAAIA,EAAEz4D,IAINy4D,EAAEz4D,GAAOxB,GAWf,QAASk6D,GAAQpwC,EAAOi1B,GAOtB,IANA,GAAI5gD,GAAGC,EACHu0B,EAAU,KAGVwnC,GAAUrwC,GACVxxB,EAAOwxB,EACJxxB,EAAKylC,QACVo8B,EAAOr5D,KAAKxI,EAAKylC,QACjBzlC,EAAOA,EAAKylC,MAId,IAAIzlC,EAAK49C,MACP,IAAK/3C,EAAI,EAAGC,EAAM9F,EAAK49C,MAAM53C,OAAYF,EAAJD,EAASA,IAC5C,GAAI4gD,EAAK9lD,KAAOX,EAAK49C,MAAM/3C,GAAGlF,GAAI,CAChC05B,EAAUr6B,EAAK49C,MAAM/3C,EACrB,OAiBN,IAZKw0B,IAEHA,GACE15B,GAAI8lD,EAAK9lD,IAEP6wB,EAAMi1B,OAERpsB,EAAQynC,KAAOJ,EAAMrnC,EAAQynC,KAAMtwC,EAAMi1B,QAKxC5gD,EAAIg8D,EAAO77D,OAAS,EAAGH,GAAK,EAAGA,IAAK,CACvC,GAAIoF,GAAI42D,EAAOh8D,EAEVoF,GAAE2yC,QACL3yC,EAAE2yC,UAE4B,IAA5B3yC,EAAE2yC,MAAM52C,QAAQqzB,IAClBpvB,EAAE2yC,MAAMp1C,KAAK6xB,GAKbosB,EAAKqb,OACPznC,EAAQynC,KAAOJ,EAAMrnC,EAAQynC,KAAMrb,EAAKqb,OAS5C,QAASC,GAAQvwC,EAAO68B,GAKtB,GAJK78B,EAAMktB,QACTltB,EAAMktB,UAERltB,EAAMktB,MAAMl2C,KAAK6lD,GACb78B,EAAM68B,KAAM,CACd,GAAIyT,GAAOJ,KAAUlwC,EAAM68B,KAC3BA,GAAKyT,KAAOJ,EAAMI,EAAMzT,EAAKyT,OAajC,QAASE,GAAWxwC,EAAO7H,EAAMC,EAAIziB,EAAM26D,GACzC,GAAIzT,IACF1kC,KAAMA,EACNC,GAAIA,EACJziB,KAAMA,EAQR,OALIqqB,GAAM68B,OACRA,EAAKyT,KAAOJ,KAAUlwC,EAAM68B,OAE9BA,EAAKyT,KAAOJ,EAAMrT,EAAKyT,SAAYA,GAE5BzT,EAOT,QAAS4T,KAKP,IAJAC,EAAYC,EAAUC,KACtBC,EAAQ,GAGI,KAALthE,GAAiB,KAALA,GAAkB,MAALA,GAAkB,MAALA,GAC3C6nB,GAGF,GAAG,CACD,GAAI05C,IAAY,CAGhB,IAAS,KAALvhE,EAAU,CAGZ,IADA,GAAI8E,GAAI8C,EAAQ,EACQ,KAAjB0nB,EAAI1K,OAAO9f,IAA8B,KAAjBwqB,EAAI1K,OAAO9f,IACxCA,GAEF,IAAqB,MAAjBwqB,EAAI1K,OAAO9f,IAA+B,IAAjBwqB,EAAI1K,OAAO9f,GAAU,CAEhD,KAAY,IAAL9E,GAAgB,MAALA,GAChB6nB,GAEF05C,IAAY,GAGhB,GAAS,KAALvhE,GAA6B,KAAjBwgE,IAAsB,CAEpC,KAAY,IAALxgE,GAAgB,MAALA,GAChB6nB,GAEF05C,IAAY,EAEd,GAAS,KAALvhE,GAA6B,KAAjBwgE,IAAsB,CAEpC,KAAY,IAALxgE,GAAS,CACd,GAAS,KAALA,GAA6B,KAAjBwgE,IAAsB,CAEpC34C,IACAA,GACA,OAGAA,IAGJ05C,GAAY,EAId,KAAY,KAALvhE,GAAiB,KAALA,GAAkB,MAALA,GAAkB,MAALA,GAC3C6nB,UAGG05C,EAGP,IAAS,IAALvhE,EAGF,YADAmhE,EAAYC,EAAUI,UAKxB,IAAIC,GAAKzhE,EAAIwgE,GACb,IAAIkB,EAAWD,GAKb,MAJAN,GAAYC,EAAUI,UACtBF,EAAQG,EACR55C,QACAA,IAKF,IAAI65C,EAAW1hE,GAIb,MAHAmhE,GAAYC,EAAUI,UACtBF,EAAQthE,MACR6nB,IAMF,IAAI44C,EAAezgE,IAAW,KAALA,EAAU,CAIjC,IAHAshE,GAASthE,EACT6nB,IAEO44C,EAAezgE,IACpBshE,GAASthE,EACT6nB,GAYF,OAVa,SAATy5C,EACFA,GAAQ,EAEQ,QAATA,EACPA,GAAQ,EAEAt9D,MAAMR,OAAO89D,MACrBA,EAAQ99D,OAAO89D,SAEjBH,EAAYC,EAAUO,YAKxB,GAAS,KAAL3hE,EAAU,CAEZ,IADA6nB,IACY,IAAL7nB,IAAiB,KAALA,GAAkB,KAALA,GAA6B,KAAjBwgE,MAC1Cc,GAASthE,EACA,KAALA,GACF6nB,IAEFA,GAEF,IAAS,KAAL7nB,EACF,KAAM4hE,GAAe,2BAIvB,OAFA/5C,UACAs5C,EAAYC,EAAUO,YAMxB,IADAR,EAAYC,EAAUS,QACV,IAAL7hE,GACLshE,GAASthE,EACT6nB,GAEF,MAAM,IAAI7O,aAAY,yBAA2B8oD,EAAKR,EAAO,IAAM,KAOrE,QAASf,KACP,GAAI9vC,KAwBJ,IAtBAoR,IACAq/B,IAGa,UAATI,IACF7wC,EAAMsxC,QAAS,EACfb,MAIW,SAATI,GAA6B,WAATA,KACtB7wC,EAAMrqB,KAAOk7D,EACbJ,KAIEC,GAAaC,EAAUO,aACzBlxC,EAAM7wB,GAAK0hE,EACXJ,KAIW,KAATI,EACF,KAAMM,GAAe,2BAQvB,IANAV,IAGAc,EAAgBvxC,GAGH,KAAT6wC,EACF,KAAMM,GAAe,2BAKvB,IAHAV,IAGc,KAAVI,EACF,KAAMM,GAAe,uBASvB,OAPAV,WAGOzwC,GAAMi1B,WACNj1B,GAAM68B,WACN78B,GAAMA,MAENA,EAOT,QAASuxC,GAAiBvxC,GACxB,KAAiB,KAAV6wC,GAAyB,KAATA,GACrBW,EAAexxC,GACF,KAAT6wC,GACFJ,IAWN,QAASe,GAAexxC,GAEtB,GAAIyxC,GAAWC,EAAc1xC,EAC7B,IAAIyxC,EAIF,WAFAE,GAAU3xC,EAAOyxC,EAMnB,IAAInB,GAAOsB,EAAwB5xC,EACnC,KAAIswC,EAAJ,CAKA,GAAII,GAAaC,EAAUO,WACzB,KAAMC,GAAe,sBAEvB,IAAIhiE,GAAK0hE,CAGT,IAFAJ,IAEa,KAATI,EAAc,CAGhB,GADAJ,IACIC,GAAaC,EAAUO,WACzB,KAAMC,GAAe,sBAEvBnxC,GAAM7wB,GAAM0hE,EACZJ,QAIAoB,GAAmB7xC,EAAO7wB,IAS9B,QAASuiE,GAAe1xC,GACtB,GAAIyxC,GAAW,IAgBf,IAba,YAATZ,IACFY,KACAA,EAAS97D,KAAO,WAChB86D,IAGIC,GAAaC,EAAUO,aACzBO,EAAStiE,GAAK0hE,EACdJ,MAKS,KAATI,EAAc,CAehB,GAdAJ,IAEKgB,IACHA,MAEFA,EAASx9B,OAASjU,EAClByxC,EAASxc,KAAOj1B,EAAMi1B,KACtBwc,EAAS5U,KAAO78B,EAAM68B,KACtB4U,EAASzxC,MAAQA,EAAMA,MAGvBuxC,EAAgBE,GAGH,KAATZ,EACF,KAAMM,GAAe,2BAEvBV,WAGOgB,GAASxc,WACTwc,GAAS5U,WACT4U,GAASzxC,YACTyxC,GAASx9B,OAGXjU,EAAM8xC,YACT9xC,EAAM8xC,cAER9xC,EAAM8xC,UAAU96D,KAAKy6D,GAGvB,MAAOA,GAYT,QAASG,GAAyB5xC,GAEhC,MAAa,QAAT6wC,GACFJ,IAGAzwC,EAAMi1B,KAAO8c,IACN,QAES,QAATlB,GACPJ,IAGAzwC,EAAM68B,KAAOkV,IACN,QAES,SAATlB,GACPJ,IAGAzwC,EAAMA,MAAQ+xC,IACP,SAGF,KAQT,QAASF,GAAmB7xC,EAAO7wB,GAEjC,GAAI8lD,IACF9lD,GAAIA,GAEFmhE,EAAOyB,GACPzB,KACFrb,EAAKqb,KAAOA,GAEdF,EAAQpwC,EAAOi1B,GAGf0c,EAAU3xC,EAAO7wB,GAQnB,QAASwiE,GAAU3xC,EAAO7H,GACxB,KAAgB,MAAT04C,GAA0B,MAATA,GAAe,CACrC,GAAIz4C,GACAziB,EAAOk7D,CACXJ,IAEA,IAAIgB,GAAWC,EAAc1xC,EAC7B,IAAIyxC,EACFr5C,EAAKq5C,MAEF,CACH,GAAIf,GAAaC,EAAUO,WACzB,KAAMC,GAAe,kCAEvB/4C,GAAKy4C,EACLT,EAAQpwC,GACN7wB,GAAIipB,IAENq4C,IAIF,GAAIH,GAAOyB,IAGPlV,EAAO2T,EAAWxwC,EAAO7H,EAAMC,EAAIziB,EAAM26D,EAC7CC,GAAQvwC,EAAO68B,GAEf1kC,EAAOC,GASX,QAAS25C,KAGP,IAFA,GAAIzB,GAAO,KAEK,KAATO,GAAc,CAGnB,IAFAJ,IACAH,KACiB,KAAVO,GAAyB,KAATA,GAAc,CACnC,GAAIH,GAAaC,EAAUO,WACzB,KAAMC,GAAe,0BAEvB,IAAInsD,GAAO6rD,CAGX,IADAJ,IACa,KAATI,EACF,KAAMM,GAAe,wBAIvB,IAFAV,IAEIC,GAAaC,EAAUO,WACzB,KAAMC,GAAe,2BAEvB,IAAIj7D,GAAQ26D,CACZlqD,GAAS2pD,EAAMtrD,EAAM9O,GAErBu6D,IACY,KAARI,GACFJ,IAIJ,GAAa,KAATI,EACF,KAAMM,GAAe,qBAEvBV,KAGF,MAAOH,GAQT,QAASa,GAAea,GACtB,MAAO,IAAIzpD,aAAYypD,EAAU,UAAYX,EAAKR,EAAO,IAAM,WAAa15D,EAAQ,KAStF,QAASk6D,GAAM/4C,EAAM25C,GACnB,MAAQ35C,GAAK9jB,QAAUy9D,EAAa35C,EAAQA,EAAKje,OAAO,EAAG,IAAM,MASnE,QAAS63D,GAASC,EAAQC,EAAQnqD,GAC5BnT,MAAMC,QAAQo9D,GAChBA,EAAO96D,QAAQ,SAAUg7D,GACnBv9D,MAAMC,QAAQq9D,GAChBA,EAAO/6D,QAAQ,SAAUi7D,GACvBrqD,EAAGoqD,EAAOC,KAIZrqD,EAAGoqD,EAAOD,KAKVt9D,MAAMC,QAAQq9D,GAChBA,EAAO/6D,QAAQ,SAAUi7D,GACvBrqD,EAAGkqD,EAAQG,KAIbrqD,EAAGkqD,EAAQC,GAWjB,QAAS5b,GAAY/0C,GAEnB,GAAI80C,GAAUsZ,EAASpuD,GACnB8wD,GACFnmB,SACAc,SACA1vC,WAmBF,IAfI+4C,EAAQnK,OACVmK,EAAQnK,MAAM/0C,QAAQ,SAAUm7D,GAC9B,GAAIC,IACFtjE,GAAIqjE,EAAQrjE,GACZqoB,MAAOvkB,OAAOu/D,EAAQh7C,OAASg7C,EAAQrjE,IAEzC+gE,GAAMuC,EAAWD,EAAQlC,MACrBmC,EAAUhmB,QACZgmB,EAAUjmB,MAAQ,SAEpB+lB,EAAUnmB,MAAMp1C,KAAKy7D,KAKrBlc,EAAQrJ,MAAO,CAMjB,GAAIwlB,GAAc,SAAUC,GAC1B,GAAIC,IACFz6C,KAAMw6C,EAAQx6C,KACdC,GAAIu6C,EAAQv6C,GAId,OAFA83C,GAAM0C,EAAWD,EAAQrC,MACzBsC,EAAU52D,MAAyB,MAAhB22D,EAAQh9D,KAAgB,QAAU,OAC9Ci9D,EAGTrc,GAAQrJ,MAAM71C,QAAQ,SAAUs7D,GAC9B,GAAIx6C,GAAMC,CAERD,GADEw6C,EAAQx6C,eAAgB/iB,QACnBu9D,EAAQx6C,KAAKi0B,OAIlBj9C,GAAIwjE,EAAQx6C,MAKdC,EADEu6C,EAAQv6C,aAAchjB,QACnBu9D,EAAQv6C,GAAGg0B,OAIdj9C,GAAIwjE,EAAQv6C,IAIZu6C,EAAQx6C,eAAgB/iB,SAAUu9D,EAAQx6C,KAAK+0B,OACjDylB,EAAQx6C,KAAK+0B,MAAM71C,QAAQ,SAAUw7D,GACnC,GAAID,GAAYF,EAAYG,EAC5BN,GAAUrlB,MAAMl2C,KAAK47D,KAIzBV,EAAS/5C,EAAMC,EAAI,SAAUD,EAAMC,GACjC,GAAIy6C,GAAUrC,EAAW+B,EAAWp6C,EAAKhpB,GAAIipB,EAAGjpB,GAAIwjE,EAAQh9D,KAAMg9D,EAAQrC,MACtEsC,EAAYF,EAAYG,EAC5BN,GAAUrlB,MAAMl2C,KAAK47D,KAGnBD,EAAQv6C,aAAchjB,SAAUu9D,EAAQv6C,GAAG80B,OAC7CylB,EAAQv6C,GAAG80B,MAAM71C,QAAQ,SAAUw7D,GACjC,GAAID,GAAYF,EAAYG,EAC5BN,GAAUrlB,MAAMl2C,KAAK47D,OAW7B,MAJIrc,GAAQ+Z,OACViC,EAAU/0D,QAAU+4C,EAAQ+Z,MAGvBiC,EAnyBT,GAAI5B,IACFC,KAAO,EACPG,UAAY,EACZG,WAAY,EACZE,QAAU,GAIRH,GACF6B,KAAK,EACLC,KAAK,EACLC,KAAK,EACLC,KAAK,EACLC,KAAK,EACLC,KAAK,EACLC,KAAK,EAELC,MAAM,EACNC,MAAM,GAGJz0C,EAAM,GACN1nB,EAAQ,EACR5H,EAAI,GACJshE,EAAQ,GACRH,EAAYC,EAAUC,KAmCtBX,EAAoB,iBA2uBxBvhE,GAAQmhE,SAAWA,EACnBnhE,EAAQ8nD,WAAaA,GAKjB,SAAS7nD,EAAQD,GAGrB,QAASioD,GAAW4c,EAAW/1D,GAC7B,GAAI0vC,MACAd,IACJt9C,MAAK0O,SACH0vC,OACEQ,cAAc,GAEhBtB,OACEonB,eAAe,EACfv5D,YAAY,IAIA5E,SAAZmI,IACF1O,KAAK0O,QAAQ4uC,MAAqB,cAAI5uC,EAAQg2D,eAAgB,EAC9D1kE,KAAK0O,QAAQ4uC,MAAkB,WAAO5uC,EAAQvD,YAAgB,EAC9DnL,KAAK0O,QAAQ0vC,MAAoB,aAAK1vC,EAAQkwC,cAAgB,EAKhE,KAAK,GAFD+lB,GAASF,EAAUrmB,MACnBwmB,EAASH,EAAUnnB,MACd/3C,EAAI,EAAGA,EAAIo/D,EAAOj/D,OAAQH,IAAK,CACtC,GAAIwoD,MACA8W,EAAQF,EAAOp/D,EACnBwoD,GAAS,GAAI8W,EAAMxkE,GACnB0tD,EAAW,KAAI8W,EAAMC,OACrB/W,EAAS,GAAI8W,EAAMl7D,OACnBokD,EAAiB,WAAI8W,EAAMtpB,WAG3BwS,EAAY,MAAI8W,EAAMz5D,MACtB2iD,EAAmB,aAAsBxnD,SAAlBwnD,EAAY,OAAkB,EAAQ/tD,KAAK0O,QAAQkwC,aAC1ER,EAAMl2C,KAAK6lD,GAGb,IAAK,GAAIxoD,GAAI,EAAGA,EAAIq/D,EAAOl/D,OAAQH,IAAK,CACtC,GAAI4gD,MACA4e,EAAQH,EAAOr/D,EACnB4gD,GAAS,GAAI4e,EAAM1kE,GACnB8lD,EAAiB,WAAI4e,EAAMxpB,WAC3B4K,EAAQ,EAAI4e,EAAM/yD,EAClBm0C,EAAQ,EAAI4e,EAAM9yD,EAClBk0C,EAAY,MAAI4e,EAAMr8C,MAEpBy9B,EAAY,MADuB,GAAjCnmD,KAAK0O,QAAQ4uC,MAAMnyC,WACL45D,EAAM35D,MAGU7E,SAAhBw+D,EAAM35D,OAAuBgB,WAAW24D,EAAM35D,MAAOiB,OAAO04D,EAAM35D,OAAS7E,OAE7F4/C,EAAa,OAAI4e,EAAMzyD,KACvB6zC,EAAqB,eAAInmD,KAAK0O,QAAQ4uC,MAAMonB,cAC5Cve,EAAqB,eAAInmD,KAAK0O,QAAQ4uC,MAAMonB,cAC5CpnB,EAAMp1C,KAAKi+C,GAGb,OAAQ7I,MAAMA,EAAOc,MAAMA,GAG7Bx+C,EAAQioD,WAAaA,GAIjB,SAAShoD,EAAQD,EAASM,GAI9BL,EAAOD,QAA6B,mBAAX6H,SAA2BA,OAAe,QAAKvH,EAAoB,KAKxF,SAASL,EAAQD,EAASM,GAK5BL,EAAOD,QADa,mBAAX6H,QACQA,OAAe,QAAKvH,EAAoB,IAGxC,WACf,KAAM0D,OAAM,+DAOZ,SAAS/D,EAAQD,EAASM,GAmB9B,QAASi2B,MAjBT,GAAInZ,GAAU9c,EAAoB,IAC9B2lC,EAAS3lC,EAAoB,IAC7BS,EAAOT,EAAoB,GAK3BylD,GAJUzlD,EAAoB,GACnBA,EAAoB,GACvBA,EAAoB,IAClBA,EAAoB,IAClBA,EAAoB,KAChCyB,EAAWzB,EAAoB,GAYnC8c,GAAQmZ,EAAK/iB,WASb+iB,EAAK/iB,UAAUuhB,QAAU,SAAUnb,GACjCxZ,KAAKgwB,OAELhwB,KAAKgwB,IAAItwB,KAAuB8R,SAASM,cAAc,OACvD9R,KAAKgwB,IAAI5jB,WAAuBoF,SAASM,cAAc,OACvD9R,KAAKgwB,IAAIoV,mBAAuB5zB,SAASM,cAAc,OACvD9R,KAAKgwB,IAAIyY,qBAAuBj3B,SAASM,cAAc,OACvD9R,KAAKgwB,IAAI8H,gBAAuBtmB,SAASM,cAAc,OACvD9R,KAAKgwB,IAAIg1C,cAAuBxzD,SAASM,cAAc,OACvD9R,KAAKgwB,IAAIi1C,eAAuBzzD,SAASM,cAAc,OACvD9R,KAAKgwB,IAAI7D,OAAuB3a,SAASM,cAAc,OACvD9R,KAAKgwB,IAAIxoB,KAAuBgK,SAASM,cAAc,OACvD9R,KAAKgwB,IAAI1I,MAAuB9V,SAASM,cAAc,OACvD9R,KAAKgwB,IAAIpoB,IAAuB4J,SAASM,cAAc,OACvD9R,KAAKgwB,IAAIzM,OAAuB/R,SAASM,cAAc,OACvD9R,KAAKgwB,IAAIk1C,UAAuB1zD,SAASM,cAAc,OACvD9R,KAAKgwB,IAAIm1C,aAAuB3zD,SAASM,cAAc,OACvD9R,KAAKgwB,IAAIo1C,cAAuB5zD,SAASM,cAAc,OACvD9R,KAAKgwB,IAAIq1C,iBAAuB7zD,SAASM,cAAc,OACvD9R,KAAKgwB,IAAIs1C,eAAuB9zD,SAASM,cAAc,OACvD9R,KAAKgwB,IAAIu1C,kBAAuB/zD,SAASM,cAAc,OAEvD9R,KAAKgwB,IAAItwB,KAAKqI,UAA4B,oBAC1C/H,KAAKgwB,IAAI5jB,WAAWrE,UAAsB,sBAC1C/H,KAAKgwB,IAAIoV,mBAAmBr9B,UAAc,+BAC1C/H,KAAKgwB,IAAIyY,qBAAqB1gC,UAAY,iCAC1C/H,KAAKgwB,IAAI8H,gBAAgB/vB,UAAiB,kBAC1C/H,KAAKgwB,IAAIg1C,cAAcj9D,UAAmB,gBAC1C/H,KAAKgwB,IAAIi1C,eAAel9D,UAAkB,iBAC1C/H,KAAKgwB,IAAIpoB,IAAIG,UAA6B,eAC1C/H,KAAKgwB,IAAIzM,OAAOxb,UAA0B,kBAC1C/H,KAAKgwB,IAAIxoB,KAAKO,UAA4B,UAC1C/H,KAAKgwB,IAAI7D,OAAOpkB,UAA0B,UAC1C/H,KAAKgwB,IAAI1I,MAAMvf,UAA2B,UAC1C/H,KAAKgwB,IAAIk1C,UAAUn9D,UAAuB,aAC1C/H,KAAKgwB,IAAIm1C,aAAap9D,UAAoB,gBAC1C/H,KAAKgwB,IAAIo1C,cAAcr9D,UAAmB,aAC1C/H,KAAKgwB,IAAIq1C,iBAAiBt9D,UAAgB,gBAC1C/H,KAAKgwB,IAAIs1C,eAAev9D,UAAkB,aAC1C/H,KAAKgwB,IAAIu1C,kBAAkBx9D,UAAe,gBAE1C/H,KAAKgwB,IAAItwB,KAAKgS,YAAY1R,KAAKgwB,IAAI5jB,YACnCpM,KAAKgwB,IAAItwB,KAAKgS,YAAY1R,KAAKgwB,IAAIoV,oBACnCplC,KAAKgwB,IAAItwB,KAAKgS,YAAY1R,KAAKgwB,IAAIyY,sBACnCzoC,KAAKgwB,IAAItwB,KAAKgS,YAAY1R,KAAKgwB,IAAI8H,iBACnC93B,KAAKgwB,IAAItwB,KAAKgS,YAAY1R,KAAKgwB,IAAIg1C,eACnChlE,KAAKgwB,IAAItwB,KAAKgS,YAAY1R,KAAKgwB,IAAIi1C,gBACnCjlE,KAAKgwB,IAAItwB,KAAKgS,YAAY1R,KAAKgwB,IAAIpoB,KACnC5H,KAAKgwB,IAAItwB,KAAKgS,YAAY1R,KAAKgwB,IAAIzM,QAEnCvjB,KAAKgwB,IAAI8H,gBAAgBpmB,YAAY1R,KAAKgwB,IAAI7D,QAC9CnsB,KAAKgwB,IAAIg1C,cAActzD,YAAY1R,KAAKgwB,IAAIxoB,MAC5CxH,KAAKgwB,IAAIi1C,eAAevzD,YAAY1R,KAAKgwB,IAAI1I,OAE7CtnB,KAAKgwB,IAAI8H,gBAAgBpmB,YAAY1R,KAAKgwB,IAAIk1C,WAC9CllE,KAAKgwB,IAAI8H,gBAAgBpmB,YAAY1R,KAAKgwB,IAAIm1C,cAC9CnlE,KAAKgwB,IAAIg1C,cAActzD,YAAY1R,KAAKgwB,IAAIo1C,eAC5CplE,KAAKgwB,IAAIg1C,cAActzD,YAAY1R,KAAKgwB,IAAIq1C,kBAC5CrlE,KAAKgwB,IAAIi1C,eAAevzD,YAAY1R,KAAKgwB,IAAIs1C,gBAC7CtlE,KAAKgwB,IAAIi1C,eAAevzD,YAAY1R,KAAKgwB,IAAIu1C,mBAE7CvlE,KAAKwT,GAAG,cAAexT,KAAK0hB,OAAOqT,KAAK/0B,OACxCA,KAAKwT,GAAG,QAASxT,KAAKs+B,SAASvJ,KAAK/0B,OACpCA,KAAKwT,GAAG,QAASxT,KAAKu+B,SAASxJ,KAAK/0B,OACpCA,KAAKwT,GAAG,YAAaxT,KAAKi+B,aAAalJ,KAAK/0B,OAC5CA,KAAKwT,GAAG,OAAQxT,KAAKk+B,QAAQnJ,KAAK/0B,MAElC,IAAIoU,GAAKpU,IACTA,MAAKwT,GAAG,SAAU,SAAUw7C,GACtBA,GAAkC,GAApBA,EAAW37C,MAEtBe,EAAGoxD,eACNpxD,EAAGoxD,aAAejsD,WAAW,WAC3BnF,EAAGoxD,aAAe,KAClBpxD,EAAGsN,UACF,IAKLtN,EAAGsN,WAMP1hB,KAAK8D,OAAS+hC,EAAO7lC,KAAKgwB,IAAItwB,MAC5B6J,gBAAgB,IAElBvJ,KAAKylE,YAEL,IAAIC,IACF,QAAS,QACT,MAAO,YAAa,OACpB,YAAa,OAAQ,UACrB,aAAc,iBAkChB,IAhCAA,EAAOn9D,QAAQ,SAAUiB,GACvB,GAAIR,GAAW,WACb,GAAIkQ,IAAQ1P,GAAOyK,OAAOjO,MAAMoN,UAAUlI,MAAM3K,KAAKkF,UAAW,GAC5D2O,GAAG01C,YACL11C,EAAGyZ,KAAK7V,MAAM5D,EAAI8E,GAGtB9E,GAAGtQ,OAAO0P,GAAGhK,EAAOR,GACpBoL,EAAGqxD,UAAUj8D,GAASR,IAIxBhJ,KAAK+F,OACHrG,QACA0M,cACA0rB,mBACAktC,iBACAC,kBACA94C,UACA3kB,QACA8f,SACA1f,OACA2b,UACAlX,UACAu7B,UAAW,EACX+9B,aAAc,GAEhB3lE,KAAK+9B,SAEL/9B,KAAK4lE,YAAc,GAGdpsD,EAAW,KAAM,IAAI5V,OAAM,wBAChC4V,GAAU9H,YAAY1R,KAAKgwB,IAAItwB,OA4BjCy2B,EAAK/iB,UAAUD,WAAa,SAAUzE,GACpC,GAAIA,EAAS,CAEX,GAAIP,IAAU,QAAS,SAAU,YAAa,YAAa,aAAc,QAAS,MAAO,cAAe,aAAc,iBAAkB,cACxIxN,GAAKmF,gBAAgBqI,EAAQnO,KAAK0O,QAASA,GAEvC,eAAiB1O,MAAK0O,SACxB/M,EAAS+1B,qBAAqB13B,KAAK40B,KAAM50B,KAAK0O,QAAQsmB,aAGpD,cAAgBtmB,KACdA,EAAQg6C,WACL1oD,KAAK2oD,YACR3oD,KAAK2oD,UAAY,GAAIhD,GAAU3lD,KAAKgwB,IAAItwB,OAItCM,KAAK2oD,YACP3oD,KAAK2oD,UAAUp1C,gBACRvT,MAAK2oD,YAMlB3oD,KAAK6lE,kBASP,GALA7lE,KAAKgC,WAAWuG,QAAQ,SAAUu9D,GAChCA,EAAU3yD,WAAWzE,KAInBA,GAAWA,EAAQgH,MACrB,KAAM,IAAI9R,OAAM,wEAIlB5D,MAAK0hB,UAOPyU,EAAK/iB,UAAU02C,SAAW,WACxB,OAAQ9pD,KAAK2oD,WAAa3oD,KAAK2oD,UAAUgL,QAM3Cx9B,EAAK/iB,UAAUG,QAAU,WAEvBvT,KAAK0W,QAGL1W,KAAK2T,MAGL3T,KAAK+lE,kBAGD/lE,KAAKgwB,IAAItwB,KAAKoK,YAChB9J,KAAKgwB,IAAItwB,KAAKoK,WAAWsH,YAAYpR,KAAKgwB,IAAItwB,MAEhDM,KAAKgwB,IAAM,KAGPhwB,KAAK2oD,YACP3oD,KAAK2oD,UAAUp1C,gBACRvT,MAAK2oD,UAId,KAAK,GAAIn/C,KAASxJ,MAAKylE,UACjBzlE,KAAKylE,UAAU5/D,eAAe2D,UACzBxJ,MAAKylE,UAAUj8D,EAG1BxJ,MAAKylE,UAAY,KACjBzlE,KAAK8D,OAAS,KAGd9D,KAAKgC,WAAWuG,QAAQ,SAAUu9D,GAChCA,EAAUvyD,YAGZvT,KAAK40B,KAAO,MAQduB,EAAK/iB,UAAU4yB,cAAgB,SAAU5L,GACvC,IAAKp6B,KAAK61B,WACR,KAAM,IAAIjyB,OAAM,yDAGlB5D,MAAK61B,WAAWmQ,cAAc5L,IAOhCjE,EAAK/iB,UAAU6yB,cAAgB,WAC7B,IAAKjmC,KAAK61B,WACR,KAAM,IAAIjyB,OAAM,yDAGlB,OAAO5D,MAAK61B,WAAWoQ,iBAQzB9P,EAAK/iB,UAAUs+B,gBAAkB,WAC/B,MAAO1xC,MAAK81B,SAAW91B,KAAK81B,QAAQ4b,uBAetCvb,EAAK/iB,UAAUsD,MAAQ,SAASsvD,KAEzBA,GAAQA,EAAK/jE,QAChBjC,KAAKk2B,SAAS,QAIX8vC,GAAQA,EAAK5xC,SAChBp0B,KAAKi2B,UAAU,QAIZ+vC,GAAQA,EAAKt3D,WAChB1O,KAAKgC,WAAWuG,QAAQ,SAAUu9D,GAChCA,EAAU3yD,WAAW2yD,EAAUxxC,kBAGjCt0B,KAAKmT,WAAWnT,KAAKs0B,kBAazB6B,EAAK/iB,UAAUsjB,IAAM,SAAShoB,GAC5B,GAAIgnB,GAAQ11B,KAAKu2B,eAGjB,IAAoB,OAAhBb,EAAM7lB,OAAgC,OAAd6lB,EAAM5lB,IAAlC,CAIA,GAAI2mB,GAAW/nB,GAA+BnI,SAApBmI,EAAQ+nB,QAAyB/nB,EAAQ+nB,SAAU,CAC7Ez2B,MAAK01B,MAAMlC,SAASkC,EAAM7lB,MAAO6lB,EAAM5lB,IAAK2mB,KAQ9CN,EAAK/iB,UAAUmjB,cAAgB,WAE7B,GAAID,GAAYt2B,KAAKg3B,eAGjBnnB,EAAQymB,EAAUvqB,IAClB+D,EAAMwmB,EAAU3pB,GACpB,IAAa,MAATkD,GAAwB,MAAPC,EAAa,CAChC,GAAI2iB,GAAY3iB,EAAI/I,UAAY8I,EAAM9I,SACtB,IAAZ0rB,IAEFA,EAAW,OAEb5iB,EAAQ,GAAIxL,MAAKwL,EAAM9I,UAAuB,IAAX0rB,GACnC3iB,EAAM,GAAIzL,MAAKyL,EAAI/I,UAAuB,IAAX0rB,GAGjC,OACE5iB,MAAOA,EACPC,IAAKA,IAuBTqmB,EAAK/iB,UAAUojB,UAAY,SAAS3mB,EAAOC,EAAKpB,GAC9C,GAAI+nB,GAAW/nB,GAA+BnI,SAApBmI,EAAQ+nB,QAAyB/nB,EAAQ+nB,SAAU,CAC7E,IAAwB,GAApBhxB,UAAUC,OAAa,CACzB,GAAIgwB,GAAQjwB,UAAU,EACtBzF,MAAK01B,MAAMlC,SAASkC,EAAM7lB,MAAO6lB,EAAM5lB,IAAK2mB,OAG5Cz2B,MAAK01B,MAAMlC,SAAS3jB,EAAOC,EAAK2mB,IAcpCN,EAAK/iB,UAAU0U,OAAS,SAASsS,EAAM1rB,GACrC,GAAI+jB,GAAWzyB,KAAK01B,MAAM5lB,IAAM9P,KAAK01B,MAAM7lB,MACvC9B,EAAIpN,EAAKiG,QAAQwzB,EAAM,QAAQrzB,UAE/B8I,EAAQ9B,EAAI0kB,EAAW,EACvB3iB,EAAM/B,EAAI0kB,EAAW,EACrBgE,EAAW/nB,GAA+BnI,SAApBmI,EAAQ+nB,QAAyB/nB,EAAQ+nB,SAAU,CAE7Ez2B,MAAK01B,MAAMlC,SAAS3jB,EAAOC,EAAK2mB,IAOlCN,EAAK/iB,UAAU6yD,UAAY,WACzB,GAAIvwC,GAAQ11B,KAAK01B,MAAM8J,UACvB,QACE3vB,MAAO,GAAIxL,MAAKqxB,EAAM7lB,OACtBC,IAAK,GAAIzL,MAAKqxB,EAAM5lB,OAQxBqmB,EAAK/iB,UAAUsO,OAAS,WACtB,GAAIojB,IAAU,EACVp2B,EAAU1O,KAAK0O,QACf3I,EAAQ/F,KAAK+F,MACbiqB,EAAMhwB,KAAKgwB,GAEf,IAAKA,EAAL,CAEAruB,EAASk2B,kBAAkB73B,KAAK40B,KAAM50B,KAAK0O,QAAQsmB,aAGxB,OAAvBtmB,EAAQ8lB,aACV7zB,EAAKmH,aAAakoB,EAAItwB,KAAM,OAC5BiB,EAAKyH,gBAAgB4nB,EAAItwB,KAAM,YAG/BiB,EAAKyH,gBAAgB4nB,EAAItwB,KAAM,OAC/BiB,EAAKmH,aAAakoB,EAAItwB,KAAM,WAI9BswB,EAAItwB,KAAKwN,MAAMunB,UAAY9zB,EAAKoJ,OAAOK,OAAOsE,EAAQ+lB,UAAW,IACjEzE,EAAItwB,KAAKwN,MAAMwnB,UAAY/zB,EAAKoJ,OAAOK,OAAOsE,EAAQgmB,UAAW,IACjE1E,EAAItwB,KAAKwN,MAAMsF,MAAQ7R,EAAKoJ,OAAOK,OAAOsE,EAAQ8D,MAAO,IAGzDzM,EAAMsG,OAAO7E,MAAUwoB,EAAI8H,gBAAgBzH,YAAcL,EAAI8H,gBAAgBrY,aAAe,EAC5F1Z,EAAMsG,OAAOib,MAASvhB,EAAMsG,OAAO7E,KACnCzB,EAAMsG,OAAOzE,KAAUooB,EAAI8H,gBAAgBvH,aAAeP,EAAI8H,gBAAgBhT,cAAgB,EAC9F/e,EAAMsG,OAAOkX,OAASxd,EAAMsG,OAAOzE,GACnC,IAAIs+D,GAAkBl2C,EAAItwB,KAAK6wB,aAAeP,EAAItwB,KAAKolB,aACnDqhD,EAAkBn2C,EAAItwB,KAAK2wB,YAAcL,EAAItwB,KAAK+f,WAIb,KAArCuQ,EAAI8H,gBAAgBhT,eACtB/e,EAAMsG,OAAO7E,KAAOzB,EAAMsG,OAAOzE,IACjC7B,EAAMsG,OAAOib,MAASvhB,EAAMsG,OAAO7E,MAEP,IAA1BwoB,EAAItwB,KAAKolB,eACXqhD,EAAkBD,GAKpBngE,EAAMomB,OAAO1Z,OAASud,EAAI7D,OAAOoE,aACjCxqB,EAAMyB,KAAKiL,OAAWud,EAAIxoB,KAAK+oB,aAC/BxqB,EAAMuhB,MAAM7U,OAAUud,EAAI1I,MAAMiJ,aAChCxqB,EAAM6B,IAAI6K,OAAYud,EAAIpoB,IAAIkd,eAAoB/e,EAAMsG,OAAOzE,IAC/D7B,EAAMwd,OAAO9Q,OAASud,EAAIzM,OAAOuB,eAAiB/e,EAAMsG,OAAOkX,MAM/D,IAAI+M,GAAgBrrB,KAAK0H,IAAI5G,EAAMyB,KAAKiL,OAAQ1M,EAAMomB,OAAO1Z,OAAQ1M,EAAMuhB,MAAM7U,QAC7E2zD,EAAargE,EAAM6B,IAAI6K,OAAS6d,EAAgBvqB,EAAMwd,OAAO9Q,OAC/DyzD,EAAmBngE,EAAMsG,OAAOzE,IAAM7B,EAAMsG,OAAOkX,MACrDyM,GAAItwB,KAAKwN,MAAMuF,OAAS9R,EAAKoJ,OAAOK,OAAOsE,EAAQ+D,OAAQ2zD,EAAa,MAGxErgE,EAAMrG,KAAK+S,OAASud,EAAItwB,KAAK6wB,aAC7BxqB,EAAMqG,WAAWqG,OAAS1M,EAAMrG,KAAK+S,OAASyzD,CAC9C,IAAI5qC,GAAkBv1B,EAAMrG,KAAK+S,OAAS1M,EAAM6B,IAAI6K,OAAS1M,EAAMwd,OAAO9Q,OACxEyzD,CACFngE,GAAM+xB,gBAAgBrlB,OAAU6oB,EAChCv1B,EAAMi/D,cAAcvyD,OAAY6oB,EAChCv1B,EAAMk/D,eAAexyD,OAAW1M,EAAMi/D,cAAcvyD,OAGpD1M,EAAMrG,KAAK8S,MAAQwd,EAAItwB,KAAK2wB,YAC5BtqB,EAAMqG,WAAWoG,MAAQzM,EAAMrG,KAAK8S,MAAQ2zD,EAC5CpgE,EAAMyB,KAAKgL,MAAQwd,EAAIg1C,cAAcvlD,cAAkB1Z,EAAMsG,OAAO7E,KACpEzB,EAAMi/D,cAAcxyD,MAAQzM,EAAMyB,KAAKgL,MACvCzM,EAAMuhB,MAAM9U,MAAQwd,EAAIi1C,eAAexlD,cAAgB1Z,EAAMsG,OAAOib,MACpEvhB,EAAMk/D,eAAezyD,MAAQzM,EAAMuhB,MAAM9U,KACzC,IAAI6zD,GAActgE,EAAMrG,KAAK8S,MAAQzM,EAAMyB,KAAKgL,MAAQzM,EAAMuhB,MAAM9U,MAAQ2zD,CAC5EpgE,GAAMomB,OAAO3Z,MAAiB6zD,EAC9BtgE,EAAM+xB,gBAAgBtlB,MAAQ6zD,EAC9BtgE,EAAM6B,IAAI4K,MAAoB6zD,EAC9BtgE,EAAMwd,OAAO/Q,MAAiB6zD,EAG9Br2C,EAAI5jB,WAAWc,MAAMuF,OAAmB1M,EAAMqG,WAAWqG,OAAS,KAClEud,EAAIoV,mBAAmBl4B,MAAMuF,OAAW1M,EAAMqG,WAAWqG,OAAS,KAClEud,EAAIyY,qBAAqBv7B,MAAMuF,OAAS1M,EAAM+xB,gBAAgBrlB,OAAS,KACvEud,EAAI8H,gBAAgB5qB,MAAMuF,OAAc1M,EAAM+xB,gBAAgBrlB,OAAS,KACvEud,EAAIg1C,cAAc93D,MAAMuF,OAAgB1M,EAAMi/D,cAAcvyD,OAAS,KACrEud,EAAIi1C,eAAe/3D,MAAMuF,OAAe1M,EAAMk/D,eAAexyD,OAAS,KAEtEud,EAAI5jB,WAAWc,MAAMsF,MAAmBzM,EAAMqG,WAAWoG,MAAQ,KACjEwd,EAAIoV,mBAAmBl4B,MAAMsF,MAAWzM,EAAM+xB,gBAAgBtlB,MAAQ,KACtEwd,EAAIyY,qBAAqBv7B,MAAMsF,MAASzM,EAAMqG,WAAWoG,MAAQ,KACjEwd,EAAI8H,gBAAgB5qB,MAAMsF,MAAczM,EAAMomB,OAAO3Z,MAAQ,KAC7Dwd,EAAIpoB,IAAIsF,MAAMsF,MAA0BzM,EAAM6B,IAAI4K,MAAQ,KAC1Dwd,EAAIzM,OAAOrW,MAAMsF,MAAuBzM,EAAMwd,OAAO/Q,MAAQ,KAG7Dwd,EAAI5jB,WAAWc,MAAM1F,KAAiB,IACtCwoB,EAAI5jB,WAAWc,MAAMtF,IAAiB,IACtCooB,EAAIoV,mBAAmBl4B,MAAM1F,KAAUzB,EAAMyB,KAAKgL,MAAQzM,EAAMsG,OAAO7E,KAAQ,KAC/EwoB,EAAIoV,mBAAmBl4B,MAAMtF,IAAS,IACtCooB,EAAIyY,qBAAqBv7B,MAAM1F,KAAO,IACtCwoB,EAAIyY,qBAAqBv7B,MAAMtF,IAAO7B,EAAM6B,IAAI6K,OAAS,KACzDud,EAAI8H,gBAAgB5qB,MAAM1F,KAAYzB,EAAMyB,KAAKgL,MAAQ,KACzDwd,EAAI8H,gBAAgB5qB,MAAMtF,IAAY7B,EAAM6B,IAAI6K,OAAS,KACzDud,EAAIg1C,cAAc93D,MAAM1F,KAAc,IACtCwoB,EAAIg1C,cAAc93D,MAAMtF,IAAc7B,EAAM6B,IAAI6K,OAAS,KACzDud,EAAIi1C,eAAe/3D,MAAM1F,KAAczB,EAAMyB,KAAKgL,MAAQzM,EAAMomB,OAAO3Z,MAAS,KAChFwd,EAAIi1C,eAAe/3D,MAAMtF,IAAa7B,EAAM6B,IAAI6K,OAAS,KACzDud,EAAIpoB,IAAIsF,MAAM1F,KAAwBzB,EAAMyB,KAAKgL,MAAQ,KACzDwd,EAAIpoB,IAAIsF,MAAMtF,IAAwB,IACtCooB,EAAIzM,OAAOrW,MAAM1F,KAAqBzB,EAAMyB,KAAKgL,MAAQ,KACzDwd,EAAIzM,OAAOrW,MAAMtF,IAAsB7B,EAAM6B,IAAI6K,OAAS1M,EAAM+xB,gBAAgBrlB,OAAU,KAI1FzS,KAAKsmE,kBAGL,IAAI18C,GAAS5pB,KAAK+F,MAAM6hC,SACG,WAAvBl5B,EAAQ8lB,cACV5K,GAAU3kB,KAAK0H,IAAI3M,KAAK+F,MAAM+xB,gBAAgBrlB,OAASzS,KAAK+F,MAAMomB,OAAO1Z,OACvEzS,KAAK+F,MAAMsG,OAAOzE,IAAM5H,KAAK+F,MAAMsG,OAAOkX,OAAQ,IAEtDyM,EAAI7D,OAAOjf,MAAM1F,KAAO,IACxBwoB,EAAI7D,OAAOjf,MAAMtF,IAAOgiB,EAAS,KACjCoG,EAAIxoB,KAAK0F,MAAM1F,KAAS,IACxBwoB,EAAIxoB,KAAK0F,MAAMtF,IAASgiB,EAAS,KACjCoG,EAAI1I,MAAMpa,MAAM1F,KAAQ,IACxBwoB,EAAI1I,MAAMpa,MAAMtF,IAAQgiB,EAAS,IAGjC,IAAI28C,GAAwC,GAAxBvmE,KAAK+F,MAAM6hC,UAAiB,SAAW,GACvD4+B,EAAmBxmE,KAAK+F,MAAM6hC,WAAa5nC,KAAK+F,MAAM4/D,aAAe,SAAW,EAYpF,IAXA31C,EAAIk1C,UAAUh4D,MAAMuqB,WAAsB8uC,EAC1Cv2C,EAAIm1C,aAAaj4D,MAAMuqB,WAAmB+uC,EAC1Cx2C,EAAIo1C,cAAcl4D,MAAMuqB,WAAkB8uC,EAC1Cv2C,EAAIq1C,iBAAiBn4D,MAAMuqB,WAAe+uC,EAC1Cx2C,EAAIs1C,eAAep4D,MAAMuqB,WAAiB8uC,EAC1Cv2C,EAAIu1C,kBAAkBr4D,MAAMuqB,WAAc+uC,EAG1CxmE,KAAKgC,WAAWuG,QAAQ,SAAUu9D,GAChChhC,EAAUghC,EAAUpkD,UAAYojB,IAE9BA,EAAS,CAEX,GAAI2hC,GAAc,CACdzmE,MAAK4lE,YAAca,GACrBzmE,KAAK4lE,cACL5lE,KAAK0hB,UAGLkX,QAAQhF,IAAI,qCAEd5zB,KAAK4lE,YAAc,EAGrB5lE,KAAK6tB,KAAK,oBAIZsI,EAAK/iB,UAAUszD,QAAU,WACvB,KAAM,IAAI9iE,OAAM,wDAUlBuyB,EAAK/iB,UAAUqyB,eAAiB,SAASrL,GACvC,IAAKp6B,KAAK41B,YACR,KAAM,IAAIhyB,OAAM,sCAGlB5D,MAAK41B,YAAY6P,eAAerL,IAQlCjE,EAAK/iB,UAAUsyB,eAAiB,WAC9B,IAAK1lC,KAAK41B,YACR,KAAM,IAAIhyB,OAAM,sCAGlB,OAAO5D,MAAK41B,YAAY8P,kBAU1BvP,EAAK/iB,UAAUmiB,QAAU,SAASvjB,GAChC,MAAOrQ,GAAS2zB,OAAOt1B,KAAMgS,EAAGhS,KAAK+F,MAAMomB,OAAO3Z,QAUpD2jB,EAAK/iB,UAAUqiB,cAAgB,SAASzjB,GACtC,MAAOrQ,GAAS2zB,OAAOt1B,KAAMgS,EAAGhS,KAAK+F,MAAMrG,KAAK8S,QAalD2jB,EAAK/iB,UAAU+hB,UAAY,SAASiF,GAClC,MAAOz4B,GAASuzB,SAASl1B,KAAMo6B,EAAMp6B,KAAK+F,MAAMomB,OAAO3Z,QAczD2jB,EAAK/iB,UAAUiiB,gBAAkB,SAAS+E,GACxC,MAAOz4B,GAASuzB,SAASl1B,KAAMo6B,EAAMp6B,KAAK+F,MAAMrG,KAAK8S,QAUvD2jB,EAAK/iB,UAAUyyD,gBAAkB,WACA,GAA3B7lE,KAAK0O,QAAQ6lB,WACfv0B,KAAK2mE,mBAGL3mE,KAAK+lE,mBAST5vC,EAAK/iB,UAAUuzD,iBAAmB,WAChC,GAAIvyD,GAAKpU,IAETA,MAAK+lE,kBAEL/lE,KAAK4mE,UAAY,WACf,MAA6B,IAAzBxyD,EAAG1F,QAAQ6lB,eAEbngB,GAAG2xD,uBAID3xD,EAAG4b,IAAItwB,OAKJ0U,EAAG4b,IAAItwB,KAAK2wB,aAAejc,EAAGrO,MAAMksC,WACtC79B,EAAG4b,IAAItwB,KAAK6wB,cAAgBnc,EAAGrO,MAAM8gE,cACtCzyD,EAAGrO,MAAMksC,UAAY79B,EAAG4b,IAAItwB,KAAK2wB,YACjCjc,EAAGrO,MAAM8gE,WAAazyD,EAAG4b,IAAItwB,KAAK6wB,aAElCnc,EAAGyZ,KAAK,aAMdltB,EAAKkI,iBAAiBpB,OAAQ,SAAUzH,KAAK4mE,WAE7C5mE,KAAK8mE,WAAaC,YAAY/mE,KAAK4mE,UAAW,MAOhDzwC,EAAK/iB,UAAU2yD,gBAAkB,WAC3B/lE,KAAK8mE,aACPp0C,cAAc1yB,KAAK8mE,YACnB9mE,KAAK8mE,WAAavgE,QAIpB5F,EAAK0I,oBAAoB5B,OAAQ,SAAUzH,KAAK4mE,WAChD5mE,KAAK4mE,UAAY,MAQnBzwC,EAAK/iB,UAAUkrB,SAAW,WACxBt+B,KAAK+9B,MAAM4B,eAAgB,GAQ7BxJ,EAAK/iB,UAAUmrB,SAAW,WACxBv+B,KAAK+9B,MAAM4B,eAAgB,GAQ7BxJ,EAAK/iB,UAAU6qB,aAAe,WAC5Bj+B,KAAK+9B,MAAMipC,iBAAmBhnE,KAAK+F,MAAM6hC,WAQ3CzR,EAAK/iB,UAAU8qB,QAAU,SAAU10B,GAGjC,GAAKxJ,KAAK+9B,MAAM4B,cAAhB,CAEA,GAAIjR,GAAQllB,EAAMo2B,QAAQE,OAEtBmnC,EAAejnE,KAAKknE,gBACpBC,EAAennE,KAAKonE,cAAcpnE,KAAK+9B,MAAMipC,iBAAmBt4C,EAGhEy4C,IAAgBF,IAClBjnE,KAAK0hB,SACL1hB,KAAK6tB,KAAK,mBAUdsI,EAAK/iB,UAAUg0D,cAAgB,SAAUx/B,GAGvC,MAFA5nC,MAAK+F,MAAM6hC,UAAYA,EACvB5nC,KAAKsmE,mBACEtmE,KAAK+F,MAAM6hC,WAQpBzR,EAAK/iB,UAAUkzD,iBAAmB,WAEhC,GAAIX,GAAe1gE,KAAK8G,IAAI/L,KAAK+F,MAAM+xB,gBAAgBrlB,OAASzS,KAAK+F,MAAMomB,OAAO1Z,OAAQ,EAc1F,OAbIkzD,IAAgB3lE,KAAK+F,MAAM4/D,eAGG,UAA5B3lE,KAAK0O,QAAQ8lB,cACfx0B,KAAK+F,MAAM6hC,WAAc+9B,EAAe3lE,KAAK+F,MAAM4/D,cAErD3lE,KAAK+F,MAAM4/D,aAAeA,GAIxB3lE,KAAK+F,MAAM6hC,UAAY,IAAG5nC,KAAK+F,MAAM6hC,UAAY,GACjD5nC,KAAK+F,MAAM6hC,UAAY+9B,IAAc3lE,KAAK+F,MAAM6hC,UAAY+9B,GAEzD3lE,KAAK+F,MAAM6hC,WAQpBzR,EAAK/iB,UAAU8zD,cAAgB,WAC7B,MAAOlnE,MAAK+F,MAAM6hC,WAGpB/nC,EAAOD,QAAUu2B,GAKb,SAASt2B,EAAQD,EAASM,GAE9B,GAAI2lC,GAAS3lC,EAAoB,GAOjCN,GAAQsgC,YAAc,SAASp3B,EAASU,GACtC,GAAI69D,GAAY,KAMZ9mC,EAAUsF,EAAOr8B,MAAM89D,aAAa99D,EAAO69D,GAC3CznC,EAAUiG,EAAOr8B,MAAM+9D,iBAAiBvnE,KAAMqnE,EAAW9mC,EAAS/2B,EAWtE,OAPI/E,OAAMm7B,EAAQzT,OAAOuS,SACvBkB,EAAQzT,OAAOuS,MAAQl1B,EAAMk1B,OAE3Bj6B,MAAMm7B,EAAQzT,OAAOwS,SACvBiB,EAAQzT,OAAOwS,MAAQn1B,EAAMm1B,OAGxBiB,IAML,SAAS//B,EAAQD,GAGrBA,EAAY,IACVm6B,QAAS,UACTK,KAAM,QAERx6B,EAAe,MAAIA,EAAY,GAC/BA,EAAe,MAAIA,EAAY,GAG/BA,EAAY,IACV4nE,OAAQ,aACRptC,KAAM,QAERx6B,EAAe,MAAIA,EAAY,GAC/BA,EAAe,MAAIA,EAAY,IAK3B,SAASC,EAAQD,GAGrBA,EAAY,IACVs9C,KAAM,OACNG,IAAK,kBACLoqB,KAAM,OACNnG,QAAS,WACTG,QAAS,WACTiG,SAAU,YACVvqB,SAAU,YACVwqB,eAAgB,+CAChBC,gBAAiB,qEACjBC,oBAAqB,wEACrBC,gBAAiB,kCACjBC,mBAAoB,+BAEtBnoE,EAAe,MAAIA,EAAY,GAC/BA,EAAe,MAAIA,EAAY,GAG/BA,EAAY,IACVs9C,KAAM,WACNG,IAAK,uBACLoqB,KAAM,QACNnG,QAAS,iBACTG,QAAS,iBACTiG,SAAU,gBACVvqB,SAAU,gBACVwqB,eAAgB,uDAChBC,gBAAiB,6EACjBC,oBAAqB,kFACrBC,gBAAiB,wCACjBC,mBAAoB,2CAEtBnoE,EAAe,MAAIA,EAAY,GAC/BA,EAAe,MAAIA,EAAY,IAK3B,WAKoC,mBAA7BooE,4BAKTA,yBAAyB50D,UAAUqsD,OAAS,SAASztD,EAAGC,EAAGvH,GACzD1K,KAAK6nB,YACL7nB,KAAK2rB,IAAI3Z,EAAGC,EAAGvH,EAAG,EAAG,EAAEzF,KAAK2mB,IAAI;EASlCo8C,yBAAyB50D,UAAU60D,OAAS,SAASj2D,EAAGC,EAAGvH,GACzD1K,KAAK6nB,YACL7nB,KAAK0S,KAAKV,EAAItH,EAAGuH,EAAIvH,EAAO,EAAJA,EAAW,EAAJA,IASjCs9D,yBAAyB50D,UAAU4b,SAAW,SAAShd,EAAGC,EAAGvH,GAE3D1K,KAAK6nB,WAEL,IAAIhc,GAAQ,EAAJnB,EACJw9D,EAAKr8D,EAAI,EACTs8D,EAAKljE,KAAK2qB,KAAK,GAAK,EAAI/jB,EACxBD,EAAI3G,KAAK2qB,KAAK/jB,EAAIA,EAAIq8D,EAAKA,EAE/BloE,MAAK8nB,OAAO9V,EAAGC,GAAKrG,EAAIu8D,IACxBnoE,KAAK+nB,OAAO/V,EAAIk2D,EAAIj2D,EAAIk2D,GACxBnoE,KAAK+nB,OAAO/V,EAAIk2D,EAAIj2D,EAAIk2D,GACxBnoE,KAAK+nB,OAAO/V,EAAGC,GAAKrG,EAAIu8D,IACxBnoE,KAAKkoB,aASP8/C,yBAAyB50D,UAAUg1D,aAAe,SAASp2D,EAAGC,EAAGvH,GAE/D1K,KAAK6nB,WAEL,IAAIhc,GAAQ,EAAJnB,EACJw9D,EAAKr8D,EAAI,EACTs8D,EAAKljE,KAAK2qB,KAAK,GAAK,EAAI/jB,EACxBD,EAAI3G,KAAK2qB,KAAK/jB,EAAIA,EAAIq8D,EAAKA,EAE/BloE,MAAK8nB,OAAO9V,EAAGC,GAAKrG,EAAIu8D,IACxBnoE,KAAK+nB,OAAO/V,EAAIk2D,EAAIj2D,EAAIk2D,GACxBnoE,KAAK+nB,OAAO/V,EAAIk2D,EAAIj2D,EAAIk2D,GACxBnoE,KAAK+nB,OAAO/V,EAAGC,GAAKrG,EAAIu8D,IACxBnoE,KAAKkoB,aASP8/C,yBAAyB50D,UAAUi1D,KAAO,SAASr2D,EAAGC,EAAGvH,GAEvD1K,KAAK6nB,WAEL,KAAK,GAAIygD,GAAI,EAAO,GAAJA,EAAQA,IAAK,CAC3B,GAAI58C,GAAU48C,EAAI,IAAM,EAAS,IAAJ59D,EAAc,GAAJA,CACvC1K,MAAK+nB,OACD/V,EAAI0Z,EAASzmB,KAAKoZ,IAAQ,EAAJiqD,EAAQrjE,KAAK2mB,GAAK,IACxC3Z,EAAIyZ,EAASzmB,KAAKuZ,IAAQ,EAAJ8pD,EAAQrjE,KAAK2mB,GAAK,KAI9C5rB,KAAKkoB,aAMP8/C,yBAAyB50D,UAAU0sD,UAAY,SAAS9tD,EAAGC,EAAGy9C,EAAG9jD,EAAGlB,GAClE,GAAI69D,GAAMtjE,KAAK2mB,GAAG,GACE,GAAhB8jC,EAAM,EAAIhlD,IAAYA,EAAMglD,EAAI,GAChB,EAAhB9jD,EAAM,EAAIlB,IAAYA,EAAMkB,EAAI,GACpC5L,KAAK6nB,YACL7nB,KAAK8nB,OAAO9V,EAAEtH,EAAEuH,GAChBjS,KAAK+nB,OAAO/V,EAAE09C,EAAEhlD,EAAEuH,GAClBjS,KAAK2rB,IAAI3Z,EAAE09C,EAAEhlD,EAAEuH,EAAEvH,EAAEA,EAAM,IAAJ69D,EAAY,IAAJA,GAAQ,GACrCvoE,KAAK+nB,OAAO/V,EAAE09C,EAAEz9C,EAAErG,EAAElB,GACpB1K,KAAK2rB,IAAI3Z,EAAE09C,EAAEhlD,EAAEuH,EAAErG,EAAElB,EAAEA,EAAE,EAAM,GAAJ69D,GAAO,GAChCvoE,KAAK+nB,OAAO/V,EAAEtH,EAAEuH,EAAErG,GAClB5L,KAAK2rB,IAAI3Z,EAAEtH,EAAEuH,EAAErG,EAAElB,EAAEA,EAAM,GAAJ69D,EAAW,IAAJA,GAAQ,GACpCvoE,KAAK+nB,OAAO/V,EAAEC,EAAEvH,GAChB1K,KAAK2rB,IAAI3Z,EAAEtH,EAAEuH,EAAEvH,EAAEA,EAAM,IAAJ69D,EAAY,IAAJA,GAAQ,IAMrCP,yBAAyB50D,UAAU6sD,QAAU,SAASjuD,EAAGC,EAAGy9C,EAAG9jD,GAC7D,GAAI48D,GAAQ,SACRC,EAAM/Y,EAAI,EAAK8Y,EACfE,EAAM98D,EAAI,EAAK48D,EACfG,EAAK32D,EAAI09C,EACTkZ,EAAK32D,EAAIrG,EACTi9D,EAAK72D,EAAI09C,EAAI,EACboZ,EAAK72D,EAAIrG,EAAI,CAEjB5L,MAAK6nB,YACL7nB,KAAK8nB,OAAO9V,EAAG82D,GACf9oE,KAAK+oE,cAAc/2D,EAAG82D,EAAKJ,EAAIG,EAAKJ,EAAIx2D,EAAG42D,EAAI52D,GAC/CjS,KAAK+oE,cAAcF,EAAKJ,EAAIx2D,EAAG02D,EAAIG,EAAKJ,EAAIC,EAAIG,GAChD9oE,KAAK+oE,cAAcJ,EAAIG,EAAKJ,EAAIG,EAAKJ,EAAIG,EAAIC,EAAID,GACjD5oE,KAAK+oE,cAAcF,EAAKJ,EAAIG,EAAI52D,EAAG82D,EAAKJ,EAAI12D,EAAG82D,IAQjDd,yBAAyB50D,UAAU2sD,SAAW,SAAS/tD,EAAGC,EAAGy9C,EAAG9jD,GAC9D,GAAIiC,GAAI,EAAE,EACNm7D,EAAWtZ,EACXuZ,EAAWr9D,EAAIiC,EAEf26D,EAAQ,SACRC,EAAMO,EAAW,EAAKR,EACtBE,EAAMO,EAAW,EAAKT,EACtBG,EAAK32D,EAAIg3D,EACTJ,EAAK32D,EAAIg3D,EACTJ,EAAK72D,EAAIg3D,EAAW,EACpBF,EAAK72D,EAAIg3D,EAAW,EACpBC,EAAMj3D,GAAKrG,EAAIq9D,EAAS,GACxBE,EAAMl3D,EAAIrG,CAEd5L,MAAK6nB,YACL7nB,KAAK8nB,OAAO6gD,EAAIG,GAEhB9oE,KAAK+oE,cAAcJ,EAAIG,EAAKJ,EAAIG,EAAKJ,EAAIG,EAAIC,EAAID,GACjD5oE,KAAK+oE,cAAcF,EAAKJ,EAAIG,EAAI52D,EAAG82D,EAAKJ,EAAI12D,EAAG82D,GAE/C9oE,KAAK+oE,cAAc/2D,EAAG82D,EAAKJ,EAAIG,EAAKJ,EAAIx2D,EAAG42D,EAAI52D,GAC/CjS,KAAK+oE,cAAcF,EAAKJ,EAAIx2D,EAAG02D,EAAIG,EAAKJ,EAAIC,EAAIG,GAEhD9oE,KAAK+nB,OAAO4gD,EAAIO,GAEhBlpE,KAAK+oE,cAAcJ,EAAIO,EAAMR,EAAIG,EAAKJ,EAAIU,EAAKN,EAAIM,GACnDnpE,KAAK+oE,cAAcF,EAAKJ,EAAIU,EAAKn3D,EAAGk3D,EAAMR,EAAI12D,EAAGk3D,GAEjDlpE,KAAK+nB,OAAO/V,EAAG82D,IAOjBd,yBAAyB50D,UAAU2kD,MAAQ,SAAS/lD,EAAGC,EAAGw8C,EAAO/oD,GAE/D,GAAI0jE,GAAKp3D,EAAItM,EAAST,KAAKuZ,IAAIiwC,GAC3B4a,EAAKp3D,EAAIvM,EAAST,KAAKoZ,IAAIowC,GAI3B6a,EAAKt3D,EAAa,GAATtM,EAAeT,KAAKuZ,IAAIiwC,GACjC8a,EAAKt3D,EAAa,GAATvM,EAAeT,KAAKoZ,IAAIowC,GAGjC+a,EAAKJ,EAAK1jE,EAAS,EAAIT,KAAKuZ,IAAIiwC,EAAQ,GAAMxpD,KAAK2mB,IACnD69C,EAAKJ,EAAK3jE,EAAS,EAAIT,KAAKoZ,IAAIowC,EAAQ,GAAMxpD,KAAK2mB,IAGnD89C,EAAKN,EAAK1jE,EAAS,EAAIT,KAAKuZ,IAAIiwC,EAAQ,GAAMxpD,KAAK2mB,IACnD+9C,EAAKN,EAAK3jE,EAAS,EAAIT,KAAKoZ,IAAIowC,EAAQ,GAAMxpD,KAAK2mB,GAEvD5rB,MAAK6nB,YACL7nB,KAAK8nB,OAAO9V,EAAGC,GACfjS,KAAK+nB,OAAOyhD,EAAIC,GAChBzpE,KAAK+nB,OAAOuhD,EAAIC,GAChBvpE,KAAK+nB,OAAO2hD,EAAIC,GAChB3pE,KAAKkoB,aASP8/C,yBAAyB50D,UAAUykD,WAAa,SAAS7lD,EAAEC,EAAE4mD,EAAGC,EAAG8Q,GAC5DA,IAAWA,GAAW,GAAG,IACd,GAAZC,IAAeA,EAAa,KAChC,IAAIC,GAAYF,EAAUlkE,MAC1B1F,MAAK8nB,OAAO9V,EAAGC,EAKf,KAJA,GAAI4M,GAAMg6C,EAAG7mD,EAAI8M,EAAMg6C,EAAG7mD,EACtB83D,EAAQjrD,EAAGD,EACXmrD,EAAgB/kE,KAAK2qB,KAAM/Q,EAAGA,EAAKC,EAAGA,GACtCmrD,EAAU,EAAG39B,GAAK,EACf09B,GAAe,IAAI,CACxB,GAAIH,GAAaD,EAAUK,IAAYH,EACnCD,GAAaG,IAAeH,EAAaG,EAC7C,IAAIruD,GAAQ1W,KAAK2qB,KAAMi6C,EAAWA,GAAc,EAAIE,EAAMA,GACnD,GAAHlrD,IAAMlD,GAASA,GACnB3J,GAAK2J,EACL1J,GAAK83D,EAAMpuD,EACX3b,KAAKssC,EAAO,SAAW,UAAUt6B,EAAEC,GACnC+3D,GAAiBH,EACjBv9B,GAAQA,MAUV,SAASzsC,EAAQD,EAASM,GAQ9B,QAASgrC,GAAK3T,EAAS7oB,GACrB1O,KAAKu3B,QAAUA,EACfv3B,KAAK0O,QAAUA,EALjB,GAAI9N,GAAUV,EAAoB,GAC9BkrC,EAASlrC,EAAoB,GAOjCgrC,GAAK93B,UAAUg5B,UAAY,SAASC,GAGlC,IAAK,GAFDxwB,GAAOwwB,EAAU,GAAGp6B,EACpB8J,EAAOswB,EAAU,GAAGp6B,EACf4Z,EAAI,EAAGA,EAAIwgB,EAAU3mC,OAAQmmB,IACpChQ,EAAOA,EAAOwwB,EAAUxgB,GAAG5Z,EAAIo6B,EAAUxgB,GAAG5Z,EAAI4J,EAChDE,EAAOA,EAAOswB,EAAUxgB,GAAG5Z,EAAIo6B,EAAUxgB,GAAG5Z,EAAI8J,CAElD,QAAQhQ,IAAK8P,EAAMlP,IAAKoP,EAAMowB,iBAAkBnsC,KAAK0O,QAAQy9B,mBAU/DjB,EAAK93B,UAAUk5B,KAAO,SAAUrV,EAAS/kB,EAAOq6B,GAC9C,GAAe,MAAXtV,GACEA,EAAQvxB,OAAS,EAAG,CACtB,GAAIgmC,GAAM9+B,EACNysC,EAAYp1C,OAAOsoC,EAAUpG,IAAIj5B,MAAMuF,OAAOhI,QAAQ,KAAK,IAgB/D,IAfAihC,EAAO9qC,EAAQyQ,cAAc,OAAQk7B,EAAU/E,YAAa+E,EAAUpG,KACtEuF,EAAKr5B,eAAe,KAAM,QAASH,EAAMnK,WACtBxB,SAAhB2L,EAAMhF,OACPw+B,EAAKr5B,eAAe,KAAM,QAASH,EAAMhF,OAKzCN,EADsC,GAApCsF,EAAMxD,QAAQ48B,WAAW38B,QACvBu8B,EAAKg/B,YAAYjzC,EAAS/kB,GAG1Bg5B,EAAKi/B,QAAQlzC,GAIiB,GAAhC/kB,EAAMxD,QAAQo9B,OAAOn9B,QAAiB,CACxC,GACIy7D,GADAz+B,EAAW/qC,EAAQyQ,cAAc,OAAQk7B,EAAU/E,YAAa+E,EAAUpG,IAG5EikC,GADsC,OAApCl4D,EAAMxD,QAAQo9B,OAAOtX,YACf,IAAMyC,EAAQ,GAAGjlB,EAAI,MAAgBpF,EAAI,IAAMqqB,EAAQA,EAAQvxB,OAAS,GAAGsM,EAAI,KAG/E,IAAMilB,EAAQ,GAAGjlB,EAAI,IAAMqnC,EAAY,IAAMzsC,EAAI,IAAMqqB,EAAQA,EAAQvxB,OAAS,GAAGsM,EAAI,IAAMqnC,EAEvG1N,EAASt5B,eAAe,KAAM,QAASH,EAAMnK,UAAY,SACvBxB,SAA/B2L,EAAMxD,QAAQo9B,OAAO5+B,OACtBy+B,EAASt5B,eAAe,KAAM,QAASH,EAAMxD,QAAQo9B,OAAO5+B,OAE9Dy+B,EAASt5B,eAAe,KAAM,IAAK+3D,GAGrC1+B,EAAKr5B,eAAe,KAAM,IAAK,IAAMzF,GAGG,GAApCsF,EAAMxD,QAAQ0D,WAAWzD,SAC3By8B,EAAOkB,KAAKrV,EAAS/kB,EAAOq6B,KAepCrB,EAAKm/B,mBAAqB,SAAS13D,GAMjC,IAAK,GAJD23D,GAAIC,EAAIC,EAAIC,EAAIC,EAAKC,EACrB/9D,EAAI3H,KAAK0oB,MAAMhb,EAAK,GAAGX,GAAK,IAAM/M,KAAK0oB,MAAMhb,EAAK,GAAGV,GAAK,IAC1D24D,EAAgB,EAAE,EAClBllE,EAASiN,EAAKjN,OACTH,EAAI,EAAOG,EAAS,EAAbH,EAAgBA,IAE9B+kE,EAAW,GAAL/kE,EAAUoN,EAAK,GAAKA,EAAKpN,EAAE,GACjCglE,EAAK53D,EAAKpN,GACVilE,EAAK73D,EAAKpN,EAAE,GACZklE,EAAc/kE,EAARH,EAAI,EAAcoN,EAAKpN,EAAE,GAAKilE,EAUpCE,GAAQ14D,IAAMs4D,EAAGt4D,EAAI,EAAEu4D,EAAGv4D,EAAIw4D,EAAGx4D,GAAI44D,EAAgB34D,IAAMq4D,EAAGr4D,EAAI,EAAEs4D,EAAGt4D,EAAIu4D,EAAGv4D,GAAI24D,GAClFD,GAAQ34D,GAAMu4D,EAAGv4D,EAAI,EAAEw4D,EAAGx4D,EAAIy4D,EAAGz4D,GAAI44D,EAAgB34D,GAAMs4D,EAAGt4D,EAAI,EAAEu4D,EAAGv4D,EAAIw4D,EAAGx4D,GAAI24D,GAGlFh+D,GAAK,IACL89D,EAAI14D,EAAI,IACR04D,EAAIz4D,EAAI,IACR04D,EAAI34D,EAAI,IACR24D,EAAI14D,EAAI,IACRu4D,EAAGx4D,EAAI,IACPw4D,EAAGv4D,EAAI,GAGT,OAAOrF,IAcTs+B,EAAKg/B,YAAc,SAASv3D,EAAMT,GAChC,GAAIs5B,GAAQt5B,EAAMxD,QAAQ48B,WAAWE,KACrC,IAAa,GAATA,GAAwBjlC,SAAVilC,EAChB,MAAOxrC,MAAKqqE,mBAAmB13D,EAO/B,KAAK,GAJD23D,GAAIC,EAAIC,EAAIC,EAAIC,EAAKC,EAAKE,EAAGC,EAAGC,EAAIC,EAAGtgD,EAAGugD,EAAGC,EAC7CC,EAAQC,EAAQC,EAASC,EAASC,EAASC,EAC3C5+D,EAAI3H,KAAK0oB,MAAMhb,EAAK,GAAGX,GAAK,IAAM/M,KAAK0oB,MAAMhb,EAAK,GAAGV,GAAK,IAC1DvM,EAASiN,EAAKjN,OACTH,EAAI,EAAOG,EAAS,EAAbH,EAAgBA,IAE9B+kE,EAAW,GAAL/kE,EAAUoN,EAAK,GAAKA,EAAKpN,EAAE,GACjCglE,EAAK53D,EAAKpN,GACVilE,EAAK73D,EAAKpN,EAAE,GACZklE,EAAc/kE,EAARH,EAAI,EAAcoN,EAAKpN,EAAE,GAAKilE,EAEpCK,EAAK5lE,KAAK2qB,KAAK3qB,KAAK8uB,IAAIu2C,EAAGt4D,EAAIu4D,EAAGv4D,EAAE,GAAK/M,KAAK8uB,IAAIu2C,EAAGr4D,EAAIs4D,EAAGt4D,EAAE,IAC9D64D,EAAK7lE,KAAK2qB,KAAK3qB,KAAK8uB,IAAIw2C,EAAGv4D,EAAIw4D,EAAGx4D,EAAE,GAAK/M,KAAK8uB,IAAIw2C,EAAGt4D,EAAIu4D,EAAGv4D,EAAE,IAC9D84D,EAAK9lE,KAAK2qB,KAAK3qB,KAAK8uB,IAAIy2C,EAAGx4D,EAAIy4D,EAAGz4D,EAAE,GAAK/M,KAAK8uB,IAAIy2C,EAAGv4D,EAAIw4D,EAAGx4D,EAAE,IAY9Dk5D,EAAUlmE,KAAK8uB,IAAIg3C,EAAKv/B,GACxB6/B,EAAUpmE,KAAK8uB,IAAIg3C,EAAG,EAAEv/B,GACxB4/B,EAAUnmE,KAAK8uB,IAAI+2C,EAAKt/B,GACxB8/B,EAAUrmE,KAAK8uB,IAAI+2C,EAAG,EAAEt/B,GACxBggC,EAAUvmE,KAAK8uB,IAAI82C,EAAKr/B,GACxB+/B,EAAUtmE,KAAK8uB,IAAI82C,EAAG,EAAEr/B,GAExBw/B,EAAI,EAAEO,EAAU,EAAEC,EAASJ,EAASE,EACpC5gD,EAAI,EAAE2gD,EAAU,EAAEF,EAASC,EAASE,EACpCL,EAAI,EAAEO,GAAUA,EAASJ,GACrBH,EAAI,IAAIA,EAAI,EAAIA,GACpBC,EAAI,EAAEC,GAAUA,EAASC,GACrBF,EAAI,IAAIA,EAAI,EAAIA,GAEpBR,GAAQ14D,IAAMs5D,EAAUhB,EAAGt4D,EAAIg5D,EAAET,EAAGv4D,EAAIu5D,EAAUf,EAAGx4D,GAAKi5D,EACxDh5D,IAAMq5D,EAAUhB,EAAGr4D,EAAI+4D,EAAET,EAAGt4D,EAAIs5D,EAAUf,EAAGv4D,GAAKg5D,GAEpDN,GAAQ34D,GAAMq5D,EAAUd,EAAGv4D,EAAI0Y,EAAE8/C,EAAGx4D,EAAIs5D,EAAUb,EAAGz4D,GAAKk5D,EACxDj5D,GAAMo5D,EAAUd,EAAGt4D,EAAIyY,EAAE8/C,EAAGv4D,EAAIq5D,EAAUb,EAAGx4D,GAAKi5D,GAEvC,GAATR,EAAI14D,GAAmB,GAAT04D,EAAIz4D,IAASy4D,EAAMH,GACxB,GAATI,EAAI34D,GAAmB,GAAT24D,EAAI14D,IAAS04D,EAAMH,GACrC59D,GAAK,IACL89D,EAAI14D,EAAI,IACR04D,EAAIz4D,EAAI,IACR04D,EAAI34D,EAAI,IACR24D,EAAI14D,EAAI,IACRu4D,EAAGx4D,EAAI,IACPw4D,EAAGv4D,EAAI,GAGT,OAAOrF,IAUXs+B,EAAKi/B,QAAU,SAASx3D,GAGtB,IAAK,GADD/F,GAAI,GACCrH,EAAI,EAAGA,EAAIoN,EAAKjN,OAAQH,IAE7BqH,GADO,GAALrH,EACGoN,EAAKpN,GAAGyM,EAAI,IAAMW,EAAKpN,GAAG0M,EAG1B,IAAMU,EAAKpN,GAAGyM,EAAI,IAAMW,EAAKpN,GAAG0M,CAGzC,OAAOrF,IAGT/M,EAAOD,QAAUsrC,GAKb,SAASrrC,EAAQD,EAASM,GAQ9B,QAASurE,GAASl0C,EAAS7oB,GACzB1O,KAAKu3B,QAAUA,EACfv3B,KAAK0O,QAAUA,EALjB,CAAA,GAAI9N,GAAUV,EAAoB,EACrBA,GAAoB,IAOjCurE,EAASr4D,UAAUg5B,UAAY,SAASC,GACtC,GAA2C,SAAvCrsC,KAAK0O,QAAQ8mC,SAASC,cAA0B,CAGlD,IAAK,GAFD55B,GAAOwwB,EAAU,GAAGp6B,EACpB8J,EAAOswB,EAAU,GAAGp6B,EACf4Z,EAAI,EAAGA,EAAIwgB,EAAU3mC,OAAQmmB,IACpChQ,EAAOA,EAAOwwB,EAAUxgB,GAAG5Z,EAAIo6B,EAAUxgB,GAAG5Z,EAAI4J,EAChDE,EAAOA,EAAOswB,EAAUxgB,GAAG5Z,EAAIo6B,EAAUxgB,GAAG5Z,EAAI8J,CAElD,QAAQhQ,IAAK8P,EAAMlP,IAAKoP,EAAMowB,iBAAkBnsC,KAAK0O,QAAQy9B,kBAI7D,IAAK,GADDu/B,MACK7/C,EAAI,EAAGA,EAAIwgB,EAAU3mC,OAAQmmB,IACpC6/C,EAAgBxjE,MACd8J,EAAGq6B,EAAUxgB,GAAG7Z,EAChBC,EAAGo6B,EAAUxgB,GAAG5Z,EAChBslB,QAASv3B,KAAKu3B,SAGlB,OAAOm0C,IAYXD,EAASn/B,KAAO,SAAUmE,EAAUqG,EAAoBvK,GACtD,GAEIo/B,GACA/iE,EAAKgjE,EACL15D,EACA3M,EAAEsmB,EALFggD,KACAC,KAKAC,EAAY,CAGhB,KAAKxmE,EAAI,EAAGA,EAAIkrC,EAAS/qC,OAAQH,IAE/B,GADA2M,EAAQq6B,EAAUnY,OAAOqc,EAASlrC,IACP,OAAvB2M,EAAMxD,QAAQxB,OACK,GAAjBgF,EAAMyW,UAAyEpiB,SAArDgmC,EAAU79B,QAAQ0lB,OAAOqD,WAAWgZ,EAASlrC,KAAyE,GAApDgnC,EAAU79B,QAAQ0lB,OAAOqD,WAAWgZ,EAASlrC,KAC3I,IAAKsmB,EAAI,EAAGA,EAAIirB,EAAmBrG,EAASlrC,IAAIG,OAAQmmB,IACtDggD,EAAa3jE,MACX8J,EAAG8kC,EAAmBrG,EAASlrC,IAAIsmB,GAAG7Z,EACtCC,EAAG6kC,EAAmBrG,EAASlrC,IAAIsmB,GAAG5Z,EACtCslB,QAASkZ,EAASlrC,KAEpBwmE,GAAa,CAMrB,IAAiB,GAAbA,EAeJ,IAZAF,EAAa11D,KAAK,SAAU7Q,EAAGa,GAC7B,MAAIb,GAAE0M,GAAK7L,EAAE6L,EACJ1M,EAAEiyB,QAAUpxB,EAAEoxB,QAEdjyB,EAAE0M,EAAI7L,EAAE6L,IAKnBy5D,EAASO,sBAAsBF,EAAeD,GAGzCtmE,EAAI,EAAGA,EAAIsmE,EAAanmE,OAAQH,IAAK,CACxC2M,EAAQq6B,EAAUnY,OAAOy3C,EAAatmE,GAAGgyB,QACzC,IAAI2P,GAAW,GAAMh1B,EAAMxD,QAAQ8mC,SAAShjC,KAE5C5J,GAAMijE,EAAatmE,GAAGyM,CACtB,IAAIi6D,GAAe,CACnB,IAA2B1lE,SAAvBulE,EAAcljE,GACZrD,EAAE,EAAIsmE,EAAanmE,SAASimE,EAAe1mE,KAAK6lB,IAAI+gD,EAAatmE,EAAE,GAAGyM,EAAIpJ,IAC1ErD,EAAI,IAAwBomE,EAAe1mE,KAAK8G,IAAI4/D,EAAa1mE,KAAK6lB,IAAI+gD,EAAatmE,EAAE,GAAGyM,EAAIpJ,KACpGgjE,EAAWH,EAASS,iBAAiBP,EAAcz5D,EAAOg1B,OAEvD,CACH,GAAIilC,GAAU5mE,GAAKumE,EAAcljE,GAAKwjE,OAASN,EAAcljE,GAAKyjE,UAC9DC,EAAU/mE,GAAKumE,EAAcljE,GAAKyjE,SAAW,EAC7CF,GAAUN,EAAanmE,SAASimE,EAAe1mE,KAAK6lB,IAAI+gD,EAAaM,GAASn6D,EAAIpJ,IAClF0jE,EAAU,IAAsBX,EAAe1mE,KAAK8G,IAAI4/D,EAAa1mE,KAAK6lB,IAAI+gD,EAAaS,GAASt6D,EAAIpJ,KAC5GgjE,EAAWH,EAASS,iBAAiBP,EAAcz5D,EAAOg1B,GAC1D4kC,EAAcljE,GAAKyjE,UAAY,EAEa,SAAxCn6D,EAAMxD,QAAQ8mC,SAASC,eACzBw2B,EAAeH,EAAcljE,GAAK2jE,YAClCT,EAAcljE,GAAK2jE,aAAer6D,EAAM+4B,aAAe4gC,EAAatmE,GAAG0M,GAExB,cAAxCC,EAAMxD,QAAQ8mC,SAASC,gBAC9Bm2B,EAASp5D,MAAQo5D,EAASp5D,MAAQs5D,EAAcljE,GAAKwjE,OACrDR,EAAShiD,QAAWkiD,EAAcljE,GAAa,SAAIgjE,EAASp5D,MAAS,GAAIo5D,EAASp5D,OAASs5D,EAAcljE,GAAKwjE,OAAO,GACjF,QAAhCl6D,EAAMxD,QAAQ8mC,SAASlG,MAAwBs8B,EAAShiD,QAAU,GAAIgiD,EAASp5D,MAC1C,SAAhCN,EAAMxD,QAAQ8mC,SAASlG,QAAmBs8B,EAAShiD,QAAU,GAAIgiD,EAASp5D,QAGvF5R,EAAQ2R,QAAQs5D,EAAatmE,GAAGyM,EAAI45D,EAAShiD,OAAQiiD,EAAatmE,GAAG0M,EAAIg6D,EAAcL,EAASp5D,MAAON,EAAM+4B,aAAe4gC,EAAatmE,GAAG0M,EAAGC,EAAMnK,UAAY,OAAQwkC,EAAU/E,YAAa+E,EAAUpG,KAElK,GAApCj0B,EAAMxD,QAAQ0D,WAAWzD,SAC3B/N,EAAQmR,UAAU85D,EAAatmE,GAAGyM,EAAI45D,EAAShiD,OAAQiiD,EAAatmE,GAAG0M,EAAGC,EAAOq6B,EAAU/E,YAAa+E,EAAUpG,OAYxHslC,EAASO,sBAAwB,SAAUF,EAAeD,GAGxD,IAAK,GADDF,GACKpmE,EAAI,EAAGA,EAAIsmE,EAAanmE,OAAQH,IACnCA,EAAI,EAAIsmE,EAAanmE,SACvBimE,EAAe1mE,KAAK6lB,IAAI+gD,EAAatmE,EAAI,GAAGyM,EAAI65D,EAAatmE,GAAGyM,IAE9DzM,EAAI,IACNomE,EAAe1mE,KAAK8G,IAAI4/D,EAAc1mE,KAAK6lB,IAAI+gD,EAAatmE,EAAI,GAAGyM,EAAI65D,EAAatmE,GAAGyM,KAErE,GAAhB25D,IACuCplE,SAArCulE,EAAcD,EAAatmE,GAAGyM,KAChC85D,EAAcD,EAAatmE,GAAGyM,IAAMo6D,OAAQ,EAAGC,SAAU,EAAGE,YAAa,IAE3ET,EAAcD,EAAatmE,GAAGyM,GAAGo6D,QAAU,IAejDX,EAASS,iBAAmB,SAAUP,EAAcz5D,EAAOg1B,GACzD,GAAI10B,GAAOoX,CAwBX,OAvBI+hD,GAAez5D,EAAMxD,QAAQ8mC,SAAShjC,OAASm5D,EAAe,GAChEn5D,EAAuB00B,EAAfykC,EAA0BzkC,EAAWykC,EAE7C/hD,EAAS,EAC2B,QAAhC1X,EAAMxD,QAAQ8mC,SAASlG,MACzB1lB,GAAU,GAAM+hD,EAEuB,SAAhCz5D,EAAMxD,QAAQ8mC,SAASlG,QAC9B1lB,GAAU,GAAM+hD,KAKlBn5D,EAAQN,EAAMxD,QAAQ8mC,SAAShjC,MAC/BoX,EAAS,EAC2B,QAAhC1X,EAAMxD,QAAQ8mC,SAASlG,MACzB1lB,GAAU,GAAM1X,EAAMxD,QAAQ8mC,SAAShjC,MAEA,SAAhCN,EAAMxD,QAAQ8mC,SAASlG,QAC9B1lB,GAAU,GAAM1X,EAAMxD,QAAQ8mC,SAAShjC,SAInCA,MAAOA,EAAOoX,OAAQA,IAGhC6hD,EAASrzB,oBAAsB,SAASszB,EAAiB30B,EAAatG,EAAU+7B,EAAYh4C,GAC1F,GAAIk3C,EAAgBhmE,OAAS,EAAG,CAE9BgmE,EAAgBv1D,KAAK,SAAU7Q,EAAGa,GAChC,MAAIb,GAAE0M,GAAK7L,EAAE6L,EACJ1M,EAAEiyB,QAAUpxB,EAAEoxB,QAEdjyB,EAAE0M,EAAI7L,EAAE6L,GAGnB,IAAI85D,KAEJL,GAASO,sBAAsBF,EAAeJ,GAC9C30B,EAAYy1B,GAAcf,EAASgB,qBAAqBX,EAAeJ,GACvE30B,EAAYy1B,GAAYrgC,iBAAmB3X,EAC3Cic,EAASvoC,KAAKskE,KAIlBf,EAASgB,qBAAuB,SAAUX,EAAeD,GAIvD,IAAK,GAHDjjE,GACAiT,EAAOgwD,EAAa,GAAG55D,EACvB8J,EAAO8vD,EAAa,GAAG55D,EAClB1M,EAAI,EAAGA,EAAIsmE,EAAanmE,OAAQH,IACvCqD,EAAMijE,EAAatmE,GAAGyM,EACKzL,SAAvBulE,EAAcljE,IAChBiT,EAAOA,EAAOgwD,EAAatmE,GAAG0M,EAAI45D,EAAatmE,GAAG0M,EAAI4J,EACtDE,EAAOA,EAAO8vD,EAAatmE,GAAG0M,EAAI45D,EAAatmE,GAAG0M,EAAI8J,GAGtD+vD,EAAcljE,GAAK2jE,aAAeV,EAAatmE,GAAG0M,CAGtD,KAAK,GAAIy6D,KAAQZ,GACXA,EAAcjmE,eAAe6mE,KAC/B7wD,EAAOA,EAAOiwD,EAAcY,GAAMH,YAAcT,EAAcY,GAAMH,YAAc1wD,EAClFE,EAAOA,EAAO+vD,EAAcY,GAAMH,YAAcT,EAAcY,GAAMH,YAAcxwD,EAItF,QAAQhQ,IAAK8P,EAAMlP,IAAKoP,IAG1Blc,EAAOD,QAAU6rE,GAIb,SAAS5rE,EAAQD,EAASM,GAO9B,QAASkrC,GAAO7T,EAAS7oB,GACvB1O,KAAKu3B,QAAUA,EACfv3B,KAAK0O,QAAUA,EAJjB,GAAI9N,GAAUV,EAAoB,EAQlCkrC,GAAOh4B,UAAUg5B,UAAY,SAASC,GAGpC,IAAK,GAFDxwB,GAAOwwB,EAAU,GAAGp6B,EACpB8J,EAAOswB,EAAU,GAAGp6B,EACf4Z,EAAI,EAAGA,EAAIwgB,EAAU3mC,OAAQmmB,IACpChQ,EAAOA,EAAOwwB,EAAUxgB,GAAG5Z,EAAIo6B,EAAUxgB,GAAG5Z,EAAI4J,EAChDE,EAAOA,EAAOswB,EAAUxgB,GAAG5Z,EAAIo6B,EAAUxgB,GAAG5Z,EAAI8J,CAElD,QAAQhQ,IAAK8P,EAAMlP,IAAKoP,EAAMowB,iBAAkBnsC,KAAK0O,QAAQy9B,mBAG/Df,EAAOh4B,UAAUk5B,KAAO,SAASrV,EAAS/kB,EAAOq6B,EAAW3iB,GAC1DwhB,EAAOkB,KAAKrV,EAAS/kB,EAAOq6B,EAAW3iB,IAYzCwhB,EAAOkB,KAAO,SAAUrV,EAAS/kB,EAAOq6B,EAAW3iB,GAClCrjB,SAAXqjB,IAAuBA,EAAS,EACpC,KAAK,GAAIrkB,GAAI,EAAGA,EAAI0xB,EAAQvxB,OAAQH,IAClC3E,EAAQmR,UAAUklB,EAAQ1xB,GAAGyM,EAAI4X,EAAQqN,EAAQ1xB,GAAG0M,EAAGC,EAAOq6B,EAAU/E,YAAa+E,EAAUpG,MAKnGtmC,EAAOD,QAAUwrC,GAIb,SAASvrC,EAAQD,EAASM,GAE9B,GAAIysE,GAAezsE,EAAoB,IACnC0sE,EAAe1sE,EAAoB,IACnC2sE,EAAe3sE,EAAoB,IACnC4sE,EAAiB5sE,EAAoB,IACrC6sE,EAAoB7sE,EAAoB,IACxC8sE,EAAkB9sE,EAAoB,IACtC+sE,EAA0B/sE,EAAoB,GAQlDN,GAAQstE,WAAa,SAAUC,GAC7B,IAAK,GAAIC,KAAiBD,GACpBA,EAAetnE,eAAeunE,KAChCptE,KAAKotE,GAAiBD,EAAeC,KAY3CxtE,EAAQytE,YAAc,SAAUF,GAC9B,IAAK,GAAIC,KAAiBD,GACpBA,EAAetnE,eAAeunE,KAChCptE,KAAKotE,GAAiB7mE,SAW5B3G,EAAQ2jD,mBAAqB,WAC3BvjD,KAAKktE,WAAWP,GAChB3sE,KAAKstE,2BACkC,GAAnCttE,KAAKgiD,UAAUnD,iBACjB7+C,KAAKutE,4BAGLvtE,KAAKyqD,gCAUT7qD,EAAQ6jD,mBAAqB,WAC3BzjD,KAAKm8D,eAAiB,EACtBn8D,KAAKwtE,aAAe,EACpBxtE,KAAKktE,WAAWN,IASlBhtE,EAAQ4jD,kBAAoB,WAC1BxjD,KAAKuvD,WACLvvD,KAAKytE,cAAgB,WACrBztE,KAAKuvD,QAAgB,UACrBvvD,KAAKuvD,QAAgB,OAAE,YAAcjS,SACnCc,SACAgG,eACAqY,eAAkB,EAClBiR,YAAennE,QACjBvG,KAAKuvD,QAAgB,UACrBvvD,KAAKuvD,QAAiB,SAAKjS,SACzBc,SACAgG,eACAqY,eAAkB,EAClBiR,YAAennE,QAEjBvG,KAAKokD,YAAcpkD,KAAKuvD,QAAgB,OAAE,WAAwB,YAElEvvD,KAAKktE,WAAWL,IASlBjtE,EAAQ8jD,qBAAuB,WAC7B1jD,KAAKwrD,cAAgBlO,SAAWc,UAEhCp+C,KAAKktE,WAAWJ,IASlBltE,EAAQkpD,wBAA0B,WAEhC9oD,KAAK2tE,8BAA+B,EACpC3tE,KAAK4tE,sBAAuB,EAEmB,GAA3C5tE,KAAKgiD,UAAUnB,iBAAiBlyC,SAELpI,SAAzBvG,KAAK6tE,kBACP7tE,KAAK6tE,gBAAkBr8D,SAASM,cAAc,OAC9C9R,KAAK6tE,gBAAgB9lE,UAAY,0BAE/B/H,KAAK6tE,gBAAgB3gE,MAAMi7B,QADR,GAAjBnoC,KAAKuoD,SAC8B,QAGA,OAEvCvoD,KAAKuf,MAAM7N,YAAY1R,KAAK6tE,kBAGLtnE,SAArBvG,KAAK8tE,cACP9tE,KAAK8tE,YAAct8D,SAASM,cAAc,OAC1C9R,KAAK8tE,YAAY/lE,UAAY,gCAE3B/H,KAAK8tE,YAAY5gE,MAAMi7B,QADJ,GAAjBnoC,KAAKuoD,SAC0B,OAGA,QAEnCvoD,KAAKuf,MAAM7N,YAAY1R,KAAK8tE,cAGRvnE,SAAlBvG,KAAK+tE,WACP/tE,KAAK+tE,SAAWv8D,SAASM,cAAc,OACvC9R,KAAK+tE,SAAShmE,UAAY,gCAC1B/H,KAAK+tE,SAAS7gE,MAAMi7B,QAAUnoC,KAAK6tE,gBAAgB3gE,MAAMi7B,QACzDnoC,KAAKuf,MAAM7N,YAAY1R,KAAK+tE,WAI9B/tE,KAAKktE,WAAWH,GAGhB/sE,KAAKwnD,yBAGwBjhD,SAAzBvG,KAAK6tE,kBAEP7tE,KAAKwnD,wBAGLxnD,KAAKuf,MAAMnO,YAAYpR,KAAK6tE,iBAC5B7tE,KAAKuf,MAAMnO,YAAYpR,KAAK8tE,aAC5B9tE,KAAKuf,MAAMnO,YAAYpR,KAAK+tE,UAE5B/tE,KAAK6tE,gBAAkBtnE,OACvBvG,KAAK8tE,YAAcvnE,OACnBvG,KAAK+tE,SAAWxnE,OAEhBvG,KAAKqtE,YAAYN,KAWvBntE,EAAQipD,wBAA0B,WAChC7oD,KAAKktE,WAAWF,GAEhBhtE,KAAKguE,mBACoC,GAArChuE,KAAKgiD,UAAUtB,WAAW/xC,SAC5B3O,KAAKiuE,2BAUTruE,EAAQ+jD,qBAAuB,WAC7B3jD,KAAKktE,WAAWD,KAMd,SAASptE,EAAQD,EAASM,GAiB9B,QAASylD,GAAUnsC,GACjBxZ,KAAK2zD,QAAS,EAEd3zD,KAAKgwB,KACHxW,UAAWA,GAGbxZ,KAAKgwB,IAAIk+C,QAAU18D,SAASM,cAAc,OAC1C9R,KAAKgwB,IAAIk+C,QAAQnmE,UAAY,UAE7B/H,KAAKgwB,IAAIxW,UAAU9H,YAAY1R,KAAKgwB,IAAIk+C,SAExCluE,KAAK8D,OAAS+hC,EAAO7lC,KAAKgwB,IAAIk+C,SAAUnoC,iBAAiB,IACzD/lC,KAAK8D,OAAO0P,GAAG,MAAOxT,KAAKmuE,cAAcp5C,KAAK/0B,MAG9C,IAAIoU,GAAKpU,KACL0lE,GACF,QAAS,QACT,YAAa,OACb,YAAa,OAAQ,UACrB,aAAc,iBAEhBA,GAAOn9D,QAAQ,SAAUiB,GACvB4K,EAAGtQ,OAAO0P,GAAGhK,EAAO,SAAUA,GAC5BA,EAAM08B,sBAKVlmC,KAAKouE,aAAevoC,EAAOp+B,QAASs+B,iBAAiB,IACrD/lC,KAAKouE,aAAa56D,GAAG,MAAO,SAAUhK,GAE/B6kE,EAAW7kE,EAAMG,OAAQ6P,IAC5BpF,EAAGk6D,eAIe/nE,SAAlBvG,KAAKylD,UACPzlD,KAAKylD,SAASlyC,UAEhBvT,KAAKylD,SAAWA,IAGhBzlD,KAAKuuE,YAAcvuE,KAAKsuE,WAAWv5C,KAAK/0B,MAiF1C,QAASquE,GAAWvlE,EAASq8B,GAC3B,KAAOr8B,GAAS,CACd,GAAIA,IAAYq8B,EACd,OAAO,CAETr8B,GAAUA,EAAQgB,WAEpB,OAAO,EAnJT,GAAI27C,GAAWvlD,EAAoB,IAC/B8c,EAAU9c,EAAoB,IAC9B2lC,EAAS3lC,EAAoB,IAC7BS,EAAOT,EAAoB,EA4D/B8c,GAAQ2oC,EAAUvyC,WAGlBuyC,EAAU5rB,QAAU,KAKpB4rB,EAAUvyC,UAAUG,QAAU,WAC5BvT,KAAKsuE,aAGLtuE,KAAKgwB,IAAIk+C,QAAQpkE,WAAWsH,YAAYpR,KAAKgwB,IAAIk+C,SAGjDluE,KAAK8D,OAAS,KACd9D,KAAKouE,aAAe,MAQtBzoB,EAAUvyC,UAAUo7D,SAAW,WAEzB7oB,EAAU5rB,SACZ4rB,EAAU5rB,QAAQu0C,aAEpB3oB,EAAU5rB,QAAU/5B,KAEpBA,KAAK2zD,QAAS,EACd3zD,KAAKgwB,IAAIk+C,QAAQhhE,MAAMi7B,QAAU,OACjCxnC,EAAKmH,aAAa9H,KAAKgwB,IAAIxW,UAAW,cAEtCxZ,KAAK6tB,KAAK,UACV7tB,KAAK6tB,KAAK,YAIV7tB,KAAKylD,SAAS1wB,KAAK,MAAO/0B,KAAKuuE,cAOjC5oB,EAAUvyC,UAAUk7D,WAAa,WAC/BtuE,KAAK2zD,QAAS,EACd3zD,KAAKgwB,IAAIk+C,QAAQhhE,MAAMi7B,QAAU,GACjCxnC,EAAKyH,gBAAgBpI,KAAKgwB,IAAIxW,UAAW,cACzCxZ,KAAKylD,SAASgpB,OAAO,MAAOzuE,KAAKuuE,aAEjCvuE,KAAK6tB,KAAK,UACV7tB,KAAK6tB,KAAK,eAQZ83B,EAAUvyC,UAAU+6D,cAAgB,SAAU3kE,GAE5CxJ,KAAKwuE,WACLhlE,EAAM08B,mBAsBRrmC,EAAOD,QAAU+lD,GAKb,SAAS9lD,GAeb,QAASmd,GAAQgG,GACf,MAAIA,GAAYyvC,EAAMzvC,GAAtB,OAWF,QAASyvC,GAAMzvC,GACb,IAAK,GAAIpa,KAAOoU,GAAQ5J,UACtB4P,EAAIpa,GAAOoU,EAAQ5J,UAAUxK,EAE/B,OAAOoa,GAxBTnjB,EAAOD,QAAUod,EAoCjBA,EAAQ5J,UAAUI,GAClBwJ,EAAQ5J,UAAUvK,iBAAmB,SAASW,EAAO2P,GAInD,MAHAnZ,MAAK0uE,WAAa1uE,KAAK0uE,gBACtB1uE,KAAK0uE,WAAWllE,GAASxJ,KAAK0uE,WAAWllE,QACvCtB,KAAKiR,GACDnZ,MAaTgd,EAAQ5J,UAAUu7D,KAAO,SAASnlE,EAAO2P,GAIvC,QAAS3F,KACPo7D,EAAKj7D,IAAInK,EAAOgK,GAChB2F,EAAGnB,MAAMhY,KAAMyF,WALjB,GAAImpE,GAAO5uE,IAUX,OATAA,MAAK0uE,WAAa1uE,KAAK0uE,eAOvBl7D,EAAG2F,GAAKA,EACRnZ,KAAKwT,GAAGhK,EAAOgK,GACRxT,MAaTgd,EAAQ5J,UAAUO,IAClBqJ,EAAQ5J,UAAUy7D,eAClB7xD,EAAQ5J,UAAU07D,mBAClB9xD,EAAQ5J,UAAU/J,oBAAsB,SAASG,EAAO2P,GAItD,GAHAnZ,KAAK0uE,WAAa1uE,KAAK0uE,eAGnB,GAAKjpE,UAAUC,OAEjB,MADA1F,MAAK0uE,cACE1uE,IAIT,IAAI+uE,GAAY/uE,KAAK0uE,WAAWllE,EAChC,KAAKulE,EAAW,MAAO/uE,KAGvB,IAAI,GAAKyF,UAAUC,OAEjB,aADO1F,MAAK0uE,WAAWllE,GAChBxJ,IAKT,KAAK,GADDgvE,GACKzpE,EAAI,EAAGA,EAAIwpE,EAAUrpE,OAAQH,IAEpC,GADAypE,EAAKD,EAAUxpE,GACXypE,IAAO71D,GAAM61D,EAAG71D,KAAOA,EAAI,CAC7B41D,EAAUzmE,OAAO/C,EAAG,EACpB,OAGJ,MAAOvF,OAWTgd,EAAQ5J,UAAUya,KAAO,SAASrkB,GAChCxJ,KAAK0uE,WAAa1uE,KAAK0uE,cACvB,IAAIx1D,MAAUhO,MAAM3K,KAAKkF,UAAW,GAChCspE,EAAY/uE,KAAK0uE,WAAWllE,EAEhC,IAAIulE,EAAW,CACbA,EAAYA,EAAU7jE,MAAM,EAC5B,KAAK,GAAI3F,GAAI,EAAGC,EAAMupE,EAAUrpE,OAAYF,EAAJD,IAAWA,EACjDwpE,EAAUxpE,GAAGyS,MAAMhY,KAAMkZ,GAI7B,MAAOlZ,OAWTgd,EAAQ5J,UAAUqyD,UAAY,SAASj8D,GAErC,MADAxJ,MAAK0uE,WAAa1uE,KAAK0uE,eAChB1uE,KAAK0uE,WAAWllE,QAWzBwT,EAAQ5J,UAAU67D,aAAe,SAASzlE,GACxC,QAAUxJ,KAAKylE,UAAUj8D,GAAO9D,SAM9B,SAAS7F,EAAQD,GAErB,GAAIsvE,GAAgCC,EAA8BC,GAOjE,SAAU1vE,EAAMC,GAGXwvE,KAAmCD,EAAiC,EAAWE,EAA2E,kBAAnCF,GAAiDA,EAA+Bl3D,MAAMpY,EAASuvE,GAAiCD,IAAmE3oE,SAAlC6oE,IAAgDvvE,EAAOD,QAAUwvE,KAU7VpvE,KAAM,WAEN,QAASylD,GAAS/2C,GAChB,GAOInJ,GAPAgE,EAAiBmF,GAAWA,EAAQnF,iBAAkB,EAEtDiQ,EAAY9K,GAAWA,EAAQ8K,WAAa/R,OAE5C4nE,KACAC,GAAUC,WAAYC,UACtBC,IAIJ,KAAKlqE,EAAI,GAAS,KAALA,EAAUA,IAAMkqE,EAAMtrE,OAAOurE,aAAanqE,KAAOoqE,KAAK,IAAMpqE,EAAI,IAAKgM,OAAO,EAEzF,KAAKhM,EAAI,GAAS,IAALA,EAASA,IAAMkqE,EAAMtrE,OAAOurE,aAAanqE,KAAOoqE,KAAKpqE,EAAGgM,OAAO,EAE5E,KAAKhM,EAAI,EAAS,GAALA,EAAUA,IAAMkqE,EAAM,GAAKlqE,IAAMoqE,KAAK,GAAKpqE,EAAGgM,OAAO,EAElE,KAAKhM,EAAI,EAAS,IAALA,EAAWA,IAAMkqE,EAAM,IAAMlqE,IAAMoqE,KAAK,IAAMpqE,EAAGgM,OAAO,EAErE,KAAKhM,EAAI,EAAS,GAALA,EAAUA,IAAMkqE,EAAM,MAAQlqE,IAAMoqE,KAAK,GAAKpqE,EAAGgM,OAAO,EAGrEk+D,GAAM,SAAWE,KAAK,IAAKp+D,OAAO,GAClCk+D,EAAM,SAAWE,KAAK,IAAKp+D,OAAO,GAClCk+D,EAAM,SAAWE,KAAK,IAAKp+D,OAAO,GAClCk+D,EAAM,SAAWE,KAAK,IAAKp+D,OAAO,GAClCk+D,EAAM,SAAWE,KAAK,IAAKp+D,OAAO,GAElCk+D,EAAY,MAAME,KAAK,GAAIp+D,OAAO,GAClCk+D,EAAU,IAAQE,KAAK,GAAIp+D,OAAO,GAClCk+D,EAAa,OAAKE,KAAK,GAAIp+D,OAAO,GAClCk+D,EAAY,MAAME,KAAK,GAAIp+D,OAAO,GAElCk+D,EAAa,OAAKE,KAAK,GAAIp+D,OAAO,GAClCk+D,EAAa,OAAKE,KAAK,GAAIp+D,OAAO,GAClCk+D,EAAa,OAAKE,KAAK,GAAIp+D,MAAOhL,QAClCkpE,EAAW,KAAOE,KAAK,GAAIp+D,OAAO,GAClCk+D,EAAiB,WAAKE,KAAK,EAAGp+D,OAAO,GACrCk+D,EAAW,KAAWE,KAAK,EAAGp+D,OAAO,GACrCk+D,EAAY,MAAUE,KAAK,GAAIp+D,OAAO,GACtCk+D,EAAW,KAAWE,KAAK,GAAIp+D,OAAO,GACtCk+D,EAAM,WAAgBE,KAAK,GAAIp+D,OAAO,GACtCk+D,EAAc,QAAQE,KAAK,GAAIp+D,OAAO,GACtCk+D,EAAgB,UAAME,KAAK,GAAIp+D,OAAO,GAEtCk+D,EAAM,MAAYE,KAAK,IAAKp+D,OAAO,GACnCk+D,EAAM,MAAYE,KAAK,IAAKp+D,OAAO,GACnCk+D,EAAM,MAAYE,KAAK,IAAKp+D,OAAO,GACnCk+D,EAAM,MAAYE,KAAK,IAAKp+D,OAAO,EAInC,IAAIq+D,GAAO,SAASpmE,GAAQqmE,EAAYrmE,EAAM,YAC1CsmE,EAAK,SAAStmE,GAAQqmE,EAAYrmE,EAAM,UAGxCqmE,EAAc,SAASrmE,EAAM3C,GAC/B,GAAoCN,SAAhC+oE,EAAOzoE,GAAM2C,EAAMumE,SAAwB,CAE7C,IAAK,GADDC,GAAQV,EAAOzoE,GAAM2C,EAAMumE,SACtBxqE,EAAI,EAAGA,EAAIyqE,EAAMtqE,OAAQH,IACTgB,SAAnBypE,EAAMzqE,GAAGgM,MACXy+D,EAAMzqE,GAAG4T,GAAG3P,GAEa,GAAlBwmE,EAAMzqE,GAAGgM,OAAmC,GAAlB/H,EAAM6qC,SACvC27B,EAAMzqE,GAAG4T,GAAG3P,GAEa,GAAlBwmE,EAAMzqE,GAAGgM,OAAoC,GAAlB/H,EAAM6qC,UACxC27B,EAAMzqE,GAAG4T,GAAG3P,EAIM,IAAlBD,GACFC,EAAMD,kBA4FZ,OAtFA8lE,GAAiBt6C,KAAO,SAASnsB,EAAKJ,EAAU3B,GAI9C,GAHaN,SAATM,IACFA,EAAO,WAEUN,SAAfkpE,EAAM7mE,GACR,KAAM,IAAIhF,OAAM,oBAAsBgF,EAEFrC,UAAlC+oE,EAAOzoE,GAAM4oE,EAAM7mE,GAAK+mE,QAC1BL,EAAOzoE,GAAM4oE,EAAM7mE,GAAK+mE,UAE1BL,EAAOzoE,GAAM4oE,EAAM7mE,GAAK+mE,MAAMznE,MAAMiR,GAAG3Q,EAAU+I,MAAMk+D,EAAM7mE,GAAK2I,SAKpE89D,EAAiBY,QAAU,SAASznE,EAAU3B,GAC/BN,SAATM,IACFA,EAAO,UAET,KAAK,GAAI+B,KAAO6mE,GACVA,EAAM5pE,eAAe+C,IACvBymE,EAAiBt6C,KAAKnsB,EAAIJ,EAAS3B,IAMzCwoE,EAAiBa,OAAS,SAAS1mE,GACjC,IAAK,GAAIZ,KAAO6mE,GACd,GAAIA,EAAM5pE,eAAe+C,GAAM,CAC7B,GAAsB,GAAlBY,EAAM6qC,UAAwC,GAApBo7B,EAAM7mE,GAAK2I,OAAiB/H,EAAMumE,SAAWN,EAAM7mE,GAAK+mE,KACpF,MAAO/mE,EAEJ,IAAsB,GAAlBY,EAAM6qC,UAAyC,GAApBo7B,EAAM7mE,GAAK2I,OAAkB/H,EAAMumE,SAAWN,EAAM7mE,GAAK+mE,KAC3F,MAAO/mE,EAEJ,IAAIY,EAAMumE,SAAWN,EAAM7mE,GAAK+mE,MAAe,SAAP/mE,EAC3C,MAAOA,GAIb,MAAO,wCAITymE,EAAiBZ,OAAS,SAAS7lE,EAAKJ,EAAU3B,GAIhD,GAHaN,SAATM,IACFA,EAAO,WAEUN,SAAfkpE,EAAM7mE,GACR,KAAM,IAAIhF,OAAM,oBAAsBgF,EAExC,IAAiBrC,SAAbiC,EAAwB,CAC1B,GAAI2nE,MACAH,EAAQV,EAAOzoE,GAAM4oE,EAAM7mE,GAAK+mE,KACpC,IAAcppE,SAAVypE,EACF,IAAK,GAAIzqE,GAAI,EAAGA,EAAIyqE,EAAMtqE,OAAQH,KAC1ByqE,EAAMzqE,GAAG4T,IAAM3Q,GAAYwnE,EAAMzqE,GAAGgM,OAASk+D,EAAM7mE,GAAK2I,QAC5D4+D,EAAYjoE,KAAKonE,EAAOzoE,GAAM4oE,EAAM7mE,GAAK+mE,MAAMpqE,GAIrD+pE,GAAOzoE,GAAM4oE,EAAM7mE,GAAK+mE,MAAQQ,MAGhCb,GAAOzoE,GAAM4oE,EAAM7mE,GAAK+mE,UAK5BN,EAAiBxlB,MAAQ,WACvBylB,GAAUC,WAAYC,WAIxBH,EAAiB97D,QAAU,WACzB+7D,GAAUC,WAAYC,UACtBh2D,EAAUnQ,oBAAoB,UAAWumE,GAAM,GAC/Cp2D,EAAUnQ,oBAAoB,QAASymE,GAAI,IAI7Ct2D,EAAU3Q,iBAAiB,UAAU+mE,GAAK,GAC1Cp2D,EAAU3Q,iBAAiB,QAAQinE,GAAG,GAG/BT,EAGT,MAAO5pB,MAQL,SAAS5lD,EAAQD,EAASM,GAE9B,GAAIkvE,IAA0D,SAASgB,EAAQvwE,IAM/E,SAAW0G,GA+RP,QAAS8pE,GAAI/qE,EAAGa,EAAG1F,GACf,OAAQgF,UAAUC,QACd,IAAK,GAAG,MAAY,OAALJ,EAAYA,EAAIa,CAC/B,KAAK,GAAG,MAAY,OAALb,EAAYA,EAAS,MAALa,EAAYA,EAAI1F,CAC/C,SAAS,KAAM,IAAImD,OAAM,iBAIjC,QAAS0sE,GAAWhrE,EAAGa,GACnB,MAAON,IAAetF,KAAK+E,EAAGa,GAGlC,QAASoqE,KAGL,OACIC,OAAQ,EACRC,gBACAC,eACA5sD,SAAW,GACX6sD,cAAgB,EAChBC,WAAY,EACZC,aAAe,KACfC,eAAgB,EAChBC,iBAAkB,EAClBC,KAAK,GAIb,QAASC,GAASC,GACVrtE,GAAOstE,+BAAgC,GAChB,mBAAZv4C,UAA2BA,QAAQw4C,MAC9Cx4C,QAAQw4C,KAAK,wBAA0BF,GAI/C,QAASG,GAAUH,EAAK/3D,GACpB,GAAIm4D,IAAY,CAChB,OAAOjsE,GAAO,WAKV,MAJIisE,KACAL,EAASC,GACTI,GAAY,GAETn4D,EAAGnB,MAAMhY,KAAMyF,YACvB0T,GAGP,QAASo4D,GAAgBr7D,EAAMg7D,GACtBM,GAAat7D,KACd+6D,EAASC,GACTM,GAAat7D,IAAQ,GAI7B,QAASu7D,GAASC,EAAMz6D,GACpB,MAAO,UAAU3R,GACb,MAAOqsE,GAAaD,EAAKnxE,KAAKP,KAAMsF,GAAI2R,IAGhD,QAAS26D,GAAgBF,EAAMG,GAC3B,MAAO,UAAUvsE,GACb,MAAOtF,MAAK8xE,aAAaC,QAAQL,EAAKnxE,KAAKP,KAAMsF,GAAIusE,IAI7D,QAASG,GAAU1sE,EAAGa,GAElB,GAGI8rE,GAASC,EAHTC,EAA0C,IAAvBhsE,EAAEqyB,OAASlzB,EAAEkzB,SAAiBryB,EAAEwyB,QAAUrzB,EAAEqzB,SAE/DoiB,EAASz1C,EAAE+yB,QAAQnlB,IAAIi/D,EAAgB,SAa3C,OAViB,GAAbhsE,EAAI40C,GACJk3B,EAAU3sE,EAAE+yB,QAAQnlB,IAAIi/D,EAAiB,EAAG,UAE5CD,GAAU/rE,EAAI40C,IAAWA,EAASk3B,KAElCA,EAAU3sE,EAAE+yB,QAAQnlB,IAAIi/D,EAAiB,EAAG,UAE5CD,GAAU/rE,EAAI40C,IAAWk3B,EAAUl3B,MAG9Bo3B,EAAiBD,GAc9B,QAASE,GAAgB1tC,EAAQzC,EAAMowC,GACnC,GAAIC,EAEJ,OAAgB,OAAZD,EAEOpwC,EAEgB,MAAvByC,EAAO6tC,aACA7tC,EAAO6tC,aAAatwC,EAAMowC,GACX,MAAf3tC,EAAO8tC,MAEdF,EAAO5tC,EAAO8tC,KAAKH,GACfC,GAAe,GAAPrwC,IACRA,GAAQ,IAEPqwC,GAAiB,KAATrwC,IACTA,EAAO,GAEJA,GAGAA,EAQf,QAASwwC,MAIT,QAASC,GAAOC,EAAQC,GAChBA,KAAiB,GACjBC,EAAcF,GAElBG,EAAW9yE,KAAM2yE,GACjB3yE,KAAKm4B,GAAK,GAAI9zB,OAAMsuE,EAAOx6C,IAGvB46C,MAAqB,IACrBA,IAAmB,EACnBlvE,GAAOmvE,aAAahzE,MACpB+yE,IAAmB,GAK3B,QAASE,GAASljE,GACd,GAAImjE,GAAkBC,EAAqBpjE,GACvCqjE,EAAQF,EAAgB16C,MAAQ,EAChC66C,EAAWH,EAAgBI,SAAW,EACtCC,EAASL,EAAgBv6C,OAAS,EAClC66C,EAAQN,EAAgBO,MAAQ,EAChCC,EAAOR,EAAgB56C,KAAO,EAC9B+E,EAAQ61C,EAAgBjxC,MAAQ,EAChC3E,EAAU41C,EAAgBlxC,QAAU,EACpCzE,EAAU21C,EAAgBnxC,QAAU,EACpCvE,EAAe01C,EAAgBpxC,aAAe,CAGlD9hC,MAAK2zE,eAAiBn2C,EACR,IAAVD,EACU,IAAVD,EACQ,KAARD,EAGJr9B,KAAK4zE,OAASF,EACF,EAARF,EAIJxzE,KAAK6zE,SAAWN,EACD,EAAXF,EACQ,GAARD,EAEJpzE,KAAK6S,SAEL7S,KAAK8zE,QAAUjwE,GAAOiuE,aAEtB9xE,KAAK+zE,UAQT,QAAS1uE,GAAOC,EAAGa,GACf,IAAK,GAAIZ,KAAKY,GACNmqE,EAAWnqE,EAAGZ,KACdD,EAAEC,GAAKY,EAAEZ,GAYjB,OARI+qE,GAAWnqE,EAAG,cACdb,EAAEF,SAAWe,EAAEf,UAGfkrE,EAAWnqE,EAAG,aACdb,EAAEyB,QAAUZ,EAAEY,SAGXzB,EAGX,QAASwtE,GAAWxpD,EAAID,GACpB,GAAI9jB,GAAGK,EAAMouE,CAiCb,IA/BqC,mBAA1B3qD,GAAK4qD,mBACZ3qD,EAAG2qD,iBAAmB5qD,EAAK4qD,kBAER,mBAAZ5qD,GAAK6qD,KACZ5qD,EAAG4qD,GAAK7qD,EAAK6qD,IAEM,mBAAZ7qD,GAAK8qD,KACZ7qD,EAAG6qD,GAAK9qD,EAAK8qD,IAEM,mBAAZ9qD,GAAK+qD,KACZ9qD,EAAG8qD,GAAK/qD,EAAK+qD,IAEW,mBAAjB/qD,GAAKgrD,UACZ/qD,EAAG+qD,QAAUhrD,EAAKgrD,SAEG,mBAAdhrD,GAAKirD,OACZhrD,EAAGgrD,KAAOjrD,EAAKirD,MAEQ,mBAAhBjrD,GAAKkrD,SACZjrD,EAAGirD,OAASlrD,EAAKkrD,QAEO,mBAAjBlrD,GAAKmrD,UACZlrD,EAAGkrD,QAAUnrD,EAAKmrD,SAEE,mBAAbnrD,GAAKorD,MACZnrD,EAAGmrD,IAAMprD,EAAKorD,KAEU,mBAAjBprD,GAAKyqD,UACZxqD,EAAGwqD,QAAUzqD,EAAKyqD,SAGlBY,GAAiBhvE,OAAS,EAC1B,IAAKH,IAAKmvE,IACN9uE,EAAO8uE,GAAiBnvE,GACxByuE,EAAM3qD,EAAKzjB,GACQ,mBAARouE,KACP1qD,EAAG1jB,GAAQouE,EAKvB,OAAO1qD,GAGX,QAASqrD,GAASC,GACd,MAAa,GAATA,EACO3vE,KAAK+yC,KAAK48B,GAEV3vE,KAAKC,MAAM0vE,GAM1B,QAASjD,GAAaiD,EAAQC,EAAcC,GAIxC,IAHA,GAAIC,GAAS,GAAK9vE,KAAK6lB,IAAI8pD,GACvB3lD,EAAO2lD,GAAU,EAEdG,EAAOrvE,OAASmvE,GACnBE,EAAS,IAAMA,CAEnB,QAAQ9lD,EAAQ6lD,EAAY,IAAM,GAAM,KAAOC,EAGnD,QAASC,GAA0BC,EAAMtvE,GACrC,GAAIuvE,IAAO13C,aAAc,EAAG+1C,OAAQ,EAUpC,OARA2B,GAAI3B,OAAS5tE,EAAMgzB,QAAUs8C,EAAKt8C,QACC,IAA9BhzB,EAAM6yB,OAASy8C,EAAKz8C,QACrBy8C,EAAK58C,QAAQnlB,IAAIgiE,EAAI3B,OAAQ,KAAK4B,QAAQxvE,MACxCuvE,EAAI3B,OAGV2B,EAAI13C,cAAgB73B,GAAUsvE,EAAK58C,QAAQnlB,IAAIgiE,EAAI3B,OAAQ,KAEpD2B,EAGX,QAASE,GAAkBH,EAAMtvE,GAC7B,GAAIuvE,EAUJ,OATAvvE,GAAQ0vE,EAAO1vE,EAAOsvE,GAClBA,EAAKK,SAAS3vE,GACduvE,EAAMF,EAA0BC,EAAMtvE,IAEtCuvE,EAAMF,EAA0BrvE,EAAOsvE,GACvCC,EAAI13C,cAAgB03C,EAAI13C,aACxB03C,EAAI3B,QAAU2B,EAAI3B,QAGf2B,EAIX,QAASK,GAAYp6C,EAAWjlB,GAC5B,MAAO,UAAU89D,EAAKnC,GAClB,GAAI2D,GAAKC,CAUT,OARe,QAAX5D,GAAoBptE,OAAOotE,KAC3BN,EAAgBr7D,EAAM,YAAcA,EAAQ,uDAAyDA,EAAO,qBAC5Gu/D,EAAMzB,EAAKA,EAAMnC,EAAQA,EAAS4D,GAGtCzB,EAAqB,gBAARA,IAAoBA,EAAMA,EACvCwB,EAAM3xE,GAAOkM,SAASikE,EAAKnC,GAC3B6D,EAAgC11E,KAAMw1E,EAAKr6C,GACpCn7B,MAIf,QAAS01E,GAAgCC,EAAK5lE,EAAU6lE,EAAU5C,GAC9D,GAAIx1C,GAAeztB,EAAS4jE,cACxBD,EAAO3jE,EAAS6jE,MAChBL,EAASxjE,EAAS8jE,OACtBb,GAA+B,MAAhBA,GAAuB,EAAOA,EAEzCx1C,GACAm4C,EAAIx9C,GAAG09C,SAASF,EAAIx9C,GAAKqF,EAAeo4C,GAExClC,GACAoC,GAAUH,EAAK,OAAQI,GAAUJ,EAAK,QAAUjC,EAAOkC,GAEvDrC,GACAyC,GAAeL,EAAKI,GAAUJ,EAAK,SAAWpC,EAASqC,GAEvD5C,GACAnvE,GAAOmvE,aAAa2C,EAAKjC,GAAQH,GAKzC,QAASttE,GAAQgwE,GACb,MAAiD,mBAA1C3vE,OAAO8M,UAAUhO,SAAS7E,KAAK01E,GAG1C,QAAS7xE,GAAO6xE,GACZ,MAAiD,kBAA1C3vE,OAAO8M,UAAUhO,SAAS7E,KAAK01E,IAClCA,YAAiB5xE,MAIzB,QAAS6xE,GAAc7S,EAAQC,EAAQ6S,GACnC,GAGI5wE,GAHAC,EAAMP,KAAK8G,IAAIs3D,EAAO39D,OAAQ49D,EAAO59D,QACrC0wE,EAAanxE,KAAK6lB,IAAIu4C,EAAO39D,OAAS49D,EAAO59D,QAC7C2wE,EAAQ,CAEZ,KAAK9wE,EAAI,EAAOC,EAAJD,EAASA,KACZ4wE,GAAe9S,EAAO99D,KAAO+9D,EAAO/9D,KACnC4wE,GAAeG,EAAMjT,EAAO99D,MAAQ+wE,EAAMhT,EAAO/9D,MACnD8wE,GAGR,OAAOA,GAAQD,EAGnB,QAASG,GAAeC,GACpB,GAAIA,EAAO,CACP,GAAIC,GAAUD,EAAM5xC,cAAcn6B,QAAQ,QAAS,KACnD+rE,GAAQE,GAAYF,IAAUG,GAAeF,IAAYA,EAE7D,MAAOD,GAGX,QAASrD,GAAqByD,GAC1B,GACIC,GACAjxE,EAFAstE,IAIJ,KAAKttE,IAAQgxE,GACLtG,EAAWsG,EAAahxE,KACxBixE,EAAiBN,EAAe3wE,GAC5BixE,IACA3D,EAAgB2D,GAAkBD,EAAYhxE,IAK1D,OAAOstE,GAGX,QAAS4D,GAAS/nE,GACd,GAAIkI,GAAO8/D,CAEX,IAA8B,IAA1BhoE,EAAMrI,QAAQ,QACduQ,EAAQ,EACR8/D,EAAS,UAER,CAAA,GAA+B,IAA3BhoE,EAAMrI,QAAQ,SAKnB,MAJAuQ,GAAQ,GACR8/D,EAAS,QAMblzE,GAAOkL,GAAS,SAAU4yB,EAAQt5B,GAC9B,GAAI9C,GAAGyxE,EACH/9D,EAASpV,GAAOiwE,QAAQ/kE,GACxBkoE,IAYJ,IAVsB,gBAAXt1C,KACPt5B,EAAQs5B,EACRA,EAASp7B,GAGbywE,EAAS,SAAUzxE,GACf,GAAI/E,GAAIqD,KAASqzE,MAAMC,IAAIJ,EAAQxxE,EACnC,OAAO0T,GAAO1Y,KAAKsD,GAAOiwE,QAAStzE,EAAGmhC,GAAU,KAGvC,MAATt5B,EACA,MAAO2uE,GAAO3uE,EAGd,KAAK9C,EAAI,EAAO0R,EAAJ1R,EAAWA,IACnB0xE,EAAQ/uE,KAAK8uE,EAAOzxE,GAExB,OAAO0xE,IAKnB,QAASX,GAAMc,GACX,GAAIC,IAAiBD,EACjBhwE,EAAQ,CAUZ,OARsB,KAAlBiwE,GAAuBC,SAASD,KAE5BjwE,EADAiwE,GAAiB,EACTpyE,KAAKC,MAAMmyE,GAEXpyE,KAAK+yC,KAAKq/B,IAInBjwE,EAGX,QAASmwE,GAAY/+C,EAAMG,GACvB,MAAO,IAAIt0B,MAAKA,KAAKmzE,IAAIh/C,EAAMG,EAAQ,EAAG,IAAI8+C,aAGlD,QAASC,GAAYl/C,EAAMm/C,EAAKC,GAC5B,MAAOC,IAAWh0E,IAAQ20B,EAAM,GAAI,GAAKm/C,EAAMC,IAAOD,EAAKC,GAAKnE,KAGpE,QAASqE,GAAWt/C,GAChB,MAAOu/C,GAAWv/C,GAAQ,IAAM,IAGpC,QAASu/C,GAAWv/C,GAChB,MAAQA,GAAO,IAAM,GAAKA,EAAO,MAAQ,GAAMA,EAAO,MAAQ,EAGlE,QAASq6C,GAAcryE,GACnB,GAAIsjB,EACAtjB,GAAEw3E,IAAyB,KAAnBx3E,EAAEi0E,IAAI3wD,WACdA,EACItjB,EAAEw3E,GAAGC,IAAS,GAAKz3E,EAAEw3E,GAAGC,IAAS,GAAKA,GACtCz3E,EAAEw3E,GAAGE,IAAQ,GAAK13E,EAAEw3E,GAAGE,IAAQX,EAAY/2E,EAAEw3E,GAAGG,IAAO33E,EAAEw3E,GAAGC,KAAUC,GACtE13E,EAAEw3E,GAAGI,IAAQ,GAAK53E,EAAEw3E,GAAGI,IAAQ,IACX,KAAf53E,EAAEw3E,GAAGI,MAAkC,IAAjB53E,EAAEw3E,GAAGK,KACY,IAAjB73E,EAAEw3E,GAAGM,KACiB,IAAtB93E,EAAEw3E,GAAGO,KAAuBH,GACvD53E,EAAEw3E,GAAGK,IAAU,GAAK73E,EAAEw3E,GAAGK,IAAU,GAAKA,GACxC73E,EAAEw3E,GAAGM,IAAU,GAAK93E,EAAEw3E,GAAGM,IAAU,GAAKA,GACxC93E,EAAEw3E,GAAGO,IAAe,GAAK/3E,EAAEw3E,GAAGO,IAAe,IAAMA,GACnD,GAEA/3E,EAAEi0E,IAAI+D,qBAAkCL,GAAXr0D,GAAmBA,EAAWo0D,MAC3Dp0D,EAAWo0D,IAGf13E,EAAEi0E,IAAI3wD,SAAWA,GAIzB,QAAS20D,GAAQj4E,GAiBb,MAhBkB,OAAdA,EAAEk4E,WACFl4E,EAAEk4E,UAAYj0E,MAAMjE,EAAE23B,GAAGwgD,YACrBn4E,EAAEi0E,IAAI3wD,SAAW,IAChBtjB,EAAEi0E,IAAIjE,QACNhwE,EAAEi0E,IAAI5D,eACNrwE,EAAEi0E,IAAI7D,YACNpwE,EAAEi0E,IAAI3D,gBACNtwE,EAAEi0E,IAAI1D,gBAEPvwE,EAAE6zE,UACF7zE,EAAEk4E,SAAWl4E,EAAEk4E,UACa,IAAxBl4E,EAAEi0E,IAAI9D,eACwB,IAA9BnwE,EAAEi0E,IAAIhE,aAAa/qE,QACnBlF,EAAEi0E,IAAImE,UAAYryE,IAGvB/F,EAAEk4E,SAGb,QAASG,GAAgBjwE,GACrB,MAAOA,GAAMA,EAAIg8B,cAAcn6B,QAAQ,IAAK,KAAO7B,EAMvD,QAASkwE,GAAaC,GAGlB,IAFA,GAAWltD,GAAGvD,EAAMoc,EAAQz8B,EAAxB1C,EAAI,EAEDA,EAAIwzE,EAAMrzE,QAAQ,CAKrB,IAJAuC,EAAQ4wE,EAAgBE,EAAMxzE,IAAI0C,MAAM,KACxC4jB,EAAI5jB,EAAMvC,OACV4iB,EAAOuwD,EAAgBE,EAAMxzE,EAAI,IACjC+iB,EAAOA,EAAOA,EAAKrgB,MAAM,KAAO,KACzB4jB,EAAI,GAAG,CAEV,GADA6Y,EAASs0C,EAAW/wE,EAAMiD,MAAM,EAAG2gB,GAAG1jB,KAAK,MAEvC,MAAOu8B,EAEX,IAAIpc,GAAQA,EAAK5iB,QAAUmmB,GAAKqqD,EAAcjuE,EAAOqgB,GAAM,IAASuD,EAAI,EAEpE,KAEJA,KAEJtmB,IAEJ,MAAO,MAGX,QAASyzE,GAAW9iE,GAChB,GAAI+iE,GAAY,IAChB,KAAK/zC,GAAQhvB,IAASgjE,GAClB,IACID,EAAYp1E,GAAO6gC,UACjB,WAAkC,GAAI3N,GAAI,GAAInzB,OAAM,gCAAiE,MAA7BmzB,GAAE44C,KAAO,mBAA0B54C,KAE7HlzB,GAAO6gC,OAAOu0C,GAChB,MAAOliD,IAEb,MAAOmO,IAAQhvB,GAKnB,QAASm/D,GAAOY,EAAOkD,GACnB,GAAIjE,GAAK5oD,CACT,OAAI6sD,GAAM5E,QACNW,EAAMiE,EAAM9gD,QACZ/L,GAAQzoB,GAAOmD,SAASivE,IAAU7xE,EAAO6xE,IAChCA,GAASpyE,GAAOoyE,KAAYf,EAErCA,EAAI/8C,GAAG09C,SAASX,EAAI/8C,GAAK7L,GACzBzoB,GAAOmvE,aAAakC,GAAK,GAClBA,GAEArxE,GAAOoyE,GAAOmD,QA6N7B,QAASC,GAAuBpD,GAC5B,MAAIA,GAAM3xE,MAAM,YACL2xE,EAAMxrE,QAAQ,WAAY,IAE9BwrE,EAAMxrE,QAAQ,MAAO,IAGhC,QAAS6uE,GAAmB33C,GACxB,GAA4Cp8B,GAAGG,EAA3CgD,EAAQi5B,EAAOr9B,MAAMi1E,GAEzB,KAAKh0E,EAAI,EAAGG,EAASgD,EAAMhD,OAAYA,EAAJH,EAAYA,IAEvCmD,EAAMnD,GADNi0E,GAAqB9wE,EAAMnD,IAChBi0E,GAAqB9wE,EAAMnD,IAE3B8zE,EAAuB3wE,EAAMnD,GAIhD,OAAO,UAAUowE,GACb,GAAIZ,GAAS,EACb,KAAKxvE,EAAI,EAAOG,EAAJH,EAAYA,IACpBwvE,GAAUrsE,EAAMnD,YAAc+rC,UAAW5oC,EAAMnD,GAAGhF,KAAKo1E,EAAKh0C,GAAUj5B,EAAMnD,EAEhF,OAAOwvE,IAKf,QAAS0E,GAAaj5E,EAAGmhC,GACrB,MAAKnhC,GAAEi4E,WAIP92C,EAAS+3C,EAAa/3C,EAAQnhC,EAAEsxE,cAE3B6H,GAAgBh4C,KACjBg4C,GAAgBh4C,GAAU23C,EAAmB33C,IAG1Cg4C,GAAgBh4C,GAAQnhC,IATpBA,EAAEsxE,aAAa8H,cAY9B,QAASF,GAAa/3C,EAAQ+C,GAG1B,QAASm1C,GAA4B5D,GACjC,MAAOvxC,GAAOo1C,eAAe7D,IAAUA,EAH3C,GAAI1wE,GAAI,CAOR,KADAw0E,GAAsBC,UAAY,EAC3Bz0E,GAAK,GAAKw0E,GAAsB9rE,KAAK0zB,IACxCA,EAASA,EAAOl3B,QAAQsvE,GAAuBF,GAC/CE,GAAsBC,UAAY,EAClCz0E,GAAK,CAGT,OAAOo8B,GAUX,QAASs4C,GAAsBlY,EAAO4Q,GAClC,GAAIrtE,GAAGk9D,EAASmQ,EAAO0B,OACvB,QAAQtS,GACR,IAAK,IACD,MAAOmY,GACX,KAAK,OACD,MAAOC,GACX,KAAK,OACL,IAAK,OACL,IAAK,OACD,MAAO3X,GAAS4X,GAAuBC,EAC3C,KAAK,IACL,IAAK,IACL,IAAK,IACD,MAAOC,GACX,KAAK,SACL,IAAK,QACL,IAAK,QACL,IAAK,QACD,MAAO9X,GAAS+X,GAAsBC,EAC1C,KAAK,IACD,GAAIhY,EACA,MAAO0X,GAGf,KAAK,KACD,GAAI1X,EACA,MAAOiY,GAGf,KAAK,MACD,GAAIjY,EACA,MAAO2X,GAGf,KAAK,MACD,MAAOO,GACX,KAAK,MACL,IAAK,OACL,IAAK,KACL,IAAK,MACL,IAAK,OACD,MAAOC,GACX,KAAK,IACL,IAAK,IACD,MAAOhI,GAAOmB,QAAQ8G,cAC1B,KAAK,IACD,MAAOC,GACX,KAAK,IACD,MAAOC,GACX,KAAK,IACL,IAAK,KACD,MAAOC,GACX,KAAK,IACD,MAAOC,GACX,KAAK,OACD,MAAOC,GACX,KAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,KACD,MAAOzY,GAASiY,GAAsBS,EAC1C,KAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACD,MAAOA,GACX,KAAK,KACD,MAAO1Y,GAASmQ,EAAOmB,QAAQqH,cAAgBxI,EAAOmB,QAAQsH,oBAClE,SAEI,MADA91E,GAAI,GAAI+1E,QAAOC,GAAaC,GAAexZ,EAAMt3D,QAAQ,KAAM,KAAM,OAK7E,QAAS+wE,GAAoBC,GACzBA,EAASA,GAAU,EACnB,IAAIC,GAAqBD,EAAOn3E,MAAMy2E,QAClCY,EAAUD,EAAkBA,EAAkBh2E,OAAS,OACvD0H,GAASuuE,EAAU,IAAIr3E,MAAMs3E,MAA0B,IAAK,EAAG,GAC/Dt+C,IAAuB,GAAXlwB,EAAM,IAAWkpE,EAAMlpE,EAAM,GAE7C,OAAoB,MAAbA,EAAM,GAAakwB,GAAWA,EAIzC,QAASu+C,GAAwB9Z,EAAOkU,EAAOtD,GAC3C,GAAIrtE,GAAGw2E,EAAgBnJ,EAAOqF,EAE9B,QAAQjW,GAER,IAAK,IACY,MAATkU,IACA6F,EAAc7D,IAA8B,GAApB3B,EAAML,GAAS,GAE3C,MAEJ,KAAK,IACL,IAAK,KACY,MAATA,IACA6F,EAAc7D,IAAS3B,EAAML,GAAS,EAE1C,MACJ,KAAK,MACL,IAAK,OACD3wE,EAAIqtE,EAAOmB,QAAQiI,YAAY9F,EAAOlU,EAAO4Q,EAAO0B,SAE3C,MAAL/uE,EACAw2E,EAAc7D,IAAS3yE,EAEvBqtE,EAAO8B,IAAI5D,aAAeoF,CAE9B,MAEJ,KAAK,IACL,IAAK,KACY,MAATA,IACA6F,EAAc5D,IAAQ5B,EAAML,GAEhC,MACJ,KAAK,KACY,MAATA,IACA6F,EAAc5D,IAAQ5B,EAAMzrE,SAChBorE,EAAM3xE,MAAM,WAAW,GAAI,KAE3C,MAEJ,KAAK,MACL,IAAK,OACY,MAAT2xE,IACAtD,EAAOqJ,WAAa1F,EAAML,GAG9B,MAEJ,KAAK,KACD6F,EAAc3D,IAAQt0E,GAAOo4E,kBAAkBhG,EAC/C,MACJ,KAAK,OACL,IAAK,QACL,IAAK,SACD6F,EAAc3D,IAAQ7B,EAAML,EAC5B,MAEJ,KAAK,IACL,IAAK,IACDtD,EAAOuJ,UAAYjG,CAEnB,MAEJ,KAAK,IACL,IAAK,KACDtD,EAAO8B,IAAImE,SAAU,CAEzB,KAAK,IACL,IAAK,KACDkD,EAAc1D,IAAQ9B,EAAML,EAC5B,MAEJ,KAAK,IACL,IAAK,KACD6F,EAAczD,IAAU/B,EAAML,EAC9B,MAEJ,KAAK,IACL,IAAK,KACD6F,EAAcxD,IAAUhC,EAAML,EAC9B,MAEJ,KAAK,IACL,IAAK,KACL,IAAK,MACL,IAAK,OACD6F,EAAcvD,IAAejC,EAAuB,KAAhB,KAAOL,GAC3C,MAEJ,KAAK,IACDtD,EAAOx6C,GAAK,GAAI9zB,MAAKiyE,EAAML,GAC3B,MAEJ,KAAK,IACDtD,EAAOx6C,GAAK,GAAI9zB,MAAyB,IAApBihB,WAAW2wD,GAChC,MAEJ,KAAK,IACL,IAAK,KACDtD,EAAOwJ,SAAU,EACjBxJ,EAAO2B,KAAOkH,EAAoBvF,EAClC,MAEJ,KAAK,KACL,IAAK,MACL,IAAK,OACD3wE,EAAIqtE,EAAOmB,QAAQsI,cAAcnG,GAExB,MAAL3wE,GACAqtE,EAAO0J,GAAK1J,EAAO0J,OACnB1J,EAAO0J,GAAM,EAAI/2E,GAEjBqtE,EAAO8B,IAAI6H,eAAiBrG,CAEhC,MAEJ,KAAK,IACL,IAAK,KACL,IAAK,IACL,IAAK,KACL,IAAK,IACL,IAAK,IACL,IAAK,IACDlU,EAAQA,EAAMx2D,OAAO,EAAG,EAE5B,KAAK,OACL,IAAK,OACL,IAAK,QACDw2D,EAAQA,EAAMx2D,OAAO,EAAG,GACpB0qE,IACAtD,EAAO0J,GAAK1J,EAAO0J,OACnB1J,EAAO0J,GAAGta,GAASuU,EAAML,GAE7B,MACJ,KAAK,KACL,IAAK,KACDtD,EAAO0J,GAAK1J,EAAO0J,OACnB1J,EAAO0J,GAAGta,GAASl+D,GAAOo4E,kBAAkBhG,IAIpD,QAASsG,GAAsB5J,GAC3B,GAAIjjB,GAAG8sB,EAAU/I,EAAMvxC,EAASy1C,EAAKC,EAAK6E,CAE1C/sB,GAAIijB,EAAO0J,GACC,MAAR3sB,EAAEgtB,IAAqB,MAAPhtB,EAAEitB,GAAoB,MAAPjtB,EAAEktB,GACjCjF,EAAM,EACNC,EAAM,EAMN4E,EAAWnM,EAAI3gB,EAAEgtB,GAAI/J,EAAOqF,GAAGG,IAAON,GAAWh0E,KAAU,EAAG,GAAG20B,MACjEi7C,EAAOpD,EAAI3gB,EAAEitB,EAAG,GAChBz6C,EAAUmuC,EAAI3gB,EAAEktB,EAAG,KAEnBjF,EAAMhF,EAAOmB,QAAQ+I,MAAMlF,IAC3BC,EAAMjF,EAAOmB,QAAQ+I,MAAMjF,IAE3B4E,EAAWnM,EAAI3gB,EAAEotB,GAAInK,EAAOqF,GAAGG,IAAON,GAAWh0E,KAAU8zE,EAAKC,GAAKp/C,MACrEi7C,EAAOpD,EAAI3gB,EAAEA,EAAG,GAEL,MAAPA,EAAE9iD,GAEFs1B,EAAUwtB,EAAE9iD,EACE+qE,EAAVz1C,KACEuxC,GAINvxC,EAFc,MAAPwtB,EAAE34B,EAEC24B,EAAE34B,EAAI4gD,EAGNA,GAGlB8E,EAAOM,GAAmBP,EAAU/I,EAAMvxC,EAAS01C,EAAKD,GAExDhF,EAAOqF,GAAGG,IAAQsE,EAAKjkD,KACvBm6C,EAAOqJ,WAAaS,EAAKlkD,UAO7B,QAASykD,GAAerK,GACpB,GAAIptE,GAAGmzB,EAAkBukD,EAAaC,EAAzBjH,IAEb,KAAItD,EAAOx6C,GAAX,CA6BA,IAzBA8kD,EAAcE,GAAiBxK,GAG3BA,EAAO0J,IAAyB,MAAnB1J,EAAOqF,GAAGE,KAAqC,MAApBvF,EAAOqF,GAAGC,KAClDsE,EAAsB5J,GAItBA,EAAOqJ,aACPkB,EAAY7M,EAAIsC,EAAOqF,GAAGG,IAAO8E,EAAY9E,KAEzCxF,EAAOqJ,WAAalE,EAAWoF,KAC/BvK,EAAO8B,IAAI+D,oBAAqB,GAGpC9/C,EAAO0kD,GAAYF,EAAW,EAAGvK,EAAOqJ,YACxCrJ,EAAOqF,GAAGC,IAASv/C,EAAK2kD,cACxB1K,EAAOqF,GAAGE,IAAQx/C,EAAK++C,cAQtBlyE,EAAI,EAAO,EAAJA,GAAyB,MAAhBotE,EAAOqF,GAAGzyE,KAAcA,EACzCotE,EAAOqF,GAAGzyE,GAAK0wE,EAAM1wE,GAAK03E,EAAY13E,EAI1C,MAAW,EAAJA,EAAOA,IACVotE,EAAOqF,GAAGzyE,GAAK0wE,EAAM1wE,GAAsB,MAAhBotE,EAAOqF,GAAGzyE,GAAqB,IAANA,EAAU,EAAI,EAAKotE,EAAOqF,GAAGzyE,EAI7D,MAApBotE,EAAOqF,GAAGI,KACgB,IAAtBzF,EAAOqF,GAAGK,KACY,IAAtB1F,EAAOqF,GAAGM,KACiB,IAA3B3F,EAAOqF,GAAGO,MACd5F,EAAO2K,UAAW,EAClB3K,EAAOqF,GAAGI,IAAQ,GAGtBzF,EAAOx6C,IAAMw6C,EAAOwJ,QAAUiB,GAAcG,IAAUvlE,MAAM,KAAMi+D,GAG/C,MAAftD,EAAO2B,MACP3B,EAAOx6C,GAAGqlD,cAAc7K,EAAOx6C,GAAGslD,gBAAkB9K,EAAO2B,MAG3D3B,EAAO2K,WACP3K,EAAOqF,GAAGI,IAAQ,KAI1B,QAASsF,GAAe/K,GACpB,GAAIO,EAEAP,GAAOx6C,KAIX+6C,EAAkBC,EAAqBR,EAAOuB,IAC9CvB,EAAOqF,IACH9E,EAAgB16C,KAChB06C,EAAgBv6C,MAChBu6C,EAAgB56C,KAAO46C,EAAgBx6C,KACvCw6C,EAAgBjxC,KAChBixC,EAAgBlxC,OAChBkxC,EAAgBnxC,OAChBmxC,EAAgBpxC,aAGpBk7C,EAAerK,IAGnB,QAASwK,IAAiBxK,GACtB,GAAIv1C,GAAM,GAAI/4B,KACd,OAAIsuE,GAAOwJ,SAEH/+C,EAAIugD,iBACJvgD,EAAIigD,cACJjgD,EAAIq6C,eAGAr6C,EAAIoF,cAAepF,EAAIgG,WAAYhG,EAAI+F,WAKvD,QAASy6C,IAA4BjL,GACjC,GAAIA,EAAOwB,KAAOtwE,GAAOg6E,SAErB,WADAC,IAASnL,EAIbA,GAAOqF,MACPrF,EAAO8B,IAAIjE,OAAQ,CAGnB,IACIjrE,GAAGw4E,EAAaC,EAAQjc,EAAOkc,EAD/BxC,EAAS,GAAK9I,EAAOuB,GAErBgK,EAAezC,EAAO/1E,OACtBy4E,EAAyB,CAI7B,KAFAH,EAAStE,EAAa/G,EAAOwB,GAAIxB,EAAOmB,SAASxvE,MAAMi1E,QAElDh0E,EAAI,EAAGA,EAAIy4E,EAAOt4E,OAAQH,IAC3Bw8D,EAAQic,EAAOz4E,GACfw4E,GAAetC,EAAOn3E,MAAM21E,EAAsBlY,EAAO4Q,SAAgB,GACrEoL,IACAE,EAAUxC,EAAOlwE,OAAO,EAAGkwE,EAAO/0E,QAAQq3E,IACtCE,EAAQv4E,OAAS,GACjBitE,EAAO8B,IAAI/D,YAAYxoE,KAAK+1E,GAEhCxC,EAASA,EAAOvwE,MAAMuwE,EAAO/0E,QAAQq3E,GAAeA,EAAYr4E,QAChEy4E,GAA0BJ,EAAYr4E,QAGtC8zE,GAAqBzX,IACjBgc,EACApL,EAAO8B,IAAIjE,OAAQ,EAGnBmC,EAAO8B,IAAIhE,aAAavoE,KAAK65D,GAEjC8Z,EAAwB9Z,EAAOgc,EAAapL,IAEvCA,EAAO0B,UAAY0J,GACxBpL,EAAO8B,IAAIhE,aAAavoE,KAAK65D,EAKrC4Q,GAAO8B,IAAI9D,cAAgBuN,EAAeC,EACtC1C,EAAO/1E,OAAS,GAChBitE,EAAO8B,IAAI/D,YAAYxoE,KAAKuzE,GAI5B9I,EAAO8B,IAAImE,WAAY,GAAQjG,EAAOqF,GAAGI,KAAS,KAClDzF,EAAO8B,IAAImE,QAAUryE,GAGzBosE,EAAOqF,GAAGI,IAAQhG,EAAgBO,EAAOmB,QAASnB,EAAOqF,GAAGI,IACpDzF,EAAOuJ,WACfc,EAAerK,GACfE,EAAcF,GAGlB,QAAS4I,IAAe1vE,GACpB,MAAOA,GAAEpB,QAAQ,sCAAuC,SAAU2zE,EAAS7T,EAAIC,EAAIC,EAAI4T,GACnF,MAAO9T,IAAMC,GAAMC,GAAM4T,IAKjC,QAAS/C,IAAazvE,GAClB,MAAOA,GAAEpB,QAAQ,yBAA0B,QAI/C,QAAS6zE,IAA2B3L,GAChC,GAAI4L,GACAC,EAEAC,EACAl5E,EACAm5E,CAEJ,IAAyB,IAArB/L,EAAOwB,GAAGzuE,OAGV,MAFAitE,GAAO8B,IAAI3D,eAAgB,OAC3B6B,EAAOx6C,GAAK,GAAI9zB,MAAKs6E,KAIzB,KAAKp5E,EAAI,EAAGA,EAAIotE,EAAOwB,GAAGzuE,OAAQH,IAC9Bm5E,EAAe,EACfH,EAAazL,KAAeH,GACN,MAAlBA,EAAOwJ,UACPoC,EAAWpC,QAAUxJ,EAAOwJ,SAEhCoC,EAAW9J,IAAMlE,IACjBgO,EAAWpK,GAAKxB,EAAOwB,GAAG5uE,GAC1Bq4E,GAA4BW,GAEvB9F,EAAQ8F,KAKbG,GAAgBH,EAAW9J,IAAI9D,cAG/B+N,GAAqD,GAArCH,EAAW9J,IAAIhE,aAAa/qE,OAE5C64E,EAAW9J,IAAImK,MAAQF,GAEJ,MAAfD,GAAsCA,EAAfC,KACvBD,EAAcC,EACdF,EAAaD,GAIrBl5E,GAAOstE,EAAQ6L,GAAcD,GAIjC,QAAST,IAASnL,GACd,GAAIptE,GAAGs5E,EACHpD,EAAS9I,EAAOuB,GAChB5vE,EAAQw6E,GAASt6E,KAAKi3E,EAE1B,IAAIn3E,EAAO,CAEP,IADAquE,EAAO8B,IAAIzD,KAAM,EACZzrE,EAAI,EAAGs5E,EAAIE,GAASr5E,OAAYm5E,EAAJt5E,EAAOA,IACpC,GAAIw5E,GAASx5E,GAAG,GAAGf,KAAKi3E,GAAS,CAE7B9I,EAAOwB,GAAK4K,GAASx5E,GAAG,IAAMjB,EAAM,IAAM,IAC1C,OAGR,IAAKiB,EAAI,EAAGs5E,EAAIG,GAASt5E,OAAYm5E,EAAJt5E,EAAOA,IACpC,GAAIy5E,GAASz5E,GAAG,GAAGf,KAAKi3E,GAAS,CAC7B9I,EAAOwB,IAAM6K,GAASz5E,GAAG,EACzB,OAGJk2E,EAAOn3E,MAAMy2E,MACbpI,EAAOwB,IAAM,KAEjByJ,GAA4BjL,OAE5BA,GAAO+F,UAAW,EAK1B,QAASuG,IAAmBtM,GACxBmL,GAASnL,GACLA,EAAO+F,YAAa,UACb/F,GAAO+F,SACd70E,GAAOq7E,wBAAwBvM,IAIvC,QAASrlE,IAAIotC,EAAKvhC,GACd,GAAc5T,GAAV2vE,IACJ,KAAK3vE,EAAI,EAAGA,EAAIm1C,EAAIh1C,SAAUH,EAC1B2vE,EAAIhtE,KAAKiR,EAAGuhC,EAAIn1C,GAAIA,GAExB,OAAO2vE,GAGX,QAASiK,IAAkBxM,GACvB,GAAuByL,GAAnBnI,EAAQtD,EAAOuB,EACf+B,KAAU1vE,EACVosE,EAAOx6C,GAAK,GAAI9zB,MACTD,EAAO6xE,GACdtD,EAAOx6C,GAAK,GAAI9zB,OAAM4xE,GAC6B,QAA3CmI,EAAUgB,GAAgB56E,KAAKyxE,IACvCtD,EAAOx6C,GAAK,GAAI9zB,OAAM+5E,EAAQ,IACN,gBAAVnI,GACdgJ,GAAmBtM,GACZ1sE,EAAQgwE,IACftD,EAAOqF,GAAK1qE,GAAI2oE,EAAM/qE,MAAM,GAAI,SAAU8X,GACtC,MAAOnY,UAASmY,EAAK,MAEzBg6D,EAAerK,IACU,gBAAZ,GACb+K,EAAe/K,GACU,gBAAZ,GAEbA,EAAOx6C,GAAK,GAAI9zB,MAAK4xE,GAErBpyE,GAAOq7E,wBAAwBvM,GAIvC,QAAS4K,IAAStrE,EAAGzR,EAAGoM,EAAGhB,EAAGs/D,EAAGr/D,EAAGwzE,GAGhC,GAAI3mD,GAAO,GAAIr0B,MAAK4N,EAAGzR,EAAGoM,EAAGhB,EAAGs/D,EAAGr/D,EAAGwzE,EAMtC,OAHQ,MAAJptE,GACAymB,EAAK6J,YAAYtwB,GAEdymB,EAGX,QAAS0kD,IAAYnrE,GACjB,GAAIymB,GAAO,GAAIr0B,MAAKA,KAAKmzE,IAAIx/D,MAAM,KAAMvS,WAIzC,OAHQ,MAAJwM,GACAymB,EAAK4mD,eAAertE,GAEjBymB,EAGX,QAAS6mD,IAAatJ,EAAOvxC,GACzB,GAAqB,gBAAVuxC,GACP,GAAKxxE,MAAMwxE,IAKP,GADAA,EAAQvxC,EAAO03C,cAAcnG,GACR,gBAAVA,GACP,MAAO,UALXA,GAAQprE,SAASorE,EAAO,GAShC,OAAOA,GASX,QAASuJ,IAAkB/D,EAAQ7G,EAAQ6K,EAAeC,EAAUh7C,GAChE,MAAOA,GAAOi7C,aAAa/K,GAAU,IAAK6K,EAAehE,EAAQiE,GAGrE,QAASC,IAAaC,EAAgBH,EAAe/6C,GACjD,GAAI30B,GAAWlM,GAAOkM,SAAS6vE,GAAgB90D,MAC3CyS,EAAU5P,GAAM5d,EAASmf,GAAG,MAC5BoO,EAAU3P,GAAM5d,EAASmf,GAAG,MAC5BmO,EAAQ1P,GAAM5d,EAASmf,GAAG,MAC1BwkD,EAAO/lD,GAAM5d,EAASmf,GAAG,MACzBqkD,EAAS5lD,GAAM5d,EAASmf,GAAG,MAC3BkkD,EAAQzlD,GAAM5d,EAASmf,GAAG,MAE1BhW,EAAOqkB,EAAUsiD,GAAuBh0E,IAAM,IAAK0xB,IACnC,IAAZD,IAAkB,MAClBA,EAAUuiD,GAAuBr/E,IAAM,KAAM88B,IACnC,IAAVD,IAAgB,MAChBA,EAAQwiD,GAAuBj0E,IAAM,KAAMyxB,IAClC,IAATq2C,IAAe,MACfA,EAAOmM,GAAuBjzE,IAAM,KAAM8mE,IAC/B,IAAXH,IAAiB,MACjBA,EAASsM,GAAuB3U,IAAM,KAAMqI,IAClC,IAAVH,IAAgB,OAAS,KAAMA,EAKvC,OAHAl6D,GAAK,GAAKumE,EACVvmE,EAAK,IAAM0mE,EAAiB,EAC5B1mE,EAAK,GAAKwrB,EACH86C,GAAkBxnE,SAAUkB,GAgBvC,QAAS2+D,IAAWlC,EAAKmK,EAAgBC,GACrC,GAEIC,GAFAlwE,EAAMiwE,EAAuBD,EAC7BG,EAAkBF,EAAuBpK,EAAIr9C,KAajD,OATI2nD,GAAkBnwE,IAClBmwE,GAAmB,GAGDnwE,EAAM,EAAxBmwE,IACAA,GAAmB,GAGvBD,EAAiBn8E,GAAO8xE,GAAKziE,IAAI+sE,EAAiB,MAE9CxM,KAAMxuE,KAAK+yC,KAAKgoC,EAAeznD,YAAc,GAC7CC,KAAMwnD,EAAexnD,QAK7B,QAASukD,IAAmBvkD,EAAMi7C,EAAMvxC,EAAS69C,EAAsBD,GACnE,GAA6CI,GAAW3nD,EAApD3rB,EAAIwwE,GAAY5kD,EAAM,EAAG,GAAG2nD,WAOhC,OALAvzE,GAAU,IAANA,EAAU,EAAIA,EAClBs1B,EAAqB,MAAXA,EAAkBA,EAAU49C,EACtCI,EAAYJ,EAAiBlzE,GAAKA,EAAImzE,EAAuB,EAAI,IAAUD,EAAJlzE,EAAqB,EAAI,GAChG2rB,EAAY,GAAKk7C,EAAO,IAAMvxC,EAAU49C,GAAkBI,EAAY,GAGlE1nD,KAAMD,EAAY,EAAIC,EAAOA,EAAO,EACpCD,UAAWA,EAAY,EAAKA,EAAYu/C,EAAWt/C,EAAO,GAAKD,GAQvE,QAAS6nD,IAAWzN,GAChB,GAEIuC,GAFAe,EAAQtD,EAAOuB,GACfvyC,EAASgxC,EAAOwB,EAKpB,OAFAxB,GAAOmB,QAAUnB,EAAOmB,SAAWjwE,GAAOiuE,WAAWa,EAAOyB,IAE9C,OAAV6B,GAAmBt0C,IAAWp7B,GAAuB,KAAV0vE,EACpCpyE,GAAOw8E,SAASzP,WAAW,KAGjB,gBAAVqF,KACPtD,EAAOuB,GAAK+B,EAAQtD,EAAOmB,QAAQwM,SAASrK,IAG5CpyE,GAAOmD,SAASivE,GACT,GAAIvD,GAAOuD,GAAO,IAClBt0C,EACH17B,EAAQ07B,GACR28C,GAA2B3L,GAE3BiL,GAA4BjL,GAGhCwM,GAAkBxM,GAGtBuC,EAAM,GAAIxC,GAAOC,GACbuC,EAAIoI,WAEJpI,EAAIhiE,IAAI,EAAG,KACXgiE,EAAIoI,SAAW/2E,GAGZ2uE,IAyCX,QAASqL,IAAOpnE,EAAIqnE,GAChB,GAAItL,GAAK3vE,CAIT,IAHuB,IAAnBi7E,EAAQ96E,QAAgBO,EAAQu6E,EAAQ,MACxCA,EAAUA,EAAQ,KAEjBA,EAAQ96E,OACT,MAAO7B,KAGX,KADAqxE,EAAMsL,EAAQ,GACTj7E,EAAI,EAAGA,EAAIi7E,EAAQ96E,SAAUH,EAC1Bi7E,EAAQj7E,GAAG4T,GAAI+7D,KACfA,EAAMsL,EAAQj7E,GAGtB,OAAO2vE,GAsvBX,QAASc,IAAeL,EAAKvuE,GACzB,GAAIq5E,EAGJ,OAAqB,gBAAVr5E,KACPA,EAAQuuE,EAAI7D,aAAaiK,YAAY30E,GAEhB,gBAAVA,IACAuuE,GAIf8K,EAAax7E,KAAK8G,IAAI4pE,EAAIj9C,OAClB6+C,EAAY5B,EAAIn9C,OAAQpxB,IAChCuuE,EAAIx9C,GAAG,OAASw9C,EAAIpB,OAAS,MAAQ,IAAM,SAASntE,EAAOq5E,GACpD9K,GAGX,QAASI,IAAUJ,EAAK+K,GACpB,MAAO/K,GAAIx9C,GAAG,OAASw9C,EAAIpB,OAAS,MAAQ,IAAMmM,KAGtD,QAAS5K,IAAUH,EAAK+K,EAAMt5E,GAC1B,MAAa,UAATs5E,EACO1K,GAAeL,EAAKvuE,GAEpBuuE,EAAIx9C,GAAG,OAASw9C,EAAIpB,OAAS,MAAQ,IAAMmM,GAAMt5E,GAIhE,QAASu5E,IAAaD,EAAME,GACxB,MAAO,UAAUx5E,GACb,MAAa,OAATA,GACA0uE,GAAU91E,KAAM0gF,EAAMt5E,GACtBvD,GAAOmvE,aAAahzE,KAAM4gF,GACnB5gF,MAEA+1E,GAAU/1E,KAAM0gF,IAqCnC,QAASG,IAAanN,GAElB,MAAc,KAAPA,EAAa,OAGxB,QAASoN,IAAa1N,GAGlB,MAAe,QAARA,EAAiB,IAuL5B,QAAS2N,IAAmB7qE,GACxBrS,GAAOkM,SAASoJ,GAAGjD,GAAQ,WACvB,MAAOlW,MAAK6S,MAAMqD,IA2D1B,QAAS8qE,IAAWC,GAEK,mBAAVC,SAGXC,GAAkBC,GAAYv9E,OAE1Bu9E,GAAYv9E,OADZo9E,EACqB5P,EACb,uGAGAxtE,IAEaA,IAplF7B,IA/WA,GAAIA,IAIAs9E,GAGA57E,GANA87E,GAAU,QAEVD,GAAiC,mBAAXhR,IAA6C,mBAAX3oE,SAA0BA,SAAW2oE,EAAO3oE,OAAoBzH,KAATowE,EAE/GziD,GAAQ1oB,KAAK0oB,MACb9nB,GAAiBS,OAAO8M,UAAUvN,eAGlCsyE,GAAO,EACPF,GAAQ,EACRC,GAAO,EACPE,GAAO,EACPC,GAAS,EACTC,GAAS,EACTC,GAAc,EAGdrzC,MAGAwvC,MAGAwE,GAA+B,mBAAXr5E,IAA0BA,GAAUA,EAAOD,QAG/Dw/E,GAAkB,sBAClBkC,GAA0B,uDAI1BC,GAAmB,gIAGnBhI,GAAmB,qKACnBQ,GAAwB,6CAGxBmB,GAA2B,QAC3BR,GAA6B,UAC7BL,GAA4B,UAC5BG,GAA2B,gBAC3BS,GAAmB,MACnBN,GAAiB,mHACjBI,GAAqB,uBACrBC,GAAc,KACdH,GAAqB,aACrBC,GAAwB,yBAGxBZ,GAAqB,KACrBO,GAAsB,OACtBN,GAAwB,QACxBC,GAAuB,QACvBG,GAAsB,aACtBD,GAAyB,WAIzBwE,GAAW,4IAEX0C,GAAY,uBAEZzC,KACK,eAAgB,0BAChB,aAAc,sBACd,eAAgB,oBAChB,aAAc,iBACd,WAAY,gBAIjBC,KACK,gBAAiB,6BACjB,WAAY,wBACZ,QAAS,mBACT,KAAM,cAIXpD,GAAuB,kBAIvB6F,IADyB,0CAA0Cx5E,MAAM,MAErEy5E,aAAiB,EACjBC,QAAY,IACZC,QAAY,IACZC,MAAU,KACVC,KAAS,MACTC,OAAW,OACXC,MAAU,UAGdtL,IACI2I,GAAK,cACLxzE,EAAI,SACJrL,EAAI,SACJoL,EAAI,OACJgB,EAAI,MACJq1E,EAAI,OACJvyB,EAAI,OACJitB,EAAI,UACJzR,EAAI,QACJgX,EAAI,UACJjwE,EAAI,OACJkwE,IAAM,YACNprD,EAAI,UACJ6lD,EAAI,aACJE,GAAI,WACJJ,GAAI,eAGR/F,IACIyL,UAAY,YACZC,WAAa,aACbC,QAAU,UACVC,SAAW,WACXC,YAAc,eAIlB7I,MAGAkG,IACIh0E,EAAG,GACHrL,EAAG,GACHoL,EAAG,GACHgB,EAAG,GACHs+D,EAAG,IAIPuX,GAAmB,gBAAgBx6E,MAAM,KACzCy6E,GAAe,kBAAkBz6E,MAAM,KAEvCuxE,IACItO,EAAO,WACH,MAAOlrE,MAAK24B,QAAU,GAE1BgqD,IAAO,SAAUhhD,GACb,MAAO3hC,MAAK8xE,aAAa8Q,YAAY5iF,KAAM2hC,IAE/CkhD,KAAO,SAAUlhD,GACb,MAAO3hC,MAAK8xE,aAAayB,OAAOvzE,KAAM2hC;EAE1CsgD,EAAO,WACH,MAAOjiF,MAAK04B,QAEhBypD,IAAO,WACH,MAAOniF,MAAKu4B,aAEhB3rB,EAAO,WACH,MAAO5M,MAAKs4B,OAEhBwqD,GAAO,SAAUnhD,GACb,MAAO3hC,MAAK8xE,aAAaiR,YAAY/iF,KAAM2hC,IAE/CqhD,IAAO,SAAUrhD,GACb,MAAO3hC,MAAK8xE,aAAamR,cAAcjjF,KAAM2hC,IAEjDuhD,KAAO,SAAUvhD,GACb,MAAO3hC,MAAK8xE,aAAaqR,SAASnjF,KAAM2hC,IAE5C+tB,EAAO,WACH,MAAO1vD,MAAKyzE,QAEhBkJ,EAAO,WACH,MAAO38E,MAAKojF,WAEhBC,GAAO,WACH,MAAO1R,GAAa3xE,KAAKw4B,OAAS,IAAK,IAE3C8qD,KAAO,WACH,MAAO3R,GAAa3xE,KAAKw4B,OAAQ,IAErC+qD,MAAQ,WACJ,MAAO5R,GAAa3xE,KAAKw4B,OAAQ,IAErCgrD,OAAS,WACL,GAAIvxE,GAAIjS,KAAKw4B,OAAQvJ,EAAOhd,GAAK,EAAI,IAAM,GAC3C,OAAOgd,GAAO0iD,EAAa1sE,KAAK6lB,IAAI7Y,GAAI,IAE5C6qE,GAAO,WACH,MAAOnL,GAAa3xE,KAAKw8E,WAAa,IAAK,IAE/CiH,KAAO,WACH,MAAO9R,GAAa3xE,KAAKw8E,WAAY,IAEzCkH,MAAQ,WACJ,MAAO/R,GAAa3xE,KAAKw8E,WAAY,IAEzCE,GAAO,WACH,MAAO/K,GAAa3xE,KAAK2jF,cAAgB,IAAK,IAElDC,KAAO,WACH,MAAOjS,GAAa3xE,KAAK2jF,cAAe,IAE5CE,MAAQ,WACJ,MAAOlS,GAAa3xE,KAAK2jF,cAAe,IAE5C5sD,EAAI,WACA,MAAO/2B,MAAKkiC,WAEhB06C,EAAI,WACA,MAAO58E,MAAK8jF,cAEhBx+E,EAAO,WACH,MAAOtF,MAAK8xE,aAAaO,SAASryE,KAAKq9B,QAASr9B,KAAKs9B,WAAW,IAEpE0tC,EAAO,WACH,MAAOhrE,MAAK8xE,aAAaO,SAASryE,KAAKq9B,QAASr9B,KAAKs9B,WAAW,IAEpEjT,EAAO,WACH,MAAOrqB,MAAKq9B,SAEhBzxB,EAAO,WACH,MAAO5L,MAAKq9B,QAAU,IAAM,IAEhC78B,EAAO,WACH,MAAOR,MAAKs9B,WAEhBzxB,EAAO,WACH,MAAO7L,MAAKu9B,WAEhBjT,EAAO,WACH,MAAOgsD,GAAMt2E,KAAKw9B,eAAiB,MAEvCumD,GAAO,WACH,MAAOpS,GAAa2E,EAAMt2E,KAAKw9B,eAAiB,IAAK,IAEzDwmD,IAAO,WACH,MAAOrS,GAAa3xE,KAAKw9B,eAAgB,IAE7CymD,KAAO,WACH,MAAOtS,GAAa3xE,KAAKw9B,eAAgB,IAE7C0mD,EAAO,WACH,GAAI5+E,GAAItF,KAAKmkF,YACTh+E,EAAI,GAKR,OAJQ,GAAJb,IACAA,GAAKA,EACLa,EAAI,KAEDA,EAAIwrE,EAAa2E,EAAMhxE,EAAI,IAAK,GAAK,IAAMqsE,EAAa2E,EAAMhxE,GAAK,GAAI,IAElF8+E,GAAO,WACH,GAAI9+E,GAAItF,KAAKmkF,YACTh+E,EAAI,GAKR,OAJQ,GAAJb,IACAA,GAAKA,EACLa,EAAI,KAEDA,EAAIwrE,EAAa2E,EAAMhxE,EAAI,IAAK,GAAKqsE,EAAa2E,EAAMhxE,GAAK,GAAI,IAE5E6X,EAAI,WACA,MAAOnd,MAAKqkF,YAEhBC,GAAK,WACD,MAAOtkF,MAAKukF,YAEhBvyE,EAAO,WACH,MAAOhS,MAAK+G,WAEhB8jB,EAAO,WACH,MAAO7qB,MAAKwkF,QAEhBtC,EAAI,WACA,MAAOliF,MAAKszE,YAIpB9B,MAEAiT,IAAS,SAAU,cAAe,WAAY,gBAAiB,eAE/D1R,IAAmB,EAyFhB0P,GAAiB/8E,QACpBH,GAAIk9E,GAAiB9nC,MACrB6+B,GAAqBj0E,GAAI,KAAOqsE,EAAgB4H,GAAqBj0E,IAAIA,GAE7E,MAAOm9E,GAAah9E,QAChBH,GAAIm9E,GAAa/nC,MACjB6+B,GAAqBj0E,GAAIA,IAAKksE,EAAS+H,GAAqBj0E,IAAI,EAEpEi0E,IAAqBkL,KAAOjT,EAAS+H,GAAqB2I,IAAK,GA0d/D98E,EAAOotE,EAAOr/D,WAEV+jE,IAAM,SAAUxE,GACZ,GAAI/sE,GAAML,CACV,KAAKA,IAAKotE,GACN/sE,EAAO+sE,EAAOptE,GACM,kBAATK,GACP5F,KAAKuF,GAAKK,EAEV5F,KAAK,IAAMuF,GAAKK,CAKxB5F,MAAKo7E,qBAAuB,GAAIC,QAAOr7E,KAAKm7E,cAAcrW,OAAS,IAAM,UAAUA,SAGvF+O,QAAU,wFAAwF5rE,MAAM,KACxGsrE,OAAS,SAAU/yE,GACf,MAAOR,MAAK6zE,QAAQrzE,EAAEm4B,UAG1BgsD,aAAe,kDAAkD18E,MAAM,KACvE26E,YAAc,SAAUpiF,GACpB,MAAOR,MAAK2kF,aAAankF,EAAEm4B,UAG/BojD,YAAc,SAAU6I,EAAWjjD,EAAQ6gC,GACvC,GAAIj9D,GAAGowE,EAAKkP,CAQZ,KANK7kF,KAAK8kF,eACN9kF,KAAK8kF,gBACL9kF,KAAK+kF,oBACL/kF,KAAKglF,sBAGJz/E,EAAI,EAAO,GAAJA,EAAQA,IAAK,CAYrB,GAVAowE,EAAM9xE,GAAOqzE,KAAK,IAAM3xE,IACpBi9D,IAAWxiE,KAAK+kF,iBAAiBx/E,KACjCvF,KAAK+kF,iBAAiBx/E,GAAK,GAAI81E,QAAO,IAAMr7E,KAAKuzE,OAAOoC,EAAK,IAAIlrE,QAAQ,IAAK,IAAM,IAAK,KACzFzK,KAAKglF,kBAAkBz/E,GAAK,GAAI81E,QAAO,IAAMr7E,KAAK4iF,YAAYjN,EAAK,IAAIlrE,QAAQ,IAAK,IAAM,IAAK,MAE9F+3D,GAAWxiE,KAAK8kF,aAAav/E,KAC9Bs/E,EAAQ,IAAM7kF,KAAKuzE,OAAOoC,EAAK,IAAM,KAAO31E,KAAK4iF,YAAYjN,EAAK,IAClE31E,KAAK8kF,aAAav/E,GAAK,GAAI81E,QAAOwJ,EAAMp6E,QAAQ,IAAK,IAAK,MAG1D+3D,GAAqB,SAAX7gC,GAAqB3hC,KAAK+kF,iBAAiBx/E,GAAG0I,KAAK22E,GAC7D,MAAOr/E,EACJ,IAAIi9D,GAAqB,QAAX7gC,GAAoB3hC,KAAKglF,kBAAkBz/E,GAAG0I,KAAK22E,GACpE,MAAOr/E,EACJ,KAAKi9D,GAAUxiE,KAAK8kF,aAAav/E,GAAG0I,KAAK22E,GAC5C,MAAOr/E,KAKnB0/E,UAAY,2DAA2Dh9E,MAAM,KAC7Ek7E,SAAW,SAAU3iF,GACjB,MAAOR,MAAKilF,UAAUzkF,EAAE83B,QAG5B4sD,eAAiB,8BAA8Bj9E,MAAM,KACrDg7E,cAAgB,SAAUziF,GACtB,MAAOR,MAAKklF,eAAe1kF,EAAE83B,QAGjC6sD,aAAe,uBAAuBl9E,MAAM,KAC5C86E,YAAc,SAAUviF,GACpB,MAAOR,MAAKmlF,aAAa3kF,EAAE83B,QAG/B8jD,cAAgB,SAAUgJ,GACtB,GAAI7/E,GAAGowE,EAAKkP,CAMZ,KAJK7kF,KAAKqlF,iBACNrlF,KAAKqlF,mBAGJ9/E,EAAI,EAAO,EAAJA,EAAOA,IAQf,GANKvF,KAAKqlF,eAAe9/E,KACrBowE,EAAM9xE,IAAQ,IAAM,IAAIy0B,IAAI/yB,GAC5Bs/E,EAAQ,IAAM7kF,KAAKmjF,SAASxN,EAAK,IAAM,KAAO31E,KAAKijF,cAActN,EAAK,IAAM,KAAO31E,KAAK+iF,YAAYpN,EAAK,IACzG31E,KAAKqlF,eAAe9/E,GAAK,GAAI81E,QAAOwJ,EAAMp6E,QAAQ,IAAK,IAAK,MAG5DzK,KAAKqlF,eAAe9/E,GAAG0I,KAAKm3E,GAC5B,MAAO7/E,IAKnB+/E,iBACIC,IAAM,YACNC,GAAK,SACLC,EAAI,aACJC,GAAK,eACLC,IAAM,kBACNC,KAAO,yBAEX9L,eAAiB,SAAUlxE,GACvB,GAAImsE,GAAS/0E,KAAKslF,gBAAgB18E,EAOlC,QANKmsE,GAAU/0E,KAAKslF,gBAAgB18E,EAAI08B,iBACpCyvC,EAAS/0E,KAAKslF,gBAAgB18E,EAAI08B,eAAe76B,QAAQ,mBAAoB,SAAUupE,GACnF,MAAOA,GAAI9oE,MAAM,KAErBlL,KAAKslF,gBAAgB18E,GAAOmsE,GAEzBA,GAGXvC,KAAO,SAAUyD,GAGb,MAAiD,OAAxCA,EAAQ,IAAIrxC,cAAcvf,OAAO,IAG9Cu1D,eAAiB,gBACjBvI,SAAW,SAAUh1C,EAAOC,EAASuoD,GACjC,MAAIxoD,GAAQ,GACDwoD,EAAU,KAAO,KAEjBA,EAAU,KAAO,MAKhCC,WACIC,QAAU,gBACVC,QAAU,mBACVC,SAAW,eACXC,QAAU,oBACVC,SAAW,sBACXC,SAAW,KAEfC,SAAW,SAAUz9E,EAAK+sE,EAAKv4C,GAC3B,GAAI23C,GAAS/0E,KAAK8lF,UAAUl9E,EAC5B,OAAyB,kBAAXmsE,GAAwBA,EAAO/8D,MAAM29D,GAAMv4C,IAAQ23C,GAGrEuR,eACIC,OAAS,QACTC,KAAO,SACP36E,EAAI,gBACJrL,EAAI,WACJimF,GAAK,aACL76E,EAAI,UACJ86E,GAAK,WACL95E,EAAI,QACJk2E,GAAK,UACL5X,EAAI,UACJyb,GAAK,YACL10E,EAAI,SACJ20E,GAAK,YAGTjH,aAAe,SAAU/K,EAAQ6K,EAAehE,EAAQiE,GACpD,GAAI3K,GAAS/0E,KAAKsmF,cAAc7K,EAChC,OAA0B,kBAAX1G,GACXA,EAAOH,EAAQ6K,EAAehE,EAAQiE,GACtC3K,EAAOtqE,QAAQ,MAAOmqE,IAG9BiS,WAAa,SAAUv6D,EAAMyoD,GACzB,GAAIpzC,GAAS3hC,KAAKsmF,cAAch6D,EAAO,EAAI,SAAW,OACtD,OAAyB,kBAAXqV,GAAwBA,EAAOozC,GAAUpzC,EAAOl3B,QAAQ,MAAOsqE,IAGjFhD,QAAU,SAAU6C,GAChB,MAAO50E,MAAK8mF,SAASr8E,QAAQ,KAAMmqE,IAEvCkS,SAAW,KACX3L,cAAgB,UAEhBmF,SAAW,SAAU7E,GACjB,MAAOA,IAGXsL,WAAa,SAAUtL,GACnB,MAAOA,IAGXhI,KAAO,SAAUkC,GACb,MAAOkC,IAAWlC,EAAK31E,KAAK68E,MAAMlF,IAAK33E,KAAK68E,MAAMjF,KAAKnE,MAG3DoJ,OACIlF,IAAM,EACNC,IAAM,GAGVkI,eAAiB,WACb,MAAO9/E,MAAK68E,MAAMlF,KAGtBqP,eAAiB,WACb,MAAOhnF,MAAK68E,MAAMjF,KAGtBqP,aAAc,eACdrN,YAAa,WACT,MAAO55E,MAAKinF,gBA0yBpBpjF,GAAS,SAAUoyE,EAAOt0C,EAAQ+C,EAAQ89B,GACtC,GAAI/hE,EAiBJ,OAfuB,iBAAb,KACN+hE,EAAS99B,EACTA,EAASn+B,GAIb9F,KACAA,EAAEwzE,kBAAmB,EACrBxzE,EAAEyzE,GAAK+B,EACPx1E,EAAE0zE,GAAKxyC,EACPlhC,EAAE2zE,GAAK1vC,EACPjkC,EAAE4zE,QAAU7R,EACZ/hE,EAAE8zE,QAAS,EACX9zE,EAAEg0E,IAAMlE,IAED6P,GAAW3/E,IAGtBoD,GAAOstE,6BAA8B,EAErCttE,GAAOq7E,wBAA0B7N,EAC7B,4LAIA,SAAUsB,GACNA,EAAOx6C,GAAK,GAAI9zB,MAAKsuE,EAAOuB,IAAMvB,EAAOwJ,QAAU,OAAS,OA0BpEt4E,GAAOkI,IAAM,WACT,GAAImN,MAAUhO,MAAM3K,KAAKkF,UAAW,EAEpC,OAAO86E,IAAO,WAAYrnE,IAG9BrV,GAAO8I,IAAM,WACT,GAAIuM,MAAUhO,MAAM3K,KAAKkF,UAAW,EAEpC,OAAO86E,IAAO,UAAWrnE,IAI7BrV,GAAOqzE,IAAM,SAAUjB,EAAOt0C,EAAQ+C,EAAQ89B,GAC1C,GAAI/hE,EAkBJ,OAhBuB,iBAAb,KACN+hE,EAAS99B,EACTA,EAASn+B,GAIb9F,KACAA,EAAEwzE,kBAAmB,EACrBxzE,EAAE07E,SAAU,EACZ17E,EAAE8zE,QAAS,EACX9zE,EAAE2zE,GAAK1vC,EACPjkC,EAAEyzE,GAAK+B,EACPx1E,EAAE0zE,GAAKxyC,EACPlhC,EAAE4zE,QAAU7R,EACZ/hE,EAAEg0E,IAAMlE,IAED6P,GAAW3/E,GAAGy2E,OAIzBrzE,GAAO2gF,KAAO,SAAUvO,GACpB,MAAOpyE,IAAe,IAARoyE,IAIlBpyE,GAAOkM,SAAW,SAAUkmE,EAAOrtE,GAC/B,GAGIqmB,GACAi4D,EACAC,EACAC,EANAr3E,EAAWkmE,EAEX3xE,EAAQ,IAiEZ,OA3DIT,IAAOwjF,WAAWpR,GAClBlmE,GACIsvE,GAAIpJ,EAAMtC,cACV/mE,EAAGqpE,EAAMrC,MACT1I,EAAG+K,EAAMpC,SAEW,gBAAVoC,IACdlmE,KACInH,EACAmH,EAASnH,GAAOqtE,EAEhBlmE,EAASytB,aAAey4C,IAElB3xE,EAAQg9E,GAAwB98E,KAAKyxE,KAC/ChnD,EAAqB,MAAb3qB,EAAM,GAAc,GAAK,EACjCyL,GACIkC,EAAG,EACHrF,EAAG0pE,EAAMhyE,EAAM4zE,KAASjpD,EACxBrjB,EAAG0qE,EAAMhyE,EAAM8zE,KAASnpD,EACxBzuB,EAAG81E,EAAMhyE,EAAM+zE,KAAWppD,EAC1BpjB,EAAGyqE,EAAMhyE,EAAMg0E,KAAWrpD,EAC1BowD,GAAI/I,EAAMhyE,EAAMi0E,KAAgBtpD,KAE1B3qB,EAAQi9E,GAAiB/8E,KAAKyxE,KACxChnD,EAAqB,MAAb3qB,EAAM,GAAc,GAAK,EACjC6iF,EAAW,SAAUG,GAIjB,GAAIpS,GAAMoS,GAAOhiE,WAAWgiE,EAAI78E,QAAQ,IAAK,KAE7C,QAAQhG,MAAMywE,GAAO,EAAIA,GAAOjmD,GAEpClf,GACIkC,EAAGk1E,EAAS7iF,EAAM,IAClB4mE,EAAGic,EAAS7iF,EAAM,IAClBsI,EAAGu6E,EAAS7iF,EAAM,IAClBsH,EAAGu7E,EAAS7iF,EAAM,IAClB9D,EAAG2mF,EAAS7iF,EAAM,IAClBuH,EAAGs7E,EAAS7iF,EAAM,IAClBorD,EAAGy3B,EAAS7iF,EAAM,MAEH,MAAZyL,EACPA,KAC2B,gBAAbA,KACT,QAAUA,IAAY,MAAQA,MACnCq3E,EAAUhS,EAAkBvxE,GAAOkM,EAASsZ,MAAOxlB,GAAOkM,EAASuZ,KAEnEvZ,KACAA,EAASsvE,GAAK+H,EAAQ5pD,aACtBztB,EAASm7D,EAAIkc,EAAQ7T,QAGzB2T,EAAM,GAAIjU,GAASljE,GAEflM,GAAOwjF,WAAWpR,IAAU3F,EAAW2F,EAAO,aAC9CiR,EAAIpT,QAAUmC,EAAMnC,SAGjBoT,GAIXrjF,GAAO0jF,QAAUlG,GAGjBx9E,GAAOw+B,cAAgBm/C,GAGvB39E,GAAOg6E,SAAW,aAIlBh6E,GAAO6wE,iBAAmBA,GAI1B7wE,GAAOmvE,aAAe,aAGtBnvE,GAAO2jF,sBAAwB,SAAUnvB,EAAWovB,GAChD,MAAI5H,IAAuBxnB,KAAe9xD,GAC/B,EAEPkhF,IAAUlhF,EACHs5E,GAAuBxnB,IAElCwnB,GAAuBxnB,GAAaovB,GAC7B,IAGX5jF,GAAO8gC,KAAO0sC,EACV,wDACA,SAAUzoE,EAAKxB,GACX,MAAOvD,IAAO6gC,OAAO97B,EAAKxB,KAOlCvD,GAAO6gC,OAAS,SAAU97B,EAAKmO,GAC3B,GAAIpE,EAcJ,OAbI/J,KAEI+J,EADmB,mBAAb,GACC9O,GAAO6jF,aAAa9+E,EAAKmO,GAGzBlT,GAAOiuE,WAAWlpE,GAGzB+J,IACA9O,GAAOkM,SAAS+jE,QAAUjwE,GAAOiwE,QAAUnhE,IAI5C9O,GAAOiwE,QAAQ6T,OAG1B9jF,GAAO6jF,aAAe,SAAUxxE,EAAMa,GAClC,MAAe,QAAXA,GACAA,EAAO6wE,KAAO1xE,EACTgvB,GAAQhvB,KACTgvB,GAAQhvB,GAAQ,GAAIu8D,IAExBvtC,GAAQhvB,GAAMihE,IAAIpgE,GAGlBlT,GAAO6gC,OAAOxuB,GAEPgvB,GAAQhvB,WAGRgvB,IAAQhvB,GACR,OAIfrS,GAAOgkF,SAAWxW,EACd,gEACA,SAAUzoE,GACN,MAAO/E,IAAOiuE,WAAWlpE,KAKjC/E,GAAOiuE,WAAa,SAAUlpE,GAC1B,GAAI87B,EAMJ,IAJI97B,GAAOA,EAAIkrE,SAAWlrE,EAAIkrE,QAAQ6T,QAClC/+E,EAAMA,EAAIkrE,QAAQ6T,QAGjB/+E,EACD,MAAO/E,IAAOiwE,OAGlB,KAAK7tE,EAAQ2C,GAAM,CAGf,GADA87B,EAASs0C,EAAWpwE,GAEhB,MAAO87B,EAEX97B,IAAOA,GAGX,MAAOkwE,GAAalwE,IAIxB/E,GAAOmD,SAAW,SAAUgc,GACxB,MAAOA,aAAe0vD,IACV,MAAP1vD,GAAestD,EAAWttD,EAAK,qBAIxCnf,GAAOwjF,WAAa,SAAUrkE,GAC1B,MAAOA,aAAeiwD,GAG1B,KAAK1tE,GAAIk/E,GAAM/+E,OAAS,EAAGH,IAAK,IAAKA,GACjCuxE,EAAS2N,GAAMl/E,IAGnB1B,IAAO0yE,eAAiB,SAAUC,GAC9B,MAAOD,GAAeC,IAG1B3yE,GAAOw8E,QAAU,SAAUyH,GACvB,GAAItnF,GAAIqD,GAAOqzE,IAAIyH,IAQnB,OAPa,OAATmJ,EACAziF,EAAO7E,EAAEi0E,IAAKqT,GAGdtnF,EAAEi0E,IAAI1D,iBAAkB,EAGrBvwE,GAGXqD,GAAOkkF,UAAY,WACf,MAAOlkF,IAAOmU,MAAM,KAAMvS,WAAWsiF,aAGzClkF,GAAOo4E,kBAAoB,SAAUhG,GACjC,MAAOK,GAAML,IAAUK,EAAML,GAAS,GAAK,KAAO,MAGtDpyE,GAAOO,OAASA,EAOhBiB,EAAOxB,GAAOsV,GAAKu5D,EAAOt/D,WAEtBilB,MAAQ,WACJ,MAAOx0B,IAAO7D,OAGlB+G,QAAU,WACN,OAAQ/G,KAAKm4B,GAA4B,KAArBn4B,KAAKw0E,SAAW,IAGxCgQ,KAAO,WACH,MAAOv/E,MAAKC,OAAOlF,KAAO,MAG9BoF,SAAW,WACP,MAAOpF,MAAKq4B,QAAQqM,OAAO,MAAM/C,OAAO,qCAG5C16B,OAAS,WACL,MAAOjH,MAAKw0E,QAAU,GAAInwE,OAAMrE,MAAQA,KAAKm4B,IAGjDhxB,YAAc,WACV,GAAI3G,GAAIqD,GAAO7D,MAAMk3E,KACrB,OAAI,GAAI12E,EAAEg4B,QAAUh4B,EAAEg4B,QAAU,KACxB,kBAAsBn0B,MAAK+O,UAAUjM,YAE9BnH,KAAKiH,SAASE,cAEdsyE,EAAaj5E,EAAG,gCAGpBi5E,EAAaj5E,EAAG,mCAI/BiI,QAAU,WACN,GAAIjI,GAAIR,IACR,QACIQ,EAAEg4B,OACFh4B,EAAEm4B,QACFn4B,EAAEk4B,OACFl4B,EAAE68B,QACF78B,EAAE88B,UACF98B,EAAE+8B,UACF/8B,EAAEg9B,iBAIVi7C,QAAU,WACN,MAAOA,GAAQz4E,OAGnBgoF,aAAe,WACX,MAAIhoF,MAAKg4E,GACEh4E,KAAKy4E,WAAavC,EAAcl2E,KAAKg4E,IAAKh4E,KAAKu0E,OAAS1wE,GAAOqzE,IAAIl3E,KAAKg4E,IAAMn0E,GAAO7D,KAAKg4E,KAAKvvE,WAAa,GAGhH,GAGXw/E,aAAe,WACX,MAAO5iF,MAAWrF,KAAKy0E,MAG3ByT,UAAW,WACP,MAAOloF,MAAKy0E,IAAI3wD,UAGpBozD,IAAM,SAAUiR,GACZ,MAAOnoF,MAAKmkF,UAAU,EAAGgE,IAG7B/O,MAAQ,SAAU+O,GASd,MARInoF,MAAKu0E,SACLv0E,KAAKmkF,UAAU,EAAGgE,GAClBnoF,KAAKu0E,QAAS,EAEV4T,GACAnoF,KAAKsrB,SAAStrB,KAAKooF,iBAAkB,MAGtCpoF,MAGX2hC,OAAS,SAAU0mD,GACf,GAAItT,GAAS0E,EAAaz5E,KAAMqoF,GAAexkF,GAAOw+B,cACtD,OAAOriC,MAAK8xE,aAAaiV,WAAWhS,IAGxC7hE,IAAMqiE,EAAY,EAAG,OAErBjqD,SAAWiqD,EAAY,GAAI,YAE3BjpD,KAAO,SAAU2pD,EAAOO,EAAO8R,GAC3B,GAEYh8D,GAAMyoD,EAFdwT,EAAOlT,EAAOY,EAAOj2E,MACrBwoF,EAAmD,KAAvCD,EAAKpE,YAAcnkF,KAAKmkF,YAqBxC,OAlBA3N,GAAQD,EAAeC,GAET,SAAVA,GAA8B,UAAVA,GAA+B,YAAVA,GACzCzB,EAAS/C,EAAUhyE,KAAMuoF,GACX,YAAV/R,EACAzB,GAAkB,EACD,SAAVyB,IACPzB,GAAkB,MAGtBzoD,EAAOtsB,KAAOuoF,EACdxT,EAAmB,WAAVyB,EAAqBlqD,EAAO,IACvB,WAAVkqD,EAAqBlqD,EAAO,IAClB,SAAVkqD,EAAmBlqD,EAAO,KAChB,QAAVkqD,GAAmBlqD,EAAOk8D,GAAY,MAC5B,SAAVhS,GAAoBlqD,EAAOk8D,GAAY,OACvCl8D,GAEDg8D,EAAUvT,EAASJ,EAASI,IAGvC1rD,KAAO,SAAU+Q,EAAMqlD,GACnB,MAAO57E,IAAOkM,UAAUuZ,GAAItpB,KAAMqpB,KAAM+Q,IAAOsK,OAAO1kC,KAAK0kC,UAAU+jD,UAAUhJ,IAGnFiJ,QAAU,SAAUjJ,GAChB,MAAOz/E,MAAKqpB,KAAKxlB,KAAU47E,IAG/B4G,SAAW,SAAUjsD,GAIjB,GAAIgD,GAAMhD,GAAQv2B,KACd8kF,EAAMtT,EAAOj4C,EAAKp9B,MAAM4oF,QAAQ,OAChCt8D,EAAOtsB,KAAKssB,KAAKq8D,EAAK,QAAQ,GAC9BhnD,EAAgB,GAAPrV,EAAY,WACV,GAAPA,EAAY,WACL,EAAPA,EAAW,UACJ,EAAPA,EAAW,UACJ,EAAPA,EAAW,UACJ,EAAPA,EAAW,WAAa,UAChC,OAAOtsB,MAAK2hC,OAAO3hC,KAAK8xE,aAAauU,SAAS1kD,EAAQ3hC,KAAM6D,GAAOu5B,MAGvE26C,WAAa,WACT,MAAOA,GAAW/3E,KAAKw4B,SAG3BqwD,MAAQ,WACJ,MAAQ7oF,MAAKmkF,YAAcnkF,KAAKq4B,QAAQM,MAAM,GAAGwrD,aAC7CnkF,KAAKmkF,YAAcnkF,KAAKq4B,QAAQM,MAAM,GAAGwrD,aAGjD7rD,IAAM,SAAU29C,GACZ,GAAI39C,GAAMt4B,KAAKu0E,OAASv0E,KAAKm4B,GAAGgoD,YAAcngF,KAAKm4B,GAAG2wD,QACtD,OAAa,OAAT7S,GACAA,EAAQsJ,GAAatJ,EAAOj2E,KAAK8xE,cAC1B9xE,KAAKkT,IAAI+iE,EAAQ39C,EAAK,MAEtBA,GAIfK,MAAQgoD,GAAa,SAAS,GAE9BiI,QAAU,SAAUpS,GAIhB,OAHAA,EAAQD,EAAeC,IAIvB,IAAK,OACDx2E,KAAK24B,MAAM,EAEf,KAAK,UACL,IAAK,QACD34B,KAAK04B,KAAK,EAEd,KAAK,OACL,IAAK,UACL,IAAK,MACD14B,KAAKq9B,MAAM,EAEf,KAAK,OACDr9B,KAAKs9B,QAAQ,EAEjB,KAAK,SACDt9B,KAAKu9B,QAAQ,EAEjB,KAAK,SACDv9B,KAAKw9B,aAAa,GAgBtB,MAXc,SAAVg5C,EACAx2E,KAAKkiC,QAAQ,GACI,YAAVs0C,GACPx2E,KAAK8jF,WAAW,GAIN,YAAVtN,GACAx2E,KAAK24B,MAAqC,EAA/B1zB,KAAKC,MAAMlF,KAAK24B,QAAU,IAGlC34B,MAGX+oF,MAAO,SAAUvS,GAEb,MADAA,GAAQD,EAAeC,GACnBA,IAAUjwE,GAAuB,gBAAViwE,EAChBx2E,KAEJA,KAAK4oF,QAAQpS,GAAOtjE,IAAI,EAAc,YAAVsjE,EAAsB,OAASA,GAAQlrD,SAAS,EAAG,OAG1F6pD,QAAS,SAAUc,EAAOO,GACtB,GAAIwS,EAEJ,OADAxS,GAAQD,EAAgC,mBAAVC,GAAwBA,EAAQ,eAChD,gBAAVA,GACAP,EAAQpyE,GAAOmD,SAASivE,GAASA,EAAQpyE,GAAOoyE,IACxCj2E,MAAQi2E,IAEhB+S,EAAUnlF,GAAOmD,SAASivE,IAAUA,GAASpyE,GAAOoyE,GAC7C+S,GAAWhpF,KAAKq4B,QAAQuwD,QAAQpS,KAI/ClB,SAAU,SAAUW,EAAOO,GACvB,GAAIwS,EAEJ,OADAxS,GAAQD,EAAgC,mBAAVC,GAAwBA,EAAQ,eAChD,gBAAVA,GACAP,EAAQpyE,GAAOmD,SAASivE,GAASA,EAAQpyE,GAAOoyE,IAChCA,GAARj2E,OAERgpF,EAAUnlF,GAAOmD,SAASivE,IAAUA,GAASpyE,GAAOoyE,IAC5Cj2E,KAAKq4B,QAAQ0wD,MAAMvS,GAASwS,IAI5CC,UAAW,SAAU5/D,EAAMC,EAAIktD,GAC3B,MAAOx2E,MAAKm1E,QAAQ9rD,EAAMmtD,IAAUx2E,KAAKs1E,SAAShsD,EAAIktD,IAG1DlyC,OAAQ,SAAU2xC,EAAOO,GACrB,GAAIwS,EAEJ,OADAxS,GAAQD,EAAeC,GAAS,eAClB,gBAAVA,GACAP,EAAQpyE,GAAOmD,SAASivE,GAASA,EAAQpyE,GAAOoyE,IACxCj2E,QAAUi2E,IAElB+S,GAAWnlF,GAAOoyE,IACTj2E,KAAKq4B,QAAQuwD,QAAQpS,IAAWwS,GAAWA,IAAahpF,KAAKq4B,QAAQ0wD,MAAMvS,KAI5FzqE,IAAKslE,EACI,mGACA,SAAU1rE,GAEN,MADAA,GAAQ9B,GAAOmU,MAAM,KAAMvS,WACZzF,KAAR2F,EAAe3F,KAAO2F,IAI1CgH,IAAK0kE,EACG,mGACA,SAAU1rE,GAEN,MADAA,GAAQ9B,GAAOmU,MAAM,KAAMvS,WACpBE,EAAQ3F,KAAOA,KAAO2F,IAIzCujF,KAAO7X,EACC,4GAEA,SAAU4E,EAAOkS,GACb,MAAa,OAATlS,GACqB,gBAAVA,KACPA,GAASA,GAGbj2E,KAAKmkF,UAAUlO,EAAOkS,GAEfnoF,OAECA,KAAKmkF,cAe7BA,UAAY,SAAUlO,EAAOkS,GACzB,GACIgB,GADAv/D,EAAS5pB,KAAKw0E,SAAW,CAE7B,OAAa,OAATyB,GACqB,gBAAVA,KACPA,EAAQuF,EAAoBvF,IAE5BhxE,KAAK6lB,IAAImrD,GAAS,KAClBA,EAAgB,GAARA,IAEPj2E,KAAKu0E,QAAU4T,IAChBgB,EAAcnpF,KAAKooF,kBAEvBpoF,KAAKw0E,QAAUyB,EACfj2E,KAAKu0E,QAAS,EACK,MAAf4U,GACAnpF,KAAKkT,IAAIi2E,EAAa,KAEtBv/D,IAAWqsD,KACNkS,GAAiBnoF,KAAKopF,kBACvB1T,EAAgC11E,KACxB6D,GAAOkM,SAASkmE,EAAQrsD,EAAQ,KAAM,GAAG,GACzC5pB,KAAKopF,oBACbppF,KAAKopF,mBAAoB,EACzBvlF,GAAOmvE,aAAahzE,MAAM,GAC1BA,KAAKopF,kBAAoB,OAI1BppF,MAEAA,KAAKu0E,OAAS3qD,EAAS5pB,KAAKooF,kBAI3CiB,QAAU,WACN,OAAQrpF,KAAKu0E,QAGjB+U,YAAc,WACV,MAAOtpF,MAAKu0E,QAGhBgV,MAAQ,WACJ,MAAOvpF,MAAKu0E,QAA2B,IAAjBv0E,KAAKw0E,SAG/B6P,SAAW,WACP,MAAOrkF,MAAKu0E,OAAS,MAAQ,IAGjCgQ,SAAW,WACP,MAAOvkF,MAAKu0E,OAAS,6BAA+B,IAGxDwT,UAAY,WAMR,MALI/nF,MAAKs0E,KACLt0E,KAAKmkF,UAAUnkF,KAAKs0E,MACM,gBAAZt0E,MAAKk0E,IACnBl0E,KAAKmkF,UAAU3I,EAAoBx7E,KAAKk0E,KAErCl0E,MAGXwpF,qBAAuB,SAAUvT,GAQ7B,MAHIA,GAJCA,EAIOpyE,GAAOoyE,GAAOkO,YAHd,GAMJnkF,KAAKmkF,YAAclO,GAAS,KAAO,GAG/CsB,YAAc,WACV,MAAOA,GAAYv3E,KAAKw4B,OAAQx4B,KAAK24B,UAGzCJ,UAAY,SAAU09C,GAClB,GAAI19C,GAAY5K,IAAO9pB,GAAO7D,MAAM4oF,QAAQ,OAAS/kF,GAAO7D,MAAM4oF,QAAQ,SAAW,OAAS,CAC9F,OAAgB,OAAT3S,EAAgB19C,EAAYv4B,KAAKkT,IAAK+iE,EAAQ19C,EAAY,MAGrE+6C,QAAU,SAAU2C,GAChB,MAAgB,OAATA,EAAgBhxE,KAAK+yC,MAAMh4C,KAAK24B,QAAU,GAAK,GAAK34B,KAAK24B,MAAoB,GAAbs9C,EAAQ,GAASj2E,KAAK24B,QAAU,IAG3G6jD,SAAW,SAAUvG,GACjB,GAAIz9C,GAAOq/C,GAAW73E,KAAMA,KAAK8xE,aAAa+K,MAAMlF,IAAK33E,KAAK8xE,aAAa+K,MAAMjF,KAAKp/C,IACtF,OAAgB,OAATy9C,EAAgBz9C,EAAOx4B,KAAKkT,IAAK+iE,EAAQz9C,EAAO,MAG3DmrD,YAAc,SAAU1N,GACpB,GAAIz9C,GAAOq/C,GAAW73E,KAAM,EAAG,GAAGw4B,IAClC,OAAgB,OAATy9C,EAAgBz9C,EAAOx4B,KAAKkT,IAAK+iE,EAAQz9C,EAAO,MAG3Di7C,KAAO,SAAUwC,GACb,GAAIxC,GAAOzzE,KAAK8xE,aAAa2B,KAAKzzE,KAClC,OAAgB,OAATi2E,EAAgBxC,EAAOzzE,KAAKkT,IAAqB,GAAhB+iE,EAAQxC,GAAW,MAG/D2P,QAAU,SAAUnN,GAChB,GAAIxC,GAAOoE,GAAW73E,KAAM,EAAG,GAAGyzE,IAClC,OAAgB,OAATwC,EAAgBxC,EAAOzzE,KAAKkT,IAAqB,GAAhB+iE,EAAQxC,GAAW,MAG/DvxC,QAAU,SAAU+zC,GAChB,GAAI/zC,IAAWliC,KAAKs4B,MAAQ,EAAIt4B,KAAK8xE,aAAa+K,MAAMlF,KAAO,CAC/D,OAAgB,OAAT1B,EAAgB/zC,EAAUliC,KAAKkT,IAAI+iE,EAAQ/zC,EAAS,MAG/D4hD,WAAa,SAAU7N,GAInB,MAAgB,OAATA,EAAgBj2E,KAAKs4B,OAAS,EAAIt4B,KAAKs4B,IAAIt4B,KAAKs4B,MAAQ,EAAI29C,EAAQA,EAAQ,IAGvFwT,eAAiB,WACb,MAAO/R,GAAY13E,KAAKw4B,OAAQ,EAAG,IAGvCk/C,YAAc,WACV,GAAIgS,GAAW1pF,KAAK8xE,aAAa+K,KACjC,OAAOnF,GAAY13E,KAAKw4B,OAAQkxD,EAAS/R,IAAK+R,EAAS9R,MAG3DziE,IAAM,SAAUqhE,GAEZ,MADAA,GAAQD,EAAeC,GAChBx2E,KAAKw2E,MAGhBW,IAAM,SAAUX,EAAOpvE,GACnB,GAAIs5E,EACJ,IAAqB,gBAAVlK,GACP,IAAKkK,IAAQlK,GACTx2E,KAAKm3E,IAAIuJ,EAAMlK,EAAMkK,QAIzBlK,GAAQD,EAAeC,GACI,kBAAhBx2E,MAAKw2E,IACZx2E,KAAKw2E,GAAOpvE,EAGpB,OAAOpH,OAMX0kC,OAAS,SAAU97B,GACf,GAAI+gF,EAEJ,OAAI/gF,KAAQrC,EACDvG,KAAK8zE,QAAQ6T,OAEpBgC,EAAgB9lF,GAAOiuE,WAAWlpE,GACb,MAAjB+gF,IACA3pF,KAAK8zE,QAAU6V,GAEZ3pF,OAIf2kC,KAAO0sC,EACH,kJACA,SAAUzoE,GACN,MAAIA,KAAQrC,EACDvG,KAAK8xE,aAEL9xE,KAAK0kC,OAAO97B,KAK/BkpE,WAAa,WACT,MAAO9xE,MAAK8zE,SAGhBsU,eAAiB,WAGb,MAAuD,KAA/CnjF,KAAK0oB,MAAM3tB,KAAKm4B,GAAGyxD,oBAAsB,OA+CzD/lF,GAAOsV,GAAG2oB,YAAcj+B,GAAOsV,GAAGqkB,aAAemjD,GAAa,gBAAgB,GAC9E98E,GAAOsV,GAAG4oB,OAASl+B,GAAOsV,GAAGokB,QAAUojD,GAAa,WAAW,GAC/D98E,GAAOsV,GAAG6oB,OAASn+B,GAAOsV,GAAGmkB,QAAUqjD,GAAa,WAAW,GAK/D98E,GAAOsV,GAAG8oB,KAAOp+B,GAAOsV,GAAGkkB,MAAQsjD,GAAa,SAAS,GAEzD98E,GAAOsV,GAAGuf,KAAOioD,GAAa,QAAQ,GACtC98E,GAAOsV,GAAGsgB,MAAQ43C,EAAU,kDAAmDsP,GAAa,QAAQ,IACpG98E,GAAOsV,GAAGqf,KAAOmoD,GAAa,YAAY,GAC1C98E,GAAOsV,GAAGi6D,MAAQ/B,EAAU,kDAAmDsP,GAAa,YAAY,IAGxG98E,GAAOsV,GAAGu6D,KAAO7vE,GAAOsV,GAAGmf,IAC3Bz0B,GAAOsV,GAAGo6D,OAAS1vE,GAAOsV,GAAGwf,MAC7B90B,GAAOsV,GAAGq6D,MAAQ3vE,GAAOsV,GAAGs6D,KAC5B5vE,GAAOsV,GAAG0wE,SAAWhmF,GAAOsV,GAAGiqE,QAC/Bv/E,GAAOsV,GAAGk6D,SAAWxvE,GAAOsV,GAAGm6D,QAG/BzvE,GAAOsV,GAAG2wE,OAASjmF,GAAOsV,GAAGhS,YAG7BtD,GAAOsV,GAAG4wE,MAAQlmF,GAAOsV,GAAGowE,MAkB5BlkF,EAAOxB,GAAOkM,SAASoJ,GAAK85D,EAAS7/D,WAEjC2gE,QAAU,WACN,GAIIx2C,GAASD,EAASD,EAJlBG,EAAex9B,KAAK2zE,cACpBD,EAAO1zE,KAAK4zE,MACZL,EAASvzE,KAAK6zE,QACdlhE,EAAO3S,KAAK6S,MACaugE,EAAQ,CAIrCzgE,GAAK6qB,aAAeA,EAAe,IAEnCD,EAAUo3C,EAASn3C,EAAe,KAClC7qB,EAAK4qB,QAAUA,EAAU,GAEzBD,EAAUq3C,EAASp3C,EAAU,IAC7B5qB,EAAK2qB,QAAUA,EAAU,GAEzBD,EAAQs3C,EAASr3C,EAAU,IAC3B3qB,EAAK0qB,MAAQA,EAAQ,GAErBq2C,GAAQiB,EAASt3C,EAAQ,IAGzB+1C,EAAQuB,EAASkM,GAAYnN,IAC7BA,GAAQiB,EAASmM,GAAY1N,IAI7BG,GAAUoB,EAASjB,EAAO,IAC1BA,GAAQ,GAGRN,GAASuB,EAASpB,EAAS,IAC3BA,GAAU,GAEV5gE,EAAK+gE,KAAOA,EACZ/gE,EAAK4gE,OAASA,EACd5gE,EAAKygE,MAAQA,GAGjBtoD,IAAM,WAYF,MAXA9qB,MAAK2zE,cAAgB1uE,KAAK6lB,IAAI9qB,KAAK2zE,eACnC3zE,KAAK4zE,MAAQ3uE,KAAK6lB,IAAI9qB,KAAK4zE,OAC3B5zE,KAAK6zE,QAAU5uE,KAAK6lB,IAAI9qB,KAAK6zE,SAE7B7zE,KAAK6S,MAAM2qB,aAAev4B,KAAK6lB,IAAI9qB,KAAK6S,MAAM2qB,cAC9Cx9B,KAAK6S,MAAM0qB,QAAUt4B,KAAK6lB,IAAI9qB,KAAK6S,MAAM0qB,SACzCv9B,KAAK6S,MAAMyqB,QAAUr4B,KAAK6lB,IAAI9qB,KAAK6S,MAAMyqB,SACzCt9B,KAAK6S,MAAMwqB,MAAQp4B,KAAK6lB,IAAI9qB,KAAK6S,MAAMwqB,OACvCr9B,KAAK6S,MAAM0gE,OAAStuE,KAAK6lB,IAAI9qB,KAAK6S,MAAM0gE,QACxCvzE,KAAK6S,MAAMugE,MAAQnuE,KAAK6lB,IAAI9qB,KAAK6S,MAAMugE,OAEhCpzE,MAGXwzE,MAAQ,WACJ,MAAOmB,GAAS30E,KAAK0zE,OAAS,IAGlC3sE,QAAU,WACN,MAAO/G,MAAK2zE,cACG,MAAb3zE,KAAK4zE,MACJ5zE,KAAK6zE,QAAU,GAAM,OACK,QAA3ByC,EAAMt2E,KAAK6zE,QAAU,KAG3B4U,SAAW,SAAUuB,GACjB,GAAIjV,GAAS4K,GAAa3/E,MAAOgqF,EAAYhqF,KAAK8xE,aAMlD,OAJIkY,KACAjV,EAAS/0E,KAAK8xE,aAAa+U,YAAY7mF,KAAM+0E,IAG1C/0E,KAAK8xE,aAAaiV,WAAWhS,IAGxC7hE,IAAM,SAAU+iE,EAAOjC,GAEnB,GAAIwB,GAAM3xE,GAAOkM,SAASkmE,EAAOjC,EAQjC,OANAh0E,MAAK2zE,eAAiB6B,EAAI7B,cAC1B3zE,KAAK4zE,OAAS4B,EAAI5B,MAClB5zE,KAAK6zE,SAAW2B,EAAI3B,QAEpB7zE,KAAK+zE,UAEE/zE,MAGXsrB,SAAW,SAAU2qD,EAAOjC,GACxB,GAAIwB,GAAM3xE,GAAOkM,SAASkmE,EAAOjC,EAQjC,OANAh0E,MAAK2zE,eAAiB6B,EAAI7B,cAC1B3zE,KAAK4zE,OAAS4B,EAAI5B,MAClB5zE,KAAK6zE,SAAW2B,EAAI3B,QAEpB7zE,KAAK+zE,UAEE/zE,MAGXmV,IAAM,SAAUqhE,GAEZ,MADAA,GAAQD,EAAeC,GAChBx2E,KAAKw2E,EAAM5xC,cAAgB,QAGtC1V,GAAK,SAAUsnD,GACX,GAAI9C,GAAMH,CAGV,IAFAiD,EAAQD,EAAeC,GAET,UAAVA,GAA+B,SAAVA,EAGrB,MAFA9C,GAAO1zE,KAAK4zE,MAAQ5zE,KAAK2zE,cAAgB,MACzCJ,EAASvzE,KAAK6zE,QAA8B,GAApBgN,GAAYnN,GACnB,UAAV8C,EAAoBjD,EAASA,EAAS,EAI7C,QADAG,EAAO1zE,KAAK4zE,MAAQ3uE,KAAK0oB,MAAMmzD,GAAY9gF,KAAK6zE,QAAU,KAClD2C,GACJ,IAAK,OAAQ,MAAO9C,GAAO,EAAI1zE,KAAK2zE,cAAgB,MACpD,KAAK,MAAO,MAAOD,GAAO1zE,KAAK2zE,cAAgB,KAC/C,KAAK,OAAQ,MAAc,IAAPD,EAAY1zE,KAAK2zE,cAAgB,IACrD,KAAK,SAAU,MAAc,IAAPD,EAAY,GAAK1zE,KAAK2zE,cAAgB,GAC5D,KAAK,SAAU,MAAc,IAAPD,EAAY,GAAK,GAAK1zE,KAAK2zE,cAAgB,GAEjE,KAAK,cAAe,MAAO1uE,MAAKC,MAAa,GAAPwuE,EAAY,GAAK,GAAK,KAAQ1zE,KAAK2zE,aACzE,SAAS,KAAM,IAAI/vE,OAAM,gBAAkB4yE,KAKvD7xC,KAAO9gC,GAAOsV,GAAGwrB,KACjBD,OAAS7gC,GAAOsV,GAAGurB,OAEnBulD,YAAc5Y,EACV,sFAEA,WACI,MAAOrxE,MAAKmH,gBAIpBA,YAAc,WAEV,GAAIisE,GAAQnuE,KAAK6lB,IAAI9qB,KAAKozE,SACtBG,EAAStuE,KAAK6lB,IAAI9qB,KAAKuzE,UACvBG,EAAOzuE,KAAK6lB,IAAI9qB,KAAK0zE,QACrBr2C,EAAQp4B,KAAK6lB,IAAI9qB,KAAKq9B,SACtBC,EAAUr4B,KAAK6lB,IAAI9qB,KAAKs9B,WACxBC,EAAUt4B,KAAK6lB,IAAI9qB,KAAKu9B,UAAYv9B,KAAKw9B,eAAiB,IAE9D,OAAKx9B,MAAKkqF,aAMFlqF,KAAKkqF,YAAc,EAAI,IAAM,IACjC,KACC9W,EAAQA,EAAQ,IAAM,KACtBG,EAASA,EAAS,IAAM,KACxBG,EAAOA,EAAO,IAAM,KACnBr2C,GAASC,GAAWC,EAAW,IAAM,KACtCF,EAAQA,EAAQ,IAAM,KACtBC,EAAUA,EAAU,IAAM,KAC1BC,EAAUA,EAAU,IAAM,IAXpB,OAcfu0C,WAAa,WACT,MAAO9xE,MAAK8zE,SAGhBgW,OAAS,WACL,MAAO9pF,MAAKmH,iBAIpBtD,GAAOkM,SAASoJ,GAAG/T,SAAWvB,GAAOkM,SAASoJ,GAAGhS,WAQjD,KAAK5B,KAAKk8E,IACFnR,EAAWmR,GAAwBl8E,KACnCw7E,GAAmBx7E,GAAEq/B,cAI7B/gC,IAAOkM,SAASoJ,GAAGgxE,eAAiB,WAChC,MAAOnqF,MAAKkvB,GAAG,OAEnBrrB,GAAOkM,SAASoJ,GAAG+wE,UAAY,WAC3B,MAAOlqF,MAAKkvB,GAAG,MAEnBrrB,GAAOkM,SAASoJ,GAAGixE,UAAY,WAC3B,MAAOpqF,MAAKkvB,GAAG,MAEnBrrB,GAAOkM,SAASoJ,GAAGkxE,QAAU,WACzB,MAAOrqF,MAAKkvB,GAAG,MAEnBrrB,GAAOkM,SAASoJ,GAAGmxE,OAAS,WACxB,MAAOtqF,MAAKkvB,GAAG,MAEnBrrB,GAAOkM,SAASoJ,GAAGoxE,QAAU,WACzB,MAAOvqF,MAAKkvB,GAAG,UAEnBrrB,GAAOkM,SAASoJ,GAAGqxE,SAAW,WAC1B,MAAOxqF,MAAKkvB,GAAG,MAEnBrrB,GAAOkM,SAASoJ,GAAGsxE,QAAU,WACzB,MAAOzqF,MAAKkvB,GAAG,MASnBrrB,GAAO6gC,OAAO,MACVgmD,aAAc,uBACd3Y,QAAU,SAAU6C,GAChB,GAAIzuE,GAAIyuE,EAAS,GACbG,EAAuC,IAA7BuB,EAAM1B,EAAS,IAAM,IAAa,KACrC,IAANzuE,EAAW,KACL,IAANA,EAAW,KACL,IAANA,EAAW,KAAO,IACvB,OAAOyuE,GAASG,KA4BpBmE,GACAr5E,EAAOD,QAAUiE,IAEfurE,EAAgC,SAAUub,EAAS/qF,EAASC,GAM1D,MALIA,GAAO8yE,QAAU9yE,EAAO8yE,UAAY9yE,EAAO8yE,SAASiY,YAAa,IAEjExJ,GAAYv9E,OAASs9E,IAGlBt9E,IACTtD,KAAKX,EAASM,EAAqBN,EAASC,KAASuvE,IAAkC7oE,IAAc1G,EAAOD,QAAUwvE,IACxH4R,IAAW,MAIhBzgF,KAAKP,QAEqBO,KAAKX,EAAU,WAAa,MAAOI,SAAYE,EAAoB,IAAIL,KAIhG,SAASA,EAAQD,EAASM,GAE9B,GAAIkvE,IAKJ,SAAU3nE,EAAQ+J,EAAUq5E,EAAYtkF,GAmBxC,QAASukF,GAAkB3xE,EAAI4xE,EAAS3xE,GACpC,MAAOG,YAAWyxE,EAAO7xE,EAAIC,GAAU2xE,GAY3C,QAASE,GAAeC,EAAK/xE,EAAIC,GAC7B,MAAIpT,OAAMC,QAAQilF,IACdC,EAAKD,EAAK9xE,EAAQD,GAAKC,IAChB,IAEJ,EASX,QAAS+xE,GAAKnoE,EAAKooE,EAAUhyE,GACzB,GAAI7T,EAEJ,IAAKyd,EAIL,GAAIA,EAAIza,QACJya,EAAIza,QAAQ6iF,EAAUhyE,OACnB,IAAI4J,EAAItd,SAAWa,EAEtB,IADAhB,EAAI,EACGA,EAAIyd,EAAItd,QACX0lF,EAAS7qF,KAAK6Y,EAAS4J,EAAIzd,GAAIA,EAAGyd,GAClCzd,QAGJ,KAAKA,IAAKyd,GACNA,EAAInd,eAAeN,IAAM6lF,EAAS7qF,KAAK6Y,EAAS4J,EAAIzd,GAAIA,EAAGyd,GAavE,QAAS3d,GAAOgmF,EAAMplC,EAAKmb,GAGvB,IAFA,GAAI/zD,GAAO/G,OAAO+G,KAAK44C,GACnB1gD,EAAI,EACDA,EAAI8H,EAAK3H,UACP07D,GAAUA,GAASiqB,EAAKh+E,EAAK9H,MAAQgB,KACtC8kF,EAAKh+E,EAAK9H,IAAM0gD,EAAI54C,EAAK9H,KAE7BA,GAEJ,OAAO8lF,GAUX,QAASjqB,GAAMiqB,EAAMplC,GACjB,MAAO5gD,GAAOgmF,EAAMplC,GAAK,GAS7B,QAASqlC,GAAQC,EAAOtW,EAAMjmB,GAC1B,GACIw8B,GADAC,EAAQxW,EAAK7hE,SAGjBo4E,GAASD,EAAMn4E,UAAY9M,OAAOgI,OAAOm9E,GACzCD,EAAOnlF,YAAcklF,EACrBC,EAAOE,OAASD,EAEZz8B,GACA3pD,EAAOmmF,EAAQx8B,GAUvB,QAASg8B,GAAO7xE,EAAIC,GAChB,MAAO,YACH,MAAOD,GAAGnB,MAAMoB,EAAS3T,YAWjC,QAASkmF,GAAS3X,EAAK96D,GACnB,aAAW86D,IAAO4X,GACP5X,EAAIh8D,MAAMkB,EAAOA,EAAK,IAAM3S,EAAYA,EAAW2S,GAEvD86D,EASX,QAAS6X,GAAYC,EAAMC,GACvB,MAAQD,KAASvlF,EAAawlF,EAAOD,EASzC,QAASE,GAAkBriF,EAAQwN,EAAO80E,GACtCd,EAAKe,EAAS/0E,GAAQ,SAAStQ,GAC3B8C,EAAOd,iBAAiBhC,EAAMolF,GAAS,KAU/C,QAASE,GAAqBxiF,EAAQwN,EAAO80E,GACzCd,EAAKe,EAAS/0E,GAAQ,SAAStQ,GAC3B8C,EAAON,oBAAoBxC,EAAMolF,GAAS,KAWlD,QAASG,GAAUjmC,EAAMhhB,GACrB,KAAOghB,GAAM,CACT,GAAIA,GAAQhhB,EACR,OAAO,CAEXghB,GAAOA,EAAKr8C,WAEhB,OAAO,EASX,QAASuiF,GAAMC,EAAKC,GAChB,MAAOD,GAAI5lF,QAAQ6lF,GAAQ,GAQ/B,QAASL,GAASI,GACd,MAAOA,GAAIn/E,OAAOlF,MAAM,QAU5B,QAASukF,GAAQvmC,EAAKsmC,EAAME,GACxB,GAAIxmC,EAAIv/C,UAAY+lF,EAChB,MAAOxmC,GAAIv/C,QAAQ6lF,EAGnB,KADA,GAAIhnF,GAAI,EACDA,EAAI0gD,EAAIvgD,QAAQ,CACnB,GAAK+mF,GAAaxmC,EAAI1gD,GAAGknF,IAAcF,IAAWE,GAAaxmC,EAAI1gD,KAAOgnF,EACtE,MAAOhnF,EAEXA,KAEJ,MAAO,GASf,QAASkD,GAAQua,GACb,MAAOhd,OAAMoN,UAAUlI,MAAM3K,KAAKyiB,EAAK,GAU3C,QAAS0pE,GAAYzmC,EAAKr9C,EAAKuN,GAK3B,IAJA,GAAI8gE,MACAlgE,KACAxR,EAAI,EAEDA,EAAI0gD,EAAIvgD,QAAQ,CACnB,GAAIsuE,GAAMprE,EAAMq9C,EAAI1gD,GAAGqD,GAAOq9C,EAAI1gD,EAC9BinF,GAAQz1E,EAAQi9D,GAAO,GACvBiD,EAAQ/uE,KAAK+9C,EAAI1gD,IAErBwR,EAAOxR,GAAKyuE,EACZzuE,IAaJ,MAVI4Q,KAII8gE,EAHCruE,EAGSquE,EAAQ9gE,KAAK,SAAyB7Q,EAAGa,GAC/C,MAAOb,GAAEsD,GAAOzC,EAAEyC,KAHZquE,EAAQ9gE,QAQnB8gE,EASX,QAAS0V,GAAS3pE,EAAK4pE,GAKnB,IAJA,GAAIC,GAAQjnF,EACRknF,EAAYF,EAAS,GAAGtnD,cAAgBsnD,EAAS1hF,MAAM,GAEvD3F,EAAI,EACDA,EAAIwnF,GAAgBrnF,QAAQ,CAI/B,GAHAmnF,EAASE,GAAgBxnF,GACzBK,EAAO,EAAWinF,EAASC,EAAYF,EAEnChnF,IAAQod,GACR,MAAOpd,EAEXL,KAEJ,MAAOgB,GAQX,QAASymF,KACL,MAAOC,MAQX,QAASC,GAAoBpkF,GACzB,GAAIqkF,GAAMrkF,EAAQskF,aAClB,OAAQD,GAAIE,aAAeF,EAAIG,aAyCnC,QAASC,GAAMC,EAAShlF,GACpB,GAAIomE,GAAO5uE,IACXA,MAAKwtF,QAAUA,EACfxtF,KAAKwI,SAAWA,EAChBxI,KAAK8I,QAAU0kF,EAAQ1kF,QACvB9I,KAAK2J,OAAS6jF,EAAQ9+E,QAAQ++E,YAI9BztF,KAAK0tF,WAAa,SAASC,GACnBhC,EAAS6B,EAAQ9+E,QAAQ+0B,QAAS+pD,KAClC5e,EAAKqd,QAAQ0B,IAIrB3tF,KAAK4tF,OAoCT,QAASC,GAAoBL,GACzB,GAAIM,GACAC,EAAaP,EAAQ9+E,QAAQq/E,UAajC,OAAO,KAVHD,EADAC,EACOA,EACAC,GACAC,EACAC,GACAC,EACCC,GAGDC,EAFAC,GAIOd,EAASe,GAS/B,QAASA,GAAaf,EAASnmB,EAAW4O,GACtC,GAAIuY,GAAcvY,EAAMwY,SAAS/oF,OAC7BgpF,EAAqBzY,EAAM0Y,gBAAgBjpF,OAC3CkpF,EAAWvnB,EAAYwnB,IAAgBL,EAAcE,IAAuB,EAC5EI,EAAWznB,GAAa0nB,GAAYC,KAAkBR,EAAcE,IAAuB,CAE/FzY,GAAM2Y,UAAYA,EAClB3Y,EAAM6Y,UAAYA,EAEdF,IACApB,EAAQyB,YAKZhZ,EAAM5O,UAAYA,EAGlB6nB,EAAiB1B,EAASvX,GAG1BuX,EAAQ3/D,KAAK,eAAgBooD,GAE7BuX,EAAQ2B,UAAUlZ,GAClBuX,EAAQyB,QAAQG,UAAYnZ,EAQhC,QAASiZ,GAAiB1B,EAASvX,GAC/B,GAAIgZ,GAAUzB,EAAQyB,QAClBR,EAAWxY,EAAMwY,SACjBY,EAAiBZ,EAAS/oF,MAGzBupF,GAAQK,aACTL,EAAQK,WAAaC,EAAqBtZ,IAI1CoZ,EAAiB,IAAMJ,EAAQO,cAC/BP,EAAQO,cAAgBD,EAAqBtZ,GACnB,IAAnBoZ,IACPJ,EAAQO,eAAgB,EAG5B,IAAIF,GAAaL,EAAQK,WACrBE,EAAgBP,EAAQO,cACxBC,EAAeD,EAAgBA,EAAcrjE,OAASmjE,EAAWnjE,OAEjEA,EAAS8pD,EAAM9pD,OAASujE,EAAUjB,EACtCxY,GAAM0Z,UAAYvyD,KAClB64C,EAAM2Z,UAAY3Z,EAAM0Z,UAAYL,EAAWK,UAE/C1Z,EAAMxnB,MAAQohC,EAASJ,EAActjE,GACrC8pD,EAAMrwD,SAAWk5C,EAAY2wB,EAActjE,GAE3C2jE,EAAeb,EAAShZ,GACxBA,EAAM8Z,gBAAkBC,EAAa/Z,EAAMp2C,OAAQo2C,EAAMn2C,QAEzDm2C,EAAM/4D,MAAQsyE,EAAgB57B,EAAS47B,EAAcf,SAAUA,GAAY,EAC3ExY,EAAMga,SAAWT,EAAgBU,EAAYV,EAAcf,SAAUA,GAAY,EAEjF0B,EAAyBlB,EAAShZ,EAGlC,IAAItsE,GAAS6jF,EAAQ1kF,OACjBsjF,GAAUnW,EAAM7hC,SAASzqC,OAAQA,KACjCA,EAASssE,EAAM7hC,SAASzqC,QAE5BssE,EAAMtsE,OAASA,EAGnB,QAASmmF,GAAeb,EAAShZ,GAC7B,GAAI9pD,GAAS8pD,EAAM9pD,OACfvC,EAASqlE,EAAQmB,gBACjBC,EAAYpB,EAAQoB,cACpBjB,EAAYH,EAAQG,eAEpBnZ,EAAM5O,YAAcwnB,IAAeO,EAAU/nB,YAAc0nB,MAC3DsB,EAAYpB,EAAQoB,WAChBr+E,EAAGo9E,EAAUvvD,QAAU,EACvB5tB,EAAGm9E,EAAUtvD,QAAU,GAG3BlW,EAASqlE,EAAQmB,aACbp+E,EAAGma,EAAOna,EACVC,EAAGka,EAAOla,IAIlBgkE,EAAMp2C,OAASwwD,EAAUr+E,GAAKma,EAAOna,EAAI4X,EAAO5X,GAChDikE,EAAMn2C,OAASuwD,EAAUp+E,GAAKka,EAAOla,EAAI2X,EAAO3X,GAQpD,QAASk+E,GAAyBlB,EAAShZ,GACvC,GAEIpX,GAAUyxB,EAAWC,EAAWp1D,EAFhCq1D,EAAOvB,EAAQwB,cAAgBxa,EAC/B2Z,EAAY3Z,EAAM0Z,UAAYa,EAAKb,SAGvC,IAAI1Z,EAAM5O,WAAa2nB,KAAiBY,EAAYc,IAAoBF,EAAK3xB,WAAat4D,GAAY,CAClG,GAAIs5B,GAAS2wD,EAAK3wD,OAASo2C,EAAMp2C,OAC7BC,EAAS0wD,EAAK1wD,OAASm2C,EAAMn2C,OAE7Bh0B,EAAI6kF,EAAYf,EAAW/vD,EAAQC,EACvCwwD,GAAYxkF,EAAEkG,EACdu+E,EAAYzkF,EAAEmG,EACd4sD,EAAY/zC,GAAIhf,EAAEkG,GAAK8Y,GAAIhf,EAAEmG,GAAMnG,EAAEkG,EAAIlG,EAAEmG,EAC3CkpB,EAAY60D,EAAanwD,EAAQC,GAEjCmvD,EAAQwB,aAAexa,MAGvBpX,GAAW2xB,EAAK3xB,SAChByxB,EAAYE,EAAKF,UACjBC,EAAYC,EAAKD,UACjBp1D,EAAYq1D,EAAKr1D,SAGrB86C,GAAMpX,SAAWA,EACjBoX,EAAMqa,UAAYA,EAClBra,EAAMsa,UAAYA,EAClBta,EAAM96C,UAAYA,EAQtB,QAASo0D,GAAqBtZ,GAK1B,IAFA,GAAIwY,MACAlpF,EAAI,EACDA,EAAI0wE,EAAMwY,SAAS/oF,QACtB+oF,EAASlpF,IACLqX,QAAS+Q,GAAMsoD,EAAMwY,SAASlpF,GAAGqX,SACjCG,QAAS4Q,GAAMsoD,EAAMwY,SAASlpF,GAAGwX,UAErCxX,GAGJ,QACIoqF,UAAWvyD,KACXqxD,SAAUA,EACVtiE,OAAQujE,EAAUjB,GAClB5uD,OAAQo2C,EAAMp2C,OACdC,OAAQm2C,EAAMn2C,QAStB,QAAS4vD,GAAUjB,GACf,GAAIY,GAAiBZ,EAAS/oF,MAG9B,IAAuB,IAAnB2pF,EACA,OACIr9E,EAAG2b,GAAM8gE,EAAS,GAAG7xE,SACrB3K,EAAG0b,GAAM8gE,EAAS,GAAG1xE,SAK7B,KADA,GAAI/K,GAAI,EAAGC,EAAI,EAAG1M,EAAI,EACX8pF,EAAJ9pF,GACHyM,GAAKy8E,EAASlpF,GAAGqX,QACjB3K,GAAKw8E,EAASlpF,GAAGwX,QACjBxX,GAGJ,QACIyM,EAAG2b,GAAM3b,EAAIq9E,GACbp9E,EAAG0b,GAAM1b,EAAIo9E,IAWrB,QAASsB,GAAYf,EAAW59E,EAAGC,GAC/B,OACID,EAAGA,EAAI49E,GAAa,EACpB39E,EAAGA,EAAI29E,GAAa,GAU5B,QAASI,GAAah+E,EAAGC,GACrB,MAAID,KAAMC,EACC2+E,GAGP9lE,GAAI9Y,IAAM8Y,GAAI7Y,GACPD,EAAI,EAAI6+E,GAAiBC,GAE7B7+E,EAAI,EAAI8+E,GAAeC,GAUlC,QAASlyB,GAAYyL,EAAIC,EAAIzkE,GACpBA,IACDA,EAAQkrF,GAEZ,IAAIj/E,GAAIw4D,EAAGzkE,EAAM,IAAMwkE,EAAGxkE,EAAM,IAC5BkM,EAAIu4D,EAAGzkE,EAAM,IAAMwkE,EAAGxkE,EAAM,GAEhC,OAAOd,MAAK2qB,KAAM5d,EAAIA,EAAMC,EAAIA,GAUpC,QAAS49E,GAAStlB,EAAIC,EAAIzkE,GACjBA,IACDA,EAAQkrF,GAEZ,IAAIj/E,GAAIw4D,EAAGzkE,EAAM,IAAMwkE,EAAGxkE,EAAM,IAC5BkM,EAAIu4D,EAAGzkE,EAAM,IAAMwkE,EAAGxkE,EAAM,GAChC,OAA0B,KAAnBd,KAAKkyD,MAAMllD,EAAGD,GAAW/M,KAAK2mB,GASzC,QAASskE,GAAYrgF,EAAOC,GACxB,MAAO+/E,GAAS//E,EAAI,GAAIA,EAAI,GAAIohF,IAAmBrB,EAAShgF,EAAM,GAAIA,EAAM,GAAIqhF,IAUpF,QAASt9B,GAAS/jD,EAAOC,GACrB,MAAOgvD,GAAYhvD,EAAI,GAAIA,EAAI,GAAIohF,IAAmBpyB,EAAYjvD,EAAM,GAAIA,EAAM,GAAIqhF,IAiB1F,QAAS5C,KACLtuF,KAAKmxF,KAAOC,GACZpxF,KAAKqxF,MAAQC,GAEbtxF,KAAKuxF,OAAQ,EACbvxF,KAAKwxF,SAAU,EAEfjE,EAAMv1E,MAAMhY,KAAMyF,WAoEtB,QAASwoF,KACLjuF,KAAKmxF,KAAOM,GACZzxF,KAAKqxF,MAAQK,GAEbnE,EAAMv1E,MAAMhY,KAAMyF,WAElBzF,KAAK2xF,MAAS3xF,KAAKwtF,QAAQyB,QAAQ2C,iBAoEvC,QAASC,KACL7xF,KAAK8xF,SAAWC,GAChB/xF,KAAKqxF,MAAQW,GACbhyF,KAAKiyF,SAAU,EAEf1E,EAAMv1E,MAAMhY,KAAMyF,WAsCtB,QAASysF,GAAuBvE,EAAI9mF,GAChC,GAAIsrF,GAAM1pF,EAAQklF,EAAGptD,SACjBlB,EAAU52B,EAAQklF,EAAGyE,eAMzB,OAJIvrF,IAAQkoF,GAAYC,MACpBmD,EAAMzF,EAAYyF,EAAIl+E,OAAOorB,GAAU,cAAc,KAGjD8yD,EAAK9yD,GAiBjB,QAAS8uD,KACLnuF,KAAK8xF,SAAWO,GAChBryF,KAAKsyF,aAEL/E,EAAMv1E,MAAMhY,KAAMyF,WA0BtB,QAAS8sF,GAAW5E,EAAI9mF,GACpB,GAAI2rF,GAAa/pF,EAAQklF,EAAGptD,SACxB+xD,EAAYtyF,KAAKsyF,SAGrB,IAAIzrF,GAAQgoF,GAAc4D,KAAqC,IAAtBD,EAAW9sF,OAEhD,MADA4sF,GAAUE,EAAW,GAAGE,aAAc,GAC9BF,EAAYA,EAGxB,IAAIjtF,GACAsX,EACAu1E,EAAiB3pF,EAAQklF,EAAGyE,gBAC5BO,KACAhpF,EAAS3J,KAAK2J,MAQlB,IALAkT,EAAgB21E,EAAW5+E,OAAO,SAASmqB,GACvC,MAAOquD,GAAUruD,EAAMp0B,OAAQA,KAI/B9C,IAASgoF,GAET,IADAtpF,EAAI,EACGA,EAAIsX,EAAcnX,QACrB4sF,EAAUz1E,EAActX,GAAGmtF,aAAc,EACzCntF,GAMR,KADAA,EAAI,EACGA,EAAI6sF,EAAe1sF,QAClB4sF,EAAUF,EAAe7sF,GAAGmtF,aAC5BC,EAAqBzqF,KAAKkqF,EAAe7sF,IAIzCsB,GAAQkoF,GAAYC,WACbsD,GAAUF,EAAe7sF,GAAGmtF,YAEvCntF,GAGJ,OAAKotF,GAAqBjtF,QAMtBgnF,EAAY7vE,EAAc5I,OAAO0+E,GAAuB,cAAc,GACtEA,GAPJ,OAoBJ,QAAStE,KACLd,EAAMv1E,MAAMhY,KAAMyF,UAElB,IAAIwmF,GAAUjB,EAAOhrF,KAAKisF,QAASjsF,KACnCA,MAAK+9B,MAAQ,GAAIowD,GAAWnuF,KAAKwtF,QAASvB,GAC1CjsF,KAAK4yF,MAAQ,GAAItE,GAAWtuF,KAAKwtF,QAASvB,GAyD9C,QAAS4G,GAAYrF,EAASpmF,GAC1BpH,KAAKwtF,QAAUA,EACfxtF,KAAKm3E,IAAI/vE,GAuFb,QAAS0rF,GAAkBC,GAEvB,GAAI1G,EAAM0G,EAASC,IACf,MAAOA,GAGX,IAAIC,GAAU5G,EAAM0G,EAASG,IACzBC,EAAU9G,EAAM0G,EAASK,GAG7B,OAAIH,IAAWE,EACJD,GAAqB,IAAME,GAIlCH,GAAWE,EACJF,EAAUC,GAAqBE,GAItC/G,EAAM0G,EAASM,IACRA,GAGJC,GA4CX,QAASC,GAAW7kF,GAChB1O,KAAKK,GAAK2sF,IAEVhtF,KAAKwtF,QAAU,KACfxtF,KAAK0O,QAAU0yD,EAAM1yD,MAAe1O,KAAKwzF,UAGzCxzF,KAAK0O,QAAQ+0B,OAASooD,EAAY7rF,KAAK0O,QAAQ+0B,QAAQ,GAEvDzjC,KAAKyzF,MAAQC,GAEb1zF,KAAK2zF,gBACL3zF,KAAK4zF,eAiOT,QAASC,GAASJ,GACd,MAAIA,GAAQK,GACD,SACAL,EAAQM,GACR,MACAN,EAAQO,GACR,OACAP,EAAQQ,GACR,QAEJ,GAQX,QAASC,GAAa/4D,GAClB,MAAIA,IAAa61D,GACN,OACA71D,GAAa41D,GACb,KACA51D,GAAa01D,GACb,OACA11D,GAAa21D,GACb,QAEJ,GASX,QAASqD,IAA6BC,EAAiBC,GACnD,GAAI7G,GAAU6G,EAAW7G,OACzB,OAAIA,GACOA,EAAQr4E,IAAIi/E,GAEhBA,EAQX,QAASE,MACLf,EAAWv7E,MAAMhY,KAAMyF,WA6D3B,QAAS8uF,MACLD,GAAet8E,MAAMhY,KAAMyF,WAE3BzF,KAAKw0F,GAAK,KACVx0F,KAAKy0F,GAAK,KA2Ed,QAASC,MACLJ,GAAet8E,MAAMhY,KAAMyF,WAsC/B,QAASkvF,MACLpB,EAAWv7E,MAAMhY,KAAMyF,WAEvBzF,KAAK40F,OAAS,KACd50F,KAAK60F,OAAS,KAmElB,QAASC,MACLR,GAAet8E,MAAMhY,KAAMyF,WA8B/B,QAASsvF,MACLT,GAAet8E,MAAMhY,KAAMyF,WA0D/B,QAASuvF,MACLzB,EAAWv7E,MAAMhY,KAAMyF,WAIvBzF,KAAKi1F,OAAQ,EACbj1F,KAAKk1F,SAAU,EAEfl1F,KAAK40F,OAAS,KACd50F,KAAK60F,OAAS,KACd70F,KAAKiX,MAAQ,EAqGjB,QAAS4uB,IAAO/8B,EAAS4F,GAGrB,MAFAA,GAAUA,MACVA,EAAQymF,YAActJ,EAAYn9E,EAAQymF,YAAatvD,GAAO2tD,SAAS4B,QAChE,GAAIC,IAAQvsF,EAAS4F,GAiIhC,QAAS2mF,IAAQvsF,EAAS4F,GACtBA,EAAUA,MAEV1O,KAAK0O,QAAU0yD,EAAM1yD,EAASm3B,GAAO2tD,UACrCxzF,KAAK0O,QAAQ++E,YAAcztF,KAAK0O,QAAQ++E,aAAe3kF,EAEvD9I,KAAKs1F,YACLt1F,KAAKivF,WACLjvF,KAAKm1F,eAELn1F,KAAK8I,QAAUA,EACf9I,KAAKi2E,MAAQ4X,EAAoB7tF,MACjCA,KAAKu1F,YAAc,GAAI1C,GAAY7yF,KAAMA,KAAK0O,QAAQ6mF,aAEtDC,GAAex1F,MAAM,GAErBmrF,EAAKz8E,EAAQymF,YAAa,SAAS7lF,GAC/B,GAAI+kF,GAAar0F,KAAKkT,IAAI,GAAK5D,GAAK,GAAIA,EAAK,IAC7CA,GAAK,IAAM+kF,EAAWoB,cAAcnmF,EAAK,IACzCA,EAAK,IAAM+kF,EAAWqB,eAAepmF,EAAK,KAC3CtP,MAyOP,QAASw1F,IAAehI,EAASt6E,GAC7B,GAAIpK,GAAU0kF,EAAQ1kF,OACtBqiF,GAAKqC,EAAQ9+E,QAAQinF,SAAU,SAASvuF,EAAO8O,GAC3CpN,EAAQoE,MAAMy/E,EAAS7jF,EAAQoE,MAAOgJ,IAAShD,EAAM9L,EAAQ,KASrE,QAASwuF,IAAgBpsF,EAAOmJ,GAC5B,GAAIkjF,GAAerkF,EAASskF,YAAY,QACxCD,GAAaE,UAAUvsF,GAAO,GAAM,GACpCqsF,EAAaj2D,QAAUjtB,EACvBA,EAAKhJ,OAAOqsF,cAAcH,GAr1E9B,GAAI9I,KAAmB,GAAI,SAAU,MAAO,KAAM,KAAM,KACpDkJ,GAAezkF,EAASM,cAAc,OAEtC85E,GAAgB,WAEhBj+D,GAAQ1oB,KAAK0oB,MACb7C,GAAM7lB,KAAK6lB,IACXsS,GAAM/4B,KAAK+4B,IAwSX6vD,GAAY,EAeZiJ,GAAe,wCAEf9H,GAAiB,gBAAkB3mF,GACnCumF,GAAyBrB,EAASllF,EAAQ,kBAAoBlB,EAC9D2nF,GAAqBE,IAAiB8H,GAAajoF,KAAK/E,UAAUC,WAElEgtF,GAAmB,QACnBC,GAAiB,MACjBC,GAAmB,QACnBC,GAAoB,SAEpB5F,GAAmB,GAEnB7B,GAAc,EACd4D,GAAa,EACb1D,GAAY,EACZC,GAAe,EAEf4B,GAAiB,EACjBC,GAAiB,EACjBC,GAAkB,EAClBC,GAAe,EACfC,GAAiB,GAEjBuF,GAAuB1F,GAAiBC,GACxC0F,GAAqBzF,GAAeC,GACpCyF,GAAgBF,GAAuBC,GAEvCvF,IAAY,IAAK,KACjBC,IAAmB,UAAW,UA4BlC3D,GAAMn6E,WAKF64E,QAAS,aAKT2B,KAAM,WACF5tF,KAAKmxF,MAAQnF,EAAkBhsF,KAAK8I,QAAS9I,KAAKmxF,KAAMnxF,KAAK0tF,YAC7D1tF,KAAK8xF,UAAY9F,EAAkBhsF,KAAK2J,OAAQ3J,KAAK8xF,SAAU9xF,KAAK0tF,YACpE1tF,KAAKqxF,OAASrF,EAAkBkB,EAAoBltF,KAAK8I,SAAU9I,KAAKqxF,MAAOrxF,KAAK0tF,aAMxFn6E,QAAS,WACLvT,KAAKmxF,MAAQhF,EAAqBnsF,KAAK8I,QAAS9I,KAAKmxF,KAAMnxF,KAAK0tF,YAChE1tF,KAAK8xF,UAAY3F,EAAqBnsF,KAAK2J,OAAQ3J,KAAK8xF,SAAU9xF,KAAK0tF,YACvE1tF,KAAKqxF,OAASlF,EAAqBe,EAAoBltF,KAAK8I,SAAU9I,KAAKqxF,MAAOrxF,KAAK0tF,aAoT/F,IAAIgJ,KACAC,UAAW9H,GACX+H,UAAWnE,GACXoE,QAAS9H,IAGTqC,GAAuB,YACvBE,GAAsB,mBAiB1BhG,GAAQgD,EAAYf,GAKhBtB,QAAS,SAAmB0B,GACxB,GAAItmB,GAAYqvB,GAAgB/I,EAAG9mF,KAG/BwgE,GAAYwnB,IAA6B,IAAdlB,EAAGjhE,SAC9B1sB,KAAKwxF,SAAU,GAGfnqB,EAAYorB,IAA2B,IAAb9E,EAAGlhE,QAC7B46C,EAAY0nB,IAIX/uF,KAAKwxF,SAAYxxF,KAAKuxF,QAIvBlqB,EAAY0nB,KACZ/uF,KAAKwxF,SAAU,GAGnBxxF,KAAKwI,SAASxI,KAAKwtF,QAASnmB,GACxBonB,UAAWd,GACXgB,iBAAkBhB,GAClBmJ,YAAaT,GACbjiD,SAAUu5C,OAKtB,IAAIoJ,KACAC,YAAanI,GACboI,YAAaxE,GACbyE,UAAWnI,GACXoI,cAAenI,GACfoI,WAAYpI,IAIZqI,IACAC,EAAGnB,GACHoB,EAAGnB,GACHoB,EAAGnB,GACHoB,EAAGnB,IAGH7E,GAAyB,cACzBC,GAAwB,qCAGxBjqF,GAAOiwF,iBACPjG,GAAyB,gBACzBC,GAAwB,6CAiB5BpG,EAAQ2C,EAAmBV,GAKvBtB,QAAS,SAAmB0B,GACxB,GAAIgE,GAAQ3xF,KAAK2xF,MACbgG,GAAgB,EAEhBC,EAAsBjK,EAAG9mF,KAAK+9B,cAAcn6B,QAAQ,KAAM,IAC1D48D,EAAY0vB,GAAkBa,GAC9Bd,EAAcO,GAAuB1J,EAAGmJ,cAAgBnJ,EAAGmJ,YAE3De,EAAWf,GAAeX,GAG1B2B,EAAatL,EAAQmF,EAAOhE,EAAGoK,UAAW,YAG1C1wB,GAAYwnB,KAA8B,IAAdlB,EAAGjhE,QAAgBmrE,GAC9B,EAAbC,IACAnG,EAAMzpF,KAAKylF,GACXmK,EAAanG,EAAMjsF,OAAS,GAEzB2hE,GAAa0nB,GAAYC,MAChC2I,GAAgB,GAIH,EAAbG,IAKJnG,EAAMmG,GAAcnK,EAEpB3tF,KAAKwI,SAASxI,KAAKwtF,QAASnmB,GACxBonB,SAAUkD,EACVhD,iBAAkBhB,GAClBmJ,YAAaA,EACb1iD,SAAUu5C,IAGVgK,GAEAhG,EAAMrpF,OAAOwvF,EAAY,MAKrC,IAAIE,KACAC,WAAYpJ,GACZqJ,UAAWzF,GACX0F,SAAUpJ,GACVqJ,YAAapJ,IAGb+C,GAA6B,aAC7BC,GAA6B,2CAejC1G,GAAQuG,EAAkBtE,GACtBtB,QAAS,SAAmB0B,GACxB,GAAI9mF,GAAOmxF,GAAuBrK,EAAG9mF,KAOrC,IAJIA,IAASgoF,KACT7uF,KAAKiyF,SAAU,GAGdjyF,KAAKiyF,QAAV,CAIA,GAAI1xD,GAAU2xD,EAAuB3xF,KAAKP,KAAM2tF,EAAI9mF,EAGhDA,IAAQkoF,GAAYC,KAAiBzuD,EAAQ,GAAG76B,OAAS66B,EAAQ,GAAG76B,SAAW,IAC/E1F,KAAKiyF,SAAU,GAGnBjyF,KAAKwI,SAASxI,KAAKwtF,QAAS3mF,GACxB4nF,SAAUluD,EAAQ,GAClBouD,gBAAiBpuD,EAAQ,GACzBu2D,YAAaX,GACb/hD,SAAUu5C,OAsBtB,IAAI0K,KACAJ,WAAYpJ,GACZqJ,UAAWzF,GACX0F,SAAUpJ,GACVqJ,YAAapJ,IAGbqD,GAAsB,2CAc1B/G,GAAQ6C,EAAYZ,GAChBtB,QAAS,SAAoB0B,GACzB,GAAI9mF,GAAOwxF,GAAgB1K,EAAG9mF,MAC1B05B,EAAUgyD,EAAWhyF,KAAKP,KAAM2tF,EAAI9mF,EACnC05B,IAILvgC,KAAKwI,SAASxI,KAAKwtF,QAAS3mF,GACxB4nF,SAAUluD,EAAQ,GAClBouD,gBAAiBpuD,EAAQ,GACzBu2D,YAAaX,GACb/hD,SAAUu5C,OAmFtBrC,EAAQ+C,EAAiBd,GAOrBtB,QAAS,SAAoBuB,EAAS8K,EAAYC,GAC9C,GAAIV,GAAWU,EAAUzB,aAAeX,GACpCqC,EAAWD,EAAUzB,aAAeT,EAIxC,IAAIwB,EACA73F,KAAK4yF,MAAMrB,OAAQ,MAChB,IAAIiH,IAAYx4F,KAAK4yF,MAAMrB,MAC9B,MAIA+G,IAAcvJ,GAAYC,MAC1BhvF,KAAK4yF,MAAMrB,OAAQ,GAGvBvxF,KAAKwI,SAASglF,EAAS8K,EAAYC,IAMvChlF,QAAS,WACLvT,KAAK+9B,MAAMxqB,UACXvT,KAAK4yF,MAAMr/E,YAInB,IAAIklF,IAAwB9L,EAASsJ,GAAa/oF,MAAO,eACrDwrF,GAAsBD,KAA0BlyF,EAGhDoyF,GAAuB,UACvBrF,GAAoB,OACpBD,GAA4B,eAC5BL,GAAoB,OACpBE,GAAqB,QACrBE,GAAqB,OAczBP,GAAYz/E,WAKR+jE,IAAK,SAAS/vE,GAENA,GAASuxF,KACTvxF,EAAQpH,KAAK44F,WAGbF,KACA14F,KAAKwtF,QAAQ1kF,QAAQoE,MAAMurF,IAAyBrxF,GAExDpH,KAAK+yF,QAAU3rF,EAAMw9B,cAAcz3B,QAMvC2H,OAAQ,WACJ9U,KAAKm3E,IAAIn3E,KAAKwtF,QAAQ9+E,QAAQ6mF,cAOlCqD,QAAS,WACL,GAAI7F,KAMJ,OALA5H,GAAKnrF,KAAKwtF,QAAQ2H,YAAa,SAASd,GAChC1I,EAAS0I,EAAW3lF,QAAQ+0B,QAAS4wD,MACrCtB,EAAUA,EAAQ9+E,OAAOogF,EAAWwE,qBAGrC/F,EAAkBC,EAAQ5qF,KAAK,OAO1C2wF,gBAAiB,SAAS7iB,GAEtB,IAAIyiB,GAAJ,CAIA,GAAItkD,GAAW6hC,EAAM7hC,SACjBjZ,EAAY86C,EAAM8Z,eAGtB,IAAI/vF,KAAKwtF,QAAQyB,QAAQ8J,UAErB,WADA3kD,GAAS7qC,gBAIb,IAAIwpF,GAAU/yF,KAAK+yF,QACfiG,EAAU3M,EAAM0G,EAASC,IACzBG,EAAU9G,EAAM0G,EAASK,IACzBH,EAAU5G,EAAM0G,EAASG,GAE7B,OAAI8F,IACC7F,GAAWh4D,EAAYo7D,IACvBtD,GAAW93D,EAAYq7D,GACjBx2F,KAAKi5F,WAAW7kD,GAH3B,SAWJ6kD,WAAY,SAAS7kD,GACjBp0C,KAAKwtF,QAAQyB,QAAQ8J,WAAY,EACjC3kD,EAAS7qC,kBA+DjB,IAAImqF,IAAiB,EACjBO,GAAc,EACdD,GAAgB,EAChBD,GAAc,EACdmF,GAAmBnF,GACnBD,GAAkB,GAClBqF,GAAe,EAuBnB5F,GAAWngF,WAKPogF,YAOArc,IAAK,SAASzoE,GAKV,MAJArJ,GAAOrF,KAAK0O,QAASA,GAGrB1O,KAAKwtF,SAAWxtF,KAAKwtF,QAAQ+H,YAAYzgF,SAClC9U,MAQXy1F,cAAe,SAASrB,GACpB,GAAInJ,EAAemJ,EAAiB,gBAAiBp0F,MACjD,MAAOA,KAGX,IAAI2zF,GAAe3zF,KAAK2zF,YAMxB,OALAS,GAAkBD,GAA6BC,EAAiBp0F,MAC3D2zF,EAAaS,EAAgB/zF,MAC9BszF,EAAaS,EAAgB/zF,IAAM+zF,EACnCA,EAAgBqB,cAAcz1F,OAE3BA,MAQXo5F,kBAAmB,SAAShF,GACxB,MAAInJ,GAAemJ,EAAiB,oBAAqBp0F,MAC9CA,MAGXo0F,EAAkBD,GAA6BC,EAAiBp0F,YACzDA,MAAK2zF,aAAaS,EAAgB/zF,IAClCL,OAQX01F,eAAgB,SAAStB,GACrB,GAAInJ,EAAemJ,EAAiB,iBAAkBp0F,MAClD,MAAOA,KAGX,IAAI4zF,GAAc5zF,KAAK4zF,WAMvB,OALAQ,GAAkBD,GAA6BC,EAAiBp0F,MAClB,KAA1CwsF,EAAQoH,EAAaQ,KACrBR,EAAY1rF,KAAKksF,GACjBA,EAAgBsB,eAAe11F,OAE5BA,MAQXq5F,mBAAoB,SAASjF,GACzB,GAAInJ,EAAemJ,EAAiB,qBAAsBp0F,MACtD,MAAOA,KAGXo0F,GAAkBD,GAA6BC,EAAiBp0F,KAChE,IAAIqI,GAAQmkF,EAAQxsF,KAAK4zF,YAAaQ,EAItC,OAHI/rF,GAAQ,IACRrI,KAAK4zF,YAAYtrF,OAAOD,EAAO,GAE5BrI,MAOXs5F,mBAAoB,WAChB,MAAOt5F,MAAK4zF,YAAYluF,OAAS,GAQrC6zF,iBAAkB,SAASnF,GACvB,QAASp0F,KAAK2zF,aAAaS,EAAgB/zF,KAQ/CwtB,KAAM,SAASooD,GAIX,QAASpoD,GAAK2rE,GACV5qB,EAAK4e,QAAQ3/D,KAAK+gD,EAAKlgE,QAAQlF,OAASgwF,EAAY3F,EAASJ,GAAS,IAAKxd,GAJ/E,GAAIrH,GAAO5uE,KACPyzF,EAAQzzF,KAAKyzF,KAOLM,IAARN,GACA5lE,GAAK,GAGTA,IAGI4lE,GAASM,IACTlmE,GAAK,IAUb4rE,QAAS,SAASxjB,GACd,MAAIj2E,MAAK05F,UACE15F,KAAK6tB,KAAKooD,QAGrBj2E,KAAKyzF,MAAQ0F,KAOjBO,QAAS,WAEL,IADA,GAAIn0F,GAAI,EACDA,EAAIvF,KAAK4zF,YAAYluF,QAAQ,CAChC,KAAM1F,KAAK4zF,YAAYruF,GAAGkuF,OAAS0F,GAAezF,KAC9C,OAAO,CAEXnuF,KAEJ,OAAO,GAOX4pF,UAAW,SAASoJ,GAGhB,GAAIoB,GAAiBt0F,KAAWkzF,EAGhC,OAAK5M,GAAS3rF,KAAK0O,QAAQ+0B,QAASzjC,KAAM25F,KAOtC35F,KAAKyzF,OAASyF,GAAmBpF,GAAkBqF,MACnDn5F,KAAKyzF,MAAQC,IAGjB1zF,KAAKyzF,MAAQzzF,KAAK45F,QAAQD,QAItB35F,KAAKyzF,OAASQ,GAAcD,GAAgBD,GAAcD,KAC1D9zF,KAAKy5F,QAAQE,MAfb35F,KAAK6pD,aACL7pD,KAAKyzF,MAAQ0F,MAyBrBS,QAAS,aAOTf,eAAgB,aAOhBhvC,MAAO,cA8DXyhC,EAAQgJ,GAAgBf,GAKpBC,UAKI/E,SAAU,GASdoL,SAAU,SAAS5jB,GACf,GAAI6jB,GAAiB95F,KAAK0O,QAAQ+/E,QAClC,OAA0B,KAAnBqL,GAAwB7jB,EAAMwY,SAAS/oF,SAAWo0F,GAS7DF,QAAS,SAAS3jB,GACd,GAAIwd,GAAQzzF,KAAKyzF,MACbpsB,EAAY4O,EAAM5O,UAElB0yB,EAAetG,GAASQ,GAAcD,IACtCvb,EAAUz4E,KAAK65F,SAAS5jB,EAG5B,OAAI8jB,KAAiB1yB,EAAY2nB,KAAiBvW,GACvCgb,EAAQK,GACRiG,GAAgBthB,EACnBpR,EAAY0nB,GACL0E,EAAQM,GACNN,EAAQQ,GAGdR,EAAQO,GAFJC,GAIRkF,MAiBf7N,EAAQiJ,GAAeD,IAKnBd,UACIhqF,MAAO,MACP6uD,UAAW,GACXo2B,SAAU,EACVtzD,UAAWs7D,IAGfoC,eAAgB,WACZ,GAAI19D,GAAYn7B,KAAK0O,QAAQysB,UACzB43D,IAOJ,OANI53D,GAAYo7D,IACZxD,EAAQ7qF,KAAKkrF,IAEbj4D,EAAYq7D,IACZzD,EAAQ7qF,KAAKgrF,IAEVH,GAGXiH,cAAe,SAAS/jB,GACpB,GAAIvnE,GAAU1O,KAAK0O,QACfurF,GAAW,EACXr0E,EAAWqwD,EAAMrwD,SACjBuV,EAAY86C,EAAM96C,UAClBnpB,EAAIikE,EAAMp2C,OACV5tB,EAAIgkE,EAAMn2C,MAed,OAZM3E,GAAYzsB,EAAQysB,YAClBzsB,EAAQysB,UAAYo7D,IACpBp7D,EAAmB,IAANnpB,EAAW4+E,GAAsB,EAAJ5+E,EAAS6+E,GAAiBC,GACpEmJ,EAAWjoF,GAAKhS,KAAKw0F,GACrB5uE,EAAW3gB,KAAK6lB,IAAImrD,EAAMp2C,UAE1B1E,EAAmB,IAANlpB,EAAW2+E,GAAsB,EAAJ3+E,EAAS8+E,GAAeC,GAClEiJ,EAAWhoF,GAAKjS,KAAKy0F,GACrB7uE,EAAW3gB,KAAK6lB,IAAImrD,EAAMn2C,UAGlCm2C,EAAM96C,UAAYA,EACX8+D,GAAYr0E,EAAWlX,EAAQ2pD,WAAal9B,EAAYzsB,EAAQysB,WAG3E0+D,SAAU,SAAS5jB,GACf,MAAOqe,IAAelhF,UAAUymF,SAASt5F,KAAKP,KAAMi2E,KAC/Cj2E,KAAKyzF,MAAQQ,MAAkBj0F,KAAKyzF,MAAQQ,KAAgBj0F,KAAKg6F,cAAc/jB,KAGxFpoD,KAAM,SAASooD,GACXj2E,KAAKw0F,GAAKve,EAAMp2C,OAChB7/B,KAAKy0F,GAAKxe,EAAMn2C,MAEhB,IAAI3E,GAAY+4D,EAAaje,EAAM96C,UAC/BA,IACAn7B,KAAKwtF,QAAQ3/D,KAAK7tB,KAAK0O,QAAQlF,MAAQ2xB,EAAW86C,GAGtDj2E,KAAK0rF,OAAO79D,KAAKttB,KAAKP,KAAMi2E,MAcpCqV,EAAQoJ,GAAiBJ,IAKrBd,UACIhqF,MAAO,QACP6uD,UAAW,EACXo2B,SAAU,GAGdoK,eAAgB,WACZ,OAAQ7F,KAGZ6G,SAAU,SAAS5jB,GACf,MAAOj2E,MAAK0rF,OAAOmO,SAASt5F,KAAKP,KAAMi2E,KAClChxE,KAAK6lB,IAAImrD,EAAM/4D,MAAQ,GAAKld,KAAK0O,QAAQ2pD,WAAar4D,KAAKyzF,MAAQQ,KAG5EpmE,KAAM,SAASooD,GAEX,GADAj2E,KAAK0rF,OAAO79D,KAAKttB,KAAKP,KAAMi2E,GACR,IAAhBA,EAAM/4D,MAAa,CACnB,GAAIg9E,GAAQjkB,EAAM/4D,MAAQ,EAAI,KAAO,KACrCld,MAAKwtF,QAAQ3/D,KAAK7tB,KAAK0O,QAAQlF,MAAQ0wF,EAAOjkB,OAkB1DqV,EAAQqJ,GAAiBpB,GAKrBC,UACIhqF,MAAO,QACPilF,SAAU,EACVr0D,KAAM,IACNi+B,UAAW,GAGfwgC,eAAgB,WACZ,OAAQvF,KAGZsG,QAAS,SAAS3jB,GACd,GAAIvnE,GAAU1O,KAAK0O,QACfyrF,EAAgBlkB,EAAMwY,SAAS/oF,SAAWgJ,EAAQ+/E,SAClD2L,EAAgBnkB,EAAMrwD,SAAWlX,EAAQ2pD,UACzCgiC,EAAYpkB,EAAM2Z,UAAYlhF,EAAQ0rB,IAM1C;GAJAp6B,KAAK60F,OAAS5e,GAITmkB,IAAkBD,GAAkBlkB,EAAM5O,WAAa0nB,GAAYC,MAAkBqL,EACtFr6F,KAAK6pD,YACF,IAAIosB,EAAM5O,UAAYwnB,GACzB7uF,KAAK6pD,QACL7pD,KAAK40F,OAAS9J,EAAkB,WAC5B9qF,KAAKyzF,MAAQyF,GACbl5F,KAAKy5F,WACN/qF,EAAQ0rB,KAAMp6B,UACd,IAAIi2E,EAAM5O,UAAY0nB,GACzB,MAAOmK,GAEX,OAAOC,KAGXtvC,MAAO,WACHvwC,aAAatZ,KAAK40F,SAGtB/mE,KAAM,SAASooD,GACPj2E,KAAKyzF,QAAUyF,KAIfjjB,GAAUA,EAAM5O,UAAY0nB,GAC5B/uF,KAAKwtF,QAAQ3/D,KAAK7tB,KAAK0O,QAAQlF,MAAQ,KAAMysE,IAE7Cj2E,KAAK60F,OAAOlF,UAAYvyD,KACxBp9B,KAAKwtF,QAAQ3/D,KAAK7tB,KAAK0O,QAAQlF,MAAOxJ,KAAK60F,aAevDvJ,EAAQwJ,GAAkBR,IAKtBd,UACIhqF,MAAO,SACP6uD,UAAW,EACXo2B,SAAU,GAGdoK,eAAgB,WACZ,OAAQ7F,KAGZ6G,SAAU,SAAS5jB,GACf,MAAOj2E,MAAK0rF,OAAOmO,SAASt5F,KAAKP,KAAMi2E,KAClChxE,KAAK6lB,IAAImrD,EAAMga,UAAYjwF,KAAK0O,QAAQ2pD,WAAar4D,KAAKyzF,MAAQQ,OAc/E3I,EAAQyJ,GAAiBT,IAKrBd,UACIhqF,MAAO,QACP6uD,UAAW,GACXwG,SAAU,IACV1jC,UAAWo7D,GAAuBC,GAClC/H,SAAU,GAGdoK,eAAgB,WACZ,MAAOtE,IAAcnhF,UAAUylF,eAAet4F,KAAKP,OAGvD65F,SAAU,SAAS5jB,GACf,GACIpX,GADA1jC,EAAYn7B,KAAK0O,QAAQysB,SAW7B,OARIA,IAAao7D,GAAuBC,IACpC33B,EAAWoX,EAAMpX,SACV1jC,EAAYo7D,GACnB13B,EAAWoX,EAAMqa,UACVn1D,EAAYq7D,KACnB33B,EAAWoX,EAAMsa,WAGdvwF,KAAK0rF,OAAOmO,SAASt5F,KAAKP,KAAMi2E,IACnC96C,EAAY86C,EAAM96C,WAClB86C,EAAMrwD,SAAW5lB,KAAK0O,QAAQ2pD,WAC9BvtC,GAAI+zC,GAAY7+D,KAAK0O,QAAQmwD,UAAYoX,EAAM5O,UAAY0nB,IAGnElhE,KAAM,SAASooD,GACX,GAAI96C,GAAY+4D,EAAaje,EAAM96C,UAC/BA,IACAn7B,KAAKwtF,QAAQ3/D,KAAK7tB,KAAK0O,QAAQlF,MAAQ2xB,EAAW86C,GAGtDj2E,KAAKwtF,QAAQ3/D,KAAK7tB,KAAK0O,QAAQlF,MAAOysE,MA2B9CqV,EAAQ0J,GAAezB,GAKnBC,UACIhqF,MAAO,MACPilF,SAAU,EACV6L,KAAM,EACN7nE,SAAU,IACV2H,KAAM,IACNi+B,UAAW,EACXkiC,aAAc,IAGlB1B,eAAgB,WACZ,OAAQxF,KAGZuG,QAAS,SAAS3jB,GACd,GAAIvnE,GAAU1O,KAAK0O,QAEfyrF,EAAgBlkB,EAAMwY,SAAS/oF,SAAWgJ,EAAQ+/E,SAClD2L,EAAgBnkB,EAAMrwD,SAAWlX,EAAQ2pD,UACzCmiC,EAAiBvkB,EAAM2Z,UAAYlhF,EAAQ0rB,IAI/C,IAFAp6B,KAAK6pD,QAEAosB,EAAM5O,UAAYwnB,IAAgC,IAAf7uF,KAAKiX,MACzC,MAAOjX,MAAKy6F,aAKhB,IAAIL,GAAiBI,GAAkBL,EAAe,CAClD,GAAIlkB,EAAM5O,WAAa0nB,GACnB,MAAO/uF,MAAKy6F,aAGhB,IAAIC,GAAgB16F,KAAKi1F,MAAShf,EAAM0Z,UAAY3vF,KAAKi1F,MAAQvmF,EAAQ+jB,UAAY,EACjFkoE,GAAiB36F,KAAKk1F,SAAWp2B,EAAY9+D,KAAKk1F,QAASjf,EAAM9pD,QAAUzd,EAAQ6rF,YAEvFv6F,MAAKi1F,MAAQhf,EAAM0Z,UACnB3vF,KAAKk1F,QAAUjf,EAAM9pD,OAEhBwuE,GAAkBD,EAGnB16F,KAAKiX,OAAS,EAFdjX,KAAKiX,MAAQ,EAKjBjX,KAAK60F,OAAS5e,CAId,IAAI2kB,GAAW56F,KAAKiX,MAAQvI,EAAQ4rF,IACpC,IAAiB,IAAbM,EAGA,MAAK56F,MAAKs5F,sBAGNt5F,KAAK40F,OAAS9J,EAAkB,WAC5B9qF,KAAKyzF,MAAQyF,GACbl5F,KAAKy5F,WACN/qF,EAAQ+jB,SAAUzyB,MACdi0F,IANAiF,GAUnB,MAAOC,KAGXsB,YAAa,WAIT,MAHAz6F,MAAK40F,OAAS9J,EAAkB,WAC5B9qF,KAAKyzF,MAAQ0F,IACdn5F,KAAK0O,QAAQ+jB,SAAUzyB,MACnBm5F,IAGXtvC,MAAO,WACHvwC,aAAatZ,KAAK40F,SAGtB/mE,KAAM,WACE7tB,KAAKyzF,OAASyF,KACdl5F,KAAK60F,OAAO+F,SAAW56F,KAAKiX,MAC5BjX,KAAKwtF,QAAQ3/D,KAAK7tB,KAAK0O,QAAQlF,MAAOxJ,KAAK60F,YAoBvDhvD,GAAOw7C,QAAU,QAMjBx7C,GAAO2tD,UAOHqH,WAAW,EAQXtF,YAAaoD,GAMbl1D,QAAQ,EASRgqD,YAAa,KAObM,WAAY,KAOZqH,SAEKN,IAAoBrxD,QAAQ,KAC5BixD,IAAmBjxD,QAAQ,IAAU,YACrCsxD,IAAkB55D,UAAWo7D,MAC7BhC,IAAiBp5D,UAAWo7D,KAAyB,WACrDvB,KACAA,IAAiBxrF,MAAO,YAAa8wF,KAAM,IAAM,SACjD3F,KAQLgB,UAMImF,WAAY,OAOZC,YAAa,OASbC,aAAc,OAOdC,eAAgB,OAOhBC,SAAU,OAQVC,kBAAmB,iBAI3B,IAAIC,IAAO,EACPC,GAAc,CA+BlBhG,IAAQjiF,WAMJ+jE,IAAK,SAASzoE,GAaV,MAZArJ,GAAOrF,KAAK0O,QAASA,GAGjBA,EAAQ6mF,aACRv1F,KAAKu1F,YAAYzgF,SAEjBpG,EAAQ++E,cAERztF,KAAKi2E,MAAM1iE,UACXvT,KAAKi2E,MAAMtsE,OAAS+E,EAAQ++E,YAC5BztF,KAAKi2E,MAAM2X,QAER5tF,MASXmlB,KAAM,SAAS8b,GACXjhC,KAAKivF,QAAQqM,QAAUr6D,EAAQo6D,GAAcD,IASjDjM,UAAW,SAASoJ,GAChB,GAAItJ,GAAUjvF,KAAKivF,OACnB,KAAIA,EAAQqM,QAAZ,CAKAt7F,KAAKu1F,YAAYuD,gBAAgBP,EAEjC,IAAIlE,GACAc,EAAcn1F,KAAKm1F,YAKnBoG,EAAgBtM,EAAQsM,gBAIvBA,GAAkBA,GAAiBA,EAAc9H,MAAQyF,MAC1DqC,EAAgBtM,EAAQsM,cAAgB,KAI5C,KADA,GAAIh2F,GAAI,EACDA,EAAI4vF,EAAYzvF,QACnB2uF,EAAac,EAAY5vF,GAQrB0pF,EAAQqM,UAAYD,IACfE,GAAiBlH,GAAckH,IAChClH,EAAWkF,iBAAiBgC,GAGhClH,EAAWxqC,QAFXwqC,EAAWlF,UAAUoJ,IAOpBgD,GAAiBlH,EAAWZ,OAASQ,GAAcD,GAAgBD,MACpEwH,EAAgBtM,EAAQsM,cAAgBlH,GAE5C9uF,MASR4P,IAAK,SAASk/E,GACV,GAAIA,YAAsBd,GACtB,MAAOc,EAIX,KAAK,GADDc,GAAcn1F,KAAKm1F,YACd5vF,EAAI,EAAGA,EAAI4vF,EAAYzvF,OAAQH,IACpC,GAAI4vF,EAAY5vF,GAAGmJ,QAAQlF,OAAS6qF,EAChC,MAAOc,GAAY5vF,EAG3B,OAAO,OASX2N,IAAK,SAASmhF,GACV,GAAIpJ,EAAeoJ,EAAY,MAAOr0F,MAClC,MAAOA,KAIX,IAAIqiD,GAAWriD,KAAKmV,IAAIk/E,EAAW3lF,QAAQlF,MAS3C,OARI64C,IACAriD,KAAKsW,OAAO+rC,GAGhBriD,KAAKm1F,YAAYjtF,KAAKmsF,GACtBA,EAAW7G,QAAUxtF,KAErBA,KAAKu1F,YAAYzgF,SACVu/E,GAQX/9E,OAAQ,SAAS+9E,GACb,GAAIpJ,EAAeoJ,EAAY,SAAUr0F,MACrC,MAAOA,KAGX,IAAIm1F,GAAcn1F,KAAKm1F,WAKvB,OAJAd,GAAar0F,KAAKmV,IAAIk/E,GACtBc,EAAY7sF,OAAOkkF,EAAQ2I,EAAad,GAAa,GAErDr0F,KAAKu1F,YAAYzgF,SACV9U,MASXwT,GAAI,SAASkyD,EAAQumB,GACjB,GAAIqJ,GAAWt1F,KAAKs1F,QAKpB,OAJAnK,GAAKe,EAASxmB,GAAS,SAASl8D,GAC5B8rF,EAAS9rF,GAAS8rF,EAAS9rF,OAC3B8rF,EAAS9rF,GAAOtB,KAAK+jF,KAElBjsF,MASX2T,IAAK,SAAS+xD,EAAQumB,GAClB,GAAIqJ,GAAWt1F,KAAKs1F,QAQpB,OAPAnK,GAAKe,EAASxmB,GAAS,SAASl8D,GACvByiF,EAGDqJ,EAAS9rF,GAAOlB,OAAOkkF,EAAQ8I,EAAS9rF,GAAQyiF,GAAU,SAFnDqJ,GAAS9rF,KAKjBxJ,MAQX6tB,KAAM,SAASrkB,EAAOmJ,GAEd3S,KAAK0O,QAAQmsF,WACbjF,GAAgBpsF,EAAOmJ,EAI3B,IAAI2iF,GAAWt1F,KAAKs1F,SAAS9rF,IAAUxJ,KAAKs1F,SAAS9rF,GAAO0B,OAC5D,IAAKoqF,GAAaA,EAAS5vF,OAA3B,CAIAiN,EAAK9L,KAAO2C,EACZmJ,EAAKpJ,eAAiB,WAClBoJ,EAAKyhC,SAAS7qC,iBAIlB,KADA,GAAIhE,GAAI,EACDA,EAAI+vF,EAAS5vF,QAChB4vF,EAAS/vF,GAAGoN,GACZpN,MAQRgO,QAAS,WACLvT,KAAK8I,SAAW0sF,GAAex1F,MAAM,GAErCA,KAAKs1F,YACLt1F,KAAKivF,WACLjvF,KAAKi2E,MAAM1iE,UACXvT,KAAK8I,QAAU,OA4BvBzD,EAAOwgC,IACHgpD,YAAaA,GACb4D,WAAYA,GACZ1D,UAAWA,GACXC,aAAcA,GAEd0E,eAAgBA,GAChBO,YAAaA,GACbD,cAAeA,GACfD,YAAaA,GACbmF,iBAAkBA,GAClBpF,gBAAiBA,GACjBqF,aAAcA,GAEdvI,eAAgBA,GAChBC,eAAgBA,GAChBC,gBAAiBA,GACjBC,aAAcA,GACdC,eAAgBA,GAChBuF,qBAAsBA,GACtBC,mBAAoBA,GACpBC,cAAeA,GAEfpB,QAASA,GACT9H,MAAOA,EACPsF,YAAaA,EAEb1E,WAAYA,EACZG,WAAYA,EACZL,kBAAmBA,EACnBI,gBAAiBA,EACjBwD,iBAAkBA,EAElB0B,WAAYA,EACZe,eAAgBA,GAChBkH,IAAKxG,GACLyG,IAAKlH,GACLmH,MAAO3G,GACP4G,MAAOjH,GACPkH,OAAQ9G,GACR+G,MAAOlH,GAEPnhF,GAAIw4E,EACJr4E,IAAKw4E,EACLhB,KAAMA,EACN/pB,MAAOA,EACP/7D,OAAQA,EACRimF,QAASA,EACTN,OAAQA,EACR2B,SAAUA,IAGV,YAAcf,IAAiB1rF,EAAoB,KACjDkvE,EAAgC,WAC9B,MAAOvpC,KACTtlC,KAAKX,EAASM,EAAqBN,EAASC,KAASuvE,IAAkC7oE,IAAc1G,EAAOD,QAAUwvE,KAChG,mBAAVvvE,IAAyBA,EAAOD,QAC9CC,EAAOD,QAAUimC,GAEjBp+B,EAAOojF,GAAchlD,IAGtBp+B,OAAQ+J,SAAU,WAKjB,SAAS3R,EAAQD,GAYrBA,EAAQ4lD,oBAAsB,WAE7BxlD,KAAK87F,aAAa97F,KAAKgiD,UAAUvC,WAAWC,iBAAiB,GAG7D1/C,KAAK6uD,eAID7uD,KAAKyhD,WACPzhD,KAAKkoD,aAEPloD,KAAK6P,SASNjQ,EAAQk8F,aAAe,SAASC,EAAkBC,GAOhD,IANA,GAAIj1C,GAAgB/mD,KAAKokD,YAAY1+C,OAEjCu2F,EAAY,GACZ/9C,EAAQ,EAGL6I,EAAgBg1C,GAA4BE,EAAR/9C,GACrCA,EAAQ,GAAK,GACfl+C,KAAKk8F,oBAAmB,GACxBl8F,KAAKm8F,0BAGLn8F,KAAKo8F,uBAGPr1C,EAAgB/mD,KAAKokD,YAAY1+C,OACjCw4C,GAAS,CAIPA,GAAQ,GAAmB,GAAd89C,GACfh8F,KAAKq8F,kBAEPr8F,KAAK0uD,2BASP9uD,EAAQ08F,YAAc,SAASn2C,GAC7B,GAAIo2C,GAA2Bv8F,KAAKolD,MACpC,IAAIe,EAAKuW,YAAc18D,KAAKgiD,UAAUvC,WAAWM,iBAAmB//C,KAAKw8F,kBAAkBr2C,KACrE,WAAlBnmD,KAAKy8F,WAAqD,GAA3Bz8F,KAAKokD,YAAY1+C,QAAc,CAEhE1F,KAAK08F,WAAWv2C,EAIhB,KAHA,GAAIjI,GAAQ,EAGJl+C,KAAKokD,YAAY1+C,OAAS1F,KAAKgiD,UAAUvC,WAAWC,iBAA6B,GAARxB,GAC/El+C,KAAK28F,uBACLz+C,GAAS,MAKXl+C,MAAK48F,mBAAmBz2C,GAAK,GAAM,GAGnCnmD,KAAKqnD,uBACLrnD,KAAK68F,sBACL78F,KAAK0uD,0BACL1uD,KAAK6uD,cAIH7uD,MAAKolD,QAAUm3C,GACjBv8F,KAAK6P,SAQTjQ,EAAQitD,sBAAwB,WACW,GAArC7sD,KAAKgiD,UAAUvC,WAAW9wC,SAC5B3O,KAAK88F,eAAe,GAAE,GAAM,IAUhCl9F,EAAQw8F,qBAAuB,WAC7Bp8F,KAAK88F,eAAe,IAAG,GAAM,IAS/Bl9F,EAAQ+8F,qBAAuB,WAC7B38F,KAAK88F,eAAe,GAAE,GAAM,IAgB9Bl9F,EAAQk9F,eAAiB,SAASC,EAAcC,EAAU/7D,EAAMg8D,GAC9D,GAAIV,GAA2Bv8F,KAAKolD,OAChC83C,EAAgBl9F,KAAKokD,YAAY1+C,MAGjC1F,MAAKykD,cAAgBzkD,KAAKkd,OAA0B,GAAjB6/E,GACrC/8F,KAAKm9F,kBAIHn9F,KAAKykD,cAAgBzkD,KAAKkd,OAA0B,IAAjB6/E,EAGrC/8F,KAAKo9F,cAAcn8D,IAEZjhC,KAAKykD,cAAgBzkD,KAAKkd,OAA0B,GAAjB6/E,KAC7B,GAAT97D,EAGFjhC,KAAKq9F,cAAcL,EAAU/7D,GAI7BjhC,KAAKs9F,uBAGTt9F,KAAKqnD,uBAGDrnD,KAAKokD,YAAY1+C,QAAUw3F,IAAkBl9F,KAAKykD,cAAgBzkD,KAAKkd,OAA0B,IAAjB6/E,KAClF/8F,KAAKu9F,eAAet8D,GACpBjhC,KAAKqnD,yBAIHrnD,KAAKykD,cAAgBzkD,KAAKkd,OAA0B,IAAjB6/E,KACrC/8F,KAAKw9F,eACLx9F,KAAKqnD,wBAGPrnD,KAAKykD,cAAgBzkD,KAAKkd,MAG1Bld,KAAK68F,sBACL78F,KAAK6uD,eAGD7uD,KAAKokD,YAAY1+C,OAASw3F,IAC5Bl9F,KAAKm8D,gBAAkB,EAEvBn8D,KAAKm8F,2BAGW,GAAdc,GAAsC12F,SAAf02F,IAErBj9F,KAAKolD,QAAUm3C,GACjBv8F,KAAK6P,QAIT7P,KAAK0uD,2BAMP9uD,EAAQ49F,aAAe,WAErB,GAAIC,GAAkBz9F,KAAK09F,mBACvBD,GAAkBz9F,KAAKgiD,UAAUvC,WAAWI,gBAC9C7/C,KAAK29F,sBAAsB,EAAI39F,KAAKgiD,UAAUvC,WAAWI,eAAiB49C,IAW9E79F,EAAQ29F,eAAiB,SAASt8D,GAChCjhC,KAAK49F,cACL59F,KAAK69F,mBAAmB58D,GAAM,IAQhCrhC,EAAQs8F,mBAAqB,SAASe,GACpC,GAAIV,GAA2Bv8F,KAAKolD,OAChC83C,EAAgBl9F,KAAKokD,YAAY1+C,MAErC1F,MAAKu9F,gBAAe,GAGpBv9F,KAAKqnD,uBACLrnD,KAAK68F,sBACL78F,KAAK6uD,eAGD7uD,KAAKokD,YAAY1+C,QAAUw3F,IAC7Bl9F,KAAKm8D,gBAAkB,IAGP,GAAd8gC,GAAsC12F,SAAf02F,IAErBj9F,KAAKolD,QAAUm3C,GACjBv8F,KAAK6P,SAUXjQ,EAAQ09F,oBAAsB,WAC5B,IAAK,GAAI92C,KAAUxmD,MAAKs9C,MACtB,GAAIt9C,KAAKs9C,MAAMz3C,eAAe2gD,GAAS,CACrC,GAAIL,GAAOnmD,KAAKs9C,MAAMkJ,EACD,IAAjBL,EAAKma,WACFna,EAAK3zC,MAAMxS,KAAKkd,MAAQld,KAAKgiD,UAAUvC,WAAWO,oBAAsBhgD,KAAKuf,MAAMC,OAAOC,aAC1F0mC,EAAK1zC,OAAOzS,KAAKkd,MAAQld,KAAKgiD,UAAUvC,WAAWO,oBAAsBhgD,KAAKuf,MAAMC,OAAOsF,eAC9F9kB,KAAKs8F,YAAYn2C,KAc3BvmD,EAAQy9F,cAAgB,SAASL,EAAU/7D,GACzC,IAAK,GAAI17B,GAAI,EAAGA,EAAIvF,KAAKokD,YAAY1+C,OAAQH,IAAK,CAChD,GAAI4gD,GAAOnmD,KAAKs9C,MAAMt9C,KAAKokD,YAAY7+C,GACvCvF,MAAK48F,mBAAmBz2C,EAAK62C,EAAU/7D,GACvCjhC,KAAK0uD,4BAeT9uD,EAAQg9F,mBAAqB,SAAS9yF,EAAYkzF,EAAW/7D,EAAO68D,GAElE,GAAIh0F,EAAW4yD,YAAc,IAEvB5yD,EAAW4yD,YAAc18D,KAAKgiD,UAAUvC,WAAWM,kBACrD+9C,GAAU,GAEZd,EAAYc,GAAU,EAAOd,EAGzBlzF,EAAW2yD,eAAiBz8D,KAAKkd,OAAkB,GAAT+jB,GAE5C,IAAK,GAAI88D,KAAmBj0F,GAAW6yD,eACrC,GAAI7yD,EAAW6yD,eAAe92D,eAAek4F,GAAkB,CAC7D,GAAIC,GAAYl0F,EAAW6yD,eAAeohC,EAI7B,IAAT98D,GACE+8D,EAAU7hC,gBAAkBryD,EAAW+yD,gBAAgB/yD,EAAW+yD,gBAAgBn3D,OAAO,IACtFo4F,IACL99F,KAAKi+F,sBAAsBn0F,EAAWi0F,EAAgBf,EAAU/7D,EAAM68D,GAIpE99F,KAAKw8F,kBAAkB1yF,IACzB9J,KAAKi+F,sBAAsBn0F,EAAWi0F,EAAgBf,EAAU/7D,EAAM68D,KAwBpFl+F,EAAQq+F,sBAAwB,SAASn0F,EAAYi0F,EAAiBf,EAAW/7D,EAAO68D,GACtF,GAAIE,GAAYl0F,EAAW6yD,eAAeohC,EAG1C,IAAIC,EAAUvhC,eAAiBz8D,KAAKkd,OAAkB,GAAT+jB,EAAe,CAE1DjhC,KAAKk+F,eAGLl+F,KAAKs9C,MAAMygD,GAAmBC,EAG9Bh+F,KAAKm+F,uBAAuBr0F,EAAWk0F,GAGvCh+F,KAAKo+F,wBAAwBt0F,EAAWk0F,GAGxCh+F,KAAKq+F,eAAev0F,GAGpBA,EAAW4E,QAAQ6uC,MAAQygD,EAAUtvF,QAAQ6uC,KAC7CzzC,EAAW4yD,aAAeshC,EAAUthC,YACpC5yD,EAAW4E,QAAQmvC,SAAW54C,KAAK8G,IAAI/L,KAAKgiD,UAAUvC,WAAWS,YAAalgD,KAAKgiD,UAAU1E,MAAMO,SAAW79C,KAAKgiD,UAAUvC,WAAWQ,oBAAoBn2C,EAAW4yD,YAAY,IACnL5yD,EAAWoyD,mBAAqBpyD,EAAW0lD,aAAa9pD,OAGxDs4F,EAAUhsF,EAAIlI,EAAWkI,EAAIlI,EAAWyyD,iBAAmB,GAAMt3D,KAAKE,UACtE64F,EAAU/rF,EAAInI,EAAWmI,EAAInI,EAAWyyD,iBAAmB,GAAMt3D,KAAKE,gBAG/D2E,GAAW6yD,eAAeohC,EAGjC,IAAIO,IAAgB,CACpB,KAAK,GAAIC,KAAez0F,GAAW6yD,eACjC,GAAI7yD,EAAW6yD,eAAe92D,eAAe04F,IACvCz0F,EAAW6yD,eAAe4hC,GAAapiC,gBAAkB6hC,EAAU7hC,eAAgB,CACrFmiC,GAAgB,CAChB,OAKe,GAAjBA,GACFx0F,EAAW+yD,gBAAgBliB,MAG7B36C,KAAKw+F,uBAAuBR,GAI5BA,EAAU7hC,eAAiB,EAG3BryD,EAAW00D,iBAGXx+D,KAAKolD,QAAS,EAIC,GAAb43C,GACFh9F,KAAK48F,mBAAmBoB,EAAUhB,EAAU/7D,EAAM68D,IAWtDl+F,EAAQ4+F,uBAAyB,SAASr4C,GACxC,IAAK,GAAI5gD,GAAI,EAAGA,EAAI4gD,EAAKqJ,aAAa9pD,OAAQH,IAC5C4gD,EAAKqJ,aAAajqD,GAAGitD,sBAczB5yD,EAAQw9F,cAAgB,SAASn8D,GAClB,GAATA,EACFjhC,KAAKy+F,sBAGLz+F,KAAK0+F,wBAUT9+F,EAAQ6+F,oBAAsB,WAC5B,GAAI5/E,GAAGC,EAAGpZ,EACNi5F,EAAY3+F,KAAKgiD,UAAUvC,WAAWK,qBAAqB9/C,KAAKkd,KAIpE,KAAK,GAAImwC,KAAUrtD,MAAKo+C,MACtB,GAAIp+C,KAAKo+C,MAAMv4C,eAAewnD,GAAS,CACrC,GAAIU,GAAO/tD,KAAKo+C,MAAMiP,EACtB,IAAIU,EAAKC,WACHD,EAAKkG,MAAQlG,EAAKiG,SACpBn1C,EAAMkvC,EAAKzkC,GAAGtX,EAAI+7C,EAAK1kC,KAAKrX,EAC5B8M,EAAMivC,EAAKzkC,GAAGrX,EAAI87C,EAAK1kC,KAAKpX,EAC5BvM,EAAST,KAAK2qB,KAAK/Q,EAAKA,EAAKC,EAAKA,GAGrB6/E,EAATj5F,GAAoB,CAEtB,GAAIoE,GAAaikD,EAAK1kC,KAClB20E,EAAYjwC,EAAKzkC,EACjBykC,GAAKzkC,GAAG5a,QAAQ6uC,KAAOwQ,EAAK1kC,KAAK3a,QAAQ6uC,OAC3CzzC,EAAaikD,EAAKzkC,GAClB00E,EAAYjwC,EAAK1kC,MAGiB,GAAhC20E,EAAU9hC,mBACZl8D,KAAK4+F,cAAc90F,EAAWk0F,GAAU,GAEA,GAAjCl0F,EAAWoyD,oBAClBl8D,KAAK4+F,cAAcZ,EAAUl0F,GAAW,MAetDlK,EAAQ8+F,qBAAuB,WAC7B,IAAK,GAAIl4C,KAAUxmD,MAAKs9C,MAEtB,GAAIt9C,KAAKs9C,MAAMz3C,eAAe2gD,GAAS,CACrC,GAAIw3C,GAAYh+F,KAAKs9C,MAAMkJ,EAG3B,IAAoC,GAAhCw3C,EAAU9hC,oBAA4D,GAAjC8hC,EAAUxuC,aAAa9pD,OAAa,CAC3E,GAAIqoD,GAAOiwC,EAAUxuC,aAAa,GAC9B1lD,EAAcikD,EAAKkG,MAAQ+pC,EAAU39F,GAAML,KAAKs9C,MAAMyQ,EAAKiG,QAAUh0D,KAAKs9C,MAAMyQ,EAAKkG,KAGrF+pC,GAAU39F,IAAMyJ,EAAWzJ,KACzByJ,EAAW4E,QAAQ6uC,KAAOygD,EAAUtvF,QAAQ6uC,KAC9Cv9C,KAAK4+F,cAAc90F,EAAWk0F,GAAU,GAGxCh+F,KAAK4+F,cAAcZ,EAAUl0F,GAAW,OAgBpDlK,EAAQi/F,4BAA8B,SAAS14C,GAG7C,IAAK,GAFD24C,GAAoB,GACpBC,EAAwB,KACnBx5F,EAAI,EAAGA,EAAI4gD,EAAKqJ,aAAa9pD,OAAQH,IAC5C,GAA6BgB,SAAzB4/C,EAAKqJ,aAAajqD,GAAkB,CACtC,GAAIy5F,GAAY,IACZ74C,GAAKqJ,aAAajqD,GAAGyuD,QAAU7N,EAAK9lD,GACtC2+F,EAAY74C,EAAKqJ,aAAajqD,GAAG8jB,KAE1B88B,EAAKqJ,aAAajqD,GAAG0uD,MAAQ9N,EAAK9lD,KACzC2+F,EAAY74C,EAAKqJ,aAAajqD,GAAG+jB,IAIlB,MAAb01E,GAAqBF,EAAoBE,EAAUniC,gBAAgBn3D,SACrEo5F,EAAoBE,EAAUniC,gBAAgBn3D,OAC9Cq5F,EAAwBC,GAKb,MAAbA,GAAkDz4F,SAA7BvG,KAAKs9C,MAAM0hD,EAAU3+F,KAC5CL,KAAK4+F,cAAcI,EAAW74C,GAAM,IAYxCvmD,EAAQi+F,mBAAqB,SAAS58D,EAAOg+D,GAE3C,IAAK,GAAIz4C,KAAUxmD,MAAKs9C,MAElBt9C,KAAKs9C,MAAMz3C,eAAe2gD,IAC5BxmD,KAAKk/F,oBAAoBl/F,KAAKs9C,MAAMkJ,GAAQvlB,EAAMg+D,IAcxDr/F,EAAQs/F,oBAAsB,SAASC,EAASl+D,EAAOg+D,EAAWG,GAKhE,GAJ6B74F,SAAzB64F,IACFA,EAAuB,GAGpBD,EAAQjjC,oBAAsBl8D,KAAKwtE,cAA6B,GAAbyxB,GACrDE,EAAQjjC,oBAAsBl8D,KAAKwtE,cAA6B,GAAbyxB,EAAoB,CASxE,IAAK,GAPDpgF,GAAGC,EAAGpZ,EACNi5F,EAAY3+F,KAAKgiD,UAAUvC,WAAWK,qBAAqB9/C,KAAKkd,MAChEmiF,GAAe,EAGfC,KACAC,EAAuBJ,EAAQ3vC,aAAa9pD,OACvCmmB,EAAI,EAAO0zE,EAAJ1zE,EAA0BA,IACxCyzE,EAAap3F,KAAKi3F,EAAQ3vC,aAAa3jC,GAAGxrB,GAK5C,IAAa,GAAT4gC,EAEF,IADAo+D,GAAe,EACVxzE,EAAI,EAAO0zE,EAAJ1zE,EAA0BA,IAAK,CACzC,GAAIkiC,GAAO/tD,KAAKo+C,MAAMkhD,EAAazzE,GACnC,IAAatlB,SAATwnD,GACEA,EAAKC,WACHD,EAAKkG,MAAQlG,EAAKiG,SACpBn1C,EAAMkvC,EAAKzkC,GAAGtX,EAAI+7C,EAAK1kC,KAAKrX,EAC5B8M,EAAMivC,EAAKzkC,GAAGrX,EAAI87C,EAAK1kC,KAAKpX,EAC5BvM,EAAST,KAAK2qB,KAAK/Q,EAAKA,EAAKC,EAAKA,GAErB6/E,EAATj5F,GAAoB,CACtB25F,GAAe,CACf,QASZ,IAAMp+D,GAASo+D,GAAiBp+D,EAE9B,IAAKpV,EAAI,EAAO0zE,EAAJ1zE,EAA0BA,IAGpC,GAFAkiC,EAAO/tD,KAAKo+C,MAAMkhD,EAAazzE,IAElBtlB,SAATwnD,EAAoB,CACtB,GAAIiwC,GAAYh+F,KAAKs9C,MAAOyQ,EAAKiG,QAAUmrC,EAAQ9+F,GAAM0tD,EAAKkG,KAAOlG,EAAKiG,OAErEgqC,GAAUxuC,aAAa9pD,QAAW1F,KAAKwtE,aAAe4xB,GACtDpB,EAAU39F,IAAM8+F,EAAQ9+F,IAC3BL,KAAK4+F,cAAcO,EAAQnB,EAAU/8D,MAkBjDrhC,EAAQg/F,cAAgB,SAAS90F,EAAYk0F,EAAW/8D,GAEtDn3B,EAAW6yD,eAAeqhC,EAAU39F,IAAM29F,CAG1C,KAAK,GAAIz4F,GAAI,EAAGA,EAAIy4F,EAAUxuC,aAAa9pD,OAAQH,IAAK,CACtD,GAAIwoD,GAAOiwC,EAAUxuC,aAAajqD,EAC9BwoD,GAAKkG,MAAQnqD,EAAWzJ,IAAM0tD,EAAKiG,QAAUlqD,EAAWzJ,GAC1DL,KAAKw/F,qBAAqB11F,EAAWk0F,EAAUjwC,GAG/C/tD,KAAKy/F,sBAAsB31F,EAAWk0F,EAAUjwC,GAIpDiwC,EAAUxuC,gBAGVxvD,KAAK0/F,8BAA8B51F,EAAWk0F,SAIvCh+F,MAAKs9C,MAAM0gD,EAAU39F,GAG5B,IAAIs/F,GAAa71F,EAAW4E,QAAQ6uC,IACpCygD,GAAU7hC,eAAiBn8D,KAAKm8D,eAChCryD,EAAW4E,QAAQ6uC,MAAQygD,EAAUtvF,QAAQ6uC,KAC7CzzC,EAAW4yD,aAAeshC,EAAUthC,YACpC5yD,EAAW4E,QAAQmvC,SAAW54C,KAAK8G,IAAI/L,KAAKgiD,UAAUvC,WAAWS,YAAalgD,KAAKgiD,UAAU1E,MAAMO,SAAW79C,KAAKgiD,UAAUvC,WAAWQ,mBAAmBn2C,EAAW4yD,aAGlK5yD,EAAW+yD,gBAAgB/yD,EAAW+yD,gBAAgBn3D,OAAS,IAAM1F,KAAKm8D,gBAC5EryD,EAAW+yD,gBAAgB30D,KAAKlI,KAAKm8D,gBAMrCryD,EAAW2yD,eAFA,GAATx7B,EAE0B,EAGAjhC,KAAKkd,MAInCpT,EAAW00D,iBAGX10D,EAAW6yD,eAAeqhC,EAAU39F,IAAIo8D,eAAiB3yD,EAAW2yD,eAGpEuhC,EAAUz9B,gBAGVz2D,EAAW02D,eAAem/B,GAG1B3/F,KAAKolD,QAAS,GAUhBxlD,EAAQi9F,oBAAsB,WAC5B,IAAK,GAAIt3F,GAAI,EAAGA,EAAIvF,KAAKokD,YAAY1+C,OAAQH,IAAK,CAChD,GAAI4gD,GAAOnmD,KAAKs9C,MAAMt9C,KAAKokD,YAAY7+C,GACvC4gD,GAAK+V,mBAAqB/V,EAAKqJ,aAAa9pD,MAG5C,IAAIk6F,GAAa,CACjB,IAAIz5C,EAAK+V,mBAAqB,EAC5B,IAAK,GAAIrwC,GAAI,EAAGA,EAAIs6B,EAAK+V,mBAAqB,EAAGrwC,IAG/C,IAAK,GAFDg0E,GAAW15C,EAAKqJ,aAAa3jC,GAAGooC,KAChC6rC,EAAa35C,EAAKqJ,aAAa3jC,GAAGmoC,OAC7B+rC,EAAIl0E,EAAE,EAAGk0E,EAAI55C,EAAK+V,mBAAoB6jC,KACxC55C,EAAKqJ,aAAauwC,GAAG9rC,MAAQ4rC,GAAY15C,EAAKqJ,aAAauwC,GAAG/rC,QAAU8rC,GACxE35C,EAAKqJ,aAAauwC,GAAG/rC,QAAU6rC,GAAY15C,EAAKqJ,aAAauwC,GAAG9rC,MAAQ6rC,KAC3EF,GAAc,EAKtBz5C,GAAK+V,oBAAsB0jC,IAa/BhgG,EAAQ4/F,qBAAuB,SAAS11F,EAAYk0F,EAAWjwC,GAEvDjkD,EAAW8yD,eAAe/2D,eAAem4F,EAAU39F,MACvDyJ,EAAW8yD,eAAeohC,EAAU39F,QAGtCyJ,EAAW8yD,eAAeohC,EAAU39F,IAAI6H,KAAK6lD,SAGtC/tD,MAAKo+C,MAAM2P,EAAK1tD,GAGvB,KAAK,GAAIkF,GAAI,EAAGA,EAAIuE,EAAW0lD,aAAa9pD,OAAQH,IAClD,GAAIuE,EAAW0lD,aAAajqD,GAAGlF,IAAM0tD,EAAK1tD,GAAI,CAC5CyJ,EAAW0lD,aAAalnD,OAAO/C,EAAE,EACjC,SAcN3F,EAAQ6/F,sBAAwB,SAAS31F,EAAYk0F,EAAWjwC,GAE1DA,EAAKkG,MAAQlG,EAAKiG,OACpBh0D,KAAKw/F,qBAAqB11F,EAAYk0F,EAAWjwC,IAG7CA,EAAKkG,MAAQ+pC,EAAU39F,IACzB0tD,EAAK0G,aAAavsD,KAAK81F,EAAU39F,IACjC0tD,EAAKzkC,GAAKxf,EACVikD,EAAKkG,KAAOnqD,EAAWzJ,KAIvB0tD,EAAKyG,eAAetsD,KAAK81F,EAAU39F,IACnC0tD,EAAK1kC,KAAOvf,EACZikD,EAAKiG,OAASlqD,EAAWzJ,IAG3BL,KAAKggG,oBAAoBl2F,EAAWk0F,EAAUjwC,KAalDnuD,EAAQ8/F,8BAAgC,SAAS51F,EAAYk0F,GAE3D,IAAK,GAAIz4F,GAAI,EAAGA,EAAIuE,EAAW0lD,aAAa9pD,OAAQH,IAAK,CACvD,GAAIwoD,GAAOjkD,EAAW0lD,aAAajqD,EAE/BwoD,GAAKkG,MAAQlG,EAAKiG,QACpBh0D,KAAKw/F,qBAAqB11F,EAAYk0F,EAAWjwC,KAcvDnuD,EAAQogG,oBAAsB,SAASl2F,EAAYk0F,EAAWjwC,GAGtDjkD,EAAWsxD,cAAcv1D,eAAem4F,EAAU39F,MACtDyJ,EAAWsxD,cAAc4iC,EAAU39F,QAErCyJ,EAAWsxD,cAAc4iC,EAAU39F,IAAI6H,KAAK6lD,GAG5CjkD,EAAW0lD,aAAatnD,KAAK6lD,IAY/BnuD,EAAQw+F,wBAA0B,SAASt0F,EAAYk0F,GACrD,GAAIl0F,EAAWsxD,cAAcv1D,eAAem4F,EAAU39F,IAAK,CACzD,IAAK,GAAIkF,GAAI,EAAGA,EAAIuE,EAAWsxD,cAAc4iC,EAAU39F,IAAIqF,OAAQH,IAAK,CACtE,GAAIwoD,GAAOjkD,EAAWsxD,cAAc4iC,EAAU39F,IAAIkF,EAC9CwoD,GAAKyG,eAAezG,EAAKyG,eAAe9uD,OAAO,IAAMs4F,EAAU39F,IACjE0tD,EAAKyG,eAAe7Z,MACpBoT,EAAKiG,OAASgqC,EAAU39F,GACxB0tD,EAAK1kC,KAAO20E,IAGZjwC,EAAK0G,aAAa9Z,MAClBoT,EAAKkG,KAAO+pC,EAAU39F,GACtB0tD,EAAKzkC,GAAK00E,GAIZA,EAAUxuC,aAAatnD,KAAK6lD,EAG5B,KAAK,GAAIliC,GAAI,EAAGA,EAAI/hB,EAAW0lD,aAAa9pD,OAAQmmB,IAClD,GAAI/hB,EAAW0lD,aAAa3jC,GAAGxrB,IAAM0tD,EAAK1tD,GAAI,CAC5CyJ,EAAW0lD,aAAalnD,OAAOujB,EAAE,EACjC,cAKC/hB,GAAWsxD,cAAc4iC,EAAU39F,MAa9CT,EAAQy+F,eAAiB,SAASv0F,GAChC,IAAK,GAAIvE,GAAI,EAAGA,EAAIuE,EAAW0lD,aAAa9pD,OAAQH,IAAK,CACvD,GAAIwoD,GAAOjkD,EAAW0lD,aAAajqD,EAC/BuE,GAAWzJ,IAAM0tD,EAAKkG,MAAQnqD,EAAWzJ,IAAM0tD,EAAKiG,QACtDlqD,EAAW0lD,aAAalnD,OAAO/C,EAAE,KAcvC3F,EAAQu+F,uBAAyB,SAASr0F,EAAYk0F,GACpD,IAAK,GAAIz4F,GAAI,EAAGA,EAAIuE,EAAW8yD,eAAeohC,EAAU39F,IAAIqF,OAAQH,IAAK,CACvE,GAAIwoD,GAAOjkD,EAAW8yD,eAAeohC,EAAU39F,IAAIkF,EAGnDvF,MAAKo+C,MAAM2P,EAAK1tD,IAAM0tD,EAGtBiwC,EAAUxuC,aAAatnD,KAAK6lD,GAC5BjkD,EAAW0lD,aAAatnD,KAAK6lD,SAGxBjkD,GAAW8yD,eAAeohC,EAAU39F,KAa7CT,EAAQivD,aAAe,WACrB,GAAIrI,EAEJ,KAAKA,IAAUxmD,MAAKs9C,MAClB,GAAIt9C,KAAKs9C,MAAMz3C,eAAe2gD,GAAS,CACrC,GAAIL,GAAOnmD,KAAKs9C,MAAMkJ,EAClBL,GAAKuW,YAAc,IACrBvW,EAAKz9B,MAAQ,IAAIzU,OAAO9P,OAAOgiD,EAAKuW,aAAa,MAMvD,IAAKlW,IAAUxmD,MAAKs9C,MACdt9C,KAAKs9C,MAAMz3C,eAAe2gD,KAC5BL,EAAOnmD,KAAKs9C,MAAMkJ,GACM,GAApBL,EAAKuW,cAELvW,EAAKz9B,MADoBniB,SAAvB4/C,EAAK2W,cACM3W,EAAK2W,cAGL34D,OAAOgiD,EAAK9lD,OAuBnCT,EAAQu8F,uBAAyB,WAC/B,GAGI31C,GAHAy5C,EAAW,EACXC,EAAW,IACXC,EAAe,CAInB,KAAK35C,IAAUxmD,MAAKs9C,MACdt9C,KAAKs9C,MAAMz3C,eAAe2gD,KAC5B25C,EAAengG,KAAKs9C,MAAMkJ,GAAQqW,gBAAgBn3D,OACnCy6F,EAAXF,IAA0BA,EAAWE,GACrCD,EAAWC,IAAeD,EAAWC,GAI7C,IAAIF,EAAWC,EAAWlgG,KAAKgiD,UAAUvC,WAAWgB,uBAAwB,CAC1E,GAAIy8C,GAAgBl9F,KAAKokD,YAAY1+C,OACjC06F,EAAcH,EAAWjgG,KAAKgiD,UAAUvC,WAAWgB,sBAEvD,KAAK+F,IAAUxmD,MAAKs9C,MACdt9C,KAAKs9C,MAAMz3C,eAAe2gD,IACxBxmD,KAAKs9C,MAAMkJ,GAAQqW,gBAAgBn3D,OAAS06F,GAC9CpgG,KAAK6+F,4BAA4B7+F,KAAKs9C,MAAMkJ,GAIlDxmD,MAAKqnD,uBACLrnD,KAAK68F,sBAED78F,KAAKokD,YAAY1+C,QAAUw3F,IAC7Bl9F,KAAKm8D,gBAAkB,KAe7Bv8D,EAAQ48F,kBAAoB,SAASr2C,GACnC,MACElhD,MAAK6lB,IAAIq7B,EAAKn0C,EAAIhS,KAAKwkD,WAAWxyC,IAAMhS,KAAKgiD,UAAUvC,WAAWe,kBAAkBxgD,KAAKkd,OAEzFjY,KAAK6lB,IAAIq7B,EAAKl0C,EAAIjS,KAAKwkD,WAAWvyC,IAAMjS,KAAKgiD,UAAUvC,WAAWe,kBAAkBxgD,KAAKkd,OAU7Ftd,EAAQy8F,gBAAkB,WACxB,IAAK,GAAI92F,GAAI,EAAGA,EAAIvF,KAAKokD,YAAY1+C,OAAQH,IAAK,CAChD,GAAI4gD,GAAOnmD,KAAKs9C,MAAMt9C,KAAKokD,YAAY7+C,GACvC,IAAoB,GAAf4gD,EAAKsF,QAAkC,GAAftF,EAAKuF,OAAkB,CAClD,GAAIhgC,GAAS,EAAS1rB,KAAKokD,YAAY1+C,OAAST,KAAK8G,IAAI,IAAIo6C,EAAKz3C,QAAQ6uC,MACtEkR,EAAQ,EAAIxpD,KAAK2mB,GAAK3mB,KAAKE,QACZ,IAAfghD,EAAKsF,SAAkBtF,EAAKn0C,EAAI0Z,EAASzmB,KAAKuZ,IAAIiwC,IACnC,GAAftI,EAAKuF,SAAkBvF,EAAKl0C,EAAIyZ,EAASzmB,KAAKoZ,IAAIowC,IACtDzuD,KAAKw+F,uBAAuBr4C,MAYlCvmD,EAAQg+F,YAAc,WAMpB,IAAK,GALDyC,GAAU,EACVC,EAAiB,EACjBC,EAAa,EACbC,EAAa,EAERj7F,EAAI,EAAGA,EAAIvF,KAAKokD,YAAY1+C,OAAQH,IAAK,CAEhD,GAAI4gD,GAAOnmD,KAAKs9C,MAAMt9C,KAAKokD,YAAY7+C,GACnC4gD,GAAK+V,mBAAqBskC,IAC5BA,EAAar6C,EAAK+V,oBAEpBmkC,GAAWl6C,EAAK+V,mBAChBokC,GAAkBr7F,KAAK8uB,IAAIoyB,EAAK+V,mBAAmB,GACnDqkC,GAAc,EAEhBF,GAAoBE,EACpBD,GAAkCC,CAElC,IAAIE,GAAWH,EAAiBr7F,KAAK8uB,IAAIssE,EAAQ,GAE7CK,EAAoBz7F,KAAK2qB,KAAK6wE,EAElCzgG,MAAKwtE,aAAevoE,KAAKC,MAAMm7F,EAAU,EAAEK,GAGvC1gG,KAAKwtE,aAAegzB,IACtBxgG,KAAKwtE,aAAegzB,IAexB5gG,EAAQ+9F,sBAAwB,SAASgD,GACvC3gG,KAAKwtE,aAAe,CACpB,IAAIozB,GAAe37F,KAAKC,MAAMlF,KAAKokD,YAAY1+C,OAASi7F,EACxD,KAAK,GAAIn6C,KAAUxmD,MAAKs9C,MAClBt9C,KAAKs9C,MAAMz3C,eAAe2gD,IACiB,GAAzCxmD,KAAKs9C,MAAMkJ,GAAQ0V,oBAA2Bl8D,KAAKs9C,MAAMkJ,GAAQgJ,aAAa9pD,QAAU,GACtFk7F,EAAe,IACjB5gG,KAAKk/F,oBAAoBl/F,KAAKs9C,MAAMkJ,IAAQ,GAAK,EAAK,GACtDo6C,GAAgB,IAa1BhhG,EAAQ89F,kBAAoB,WAC1B,GAAImD,GAAS,EACTC,EAAQ,CACZ,KAAK,GAAIt6C,KAAUxmD,MAAKs9C,MAClBt9C,KAAKs9C,MAAMz3C,eAAe2gD,KACiB,GAAzCxmD,KAAKs9C,MAAMkJ,GAAQ0V,oBAA2Bl8D,KAAKs9C,MAAMkJ,GAAQgJ,aAAa9pD,QAAU,IAC1Fm7F,GAAU,GAEZC,GAAS,EAGb,OAAOD,GAAOC,IAMZ,SAASjhG,EAAQD,EAASM,GAE9B,GAAIS,GAAOT,EAAoB,GAC3BqD,EAAOrD,EAAoB,GAgB/BN,GAAQooD,iBAAmB,WACzBhoD,KAAKuvD,QAAgB,OAAEvvD,KAAKy8F,WAAWn/C,MAAQt9C,KAAKs9C,MACpDt9C,KAAKuvD,QAAgB,OAAEvvD,KAAKy8F,WAAWr+C,MAAQp+C,KAAKo+C,MACpDp+C,KAAKuvD,QAAgB,OAAEvvD,KAAKy8F,WAAWr4C,YAAcpkD,KAAKokD,aAa5DxkD,EAAQmhG,gBAAkB,SAASC,EAAUC,GACxB16F,SAAf06F,GAA0C,UAAdA,EAC9BjhG,KAAKkhG,sBAAsBF,GAG3BhhG,KAAKmhG,sBAAsBH,IAY/BphG,EAAQshG,sBAAwB,SAASF,GACvChhG,KAAKokD,YAAcpkD,KAAKuvD,QAAgB,OAAEyxC,GAAuB,YACjEhhG,KAAKs9C,MAAct9C,KAAKuvD,QAAgB,OAAEyxC,GAAiB,MAC3DhhG,KAAKo+C,MAAcp+C,KAAKuvD,QAAgB,OAAEyxC,GAAiB,OAU7DphG,EAAQwhG,uBAAyB,WAC/BphG,KAAKokD,YAAcpkD,KAAKuvD,QAAiB,QAAe,YACxDvvD,KAAKs9C,MAAct9C,KAAKuvD,QAAiB,QAAS,MAClDvvD,KAAKo+C,MAAcp+C,KAAKuvD,QAAiB,QAAS,OAWpD3vD,EAAQuhG,sBAAwB,SAASH,GACvChhG,KAAKokD,YAAcpkD,KAAKuvD,QAAgB,OAAEyxC,GAAuB,YACjEhhG,KAAKs9C,MAAct9C,KAAKuvD,QAAgB,OAAEyxC,GAAiB,MAC3DhhG,KAAKo+C,MAAcp+C,KAAKuvD,QAAgB,OAAEyxC,GAAiB,OAU7DphG,EAAQyhG,kBAAoB,WAC1BrhG,KAAK+gG,gBAAgB/gG,KAAKy8F,YAU5B78F,EAAQ68F,QAAU,WAChB,MAAOz8F,MAAKytE,aAAaztE,KAAKytE,aAAa/nE,OAAO,IAUpD9F,EAAQ0hG,gBAAkB,WACxB,GAAIthG,KAAKytE,aAAa/nE,OAAS,EAC7B,MAAO1F,MAAKytE,aAAaztE,KAAKytE,aAAa/nE,OAAO,EAGlD,MAAM,IAAIU,WAAU,iEAaxBxG,EAAQ2hG,iBAAmB,SAASC,GAClCxhG,KAAKytE,aAAavlE,KAAKs5F,IAUzB5hG,EAAQ6hG,kBAAoB,WAC1BzhG,KAAKytE,aAAa9yB,OAWpB/6C,EAAQ8hG,iBAAmB,SAASF,GAElCxhG,KAAKuvD,QAAgB,OAAEiyC,IAAUlkD,SACAc,SACAgG,eACAqY,eAAkBz8D,KAAKkd,MACvBwwD,YAAennE,QAGhDvG,KAAKuvD,QAAgB,OAAEiyC,GAAoB,YAAI,GAAIj+F,IAC9ClD,GAAGmhG,EACFp2F,OACEgB,WAAY,UACZC,OAAQ,iBAEJrM,KAAKgiD,WACjBhiD,KAAKuvD,QAAgB,OAAEiyC,GAAoB,YAAE9kC,YAAc,GAW7D98D,EAAQ+hG,oBAAsB,SAASX,SAC9BhhG,MAAKuvD,QAAgB,OAAEyxC,IAWhCphG,EAAQgiG,oBAAsB,SAASZ,SAC9BhhG,MAAKuvD,QAAgB,OAAEyxC,IAWhCphG,EAAQiiG,cAAgB,SAASb,GAE/BhhG,KAAKuvD,QAAgB,OAAEyxC,GAAYhhG,KAAKuvD,QAAgB,OAAEyxC,GAG1DhhG,KAAK2hG,oBAAoBX,IAW3BphG,EAAQkiG,gBAAkB,SAASd,GAEjChhG,KAAKuvD,QAAgB,OAAEyxC,GAAYhhG,KAAKuvD,QAAgB,OAAEyxC,GAG1DhhG,KAAK4hG,oBAAoBZ,IAa3BphG,EAAQmiG,qBAAuB,SAASf,GAEtC,IAAK,GAAIx6C,KAAUxmD,MAAKs9C,MAClBt9C,KAAKs9C,MAAMz3C,eAAe2gD,KAC5BxmD,KAAKuvD,QAAgB,OAAEyxC,GAAiB,MAAEx6C,GAAUxmD,KAAKs9C,MAAMkJ,GAKnE,KAAK,GAAI6G,KAAUrtD,MAAKo+C,MAClBp+C,KAAKo+C,MAAMv4C,eAAewnD,KAC5BrtD,KAAKuvD,QAAgB,OAAEyxC,GAAiB,MAAE3zC,GAAUrtD,KAAKo+C,MAAMiP,GAKnE,KAAK,GAAI9nD,GAAI,EAAGA,EAAIvF,KAAKokD,YAAY1+C,OAAQH,IAC3CvF,KAAKuvD,QAAgB,OAAEyxC,GAAuB,YAAE94F,KAAKlI,KAAKokD,YAAY7+C,KAW1E3F,EAAQoiG,6BAA+B,WACrChiG,KAAK87F,aAAa,GAAE,IAUtBl8F,EAAQ88F,WAAa,SAASv2C,GAE5B,GAAI87C,GAASjiG,KAAKy8F,gBAWXz8F,MAAKs9C,MAAM6I,EAAK9lD,GAEvB,IAAI6hG,GAAmBvhG,EAAKoE,YAG5B/E,MAAK6hG,cAAcI,GAGnBjiG,KAAK0hG,iBAAiBQ,GAGtBliG,KAAKuhG,iBAAiBW,GAGtBliG,KAAK+gG,gBAAgB/gG,KAAKy8F,WAG1Bz8F,KAAKs9C,MAAM6I,EAAK9lD,IAAM8lD,GAUxBvmD,EAAQu9F,gBAAkB,WAExB,GAAI8E,GAASjiG,KAAKy8F,SAGlB,IAAc,WAAVwF,IAC8B,GAA3BjiG,KAAKokD,YAAY1+C,QACpB1F,KAAKuvD,QAAgB,OAAE0yC,GAAqB,YAAEzvF,MAAMxS,KAAKkd,MAAQld,KAAKgiD,UAAUvC,WAAWO,oBAAsBhgD,KAAKuf,MAAMC,OAAOC,aACnIzf,KAAKuvD,QAAgB,OAAE0yC,GAAqB,YAAExvF,OAAOzS,KAAKkd,MAAQld,KAAKgiD,UAAUvC,WAAWO,oBAAsBhgD,KAAKuf,MAAMC,OAAOsF,cAAe,CACnJ,GAAIq9E,GAAiBniG,KAAKshG,iBAG1BthG,MAAKgiG,+BAILhiG,KAAK+hG,qBAAqBI,GAI1BniG,KAAK2hG,oBAAoBM,GAGzBjiG,KAAK8hG,gBAAgBK,GAGrBniG,KAAK+gG,gBAAgBoB,GAGrBniG,KAAKyhG,oBAGLzhG,KAAKqnD,uBAGLrnD,KAAK0uD,4BAeX9uD,EAAQ2xD,sBAAwB,SAAS6wC,EAAYC,GACnD,GAAIC,KACJ,IAAiB/7F,SAAb87F,EACF,IAAK,GAAIJ,KAAUjiG,MAAKuvD,QAAgB,OAClCvvD,KAAKuvD,QAAgB,OAAE1pD,eAAeo8F,KAExCjiG,KAAKkhG,sBAAsBe,GAC3BK,EAAap6F,KAAMlI,KAAKoiG,WAK5B,KAAK,GAAIH,KAAUjiG,MAAKuvD,QAAgB,OACtC,GAAIvvD,KAAKuvD,QAAgB,OAAE1pD,eAAeo8F,GAAS,CAEjDjiG,KAAKkhG,sBAAsBe,EAC3B,IAAI/oF,GAAOlT,MAAMoN,UAAU9K,OAAO/H,KAAKkF,UAAW,EAEhD68F,GAAap6F,KADXgR,EAAKxT,OAAS,EACG1F,KAAKoiG,GAAalpF,EAAK,GAAGA,EAAK,IAG/BlZ,KAAKoiG,GAAaC,IAO7C,MADAriG,MAAKqhG,oBACEiB,GAaT1iG,EAAQ4xD,mBAAqB,SAAS4wC,EAAYC,GAChD,GAAIC,IAAe,CACnB,IAAiB/7F,SAAb87F,EACFriG,KAAKohG,yBACLkB,EAAetiG,KAAKoiG,SAEjB,CACHpiG,KAAKohG,wBACL,IAAIloF,GAAOlT,MAAMoN,UAAU9K,OAAO/H,KAAKkF,UAAW,EAEhD68F,GADEppF,EAAKxT,OAAS,EACD1F,KAAKoiG,GAAalpF,EAAK,GAAGA,EAAK,IAG/BlZ,KAAKoiG,GAAaC,GAKrC,MADAriG,MAAKqhG,oBACEiB,GAaT1iG,EAAQ2iG,sBAAwB,SAASH,EAAYC,GACnD,GAAiB97F,SAAb87F,EACF,IAAK,GAAIJ,KAAUjiG,MAAKuvD,QAAgB,OAClCvvD,KAAKuvD,QAAgB,OAAE1pD,eAAeo8F,KAExCjiG,KAAKmhG,sBAAsBc,GAC3BjiG,KAAKoiG,UAKT,KAAK,GAAIH,KAAUjiG,MAAKuvD,QAAgB,OACtC,GAAIvvD,KAAKuvD,QAAgB,OAAE1pD,eAAeo8F,GAAS,CAEjDjiG,KAAKmhG,sBAAsBc,EAC3B,IAAI/oF,GAAOlT,MAAMoN,UAAU9K,OAAO/H,KAAKkF,UAAW,EAC9CyT,GAAKxT,OAAS,EAChB1F,KAAKoiG,GAAalpF,EAAK,GAAGA,EAAK,IAG/BlZ,KAAKoiG,GAAaC,GAK1BriG,KAAKqhG,qBAaPzhG,EAAQiwD,gBAAkB,SAASuyC,EAAYC,GAC7C,GAAInpF,GAAOlT,MAAMoN,UAAU9K,OAAO/H,KAAKkF,UAAW,EACjCc,UAAb87F,GACFriG,KAAKuxD,sBAAsB6wC,GAC3BpiG,KAAKuiG,sBAAsBH,IAGvBlpF,EAAKxT,OAAS,GAChB1F,KAAKuxD,sBAAsB6wC,EAAYlpF,EAAK,GAAGA,EAAK,IACpDlZ,KAAKuiG,sBAAsBH,EAAYlpF,EAAK,GAAGA,EAAK,MAGpDlZ,KAAKuxD,sBAAsB6wC,EAAYC,GACvCriG,KAAKuiG,sBAAsBH,EAAYC,KAY7CziG,EAAQ0nD,oBAAsB,WAC5B,GAAI26C,GAASjiG,KAAKy8F,SAClBz8F,MAAKuvD,QAAgB,OAAE0yC,GAAqB,eAC5CjiG,KAAKokD,YAAcpkD,KAAKuvD,QAAgB,OAAE0yC,GAAqB,aAWjEriG,EAAQ4iG,iBAAmB,SAASx7E,EAAIi6E,GACtC,GAAsD96C,GAAlDC,EAAO,IAAKC,EAAO,KAAMC,EAAO,IAAKC,EAAO,IAChD,KAAK,GAAI07C,KAAUjiG,MAAKuvD,QAAQ0xC,GAC9B,GAAIjhG,KAAKuvD,QAAQ0xC,GAAYp7F,eAAeo8F,IACc17F,SAApDvG,KAAKuvD,QAAQ0xC,GAAYgB,GAAqB,YAAiB,CAEjEjiG,KAAK+gG,gBAAgBkB,EAAOhB,GAE5B76C,EAAO,IAAKC,EAAO,KAAMC,EAAO,IAAKC,EAAO,IAC5C,KAAK,GAAIC,KAAUxmD,MAAKs9C,MAClBt9C,KAAKs9C,MAAMz3C,eAAe2gD,KAC5BL,EAAOnmD,KAAKs9C,MAAMkJ,GAClBL,EAAKkQ,OAAOrvC,GACRs/B,EAAOH,EAAKn0C,EAAI,GAAMm0C,EAAK3zC,QAAQ8zC,EAAOH,EAAKn0C,EAAI,GAAMm0C,EAAK3zC,OAC9D+zC,EAAOJ,EAAKn0C,EAAI,GAAMm0C,EAAK3zC,QAAQ+zC,EAAOJ,EAAKn0C,EAAI,GAAMm0C,EAAK3zC,OAC9D4zC,EAAOD,EAAKl0C,EAAI,GAAMk0C,EAAK1zC,SAAS2zC,EAAOD,EAAKl0C,EAAI,GAAMk0C,EAAK1zC,QAC/D4zC,EAAOF,EAAKl0C,EAAI,GAAMk0C,EAAK1zC,SAAS4zC,EAAOF,EAAKl0C,EAAI,GAAMk0C,EAAK1zC,QAGvE0zC,GAAOnmD,KAAKuvD,QAAQ0xC,GAAYgB,GAAqB,YACrD97C,EAAKn0C,EAAI,IAAOu0C,EAAOD,GACvBH,EAAKl0C,EAAI,IAAOo0C,EAAOD,GACvBD,EAAK3zC,MAAQ,GAAK2zC,EAAKn0C,EAAIs0C,GAC3BH,EAAK1zC,OAAS,GAAK0zC,EAAKl0C,EAAIm0C,GAC5BD,EAAKz3C,QAAQgd,OAASzmB,KAAK2qB,KAAK3qB,KAAK8uB,IAAI,GAAIoyB,EAAK3zC,MAAM,GAAKvN,KAAK8uB,IAAI,GAAIoyB,EAAK1zC,OAAO,IACtF0zC,EAAK9iB,SAASrjC,KAAKkd,OACnBipC,EAAKoX,YAAYv2C,KAMzBpnB,EAAQ6iG,oBAAsB,SAASz7E,GACrChnB,KAAKwiG,iBAAiBx7E,EAAI,UAC1BhnB,KAAKwiG,iBAAiBx7E,EAAI,UAC1BhnB,KAAKqhG,sBAMH,SAASxhG,EAAQD,EAASM,GAE9B,GAAIqD,GAAOrD,EAAoB,GAS/BN,GAAQ8iG,yBAA2B,SAAS1+F,EAAQ2pD,GAClD,GAAIrQ,GAAQt9C,KAAKs9C,KACjB,KAAK,GAAIkJ,KAAUlJ,GACbA,EAAMz3C,eAAe2gD,IACnBlJ,EAAMkJ,GAAQoH,kBAAkB5pD,IAClC2pD,EAAiBzlD,KAAKs+C,IAY9B5mD,EAAQ+iG,4BAA8B,SAAU3+F,GAC9C,GAAI2pD,KAEJ,OADA3tD,MAAKuxD,sBAAsB,2BAA2BvtD,EAAO2pD,GACtDA,GAWT/tD,EAAQgjG,yBAA2B,SAASziE,GAC1C,GAAInuB,GAAIhS,KAAK6rD,qBAAqB1rB,EAAQnuB,GACtCC,EAAIjS,KAAK+rD,qBAAqB5rB,EAAQluB,EAE1C,QACEzK,KAAQwK,EACRpK,IAAQqK,EACRqV,MAAQtV,EACRuR,OAAQtR,IAYZrS,EAAQsrD,WAAa,SAAU/qB,GAE7B,GAAI0iE,GAAiB7iG,KAAK4iG,yBAAyBziE,GAC/CwtB,EAAmB3tD,KAAK2iG,4BAA4BE,EAIxD,OAAIl1C,GAAiBjoD,OAAS,EACpB1F,KAAKs9C,MAAMqQ,EAAiBA,EAAiBjoD,OAAS,IAGvD,MAWX9F,EAAQkjG,yBAA2B,SAAU9+F,EAAQ8pD,GACnD,GAAI1P,GAAQp+C,KAAKo+C,KACjB,KAAK,GAAIiP,KAAUjP,GACbA,EAAMv4C,eAAewnD,IACnBjP,EAAMiP,GAAQO,kBAAkB5pD,IAClC8pD,EAAiB5lD,KAAKmlD,IAa9BztD,EAAQmjG,4BAA8B,SAAU/+F,GAC9C,GAAI8pD,KAEJ,OADA9tD,MAAKuxD,sBAAsB,2BAA2BvtD,EAAO8pD,GACtDA,GAWTluD,EAAQ0tD,WAAa,SAASntB,GAC5B,GAAI0iE,GAAiB7iG,KAAK4iG,yBAAyBziE,GAC/C2tB,EAAmB9tD,KAAK+iG,4BAA4BF,EAExD,OAAI/0C,GAAiBpoD,OAAS,EACrB1F,KAAKo+C,MAAM0P,EAAiBA,EAAiBpoD,OAAS,IAGtD,MAWX9F,EAAQojG,gBAAkB,SAAShgF,GAC7BA,YAAezf,GACjBvD,KAAKwrD,aAAalO,MAAMt6B,EAAI3iB,IAAM2iB,EAGlChjB,KAAKwrD,aAAapN,MAAMp7B,EAAI3iB,IAAM2iB,GAUtCpjB,EAAQqjG,YAAc,SAASjgF,GACzBA,YAAezf,GACjBvD,KAAKkiD,SAAS5E,MAAMt6B,EAAI3iB,IAAM2iB,EAG9BhjB,KAAKkiD,SAAS9D,MAAMp7B,EAAI3iB,IAAM2iB,GAWlCpjB,EAAQsjG,qBAAuB,SAASlgF,GAClCA,YAAezf,SACVvD,MAAKwrD,aAAalO,MAAMt6B,EAAI3iB,UAG5BL,MAAKwrD,aAAapN,MAAMp7B,EAAI3iB,KAUvCT,EAAQs+F,aAAe,SAASiF,GACT58F,SAAjB48F,IACFA,GAAe,EAEjB,KAAI,GAAI38C,KAAUxmD,MAAKwrD,aAAalO,MAC/Bt9C,KAAKwrD,aAAalO,MAAMz3C,eAAe2gD,IACxCxmD,KAAKwrD,aAAalO,MAAMkJ,GAAQhV,UAGpC,KAAI,GAAI6b,KAAUrtD,MAAKwrD,aAAapN,MAC/Bp+C,KAAKwrD,aAAapN,MAAMv4C,eAAewnD,IACxCrtD,KAAKwrD,aAAapN,MAAMiP,GAAQ7b,UAIpCxxC,MAAKwrD,cAAgBlO,SAASc,UAEV,GAAhB+kD,GACFnjG,KAAK6tB,KAAK,SAAU7tB,KAAK62B,iBAU7Bj3B,EAAQwjG,kBAAoB,SAASD,GACd58F,SAAjB48F,IACFA,GAAe,EAGjB,KAAK,GAAI38C,KAAUxmD,MAAKwrD,aAAalO,MAC/Bt9C,KAAKwrD,aAAalO,MAAMz3C,eAAe2gD,IACrCxmD,KAAKwrD,aAAalO,MAAMkJ,GAAQkW,YAAc,IAChD18D,KAAKwrD,aAAalO,MAAMkJ,GAAQhV,WAChCxxC,KAAKkjG,qBAAqBljG,KAAKwrD,aAAalO,MAAMkJ,IAKpC,IAAhB28C,GACFnjG,KAAK6tB,KAAK,SAAU7tB,KAAK62B,iBAW7Bj3B,EAAQyjG,sBAAwB,WAC9B,GAAIpsF,GAAQ,CACZ,KAAK,GAAIuvC,KAAUxmD,MAAKwrD,aAAalO,MAC/Bt9C,KAAKwrD,aAAalO,MAAMz3C,eAAe2gD,KACzCvvC,GAAS,EAGb,OAAOA,IASTrX,EAAQ0jG,iBAAmB,WACzB,IAAK,GAAI98C,KAAUxmD,MAAKwrD,aAAalO,MACnC,GAAIt9C,KAAKwrD,aAAalO,MAAMz3C,eAAe2gD,GACzC,MAAOxmD,MAAKwrD,aAAalO,MAAMkJ,EAGnC,OAAO,OAST5mD,EAAQ2jG,iBAAmB,WACzB,IAAK,GAAIl2C,KAAUrtD,MAAKwrD,aAAapN,MACnC,GAAIp+C,KAAKwrD,aAAapN,MAAMv4C,eAAewnD,GACzC,MAAOrtD,MAAKwrD,aAAapN,MAAMiP,EAGnC,OAAO,OAUTztD,EAAQ4jG,sBAAwB,WAC9B,GAAIvsF,GAAQ,CACZ,KAAK,GAAIo2C,KAAUrtD,MAAKwrD,aAAapN,MAC/Bp+C,KAAKwrD,aAAapN,MAAMv4C,eAAewnD,KACzCp2C,GAAS,EAGb,OAAOA,IAUTrX,EAAQ6jG,wBAA0B,WAChC,GAAIxsF,GAAQ,CACZ,KAAI,GAAIuvC,KAAUxmD,MAAKwrD,aAAalO,MAC/Bt9C,KAAKwrD,aAAalO,MAAMz3C,eAAe2gD,KACxCvvC,GAAS,EAGb,KAAI,GAAIo2C,KAAUrtD,MAAKwrD,aAAapN,MAC/Bp+C,KAAKwrD,aAAapN,MAAMv4C,eAAewnD,KACxCp2C,GAAS,EAGb,OAAOA,IASTrX,EAAQ8jG,kBAAoB,WAC1B,IAAI,GAAIl9C,KAAUxmD,MAAKwrD,aAAalO,MAClC,GAAGt9C,KAAKwrD,aAAalO,MAAMz3C,eAAe2gD,GACxC,OAAO,CAGX,KAAI,GAAI6G,KAAUrtD,MAAKwrD,aAAapN,MAClC,GAAGp+C,KAAKwrD,aAAapN,MAAMv4C,eAAewnD,GACxC,OAAO,CAGX,QAAO,GAUTztD,EAAQ+jG,oBAAsB,WAC5B,IAAI,GAAIn9C,KAAUxmD,MAAKwrD,aAAalO,MAClC,GAAGt9C,KAAKwrD,aAAalO,MAAMz3C,eAAe2gD,IACpCxmD,KAAKwrD,aAAalO,MAAMkJ,GAAQkW,YAAc,EAChD,OAAO,CAIb,QAAO,GAST98D,EAAQgkG,sBAAwB,SAASz9C,GACvC,IAAK,GAAI5gD,GAAI,EAAGA,EAAI4gD,EAAKqJ,aAAa9pD,OAAQH,IAAK,CACjD,GAAIwoD,GAAO5H,EAAKqJ,aAAajqD,EAC7BwoD,GAAKtc,SACLzxC,KAAKgjG,gBAAgBj1C,KAUzBnuD,EAAQikG,qBAAuB,SAAS19C,GACtC,IAAK,GAAI5gD,GAAI,EAAGA,EAAI4gD,EAAKqJ,aAAa9pD,OAAQH,IAAK,CACjD,GAAIwoD,GAAO5H,EAAKqJ,aAAajqD,EAC7BwoD,GAAKxhD,OAAQ,EACbvM,KAAKijG,YAAYl1C,KAWrBnuD,EAAQkkG,wBAA0B,SAAS39C,GACzC,IAAK,GAAI5gD,GAAI,EAAGA,EAAI4gD,EAAKqJ,aAAa9pD,OAAQH,IAAK,CACjD,GAAIwoD,GAAO5H,EAAKqJ,aAAajqD,EAC7BwoD,GAAKvc,WACLxxC,KAAKkjG,qBAAqBn1C,KAgB9BnuD,EAAQyrD,cAAgB,SAASrnD,EAAQ+/F,EAAQZ,EAAca,EAAgBC,GACxD19F,SAAjB48F,IACFA,GAAe,GAEM58F,SAAnBy9F,IACFA,GAAiB,GAGa,GAA5BhkG,KAAK0jG,qBAA0C,GAAVK,GAAgD,GAA7B/jG,KAAK4tE,sBAC/D5tE,KAAKk+F,cAAa,GAIG,GAAnBl6F,EAAOwvC,UAAmD,GAA7BxzC,KAAKgiD,UAAUxS,aAAsBy0D,EAQ1C,GAAnBjgG,EAAOwvC,UACdxzC,KAAKgjG,gBAAgBh/F,GACrBm/F,GAAe,IAGfn/F,EAAOwtC,WACPxxC,KAAKkjG,qBAAqBl/F,KAb1BA,EAAOytC,SACPzxC,KAAKgjG,gBAAgBh/F,GACjBA,YAAkBT,IAA6C,GAArCvD,KAAK2tE,8BAA2D,GAAlBq2B,GAC1EhkG,KAAK4jG,sBAAsB5/F,IAaX,GAAhBm/F,GACFnjG,KAAK6tB,KAAK,SAAU7tB,KAAK62B,iBAY7Bj3B,EAAQ4tD,YAAc,SAASxpD,GACT,GAAhBA,EAAOuI,QACTvI,EAAOuI,OAAQ,EACfvM,KAAK6tB,KAAK,YAAYs4B,KAAKniD,EAAO3D,OAWtCT,EAAQ2tD,aAAe,SAASvpD,GACV,GAAhBA,EAAOuI,QACTvI,EAAOuI,OAAQ,EACfvM,KAAKijG,YAAYj/F,GACbA,YAAkBT,IACpBvD,KAAK6tB,KAAK,aAAas4B,KAAKniD,EAAO3D,MAGnC2D,YAAkBT,IACpBvD,KAAK6jG,qBAAqB7/F,IAa9BpE,EAAQorD,aAAe,aAUvBprD,EAAQssD,WAAa,SAAS/rB,GAC5B,GAAIgmB,GAAOnmD,KAAKkrD,WAAW/qB,EAC3B,IAAY,MAARgmB,EACFnmD,KAAKqrD,cAAclF,GAAM,OAEtB,CACH,GAAI4H,GAAO/tD,KAAKstD,WAAWntB,EACf,OAAR4tB,EACF/tD,KAAKqrD,cAAc0C,GAAM,GAGzB/tD,KAAKk+F,eAGT,GAAIlvC,GAAahvD,KAAK62B,cACtBm4B,GAAoB,SAClBk1C,KAAMlyF,EAAGmuB,EAAQnuB,EAAGC,EAAGkuB,EAAQluB,GAC/BuN,QAASxN,EAAGhS,KAAK6rD,qBAAqB1rB,EAAQnuB,GAAIC,EAAGjS,KAAK+rD,qBAAqB5rB,EAAQluB,KAEzFjS,KAAK6tB,KAAK,QAASmhC,GACnBhvD,KAAKmjD,WAUPvjD,EAAQusD,iBAAmB,SAAShsB,GAClC,GAAIgmB,GAAOnmD,KAAKkrD,WAAW/qB,EACf,OAARgmB,GAAyB5/C,SAAT4/C,IAElBnmD,KAAKwkD,YAAexyC,EAAMhS,KAAK6rD,qBAAqB1rB,EAAQnuB,GACxCC,EAAMjS,KAAK+rD,qBAAqB5rB,EAAQluB,IAC5DjS,KAAKs8F,YAAYn2C,GAEnB,IAAI6I,GAAahvD,KAAK62B,cACtBm4B,GAAoB,SAClBk1C,KAAMlyF,EAAGmuB,EAAQnuB,EAAGC,EAAGkuB,EAAQluB,GAC/BuN,QAASxN,EAAGhS,KAAK6rD,qBAAqB1rB,EAAQnuB,GAAIC,EAAGjS,KAAK+rD,qBAAqB5rB,EAAQluB,KAEzFjS,KAAK6tB,KAAK,cAAemhC,IAU3BpvD,EAAQwsD,cAAgB,SAASjsB,GAC/B,GAAIgmB,GAAOnmD,KAAKkrD,WAAW/qB,EAC3B,IAAY,MAARgmB,EACFnmD,KAAKqrD,cAAclF,GAAK,OAErB,CACH,GAAI4H,GAAO/tD,KAAKstD,WAAWntB,EACf,OAAR4tB,GACF/tD,KAAKqrD,cAAc0C,GAAK,GAG5B/tD,KAAKmjD,WAUPvjD,EAAQysD,iBAAmB,SAASlsB,GAClCngC,KAAKmkG,6BAA6BhkE,GAClCngC,KAAKokG,2BAA2BjkE,IAGlCvgC,EAAQukG,6BAA+B,aACvCvkG,EAAQwkG,2BAA6B,aAOrCxkG,EAAQi3B,aAAe,WACrB,GAAIy0B,GAAUtrD,KAAKqkG,mBACfC,EAAUtkG,KAAKukG,kBACnB,QAAQjnD,MAAMgO,EAASlN,MAAMkmD,IAS/B1kG,EAAQykG,iBAAmB,WACzB,GAAIG,KACJ,IAAiC,GAA7BxkG,KAAKgiD,UAAUxS,WACjB,IAAK,GAAIgX,KAAUxmD,MAAKwrD,aAAalO,MAC/Bt9C,KAAKwrD,aAAalO,MAAMz3C,eAAe2gD,IACzCg+C,EAAQt8F,KAAKs+C,EAInB,OAAOg+C,IAST5kG,EAAQ2kG,iBAAmB,WACzB,GAAIC,KACJ,IAAiC,GAA7BxkG,KAAKgiD,UAAUxS,WACjB,IAAK,GAAI6d,KAAUrtD,MAAKwrD,aAAapN,MAC/Bp+C,KAAKwrD,aAAapN,MAAMv4C,eAAewnD,IACzCm3C,EAAQt8F,KAAKmlD,EAInB,OAAOm3C,IAST5kG,EAAQ+2B,aAAe,WACrBiC,QAAQhF,IAAI,gEAUdh0B,EAAQ6kG,YAAc,SAAS/zD,EAAWszD,GACxC,GAAIz+F,GAAG27B,EAAM7gC,CAEb,KAAKqwC,GAAkCnqC,QAApBmqC,EAAUhrC,OAC3B,KAAM,qCAKR,KAFA1F,KAAKk+F,cAAa,GAEb34F,EAAI,EAAG27B,EAAOwP,EAAUhrC,OAAYw7B,EAAJ37B,EAAUA,IAAK,CAClDlF,EAAKqwC,EAAUnrC,EAEf,IAAI4gD,GAAOnmD,KAAKs9C,MAAMj9C,EACtB,KAAK8lD,EACH,KAAM,IAAIu+C,YAAW,iBAAmBrkG,EAAK,cAE/CL,MAAKqrD,cAAclF,GAAK,GAAK,EAAK69C,GAAe,GAEnDhkG,KAAK0hB,UASP9hB,EAAQ+kG,YAAc,SAASj0D,GAC7B,GAAInrC,GAAG27B,EAAM7gC,CAEb,KAAKqwC,GAAkCnqC,QAApBmqC,EAAUhrC,OAC3B,KAAM,qCAKR,KAFA1F,KAAKk+F,cAAa,GAEb34F,EAAI,EAAG27B,EAAOwP,EAAUhrC,OAAYw7B,EAAJ37B,EAAUA,IAAK,CAClDlF,EAAKqwC,EAAUnrC,EAEf,IAAIwoD,GAAO/tD,KAAKo+C,MAAM/9C,EACtB,KAAK0tD,EACH,KAAM,IAAI22C,YAAW,iBAAmBrkG,EAAK,cAE/CL,MAAKqrD,cAAc0C,GAAK,GAAK,GAAK,GAAM,GAE1C/tD,KAAK0hB,UAOP9hB,EAAQ4uD,iBAAmB,WACzB,IAAI,GAAIhI,KAAUxmD,MAAKwrD,aAAalO,MAC/Bt9C,KAAKwrD,aAAalO,MAAMz3C,eAAe2gD,KACnCxmD,KAAKs9C,MAAMz3C,eAAe2gD,UACtBxmD,MAAKwrD,aAAalO,MAAMkJ,GAIrC,KAAI,GAAI6G,KAAUrtD,MAAKwrD,aAAapN,MAC/Bp+C,KAAKwrD,aAAapN,MAAMv4C,eAAewnD,KACnCrtD,KAAKo+C,MAAMv4C,eAAewnD,UACtBrtD,MAAKwrD,aAAapN,MAAMiP,MASnC,SAASxtD,EAAQD,EAASM,GAE9B,GAAIS,GAAOT,EAAoB,GAC3BqD,EAAOrD,EAAoB,IAC3BkD,EAAOlD,EAAoB,GAO/BN,GAAQglG,qBAAuB,WAC7B5kG,KAAK2qD,oBAAoB3qD,KAAK6tE,iBAC9B7tE,KAAK6kG,mBAEL7kG,KAAKmkG,6BAA+B,mBAC7BnkG,MAAKuvD,QAAiB,QAAS,MAAc,iBAC7CvvD,MAAKuvD,QAAiB,QAAS,MAAiB,cACvDvvD,KAAKmiD,oBAAqB,EAC1BniD,KAAK6jD,kBAAmB,GAU1BjkD,EAAQklG,4BAA8B,WACpC,IAAK,GAAIC,KAAgB/kG,MAAK8jD,gBACxB9jD,KAAK8jD,gBAAgBj+C,eAAek/F,KACtC/kG,KAAK+kG,GAAgB/kG,KAAK8jD,gBAAgBihD,SACnC/kG,MAAK8jD,gBAAgBihD,KAUlCnlG,EAAQolG,gBAAkB,WACxBhlG,KAAKuoD,UAAYvoD,KAAKuoD,QACtB,IAAI08C,GAAUjlG,KAAK6tE,gBACfE,EAAW/tE,KAAK+tE,SAChBD,EAAc9tE,KAAK8tE,WACF,IAAjB9tE,KAAKuoD,UACP08C,EAAQ/3F,MAAMi7B,QAAQ,QACtB4lC,EAAS7gE,MAAMi7B,QAAQ,QACvB2lC,EAAY5gE,MAAMi7B,QAAQ,OAC1B4lC,EAAS97C,QAAUjyB,KAAKglG,gBAAgBjwE,KAAK/0B,QAG7CilG,EAAQ/3F,MAAMi7B,QAAQ,OACtB4lC,EAAS7gE,MAAMi7B,QAAQ,OACvB2lC,EAAY5gE,MAAMi7B,QAAQ,QAC1B4lC,EAAS97C,QAAU,MAErBjyB,KAAKwnD,yBAQP5nD,EAAQ4nD,sBAAwB,WAE1BxnD,KAAKklG,eACPllG,KAAK2T,IAAI,SAAU3T,KAAKklG,cAG1B,IAAIxgE,GAAS1kC,KAAKgiD,UAAU9c,QAAQllC,KAAKgiD,UAAUtd,OAqBnD,IAnB6Bn+B,SAAzBvG,KAAKmlG,kBACPnlG,KAAKmlG,gBAAgBrrC,uBACrB95D,KAAKmlG,gBAAkB5+F,OACvBvG,KAAKolG,oBAAsB,KAC3BplG,KAAKmiD,oBAAqB,EAC1BniD,KAAKmjD,WAIPnjD,KAAK8kG,8BAGL9kG,KAAK6jD,kBAAmB,EAGxB7jD,KAAK2tE,8BAA+B,EACpC3tE,KAAK4tE,sBAAuB,EAC5B5tE,KAAK6kG,mBAEgB,GAAjB7kG,KAAKuoD,SAAkB,CACzB,KAAOvoD,KAAK6tE,gBAAgBlqD,iBAC1B3jB,KAAK6tE,gBAAgBz8D,YAAYpR,KAAK6tE,gBAAgBjqD,WAGxD5jB,MAAK6kG,gBAA6B,YAAIrzF,SAASM,cAAc,QAC7D9R,KAAK6kG,gBAA6B,YAAE98F,UAAY,6BAChD/H,KAAK6kG,gBAAkC,iBAAIrzF,SAASM,cAAc,QAClE9R,KAAK6kG,gBAAkC,iBAAE98F,UAAY,4BACrD/H,KAAK6kG,gBAAkC,iBAAE3gF,UAAYwgB,EAAgB,QACrE1kC,KAAK6kG,gBAA6B,YAAEnzF,YAAY1R,KAAK6kG,gBAAkC,kBAEvF7kG,KAAK6kG,gBAAmC,kBAAIrzF,SAASM,cAAc,OACnE9R,KAAK6kG,gBAAmC,kBAAE98F,UAAY,wBAEtD/H,KAAK6kG,gBAA6B,YAAIrzF,SAASM,cAAc,QAC7D9R,KAAK6kG,gBAA6B,YAAE98F,UAAY,iCAChD/H,KAAK6kG,gBAAkC,iBAAIrzF,SAASM,cAAc,QAClE9R,KAAK6kG,gBAAkC,iBAAE98F,UAAY,4BACrD/H,KAAK6kG,gBAAkC,iBAAE3gF,UAAYwgB,EAAgB,QACrE1kC,KAAK6kG,gBAA6B,YAAEnzF,YAAY1R,KAAK6kG,gBAAkC,kBAEvF7kG,KAAK6tE,gBAAgBn8D,YAAY1R,KAAK6kG,gBAA6B,aACnE7kG,KAAK6tE,gBAAgBn8D,YAAY1R,KAAK6kG,gBAAmC,mBACzE7kG,KAAK6tE,gBAAgBn8D,YAAY1R,KAAK6kG,gBAA6B,aAE/B,GAAhC7kG,KAAKqjG,yBAAgCrjG,KAAKi9C,iBAAiBC,MAC7Dl9C,KAAK6kG,gBAAmC,kBAAIrzF,SAASM,cAAc,OACnE9R,KAAK6kG,gBAAmC,kBAAE98F,UAAY,wBAEtD/H,KAAK6kG,gBAA8B,aAAIrzF,SAASM,cAAc,QAC9D9R,KAAK6kG,gBAA8B,aAAE98F,UAAY,8BACjD/H,KAAK6kG,gBAAmC,kBAAIrzF,SAASM,cAAc,QACnE9R,KAAK6kG,gBAAmC,kBAAE98F,UAAY,4BACtD/H,KAAK6kG,gBAAmC,kBAAE3gF,UAAYwgB,EAAiB,SACvE1kC,KAAK6kG,gBAA8B,aAAEnzF,YAAY1R,KAAK6kG,gBAAmC,mBAEzF7kG,KAAK6tE,gBAAgBn8D,YAAY1R,KAAK6kG,gBAAmC,mBACzE7kG,KAAK6tE,gBAAgBn8D,YAAY1R,KAAK6kG,gBAA8B,eAE7B,GAAhC7kG,KAAKwjG,yBAAgE,GAAhCxjG,KAAKqjG,0BACjDrjG,KAAK6kG,gBAAmC,kBAAIrzF,SAASM,cAAc,OACnE9R,KAAK6kG,gBAAmC,kBAAE98F,UAAY,wBAEtD/H,KAAK6kG,gBAA8B,aAAIrzF,SAASM,cAAc,QAC9D9R,KAAK6kG,gBAA8B,aAAE98F,UAAY,8BACjD/H,KAAK6kG,gBAAmC,kBAAIrzF,SAASM,cAAc,QACnE9R,KAAK6kG,gBAAmC,kBAAE98F,UAAY,4BACtD/H,KAAK6kG,gBAAmC,kBAAE3gF,UAAYwgB,EAAiB,SACvE1kC,KAAK6kG,gBAA8B,aAAEnzF,YAAY1R,KAAK6kG,gBAAmC,mBAEzF7kG,KAAK6tE,gBAAgBn8D,YAAY1R,KAAK6kG,gBAAmC,mBACzE7kG,KAAK6tE,gBAAgBn8D,YAAY1R,KAAK6kG,gBAA8B,eAEtC,GAA5B7kG,KAAK0jG,sBACP1jG,KAAK6kG,gBAAmC,kBAAIrzF,SAASM,cAAc,OACnE9R,KAAK6kG,gBAAmC,kBAAE98F,UAAY,wBAEtD/H,KAAK6kG,gBAA4B,WAAIrzF,SAASM,cAAc,QAC5D9R,KAAK6kG,gBAA4B,WAAE98F,UAAY,gCAC/C/H,KAAK6kG,gBAAiC,gBAAIrzF,SAASM,cAAc,QACjE9R,KAAK6kG,gBAAiC,gBAAE98F,UAAY,4BACpD/H,KAAK6kG,gBAAiC,gBAAE3gF,UAAYwgB,EAAY,IAChE1kC,KAAK6kG,gBAA4B,WAAEnzF,YAAY1R,KAAK6kG,gBAAiC,iBAErF7kG,KAAK6tE,gBAAgBn8D,YAAY1R,KAAK6kG,gBAAmC,mBACzE7kG,KAAK6tE,gBAAgBn8D,YAAY1R,KAAK6kG,gBAA4B,aAKpE7kG,KAAK6kG,gBAA6B,YAAE5yE,QAAUjyB,KAAKqlG,sBAAsBtwE,KAAK/0B,MAC9EA,KAAK6kG,gBAA6B,YAAE5yE,QAAUjyB,KAAKslG,sBAAsBvwE,KAAK/0B,MAC1C,GAAhCA,KAAKqjG,yBAAgCrjG,KAAKi9C,iBAAiBC,KAC7Dl9C,KAAK6kG,gBAA8B,aAAE5yE,QAAUjyB,KAAKulG,UAAUxwE,KAAK/0B,MAE5B,GAAhCA,KAAKwjG,yBAAgE,GAAhCxjG,KAAKqjG,0BACjDrjG,KAAK6kG,gBAA8B,aAAE5yE,QAAUjyB,KAAKwlG,uBAAuBzwE,KAAK/0B,OAElD,GAA5BA,KAAK0jG,sBACP1jG,KAAK6kG,gBAA4B,WAAE5yE,QAAUjyB,KAAKwqD,gBAAgBz1B,KAAK/0B,OAEzEA,KAAK+tE,SAAS97C,QAAUjyB,KAAKglG,gBAAgBjwE,KAAK/0B,KAElD;GAAIoU,GAAKpU,IACTA,MAAKklG,cAAgB9wF,EAAGozC,sBACxBxnD,KAAKwT,GAAG,SAAUxT,KAAKklG,mBAEpB,CACH,KAAOllG,KAAK8tE,YAAYnqD,iBACtB3jB,KAAK8tE,YAAY18D,YAAYpR,KAAK8tE,YAAYlqD,WAGhD5jB,MAAK6kG,gBAA8B,aAAIrzF,SAASM,cAAc,QAC9D9R,KAAK6kG,gBAA8B,aAAE98F,UAAY,uCACjD/H,KAAK6kG,gBAAmC,kBAAIrzF,SAASM,cAAc,QACnE9R,KAAK6kG,gBAAmC,kBAAE98F,UAAY,4BACtD/H,KAAK6kG,gBAAmC,kBAAE3gF,UAAYwgB,EAAa,KACnE1kC,KAAK6kG,gBAA8B,aAAEnzF,YAAY1R,KAAK6kG,gBAAmC,mBAEzF7kG,KAAK8tE,YAAYp8D,YAAY1R,KAAK6kG,gBAA8B,cAEhE7kG,KAAK6kG,gBAA8B,aAAE5yE,QAAUjyB,KAAKglG,gBAAgBjwE,KAAK/0B,QAW7EJ,EAAQylG,sBAAwB,WAE9BrlG,KAAK4kG,uBACD5kG,KAAKklG,eACPllG,KAAK2T,IAAI,SAAU3T,KAAKklG,cAG1B,IAAIxgE,GAAS1kC,KAAKgiD,UAAU9c,QAAQllC,KAAKgiD,UAAUtd,OAEnD1kC,MAAK6kG,mBACL7kG,KAAK6kG,gBAA0B,SAAIrzF,SAASM,cAAc,QAC1D9R,KAAK6kG,gBAA0B,SAAE98F,UAAY,8BAC7C/H,KAAK6kG,gBAA+B,cAAIrzF,SAASM,cAAc,QAC/D9R,KAAK6kG,gBAA+B,cAAE98F,UAAY,4BAClD/H,KAAK6kG,gBAA+B,cAAE3gF,UAAYwgB,EAAa,KAC/D1kC,KAAK6kG,gBAA0B,SAAEnzF,YAAY1R,KAAK6kG,gBAA+B,eAEjF7kG,KAAK6kG,gBAAmC,kBAAIrzF,SAASM,cAAc,OACnE9R,KAAK6kG,gBAAmC,kBAAE98F,UAAY,wBAEtD/H,KAAK6kG,gBAAiC,gBAAIrzF,SAASM,cAAc,QACjE9R,KAAK6kG,gBAAiC,gBAAE98F,UAAY,8BACpD/H,KAAK6kG,gBAAsC,qBAAIrzF,SAASM,cAAc,QACtE9R,KAAK6kG,gBAAsC,qBAAE98F,UAAY,4BACzD/H,KAAK6kG,gBAAsC,qBAAE3gF,UAAYwgB,EAAuB,eAChF1kC,KAAK6kG,gBAAiC,gBAAEnzF,YAAY1R,KAAK6kG,gBAAsC,sBAE/F7kG,KAAK6tE,gBAAgBn8D,YAAY1R,KAAK6kG,gBAA0B,UAChE7kG,KAAK6tE,gBAAgBn8D,YAAY1R,KAAK6kG,gBAAmC,mBACzE7kG,KAAK6tE,gBAAgBn8D,YAAY1R,KAAK6kG,gBAAiC,iBAGvE7kG,KAAK6kG,gBAA0B,SAAE5yE,QAAUjyB,KAAKwnD,sBAAsBzyB,KAAK/0B,KAG3E,IAAIoU,GAAKpU,IACTA,MAAKklG,cAAgB9wF,EAAGqxF,SACxBzlG,KAAKwT,GAAG,SAAUxT,KAAKklG,gBASzBtlG,EAAQ0lG,sBAAwB,WAE9BtlG,KAAK4kG,uBACL5kG,KAAKk+F,cAAa,GAClBl+F,KAAK6jD,kBAAmB,EAEpB7jD,KAAKklG,eACPllG,KAAK2T,IAAI,SAAU3T,KAAKklG,cAG1B,IAAIxgE,GAAS1kC,KAAKgiD,UAAU9c,QAAQllC,KAAKgiD,UAAUtd,OAEnD1kC,MAAKk+F,eACLl+F,KAAK4tE,sBAAuB,EAC5B5tE,KAAK2tE,8BAA+B,EAEpC3tE,KAAK6kG,mBACL7kG,KAAK6kG,gBAA0B,SAAIrzF,SAASM,cAAc,QAC1D9R,KAAK6kG,gBAA0B,SAAE98F,UAAY,8BAC7C/H,KAAK6kG,gBAA+B,cAAIrzF,SAASM,cAAc,QAC/D9R,KAAK6kG,gBAA+B,cAAE98F,UAAY,4BAClD/H,KAAK6kG,gBAA+B,cAAE3gF,UAAYwgB,EAAa,KAC/D1kC,KAAK6kG,gBAA0B,SAAEnzF,YAAY1R,KAAK6kG,gBAA+B,eAEjF7kG,KAAK6kG,gBAAmC,kBAAIrzF,SAASM,cAAc,OACnE9R,KAAK6kG,gBAAmC,kBAAE98F,UAAY,wBAEtD/H,KAAK6kG,gBAAiC,gBAAIrzF,SAASM,cAAc,QACjE9R,KAAK6kG,gBAAiC,gBAAE98F,UAAY,8BACpD/H,KAAK6kG,gBAAsC,qBAAIrzF,SAASM,cAAc,QACtE9R,KAAK6kG,gBAAsC,qBAAE98F,UAAY,4BACzD/H,KAAK6kG,gBAAsC,qBAAE3gF,UAAYwgB,EAAwB,gBACjF1kC,KAAK6kG,gBAAiC,gBAAEnzF,YAAY1R,KAAK6kG,gBAAsC,sBAE/F7kG,KAAK6tE,gBAAgBn8D,YAAY1R,KAAK6kG,gBAA0B,UAChE7kG,KAAK6tE,gBAAgBn8D,YAAY1R,KAAK6kG,gBAAmC,mBACzE7kG,KAAK6tE,gBAAgBn8D,YAAY1R,KAAK6kG,gBAAiC,iBAGvE7kG,KAAK6kG,gBAA0B,SAAE5yE,QAAUjyB,KAAKwnD,sBAAsBzyB,KAAK/0B,KAG3E,IAAIoU,GAAKpU,IACTA,MAAKklG,cAAgB9wF,EAAGsxF,eACxB1lG,KAAKwT,GAAG,SAAUxT,KAAKklG,eAGvBllG,KAAK8jD,gBAA8B,aAAI9jD,KAAKgrD,aAC5ChrD,KAAK8jD,gBAA8C,6BAAI9jD,KAAKmkG,6BAC5DnkG,KAAK8jD,gBAAkC,iBAAI9jD,KAAKirD,iBAChDjrD,KAAK8jD,gBAAgC,eAAI9jD,KAAKisD,eAC9CjsD,KAAKgrD,aAAehrD,KAAK0lG,eACzB1lG,KAAKmkG,6BAA+B,aACpCnkG,KAAKirD,iBAAmB,aACxBjrD,KAAKisD,eAAiBjsD,KAAK2lG,eAG3B3lG,KAAKmjD,WAQPvjD,EAAQ4lG,uBAAyB,WAE/BxlG,KAAK4kG,uBACL5kG,KAAKmiD,oBAAqB,EAEtBniD,KAAKklG,eACPllG,KAAK2T,IAAI,SAAU3T,KAAKklG,eAG1BllG,KAAKmlG,gBAAkBnlG,KAAKujG,mBAC5BvjG,KAAKmlG,gBAAgBtrC,qBAErB,IAAIn1B,GAAS1kC,KAAKgiD,UAAU9c,QAAQllC,KAAKgiD,UAAUtd,OAEnD1kC,MAAK6kG,mBACL7kG,KAAK6kG,gBAA0B,SAAIrzF,SAASM,cAAc,QAC1D9R,KAAK6kG,gBAA0B,SAAE98F,UAAY,8BAC7C/H,KAAK6kG,gBAA+B,cAAIrzF,SAASM,cAAc,QAC/D9R,KAAK6kG,gBAA+B,cAAE98F,UAAY,4BAClD/H,KAAK6kG,gBAA+B,cAAE3gF,UAAYwgB,EAAa,KAC/D1kC,KAAK6kG,gBAA0B,SAAEnzF,YAAY1R,KAAK6kG,gBAA+B,eAEjF7kG,KAAK6kG,gBAAmC,kBAAIrzF,SAASM,cAAc,OACnE9R,KAAK6kG,gBAAmC,kBAAE98F,UAAY,wBAEtD/H,KAAK6kG,gBAAiC,gBAAIrzF,SAASM,cAAc,QACjE9R,KAAK6kG,gBAAiC,gBAAE98F,UAAY,8BACpD/H,KAAK6kG,gBAAsC,qBAAIrzF,SAASM,cAAc,QACtE9R,KAAK6kG,gBAAsC,qBAAE98F,UAAY,4BACzD/H,KAAK6kG,gBAAsC,qBAAE3gF,UAAYwgB,EAA4B,oBACrF1kC,KAAK6kG,gBAAiC,gBAAEnzF,YAAY1R,KAAK6kG,gBAAsC,sBAE/F7kG,KAAK6tE,gBAAgBn8D,YAAY1R,KAAK6kG,gBAA0B,UAChE7kG,KAAK6tE,gBAAgBn8D,YAAY1R,KAAK6kG,gBAAmC,mBACzE7kG,KAAK6tE,gBAAgBn8D,YAAY1R,KAAK6kG,gBAAiC,iBAGvE7kG,KAAK6kG,gBAA0B,SAAE5yE,QAAUjyB,KAAKwnD,sBAAsBzyB,KAAK/0B,MAG3EA,KAAK8jD,gBAA8B,aAAS9jD,KAAKgrD,aACjDhrD,KAAK8jD,gBAA8C,6BAAK9jD,KAAKmkG,6BAC7DnkG,KAAK8jD,gBAA4B,WAAW9jD,KAAKksD,WACjDlsD,KAAK8jD,gBAAkC,iBAAK9jD,KAAKirD,iBACjDjrD,KAAK8jD,gBAA+B,cAAQ9jD,KAAK2rD,cACjD3rD,KAAKgrD,aAAmBhrD,KAAK4lG,mBAC7B5lG,KAAKksD,WAAmB,aACxBlsD,KAAK2rD,cAAmB3rD,KAAK6lG,iBAC7B7lG,KAAKirD,iBAAmB,aACxBjrD,KAAKmkG,6BAA+BnkG,KAAK8lG,oBAGzC9lG,KAAKmjD,WAUPvjD,EAAQgmG,mBAAqB,SAASzlE,GACpCngC,KAAKmlG,gBAAgBtwC,aAAaxrC,KAAKmoB,WACvCxxC,KAAKmlG,gBAAgBtwC,aAAavrC,GAAGkoB,WACrCxxC,KAAKolG,oBAAsBplG,KAAKmlG,gBAAgBprC,wBAAwB/5D,KAAK6rD,qBAAqB1rB,EAAQnuB,GAAGhS,KAAK+rD,qBAAqB5rB,EAAQluB,IAC9G,OAA7BjS,KAAKolG,sBACPplG,KAAKolG,oBAAoB3zD,SACzBzxC,KAAK6jD,kBAAmB,GAE1B7jD,KAAKmjD,WAUPvjD,EAAQimG,iBAAmB,SAASr8F,GAClC,GAAI22B,GAAUngC,KAAK6qD,YAAYrhD,EAAMo2B,QAAQzT,OACZ,QAA7BnsB,KAAKolG,qBAA6D7+F,SAA7BvG,KAAKolG,sBAC5CplG,KAAKolG,oBAAoBpzF,EAAIhS,KAAK6rD,qBAAqB1rB,EAAQnuB,GAC/DhS,KAAKolG,oBAAoBnzF,EAAIjS,KAAK+rD,qBAAqB5rB,EAAQluB,IAEjEjS,KAAKmjD,WASPvjD,EAAQkmG,oBAAsB,SAAS3lE,GACrC,GAAI4lE,GAAU/lG,KAAKkrD,WAAW/qB,EACd,QAAZ4lE,GACqD,GAAnD/lG,KAAKmlG,gBAAgBtwC,aAAaxrC,KAAKmqB,WACzCxzC,KAAKmlG,gBAAgBjrC,uBACrBl6D,KAAKgmG,UAAUD,EAAQ1lG,GAAIL,KAAKmlG,gBAAgB77E,GAAGjpB,IACnDL,KAAKmlG,gBAAgBtwC,aAAaxrC,KAAKmoB,YAEY,GAAjDxxC,KAAKmlG,gBAAgBtwC,aAAavrC,GAAGkqB,WACvCxzC,KAAKmlG,gBAAgBjrC,uBACrBl6D,KAAKgmG,UAAUhmG,KAAKmlG,gBAAgB97E,KAAKhpB,GAAI0lG,EAAQ1lG,IACrDL,KAAKmlG,gBAAgBtwC,aAAavrC,GAAGkoB,aAIvCxxC,KAAKmlG,gBAAgBjrC,uBAEvBl6D,KAAK6jD,kBAAmB,EACxB7jD,KAAKmjD,WASPvjD,EAAQ8lG,eAAiB,SAASvlE,GAChC,GAAoC,GAAhCngC,KAAKqjG,wBAA8B,CACrC,GAAIl9C,GAAOnmD,KAAKkrD,WAAW/qB,EAE3B,IAAY,MAARgmB,EACF,GAAIA,EAAKuW,YAAc,EACrBupC,MAAMjmG,KAAKgiD,UAAU9c,QAAQllC,KAAKgiD,UAAUtd,QAAyB,qBAElE,CACH1kC,KAAKqrD,cAAclF,GAAK,EACxB,IAAI+/C,GAAelmG,KAAKuvD,QAAiB,QAAS,KAGlD22C,GAAyB,WAAI,GAAI3iG,IAAMlD,GAAG,oBAAoBL,KAAKgiD,UACnE,IAAImkD,GAAaD,EAAyB,UAC1CC,GAAWn0F,EAAIm0C,EAAKn0C,EACpBm0F,EAAWl0F,EAAIk0C,EAAKl0C,EAGpBjS,KAAKo+C,MAAsB,eAAI,GAAIh7C,IAAM/C,GAAG,iBAAiBgpB,KAAK88B,EAAK9lD,GAAGipB,GAAG68E,EAAW9lG,IAAKL,KAAMA,KAAKgiD,UACxG,IAAIokD,GAAiBpmG,KAAKo+C,MAAsB,cAChDgoD,GAAe/8E,KAAO88B,EACtBigD,EAAep4C,WAAY,EAC3Bo4C,EAAe13F,QAAQ0yC,cAAgBzyC,SAAS,EAC5C0yC,SAAS,EACTx6C,KAAM,aACNy6C,UAAW,IAEf8kD,EAAe5yD,UAAW,EAC1B4yD,EAAe98E,GAAK68E,EAEpBnmG,KAAK8jD,gBAA+B,cAAI9jD,KAAK2rD,cAC7C3rD,KAAK2rD,cAAgB,SAASniD,GAC5B,GAAI22B,GAAUngC,KAAK6qD,YAAYrhD,EAAMo2B,QAAQzT,QACzCi6E,EAAiBpmG,KAAKo+C,MAAsB,cAChDgoD,GAAe98E,GAAGtX,EAAIhS,KAAK6rD,qBAAqB1rB,EAAQnuB,GACxDo0F,EAAe98E,GAAGrX,EAAIjS,KAAK+rD,qBAAqB5rB,EAAQluB,IAG1DjS,KAAKolD,QAAS,EACdplD,KAAK6P,WAMbjQ,EAAQ+lG,eAAiB,SAASn8F,GAChC,GAAoC,GAAhCxJ,KAAKqjG,wBAA8B,CACrC,GAAIljE,GAAUngC,KAAK6qD,YAAYrhD,EAAMo2B,QAAQzT,OAE7CnsB,MAAK2rD,cAAgB3rD,KAAK8jD,gBAA+B,oBAClD9jD,MAAK8jD,gBAA+B,aAG3C,IAAIuiD,GAAgBrmG,KAAKo+C,MAAsB,eAAE4V,aAG1Ch0D,MAAKo+C,MAAsB,qBAC3Bp+C,MAAKuvD,QAAiB,QAAS,MAAc,iBAC7CvvD,MAAKuvD,QAAiB,QAAS,MAAiB,aAEvD,IAAIpJ,GAAOnmD,KAAKkrD,WAAW/qB,EACf,OAARgmB,IACEA,EAAKuW,YAAc,EACrBupC,MAAMjmG,KAAKgiD,UAAU9c,QAAQllC,KAAKgiD,UAAUtd,QAAyB,kBAGrE1kC,KAAKsmG,YAAYD,EAAclgD,EAAK9lD,IACpCL,KAAKwnD,0BAGTxnD,KAAKk+F,iBAQTt+F,EAAQ6lG,SAAW,WACjB,GAAIzlG,KAAK0jG,qBAAwC,GAAjB1jG,KAAKuoD,SAAkB,CACrD,GAAIs6C,GAAiB7iG,KAAK4iG,yBAAyB5iG,KAAKukD,iBACpDgiD,GAAelmG,GAAGM,EAAKoE,aAAaiN,EAAE6wF,EAAer7F,KAAKyK,EAAE4wF,EAAej7F,IAAI8gB,MAAM,MAAMmqC,gBAAe,EAAKC,gBAAe,EAClI,IAAI9yD,KAAKi9C,iBAAiB/pC,IAAK,CAC7B,GAAwC,GAApClT,KAAKi9C,iBAAiB/pC,IAAIxN,OAU5B,KAAM,IAAI9B,OAAM,sEAThB,IAAIwQ,GAAKpU,IACTA,MAAKi9C,iBAAiB/pC,IAAIqzF,EAAa,SAASC,GAC9CpyF,EAAGswC,UAAUxxC,IAAIszF,GACjBpyF,EAAGozC,wBACHpzC,EAAGgxC,QAAS,EACZhxC,EAAGvE,cAWP7P,MAAK0kD,UAAUxxC,IAAIqzF,GACnBvmG,KAAKwnD,wBACLxnD,KAAKolD,QAAS,EACdplD,KAAK6P,UAWXjQ,EAAQ0mG,YAAc,SAASG,EAAaC,GAC1C,GAAqB,GAAjB1mG,KAAKuoD,SAAkB,CACzB,GAAIg+C,IAAel9E,KAAKo9E,EAAcn9E,GAAGo9E,EACzC,IAAI1mG,KAAKi9C,iBAAiBG,QAAS,CACjC,GAA4C,GAAxCp9C,KAAKi9C,iBAAiBG,QAAQ13C,OAShC,KAAM,IAAI9B,OAAM,0EARhB,IAAIwQ,GAAKpU,IACTA,MAAKi9C,iBAAiBG,QAAQmpD,EAAa,SAASC,GAClDpyF,EAAGuwC,UAAUzxC,IAAIszF,GACjBpyF,EAAGgxC,QAAS,EACZhxC,EAAGvE,cAUP7P,MAAK2kD,UAAUzxC,IAAIqzF,GACnBvmG,KAAKolD,QAAS,EACdplD,KAAK6P,UAUXjQ,EAAQomG,UAAY,SAASS,EAAaC,GACxC,GAAqB,GAAjB1mG,KAAKuoD,SAAkB,CACzB,GAAIg+C,IAAelmG,GAAIL,KAAKmlG,gBAAgB9kG,GAAIgpB,KAAKo9E,EAAcn9E,GAAGo9E,EACtE,IAAI1mG,KAAKi9C,iBAAiBE,SAAU,CAClC,GAA6C,GAAzCn9C,KAAKi9C,iBAAiBE,SAASz3C,OASjC,KAAM,IAAI9B,OAAM,wEARhB,IAAIwQ,GAAKpU,IACTA,MAAKi9C,iBAAiBE,SAASopD,EAAa,SAASC,GACnDpyF,EAAGuwC,UAAU7vC,OAAO0xF,GACpBpyF,EAAGgxC,QAAS,EACZhxC,EAAGvE,cAUP7P,MAAK2kD,UAAU7vC,OAAOyxF,GACtBvmG,KAAKolD,QAAS,EACdplD,KAAK6P,UAUXjQ,EAAQ2lG,UAAY,WAClB,IAAIvlG,KAAKi9C,iBAAiBC,MAAyB,GAAjBl9C,KAAKuoD,SA4BrC,KAAM,IAAI3kD,OAAM,iDA3BhB,IAAIuiD,GAAOnmD,KAAKsjG,mBACZ3wF,GAAQtS,GAAG8lD,EAAK9lD,GAClBqoB,MAAOy9B,EAAKz9B,MACZxW,MAAOi0C,EAAKz3C,QAAQwD,MACpBwrC,MAAOyI,EAAKz3C,QAAQgvC,MACpBtyC,OACEgB,WAAW+5C,EAAKz3C,QAAQtD,MAAMgB,WAC9BC,OAAO85C,EAAKz3C,QAAQtD,MAAMiB,OAC1BC,WACEF,WAAW+5C,EAAKz3C,QAAQtD,MAAMkB,UAAUF,WACxCC,OAAO85C,EAAKz3C,QAAQtD,MAAMkB,UAAUD,SAG1C,IAAyC,GAArCrM,KAAKi9C,iBAAiBC,KAAKx3C,OAU7B,KAAM,IAAI9B,OAAM,wEAThB,IAAIwQ,GAAKpU,IACTA,MAAKi9C,iBAAiBC,KAAKvqC,EAAM,SAAU6zF,GACzCpyF,EAAGswC,UAAU5vC,OAAO0xF,GACpBpyF,EAAGozC,wBACHpzC,EAAGgxC,QAAS,EACZhxC,EAAGvE,WAoBXjQ,EAAQ4qD,gBAAkB,WACxB,IAAKxqD,KAAK0jG,qBAAwC,GAAjB1jG,KAAKuoD,SACpC,GAAKvoD,KAAK2jG,sBA4BRsC,MAAMjmG,KAAKgiD,UAAU9c,QAAQllC,KAAKgiD,UAAUtd,QAA4B,wBA5BzC,CAC/B,GAAIiiE,GAAgB3mG,KAAKqkG,mBACrBuC,EAAgB5mG,KAAKukG,kBACzB,IAAIvkG,KAAKi9C,iBAAiBI,IAAK,CAC7B,GAAIjpC,GAAKpU,KACL2S,GAAQ2qC,MAAOqpD,EAAevoD,MAAOwoD,EACzC,IAAwC,GAApC5mG,KAAKi9C,iBAAiBI,IAAI33C,OAU5B,KAAM,IAAI9B,OAAM,0EAThB5D,MAAKi9C,iBAAiBI,IAAI1qC,EAAM,SAAU6zF,GACxCpyF,EAAGuwC,UAAUruC,OAAOkwF,EAAcpoD,OAClChqC,EAAGswC,UAAUpuC,OAAOkwF,EAAclpD,OAClClpC,EAAG8pF,eACH9pF,EAAGgxC,QAAS,EACZhxC,EAAGvE,cAQP7P,MAAK2kD,UAAUruC,OAAOswF,GACtB5mG,KAAK0kD,UAAUpuC,OAAOqwF,GACtB3mG,KAAKk+F,eACLl+F,KAAKolD,QAAS,EACdplD,KAAK6P,WAYT,SAAShQ,EAAQD,EAASM,GAE9B,GACI2lC,IADO3lC,EAAoB,GAClBA,EAAoB,IAEjCN,GAAQouE,iBAAmB,WAEzB,GAA8C,GAA1ChuE,KAAKoiD,kBAAkBC,SAAS38C,OAAa,CAC/C,IAAK,GAAIH,GAAI,EAAGA,EAAIvF,KAAKoiD,kBAAkBC,SAAS38C,OAAQH,IAC1DvF,KAAKoiD,kBAAkBC,SAAS98C,GAAGmlD,SAErC1qD,MAAKoiD,kBAAkBC,YAGzBriD,KAAKokG,2BAA6B,aAG9BpkG,KAAK6mG,gBAAkB7mG,KAAK6mG,eAAwB,SAAK7mG,KAAK6mG,eAAwB,QAAE/8F,YAC1F9J,KAAK6mG,eAAwB,QAAE/8F,WAAWsH,YAAYpR,KAAK6mG,eAAwB,UAYvFjnG,EAAQquE,wBAA0B,WAChCjuE,KAAKguE,mBAELhuE,KAAK6mG,iBACL,IAAIA,IAAkB,KAAK,OAAO,OAAO,QAAQ,SAAS,UAAU,eAChEC,GAAwB,UAAU,YAAY,YAAY,aAAa,UAAU,WAAW,cAEhG9mG,MAAK6mG,eAAwB,QAAIr1F,SAASM,cAAc,OACxD9R,KAAKuf,MAAM7N,YAAY1R,KAAK6mG,eAAwB,QAEpD,KAAK,GAAIthG,GAAI,EAAGA,EAAIshG,EAAenhG,OAAQH,IAAK,CAC9CvF,KAAK6mG,eAAeA,EAAethG,IAAMiM,SAASM,cAAc,OAChE9R,KAAK6mG,eAAeA,EAAethG,IAAIwC,UAAY,sBAAwB8+F,EAAethG,GAC1FvF,KAAK6mG,eAAwB,QAAEn1F,YAAY1R,KAAK6mG,eAAeA,EAAethG,IAE9E,IAAIzB,GAAS+hC,EAAO7lC,KAAK6mG,eAAeA,EAAethG,KAAMwgC,iBAAiB,GAC9EjiC,GAAO0P,GAAG,QAASxT,KAAK8mG,EAAqBvhG,IAAIwvB,KAAK/0B,OACtDA,KAAKoiD,kBAAkBE,KAAKp6C,KAAKpE,GAGnC9D,KAAKokG,2BAA6BpkG,KAAK+mG,cAEvC/mG,KAAKoiD,kBAAkBC,SAAWriD,KAAKoiD,kBAAkBE,MAS3D1iD,EAAQonG,YAAc,SAASx9F,GAC7BxJ,KAAKulD,YAAYx1C,SAAS,MAC1BvG,EAAM08B,mBAQRtmC,EAAQmnG,cAAgB,WACtB/mG,KAAKmqD,eACLnqD,KAAKgqD,eACLhqD,KAAKsqD,aAYP1qD,EAAQmqD,QAAU,SAASvgD,GACzBxJ,KAAKqjD,WAAarjD,KAAKgiD,UAAUrB,SAASC,MAAM3uC,EAChDjS,KAAK6P,QACLrG,EAAMD,kBAQR3J,EAAQqqD,UAAY,SAASzgD,GAC3BxJ,KAAKqjD,YAAcrjD,KAAKgiD,UAAUrB,SAASC,MAAM3uC,EACjDjS,KAAK6P,QACLrG,EAAMD,kBAQR3J,EAAQsqD,UAAY,SAAS1gD,GAC3BxJ,KAAKojD,WAAapjD,KAAKgiD,UAAUrB,SAASC,MAAM5uC,EAChDhS,KAAK6P,QACLrG,EAAMD,kBAQR3J,EAAQwqD,WAAa,SAAS5gD,GAC5BxJ,KAAKojD,YAAcpjD,KAAKgiD,UAAUrB,SAASC,MAAM3uC,EACjDjS,KAAK6P,QACLrG,EAAMD,kBAQR3J,EAAQyqD,QAAU,SAAS7gD,GACzBxJ,KAAKsjD,cAAgBtjD,KAAKgiD,UAAUrB,SAASC,MAAMtgB,KACnDtgC,KAAK6P,QACLrG,EAAMD,kBAQR3J,EAAQ2qD,SAAW,SAAS/gD,GAC1BxJ,KAAKsjD,eAAiBtjD,KAAKgiD,UAAUrB,SAASC,MAAMtgB,KACpDtgC,KAAK6P,QACLrG,EAAMD,kBAQR3J,EAAQ0qD,UAAY,SAAS9gD,GAC3BxJ,KAAKsjD,cAAgB,EACrB95C,GAASA,EAAMD,kBAQjB3J,EAAQoqD,aAAe,SAASxgD,GAC9BxJ,KAAKqjD,WAAa,EAClB75C,GAASA,EAAMD,kBAQjB3J,EAAQuqD,aAAe,SAAS3gD,GAC9BxJ,KAAKojD,WAAa,EAClB55C,GAASA,EAAMD,mBAMb,SAAS1J,EAAQD,GAErBA,EAAQqoD,aAAe,WACrB,IAAK,GAAIzB,KAAUxmD,MAAKs9C,MACtB,GAAIt9C,KAAKs9C,MAAMz3C,eAAe2gD,GAAS,CACrC,GAAIL,GAAOnmD,KAAKs9C,MAAMkJ,EACO,IAAzBL,EAAKuV,mBACPvV,EAAKjI,MAAQ,GACbiI,EAAKwV,qBAAsB,KAYnC/7D,EAAQ0lD,yBAA2B,WACjC,GAAiD,GAA7CtlD,KAAKgiD,UAAUjB,mBAAmBpyC,SAAmB3O,KAAKokD,YAAY1+C,OAAS,EAAG,CAEpF,GACIygD,GAAMK,EADNygD,EAAU,EAEVC,GAAe,EACfC,GAAiB,CAErB,KAAK3gD,IAAUxmD,MAAKs9C,MACdt9C,KAAKs9C,MAAMz3C,eAAe2gD,KAC5BL,EAAOnmD,KAAKs9C,MAAMkJ,GACA,IAAdL,EAAKjI,MACPgpD,GAAe,EAGfC,GAAiB,EAEfF,EAAU9gD,EAAK/H,MAAM14C,SACvBuhG,EAAU9gD,EAAK/H,MAAM14C,QAM3B,IAAsB,GAAlByhG,GAA0C,GAAhBD,EAC5B,KAAM,IAAItjG,OAAM,wHAQhB5D,MAAKonG,mBAGiB,GAAlBD,IAC8C,WAA5CnnG,KAAKgiD,UAAUjB,mBAAmBG,OACpClhD,KAAKqnG,iBAAiBJ,GAGtBjnG,KAAKsnG,0BAAyB,GAKlC,IAAIC,GAAevnG,KAAKwnG,kBAGxBxnG,MAAKynG,uBAAuBF,GAG5BvnG,KAAK6P,UAYXjQ,EAAQ6nG,uBAAyB,SAASF,GACxC,GAAI/gD,GAAQL,CAGZ,KAAK,GAAIjI,KAASqpD,GAChB,GAAIA,EAAa1hG,eAAeq4C,GAE9B,IAAKsI,IAAU+gD,GAAarpD,GAAOZ,MAC7BiqD,EAAarpD,GAAOZ,MAAMz3C,eAAe2gD,KAC3CL,EAAOohD,EAAarpD,GAAOZ,MAAMkJ,GACkB,MAA/CxmD,KAAKgiD,UAAUjB,mBAAmB5lB,WAAoE,MAA/Cn7B,KAAKgiD,UAAUjB,mBAAmB5lB,UACvFgrB,EAAKsF,SACPtF,EAAKn0C,EAAIu1F,EAAarpD,GAAOwpD,OAC7BvhD,EAAKsF,QAAS,EAEd87C,EAAarpD,GAAOwpD,QAAUH,EAAarpD,GAAO+C,aAIhDkF,EAAKuF,SACPvF,EAAKl0C,EAAIs1F,EAAarpD,GAAOwpD,OAC7BvhD,EAAKuF,QAAS,EAEd67C,EAAarpD,GAAOwpD,QAAUH,EAAarpD,GAAO+C,aAGtDjhD,KAAK2nG,kBAAkBxhD,EAAK/H,MAAM+H,EAAK9lD,GAAGknG,EAAaphD,EAAKjI,OAOpEl+C,MAAKkoD,cAUPtoD,EAAQ4nG,iBAAmB,WACzB,GACIhhD,GAAQL,EAAMjI,EADdqpD,IAKJ,KAAK/gD,IAAUxmD,MAAKs9C,MACdt9C,KAAKs9C,MAAMz3C,eAAe2gD,KAC5BL,EAAOnmD,KAAKs9C,MAAMkJ,GAClBL,EAAKsF,QAAS,EACdtF,EAAKuF,QAAS,EACqC,MAA/C1rD,KAAKgiD,UAAUjB,mBAAmB5lB,WAAoE,MAA/Cn7B,KAAKgiD,UAAUjB,mBAAmB5lB,UAC3FgrB,EAAKl0C,EAAIjS,KAAKgiD,UAAUjB,mBAAmBC,gBAAgBmF,EAAKjI,MAGhEiI,EAAKn0C,EAAIhS,KAAKgiD,UAAUjB,mBAAmBC,gBAAgBmF,EAAKjI,MAEjC33C,SAA7BghG,EAAaphD,EAAKjI,SACpBqpD,EAAaphD,EAAKjI,QAAUkuB,OAAQ,EAAG9uB,SAAWoqD,OAAO,EAAGzmD,YAAY,IAE1EsmD,EAAaphD,EAAKjI,OAAOkuB,QAAU,EACnCm7B,EAAaphD,EAAKjI,OAAOZ,MAAMkJ,GAAUL,EAK7C,IAAIyhD,GAAW,CACf,KAAK1pD,IAASqpD,GACRA,EAAa1hG,eAAeq4C,IAC1B0pD,EAAWL,EAAarpD,GAAOkuB,SACjCw7B,EAAWL,EAAarpD,GAAOkuB,OAMrC,KAAKluB,IAASqpD,GACRA,EAAa1hG,eAAeq4C,KAC9BqpD,EAAarpD,GAAO+C,aAAe2mD,EAAW,GAAK5nG,KAAKgiD,UAAUjB,mBAAmBE,YACrFsmD,EAAarpD,GAAO+C,aAAgBsmD,EAAarpD,GAAOkuB,OAAS,EACjEm7B,EAAarpD,GAAOwpD,OAASH,EAAarpD,GAAO+C,YAAe,IAAOsmD,EAAarpD,GAAOkuB,OAAS,GAAKm7B,EAAarpD,GAAO+C,YAIjI,OAAOsmD,IAUT3nG,EAAQynG,iBAAmB,SAASJ,GAClC,GAAIzgD,GAAQL,CAGZ,KAAKK,IAAUxmD,MAAKs9C,MACdt9C,KAAKs9C,MAAMz3C,eAAe2gD,KAC5BL,EAAOnmD,KAAKs9C,MAAMkJ,GACdL,EAAK/H,MAAM14C,QAAUuhG,IACvB9gD,EAAKjI,MAAQ,GAMnB,KAAKsI,IAAUxmD,MAAKs9C,MACdt9C,KAAKs9C,MAAMz3C,eAAe2gD,KAC5BL,EAAOnmD,KAAKs9C,MAAMkJ,GACA,GAAdL,EAAKjI,OACPl+C,KAAK6nG,UAAU,EAAE1hD,EAAK/H,MAAM+H,EAAK9lD,MAczCT,EAAQ0nG,yBAA2B,WACjC,GAAI9gD,GAAQL,EAAM2hD,EACd5H,EAAW,GAGf4H,GAAY9nG,KAAKs9C,MAAMt9C,KAAKokD,YAAY,IACxC0jD,EAAU5pD,MAAQgiD,EAClBlgG,KAAK+nG,kBAAkB7H,EAAS4H,EAAU1pD,MAAM0pD,EAAUznG,GAG1D,KAAKmmD,IAAUxmD,MAAKs9C,MACdt9C,KAAKs9C,MAAMz3C,eAAe2gD,KAC5BL,EAAOnmD,KAAKs9C,MAAMkJ,GAClB05C,EAAW/5C,EAAKjI,MAAQgiD,EAAW/5C,EAAKjI,MAAQgiD,EAKpD,KAAK15C,IAAUxmD,MAAKs9C,MACdt9C,KAAKs9C,MAAMz3C,eAAe2gD,KAC5BL,EAAOnmD,KAAKs9C,MAAMkJ,GAClBL,EAAKjI,OAASgiD,IAepBtgG,EAAQwnG,iBAAmB,WACzBpnG,KAAKgiD,UAAUvC,WAAW9wC,SAAU,EACpC3O,KAAKgiD,UAAUlD,QAAQC,UAAUpwC,SAAU,EAC3C3O,KAAKgiD,UAAUlD,QAAQU,sBAAsB7wC,SAAU,EACvD3O,KAAKstE,2BACsC,GAAvCttE,KAAKgiD,UAAUZ,aAAazyC,UAC9B3O,KAAKgiD,UAAUZ,aAAaC,SAAU,GAExCrhD,KAAK+oD,wBAEL,IAAI4pB,GAAS3yE,KAAKgiD,UAAUjB,kBAC5B4xB,GAAO3xB,gBAAkB/7C,KAAK6lB,IAAI6nD,EAAO3xB,kBACjB,MAApB2xB,EAAOx3C,WAAyC,MAApBw3C,EAAOx3C,aACrCw3C,EAAO3xB,iBAAmB,IAGJ,MAApB2xB,EAAOx3C,WAAyC,MAApBw3C,EAAOx3C,UACM,GAAvCn7B,KAAKgiD,UAAUZ,aAAazyC,UAC9B3O,KAAKgiD,UAAUZ,aAAav6C,KAAO,YAIM,GAAvC7G,KAAKgiD,UAAUZ,aAAazyC,UAC9B3O,KAAKgiD,UAAUZ,aAAav6C,KAAO,eAgBzCjH,EAAQ+nG,kBAAoB,SAASvpD,EAAO4pD,EAAUT,EAAcU,GAClE,IAAK,GAAI1iG,GAAI,EAAGA,EAAI64C,EAAM14C,OAAQH,IAAK,CACrC,GAAIy4F,GAAY,IAEdA,GADE5/C,EAAM74C,GAAG0uD,MAAQ+zC,EACP5pD,EAAM74C,GAAG8jB,KAGT+0B,EAAM74C,GAAG+jB,EAIvB,IAAI4+E,IAAY,CACmC,OAA/CloG,KAAKgiD,UAAUjB,mBAAmB5lB,WAAoE,MAA/Cn7B,KAAKgiD,UAAUjB,mBAAmB5lB,UACvF6iE,EAAUvyC,QAAUuyC,EAAU9/C,MAAQ+pD,IACxCjK,EAAUvyC,QAAS,EACnBuyC,EAAUhsF,EAAIu1F,EAAavJ,EAAU9/C,OAAOwpD,OAC5CQ,GAAY,GAIVlK,EAAUtyC,QAAUsyC,EAAU9/C,MAAQ+pD,IACxCjK,EAAUtyC,QAAS,EACnBsyC,EAAU/rF,EAAIs1F,EAAavJ,EAAU9/C,OAAOwpD,OAC5CQ,GAAY,GAIC,GAAbA,IACFX,EAAavJ,EAAU9/C,OAAOwpD,QAAUH,EAAavJ,EAAU9/C,OAAO+C,YAClE+8C,EAAU5/C,MAAM14C,OAAS,GAC3B1F,KAAK2nG,kBAAkB3J,EAAU5/C,MAAM4/C,EAAU39F,GAAGknG,EAAavJ,EAAU9/C,UAenFt+C,EAAQioG,UAAY,SAAS3pD,EAAOE,EAAO4pD,GACzC,IAAK,GAAIziG,GAAI,EAAGA,EAAI64C,EAAM14C,OAAQH,IAAK,CACrC,GAAIy4F,GAAY,IAEdA,GADE5/C,EAAM74C,GAAG0uD,MAAQ+zC,EACP5pD,EAAM74C,GAAG8jB,KAGT+0B,EAAM74C,GAAG+jB,IAEA,IAAnB00E,EAAU9/C,OAAe8/C,EAAU9/C,MAAQA,KAC7C8/C,EAAU9/C,MAAQA,EACd8/C,EAAU5/C,MAAM14C,OAAS,GAC3B1F,KAAK6nG,UAAU3pD,EAAM,EAAG8/C,EAAU5/C,MAAO4/C,EAAU39F,OAe3DT,EAAQmoG,kBAAoB,SAAS7pD,EAAOE,EAAO4pD,GACjDhoG,KAAKs9C,MAAM0qD,GAAUrsC,qBAAsB,CAE3C,KAAK,GADDqiC,GAAW7iE,EACN51B,EAAI,EAAGA,EAAI64C,EAAM14C,OAAQH,IAChC41B,EAAY,EACRijB,EAAM74C,GAAG0uD,MAAQ+zC,GACnBhK,EAAY5/C,EAAM74C,GAAG8jB,KACrB8R,EAAY,IAGZ6iE,EAAY5/C,EAAM74C,GAAG+jB,GAEA,IAAnB00E,EAAU9/C,QACZ8/C,EAAU9/C,MAAQA,EAAQ/iB,EAI9B,KAAK,GAAI51B,GAAI,EAAGA,EAAI64C,EAAM14C,OAAQH,IACAy4F,EAA5B5/C,EAAM74C,GAAG0uD,MAAQ+zC,EAAuB5pD,EAAM74C,GAAG8jB,KACnC+0B,EAAM74C,GAAG+jB,GAEvB00E,EAAU5/C,MAAM14C,OAAS,GAAKs4F,EAAUriC,uBAAwB,GAClE37D,KAAK+nG,kBAAkB/J,EAAU9/C,MAAO8/C,EAAU5/C,MAAO4/C,EAAU39F,KAWzET,EAAQuoG,cAAgB,WACtB,IAAK,GAAI3hD,KAAUxmD,MAAKs9C,MAClBt9C,KAAKs9C,MAAMz3C,eAAe2gD,KAC5BxmD,KAAKs9C,MAAMkJ,GAAQiF,QAAS,EAC5BzrD,KAAKs9C,MAAMkJ,GAAQkF,QAAS,KAQ9B,SAAS7rD,EAAQD,EAASM,GAkgB9B,QAASkoG,KACPpoG,KAAKgiD,UAAUZ,aAAazyC,SAAW3O,KAAKgiD,UAAUZ,aAAazyC,OACnE,IAAI05F,GAAqB72F,SAAS82F,eAAe,qBACCD,GAAmBn7F,MAAMd,WAAhC,GAAvCpM,KAAKgiD,UAAUZ,aAAazyC,QAAwD,UACR,UAEhF3O,KAAK+oD,wBAAuB,GAO9B,QAASw/C,KACP,IAAK,GAAI/hD,KAAUxmD,MAAKkkD,iBAClBlkD,KAAKkkD,iBAAiBr+C,eAAe2gD,KACvCxmD,KAAKkkD,iBAAiBsC,GAAQsV,GAAK,EAAI97D,KAAKkkD,iBAAiBsC,GAAQuV,GAAK,EAC1E/7D,KAAKkkD,iBAAiBsC,GAAQoV,GAAK,EAAI57D,KAAKkkD,iBAAiBsC,GAAQqV,GAAK,EAG7B,IAA7C77D,KAAKgiD,UAAUjB,mBAAmBpyC,SACpC3O,KAAKslD,2BACLkjD,EAAiBjoG,KAAKP,KAAM,aAAc,EAAG,8CAC7CwoG,EAAiBjoG,KAAKP,KAAM,aAAc,EAAG,0BAC7CwoG,EAAiBjoG,KAAKP,KAAM,aAAc,EAAG,0BAC7CwoG,EAAiBjoG,KAAKP,KAAM,aAAc,EAAG,wBAC7CwoG,EAAiBjoG,KAAKP,KAAM,eAAgB,EAAG,oBAG/CA,KAAKq8F,kBAEPr8F,KAAKolD,QAAS,EACdplD,KAAK6P,QAMP,QAAS44F,KACP,GAAI/5F,GAAU,gDACVg6F,KACAC,EAAen3F,SAAS82F,eAAe,wBACvCM,EAAep3F,SAAS82F,eAAe,uBAC3C,IAA4B,GAAxBK,EAAaE,QAAiB,CAMhC,GALI7oG,KAAKgiD,UAAUlD,QAAQC,UAAUE,uBAAyBj/C,KAAK8oG,gBAAgBhqD,QAAQC,UAAUE,uBAAwBypD,EAAgBxgG,KAAK,0BAA4BlI,KAAKgiD,UAAUlD,QAAQC,UAAUE,uBAC3Mj/C,KAAKgiD,UAAUlD,QAAQI,gBAAkBl/C,KAAK8oG,gBAAgBhqD,QAAQC,UAAUG,gBAAyCwpD,EAAgBxgG,KAAK,mBAAqBlI,KAAKgiD,UAAUlD,QAAQI,gBAC1Ll/C,KAAKgiD,UAAUlD,QAAQK,cAAgBn/C,KAAK8oG,gBAAgBhqD,QAAQC,UAAUI,cAA2CupD,EAAgBxgG,KAAK,iBAAmBlI,KAAKgiD,UAAUlD,QAAQK,cACxLn/C,KAAKgiD,UAAUlD,QAAQM,gBAAkBp/C,KAAK8oG,gBAAgBhqD,QAAQC,UAAUK,gBAAyCspD,EAAgBxgG,KAAK,mBAAqBlI,KAAKgiD,UAAUlD,QAAQM,gBAC1Lp/C,KAAKgiD,UAAUlD,QAAQO,SAAWr/C,KAAK8oG,gBAAgBhqD,QAAQC,UAAUM,SAAgDqpD,EAAgBxgG,KAAK,YAAclI,KAAKgiD,UAAUlD,QAAQO,SACzJ,GAA1BqpD,EAAgBhjG,OAAa,CAC/BgJ,EAAU,kBACVA,GAAW,wBACX,KAAK,GAAInJ,GAAI,EAAGA,EAAImjG,EAAgBhjG,OAAQH,IAC1CmJ,GAAWg6F,EAAgBnjG,GACvBA,EAAImjG,EAAgBhjG,OAAS,IAC/BgJ,GAAW,KAGfA,IAAW,KAET1O,KAAKgiD,UAAUZ,aAAazyC,SAAW3O,KAAK8oG,gBAAgB1nD,aAAazyC,UAC7C,GAA1B+5F,EAAgBhjG,OAAcgJ,EAAU,kBACtCA,GAAW,KACjBA,GAAW,iBAAmB1O,KAAKgiD,UAAUZ,aAAazyC,SAE7C,iDAAXD,IACFA,GAAW,UAGV,IAA4B,GAAxBk6F,EAAaC,QAAiB,CAQrC,GAPAn6F,EAAU,kBACVA,GAAW,wCACP1O,KAAKgiD,UAAUlD,QAAQQ,UAAUC,cAAgBv/C,KAAK8oG,gBAAgBhqD,QAAQQ,UAAUC,cAAgBmpD,EAAgBxgG,KAAK,iBAAmBlI,KAAKgiD,UAAUlD,QAAQQ,UAAUC,cACjLv/C,KAAKgiD,UAAUlD,QAAQI,gBAAkBl/C,KAAK8oG,gBAAgBhqD,QAAQQ,UAAUJ,gBAAwBwpD,EAAgBxgG,KAAK,mBAAqBlI,KAAKgiD,UAAUlD,QAAQI,gBACzKl/C,KAAKgiD,UAAUlD,QAAQK,cAAgBn/C,KAAK8oG,gBAAgBhqD,QAAQQ,UAAUH,cAA0BupD,EAAgBxgG,KAAK,iBAAmBlI,KAAKgiD,UAAUlD,QAAQK,cACvKn/C,KAAKgiD,UAAUlD,QAAQM,gBAAkBp/C,KAAK8oG,gBAAgBhqD,QAAQQ,UAAUF,gBAAwBspD,EAAgBxgG,KAAK,mBAAqBlI,KAAKgiD,UAAUlD,QAAQM,gBACzKp/C,KAAKgiD,UAAUlD,QAAQO,SAAWr/C,KAAK8oG,gBAAgBhqD,QAAQQ,UAAUD,SAA+BqpD,EAAgBxgG,KAAK,YAAclI,KAAKgiD,UAAUlD,QAAQO,SACxI,GAA1BqpD,EAAgBhjG,OAAa,CAC/BgJ,GAAW,gBACX,KAAK,GAAInJ,GAAI,EAAGA,EAAImjG,EAAgBhjG,OAAQH,IAC1CmJ,GAAWg6F,EAAgBnjG,GACvBA,EAAImjG,EAAgBhjG,OAAS,IAC/BgJ,GAAW,KAGfA,IAAW,KAEiB,GAA1Bg6F,EAAgBhjG,SAAcgJ,GAAW,KACzC1O,KAAKgiD,UAAUZ,cAAgBphD,KAAK8oG,gBAAgB1nD,eACtD1yC,GAAW,mBAAqB1O,KAAKgiD,UAAUZ,cAEjD1yC,GAAW,SAER,CAOH,GANAA,EAAU,kBACN1O,KAAKgiD,UAAUlD,QAAQU,sBAAsBD,cAAgBv/C,KAAK8oG,gBAAgBhqD,QAAQU,sBAAsBD,cAAgBmpD,EAAgBxgG,KAAK,iBAAmBlI,KAAKgiD,UAAUlD,QAAQU,sBAAsBD,cACrNv/C,KAAKgiD,UAAUlD,QAAQI,gBAAkBl/C,KAAK8oG,gBAAgBhqD,QAAQU,sBAAsBN,gBAAwBwpD,EAAgBxgG,KAAK,mBAAqBlI,KAAKgiD,UAAUlD,QAAQI,gBACrLl/C,KAAKgiD,UAAUlD,QAAQK,cAAgBn/C,KAAK8oG,gBAAgBhqD,QAAQU,sBAAsBL,cAA0BupD,EAAgBxgG,KAAK,iBAAmBlI,KAAKgiD,UAAUlD,QAAQK,cACnLn/C,KAAKgiD,UAAUlD,QAAQM,gBAAkBp/C,KAAK8oG,gBAAgBhqD,QAAQU,sBAAsBJ,gBAAwBspD,EAAgBxgG,KAAK,mBAAqBlI,KAAKgiD,UAAUlD,QAAQM,gBACrLp/C,KAAKgiD,UAAUlD,QAAQO,SAAWr/C,KAAK8oG,gBAAgBhqD,QAAQU,sBAAsBH,SAA+BqpD,EAAgBxgG,KAAK,YAAclI,KAAKgiD,UAAUlD,QAAQO,SACpJ,GAA1BqpD,EAAgBhjG,OAAa,CAC/BgJ,GAAW,oCACX,KAAK,GAAInJ,GAAI,EAAGA,EAAImjG,EAAgBhjG,OAAQH,IAC1CmJ,GAAWg6F,EAAgBnjG,GACvBA,EAAImjG,EAAgBhjG,OAAS,IAC/BgJ,GAAW,KAGfA,IAAW,MAOb,GALAA,GAAW,wBACXg6F,KACI1oG,KAAKgiD,UAAUjB,mBAAmB5lB,WAAan7B,KAAK8oG,gBAAgB/nD,mBAAmB5lB,WAAkCutE,EAAgBxgG,KAAK,cAAgBlI,KAAKgiD,UAAUjB,mBAAmB5lB,WAChMl2B,KAAK6lB,IAAI9qB,KAAKgiD,UAAUjB,mBAAmBC,kBAAoBhhD,KAAK8oG,gBAAgB/nD,mBAAmBC,iBAAkB0nD,EAAgBxgG,KAAK,oBAAsBlI,KAAKgiD,UAAUjB,mBAAmBC,iBACtMhhD,KAAKgiD,UAAUjB,mBAAmBE,aAAejhD,KAAK8oG,gBAAgB/nD,mBAAmBE,aAAgCynD,EAAgBxgG,KAAK,gBAAkBlI,KAAKgiD,UAAUjB,mBAAmBE,aACxK,GAA1BynD,EAAgBhjG,OAAa,CAC/B,IAAK,GAAIH,GAAI,EAAGA,EAAImjG,EAAgBhjG,OAAQH,IAC1CmJ,GAAWg6F,EAAgBnjG,GACvBA,EAAImjG,EAAgBhjG,OAAS,IAC/BgJ,GAAW,KAGfA,IAAW,QAGXA,IAAW,eAEbA,IAAW,KAIb1O,KAAK+oG,WAAW7kF,UAAYxV,EAO9B,QAASs6F,KACP,GAAI5zF,IAAO,iBAAkB,gBAAiB,iBAC1C6zF,EAAcz3F,SAAS03F,cAAc,6CAA6C9hG,MAClF+hG,EAAU,SAAWF,EAAc,SACnCG,EAAQ53F,SAAS82F,eAAea,EACpCC,GAAMl8F,MAAMi7B,QAAU,OACtB,KAAK,GAAI5iC,GAAI,EAAGA,EAAI6P,EAAI1P,OAAQH,IAC1B6P,EAAI7P,IAAM4jG,IACZC,EAAQ53F,SAAS82F,eAAelzF,EAAI7P,IACpC6jG,EAAMl8F,MAAMi7B,QAAU,OAG1BnoC,MAAKmoG,gBACc,KAAfc,GACFjpG,KAAKgiD,UAAUjB,mBAAmBpyC,SAAU,EAC5C3O,KAAKgiD,UAAUlD,QAAQU,sBAAsB7wC,SAAU,EACvD3O,KAAKgiD,UAAUlD,QAAQC,UAAUpwC,SAAU,GAErB,KAAfs6F,EAC0C,GAA7CjpG,KAAKgiD,UAAUjB,mBAAmBpyC,UACpC3O,KAAKgiD,UAAUjB,mBAAmBpyC,SAAU,EAC5C3O,KAAKgiD,UAAUlD,QAAQU,sBAAsB7wC,SAAU,EACvD3O,KAAKgiD,UAAUlD,QAAQC,UAAUpwC,SAAU,EAC3C3O,KAAKgiD,UAAUZ,aAAazyC,SAAU,EACtC3O,KAAKslD,6BAIPtlD,KAAKgiD,UAAUjB,mBAAmBpyC,SAAU,EAC5C3O,KAAKgiD,UAAUlD,QAAQU,sBAAsB7wC,SAAU,EACvD3O,KAAKgiD,UAAUlD,QAAQC,UAAUpwC,SAAU,GAE7C3O,KAAKstE,0BACL,IAAI+6B,GAAqB72F,SAAS82F,eAAe,qBACCD,GAAmBn7F,MAAMd,WAAhC,GAAvCpM,KAAKgiD,UAAUZ,aAAazyC,QAAwD,UACR,UAChF3O,KAAKolD,QAAS,EACdplD,KAAK6P,QAWP,QAAS24F,GAAkBnoG,EAAGiN,EAAI+7F,GAChC,GAAIC,GAAUjpG,EAAK,SACfkpG,EAAa/3F,SAAS82F,eAAejoG,GAAI+G,KAEzCpB,OAAMC,QAAQqH,IAChBkE,SAAS82F,eAAegB,GAASliG,MAAQkG,EAAIzC,SAAS0+F,IACtDvpG,KAAKwpG,yBAAyBH,EAAsB/7F,EAAIzC,SAAS0+F,OAGjE/3F,SAAS82F,eAAegB,GAASliG,MAAQyD,SAASyC,GAAOgY,WAAWikF,GACpEvpG,KAAKwpG,yBAAyBH,EAAuBx+F,SAASyC,GAAOgY,WAAWikF,MAGrD,gCAAzBF,GACuB,sCAAzBA,GACyB,kCAAzBA,IACArpG,KAAKslD,2BAEPtlD,KAAKolD,QAAS,EACdplD,KAAK6P,QA7sBP,GAAIlP,GAAOT,EAAoB,GAC3BupG,EAAiBvpG,EAAoB,IACrCwpG,EAA4BxpG,EAAoB,IAChDypG,EAAiBzpG,EAAoB,GAOzCN,GAAQgqG,iBAAmB,WACzB5pG,KAAKgiD,UAAUlD,QAAQC,UAAUpwC,SAAW3O,KAAKgiD,UAAUlD,QAAQC,UAAUpwC,QAC7E3O,KAAKstE,2BACLttE,KAAKolD,QAAS,EACdplD,KAAK6P,SASPjQ,EAAQ0tE,yBAA2B,WAEe,GAA5CttE,KAAKgiD,UAAUlD,QAAQC,UAAUpwC,SACnC3O,KAAKqtE,YAAYo8B,GACjBzpG,KAAKqtE,YAAYq8B,GAEjB1pG,KAAKgiD,UAAUlD,QAAQI,eAAiBl/C,KAAKgiD,UAAUlD,QAAQC,UAAUG,eACzEl/C,KAAKgiD,UAAUlD,QAAQK,aAAen/C,KAAKgiD,UAAUlD,QAAQC,UAAUI,aACvEn/C,KAAKgiD,UAAUlD,QAAQM,eAAiBp/C,KAAKgiD,UAAUlD,QAAQC,UAAUK,eACzEp/C,KAAKgiD,UAAUlD,QAAQO,QAAUr/C,KAAKgiD,UAAUlD,QAAQC,UAAUM,QAElEr/C,KAAKktE,WAAWy8B,IAE+C,GAAxD3pG,KAAKgiD,UAAUlD,QAAQU,sBAAsB7wC,SACpD3O,KAAKqtE,YAAYs8B,GACjB3pG,KAAKqtE,YAAYo8B,GAEjBzpG,KAAKgiD,UAAUlD,QAAQI,eAAiBl/C,KAAKgiD,UAAUlD,QAAQU,sBAAsBN,eACrFl/C,KAAKgiD,UAAUlD,QAAQK,aAAen/C,KAAKgiD,UAAUlD,QAAQU,sBAAsBL,aACnFn/C,KAAKgiD,UAAUlD,QAAQM,eAAiBp/C,KAAKgiD,UAAUlD,QAAQU,sBAAsBJ,eACrFp/C,KAAKgiD,UAAUlD,QAAQO,QAAUr/C,KAAKgiD,UAAUlD,QAAQU,sBAAsBH,QAE9Er/C,KAAKktE,WAAWw8B,KAGhB1pG,KAAKqtE,YAAYs8B,GACjB3pG,KAAKqtE,YAAYq8B,GACjB1pG,KAAK6pG,cAAgBtjG,OAErBvG,KAAKgiD,UAAUlD,QAAQI,eAAiBl/C,KAAKgiD,UAAUlD,QAAQQ,UAAUJ,eACzEl/C,KAAKgiD,UAAUlD,QAAQK,aAAen/C,KAAKgiD,UAAUlD,QAAQQ,UAAUH,aACvEn/C,KAAKgiD,UAAUlD,QAAQM,eAAiBp/C,KAAKgiD,UAAUlD,QAAQQ,UAAUF,eACzEp/C,KAAKgiD,UAAUlD,QAAQO,QAAUr/C,KAAKgiD,UAAUlD,QAAQQ,UAAUD,QAElEr/C,KAAKktE,WAAWu8B,KAUpB7pG,EAAQkqG,4BAA8B,WAEL,GAA3B9pG,KAAKokD,YAAY1+C,OACnB1F,KAAKs9C,MAAMt9C,KAAKokD,YAAY,IAAIqa,UAAU,EAAG,IAIzCz+D,KAAKokD,YAAY1+C,OAAS1F,KAAKgiD,UAAUvC,WAAWE,kBAAyD,GAArC3/C,KAAKgiD,UAAUvC,WAAW9wC,SACpG3O,KAAK87F,aAAa97F,KAAKgiD,UAAUvC,WAAWG,eAAe,GAI7D5/C,KAAK+pG,qBAUTnqG,EAAQmqG,iBAAmB,WAKzB/pG,KAAKgqG,gCACLhqG,KAAKiqG,uBAEDjqG,KAAKgiD,UAAUlD,QAAQM,eAAiB,IACC,GAAvCp/C,KAAKgiD,UAAUZ,aAAazyC,SAA0D,GAAvC3O,KAAKgiD,UAAUZ,aAAaC,QAC7ErhD,KAAKkqG,oCAGuD,GAAxDlqG,KAAKgiD,UAAUlD,QAAQU,sBAAsB7wC,QAC/C3O,KAAKmqG,qCAGLnqG,KAAKoqG,2BAebxqG,EAAQ8uD,wBAA0B,WAChC,GAA2C,GAAvC1uD,KAAKgiD,UAAUZ,aAAazyC,SAA0D,GAAvC3O,KAAKgiD,UAAUZ,aAAaC,QAAiB,CAC9FrhD,KAAKkkD,oBACLlkD,KAAKmkD,yBAEL,KAAK,GAAIqC,KAAUxmD,MAAKs9C,MAClBt9C,KAAKs9C,MAAMz3C,eAAe2gD,KAC5BxmD,KAAKkkD,iBAAiBsC,GAAUxmD,KAAKs9C,MAAMkJ,GAG/C,IAAI0/C,GAAelmG,KAAKuvD,QAAiB,QAAS,KAClD,KAAK,GAAI86C,KAAiBnE,GACpBA,EAAargG,eAAewkG,KAC1BrqG,KAAKo+C,MAAMv4C,eAAeqgG,EAAamE,GAAe/3C,cACxDtyD,KAAKkkD,iBAAiBmmD,GAAiBnE,EAAamE,GAGpDnE,EAAamE,GAAe5rC,UAAU,EAAG,GAK/C,KAAK,GAAIlX,KAAOvnD,MAAKkkD,iBACflkD,KAAKkkD,iBAAiBr+C,eAAe0hD,IACvCvnD,KAAKmkD,uBAAuBj8C,KAAKq/C,OAKrCvnD,MAAKkkD,iBAAmBlkD,KAAKs9C,MAC7Bt9C,KAAKmkD,uBAAyBnkD,KAAKokD,aAUvCxkD,EAAQoqG,8BAAgC,WACtC,GAAInrF,GAAIC,EAAI8G,EAAUugC,EAAM5gD,EACxB+3C,EAAQt9C,KAAKkkD,iBACbomD,EAAUtqG,KAAKgiD,UAAUlD,QAAQI,eACjCqrD,EAAe,CAEnB,KAAKhlG,EAAI,EAAGA,EAAIvF,KAAKmkD,uBAAuBz+C,OAAQH,IAClD4gD,EAAO7I,EAAMt9C,KAAKmkD,uBAAuB5+C,IACzC4gD,EAAK9G,QAAUr/C,KAAKgiD,UAAUlD,QAAQO,QAEhB,WAAlBr/C,KAAKy8F,WAAqC,GAAX6N,GACjCzrF,GAAMsnC,EAAKn0C,EACX8M,GAAMqnC,EAAKl0C,EACX2T,EAAW3gB,KAAK2qB,KAAK/Q,EAAKA,EAAKC,EAAKA,GAEpCyrF,EAA4B,GAAZ3kF,EAAiB,EAAK0kF,EAAU1kF,EAChDugC,EAAKyV,GAAK/8C,EAAK0rF,EACfpkD,EAAK0V,GAAK/8C,EAAKyrF,IAGfpkD,EAAKyV,GAAK,EACVzV,EAAK0V,GAAK,IAahBj8D,EAAQwqG,uBAAyB,WAC/B,GAAII,GAAYz8C,EAAMV,EAClBxuC,EAAIC,EAAI88C,EAAIC,EAAI4uC,EAAa7kF,EAC7Bw4B,EAAQp+C,KAAKo+C,KAGjB,KAAKiP,IAAUjP,GACTA,EAAMv4C,eAAewnD,KACvBU,EAAO3P,EAAMiP,GACTU,EAAKC,WAEHhuD,KAAKs9C,MAAMz3C,eAAekoD,EAAKkG,OAASj0D,KAAKs9C,MAAMz3C,eAAekoD,EAAKiG,UACzEw2C,EAAaz8C,EAAKjP,QAAQK,aAE1BqrD,IAAez8C,EAAKzkC,GAAGozC,YAAc3O,EAAK1kC,KAAKqzC,YAAc,GAAK18D,KAAKgiD,UAAUvC,WAAWY,WAE5FxhC,EAAMkvC,EAAK1kC,KAAKrX,EAAI+7C,EAAKzkC,GAAGtX,EAC5B8M,EAAMivC,EAAK1kC,KAAKpX,EAAI87C,EAAKzkC,GAAGrX,EAC5B2T,EAAW3gB,KAAK2qB,KAAK/Q,EAAKA,EAAKC,EAAKA,GAEpB,GAAZ8G,IACFA,EAAW,KAIb6kF,EAAczqG,KAAKgiD,UAAUlD,QAAQM,gBAAkBorD,EAAa5kF,GAAYA,EAEhFg2C,EAAK/8C,EAAK4rF,EACV5uC,EAAK/8C,EAAK2rF,EAEV18C,EAAK1kC,KAAKuyC,IAAMA,EAChB7N,EAAK1kC,KAAKwyC,IAAMA,EAChB9N,EAAKzkC,GAAGsyC,IAAMA,EACd7N,EAAKzkC,GAAGuyC,IAAMA,KAexBj8D,EAAQsqG,kCAAoC,WAC1C,GAAIM,GAAYz8C,EAAMV,EAAQq9C,EAC1BtsD,EAAQp+C,KAAKo+C,KAGjB,KAAKiP,IAAUjP,GACb,GAAIA,EAAMv4C,eAAewnD,KACvBU,EAAO3P,EAAMiP,GACTU,EAAKC,WAEHhuD,KAAKs9C,MAAMz3C,eAAekoD,EAAKkG,OAASj0D,KAAKs9C,MAAMz3C,eAAekoD,EAAKiG,SACzD,MAAZjG,EAAKuB,KAAa,CACpB,GAAIq7C,GAAQ58C,EAAKzkC,GACbshF,EAAQ78C,EAAKuB,IACbu7C,EAAQ98C,EAAK1kC,IAEjBmhF,GAAaz8C,EAAKjP,QAAQK,aAE1BurD,EAAsBC,EAAMjuC,YAAcmuC,EAAMnuC,YAAc,EAG9D8tC,GAAcE,EAAsB1qG,KAAKgiD,UAAUvC,WAAWY,WAC9DrgD,KAAK8qG,sBAAsBH,EAAOC,EAAO,GAAMJ,GAC/CxqG,KAAK8qG,sBAAsBF,EAAOC,EAAO,GAAML,KAiB3D5qG,EAAQkrG,sBAAwB,SAAUH,EAAOC,EAAOJ,GACtD,GAAI3rF,GAAIC,EAAI88C,EAAIC,EAAI4uC,EAAa7kF,CAEjC/G,GAAM8rF,EAAM34F,EAAI44F,EAAM54F,EACtB8M,EAAM6rF,EAAM14F,EAAI24F,EAAM34F,EACtB2T,EAAW3gB,KAAK2qB,KAAK/Q,EAAKA,EAAKC,EAAKA,GAEpB,GAAZ8G,IACFA,EAAW,KAIb6kF,EAAczqG,KAAKgiD,UAAUlD,QAAQM,gBAAkBorD,EAAa5kF,GAAYA,EAEhFg2C,EAAK/8C,EAAK4rF,EACV5uC,EAAK/8C,EAAK2rF,EAEVE,EAAM/uC,IAAMA,EACZ+uC,EAAM9uC,IAAMA,EACZ+uC,EAAMhvC,IAAMA,EACZgvC,EAAM/uC,IAAMA,GAIdj8D,EAAQ6qD,6BAA+B,WACrC,GAAkClkD,SAA9BvG,KAAK+qG,qBAAoC,CAC3C,KAAO/qG,KAAK+qG,qBAAqBpnF,iBAC/B3jB,KAAK+qG,qBAAqB35F,YAAYpR,KAAK+qG,qBAAqBnnF,WAGlE5jB,MAAK+qG,qBAAqBjhG,WAAWsH,YAAYpR,KAAK+qG,sBACtD/qG,KAAK+qG,qBAAuBxkG,SAQhC3G,EAAQ2tE,0BAA4B,WAClC,GAAkChnE,SAA9BvG,KAAK+qG,qBAAoC,CAC3C/qG,KAAK8oG,mBACLnoG,EAAK6F,WAAWxG,KAAK8oG,gBAAgB9oG,KAAKgiD,UAE1C,IAAIgpD,IAAgC,KAAM,KAAM,KAAM,KACtDhrG,MAAK+qG,qBAAuBv5F,SAASM,cAAc,OACnD9R,KAAK+qG,qBAAqBhjG,UAAY,uBACtC/H,KAAK+qG,qBAAqB7mF,UAAY,onBAW2E,GAAKlkB,KAAKgiD,UAAUlD,QAAQC,UAAUE,sBAAyB,wGAA2G,GAAKj/C,KAAKgiD,UAAUlD,QAAQC,UAAUE,sBAAyB,4JAGpPj/C,KAAKgiD,UAAUlD,QAAQC,UAAUG,eAAiB,wFAA0Fl/C,KAAKgiD,UAAUlD,QAAQC,UAAUG,eAAiB,2JAG/Ll/C,KAAKgiD,UAAUlD,QAAQC,UAAUI,aAAe,sFAAwFn/C,KAAKgiD,UAAUlD,QAAQC,UAAUI,aAAe,6JAGtLn/C,KAAKgiD,UAAUlD,QAAQC,UAAUK,eAAiB,0FAA4Fp/C,KAAKgiD,UAAUlD,QAAQC,UAAUK,eAAiB,sJAGvMp/C,KAAKgiD,UAAUlD,QAAQC,UAAUM,QAAU,4FAA8Fr/C,KAAKgiD,UAAUlD,QAAQC,UAAUM,QAAU,sPAM/Kr/C,KAAKgiD,UAAUlD,QAAQQ,UAAUC,aAAe,kGAAoGv/C,KAAKgiD,UAAUlD,QAAQQ,UAAUC,aAAe,2JAGnMv/C,KAAKgiD,UAAUlD,QAAQQ,UAAUJ,eAAiB,uFAAyFl/C,KAAKgiD,UAAUlD,QAAQQ,UAAUJ,eAAiB,0JAG9Ll/C,KAAKgiD,UAAUlD,QAAQQ,UAAUH,aAAe,qFAAuFn/C,KAAKgiD,UAAUlD,QAAQQ,UAAUH,aAAe,4JAGrLn/C,KAAKgiD,UAAUlD,QAAQQ,UAAUF,eAAiB,yFAA2Fp/C,KAAKgiD,UAAUlD,QAAQQ,UAAUF,eAAiB,qJAGtMp/C,KAAKgiD,UAAUlD,QAAQQ,UAAUD,QAAU,2FAA6Fr/C,KAAKgiD,UAAUlD,QAAQQ,UAAUD,QAAU,oQAM9Kr/C,KAAKgiD,UAAUlD,QAAQU,sBAAsBD,aAAe,kGAAoGv/C,KAAKgiD,UAAUlD,QAAQU,sBAAsBD,aAAe,2JAG3Nv/C,KAAKgiD,UAAUlD,QAAQU,sBAAsBN,eAAiB,uFAAyFl/C,KAAKgiD,UAAUlD,QAAQU,sBAAsBN,eAAiB,0JAGtNl/C,KAAKgiD,UAAUlD,QAAQU,sBAAsBL,aAAe,qFAAuFn/C,KAAKgiD,UAAUlD,QAAQU,sBAAsBL,aAAe,4JAG7Mn/C,KAAKgiD,UAAUlD,QAAQU,sBAAsBJ,eAAiB,yFAA2Fp/C,KAAKgiD,UAAUlD,QAAQU,sBAAsBJ,eAAiB,qJAG9Np/C,KAAKgiD,UAAUlD,QAAQU,sBAAsBH,QAAU,2FAA6Fr/C,KAAKgiD,UAAUlD,QAAQU,sBAAsBH,QAAU,uJAG3M2rD,EAA6BtkG,QAAQ1G,KAAKgiD,UAAUjB,mBAAmB5lB,WAAa,0FAA4Fn7B,KAAKgiD,UAAUjB,mBAAmB5lB,UAAY,oKAGtNn7B,KAAKgiD,UAAUjB,mBAAmBC,gBAAkB,yFAA2FhhD,KAAKgiD,UAAUjB,mBAAmBC,gBAAkB,6JAGvMhhD,KAAKgiD,UAAUjB,mBAAmBE,YAAc,wFAA0FjhD,KAAKgiD,UAAUjB,mBAAmBE,YAAc,odAU9RjhD,KAAK0Z,iBAAiBuxF,cAAcp5F,aAAa7R,KAAK+qG,qBAAsB/qG,KAAK0Z,kBACjF1Z,KAAK+oG,WAAav3F,SAASM,cAAc,OACzC9R,KAAK+oG,WAAW77F,MAAM2wC,SAAW,OACjC79C,KAAK+oG,WAAW77F,MAAM0zD,WAAa,UACnC5gE,KAAK0Z,iBAAiBuxF,cAAcp5F,aAAa7R,KAAK+oG,WAAY/oG,KAAK0Z,iBAEvE;GAAIwxF,EACJA,GAAe15F,SAAS82F,eAAe,eACvC4C,EAAapiF,SAAW0/E,EAAiBzzE,KAAK/0B,KAAM,cAAe,GAAI,2CACvEkrG,EAAe15F,SAAS82F,eAAe,eACvC4C,EAAapiF,SAAW0/E,EAAiBzzE,KAAK/0B,KAAM,cAAe,EAAG,0BACtEkrG,EAAe15F,SAAS82F,eAAe,eACvC4C,EAAapiF,SAAW0/E,EAAiBzzE,KAAK/0B,KAAM,cAAe,EAAG,0BACtEkrG,EAAe15F,SAAS82F,eAAe,eACvC4C,EAAapiF,SAAW0/E,EAAiBzzE,KAAK/0B,KAAM,cAAe,EAAG,wBACtEkrG,EAAe15F,SAAS82F,eAAe,iBACvC4C,EAAapiF,SAAW0/E,EAAiBzzE,KAAK/0B,KAAM,gBAAiB,EAAG,mBAExEkrG,EAAe15F,SAAS82F,eAAe,cACvC4C,EAAapiF,SAAW0/E,EAAiBzzE,KAAK/0B,KAAM,aAAc,EAAG,kCACrEkrG,EAAe15F,SAAS82F,eAAe,cACvC4C,EAAapiF,SAAW0/E,EAAiBzzE,KAAK/0B,KAAM,aAAc,EAAG,0BACrEkrG,EAAe15F,SAAS82F,eAAe,cACvC4C,EAAapiF,SAAW0/E,EAAiBzzE,KAAK/0B,KAAM,aAAc,EAAG,0BACrEkrG,EAAe15F,SAAS82F,eAAe,cACvC4C,EAAapiF,SAAW0/E,EAAiBzzE,KAAK/0B,KAAM,aAAc,EAAG,wBACrEkrG,EAAe15F,SAAS82F,eAAe,gBACvC4C,EAAapiF,SAAW0/E,EAAiBzzE,KAAK/0B,KAAM,eAAgB,EAAG,mBAEvEkrG,EAAe15F,SAAS82F,eAAe,cACvC4C,EAAapiF,SAAW0/E,EAAiBzzE,KAAK/0B,KAAM,aAAc,EAAG,8CACrEkrG,EAAe15F,SAAS82F,eAAe,cACvC4C,EAAapiF,SAAW0/E,EAAiBzzE,KAAK/0B,KAAM,aAAc,EAAG,0BACrEkrG,EAAe15F,SAAS82F,eAAe,cACvC4C,EAAapiF,SAAW0/E,EAAiBzzE,KAAK/0B,KAAM,aAAc,EAAG,0BACrEkrG,EAAe15F,SAAS82F,eAAe,cACvC4C,EAAapiF,SAAW0/E,EAAiBzzE,KAAK/0B,KAAM,aAAc,EAAG,wBACrEkrG,EAAe15F,SAAS82F,eAAe,gBACvC4C,EAAapiF,SAAW0/E,EAAiBzzE,KAAK/0B,KAAM,eAAgB,EAAG,mBACvEkrG,EAAe15F,SAAS82F,eAAe,qBACvC4C,EAAapiF,SAAW0/E,EAAiBzzE,KAAK/0B,KAAM,oBAAqBgrG,EAA8B,gCACvGE,EAAe15F,SAAS82F,eAAe,kBACvC4C,EAAapiF,SAAW0/E,EAAiBzzE,KAAK/0B,KAAM,iBAAkB,EAAG,sCACzEkrG,EAAe15F,SAAS82F,eAAe,iBACvC4C,EAAapiF,SAAW0/E,EAAiBzzE,KAAK/0B,KAAM,gBAAiB,EAAG,iCAExE,IAAI2oG,GAAen3F,SAAS82F,eAAe,wBACvCM,EAAep3F,SAAS82F,eAAe,wBACvC6C,EAAe35F,SAAS82F,eAAe,uBAC3CM,GAAaC,SAAU,EACnB7oG,KAAKgiD,UAAUlD,QAAQC,UAAUpwC,UACnCg6F,EAAaE,SAAU,GAErB7oG,KAAKgiD,UAAUjB,mBAAmBpyC,UACpCw8F,EAAatC,SAAU,EAGzB,IAAIR,GAAqB72F,SAAS82F,eAAe,sBAC7C8C,EAAwB55F,SAAS82F,eAAe,yBAChD+C,EAAwB75F,SAAS82F,eAAe,wBAEpDD,GAAmBp2E,QAAUm2E,EAAwBrzE,KAAK/0B,MAC1DorG,EAAsBn5E,QAAUs2E,EAAqBxzE,KAAK/0B,MAC1DqrG,EAAsBp5E,QAAUw2E,EAAqB1zE,KAAK/0B,MAExDqoG,EAAmBn7F,MAAMd,WADQ,GAA/BpM,KAAKgiD,UAAUZ,cAA8D,GAAtCphD,KAAKgiD,UAAUspD,oBAClB,UAGA,UAIxCtC,EAAqBhxF,MAAMhY,MAE3B2oG,EAAa7/E,SAAWkgF,EAAqBj0E,KAAK/0B,MAClD4oG,EAAa9/E,SAAWkgF,EAAqBj0E,KAAK/0B,MAClDmrG,EAAariF,SAAWkgF,EAAqBj0E,KAAK/0B,QAWtDJ,EAAQ4pG,yBAA2B,SAAUH,EAAuBjiG,GAClE,GAAImkG,GAAYlC,EAAsBphG,MAAM,IACpB,IAApBsjG,EAAU7lG,OACZ1F,KAAKgiD,UAAUupD,EAAU,IAAMnkG,EAEJ,GAApBmkG,EAAU7lG,OACjB1F,KAAKgiD,UAAUupD,EAAU,IAAIA,EAAU,IAAMnkG,EAElB,GAApBmkG,EAAU7lG,SACjB1F,KAAKgiD,UAAUupD,EAAU,IAAIA,EAAU,IAAIA,EAAU,IAAMnkG,KA6N3D,SAASvH,GAEb,QAAS2rG,GAAeC,GACvB,KAAM,IAAI7nG,OAAM,uBAAyB6nG,EAAM,MAEhDD,EAAen+F,KAAO,WAAa,UACnCm+F,EAAeE,QAAUF,EACzB3rG,EAAOD,QAAU4rG,EACjBA,EAAenrG,GAAK,IAKhB,SAASR,EAAQD,GAQrBA,EAAQqqG,qBAAuB,WAC7B,GAAIprF,GAAIC,EAAW8G,EAAUg2C,EAAIC,EAAI6uC,EACnCiB,EAAgBhB,EAAOC,EAAOrlG,EAAGsmB,EAE/ByxB,EAAQt9C,KAAKkkD,iBACbE,EAAcpkD,KAAKmkD,uBAGnBynD,EAAS,GAAK,EACdzlG,EAAI,EAAI,EAGRo5C,EAAev/C,KAAKgiD,UAAUlD,QAAQQ,UAAUC,aAChDssD,EAAkBtsD,CAItB,KAAKh6C,EAAI,EAAGA,EAAI6+C,EAAY1+C,OAAS,EAAGH,IAEtC,IADAolG,EAAQrtD,EAAM8G,EAAY7+C,IACrBsmB,EAAItmB,EAAI,EAAGsmB,EAAIu4B,EAAY1+C,OAAQmmB,IAAK,CAC3C++E,EAAQttD,EAAM8G,EAAYv4B,IAC1B6+E,EAAsBC,EAAMjuC,YAAckuC,EAAMluC,YAAc,EAE9D79C,EAAK+rF,EAAM54F,EAAI24F,EAAM34F,EACrB8M,EAAK8rF,EAAM34F,EAAI04F,EAAM14F,EACrB2T,EAAW3gB,KAAK2qB,KAAK/Q,EAAKA,EAAKC,EAAKA,GAGpB,GAAZ8G,IACFA,EAAW,GAAI3gB,KAAKE,SACpB0Z,EAAK+G,GAGPimF,EAA0C,GAAvBnB,EAA4BnrD,EAAgBA,GAAgB,EAAImrD,EAAsB1qG,KAAKgiD,UAAUvC,WAAWW,sBACnI,IAAI96C,GAAIsmG,EAASC,CACF,GAAIA,EAAfjmF,IAEA+lF,EADa,GAAME,EAAjBjmF,EACe,EAGAtgB,EAAIsgB,EAAWzf,EAIlCwlG,GAA0C,GAAvBjB,EAA4B,EAAI,EAAIA,EAAsB1qG,KAAKgiD,UAAUvC,WAAWU,mBACvGwrD,GAAkC1mG,KAAK0H,IAAIiZ,EAAS,IAAKimF,GAEzDjwC,EAAK/8C,EAAK8sF,EACV9vC,EAAK/8C,EAAK6sF,EACVhB,EAAM/uC,IAAMA,EACZ+uC,EAAM9uC,IAAMA,EACZ+uC,EAAMhvC,IAAMA,EACZgvC,EAAM/uC,IAAMA,MAUhB,SAASh8D,EAAQD,GAQrBA,EAAQqqG,qBAAuB,WAC7B,GAAIprF,GAAIC,EAAI8G,EAAUg2C,EAAIC,EACxB8vC,EAAgBhB,EAAOC,EAAOrlG,EAAGsmB,EAE/ByxB,EAAQt9C,KAAKkkD,iBACbE,EAAcpkD,KAAKmkD,uBAGnB5E,EAAev/C,KAAKgiD,UAAUlD,QAAQU,sBAAsBD,YAIhE,KAAKh6C,EAAI,EAAGA,EAAI6+C,EAAY1+C,OAAS,EAAGH,IAEtC,IADAolG,EAAQrtD,EAAM8G,EAAY7+C,IACrBsmB,EAAItmB,EAAI,EAAGsmB,EAAIu4B,EAAY1+C,OAAQmmB,IAItC,GAHA++E,EAAQttD,EAAM8G,EAAYv4B,IAGtB8+E,EAAMzsD,OAAS0sD,EAAM1sD,MAAO,CAE9Br/B,EAAK+rF,EAAM54F,EAAI24F,EAAM34F,EACrB8M,EAAK8rF,EAAM34F,EAAI04F,EAAM14F,EACrB2T,EAAW3gB,KAAK2qB,KAAK/Q,EAAKA,EAAKC,EAAKA,EAGpC,IAAIgtF,GAAY,GAEdH,GADapsD,EAAX35B,GACgB3gB,KAAK8uB,IAAI+3E,EAAUlmF,EAAS,GAAK3gB,KAAK8uB,IAAI+3E,EAAUvsD,EAAa,GAGlE,EAGD,GAAZ35B,EACFA,EAAW,IAGX+lF,GAAkC/lF,EAEpCg2C,EAAK/8C,EAAK8sF,EACV9vC,EAAK/8C,EAAK6sF,EAEVhB,EAAM/uC,IAAMA,EACZ+uC,EAAM9uC,IAAMA,EACZ+uC,EAAMhvC,IAAMA,EACZgvC,EAAM/uC,IAAMA,IAYtBj8D,EAAQuqG,mCAAqC,WAS3C,IAAK,GARDK,GAAYz8C,EAAMV,EAClBxuC,EAAIC,EAAI88C,EAAIC,EAAI4uC,EAAa7kF,EAC7Bw4B,EAAQp+C,KAAKo+C,MAEbd,EAAQt9C,KAAKkkD,iBACbE,EAAcpkD,KAAKmkD,uBAGd5+C,EAAI,EAAGA,EAAI6+C,EAAY1+C,OAAQH,IAAK,CAC3C,GAAIolG,GAAQrtD,EAAM8G,EAAY7+C,GAC9BolG,GAAMoB,SAAW,EACjBpB,EAAMqB,SAAW,EAKnB,IAAK3+C,IAAUjP,GACb,GAAIA,EAAMv4C,eAAewnD,KACvBU,EAAO3P,EAAMiP,GACTU,EAAKC,WAEHhuD,KAAKs9C,MAAMz3C,eAAekoD,EAAKkG,OAASj0D,KAAKs9C,MAAMz3C,eAAekoD,EAAKiG,SAqBzE,GApBAw2C,EAAaz8C,EAAKjP,QAAQK,aAE1BqrD,IAAez8C,EAAKzkC,GAAGozC,YAAc3O,EAAK1kC,KAAKqzC,YAAc,GAAK18D,KAAKgiD,UAAUvC,WAAWY,WAE5FxhC,EAAMkvC,EAAK1kC,KAAKrX,EAAI+7C,EAAKzkC,GAAGtX,EAC5B8M,EAAMivC,EAAK1kC,KAAKpX,EAAI87C,EAAKzkC,GAAGrX,EAC5B2T,EAAW3gB,KAAK2qB,KAAK/Q,EAAKA,EAAKC,EAAKA,GAEpB,GAAZ8G,IACFA,EAAW,KAIb6kF,EAAczqG,KAAKgiD,UAAUlD,QAAQM,gBAAkBorD,EAAa5kF,GAAYA,EAEhFg2C,EAAK/8C,EAAK4rF,EACV5uC,EAAK/8C,EAAK2rF,EAIN18C,EAAKzkC,GAAG40B,OAAS6P,EAAK1kC,KAAK60B,MAC7B6P,EAAKzkC,GAAGyiF,UAAYnwC,EACpB7N,EAAKzkC,GAAG0iF,UAAYnwC,EACpB9N,EAAK1kC,KAAK0iF,UAAYnwC,EACtB7N,EAAK1kC,KAAK2iF,UAAYnwC,MAEnB,CACH,GAAI7U,GAAS,EACb+G,GAAKzkC,GAAGsyC,IAAM5U,EAAO4U,EACrB7N,EAAKzkC,GAAGuyC,IAAM7U,EAAO6U,EACrB9N,EAAK1kC,KAAKuyC,IAAM5U,EAAO4U,EACvB7N,EAAK1kC,KAAKwyC,IAAM7U,EAAO6U,EAQjC,GACIkwC,GAAUC,EADVvB,EAAc,CAElB,KAAKllG,EAAI,EAAGA,EAAI6+C,EAAY1+C,OAAQH,IAAK,CACvC,GAAI4gD,GAAO7I,EAAM8G,EAAY7+C,GAC7BwmG,GAAW9mG,KAAK8G,IAAI0+F,EAAYxlG,KAAK0H,KAAK89F,EAAYtkD,EAAK4lD,WAC3DC,EAAW/mG,KAAK8G,IAAI0+F,EAAYxlG,KAAK0H,KAAK89F,EAAYtkD,EAAK6lD,WAE3D7lD,EAAKyV,IAAMmwC,EACX5lD,EAAK0V,IAAMmwC,EAIb,GAAIC,GAAU,EACVC,EAAU,CACd,KAAK3mG,EAAI,EAAGA,EAAI6+C,EAAY1+C,OAAQH,IAAK,CACvC,GAAI4gD,GAAO7I,EAAM8G,EAAY7+C,GAC7B0mG,IAAW9lD,EAAKyV,GAChBswC,GAAW/lD,EAAK0V,GAElB,GAAIswC,GAAeF,EAAU7nD,EAAY1+C,OACrC0mG,EAAeF,EAAU9nD,EAAY1+C,MAEzC,KAAKH,EAAI,EAAGA,EAAI6+C,EAAY1+C,OAAQH,IAAK,CACvC,GAAI4gD,GAAO7I,EAAM8G,EAAY7+C,GAC7B4gD,GAAKyV,IAAMuwC,EACXhmD,EAAK0V,IAAMuwC,KAOX,SAASvsG,EAAQD,GAQrBA,EAAQqqG,qBAAuB,WAC7B,GAA8D,GAA1DjqG,KAAKgiD,UAAUlD,QAAQC,UAAUE,sBAA4B,CAC/D,GAAIkH,GACA7I,EAAQt9C,KAAKkkD,iBACbE,EAAcpkD,KAAKmkD,uBACnBkoD,EAAYjoD,EAAY1+C,MAE5B1F,MAAKssG,mBAAmBhvD,EAAM8G,EAK9B,KAAK,GAHDylD,GAAgB7pG,KAAK6pG,cAGhBtkG,EAAI,EAAO8mG,EAAJ9mG,EAAeA,IAC7B4gD,EAAO7I,EAAM8G,EAAY7+C,IACrB4gD,EAAKz3C,QAAQ6uC,KAAO,IAEtBv9C,KAAKusG,sBAAsB1C,EAAcnqG,KAAK8sG,SAASC,GAAGtmD,GAC1DnmD,KAAKusG,sBAAsB1C,EAAcnqG,KAAK8sG,SAASE,GAAGvmD,GAC1DnmD,KAAKusG,sBAAsB1C,EAAcnqG,KAAK8sG,SAASG,GAAGxmD,GAC1DnmD,KAAKusG,sBAAsB1C,EAAcnqG,KAAK8sG,SAASI,GAAGzmD,MAelEvmD,EAAQ2sG,sBAAwB,SAASM,EAAa1mD,GAEpD,GAAI0mD,EAAaC,cAAgB,EAAG,CAClC,GAAIjuF,GAAGC,EAAG8G,CAUV,IAPA/G,EAAKguF,EAAaE,aAAa/6F,EAAIm0C,EAAKn0C,EACxC8M,EAAK+tF,EAAaE,aAAa96F,EAAIk0C,EAAKl0C,EACxC2T,EAAW3gB,KAAK2qB,KAAK/Q,EAAKA,EAAKC,EAAKA,GAKhC8G,EAAWinF,EAAaG,SAAWhtG,KAAKgiD,UAAUlD,QAAQC,UAAUC,cAAe,CAErE,GAAZp5B,IACFA,EAAW,GAAI3gB,KAAKE,SACpB0Z,EAAK+G,EAEP,IAAI2kF,GAAevqG,KAAKgiD,UAAUlD,QAAQC,UAAUE,sBAAwB4tD,EAAatvD,KAAO4I,EAAKz3C,QAAQ6uC,MAAQ33B,EAAWA,EAAWA,GACvIg2C,EAAK/8C,EAAK0rF,EACV1uC,EAAK/8C,EAAKyrF,CACdpkD,GAAKyV,IAAMA,EACXzV,EAAK0V,IAAMA,MAIX,IAAkC,GAA9BgxC,EAAaC,cACf9sG,KAAKusG,sBAAsBM,EAAaL,SAASC,GAAGtmD,GACpDnmD,KAAKusG,sBAAsBM,EAAaL,SAASE,GAAGvmD,GACpDnmD,KAAKusG,sBAAsBM,EAAaL,SAASG,GAAGxmD,GACpDnmD,KAAKusG,sBAAsBM,EAAaL,SAASI,GAAGzmD,OAGpD,IAAI0mD,EAAaL,SAAS75F,KAAKtS,IAAM8lD,EAAK9lD,GAAI,CAE5B,GAAZulB,IACFA,EAAW,GAAI3gB,KAAKE,SACpB0Z,EAAK+G,EAEP,IAAI2kF,GAAevqG,KAAKgiD,UAAUlD,QAAQC,UAAUE,sBAAwB4tD,EAAatvD,KAAO4I,EAAKz3C,QAAQ6uC,MAAQ33B,EAAWA,EAAWA,GACvIg2C,EAAK/8C,EAAK0rF,EACV1uC,EAAK/8C,EAAKyrF,CACdpkD,GAAKyV,IAAMA,EACXzV,EAAK0V,IAAMA,KAcrBj8D,EAAQ0sG,mBAAqB,SAAShvD,EAAM8G,GAU1C,IAAK,GATD+B,GACAkmD,EAAYjoD,EAAY1+C,OAExB4gD,EAAOriD,OAAOgpG,UAChB7mD,EAAOniD,OAAOgpG,UACd1mD,GAAOtiD,OAAOgpG,UACd5mD,GAAOpiD,OAAOgpG,UAGP1nG,EAAI,EAAO8mG,EAAJ9mG,EAAeA,IAAK,CAClC,GAAIyM,GAAIsrC,EAAM8G,EAAY7+C,IAAIyM,EAC1BC,EAAIqrC,EAAM8G,EAAY7+C,IAAI0M,CAC1BqrC,GAAM8G,EAAY7+C,IAAImJ,QAAQ6uC,KAAO,IAC/B+I,EAAJt0C,IAAYs0C,EAAOt0C,GACnBA,EAAIu0C,IAAQA,EAAOv0C,GACfo0C,EAAJn0C,IAAYm0C,EAAOn0C,GACnBA,EAAIo0C,IAAQA,EAAOp0C,IAI3B,GAAIi7F,GAAWjoG,KAAK6lB,IAAIy7B,EAAOD,GAAQrhD,KAAK6lB,IAAIu7B,EAAOD,EACnD8mD,GAAW,GAAI9mD,GAAQ,GAAM8mD,EAAU7mD,GAAQ,GAAM6mD,IACtC5mD,GAAQ,GAAM4mD,EAAU3mD,GAAQ,GAAM2mD,EAGzD,IAAIC,GAAkB,KAClBC,EAAWnoG,KAAK0H,IAAIwgG,EAAgBloG,KAAK6lB,IAAIy7B,EAAOD,IACpD+mD,EAAe,GAAMD,EACrB9tC,EAAU,IAAOhZ,EAAOC,GAAOgZ,EAAU,IAAOnZ,EAAOC,GAGvDwjD,GACFnqG,MACEqtG,cAAe/6F,EAAE,EAAGC,EAAE,GACtBsrC,KAAK,EACL7nB,OACE4wB,KAAMgZ,EAAQ+tC,EAAa9mD,KAAK+Y,EAAQ+tC,EACxCjnD,KAAMmZ,EAAQ8tC,EAAahnD,KAAKkZ,EAAQ8tC,GAE1C/6F,KAAM86F,EACNJ,SAAU,EAAII,EACdZ,UAAY75F,KAAK,MACjBqpC,SAAU,EACVkC,MAAO,EACP4uD,cAAe,GAMnB,KAHA9sG,KAAKstG,aAAazD,EAAcnqG,MAG3B6F,EAAI,EAAO8mG,EAAJ9mG,EAAeA,IACzB4gD,EAAO7I,EAAM8G,EAAY7+C,IACrB4gD,EAAKz3C,QAAQ6uC,KAAO,GACtBv9C,KAAKutG,aAAa1D,EAAcnqG,KAAKymD,EAKzCnmD,MAAK6pG,cAAgBA,GAWvBjqG,EAAQ4tG,kBAAoB,SAASX,EAAc1mD,GACjD,GAAIsnD,GAAYZ,EAAatvD,KAAO4I,EAAKz3C,QAAQ6uC,KAC7CmwD,EAAe,EAAED,CAErBZ,GAAaE,aAAa/6F,EAAI66F,EAAaE,aAAa/6F,EAAI66F,EAAatvD,KAAO4I,EAAKn0C,EAAIm0C,EAAKz3C,QAAQ6uC,KACtGsvD,EAAaE,aAAa/6F,GAAK07F,EAE/Bb,EAAaE,aAAa96F,EAAI46F,EAAaE,aAAa96F,EAAI46F,EAAatvD,KAAO4I,EAAKl0C,EAAIk0C,EAAKz3C,QAAQ6uC,KACtGsvD,EAAaE,aAAa96F,GAAKy7F,EAE/Bb,EAAatvD,KAAOkwD,CACpB,IAAIE,GAAc1oG,KAAK0H,IAAI1H,KAAK0H,IAAIw5C,EAAK1zC,OAAO0zC,EAAKz6B,QAAQy6B,EAAK3zC,MAClEq6F,GAAa7wD,SAAY6wD,EAAa7wD,SAAW2xD,EAAeA,EAAcd,EAAa7wD,UAa7Fp8C,EAAQ2tG,aAAe,SAASV,EAAa1mD,EAAKynD,IAC1B,GAAlBA,GAA6CrnG,SAAnBqnG,IAE5B5tG,KAAKwtG,kBAAkBX,EAAa1mD,GAGlC0mD,EAAaL,SAASC,GAAG/2E,MAAM6wB,KAAOJ,EAAKn0C,EACzC66F,EAAaL,SAASC,GAAG/2E,MAAM2wB,KAAOF,EAAKl0C,EAC7CjS,KAAK6tG,eAAehB,EAAa1mD,EAAK,MAGtCnmD,KAAK6tG,eAAehB,EAAa1mD,EAAK,MAIpC0mD,EAAaL,SAASC,GAAG/2E,MAAM2wB,KAAOF,EAAKl0C,EAC7CjS,KAAK6tG,eAAehB,EAAa1mD,EAAK,MAGtCnmD,KAAK6tG,eAAehB,EAAa1mD,EAAK,OAc5CvmD,EAAQiuG,eAAiB,SAAShB,EAAa1mD,EAAK2nD,GAClD,OAAQjB,EAAaL,SAASsB,GAAQhB,eACpC,IAAK,GACHD,EAAaL,SAASsB,GAAQtB,SAAS75F,KAAOwzC,EAC9C0mD,EAAaL,SAASsB,GAAQhB,cAAgB,EAC9C9sG,KAAKwtG,kBAAkBX,EAAaL,SAASsB,GAAQ3nD,EACrD,MACF,KAAK,GAGC0mD,EAAaL,SAASsB,GAAQtB,SAAS75F,KAAKX,GAAKm0C,EAAKn0C,GACtD66F,EAAaL,SAASsB,GAAQtB,SAAS75F,KAAKV,GAAKk0C,EAAKl0C,GACxDk0C,EAAKn0C,GAAK/M,KAAKE,SACfghD,EAAKl0C,GAAKhN,KAAKE,WAGfnF,KAAKstG,aAAaT,EAAaL,SAASsB,IACxC9tG,KAAKutG,aAAaV,EAAaL,SAASsB,GAAQ3nD,GAElD,MACF,KAAK,GACHnmD,KAAKutG,aAAaV,EAAaL,SAASsB,GAAQ3nD,KAatDvmD,EAAQ0tG,aAAe,SAAST,GAE9B,GAAIkB,GAAgB,IACc,IAA9BlB,EAAaC,gBACfiB,EAAgBlB,EAAaL,SAAS75F,KACtCk6F,EAAatvD,KAAO,EAAGsvD,EAAaE,aAAa/6F,EAAI,EAAG66F,EAAaE,aAAa96F,EAAI,GAExF46F,EAAaC,cAAgB,EAC7BD,EAAaL,SAAS75F,KAAO,KAC7B3S,KAAKguG,cAAcnB,EAAa,MAChC7sG,KAAKguG,cAAcnB,EAAa,MAChC7sG,KAAKguG,cAAcnB,EAAa,MAChC7sG,KAAKguG,cAAcnB,EAAa,MAEX,MAAjBkB,GACF/tG,KAAKutG,aAAaV,EAAakB,IAenCnuG,EAAQouG,cAAgB,SAASnB,EAAciB,GAC7C,GAAIxnD,GAAKC,EAAKH,EAAKC,EACf4nD,EAAY,GAAMpB,EAAav6F,IACnC,QAAQw7F,GACN,IAAK,KACHxnD,EAAOumD,EAAan3E,MAAM4wB,KAC1BC,EAAOsmD,EAAan3E,MAAM4wB,KAAO2nD,EACjC7nD,EAAOymD,EAAan3E,MAAM0wB,KAC1BC,EAAOwmD,EAAan3E,MAAM0wB,KAAO6nD,CACjC,MACF,KAAK,KACH3nD,EAAOumD,EAAan3E,MAAM4wB,KAAO2nD,EACjC1nD,EAAOsmD,EAAan3E,MAAM6wB,KAC1BH,EAAOymD,EAAan3E,MAAM0wB,KAC1BC,EAAOwmD,EAAan3E,MAAM0wB,KAAO6nD,CACjC,MACF,KAAK,KACH3nD,EAAOumD,EAAan3E,MAAM4wB,KAC1BC,EAAOsmD,EAAan3E,MAAM4wB,KAAO2nD,EACjC7nD,EAAOymD,EAAan3E,MAAM0wB,KAAO6nD,EACjC5nD,EAAOwmD,EAAan3E,MAAM2wB,IAC1B,MACF,KAAK,KACHC,EAAOumD,EAAan3E,MAAM4wB,KAAO2nD,EACjC1nD,EAAOsmD,EAAan3E,MAAM6wB,KAC1BH,EAAOymD,EAAan3E,MAAM0wB,KAAO6nD,EACjC5nD,EAAOwmD,EAAan3E,MAAM2wB,KAK9BwmD,EAAaL,SAASsB,IACpBf,cAAc/6F,EAAE,EAAEC,EAAE,GACpBsrC,KAAK,EACL7nB,OAAO4wB,KAAKA,EAAKC,KAAKA,EAAKH,KAAKA,EAAKC,KAAKA,GAC1C/zC,KAAM,GAAMu6F,EAAav6F,KACzB06F,SAAU,EAAIH,EAAaG,SAC3BR,UAAW75F,KAAK,MAChBqpC,SAAU,EACVkC,MAAO2uD,EAAa3uD,MAAM,EAC1B4uD,cAAe,IAYnBltG,EAAQsuG,UAAY,SAASlnF,EAAI5b,GACJ7E,SAAvBvG,KAAK6pG,gBAEP7iF,EAAIO,UAAY,EAEhBvnB,KAAKmuG,YAAYnuG,KAAK6pG,cAAcnqG,KAAKsnB,EAAI5b,KAajDxL,EAAQuuG,YAAc,SAASC,EAAOpnF,EAAI5b,GAC1B7E,SAAV6E,IACFA,EAAQ,WAGkB,GAAxBgjG,EAAOtB,gBACT9sG,KAAKmuG,YAAYC,EAAO5B,SAASC,GAAGzlF,GACpChnB,KAAKmuG,YAAYC,EAAO5B,SAASE,GAAG1lF,GACpChnB,KAAKmuG,YAAYC,EAAO5B,SAASI,GAAG5lF,GACpChnB,KAAKmuG,YAAYC,EAAO5B,SAASG,GAAG3lF,IAEtCA,EAAIY,YAAcxc,EAClB4b,EAAIa,YACJb,EAAIc,OAAOsmF,EAAO14E,MAAM4wB,KAAK8nD,EAAO14E,MAAM0wB,MAC1Cp/B,EAAIe,OAAOqmF,EAAO14E,MAAM6wB,KAAK6nD,EAAO14E,MAAM0wB,MAC1Cp/B,EAAIlH,SAEJkH,EAAIa,YACJb,EAAIc,OAAOsmF,EAAO14E,MAAM6wB,KAAK6nD,EAAO14E,MAAM0wB,MAC1Cp/B,EAAIe,OAAOqmF,EAAO14E,MAAM6wB,KAAK6nD,EAAO14E,MAAM2wB,MAC1Cr/B,EAAIlH,SAEJkH,EAAIa,YACJb,EAAIc,OAAOsmF,EAAO14E,MAAM6wB,KAAK6nD,EAAO14E,MAAM2wB,MAC1Cr/B,EAAIe,OAAOqmF,EAAO14E,MAAM4wB,KAAK8nD,EAAO14E,MAAM2wB,MAC1Cr/B,EAAIlH,SAEJkH,EAAIa,YACJb,EAAIc,OAAOsmF,EAAO14E,MAAM4wB,KAAK8nD,EAAO14E,MAAM2wB,MAC1Cr/B,EAAIe,OAAOqmF,EAAO14E,MAAM4wB,KAAK8nD,EAAO14E,MAAM0wB,MAC1Cp/B,EAAIlH,WAaF,SAASjgB,GAEbA,EAAOD,QAAU,SAASC,GAQzB,MAPIA,GAAOwuG,kBACVxuG,EAAOwxE,UAAY,aACnBxxE,EAAOyuG,SAEPzuG,EAAO2sG,YACP3sG,EAAOwuG,gBAAkB,GAEnBxuG,IAMJ,SAASA,EAAQD,IAEO,SAAS2uG,GAA0B1uG,EAAOD,QAAU2uG,IAEnDhuG,KAAKX"} \ No newline at end of file diff --git a/dist/vis.min.js b/dist/vis.min.js index 3a4eff53..a4015de6 100644 --- a/dist/vis.min.js +++ b/dist/vis.min.js @@ -4,7 +4,7 @@ * * A dynamic, browser-based visualization library. * - * @version 3.9.0 + * @version 3.9.1-SNAPSHOT * @date 2015-01-16 * * @license @@ -23,17 +23,17 @@ * Vis.js may be distributed under either license. */ "use strict";!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):"object"==typeof exports?exports.vis=e():t.vis=e()}(this,function(){return function(t){function e(s){if(i[s])return i[s].exports;var o=i[s]={exports:{},id:s,loaded:!1};return t[s].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var i={};return e.m=t,e.c=i,e.p="",e(0)}([function(t,e,i){e.util=i(1),e.DOMutil=i(2),e.DataSet=i(3),e.DataView=i(4),e.Queue=i(5),e.Graph3d=i(6),e.graph3d={Camera:i(7),Filter:i(8),Point2d:i(9),Point3d:i(10),Slider:i(11),StepNumber:i(12)},e.Timeline=i(13),e.Graph2d=i(14),e.timeline={DateUtil:i(15),DataStep:i(16),Range:i(17),stack:i(18),TimeStep:i(19),components:{items:{Item:i(31),BackgroundItem:i(32),BoxItem:i(33),PointItem:i(34),RangeItem:i(35)},Component:i(20),CurrentTime:i(21),CustomTime:i(22),DataAxis:i(23),GraphGroup:i(24),Group:i(25),BackgroundGroup:i(26),ItemSet:i(27),Legend:i(28),LineGraph:i(29),TimeAxis:i(30)}},e.Network=i(36),e.network={Edge:i(37),Groups:i(38),Images:i(39),Node:i(40),Popup:i(41),dotparser:i(42),gephiParser:i(43)},e.Graph=function(){throw new Error("Graph is renamed to Network. Please create a graph as new vis.Network(...)")},e.moment=i(44),e.hammer=i(45)},function(t,e,i){var s=i(44);e.isNumber=function(t){return t instanceof Number||"number"==typeof t},e.isString=function(t){return t instanceof String||"string"==typeof t},e.isDate=function(t){if(t instanceof Date)return!0;if(e.isString(t)){var i=o.exec(t);if(i)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},e.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},e.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},e.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var s=arguments[e];for(var o in s)s.hasOwnProperty(o)&&(t[o]=s[o])}return t},e.selectiveExtend=function(t,e){if(!Array.isArray(t))throw new Error("Array with property names expected as first argument");for(var i=2;ii;i++)if(t[i]!=e[i])return!1;return!0},e.convert=function(t,i){var n;if(void 0===t)return void 0;if(null===t)return null;if(!i)return t;if("string"!=typeof i&&!(i instanceof String))throw new Error("Type must be a string");switch(i){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return String(t);case"Date":if(e.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(s.isMoment(t))return new Date(t.valueOf());if(e.isString(t))return n=o.exec(t),n?new Date(Number(n[1])):s(t).toDate();throw new Error("Cannot convert object of type "+e.getType(t)+" to type Date");case"Moment":if(e.isNumber(t))return s(t);if(t instanceof Date)return s(t.valueOf());if(s.isMoment(t))return s(t);if(e.isString(t))return n=o.exec(t),s(n?Number(n[1]):t);throw new Error("Cannot convert object of type "+e.getType(t)+" to type Date");case"ISODate":if(e.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(s.isMoment(t))return t.toDate().toISOString();if(e.isString(t))return n=o.exec(t),n?new Date(Number(n[1])).toISOString():new Date(t).toISOString();throw new Error("Cannot convert object of type "+e.getType(t)+" to type ISODate");case"ASPDate":if(e.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(e.isString(t)){n=o.exec(t);var r;return r=n?new Date(Number(n[1])).valueOf():new Date(t).valueOf(),"/Date("+r+")/"}throw new Error("Cannot convert object of type "+e.getType(t)+" to type ASPDate");default:throw new Error('Unknown type "'+i+'"')}};var o=/^\/?Date\((\-?\d+)/i;e.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":Array.isArray(t)?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},e.getAbsoluteLeft=function(t){return t.getBoundingClientRect().left+window.pageXOffset},e.getAbsoluteTop=function(t){return t.getBoundingClientRect().top+window.pageYOffset},e.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},e.removeClassName=function(t,e){var i=t.className.split(" "),s=i.indexOf(e);-1!=s&&(i.splice(s,1),t.className=i.join(" "))},e.forEach=function(t,e){var i,s;if(Array.isArray(t))for(i=0,s=t.length;s>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},e.toArray=function(t){var e=[];for(var i in t)t.hasOwnProperty(i)&&e.push(t[i]);return e},e.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},e.addEventListener=function(t,e,i,s){t.addEventListener?(void 0===s&&(s=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,s)):t.attachEvent("on"+e,i)},e.removeEventListener=function(t,e,i,s){t.removeEventListener?(void 0===s&&(s=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,s)):t.detachEvent("on"+e,i)},e.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},e.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},e.option={},e.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},e.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},e.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?String(t):e||null},e.option.asSize=function(t,i){return"function"==typeof t&&(t=t()),e.isString(t)?t:e.isNumber(t)?t+"px":i||null},e.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null},e.hexToRGB=function(t){var e=/^#?([a-f\d])([a-f\d])([a-f\d])$/i;t=t.replace(e,function(t,e,i,s){return e+e+i+i+s+s});var i=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(t);return i?{r:parseInt(i[1],16),g:parseInt(i[2],16),b:parseInt(i[3],16)}:null},e.RGBToHex=function(t,e,i){return"#"+((1<<24)+(t<<16)+(e<<8)+i).toString(16).slice(1)},e.parseColor=function(t){var i;if(e.isString(t)){if(e.isValidRGB(t)){var s=t.substr(4).substr(0,t.length-5).split(",");t=e.RGBToHex(s[0],s[1],s[2])}if(e.isValidHex(t)){var o=e.hexToHSV(t),n={h:o.h,s:.45*o.s,v:Math.min(1,1.05*o.v)},r={h:o.h,s:Math.min(1,1.25*o.v),v:.6*o.v},a=e.HSVToHex(r.h,r.h,r.v),h=e.HSVToHex(n.h,n.s,n.v);i={background:t,border:a,highlight:{background:h,border:a},hover:{background:h,border:a}}}else i={background:t,border:t,highlight:{background:t,border:t},hover:{background:t,border:t}}}else i={},i.background=t.background||"white",i.border=t.border||i.background,e.isString(t.highlight)?i.highlight={border:t.highlight,background:t.highlight}:(i.highlight={},i.highlight.background=t.highlight&&t.highlight.background||i.background,i.highlight.border=t.highlight&&t.highlight.border||i.border),e.isString(t.hover)?i.hover={border:t.hover,background:t.hover}:(i.hover={},i.hover.background=t.hover&&t.hover.background||i.background,i.hover.border=t.hover&&t.hover.border||i.border);return i},e.RGBToHSV=function(t,e,i){t/=255,e/=255,i/=255;var s=Math.min(t,Math.min(e,i)),o=Math.max(t,Math.max(e,i));if(s==o)return{h:0,s:0,v:s};var n=t==s?e-i:i==s?t-e:i-t,r=t==s?3:i==s?1:5,a=60*(r-n/(o-s))/360,h=(o-s)/o,d=o;return{h:a,s:h,v:d}};var n={split:function(t){var e={};return t.split(";").forEach(function(t){if(""!=t.trim()){var i=t.split(":"),s=i[0].trim(),o=i[1].trim();e[s]=o}}),e},join:function(t){return Object.keys(t).map(function(e){return e+": "+t[e]}).join("; ")}};e.addCssText=function(t,i){var s=n.split(t.style.cssText),o=n.split(i),r=e.extend(s,o);t.style.cssText=n.join(r)},e.removeCssText=function(t,e){var i=n.split(t.style.cssText),s=n.split(e);for(var o in s)s.hasOwnProperty(o)&&delete i[o];t.style.cssText=n.join(i)},e.HSVToRGB=function(t,e,i){var s,o,n,r=Math.floor(6*t),a=6*t-r,h=i*(1-e),d=i*(1-a*e),l=i*(1-(1-a)*e);switch(r%6){case 0:s=i,o=l,n=h;break;case 1:s=d,o=i,n=h;break;case 2:s=h,o=i,n=l;break;case 3:s=h,o=d,n=i;break;case 4:s=l,o=h,n=i;break;case 5:s=i,o=h,n=d}return{r:Math.floor(255*s),g:Math.floor(255*o),b:Math.floor(255*n)}},e.HSVToHex=function(t,i,s){var o=e.HSVToRGB(t,i,s);return e.RGBToHex(o.r,o.g,o.b)},e.hexToHSV=function(t){var i=e.hexToRGB(t);return e.RGBToHSV(i.r,i.g,i.b)},e.isValidHex=function(t){var e=/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(t);return e},e.isValidRGB=function(t){t=t.replace(" ","");var e=/rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)/i.test(t);return e},e.selectiveBridgeObject=function(t,i){if("object"==typeof i){for(var s=Object.create(i),o=0;o=r&&o>n;){var h=Math.floor((r+a)/2),d=t[h],l=void 0===s?d[i]:d[i][s],c=e(l);if(0==c)return h;-1==c?r=h+1:a=h-1,n++}return-1},e.binarySearchValue=function(t,e,i,s){for(var o,n,r,a,h=1e4,d=0,l=0,c=t.length-1;c>=l&&h>d;){if(a=Math.floor(.5*(c+l)),o=t[Math.max(0,a-1)][i],n=t[a][i],r=t[Math.min(t.length-1,a+1)][i],n==e)return a;if(e>o&&n>e)return"before"==s?Math.max(0,a-1):a;if(e>n&&r>e)return"before"==s?a:Math.min(t.length-1,a+1);e>n?l=a+1:c=a-1,d++}return-1},e.easeInOutQuad=function(t,e,i,s){var o=i-e;return t/=s/2,1>t?o/2*t*t+e:(t--,-o/2*(t*(t-2)-1)+e)},e.easingFunctions={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return t*(2-t)},easeInOutQuad:function(t){return.5>t?2*t*t:-1+(4-2*t)*t},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return--t*t*t+1},easeInOutCubic:function(t){return.5>t?4*t*t*t:(t-1)*(2*t-2)*(2*t-2)+1},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return 1- --t*t*t*t},easeInOutQuart:function(t){return.5>t?8*t*t*t*t:1-8*--t*t*t*t},easeInQuint:function(t){return t*t*t*t*t},easeOutQuint:function(t){return 1+--t*t*t*t*t},easeInOutQuint:function(t){return.5>t?16*t*t*t*t*t:1+16*--t*t*t*t*t}}},function(t,e){e.prepareElements=function(t){for(var e in t)t.hasOwnProperty(e)&&(t[e].redundant=t[e].used,t[e].used=[])},e.cleanupElements=function(t){for(var e in t)if(t.hasOwnProperty(e)&&t[e].redundant){for(var i=0;i0?(s=e[t].redundant[0],e[t].redundant.shift()):(s=document.createElementNS("http://www.w3.org/2000/svg",t),i.appendChild(s)):(s=document.createElementNS("http://www.w3.org/2000/svg",t),e[t]={used:[],redundant:[]},i.appendChild(s)),e[t].used.push(s),s},e.getDOMElement=function(t,e,i,s){var o;return e.hasOwnProperty(t)?e[t].redundant.length>0?(o=e[t].redundant[0],e[t].redundant.shift()):(o=document.createElement(t),void 0!==s?i.insertBefore(o,s):i.appendChild(o)):(o=document.createElement(t),e[t]={used:[],redundant:[]},void 0!==s?i.insertBefore(o,s):i.appendChild(o)),e[t].used.push(o),o},e.drawPoint=function(t,i,s,o,n){var r;return"circle"==s.options.drawPoints.style?(r=e.getSVGElement("circle",o,n),r.setAttributeNS(null,"cx",t),r.setAttributeNS(null,"cy",i),r.setAttributeNS(null,"r",.5*s.options.drawPoints.size)):(r=e.getSVGElement("rect",o,n),r.setAttributeNS(null,"x",t-.5*s.options.drawPoints.size),r.setAttributeNS(null,"y",i-.5*s.options.drawPoints.size),r.setAttributeNS(null,"width",s.options.drawPoints.size),r.setAttributeNS(null,"height",s.options.drawPoints.size)),void 0!==s.options.drawPoints.styles&&r.setAttributeNS(null,"style",s.group.options.drawPoints.styles),r.setAttributeNS(null,"class",s.className+" point"),r},e.drawBar=function(t,i,s,o,n,r,a){if(0!=o){0>o&&(o*=-1,i-=o);var h=e.getSVGElement("rect",r,a);h.setAttributeNS(null,"x",t-.5*s),h.setAttributeNS(null,"y",i),h.setAttributeNS(null,"width",s),h.setAttributeNS(null,"height",o),h.setAttributeNS(null,"class",n)}}},function(t,e,i){function s(t,e){if(!t||Array.isArray(t)||o.isDataTable(t)||(e=t,t=null),this._options=e||{},this._data={},this._fieldId=this._options.fieldId||"id",this._type={},this._options.type)for(var i in this._options.type)if(this._options.type.hasOwnProperty(i)){var s=this._options.type[i];this._type[i]="Date"==s||"ISODate"==s||"ASPDate"==s?"Date":s}if(this._options.convert)throw new Error('Option "convert" is deprecated. Use "type" instead.');this._subscribers={},t&&this.add(t),this.setOptions(e)}var o=i(1),n=i(5);s.prototype.setOptions=function(t){t&&void 0!==t.queue&&(t.queue===!1?this._queue&&(this._queue.destroy(),delete this._queue):(this._queue||(this._queue=n.extend(this,{replace:["add","update","remove"]})),"object"==typeof t.queue&&this._queue.setOptions(t.queue)))},s.prototype.on=function(t,e){var i=this._subscribers[t];i||(i=[],this._subscribers[t]=i),i.push({callback:e})},s.prototype.subscribe=s.prototype.on,s.prototype.off=function(t,e){var i=this._subscribers[t];i&&(this._subscribers[t]=i.filter(function(t){return t.callback!=e}))},s.prototype.unsubscribe=s.prototype.off,s.prototype._trigger=function(t,e,i){if("*"==t)throw new Error("Cannot trigger event *");var s=[];t in this._subscribers&&(s=s.concat(this._subscribers[t])),"*"in this._subscribers&&(s=s.concat(this._subscribers["*"]));for(var o=0;or;r++)i=n._addItem(t[r]),s.push(i);else if(o.isDataTable(t))for(var h=this._getColumnNames(t),d=0,l=t.getNumberOfRows();l>d;d++){for(var c={},p=0,u=h.length;u>p;p++){var m=h[p];c[m]=t.getValue(d,p)}i=n._addItem(c),s.push(i)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");i=n._addItem(t),s.push(i)}return s.length&&this._trigger("add",{items:s},e),s},s.prototype.update=function(t,e){var i=[],s=[],n=[],r=this,a=r._fieldId,h=function(t){var e=t[a];r._data[e]?(e=r._updateItem(t),s.push(e),n.push(t)):(e=r._addItem(t),i.push(e))};if(Array.isArray(t))for(var d=0,l=t.length;l>d;d++)h(t[d]);else if(o.isDataTable(t))for(var c=this._getColumnNames(t),p=0,u=t.getNumberOfRows();u>p;p++){for(var m={},f=0,g=c.length;g>f;f++){var v=c[f];m[v]=t.getValue(p,f)}h(m)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");h(t)}return i.length&&this._trigger("add",{items:i},e),s.length&&this._trigger("update",{items:s,data:n},e),i.concat(s)},s.prototype.get=function(){var t,e,i,s,n=this,r=o.getType(arguments[0]);"String"==r||"Number"==r?(t=arguments[0],i=arguments[1],s=arguments[2]):"Array"==r?(e=arguments[0],i=arguments[1],s=arguments[2]):(i=arguments[0],s=arguments[1]);var a;if(i&&i.returnType){var h=["DataTable","Array","Object"];if(a=-1==h.indexOf(i.returnType)?"Array":i.returnType,s&&a!=o.getType(s))throw new Error('Type of parameter "data" ('+o.getType(s)+") does not correspond with specified options.type ("+i.type+")");if("DataTable"==a&&!o.isDataTable(s))throw new Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else a=s&&"DataTable"==o.getType(s)?"DataTable":"Array";var d,l,c,p,u=i&&i.type||this._options.type,m=i&&i.filter,f=[];if(void 0!=t)d=n._getItem(t,u),m&&!m(d)&&(d=null);else if(void 0!=e)for(c=0,p=e.length;p>c;c++)d=n._getItem(e[c],u),(!m||m(d))&&f.push(d);else for(l in this._data)this._data.hasOwnProperty(l)&&(d=n._getItem(l,u),(!m||m(d))&&f.push(d));if(i&&i.order&&void 0==t&&this._sort(f,i.order),i&&i.fields){var g=i.fields;if(void 0!=t)d=this._filterFields(d,g);else for(c=0,p=f.length;p>c;c++)f[c]=this._filterFields(f[c],g)}if("DataTable"==a){var v=this._getColumnNames(s);if(void 0!=t)n._appendRow(s,v,d);else for(c=0;cc;c++)s.push(f[c]);return s}return f},s.prototype.getIds=function(t){var e,i,s,o,n,r=this._data,a=t&&t.filter,h=t&&t.order,d=t&&t.type||this._options.type,l=[];if(a)if(h){n=[];for(s in r)r.hasOwnProperty(s)&&(o=this._getItem(s,d),a(o)&&n.push(o));for(this._sort(n,h),e=0,i=n.length;i>e;e++)l[e]=n[e][this._fieldId]}else for(s in r)r.hasOwnProperty(s)&&(o=this._getItem(s,d),a(o)&&l.push(o[this._fieldId]));else if(h){n=[];for(s in r)r.hasOwnProperty(s)&&n.push(r[s]);for(this._sort(n,h),e=0,i=n.length;i>e;e++)l[e]=n[e][this._fieldId]}else for(s in r)r.hasOwnProperty(s)&&(o=r[s],l.push(o[this._fieldId]));return l},s.prototype.getDataSet=function(){return this},s.prototype.forEach=function(t,e){var i,s,o=e&&e.filter,n=e&&e.type||this._options.type,r=this._data;if(e&&e.order)for(var a=this.get(e),h=0,d=a.length;d>h;h++)i=a[h],s=i[this._fieldId],t(i,s);else for(s in r)r.hasOwnProperty(s)&&(i=this._getItem(s,n),(!o||o(i))&&t(i,s))},s.prototype.map=function(t,e){var i,s=e&&e.filter,o=e&&e.type||this._options.type,n=[],r=this._data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,o),(!s||s(i))&&n.push(t(i,a)));return e&&e.order&&this._sort(n,e.order),n},s.prototype._filterFields=function(t,e){var i={};for(var s in t)t.hasOwnProperty(s)&&-1!=e.indexOf(s)&&(i[s]=t[s]);return i},s.prototype._sort=function(t,e){if(o.isString(e)){var i=e;t.sort(function(t,e){var s=t[i],o=e[i];return s>o?1:o>s?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},s.prototype.remove=function(t,e){var i,s,o,n=[];if(Array.isArray(t))for(i=0,s=t.length;s>i;i++)o=this._remove(t[i]),null!=o&&n.push(o);else o=this._remove(t),null!=o&&n.push(o);return n.length&&this._trigger("remove",{items:n},e),n},s.prototype._remove=function(t){if(o.isNumber(t)||o.isString(t)){if(this._data[t])return delete this._data[t],t}else if(t instanceof Object){var e=t[this._fieldId];if(e&&this._data[e])return delete this._data[e],e}return null},s.prototype.clear=function(t){var e=Object.keys(this._data);return this._data={},this._trigger("remove",{items:e},t),e},s.prototype.max=function(t){var e=this._data,i=null,s=null;for(var o in e)if(e.hasOwnProperty(o)){var n=e[o],r=n[t];null!=r&&(!i||r>s)&&(i=n,s=r)}return i},s.prototype.min=function(t){var e=this._data,i=null,s=null;for(var o in e)if(e.hasOwnProperty(o)){var n=e[o],r=n[t];null!=r&&(!i||s>r)&&(i=n,s=r)}return i},s.prototype.distinct=function(t){var e,i=this._data,s=[],n=this._options.type&&this._options.type[t]||null,r=0;for(var a in i)if(i.hasOwnProperty(a)){var h=i[a],d=h[t],l=!1;for(e=0;r>e;e++)if(s[e]==d){l=!0;break}l||void 0===d||(s[r]=d,r++)}if(n)for(e=0;ei;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},s.prototype._appendRow=function(t,e,i){for(var s=t.addRow(),o=0,n=e.length;n>o;o++){var r=e[o];t.setValue(s,o,i[r])}},t.exports=s},function(t,e,i){function s(t,e){this._data=null,this._ids={},this._options=e||{},this._fieldId="id",this._subscribers={};var i=this;this.listener=function(){i._onEvent.apply(i,arguments)},this.setData(t)}var o=i(1),n=i(3);s.prototype.setData=function(t){var e,i,s;if(this._data){this._data.unsubscribe&&this._data.unsubscribe("*",this.listener),e=[];for(var o in this._ids)this._ids.hasOwnProperty(o)&&e.push(o);this._ids={},this._trigger("remove",{items:e})}if(this._data=t,this._data){for(this._fieldId=this._options.fieldId||this._data&&this._data.options&&this._data.options.fieldId||"id",e=this._data.getIds({filter:this._options&&this._options.filter}),i=0,s=e.length;s>i;i++)o=e[i],this._ids[o]=!0;this._trigger("add",{items:e}),this._data.on&&this._data.on("*",this.listener)}},s.prototype.get=function(){var t,e,i,s=this,n=o.getType(arguments[0]);"String"==n||"Number"==n||"Array"==n?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var r=o.extend({},this._options,e);this._options.filter&&e&&e.filter&&(r.filter=function(t){return s._options.filter(t)&&e.filter(t)});var a=[];return void 0!=t&&a.push(t),a.push(r),a.push(i),this._data&&this._data.get.apply(this._data,a)},s.prototype.getIds=function(t){var e;if(this._data){var i,s=this._options.filter;i=t&&t.filter?s?function(e){return s(e)&&t.filter(e)}:t.filter:s,e=this._data.getIds({filter:i,order:t&&t.order})}else e=[];return e},s.prototype.getDataSet=function(){for(var t=this;t instanceof s;)t=t._data;return t||null},s.prototype._onEvent=function(t,e,i){var s,o,n,r,a=e&&e.items,h=this._data,d=[],l=[],c=[];if(a&&h){switch(t){case"add":for(s=0,o=a.length;o>s;s++)n=a[s],r=this.get(n),r&&(this._ids[n]=!0,d.push(n));break;case"update":for(s=0,o=a.length;o>s;s++)n=a[s],r=this.get(n),r?this._ids[n]?l.push(n):(this._ids[n]=!0,d.push(n)):this._ids[n]&&(delete this._ids[n],c.push(n));break;case"remove":for(s=0,o=a.length;o>s;s++)n=a[s],this._ids[n]&&(delete this._ids[n],c.push(n))}d.length&&this._trigger("add",{items:d},i),l.length&&this._trigger("update",{items:l},i),c.length&&this._trigger("remove",{items:c},i)}},s.prototype.on=n.prototype.on,s.prototype.off=n.prototype.off,s.prototype._trigger=n.prototype._trigger,s.prototype.subscribe=s.prototype.on,s.prototype.unsubscribe=s.prototype.off,t.exports=s},function(t){function e(t){this.delay=null,this.max=1/0,this._queue=[],this._timeout=null,this._extended=null,this.setOptions(t)}e.prototype.setOptions=function(t){t&&"undefined"!=typeof t.delay&&(this.delay=t.delay),t&&"undefined"!=typeof t.max&&(this.max=t.max),this._flushIfNeeded()},e.extend=function(t,i){var s=new e(i);if(void 0!==t.flush)throw new Error("Target object already has a property flush");t.flush=function(){s.flush()};var o=[{name:"flush",original:void 0}];if(i&&i.replace)for(var n=0;nthis.max&&this.flush(),clearTimeout(this._timeout),this.queue.length>0&&"number"==typeof this.delay){var t=this;this._timeout=setTimeout(function(){t.flush()},this.delay)}},e.prototype.flush=function(){for(;this._queue.length>0;){var t=this._queue.shift();t.fn.apply(t.context||t.fn,t.args||[])}},t.exports=e},function(t,e,i){function s(t,e,i){if(!(this instanceof s))throw new SyntaxError("Constructor must be called with the new operator");this.containerElement=t,this.width="400px",this.height="400px",this.margin=10,this.defaultXCenter="55%",this.defaultYCenter="50%",this.xLabel="x",this.yLabel="y",this.zLabel="z";var o=function(t){return t};this.xValueLabel=o,this.yValueLabel=o,this.zValueLabel=o,this.filterLabel="time",this.legendLabel="value",this.style=s.STYLE.DOT,this.showPerspective=!0,this.showGrid=!0,this.keepAspectRatio=!0,this.showShadow=!1,this.showGrayBottom=!1,this.showTooltip=!1,this.verticalRatio=.5,this.animationInterval=1e3,this.animationPreload=!1,this.camera=new p,this.eye=new l(0,0,-1),this.dataTable=null,this.dataPoints=null,this.colX=void 0,this.colY=void 0,this.colZ=void 0,this.colValue=void 0,this.colFilter=void 0,this.xMin=0,this.xStep=void 0,this.xMax=1,this.yMin=0,this.yStep=void 0,this.yMax=1,this.zMin=0,this.zStep=void 0,this.zMax=1,this.valueMin=0,this.valueMax=1,this.xBarWidth=1,this.yBarWidth=1,this.colorAxis="#4D4D4D",this.colorGrid="#D3D3D3",this.colorDot="#7DC1FF",this.colorDotBorder="#3267D2",this.create(),this.setOptions(i),e&&this.setData(e)}function o(t){return"clientX"in t?t.clientX:t.targetTouches[0]&&t.targetTouches[0].clientX||0}function n(t){return"clientY"in t?t.clientY:t.targetTouches[0]&&t.targetTouches[0].clientY||0}var r=i(56),a=i(3),h=i(4),d=i(1),l=i(10),c=i(9),p=i(7),u=i(8),m=i(11),f=i(12);r(s.prototype),s.prototype._setScale=function(){this.scale=new l(1/(this.xMax-this.xMin),1/(this.yMax-this.yMin),1/(this.zMax-this.zMin)),this.keepAspectRatio&&(this.scale.x3&&(this.colFilter=3);else{if(this.style!==s.STYLE.DOTCOLOR&&this.style!==s.STYLE.DOTSIZE&&this.style!==s.STYLE.BARCOLOR&&this.style!==s.STYLE.BARSIZE)throw'Unknown style "'+this.style+'"';this.colX=0,this.colY=1,this.colZ=2,this.colValue=3,t.getNumberOfColumns()>4&&(this.colFilter=4)}},s.prototype.getNumberOfRows=function(t){return t.length},s.prototype.getNumberOfColumns=function(t){var e=0;for(var i in t[0])t[0].hasOwnProperty(i)&&e++;return e},s.prototype.getDistinctValues=function(t,e){for(var i=[],s=0;st[s][e]&&(i.min=t[s][e]),i.maxt;t++){var m=(t-p)/(u-p),g=240*m,v=this._hsv2rgb(g,1,1);c.strokeStyle=v,c.beginPath(),c.moveTo(h,r+t),c.lineTo(a,r+t),c.stroke()}c.strokeStyle=this.colorAxis,c.strokeRect(h,r,i,n)}if(this.style===s.STYLE.DOTSIZE&&(c.strokeStyle=this.colorAxis,c.fillStyle=this.colorDot,c.beginPath(),c.moveTo(h,r),c.lineTo(a,r),c.lineTo(a-i+e,d),c.lineTo(h,d),c.closePath(),c.fill(),c.stroke()),this.style===s.STYLE.DOTCOLOR||this.style===s.STYLE.DOTSIZE){var y=5,b=new f(this.valueMin,this.valueMax,(this.valueMax-this.valueMin)/5,!0);for(b.start(),b.getCurrent()0?this.yMin:this.yMax,o=this._convert3Dto2D(new l(x,r,this.zMin)),Math.cos(2*_)>0?(g.textAlign="center",g.textBaseline="top",o.y+=b):Math.sin(2*_)<0?(g.textAlign="right",g.textBaseline="middle"):(g.textAlign="left",g.textBaseline="middle"),g.fillStyle=this.colorAxis,g.fillText(" "+this.xValueLabel(i.getCurrent())+" ",o.x,o.y),i.next()}for(g.lineWidth=1,s=void 0===this.defaultYStep,i=new f(this.yMin,this.yMax,this.yStep,s),i.start(),i.getCurrent()0?this.xMin:this.xMax,o=this._convert3Dto2D(new l(n,i.getCurrent(),this.zMin)),Math.cos(2*_)<0?(g.textAlign="center",g.textBaseline="top",o.y+=b):Math.sin(2*_)>0?(g.textAlign="right",g.textBaseline="middle"):(g.textAlign="left",g.textBaseline="middle"),g.fillStyle=this.colorAxis,g.fillText(" "+this.yValueLabel(i.getCurrent())+" ",o.x,o.y),i.next();for(g.lineWidth=1,s=void 0===this.defaultZStep,i=new f(this.zMin,this.zMax,this.zStep,s),i.start(),i.getCurrent()0?this.xMin:this.xMax,r=Math.sin(_)<0?this.yMin:this.yMax;!i.end();)t=this._convert3Dto2D(new l(n,r,i.getCurrent())),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(t.x,t.y),g.lineTo(t.x-b,t.y),g.stroke(),g.textAlign="right",g.textBaseline="middle",g.fillStyle=this.colorAxis,g.fillText(this.zValueLabel(i.getCurrent())+" ",t.x-5,t.y),i.next();g.lineWidth=1,t=this._convert3Dto2D(new l(n,r,this.zMin)),e=this._convert3Dto2D(new l(n,r,this.zMax)),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(t.x,t.y),g.lineTo(e.x,e.y),g.stroke(),g.lineWidth=1,p=this._convert3Dto2D(new l(this.xMin,this.yMin,this.zMin)),u=this._convert3Dto2D(new l(this.xMax,this.yMin,this.zMin)),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(p.x,p.y),g.lineTo(u.x,u.y),g.stroke(),p=this._convert3Dto2D(new l(this.xMin,this.yMax,this.zMin)),u=this._convert3Dto2D(new l(this.xMax,this.yMax,this.zMin)),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(p.x,p.y),g.lineTo(u.x,u.y),g.stroke(),g.lineWidth=1,t=this._convert3Dto2D(new l(this.xMin,this.yMin,this.zMin)),e=this._convert3Dto2D(new l(this.xMin,this.yMax,this.zMin)),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(t.x,t.y),g.lineTo(e.x,e.y),g.stroke(),t=this._convert3Dto2D(new l(this.xMax,this.yMin,this.zMin)),e=this._convert3Dto2D(new l(this.xMax,this.yMax,this.zMin)),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(t.x,t.y),g.lineTo(e.x,e.y),g.stroke();var w=this.xLabel;w.length>0&&(c=.1/this.scale.y,n=(this.xMin+this.xMax)/2,r=Math.cos(_)>0?this.yMin-c:this.yMax+c,o=this._convert3Dto2D(new l(n,r,this.zMin)),Math.cos(2*_)>0?(g.textAlign="center",g.textBaseline="top"):Math.sin(2*_)<0?(g.textAlign="right",g.textBaseline="middle"):(g.textAlign="left",g.textBaseline="middle"),g.fillStyle=this.colorAxis,g.fillText(w,o.x,o.y));var M=this.yLabel;M.length>0&&(d=.1/this.scale.x,n=Math.sin(_)>0?this.xMin-d:this.xMax+d,r=(this.yMin+this.yMax)/2,o=this._convert3Dto2D(new l(n,r,this.zMin)),Math.cos(2*_)<0?(g.textAlign="center",g.textBaseline="top"):Math.sin(2*_)>0?(g.textAlign="right",g.textBaseline="middle"):(g.textAlign="left",g.textBaseline="middle"),g.fillStyle=this.colorAxis,g.fillText(M,o.x,o.y));var S=this.zLabel;S.length>0&&(h=30,n=Math.cos(_)>0?this.xMin:this.xMax,r=Math.sin(_)<0?this.yMin:this.yMax,a=(this.zMin+this.zMax)/2,o=this._convert3Dto2D(new l(n,r,a)),g.textAlign="right",g.textBaseline="middle",g.fillStyle=this.colorAxis,g.fillText(S,o.x-h,o.y))},s.prototype._hsv2rgb=function(t,e,i){var s,o,n,r,a,h;switch(r=i*e,a=Math.floor(t/60),h=r*(1-Math.abs(t/60%2-1)),a){case 0:s=r,o=h,n=0;break;case 1:s=h,o=r,n=0;break;case 2:s=0,o=r,n=h;break;case 3:s=0,o=h,n=r;break;case 4:s=h,o=0,n=r;break;case 5:s=r,o=0,n=h;break;default:s=0,o=0,n=0}return"RGB("+parseInt(255*s)+","+parseInt(255*o)+","+parseInt(255*n)+")"},s.prototype._redrawDataGrid=function(){var t,e,i,o,n,r,a,h,d,c,p,u,m,f=this.frame.canvas,g=f.getContext("2d");if(!(void 0===this.dataPoints||this.dataPoints.length<=0)){for(n=0;n0}else r=!0;r?(m=(t.point.z+e.point.z+i.point.z+o.point.z)/4,c=240*(1-(m-this.zMin)*this.scale.z/this.verticalRatio),p=1,this.showShadow?(u=Math.min(1+M.x/S/2,1),a=this._hsv2rgb(c,p,u),h=a):(u=1,a=this._hsv2rgb(c,p,u),h=this.colorAxis)):(a="gray",h=this.colorAxis),d=.5,g.lineWidth=d,g.fillStyle=a,g.strokeStyle=h,g.beginPath(),g.moveTo(t.screen.x,t.screen.y),g.lineTo(e.screen.x,e.screen.y),g.lineTo(o.screen.x,o.screen.y),g.lineTo(i.screen.x,i.screen.y),g.closePath(),g.fill(),g.stroke()}}else for(n=0;np&&(p=0);var u,m,f;this.style===s.STYLE.DOTCOLOR?(u=240*(1-(d.point.value-this.valueMin)*this.scale.value),m=this._hsv2rgb(u,1,1),f=this._hsv2rgb(u,1,.8)):this.style===s.STYLE.DOTSIZE?(m=this.colorDot,f=this.colorDotBorder):(u=240*(1-(d.point.z-this.zMin)*this.scale.z/this.verticalRatio),m=this._hsv2rgb(u,1,1),f=this._hsv2rgb(u,1,.8)),i.lineWidth=1,i.strokeStyle=f,i.fillStyle=m,i.beginPath(),i.arc(d.screen.x,d.screen.y,p,0,2*Math.PI,!0),i.fill(),i.stroke()}}},s.prototype._redrawDataBar=function(){var t,e,i,o,n=this.frame.canvas,r=n.getContext("2d");if(!(void 0===this.dataPoints||this.dataPoints.length<=0)){for(t=0;t0&&(t=this.dataPoints[0],s.lineWidth=1,s.strokeStyle="blue",s.beginPath(),s.moveTo(t.screen.x,t.screen.y)),e=1;e0&&s.stroke()}},s.prototype._onMouseDown=function(t){if(t=t||window.event,this.leftButtonDown&&this._onMouseUp(t),this.leftButtonDown=t.which?1===t.which:1===t.button,this.leftButtonDown||this.touchDown){this.startMouseX=o(t),this.startMouseY=n(t),this.startStart=new Date(this.start),this.startEnd=new Date(this.end),this.startArmRotation=this.camera.getArmRotation(),this.frame.style.cursor="move";var e=this;this.onmousemove=function(t){e._onMouseMove(t)},this.onmouseup=function(t){e._onMouseUp(t)},d.addEventListener(document,"mousemove",e.onmousemove),d.addEventListener(document,"mouseup",e.onmouseup),d.preventDefault(t)}},s.prototype._onMouseMove=function(t){t=t||window.event;var e=parseFloat(o(t))-this.startMouseX,i=parseFloat(n(t))-this.startMouseY,s=this.startArmRotation.horizontal+e/200,r=this.startArmRotation.vertical+i/200,a=4,h=Math.sin(a/360*2*Math.PI);Math.abs(Math.sin(s))0?1:0>t?-1:0}var s=e[0],o=e[1],n=e[2],r=i((o.x-s.x)*(t.y-s.y)-(o.y-s.y)*(t.x-s.x)),a=i((n.x-o.x)*(t.y-o.y)-(n.y-o.y)*(t.x-o.x)),h=i((s.x-n.x)*(t.y-n.y)-(s.y-n.y)*(t.x-n.x));return!(0!=r&&0!=a&&r!=a||0!=a&&0!=h&&a!=h||0!=r&&0!=h&&r!=h)},s.prototype._dataPointFromXY=function(t,e){var i,o=100,n=null,r=null,a=null,h=new c(t,e);if(this.style===s.STYLE.BAR||this.style===s.STYLE.BARCOLOR||this.style===s.STYLE.BARSIZE)for(i=this.dataPoints.length-1;i>=0;i--){n=this.dataPoints[i];var d=n.surfaces;if(d)for(var l=d.length-1;l>=0;l--){var p=d[l],u=p.corners,m=[u[0].screen,u[1].screen,u[2].screen],f=[u[2].screen,u[3].screen,u[0].screen];if(this._insideTriangle(h,m)||this._insideTriangle(h,f))return n}}else for(i=0;ib)&&o>b&&(a=b,r=n)}}return r},s.prototype._showTooltip=function(t){var e,i,s;this.tooltip?(e=this.tooltip.dom.content,i=this.tooltip.dom.line,s=this.tooltip.dom.dot):(e=document.createElement("div"),e.style.position="absolute",e.style.padding="10px",e.style.border="1px solid #4d4d4d",e.style.color="#1a1a1a",e.style.background="rgba(255,255,255,0.7)",e.style.borderRadius="2px",e.style.boxShadow="5px 5px 10px rgba(128,128,128,0.5)",i=document.createElement("div"),i.style.position="absolute",i.style.height="40px",i.style.width="0",i.style.borderLeft="1px solid #4d4d4d",s=document.createElement("div"),s.style.position="absolute",s.style.height="0",s.style.width="0",s.style.border="5px solid #4d4d4d",s.style.borderRadius="5px",this.tooltip={dataPoint:null,dom:{content:e,line:i,dot:s}}),this._hideTooltip(),this.tooltip.dataPoint=t,e.innerHTML="function"==typeof this.showTooltip?this.showTooltip(t.point):"
x:"+t.point.x+"
y:"+t.point.y+"
z:"+t.point.z+"
",e.style.left="0",e.style.top="0",this.frame.appendChild(e),this.frame.appendChild(i),this.frame.appendChild(s);var o=e.offsetWidth,n=e.offsetHeight,r=i.offsetHeight,a=s.offsetWidth,h=s.offsetHeight,d=t.screen.x-o/2;d=Math.min(Math.max(d,10),this.frame.clientWidth-10-o),i.style.left=t.screen.x+"px",i.style.top=t.screen.y-r+"px",e.style.left=d+"px",e.style.top=t.screen.y-r-n+"px",s.style.left=t.screen.x-a/2+"px",s.style.top=t.screen.y-h/2+"px"},s.prototype._hideTooltip=function(){if(this.tooltip){this.tooltip.dataPoint=null;for(var t in this.tooltip.dom)if(this.tooltip.dom.hasOwnProperty(t)){var e=this.tooltip.dom[t];e&&e.parentNode&&e.parentNode.removeChild(e)}}},t.exports=s},function(t,e,i){function s(){this.armLocation=new o,this.armRotation={},this.armRotation.horizontal=0,this.armRotation.vertical=0,this.armLength=1.7,this.cameraLocation=new o,this.cameraRotation=new o(.5*Math.PI,0,0),this.calculateCameraOrientation()}var o=i(10);s.prototype.setArmLocation=function(t,e,i){this.armLocation.x=t,this.armLocation.y=e,this.armLocation.z=i,this.calculateCameraOrientation()},s.prototype.setArmRotation=function(t,e){void 0!==t&&(this.armRotation.horizontal=t),void 0!==e&&(this.armRotation.vertical=e,this.armRotation.vertical<0&&(this.armRotation.vertical=0),this.armRotation.vertical>.5*Math.PI&&(this.armRotation.vertical=.5*Math.PI)),(void 0!==t||void 0!==e)&&this.calculateCameraOrientation()},s.prototype.getArmRotation=function(){var t={};return t.horizontal=this.armRotation.horizontal,t.vertical=this.armRotation.vertical,t},s.prototype.setArmLength=function(t){void 0!==t&&(this.armLength=t,this.armLength<.71&&(this.armLength=.71),this.armLength>5&&(this.armLength=5),this.calculateCameraOrientation())},s.prototype.getArmLength=function(){return this.armLength},s.prototype.getCameraLocation=function(){return this.cameraLocation},s.prototype.getCameraRotation=function(){return this.cameraRotation},s.prototype.calculateCameraOrientation=function(){this.cameraLocation.x=this.armLocation.x-this.armLength*Math.sin(this.armRotation.horizontal)*Math.cos(this.armRotation.vertical),this.cameraLocation.y=this.armLocation.y-this.armLength*Math.cos(this.armRotation.horizontal)*Math.cos(this.armRotation.vertical),this.cameraLocation.z=this.armLocation.z+this.armLength*Math.sin(this.armRotation.vertical),this.cameraRotation.x=Math.PI/2-this.armRotation.vertical,this.cameraRotation.y=0,this.cameraRotation.z=-this.armRotation.horizontal},t.exports=s},function(t,e,i){function s(t,e,i){this.data=t,this.column=e,this.graph=i,this.index=void 0,this.value=void 0,this.values=i.getDistinctValues(t.get(),this.column),this.values.sort(function(t,e){return t>e?1:e>t?-1:0}),this.values.length>0&&this.selectValue(0),this.dataPoints=[],this.loaded=!1,this.onLoadCallback=void 0,i.animationPreload?(this.loaded=!1,this.loadInBackground()):this.loaded=!0}var o=i(4);s.prototype.isLoaded=function(){return this.loaded},s.prototype.getLoadedProgress=function(){for(var t=this.values.length,e=0;this.dataPoints[e];)e++;return Math.round(e/t*100)},s.prototype.getLabel=function(){return this.graph.filterLabel},s.prototype.getColumn=function(){return this.column},s.prototype.getSelectedValue=function(){return void 0===this.index?void 0:this.values[this.index]},s.prototype.getValues=function(){return this.values},s.prototype.getValue=function(t){if(t>=this.values.length)throw"Error: index out of range";return this.values[t]},s.prototype._getDataPoints=function(t){if(void 0===t&&(t=this.index),void 0===t)return[];var e;if(this.dataPoints[t])e=this.dataPoints[t];else{var i={};i.column=this.column,i.value=this.values[t];var s=new o(this.data,{filter:function(t){return t[i.column]==i.value}}).get();e=this.graph._getDataPoints(s),this.dataPoints[t]=e}return e},s.prototype.setOnLoadCallback=function(t){this.onLoadCallback=t},s.prototype.selectValue=function(t){if(t>=this.values.length)throw"Error: index out of range";this.index=t,this.value=this.values[t]},s.prototype.loadInBackground=function(t){void 0===t&&(t=0);var e=this.graph.frame;if(tt;t++){var m=(t-p)/(u-p),g=240*m,v=this._hsv2rgb(g,1,1);c.strokeStyle=v,c.beginPath(),c.moveTo(h,r+t),c.lineTo(a,r+t),c.stroke()}c.strokeStyle=this.colorAxis,c.strokeRect(h,r,i,n)}if(this.style===s.STYLE.DOTSIZE&&(c.strokeStyle=this.colorAxis,c.fillStyle=this.colorDot,c.beginPath(),c.moveTo(h,r),c.lineTo(a,r),c.lineTo(a-i+e,d),c.lineTo(h,d),c.closePath(),c.fill(),c.stroke()),this.style===s.STYLE.DOTCOLOR||this.style===s.STYLE.DOTSIZE){var y=5,b=new f(this.valueMin,this.valueMax,(this.valueMax-this.valueMin)/5,!0);for(b.start(),b.getCurrent()0?this.yMin:this.yMax,o=this._convert3Dto2D(new l(x,r,this.zMin)),Math.cos(2*_)>0?(g.textAlign="center",g.textBaseline="top",o.y+=b):Math.sin(2*_)<0?(g.textAlign="right",g.textBaseline="middle"):(g.textAlign="left",g.textBaseline="middle"),g.fillStyle=this.colorAxis,g.fillText(" "+this.xValueLabel(i.getCurrent())+" ",o.x,o.y),i.next()}for(g.lineWidth=1,s=void 0===this.defaultYStep,i=new f(this.yMin,this.yMax,this.yStep,s),i.start(),i.getCurrent()0?this.xMin:this.xMax,o=this._convert3Dto2D(new l(n,i.getCurrent(),this.zMin)),Math.cos(2*_)<0?(g.textAlign="center",g.textBaseline="top",o.y+=b):Math.sin(2*_)>0?(g.textAlign="right",g.textBaseline="middle"):(g.textAlign="left",g.textBaseline="middle"),g.fillStyle=this.colorAxis,g.fillText(" "+this.yValueLabel(i.getCurrent())+" ",o.x,o.y),i.next();for(g.lineWidth=1,s=void 0===this.defaultZStep,i=new f(this.zMin,this.zMax,this.zStep,s),i.start(),i.getCurrent()0?this.xMin:this.xMax,r=Math.sin(_)<0?this.yMin:this.yMax;!i.end();)t=this._convert3Dto2D(new l(n,r,i.getCurrent())),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(t.x,t.y),g.lineTo(t.x-b,t.y),g.stroke(),g.textAlign="right",g.textBaseline="middle",g.fillStyle=this.colorAxis,g.fillText(this.zValueLabel(i.getCurrent())+" ",t.x-5,t.y),i.next();g.lineWidth=1,t=this._convert3Dto2D(new l(n,r,this.zMin)),e=this._convert3Dto2D(new l(n,r,this.zMax)),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(t.x,t.y),g.lineTo(e.x,e.y),g.stroke(),g.lineWidth=1,p=this._convert3Dto2D(new l(this.xMin,this.yMin,this.zMin)),u=this._convert3Dto2D(new l(this.xMax,this.yMin,this.zMin)),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(p.x,p.y),g.lineTo(u.x,u.y),g.stroke(),p=this._convert3Dto2D(new l(this.xMin,this.yMax,this.zMin)),u=this._convert3Dto2D(new l(this.xMax,this.yMax,this.zMin)),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(p.x,p.y),g.lineTo(u.x,u.y),g.stroke(),g.lineWidth=1,t=this._convert3Dto2D(new l(this.xMin,this.yMin,this.zMin)),e=this._convert3Dto2D(new l(this.xMin,this.yMax,this.zMin)),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(t.x,t.y),g.lineTo(e.x,e.y),g.stroke(),t=this._convert3Dto2D(new l(this.xMax,this.yMin,this.zMin)),e=this._convert3Dto2D(new l(this.xMax,this.yMax,this.zMin)),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(t.x,t.y),g.lineTo(e.x,e.y),g.stroke();var w=this.xLabel;w.length>0&&(c=.1/this.scale.y,n=(this.xMin+this.xMax)/2,r=Math.cos(_)>0?this.yMin-c:this.yMax+c,o=this._convert3Dto2D(new l(n,r,this.zMin)),Math.cos(2*_)>0?(g.textAlign="center",g.textBaseline="top"):Math.sin(2*_)<0?(g.textAlign="right",g.textBaseline="middle"):(g.textAlign="left",g.textBaseline="middle"),g.fillStyle=this.colorAxis,g.fillText(w,o.x,o.y));var S=this.yLabel;S.length>0&&(d=.1/this.scale.x,n=Math.sin(_)>0?this.xMin-d:this.xMax+d,r=(this.yMin+this.yMax)/2,o=this._convert3Dto2D(new l(n,r,this.zMin)),Math.cos(2*_)<0?(g.textAlign="center",g.textBaseline="top"):Math.sin(2*_)>0?(g.textAlign="right",g.textBaseline="middle"):(g.textAlign="left",g.textBaseline="middle"),g.fillStyle=this.colorAxis,g.fillText(S,o.x,o.y));var M=this.zLabel;M.length>0&&(h=30,n=Math.cos(_)>0?this.xMin:this.xMax,r=Math.sin(_)<0?this.yMin:this.yMax,a=(this.zMin+this.zMax)/2,o=this._convert3Dto2D(new l(n,r,a)),g.textAlign="right",g.textBaseline="middle",g.fillStyle=this.colorAxis,g.fillText(M,o.x-h,o.y))},s.prototype._hsv2rgb=function(t,e,i){var s,o,n,r,a,h;switch(r=i*e,a=Math.floor(t/60),h=r*(1-Math.abs(t/60%2-1)),a){case 0:s=r,o=h,n=0;break;case 1:s=h,o=r,n=0;break;case 2:s=0,o=r,n=h;break;case 3:s=0,o=h,n=r;break;case 4:s=h,o=0,n=r;break;case 5:s=r,o=0,n=h;break;default:s=0,o=0,n=0}return"RGB("+parseInt(255*s)+","+parseInt(255*o)+","+parseInt(255*n)+")"},s.prototype._redrawDataGrid=function(){var t,e,i,o,n,r,a,h,d,c,p,u,m,f=this.frame.canvas,g=f.getContext("2d");if(!(void 0===this.dataPoints||this.dataPoints.length<=0)){for(n=0;n0}else r=!0;r?(m=(t.point.z+e.point.z+i.point.z+o.point.z)/4,c=240*(1-(m-this.zMin)*this.scale.z/this.verticalRatio),p=1,this.showShadow?(u=Math.min(1+S.x/M/2,1),a=this._hsv2rgb(c,p,u),h=a):(u=1,a=this._hsv2rgb(c,p,u),h=this.colorAxis)):(a="gray",h=this.colorAxis),d=.5,g.lineWidth=d,g.fillStyle=a,g.strokeStyle=h,g.beginPath(),g.moveTo(t.screen.x,t.screen.y),g.lineTo(e.screen.x,e.screen.y),g.lineTo(o.screen.x,o.screen.y),g.lineTo(i.screen.x,i.screen.y),g.closePath(),g.fill(),g.stroke()}}else for(n=0;np&&(p=0);var u,m,f;this.style===s.STYLE.DOTCOLOR?(u=240*(1-(d.point.value-this.valueMin)*this.scale.value),m=this._hsv2rgb(u,1,1),f=this._hsv2rgb(u,1,.8)):this.style===s.STYLE.DOTSIZE?(m=this.colorDot,f=this.colorDotBorder):(u=240*(1-(d.point.z-this.zMin)*this.scale.z/this.verticalRatio),m=this._hsv2rgb(u,1,1),f=this._hsv2rgb(u,1,.8)),i.lineWidth=1,i.strokeStyle=f,i.fillStyle=m,i.beginPath(),i.arc(d.screen.x,d.screen.y,p,0,2*Math.PI,!0),i.fill(),i.stroke()}}},s.prototype._redrawDataBar=function(){var t,e,i,o,n=this.frame.canvas,r=n.getContext("2d");if(!(void 0===this.dataPoints||this.dataPoints.length<=0)){for(t=0;t0&&(t=this.dataPoints[0],s.lineWidth=1,s.strokeStyle="blue",s.beginPath(),s.moveTo(t.screen.x,t.screen.y)),e=1;e0&&s.stroke()}},s.prototype._onMouseDown=function(t){if(t=t||window.event,this.leftButtonDown&&this._onMouseUp(t),this.leftButtonDown=t.which?1===t.which:1===t.button,this.leftButtonDown||this.touchDown){this.startMouseX=o(t),this.startMouseY=n(t),this.startStart=new Date(this.start),this.startEnd=new Date(this.end),this.startArmRotation=this.camera.getArmRotation(),this.frame.style.cursor="move";var e=this;this.onmousemove=function(t){e._onMouseMove(t)},this.onmouseup=function(t){e._onMouseUp(t)},d.addEventListener(document,"mousemove",e.onmousemove),d.addEventListener(document,"mouseup",e.onmouseup),d.preventDefault(t)}},s.prototype._onMouseMove=function(t){t=t||window.event;var e=parseFloat(o(t))-this.startMouseX,i=parseFloat(n(t))-this.startMouseY,s=this.startArmRotation.horizontal+e/200,r=this.startArmRotation.vertical+i/200,a=4,h=Math.sin(a/360*2*Math.PI);Math.abs(Math.sin(s))0?1:0>t?-1:0}var s=e[0],o=e[1],n=e[2],r=i((o.x-s.x)*(t.y-s.y)-(o.y-s.y)*(t.x-s.x)),a=i((n.x-o.x)*(t.y-o.y)-(n.y-o.y)*(t.x-o.x)),h=i((s.x-n.x)*(t.y-n.y)-(s.y-n.y)*(t.x-n.x));return!(0!=r&&0!=a&&r!=a||0!=a&&0!=h&&a!=h||0!=r&&0!=h&&r!=h)},s.prototype._dataPointFromXY=function(t,e){var i,o=100,n=null,r=null,a=null,h=new c(t,e);if(this.style===s.STYLE.BAR||this.style===s.STYLE.BARCOLOR||this.style===s.STYLE.BARSIZE)for(i=this.dataPoints.length-1;i>=0;i--){n=this.dataPoints[i];var d=n.surfaces;if(d)for(var l=d.length-1;l>=0;l--){var p=d[l],u=p.corners,m=[u[0].screen,u[1].screen,u[2].screen],f=[u[2].screen,u[3].screen,u[0].screen];if(this._insideTriangle(h,m)||this._insideTriangle(h,f))return n}}else for(i=0;ib)&&o>b&&(a=b,r=n)}}return r},s.prototype._showTooltip=function(t){var e,i,s;this.tooltip?(e=this.tooltip.dom.content,i=this.tooltip.dom.line,s=this.tooltip.dom.dot):(e=document.createElement("div"),e.style.position="absolute",e.style.padding="10px",e.style.border="1px solid #4d4d4d",e.style.color="#1a1a1a",e.style.background="rgba(255,255,255,0.7)",e.style.borderRadius="2px",e.style.boxShadow="5px 5px 10px rgba(128,128,128,0.5)",i=document.createElement("div"),i.style.position="absolute",i.style.height="40px",i.style.width="0",i.style.borderLeft="1px solid #4d4d4d",s=document.createElement("div"),s.style.position="absolute",s.style.height="0",s.style.width="0",s.style.border="5px solid #4d4d4d",s.style.borderRadius="5px",this.tooltip={dataPoint:null,dom:{content:e,line:i,dot:s}}),this._hideTooltip(),this.tooltip.dataPoint=t,e.innerHTML="function"==typeof this.showTooltip?this.showTooltip(t.point):"
x:"+t.point.x+"
y:"+t.point.y+"
z:"+t.point.z+"
",e.style.left="0",e.style.top="0",this.frame.appendChild(e),this.frame.appendChild(i),this.frame.appendChild(s);var o=e.offsetWidth,n=e.offsetHeight,r=i.offsetHeight,a=s.offsetWidth,h=s.offsetHeight,d=t.screen.x-o/2;d=Math.min(Math.max(d,10),this.frame.clientWidth-10-o),i.style.left=t.screen.x+"px",i.style.top=t.screen.y-r+"px",e.style.left=d+"px",e.style.top=t.screen.y-r-n+"px",s.style.left=t.screen.x-a/2+"px",s.style.top=t.screen.y-h/2+"px"},s.prototype._hideTooltip=function(){if(this.tooltip){this.tooltip.dataPoint=null;for(var t in this.tooltip.dom)if(this.tooltip.dom.hasOwnProperty(t)){var e=this.tooltip.dom[t];e&&e.parentNode&&e.parentNode.removeChild(e)}}},t.exports=s},function(t,e,i){function s(){this.armLocation=new o,this.armRotation={},this.armRotation.horizontal=0,this.armRotation.vertical=0,this.armLength=1.7,this.cameraLocation=new o,this.cameraRotation=new o(.5*Math.PI,0,0),this.calculateCameraOrientation()}var o=i(10);s.prototype.setArmLocation=function(t,e,i){this.armLocation.x=t,this.armLocation.y=e,this.armLocation.z=i,this.calculateCameraOrientation()},s.prototype.setArmRotation=function(t,e){void 0!==t&&(this.armRotation.horizontal=t),void 0!==e&&(this.armRotation.vertical=e,this.armRotation.vertical<0&&(this.armRotation.vertical=0),this.armRotation.vertical>.5*Math.PI&&(this.armRotation.vertical=.5*Math.PI)),(void 0!==t||void 0!==e)&&this.calculateCameraOrientation()},s.prototype.getArmRotation=function(){var t={};return t.horizontal=this.armRotation.horizontal,t.vertical=this.armRotation.vertical,t},s.prototype.setArmLength=function(t){void 0!==t&&(this.armLength=t,this.armLength<.71&&(this.armLength=.71),this.armLength>5&&(this.armLength=5),this.calculateCameraOrientation())},s.prototype.getArmLength=function(){return this.armLength},s.prototype.getCameraLocation=function(){return this.cameraLocation},s.prototype.getCameraRotation=function(){return this.cameraRotation},s.prototype.calculateCameraOrientation=function(){this.cameraLocation.x=this.armLocation.x-this.armLength*Math.sin(this.armRotation.horizontal)*Math.cos(this.armRotation.vertical),this.cameraLocation.y=this.armLocation.y-this.armLength*Math.cos(this.armRotation.horizontal)*Math.cos(this.armRotation.vertical),this.cameraLocation.z=this.armLocation.z+this.armLength*Math.sin(this.armRotation.vertical),this.cameraRotation.x=Math.PI/2-this.armRotation.vertical,this.cameraRotation.y=0,this.cameraRotation.z=-this.armRotation.horizontal},t.exports=s},function(t,e,i){function s(t,e,i){this.data=t,this.column=e,this.graph=i,this.index=void 0,this.value=void 0,this.values=i.getDistinctValues(t.get(),this.column),this.values.sort(function(t,e){return t>e?1:e>t?-1:0}),this.values.length>0&&this.selectValue(0),this.dataPoints=[],this.loaded=!1,this.onLoadCallback=void 0,i.animationPreload?(this.loaded=!1,this.loadInBackground()):this.loaded=!0}var o=i(4);s.prototype.isLoaded=function(){return this.loaded},s.prototype.getLoadedProgress=function(){for(var t=this.values.length,e=0;this.dataPoints[e];)e++;return Math.round(e/t*100)},s.prototype.getLabel=function(){return this.graph.filterLabel},s.prototype.getColumn=function(){return this.column},s.prototype.getSelectedValue=function(){return void 0===this.index?void 0:this.values[this.index]},s.prototype.getValues=function(){return this.values},s.prototype.getValue=function(t){if(t>=this.values.length)throw"Error: index out of range";return this.values[t]},s.prototype._getDataPoints=function(t){if(void 0===t&&(t=this.index),void 0===t)return[];var e;if(this.dataPoints[t])e=this.dataPoints[t];else{var i={};i.column=this.column,i.value=this.values[t];var s=new o(this.data,{filter:function(t){return t[i.column]==i.value}}).get();e=this.graph._getDataPoints(s),this.dataPoints[t]=e}return e},s.prototype.setOnLoadCallback=function(t){this.onLoadCallback=t},s.prototype.selectValue=function(t){if(t>=this.values.length)throw"Error: index out of range";this.index=t,this.value=this.values[t]},s.prototype.loadInBackground=function(t){void 0===t&&(t=0);var e=this.graph.frame;if(t0&&(t--,this.setIndex(t))},s.prototype.next=function(){var t=this.getIndex();t0?this.setIndex(0):this.index=void 0},s.prototype.setIndex=function(t){if(!(ts&&(s=0),s>this.values.length-1&&(s=this.values.length-1),s},s.prototype.indexToLeft=function(t){var e=parseFloat(this.frame.bar.style.width)-this.frame.slide.clientWidth-10,i=t/(this.values.length-1)*e,s=i+3;return s},s.prototype._onMouseMove=function(t){var e=t.clientX-this.startClientX,i=this.startSlideX+e,s=this.leftToIndex(i);this.setIndex(s),o.preventDefault()},s.prototype._onMouseUp=function(){this.frame.style.cursor="auto",o.removeEventListener(document,"mousemove",this.onmousemove),o.removeEventListener(document,"mouseup",this.onmouseup),o.preventDefault()},t.exports=s},function(t){function e(t,e,i,s){this._start=0,this._end=0,this._step=1,this.prettyStep=!0,this.precision=5,this._current=0,this.setRange(t,e,i,s)}e.prototype.setRange=function(t,e,i,s){this._start=t?t:0,this._end=e?e:0,this.setStep(i,s)},e.prototype.setStep=function(t,i){void 0===t||0>=t||(void 0!==i&&(this.prettyStep=i),this._step=this.prettyStep===!0?e.calculatePrettyStep(t):t)},e.calculatePrettyStep=function(t){var e=function(t){return Math.log(t)/Math.LN10},i=Math.pow(10,Math.round(e(t))),s=2*Math.pow(10,Math.round(e(t/2))),o=5*Math.pow(10,Math.round(e(t/5))),n=i;return Math.abs(s-t)<=Math.abs(n-t)&&(n=s),Math.abs(o-t)<=Math.abs(n-t)&&(n=o),0>=n&&(n=1),n},e.prototype.getCurrent=function(){return parseFloat(this._current.toPrecision(this.precision))},e.prototype.getStep=function(){return this._step},e.prototype.start=function(){this._current=this._start-this._start%this._step},e.prototype.next=function(){this._current+=this._step},e.prototype.end=function(){return this._current>this._end},t.exports=e},function(t,e,i){function s(t,e,i,r){if(!(this instanceof s))throw new SyntaxError("Constructor must be called with the new operator");if(!(Array.isArray(i)||i instanceof n)&&i instanceof Object){var h=r;r=i,i=h}var u=this;this.defaultOptions={start:null,end:null,autoResize:!0,orientation:"bottom",width:null,height:null,maxHeight:null,minHeight:null},this.options=o.deepExtend({},this.defaultOptions),this._create(t),this.components=[],this.body={dom:this.dom,domProps:this.props,emitter:{on:this.on.bind(this),off:this.off.bind(this),emit:this.emit.bind(this)},hiddenDates:[],util:{snap:null,toScreen:u._toScreen.bind(u),toGlobalScreen:u._toGlobalScreen.bind(u),toTime:u._toTime.bind(u),toGlobalTime:u._toGlobalTime.bind(u)}},this.range=new a(this.body),this.components.push(this.range),this.body.range=this.range,this.timeAxis=new d(this.body),this.components.push(this.timeAxis),this.body.util.snap=this.timeAxis.snap.bind(this.timeAxis),this.currentTime=new l(this.body),this.components.push(this.currentTime),this.customTime=new c(this.body),this.components.push(this.customTime),this.itemSet=new p(this.body),this.components.push(this.itemSet),this.itemsData=null,this.groupsData=null,r&&this.setOptions(r),i&&this.setGroups(i),e?this.setItems(e):this.redraw()}var o=(i(56),i(45),i(1)),n=i(3),r=i(4),a=i(17),h=i(46),d=i(30),l=i(21),c=i(22),p=i(27);s.prototype=new h,s.prototype.setItems=function(t){var e,i=null==this.itemsData;if(e=t?t instanceof n||t instanceof r?t:new n(t,{type:{start:"Date",end:"Date"}}):null,this.itemsData=e,this.itemSet&&this.itemSet.setItems(e),i)if(void 0!=this.options.start||void 0!=this.options.end){if(void 0==this.options.start||void 0==this.options.end)var s=this._getDataRange();var o=void 0!=this.options.start?this.options.start:s.start,a=void 0!=this.options.end?this.options.end:s.end;this.setWindow(o,a,{animate:!1})}else this.fit({animate:!1})},s.prototype.setGroups=function(t){var e;e=t?t instanceof n||t instanceof r?t:new n(t):null,this.groupsData=e,this.itemSet.setGroups(e)},s.prototype.setSelection=function(t,e){this.itemSet&&this.itemSet.setSelection(t),e&&e.focus&&this.focus(t,e)},s.prototype.getSelection=function(){return this.itemSet&&this.itemSet.getSelection()||[]},s.prototype.focus=function(t,e){if(this.itemsData&&void 0!=t){var i=Array.isArray(t)?t:[t],s=this.itemsData.getDataSet().get(i,{type:{start:"Date",end:"Date"}}),o=null,n=null;if(s.forEach(function(t){var e=t.start.valueOf(),i="end"in t?t.end.valueOf():t.start.valueOf();(null===o||o>e)&&(o=e),(null===n||i>n)&&(n=i)}),null!==o&&null!==n){var r=(o+n)/2,a=Math.max(this.range.end-this.range.start,1.1*(n-o)),h=e&&void 0!==e.animate?e.animate:!0;this.range.setRange(r-a/2,r+a/2,h)}}},s.prototype.getItemRange=function(){var t=this.itemsData.getDataSet(),e=null,i=null;if(t){var s=t.min("start");e=s?o.convert(s.start,"Date").valueOf():null;var n=t.max("start");n&&(i=o.convert(n.start,"Date").valueOf());var r=t.max("end");r&&(i=null==i?o.convert(r.end,"Date").valueOf():Math.max(i,o.convert(r.end,"Date").valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},t.exports=s},function(t,e,i){function s(t,e,i,s){if(!(Array.isArray(i)||i instanceof n)&&i instanceof Object){var r=s;s=i,i=r}var h=this;this.defaultOptions={start:null,end:null,autoResize:!0,orientation:"bottom",width:null,height:null,maxHeight:null,minHeight:null},this.options=o.deepExtend({},this.defaultOptions),this._create(t),this.components=[],this.body={dom:this.dom,domProps:this.props,emitter:{on:this.on.bind(this),off:this.off.bind(this),emit:this.emit.bind(this)},hiddenDates:[],util:{snap:null,toScreen:h._toScreen.bind(h),toGlobalScreen:h._toGlobalScreen.bind(h),toTime:h._toTime.bind(h),toGlobalTime:h._toGlobalTime.bind(h)}},this.range=new a(this.body),this.components.push(this.range),this.body.range=this.range,this.timeAxis=new d(this.body),this.components.push(this.timeAxis),this.body.util.snap=this.timeAxis.snap.bind(this.timeAxis),this.currentTime=new l(this.body),this.components.push(this.currentTime),this.customTime=new c(this.body),this.components.push(this.customTime),this.linegraph=new p(this.body),this.components.push(this.linegraph),this.itemsData=null,this.groupsData=null,s&&this.setOptions(s),i&&this.setGroups(i),e?this.setItems(e):this.redraw()}var o=(i(56),i(45),i(1)),n=i(3),r=i(4),a=i(17),h=i(46),d=i(30),l=i(21),c=i(22),p=i(29);s.prototype=new h,s.prototype.setItems=function(t){var e,i=null==this.itemsData;if(e=t?t instanceof n||t instanceof r?t:new n(t,{type:{start:"Date",end:"Date"}}):null,this.itemsData=e,this.linegraph&&this.linegraph.setItems(e),i)if(void 0!=this.options.start||void 0!=this.options.end){var s=void 0!=this.options.start?this.options.start:null,o=void 0!=this.options.end?this.options.end:null;this.setWindow(s,o,{animate:!1})}else this.fit({animate:!1})},s.prototype.setGroups=function(t){var e;e=t?t instanceof n||t instanceof r?t:new n(t):null,this.groupsData=e,this.linegraph.setGroups(e)},s.prototype.getLegend=function(t,e,i){return void 0===e&&(e=15),void 0===i&&(i=15),void 0!==this.linegraph.groups[t]?this.linegraph.groups[t].getLegend(e,i):"cannot find group:"+t},s.prototype.isGroupVisible=function(t){return void 0!==this.linegraph.groups[t]?this.linegraph.groups[t].visible&&(void 0===this.linegraph.options.groups.visibility[t]||1==this.linegraph.options.groups.visibility[t]):!1},s.prototype.getItemRange=function(){var t=null,e=null;for(var i in this.linegraph.groups)if(this.linegraph.groups.hasOwnProperty(i)&&1==this.linegraph.groups[i].visible)for(var s=0;sr?r:t,e=null==e?r:r>e?r:e}return{min:null!=t?new Date(t):null,max:null!=e?new Date(e):null}},t.exports=s},function(t,e,i){var s=i(44);e.convertHiddenOptions=function(t,e){if(t.hiddenDates=[],e&&1==Array.isArray(e)){for(var i=0;i=4*a){var p=0,u=n.clone();switch(i[h].repeat){case"daily":d.day()!=l.day()&&(p=1),d.dayOfYear(o.dayOfYear()),d.year(o.year()),d.subtract(7,"days"),l.dayOfYear(o.dayOfYear()),l.year(o.year()),l.subtract(7-p,"days"),u.add(1,"weeks");break;case"weekly":var m=l.diff(d,"days"),f=d.day();d.date(o.date()),d.month(o.month()),d.year(o.year()),l=d.clone(),d.day(f),l.day(f),l.add(m,"days"),d.subtract(1,"weeks"),l.subtract(1,"weeks"),u.add(1,"weeks");break;case"monthly":d.month()!=l.month()&&(p=1),d.month(o.month()),d.year(o.year()),d.subtract(1,"months"),l.month(o.month()),l.year(o.year()),l.subtract(1,"months"),l.add(p,"months"),u.add(1,"months");break;case"yearly":d.year()!=l.year()&&(p=1),d.year(o.year()),d.subtract(1,"years"),l.year(o.year()),l.subtract(1,"years"),l.add(p,"years"),u.add(1,"years");break;default:return void console.log("Wrong repeat format, allowed are: daily, weekly, monthly, yearly. Given:",i[h].repeat)}for(;u>d;)switch(t.hiddenDates.push({start:d.valueOf(),end:l.valueOf()}),i[h].repeat){case"daily":d.add(1,"days"),l.add(1,"days");break;case"weekly":d.add(1,"weeks"),l.add(1,"weeks");break;case"monthly":d.add(1,"months"),l.add(1,"months");break;case"yearly":d.add(1,"y"),l.add(1,"y");break;default:return void console.log("Wrong repeat format, allowed are: daily, weekly, monthly, yearly. Given:",i[h].repeat)}t.hiddenDates.push({start:d.valueOf(),end:l.valueOf()})}}e.removeDuplicates(t);var g=e.isHidden(t.range.start,t.hiddenDates),v=e.isHidden(t.range.end,t.hiddenDates),y=t.range.start,b=t.range.end;1==g.hidden&&(y=1==t.range.startToFront?g.startDate-1:g.endDate+1),1==v.hidden&&(b=1==t.range.endToFront?v.startDate-1:v.endDate+1),(1==g.hidden||1==v.hidden)&&t.range._applyRange(y,b)}},e.removeDuplicates=function(t){for(var e=t.hiddenDates,i=[],s=0;s=e[s].start&&e[o].end<=e[s].end?e[o].remove=!0:e[o].start>=e[s].start&&e[o].start<=e[s].end?(e[s].end=e[o].end,e[o].remove=!0):e[o].end>=e[s].start&&e[o].end<=e[s].end&&(e[s].start=e[o].start,e[o].remove=!0));for(var s=0;s=r&&a>o){i=!0;break}}if(1==i&&o=e&&i>r&&(s+=r-n)}return s},e.correctTimeForHidden=function(t,i,o){return o=s(o).toDate().valueOf(),o-=e.getHiddenDurationBefore(t,i,o)},e.getHiddenDurationBefore=function(t,e,i){var o=0;i=s(i).toDate().valueOf();for(var n=0;n=e.start&&a=a&&(o+=a-r)}return o},e.getAccumulatedHiddenDuration=function(t,e,i){for(var s=0,o=0,n=e.start,r=0;r=e.start&&h=i)break;s+=h-a}}return s},e.snapAwayFromHidden=function(t,i,s,o){var n=e.isHidden(i,t);return 1==n.hidden?0>s?1==o?n.startDate-(n.endDate-i)-1:n.startDate-1:1==o?n.endDate+(i-n.startDate)+1:n.endDate+1:i},e.isHidden=function(t,e){for(var i=0;i=s&&o>t)return{hidden:!0,startDate:s,endDate:o}}return{hidden:!1,startDate:s,endDate:o}}},function(t){function e(t,e,i,s,o,n){this.current=0,this.autoScale=!0,this.stepIndex=0,this.step=1,this.scale=1,this.marginStart,this.marginEnd,this.deadSpace=0,this.majorSteps=[1,2,5,10],this.minorSteps=[.25,.5,1,2],this.alignZeros=n,this.setRange(t,e,i,s,o)}e.prototype.setRange=function(t,e,i,s,o){this._start=void 0===o.min?t:o.min,this._end=void 0===o.max?e:o.max,this._start==this._end&&(this._start-=.75,this._end+=1),1==this.autoScale&&this.setMinimumStep(i,s),this.setFirst(o)},e.prototype.setMinimumStep=function(t,e){var i=this._end-this._start,s=1.2*i,o=t*(s/e),n=Math.round(Math.log(s)/Math.LN10),r=-1,a=Math.pow(10,n),h=0;0>n&&(h=n);for(var d=!1,l=h;Math.abs(l)<=Math.abs(n);l++){a=Math.pow(10,l);for(var c=0;c=o){d=!0,r=c;break}}if(1==d)break}this.stepIndex=r,this.scale=a,this.step=a*this.minorSteps[r]},e.prototype.setFirst=function(t){void 0===t&&(t={});var e=void 0===t.min?this._start-2*this.scale*this.minorSteps[this.stepIndex]:t.min,i=void 0===t.max?this._end+this.scale*this.minorSteps[this.stepIndex]:t.max;this.marginEnd=void 0===t.max?this.roundToMinor(i):t.max,this.marginStart=void 0===t.min?this.roundToMinor(e):t.min,1==this.alignZeros&&(this.marginEnd-this.marginStart)%this.step!=0&&(this.marginEnd+=this.marginEnd%this.step),this.deadSpace=this.roundToMinor(i)-i+this.roundToMinor(e)-e,this.marginRange=this.marginEnd-this.marginStart,this.current=this.marginEnd},e.prototype.roundToMinor=function(t){var e=t-t%(this.scale*this.minorSteps[this.stepIndex]);return t%(this.scale*this.minorSteps[this.stepIndex])>.5*this.scale*this.minorSteps[this.stepIndex]?e+this.scale*this.minorSteps[this.stepIndex]:e},e.prototype.hasNext=function(){return this.current>=this.marginStart},e.prototype.next=function(){var t=this.current;this.current-=this.step,this.current==t&&(this.current=this._end)},e.prototype.previous=function(){this.current+=this.step,this.marginEnd+=this.step,this.marginRange=this.marginEnd-this.marginStart},e.prototype.getCurrent=function(t){var e=Math.abs(this.current)0;s--){if("0"!=i[s]){if("."==i[s]||","==i[s]){i=i.slice(0,s);break}break}i=i.slice(0,s)}}else{var o="",n=i.indexOf("e");if(-1!=n&&(o=i.slice(n),i=i.slice(0,n)),n=Math.max(i.indexOf(","),i.indexOf(".")),-1===n?(0!==t&&(i+="."),n=i.length+t):0!==t&&(n+=t+1),n>i.length)for(var r=n-i.length;r>0;r--)i+="0";else i=i.slice(0,n);i+=o}return i},e.prototype.snap=function(){},e.prototype.isMajor=function(){return this.current%(this.scale*this.majorSteps[this.stepIndex])==0},t.exports=e},function(t,e,i){function s(t,e){var i=h().hours(0).minutes(0).seconds(0).milliseconds(0);this.start=i.clone().add(-3,"days").valueOf(),this.end=i.clone().add(4,"days").valueOf(),this.body=t,this.deltaDifference=0,this.scaleOffset=0,this.startToFront=!1,this.endToFront=!0,this.defaultOptions={start:null,end:null,direction:"horizontal",moveable:!0,zoomable:!0,min:null,max:null,zoomMin:10,zoomMax:31536e10},this.options=r.extend({},this.defaultOptions),this.props={touch:{}},this.animateTimer=null,this.body.emitter.on("dragstart",this._onDragStart.bind(this)),this.body.emitter.on("drag",this._onDrag.bind(this)),this.body.emitter.on("dragend",this._onDragEnd.bind(this)),this.body.emitter.on("hold",this._onHold.bind(this)),this.body.emitter.on("mousewheel",this._onMouseWheel.bind(this)),this.body.emitter.on("DOMMouseScroll",this._onMouseWheel.bind(this)),this.body.emitter.on("touch",this._onTouch.bind(this)),this.body.emitter.on("pinch",this._onPinch.bind(this)),this.setOptions(e)}function o(t){if("horizontal"!=t&&"vertical"!=t)throw new TypeError('Unknown direction "'+t+'". Choose "horizontal" or "vertical".')}function n(t,e){return{x:t.pageX-r.getAbsoluteLeft(e),y:t.pageY-r.getAbsoluteTop(e)}}var r=i(1),a=i(47),h=i(44),d=i(20),l=i(15);s.prototype=new d,s.prototype.setOptions=function(t){if(t){var e=["direction","min","max","zoomMin","zoomMax","moveable","zoomable","activate","hiddenDates"];r.selectiveExtend(e,this.options,t),("start"in t||"end"in t)&&this.setRange(t.start,t.end)}},s.prototype.setRange=function(t,e,i,s){s!==!0&&(s=!1);var o=void 0!=t?r.convert(t,"Date").valueOf():null,n=void 0!=e?r.convert(e,"Date").valueOf():null;if(this._cancelAnimation(),i){var a=this,h=this.start,d=this.end,c="number"==typeof i?i:500,p=(new Date).valueOf(),u=!1,m=function(){if(!a.props.touch.dragging){var t=(new Date).valueOf(),e=t-p,i=e>c,g=i||null===o?o:r.easeInOutQuad(e,h,o,c),v=i||null===n?n:r.easeInOutQuad(e,d,n,c);f=a._applyRange(g,v),l.updateHiddenDates(a.body,a.options.hiddenDates),u=u||f,f&&a.body.emitter.emit("rangechange",{start:new Date(a.start),end:new Date(a.end),byUser:s}),i?u&&a.body.emitter.emit("rangechanged",{start:new Date(a.start),end:new Date(a.end),byUser:s}):a.animateTimer=setTimeout(m,20)}};return m()}var f=this._applyRange(o,n);if(l.updateHiddenDates(this.body,this.options.hiddenDates),f){var g={start:new Date(this.start),end:new Date(this.end),byUser:s};this.body.emitter.emit("rangechange",g),this.body.emitter.emit("rangechanged",g)}},s.prototype._cancelAnimation=function(){this.animateTimer&&(clearTimeout(this.animateTimer),this.animateTimer=null)},s.prototype._applyRange=function(t,e){var i,s=null!=t?r.convert(t,"Date").valueOf():this.start,o=null!=e?r.convert(e,"Date").valueOf():this.end,n=null!=this.options.max?r.convert(this.options.max,"Date").valueOf():null,a=null!=this.options.min?r.convert(this.options.min,"Date").valueOf():null;if(isNaN(s)||null===s)throw new Error('Invalid start "'+t+'"');if(isNaN(o)||null===o)throw new Error('Invalid end "'+e+'"');if(s>o&&(o=s),null!==a&&a>s&&(i=a-s,s+=i,o+=i,null!=n&&o>n&&(o=n)),null!==n&&o>n&&(i=o-n,s-=i,o-=i,null!=a&&a>s&&(s=a)),null!==this.options.zoomMin){var h=parseFloat(this.options.zoomMin);0>h&&(h=0),h>o-s&&(this.end-this.start===h?(s=this.start,o=this.end):(i=h-(o-s),s-=i/2,o+=i/2))}if(null!==this.options.zoomMax){var d=parseFloat(this.options.zoomMax);0>d&&(d=0),o-s>d&&(this.end-this.start===d?(s=this.start,o=this.end):(i=o-s-d,s+=i/2,o-=i/2))}var l=this.start!=s||this.end!=o;return s>=this.start&&s<=this.end||o>=this.start&&o<=this.end||this.start>=s&&this.start<=o||this.end>=s&&this.end<=o||this.body.emitter.emit("checkRangedItems"),this.start=s,this.end=o,l},s.prototype.getRange=function(){return{start:this.start,end:this.end}},s.prototype.conversion=function(t,e){return s.conversion(this.start,this.end,t,e)},s.conversion=function(t,e,i,s){return void 0===s&&(s=0),0!=i&&e-t!=0?{offset:t,scale:i/(e-t-s)}:{offset:0,scale:1}},s.prototype._onDragStart=function(){this.deltaDifference=0,this.previousDelta=0,this.options.moveable&&this.props.touch.allowDragging&&(this.props.touch.start=this.start,this.props.touch.end=this.end,this.props.touch.dragging=!0,this.body.dom.root&&(this.body.dom.root.style.cursor="move"))},s.prototype._onDrag=function(t){if(this.options.moveable&&this.props.touch.allowDragging){var e=this.options.direction;o(e);var i="horizontal"==e?t.gesture.deltaX:t.gesture.deltaY;i-=this.deltaDifference;var s=this.props.touch.end-this.props.touch.start,n=l.getHiddenDurationBetween(this.body.hiddenDates,this.start,this.end);s-=n;var r="horizontal"==e?this.body.domProps.center.width:this.body.domProps.center.height,a=-i/r*s,h=this.props.touch.start+a,d=this.props.touch.end+a,c=l.snapAwayFromHidden(this.body.hiddenDates,h,this.previousDelta-i,!0),p=l.snapAwayFromHidden(this.body.hiddenDates,d,this.previousDelta-i,!0);if(c!=h||p!=d)return this.deltaDifference+=i,this.props.touch.start=c,this.props.touch.end=p,void this._onDrag(t);this.previousDelta=i,this._applyRange(h,d),this.body.emitter.emit("rangechange",{start:new Date(this.start),end:new Date(this.end),byUser:!0})}},s.prototype._onDragEnd=function(){this.options.moveable&&this.props.touch.allowDragging&&(this.props.touch.dragging=!1,this.body.dom.root&&(this.body.dom.root.style.cursor="auto"),this.body.emitter.emit("rangechanged",{start:new Date(this.start),end:new Date(this.end),byUser:!0}))},s.prototype._onMouseWheel=function(t){if(this.options.zoomable&&this.options.moveable){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){var i;i=0>e?1-e/5:1/(1+e/5);var s=a.fakeGesture(this,t),o=n(s.center,this.body.dom.center),r=this._pointerToDate(o);this.zoom(i,r,e)}t.preventDefault()}},s.prototype._onTouch=function(){this.props.touch.start=this.start,this.props.touch.end=this.end,this.props.touch.allowDragging=!0,this.props.touch.center=null,this.scaleOffset=0,this.deltaDifference=0},s.prototype._onHold=function(){this.props.touch.allowDragging=!1},s.prototype._onPinch=function(t){if(this.options.zoomable&&this.options.moveable&&(this.props.touch.allowDragging=!1,t.gesture.touches.length>1)){this.props.touch.center||(this.props.touch.center=n(t.gesture.center,this.body.dom.center));var e=1/(t.gesture.scale+this.scaleOffset),i=this._pointerToDate(this.props.touch.center),s=l.getHiddenDurationBetween(this.body.hiddenDates,this.start,this.end),o=l.getHiddenDurationBefore(this.body.hiddenDates,this,i),r=s-o,a=i-o+(this.props.touch.start-(i-o))*e,h=i+r+(this.props.touch.end-(i+r))*e;this.startToFront=1-e>0?!1:!0,this.endToFront=e-1>0?!1:!0;var d=l.snapAwayFromHidden(this.body.hiddenDates,a,1-e,!0),c=l.snapAwayFromHidden(this.body.hiddenDates,h,e-1,!0);(d!=a||c!=h)&&(this.props.touch.start=d,this.props.touch.end=c,this.scaleOffset=1-t.gesture.scale,a=d,h=c),this.setRange(a,h,!1,!0),this.startToFront=!1,this.endToFront=!0}},s.prototype._pointerToDate=function(t){var e,i=this.options.direction;if(o(i),"horizontal"==i)return this.body.util.toTime(t.x).valueOf();var s=this.body.domProps.center.height;return e=this.conversion(s),t.y/e.scale+e.offset},s.prototype.zoom=function(t,e,i){null==e&&(e=(this.start+this.end)/2);var s=l.getHiddenDurationBetween(this.body.hiddenDates,this.start,this.end),o=l.getHiddenDurationBefore(this.body.hiddenDates,this,e),n=s-o,r=e-o+(this.start-(e-o))*t,a=e+n+(this.end-(e+n))*t;this.startToFront=i>0?!1:!0,this.endToFront=-i>0?!1:!0;var h=l.snapAwayFromHidden(this.body.hiddenDates,r,i,!0),d=l.snapAwayFromHidden(this.body.hiddenDates,a,-i,!0);(h!=r||d!=a)&&(r=h,a=d),this.setRange(r,a,!1,!0),this.startToFront=!1,this.endToFront=!0},s.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,s=this.end+e*t;this.start=i,this.end=s},s.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,s=this.start-i,o=this.end-i;this.setRange(s,o)},t.exports=s},function(t,e){var i=.001;e.orderByStart=function(t){t.sort(function(t,e){return t.data.start-e.data.start})},e.orderByEnd=function(t){t.sort(function(t,e){var i="end"in t.data?t.data.end:t.data.start,s="end"in e.data?e.data.end:e.data.start;return i-s})},e.stack=function(t,i,s){var o,n;if(s)for(o=0,n=t.length;n>o;o++)t[o].top=null;for(o=0,n=t.length;n>o;o++){var r=t[o];if(r.stack&&null===r.top){r.top=i.axis;do{for(var a=null,h=0,d=t.length;d>h;h++){var l=t[h];if(null!==l.top&&l!==r&&l.stack&&e.collision(r,l,i.item)){a=l;break}}null!=a&&(r.top=a.top+a.height+i.item.vertical)}while(a)}}},e.nostack=function(t,e,i){var s,o,n;for(s=0,o=t.length;o>s;s++)if(void 0!==t[s].data.subgroup){n=e.axis;for(var r in i)i.hasOwnProperty(r)&&1==i[r].visible&&i[r].indexe.left&&t.top-s.vertical+ie.top}},function(t,e,i){function s(t,e,i,o){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale="day",this.step=1,this.setRange(t,e,i),this.switchedDay=!1,this.switchedMonth=!1,this.switchedYear=!1,this.hiddenDates=o,void 0===o&&(this.hiddenDates=[]),this.format=s.FORMAT}var o=i(44),n=i(15),r=i(1);s.FORMAT={minorLabels:{millisecond:"SSS",second:"s",minute:"HH:mm",hour:"HH:mm",weekday:"ddd D",day:"D",month:"MMM",year:"YYYY"},majorLabels:{millisecond:"HH:mm:ss",second:"D MMMM HH:mm",minute:"ddd D MMMM",hour:"ddd D MMMM",weekday:"MMMM YYYY",day:"MMMM YYYY",month:"YYYY",year:""}},s.prototype.setFormat=function(t){var e=r.deepExtend({},s.FORMAT);this.format=r.deepExtend(e,t)},s.prototype.setRange=function(t,e,i){if(!(t instanceof Date&&e instanceof Date))throw"No legal start or end date in method setRange";this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i)},s.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},s.prototype.roundToMinor=function(){switch(this.scale){case"year":this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case"month":this.current.setDate(1);case"day":case"weekday":this.current.setHours(0);case"hour":this.current.setMinutes(0);case"minute":this.current.setSeconds(0);case"second":this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case"millisecond":this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case"second":this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case"minute":this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case"hour":this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case"weekday":case"day":this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case"month":this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step);break;case"year":this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step)}},s.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},s.prototype.next=function(){var t=this.current.valueOf();if(this.current.getMonth()<6)switch(this.scale){case"millisecond":this.current=new Date(this.current.valueOf()+this.step);break;case"second":this.current=new Date(this.current.valueOf()+1e3*this.step);break;case"minute":this.current=new Date(this.current.valueOf()+1e3*this.step*60);break;case"hour":this.current=new Date(this.current.valueOf()+1e3*this.step*60*60);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case"weekday":case"day":this.current.setDate(this.current.getDate()+this.step); break;case"month":this.current.setMonth(this.current.getMonth()+this.step);break;case"year":this.current.setFullYear(this.current.getFullYear()+this.step)}else switch(this.scale){case"millisecond":this.current=new Date(this.current.valueOf()+this.step);break;case"second":this.current.setSeconds(this.current.getSeconds()+this.step);break;case"minute":this.current.setMinutes(this.current.getMinutes()+this.step);break;case"hour":this.current.setHours(this.current.getHours()+this.step);break;case"weekday":case"day":this.current.setDate(this.current.getDate()+this.step);break;case"month":this.current.setMonth(this.current.getMonth()+this.step);break;case"year":this.current.setFullYear(this.current.getFullYear()+this.step)}if(1!=this.step)switch(this.scale){case"millisecond":this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},s.prototype.setAutoScale=function(t){this.autoScale=t},s.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,s=864e5,o=36e5,n=6e4,r=1e3,a=1;1e3*e>t&&(this.scale="year",this.step=1e3),500*e>t&&(this.scale="year",this.step=500),100*e>t&&(this.scale="year",this.step=100),50*e>t&&(this.scale="year",this.step=50),10*e>t&&(this.scale="year",this.step=10),5*e>t&&(this.scale="year",this.step=5),e>t&&(this.scale="year",this.step=1),3*i>t&&(this.scale="month",this.step=3),i>t&&(this.scale="month",this.step=1),5*s>t&&(this.scale="day",this.step=5),2*s>t&&(this.scale="day",this.step=2),s>t&&(this.scale="day",this.step=1),s/2>t&&(this.scale="weekday",this.step=1),4*o>t&&(this.scale="hour",this.step=4),o>t&&(this.scale="hour",this.step=1),15*n>t&&(this.scale="minute",this.step=15),10*n>t&&(this.scale="minute",this.step=10),5*n>t&&(this.scale="minute",this.step=5),n>t&&(this.scale="minute",this.step=1),15*r>t&&(this.scale="second",this.step=15),10*r>t&&(this.scale="second",this.step=10),5*r>t&&(this.scale="second",this.step=5),r>t&&(this.scale="second",this.step=1),200*a>t&&(this.scale="millisecond",this.step=200),100*a>t&&(this.scale="millisecond",this.step=100),50*a>t&&(this.scale="millisecond",this.step=50),10*a>t&&(this.scale="millisecond",this.step=10),5*a>t&&(this.scale="millisecond",this.step=5),a>t&&(this.scale="millisecond",this.step=1)}},s.prototype.snap=function(t){var e=new Date(t.valueOf());if("year"==this.scale){var i=e.getFullYear()+Math.round(e.getMonth()/12);e.setFullYear(Math.round(i/this.step)*this.step),e.setMonth(0),e.setDate(0),e.setHours(0),e.setMinutes(0),e.setSeconds(0),e.setMilliseconds(0)}else if("month"==this.scale)e.getDate()>15?(e.setDate(1),e.setMonth(e.getMonth()+1)):e.setDate(1),e.setHours(0),e.setMinutes(0),e.setSeconds(0),e.setMilliseconds(0);else if("day"==this.scale){switch(this.step){case 5:case 2:e.setHours(24*Math.round(e.getHours()/24));break;default:e.setHours(12*Math.round(e.getHours()/12))}e.setMinutes(0),e.setSeconds(0),e.setMilliseconds(0)}else if("weekday"==this.scale){switch(this.step){case 5:case 2:e.setHours(12*Math.round(e.getHours()/12));break;default:e.setHours(6*Math.round(e.getHours()/6))}e.setMinutes(0),e.setSeconds(0),e.setMilliseconds(0)}else if("hour"==this.scale){switch(this.step){case 4:e.setMinutes(60*Math.round(e.getMinutes()/60));break;default:e.setMinutes(30*Math.round(e.getMinutes()/30))}e.setSeconds(0),e.setMilliseconds(0)}else if("minute"==this.scale){switch(this.step){case 15:case 10:e.setMinutes(5*Math.round(e.getMinutes()/5)),e.setSeconds(0);break;case 5:e.setSeconds(60*Math.round(e.getSeconds()/60));break;default:e.setSeconds(30*Math.round(e.getSeconds()/30))}e.setMilliseconds(0)}else if("second"==this.scale)switch(this.step){case 15:case 10:e.setSeconds(5*Math.round(e.getSeconds()/5)),e.setMilliseconds(0);break;case 5:e.setMilliseconds(1e3*Math.round(e.getMilliseconds()/1e3));break;default:e.setMilliseconds(500*Math.round(e.getMilliseconds()/500))}else if("millisecond"==this.scale){var s=this.step>5?this.step/2:1;e.setMilliseconds(Math.round(e.getMilliseconds()/s)*s)}return e},s.prototype.isMajor=function(){if(1==this.switchedYear)switch(this.switchedYear=!1,this.scale){case"year":case"month":case"weekday":case"day":case"hour":case"minute":case"second":case"millisecond":return!0;default:return!1}else if(1==this.switchedMonth)switch(this.switchedMonth=!1,this.scale){case"weekday":case"day":case"hour":case"minute":case"second":case"millisecond":return!0;default:return!1}else if(1==this.switchedDay)switch(this.switchedDay=!1,this.scale){case"millisecond":case"second":case"minute":case"hour":return!0;default:return!1}switch(this.scale){case"millisecond":return 0==this.current.getMilliseconds();case"second":return 0==this.current.getSeconds();case"minute":return 0==this.current.getHours()&&0==this.current.getMinutes();case"hour":return 0==this.current.getHours();case"weekday":case"day":return 1==this.current.getDate();case"month":return 0==this.current.getMonth();case"year":return!1;default:return!1}},s.prototype.getLabelMinor=function(t){void 0==t&&(t=this.current);var e=this.format.minorLabels[this.scale];return e&&e.length>0?o(t).format(e):""},s.prototype.getLabelMajor=function(t){void 0==t&&(t=this.current);var e=this.format.majorLabels[this.scale];return e&&e.length>0?o(t).format(e):""},s.prototype.getClassName=function(){function t(t){return t/h%2==0?" even":" odd"}function e(t){return t.isSame(new Date,"day")?" today":t.isSame(o().add(1,"day"),"day")?" tomorrow":t.isSame(o().add(-1,"day"),"day")?" yesterday":""}function i(t){return t.isSame(new Date,"week")?" current-week":""}function s(t){return t.isSame(new Date,"month")?" current-month":""}function n(t){return t.isSame(new Date,"year")?" current-year":""}var r=o(this.current),a=r.locale?r.locale("en"):r.lang("en"),h=this.step;switch(this.scale){case"millisecond":return t(a.milliseconds()).trim();case"second":return t(a.seconds()).trim();case"minute":return t(a.minutes()).trim();case"hour":var d=a.hours();return 4==this.step&&(d=d+"-"+(d+4)),d+"h"+e(a)+t(a.hours());case"weekday":return a.format("dddd").toLowerCase()+e(a)+i(a)+t(a.date());case"day":var l=a.date(),c=a.format("MMMM").toLowerCase();return"day"+l+" "+c+s(a)+t(l-1);case"month":return a.format("MMMM").toLowerCase()+s(a)+t(a.month());case"year":var p=a.year();return"year"+p+n(a)+t(p);default:return""}},t.exports=s},function(t){function e(){this.options=null,this.props=null}e.prototype.setOptions=function(t){t&&util.extend(this.options,t)},e.prototype.redraw=function(){return!1},e.prototype.destroy=function(){},e.prototype._isResized=function(){var t=this.props._previousWidth!==this.props.width||this.props._previousHeight!==this.props.height;return this.props._previousWidth=this.props.width,this.props._previousHeight=this.props.height,t},t.exports=e},function(t,e,i){function s(t,e){this.body=t,this.defaultOptions={showCurrentTime:!0,locales:a,locale:"en"},this.options=o.extend({},this.defaultOptions),this.offset=0,this._create(),this.setOptions(e)}var o=i(1),n=i(20),r=i(44),a=i(48);s.prototype=new n,s.prototype._create=function(){var t=document.createElement("div");t.className="currenttime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",this.bar=t},s.prototype.destroy=function(){this.options.showCurrentTime=!1,this.redraw(),this.body=null},s.prototype.setOptions=function(t){t&&o.selectiveExtend(["showCurrentTime","locale","locales"],this.options,t)},s.prototype.redraw=function(){if(this.options.showCurrentTime){var t=this.body.dom.backgroundVertical;this.bar.parentNode!=t&&(this.bar.parentNode&&this.bar.parentNode.removeChild(this.bar),t.appendChild(this.bar),this.start());var e=new Date((new Date).valueOf()+this.offset),i=this.body.util.toScreen(e),s=this.options.locales[this.options.locale],o=s.current+" "+s.time+": "+r(e).format("dddd, MMMM Do YYYY, H:mm:ss");o=o.charAt(0).toUpperCase()+o.substring(1),this.bar.style.left=i+"px",this.bar.title=o}else this.bar.parentNode&&this.bar.parentNode.removeChild(this.bar),this.stop();return!1},s.prototype.start=function(){function t(){e.stop();var i=e.body.range.conversion(e.body.domProps.center.width).scale,s=1/i/10;30>s&&(s=30),s>1e3&&(s=1e3),e.redraw(),e.currentTimeTimer=setTimeout(t,s)}var e=this;t()},s.prototype.stop=function(){void 0!==this.currentTimeTimer&&(clearTimeout(this.currentTimeTimer),delete this.currentTimeTimer)},s.prototype.setCurrentTime=function(t){var e=o.convert(t,"Date").valueOf(),i=(new Date).valueOf();this.offset=e-i,this.redraw()},s.prototype.getCurrentTime=function(){return new Date((new Date).valueOf()+this.offset)},t.exports=s},function(t,e,i){function s(t,e){this.body=t,this.defaultOptions={showCustomTime:!1,locales:h,locale:"en"},this.options=n.extend({},this.defaultOptions),this.customTime=new Date,this.eventParams={},this._create(),this.setOptions(e)}var o=i(45),n=i(1),r=i(20),a=i(44),h=i(48);s.prototype=new r,s.prototype.setOptions=function(t){t&&n.selectiveExtend(["showCustomTime","locale","locales"],this.options,t)},s.prototype._create=function(){var t=document.createElement("div");t.className="customtime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",this.bar=t;var e=document.createElement("div");e.style.position="relative",e.style.top="0px",e.style.left="-10px",e.style.height="100%",e.style.width="20px",t.appendChild(e),this.hammer=o(t,{prevent_default:!0}),this.hammer.on("dragstart",this._onDragStart.bind(this)),this.hammer.on("drag",this._onDrag.bind(this)),this.hammer.on("dragend",this._onDragEnd.bind(this))},s.prototype.destroy=function(){this.options.showCustomTime=!1,this.redraw(),this.hammer.enable(!1),this.hammer=null,this.body=null},s.prototype.redraw=function(){if(this.options.showCustomTime){var t=this.body.dom.backgroundVertical;this.bar.parentNode!=t&&(this.bar.parentNode&&this.bar.parentNode.removeChild(this.bar),t.appendChild(this.bar));var e=this.body.util.toScreen(this.customTime),i=this.options.locales[this.options.locale],s=i.time+": "+a(this.customTime).format("dddd, MMMM Do YYYY, H:mm:ss");s=s.charAt(0).toUpperCase()+s.substring(1),this.bar.style.left=e+"px",this.bar.title=s}else this.bar.parentNode&&this.bar.parentNode.removeChild(this.bar);return!1},s.prototype.setCustomTime=function(t){this.customTime=n.convert(t,"Date"),this.redraw()},s.prototype.getCustomTime=function(){return new Date(this.customTime.valueOf())},s.prototype._onDragStart=function(t){this.eventParams.dragging=!0,this.eventParams.customTime=this.customTime,t.stopPropagation(),t.preventDefault()},s.prototype._onDrag=function(t){if(this.eventParams.dragging){var e=t.gesture.deltaX,i=this.body.util.toScreen(this.eventParams.customTime)+e,s=this.body.util.toTime(i);this.setCustomTime(s),this.body.emitter.emit("timechange",{time:new Date(this.customTime.valueOf())}),t.stopPropagation(),t.preventDefault()}},s.prototype._onDragEnd=function(t){this.eventParams.dragging&&(this.body.emitter.emit("timechanged",{time:new Date(this.customTime.valueOf())}),t.stopPropagation(),t.preventDefault())},t.exports=s},function(t,e,i){function s(t,e,i,s){this.id=o.randomUUID(),this.body=t,this.defaultOptions={orientation:"left",showMinorLabels:!0,showMajorLabels:!0,icons:!0,majorLinesOffset:7,minorLinesOffset:4,labelOffsetX:10,labelOffsetY:2,iconWidth:20,width:"40px",visible:!0,alignZeros:!0,customRange:{left:{min:void 0,max:void 0},right:{min:void 0,max:void 0}},title:{left:{text:void 0},right:{text:void 0}},format:{left:{decimals:void 0},right:{decimals:void 0}}},this.linegraphOptions=s,this.linegraphSVG=i,this.props={},this.DOMelements={lines:{},labels:{},title:{}},this.dom={},this.range={start:0,end:0},this.options=o.extend({},this.defaultOptions),this.conversionFactor=1,this.setOptions(e),this.width=Number((""+this.options.width).replace("px","")),this.minWidth=this.width,this.height=this.linegraphSVG.offsetHeight,this.hidden=!1,this.stepPixels=25,this.stepPixelsForced=25,this.zeroCrossing=-1,this.lineOffset=0,this.master=!0,this.svgElements={},this.iconsRemoved=!1,this.groups={},this.amountOfGroups=0,this._create();var n=this;this.body.emitter.on("verticalDrag",function(){n.dom.lineContainer.style.top=n.body.domProps.scrollTop+"px"})}var o=i(1),n=i(2),r=i(20),a=i(16);s.prototype=new r,s.prototype.addGroup=function(t,e){this.groups.hasOwnProperty(t)||(this.groups[t]=e),this.amountOfGroups+=1},s.prototype.updateGroup=function(t,e){this.groups[t]=e},s.prototype.removeGroup=function(t){this.groups.hasOwnProperty(t)&&(delete this.groups[t],this.amountOfGroups-=1)},s.prototype.setOptions=function(t){if(t){var e=!1;this.options.orientation!=t.orientation&&void 0!==t.orientation&&(e=!0);var i=["orientation","showMinorLabels","showMajorLabels","icons","majorLinesOffset","minorLinesOffset","labelOffsetX","labelOffsetY","iconWidth","width","visible","customRange","title","format","alignZeros"];o.selectiveExtend(i,this.options,t),this.minWidth=Number((""+this.options.width).replace("px","")),1==e&&this.dom.frame&&(this.hide(),this.show())}},s.prototype._create=function(){this.dom.frame=document.createElement("div"),this.dom.frame.style.width=this.options.width,this.dom.frame.style.height=this.height,this.dom.lineContainer=document.createElement("div"),this.dom.lineContainer.style.width="100%",this.dom.lineContainer.style.height=this.height,this.dom.lineContainer.style.position="relative",this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.style.position="absolute",this.svg.style.top="0px",this.svg.style.height="100%",this.svg.style.width="100%",this.svg.style.display="block",this.dom.frame.appendChild(this.svg)},s.prototype._redrawGroupIcons=function(){n.prepareElements(this.svgElements);var t,e=this.options.iconWidth,i=15,s=4,o=s+.5*i;t="left"==this.options.orientation?s:this.width-e-s;for(var r in this.groups)this.groups.hasOwnProperty(r)&&(1!=this.groups[r].visible||void 0!==this.linegraphOptions.visibility[r]&&1!=this.linegraphOptions.visibility[r]||(this.groups[r].drawIcon(t,o,this.svgElements,this.svg,e,i),o+=i+s));n.cleanupElements(this.svgElements),this.iconsRemoved=!1},s.prototype._cleanupIcons=function(){0==this.iconsRemoved&&(n.prepareElements(this.svgElements),n.cleanupElements(this.svgElements),this.iconsRemoved=!0)},s.prototype.show=function(){this.hidden=!1,this.dom.frame.parentNode||("left"==this.options.orientation?this.body.dom.left.appendChild(this.dom.frame):this.body.dom.right.appendChild(this.dom.frame)),this.dom.lineContainer.parentNode||this.body.dom.backgroundHorizontal.appendChild(this.dom.lineContainer)},s.prototype.hide=function(){this.hidden=!0,this.dom.frame.parentNode&&this.dom.frame.parentNode.removeChild(this.dom.frame),this.dom.lineContainer.parentNode&&this.dom.lineContainer.parentNode.removeChild(this.dom.lineContainer)},s.prototype.setRange=function(t,e){0==this.master&&1==this.options.alignZeros&&-1!=this.zeroCrossing&&t>0&&(t=0),this.range.start=t,this.range.end=e},s.prototype.redraw=function(){var t=!1,e=0;this.dom.lineContainer.style.top=this.body.domProps.scrollTop+"px";for(var i in this.groups)this.groups.hasOwnProperty(i)&&(1!=this.groups[i].visible||void 0!==this.linegraphOptions.visibility[i]&&1!=this.linegraphOptions.visibility[i]||e++);if(0==this.amountOfGroups||0==e)this.hide();else{this.show(),this.height=Number(this.linegraphSVG.style.height.replace("px","")),this.dom.lineContainer.style.height=this.height+"px",this.width=1==this.options.visible?Number((""+this.options.width).replace("px","")):0;var s=this.props,o=this.dom.frame;o.className="dataaxis",this._calculateCharSize();var n=this.options.orientation,r=this.options.showMinorLabels,a=this.options.showMajorLabels;s.minorLabelHeight=r?s.minorCharHeight:0,s.majorLabelHeight=a?s.majorCharHeight:0,s.minorLineWidth=this.body.dom.backgroundHorizontal.offsetWidth-this.lineOffset-this.width+2*this.options.minorLinesOffset,s.minorLineHeight=1,s.majorLineWidth=this.body.dom.backgroundHorizontal.offsetWidth-this.lineOffset-this.width+2*this.options.majorLinesOffset,s.majorLineHeight=1,"left"==n?(o.style.top="0",o.style.left="0",o.style.bottom="",o.style.width=this.width+"px",o.style.height=this.height+"px",this.props.width=this.body.domProps.left.width,this.props.height=this.body.domProps.left.height):(o.style.top="",o.style.bottom="0",o.style.left="0",o.style.width=this.width+"px",o.style.height=this.height+"px",this.props.width=this.body.domProps.right.width,this.props.height=this.body.domProps.right.height),t=this._redrawLabels(),t=this._isResized()||t,1==this.options.icons?this._redrawGroupIcons():this._cleanupIcons(),this._redrawTitle(n)}return t},s.prototype._redrawLabels=function(){var t=!1;n.prepareElements(this.DOMelements.lines),n.prepareElements(this.DOMelements.labels);var e=this.options.orientation,i=this.master?this.props.majorCharHeight||10:this.stepPixelsForced,s=new a(this.range.start,this.range.end,i,this.dom.frame.offsetHeight,this.options.customRange[this.options.orientation],0==this.master&&this.options.alignZeros);this.step=s;var o=(this.dom.frame.offsetHeight-s.deadSpace*(this.dom.frame.offsetHeight/s.marginRange))/((s.marginRange-s.deadSpace)/s.step);this.stepPixels=o;var r=this.height/o,h=0;if(0==this.master){o=this.stepPixelsForced,h=Math.round(this.dom.frame.offsetHeight/o-r);for(var d=0;.5*h>d;d++)s.previous();if(r=this.height/o,-1!=this.zeroCrossing&&1==this.options.alignZeros){var l=s.marginEnd/s.step-this.zeroCrossing;if(l>0)for(var d=0;l>d;d++)s.next();else if(0>l)for(var d=0;-l>d;d++)s.previous()}}else r+=.25;this.valueAtZero=s.marginEnd;var c,p=0,u=1;void 0!==this.options.format[e]&&(c=this.options.format[e].decimals),this.maxLabelSize=0;for(var m=0;u=0&&this._redrawLabel(m-2,s.getCurrent(c),e,"yAxis major",this.props.majorCharHeight),this._redrawLine(m,e,"grid horizontal major",this.options.majorLinesOffset,this.props.majorLineWidth)):this._redrawLine(m,e,"grid horizontal minor",this.options.minorLinesOffset,this.props.minorLineWidth),1==this.master&&0==s.current&&(this.zeroCrossing=u),u++}this.conversionFactor=0==this.master?m/(this.valueAtZero-s.current):this.dom.frame.offsetHeight/s.marginRange;var g=0;void 0!==this.options.title[e]&&void 0!==this.options.title[e].text&&(g=this.props.titleCharHeight);var v=1==this.options.icons?Math.max(this.options.iconWidth,g)+this.options.labelOffsetX+15:g+this.options.labelOffsetX+15;return this.maxLabelSize>this.width-v&&1==this.options.visible?(this.width=this.maxLabelSize+v,this.options.width=this.width+"px",n.cleanupElements(this.DOMelements.lines),n.cleanupElements(this.DOMelements.labels),this.redraw(),t=!0):this.maxLabelSizethis.minWidth?(this.width=Math.max(this.minWidth,this.maxLabelSize+v),this.options.width=this.width+"px",n.cleanupElements(this.DOMelements.lines),n.cleanupElements(this.DOMelements.labels),this.redraw(),t=!0):(n.cleanupElements(this.DOMelements.lines),n.cleanupElements(this.DOMelements.labels),t=!1),t},s.prototype.convertValue=function(t){var e=this.valueAtZero-t,i=e*this.conversionFactor;return i},s.prototype._redrawLabel=function(t,e,i,s,o){var r=n.getDOMElement("div",this.DOMelements.labels,this.dom.frame);r.className=s,r.innerHTML=e,"left"==i?(r.style.left="-"+this.options.labelOffsetX+"px",r.style.textAlign="right"):(r.style.right="-"+this.options.labelOffsetX+"px",r.style.textAlign="left"),r.style.top=t-.5*o+this.options.labelOffsetY+"px",e+="";var a=Math.max(this.props.majorCharWidth,this.props.minorCharWidth);this.maxLabelSized;d++){var c=this.visibleItems[d];c.repositionY(e)}return s},s.prototype._calculateHeight=function(t){var e,i=this.visibleItems;this.resetSubgroups();var s=this;if(i.length){var n=i[0].top,r=i[0].top+i[0].height;if(o.forEach(i,function(t){n=Math.min(n,t.top),r=Math.max(r,t.top+t.height),void 0!==t.data.subgroup&&(s.subgroups[t.data.subgroup].height=Math.max(s.subgroups[t.data.subgroup].height,t.height),s.subgroups[t.data.subgroup].visible=!0)}),n>t.axis){var a=n-t.axis;r-=a,o.forEach(i,function(t){t.top-=a})}e=r+t.item.vertical/2}else e=t.axis+t.item.vertical;return e=Math.max(e,this.props.label.height)},s.prototype.show=function(){this.dom.label.parentNode||this.itemSet.dom.labelSet.appendChild(this.dom.label),this.dom.foreground.parentNode||this.itemSet.dom.foreground.appendChild(this.dom.foreground),this.dom.background.parentNode||this.itemSet.dom.background.appendChild(this.dom.background),this.dom.axis.parentNode||this.itemSet.dom.axis.appendChild(this.dom.axis)},s.prototype.hide=function(){var t=this.dom.label;t.parentNode&&t.parentNode.removeChild(t);var e=this.dom.foreground;e.parentNode&&e.parentNode.removeChild(e);var i=this.dom.background;i.parentNode&&i.parentNode.removeChild(i);var s=this.dom.axis;s.parentNode&&s.parentNode.removeChild(s)},s.prototype.add=function(t){if(this.items[t.id]=t,t.setParent(this),void 0!==t.data.subgroup&&(void 0===this.subgroups[t.data.subgroup]&&(this.subgroups[t.data.subgroup]={height:0,visible:!1,index:this.subgroupIndex,items:[]},this.subgroupIndex++),this.subgroups[t.data.subgroup].items.push(t)),this.orderSubgroups(),-1==this.visibleItems.indexOf(t)){var e=this.itemSet.body.range;this._checkIfVisible(t,this.visibleItems,e)}},s.prototype.orderSubgroups=function(){if(void 0!==this.subgroupOrderer){var t=[];if("string"==typeof this.subgroupOrderer){for(var e in this.subgroups)t.push({subgroup:e,sortField:this.subgroups[e].items[0].data[this.subgroupOrderer]});t.sort(function(t,e){return t.sortField-e.sortField})}else if("function"==typeof this.subgroupOrderer){for(var e in this.subgroups)t.push(this.subgroups[e].items[0].data);t.sort(this.subgroupOrderer)}if(t.length>0)for(var i=0;it?-1:l>=t?0:1};if(e.length>0)for(n=0;nl}),1==this.checkRangedItems)for(this.checkRangedItems=!1,n=0;nl})}for(n=0;n=0&&(n=e[r],!o(n));r--)void 0===s[n.id]&&(s[n.id]=!0,i.push(n)); for(r=t+1;rs;s++){var n=this.visibleItems[s];n.repositionY(e)}return i},s.prototype.show=function(){this.dom.background.parentNode||this.itemSet.dom.background.appendChild(this.dom.background)},t.exports=s},function(t,e,i){function s(t,e){this.body=t,this.defaultOptions={type:null,orientation:"bottom",align:"auto",stack:!0,groupOrder:null,selectable:!0,editable:{updateTime:!1,updateGroup:!1,add:!1,remove:!1},onAdd:function(t,e){e(t)},onUpdate:function(t,e){e(t)},onMove:function(t,e){e(t)},onRemove:function(t,e){e(t)},onMoving:function(t,e){e(t)},margin:{item:{horizontal:10,vertical:10},axis:20},padding:5},this.options=n.extend({},this.defaultOptions),this.itemOptions={type:{start:"Date",end:"Date"}},this.conversion={toScreen:t.util.toScreen,toTime:t.util.toTime},this.dom={},this.props={},this.hammer=null;var i=this;this.itemsData=null,this.groupsData=null,this.itemListeners={add:function(t,e){i._onAdd(e.items)},update:function(t,e){i._onUpdate(e.items)},remove:function(t,e){i._onRemove(e.items)}},this.groupListeners={add:function(t,e){i._onAddGroups(e.items)},update:function(t,e){i._onUpdateGroups(e.items)},remove:function(t,e){i._onRemoveGroups(e.items)}},this.items={},this.groups={},this.groupIds=[],this.selection=[],this.stackDirty=!0,this.touchParams={},this._create(),this.setOptions(e)}var o=i(45),n=i(1),r=i(3),a=i(4),h=i(20),d=i(25),l=i(26),c=i(33),p=i(34),u=i(35),m=i(32),f="__ungrouped__",g="__background__";s.prototype=new h,s.types={background:m,box:c,range:u,point:p},s.prototype._create=function(){var t=document.createElement("div");t.className="itemset",t["timeline-itemset"]=this,this.dom.frame=t;var e=document.createElement("div");e.className="background",t.appendChild(e),this.dom.background=e;var i=document.createElement("div");i.className="foreground",t.appendChild(i),this.dom.foreground=i;var s=document.createElement("div");s.className="axis",this.dom.axis=s;var n=document.createElement("div");n.className="labelset",this.dom.labelSet=n,this._updateUngrouped();var r=new l(g,null,this);r.show(),this.groups[g]=r,this.hammer=o(this.body.dom.centerContainer,{preventDefault:!0}),this.hammer.on("touch",this._onTouch.bind(this)),this.hammer.on("dragstart",this._onDragStart.bind(this)),this.hammer.on("drag",this._onDrag.bind(this)),this.hammer.on("dragend",this._onDragEnd.bind(this)),this.hammer.on("tap",this._onSelectItem.bind(this)),this.hammer.on("hold",this._onMultiSelectItem.bind(this)),this.hammer.on("doubletap",this._onAddItem.bind(this)),this.show()},s.prototype.setOptions=function(t){if(t){var e=["type","align","orientation","padding","stack","selectable","groupOrder","dataAttributes","template","hide"];n.selectiveExtend(e,this.options,t),"margin"in t&&("number"==typeof t.margin?(this.options.margin.axis=t.margin,this.options.margin.item.horizontal=t.margin,this.options.margin.item.vertical=t.margin):"object"==typeof t.margin&&(n.selectiveExtend(["axis"],this.options.margin,t.margin),"item"in t.margin&&("number"==typeof t.margin.item?(this.options.margin.item.horizontal=t.margin.item,this.options.margin.item.vertical=t.margin.item):"object"==typeof t.margin.item&&n.selectiveExtend(["horizontal","vertical"],this.options.margin.item,t.margin.item)))),"editable"in t&&("boolean"==typeof t.editable?(this.options.editable.updateTime=t.editable,this.options.editable.updateGroup=t.editable,this.options.editable.add=t.editable,this.options.editable.remove=t.editable):"object"==typeof t.editable&&n.selectiveExtend(["updateTime","updateGroup","add","remove"],this.options.editable,t.editable));var i=function(e){var i=t[e];if(i){if(!(i instanceof Function))throw new Error("option "+e+" must be a function "+e+"(item, callback)");this.options[e]=i}}.bind(this);["onAdd","onUpdate","onRemove","onMove","onMoving"].forEach(i),this.markDirty()}},s.prototype.markDirty=function(){this.groupIds=[],this.stackDirty=!0},s.prototype.destroy=function(){this.hide(),this.setItems(null),this.setGroups(null),this.hammer=null,this.body=null,this.conversion=null},s.prototype.hide=function(){this.dom.frame.parentNode&&this.dom.frame.parentNode.removeChild(this.dom.frame),this.dom.axis.parentNode&&this.dom.axis.parentNode.removeChild(this.dom.axis),this.dom.labelSet.parentNode&&this.dom.labelSet.parentNode.removeChild(this.dom.labelSet)},s.prototype.show=function(){this.dom.frame.parentNode||this.body.dom.center.appendChild(this.dom.frame),this.dom.axis.parentNode||this.body.dom.backgroundVertical.appendChild(this.dom.axis),this.dom.labelSet.parentNode||this.body.dom.left.appendChild(this.dom.labelSet)},s.prototype.setSelection=function(t){var e,i,s,o;for(void 0==t&&(t=[]),Array.isArray(t)||(t=[t]),e=0,i=this.selection.length;i>e;e++)s=this.selection[e],o=this.items[s],o&&o.unselect();for(this.selection=[],e=0,i=t.length;i>e;e++)s=t[e],o=this.items[s],o&&(this.selection.push(s),o.select())},s.prototype.getSelection=function(){return this.selection.concat([])},s.prototype.getVisibleItems=function(){var t=this.body.range.getRange(),e=this.body.util.toScreen(t.start),i=this.body.util.toScreen(t.end),s=[];for(var o in this.groups)if(this.groups.hasOwnProperty(o))for(var n=this.groups[o],r=n.visibleItems,a=0;ae&&s.push(h.id)}return s},s.prototype._deselect=function(t){for(var e=this.selection,i=0,s=e.length;s>i;i++)if(e[i]==t){e.splice(i,1);break}},s.prototype.redraw=function(){var t=this.options.margin,e=this.body.range,i=n.option.asSize,s=this.options,o=s.orientation,r=!1,a=this.dom.frame,h=s.editable.updateTime||s.editable.updateGroup;this.props.top=this.body.domProps.top.height+this.body.domProps.border.top,this.props.left=this.body.domProps.left.width+this.body.domProps.border.left,a.className="itemset"+(h?" editable":""),r=this._orderGroups()||r;var d=e.end-e.start,l=d!=this.lastVisibleInterval||this.props.width!=this.props.lastWidth;l&&(this.stackDirty=!0),this.lastVisibleInterval=d,this.props.lastWidth=this.props.width;var c=this.stackDirty,p=this._firstGroup(),u={item:t.item,axis:t.axis},m={item:t.item,axis:t.item.vertical/2},f=0,v=t.axis+t.item.vertical;return this.groups[g].redraw(e,m,c),n.forEach(this.groups,function(t){var i=t==p?u:m,s=t.redraw(e,i,c);r=s||r,f+=t.height}),f=Math.max(f,v),this.stackDirty=!1,a.style.height=i(f),this.props.width=a.offsetWidth,this.props.height=f,this.dom.axis.style.top=i("top"==o?this.body.domProps.top.height+this.body.domProps.border.top:this.body.domProps.top.height+this.body.domProps.centerContainer.height),this.dom.axis.style.left="0",r=this._isResized()||r},s.prototype._firstGroup=function(){var t="top"==this.options.orientation?0:this.groupIds.length-1,e=this.groupIds[t],i=this.groups[e]||this.groups[f];return i||null},s.prototype._updateUngrouped=function(){{var t,e,i=this.groups[f];this.groups[g]}if(this.groupsData){if(i){i.hide(),delete this.groups[f];for(e in this.items)if(this.items.hasOwnProperty(e)){t=this.items[e],t.parent&&t.parent.remove(t);var s=this._getGroupId(t.data),o=this.groups[s];o&&o.add(t)||t.hide()}}}else if(!i){var n=null,r=null;i=new d(n,r,this),this.groups[f]=i;for(e in this.items)this.items.hasOwnProperty(e)&&(t=this.items[e],i.add(t));i.show()}},s.prototype.getLabelSet=function(){return this.dom.labelSet},s.prototype.setItems=function(t){var e,i=this,s=this.itemsData;if(t){if(!(t instanceof r||t instanceof a))throw new TypeError("Data must be an instance of DataSet or DataView");this.itemsData=t}else this.itemsData=null;if(s&&(n.forEach(this.itemListeners,function(t,e){s.off(e,t)}),e=s.getIds(),this._onRemove(e)),this.itemsData){var o=this.id;n.forEach(this.itemListeners,function(t,e){i.itemsData.on(e,t,o)}),e=this.itemsData.getIds(),this._onAdd(e),this._updateUngrouped()}},s.prototype.getItems=function(){return this.itemsData},s.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(n.forEach(this.groupListeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this.groupsData=null,this._onRemoveGroups(e)),t){if(!(t instanceof r||t instanceof a))throw new TypeError("Data must be an instance of DataSet or DataView");this.groupsData=t}else this.groupsData=null;if(this.groupsData){var s=this.id;n.forEach(this.groupListeners,function(t,e){i.groupsData.on(e,t,s)}),e=this.groupsData.getIds(),this._onAddGroups(e)}this._updateUngrouped(),this._order(),this.body.emitter.emit("change",{queue:!0})},s.prototype.getGroups=function(){return this.groupsData},s.prototype.removeItem=function(t){var e=this.itemsData.get(t),i=this.itemsData.getDataSet();e&&this.options.onRemove(e,function(e){e&&i.remove(t)})},s.prototype._getType=function(t){return t.type||this.options.type||(t.end?"range":"box")},s.prototype._getGroupId=function(t){var e=this._getType(t);return"background"==e&&void 0==t.group?g:this.groupsData?t.group:f},s.prototype._onUpdate=function(t){var e=this;t.forEach(function(t){var i=e.itemsData.get(t,e.itemOptions),o=e.items[t],n=e._getType(i),r=s.types[n];if(o&&(r&&o instanceof r?e._updateItem(o,i):(e._removeItem(o),o=null)),!o){if(!r)throw new TypeError("rangeoverflow"==n?'Item type "rangeoverflow" is deprecated. Use css styling instead: .vis.timeline .item.range .content {overflow: visible;}':'Unknown item type "'+n+'"');o=new r(i,e.conversion,e.options),o.id=t,e._addItem(o)}}),this._order(),this.stackDirty=!0,this.body.emitter.emit("change",{queue:!0})},s.prototype._onAdd=s.prototype._onUpdate,s.prototype._onRemove=function(t){var e=0,i=this;t.forEach(function(t){var s=i.items[t];s&&(e++,i._removeItem(s))}),e&&(this._order(),this.stackDirty=!0,this.body.emitter.emit("change",{queue:!0}))},s.prototype._order=function(){n.forEach(this.groups,function(t){t.order()})},s.prototype._onUpdateGroups=function(t){this._onAddGroups(t)},s.prototype._onAddGroups=function(t){var e=this;t.forEach(function(t){var i=e.groupsData.get(t),s=e.groups[t];if(s)s.setData(i);else{if(t==f||t==g)throw new Error("Illegal group id. "+t+" is a reserved id.");var o=Object.create(e.options);n.extend(o,{height:null}),s=new d(t,i,e),e.groups[t]=s;for(var r in e.items)if(e.items.hasOwnProperty(r)){var a=e.items[r];a.data.group==t&&s.add(a)}s.order(),s.show()}}),this.body.emitter.emit("change",{queue:!0})},s.prototype._onRemoveGroups=function(t){var e=this.groups;t.forEach(function(t){var i=e[t];i&&(i.hide(),delete e[t])}),this.markDirty(),this.body.emitter.emit("change",{queue:!0})},s.prototype._orderGroups=function(){if(this.groupsData){var t=this.groupsData.getIds({order:this.options.groupOrder}),e=!n.equalArray(t,this.groupIds);if(e){var i=this.groups;t.forEach(function(t){i[t].hide()}),t.forEach(function(t){i[t].show()}),this.groupIds=t}return e}return!1},s.prototype._addItem=function(t){this.items[t.id]=t;var e=this._getGroupId(t.data),i=this.groups[e];i&&i.add(t)},s.prototype._updateItem=function(t,e){var i=t.data.group;if(t.setData(e),i!=t.data.group){var s=this.groups[i];s&&s.remove(t);var o=this._getGroupId(t.data),n=this.groups[o];n&&n.add(t)}},s.prototype._removeItem=function(t){t.hide(),delete this.items[t.id];var e=this.selection.indexOf(t.id);-1!=e&&this.selection.splice(e,1),t.parent&&t.parent.remove(t)},s.prototype._constructByEndArray=function(t){for(var e=[],i=0;i0||o.length>0)&&this.body.emitter.emit("select",{items:a})}},s.prototype._onAddItem=function(t){if(this.options.selectable&&this.options.editable.add){var e=this,i=this.body.util.snap||null,o=s.itemFromTarget(t);if(o){var r=e.itemsData.get(o.id);this.options.onUpdate(r,function(t){t&&e.itemsData.getDataSet().update(t)})}else{var a=n.getAbsoluteLeft(this.dom.frame),h=t.gesture.center.pageX-a,d=this.body.util.toTime(h),l={start:i?i(d):d,content:"new item"};if("range"===this.options.type){var c=this.body.util.toTime(h+this.props.width/5);l.end=i?i(c):c}l[this.itemsData._fieldId]=n.randomUUID();var p=s.groupFromTarget(t);p&&(l.group=p.groupId),this.options.onAdd(l,function(t){t&&e.itemsData.getDataSet().add(t)})}}},s.prototype._onMultiSelectItem=function(t){if(this.options.selectable){var e,i=s.itemFromTarget(t);if(i){e=this.getSelection();var o=t.gesture.touches[0]&&t.gesture.touches[0].shiftKey||!1;if(o){e.push(i.id);var n=s._getItemRange(this.itemsData.get(e,this.itemOptions));e=[];for(var r in this.items)if(this.items.hasOwnProperty(r)){var a=this.items[r],h=a.data.start,d=void 0!==a.data.end?a.data.end:h;h>=n.min&&d<=n.max&&e.push(a.id)}}else{var l=e.indexOf(i.id);-1==l?e.push(i.id):e.splice(l,1)}this.setSelection(e),this.body.emitter.emit("select",{items:this.getSelection()})}}},s._getItemRange=function(t){var e=null,i=null;return t.forEach(function(t){(null==i||t.starte)&&(e=t.end):(null==e||t.start>e)&&(e=t.start)}),{min:i,max:e}},s.itemFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-item"))return e["timeline-item"];e=e.parentNode}return null},s.groupFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-group"))return e["timeline-group"];e=e.parentNode}return null},s.itemSetFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-itemset"))return e["timeline-itemset"];e=e.parentNode}return null},t.exports=s},function(t,e,i){function s(t,e,i,s){this.body=t,this.defaultOptions={enabled:!0,icons:!0,iconSize:20,iconSpacing:6,left:{visible:!0,position:"top-left"},right:{visible:!0,position:"top-left"}},this.side=i,this.options=o.extend({},this.defaultOptions),this.linegraphOptions=s,this.svgElements={},this.dom={},this.groups={},this.amountOfGroups=0,this._create(),this.setOptions(e)}var o=i(1),n=i(2),r=i(20);s.prototype=new r,s.prototype.clear=function(){this.groups={},this.amountOfGroups=0},s.prototype.addGroup=function(t,e){this.groups.hasOwnProperty(t)||(this.groups[t]=e),this.amountOfGroups+=1},s.prototype.updateGroup=function(t,e){this.groups[t]=e},s.prototype.removeGroup=function(t){this.groups.hasOwnProperty(t)&&(delete this.groups[t],this.amountOfGroups-=1)},s.prototype._create=function(){this.dom.frame=document.createElement("div"),this.dom.frame.className="legend",this.dom.frame.style.position="absolute",this.dom.frame.style.top="10px",this.dom.frame.style.display="block",this.dom.textArea=document.createElement("div"),this.dom.textArea.className="legendText",this.dom.textArea.style.position="relative",this.dom.textArea.style.top="0px",this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.style.position="absolute",this.svg.style.top="0px",this.svg.style.width=this.options.iconSize+5+"px",this.svg.style.height="100%",this.dom.frame.appendChild(this.svg),this.dom.frame.appendChild(this.dom.textArea)},s.prototype.hide=function(){this.dom.frame.parentNode&&this.dom.frame.parentNode.removeChild(this.dom.frame)},s.prototype.show=function(){this.dom.frame.parentNode||this.body.dom.center.appendChild(this.dom.frame)},s.prototype.setOptions=function(t){var e=["enabled","orientation","icons","left","right"];o.selectiveDeepExtend(e,this.options,t)},s.prototype.redraw=function(){var t=0;for(var e in this.groups)this.groups.hasOwnProperty(e)&&(1!=this.groups[e].visible||void 0!==this.linegraphOptions.visibility[e]&&1!=this.linegraphOptions.visibility[e]||t++);if(0==this.options[this.side].visible||0==this.amountOfGroups||0==this.options.enabled||0==t)this.hide();else{if(this.show(),"top-left"==this.options[this.side].position||"bottom-left"==this.options[this.side].position?(this.dom.frame.style.left="4px",this.dom.frame.style.textAlign="left",this.dom.textArea.style.textAlign="left",this.dom.textArea.style.left=this.options.iconSize+15+"px",this.dom.textArea.style.right="",this.svg.style.left="0px",this.svg.style.right=""):(this.dom.frame.style.right="4px",this.dom.frame.style.textAlign="right",this.dom.textArea.style.textAlign="right",this.dom.textArea.style.right=this.options.iconSize+15+"px",this.dom.textArea.style.left="",this.svg.style.right="0px",this.svg.style.left=""),"top-left"==this.options[this.side].position||"top-right"==this.options[this.side].position)this.dom.frame.style.top=4-Number(this.body.dom.center.style.top.replace("px",""))+"px",this.dom.frame.style.bottom="";else{var i=this.body.domProps.center.height-this.body.domProps.centerContainer.height;this.dom.frame.style.bottom=4+i+Number(this.body.dom.center.style.top.replace("px",""))+"px",this.dom.frame.style.top=""}0==this.options.icons?(this.dom.frame.style.width=this.dom.textArea.offsetWidth+10+"px",this.dom.textArea.style.right="",this.dom.textArea.style.left="",this.svg.style.width="0px"):(this.dom.frame.style.width=this.options.iconSize+15+this.dom.textArea.offsetWidth+10+"px",this.drawLegendIcons());var s="";for(var e in this.groups)this.groups.hasOwnProperty(e)&&(1!=this.groups[e].visible||void 0!==this.linegraphOptions.visibility[e]&&1!=this.linegraphOptions.visibility[e]||(s+=this.groups[e].content+"
"));this.dom.textArea.innerHTML=s,this.dom.textArea.style.lineHeight=.75*this.options.iconSize+this.options.iconSpacing+"px"}},s.prototype.drawLegendIcons=function(){if(this.dom.frame.parentNode){n.prepareElements(this.svgElements);var t=window.getComputedStyle(this.dom.frame).paddingTop,e=Number(t.replace("px","")),i=e,s=this.options.iconSize,o=.75*this.options.iconSize,r=e+.5*o+3;this.svg.style.width=s+5+e+"px";for(var a in this.groups)this.groups.hasOwnProperty(a)&&(1!=this.groups[a].visible||void 0!==this.linegraphOptions.visibility[a]&&1!=this.linegraphOptions.visibility[a]||(this.groups[a].drawIcon(i,r,this.svgElements,this.svg,s,o),r+=o+this.options.iconSpacing));n.cleanupElements(this.svgElements)}},t.exports=s},function(t,e,i){function s(t,e){this.id=o.randomUUID(),this.body=t,this.defaultOptions={yAxisOrientation:"left",defaultGroup:"default",sort:!0,sampling:!0,graphHeight:"400px",shaded:{enabled:!1,orientation:"bottom"},style:"line",barChart:{width:50,handleOverlap:"overlap",align:"center"},catmullRom:{enabled:!0,parametrization:"centripetal",alpha:.5},drawPoints:{enabled:!0,size:6,style:"square"},dataAxis:{showMinorLabels:!0,showMajorLabels:!0,icons:!1,width:"40px",visible:!0,alignZeros:!0,customRange:{left:{min:void 0,max:void 0},right:{min:void 0,max:void 0}}},legend:{enabled:!1,icons:!0,left:{visible:!0,position:"top-left"},right:{visible:!0,position:"top-right"}},groups:{visibility:{}}},this.options=o.extend({},this.defaultOptions),this.dom={},this.props={},this.hammer=null,this.groups={},this.abortedGraphUpdate=!1,this.updateSVGheight=!1,this.updateSVGheightOnResize=!1;var i=this;this.itemsData=null,this.groupsData=null,this.itemListeners={add:function(t,e){i._onAdd(e.items)},update:function(t,e){i._onUpdate(e.items)},remove:function(t,e){i._onRemove(e.items)}},this.groupListeners={add:function(t,e){i._onAddGroups(e.items)},update:function(t,e){i._onUpdateGroups(e.items)},remove:function(t,e){i._onRemoveGroups(e.items)}},this.items={},this.selection=[],this.lastStart=this.body.range.start,this.touchParams={},this.svgElements={},this.setOptions(e),this.groupsUsingDefaultStyles=[0],this.COUNTER=0,this.body.emitter.on("rangechanged",function(){i.lastStart=i.body.range.start,i.svg.style.left=o.option.asSize(-i.props.width),i.redraw.call(i,!0)}),this._create(),this.framework={svg:this.svg,svgElements:this.svgElements,options:this.options,groups:this.groups},this.body.emitter.emit("change")}var o=i(1),n=i(2),r=i(3),a=i(4),h=i(20),d=i(23),l=i(24),c=i(28),p=i(52),u="__ungrouped__";s.prototype=new h,s.prototype._create=function(){var t=document.createElement("div");t.className="LineGraph",this.dom.frame=t,this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.style.position="relative",this.svg.style.height=(""+this.options.graphHeight).replace("px","")+"px",this.svg.style.display="block",t.appendChild(this.svg),this.options.dataAxis.orientation="left",this.yAxisLeft=new d(this.body,this.options.dataAxis,this.svg,this.options.groups),this.options.dataAxis.orientation="right",this.yAxisRight=new d(this.body,this.options.dataAxis,this.svg,this.options.groups),delete this.options.dataAxis.orientation,this.legendLeft=new c(this.body,this.options.legend,"left",this.options.groups),this.legendRight=new c(this.body,this.options.legend,"right",this.options.groups),this.show()},s.prototype.setOptions=function(t){if(t){var e=["sampling","defaultGroup","height","graphHeight","yAxisOrientation","style","barChart","dataAxis","sort","groups"];void 0===t.graphHeight&&void 0!==t.height&&void 0!==this.body.domProps.centerContainer.height?(this.updateSVGheight=!0,this.updateSVGheightOnResize=!0):void 0!==this.body.domProps.centerContainer.height&&void 0!==t.graphHeight&&parseInt((t.graphHeight+"").replace("px",""))0){var d=this.body.util.toGlobalTime(-this.body.domProps.root.width),l=this.body.util.toGlobalTime(2*this.body.domProps.root.width),c={};for(this._getRelevantData(a,c,d,l),this._applySampling(a,c),e=0;eu&&console.log("WARNING: there may be an infinite loop in the _updateGraph emitter cycle."),this.COUNTER=0,this.abortedGraphUpdate=!1,e=0;e0)for(r=0;rs){d.push(h);break}d.push(h)}}else for(a=0;ai&&h.x0)for(var s=0;s0){var n=1,r=o.length,a=this.body.util.toGlobalScreen(o[o.length-1].x)-this.body.util.toGlobalScreen(o[0].x),h=r/a;n=Math.min(Math.ceil(.2*r),Math.max(1,Math.round(h)));for(var d=[],l=0;r>l;l+=n)d.push(o[l]);e[t[s]]=d}}},s.prototype._getYRanges=function(t,e,i){var s,o,n,r,a=[],h=[];if(t.length>0){for(n=0;n0&&(o=this.groups[t[n]],"stack"==r.barChart.handleOverlap&&"bar"==r.style?"left"==r.yAxisOrientation?a=a.concat(o.getYRange(s)):h=h.concat(o.getYRange(s)):i[t[n]]=o.getYRange(s,t[n]));p.getStackedBarYRange(a,i,t,"__barchartLeft","left"),p.getStackedBarYRange(h,i,t,"__barchartRight","right")}},s.prototype._updateYAxis=function(t,e){var i,s,o=!1,n=!1,r=!1,a=1e9,h=1e9,d=-1e9,l=-1e9;if(t.length>0){for(var c=0;ci?i:a,d=s>d?s:d):(r=!0,h=h>i?i:h,l=s>l?s:l));1==n&&this.yAxisLeft.setRange(a,d),1==r&&this.yAxisRight.setRange(h,l)}return o=this._toggleAxisVisiblity(n,this.yAxisLeft)||o,o=this._toggleAxisVisiblity(r,this.yAxisRight)||o,1==r&&1==n?(this.yAxisLeft.drawIcons=!0,this.yAxisRight.drawIcons=!0):(this.yAxisLeft.drawIcons=!1,this.yAxisRight.drawIcons=!1),this.yAxisRight.master=!n,0==this.yAxisRight.master?(this.yAxisLeft.lineOffset=1==r?this.yAxisRight.width:0,o=this.yAxisLeft.redraw()||o,this.yAxisRight.stepPixelsForced=this.yAxisLeft.stepPixels,this.yAxisRight.zeroCrossing=this.yAxisLeft.zeroCrossing,o=this.yAxisRight.redraw()||o):o=this.yAxisRight.redraw()||o,-1!=t.indexOf("__barchartLeft")&&t.splice(t.indexOf("__barchartLeft"),1),-1!=t.indexOf("__barchartRight")&&t.splice(t.indexOf("__barchartRight"),1),o},s.prototype._toggleAxisVisiblity=function(t,e){var i=!1;return 0==t?e.dom.frame.parentNode&&0==e.hidden&&(e.hide(),i=!0):e.dom.frame.parentNode||1!=e.hidden||(e.show(),i=!0),i},s.prototype._convertXcoordinates=function(t){for(var e,i,s=[],o=this.body.util.toScreen,n=0;ny;)y++,l=h.getCurrent(),c=h.isMajor(),u=h.getClassName(),f=m,m=this.body.util.toScreen(l),g=m-f,p&&(p.style.width=g+"px"),this.options.showMinorLabels&&this._repaintMinorText(m,h.getLabelMinor(),t,u),c&&this.options.showMajorLabels?(m>0&&(void 0==v&&(v=m),this._repaintMajorText(m,h.getLabelMajor(),t,u)),p=this._repaintMajorLine(m,t,u)):p=this._repaintMinorLine(m,t,u),h.next();if(this.options.showMajorLabels){var b=this.body.util.toTime(0),_=h.getLabelMajor(b),x=_.length*(this.props.majorCharWidth||10)+10;(void 0==v||v>x)&&this._repaintMajorText(0,_,t,u)}o.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},s.prototype._repaintMinorText=function(t,e,i,s){var o=this.dom.redundant.minorTexts.shift();if(!o){var n=document.createTextNode("");o=document.createElement("div"),o.appendChild(n),this.dom.foreground.appendChild(o)}this.dom.minorTexts.push(o),o.childNodes[0].nodeValue=e,o.style.top="top"==i?this.props.majorLabelHeight+"px":"0",o.style.left=t+"px",o.className="text minor "+s},s.prototype._repaintMajorText=function(t,e,i,s){var o=this.dom.redundant.majorTexts.shift();if(!o){var n=document.createTextNode(e);o=document.createElement("div"),o.appendChild(n),this.dom.foreground.appendChild(o)}this.dom.majorTexts.push(o),o.childNodes[0].nodeValue=e,o.className="text major "+s,o.style.top="top"==i?"0":this.props.minorLabelHeight+"px",o.style.left=t+"px"},s.prototype._repaintMinorLine=function(t,e,i){var s=this.dom.redundant.lines.shift();s||(s=document.createElement("div"),this.dom.background.appendChild(s)),this.dom.lines.push(s);var o=this.props;return s.style.top="top"==e?o.majorLabelHeight+"px":this.body.domProps.top.height+"px",s.style.height=o.minorLineHeight+"px",s.style.left=t-o.minorLineWidth/2+"px",s.className="grid vertical minor "+i,s},s.prototype._repaintMajorLine=function(t,e,i){var s=this.dom.redundant.lines.shift();s||(s=document.createElement("div"),this.dom.background.appendChild(s)),this.dom.lines.push(s);var o=this.props;return s.style.top="top"==e?"0":this.body.domProps.top.height+"px",s.style.left=t-o.majorLineWidth/2+"px",s.style.height=o.majorLineHeight+"px",s.className="grid vertical major "+i,s},s.prototype._calculateCharSize=function(){this.dom.measureCharMinor||(this.dom.measureCharMinor=document.createElement("DIV"),this.dom.measureCharMinor.className="text minor measure",this.dom.measureCharMinor.style.position="absolute",this.dom.measureCharMinor.appendChild(document.createTextNode("0")),this.dom.foreground.appendChild(this.dom.measureCharMinor)),this.props.minorCharHeight=this.dom.measureCharMinor.clientHeight,this.props.minorCharWidth=this.dom.measureCharMinor.clientWidth,this.dom.measureCharMajor||(this.dom.measureCharMajor=document.createElement("DIV"),this.dom.measureCharMajor.className="text major measure",this.dom.measureCharMajor.style.position="absolute",this.dom.measureCharMajor.appendChild(document.createTextNode("0")),this.dom.foreground.appendChild(this.dom.measureCharMajor)),this.props.majorCharHeight=this.dom.measureCharMajor.clientHeight,this.props.majorCharWidth=this.dom.measureCharMajor.clientWidth},s.prototype.snap=function(t){return this.step.snap(t)},t.exports=s},function(t,e,i){function s(t,e,i){this.id=null,this.parent=null,this.data=t,this.dom=null,this.conversion=e||{},this.options=i||{},this.selected=!1,this.displayed=!1,this.dirty=!0,this.top=null,this.left=null,this.width=null,this.height=null}var o=i(45),n=i(1);s.prototype.stack=!0,s.prototype.select=function(){this.selected=!0,this.dirty=!0,this.displayed&&this.redraw()},s.prototype.unselect=function(){this.selected=!1,this.dirty=!0,this.displayed&&this.redraw()},s.prototype.setData=function(t){this.data=t,this.dirty=!0,this.displayed&&this.redraw()},s.prototype.setParent=function(t){this.displayed?(this.hide(),this.parent=t,this.parent&&this.show()):this.parent=t},s.prototype.isVisible=function(){return!1},s.prototype.show=function(){return!1},s.prototype.hide=function(){return!1},s.prototype.redraw=function(){},s.prototype.repositionX=function(){},s.prototype.repositionY=function(){},s.prototype._repaintDeleteButton=function(t){if(this.selected&&this.options.editable.remove&&!this.dom.deleteButton){var e=this,i=document.createElement("div");i.className="delete",i.title="Delete this item",o(i,{preventDefault:!0}).on("tap",function(t){e.parent.removeFromDataSet(e),t.stopPropagation()}),t.appendChild(i),this.dom.deleteButton=i}else!this.selected&&this.dom.deleteButton&&(this.dom.deleteButton.parentNode&&this.dom.deleteButton.parentNode.removeChild(this.dom.deleteButton),this.dom.deleteButton=null)},s.prototype._updateContents=function(t){var e;if(this.options.template){var i=this.parent.itemSet.itemsData.get(this.id);e=this.options.template(i)}else e=this.data.content;if(e!==this.content){if(e instanceof Element)t.innerHTML="",t.appendChild(e);else if(void 0!=e)t.innerHTML=e;else if("background"!=this.data.type||void 0!==this.data.content)throw new Error('Property "content" missing in item '+this.id);this.content=e}},s.prototype._updateTitle=function(t){null!=this.data.title?t.title=this.data.title||"":t.removeAttribute("title")},s.prototype._updateDataAttributes=function(t){if(this.options.dataAttributes&&this.options.dataAttributes.length>0){var e=[];if(Array.isArray(this.options.dataAttributes))e=this.options.dataAttributes;else{if("all"!=this.options.dataAttributes)return;e=Object.keys(this.data)}for(var i=0;it.start},s.prototype.redraw=function(){var t=this.dom;if(t||(this.dom={},t=this.dom,t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content),this.dirty=!0),!this.parent)throw new Error("Cannot redraw item: no parent attached");if(!t.box.parentNode){var e=this.parent.dom.background;if(!e)throw new Error("Cannot redraw item: parent has no background container element");e.appendChild(t.box)}if(this.displayed=!0,this.dirty){this._updateContents(this.dom.content),this._updateTitle(this.dom.content),this._updateDataAttributes(this.dom.content),this._updateStyle(this.dom.box);var i=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");t.box.className=this.baseClassName+i,this.overflow="hidden"!==window.getComputedStyle(t.content).overflow,this.props.content.width=this.dom.content.offsetWidth,this.height=0,this.dirty=!1}},s.prototype.show=r.prototype.show,s.prototype.hide=r.prototype.hide,s.prototype.repositionX=r.prototype.repositionX,s.prototype.repositionY=function(t){var e="top"===this.options.orientation;this.dom.content.style.top=e?"":"0",this.dom.content.style.bottom=e?"0":"";var i;if(void 0!==this.data.subgroup){var s=this.data.subgroup,o=this.parent.subgroups,r=o[s].index;if(1==e){i=this.parent.subgroups[s].height+t.item.vertical,i+=0==r?t.axis-.5*t.item.vertical:0;var a=this.parent.top;for(var h in o)o.hasOwnProperty(h)&&1==o[h].visible&&o[h].indexr&&(a+=o[h].height+t.item.vertical);i=this.parent.subgroups[s].height+t.item.vertical,this.dom.box.style.top=a+"px",this.dom.box.style.bottom=""}}else this.parent instanceof n?(i=Math.max(this.parent.height,this.parent.itemSet.body.domProps.center.height,this.parent.itemSet.body.domProps.centerContainer.height),this.dom.box.style.top=e?"0":"",this.dom.box.style.bottom=e?"":"0"):(i=this.parent.height,this.dom.box.style.top=this.parent.top+"px",this.dom.box.style.bottom="");this.dom.box.style.height=i+"px"},t.exports=s},function(t,e,i){function s(t,e,i){if(this.props={dot:{width:0,height:0},line:{width:0,height:0}},t&&void 0==t.start)throw new Error('Property "start" missing in item '+t);o.call(this,t,e,i)}{var o=i(31);i(1)}s.prototype=new o(null,null,null),s.prototype.isVisible=function(t){var e=(t.end-t.start)/4;return this.data.start>t.start-e&&this.data.startt.start-e&&this.data.startt.start},s.prototype.redraw=function(){var t=this.dom;if(t||(this.dom={},t=this.dom,t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content),t.box["timeline-item"]=this,this.dirty=!0),!this.parent)throw new Error("Cannot redraw item: no parent attached");if(!t.box.parentNode){var e=this.parent.dom.foreground;if(!e)throw new Error("Cannot redraw item: parent has no foreground container element");e.appendChild(t.box)}if(this.displayed=!0,this.dirty){this._updateContents(this.dom.content),this._updateTitle(this.dom.box),this._updateDataAttributes(this.dom.box),this._updateStyle(this.dom.box);var i=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");t.box.className=this.baseClassName+i,this.overflow="hidden"!==window.getComputedStyle(t.content).overflow,this.dom.content.style.maxWidth="none",this.props.content.width=this.dom.content.offsetWidth,this.height=this.dom.box.offsetHeight,this.dom.content.style.maxWidth="",this.dirty=!1}this._repaintDeleteButton(t.box),this._repaintDragLeft(),this._repaintDragRight()},s.prototype.show=function(){this.displayed||this.redraw()},s.prototype.hide=function(){if(this.displayed){var t=this.dom.box;t.parentNode&&t.parentNode.removeChild(t),this.top=null,this.left=null,this.displayed=!1}},s.prototype.repositionX=function(){var t,e,i=this.parent.width,s=this.conversion.toScreen(this.data.start),o=this.conversion.toScreen(this.data.end);-i>s&&(s=-i),o>2*i&&(o=2*i);var n=Math.max(o-s,1);switch(this.overflow?(this.left=s,this.width=n+this.props.content.width,e=this.props.content.width):(this.left=s,this.width=n,e=Math.min(o-s-2*this.options.padding,this.props.content.width)),this.dom.box.style.left=this.left+"px",this.dom.box.style.width=n+"px",this.options.align){case"left":this.dom.content.style.left="0";break;case"right":this.dom.content.style.left=Math.max(n-e-2*this.options.padding,0)+"px";break;case"center":this.dom.content.style.left=Math.max((n-e-2*this.options.padding)/2,0)+"px";break;default:t=this.overflow?o>0?Math.max(-s,0):-e:0>s?Math.min(-s,o-s-e-2*this.options.padding):0,this.dom.content.style.left=t+"px"}},s.prototype.repositionY=function(){var t=this.options.orientation,e=this.dom.box;e.style.top="top"==t?this.top+"px":this.parent.height-this.top-this.height+"px"},s.prototype._repaintDragLeft=function(){if(this.selected&&this.options.editable.updateTime&&!this.dom.dragLeft){var t=document.createElement("div");t.className="drag-left",t.dragLeftItem=this,o(t,{preventDefault:!0}).on("drag",function(){}),this.dom.box.appendChild(t),this.dom.dragLeft=t}else!this.selected&&this.dom.dragLeft&&(this.dom.dragLeft.parentNode&&this.dom.dragLeft.parentNode.removeChild(this.dom.dragLeft),this.dom.dragLeft=null)},s.prototype._repaintDragRight=function(){if(this.selected&&this.options.editable.updateTime&&!this.dom.dragRight){var t=document.createElement("div");t.className="drag-right",t.dragRightItem=this,o(t,{preventDefault:!0}).on("drag",function(){}),this.dom.box.appendChild(t),this.dom.dragRight=t}else!this.selected&&this.dom.dragRight&&(this.dom.dragRight.parentNode&&this.dom.dragRight.parentNode.removeChild(this.dom.dragRight),this.dom.dragRight=null)},t.exports=s},function(t,e,i){function s(t,e,i){if(!(this instanceof s))throw new SyntaxError("Constructor must be called with the new operator");this._determineBrowserMethod(),this._initializeMixinLoaders(),this.containerElement=t,this.renderRefreshRate=60,this.renderTimestep=1e3/this.renderRefreshRate,this.renderTime=0,this.physicsTime=0,this.runDoubleSpeed=!1,this.physicsDiscreteStepsize=.5,this.initializing=!0,this.triggerFunctions={add:null,edit:null,editEdge:null,connect:null,del:null},this.defaultOptions={nodes:{mass:1,radiusMin:10,radiusMax:30,radius:10,shape:"ellipse",image:void 0,widthMin:16,widthMax:64,fontColor:"black",fontSize:14,fontFace:"verdana",fontFill:void 0,fontStrokeWidth:0,fontStrokeColor:"white",level:-1,color:{border:"#2B7CE9",background:"#97C2FC",highlight:{border:"#2B7CE9",background:"#D2E5FF"},hover:{border:"#2B7CE9",background:"#D2E5FF"}},group:void 0,borderWidth:1,borderWidthSelected:void 0},edges:{widthMin:1,widthMax:15,width:1,widthSelectionMultiplier:2,hoverWidth:1.5,style:"line",color:{color:"#848484",highlight:"#848484",hover:"#848484"},fontColor:"#343434",fontSize:14,fontFace:"arial",fontFill:"white",fontStrokeWidth:0,fontStrokeColor:"white",labelAlignment:"horizontal",arrowScaleFactor:1,dash:{length:10,gap:5,altLength:void 0},inheritColor:"from"},configurePhysics:!1,physics:{barnesHut:{enabled:!0,thetaInverted:2,gravitationalConstant:-2e3,centralGravity:.3,springLength:95,springConstant:.04,damping:.09},repulsion:{centralGravity:0,springLength:200,springConstant:.05,nodeDistance:100,damping:.09},hierarchicalRepulsion:{enabled:!1,centralGravity:0,springLength:100,springConstant:.01,nodeDistance:150,damping:.09},damping:null,centralGravity:null,springLength:null,springConstant:null},clustering:{enabled:!1,initialMaxNodes:100,clusterThreshold:500,reduceToNodes:300,chainThreshold:.4,clusterEdgeThreshold:20,sectorThreshold:100,screenSizeThreshold:.2,fontSizeMultiplier:4,maxFontSize:1e3,forceAmplification:.1,distanceAmplification:.1,edgeGrowth:20,nodeScaling:{width:1,height:1,radius:1},maxNodeSizeIncrements:600,activeAreaBoxSize:80,clusterLevelDifference:2},navigation:{enabled:!1},keyboard:{enabled:!1,speed:{x:10,y:10,zoom:.02}},dataManipulation:{enabled:!1,initiallyVisible:!1},hierarchicalLayout:{enabled:!1,levelSeparation:150,nodeSpacing:100,direction:"UD",layout:"hubsize"},freezeForStabilization:!1,smoothCurves:{enabled:!0,dynamic:!0,type:"continuous",roundness:.5},maxVelocity:30,minVelocity:.1,stabilize:!0,stabilizationIterations:1e3,zoomExtentOnStabilize:!0,locale:"en",locales:_,tooltip:{delay:300,fontColor:"black",fontSize:14,fontFace:"verdana",color:{border:"#666",background:"#FFFFC6"}},dragNetwork:!0,dragNodes:!0,zoomable:!0,hover:!1,hideEdgesOnDrag:!1,hideNodesOnDrag:!1,width:"100%",height:"100%",selectable:!0},this.constants=a.extend({},this.defaultOptions),this.pixelRatio=1,this.hoverObj={nodes:{},edges:{}},this.controlNodesActive=!1,this.navigationHammers={existing:[],_new:[]},this.animationSpeed=1/this.renderRefreshRate,this.animationEasingFunction="easeInOutQuint",this.easingTime=0,this.sourceScale=0,this.targetScale=0,this.sourceTranslation=0,this.targetTranslation=0,this.lockedOnNodeId=null,this.lockedOnNodeOffset=null,this.touchTime=0;var o=this;this.groups=new u,this.images=new m,this.images.setOnloadCallback(function(){o._redraw()}),this.xIncrement=0,this.yIncrement=0,this.zoomIncrement=0,this._loadPhysicsSystem(),this._create(),this._loadSectorSystem(),this._loadClusterSystem(),this._loadSelectionSystem(),this._loadHierarchySystem(),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1),this.setOptions(i),this.freezeSimulation=!1,this.cachedFunctions={},this.startedStabilization=!1,this.stabilized=!1,this.stabilizationIterations=null,this.draggingNodes=!1,this.calculationNodes={},this.calculationNodeIndices=[],this.nodeIndices=[],this.nodes={},this.edges={},this.canvasTopLeft={x:0,y:0},this.canvasBottomRight={x:0,y:0},this.pointerPosition={x:0,y:0},this.areaCenter={},this.scale=1,this.previousScale=this.scale,this.nodesData=null,this.edgesData=null,this.nodesListeners={add:function(t,e){o._addNodes(e.items),o.start()},update:function(t,e){o._updateNodes(e.items,e.data),o.start()},remove:function(t,e){o._removeNodes(e.items),o.start()}},this.edgesListeners={add:function(t,e){o._addEdges(e.items),o.start()},update:function(t,e){o._updateEdges(e.items),o.start()},remove:function(t,e){o._removeEdges(e.items),o.start()}},this.moving=!0,this.timer=void 0,this.setData(e,this.constants.clustering.enabled||this.constants.hierarchicalLayout.enabled),this.initializing=!1,1==this.constants.hierarchicalLayout.enabled?this._setupHierarchicalLayout():0==this.constants.stabilize&&this.zoomExtent(void 0,!0,this.constants.clustering.enabled),this.constants.clustering.enabled&&this.startWithClustering()}var o=i(56),n=i(45),r=i(57),a=i(1),h=i(47),d=i(3),l=i(4),c=i(42),p=i(43),u=i(38),m=i(39),f=i(40),g=i(37),v=i(41),y=i(54),b=i(55),_=i(49);i(50),o(s.prototype),s.prototype._determineBrowserMethod=function(){var t=navigator.userAgent.toLowerCase();this.requiresTimeout=!1,-1!=t.indexOf("msie 9.0")?this.requiresTimeout=!0:-1!=t.indexOf("safari")&&t.indexOf("chrome")<=-1&&(this.requiresTimeout=!0)},s.prototype._getScriptPath=function(){for(var t=document.getElementsByTagName("script"),e=0;et.boundingBox.left&&(s=t.boundingBox.left),ot.boundingBox.bottom&&(e=t.boundingBox.bottom),i=this.constants.clustering.initialMaxNodes?49.07548/(n+142.05338)+91444e-8:12.662/(n+7.4147)+.0964822:1==this.constants.clustering.enabled&&n>=this.constants.clustering.initialMaxNodes?77.5271985/(n+187.266146)+476710517e-13:30.5062972/(n+19.93597763)+.08413486;var r=Math.min(this.frame.canvas.clientWidth/600,this.frame.canvas.clientHeight/600);s*=r}else{var a=1.1*Math.abs(o.maxX-o.minX),h=1.1*Math.abs(o.maxY-o.minY),d=this.frame.canvas.clientWidth/a,l=this.frame.canvas.clientHeight/h;s=l>=d?d:l}s>1&&(s=1);var c=this._findCenter(o);if(0==i){var p={position:c,scale:s,animation:t};this.moveTo(p),this.moving=!0,this.start()}else c.x*=s,c.y*=s,c.x-=.5*this.frame.canvas.clientWidth,c.y-=.5*this.frame.canvas.clientHeight,this._setScale(s),this._setTranslation(-c.x,-c.y)},s.prototype._updateNodeIndexList=function(){this._clearNodeIndexList();for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodeIndices.push(t)},s.prototype.setData=function(t,e){if(void 0===e&&(e=!1),this.initializing=!0,t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(1==this.constants.dataManipulation.enabled&&this._createManipulatorBar(),this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var i=c.DOTToGraph(t.dot);return void this.setData(i)}}else if(t&&t.gephi){if(t&&t.gephi){var s=p.parseGephi(t.gephi);return void this.setData(s)}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this._putDataInSector(),0==e&&(1==this.constants.hierarchicalLayout.enabled?(this._resetLevels(),this._setupHierarchicalLayout()):this.constants.stabilize&&this._stabilize(),this.start()),this.initializing=!1},s.prototype.setOptions=function(t){if(t){var e,i=["nodes","edges","smoothCurves","hierarchicalLayout","clustering","navigation","keyboard","dataManipulation","onAdd","onEdit","onEditEdge","onConnect","onDelete","clickToUse"];if(a.selectiveNotDeepExtend(i,this.constants,t),a.selectiveNotDeepExtend(["color"],this.constants.nodes,t.nodes),a.selectiveNotDeepExtend(["color","length"],this.constants.edges,t.edges),t.physics&&(a.mergeOptions(this.constants.physics,t.physics,"barnesHut"),a.mergeOptions(this.constants.physics,t.physics,"repulsion"),t.physics.hierarchicalRepulsion)){this.constants.hierarchicalLayout.enabled=!0,this.constants.physics.hierarchicalRepulsion.enabled=!0,this.constants.physics.barnesHut.enabled=!1; for(e in t.physics.hierarchicalRepulsion)t.physics.hierarchicalRepulsion.hasOwnProperty(e)&&(this.constants.physics.hierarchicalRepulsion[e]=t.physics.hierarchicalRepulsion[e])}if(t.onAdd&&(this.triggerFunctions.add=t.onAdd),t.onEdit&&(this.triggerFunctions.edit=t.onEdit),t.onEditEdge&&(this.triggerFunctions.editEdge=t.onEditEdge),t.onConnect&&(this.triggerFunctions.connect=t.onConnect),t.onDelete&&(this.triggerFunctions.del=t.onDelete),a.mergeOptions(this.constants,t,"smoothCurves"),a.mergeOptions(this.constants,t,"hierarchicalLayout"),a.mergeOptions(this.constants,t,"clustering"),a.mergeOptions(this.constants,t,"navigation"),a.mergeOptions(this.constants,t,"keyboard"),a.mergeOptions(this.constants,t,"dataManipulation"),t.dataManipulation&&(this.editMode=this.constants.dataManipulation.initiallyVisible),t.edges&&(void 0!==t.edges.color&&(a.isString(t.edges.color)?(this.constants.edges.color={},this.constants.edges.color.color=t.edges.color,this.constants.edges.color.highlight=t.edges.color,this.constants.edges.color.hover=t.edges.color):(void 0!==t.edges.color.color&&(this.constants.edges.color.color=t.edges.color.color),void 0!==t.edges.color.highlight&&(this.constants.edges.color.highlight=t.edges.color.highlight),void 0!==t.edges.color.hover&&(this.constants.edges.color.hover=t.edges.color.hover)),this.constants.edges.inheritColor=!1),t.edges.fontColor||void 0!==t.edges.color&&(a.isString(t.edges.color)?this.constants.edges.fontColor=t.edges.color:void 0!==t.edges.color.color&&(this.constants.edges.fontColor=t.edges.color.color))),t.nodes&&t.nodes.color){var s=a.parseColor(t.nodes.color);this.constants.nodes.color.background=s.background,this.constants.nodes.color.border=s.border,this.constants.nodes.color.highlight.background=s.highlight.background,this.constants.nodes.color.highlight.border=s.highlight.border,this.constants.nodes.color.hover.background=s.hover.background,this.constants.nodes.color.hover.border=s.hover.border}if(t.groups)for(var o in t.groups)if(t.groups.hasOwnProperty(o)){var n=t.groups[o];this.groups.add(o,n)}if(t.tooltip){for(e in t.tooltip)t.tooltip.hasOwnProperty(e)&&(this.constants.tooltip[e]=t.tooltip[e]);t.tooltip.color&&(this.constants.tooltip.color=a.parseColor(t.tooltip.color))}if("clickToUse"in t&&(t.clickToUse?this.activator||(this.activator=new b(this.frame),this.activator.on("change",this._createKeyBinds.bind(this))):this.activator&&(this.activator.destroy(),delete this.activator)),t.labels)throw new Error('Option "labels" is deprecated. Use options "locale" and "locales" instead.');this._loadPhysicsSystem(),this._loadNavigationControls(),this._loadManipulationSystem(),this._configureSmoothCurves(),this._createKeyBinds(),this.setSize(this.constants.width,this.constants.height),this.moving=!0,this.start()}},s.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="vis network-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),this.frame.canvas.getContext){var t=this.frame.canvas.getContext("2d");this.pixelRatio=(window.devicePixelRatio||1)/(t.webkitBackingStorePixelRatio||t.mozBackingStorePixelRatio||t.msBackingStorePixelRatio||t.oBackingStorePixelRatio||t.backingStorePixelRatio||1),this.frame.canvas.getContext("2d").setTransform(this.pixelRatio,0,0,this.pixelRatio,0,0)}else{var e=document.createElement("DIV");e.style.color="red",e.style.fontWeight="bold",e.style.padding="10px",e.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(e)}var i=this;this.drag={},this.pinch={},this.hammer=n(this.frame.canvas,{prevent_default:!0}),this.hammer.on("tap",i._onTap.bind(i)),this.hammer.on("doubletap",i._onDoubleTap.bind(i)),this.hammer.on("hold",i._onHold.bind(i)),this.hammer.on("pinch",i._onPinch.bind(i)),this.hammer.on("touch",i._onTouch.bind(i)),this.hammer.on("dragstart",i._onDragStart.bind(i)),this.hammer.on("drag",i._onDrag.bind(i)),this.hammer.on("dragend",i._onDragEnd.bind(i)),this.hammer.on("mousewheel",i._onMouseWheel.bind(i)),this.hammer.on("DOMMouseScroll",i._onMouseWheel.bind(i)),this.hammer.on("mousemove",i._onMouseMoveTitle.bind(i)),this.hammerFrame=n(this.frame,{prevent_default:!0}),this.hammerFrame.on("release",i._onRelease.bind(i)),this.containerElement.appendChild(this.frame)},s.prototype._createKeyBinds=function(){var t=this;void 0!==this.keycharm&&this.keycharm.destroy(),this.keycharm=r(),this.keycharm.reset(),this.constants.keyboard.enabled&&this.isActive()&&(this.keycharm.bind("up",this._moveUp.bind(t),"keydown"),this.keycharm.bind("up",this._yStopMoving.bind(t),"keyup"),this.keycharm.bind("down",this._moveDown.bind(t),"keydown"),this.keycharm.bind("down",this._yStopMoving.bind(t),"keyup"),this.keycharm.bind("left",this._moveLeft.bind(t),"keydown"),this.keycharm.bind("left",this._xStopMoving.bind(t),"keyup"),this.keycharm.bind("right",this._moveRight.bind(t),"keydown"),this.keycharm.bind("right",this._xStopMoving.bind(t),"keyup"),this.keycharm.bind("=",this._zoomIn.bind(t),"keydown"),this.keycharm.bind("=",this._stopZoom.bind(t),"keyup"),this.keycharm.bind("num+",this._zoomIn.bind(t),"keydown"),this.keycharm.bind("num+",this._stopZoom.bind(t),"keyup"),this.keycharm.bind("num-",this._zoomOut.bind(t),"keydown"),this.keycharm.bind("num-",this._stopZoom.bind(t),"keyup"),this.keycharm.bind("-",this._zoomOut.bind(t),"keydown"),this.keycharm.bind("-",this._stopZoom.bind(t),"keyup"),this.keycharm.bind("[",this._zoomIn.bind(t),"keydown"),this.keycharm.bind("[",this._stopZoom.bind(t),"keyup"),this.keycharm.bind("]",this._zoomOut.bind(t),"keydown"),this.keycharm.bind("]",this._stopZoom.bind(t),"keyup"),this.keycharm.bind("pageup",this._zoomIn.bind(t),"keydown"),this.keycharm.bind("pageup",this._stopZoom.bind(t),"keyup"),this.keycharm.bind("pagedown",this._zoomOut.bind(t),"keydown"),this.keycharm.bind("pagedown",this._stopZoom.bind(t),"keyup")),1==this.constants.dataManipulation.enabled&&(this.keycharm.bind("esc",this._createManipulatorBar.bind(t)),this.keycharm.bind("delete",this._deleteSelected.bind(t)))},s.prototype.destroy=function(){this.start=function(){},this.redraw=function(){},this.timer=!1,this._cleanupPhysicsConfiguration(),this.keycharm.reset(),this.hammer.dispose(),this.off(),this._recursiveDOMDelete(this.containerElement)},s.prototype._recursiveDOMDelete=function(t){for(;1==t.hasChildNodes();)this._recursiveDOMDelete(t.firstChild),t.removeChild(t.firstChild)},s.prototype._getPointer=function(t){return{x:t.pageX-a.getAbsoluteLeft(this.frame.canvas),y:t.pageY-a.getAbsoluteTop(this.frame.canvas)}},s.prototype._onTouch=function(t){(new Date).valueOf()-this.touchTime>100&&(this.drag.pointer=this._getPointer(t.gesture.center),this.drag.pinched=!1,this.pinch.scale=this._getScale(),this.touchTime=(new Date).valueOf(),this._handleTouch(this.drag.pointer))},s.prototype._onDragStart=function(t){this._handleDragStart(t)},s.prototype._handleDragStart=function(t){void 0===this.drag.pointer&&this._onTouch(t);var e=this._getNodeAt(this.drag.pointer);if(this.drag.dragging=!0,this.drag.selection=[],this.drag.translation=this._getTranslation(),this.drag.nodeId=null,this.draggingNodes=!1,null!=e&&1==this.constants.dragNodes){this.draggingNodes=!0,this.drag.nodeId=e.id,e.isSelected()||this._selectObject(e,!1),this.emit("dragStart",{nodeIds:this.getSelection().nodes});for(var i in this.selectionObj.nodes)if(this.selectionObj.nodes.hasOwnProperty(i)){var s=this.selectionObj.nodes[i],o={id:s.id,node:s,x:s.x,y:s.y,xFixed:s.xFixed,yFixed:s.yFixed};s.xFixed=!0,s.yFixed=!0,this.drag.selection.push(o)}}},s.prototype._onDrag=function(t){this._handleOnDrag(t)},s.prototype._handleOnDrag=function(t){if(!this.drag.pinched){this.releaseNode();var e=this._getPointer(t.gesture.center),i=this,s=this.drag,o=s.selection;if(o&&o.length&&1==this.constants.dragNodes){var n=e.x-s.pointer.x,r=e.y-s.pointer.y;o.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._XconvertDOMtoCanvas(i._XconvertCanvasToDOM(t.x)+n)),t.yFixed||(e.y=i._YconvertDOMtoCanvas(i._YconvertCanvasToDOM(t.y)+r))}),this.moving||(this.moving=!0,this.start())}else if(1==this.constants.dragNetwork){if(void 0===this.drag.pointer)return void this._handleDragStart(t);var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw()}}},s.prototype._onDragEnd=function(t){this._handleDragEnd(t)},s.prototype._handleDragEnd=function(){this.drag.dragging=!1;var t=this.drag.selection;t&&t.length?(t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed}),this.moving=!0,this.start()):this._redraw(),0==this.draggingNodes?this.emit("dragEnd",{nodeIds:[]}):this.emit("dragEnd",{nodeIds:this.getSelection().nodes})},s.prototype._onTap=function(t){var e=this._getPointer(t.gesture.center);this.pointerPosition=e,this._handleTap(e)},s.prototype._onDoubleTap=function(t){var e=this._getPointer(t.gesture.center);this._handleDoubleTap(e)},s.prototype._onHold=function(t){var e=this._getPointer(t.gesture.center);this.pointerPosition=e,this._handleOnHold(e)},s.prototype._onRelease=function(t){var e=this._getPointer(t.gesture.center);this._handleOnRelease(e)},s.prototype._onPinch=function(t){var e=this._getPointer(t.gesture.center);this.drag.pinched=!0,"scale"in this.pinch||(this.pinch.scale=1);var i=this.pinch.scale*t.gesture.scale;this._zoom(i,e)},s.prototype._zoom=function(t,e){if(1==this.constants.zoomable){var i=this._getScale();1e-5>t&&(t=1e-5),t>10&&(t=10);var s=null;void 0!==this.drag&&1==this.drag.dragging&&(s=this.DOMtoCanvas(this.drag.pointer));var o=this._getTranslation(),n=t/i,r=(1-n)*e.x+o.x*n,a=(1-n)*e.y+o.y*n;if(this.areaCenter={x:this._XconvertDOMtoCanvas(e.x),y:this._YconvertDOMtoCanvas(e.y)},this._setScale(t),this._setTranslation(r,a),this.updateClustersDefault(),null!=s){var h=this.canvasToDOM(s);this.drag.pointer.x=h.x,this.drag.pointer.y=h.y}return this._redraw(),t>i?this.emit("zoom",{direction:"+"}):this.emit("zoom",{direction:"-"}),t}},s.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){var i=this._getScale(),s=e/10;0>e&&(s/=1-s),i*=1+s;var o=h.fakeGesture(this,t),n=this._getPointer(o.center);this._zoom(i,n)}t.preventDefault()},s.prototype._onMouseMoveTitle=function(t){var e=h.fakeGesture(this,t),i=this._getPointer(e.center);this.popupObj&&this._checkHidePopup(i);var s=this,o=function(){s._checkShowPopup(i)};if(this.popupTimer&&clearInterval(this.popupTimer),this.drag.dragging||(this.popupTimer=setTimeout(o,this.constants.tooltip.delay)),1==this.constants.hover){for(var n in this.hoverObj.edges)this.hoverObj.edges.hasOwnProperty(n)&&(this.hoverObj.edges[n].hover=!1,delete this.hoverObj.edges[n]);var r=this._getNodeAt(i);null==r&&(r=this._getEdgeAt(i)),null!=r&&this._hoverObject(r);for(var a in this.hoverObj.nodes)this.hoverObj.nodes.hasOwnProperty(a)&&(r instanceof f&&r.id!=a||r instanceof g||null==r)&&(this._blurObject(this.hoverObj.nodes[a]),delete this.hoverObj.nodes[a]);this.redraw()}},s.prototype._checkShowPopup=function(t){var e,i={left:this._XconvertDOMtoCanvas(t.x),top:this._YconvertDOMtoCanvas(t.y),right:this._XconvertDOMtoCanvas(t.x),bottom:this._YconvertDOMtoCanvas(t.y)},s=this.popupObj,o=!1;if(void 0==this.popupObj){var n=this.nodes,r=[];for(e in n)if(n.hasOwnProperty(e)){var a=n[e];a.isOverlappingWith(i)&&void 0!==a.getTitle()&&r.push(e)}r.length>0&&(this.popupObj=this.nodes[r[r.length-1]],o=!0)}if(void 0===this.popupObj&&0==o){var h=this.edges,d=[];for(e in h)if(h.hasOwnProperty(e)){var l=h[e];l.connected&&void 0!==l.getTitle()&&l.isOverlappingWith(i)&&d.push(e)}d.length>0&&(this.popupObj=this.edges[d[d.length-1]])}if(this.popupObj){if(this.popupObj!=s){var c=this;c.popup||(c.popup=new v(c.frame,c.constants.tooltip)),c.popup.setPosition(t.x-3,t.y-3),c.popup.setText(c.popupObj.getTitle()),c.popup.show()}}else this.popup&&this.popup.hide()},s.prototype._checkHidePopup=function(t){this.popupObj&&this._getNodeAt(t)||(this.popupObj=void 0,this.popup&&this.popup.hide())},s.prototype.setSize=function(t,e){var i=!1,s=this.frame.canvas.width,o=this.frame.canvas.height;t!=this.constants.width||e!=this.constants.height||this.frame.style.width!=t||this.frame.style.height!=e?(this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth*this.pixelRatio,this.frame.canvas.height=this.frame.canvas.clientHeight*this.pixelRatio,this.constants.width=t,this.constants.height=e,i=!0):(this.frame.canvas.width!=this.frame.canvas.clientWidth*this.pixelRatio&&(this.frame.canvas.width=this.frame.canvas.clientWidth*this.pixelRatio,i=!0),this.frame.canvas.height!=this.frame.canvas.clientHeight*this.pixelRatio&&(this.frame.canvas.height=this.frame.canvas.clientHeight*this.pixelRatio,i=!0)),1==i&&this.emit("resize",{width:this.frame.canvas.width*this.pixelRatio,height:this.frame.canvas.height*this.pixelRatio,oldWidth:s*this.pixelRatio,oldHeight:o*this.pixelRatio})},s.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof d||t instanceof l)this.nodesData=t;else if(Array.isArray(t))this.nodesData=new d,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new d}if(e&&a.forEach(this.nodesListeners,function(t,i){e.off(i,t)}),this.nodes={},this.nodesData){var i=this;a.forEach(this.nodesListeners,function(t,e){i.nodesData.on(e,t)});var s=this.nodesData.getIds();this._addNodes(s)}this._updateSelection()},s.prototype._addNodes=function(t){for(var e,i=0,s=t.length;s>i;i++){e=t[i];var o=this.nodesData.get(e),n=new f(o,this.images,this.groups,this.constants);if(this.nodes[e]=n,!(0!=n.xFixed&&0!=n.yFixed||null!==n.x&&null!==n.y)){var r=1*t.length+10,a=2*Math.PI*Math.random();0==n.xFixed&&(n.x=r*Math.cos(a)),0==n.yFixed&&(n.y=r*Math.sin(a))}this.moving=!0}this._updateNodeIndexList(),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this._updateCalculationNodes(),this._reconnectEdges(),this._updateValueRange(this.nodes),this.updateLabels()},s.prototype._updateNodes=function(t,e){for(var i=this.nodes,s=0,o=t.length;o>s;s++){var n=t[s],r=i[n],a=e[s];r?r.setProperties(a,this.constants):(r=new f(properties,this.images,this.groups,this.constants),i[n]=r)}this.moving=!0,1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this._updateNodeIndexList(),this._updateValueRange(i)},s.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,s=t.length;s>i;i++){var o=t[i];delete e[o]}this._updateNodeIndexList(),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this._updateCalculationNodes(),this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},s.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof d||t instanceof l)this.edgesData=t;else if(Array.isArray(t))this.edgesData=new d,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new d}if(e&&a.forEach(this.edgesListeners,function(t,i){e.off(i,t)}),this.edges={},this.edgesData){var i=this;a.forEach(this.edgesListeners,function(t,e){i.edgesData.on(e,t)});var s=this.edgesData.getIds();this._addEdges(s)}this._reconnectEdges()},s.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,s=0,o=t.length;o>s;s++){var n=t[s],r=e[n];r&&r.disconnect();var a=i.get(n,{showInternalIds:!0});e[n]=new g(a,this,this.constants)}this.moving=!0,this._updateValueRange(e),this._createBezierNodes(),this._updateCalculationNodes(),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout())},s.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,s=0,o=t.length;o>s;s++){var n=t[s],r=i.get(n),a=e[n];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new g(r,this,this.constants),this.edges[n]=a)}this._createBezierNodes(),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this.moving=!0,this._updateValueRange(e)},s.prototype._removeEdges=function(t){for(var e=this.edges,i=0,s=t.length;s>i;i++){var o=t[i],n=e[o];n&&(null!=n.via&&delete this.sectors.support.nodes[n.via.id],n.disconnect(),delete e[o])}this.moving=!0,this._updateValueRange(e),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this._updateCalculationNodes()},s.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[],e[t].dynamicEdges=[]);for(t in i)if(i.hasOwnProperty(t)){var s=i[t];s.from=null,s.to=null,s.connect()}},s.prototype._updateValueRange=function(t){var e,i=void 0,s=void 0;for(e in t)if(t.hasOwnProperty(e)){var o=t[e].getValue();void 0!==o&&(i=void 0===i?o:Math.min(o,i),s=void 0===s?o:Math.max(o,s))}if(void 0!==i&&void 0!==s)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,s)},s.prototype.redraw=function(){this.setSize(this.constants.width,this.constants.height),this._redraw()},s.prototype._redraw=function(t){var e=this.frame.canvas.getContext("2d");e.setTransform(this.pixelRatio,0,0,this.pixelRatio,0,0);var i=this.frame.canvas.width*this.pixelRatio,s=this.frame.canvas.height*this.pixelRatio;e.clearRect(0,0,i,s),e.save(),e.translate(this.translation.x,this.translation.y),e.scale(this.scale,this.scale),this.canvasTopLeft={x:this._XconvertDOMtoCanvas(0),y:this._YconvertDOMtoCanvas(0)},this.canvasBottomRight={x:this._XconvertDOMtoCanvas(this.frame.canvas.clientWidth*this.pixelRatio),y:this._YconvertDOMtoCanvas(this.frame.canvas.clientHeight*this.pixelRatio)},1!=t&&(this._doInAllSectors("_drawAllSectorNodes",e),(0==this.drag.dragging||void 0===this.drag.dragging||0==this.constants.hideEdgesOnDrag)&&this._doInAllSectors("_drawEdges",e)),(0==this.drag.dragging||void 0===this.drag.dragging||0==this.constants.hideNodesOnDrag)&&this._doInAllSectors("_drawNodes",e,!1),1!=t&&1==this.controlNodesActive&&this._doInAllSectors("_drawControlNodes",e),e.restore(),1==t&&e.clearRect(0,0,i,s)},s.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e),this.emit("viewChanged")},s.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},s.prototype._setScale=function(t){this.scale=t},s.prototype._getScale=function(){return this.scale},s.prototype._XconvertDOMtoCanvas=function(t){return(t-this.translation.x)/this.scale},s.prototype._XconvertCanvasToDOM=function(t){return t*this.scale+this.translation.x},s.prototype._YconvertDOMtoCanvas=function(t){return(t-this.translation.y)/this.scale},s.prototype._YconvertCanvasToDOM=function(t){return t*this.scale+this.translation.y},s.prototype.canvasToDOM=function(t){return{x:this._XconvertCanvasToDOM(t.x),y:this._YconvertCanvasToDOM(t.y)}},s.prototype.DOMtoCanvas=function(t){return{x:this._XconvertDOMtoCanvas(t.x),y:this._YconvertDOMtoCanvas(t.y)}},s.prototype._drawNodes=function(t,e){void 0===e&&(e=!1);var i=this.nodes,s=[];for(var o in i)i.hasOwnProperty(o)&&(i[o].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight),i[o].isSelected()?s.push(o):(i[o].inArea()||e)&&i[o].draw(t));for(var n=0,r=s.length;r>n;n++)(i[s[n]].inArea()||e)&&i[s[n]].draw(t)},s.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var s=e[i];s.setScale(this.scale),s.connected&&e[i].draw(t)}},s.prototype._drawControlNodes=function(t){var e=this.edges;for(var i in e)e.hasOwnProperty(i)&&e[i]._drawControlNodes(t)},s.prototype._stabilize=function(){1==this.constants.freezeForStabilization&&this._freezeDefinedNodes();for(var t=0;this.moving&&t0)for(t in i)i.hasOwnProperty(t)&&(i[t].discreteStepLimited(e,this.constants.maxVelocity),s=!0);else for(t in i)i.hasOwnProperty(t)&&(i[t].discreteStep(e),s=!0);if(1==s){var o=this.constants.minVelocity/Math.max(this.scale,.05);return o>.5*this.constants.maxVelocity?!0:this._isMoving(o)}return!1},s.prototype._revertPhysicsState=function(){var t=this.nodes;for(var e in t)t.hasOwnProperty(e)&&t[e].revertPosition()},s.prototype._revertPhysicsTick=function(){this._doInAllActiveSectors("_revertPhysicsState"),1==this.constants.smoothCurves.enabled&&1==this.constants.smoothCurves.dynamic&&this._doInSupportSector("_revertPhysicsState")},s.prototype._physicsTick=function(){if(!this.freezeSimulation&&1==this.moving){var t=!1,e=!1;this._doInAllActiveSectors("_initializeForceCalculation");var i=this._doInAllActiveSectors("_discreteStepNodes");1==this.constants.smoothCurves.enabled&&1==this.constants.smoothCurves.dynamic&&(e=this._doInSupportSector("_discreteStepNodes"));for(var s=0;s2*e||1==this.runDoubleSpeed)&&1==this.moving&&(this._physicsTick(),0!=this.renderTime&&(this.runDoubleSpeed=!0));var i=Date.now();this._redraw(),this.renderTime=Date.now()-i,this.start()},"undefined"!=typeof window&&(window.requestAnimationFrame=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame),s.prototype.start=function(){if(1==this.moving||0!=this.xIncrement||0!=this.yIncrement||0!=this.zoomIncrement)this.timer||(this.timer=1==this.requiresTimeout?window.setTimeout(this._animationStep.bind(this),this.renderTimestep):window.requestAnimationFrame(this._animationStep.bind(this)));else if(this._redraw(),this.stabilizationIterations>1){var t=this,e={iterations:t.stabilizationIterations};this.stabilizationIterations=0,this.startedStabilization=!1,setTimeout(function(){t.emit("stabilized",e)},0)}else this.stabilizationIterations=0},s.prototype._handleNavigation=function(){if(0!=this.xIncrement||0!=this.yIncrement){var t=this._getTranslation();this._setTranslation(t.x+this.xIncrement,t.y+this.yIncrement)}if(0!=this.zoomIncrement){var e={x:this.frame.canvas.clientWidth/2,y:this.frame.canvas.clientHeight/2};this._zoom(this.scale*(1+this.zoomIncrement),e)}},s.prototype.toggleFreeze=function(){0==this.freezeSimulation?this.freezeSimulation=!0:(this.freezeSimulation=!1,this.start())},s.prototype._configureSmoothCurves=function(t){if(void 0===t&&(t=!0),1==this.constants.smoothCurves.enabled&&1==this.constants.smoothCurves.dynamic){this._createBezierNodes();for(var e in this.sectors.support.nodes)this.sectors.support.nodes.hasOwnProperty(e)&&void 0===this.edges[this.sectors.support.nodes[e].parentEdgeId]&&delete this.sectors.support.nodes[e]}else{this.sectors.support.nodes={};for(var i in this.edges)this.edges.hasOwnProperty(i)&&(this.edges[i].via=null)}this._updateCalculationNodes(),t||(this.moving=!0,this.start())},s.prototype._createBezierNodes=function(){if(1==this.constants.smoothCurves.enabled&&1==this.constants.smoothCurves.dynamic)for(var t in this.edges)if(this.edges.hasOwnProperty(t)){var e=this.edges[t];if(null==e.via){var i="edgeId:".concat(e.id);this.sectors.support.nodes[i]=new f({id:i,mass:1,shape:"circle",image:"",internalMultiplier:1},{},{},this.constants),e.via=this.sectors.support.nodes[i],e.via.parentEdgeId=e.id,e.positionBezierNode()}}},s.prototype._initializeMixinLoaders=function(){for(var t in y)y.hasOwnProperty(t)&&(s.prototype[t]=y[t])},s.prototype.storePosition=function(){console.log("storePosition is depricated: use .storePositions() from now on."),this.storePositions()},s.prototype.storePositions=function(){var t=[];for(var e in this.nodes)if(this.nodes.hasOwnProperty(e)){var i=this.nodes[e],s=!this.nodes.xFixed,o=!this.nodes.yFixed;(this.nodesData._data[e].x!=Math.round(i.x)||this.nodesData._data[e].y!=Math.round(i.y))&&t.push({id:e,x:Math.round(i.x),y:Math.round(i.y),allowedToMoveX:s,allowedToMoveY:o})}this.nodesData.update(t)},s.prototype.getPositions=function(t){var e={};if(void 0!==t){if(1==Array.isArray(t)){for(var i=0;i=1&&(this.easingTime=0,this._redraw=null!=this.lockedOnNodeId?this._lockedRedraw:this._classicRedraw,this.emit("animationFinished"))},s.prototype._classicRedraw=function(){},s.prototype.isActive=function(){return!this.activator||this.activator.active},s.prototype.setScale=function(){return this._setScale()},s.prototype.getScale=function(){return this._getScale()},s.prototype.getCenterCoordinates=function(){return this.DOMtoCanvas({x:.5*this.frame.canvas.clientWidth,y:.5*this.frame.canvas.clientHeight})},s.prototype.getBoundingBox=function(t){return void 0!==this.nodes[t]?this.nodes[t].boundingBox:void 0},t.exports=s},function(t,e,i){function s(t,e,i){if(!e)throw"No network provided";var s=["edges","physics"],n=o.selectiveBridgeObject(s,i);this.options=n.edges,this.physics=n.physics,this.options.smoothCurves=i.smoothCurves,this.network=e,this.id=void 0,this.fromId=void 0,this.toId=void 0,this.title=void 0,this.widthSelected=this.options.width*this.options.widthSelectionMultiplier,this.value=void 0,this.selected=!1,this.hover=!1,this.labelDimensions={top:0,left:0,width:0,height:0,yLine:0},this.dirtyLabel=!0,this.from=null,this.to=null,this.via=null,this.fromBackup=null,this.toBackup=null,this.originalFromId=[],this.originalToId=[],this.connected=!1,this.widthFixed=!1,this.lengthFixed=!1,this.setProperties(t),this.controlNodesEnabled=!1,this.controlNodes={from:null,to:null,positions:{}},this.connectedNode=null}var o=i(1),n=i(40);s.prototype.setProperties=function(t){if(t){var e=["style","fontSize","fontFace","fontColor","fontFill","fontStrokeWidth","fontStrokeColor","width","widthSelectionMultiplier","hoverWidth","arrowScaleFactor","dash","inheritColor","labelAlignment"];switch(o.selectiveDeepExtend(e,this.options,t),void 0!==t.from&&(this.fromId=t.from),void 0!==t.to&&(this.toId=t.to),void 0!==t.id&&(this.id=t.id),void 0!==t.label&&(this.label=t.label,this.dirtyLabel=!0),void 0!==t.title&&(this.title=t.title),void 0!==t.value&&(this.value=t.value),void 0!==t.length&&(this.physics.springLength=t.length),void 0!==t.color&&(this.options.inheritColor=!1,o.isString(t.color)?(this.options.color.color=t.color,this.options.color.highlight=t.color):(void 0!==t.color.color&&(this.options.color.color=t.color.color),void 0!==t.color.highlight&&(this.options.color.highlight=t.color.highlight),void 0!==t.color.hover&&(this.options.color.hover=t.color.hover))),this.connect(),this.widthFixed=this.widthFixed||void 0!==t.width,this.lengthFixed=this.lengthFixed||void 0!==t.length,this.widthSelected=this.options.width*this.options.widthSelectionMultiplier,this.options.style){case"line":this.draw=this._drawLine;break;case"arrow":this.draw=this._drawArrow;break;case"arrow-center":this.draw=this._drawArrowCenter;break;case"dash-line":this.draw=this._drawDashLine;break;default:this.draw=this._drawLine}}},s.prototype.connect=function(){this.disconnect(),this.from=this.network.nodes[this.fromId]||null,this.to=this.network.nodes[this.toId]||null,this.connected=this.from&&this.to,this.connected?(this.from.attachEdge(this),this.to.attachEdge(this)):(this.from&&this.from.detachEdge(this),this.to&&this.to.detachEdge(this))},s.prototype.disconnect=function(){this.from&&(this.from.detachEdge(this),this.from=null),this.to&&(this.to.detachEdge(this),this.to=null),this.connected=!1 },s.prototype.getTitle=function(){return"function"==typeof this.title?this.title():this.title},s.prototype.getValue=function(){return this.value},s.prototype.setValueRange=function(t,e){if(!this.widthFixed&&void 0!==this.value){var i=(this.options.widthMax-this.options.widthMin)/(e-t);this.options.width=(this.value-t)*i+this.options.widthMin,this.widthSelected=this.options.width*this.options.widthSelectionMultiplier}},s.prototype.draw=function(){throw"Method draw not initialized in edge"},s.prototype.isOverlappingWith=function(t){if(this.connected){var e=10,i=this.from.x,s=this.from.y,o=this.to.x,n=this.to.y,r=t.left,a=t.top,h=this._getDistanceToEdge(i,s,o,n,r,a);return e>h}return!1},s.prototype._getColor=function(){var t=this.options.color;return"to"==this.options.inheritColor?t={highlight:this.to.options.color.highlight.border,hover:this.to.options.color.hover.border,color:this.to.options.color.border}:("from"==this.options.inheritColor||1==this.options.inheritColor)&&(t={highlight:this.from.options.color.highlight.border,hover:this.from.options.color.hover.border,color:this.from.options.color.border}),1==this.selected?t.highlight:1==this.hover?t.hover:t.color},s.prototype._drawLine=function(t){if(t.strokeStyle=this._getColor(),t.lineWidth=this._getLineWidth(),this.from!=this.to){var e,i=this._line(t);if(this.label){if(1==this.options.smoothCurves.enabled&&null!=i){var s=.5*(.5*(this.from.x+i.x)+.5*(this.to.x+i.x)),o=.5*(.5*(this.from.y+i.y)+.5*(this.to.y+i.y));e={x:s,y:o}}else e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}}else{var n,r,a=this.physics.springLength/4,h=this.from;h.width||h.resize(t),h.width>h.height?(n=h.x+h.width/2,r=h.y-a):(n=h.x+a,r=h.y-h.height/2),this._circle(t,n,r,a),e=this._pointOnCircle(n,r,a,.5),this._label(t,this.label,e.x,e.y)}},s.prototype._getLineWidth=function(){return 1==this.selected?Math.max(Math.min(this.widthSelected,this.options.widthMax),.3*this.networkScaleInv):1==this.hover?Math.max(Math.min(this.options.hoverWidth,this.options.widthMax),.3*this.networkScaleInv):Math.max(this.options.width,.3*this.networkScaleInv)},s.prototype._getViaCoordinates=function(){if(1==this.options.smoothCurves.dynamic&&1==this.options.smoothCurves.enabled)return this.via;if(0==this.options.smoothCurves.enabled)return{x:0,y:0};var t=null,e=null,i=this.options.smoothCurves.roundness,s=this.options.smoothCurves.type,o=Math.abs(this.from.x-this.to.x),n=Math.abs(this.from.y-this.to.y);return"discrete"==s||"diagonalCross"==s?Math.abs(this.from.x-this.to.x)this.to.y?this.from.xthis.to.x&&(t=this.from.x-i*n,e=this.from.y-i*n):this.from.ythis.to.x&&(t=this.from.x-i*n,e=this.from.y+i*n)),"discrete"==s&&(t=i*n>o?this.from.x:t)):Math.abs(this.from.x-this.to.x)>Math.abs(this.from.y-this.to.y)&&(this.from.y>this.to.y?this.from.xthis.to.x&&(t=this.from.x-i*o,e=this.from.y-i*o):this.from.ythis.to.x&&(t=this.from.x-i*o,e=this.from.y+i*o)),"discrete"==s&&(e=i*o>n?this.from.y:e)):"straightCross"==s?Math.abs(this.from.x-this.to.x)Math.abs(this.from.y-this.to.y)&&(t=this.from.xthis.to.y?this.from.xthis.to.x&&(t=this.from.x-i*n,e=this.from.y-i*n,t=this.to.x>t?this.to.x:t):this.from.ythis.to.x&&(t=this.from.x-i*n,e=this.from.y+i*n,t=this.to.x>t?this.to.x:t)):Math.abs(this.from.x-this.to.x)>Math.abs(this.from.y-this.to.y)&&(this.from.y>this.to.y?this.from.xe?this.to.y:e):this.from.x>this.to.x&&(t=this.from.x-i*o,e=this.from.y-i*o,e=this.to.y>e?this.to.y:e):this.from.ythis.to.x&&(t=this.from.x-i*o,e=this.from.y+i*o,e=this.to.yd;d++){var l=t.measureText(n[d]).width;h=l>h?l:h}var c=this.options.fontSize*r,p=i-h/2,u=s-c/2;this.labelDimensions={top:u,left:p,width:h,height:c,yLine:o}}var o=this.labelDimensions.yLine;t.save(),"horizontal"!=this.options.labelAlignment&&(t.translate(i,o),this._rotateForLabelAlignment(t),i=0,o=0),this._drawLabelRect(t),this._drawLabelText(t,i,o,n,r,a),t.restore()}},s.prototype._rotateForLabelAlignment=function(t){var e=this.from.y-this.to.y,i=this.from.x-this.to.x,s=Math.atan2(e,i);(-1>s&&0>i||s>0&&0>i)&&(s+=Math.PI),t.rotate(s)},s.prototype._drawLabelRect=function(t){if(void 0!==this.options.fontFill&&null!==this.options.fontFill&&"none"!==this.options.fontFill){t.fillStyle=this.options.fontFill;var e=2;"line-center"==this.options.labelAlignment?t.fillRect(.5*-this.labelDimensions.width,.5*-this.labelDimensions.height,this.labelDimensions.width,this.labelDimensions.height):"line-above"==this.options.labelAlignment?t.fillRect(.5*-this.labelDimensions.width,-(this.labelDimensions.height+e),this.labelDimensions.width,this.labelDimensions.height):"line-below"==this.options.labelAlignment?t.fillRect(.5*-this.labelDimensions.width,e,this.labelDimensions.width,this.labelDimensions.height):t.fillRect(this.labelDimensions.left,this.labelDimensions.top,this.labelDimensions.width,this.labelDimensions.height)}},s.prototype._drawLabelText=function(t,e,i,s,o,n){if(t.fillStyle=this.options.fontColor||"black",t.textAlign="center","horizontal"!=this.options.labelAlignment){var r=2;"line-above"==this.options.labelAlignment?(t.textBaseline="alphabetic",i-=2*r):"line-below"==this.options.labelAlignment?(t.textBaseline="hanging",i+=2*r):t.textBaseline="middle"}else t.textBaseline="middle";this.options.fontStrokeWidth>0&&(t.lineWidth=this.options.fontStrokeWidth,t.strokeStyle=this.options.fontStrokeColor,t.lineJoin="round");for(var a=0;o>a;a++)this.options.fontStrokeWidth>0&&t.strokeText(s[a],e,i),t.fillText(s[a],e,i),i+=n},s.prototype._drawDashLine=function(t){t.strokeStyle=this._getColor(),t.lineWidth=this._getLineWidth();var e=null;if(void 0!==t.setLineDash){t.save();var i=[0];i=void 0!==this.options.dash.length&&void 0!==this.options.dash.gap?[this.options.dash.length,this.options.dash.gap]:[5,5],t.setLineDash(i),t.lineDashOffset=0,e=this._line(t),t.setLineDash([0]),t.lineDashOffset=0,t.restore()}else t.beginPath(),t.lineCap="round",void 0!==this.options.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.options.dash.length,this.options.dash.gap,this.options.dash.altLength,this.options.dash.gap]):void 0!==this.options.dash.length&&void 0!==this.options.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.options.dash.length,this.options.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke();if(this.label){var s;if(1==this.options.smoothCurves.enabled&&null!=e){var o=.5*(.5*(this.from.x+e.x)+.5*(this.to.x+e.x)),n=.5*(.5*(this.from.y+e.y)+.5*(this.to.y+e.y));s={x:o,y:n}}else s=this._pointOnLine(.5);this._label(t,this.label,s.x,s.y)}},s.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},s.prototype._pointOnCircle=function(t,e,i,s){var o=2*(s-3/8)*Math.PI;return{x:t+i*Math.cos(o),y:e-i*Math.sin(o)}},s.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this._getColor(),t.fillStyle=t.strokeStyle,t.lineWidth=this._getLineWidth(),this.from!=this.to){var i=this._line(t),s=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),o=(10+5*this.options.width)*this.options.arrowScaleFactor;if(1==this.options.smoothCurves.enabled&&null!=i){var n=.5*(.5*(this.from.x+i.x)+.5*(this.to.x+i.x)),r=.5*(.5*(this.from.y+i.y)+.5*(this.to.y+i.y));e={x:n,y:r}}else e=this._pointOnLine(.5);t.arrow(e.x,e.y,s,o),t.fill(),t.stroke(),this.label&&this._label(t,this.label,e.x,e.y)}else{var a,h,d=.25*Math.max(100,this.physics.springLength),l=this.from;l.width||l.resize(t),l.width>l.height?(a=l.x+.5*l.width,h=l.y-d):(a=l.x+d,h=l.y-.5*l.height),this._circle(t,a,h,d);var s=.2*Math.PI,o=(10+5*this.options.width)*this.options.arrowScaleFactor;e=this._pointOnCircle(a,h,d,.5),t.arrow(e.x,e.y,s,o),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(a,h,d,.5),this._label(t,this.label,e.x,e.y))}},s.prototype._pointOnBezier=function(t){var e=this._getViaCoordinates(),i=Math.pow(1-t,2)*this.from.x+2*t*(1-t)*e.x+Math.pow(t,2)*this.to.x,s=Math.pow(1-t,2)*this.from.y+2*t*(1-t)*e.y+Math.pow(t,2)*this.to.y;return{x:i,y:s}},s.prototype._findBorderPosition=function(t,e){var i,s,o,n,r,a=10,h=0,d=0,l=1,c=.2,p=this.to;for(1==t&&(p=this.from);l>=d&&a>h;){var u=.5*(d+l);if(i=this._pointOnBezier(u),s=Math.atan2(p.y-i.y,p.x-i.x),o=p.distanceToBorder(e,s),n=Math.sqrt(Math.pow(i.x-p.x,2)+Math.pow(i.y-p.y,2)),r=o-n,Math.abs(r)r?0==t?d=u:l=u:0==t?l=u:d=u,h++}return i.t=u,i},s.prototype._drawArrow=function(t){t.strokeStyle=this._getColor(),t.fillStyle=t.strokeStyle,t.lineWidth=this._getLineWidth();var e,i,s;if(this.from!=this.to){if(this._line(t),1==this.options.smoothCurves.enabled){var o=this._getViaCoordinates();s=this._findBorderPosition(!1,t);var n=this._pointOnBezier(Math.max(0,s.t-.1));e=Math.atan2(s.y-n.y,s.x-n.x)}else{e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var r=this.to.x-this.from.x,a=this.to.y-this.from.y,h=Math.sqrt(r*r+a*a),d=this.to.distanceToBorder(t,e),l=(h-d)/h;s={},s.x=(1-l)*this.from.x+l*this.to.x,s.y=(1-l)*this.from.y+l*this.to.y}if(i=(10+5*this.options.width)*this.options.arrowScaleFactor,t.arrow(s.x,s.y,e,i),t.fill(),t.stroke(),this.label){var c;c=1==this.options.smoothCurves.enabled&&null!=o?this._pointOnBezier(.5):this._pointOnLine(.5),this._label(t,this.label,c.x,c.y)}}else{var p,u,m,f=this.from,g=.25*Math.max(100,this.physics.springLength);f.width||f.resize(t),f.width>f.height?(p=f.x+.5*f.width,u=f.y-g,m={x:p,y:f.y,angle:.9*Math.PI}):(p=f.x+g,u=f.y-.5*f.height,m={x:f.x,y:u,angle:.6*Math.PI}),t.beginPath(),t.arc(p,u,g,0,2*Math.PI,!1),t.stroke();var i=(10+5*this.options.width)*this.options.arrowScaleFactor;t.arrow(m.x,m.y,m.angle,i),t.fill(),t.stroke(),this.label&&(c=this._pointOnCircle(p,u,g,.5),this._label(t,this.label,c.x,c.y))}},s.prototype._getDistanceToEdge=function(t,e,i,s,o,n){var r=0;if(this.from!=this.to)if(1==this.options.smoothCurves.enabled){var a,h;if(1==this.options.smoothCurves.enabled&&1==this.options.smoothCurves.dynamic)a=this.via.x,h=this.via.y;else{var d=this._getViaCoordinates();a=d.x,h=d.y}var l,c,p,u,m,f,g,v=1e9;for(c=0;10>c;c++)p=.1*c,u=Math.pow(1-p,2)*t+2*p*(1-p)*a+Math.pow(p,2)*i,m=Math.pow(1-p,2)*e+2*p*(1-p)*h+Math.pow(p,2)*s,c>0&&(l=this._getDistanceToLine(f,g,u,m,o,n),v=v>l?l:v),f=u,g=m;r=v}else r=this._getDistanceToLine(t,e,i,s,o,n);else{var u,m,y,b,_=.25*this.physics.springLength,x=this.from;x.width>x.height?(u=x.x+.5*x.width,m=x.y-_):(u=x.x+_,m=x.y-.5*x.height),y=u-o,b=m-n,r=Math.abs(Math.sqrt(y*y+b*b)-_)}return this.labelDimensions.lefto&&this.labelDimensions.topn?0:r},s.prototype._getDistanceToLine=function(t,e,i,s,o,n){var r=i-t,a=s-e,h=r*r+a*a,d=((o-t)*r+(n-e)*a)/h;d>1?d=1:0>d&&(d=0);var l=t+d*r,c=e+d*a,p=l-o,u=c-n;return Math.sqrt(p*p+u*u)},s.prototype.setScale=function(t){this.networkScaleInv=1/t},s.prototype.select=function(){this.selected=!0},s.prototype.unselect=function(){this.selected=!1},s.prototype.positionBezierNode=function(){null!==this.via&&null!==this.from&&null!==this.to?(this.via.x=.5*(this.from.x+this.to.x),this.via.y=.5*(this.from.y+this.to.y)):(this.via.x=0,this.via.y=0)},s.prototype._drawControlNodes=function(t){if(1==this.controlNodesEnabled){if(null===this.controlNodes.from&&null===this.controlNodes.to){var e="edgeIdFrom:".concat(this.id),i="edgeIdTo:".concat(this.id),s={nodes:{group:"",radius:7,borderWidth:2,borderWidthSelected:2},physics:{damping:0},clustering:{maxNodeSizeIncrements:0,nodeScaling:{width:0,height:0,radius:0}}};this.controlNodes.from=new n({id:e,shape:"dot",color:{background:"#ff0000",border:"#3c3c3c",highlight:{background:"#07f968"}}},{},{},s),this.controlNodes.to=new n({id:i,shape:"dot",color:{background:"#ff0000",border:"#3c3c3c",highlight:{background:"#07f968"}}},{},{},s)}this.controlNodes.positions={},0==this.controlNodes.from.selected&&(this.controlNodes.positions.from=this.getControlNodeFromPosition(t),this.controlNodes.from.x=this.controlNodes.positions.from.x,this.controlNodes.from.y=this.controlNodes.positions.from.y),0==this.controlNodes.to.selected&&(this.controlNodes.positions.to=this.getControlNodeToPosition(t),this.controlNodes.to.x=this.controlNodes.positions.to.x,this.controlNodes.to.y=this.controlNodes.positions.to.y),this.controlNodes.from.draw(t),this.controlNodes.to.draw(t)}else this.controlNodes={from:null,to:null,positions:{}}},s.prototype._enableControlNodes=function(){this.fromBackup=this.from,this.toBackup=this.to,this.controlNodesEnabled=!0},s.prototype._disableControlNodes=function(){this.fromId=this.from.id,this.toId=this.to.id,this.fromId!=this.fromBackup.id?this.fromBackup.detachEdge(this):this.toId!=this.toBackup.id&&this.toBackup.detachEdge(this),this.fromBackup=null,this.toBackup=null,this.controlNodesEnabled=!1},s.prototype._getSelectedControlNode=function(t,e){var i=this.controlNodes.positions,s=Math.sqrt(Math.pow(t-i.from.x,2)+Math.pow(e-i.from.y,2)),o=Math.sqrt(Math.pow(t-i.to.x,2)+Math.pow(e-i.to.y,2));return 15>s?(this.connectedNode=this.from,this.from=this.controlNodes.from,this.controlNodes.from):15>o?(this.connectedNode=this.to,this.to=this.controlNodes.to,this.controlNodes.to):null},s.prototype._restoreControlNodes=function(){1==this.controlNodes.from.selected?(this.from=this.connectedNode,this.connectedNode=null,this.controlNodes.from.unselect()):1==this.controlNodes.to.selected&&(this.to=this.connectedNode,this.connectedNode=null,this.controlNodes.to.unselect())},s.prototype.getControlNodeFromPosition=function(t){var e;if(1==this.options.smoothCurves.enabled)e=this._findBorderPosition(!0,t);else{var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),s=this.to.x-this.from.x,o=this.to.y-this.from.y,n=Math.sqrt(s*s+o*o),r=this.from.distanceToBorder(t,i+Math.PI),a=(n-r)/n;e={},e.x=a*this.from.x+(1-a)*this.to.x,e.y=a*this.from.y+(1-a)*this.to.y}return e},s.prototype.getControlNodeToPosition=function(t){var e;if(1==this.options.smoothCurves.enabled)e=this._findBorderPosition(!1,t);else{var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),s=this.to.x-this.from.x,o=this.to.y-this.from.y,n=Math.sqrt(s*s+o*o),r=this.to.distanceToBorder(t,i),a=(n-r)/n;e={},e.x=(1-a)*this.from.x+a*this.to.x,e.y=(1-a)*this.from.y+a*this.to.y}return e},t.exports=s},function(t,e,i){function s(){this.clear(),this.defaultIndex=0}i(1);s.DEFAULT=[{border:"#2B7CE9",background:"#97C2FC",highlight:{border:"#2B7CE9",background:"#D2E5FF"},hover:{border:"#2B7CE9",background:"#D2E5FF"}},{border:"#FFA500",background:"#FFFF00",highlight:{border:"#FFA500",background:"#FFFFA3"},hover:{border:"#FFA500",background:"#FFFFA3"}},{border:"#FA0A10",background:"#FB7E81",highlight:{border:"#FA0A10",background:"#FFAFB1"},hover:{border:"#FA0A10",background:"#FFAFB1"}},{border:"#41A906",background:"#7BE141",highlight:{border:"#41A906",background:"#A1EC76"},hover:{border:"#41A906",background:"#A1EC76"}},{border:"#E129F0",background:"#EB7DF4",highlight:{border:"#E129F0",background:"#F0B3F5"},hover:{border:"#E129F0",background:"#F0B3F5"}},{border:"#7C29F0",background:"#AD85E4",highlight:{border:"#7C29F0",background:"#D3BDF0"},hover:{border:"#7C29F0",background:"#D3BDF0"}},{border:"#C37F00",background:"#FFA807",highlight:{border:"#C37F00",background:"#FFCA66"},hover:{border:"#C37F00",background:"#FFCA66"}},{border:"#4220FB",background:"#6E6EFD",highlight:{border:"#4220FB",background:"#9B9BFD"},hover:{border:"#4220FB",background:"#9B9BFD"}},{border:"#FD5A77",background:"#FFC0CB",highlight:{border:"#FD5A77",background:"#FFD1D9"},hover:{border:"#FD5A77",background:"#FFD1D9"}},{border:"#4AD63A",background:"#C2FABC",highlight:{border:"#4AD63A",background:"#E6FFE3"},hover:{border:"#4AD63A",background:"#E6FFE3"}}],s.prototype.clear=function(){this.groups={},this.groups.length=function(){var t=0;for(var e in this)this.hasOwnProperty(e)&&t++;return t}},s.prototype.get=function(t){var e=this.groups[t];if(void 0==e){var i=this.defaultIndex%s.DEFAULT.length;this.defaultIndex++,e={},e.color=s.DEFAULT[i],this.groups[t]=e}return e},s.prototype.add=function(t,e){return this.groups[t]=e,e},t.exports=s},function(t){function e(){this.images={},this.imageBroken={},this.callback=void 0}e.prototype.setOnloadCallback=function(t){this.callback=t},e.prototype.load=function(t,e){var i=this.images[t];if(void 0===i){var s=this;i=new Image,i.onload=function(){0==this.width&&(document.body.appendChild(this),this.width=this.offsetWidth,this.height=this.offsetHeight,document.body.removeChild(this)),s.callback&&(s.images[t]=i,s.callback(this))},i.onerror=function(){void 0===e?(console.error("Could not load image:",t),delete this.src,s.callback&&s.callback(this)):s.imageBroken[t]===!0?(console.error("Could not load brokenImage:",e),delete this.src,s.callback&&s.callback(this)):(this.src=e,s.imageBroken[t]=!0)},i.src=t}return i},t.exports=e},function(t,e,i){function s(t,e,i,s){var n=o.selectiveBridgeObject(["nodes"],s);this.options=n.nodes,this.selected=!1,this.hover=!1,this.edges=[],this.dynamicEdges=[],this.reroutedEdges={},this.fontDrawThreshold=3,this.id=void 0,this.allowedToMoveX=!1,this.allowedToMoveY=!1,this.xFixed=!1,this.yFixed=!1,this.horizontalAlignLeft=!0,this.verticalAlignTop=!0,this.baseRadiusValue=s.nodes.radius,this.radiusFixed=!1,this.level=-1,this.preassignedLevel=!1,this.hierarchyEnumerated=!1,this.labelDimensions={top:0,left:0,width:0,height:0,yLine:0},this.boundingBox={top:0,left:0,right:0,bottom:0},this.imagelist=e,this.grouplist=i,this.fx=0,this.fy=0,this.vx=0,this.vy=0,this.x=null,this.y=null,this.previousState={vx:0,vy:0,x:0,y:0},this.damping=s.physics.damping,this.fixedData={x:null,y:null},this.setProperties(t,n),this.resetCluster(),this.dynamicEdgesLength=0,this.clusterSession=0,this.clusterSizeWidthFactor=s.clustering.nodeScaling.width,this.clusterSizeHeightFactor=s.clustering.nodeScaling.height,this.clusterSizeRadiusFactor=s.clustering.nodeScaling.radius,this.maxNodeSizeIncrements=s.clustering.maxNodeSizeIncrements,this.growthIndicator=0,this.networkScaleInv=1,this.networkScale=1,this.canvasTopLeft={x:-300,y:-300},this.canvasBottomRight={x:300,y:300},this.parentEdgeId=null}var o=i(1);s.prototype.revertPosition=function(){this.x=this.previousState.x,this.y=this.previousState.y,this.vx=this.previousState.vx,this.vy=this.previousState.vy},s.prototype.resetCluster=function(){this.formationScale=void 0,this.clusterSize=1,this.containedNodes={},this.containedEdges={},this.clusterSessions=[]},s.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),-1==this.dynamicEdges.indexOf(t)&&this.dynamicEdges.push(t),this.dynamicEdgesLength=this.dynamicEdges.length},s.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&this.edges.splice(e,1),e=this.dynamicEdges.indexOf(t),-1!=e&&this.dynamicEdges.splice(e,1),this.dynamicEdgesLength=this.dynamicEdges.length},s.prototype.setProperties=function(t,e){if(t){var i=["borderWidth","borderWidthSelected","shape","image","brokenImage","radius","fontColor","fontSize","fontFace","fontFill","fontStrokeWidth","fontStrokeColor","group","mass"];if(o.selectiveDeepExtend(i,this.options,t),void 0!==t.id&&(this.id=t.id),void 0!==t.label&&(this.label=t.label,this.originalLabel=t.label),void 0!==t.title&&(this.title=t.title),void 0!==t.x&&(this.x=t.x),void 0!==t.y&&(this.y=t.y),void 0!==t.value&&(this.value=t.value),void 0!==t.level&&(this.level=t.level,this.preassignedLevel=!0),void 0!==t.horizontalAlignLeft&&(this.horizontalAlignLeft=t.horizontalAlignLeft),void 0!==t.verticalAlignTop&&(this.verticalAlignTop=t.verticalAlignTop),void 0!==t.triggerFunction&&(this.triggerFunction=t.triggerFunction),void 0===this.id)throw"Node must have an id";if("number"==typeof this.options.group||"string"==typeof this.options.group&&""!=this.options.group){var s=this.grouplist.get(this.options.group);o.deepExtend(this.options,s),this.options.color=o.parseColor(this.options.color)}if(void 0!==t.radius&&(this.baseRadiusValue=this.options.radius),void 0!==t.color&&(this.options.color=o.parseColor(t.color)),void 0!==this.options.image&&""!=this.options.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.options.image,this.options.brokenImage)}switch(void 0!==t.allowedToMoveX?(this.xFixed=!t.allowedToMoveX,this.allowedToMoveX=t.allowedToMoveX):void 0!==t.x&&0==this.allowedToMoveX&&(this.xFixed=!0),void 0!==t.allowedToMoveY?(this.yFixed=!t.allowedToMoveY,this.allowedToMoveY=t.allowedToMoveY):void 0!==t.y&&0==this.allowedToMoveY&&(this.yFixed=!0),this.radiusFixed=this.radiusFixed||void 0!==t.radius,("image"===this.options.shape||"circularImage"===this.options.shape)&&(this.options.radiusMin=e.nodes.widthMin,this.options.radiusMax=e.nodes.widthMax),this.options.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"circularImage":this.draw=this._drawCircularImage,this.resize=this._resizeCircularImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},s.prototype.select=function(){this.selected=!0,this._reset()},s.prototype.unselect=function(){this.selected=!1,this._reset()},s.prototype.clearSizeCache=function(){this._reset()},s.prototype._reset=function(){this.width=void 0,this.height=void 0},s.prototype.getTitle=function(){return"function"==typeof this.title?this.title():this.title},s.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.options.shape){case"circle":case"dot":return this.options.radius+i;case"ellipse":var s=this.width/2,o=this.height/2,n=Math.sin(e)*s,r=Math.cos(e)*o;return s*o/Math.sqrt(n*n+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},s.prototype._setForce=function(t,e){this.fx=t,this.fy=e},s.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},s.prototype.storeState=function(){this.previousState.x=this.x,this.previousState.y=this.y,this.previousState.vx=this.vx,this.previousState.vy=this.vy},s.prototype.discreteStep=function(t){if(this.storeState(),this.xFixed)this.fx=0,this.vx=0;else{var e=this.damping*this.vx,i=(this.fx-e)/this.options.mass;this.vx+=i*t,this.x+=this.vx*t}if(this.yFixed)this.fy=0,this.vy=0;else{var s=this.damping*this.vy,o=(this.fy-s)/this.options.mass;this.vy+=o*t,this.y+=this.vy*t}},s.prototype.discreteStepLimited=function(t,e){if(this.storeState(),this.xFixed)this.fx=0,this.vx=0;else{var i=this.damping*this.vx,s=(this.fx-i)/this.options.mass;this.vx+=s*t,this.vx=Math.abs(this.vx)>e?this.vx>0?e:-e:this.vx,this.x+=this.vx*t}if(this.yFixed)this.fy=0,this.vy=0;else{var o=this.damping*this.vy,n=(this.fy-o)/this.options.mass;this.vy+=n*t,this.vy=Math.abs(this.vy)>e?this.vy>0?e:-e:this.vy,this.y+=this.vy*t}},s.prototype.isFixed=function(){return this.xFixed&&this.yFixed},s.prototype.isMoving=function(t){var e=Math.sqrt(Math.pow(this.vx,2)+Math.pow(this.vy,2));return e>t},s.prototype.isSelected=function(){return this.selected},s.prototype.getValue=function(){return this.value},s.prototype.getDistance=function(t,e){var i=this.x-t,s=this.y-e;return Math.sqrt(i*i+s*s)},s.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value)if(e==t)this.options.radius=(this.options.radiusMin+this.options.radiusMax)/2;else{var i=(this.options.radiusMax-this.options.radiusMin)/(e-t);this.options.radius=(this.value-t)*i+this.options.radiusMin}this.baseRadiusValue=this.options.radius},s.prototype.draw=function(){throw"Draw method not initialized for node"},s.prototype.resize=function(){throw"Resize method not initialized for node"},s.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},s.prototype._resizeImage=function(){if(!this.width||!this.height){var t,e;if(this.value){this.options.radius=this.baseRadiusValue;var i=this.imageObj.height/this.imageObj.width;void 0!==i?(t=this.options.radius||this.imageObj.width,e=this.options.radius*i||this.imageObj.height):(t=0,e=0)}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e,this.growthIndicator=0,this.width>0&&this.height>0&&(this.width+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeWidthFactor,this.height+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeHeightFactor,this.options.radius+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-t)}},s.prototype._drawImageAtPosition=function(t){if(0!=this.imageObj.width){if(this.clusterSize>1){var e=this.clusterSize>1?10:0;e*=this.networkScaleInv,e=Math.min(.2*this.width,e),t.globalAlpha=.5,t.drawImage(this.imageObj,this.left-e,this.top-e,this.width+2*e,this.height+2*e)}t.globalAlpha=1,t.drawImage(this.imageObj,this.left,this.top,this.width,this.height)}},s.prototype._drawImageLabel=function(t){var e,i=0;if(this.height){i=this.height/2;var s=this.getTextSize(t);s.lineCount>=1&&(i+=s.height/2,i+=3)}e=this.y+i,this._label(t,this.label,this.x,e,void 0)},s.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._drawImageAtPosition(t),this.boundingBox.top=this.top,this.boundingBox.left=this.left,this.boundingBox.right=this.left+this.width,this.boundingBox.bottom=this.top+this.height,this._drawImageLabel(t),this.boundingBox.left=Math.min(this.boundingBox.left,this.labelDimensions.left),this.boundingBox.right=Math.max(this.boundingBox.right,this.labelDimensions.left+this.labelDimensions.width),this.boundingBox.bottom=Math.max(this.boundingBox.bottom,this.boundingBox.bottom+this.labelDimensions.height)},s.prototype._resizeCircularImage=function(t){if(this.imageObj.src&&this.imageObj.width&&this.imageObj.height)this._swapToImageResizeWhenImageLoaded&&(this.width=0,this.height=0,delete this._swapToImageResizeWhenImageLoaded),this._resizeImage(t);else if(!this.width){var e=2*this.options.radius;this.width=e,this.height=e,this.options.radius+=.5*Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.options.radius-.5*e,this._swapToImageResizeWhenImageLoaded=!0}},s.prototype._drawCircularImage=function(t){this._resizeCircularImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=this.left+this.width/2,i=this.top+this.height/2,s=Math.abs(this.height/2);this._drawRawCircle(t,e,i,s),t.save(),t.circle(this.x,this.y,s),t.stroke(),t.clip(),this._drawImageAtPosition(t),t.restore(),this.boundingBox.top=this.y-this.options.radius,this.boundingBox.left=this.x-this.options.radius,this.boundingBox.right=this.x+this.options.radius,this.boundingBox.bottom=this.y+this.options.radius,this._drawImageLabel(t),this.boundingBox.left=Math.min(this.boundingBox.left,this.labelDimensions.left),this.boundingBox.right=Math.max(this.boundingBox.right,this.labelDimensions.left+this.labelDimensions.width),this.boundingBox.bottom=Math.max(this.boundingBox.bottom,this.boundingBox.bottom+this.labelDimensions.height)},s.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=.5*Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeWidthFactor,this.height+=.5*Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeHeightFactor,this.growthIndicator=this.width-(i.width+2*e)}},s.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=this.options.borderWidth,s=this.options.borderWidthSelected||2*this.options.borderWidth;t.strokeStyle=this.selected?this.options.color.highlight.border:this.hover?this.options.color.hover.border:this.options.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.roundRect(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth,this.options.radius),t.stroke()),t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.fillStyle=this.selected?this.options.color.highlight.background:this.hover?this.options.color.hover.background:this.options.color.background,t.roundRect(this.left,this.top,this.width,this.height,this.options.radius),t.fill(),t.stroke(),this.boundingBox.top=this.top,this.boundingBox.left=this.left,this.boundingBox.right=this.left+this.width,this.boundingBox.bottom=this.top+this.height,this._label(t,this.label,this.x,this.y)},s.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),s=i.width+2*e;this.width=s,this.height=s,this.width+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeWidthFactor,this.height+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeHeightFactor,this.options.radius+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-s}},s.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=this.options.borderWidth,s=this.options.borderWidthSelected||2*this.options.borderWidth; -t.strokeStyle=this.selected?this.options.color.highlight.border:this.hover?this.options.color.hover.border:this.options.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.database(this.x-this.width/2-2*t.lineWidth,this.y-.5*this.height-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.fillStyle=this.selected?this.options.color.highlight.background:this.hover?this.options.color.hover.background:this.options.color.background,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this.boundingBox.top=this.top,this.boundingBox.left=this.left,this.boundingBox.right=this.left+this.width,this.boundingBox.bottom=this.top+this.height,this._label(t,this.label,this.x,this.y)},s.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),s=Math.max(i.width,i.height)+2*e;this.options.radius=s/2,this.width=s,this.height=s,this.options.radius+=.5*Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.options.radius-.5*s}},s.prototype._drawRawCircle=function(t,e,i,s){var o=2.5,n=this.options.borderWidth,r=this.options.borderWidthSelected||2*this.options.borderWidth;t.strokeStyle=this.selected?this.options.color.highlight.border:this.hover?this.options.color.hover.border:this.options.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?r:n)+(this.clusterSize>1?o:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.circle(e,i,s+2*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?r:n)+(this.clusterSize>1?o:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.fillStyle=this.selected?this.options.color.highlight.background:this.hover?this.options.color.hover.background:this.options.color.background,t.circle(this.x,this.y,s),t.fill(),t.stroke()},s.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._drawRawCircle(t,this.x,this.y,this.options.radius),this.boundingBox.top=this.y-this.options.radius,this.boundingBox.left=this.x-this.options.radius,this.boundingBox.right=this.x+this.options.radius,this.boundingBox.bottom=this.y+this.options.radius,this._label(t,this.label,this.x,this.y)},s.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.width1&&(t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.ellipse(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.fillStyle=this.selected?this.options.color.highlight.background:this.hover?this.options.color.hover.background:this.options.color.background,t.ellipse(this.left,this.top,this.width,this.height),t.fill(),t.stroke(),this.boundingBox.top=this.top,this.boundingBox.left=this.left,this.boundingBox.right=this.left+this.width,this.boundingBox.bottom=this.top+this.height,this._label(t,this.label,this.x,this.y)},s.prototype._drawDot=function(t){this._drawShape(t,"circle")},s.prototype._drawTriangle=function(t){this._drawShape(t,"triangle")},s.prototype._drawTriangleDown=function(t){this._drawShape(t,"triangleDown")},s.prototype._drawSquare=function(t){this._drawShape(t,"square")},s.prototype._drawStar=function(t){this._drawShape(t,"star")},s.prototype._resizeShape=function(){if(!this.width){this.options.radius=this.baseRadiusValue;var t=2*this.options.radius;this.width=t,this.height=t,this.width+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeWidthFactor,this.height+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeHeightFactor,this.options.radius+=.5*Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-t}},s.prototype._drawShape=function(t,e){this._resizeShape(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var i=2.5,s=this.options.borderWidth,o=this.options.borderWidthSelected||2*this.options.borderWidth,n=2;switch(e){case"dot":n=2;break;case"square":n=2;break;case"triangle":n=3;break;case"triangleDown":n=3;break;case"star":n=4}t.strokeStyle=this.selected?this.options.color.highlight.border:this.hover?this.options.color.hover.border:this.options.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?o:s)+(this.clusterSize>1?i:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t[e](this.x,this.y,this.options.radius+n*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?o:s)+(this.clusterSize>1?i:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.fillStyle=this.selected?this.options.color.highlight.background:this.hover?this.options.color.hover.background:this.options.color.background,t[e](this.x,this.y,this.options.radius),t.fill(),t.stroke(),this.boundingBox.top=this.y-this.options.radius,this.boundingBox.left=this.x-this.options.radius,this.boundingBox.right=this.x+this.options.radius,this.boundingBox.bottom=this.y+this.options.radius,this.label&&(this._label(t,this.label,this.x,this.y+this.height/2,void 0,"hanging",!0),this.boundingBox.left=Math.min(this.boundingBox.left,this.labelDimensions.left),this.boundingBox.right=Math.max(this.boundingBox.right,this.labelDimensions.left+this.labelDimensions.width),this.boundingBox.bottom=Math.max(this.boundingBox.bottom,this.boundingBox.bottom+this.labelDimensions.height))},s.prototype._resizeText=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeWidthFactor,this.height+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeHeightFactor,this.options.radius+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-(i.width+2*e)}},s.prototype._drawText=function(t){this._resizeText(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._label(t,this.label,this.x,this.y),this.boundingBox.top=this.top,this.boundingBox.left=this.left,this.boundingBox.right=this.left+this.width,this.boundingBox.bottom=this.top+this.height},s.prototype._label=function(t,e,i,s,o,n,r){if(e&&Number(this.options.fontSize)*this.networkScale>this.fontDrawThreshold){t.font=(this.selected?"bold ":"")+this.options.fontSize+"px "+this.options.fontFace;var a=e.split("\n"),h=a.length,d=Number(this.options.fontSize),l=s+(1-h)/2*d;1==r&&(l=s+(1-h)/(2*d));for(var c=t.measureText(a[0]).width,p=1;h>p;p++){var u=t.measureText(a[p]).width;c=u>c?u:c}var m=this.options.fontSize*h,f=i-c/2,g=s-m/2;"hanging"==n&&(g+=.5*d,g+=4,l+=4),this.labelDimensions={top:g,left:f,width:c,height:m,yLine:l},void 0!==this.options.fontFill&&null!==this.options.fontFill&&"none"!==this.options.fontFill&&(t.fillStyle=this.options.fontFill,t.fillRect(f,g,c,m)),t.fillStyle=this.options.fontColor||"black",t.textAlign=o||"center",t.textBaseline=n||"middle",this.options.fontStrokeWidth>0&&(t.lineWidth=this.options.fontStrokeWidth,t.strokeStyle=this.options.fontStrokeColor,t.lineJoin="round");for(var p=0;h>p;p++)this.options.fontStrokeWidth&&t.strokeText(a[p],i,l),t.fillText(a[p],i,l),l+=d}},s.prototype.getTextSize=function(t){if(void 0!==this.label){t.font=(this.selected?"bold ":"")+this.options.fontSize+"px "+this.options.fontFace;for(var e=this.label.split("\n"),i=(Number(this.options.fontSize)+4)*e.length,s=0,o=0,n=e.length;n>o;o++)s=Math.max(s,t.measureText(e[o]).width);return{width:s,height:i,lineCount:e.length}}return{width:0,height:0,lineCount:0}},s.prototype.inArea=function(){return void 0!==this.width?this.x+this.width*this.networkScaleInv>=this.canvasTopLeft.x&&this.x-this.width*this.networkScaleInv=this.canvasTopLeft.y&&this.y-this.height*this.networkScaleInv=this.canvasTopLeft.x&&this.x=this.canvasTopLeft.y&&this.ys&&(n=s-e-this.padding),no&&(r=o-i-this.padding),ri;i++)if(e.id===r.nodes[i].id){o=r.nodes[i];break}for(o||(o={id:e.id},t.node&&(o.attr=a(o.attr,t.node))),i=n.length-1;i>=0;i--){var h=n[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(o)&&h.nodes.push(o)}e.attr&&(o.attr=a(o.attr,e.attr))}function l(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=a({},t.edge);e.attr=a(i,e.attr)}}function c(t,e,i,s,o){var n={from:e,to:i,type:s};return t.edge&&(n.attr=a({},t.edge)),n.attr=a(n.attr||{},o),n}function p(){for(N=D.NULL,k="";" "==E||" "==E||"\n"==E||"\r"==E;)o();do{var t=!1;if("#"==E){for(var e=O-1;" "==T.charAt(e)||" "==T.charAt(e);)e--;if("\n"==T.charAt(e)||""==T.charAt(e)){for(;""!=E&&"\n"!=E;)o();t=!0}}if("/"==E&&"/"==n()){for(;""!=E&&"\n"!=E;)o();t=!0}if("/"==E&&"*"==n()){for(;""!=E;){if("*"==E&&"/"==n()){o(),o();break}o()}t=!0}for(;" "==E||" "==E||"\n"==E||"\r"==E;)o()}while(t);if(""==E)return void(N=D.DELIMITER);var i=E+n();if(C[i])return N=D.DELIMITER,k=i,o(),void o();if(C[E])return N=D.DELIMITER,k=E,void o();if(r(E)||"-"==E){for(k+=E,o();r(E);)k+=E,o();return"false"==k?k=!1:"true"==k?k=!0:isNaN(Number(k))||(k=Number(k)),void(N=D.IDENTIFIER)}if('"'==E){for(o();""!=E&&('"'!=E||'"'==E&&'"'==n());)k+=E,'"'==E&&o(),o();if('"'!=E)throw x('End of string " expected');return o(),void(N=D.IDENTIFIER)}for(N=D.UNKNOWN;""!=E;)k+=E,o();throw new SyntaxError('Syntax error in part "'+w(k,30)+'"')}function u(){var t={};if(s(),p(),"strict"==k&&(t.strict=!0,p()),("graph"==k||"digraph"==k)&&(t.type=k,p()),N==D.IDENTIFIER&&(t.id=k,p()),"{"!=k)throw x("Angle bracket { expected");if(p(),m(t),"}"!=k)throw x("Angle bracket } expected");if(p(),""!==k)throw x("End of file expected");return p(),delete t.node,delete t.edge,delete t.graph,t}function m(t){for(;""!==k&&"}"!=k;)f(t),";"==k&&p()}function f(t){var e=g(t);if(e)return void b(t,e);var i=v(t);if(!i){if(N!=D.IDENTIFIER)throw x("Identifier expected");var s=k;if(p(),"="==k){if(p(),N!=D.IDENTIFIER)throw x("Identifier expected");t[s]=k,p()}else y(t,s)}}function g(t){var e=null;if("subgraph"==k&&(e={},e.type="subgraph",p(),N==D.IDENTIFIER&&(e.id=k,p())),"{"==k){if(p(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,m(e),"}"!=k)throw x("Angle bracket } expected");p(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function v(t){return"node"==k?(p(),t.node=_(),"node"):"edge"==k?(p(),t.edge=_(),"edge"):"graph"==k?(p(),t.graph=_(),"graph"):null}function y(t,e){var i={id:e},s=_();s&&(i.attr=s),d(t,i),b(t,e)}function b(t,e){for(;"->"==k||"--"==k;){var i,s=k;p();var o=g(t);if(o)i=o;else{if(N!=D.IDENTIFIER)throw x("Identifier or subgraph expected");i=k,d(t,{id:i}),p()}var n=_(),r=c(t,e,i,s,n);l(t,r),e=i}}function _(){for(var t=null;"["==k;){for(p(),t={};""!==k&&"]"!=k;){if(N!=D.IDENTIFIER)throw x("Attribute name expected");var e=k;if(p(),"="!=k)throw x("Equal sign = expected");if(p(),N!=D.IDENTIFIER)throw x("Attribute value expected");var i=k;h(t,e,i),p(),","==k&&p()}if("]"!=k)throw x("Bracket ] expected");p()}return t}function x(t){return new SyntaxError(t+', got "'+w(k,30)+'" (char '+O+")")}function w(t,e){return t.length<=e?t:t.substr(0,27)+"..."}function M(t,e,i){Array.isArray(t)?t.forEach(function(t){Array.isArray(e)?e.forEach(function(e){i(t,e)}):i(t,e)}):Array.isArray(e)?e.forEach(function(e){i(t,e)}):i(t,e)}function S(t){var e=i(t),s={nodes:[],edges:[],options:{}};if(e.nodes&&e.nodes.forEach(function(t){var e={id:t.id,label:String(t.label||t.id)};a(e,t.attr),e.image&&(e.shape="image"),s.nodes.push(e)}),e.edges){var o=function(t){var e={from:t.from,to:t.to};return a(e,t.attr),e.style="->"==t.type?"arrow":"line",e};e.edges.forEach(function(t){var e,i;e=t.from instanceof Object?t.from.nodes:{id:t.from},i=t.to instanceof Object?t.to.nodes:{id:t.to},t.from instanceof Object&&t.from.edges&&t.from.edges.forEach(function(t){var e=o(t);s.edges.push(e)}),M(e,i,function(e,i){var n=c(s,e.id,i.id,t.type,t.attr),r=o(n);s.edges.push(r)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=o(t);s.edges.push(e)})})}return e.attr&&(s.options=e.attr),s}var D={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},C={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},T="",O=0,E="",k="",N=D.NULL,L=/[a-zA-Z_0-9.:#]/;e.parseDOT=i,e.DOTToGraph=S},function(t,e){function i(t,e){var i=[],s=[];this.options={edges:{inheritColor:!0},nodes:{allowedToMove:!1,parseColor:!1}},void 0!==e&&(this.options.nodes.allowedToMove=e.allowedToMove|!1,this.options.nodes.parseColor=e.parseColor|!1,this.options.edges.inheritColor=e.inheritColor|!0);for(var o=t.edges,n=t.nodes,r=0;r=s&&(s=864e5),e=new Date(e.valueOf()-.05*s),i=new Date(i.valueOf()+.05*s)}return{start:e,end:i}},s.prototype.setWindow=function(t,e,i){var s=i&&void 0!==i.animate?i.animate:!0;if(1==arguments.length){var o=arguments[0];this.range.setRange(o.start,o.end,s)}else this.range.setRange(t,e,s)},s.prototype.moveTo=function(t,e){var i=this.range.end-this.range.start,s=r.convert(t,"Date").valueOf(),o=s-i/2,n=s+i/2,a=e&&void 0!==e.animate?e.animate:!0;this.range.setRange(o,n,a)},s.prototype.getWindow=function(){var t=this.range.getRange();return{start:new Date(t.start),end:new Date(t.end)}},s.prototype.redraw=function(){var t=!1,e=this.options,i=this.props,s=this.dom;if(s){h.updateHiddenDates(this.body,this.options.hiddenDates),"top"==e.orientation?(r.addClassName(s.root,"top"),r.removeClassName(s.root,"bottom")):(r.removeClassName(s.root,"top"),r.addClassName(s.root,"bottom")),s.root.style.maxHeight=r.option.asSize(e.maxHeight,""),s.root.style.minHeight=r.option.asSize(e.minHeight,""),s.root.style.width=r.option.asSize(e.width,""),i.border.left=(s.centerContainer.offsetWidth-s.centerContainer.clientWidth)/2,i.border.right=i.border.left,i.border.top=(s.centerContainer.offsetHeight-s.centerContainer.clientHeight)/2,i.border.bottom=i.border.top;var o=s.root.offsetHeight-s.root.clientHeight,n=s.root.offsetWidth-s.root.clientWidth;0===s.centerContainer.clientHeight&&(i.border.left=i.border.top,i.border.right=i.border.left),0===s.root.clientHeight&&(n=o),i.center.height=s.center.offsetHeight,i.left.height=s.left.offsetHeight,i.right.height=s.right.offsetHeight,i.top.height=s.top.clientHeight||-i.border.top,i.bottom.height=s.bottom.clientHeight||-i.border.bottom;var a=Math.max(i.left.height,i.center.height,i.right.height),d=i.top.height+a+i.bottom.height+o+i.border.top+i.border.bottom;s.root.style.height=r.option.asSize(e.height,d+"px"),i.root.height=s.root.offsetHeight,i.background.height=i.root.height-o;var l=i.root.height-i.top.height-i.bottom.height-o;i.centerContainer.height=l,i.leftContainer.height=l,i.rightContainer.height=i.leftContainer.height,i.root.width=s.root.offsetWidth,i.background.width=i.root.width-n,i.left.width=s.leftContainer.clientWidth||-i.border.left,i.leftContainer.width=i.left.width,i.right.width=s.rightContainer.clientWidth||-i.border.right,i.rightContainer.width=i.right.width;var c=i.root.width-i.left.width-i.right.width-n;i.center.width=c,i.centerContainer.width=c,i.top.width=c,i.bottom.width=c,s.background.style.height=i.background.height+"px",s.backgroundVertical.style.height=i.background.height+"px",s.backgroundHorizontal.style.height=i.centerContainer.height+"px",s.centerContainer.style.height=i.centerContainer.height+"px",s.leftContainer.style.height=i.leftContainer.height+"px",s.rightContainer.style.height=i.rightContainer.height+"px",s.background.style.width=i.background.width+"px",s.backgroundVertical.style.width=i.centerContainer.width+"px",s.backgroundHorizontal.style.width=i.background.width+"px",s.centerContainer.style.width=i.center.width+"px",s.top.style.width=i.top.width+"px",s.bottom.style.width=i.bottom.width+"px",s.background.style.left="0",s.background.style.top="0",s.backgroundVertical.style.left=i.left.width+i.border.left+"px",s.backgroundVertical.style.top="0",s.backgroundHorizontal.style.left="0",s.backgroundHorizontal.style.top=i.top.height+"px",s.centerContainer.style.left=i.left.width+"px",s.centerContainer.style.top=i.top.height+"px",s.leftContainer.style.left="0",s.leftContainer.style.top=i.top.height+"px",s.rightContainer.style.left=i.left.width+i.center.width+"px",s.rightContainer.style.top=i.top.height+"px",s.top.style.left=i.left.width+"px",s.top.style.top="0",s.bottom.style.left=i.left.width+"px",s.bottom.style.top=i.top.height+i.centerContainer.height+"px",this._updateScrollTop();var p=this.props.scrollTop;"bottom"==e.orientation&&(p+=Math.max(this.props.centerContainer.height-this.props.center.height-this.props.border.top-this.props.border.bottom,0)),s.center.style.left="0",s.center.style.top=p+"px",s.left.style.left="0",s.left.style.top=p+"px",s.right.style.left="0",s.right.style.top=p+"px";var u=0==this.props.scrollTop?"hidden":"",m=this.props.scrollTop==this.props.scrollTopMin?"hidden":"";if(s.shadowTop.style.visibility=u,s.shadowBottom.style.visibility=m,s.shadowTopLeft.style.visibility=u,s.shadowBottomLeft.style.visibility=m,s.shadowTopRight.style.visibility=u,s.shadowBottomRight.style.visibility=m,this.components.forEach(function(e){t=e.redraw()||t}),t){var f=3;this.redrawCount0&&(this.props.scrollTop=0),this.props.scrollTops;s++){var o=s%2===0?1.3*i:.5*i;this.lineTo(t+o*Math.sin(2*s*Math.PI/10),e-o*Math.cos(2*s*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,s,o){var n=Math.PI/180;0>i-2*o&&(o=i/2),0>s-2*o&&(o=s/2),this.beginPath(),this.moveTo(t+o,e),this.lineTo(t+i-o,e),this.arc(t+i-o,e+o,o,270*n,360*n,!1),this.lineTo(t+i,e+s-o),this.arc(t+i-o,e+s-o,o,0,90*n,!1),this.lineTo(t+o,e+s),this.arc(t+o,e+s-o,o,90*n,180*n,!1),this.lineTo(t,e+o),this.arc(t+o,e+o,o,180*n,270*n,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,s){var o=.5522848,n=i/2*o,r=s/2*o,a=t+i,h=e+s,d=t+i/2,l=e+s/2;this.beginPath(),this.moveTo(t,l),this.bezierCurveTo(t,l-r,d-n,e,d,e),this.bezierCurveTo(d+n,e,a,l-r,a,l),this.bezierCurveTo(a,l+r,d+n,h,d,h),this.bezierCurveTo(d-n,h,t,l+r,t,l)},CanvasRenderingContext2D.prototype.database=function(t,e,i,s){var o=1/3,n=i,r=s*o,a=.5522848,h=n/2*a,d=r/2*a,l=t+n,c=e+r,p=t+n/2,u=e+r/2,m=e+(s-r/2),f=e+s;this.beginPath(),this.moveTo(l,u),this.bezierCurveTo(l,u+d,p+h,c,p,c),this.bezierCurveTo(p-h,c,t,u+d,t,u),this.bezierCurveTo(t,u-d,p-h,e,p,e),this.bezierCurveTo(p+h,e,l,u-d,l,u),this.lineTo(l,m),this.bezierCurveTo(l,m+d,p+h,f,p,f),this.bezierCurveTo(p-h,f,t,m+d,t,m),this.lineTo(t,u)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,s){var o=t-s*Math.cos(i),n=e-s*Math.sin(i),r=t-.9*s*Math.cos(i),a=e-.9*s*Math.sin(i),h=o+s/3*Math.cos(i+.5*Math.PI),d=n+s/3*Math.sin(i+.5*Math.PI),l=o+s/3*Math.cos(i-.5*Math.PI),c=n+s/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,d),this.lineTo(r,a),this.lineTo(l,c),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,s,o){o||(o=[10,5]),0==p&&(p=.001);var n=o.length;this.moveTo(t,e);for(var r=i-t,a=s-e,h=a/r,d=Math.sqrt(r*r+a*a),l=0,c=!0;d>=.1;){var p=o[l++%n];p>d&&(p=d);var u=Math.sqrt(p*p/(1+h*h));0>r&&(u=-u),t+=u,e+=h*u,this[c?"lineTo":"moveTo"](t,e),d-=p,c=!c}})},function(t,e,i){function s(t,e){this.groupId=t,this.options=e}var o=i(2),n=i(53);s.prototype.getYRange=function(t){for(var e=t[0].y,i=t[0].y,s=0;st[s].y?t[s].y:e,i=i0){var r,a,h=Number(i.svg.style.height.replace("px",""));if(r=o.getSVGElement("path",i.svgElements,i.svg),r.setAttributeNS(null,"class",e.className),void 0!==e.style&&r.setAttributeNS(null,"style",e.style),a=1==e.options.catmullRom.enabled?s._catmullRom(t,e):s._linear(t),1==e.options.shaded.enabled){var d,l=o.getSVGElement("path",i.svgElements,i.svg);d="top"==e.options.shaded.orientation?"M"+t[0].x+",0 "+a+"L"+t[t.length-1].x+",0":"M"+t[0].x+","+h+" "+a+"L"+t[t.length-1].x+","+h,l.setAttributeNS(null,"class",e.className+" fill"),void 0!==e.options.shaded.style&&l.setAttributeNS(null,"style",e.options.shaded.style),l.setAttributeNS(null,"d",d)}r.setAttributeNS(null,"d","M"+a),1==e.options.drawPoints.enabled&&n.draw(t,e,i)}},s._catmullRomUniform=function(t){for(var e,i,s,o,n,r,a=Math.round(t[0].x)+","+Math.round(t[0].y)+" ",h=1/6,d=t.length,l=0;d-1>l;l++)e=0==l?t[0]:t[l-1],i=t[l],s=t[l+1],o=d>l+2?t[l+2]:s,n={x:(-e.x+6*i.x+s.x)*h,y:(-e.y+6*i.y+s.y)*h},r={x:(i.x+6*s.x-o.x)*h,y:(i.y+6*s.y-o.y)*h},a+="C"+n.x+","+n.y+" "+r.x+","+r.y+" "+s.x+","+s.y+" ";return a},s._catmullRom=function(t,e){var i=e.options.catmullRom.alpha;if(0==i||void 0===i)return this._catmullRomUniform(t);for(var s,o,n,r,a,h,d,l,c,p,u,m,f,g,v,y,b,_,x,w=Math.round(t[0].x)+","+Math.round(t[0].y)+" ",M=t.length,S=0;M-1>S;S++)s=0==S?t[0]:t[S-1],o=t[S],n=t[S+1],r=M>S+2?t[S+2]:n,d=Math.sqrt(Math.pow(s.x-o.x,2)+Math.pow(s.y-o.y,2)),l=Math.sqrt(Math.pow(o.x-n.x,2)+Math.pow(o.y-n.y,2)),c=Math.sqrt(Math.pow(n.x-r.x,2)+Math.pow(n.y-r.y,2)),g=Math.pow(c,i),y=Math.pow(c,2*i),v=Math.pow(l,i),b=Math.pow(l,2*i),x=Math.pow(d,i),_=Math.pow(d,2*i),p=2*_+3*x*v+b,u=2*y+3*g*v+b,m=3*x*(x+v),m>0&&(m=1/m),f=3*g*(g+v),f>0&&(f=1/f),a={x:(-b*s.x+p*o.x+_*n.x)*m,y:(-b*s.y+p*o.y+_*n.y)*m},h={x:(y*o.x+u*n.x-b*r.x)*f,y:(y*o.y+u*n.y-b*r.y)*f},0==a.x&&0==a.y&&(a=o),0==h.x&&0==h.y&&(h=n),w+="C"+a.x+","+a.y+" "+h.x+","+h.y+" "+n.x+","+n.y+" ";return w},s._linear=function(t){for(var e="",i=0;it[s].y?t[s].y:e,i=i0&&(n=Math.min(n,Math.abs(c[d-1].x-r))),a=s._getSafeDrawData(n,h,m);else{var g=d+(p[r].amount-p[r].resolved),v=d-(p[r].resolved+1);g0&&(n=Math.min(n,Math.abs(c[v].x-r))),a=s._getSafeDrawData(n,h,m),p[r].resolved+=1,"stack"==h.options.barChart.handleOverlap?(f=p[r].accumulated,p[r].accumulated+=h.zeroPosition-c[d].y):"sideBySide"==h.options.barChart.handleOverlap&&(a.width=a.width/p[r].amount,a.offset+=p[r].resolved*a.width-.5*a.width*(p[r].amount+1),"left"==h.options.barChart.align?a.offset-=.5*a.width:"right"==h.options.barChart.align&&(a.offset+=.5*a.width))}o.drawBar(c[d].x+a.offset,c[d].y-f,a.width,h.zeroPosition-c[d].y,h.className+" bar",i.svgElements,i.svg),1==h.options.drawPoints.enabled&&o.drawPoint(c[d].x+a.offset,c[d].y,h,i.svgElements,i.svg)}},s._getDataIntersections=function(t,e){for(var i,s=0;s0&&(i=Math.min(i,Math.abs(e[s-1].x-e[s].x))),0==i&&(void 0===t[e[s].x]&&(t[e[s].x]={amount:0,resolved:0,accumulated:0}),t[e[s].x].amount+=1)},s._getSafeDrawData=function(t,e,i){var s,o;return t0?(s=i>t?i:t,o=0,"left"==e.options.barChart.align?o-=.5*t:"right"==e.options.barChart.align&&(o+=.5*t)):(s=e.options.barChart.width,o=0,"left"==e.options.barChart.align?o-=.5*e.options.barChart.width:"right"==e.options.barChart.align&&(o+=.5*e.options.barChart.width)),{width:s,offset:o}},s.getStackedBarYRange=function(t,e,i,o,n){if(t.length>0){t.sort(function(t,e){return t.x==e.x?t.groupId-e.groupId:t.x-e.x});var r={};s._getDataIntersections(r,t),e[o]=s._getStackedBarYRange(r,t),e[o].yAxisOrientation=n,i.push(o)}},s._getStackedBarYRange=function(t,e){for(var i,s=e[0].y,o=e[0].y,n=0;ne[n].y?e[n].y:s,o=ot[r].accumulated?t[r].accumulated:s,o=ot[s].y?t[s].y:e,i=is;++s)i[s].apply(this,e)}return this},e.prototype.listeners=function(t){return this._callbacks=this._callbacks||{},this._callbacks[t]||[]},e.prototype.hasListeners=function(t){return!!this.listeners(t).length}},function(t,e){var i,s,o;!function(n,r){s=[],i=r,o="function"==typeof i?i.apply(e,s):i,!(void 0!==o&&(t.exports=o))}(this,function(){function t(t){var e,i=t&&t.preventDefault||!1,s=t&&t.container||window,o={},n={keydown:{},keyup:{}},r={};for(e=97;122>=e;e++)r[String.fromCharCode(e)]={code:65+(e-97),shift:!1};for(e=65;90>=e;e++)r[String.fromCharCode(e)]={code:e,shift:!0};for(e=0;9>=e;e++)r[""+e]={code:48+e,shift:!1};for(e=1;12>=e;e++)r["F"+e]={code:111+e,shift:!1};for(e=0;9>=e;e++)r["num"+e]={code:96+e,shift:!1};r["num*"]={code:106,shift:!1},r["num+"]={code:107,shift:!1},r["num-"]={code:109,shift:!1},r["num/"]={code:111,shift:!1},r["num."]={code:110,shift:!1},r.left={code:37,shift:!1},r.up={code:38,shift:!1},r.right={code:39,shift:!1},r.down={code:40,shift:!1},r.space={code:32,shift:!1},r.enter={code:13,shift:!1},r.shift={code:16,shift:void 0},r.esc={code:27,shift:!1},r.backspace={code:8,shift:!1},r.tab={code:9,shift:!1},r.ctrl={code:17,shift:!1},r.alt={code:18,shift:!1},r["delete"]={code:46,shift:!1},r.pageup={code:33,shift:!1},r.pagedown={code:34,shift:!1},r["="]={code:187,shift:!1},r["-"]={code:189,shift:!1},r["]"]={code:221,shift:!1},r["["]={code:219,shift:!1};var a=function(t){d(t,"keydown")},h=function(t){d(t,"keyup")},d=function(t,e){if(void 0!==n[e][t.keyCode]){for(var s=n[e][t.keyCode],o=0;oe-n?(i=t.clone().add(o-1,"months"),s=(e-n)/(n-i)):(i=t.clone().add(o+1,"months"),s=(e-n)/(i-n)),-(o+s)}function f(t,e,i){var s;return null==i?e:null!=t.meridiemHour?t.meridiemHour(e,i):null!=t.isPM?(s=t.isPM(i),s&&12>e&&(e+=12),s||12!==e||(e=0),e):e}function g(){}function v(t,e){e!==!1&&F(t),_(this,t),this._d=new Date(+t._d),Di===!1&&(Di=!0,Ce.updateOffset(this),Di=!1)}function y(t){var e=N(t),i=e.year||0,s=e.quarter||0,o=e.month||0,n=e.week||0,r=e.day||0,a=e.hour||0,h=e.minute||0,d=e.second||0,l=e.millisecond||0;this._milliseconds=+l+1e3*d+6e4*h+36e5*a,this._days=+r+7*n,this._months=+o+3*s+12*i,this._data={},this._locale=Ce.localeData(),this._bubble()}function b(t,e){for(var i in e)a(e,i)&&(t[i]=e[i]);return a(e,"toString")&&(t.toString=e.toString),a(e,"valueOf")&&(t.valueOf=e.valueOf),t}function _(t,e){var i,s,o;if("undefined"!=typeof e._isAMomentObject&&(t._isAMomentObject=e._isAMomentObject),"undefined"!=typeof e._i&&(t._i=e._i),"undefined"!=typeof e._f&&(t._f=e._f),"undefined"!=typeof e._l&&(t._l=e._l),"undefined"!=typeof e._strict&&(t._strict=e._strict),"undefined"!=typeof e._tzm&&(t._tzm=e._tzm),"undefined"!=typeof e._isUTC&&(t._isUTC=e._isUTC),"undefined"!=typeof e._offset&&(t._offset=e._offset),"undefined"!=typeof e._pf&&(t._pf=e._pf),"undefined"!=typeof e._locale&&(t._locale=e._locale),Ye.length>0)for(i in Ye)s=Ye[i],o=e[s],"undefined"!=typeof o&&(t[s]=o);return t}function x(t){return 0>t?Math.ceil(t):Math.floor(t)}function w(t,e,i){for(var s=""+Math.abs(t),o=t>=0;s.lengths;s++)(i&&t[s]!==e[s]||!i&&I(t[s])!==I(e[s]))&&r++;return r+n}function k(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=gi[t]||vi[e]||e}return t}function N(t){var e,i,s={};for(i in t)a(t,i)&&(e=k(i),e&&(s[e]=t[i]));return s}function L(t){var e,i;if(0===t.indexOf("week"))e=7,i="day";else{if(0!==t.indexOf("month"))return;e=12,i="month"}Ce[t]=function(s,o){var r,a,h=Ce._locale[t],d=[];if("number"==typeof s&&(o=s,s=n),a=function(t){var e=Ce().utc().set(i,t);return h.call(Ce._locale,e,s||"")},null!=o)return a(o);for(r=0;e>r;r++)d.push(a(r));return d}}function I(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=e>=0?Math.floor(e):Math.ceil(e)),i}function z(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function P(t,e,i){return me(Ce([t,11,31+e-i]),e,i).week}function A(t){return R(t)?366:365}function R(t){return t%4===0&&t%100!==0||t%400===0}function F(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[ze]<0||t._a[ze]>11?ze:t._a[Pe]<1||t._a[Pe]>z(t._a[Ie],t._a[ze])?Pe:t._a[Ae]<0||t._a[Ae]>24||24===t._a[Ae]&&(0!==t._a[Re]||0!==t._a[Fe]||0!==t._a[He])?Ae:t._a[Re]<0||t._a[Re]>59?Re:t._a[Fe]<0||t._a[Fe]>59?Fe:t._a[He]<0||t._a[He]>999?He:-1,t._pf._overflowDayOfYear&&(Ie>e||e>Pe)&&(e=Pe),t._pf.overflow=e)}function H(t){return null==t._isValid&&(t._isValid=!isNaN(t._d.getTime())&&t._pf.overflow<0&&!t._pf.empty&&!t._pf.invalidMonth&&!t._pf.nullInput&&!t._pf.invalidFormat&&!t._pf.userInvalidated,t._strict&&(t._isValid=t._isValid&&0===t._pf.charsLeftOver&&0===t._pf.unusedTokens.length&&t._pf.bigHour===n)),t._isValid}function B(t){return t?t.toLowerCase().replace("_","-"):t}function Y(t){for(var e,i,s,o,n=0;n0;){if(s=W(o.slice(0,e).join("-")))return s;if(i&&i.length>=e&&E(o,i,!0)>=e-1)break;e--}n++}return null}function W(t){var e=null;if(!Be[t]&&We)try{e=Ce.locale(),!function(){var t=new Error('Cannot find module "./locale"');throw t.code="MODULE_NOT_FOUND",t}(),Ce.locale(e)}catch(i){}return Be[t]}function G(t,e){var i,s;return e._isUTC?(i=e.clone(),s=(Ce.isMoment(t)||O(t)?+t:+Ce(t))-+i,i._d.setTime(+i._d+s),Ce.updateOffset(i,!1),i):Ce(t).local()}function j(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function V(t){var e,i,s=t.match(Ue);for(e=0,i=s.length;i>e;e++)s[e]=wi[s[e]]?wi[s[e]]:j(s[e]);return function(o){var n="";for(e=0;i>e;e++)n+=s[e]instanceof Function?s[e].call(o,t):s[e];return n}}function U(t,e){return t.isValid()?(e=X(e,t.localeData()),yi[e]||(yi[e]=V(e)),yi[e](t)):t.localeData().invalidDate()}function X(t,e){function i(t){return e.longDateFormat(t)||t}var s=5;for(Xe.lastIndex=0;s>=0&&Xe.test(t);)t=t.replace(Xe,i),Xe.lastIndex=0,s-=1;return t}function q(t,e){var i,s=e._strict;switch(t){case"Q":return oi;case"DDDD":return ri;case"YYYY":case"GGGG":case"gggg":return s?ai:Qe;case"Y":case"G":case"g":return di;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return s?hi:Ke;case"S":if(s)return oi;case"SS":if(s)return ni;case"SSS":if(s)return ri;case"DDD":return Ze;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Je;case"a":case"A":return e._locale._meridiemParse;case"x":return ii;case"X":return si;case"Z":case"ZZ":return ti;case"T":return ei;case"SSSS":return $e;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return s?ni:qe;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return qe;case"Do":return s?e._locale._ordinalParse:e._locale._ordinalParseLenient;default:return i=new RegExp(se(ie(t.replace("\\","")),"i"))}}function Z(t){t=t||"";var e=t.match(ti)||[],i=e[e.length-1]||[],s=(i+"").match(mi)||["-",0,0],o=+(60*s[1])+I(s[2]);return"+"===s[0]?o:-o}function Q(t,e,i){var s,o=i._a;switch(t){case"Q":null!=e&&(o[ze]=3*(I(e)-1));break;case"M":case"MM":null!=e&&(o[ze]=I(e)-1);break;case"MMM":case"MMMM":s=i._locale.monthsParse(e,t,i._strict),null!=s?o[ze]=s:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(o[Pe]=I(e));break;case"Do":null!=e&&(o[Pe]=I(parseInt(e.match(/\d{1,2}/)[0],10)));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=I(e));break;case"YY":o[Ie]=Ce.parseTwoDigitYear(e);break;case"YYYY":case"YYYYY":case"YYYYYY":o[Ie]=I(e);break;case"a":case"A":i._meridiem=e;break;case"h":case"hh":i._pf.bigHour=!0;case"H":case"HH":o[Ae]=I(e);break;case"m":case"mm":o[Re]=I(e);break;case"s":case"ss":o[Fe]=I(e);break;case"S":case"SS":case"SSS":case"SSSS":o[He]=I(1e3*("0."+e));break;case"x":i._d=new Date(I(e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=Z(e);break;case"dd":case"ddd":case"dddd":s=i._locale.weekdaysParse(e),null!=s?(i._w=i._w||{},i._w.d=s):i._pf.invalidWeekday=e;break;case"w":case"ww":case"W":case"WW":case"d":case"e":case"E":t=t.substr(0,1);case"gggg":case"GGGG":case"GGGGG":t=t.substr(0,2),e&&(i._w=i._w||{},i._w[t]=I(e));break;case"gg":case"GG":i._w=i._w||{},i._w[t]=Ce.parseTwoDigitYear(e)}}function K(t){var e,i,s,o,n,a,h;e=t._w,null!=e.GG||null!=e.W||null!=e.E?(n=1,a=4,i=r(e.GG,t._a[Ie],me(Ce(),1,4).year),s=r(e.W,1),o=r(e.E,1)):(n=t._locale._week.dow,a=t._locale._week.doy,i=r(e.gg,t._a[Ie],me(Ce(),n,a).year),s=r(e.w,1),null!=e.d?(o=e.d,n>o&&++s):o=null!=e.e?e.e+n:n),h=fe(i,s,o,a,n),t._a[Ie]=h.year,t._dayOfYear=h.dayOfYear}function $(t){var e,i,s,o,n=[];if(!t._d){for(s=te(t),t._w&&null==t._a[Pe]&&null==t._a[ze]&&K(t),t._dayOfYear&&(o=r(t._a[Ie],s[Ie]),t._dayOfYear>A(o)&&(t._pf._overflowDayOfYear=!0),i=le(o,0,t._dayOfYear),t._a[ze]=i.getUTCMonth(),t._a[Pe]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=n[e]=s[e];for(;7>e;e++)t._a[e]=n[e]=null==t._a[e]?2===e?1:0:t._a[e];24===t._a[Ae]&&0===t._a[Re]&&0===t._a[Fe]&&0===t._a[He]&&(t._nextDay=!0,t._a[Ae]=0),t._d=(t._useUTC?le:de).apply(null,n),null!=t._tzm&&t._d.setUTCMinutes(t._d.getUTCMinutes()-t._tzm),t._nextDay&&(t._a[Ae]=24)}}function J(t){var e;t._d||(e=N(t._i),t._a=[e.year,e.month,e.day||e.date,e.hour,e.minute,e.second,e.millisecond],$(t))}function te(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function ee(t){if(t._f===Ce.ISO_8601)return void ne(t);t._a=[],t._pf.empty=!0;var e,i,s,o,r,a=""+t._i,h=a.length,d=0;for(s=X(t._f,t._locale).match(Ue)||[],e=0;e0&&t._pf.unusedInput.push(r),a=a.slice(a.indexOf(i)+i.length),d+=i.length),wi[o]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(o),Q(o,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(o);t._pf.charsLeftOver=h-d,a.length>0&&t._pf.unusedInput.push(a),t._pf.bigHour===!0&&t._a[Ae]<=12&&(t._pf.bigHour=n),t._a[Ae]=f(t._locale,t._a[Ae],t._meridiem),$(t),F(t)}function ie(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,s,o){return e||i||s||o})}function se(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function oe(t){var e,i,s,o,n;if(0===t._f.length)return t._pf.invalidFormat=!0,void(t._d=new Date(0/0));for(o=0;on)&&(s=n,i=e));b(t,i||e)}function ne(t){var e,i,s=t._i,o=li.exec(s);if(o){for(t._pf.iso=!0,e=0,i=pi.length;i>e;e++)if(pi[e][1].exec(s)){t._f=pi[e][0]+(o[6]||" ");break}for(e=0,i=ui.length;i>e;e++)if(ui[e][1].exec(s)){t._f+=ui[e][0];break}s.match(ti)&&(t._f+="Z"),ee(t)}else t._isValid=!1}function re(t){ne(t),t._isValid===!1&&(delete t._isValid,Ce.createFromInputFallback(t))}function ae(t,e){var i,s=[];for(i=0;it&&a.setFullYear(t),a}function le(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function ce(t,e){if("string"==typeof t)if(isNaN(t)){if(t=e.weekdaysParse(t),"number"!=typeof t)return null}else t=parseInt(t,10);return t}function pe(t,e,i,s,o){return o.relativeTime(e||1,!!i,t,s)}function ue(t,e,i){var s=Ce.duration(t).abs(),o=Ne(s.as("s")),n=Ne(s.as("m")),r=Ne(s.as("h")),a=Ne(s.as("d")),h=Ne(s.as("M")),d=Ne(s.as("y")),l=o0,l[4]=i,pe.apply({},l)}function me(t,e,i){var s,o=i-e,n=i-t.day();return n>o&&(n-=7),o-7>n&&(n+=7),s=Ce(t).add(n,"d"),{week:Math.ceil(s.dayOfYear()/7),year:s.year()}}function fe(t,e,i,s,o){var n,r,a=le(t,0,1).getUTCDay();return a=0===a?7:a,i=null!=i?i:o,n=o-a+(a>s?7:0)-(o>a?7:0),r=7*(e-1)+(i-o)+n+1,{year:r>0?t:t-1,dayOfYear:r>0?r:A(t-1)+r}}function ge(t){var e,i=t._i,s=t._f;return t._locale=t._locale||Ce.localeData(t._l),null===i||s===n&&""===i?Ce.invalid({nullInput:!0}):("string"==typeof i&&(t._i=i=t._locale.preparse(i)),Ce.isMoment(i)?new v(i,!0):(s?T(s)?oe(t):ee(t):he(t),e=new v(t),e._nextDay&&(e.add(1,"d"),e._nextDay=n),e))}function ve(t,e){var i,s;if(1===e.length&&T(e[0])&&(e=e[0]),!e.length)return Ce();for(i=e[0],s=1;s=0?"+":"-";return e+w(Math.abs(t),6)},gg:function(){return w(this.weekYear()%100,2)},gggg:function(){return w(this.weekYear(),4)},ggggg:function(){return w(this.weekYear(),5)},GG:function(){return w(this.isoWeekYear()%100,2)},GGGG:function(){return w(this.isoWeekYear(),4)},GGGGG:function(){return w(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.localeData().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.localeData().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return I(this.milliseconds()/100)},SS:function(){return w(I(this.milliseconds()/10),2)},SSS:function(){return w(this.milliseconds(),3)},SSSS:function(){return w(this.milliseconds(),3)},Z:function(){var t=this.utcOffset(),e="+";return 0>t&&(t=-t,e="-"),e+w(I(t/60),2)+":"+w(I(t)%60,2)},ZZ:function(){var t=this.utcOffset(),e="+";return 0>t&&(t=-t,e="-"),e+w(I(t/60),2)+w(I(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},x:function(){return this.valueOf()},X:function(){return this.unix()},Q:function(){return this.quarter()}},Mi={},Si=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"],Di=!1;_i.length;)Oe=_i.pop(),wi[Oe+"o"]=u(wi[Oe],Oe);for(;xi.length;)Oe=xi.pop(),wi[Oe+Oe]=p(wi[Oe],2);wi.DDDD=p(wi.DDD,3),b(g.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e;this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t,e,i){var s,o,n;for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),s=0;12>s;s++){if(o=Ce.utc([2e3,s]),i&&!this._longMonthsParse[s]&&(this._longMonthsParse[s]=new RegExp("^"+this.months(o,"").replace(".","")+"$","i"),this._shortMonthsParse[s]=new RegExp("^"+this.monthsShort(o,"").replace(".","")+"$","i")),i||this._monthsParse[s]||(n="^"+this.months(o,"")+"|^"+this.monthsShort(o,""),this._monthsParse[s]=new RegExp(n.replace(".",""),"i")),i&&"MMMM"===e&&this._longMonthsParse[s].test(t))return s;if(i&&"MMM"===e&&this._shortMonthsParse[s].test(t))return s;if(!i&&this._monthsParse[s].test(t))return s}},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},weekdaysParse:function(t){var e,i,s;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=Ce([2e3,1]).day(e),s="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=new RegExp(s.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e},_longDateFormat:{LTS:"h:mm:ss A",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(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},isPM:function(t){return"p"===(t+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(t,e,i){var s=this._calendar[t];return"function"==typeof s?s.apply(e,[i]):s},_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"},relativeTime:function(t,e,i,s){var o=this._relativeTime[i];return"function"==typeof o?o(t,e,i,s):o.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",_ordinalParse:/\d{1,2}/,preparse:function(t){return t},postformat:function(t){return t},week:function(t){return me(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},firstDayOfWeek:function(){return this._week.dow},firstDayOfYear:function(){return this._week.doy},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),Ce=function(t,e,i,s){var o;return"boolean"==typeof i&&(s=i,i=n),o={},o._isAMomentObject=!0,o._i=t,o._f=e,o._l=i,o._strict=s,o._isUTC=!1,o._pf=h(),ge(o)},Ce.suppressDeprecationWarnings=!1,Ce.createFromInputFallback=l("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(t){t._d=new Date(t._i+(t._useUTC?" UTC":""))}),Ce.min=function(){var t=[].slice.call(arguments,0);return ve("isBefore",t)},Ce.max=function(){var t=[].slice.call(arguments,0);return ve("isAfter",t)},Ce.utc=function(t,e,i,s){var o;return"boolean"==typeof i&&(s=i,i=n),o={},o._isAMomentObject=!0,o._useUTC=!0,o._isUTC=!0,o._l=i,o._i=t,o._f=e,o._strict=s,o._pf=h(),ge(o).utc()},Ce.unix=function(t){return Ce(1e3*t)},Ce.duration=function(t,e){var i,s,o,n,r=t,h=null;return Ce.isDuration(t)?r={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(r={},e?r[e]=t:r.milliseconds=t):(h=je.exec(t))?(i="-"===h[1]?-1:1,r={y:0,d:I(h[Pe])*i,h:I(h[Ae])*i,m:I(h[Re])*i,s:I(h[Fe])*i,ms:I(h[He])*i}):(h=Ve.exec(t))?(i="-"===h[1]?-1:1,o=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},r={y:o(h[2]),M:o(h[3]),d:o(h[4]),h:o(h[5]),m:o(h[6]),s:o(h[7]),w:o(h[8])}):null==r?r={}:"object"==typeof r&&("from"in r||"to"in r)&&(n=S(Ce(r.from),Ce(r.to)),r={},r.ms=n.milliseconds,r.M=n.months),s=new y(r),Ce.isDuration(t)&&a(t,"_locale")&&(s._locale=t._locale),s},Ce.version=Ee,Ce.defaultFormat=ci,Ce.ISO_8601=function(){},Ce.momentProperties=Ye,Ce.updateOffset=function(){},Ce.relativeTimeThreshold=function(t,e){return bi[t]===n?!1:e===n?bi[t]:(bi[t]=e,!0)},Ce.lang=l("moment.lang is deprecated. Use moment.locale instead.",function(t,e){return Ce.locale(t,e)}),Ce.locale=function(t,e){var i;return t&&(i="undefined"!=typeof e?Ce.defineLocale(t,e):Ce.localeData(t),i&&(Ce.duration._locale=Ce._locale=i)),Ce._locale._abbr},Ce.defineLocale=function(t,e){return null!==e?(e.abbr=t,Be[t]||(Be[t]=new g),Be[t].set(e),Ce.locale(t),Be[t]):(delete Be[t],null)},Ce.langData=l("moment.langData is deprecated. Use moment.localeData instead.",function(t){return Ce.localeData(t)}),Ce.localeData=function(t){var e;if(t&&t._locale&&t._locale._abbr&&(t=t._locale._abbr),!t)return Ce._locale;if(!T(t)){if(e=W(t))return e;t=[t]}return Y(t)},Ce.isMoment=function(t){return t instanceof v||null!=t&&a(t,"_isAMomentObject")},Ce.isDuration=function(t){return t instanceof y};for(Oe=Si.length-1;Oe>=0;--Oe)L(Si[Oe]);Ce.normalizeUnits=function(t){return k(t)},Ce.invalid=function(t){var e=Ce.utc(0/0);return null!=t?b(e._pf,t):e._pf.userInvalidated=!0,e},Ce.parseZone=function(){return Ce.apply(null,arguments).parseZone()},Ce.parseTwoDigitYear=function(t){return I(t)+(I(t)>68?1900:2e3)},Ce.isDate=O,b(Ce.fn=v.prototype,{clone:function(){return Ce(this)},valueOf:function(){return+this._d-6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var t=Ce(this).utc();return 00:!1},parsingFlags:function(){return b({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(t){return this.utcOffset(0,t)},local:function(t){return this._isUTC&&(this.utcOffset(0,t),this._isUTC=!1,t&&this.subtract(this._dateUtcOffset(),"m")),this},format:function(t){var e=U(this,t||Ce.defaultFormat);return this.localeData().postformat(e)},add:D(1,"add"),subtract:D(-1,"subtract"),diff:function(t,e,i){var s,o,n=G(t,this),r=6e4*(n.utcOffset()-this.utcOffset());return e=k(e),"year"===e||"month"===e||"quarter"===e?(o=m(this,n),"quarter"===e?o/=3:"year"===e&&(o/=12)):(s=this-n,o="second"===e?s/1e3:"minute"===e?s/6e4:"hour"===e?s/36e5:"day"===e?(s-r)/864e5:"week"===e?(s-r)/6048e5:s),i?o:x(o)},from:function(t,e){return Ce.duration({to:this,from:t}).locale(this.locale()).humanize(!e)},fromNow:function(t){return this.from(Ce(),t)},calendar:function(t){var e=t||Ce(),i=G(e,this).startOf("day"),s=this.diff(i,"days",!0),o=-6>s?"sameElse":-1>s?"lastWeek":0>s?"lastDay":1>s?"sameDay":2>s?"nextDay":7>s?"nextWeek":"sameElse";return this.format(this.localeData().calendar(o,this,Ce(e)))},isLeapYear:function(){return R(this.year())},isDST:function(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},day:function(t){var e=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=t?(t=ce(t,this.localeData()),this.add(t-e,"d")):e},month:xe("Month",!0),startOf:function(t){switch(t=k(t)){case"year":this.month(0);case"quarter":case"month":this.date(1);case"week":case"isoWeek":case"day":this.hours(0);case"hour":this.minutes(0);case"minute":this.seconds(0);case"second":this.milliseconds(0)}return"week"===t?this.weekday(0):"isoWeek"===t&&this.isoWeekday(1),"quarter"===t&&this.month(3*Math.floor(this.month()/3)),this},endOf:function(t){return t=k(t),t===n||"millisecond"===t?this:this.startOf(t).add(1,"isoWeek"===t?"week":t).subtract(1,"ms")},isAfter:function(t,e){var i;return e=k("undefined"!=typeof e?e:"millisecond"),"millisecond"===e?(t=Ce.isMoment(t)?t:Ce(t),+this>+t):(i=Ce.isMoment(t)?+t:+Ce(t),i<+this.clone().startOf(e))},isBefore:function(t,e){var i;return e=k("undefined"!=typeof e?e:"millisecond"),"millisecond"===e?(t=Ce.isMoment(t)?t:Ce(t),+t>+this):(i=Ce.isMoment(t)?+t:+Ce(t),+this.clone().endOf(e)t?this:t}),max:l("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(t){return t=Ce.apply(null,arguments),t>this?this:t}),zone:l("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779",function(t,e){return null!=t?("string"!=typeof t&&(t=-t),this.utcOffset(t,e),this):-this.utcOffset()}),utcOffset:function(t,e){var i,s=this._offset||0;return null!=t?("string"==typeof t&&(t=Z(t)),Math.abs(t)<16&&(t=60*t),!this._isUTC&&e&&(i=this._dateUtcOffset()),this._offset=t,this._isUTC=!0,null!=i&&this.add(i,"m"),s!==t&&(!e||this._changeInProgress?C(this,Ce.duration(t-s,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,Ce.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?s:this._dateUtcOffset()},isLocal:function(){return!this._isUTC},isUtcOffset:function(){return this._isUTC},isUtc:function(){return this._isUTC&&0===this._offset},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.utcOffset(this._tzm):"string"==typeof this._i&&this.utcOffset(Z(this._i)),this},hasAlignedHourOffset:function(t){return t=t?Ce(t).utcOffset():0,(this.utcOffset()-t)%60===0},daysInMonth:function(){return z(this.year(),this.month())},dayOfYear:function(t){var e=Ne((Ce(this).startOf("day")-Ce(this).startOf("year"))/864e5)+1;return null==t?e:this.add(t-e,"d")},quarter:function(t){return null==t?Math.ceil((this.month()+1)/3):this.month(3*(t-1)+this.month()%3)},weekYear:function(t){var e=me(this,this.localeData()._week.dow,this.localeData()._week.doy).year;return null==t?e:this.add(t-e,"y")},isoWeekYear:function(t){var e=me(this,1,4).year;return null==t?e:this.add(t-e,"y")},week:function(t){var e=this.localeData().week(this);return null==t?e:this.add(7*(t-e),"d")},isoWeek:function(t){var e=me(this,1,4).week;return null==t?e:this.add(7*(t-e),"d")},weekday:function(t){var e=(this.day()+7-this.localeData()._week.dow)%7;return null==t?e:this.add(t-e,"d")},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},isoWeeksInYear:function(){return P(this.year(),1,4)},weeksInYear:function(){var t=this.localeData()._week;return P(this.year(),t.dow,t.doy)},get:function(t){return t=k(t),this[t]()},set:function(t,e){var i;if("object"==typeof t)for(i in t)this.set(i,t[i]);else t=k(t),"function"==typeof this[t]&&this[t](e);return this},locale:function(t){var e;return t===n?this._locale._abbr:(e=Ce.localeData(t),null!=e&&(this._locale=e),this)},lang:l("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(t){return t===n?this.localeData():this.locale(t)}),localeData:function(){return this._locale},_dateUtcOffset:function(){return 15*-Math.round(this._d.getTimezoneOffset()/15)}}),Ce.fn.millisecond=Ce.fn.milliseconds=xe("Milliseconds",!1),Ce.fn.second=Ce.fn.seconds=xe("Seconds",!1),Ce.fn.minute=Ce.fn.minutes=xe("Minutes",!1),Ce.fn.hour=Ce.fn.hours=xe("Hours",!0),Ce.fn.date=xe("Date",!0),Ce.fn.dates=l("dates accessor is deprecated. Use date instead.",xe("Date",!0)),Ce.fn.year=xe("FullYear",!0),Ce.fn.years=l("years accessor is deprecated. Use year instead.",xe("FullYear",!0)),Ce.fn.days=Ce.fn.day,Ce.fn.months=Ce.fn.month,Ce.fn.weeks=Ce.fn.week,Ce.fn.isoWeeks=Ce.fn.isoWeek,Ce.fn.quarters=Ce.fn.quarter,Ce.fn.toJSON=Ce.fn.toISOString,Ce.fn.isUTC=Ce.fn.isUtc,b(Ce.duration.fn=y.prototype,{_bubble:function(){var t,e,i,s=this._milliseconds,o=this._days,n=this._months,r=this._data,a=0;r.milliseconds=s%1e3,t=x(s/1e3),r.seconds=t%60,e=x(t/60),r.minutes=e%60,i=x(e/60),r.hours=i%24,o+=x(i/24),a=x(we(o)),o-=x(Me(a)),n+=x(o/30),o%=30,a+=x(n/12),n%=12,r.days=o,r.months=n,r.years=a},abs:function(){return 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),this},weeks:function(){return x(this.days()/7)},valueOf:function(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*I(this._months/12)},humanize:function(t){var e=ue(this,!t,this.localeData());return t&&(e=this.localeData().pastFuture(+this,e)),this.localeData().postformat(e)},add:function(t,e){var i=Ce.duration(t,e);return this._milliseconds+=i._milliseconds,this._days+=i._days,this._months+=i._months,this._bubble(),this},subtract:function(t,e){var i=Ce.duration(t,e);return this._milliseconds-=i._milliseconds,this._days-=i._days,this._months-=i._months,this._bubble(),this},get:function(t){return t=k(t),this[t.toLowerCase()+"s"]()},as:function(t){var e,i;if(t=k(t),"month"===t||"year"===t)return e=this._days+this._milliseconds/864e5,i=this._months+12*we(e),"month"===t?i:i/12;switch(e=this._days+Math.round(Me(this._months/12)),t){case"week":return e/7+this._milliseconds/6048e5;case"day":return e+this._milliseconds/864e5;case"hour":return 24*e+this._milliseconds/36e5;case"minute":return 24*e*60+this._milliseconds/6e4;case"second":return 24*e*60*60+this._milliseconds/1e3;case"millisecond":return Math.floor(24*e*60*60*1e3)+this._milliseconds;default:throw new Error("Unknown unit "+t)}},lang:Ce.fn.lang,locale:Ce.fn.locale,toIsoString:l("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",function(){return this.toISOString()}),toISOString:function(){var t=Math.abs(this.years()),e=Math.abs(this.months()),i=Math.abs(this.days()),s=Math.abs(this.hours()),o=Math.abs(this.minutes()),n=Math.abs(this.seconds()+this.milliseconds()/1e3);return this.asSeconds()?(this.asSeconds()<0?"-":"")+"P"+(t?t+"Y":"")+(e?e+"M":"")+(i?i+"D":"")+(s||o||n?"T":"")+(s?s+"H":"")+(o?o+"M":"")+(n?n+"S":""):"P0D"},localeData:function(){return this._locale},toJSON:function(){return this.toISOString()}}),Ce.duration.fn.toString=Ce.duration.fn.toISOString;for(Oe in fi)a(fi,Oe)&&Se(Oe.toLowerCase());Ce.duration.fn.asMilliseconds=function(){return this.as("ms")},Ce.duration.fn.asSeconds=function(){return this.as("s")},Ce.duration.fn.asMinutes=function(){return this.as("m")},Ce.duration.fn.asHours=function(){return this.as("h")},Ce.duration.fn.asDays=function(){return this.as("d")},Ce.duration.fn.asWeeks=function(){return this.as("weeks")},Ce.duration.fn.asMonths=function(){return this.as("M")},Ce.duration.fn.asYears=function(){return this.as("y")},Ce.locale("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(t){var e=t%10,i=1===I(t%100/10)?"th":1===e?"st":2===e?"nd":3===e?"rd":"th";return t+i}}),We?o.exports=Ce:(s=function(t,e,i){return i.config&&i.config()&&i.config().noGlobal===!0&&(ke.moment=Te),Ce}.call(e,i,e,o),!(s!==n&&(o.exports=s)),De(!0))}).call(this)}).call(e,function(){return this}(),i(71)(t))},function(t,e,i){var s;!function(o,n){function r(){a.READY||(w.determineEventTypes(),x.each(a.gestures,function(t){S.register(t)}),w.onTouch(a.DOCUMENT,v,S.detect),w.onTouch(a.DOCUMENT,y,S.detect),a.READY=!0)}var a=function D(t,e){return new D.Instance(t,e||{})};a.VERSION="1.1.3",a.defaults={behavior:{userSelect:"none",touchAction:"pan-y",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}},a.DOCUMENT=document,a.HAS_POINTEREVENTS=navigator.pointerEnabled||navigator.msPointerEnabled,a.HAS_TOUCHEVENTS="ontouchstart"in o,a.IS_MOBILE=/mobile|tablet|ip(ad|hone|od)|android|silk/i.test(navigator.userAgent),a.NO_MOUSEEVENTS=a.HAS_TOUCHEVENTS&&a.IS_MOBILE||a.HAS_POINTEREVENTS,a.CALCULATE_INTERVAL=25;var h={},d=a.DIRECTION_DOWN="down",l=a.DIRECTION_LEFT="left",c=a.DIRECTION_UP="up",p=a.DIRECTION_RIGHT="right",u=a.POINTER_MOUSE="mouse",m=a.POINTER_TOUCH="touch",f=a.POINTER_PEN="pen",g=a.EVENT_START="start",v=a.EVENT_MOVE="move",y=a.EVENT_END="end",b=a.EVENT_RELEASE="release",_=a.EVENT_TOUCH="touch";a.READY=!1,a.plugins=a.plugins||{},a.gestures=a.gestures||{};var x=a.utils={extend:function(t,e,i){for(var s in e)!e.hasOwnProperty(s)||t[s]!==n&&i||(t[s]=e[s]);return t},on:function(t,e,i){t.addEventListener(e,i,!1)},off:function(t,e,i){t.removeEventListener(e,i,!1)},each:function(t,e,i){var s,o;if("forEach"in t)t.forEach(e,i);else if(t.length!==n){for(s=0,o=t.length;o>s;s++)if(e.call(i,t[s],s,t)===!1)return}else for(s in t)if(t.hasOwnProperty(s)&&e.call(i,t[s],s,t)===!1)return},inStr:function(t,e){return t.indexOf(e)>-1},inArray:function(t,e){if(t.indexOf){var i=t.indexOf(e);return-1===i?!1:i}for(var s=0,o=t.length;o>s;s++)if(t[s]===e)return s;return!1},toArray:function(t){return Array.prototype.slice.call(t,0)},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){var e=[],i=[],s=[],o=[],n=Math.min,r=Math.max;return 1===t.length?{pageX:t[0].pageX,pageY:t[0].pageY,clientX:t[0].clientX,clientY:t[0].clientY}:(x.each(t,function(t){e.push(t.pageX),i.push(t.pageY),s.push(t.clientX),o.push(t.clientY)}),{pageX:(n.apply(Math,e)+r.apply(Math,e))/2,pageY:(n.apply(Math,i)+r.apply(Math,i))/2,clientX:(n.apply(Math,s)+r.apply(Math,s))/2,clientY:(n.apply(Math,o)+r.apply(Math,o))/2})},getVelocity:function(t,e,i){return{x:Math.abs(e/t)||0,y:Math.abs(i/t)||0}},getAngle:function(t,e){var i=e.clientX-t.clientX,s=e.clientY-t.clientY;return 180*Math.atan2(s,i)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.clientX-e.clientX),s=Math.abs(t.clientY-e.clientY);return i>=s?t.clientX-e.clientX>0?l:p:t.clientY-e.clientY>0?c:d},getDistance:function(t,e){var i=e.clientX-t.clientX,s=e.clientY-t.clientY;return Math.sqrt(i*i+s*s)},getScale:function(t,e){return t.length>=2&&e.length>=2?this.getDistance(e[0],e[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,e){return t.length>=2&&e.length>=2?this.getAngle(e[1],e[0])-this.getAngle(t[1],t[0]):0},isVertical:function(t){return t==c||t==d},setPrefixedCss:function(t,e,i,s){var o=["","Webkit","Moz","O","ms"];e=x.toCamelCase(e);for(var n=0;n0&&this.started&&(r=v),this.started=!0;var d=this.collectEventData(i,r,o,t);return e!=y&&s.call(S,d),a&&(d.changedLength=h,d.eventType=a,s.call(S,d),d.eventType=r,delete d.changedLength),r==y&&(s.call(S,d),this.started=!1),r},determineEventTypes:function(){var t;return t=a.HAS_POINTEREVENTS?o.PointerEvent?["pointerdown","pointermove","pointerup pointercancel lostpointercapture"]:["MSPointerDown","MSPointerMove","MSPointerUp MSPointerCancel MSLostPointerCapture"]:a.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],h[g]=t[0],h[v]=t[1],h[y]=t[2],h},getTouchList:function(t,e){if(a.HAS_POINTEREVENTS)return M.getTouchList();if(t.touches){if(e==v)return t.touches;var i=[],s=[].concat(x.toArray(t.touches),x.toArray(t.changedTouches)),o=[];return x.each(s,function(t){x.inArray(i,t.identifier)===!1&&o.push(t),i.push(t.identifier)}),o}return t.identifier=1,[t]},collectEventData:function(t,e,i,s){var o=m;return x.inStr(s.type,"mouse")||M.matchType(u,s)?o=u:M.matchType(f,s)&&(o=f),{center:x.getCenter(i),timeStamp:Date.now(),target:s.target,touches:i,eventType:e,pointerType:o,srcEvent:s,preventDefault:function(){var t=this.srcEvent;t.preventManipulation&&t.preventManipulation(),t.preventDefault&&t.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return S.stopDetect()}}}},M=a.PointerEvent={pointers:{},getTouchList:function(){var t=[];return x.each(this.pointers,function(e){t.push(e)}),t},updatePointer:function(t,e){t==y||t!=y&&1!==e.buttons?delete this.pointers[e.pointerId]:(e.identifier=e.pointerId,this.pointers[e.pointerId]=e)},matchType:function(t,e){if(!e.pointerType)return!1;var i=e.pointerType,s={};return s[u]=i===(e.MSPOINTER_TYPE_MOUSE||u),s[m]=i===(e.MSPOINTER_TYPE_TOUCH||m),s[f]=i===(e.MSPOINTER_TYPE_PEN||f),s[t]},reset:function(){this.pointers={}}},S=a.detection={gestures:[],current:null,previous:null,stopped:!1,startDetect:function(t,e){this.current||(this.stopped=!1,this.current={inst:t,startEvent:x.extend({},e),lastEvent:!1,lastCalcEvent:!1,futureCalcEvent:!1,lastCalcData:{},name:""},this.detect(e))},detect:function(t){if(this.current&&!this.stopped){t=this.extendEventData(t);var e=this.current.inst,i=e.options;return x.each(this.gestures,function(s){!this.stopped&&e.enabled&&i[s.name]&&s.handler.call(s,t,e)},this),this.current&&(this.current.lastEvent=t),t.eventType==y&&this.stopDetect(),t}},stopDetect:function(){this.previous=x.extend({},this.current),this.current=null,this.stopped=!0},getCalculatedData:function(t,e,i,s,o){var n=this.current,r=!1,h=n.lastCalcEvent,d=n.lastCalcData;h&&t.timeStamp-h.timeStamp>a.CALCULATE_INTERVAL&&(e=h.center,i=t.timeStamp-h.timeStamp,s=t.center.clientX-h.center.clientX,o=t.center.clientY-h.center.clientY,r=!0),(t.eventType==_||t.eventType==b)&&(n.futureCalcEvent=t),(!n.lastCalcEvent||r)&&(d.velocity=x.getVelocity(i,s,o),d.angle=x.getAngle(e,t.center),d.direction=x.getDirection(e,t.center),n.lastCalcEvent=n.futureCalcEvent||t,n.futureCalcEvent=t),t.velocityX=d.velocity.x,t.velocityY=d.velocity.y,t.interimAngle=d.angle,t.interimDirection=d.direction},extendEventData:function(t){var e=this.current,i=e.startEvent,s=e.lastEvent||i;(t.eventType==_||t.eventType==b)&&(i.touches=[],x.each(t.touches,function(t){i.touches.push({clientX:t.clientX,clientY:t.clientY})}));var o=t.timeStamp-i.timeStamp,n=t.center.clientX-i.center.clientX,r=t.center.clientY-i.center.clientY;return this.getCalculatedData(t,s.center,o,n,r),x.extend(t,{startEvent:i,deltaTime:o,deltaX:n,deltaY:r,distance:x.getDistance(i.center,t.center),angle:x.getAngle(i.center,t.center),direction:x.getDirection(i.center,t.center),scale:x.getScale(i.touches,t.touches),rotation:x.getRotation(i.touches,t.touches)}),t},register:function(t){var e=t.defaults||{};return e[t.name]===n&&(e[t.name]=!0),x.extend(a.defaults,e,!0),t.index=t.index||1e3,this.gestures.push(t),this.gestures.sort(function(t,e){return t.indexe.index?1:0}),this.gestures}};a.Instance=function(t,e){var i=this;r(),this.element=t,this.enabled=!0,x.each(e,function(t,i){delete e[i],e[x.toCamelCase(i)]=t}),this.options=x.extend(x.extend({},a.defaults),e||{}),this.options.behavior&&x.toggleBehavior(this.element,this.options.behavior,!0),this.eventStartHandler=w.onTouch(t,g,function(t){i.enabled&&t.eventType==g?S.startDetect(i,t):t.eventType==_&&S.detect(t)}),this.eventHandlers=[]},a.Instance.prototype={on:function(t,e){var i=this;return w.on(i.element,t,e,function(t){i.eventHandlers.push({gesture:t,handler:e})}),i},off:function(t,e){var i=this;return w.off(i.element,t,e,function(t){var s=x.inArray({gesture:t,handler:e});s!==!1&&i.eventHandlers.splice(s,1)}),i},trigger:function(t,e){e||(e={});var i=a.DOCUMENT.createEvent("Event");i.initEvent(t,!0,!0),i.gesture=e;var s=this.element;return x.hasParent(e.target,s)&&(s=e.target),s.dispatchEvent(i),this},enable:function(t){return this.enabled=t,this},dispose:function(){var t,e;for(x.toggleBehavior(this.element,this.options.behavior,!1),t=-1;e=this.eventHandlers[++t];)x.off(this.element,e.gesture,e.handler);return this.eventHandlers=[],w.off(this.element,h[g],this.eventStartHandler),null}},function(t){function e(e,s){var o=S.current;if(!(s.options.dragMaxTouches>0&&e.touches.length>s.options.dragMaxTouches))switch(e.eventType){case g:i=!1;break;case v:if(e.distance0)){var r=Math.abs(s.options.dragMinDistance/e.distance);n.pageX+=e.deltaX*r,n.pageY+=e.deltaY*r,n.clientX+=e.deltaX*r,n.clientY+=e.deltaY*r,e=S.extendEventData(e)}(o.lastEvent.dragLockToAxis||s.options.dragLockToAxis&&s.options.dragLockMinDistance<=e.distance)&&(e.dragLockToAxis=!0);var a=o.lastEvent.direction;e.dragLockToAxis&&a!==e.direction&&(e.direction=x.isVertical(a)?e.deltaY<0?c:d:e.deltaX<0?l:p),i||(s.trigger(t+"start",e),i=!0),s.trigger(t,e),s.trigger(t+e.direction,e);var h=x.isVertical(e.direction);(s.options.dragBlockVertical&&h||s.options.dragBlockHorizontal&&!h)&&e.preventDefault();break;case b:i&&e.changedLength<=s.options.dragMaxTouches&&(s.trigger(t+"end",e),i=!1);break;case y:i=!1}}var i=!1;a.gestures.Drag={name:t,index:50,handler:e,defaults:{dragMinDistance:10,dragDistanceCorrection:!0,dragMaxTouches:1,dragBlockHorizontal:!1,dragBlockVertical:!1,dragLockToAxis:!1,dragLockMinDistance:25}}}("drag"),a.gestures.Gesture={name:"gesture",index:1337,handler:function(t,e){e.trigger(this.name,t)}},function(t){function e(e,s){var o=s.options,n=S.current;switch(e.eventType){case g:clearTimeout(i),n.name=t,i=setTimeout(function(){n&&n.name==t&&s.trigger(t,e)},o.holdTimeout);break;case v:e.distance>o.holdThreshold&&clearTimeout(i);break;case b:clearTimeout(i)}}var i;a.gestures.Hold={name:t,index:10,defaults:{holdTimeout:500,holdThreshold:2},handler:e}}("hold"),a.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==b&&e.trigger(this.name,t)}},a.gestures.Swipe={name:"swipe",index:40,defaults:{swipeMinTouches:1,swipeMaxTouches:1,swipeVelocityX:.6,swipeVelocityY:.6},handler:function(t,e){if(t.eventType==b){var i=t.touches.length,s=e.options;if(is.swipeMaxTouches)return;(t.velocityX>s.swipeVelocityX||t.velocityY>s.swipeVelocityY)&&(e.trigger(this.name,t),e.trigger(this.name+t.direction,t))}}},function(t){function e(e,s){var o,n,r=s.options,a=S.current,h=S.previous;switch(e.eventType){case g:i=!1;break;case v:i=i||e.distance>r.tapMaxDistance;break;case y:!x.inStr(e.srcEvent.type,"cancel")&&e.deltaTimes.options.transformMinRotation&&s.trigger("rotate",e),o>s.options.transformMinScale&&(s.trigger("pinch",e),s.trigger("pinch"+(e.scale<1?"in":"out"),e)); -break;case b:i&&e.changedLength<2&&(s.trigger(t+"end",e),i=!1)}}var i=!1;a.gestures.Transform={name:t,index:45,defaults:{transformMinScale:.01,transformMinRotation:1},handler:e}}("transform"),s=function(){return a}.call(e,i,e,t),!(s!==n&&(t.exports=s))}(window)},function(t,e){e.startWithClustering=function(){this.clusterToFit(this.constants.clustering.initialMaxNodes,!0),this.updateLabels(),this.stabilize&&this._stabilize(),this.start()},e.clusterToFit=function(t,e){for(var i=this.nodeIndices.length,s=50,o=0;i>t&&s>o;)o%3==0?(this.forceAggregateHubs(!0),this.normalizeClusterLevels()):this.increaseClusterLevel(),i=this.nodeIndices.length,o+=1;o>0&&1==e&&this.repositionNodes(),this._updateCalculationNodes()},e.openCluster=function(t){var e=this.moving;if(t.clusterSize>this.constants.clustering.sectorThreshold&&this._nodeInActiveArea(t)&&("default"!=this._sector()||1!=this.nodeIndices.length)){this._addSector(t);for(var i=0;this.nodeIndices.lengthi;)this.decreaseClusterLevel(),i+=1}else this._expandClusterNode(t,!1,!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this._updateCalculationNodes(),this.updateLabels();this.moving!=e&&this.start()},e.updateClustersDefault=function(){1==this.constants.clustering.enabled&&this.updateClusters(0,!1,!1)},e.increaseClusterLevel=function(){this.updateClusters(-1,!1,!0)},e.decreaseClusterLevel=function(){this.updateClusters(1,!1,!0)},e.updateClusters=function(t,e,i,s){var o=this.moving,n=this.nodeIndices.length;this.previousScale>this.scale&&0==t&&this._collapseSector(),this.previousScale>this.scale||-1==t?this._formClusters(i):(this.previousScalethis.scale||-1==t)&&(this._aggregateHubs(i),this._updateNodeIndexList()),(this.previousScale>this.scale||-1==t)&&(this.handleChains(),this._updateNodeIndexList()),this.previousScale=this.scale,this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.lengththis.constants.clustering.chainThreshold&&this._reduceAmountOfChains(1-this.constants.clustering.chainThreshold/t)},e._aggregateHubs=function(t){this._getHubSize(),this._formClustersByHub(t,!1)},e.forceAggregateHubs=function(t){var e=this.moving,i=this.nodeIndices.length;this._aggregateHubs(!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.length!=i&&(this.clusterSession+=1),(0==t||void 0===t)&&this.moving!=e&&this.start()},e._openClustersBySize=function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];1==e.inView()&&(e.width*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientWidth||e.height*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientHeight)&&this.openCluster(e)}},e._openClusters=function(t,e){for(var i=0;i1&&(t.clusterSizei)){var r=n.from,a=n.to;n.to.options.mass>n.from.options.mass&&(r=n.to,a=n.from),1==a.dynamicEdgesLength?this._addToCluster(r,a,!1):1==r.dynamicEdgesLength&&this._addToCluster(a,r,!1)}}},e._forceClustersByZoom=function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];if(1==e.dynamicEdgesLength&&0!=e.dynamicEdges.length){var i=e.dynamicEdges[0],s=i.toId==e.id?this.nodes[i.fromId]:this.nodes[i.toId];e.id!=s.id&&(s.options.mass>e.options.mass?this._addToCluster(s,e,!0):this._addToCluster(e,s,!0))}}},e._clusterToSmallestNeighbour=function(t){for(var e=-1,i=null,s=0;so.clusterSessions.length&&(e=o.clusterSessions.length,i=o)}null!=o&&void 0!==this.nodes[o.id]&&this._addToCluster(o,t,!0)},e._formClustersByHub=function(t,e){for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&this._formClusterFromHub(this.nodes[i],t,e)},e._formClusterFromHub=function(t,e,i,s){if(void 0===s&&(s=0),t.dynamicEdgesLength>=this.hubThreshold&&0==i||t.dynamicEdgesLength==this.hubThreshold&&1==i){for(var o,n,r,a=this.constants.clustering.clusterEdgeThreshold/this.scale,h=!1,d=[],l=t.dynamicEdges.length,c=0;l>c;c++)d.push(t.dynamicEdges[c].id);if(0==e)for(h=!1,c=0;l>c;c++){var p=this.edges[d[c]];if(void 0!==p&&p.connected&&p.toId!=p.fromId&&(o=p.to.x-p.from.x,n=p.to.y-p.from.y,r=Math.sqrt(o*o+n*n),a>r)){h=!0;break}}if(!e&&h||e)for(c=0;l>c;c++)if(p=this.edges[d[c]],void 0!==p){var u=this.nodes[p.fromId==t.id?p.toId:p.fromId];u.dynamicEdges.length<=this.hubThreshold+s&&u.id!=t.id&&this._addToCluster(t,u,e)}}},e._addToCluster=function(t,e,i){t.containedNodes[e.id]=e;for(var s=0;s1)for(var s=0;s1&&(e.label="[".concat(String(e.clusterSize),"]"))}for(t in this.nodes)this.nodes.hasOwnProperty(t)&&(e=this.nodes[t],1==e.clusterSize&&(e.label=void 0!==e.originalLabel?e.originalLabel:String(e.id)))},e.normalizeClusterLevels=function(){var t,e=0,i=1e9,s=0;for(t in this.nodes)this.nodes.hasOwnProperty(t)&&(s=this.nodes[t].clusterSessions.length,s>e&&(e=s),i>s&&(i=s));if(e-i>this.constants.clustering.clusterLevelDifference){var o=this.nodeIndices.length,n=e-this.constants.clustering.clusterLevelDifference;for(t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodes[t].clusterSessions.lengths&&(s=n.dynamicEdgesLength),t+=n.dynamicEdgesLength,e+=Math.pow(n.dynamicEdgesLength,2),i+=1}t/=i,e/=i;var r=e-Math.pow(t,2),a=Math.sqrt(r);this.hubThreshold=Math.floor(t+2*a),this.hubThreshold>s&&(this.hubThreshold=s)},e._reduceAmountOfChains=function(t){this.hubThreshold=2;var e=Math.floor(this.nodeIndices.length*t);for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&e>0&&(this._formClusterFromHub(this.nodes[i],!0,!0,1),e-=1)},e._getChainFraction=function(){var t=0,e=0;for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&(2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&(t+=1),e+=1);return t/e}},function(t,e,i){var s=i(1),o=i(40);e._putDataInSector=function(){this.sectors.active[this._sector()].nodes=this.nodes,this.sectors.active[this._sector()].edges=this.edges,this.sectors.active[this._sector()].nodeIndices=this.nodeIndices},e._switchToSector=function(t,e){void 0===e||"active"==e?this._switchToActiveSector(t):this._switchToFrozenSector(t)},e._switchToActiveSector=function(t){this.nodeIndices=this.sectors.active[t].nodeIndices,this.nodes=this.sectors.active[t].nodes,this.edges=this.sectors.active[t].edges},e._switchToSupportSector=function(){this.nodeIndices=this.sectors.support.nodeIndices,this.nodes=this.sectors.support.nodes,this.edges=this.sectors.support.edges},e._switchToFrozenSector=function(t){this.nodeIndices=this.sectors.frozen[t].nodeIndices,this.nodes=this.sectors.frozen[t].nodes,this.edges=this.sectors.frozen[t].edges},e._loadLatestSector=function(){this._switchToSector(this._sector())},e._sector=function(){return this.activeSector[this.activeSector.length-1]},e._previousSector=function(){if(this.activeSector.length>1)return this.activeSector[this.activeSector.length-2];throw new TypeError("there are not enough sectors in the this.activeSector array.")},e._setActiveSector=function(t){this.activeSector.push(t)},e._forgetLastSector=function(){this.activeSector.pop()},e._createNewSector=function(t){this.sectors.active[t]={nodes:{},edges:{},nodeIndices:[],formationScale:this.scale,drawingNode:void 0},this.sectors.active[t].drawingNode=new o({id:t,color:{background:"#eaefef",border:"495c5e"}},{},{},this.constants),this.sectors.active[t].drawingNode.clusterSize=2},e._deleteActiveSector=function(t){delete this.sectors.active[t]},e._deleteFrozenSector=function(t){delete this.sectors.frozen[t]},e._freezeSector=function(t){this.sectors.frozen[t]=this.sectors.active[t],this._deleteActiveSector(t)},e._activateSector=function(t){this.sectors.active[t]=this.sectors.frozen[t],this._deleteFrozenSector(t)},e._mergeThisWithFrozen=function(t){for(var e in this.nodes)this.nodes.hasOwnProperty(e)&&(this.sectors.frozen[t].nodes[e]=this.nodes[e]);for(var i in this.edges)this.edges.hasOwnProperty(i)&&(this.sectors.frozen[t].edges[i]=this.edges[i]);for(var s=0;s1?this[t](o[0],o[1]):this[t](e))}return this._loadLatestSector(),i},e._doInSupportSector=function(t,e){var i=!1;if(void 0===e)this._switchToSupportSector(),i=this[t]();else{this._switchToSupportSector();var s=Array.prototype.splice.call(arguments,1);i=s.length>1?this[t](s[0],s[1]):this[t](e)}return this._loadLatestSector(),i},e._doInAllFrozenSectors=function(t,e){if(void 0===e)for(var i in this.sectors.frozen)this.sectors.frozen.hasOwnProperty(i)&&(this._switchToFrozenSector(i),this[t]());else for(var i in this.sectors.frozen)if(this.sectors.frozen.hasOwnProperty(i)){this._switchToFrozenSector(i);var s=Array.prototype.splice.call(arguments,1);s.length>1?this[t](s[0],s[1]):this[t](e)}this._loadLatestSector()},e._doInAllSectors=function(t,e){var i=Array.prototype.splice.call(arguments,1);void 0===e?(this._doInAllActiveSectors(t),this._doInAllFrozenSectors(t)):i.length>1?(this._doInAllActiveSectors(t,i[0],i[1]),this._doInAllFrozenSectors(t,i[0],i[1])):(this._doInAllActiveSectors(t,e),this._doInAllFrozenSectors(t,e))},e._clearNodeIndexList=function(){var t=this._sector();this.sectors.active[t].nodeIndices=[],this.nodeIndices=this.sectors.active[t].nodeIndices},e._drawSectorNodes=function(t,e){var i,s=1e9,o=-1e9,n=1e9,r=-1e9;for(var a in this.sectors[e])if(this.sectors[e].hasOwnProperty(a)&&void 0!==this.sectors[e][a].drawingNode){this._switchToSector(a,e),s=1e9,o=-1e9,n=1e9,r=-1e9;for(var h in this.nodes)this.nodes.hasOwnProperty(h)&&(i=this.nodes[h],i.resize(t),n>i.x-.5*i.width&&(n=i.x-.5*i.width),ri.y-.5*i.height&&(s=i.y-.5*i.height),o0?this.nodes[i[i.length-1]]:null},e._getEdgesOverlappingWith=function(t,e){var i=this.edges;for(var s in i)i.hasOwnProperty(s)&&i[s].isOverlappingWith(t)&&e.push(s)},e._getAllEdgesOverlappingWith=function(t){var e=[];return this._doInAllActiveSectors("_getEdgesOverlappingWith",t,e),e},e._getEdgeAt=function(t){var e=this._pointerToPositionObject(t),i=this._getAllEdgesOverlappingWith(e);return i.length>0?this.edges[i[i.length-1]]:null},e._addToSelection=function(t){t instanceof s?this.selectionObj.nodes[t.id]=t:this.selectionObj.edges[t.id]=t},e._addToHover=function(t){t instanceof s?this.hoverObj.nodes[t.id]=t:this.hoverObj.edges[t.id]=t},e._removeFromSelection=function(t){t instanceof s?delete this.selectionObj.nodes[t.id]:delete this.selectionObj.edges[t.id]},e._unselectAll=function(t){void 0===t&&(t=!1);for(var e in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(e)&&this.selectionObj.nodes[e].unselect();for(var i in this.selectionObj.edges)this.selectionObj.edges.hasOwnProperty(i)&&this.selectionObj.edges[i].unselect();this.selectionObj={nodes:{},edges:{}},0==t&&this.emit("select",this.getSelection())},e._unselectClusters=function(t){void 0===t&&(t=!1);for(var e in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(e)&&this.selectionObj.nodes[e].clusterSize>1&&(this.selectionObj.nodes[e].unselect(),this._removeFromSelection(this.selectionObj.nodes[e]));0==t&&this.emit("select",this.getSelection())},e._getSelectedNodeCount=function(){var t=0;for(var e in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(e)&&(t+=1);return t},e._getSelectedNode=function(){for(var t in this.selectionObj.nodes)if(this.selectionObj.nodes.hasOwnProperty(t))return this.selectionObj.nodes[t];return null},e._getSelectedEdge=function(){for(var t in this.selectionObj.edges)if(this.selectionObj.edges.hasOwnProperty(t))return this.selectionObj.edges[t];return null},e._getSelectedEdgeCount=function(){var t=0;for(var e in this.selectionObj.edges)this.selectionObj.edges.hasOwnProperty(e)&&(t+=1);return t},e._getSelectedObjectCount=function(){var t=0;for(var e in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(e)&&(t+=1);for(var i in this.selectionObj.edges)this.selectionObj.edges.hasOwnProperty(i)&&(t+=1);return t},e._selectionIsEmpty=function(){for(var t in this.selectionObj.nodes)if(this.selectionObj.nodes.hasOwnProperty(t))return!1;for(var e in this.selectionObj.edges)if(this.selectionObj.edges.hasOwnProperty(e))return!1;return!0},e._clusterInSelection=function(){for(var t in this.selectionObj.nodes)if(this.selectionObj.nodes.hasOwnProperty(t)&&this.selectionObj.nodes[t].clusterSize>1)return!0;return!1},e._selectConnectedEdges=function(t){for(var e=0;ei;i++){o=t[i];var n=this.nodes[o];if(!n)throw new RangeError('Node with id "'+o+'" not found');this._selectObject(n,!0,!0,e,!0)}this.redraw()},e.selectEdges=function(t){var e,i,s;if(!t||void 0==t.length)throw"Selection must be an array with ids";for(this._unselectAll(!0),e=0,i=t.length;i>e;e++){s=t[e];var o=this.edges[s];if(!o)throw new RangeError('Edge with id "'+s+'" not found');this._selectObject(o,!0,!0,!1,!0)}this.redraw()},e._updateSelection=function(){for(var t in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(t)&&(this.nodes.hasOwnProperty(t)||delete this.selectionObj.nodes[t]);for(var e in this.selectionObj.edges)this.selectionObj.edges.hasOwnProperty(e)&&(this.edges.hasOwnProperty(e)||delete this.selectionObj.edges[e])}},function(t,e,i){var s=i(1),o=i(40),n=i(37);e._clearManipulatorBar=function(){this._recursiveDOMDelete(this.manipulationDiv),this.manipulationDOM={},this._manipulationReleaseOverload=function(){},delete this.sectors.support.nodes.targetNode,delete this.sectors.support.nodes.targetViaNode,this.controlNodesActive=!1,this.freezeSimulation=!1},e._restoreOverloadedFunctions=function(){for(var t in this.cachedFunctions)this.cachedFunctions.hasOwnProperty(t)&&(this[t]=this.cachedFunctions[t],delete this.cachedFunctions[t])},e._toggleEditMode=function(){this.editMode=!this.editMode;var t=this.manipulationDiv,e=this.closeDiv,i=this.editModeDiv;1==this.editMode?(t.style.display="block",e.style.display="block",i.style.display="none",e.onclick=this._toggleEditMode.bind(this)):(t.style.display="none",e.style.display="none",i.style.display="block",e.onclick=null),this._createManipulatorBar()},e._createManipulatorBar=function(){this.boundFunction&&this.off("select",this.boundFunction);var t=this.constants.locales[this.constants.locale];if(void 0!==this.edgeBeingEdited&&(this.edgeBeingEdited._disableControlNodes(),this.edgeBeingEdited=void 0,this.selectedControlNode=null,this.controlNodesActive=!1,this._redraw()),this._restoreOverloadedFunctions(),this.freezeSimulation=!1,this.blockConnectingEdgeSelection=!1,this.forceAppendSelection=!1,this.manipulationDOM={},1==this.editMode){for(;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);this.manipulationDOM.addNodeSpan=document.createElement("span"),this.manipulationDOM.addNodeSpan.className="network-manipulationUI add",this.manipulationDOM.addNodeLabelSpan=document.createElement("span"),this.manipulationDOM.addNodeLabelSpan.className="network-manipulationLabel",this.manipulationDOM.addNodeLabelSpan.innerHTML=t.addNode,this.manipulationDOM.addNodeSpan.appendChild(this.manipulationDOM.addNodeLabelSpan),this.manipulationDOM.seperatorLineDiv1=document.createElement("div"),this.manipulationDOM.seperatorLineDiv1.className="network-seperatorLine",this.manipulationDOM.addEdgeSpan=document.createElement("span"),this.manipulationDOM.addEdgeSpan.className="network-manipulationUI connect",this.manipulationDOM.addEdgeLabelSpan=document.createElement("span"),this.manipulationDOM.addEdgeLabelSpan.className="network-manipulationLabel",this.manipulationDOM.addEdgeLabelSpan.innerHTML=t.addEdge,this.manipulationDOM.addEdgeSpan.appendChild(this.manipulationDOM.addEdgeLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.addNodeSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv1),this.manipulationDiv.appendChild(this.manipulationDOM.addEdgeSpan),1==this._getSelectedNodeCount()&&this.triggerFunctions.edit?(this.manipulationDOM.seperatorLineDiv2=document.createElement("div"),this.manipulationDOM.seperatorLineDiv2.className="network-seperatorLine",this.manipulationDOM.editNodeSpan=document.createElement("span"),this.manipulationDOM.editNodeSpan.className="network-manipulationUI edit",this.manipulationDOM.editNodeLabelSpan=document.createElement("span"),this.manipulationDOM.editNodeLabelSpan.className="network-manipulationLabel",this.manipulationDOM.editNodeLabelSpan.innerHTML=t.editNode,this.manipulationDOM.editNodeSpan.appendChild(this.manipulationDOM.editNodeLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv2),this.manipulationDiv.appendChild(this.manipulationDOM.editNodeSpan)):1==this._getSelectedEdgeCount()&&0==this._getSelectedNodeCount()&&(this.manipulationDOM.seperatorLineDiv3=document.createElement("div"),this.manipulationDOM.seperatorLineDiv3.className="network-seperatorLine",this.manipulationDOM.editEdgeSpan=document.createElement("span"),this.manipulationDOM.editEdgeSpan.className="network-manipulationUI edit",this.manipulationDOM.editEdgeLabelSpan=document.createElement("span"),this.manipulationDOM.editEdgeLabelSpan.className="network-manipulationLabel",this.manipulationDOM.editEdgeLabelSpan.innerHTML=t.editEdge,this.manipulationDOM.editEdgeSpan.appendChild(this.manipulationDOM.editEdgeLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv3),this.manipulationDiv.appendChild(this.manipulationDOM.editEdgeSpan)),0==this._selectionIsEmpty()&&(this.manipulationDOM.seperatorLineDiv4=document.createElement("div"),this.manipulationDOM.seperatorLineDiv4.className="network-seperatorLine",this.manipulationDOM.deleteSpan=document.createElement("span"),this.manipulationDOM.deleteSpan.className="network-manipulationUI delete",this.manipulationDOM.deleteLabelSpan=document.createElement("span"),this.manipulationDOM.deleteLabelSpan.className="network-manipulationLabel",this.manipulationDOM.deleteLabelSpan.innerHTML=t.del,this.manipulationDOM.deleteSpan.appendChild(this.manipulationDOM.deleteLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv4),this.manipulationDiv.appendChild(this.manipulationDOM.deleteSpan)),this.manipulationDOM.addNodeSpan.onclick=this._createAddNodeToolbar.bind(this),this.manipulationDOM.addEdgeSpan.onclick=this._createAddEdgeToolbar.bind(this),1==this._getSelectedNodeCount()&&this.triggerFunctions.edit?this.manipulationDOM.editNodeSpan.onclick=this._editNode.bind(this):1==this._getSelectedEdgeCount()&&0==this._getSelectedNodeCount()&&(this.manipulationDOM.editEdgeSpan.onclick=this._createEditEdgeToolbar.bind(this)),0==this._selectionIsEmpty()&&(this.manipulationDOM.deleteSpan.onclick=this._deleteSelected.bind(this)),this.closeDiv.onclick=this._toggleEditMode.bind(this);var e=this;this.boundFunction=e._createManipulatorBar,this.on("select",this.boundFunction)}else{for(;this.editModeDiv.hasChildNodes();)this.editModeDiv.removeChild(this.editModeDiv.firstChild);this.manipulationDOM.editModeSpan=document.createElement("span"),this.manipulationDOM.editModeSpan.className="network-manipulationUI edit editmode",this.manipulationDOM.editModeLabelSpan=document.createElement("span"),this.manipulationDOM.editModeLabelSpan.className="network-manipulationLabel",this.manipulationDOM.editModeLabelSpan.innerHTML=t.edit,this.manipulationDOM.editModeSpan.appendChild(this.manipulationDOM.editModeLabelSpan),this.editModeDiv.appendChild(this.manipulationDOM.editModeSpan),this.manipulationDOM.editModeSpan.onclick=this._toggleEditMode.bind(this)}},e._createAddNodeToolbar=function(){this._clearManipulatorBar(),this.boundFunction&&this.off("select",this.boundFunction);var t=this.constants.locales[this.constants.locale];this.manipulationDOM={},this.manipulationDOM.backSpan=document.createElement("span"),this.manipulationDOM.backSpan.className="network-manipulationUI back",this.manipulationDOM.backLabelSpan=document.createElement("span"),this.manipulationDOM.backLabelSpan.className="network-manipulationLabel",this.manipulationDOM.backLabelSpan.innerHTML=t.back,this.manipulationDOM.backSpan.appendChild(this.manipulationDOM.backLabelSpan),this.manipulationDOM.seperatorLineDiv1=document.createElement("div"),this.manipulationDOM.seperatorLineDiv1.className="network-seperatorLine",this.manipulationDOM.descriptionSpan=document.createElement("span"),this.manipulationDOM.descriptionSpan.className="network-manipulationUI none",this.manipulationDOM.descriptionLabelSpan=document.createElement("span"),this.manipulationDOM.descriptionLabelSpan.className="network-manipulationLabel",this.manipulationDOM.descriptionLabelSpan.innerHTML=t.addDescription,this.manipulationDOM.descriptionSpan.appendChild(this.manipulationDOM.descriptionLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.backSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv1),this.manipulationDiv.appendChild(this.manipulationDOM.descriptionSpan),this.manipulationDOM.backSpan.onclick=this._createManipulatorBar.bind(this); -var e=this;this.boundFunction=e._addNode,this.on("select",this.boundFunction)},e._createAddEdgeToolbar=function(){this._clearManipulatorBar(),this._unselectAll(!0),this.freezeSimulation=!0,this.boundFunction&&this.off("select",this.boundFunction);var t=this.constants.locales[this.constants.locale];this._unselectAll(),this.forceAppendSelection=!1,this.blockConnectingEdgeSelection=!0,this.manipulationDOM={},this.manipulationDOM.backSpan=document.createElement("span"),this.manipulationDOM.backSpan.className="network-manipulationUI back",this.manipulationDOM.backLabelSpan=document.createElement("span"),this.manipulationDOM.backLabelSpan.className="network-manipulationLabel",this.manipulationDOM.backLabelSpan.innerHTML=t.back,this.manipulationDOM.backSpan.appendChild(this.manipulationDOM.backLabelSpan),this.manipulationDOM.seperatorLineDiv1=document.createElement("div"),this.manipulationDOM.seperatorLineDiv1.className="network-seperatorLine",this.manipulationDOM.descriptionSpan=document.createElement("span"),this.manipulationDOM.descriptionSpan.className="network-manipulationUI none",this.manipulationDOM.descriptionLabelSpan=document.createElement("span"),this.manipulationDOM.descriptionLabelSpan.className="network-manipulationLabel",this.manipulationDOM.descriptionLabelSpan.innerHTML=t.edgeDescription,this.manipulationDOM.descriptionSpan.appendChild(this.manipulationDOM.descriptionLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.backSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv1),this.manipulationDiv.appendChild(this.manipulationDOM.descriptionSpan),this.manipulationDOM.backSpan.onclick=this._createManipulatorBar.bind(this);var e=this;this.boundFunction=e._handleConnect,this.on("select",this.boundFunction),this.cachedFunctions._handleTouch=this._handleTouch,this.cachedFunctions._manipulationReleaseOverload=this._manipulationReleaseOverload,this.cachedFunctions._handleDragStart=this._handleDragStart,this.cachedFunctions._handleDragEnd=this._handleDragEnd,this._handleTouch=this._handleConnect,this._manipulationReleaseOverload=function(){},this._handleDragStart=function(){},this._handleDragEnd=this._finishConnect,this._redraw()},e._createEditEdgeToolbar=function(){this._clearManipulatorBar(),this.controlNodesActive=!0,this.boundFunction&&this.off("select",this.boundFunction),this.edgeBeingEdited=this._getSelectedEdge(),this.edgeBeingEdited._enableControlNodes();var t=this.constants.locales[this.constants.locale];this.manipulationDOM={},this.manipulationDOM.backSpan=document.createElement("span"),this.manipulationDOM.backSpan.className="network-manipulationUI back",this.manipulationDOM.backLabelSpan=document.createElement("span"),this.manipulationDOM.backLabelSpan.className="network-manipulationLabel",this.manipulationDOM.backLabelSpan.innerHTML=t.back,this.manipulationDOM.backSpan.appendChild(this.manipulationDOM.backLabelSpan),this.manipulationDOM.seperatorLineDiv1=document.createElement("div"),this.manipulationDOM.seperatorLineDiv1.className="network-seperatorLine",this.manipulationDOM.descriptionSpan=document.createElement("span"),this.manipulationDOM.descriptionSpan.className="network-manipulationUI none",this.manipulationDOM.descriptionLabelSpan=document.createElement("span"),this.manipulationDOM.descriptionLabelSpan.className="network-manipulationLabel",this.manipulationDOM.descriptionLabelSpan.innerHTML=t.editEdgeDescription,this.manipulationDOM.descriptionSpan.appendChild(this.manipulationDOM.descriptionLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.backSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv1),this.manipulationDiv.appendChild(this.manipulationDOM.descriptionSpan),this.manipulationDOM.backSpan.onclick=this._createManipulatorBar.bind(this),this.cachedFunctions._handleTouch=this._handleTouch,this.cachedFunctions._manipulationReleaseOverload=this._manipulationReleaseOverload,this.cachedFunctions._handleTap=this._handleTap,this.cachedFunctions._handleDragStart=this._handleDragStart,this.cachedFunctions._handleOnDrag=this._handleOnDrag,this._handleTouch=this._selectControlNode,this._handleTap=function(){},this._handleOnDrag=this._controlNodeDrag,this._handleDragStart=function(){},this._manipulationReleaseOverload=this._releaseControlNode,this._redraw()},e._selectControlNode=function(t){this.edgeBeingEdited.controlNodes.from.unselect(),this.edgeBeingEdited.controlNodes.to.unselect(),this.selectedControlNode=this.edgeBeingEdited._getSelectedControlNode(this._XconvertDOMtoCanvas(t.x),this._YconvertDOMtoCanvas(t.y)),null!==this.selectedControlNode&&(this.selectedControlNode.select(),this.freezeSimulation=!0),this._redraw()},e._controlNodeDrag=function(t){var e=this._getPointer(t.gesture.center);null!==this.selectedControlNode&&void 0!==this.selectedControlNode&&(this.selectedControlNode.x=this._XconvertDOMtoCanvas(e.x),this.selectedControlNode.y=this._YconvertDOMtoCanvas(e.y)),this._redraw()},e._releaseControlNode=function(t){var e=this._getNodeAt(t);null!==e?(1==this.edgeBeingEdited.controlNodes.from.selected&&(this.edgeBeingEdited._restoreControlNodes(),this._editEdge(e.id,this.edgeBeingEdited.to.id),this.edgeBeingEdited.controlNodes.from.unselect()),1==this.edgeBeingEdited.controlNodes.to.selected&&(this.edgeBeingEdited._restoreControlNodes(),this._editEdge(this.edgeBeingEdited.from.id,e.id),this.edgeBeingEdited.controlNodes.to.unselect())):this.edgeBeingEdited._restoreControlNodes(),this.freezeSimulation=!1,this._redraw()},e._handleConnect=function(t){if(0==this._getSelectedNodeCount()){var e=this._getNodeAt(t);if(null!=e)if(e.clusterSize>1)alert(this.constants.locales[this.constants.locale].createEdgeError);else{this._selectObject(e,!1);var i=this.sectors.support.nodes;i.targetNode=new o({id:"targetNode"},{},{},this.constants);var s=i.targetNode;s.x=e.x,s.y=e.y,this.edges.connectionEdge=new n({id:"connectionEdge",from:e.id,to:s.id},this,this.constants);var r=this.edges.connectionEdge;r.from=e,r.connected=!0,r.options.smoothCurves={enabled:!0,dynamic:!1,type:"continuous",roundness:.5},r.selected=!0,r.to=s,this.cachedFunctions._handleOnDrag=this._handleOnDrag,this._handleOnDrag=function(t){var e=this._getPointer(t.gesture.center),i=this.edges.connectionEdge;i.to.x=this._XconvertDOMtoCanvas(e.x),i.to.y=this._YconvertDOMtoCanvas(e.y)},this.moving=!0,this.start()}}},e._finishConnect=function(t){if(1==this._getSelectedNodeCount()){var e=this._getPointer(t.gesture.center);this._handleOnDrag=this.cachedFunctions._handleOnDrag,delete this.cachedFunctions._handleOnDrag;var i=this.edges.connectionEdge.fromId;delete this.edges.connectionEdge,delete this.sectors.support.nodes.targetNode,delete this.sectors.support.nodes.targetViaNode;var s=this._getNodeAt(e);null!=s&&(s.clusterSize>1?alert(this.constants.locales[this.constants.locale].createEdgeError):(this._createEdge(i,s.id),this._createManipulatorBar())),this._unselectAll()}},e._addNode=function(){if(this._selectionIsEmpty()&&1==this.editMode){var t=this._pointerToPositionObject(this.pointerPosition),e={id:s.randomUUID(),x:t.left,y:t.top,label:"new",allowedToMoveX:!0,allowedToMoveY:!0};if(this.triggerFunctions.add){if(2!=this.triggerFunctions.add.length)throw new Error("The function for add does not support two arguments (data,callback)");var i=this;this.triggerFunctions.add(e,function(t){i.nodesData.add(t),i._createManipulatorBar(),i.moving=!0,i.start()})}else this.nodesData.add(e),this._createManipulatorBar(),this.moving=!0,this.start()}},e._createEdge=function(t,e){if(1==this.editMode){var i={from:t,to:e};if(this.triggerFunctions.connect){if(2!=this.triggerFunctions.connect.length)throw new Error("The function for connect does not support two arguments (data,callback)");var s=this;this.triggerFunctions.connect(i,function(t){s.edgesData.add(t),s.moving=!0,s.start()})}else this.edgesData.add(i),this.moving=!0,this.start()}},e._editEdge=function(t,e){if(1==this.editMode){var i={id:this.edgeBeingEdited.id,from:t,to:e};if(this.triggerFunctions.editEdge){if(2!=this.triggerFunctions.editEdge.length)throw new Error("The function for edit does not support two arguments (data, callback)");var s=this;this.triggerFunctions.editEdge(i,function(t){s.edgesData.update(t),s.moving=!0,s.start()})}else this.edgesData.update(i),this.moving=!0,this.start()}},e._editNode=function(){if(!this.triggerFunctions.edit||1!=this.editMode)throw new Error("No edit function has been bound to this button");var t=this._getSelectedNode(),e={id:t.id,label:t.label,group:t.options.group,shape:t.options.shape,color:{background:t.options.color.background,border:t.options.color.border,highlight:{background:t.options.color.highlight.background,border:t.options.color.highlight.border}}};if(2!=this.triggerFunctions.edit.length)throw new Error("The function for edit does not support two arguments (data, callback)");var i=this;this.triggerFunctions.edit(e,function(t){i.nodesData.update(t),i._createManipulatorBar(),i.moving=!0,i.start()})},e._deleteSelected=function(){if(!this._selectionIsEmpty()&&1==this.editMode)if(this._clusterInSelection())alert(this.constants.locales[this.constants.locale].deleteClusterError);else{var t=this.getSelectedNodes(),e=this.getSelectedEdges();if(this.triggerFunctions.del){var i=this,s={nodes:t,edges:e};if(2!=this.triggerFunctions.del.length)throw new Error("The function for delete does not support two arguments (data, callback)");this.triggerFunctions.del(s,function(t){i.edgesData.remove(t.edges),i.nodesData.remove(t.nodes),i._unselectAll(),i.moving=!0,i.start()})}else this.edgesData.remove(e),this.nodesData.remove(t),this._unselectAll(),this.moving=!0,this.start()}}},function(t,e,i){var s=(i(1),i(45));e._cleanNavigation=function(){if(0!=this.navigationHammers.existing.length){for(var t=0;t0){var t,e,i=0,s=!1,o=!1;for(e in this.nodes)this.nodes.hasOwnProperty(e)&&(t=this.nodes[e],-1!=t.level?s=!0:o=!0,is&&(n.xFixed=!1,n.x=i[n.level].minPos,r=!0):n.yFixed&&n.level>s&&(n.yFixed=!1,n.y=i[n.level].minPos,r=!0),1==r&&(i[n.level].minPos+=i[n.level].nodeSpacing,n.edges.length>1&&this._placeBranchNodes(n.edges,n.id,i,n.level))}},e._setLevel=function(t,e,i){for(var s=0;st)&&(o.level=t,o.edges.length>1&&this._setLevel(t+1,o.edges,o.id))}},e._setLevelDirected=function(t,e,i){this.nodes[i].hierarchyEnumerated=!0;for(var s,o,n=0;n1&&s.hierarchyEnumerated===!1&&this._setLevelDirected(s.level,s.edges,s.id)},e._restoreNodes=function(){for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&(this.nodes[t].xFixed=!1,this.nodes[t].yFixed=!1)}},function(t,e,i){function s(){this.constants.smoothCurves.enabled=!this.constants.smoothCurves.enabled;var t=document.getElementById("graph_toggleSmooth");t.style.background=1==this.constants.smoothCurves.enabled?"#A4FF56":"#FF8532",this._configureSmoothCurves(!1)}function o(){for(var t in this.calculationNodes)this.calculationNodes.hasOwnProperty(t)&&(this.calculationNodes[t].vx=0,this.calculationNodes[t].vy=0,this.calculationNodes[t].fx=0,this.calculationNodes[t].fy=0);1==this.constants.hierarchicalLayout.enabled?(this._setupHierarchicalLayout(),a.call(this,"graph_H_nd",1,"physics_hierarchicalRepulsion_nodeDistance"),a.call(this,"graph_H_cg",1,"physics_centralGravity"),a.call(this,"graph_H_sc",1,"physics_springConstant"),a.call(this,"graph_H_sl",1,"physics_springLength"),a.call(this,"graph_H_damp",1,"physics_damping")):this.repositionNodes(),this.moving=!0,this.start()}function n(){var t="No options are required, default values used.",e=[],i=document.getElementById("graph_physicsMethod1"),s=document.getElementById("graph_physicsMethod2");if(1==i.checked){if(this.constants.physics.barnesHut.gravitationalConstant!=this.backupConstants.physics.barnesHut.gravitationalConstant&&e.push("gravitationalConstant: "+this.constants.physics.barnesHut.gravitationalConstant),this.constants.physics.centralGravity!=this.backupConstants.physics.barnesHut.centralGravity&&e.push("centralGravity: "+this.constants.physics.centralGravity),this.constants.physics.springLength!=this.backupConstants.physics.barnesHut.springLength&&e.push("springLength: "+this.constants.physics.springLength),this.constants.physics.springConstant!=this.backupConstants.physics.barnesHut.springConstant&&e.push("springConstant: "+this.constants.physics.springConstant),this.constants.physics.damping!=this.backupConstants.physics.barnesHut.damping&&e.push("damping: "+this.constants.physics.damping),0!=e.length){t="var options = {",t+="physics: {barnesHut: {";for(var o=0;othis.constants.clustering.clusterThreshold&&1==this.constants.clustering.enabled&&this.clusterToFit(this.constants.clustering.reduceToNodes,!1),this._calculateForces())},e._calculateForces=function(){this._calculateGravitationalForces(),this._calculateNodeForces(),this.constants.physics.springConstant>0&&(1==this.constants.smoothCurves.enabled&&1==this.constants.smoothCurves.dynamic?this._calculateSpringForcesWithSupport():1==this.constants.physics.hierarchicalRepulsion.enabled?this._calculateHierarchicalSpringForces():this._calculateSpringForces())},e._updateCalculationNodes=function(){if(1==this.constants.smoothCurves.enabled&&1==this.constants.smoothCurves.dynamic){this.calculationNodes={},this.calculationNodeIndices=[];for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&(this.calculationNodes[t]=this.nodes[t]);var e=this.sectors.support.nodes;for(var i in e)e.hasOwnProperty(i)&&(this.edges.hasOwnProperty(e[i].parentEdgeId)?this.calculationNodes[i]=e[i]:e[i]._setForce(0,0));for(var s in this.calculationNodes)this.calculationNodes.hasOwnProperty(s)&&this.calculationNodeIndices.push(s)}else this.calculationNodes=this.nodes,this.calculationNodeIndices=this.nodeIndices},e._calculateGravitationalForces=function(){var t,e,i,s,o,n=this.calculationNodes,r=this.constants.physics.centralGravity,a=0;for(o=0;oSimulation Mode:Barnes HutRepulsionHierarchical
Options:
',this.containerElement.parentElement.insertBefore(this.physicsConfiguration,this.containerElement),this.optionsDiv=document.createElement("div"),this.optionsDiv.style.fontSize="14px",this.optionsDiv.style.fontFamily="verdana",this.containerElement.parentElement.insertBefore(this.optionsDiv,this.containerElement); -var e;e=document.getElementById("graph_BH_gc"),e.onchange=a.bind(this,"graph_BH_gc",-1,"physics_barnesHut_gravitationalConstant"),e=document.getElementById("graph_BH_cg"),e.onchange=a.bind(this,"graph_BH_cg",1,"physics_centralGravity"),e=document.getElementById("graph_BH_sc"),e.onchange=a.bind(this,"graph_BH_sc",1,"physics_springConstant"),e=document.getElementById("graph_BH_sl"),e.onchange=a.bind(this,"graph_BH_sl",1,"physics_springLength"),e=document.getElementById("graph_BH_damp"),e.onchange=a.bind(this,"graph_BH_damp",1,"physics_damping"),e=document.getElementById("graph_R_nd"),e.onchange=a.bind(this,"graph_R_nd",1,"physics_repulsion_nodeDistance"),e=document.getElementById("graph_R_cg"),e.onchange=a.bind(this,"graph_R_cg",1,"physics_centralGravity"),e=document.getElementById("graph_R_sc"),e.onchange=a.bind(this,"graph_R_sc",1,"physics_springConstant"),e=document.getElementById("graph_R_sl"),e.onchange=a.bind(this,"graph_R_sl",1,"physics_springLength"),e=document.getElementById("graph_R_damp"),e.onchange=a.bind(this,"graph_R_damp",1,"physics_damping"),e=document.getElementById("graph_H_nd"),e.onchange=a.bind(this,"graph_H_nd",1,"physics_hierarchicalRepulsion_nodeDistance"),e=document.getElementById("graph_H_cg"),e.onchange=a.bind(this,"graph_H_cg",1,"physics_centralGravity"),e=document.getElementById("graph_H_sc"),e.onchange=a.bind(this,"graph_H_sc",1,"physics_springConstant"),e=document.getElementById("graph_H_sl"),e.onchange=a.bind(this,"graph_H_sl",1,"physics_springLength"),e=document.getElementById("graph_H_damp"),e.onchange=a.bind(this,"graph_H_damp",1,"physics_damping"),e=document.getElementById("graph_H_direction"),e.onchange=a.bind(this,"graph_H_direction",t,"hierarchicalLayout_direction"),e=document.getElementById("graph_H_levsep"),e.onchange=a.bind(this,"graph_H_levsep",1,"hierarchicalLayout_levelSeparation"),e=document.getElementById("graph_H_nspac"),e.onchange=a.bind(this,"graph_H_nspac",1,"hierarchicalLayout_nodeSpacing");var i=document.getElementById("graph_physicsMethod1"),d=document.getElementById("graph_physicsMethod2"),l=document.getElementById("graph_physicsMethod3");d.checked=!0,this.constants.physics.barnesHut.enabled&&(i.checked=!0),this.constants.hierarchicalLayout.enabled&&(l.checked=!0);var c=document.getElementById("graph_toggleSmooth"),p=document.getElementById("graph_repositionNodes"),u=document.getElementById("graph_generateOptions");c.onclick=s.bind(this),p.onclick=o.bind(this),u.onclick=n.bind(this),c.style.background=1==this.constants.smoothCurves&&0==this.constants.dynamicSmoothCurves?"#A4FF56":"#FF8532",r.apply(this),i.onchange=r.bind(this),d.onchange=r.bind(this),l.onchange=r.bind(this)}},e._overWriteGraphConstants=function(t,e){var i=t.split("_");1==i.length?this.constants[i[0]]=e:2==i.length?this.constants[i[0]][i[1]]=e:3==i.length&&(this.constants[i[0]][i[1]][i[2]]=e)}},function(t){function e(t){throw new Error("Cannot find module '"+t+"'.")}e.keys=function(){return[]},e.resolve=e,t.exports=e,e.id=67},function(t,e){e._calculateNodeForces=function(){var t,e,i,s,o,n,r,a,h,d,l,c=this.calculationNodes,p=this.calculationNodeIndices,u=-2/3,m=4/3,f=this.constants.physics.repulsion.nodeDistance,g=f;for(d=0;di&&(r=.5*g>i?1:v*i+m,r*=0==n?1:1+n*this.constants.clustering.forceAmplification,r/=Math.max(i,.01*g),s=t*r,o=e*r,a.fx-=s,a.fy-=o,h.fx+=s,h.fy+=o)}}},function(t,e){e._calculateNodeForces=function(){var t,e,i,s,o,n,r,a,h,d,l=this.calculationNodes,c=this.calculationNodeIndices,p=this.constants.physics.hierarchicalRepulsion.nodeDistance;for(h=0;hi?-Math.pow(u*i,2)+Math.pow(u*p,2):0,0==i?i=.01:n/=i,s=t*n,o=e*n,r.fx-=s,r.fy-=o,a.fx+=s,a.fy+=o}},e._calculateHierarchicalSpringForces=function(){for(var t,e,i,s,o,n,r,a,h,d=this.edges,l=this.calculationNodes,c=this.calculationNodeIndices,p=0;pn;n++)t=e[i[n]],t.options.mass>0&&(this._getForceContribution(o.root.children.NW,t),this._getForceContribution(o.root.children.NE,t),this._getForceContribution(o.root.children.SW,t),this._getForceContribution(o.root.children.SE,t))}},e._getForceContribution=function(t,e){if(t.childrenCount>0){var i,s,o;if(i=t.centerOfMass.x-e.x,s=t.centerOfMass.y-e.y,o=Math.sqrt(i*i+s*s),o*t.calcSize>this.constants.physics.barnesHut.thetaInverted){0==o&&(o=.1*Math.random(),i=o);var n=this.constants.physics.barnesHut.gravitationalConstant*t.mass*e.options.mass/(o*o*o),r=i*n,a=s*n;e.fx+=r,e.fy+=a}else if(4==t.childrenCount)this._getForceContribution(t.children.NW,e),this._getForceContribution(t.children.NE,e),this._getForceContribution(t.children.SW,e),this._getForceContribution(t.children.SE,e);else if(t.children.data.id!=e.id){0==o&&(o=.5*Math.random(),i=o);var n=this.constants.physics.barnesHut.gravitationalConstant*t.mass*e.options.mass/(o*o*o),r=i*n,a=s*n;e.fx+=r,e.fy+=a}}},e._formBarnesHutTree=function(t,e){for(var i,s=e.length,o=Number.MAX_VALUE,n=Number.MAX_VALUE,r=-Number.MAX_VALUE,a=-Number.MAX_VALUE,h=0;s>h;h++){var d=t[e[h]].x,l=t[e[h]].y;t[e[h]].options.mass>0&&(o>d&&(o=d),d>r&&(r=d),n>l&&(n=l),l>a&&(a=l))}var c=Math.abs(r-o)-Math.abs(a-n);c>0?(n-=.5*c,a+=.5*c):(o+=.5*c,r-=.5*c);var p=1e-5,u=Math.max(p,Math.abs(r-o)),m=.5*u,f=.5*(o+r),g=.5*(n+a),v={root:{centerOfMass:{x:0,y:0},mass:0,range:{minX:f-m,maxX:f+m,minY:g-m,maxY:g+m},size:u,calcSize:1/u,children:{data:null},maxWidth:0,level:0,childrenCount:4}};for(this._splitBranch(v.root),h=0;s>h;h++)i=t[e[h]],i.options.mass>0&&this._placeInTree(v.root,i);this.barnesHutTree=v},e._updateBranchMass=function(t,e){var i=t.mass+e.options.mass,s=1/i;t.centerOfMass.x=t.centerOfMass.x*t.mass+e.x*e.options.mass,t.centerOfMass.x*=s,t.centerOfMass.y=t.centerOfMass.y*t.mass+e.y*e.options.mass,t.centerOfMass.y*=s,t.mass=i;var o=Math.max(Math.max(e.height,e.radius),e.width);t.maxWidth=t.maxWidthe.x?t.children.NW.range.maxY>e.y?this._placeInRegion(t,e,"NW"):this._placeInRegion(t,e,"SW"):t.children.NW.range.maxY>e.y?this._placeInRegion(t,e,"NE"):this._placeInRegion(t,e,"SE")},e._placeInRegion=function(t,e,i){switch(t.children[i].childrenCount){case 0:t.children[i].children.data=e,t.children[i].childrenCount=1,this._updateBranchMass(t.children[i],e);break;case 1:t.children[i].children.data.x==e.x&&t.children[i].children.data.y==e.y?(e.x+=Math.random(),e.y+=Math.random()):(this._splitBranch(t.children[i]),this._placeInTree(t.children[i],e));break;case 4:this._placeInTree(t.children[i],e)}},e._splitBranch=function(t){var e=null;1==t.childrenCount&&(e=t.children.data,t.mass=0,t.centerOfMass.x=0,t.centerOfMass.y=0),t.childrenCount=4,t.children.data=null,this._insertRegion(t,"NW"),this._insertRegion(t,"NE"),this._insertRegion(t,"SW"),this._insertRegion(t,"SE"),null!=e&&this._placeInTree(t,e)},e._insertRegion=function(t,e){var i,s,o,n,r=.5*t.size;switch(e){case"NW":i=t.range.minX,s=t.range.minX+r,o=t.range.minY,n=t.range.minY+r;break;case"NE":i=t.range.minX+r,s=t.range.maxX,o=t.range.minY,n=t.range.minY+r;break;case"SW":i=t.range.minX,s=t.range.minX+r,o=t.range.minY+r,n=t.range.maxY;break;case"SE":i=t.range.minX+r,s=t.range.maxX,o=t.range.minY+r,n=t.range.maxY}t.children[e]={centerOfMass:{x:0,y:0},mass:0,range:{minX:i,maxX:s,minY:o,maxY:n},size:.5*t.size,calcSize:2*t.calcSize,children:{data:null},maxWidth:0,level:t.level+1,childrenCount:0}},e._drawTree=function(t,e){void 0!==this.barnesHutTree&&(t.lineWidth=1,this._drawBranch(this.barnesHutTree.root,t,e))},e._drawBranch=function(t,e,i){void 0===i&&(i="#FF0000"),4==t.childrenCount&&(this._drawBranch(t.children.NW,e),this._drawBranch(t.children.NE,e),this._drawBranch(t.children.SE,e),this._drawBranch(t.children.SW,e)),e.strokeStyle=i,e.beginPath(),e.moveTo(t.range.minX,t.range.minY),e.lineTo(t.range.maxX,t.range.minY),e.stroke(),e.beginPath(),e.moveTo(t.range.maxX,t.range.minY),e.lineTo(t.range.maxX,t.range.maxY),e.stroke(),e.beginPath(),e.moveTo(t.range.maxX,t.range.maxY),e.lineTo(t.range.minX,t.range.maxY),e.stroke(),e.beginPath(),e.moveTo(t.range.minX,t.range.maxY),e.lineTo(t.range.minX,t.range.minY),e.stroke()}},function(t){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children=[],t.webpackPolyfill=1),t}}])}); +t.strokeStyle=this.selected?this.options.color.highlight.border:this.hover?this.options.color.hover.border:this.options.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.database(this.x-this.width/2-2*t.lineWidth,this.y-.5*this.height-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.fillStyle=this.selected?this.options.color.highlight.background:this.hover?this.options.color.hover.background:this.options.color.background,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this.boundingBox.top=this.top,this.boundingBox.left=this.left,this.boundingBox.right=this.left+this.width,this.boundingBox.bottom=this.top+this.height,this._label(t,this.label,this.x,this.y)},s.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),s=Math.max(i.width,i.height)+2*e;this.options.radius=s/2,this.width=s,this.height=s,this.options.radius+=.5*Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.options.radius-.5*s}},s.prototype._drawRawCircle=function(t,e,i,s){var o=2.5,n=this.options.borderWidth,r=this.options.borderWidthSelected||2*this.options.borderWidth;t.strokeStyle=this.selected?this.options.color.highlight.border:this.hover?this.options.color.hover.border:this.options.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?r:n)+(this.clusterSize>1?o:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.circle(e,i,s+2*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?r:n)+(this.clusterSize>1?o:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.fillStyle=this.selected?this.options.color.highlight.background:this.hover?this.options.color.hover.background:this.options.color.background,t.circle(this.x,this.y,s),t.fill(),t.stroke()},s.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._drawRawCircle(t,this.x,this.y,this.options.radius),this.boundingBox.top=this.y-this.options.radius,this.boundingBox.left=this.x-this.options.radius,this.boundingBox.right=this.x+this.options.radius,this.boundingBox.bottom=this.y+this.options.radius,this._label(t,this.label,this.x,this.y)},s.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.width1&&(t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.ellipse(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.fillStyle=this.selected?this.options.color.highlight.background:this.hover?this.options.color.hover.background:this.options.color.background,t.ellipse(this.left,this.top,this.width,this.height),t.fill(),t.stroke(),this.boundingBox.top=this.top,this.boundingBox.left=this.left,this.boundingBox.right=this.left+this.width,this.boundingBox.bottom=this.top+this.height,this._label(t,this.label,this.x,this.y)},s.prototype._drawDot=function(t){this._drawShape(t,"circle")},s.prototype._drawTriangle=function(t){this._drawShape(t,"triangle")},s.prototype._drawTriangleDown=function(t){this._drawShape(t,"triangleDown")},s.prototype._drawSquare=function(t){this._drawShape(t,"square")},s.prototype._drawStar=function(t){this._drawShape(t,"star")},s.prototype._resizeShape=function(){if(!this.width){this.options.radius=this.baseRadiusValue;var t=2*this.options.radius;this.width=t,this.height=t,this.width+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeWidthFactor,this.height+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeHeightFactor,this.options.radius+=.5*Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-t}},s.prototype._drawShape=function(t,e){this._resizeShape(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var i=2.5,s=this.options.borderWidth,o=this.options.borderWidthSelected||2*this.options.borderWidth,n=2;switch(e){case"dot":n=2;break;case"square":n=2;break;case"triangle":n=3;break;case"triangleDown":n=3;break;case"star":n=4}t.strokeStyle=this.selected?this.options.color.highlight.border:this.hover?this.options.color.hover.border:this.options.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?o:s)+(this.clusterSize>1?i:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t[e](this.x,this.y,this.options.radius+n*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?o:s)+(this.clusterSize>1?i:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.fillStyle=this.selected?this.options.color.highlight.background:this.hover?this.options.color.hover.background:this.options.color.background,t[e](this.x,this.y,this.options.radius),t.fill(),t.stroke(),this.boundingBox.top=this.y-this.options.radius,this.boundingBox.left=this.x-this.options.radius,this.boundingBox.right=this.x+this.options.radius,this.boundingBox.bottom=this.y+this.options.radius,this.label&&(this._label(t,this.label,this.x,this.y+this.height/2,void 0,"hanging",!0),this.boundingBox.left=Math.min(this.boundingBox.left,this.labelDimensions.left),this.boundingBox.right=Math.max(this.boundingBox.right,this.labelDimensions.left+this.labelDimensions.width),this.boundingBox.bottom=Math.max(this.boundingBox.bottom,this.boundingBox.bottom+this.labelDimensions.height))},s.prototype._resizeText=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeWidthFactor,this.height+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeHeightFactor,this.options.radius+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-(i.width+2*e)}},s.prototype._drawText=function(t){this._resizeText(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._label(t,this.label,this.x,this.y),this.boundingBox.top=this.top,this.boundingBox.left=this.left,this.boundingBox.right=this.left+this.width,this.boundingBox.bottom=this.top+this.height},s.prototype._label=function(t,e,i,s,o,n,r){if(e&&Number(this.options.fontSize)*this.networkScale>this.fontDrawThreshold){t.font=(this.selected?"bold ":"")+this.options.fontSize+"px "+this.options.fontFace;var a=e.split("\n"),h=a.length,d=Number(this.options.fontSize),l=s+(1-h)/2*d;1==r&&(l=s+(1-h)/(2*d));for(var c=t.measureText(a[0]).width,p=1;h>p;p++){var u=t.measureText(a[p]).width;c=u>c?u:c}var m=this.options.fontSize*h,f=i-c/2,g=s-m/2;"hanging"==n&&(g+=.5*d,g+=4,l+=4),this.labelDimensions={top:g,left:f,width:c,height:m,yLine:l},void 0!==this.options.fontFill&&null!==this.options.fontFill&&"none"!==this.options.fontFill&&(t.fillStyle=this.options.fontFill,t.fillRect(f,g,c,m)),t.fillStyle=this.options.fontColor||"black",t.textAlign=o||"center",t.textBaseline=n||"middle",this.options.fontStrokeWidth>0&&(t.lineWidth=this.options.fontStrokeWidth,t.strokeStyle=this.options.fontStrokeColor,t.lineJoin="round");for(var p=0;h>p;p++)this.options.fontStrokeWidth&&t.strokeText(a[p],i,l),t.fillText(a[p],i,l),l+=d}},s.prototype.getTextSize=function(t){if(void 0!==this.label){t.font=(this.selected?"bold ":"")+this.options.fontSize+"px "+this.options.fontFace;for(var e=this.label.split("\n"),i=(Number(this.options.fontSize)+4)*e.length,s=0,o=0,n=e.length;n>o;o++)s=Math.max(s,t.measureText(e[o]).width);return{width:s,height:i,lineCount:e.length}}return{width:0,height:0,lineCount:0}},s.prototype.inArea=function(){return void 0!==this.width?this.x+this.width*this.networkScaleInv>=this.canvasTopLeft.x&&this.x-this.width*this.networkScaleInv=this.canvasTopLeft.y&&this.y-this.height*this.networkScaleInv=this.canvasTopLeft.x&&this.x=this.canvasTopLeft.y&&this.ys&&(n=s-e-this.padding),no&&(r=o-i-this.padding),ri;i++)if(e.id===r.nodes[i].id){o=r.nodes[i];break}for(o||(o={id:e.id},t.node&&(o.attr=a(o.attr,t.node))),i=n.length-1;i>=0;i--){var h=n[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(o)&&h.nodes.push(o)}e.attr&&(o.attr=a(o.attr,e.attr))}function l(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=a({},t.edge);e.attr=a(i,e.attr)}}function c(t,e,i,s,o){var n={from:e,to:i,type:s};return t.edge&&(n.attr=a({},t.edge)),n.attr=a(n.attr||{},o),n}function p(){for(N=D.NULL,k="";" "==E||" "==E||"\n"==E||"\r"==E;)o();do{var t=!1;if("#"==E){for(var e=O-1;" "==T.charAt(e)||" "==T.charAt(e);)e--;if("\n"==T.charAt(e)||""==T.charAt(e)){for(;""!=E&&"\n"!=E;)o();t=!0}}if("/"==E&&"/"==n()){for(;""!=E&&"\n"!=E;)o();t=!0}if("/"==E&&"*"==n()){for(;""!=E;){if("*"==E&&"/"==n()){o(),o();break}o()}t=!0}for(;" "==E||" "==E||"\n"==E||"\r"==E;)o()}while(t);if(""==E)return void(N=D.DELIMITER);var i=E+n();if(C[i])return N=D.DELIMITER,k=i,o(),void o();if(C[E])return N=D.DELIMITER,k=E,void o();if(r(E)||"-"==E){for(k+=E,o();r(E);)k+=E,o();return"false"==k?k=!1:"true"==k?k=!0:isNaN(Number(k))||(k=Number(k)),void(N=D.IDENTIFIER)}if('"'==E){for(o();""!=E&&('"'!=E||'"'==E&&'"'==n());)k+=E,'"'==E&&o(),o();if('"'!=E)throw x('End of string " expected');return o(),void(N=D.IDENTIFIER)}for(N=D.UNKNOWN;""!=E;)k+=E,o();throw new SyntaxError('Syntax error in part "'+w(k,30)+'"')}function u(){var t={};if(s(),p(),"strict"==k&&(t.strict=!0,p()),("graph"==k||"digraph"==k)&&(t.type=k,p()),N==D.IDENTIFIER&&(t.id=k,p()),"{"!=k)throw x("Angle bracket { expected");if(p(),m(t),"}"!=k)throw x("Angle bracket } expected");if(p(),""!==k)throw x("End of file expected");return p(),delete t.node,delete t.edge,delete t.graph,t}function m(t){for(;""!==k&&"}"!=k;)f(t),";"==k&&p()}function f(t){var e=g(t);if(e)return void b(t,e);var i=v(t);if(!i){if(N!=D.IDENTIFIER)throw x("Identifier expected");var s=k;if(p(),"="==k){if(p(),N!=D.IDENTIFIER)throw x("Identifier expected");t[s]=k,p()}else y(t,s)}}function g(t){var e=null;if("subgraph"==k&&(e={},e.type="subgraph",p(),N==D.IDENTIFIER&&(e.id=k,p())),"{"==k){if(p(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,m(e),"}"!=k)throw x("Angle bracket } expected");p(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function v(t){return"node"==k?(p(),t.node=_(),"node"):"edge"==k?(p(),t.edge=_(),"edge"):"graph"==k?(p(),t.graph=_(),"graph"):null}function y(t,e){var i={id:e},s=_();s&&(i.attr=s),d(t,i),b(t,e)}function b(t,e){for(;"->"==k||"--"==k;){var i,s=k;p();var o=g(t);if(o)i=o;else{if(N!=D.IDENTIFIER)throw x("Identifier or subgraph expected");i=k,d(t,{id:i}),p()}var n=_(),r=c(t,e,i,s,n);l(t,r),e=i}}function _(){for(var t=null;"["==k;){for(p(),t={};""!==k&&"]"!=k;){if(N!=D.IDENTIFIER)throw x("Attribute name expected");var e=k;if(p(),"="!=k)throw x("Equal sign = expected");if(p(),N!=D.IDENTIFIER)throw x("Attribute value expected");var i=k;h(t,e,i),p(),","==k&&p()}if("]"!=k)throw x("Bracket ] expected");p()}return t}function x(t){return new SyntaxError(t+', got "'+w(k,30)+'" (char '+O+")")}function w(t,e){return t.length<=e?t:t.substr(0,27)+"..."}function S(t,e,i){Array.isArray(t)?t.forEach(function(t){Array.isArray(e)?e.forEach(function(e){i(t,e)}):i(t,e)}):Array.isArray(e)?e.forEach(function(e){i(t,e)}):i(t,e)}function M(t){var e=i(t),s={nodes:[],edges:[],options:{}};if(e.nodes&&e.nodes.forEach(function(t){var e={id:t.id,label:String(t.label||t.id)};a(e,t.attr),e.image&&(e.shape="image"),s.nodes.push(e)}),e.edges){var o=function(t){var e={from:t.from,to:t.to};return a(e,t.attr),e.style="->"==t.type?"arrow":"line",e};e.edges.forEach(function(t){var e,i;e=t.from instanceof Object?t.from.nodes:{id:t.from},i=t.to instanceof Object?t.to.nodes:{id:t.to},t.from instanceof Object&&t.from.edges&&t.from.edges.forEach(function(t){var e=o(t);s.edges.push(e)}),S(e,i,function(e,i){var n=c(s,e.id,i.id,t.type,t.attr),r=o(n);s.edges.push(r)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=o(t);s.edges.push(e)})})}return e.attr&&(s.options=e.attr),s}var D={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},C={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},T="",O=0,E="",k="",N=D.NULL,I=/[a-zA-Z_0-9.:#]/;e.parseDOT=i,e.DOTToGraph=M},function(t,e){function i(t,e){var i=[],s=[];this.options={edges:{inheritColor:!0},nodes:{allowedToMove:!1,parseColor:!1}},void 0!==e&&(this.options.nodes.allowedToMove=e.allowedToMove|!1,this.options.nodes.parseColor=e.parseColor|!1,this.options.edges.inheritColor=e.inheritColor|!0);for(var o=t.edges,n=t.nodes,r=0;r=s&&(s=864e5),e=new Date(e.valueOf()-.05*s),i=new Date(i.valueOf()+.05*s)}return{start:e,end:i}},s.prototype.setWindow=function(t,e,i){var s=i&&void 0!==i.animate?i.animate:!0;if(1==arguments.length){var o=arguments[0];this.range.setRange(o.start,o.end,s)}else this.range.setRange(t,e,s)},s.prototype.moveTo=function(t,e){var i=this.range.end-this.range.start,s=r.convert(t,"Date").valueOf(),o=s-i/2,n=s+i/2,a=e&&void 0!==e.animate?e.animate:!0;this.range.setRange(o,n,a)},s.prototype.getWindow=function(){var t=this.range.getRange();return{start:new Date(t.start),end:new Date(t.end)}},s.prototype.redraw=function(){var t=!1,e=this.options,i=this.props,s=this.dom;if(s){h.updateHiddenDates(this.body,this.options.hiddenDates),"top"==e.orientation?(r.addClassName(s.root,"top"),r.removeClassName(s.root,"bottom")):(r.removeClassName(s.root,"top"),r.addClassName(s.root,"bottom")),s.root.style.maxHeight=r.option.asSize(e.maxHeight,""),s.root.style.minHeight=r.option.asSize(e.minHeight,""),s.root.style.width=r.option.asSize(e.width,""),i.border.left=(s.centerContainer.offsetWidth-s.centerContainer.clientWidth)/2,i.border.right=i.border.left,i.border.top=(s.centerContainer.offsetHeight-s.centerContainer.clientHeight)/2,i.border.bottom=i.border.top;var o=s.root.offsetHeight-s.root.clientHeight,n=s.root.offsetWidth-s.root.clientWidth;0===s.centerContainer.clientHeight&&(i.border.left=i.border.top,i.border.right=i.border.left),0===s.root.clientHeight&&(n=o),i.center.height=s.center.offsetHeight,i.left.height=s.left.offsetHeight,i.right.height=s.right.offsetHeight,i.top.height=s.top.clientHeight||-i.border.top,i.bottom.height=s.bottom.clientHeight||-i.border.bottom;var a=Math.max(i.left.height,i.center.height,i.right.height),d=i.top.height+a+i.bottom.height+o+i.border.top+i.border.bottom;s.root.style.height=r.option.asSize(e.height,d+"px"),i.root.height=s.root.offsetHeight,i.background.height=i.root.height-o;var l=i.root.height-i.top.height-i.bottom.height-o;i.centerContainer.height=l,i.leftContainer.height=l,i.rightContainer.height=i.leftContainer.height,i.root.width=s.root.offsetWidth,i.background.width=i.root.width-n,i.left.width=s.leftContainer.clientWidth||-i.border.left,i.leftContainer.width=i.left.width,i.right.width=s.rightContainer.clientWidth||-i.border.right,i.rightContainer.width=i.right.width;var c=i.root.width-i.left.width-i.right.width-n;i.center.width=c,i.centerContainer.width=c,i.top.width=c,i.bottom.width=c,s.background.style.height=i.background.height+"px",s.backgroundVertical.style.height=i.background.height+"px",s.backgroundHorizontal.style.height=i.centerContainer.height+"px",s.centerContainer.style.height=i.centerContainer.height+"px",s.leftContainer.style.height=i.leftContainer.height+"px",s.rightContainer.style.height=i.rightContainer.height+"px",s.background.style.width=i.background.width+"px",s.backgroundVertical.style.width=i.centerContainer.width+"px",s.backgroundHorizontal.style.width=i.background.width+"px",s.centerContainer.style.width=i.center.width+"px",s.top.style.width=i.top.width+"px",s.bottom.style.width=i.bottom.width+"px",s.background.style.left="0",s.background.style.top="0",s.backgroundVertical.style.left=i.left.width+i.border.left+"px",s.backgroundVertical.style.top="0",s.backgroundHorizontal.style.left="0",s.backgroundHorizontal.style.top=i.top.height+"px",s.centerContainer.style.left=i.left.width+"px",s.centerContainer.style.top=i.top.height+"px",s.leftContainer.style.left="0",s.leftContainer.style.top=i.top.height+"px",s.rightContainer.style.left=i.left.width+i.center.width+"px",s.rightContainer.style.top=i.top.height+"px",s.top.style.left=i.left.width+"px",s.top.style.top="0",s.bottom.style.left=i.left.width+"px",s.bottom.style.top=i.top.height+i.centerContainer.height+"px",this._updateScrollTop();var p=this.props.scrollTop;"bottom"==e.orientation&&(p+=Math.max(this.props.centerContainer.height-this.props.center.height-this.props.border.top-this.props.border.bottom,0)),s.center.style.left="0",s.center.style.top=p+"px",s.left.style.left="0",s.left.style.top=p+"px",s.right.style.left="0",s.right.style.top=p+"px";var u=0==this.props.scrollTop?"hidden":"",m=this.props.scrollTop==this.props.scrollTopMin?"hidden":"";if(s.shadowTop.style.visibility=u,s.shadowBottom.style.visibility=m,s.shadowTopLeft.style.visibility=u,s.shadowBottomLeft.style.visibility=m,s.shadowTopRight.style.visibility=u,s.shadowBottomRight.style.visibility=m,this.components.forEach(function(e){t=e.redraw()||t}),t){var f=3;this.redrawCount0&&(this.props.scrollTop=0),this.props.scrollTops;s++){var o=s%2===0?1.3*i:.5*i;this.lineTo(t+o*Math.sin(2*s*Math.PI/10),e-o*Math.cos(2*s*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,s,o){var n=Math.PI/180;0>i-2*o&&(o=i/2),0>s-2*o&&(o=s/2),this.beginPath(),this.moveTo(t+o,e),this.lineTo(t+i-o,e),this.arc(t+i-o,e+o,o,270*n,360*n,!1),this.lineTo(t+i,e+s-o),this.arc(t+i-o,e+s-o,o,0,90*n,!1),this.lineTo(t+o,e+s),this.arc(t+o,e+s-o,o,90*n,180*n,!1),this.lineTo(t,e+o),this.arc(t+o,e+o,o,180*n,270*n,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,s){var o=.5522848,n=i/2*o,r=s/2*o,a=t+i,h=e+s,d=t+i/2,l=e+s/2;this.beginPath(),this.moveTo(t,l),this.bezierCurveTo(t,l-r,d-n,e,d,e),this.bezierCurveTo(d+n,e,a,l-r,a,l),this.bezierCurveTo(a,l+r,d+n,h,d,h),this.bezierCurveTo(d-n,h,t,l+r,t,l)},CanvasRenderingContext2D.prototype.database=function(t,e,i,s){var o=1/3,n=i,r=s*o,a=.5522848,h=n/2*a,d=r/2*a,l=t+n,c=e+r,p=t+n/2,u=e+r/2,m=e+(s-r/2),f=e+s;this.beginPath(),this.moveTo(l,u),this.bezierCurveTo(l,u+d,p+h,c,p,c),this.bezierCurveTo(p-h,c,t,u+d,t,u),this.bezierCurveTo(t,u-d,p-h,e,p,e),this.bezierCurveTo(p+h,e,l,u-d,l,u),this.lineTo(l,m),this.bezierCurveTo(l,m+d,p+h,f,p,f),this.bezierCurveTo(p-h,f,t,m+d,t,m),this.lineTo(t,u)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,s){var o=t-s*Math.cos(i),n=e-s*Math.sin(i),r=t-.9*s*Math.cos(i),a=e-.9*s*Math.sin(i),h=o+s/3*Math.cos(i+.5*Math.PI),d=n+s/3*Math.sin(i+.5*Math.PI),l=o+s/3*Math.cos(i-.5*Math.PI),c=n+s/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,d),this.lineTo(r,a),this.lineTo(l,c),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,s,o){o||(o=[10,5]),0==p&&(p=.001);var n=o.length;this.moveTo(t,e);for(var r=i-t,a=s-e,h=a/r,d=Math.sqrt(r*r+a*a),l=0,c=!0;d>=.1;){var p=o[l++%n];p>d&&(p=d);var u=Math.sqrt(p*p/(1+h*h));0>r&&(u=-u),t+=u,e+=h*u,this[c?"lineTo":"moveTo"](t,e),d-=p,c=!c}})},function(t,e,i){function s(t,e){this.groupId=t,this.options=e}var o=i(2),n=i(53);s.prototype.getYRange=function(t){for(var e=t[0].y,i=t[0].y,s=0;st[s].y?t[s].y:e,i=i0){var r,a,h=Number(i.svg.style.height.replace("px",""));if(r=o.getSVGElement("path",i.svgElements,i.svg),r.setAttributeNS(null,"class",e.className),void 0!==e.style&&r.setAttributeNS(null,"style",e.style),a=1==e.options.catmullRom.enabled?s._catmullRom(t,e):s._linear(t),1==e.options.shaded.enabled){var d,l=o.getSVGElement("path",i.svgElements,i.svg);d="top"==e.options.shaded.orientation?"M"+t[0].x+",0 "+a+"L"+t[t.length-1].x+",0":"M"+t[0].x+","+h+" "+a+"L"+t[t.length-1].x+","+h,l.setAttributeNS(null,"class",e.className+" fill"),void 0!==e.options.shaded.style&&l.setAttributeNS(null,"style",e.options.shaded.style),l.setAttributeNS(null,"d",d)}r.setAttributeNS(null,"d","M"+a),1==e.options.drawPoints.enabled&&n.draw(t,e,i)}},s._catmullRomUniform=function(t){for(var e,i,s,o,n,r,a=Math.round(t[0].x)+","+Math.round(t[0].y)+" ",h=1/6,d=t.length,l=0;d-1>l;l++)e=0==l?t[0]:t[l-1],i=t[l],s=t[l+1],o=d>l+2?t[l+2]:s,n={x:(-e.x+6*i.x+s.x)*h,y:(-e.y+6*i.y+s.y)*h},r={x:(i.x+6*s.x-o.x)*h,y:(i.y+6*s.y-o.y)*h},a+="C"+n.x+","+n.y+" "+r.x+","+r.y+" "+s.x+","+s.y+" ";return a},s._catmullRom=function(t,e){var i=e.options.catmullRom.alpha;if(0==i||void 0===i)return this._catmullRomUniform(t);for(var s,o,n,r,a,h,d,l,c,p,u,m,f,g,v,y,b,_,x,w=Math.round(t[0].x)+","+Math.round(t[0].y)+" ",S=t.length,M=0;S-1>M;M++)s=0==M?t[0]:t[M-1],o=t[M],n=t[M+1],r=S>M+2?t[M+2]:n,d=Math.sqrt(Math.pow(s.x-o.x,2)+Math.pow(s.y-o.y,2)),l=Math.sqrt(Math.pow(o.x-n.x,2)+Math.pow(o.y-n.y,2)),c=Math.sqrt(Math.pow(n.x-r.x,2)+Math.pow(n.y-r.y,2)),g=Math.pow(c,i),y=Math.pow(c,2*i),v=Math.pow(l,i),b=Math.pow(l,2*i),x=Math.pow(d,i),_=Math.pow(d,2*i),p=2*_+3*x*v+b,u=2*y+3*g*v+b,m=3*x*(x+v),m>0&&(m=1/m),f=3*g*(g+v),f>0&&(f=1/f),a={x:(-b*s.x+p*o.x+_*n.x)*m,y:(-b*s.y+p*o.y+_*n.y)*m},h={x:(y*o.x+u*n.x-b*r.x)*f,y:(y*o.y+u*n.y-b*r.y)*f},0==a.x&&0==a.y&&(a=o),0==h.x&&0==h.y&&(h=n),w+="C"+a.x+","+a.y+" "+h.x+","+h.y+" "+n.x+","+n.y+" ";return w},s._linear=function(t){for(var e="",i=0;it[s].y?t[s].y:e,i=i0&&(n=Math.min(n,Math.abs(c[d-1].x-r))),a=s._getSafeDrawData(n,h,m);else{var g=d+(p[r].amount-p[r].resolved),v=d-(p[r].resolved+1);g0&&(n=Math.min(n,Math.abs(c[v].x-r))),a=s._getSafeDrawData(n,h,m),p[r].resolved+=1,"stack"==h.options.barChart.handleOverlap?(f=p[r].accumulated,p[r].accumulated+=h.zeroPosition-c[d].y):"sideBySide"==h.options.barChart.handleOverlap&&(a.width=a.width/p[r].amount,a.offset+=p[r].resolved*a.width-.5*a.width*(p[r].amount+1),"left"==h.options.barChart.align?a.offset-=.5*a.width:"right"==h.options.barChart.align&&(a.offset+=.5*a.width))}o.drawBar(c[d].x+a.offset,c[d].y-f,a.width,h.zeroPosition-c[d].y,h.className+" bar",i.svgElements,i.svg),1==h.options.drawPoints.enabled&&o.drawPoint(c[d].x+a.offset,c[d].y,h,i.svgElements,i.svg)}},s._getDataIntersections=function(t,e){for(var i,s=0;s0&&(i=Math.min(i,Math.abs(e[s-1].x-e[s].x))),0==i&&(void 0===t[e[s].x]&&(t[e[s].x]={amount:0,resolved:0,accumulated:0}),t[e[s].x].amount+=1)},s._getSafeDrawData=function(t,e,i){var s,o;return t0?(s=i>t?i:t,o=0,"left"==e.options.barChart.align?o-=.5*t:"right"==e.options.barChart.align&&(o+=.5*t)):(s=e.options.barChart.width,o=0,"left"==e.options.barChart.align?o-=.5*e.options.barChart.width:"right"==e.options.barChart.align&&(o+=.5*e.options.barChart.width)),{width:s,offset:o}},s.getStackedBarYRange=function(t,e,i,o,n){if(t.length>0){t.sort(function(t,e){return t.x==e.x?t.groupId-e.groupId:t.x-e.x});var r={};s._getDataIntersections(r,t),e[o]=s._getStackedBarYRange(r,t),e[o].yAxisOrientation=n,i.push(o)}},s._getStackedBarYRange=function(t,e){for(var i,s=e[0].y,o=e[0].y,n=0;ne[n].y?e[n].y:s,o=ot[r].accumulated?t[r].accumulated:s,o=ot[s].y?t[s].y:e,i=is;++s)i[s].apply(this,e)}return this},e.prototype.listeners=function(t){return this._callbacks=this._callbacks||{},this._callbacks[t]||[]},e.prototype.hasListeners=function(t){return!!this.listeners(t).length}},function(t,e){var i,s,o;!function(n,r){s=[],i=r,o="function"==typeof i?i.apply(e,s):i,!(void 0!==o&&(t.exports=o))}(this,function(){function t(t){var e,i=t&&t.preventDefault||!1,s=t&&t.container||window,o={},n={keydown:{},keyup:{}},r={};for(e=97;122>=e;e++)r[String.fromCharCode(e)]={code:65+(e-97),shift:!1};for(e=65;90>=e;e++)r[String.fromCharCode(e)]={code:e,shift:!0};for(e=0;9>=e;e++)r[""+e]={code:48+e,shift:!1};for(e=1;12>=e;e++)r["F"+e]={code:111+e,shift:!1};for(e=0;9>=e;e++)r["num"+e]={code:96+e,shift:!1};r["num*"]={code:106,shift:!1},r["num+"]={code:107,shift:!1},r["num-"]={code:109,shift:!1},r["num/"]={code:111,shift:!1},r["num."]={code:110,shift:!1},r.left={code:37,shift:!1},r.up={code:38,shift:!1},r.right={code:39,shift:!1},r.down={code:40,shift:!1},r.space={code:32,shift:!1},r.enter={code:13,shift:!1},r.shift={code:16,shift:void 0},r.esc={code:27,shift:!1},r.backspace={code:8,shift:!1},r.tab={code:9,shift:!1},r.ctrl={code:17,shift:!1},r.alt={code:18,shift:!1},r["delete"]={code:46,shift:!1},r.pageup={code:33,shift:!1},r.pagedown={code:34,shift:!1},r["="]={code:187,shift:!1},r["-"]={code:189,shift:!1},r["]"]={code:221,shift:!1},r["["]={code:219,shift:!1};var a=function(t){d(t,"keydown")},h=function(t){d(t,"keyup")},d=function(t,e){if(void 0!==n[e][t.keyCode]){for(var s=n[e][t.keyCode],o=0;oe-n?(i=t.clone().add(o-1,"months"),s=(e-n)/(n-i)):(i=t.clone().add(o+1,"months"),s=(e-n)/(i-n)),-(o+s)}function f(t,e,i){var s;return null==i?e:null!=t.meridiemHour?t.meridiemHour(e,i):null!=t.isPM?(s=t.isPM(i),s&&12>e&&(e+=12),s||12!==e||(e=0),e):e}function g(){}function v(t,e){e!==!1&&F(t),_(this,t),this._d=new Date(+t._d),Di===!1&&(Di=!0,Ce.updateOffset(this),Di=!1)}function y(t){var e=N(t),i=e.year||0,s=e.quarter||0,o=e.month||0,n=e.week||0,r=e.day||0,a=e.hour||0,h=e.minute||0,d=e.second||0,l=e.millisecond||0;this._milliseconds=+l+1e3*d+6e4*h+36e5*a,this._days=+r+7*n,this._months=+o+3*s+12*i,this._data={},this._locale=Ce.localeData(),this._bubble()}function b(t,e){for(var i in e)a(e,i)&&(t[i]=e[i]);return a(e,"toString")&&(t.toString=e.toString),a(e,"valueOf")&&(t.valueOf=e.valueOf),t}function _(t,e){var i,s,o;if("undefined"!=typeof e._isAMomentObject&&(t._isAMomentObject=e._isAMomentObject),"undefined"!=typeof e._i&&(t._i=e._i),"undefined"!=typeof e._f&&(t._f=e._f),"undefined"!=typeof e._l&&(t._l=e._l),"undefined"!=typeof e._strict&&(t._strict=e._strict),"undefined"!=typeof e._tzm&&(t._tzm=e._tzm),"undefined"!=typeof e._isUTC&&(t._isUTC=e._isUTC),"undefined"!=typeof e._offset&&(t._offset=e._offset),"undefined"!=typeof e._pf&&(t._pf=e._pf),"undefined"!=typeof e._locale&&(t._locale=e._locale),Ye.length>0)for(i in Ye)s=Ye[i],o=e[s],"undefined"!=typeof o&&(t[s]=o);return t}function x(t){return 0>t?Math.ceil(t):Math.floor(t)}function w(t,e,i){for(var s=""+Math.abs(t),o=t>=0;s.lengths;s++)(i&&t[s]!==e[s]||!i&&L(t[s])!==L(e[s]))&&r++;return r+n}function k(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=gi[t]||vi[e]||e}return t}function N(t){var e,i,s={};for(i in t)a(t,i)&&(e=k(i),e&&(s[e]=t[i]));return s}function I(t){var e,i;if(0===t.indexOf("week"))e=7,i="day";else{if(0!==t.indexOf("month"))return;e=12,i="month"}Ce[t]=function(s,o){var r,a,h=Ce._locale[t],d=[];if("number"==typeof s&&(o=s,s=n),a=function(t){var e=Ce().utc().set(i,t);return h.call(Ce._locale,e,s||"")},null!=o)return a(o);for(r=0;e>r;r++)d.push(a(r));return d}}function L(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=e>=0?Math.floor(e):Math.ceil(e)),i}function z(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function A(t,e,i){return me(Ce([t,11,31+e-i]),e,i).week}function P(t){return R(t)?366:365}function R(t){return t%4===0&&t%100!==0||t%400===0}function F(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[ze]<0||t._a[ze]>11?ze:t._a[Ae]<1||t._a[Ae]>z(t._a[Le],t._a[ze])?Ae:t._a[Pe]<0||t._a[Pe]>24||24===t._a[Pe]&&(0!==t._a[Re]||0!==t._a[Fe]||0!==t._a[He])?Pe:t._a[Re]<0||t._a[Re]>59?Re:t._a[Fe]<0||t._a[Fe]>59?Fe:t._a[He]<0||t._a[He]>999?He:-1,t._pf._overflowDayOfYear&&(Le>e||e>Ae)&&(e=Ae),t._pf.overflow=e)}function H(t){return null==t._isValid&&(t._isValid=!isNaN(t._d.getTime())&&t._pf.overflow<0&&!t._pf.empty&&!t._pf.invalidMonth&&!t._pf.nullInput&&!t._pf.invalidFormat&&!t._pf.userInvalidated,t._strict&&(t._isValid=t._isValid&&0===t._pf.charsLeftOver&&0===t._pf.unusedTokens.length&&t._pf.bigHour===n)),t._isValid}function B(t){return t?t.toLowerCase().replace("_","-"):t}function Y(t){for(var e,i,s,o,n=0;n0;){if(s=W(o.slice(0,e).join("-")))return s;if(i&&i.length>=e&&E(o,i,!0)>=e-1)break;e--}n++}return null}function W(t){var e=null;if(!Be[t]&&We)try{e=Ce.locale(),!function(){var t=new Error('Cannot find module "./locale"');throw t.code="MODULE_NOT_FOUND",t}(),Ce.locale(e)}catch(i){}return Be[t]}function G(t,e){var i,s;return e._isUTC?(i=e.clone(),s=(Ce.isMoment(t)||O(t)?+t:+Ce(t))-+i,i._d.setTime(+i._d+s),Ce.updateOffset(i,!1),i):Ce(t).local()}function j(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function U(t){var e,i,s=t.match(Ve);for(e=0,i=s.length;i>e;e++)s[e]=wi[s[e]]?wi[s[e]]:j(s[e]);return function(o){var n="";for(e=0;i>e;e++)n+=s[e]instanceof Function?s[e].call(o,t):s[e];return n}}function V(t,e){return t.isValid()?(e=X(e,t.localeData()),yi[e]||(yi[e]=U(e)),yi[e](t)):t.localeData().invalidDate()}function X(t,e){function i(t){return e.longDateFormat(t)||t}var s=5;for(Xe.lastIndex=0;s>=0&&Xe.test(t);)t=t.replace(Xe,i),Xe.lastIndex=0,s-=1;return t}function q(t,e){var i,s=e._strict;switch(t){case"Q":return oi;case"DDDD":return ri;case"YYYY":case"GGGG":case"gggg":return s?ai:Qe;case"Y":case"G":case"g":return di;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return s?hi:Ke;case"S":if(s)return oi;case"SS":if(s)return ni;case"SSS":if(s)return ri;case"DDD":return Ze;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Je;case"a":case"A":return e._locale._meridiemParse;case"x":return ii;case"X":return si;case"Z":case"ZZ":return ti;case"T":return ei;case"SSSS":return $e;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return s?ni:qe;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return qe;case"Do":return s?e._locale._ordinalParse:e._locale._ordinalParseLenient;default:return i=new RegExp(se(ie(t.replace("\\","")),"i"))}}function Z(t){t=t||"";var e=t.match(ti)||[],i=e[e.length-1]||[],s=(i+"").match(mi)||["-",0,0],o=+(60*s[1])+L(s[2]);return"+"===s[0]?o:-o}function Q(t,e,i){var s,o=i._a;switch(t){case"Q":null!=e&&(o[ze]=3*(L(e)-1));break;case"M":case"MM":null!=e&&(o[ze]=L(e)-1);break;case"MMM":case"MMMM":s=i._locale.monthsParse(e,t,i._strict),null!=s?o[ze]=s:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(o[Ae]=L(e));break;case"Do":null!=e&&(o[Ae]=L(parseInt(e.match(/\d{1,2}/)[0],10)));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=L(e));break;case"YY":o[Le]=Ce.parseTwoDigitYear(e);break;case"YYYY":case"YYYYY":case"YYYYYY":o[Le]=L(e);break;case"a":case"A":i._meridiem=e;break;case"h":case"hh":i._pf.bigHour=!0;case"H":case"HH":o[Pe]=L(e);break;case"m":case"mm":o[Re]=L(e);break;case"s":case"ss":o[Fe]=L(e);break;case"S":case"SS":case"SSS":case"SSSS":o[He]=L(1e3*("0."+e));break;case"x":i._d=new Date(L(e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=Z(e);break;case"dd":case"ddd":case"dddd":s=i._locale.weekdaysParse(e),null!=s?(i._w=i._w||{},i._w.d=s):i._pf.invalidWeekday=e;break;case"w":case"ww":case"W":case"WW":case"d":case"e":case"E":t=t.substr(0,1);case"gggg":case"GGGG":case"GGGGG":t=t.substr(0,2),e&&(i._w=i._w||{},i._w[t]=L(e));break;case"gg":case"GG":i._w=i._w||{},i._w[t]=Ce.parseTwoDigitYear(e)}}function K(t){var e,i,s,o,n,a,h;e=t._w,null!=e.GG||null!=e.W||null!=e.E?(n=1,a=4,i=r(e.GG,t._a[Le],me(Ce(),1,4).year),s=r(e.W,1),o=r(e.E,1)):(n=t._locale._week.dow,a=t._locale._week.doy,i=r(e.gg,t._a[Le],me(Ce(),n,a).year),s=r(e.w,1),null!=e.d?(o=e.d,n>o&&++s):o=null!=e.e?e.e+n:n),h=fe(i,s,o,a,n),t._a[Le]=h.year,t._dayOfYear=h.dayOfYear}function $(t){var e,i,s,o,n=[];if(!t._d){for(s=te(t),t._w&&null==t._a[Ae]&&null==t._a[ze]&&K(t),t._dayOfYear&&(o=r(t._a[Le],s[Le]),t._dayOfYear>P(o)&&(t._pf._overflowDayOfYear=!0),i=le(o,0,t._dayOfYear),t._a[ze]=i.getUTCMonth(),t._a[Ae]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=n[e]=s[e];for(;7>e;e++)t._a[e]=n[e]=null==t._a[e]?2===e?1:0:t._a[e];24===t._a[Pe]&&0===t._a[Re]&&0===t._a[Fe]&&0===t._a[He]&&(t._nextDay=!0,t._a[Pe]=0),t._d=(t._useUTC?le:de).apply(null,n),null!=t._tzm&&t._d.setUTCMinutes(t._d.getUTCMinutes()-t._tzm),t._nextDay&&(t._a[Pe]=24)}}function J(t){var e;t._d||(e=N(t._i),t._a=[e.year,e.month,e.day||e.date,e.hour,e.minute,e.second,e.millisecond],$(t))}function te(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function ee(t){if(t._f===Ce.ISO_8601)return void ne(t);t._a=[],t._pf.empty=!0;var e,i,s,o,r,a=""+t._i,h=a.length,d=0;for(s=X(t._f,t._locale).match(Ve)||[],e=0;e0&&t._pf.unusedInput.push(r),a=a.slice(a.indexOf(i)+i.length),d+=i.length),wi[o]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(o),Q(o,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(o);t._pf.charsLeftOver=h-d,a.length>0&&t._pf.unusedInput.push(a),t._pf.bigHour===!0&&t._a[Pe]<=12&&(t._pf.bigHour=n),t._a[Pe]=f(t._locale,t._a[Pe],t._meridiem),$(t),F(t)}function ie(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,s,o){return e||i||s||o})}function se(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function oe(t){var e,i,s,o,n;if(0===t._f.length)return t._pf.invalidFormat=!0,void(t._d=new Date(0/0));for(o=0;on)&&(s=n,i=e));b(t,i||e)}function ne(t){var e,i,s=t._i,o=li.exec(s);if(o){for(t._pf.iso=!0,e=0,i=pi.length;i>e;e++)if(pi[e][1].exec(s)){t._f=pi[e][0]+(o[6]||" ");break}for(e=0,i=ui.length;i>e;e++)if(ui[e][1].exec(s)){t._f+=ui[e][0];break}s.match(ti)&&(t._f+="Z"),ee(t)}else t._isValid=!1}function re(t){ne(t),t._isValid===!1&&(delete t._isValid,Ce.createFromInputFallback(t))}function ae(t,e){var i,s=[];for(i=0;it&&a.setFullYear(t),a}function le(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function ce(t,e){if("string"==typeof t)if(isNaN(t)){if(t=e.weekdaysParse(t),"number"!=typeof t)return null}else t=parseInt(t,10);return t}function pe(t,e,i,s,o){return o.relativeTime(e||1,!!i,t,s)}function ue(t,e,i){var s=Ce.duration(t).abs(),o=Ne(s.as("s")),n=Ne(s.as("m")),r=Ne(s.as("h")),a=Ne(s.as("d")),h=Ne(s.as("M")),d=Ne(s.as("y")),l=o0,l[4]=i,pe.apply({},l)}function me(t,e,i){var s,o=i-e,n=i-t.day();return n>o&&(n-=7),o-7>n&&(n+=7),s=Ce(t).add(n,"d"),{week:Math.ceil(s.dayOfYear()/7),year:s.year()}}function fe(t,e,i,s,o){var n,r,a=le(t,0,1).getUTCDay();return a=0===a?7:a,i=null!=i?i:o,n=o-a+(a>s?7:0)-(o>a?7:0),r=7*(e-1)+(i-o)+n+1,{year:r>0?t:t-1,dayOfYear:r>0?r:P(t-1)+r}}function ge(t){var e,i=t._i,s=t._f;return t._locale=t._locale||Ce.localeData(t._l),null===i||s===n&&""===i?Ce.invalid({nullInput:!0}):("string"==typeof i&&(t._i=i=t._locale.preparse(i)),Ce.isMoment(i)?new v(i,!0):(s?T(s)?oe(t):ee(t):he(t),e=new v(t),e._nextDay&&(e.add(1,"d"),e._nextDay=n),e))}function ve(t,e){var i,s;if(1===e.length&&T(e[0])&&(e=e[0]),!e.length)return Ce();for(i=e[0],s=1;s=0?"+":"-";return e+w(Math.abs(t),6)},gg:function(){return w(this.weekYear()%100,2)},gggg:function(){return w(this.weekYear(),4)},ggggg:function(){return w(this.weekYear(),5)},GG:function(){return w(this.isoWeekYear()%100,2)},GGGG:function(){return w(this.isoWeekYear(),4)},GGGGG:function(){return w(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.localeData().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.localeData().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return L(this.milliseconds()/100)},SS:function(){return w(L(this.milliseconds()/10),2)},SSS:function(){return w(this.milliseconds(),3)},SSSS:function(){return w(this.milliseconds(),3)},Z:function(){var t=this.utcOffset(),e="+";return 0>t&&(t=-t,e="-"),e+w(L(t/60),2)+":"+w(L(t)%60,2)},ZZ:function(){var t=this.utcOffset(),e="+";return 0>t&&(t=-t,e="-"),e+w(L(t/60),2)+w(L(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},x:function(){return this.valueOf()},X:function(){return this.unix()},Q:function(){return this.quarter()}},Si={},Mi=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"],Di=!1;_i.length;)Oe=_i.pop(),wi[Oe+"o"]=u(wi[Oe],Oe);for(;xi.length;)Oe=xi.pop(),wi[Oe+Oe]=p(wi[Oe],2);wi.DDDD=p(wi.DDD,3),b(g.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e;this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t,e,i){var s,o,n;for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),s=0;12>s;s++){if(o=Ce.utc([2e3,s]),i&&!this._longMonthsParse[s]&&(this._longMonthsParse[s]=new RegExp("^"+this.months(o,"").replace(".","")+"$","i"),this._shortMonthsParse[s]=new RegExp("^"+this.monthsShort(o,"").replace(".","")+"$","i")),i||this._monthsParse[s]||(n="^"+this.months(o,"")+"|^"+this.monthsShort(o,""),this._monthsParse[s]=new RegExp(n.replace(".",""),"i")),i&&"MMMM"===e&&this._longMonthsParse[s].test(t))return s;if(i&&"MMM"===e&&this._shortMonthsParse[s].test(t))return s;if(!i&&this._monthsParse[s].test(t))return s}},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},weekdaysParse:function(t){var e,i,s;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=Ce([2e3,1]).day(e),s="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=new RegExp(s.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e},_longDateFormat:{LTS:"h:mm:ss A",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(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},isPM:function(t){return"p"===(t+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(t,e,i){var s=this._calendar[t];return"function"==typeof s?s.apply(e,[i]):s},_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"},relativeTime:function(t,e,i,s){var o=this._relativeTime[i];return"function"==typeof o?o(t,e,i,s):o.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",_ordinalParse:/\d{1,2}/,preparse:function(t){return t},postformat:function(t){return t},week:function(t){return me(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},firstDayOfWeek:function(){return this._week.dow},firstDayOfYear:function(){return this._week.doy},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),Ce=function(t,e,i,s){var o;return"boolean"==typeof i&&(s=i,i=n),o={},o._isAMomentObject=!0,o._i=t,o._f=e,o._l=i,o._strict=s,o._isUTC=!1,o._pf=h(),ge(o)},Ce.suppressDeprecationWarnings=!1,Ce.createFromInputFallback=l("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(t){t._d=new Date(t._i+(t._useUTC?" UTC":""))}),Ce.min=function(){var t=[].slice.call(arguments,0);return ve("isBefore",t)},Ce.max=function(){var t=[].slice.call(arguments,0);return ve("isAfter",t)},Ce.utc=function(t,e,i,s){var o;return"boolean"==typeof i&&(s=i,i=n),o={},o._isAMomentObject=!0,o._useUTC=!0,o._isUTC=!0,o._l=i,o._i=t,o._f=e,o._strict=s,o._pf=h(),ge(o).utc()},Ce.unix=function(t){return Ce(1e3*t)},Ce.duration=function(t,e){var i,s,o,n,r=t,h=null;return Ce.isDuration(t)?r={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(r={},e?r[e]=t:r.milliseconds=t):(h=je.exec(t))?(i="-"===h[1]?-1:1,r={y:0,d:L(h[Ae])*i,h:L(h[Pe])*i,m:L(h[Re])*i,s:L(h[Fe])*i,ms:L(h[He])*i}):(h=Ue.exec(t))?(i="-"===h[1]?-1:1,o=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},r={y:o(h[2]),M:o(h[3]),d:o(h[4]),h:o(h[5]),m:o(h[6]),s:o(h[7]),w:o(h[8])}):null==r?r={}:"object"==typeof r&&("from"in r||"to"in r)&&(n=M(Ce(r.from),Ce(r.to)),r={},r.ms=n.milliseconds,r.M=n.months),s=new y(r),Ce.isDuration(t)&&a(t,"_locale")&&(s._locale=t._locale),s},Ce.version=Ee,Ce.defaultFormat=ci,Ce.ISO_8601=function(){},Ce.momentProperties=Ye,Ce.updateOffset=function(){},Ce.relativeTimeThreshold=function(t,e){return bi[t]===n?!1:e===n?bi[t]:(bi[t]=e,!0)},Ce.lang=l("moment.lang is deprecated. Use moment.locale instead.",function(t,e){return Ce.locale(t,e)}),Ce.locale=function(t,e){var i;return t&&(i="undefined"!=typeof e?Ce.defineLocale(t,e):Ce.localeData(t),i&&(Ce.duration._locale=Ce._locale=i)),Ce._locale._abbr},Ce.defineLocale=function(t,e){return null!==e?(e.abbr=t,Be[t]||(Be[t]=new g),Be[t].set(e),Ce.locale(t),Be[t]):(delete Be[t],null)},Ce.langData=l("moment.langData is deprecated. Use moment.localeData instead.",function(t){return Ce.localeData(t)}),Ce.localeData=function(t){var e;if(t&&t._locale&&t._locale._abbr&&(t=t._locale._abbr),!t)return Ce._locale;if(!T(t)){if(e=W(t))return e;t=[t]}return Y(t)},Ce.isMoment=function(t){return t instanceof v||null!=t&&a(t,"_isAMomentObject")},Ce.isDuration=function(t){return t instanceof y};for(Oe=Mi.length-1;Oe>=0;--Oe)I(Mi[Oe]);Ce.normalizeUnits=function(t){return k(t)},Ce.invalid=function(t){var e=Ce.utc(0/0);return null!=t?b(e._pf,t):e._pf.userInvalidated=!0,e},Ce.parseZone=function(){return Ce.apply(null,arguments).parseZone()},Ce.parseTwoDigitYear=function(t){return L(t)+(L(t)>68?1900:2e3)},Ce.isDate=O,b(Ce.fn=v.prototype,{clone:function(){return Ce(this)},valueOf:function(){return+this._d-6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var t=Ce(this).utc();return 00:!1},parsingFlags:function(){return b({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(t){return this.utcOffset(0,t)},local:function(t){return this._isUTC&&(this.utcOffset(0,t),this._isUTC=!1,t&&this.subtract(this._dateUtcOffset(),"m")),this},format:function(t){var e=V(this,t||Ce.defaultFormat);return this.localeData().postformat(e)},add:D(1,"add"),subtract:D(-1,"subtract"),diff:function(t,e,i){var s,o,n=G(t,this),r=6e4*(n.utcOffset()-this.utcOffset());return e=k(e),"year"===e||"month"===e||"quarter"===e?(o=m(this,n),"quarter"===e?o/=3:"year"===e&&(o/=12)):(s=this-n,o="second"===e?s/1e3:"minute"===e?s/6e4:"hour"===e?s/36e5:"day"===e?(s-r)/864e5:"week"===e?(s-r)/6048e5:s),i?o:x(o)},from:function(t,e){return Ce.duration({to:this,from:t}).locale(this.locale()).humanize(!e)},fromNow:function(t){return this.from(Ce(),t)},calendar:function(t){var e=t||Ce(),i=G(e,this).startOf("day"),s=this.diff(i,"days",!0),o=-6>s?"sameElse":-1>s?"lastWeek":0>s?"lastDay":1>s?"sameDay":2>s?"nextDay":7>s?"nextWeek":"sameElse";return this.format(this.localeData().calendar(o,this,Ce(e)))},isLeapYear:function(){return R(this.year())},isDST:function(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},day:function(t){var e=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=t?(t=ce(t,this.localeData()),this.add(t-e,"d")):e},month:xe("Month",!0),startOf:function(t){switch(t=k(t)){case"year":this.month(0);case"quarter":case"month":this.date(1);case"week":case"isoWeek":case"day":this.hours(0);case"hour":this.minutes(0);case"minute":this.seconds(0);case"second":this.milliseconds(0)}return"week"===t?this.weekday(0):"isoWeek"===t&&this.isoWeekday(1),"quarter"===t&&this.month(3*Math.floor(this.month()/3)),this},endOf:function(t){return t=k(t),t===n||"millisecond"===t?this:this.startOf(t).add(1,"isoWeek"===t?"week":t).subtract(1,"ms")},isAfter:function(t,e){var i;return e=k("undefined"!=typeof e?e:"millisecond"),"millisecond"===e?(t=Ce.isMoment(t)?t:Ce(t),+this>+t):(i=Ce.isMoment(t)?+t:+Ce(t),i<+this.clone().startOf(e))},isBefore:function(t,e){var i;return e=k("undefined"!=typeof e?e:"millisecond"),"millisecond"===e?(t=Ce.isMoment(t)?t:Ce(t),+t>+this):(i=Ce.isMoment(t)?+t:+Ce(t),+this.clone().endOf(e)t?this:t}),max:l("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(t){return t=Ce.apply(null,arguments),t>this?this:t}),zone:l("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779",function(t,e){return null!=t?("string"!=typeof t&&(t=-t),this.utcOffset(t,e),this):-this.utcOffset()}),utcOffset:function(t,e){var i,s=this._offset||0;return null!=t?("string"==typeof t&&(t=Z(t)),Math.abs(t)<16&&(t=60*t),!this._isUTC&&e&&(i=this._dateUtcOffset()),this._offset=t,this._isUTC=!0,null!=i&&this.add(i,"m"),s!==t&&(!e||this._changeInProgress?C(this,Ce.duration(t-s,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,Ce.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?s:this._dateUtcOffset()},isLocal:function(){return!this._isUTC},isUtcOffset:function(){return this._isUTC},isUtc:function(){return this._isUTC&&0===this._offset},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.utcOffset(this._tzm):"string"==typeof this._i&&this.utcOffset(Z(this._i)),this},hasAlignedHourOffset:function(t){return t=t?Ce(t).utcOffset():0,(this.utcOffset()-t)%60===0},daysInMonth:function(){return z(this.year(),this.month())},dayOfYear:function(t){var e=Ne((Ce(this).startOf("day")-Ce(this).startOf("year"))/864e5)+1;return null==t?e:this.add(t-e,"d")},quarter:function(t){return null==t?Math.ceil((this.month()+1)/3):this.month(3*(t-1)+this.month()%3)},weekYear:function(t){var e=me(this,this.localeData()._week.dow,this.localeData()._week.doy).year;return null==t?e:this.add(t-e,"y")},isoWeekYear:function(t){var e=me(this,1,4).year;return null==t?e:this.add(t-e,"y")},week:function(t){var e=this.localeData().week(this);return null==t?e:this.add(7*(t-e),"d")},isoWeek:function(t){var e=me(this,1,4).week;return null==t?e:this.add(7*(t-e),"d")},weekday:function(t){var e=(this.day()+7-this.localeData()._week.dow)%7;return null==t?e:this.add(t-e,"d")},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},isoWeeksInYear:function(){return A(this.year(),1,4)},weeksInYear:function(){var t=this.localeData()._week;return A(this.year(),t.dow,t.doy)},get:function(t){return t=k(t),this[t]()},set:function(t,e){var i;if("object"==typeof t)for(i in t)this.set(i,t[i]);else t=k(t),"function"==typeof this[t]&&this[t](e);return this},locale:function(t){var e;return t===n?this._locale._abbr:(e=Ce.localeData(t),null!=e&&(this._locale=e),this)},lang:l("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(t){return t===n?this.localeData():this.locale(t)}),localeData:function(){return this._locale},_dateUtcOffset:function(){return 15*-Math.round(this._d.getTimezoneOffset()/15)}}),Ce.fn.millisecond=Ce.fn.milliseconds=xe("Milliseconds",!1),Ce.fn.second=Ce.fn.seconds=xe("Seconds",!1),Ce.fn.minute=Ce.fn.minutes=xe("Minutes",!1),Ce.fn.hour=Ce.fn.hours=xe("Hours",!0),Ce.fn.date=xe("Date",!0),Ce.fn.dates=l("dates accessor is deprecated. Use date instead.",xe("Date",!0)),Ce.fn.year=xe("FullYear",!0),Ce.fn.years=l("years accessor is deprecated. Use year instead.",xe("FullYear",!0)),Ce.fn.days=Ce.fn.day,Ce.fn.months=Ce.fn.month,Ce.fn.weeks=Ce.fn.week,Ce.fn.isoWeeks=Ce.fn.isoWeek,Ce.fn.quarters=Ce.fn.quarter,Ce.fn.toJSON=Ce.fn.toISOString,Ce.fn.isUTC=Ce.fn.isUtc,b(Ce.duration.fn=y.prototype,{_bubble:function(){var t,e,i,s=this._milliseconds,o=this._days,n=this._months,r=this._data,a=0;r.milliseconds=s%1e3,t=x(s/1e3),r.seconds=t%60,e=x(t/60),r.minutes=e%60,i=x(e/60),r.hours=i%24,o+=x(i/24),a=x(we(o)),o-=x(Se(a)),n+=x(o/30),o%=30,a+=x(n/12),n%=12,r.days=o,r.months=n,r.years=a},abs:function(){return 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),this},weeks:function(){return x(this.days()/7)},valueOf:function(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*L(this._months/12)},humanize:function(t){var e=ue(this,!t,this.localeData());return t&&(e=this.localeData().pastFuture(+this,e)),this.localeData().postformat(e)},add:function(t,e){var i=Ce.duration(t,e);return this._milliseconds+=i._milliseconds,this._days+=i._days,this._months+=i._months,this._bubble(),this},subtract:function(t,e){var i=Ce.duration(t,e);return this._milliseconds-=i._milliseconds,this._days-=i._days,this._months-=i._months,this._bubble(),this},get:function(t){return t=k(t),this[t.toLowerCase()+"s"]()},as:function(t){var e,i;if(t=k(t),"month"===t||"year"===t)return e=this._days+this._milliseconds/864e5,i=this._months+12*we(e),"month"===t?i:i/12;switch(e=this._days+Math.round(Se(this._months/12)),t){case"week":return e/7+this._milliseconds/6048e5;case"day":return e+this._milliseconds/864e5;case"hour":return 24*e+this._milliseconds/36e5;case"minute":return 24*e*60+this._milliseconds/6e4;case"second":return 24*e*60*60+this._milliseconds/1e3;case"millisecond":return Math.floor(24*e*60*60*1e3)+this._milliseconds;default:throw new Error("Unknown unit "+t)}},lang:Ce.fn.lang,locale:Ce.fn.locale,toIsoString:l("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",function(){return this.toISOString()}),toISOString:function(){var t=Math.abs(this.years()),e=Math.abs(this.months()),i=Math.abs(this.days()),s=Math.abs(this.hours()),o=Math.abs(this.minutes()),n=Math.abs(this.seconds()+this.milliseconds()/1e3);return this.asSeconds()?(this.asSeconds()<0?"-":"")+"P"+(t?t+"Y":"")+(e?e+"M":"")+(i?i+"D":"")+(s||o||n?"T":"")+(s?s+"H":"")+(o?o+"M":"")+(n?n+"S":""):"P0D"},localeData:function(){return this._locale},toJSON:function(){return this.toISOString()}}),Ce.duration.fn.toString=Ce.duration.fn.toISOString;for(Oe in fi)a(fi,Oe)&&Me(Oe.toLowerCase());Ce.duration.fn.asMilliseconds=function(){return this.as("ms")},Ce.duration.fn.asSeconds=function(){return this.as("s")},Ce.duration.fn.asMinutes=function(){return this.as("m")},Ce.duration.fn.asHours=function(){return this.as("h")},Ce.duration.fn.asDays=function(){return this.as("d")},Ce.duration.fn.asWeeks=function(){return this.as("weeks")},Ce.duration.fn.asMonths=function(){return this.as("M")},Ce.duration.fn.asYears=function(){return this.as("y")},Ce.locale("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(t){var e=t%10,i=1===L(t%100/10)?"th":1===e?"st":2===e?"nd":3===e?"rd":"th";return t+i}}),We?o.exports=Ce:(s=function(t,e,i){return i.config&&i.config()&&i.config().noGlobal===!0&&(ke.moment=Te),Ce}.call(e,i,e,o),!(s!==n&&(o.exports=s)),De(!0))}).call(this)}).call(e,function(){return this}(),i(71)(t))},function(t,e,i){var s;!function(o,n,r,a){function h(t,e,i){return setTimeout(m(t,i),e)}function d(t,e,i){return Array.isArray(t)?(l(t,i[e],i),!0):!1}function l(t,e,i){var s;if(t)if(t.forEach)t.forEach(e,i);else if(t.length!==a)for(s=0;s-1}function x(t){return t.trim().split(/\s+/g)}function w(t,e,i){if(t.indexOf&&!i)return t.indexOf(e);for(var s=0;si[e]}):s.sort()),s}function D(t,e){for(var i,s,o=e[0].toUpperCase()+e.slice(1),n=0;n1&&!i.firstMultiple?i.firstMultiple=z(e):1===o&&(i.firstMultiple=!1);var n=i.firstInput,r=i.firstMultiple,a=r?r.center:n.center,h=e.center=A(s);e.timeStamp=ve(),e.deltaTime=e.timeStamp-n.timeStamp,e.angle=H(a,h),e.distance=F(a,h),I(i,e),e.offsetDirection=R(e.deltaX,e.deltaY),e.scale=r?Y(r.pointers,s):1,e.rotation=r?B(r.pointers,s):0,L(i,e);var d=t.element;b(e.srcEvent.target,d)&&(d=e.srcEvent.target),e.target=d}function I(t,e){var i=e.center,s=t.offsetDelta||{},o=t.prevDelta||{},n=t.prevInput||{};(e.eventType===Oe||n.eventType===ke)&&(o=t.prevDelta={x:n.deltaX||0,y:n.deltaY||0},s=t.offsetDelta={x:i.x,y:i.y}),e.deltaX=o.x+(i.x-s.x),e.deltaY=o.y+(i.y-s.y)}function L(t,e){var i,s,o,n,r=t.lastInterval||e,h=e.timeStamp-r.timeStamp;if(e.eventType!=Ne&&(h>Te||r.velocity===a)){var d=r.deltaX-e.deltaX,l=r.deltaY-e.deltaY,c=P(h,d,l);s=c.x,o=c.y,i=ge(c.x)>ge(c.y)?c.x:c.y,n=R(d,l),t.lastInterval=e}else i=r.velocity,s=r.velocityX,o=r.velocityY,n=r.direction;e.velocity=i,e.velocityX=s,e.velocityY=o,e.direction=n}function z(t){for(var e=[],i=0;io;)i+=t[o].clientX,s+=t[o].clientY,o++;return{x:fe(i/e),y:fe(s/e)}}function P(t,e,i){return{x:e/t||0,y:i/t||0}}function R(t,e){return t===e?Ie:ge(t)>=ge(e)?t>0?Le:ze:e>0?Ae:Pe}function F(t,e,i){i||(i=Be);var s=e[i[0]]-t[i[0]],o=e[i[1]]-t[i[1]];return Math.sqrt(s*s+o*o)}function H(t,e,i){i||(i=Be);var s=e[i[0]]-t[i[0]],o=e[i[1]]-t[i[1]];return 180*Math.atan2(o,s)/Math.PI}function B(t,e){return H(e[1],e[0],Ye)-H(t[1],t[0],Ye)}function Y(t,e){return F(e[0],e[1],Ye)/F(t[0],t[1],Ye)}function W(){this.evEl=Ge,this.evWin=je,this.allow=!0,this.pressed=!1,O.apply(this,arguments)}function G(){this.evEl=Xe,this.evWin=qe,O.apply(this,arguments),this.store=this.manager.session.pointerEvents=[]}function j(){this.evTarget=Qe,this.evWin=Ke,this.started=!1,O.apply(this,arguments)}function U(t,e){var i=S(t.touches),s=S(t.changedTouches);return e&(ke|Ne)&&(i=M(i.concat(s),"identifier",!0)),[i,s]}function V(){this.evTarget=Je,this.targetIds={},O.apply(this,arguments)}function X(t,e){var i=S(t.touches),s=this.targetIds;if(e&(Oe|Ee)&&1===i.length)return s[i[0].identifier]=!0,[i,i];var o,n,r=S(t.changedTouches),a=[],h=this.target;if(n=i.filter(function(t){return b(t.target,h)}),e===Oe)for(o=0;oa&&(e.push(t),a=e.length-1):o&(ke|Ne)&&(i=!0),0>a||(e[a]=t,this.callback(this.manager,o,{pointers:e,changedPointers:[t],pointerType:n,srcEvent:t}),i&&e.splice(a,1))}});var Ze={touchstart:Oe,touchmove:Ee,touchend:ke,touchcancel:Ne},Qe="touchstart",Ke="touchstart touchmove touchend touchcancel";u(j,O,{handler:function(t){var e=Ze[t.type];if(e===Oe&&(this.started=!0),this.started){var i=U.call(this,t,e);e&(ke|Ne)&&i[0].length-i[1].length===0&&(this.started=!1),this.callback(this.manager,e,{pointers:i[0],changedPointers:i[1],pointerType:Se,srcEvent:t})}}});var $e={touchstart:Oe,touchmove:Ee,touchend:ke,touchcancel:Ne},Je="touchstart touchmove touchend touchcancel";u(V,O,{handler:function(t){var e=$e[t.type],i=X.call(this,t,e);i&&this.callback(this.manager,e,{pointers:i[0],changedPointers:i[1],pointerType:Se,srcEvent:t})}}),u(q,O,{handler:function(t,e,i){var s=i.pointerType==Se,o=i.pointerType==De;if(s)this.mouse.allow=!1;else if(o&&!this.mouse.allow)return;e&(ke|Ne)&&(this.mouse.allow=!0),this.callback(t,e,i)},destroy:function(){this.touch.destroy(),this.mouse.destroy()}});var ti=D(ue.style,"touchAction"),ei=ti!==a,ii="compute",si="auto",oi="manipulation",ni="none",ri="pan-x",ai="pan-y";Z.prototype={set:function(t){t==ii&&(t=this.compute()),ei&&(this.manager.element.style[ti]=t),this.actions=t.toLowerCase().trim()},update:function(){this.set(this.manager.options.touchAction)},compute:function(){var t=[];return l(this.manager.recognizers,function(e){f(e.options.enable,[e])&&(t=t.concat(e.getTouchAction()))}),Q(t.join(" "))},preventDefaults:function(t){if(!ei){var e=t.srcEvent,i=t.offsetDirection;if(this.manager.session.prevented)return void e.preventDefault();var s=this.actions,o=_(s,ni),n=_(s,ai),r=_(s,ri);return o||n&&i&Re||r&&i&Fe?this.preventSrc(e):void 0}},preventSrc:function(t){this.manager.session.prevented=!0,t.preventDefault()}};var hi=1,di=2,li=4,ci=8,pi=ci,ui=16,mi=32;K.prototype={defaults:{},set:function(t){return c(this.options,t),this.manager&&this.manager.touchAction.update(),this},recognizeWith:function(t){if(d(t,"recognizeWith",this))return this;var e=this.simultaneous;return t=te(t,this),e[t.id]||(e[t.id]=t,t.recognizeWith(this)),this},dropRecognizeWith:function(t){return d(t,"dropRecognizeWith",this)?this:(t=te(t,this),delete this.simultaneous[t.id],this)},requireFailure:function(t){if(d(t,"requireFailure",this))return this;var e=this.requireFail;return t=te(t,this),-1===w(e,t)&&(e.push(t),t.requireFailure(this)),this},dropRequireFailure:function(t){if(d(t,"dropRequireFailure",this))return this;t=te(t,this);var e=w(this.requireFail,t);return e>-1&&this.requireFail.splice(e,1),this},hasRequireFailures:function(){return this.requireFail.length>0},canRecognizeWith:function(t){return!!this.simultaneous[t.id]},emit:function(t){function e(e){i.manager.emit(i.options.event+(e?$(s):""),t)}var i=this,s=this.state;ci>s&&e(!0),e(),s>=ci&&e(!0)},tryEmit:function(t){return this.canEmit()?this.emit(t):void(this.state=mi)},canEmit:function(){for(var t=0;tn?Le:ze,i=n!=this.pX,s=Math.abs(t.deltaX)):(o=0===r?Ie:0>r?Ae:Pe,i=r!=this.pY,s=Math.abs(t.deltaY))),t.direction=o,i&&s>e.threshold&&o&e.direction},attrTest:function(t){return ee.prototype.attrTest.call(this,t)&&(this.state&di||!(this.state&di)&&this.directionTest(t))},emit:function(t){this.pX=t.deltaX,this.pY=t.deltaY;var e=J(t.direction);e&&this.manager.emit(this.options.event+e,t),this._super.emit.call(this,t)}}),u(se,ee,{defaults:{event:"pinch",threshold:0,pointers:2},getTouchAction:function(){return[ni]},attrTest:function(t){return this._super.attrTest.call(this,t)&&(Math.abs(t.scale-1)>this.options.threshold||this.state&di)},emit:function(t){if(this._super.emit.call(this,t),1!==t.scale){var e=t.scale<1?"in":"out";this.manager.emit(this.options.event+e,t)}}}),u(oe,K,{defaults:{event:"press",pointers:1,time:500,threshold:5},getTouchAction:function(){return[si]},process:function(t){var e=this.options,i=t.pointers.length===e.pointers,s=t.distancee.time; +if(this._input=t,!s||!i||t.eventType&(ke|Ne)&&!o)this.reset();else if(t.eventType&Oe)this.reset(),this._timer=h(function(){this.state=pi,this.tryEmit()},e.time,this);else if(t.eventType&ke)return pi;return mi},reset:function(){clearTimeout(this._timer)},emit:function(t){this.state===pi&&(t&&t.eventType&ke?this.manager.emit(this.options.event+"up",t):(this._input.timeStamp=ve(),this.manager.emit(this.options.event,this._input)))}}),u(ne,ee,{defaults:{event:"rotate",threshold:0,pointers:2},getTouchAction:function(){return[ni]},attrTest:function(t){return this._super.attrTest.call(this,t)&&(Math.abs(t.rotation)>this.options.threshold||this.state&di)}}),u(re,ee,{defaults:{event:"swipe",threshold:10,velocity:.65,direction:Re|Fe,pointers:1},getTouchAction:function(){return ie.prototype.getTouchAction.call(this)},attrTest:function(t){var e,i=this.options.direction;return i&(Re|Fe)?e=t.velocity:i&Re?e=t.velocityX:i&Fe&&(e=t.velocityY),this._super.attrTest.call(this,t)&&i&t.direction&&t.distance>this.options.threshold&&ge(e)>this.options.velocity&&t.eventType&ke},emit:function(t){var e=J(t.direction);e&&this.manager.emit(this.options.event+e,t),this.manager.emit(this.options.event,t)}}),u(ae,K,{defaults:{event:"tap",pointers:1,taps:1,interval:300,time:250,threshold:2,posThreshold:10},getTouchAction:function(){return[oi]},process:function(t){var e=this.options,i=t.pointers.length===e.pointers,s=t.distancet&&s>o;)o%3==0?(this.forceAggregateHubs(!0),this.normalizeClusterLevels()):this.increaseClusterLevel(),i=this.nodeIndices.length,o+=1;o>0&&1==e&&this.repositionNodes(),this._updateCalculationNodes()},e.openCluster=function(t){var e=this.moving;if(t.clusterSize>this.constants.clustering.sectorThreshold&&this._nodeInActiveArea(t)&&("default"!=this._sector()||1!=this.nodeIndices.length)){this._addSector(t);for(var i=0;this.nodeIndices.lengthi;)this.decreaseClusterLevel(),i+=1}else this._expandClusterNode(t,!1,!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this._updateCalculationNodes(),this.updateLabels();this.moving!=e&&this.start()},e.updateClustersDefault=function(){1==this.constants.clustering.enabled&&this.updateClusters(0,!1,!1)},e.increaseClusterLevel=function(){this.updateClusters(-1,!1,!0)},e.decreaseClusterLevel=function(){this.updateClusters(1,!1,!0)},e.updateClusters=function(t,e,i,s){var o=this.moving,n=this.nodeIndices.length;this.previousScale>this.scale&&0==t&&this._collapseSector(),this.previousScale>this.scale||-1==t?this._formClusters(i):(this.previousScalethis.scale||-1==t)&&(this._aggregateHubs(i),this._updateNodeIndexList()),(this.previousScale>this.scale||-1==t)&&(this.handleChains(),this._updateNodeIndexList()),this.previousScale=this.scale,this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.lengththis.constants.clustering.chainThreshold&&this._reduceAmountOfChains(1-this.constants.clustering.chainThreshold/t)},e._aggregateHubs=function(t){this._getHubSize(),this._formClustersByHub(t,!1)},e.forceAggregateHubs=function(t){var e=this.moving,i=this.nodeIndices.length;this._aggregateHubs(!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.length!=i&&(this.clusterSession+=1),(0==t||void 0===t)&&this.moving!=e&&this.start()},e._openClustersBySize=function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];1==e.inView()&&(e.width*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientWidth||e.height*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientHeight)&&this.openCluster(e)}},e._openClusters=function(t,e){for(var i=0;i1&&(t.clusterSizei)){var r=n.from,a=n.to;n.to.options.mass>n.from.options.mass&&(r=n.to,a=n.from),1==a.dynamicEdgesLength?this._addToCluster(r,a,!1):1==r.dynamicEdgesLength&&this._addToCluster(a,r,!1)}}},e._forceClustersByZoom=function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];if(1==e.dynamicEdgesLength&&0!=e.dynamicEdges.length){var i=e.dynamicEdges[0],s=i.toId==e.id?this.nodes[i.fromId]:this.nodes[i.toId];e.id!=s.id&&(s.options.mass>e.options.mass?this._addToCluster(s,e,!0):this._addToCluster(e,s,!0))}}},e._clusterToSmallestNeighbour=function(t){for(var e=-1,i=null,s=0;so.clusterSessions.length&&(e=o.clusterSessions.length,i=o)}null!=o&&void 0!==this.nodes[o.id]&&this._addToCluster(o,t,!0)},e._formClustersByHub=function(t,e){for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&this._formClusterFromHub(this.nodes[i],t,e)},e._formClusterFromHub=function(t,e,i,s){if(void 0===s&&(s=0),t.dynamicEdgesLength>=this.hubThreshold&&0==i||t.dynamicEdgesLength==this.hubThreshold&&1==i){for(var o,n,r,a=this.constants.clustering.clusterEdgeThreshold/this.scale,h=!1,d=[],l=t.dynamicEdges.length,c=0;l>c;c++)d.push(t.dynamicEdges[c].id);if(0==e)for(h=!1,c=0;l>c;c++){var p=this.edges[d[c]];if(void 0!==p&&p.connected&&p.toId!=p.fromId&&(o=p.to.x-p.from.x,n=p.to.y-p.from.y,r=Math.sqrt(o*o+n*n),a>r)){h=!0;break}}if(!e&&h||e)for(c=0;l>c;c++)if(p=this.edges[d[c]],void 0!==p){var u=this.nodes[p.fromId==t.id?p.toId:p.fromId];u.dynamicEdges.length<=this.hubThreshold+s&&u.id!=t.id&&this._addToCluster(t,u,e)}}},e._addToCluster=function(t,e,i){t.containedNodes[e.id]=e;for(var s=0;s1)for(var s=0;s1&&(e.label="[".concat(String(e.clusterSize),"]"))}for(t in this.nodes)this.nodes.hasOwnProperty(t)&&(e=this.nodes[t],1==e.clusterSize&&(e.label=void 0!==e.originalLabel?e.originalLabel:String(e.id)))},e.normalizeClusterLevels=function(){var t,e=0,i=1e9,s=0;for(t in this.nodes)this.nodes.hasOwnProperty(t)&&(s=this.nodes[t].clusterSessions.length,s>e&&(e=s),i>s&&(i=s));if(e-i>this.constants.clustering.clusterLevelDifference){var o=this.nodeIndices.length,n=e-this.constants.clustering.clusterLevelDifference;for(t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodes[t].clusterSessions.lengths&&(s=n.dynamicEdgesLength),t+=n.dynamicEdgesLength,e+=Math.pow(n.dynamicEdgesLength,2),i+=1}t/=i,e/=i;var r=e-Math.pow(t,2),a=Math.sqrt(r);this.hubThreshold=Math.floor(t+2*a),this.hubThreshold>s&&(this.hubThreshold=s)},e._reduceAmountOfChains=function(t){this.hubThreshold=2;var e=Math.floor(this.nodeIndices.length*t);for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&e>0&&(this._formClusterFromHub(this.nodes[i],!0,!0,1),e-=1)},e._getChainFraction=function(){var t=0,e=0;for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&(2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&(t+=1),e+=1);return t/e}},function(t,e,i){var s=i(1),o=i(40);e._putDataInSector=function(){this.sectors.active[this._sector()].nodes=this.nodes,this.sectors.active[this._sector()].edges=this.edges,this.sectors.active[this._sector()].nodeIndices=this.nodeIndices},e._switchToSector=function(t,e){void 0===e||"active"==e?this._switchToActiveSector(t):this._switchToFrozenSector(t)},e._switchToActiveSector=function(t){this.nodeIndices=this.sectors.active[t].nodeIndices,this.nodes=this.sectors.active[t].nodes,this.edges=this.sectors.active[t].edges},e._switchToSupportSector=function(){this.nodeIndices=this.sectors.support.nodeIndices,this.nodes=this.sectors.support.nodes,this.edges=this.sectors.support.edges},e._switchToFrozenSector=function(t){this.nodeIndices=this.sectors.frozen[t].nodeIndices,this.nodes=this.sectors.frozen[t].nodes,this.edges=this.sectors.frozen[t].edges},e._loadLatestSector=function(){this._switchToSector(this._sector())},e._sector=function(){return this.activeSector[this.activeSector.length-1]},e._previousSector=function(){if(this.activeSector.length>1)return this.activeSector[this.activeSector.length-2];throw new TypeError("there are not enough sectors in the this.activeSector array.")},e._setActiveSector=function(t){this.activeSector.push(t)},e._forgetLastSector=function(){this.activeSector.pop()},e._createNewSector=function(t){this.sectors.active[t]={nodes:{},edges:{},nodeIndices:[],formationScale:this.scale,drawingNode:void 0},this.sectors.active[t].drawingNode=new o({id:t,color:{background:"#eaefef",border:"495c5e"}},{},{},this.constants),this.sectors.active[t].drawingNode.clusterSize=2},e._deleteActiveSector=function(t){delete this.sectors.active[t]},e._deleteFrozenSector=function(t){delete this.sectors.frozen[t]},e._freezeSector=function(t){this.sectors.frozen[t]=this.sectors.active[t],this._deleteActiveSector(t)},e._activateSector=function(t){this.sectors.active[t]=this.sectors.frozen[t],this._deleteFrozenSector(t)},e._mergeThisWithFrozen=function(t){for(var e in this.nodes)this.nodes.hasOwnProperty(e)&&(this.sectors.frozen[t].nodes[e]=this.nodes[e]);for(var i in this.edges)this.edges.hasOwnProperty(i)&&(this.sectors.frozen[t].edges[i]=this.edges[i]);for(var s=0;s1?this[t](o[0],o[1]):this[t](e))}return this._loadLatestSector(),i},e._doInSupportSector=function(t,e){var i=!1;if(void 0===e)this._switchToSupportSector(),i=this[t]();else{this._switchToSupportSector();var s=Array.prototype.splice.call(arguments,1);i=s.length>1?this[t](s[0],s[1]):this[t](e)}return this._loadLatestSector(),i},e._doInAllFrozenSectors=function(t,e){if(void 0===e)for(var i in this.sectors.frozen)this.sectors.frozen.hasOwnProperty(i)&&(this._switchToFrozenSector(i),this[t]());else for(var i in this.sectors.frozen)if(this.sectors.frozen.hasOwnProperty(i)){this._switchToFrozenSector(i);var s=Array.prototype.splice.call(arguments,1);s.length>1?this[t](s[0],s[1]):this[t](e)}this._loadLatestSector()},e._doInAllSectors=function(t,e){var i=Array.prototype.splice.call(arguments,1);void 0===e?(this._doInAllActiveSectors(t),this._doInAllFrozenSectors(t)):i.length>1?(this._doInAllActiveSectors(t,i[0],i[1]),this._doInAllFrozenSectors(t,i[0],i[1])):(this._doInAllActiveSectors(t,e),this._doInAllFrozenSectors(t,e))},e._clearNodeIndexList=function(){var t=this._sector();this.sectors.active[t].nodeIndices=[],this.nodeIndices=this.sectors.active[t].nodeIndices},e._drawSectorNodes=function(t,e){var i,s=1e9,o=-1e9,n=1e9,r=-1e9;for(var a in this.sectors[e])if(this.sectors[e].hasOwnProperty(a)&&void 0!==this.sectors[e][a].drawingNode){this._switchToSector(a,e),s=1e9,o=-1e9,n=1e9,r=-1e9;for(var h in this.nodes)this.nodes.hasOwnProperty(h)&&(i=this.nodes[h],i.resize(t),n>i.x-.5*i.width&&(n=i.x-.5*i.width),ri.y-.5*i.height&&(s=i.y-.5*i.height),o0?this.nodes[i[i.length-1]]:null},e._getEdgesOverlappingWith=function(t,e){var i=this.edges;for(var s in i)i.hasOwnProperty(s)&&i[s].isOverlappingWith(t)&&e.push(s)},e._getAllEdgesOverlappingWith=function(t){var e=[];return this._doInAllActiveSectors("_getEdgesOverlappingWith",t,e),e},e._getEdgeAt=function(t){var e=this._pointerToPositionObject(t),i=this._getAllEdgesOverlappingWith(e);return i.length>0?this.edges[i[i.length-1]]:null},e._addToSelection=function(t){t instanceof s?this.selectionObj.nodes[t.id]=t:this.selectionObj.edges[t.id]=t},e._addToHover=function(t){t instanceof s?this.hoverObj.nodes[t.id]=t:this.hoverObj.edges[t.id]=t},e._removeFromSelection=function(t){t instanceof s?delete this.selectionObj.nodes[t.id]:delete this.selectionObj.edges[t.id]},e._unselectAll=function(t){void 0===t&&(t=!1);for(var e in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(e)&&this.selectionObj.nodes[e].unselect();for(var i in this.selectionObj.edges)this.selectionObj.edges.hasOwnProperty(i)&&this.selectionObj.edges[i].unselect();this.selectionObj={nodes:{},edges:{}},0==t&&this.emit("select",this.getSelection())},e._unselectClusters=function(t){void 0===t&&(t=!1);for(var e in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(e)&&this.selectionObj.nodes[e].clusterSize>1&&(this.selectionObj.nodes[e].unselect(),this._removeFromSelection(this.selectionObj.nodes[e]));0==t&&this.emit("select",this.getSelection())},e._getSelectedNodeCount=function(){var t=0;for(var e in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(e)&&(t+=1);return t},e._getSelectedNode=function(){for(var t in this.selectionObj.nodes)if(this.selectionObj.nodes.hasOwnProperty(t))return this.selectionObj.nodes[t];return null},e._getSelectedEdge=function(){for(var t in this.selectionObj.edges)if(this.selectionObj.edges.hasOwnProperty(t))return this.selectionObj.edges[t];return null},e._getSelectedEdgeCount=function(){var t=0;for(var e in this.selectionObj.edges)this.selectionObj.edges.hasOwnProperty(e)&&(t+=1);return t},e._getSelectedObjectCount=function(){var t=0;for(var e in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(e)&&(t+=1);for(var i in this.selectionObj.edges)this.selectionObj.edges.hasOwnProperty(i)&&(t+=1);return t},e._selectionIsEmpty=function(){for(var t in this.selectionObj.nodes)if(this.selectionObj.nodes.hasOwnProperty(t))return!1;for(var e in this.selectionObj.edges)if(this.selectionObj.edges.hasOwnProperty(e))return!1;return!0},e._clusterInSelection=function(){for(var t in this.selectionObj.nodes)if(this.selectionObj.nodes.hasOwnProperty(t)&&this.selectionObj.nodes[t].clusterSize>1)return!0;return!1},e._selectConnectedEdges=function(t){for(var e=0;ei;i++){o=t[i];var n=this.nodes[o];if(!n)throw new RangeError('Node with id "'+o+'" not found');this._selectObject(n,!0,!0,e,!0)}this.redraw()},e.selectEdges=function(t){var e,i,s;if(!t||void 0==t.length)throw"Selection must be an array with ids";for(this._unselectAll(!0),e=0,i=t.length;i>e;e++){s=t[e];var o=this.edges[s];if(!o)throw new RangeError('Edge with id "'+s+'" not found');this._selectObject(o,!0,!0,!1,!0)}this.redraw()},e._updateSelection=function(){for(var t in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(t)&&(this.nodes.hasOwnProperty(t)||delete this.selectionObj.nodes[t]);for(var e in this.selectionObj.edges)this.selectionObj.edges.hasOwnProperty(e)&&(this.edges.hasOwnProperty(e)||delete this.selectionObj.edges[e])}},function(t,e,i){var s=i(1),o=i(40),n=i(37);e._clearManipulatorBar=function(){this._recursiveDOMDelete(this.manipulationDiv),this.manipulationDOM={},this._manipulationReleaseOverload=function(){},delete this.sectors.support.nodes.targetNode,delete this.sectors.support.nodes.targetViaNode,this.controlNodesActive=!1,this.freezeSimulation=!1},e._restoreOverloadedFunctions=function(){for(var t in this.cachedFunctions)this.cachedFunctions.hasOwnProperty(t)&&(this[t]=this.cachedFunctions[t],delete this.cachedFunctions[t])},e._toggleEditMode=function(){this.editMode=!this.editMode;var t=this.manipulationDiv,e=this.closeDiv,i=this.editModeDiv;1==this.editMode?(t.style.display="block",e.style.display="block",i.style.display="none",e.onclick=this._toggleEditMode.bind(this)):(t.style.display="none",e.style.display="none",i.style.display="block",e.onclick=null),this._createManipulatorBar()},e._createManipulatorBar=function(){this.boundFunction&&this.off("select",this.boundFunction);var t=this.constants.locales[this.constants.locale];if(void 0!==this.edgeBeingEdited&&(this.edgeBeingEdited._disableControlNodes(),this.edgeBeingEdited=void 0,this.selectedControlNode=null,this.controlNodesActive=!1,this._redraw()),this._restoreOverloadedFunctions(),this.freezeSimulation=!1,this.blockConnectingEdgeSelection=!1,this.forceAppendSelection=!1,this.manipulationDOM={},1==this.editMode){for(;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);this.manipulationDOM.addNodeSpan=document.createElement("span"),this.manipulationDOM.addNodeSpan.className="network-manipulationUI add",this.manipulationDOM.addNodeLabelSpan=document.createElement("span"),this.manipulationDOM.addNodeLabelSpan.className="network-manipulationLabel",this.manipulationDOM.addNodeLabelSpan.innerHTML=t.addNode,this.manipulationDOM.addNodeSpan.appendChild(this.manipulationDOM.addNodeLabelSpan),this.manipulationDOM.seperatorLineDiv1=document.createElement("div"),this.manipulationDOM.seperatorLineDiv1.className="network-seperatorLine",this.manipulationDOM.addEdgeSpan=document.createElement("span"),this.manipulationDOM.addEdgeSpan.className="network-manipulationUI connect",this.manipulationDOM.addEdgeLabelSpan=document.createElement("span"),this.manipulationDOM.addEdgeLabelSpan.className="network-manipulationLabel",this.manipulationDOM.addEdgeLabelSpan.innerHTML=t.addEdge,this.manipulationDOM.addEdgeSpan.appendChild(this.manipulationDOM.addEdgeLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.addNodeSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv1),this.manipulationDiv.appendChild(this.manipulationDOM.addEdgeSpan),1==this._getSelectedNodeCount()&&this.triggerFunctions.edit?(this.manipulationDOM.seperatorLineDiv2=document.createElement("div"),this.manipulationDOM.seperatorLineDiv2.className="network-seperatorLine",this.manipulationDOM.editNodeSpan=document.createElement("span"),this.manipulationDOM.editNodeSpan.className="network-manipulationUI edit",this.manipulationDOM.editNodeLabelSpan=document.createElement("span"),this.manipulationDOM.editNodeLabelSpan.className="network-manipulationLabel",this.manipulationDOM.editNodeLabelSpan.innerHTML=t.editNode,this.manipulationDOM.editNodeSpan.appendChild(this.manipulationDOM.editNodeLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv2),this.manipulationDiv.appendChild(this.manipulationDOM.editNodeSpan)):1==this._getSelectedEdgeCount()&&0==this._getSelectedNodeCount()&&(this.manipulationDOM.seperatorLineDiv3=document.createElement("div"),this.manipulationDOM.seperatorLineDiv3.className="network-seperatorLine",this.manipulationDOM.editEdgeSpan=document.createElement("span"),this.manipulationDOM.editEdgeSpan.className="network-manipulationUI edit",this.manipulationDOM.editEdgeLabelSpan=document.createElement("span"),this.manipulationDOM.editEdgeLabelSpan.className="network-manipulationLabel",this.manipulationDOM.editEdgeLabelSpan.innerHTML=t.editEdge,this.manipulationDOM.editEdgeSpan.appendChild(this.manipulationDOM.editEdgeLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv3),this.manipulationDiv.appendChild(this.manipulationDOM.editEdgeSpan)),0==this._selectionIsEmpty()&&(this.manipulationDOM.seperatorLineDiv4=document.createElement("div"),this.manipulationDOM.seperatorLineDiv4.className="network-seperatorLine",this.manipulationDOM.deleteSpan=document.createElement("span"),this.manipulationDOM.deleteSpan.className="network-manipulationUI delete",this.manipulationDOM.deleteLabelSpan=document.createElement("span"),this.manipulationDOM.deleteLabelSpan.className="network-manipulationLabel",this.manipulationDOM.deleteLabelSpan.innerHTML=t.del,this.manipulationDOM.deleteSpan.appendChild(this.manipulationDOM.deleteLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv4),this.manipulationDiv.appendChild(this.manipulationDOM.deleteSpan)),this.manipulationDOM.addNodeSpan.onclick=this._createAddNodeToolbar.bind(this),this.manipulationDOM.addEdgeSpan.onclick=this._createAddEdgeToolbar.bind(this),1==this._getSelectedNodeCount()&&this.triggerFunctions.edit?this.manipulationDOM.editNodeSpan.onclick=this._editNode.bind(this):1==this._getSelectedEdgeCount()&&0==this._getSelectedNodeCount()&&(this.manipulationDOM.editEdgeSpan.onclick=this._createEditEdgeToolbar.bind(this)),0==this._selectionIsEmpty()&&(this.manipulationDOM.deleteSpan.onclick=this._deleteSelected.bind(this)),this.closeDiv.onclick=this._toggleEditMode.bind(this); +var e=this;this.boundFunction=e._createManipulatorBar,this.on("select",this.boundFunction)}else{for(;this.editModeDiv.hasChildNodes();)this.editModeDiv.removeChild(this.editModeDiv.firstChild);this.manipulationDOM.editModeSpan=document.createElement("span"),this.manipulationDOM.editModeSpan.className="network-manipulationUI edit editmode",this.manipulationDOM.editModeLabelSpan=document.createElement("span"),this.manipulationDOM.editModeLabelSpan.className="network-manipulationLabel",this.manipulationDOM.editModeLabelSpan.innerHTML=t.edit,this.manipulationDOM.editModeSpan.appendChild(this.manipulationDOM.editModeLabelSpan),this.editModeDiv.appendChild(this.manipulationDOM.editModeSpan),this.manipulationDOM.editModeSpan.onclick=this._toggleEditMode.bind(this)}},e._createAddNodeToolbar=function(){this._clearManipulatorBar(),this.boundFunction&&this.off("select",this.boundFunction);var t=this.constants.locales[this.constants.locale];this.manipulationDOM={},this.manipulationDOM.backSpan=document.createElement("span"),this.manipulationDOM.backSpan.className="network-manipulationUI back",this.manipulationDOM.backLabelSpan=document.createElement("span"),this.manipulationDOM.backLabelSpan.className="network-manipulationLabel",this.manipulationDOM.backLabelSpan.innerHTML=t.back,this.manipulationDOM.backSpan.appendChild(this.manipulationDOM.backLabelSpan),this.manipulationDOM.seperatorLineDiv1=document.createElement("div"),this.manipulationDOM.seperatorLineDiv1.className="network-seperatorLine",this.manipulationDOM.descriptionSpan=document.createElement("span"),this.manipulationDOM.descriptionSpan.className="network-manipulationUI none",this.manipulationDOM.descriptionLabelSpan=document.createElement("span"),this.manipulationDOM.descriptionLabelSpan.className="network-manipulationLabel",this.manipulationDOM.descriptionLabelSpan.innerHTML=t.addDescription,this.manipulationDOM.descriptionSpan.appendChild(this.manipulationDOM.descriptionLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.backSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv1),this.manipulationDiv.appendChild(this.manipulationDOM.descriptionSpan),this.manipulationDOM.backSpan.onclick=this._createManipulatorBar.bind(this);var e=this;this.boundFunction=e._addNode,this.on("select",this.boundFunction)},e._createAddEdgeToolbar=function(){this._clearManipulatorBar(),this._unselectAll(!0),this.freezeSimulation=!0,this.boundFunction&&this.off("select",this.boundFunction);var t=this.constants.locales[this.constants.locale];this._unselectAll(),this.forceAppendSelection=!1,this.blockConnectingEdgeSelection=!0,this.manipulationDOM={},this.manipulationDOM.backSpan=document.createElement("span"),this.manipulationDOM.backSpan.className="network-manipulationUI back",this.manipulationDOM.backLabelSpan=document.createElement("span"),this.manipulationDOM.backLabelSpan.className="network-manipulationLabel",this.manipulationDOM.backLabelSpan.innerHTML=t.back,this.manipulationDOM.backSpan.appendChild(this.manipulationDOM.backLabelSpan),this.manipulationDOM.seperatorLineDiv1=document.createElement("div"),this.manipulationDOM.seperatorLineDiv1.className="network-seperatorLine",this.manipulationDOM.descriptionSpan=document.createElement("span"),this.manipulationDOM.descriptionSpan.className="network-manipulationUI none",this.manipulationDOM.descriptionLabelSpan=document.createElement("span"),this.manipulationDOM.descriptionLabelSpan.className="network-manipulationLabel",this.manipulationDOM.descriptionLabelSpan.innerHTML=t.edgeDescription,this.manipulationDOM.descriptionSpan.appendChild(this.manipulationDOM.descriptionLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.backSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv1),this.manipulationDiv.appendChild(this.manipulationDOM.descriptionSpan),this.manipulationDOM.backSpan.onclick=this._createManipulatorBar.bind(this);var e=this;this.boundFunction=e._handleConnect,this.on("select",this.boundFunction),this.cachedFunctions._handleTouch=this._handleTouch,this.cachedFunctions._manipulationReleaseOverload=this._manipulationReleaseOverload,this.cachedFunctions._handleDragStart=this._handleDragStart,this.cachedFunctions._handleDragEnd=this._handleDragEnd,this._handleTouch=this._handleConnect,this._manipulationReleaseOverload=function(){},this._handleDragStart=function(){},this._handleDragEnd=this._finishConnect,this._redraw()},e._createEditEdgeToolbar=function(){this._clearManipulatorBar(),this.controlNodesActive=!0,this.boundFunction&&this.off("select",this.boundFunction),this.edgeBeingEdited=this._getSelectedEdge(),this.edgeBeingEdited._enableControlNodes();var t=this.constants.locales[this.constants.locale];this.manipulationDOM={},this.manipulationDOM.backSpan=document.createElement("span"),this.manipulationDOM.backSpan.className="network-manipulationUI back",this.manipulationDOM.backLabelSpan=document.createElement("span"),this.manipulationDOM.backLabelSpan.className="network-manipulationLabel",this.manipulationDOM.backLabelSpan.innerHTML=t.back,this.manipulationDOM.backSpan.appendChild(this.manipulationDOM.backLabelSpan),this.manipulationDOM.seperatorLineDiv1=document.createElement("div"),this.manipulationDOM.seperatorLineDiv1.className="network-seperatorLine",this.manipulationDOM.descriptionSpan=document.createElement("span"),this.manipulationDOM.descriptionSpan.className="network-manipulationUI none",this.manipulationDOM.descriptionLabelSpan=document.createElement("span"),this.manipulationDOM.descriptionLabelSpan.className="network-manipulationLabel",this.manipulationDOM.descriptionLabelSpan.innerHTML=t.editEdgeDescription,this.manipulationDOM.descriptionSpan.appendChild(this.manipulationDOM.descriptionLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.backSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv1),this.manipulationDiv.appendChild(this.manipulationDOM.descriptionSpan),this.manipulationDOM.backSpan.onclick=this._createManipulatorBar.bind(this),this.cachedFunctions._handleTouch=this._handleTouch,this.cachedFunctions._manipulationReleaseOverload=this._manipulationReleaseOverload,this.cachedFunctions._handleTap=this._handleTap,this.cachedFunctions._handleDragStart=this._handleDragStart,this.cachedFunctions._handleOnDrag=this._handleOnDrag,this._handleTouch=this._selectControlNode,this._handleTap=function(){},this._handleOnDrag=this._controlNodeDrag,this._handleDragStart=function(){},this._manipulationReleaseOverload=this._releaseControlNode,this._redraw()},e._selectControlNode=function(t){this.edgeBeingEdited.controlNodes.from.unselect(),this.edgeBeingEdited.controlNodes.to.unselect(),this.selectedControlNode=this.edgeBeingEdited._getSelectedControlNode(this._XconvertDOMtoCanvas(t.x),this._YconvertDOMtoCanvas(t.y)),null!==this.selectedControlNode&&(this.selectedControlNode.select(),this.freezeSimulation=!0),this._redraw()},e._controlNodeDrag=function(t){var e=this._getPointer(t.gesture.center);null!==this.selectedControlNode&&void 0!==this.selectedControlNode&&(this.selectedControlNode.x=this._XconvertDOMtoCanvas(e.x),this.selectedControlNode.y=this._YconvertDOMtoCanvas(e.y)),this._redraw()},e._releaseControlNode=function(t){var e=this._getNodeAt(t);null!==e?(1==this.edgeBeingEdited.controlNodes.from.selected&&(this.edgeBeingEdited._restoreControlNodes(),this._editEdge(e.id,this.edgeBeingEdited.to.id),this.edgeBeingEdited.controlNodes.from.unselect()),1==this.edgeBeingEdited.controlNodes.to.selected&&(this.edgeBeingEdited._restoreControlNodes(),this._editEdge(this.edgeBeingEdited.from.id,e.id),this.edgeBeingEdited.controlNodes.to.unselect())):this.edgeBeingEdited._restoreControlNodes(),this.freezeSimulation=!1,this._redraw()},e._handleConnect=function(t){if(0==this._getSelectedNodeCount()){var e=this._getNodeAt(t);if(null!=e)if(e.clusterSize>1)alert(this.constants.locales[this.constants.locale].createEdgeError);else{this._selectObject(e,!1);var i=this.sectors.support.nodes;i.targetNode=new o({id:"targetNode"},{},{},this.constants);var s=i.targetNode;s.x=e.x,s.y=e.y,this.edges.connectionEdge=new n({id:"connectionEdge",from:e.id,to:s.id},this,this.constants);var r=this.edges.connectionEdge;r.from=e,r.connected=!0,r.options.smoothCurves={enabled:!0,dynamic:!1,type:"continuous",roundness:.5},r.selected=!0,r.to=s,this.cachedFunctions._handleOnDrag=this._handleOnDrag,this._handleOnDrag=function(t){var e=this._getPointer(t.gesture.center),i=this.edges.connectionEdge;i.to.x=this._XconvertDOMtoCanvas(e.x),i.to.y=this._YconvertDOMtoCanvas(e.y)},this.moving=!0,this.start()}}},e._finishConnect=function(t){if(1==this._getSelectedNodeCount()){var e=this._getPointer(t.gesture.center);this._handleOnDrag=this.cachedFunctions._handleOnDrag,delete this.cachedFunctions._handleOnDrag;var i=this.edges.connectionEdge.fromId;delete this.edges.connectionEdge,delete this.sectors.support.nodes.targetNode,delete this.sectors.support.nodes.targetViaNode;var s=this._getNodeAt(e);null!=s&&(s.clusterSize>1?alert(this.constants.locales[this.constants.locale].createEdgeError):(this._createEdge(i,s.id),this._createManipulatorBar())),this._unselectAll()}},e._addNode=function(){if(this._selectionIsEmpty()&&1==this.editMode){var t=this._pointerToPositionObject(this.pointerPosition),e={id:s.randomUUID(),x:t.left,y:t.top,label:"new",allowedToMoveX:!0,allowedToMoveY:!0};if(this.triggerFunctions.add){if(2!=this.triggerFunctions.add.length)throw new Error("The function for add does not support two arguments (data,callback)");var i=this;this.triggerFunctions.add(e,function(t){i.nodesData.add(t),i._createManipulatorBar(),i.moving=!0,i.start()})}else this.nodesData.add(e),this._createManipulatorBar(),this.moving=!0,this.start()}},e._createEdge=function(t,e){if(1==this.editMode){var i={from:t,to:e};if(this.triggerFunctions.connect){if(2!=this.triggerFunctions.connect.length)throw new Error("The function for connect does not support two arguments (data,callback)");var s=this;this.triggerFunctions.connect(i,function(t){s.edgesData.add(t),s.moving=!0,s.start()})}else this.edgesData.add(i),this.moving=!0,this.start()}},e._editEdge=function(t,e){if(1==this.editMode){var i={id:this.edgeBeingEdited.id,from:t,to:e};if(this.triggerFunctions.editEdge){if(2!=this.triggerFunctions.editEdge.length)throw new Error("The function for edit does not support two arguments (data, callback)");var s=this;this.triggerFunctions.editEdge(i,function(t){s.edgesData.update(t),s.moving=!0,s.start()})}else this.edgesData.update(i),this.moving=!0,this.start()}},e._editNode=function(){if(!this.triggerFunctions.edit||1!=this.editMode)throw new Error("No edit function has been bound to this button");var t=this._getSelectedNode(),e={id:t.id,label:t.label,group:t.options.group,shape:t.options.shape,color:{background:t.options.color.background,border:t.options.color.border,highlight:{background:t.options.color.highlight.background,border:t.options.color.highlight.border}}};if(2!=this.triggerFunctions.edit.length)throw new Error("The function for edit does not support two arguments (data, callback)");var i=this;this.triggerFunctions.edit(e,function(t){i.nodesData.update(t),i._createManipulatorBar(),i.moving=!0,i.start()})},e._deleteSelected=function(){if(!this._selectionIsEmpty()&&1==this.editMode)if(this._clusterInSelection())alert(this.constants.locales[this.constants.locale].deleteClusterError);else{var t=this.getSelectedNodes(),e=this.getSelectedEdges();if(this.triggerFunctions.del){var i=this,s={nodes:t,edges:e};if(2!=this.triggerFunctions.del.length)throw new Error("The function for delete does not support two arguments (data, callback)");this.triggerFunctions.del(s,function(t){i.edgesData.remove(t.edges),i.nodesData.remove(t.nodes),i._unselectAll(),i.moving=!0,i.start()})}else this.edgesData.remove(e),this.nodesData.remove(t),this._unselectAll(),this.moving=!0,this.start()}}},function(t,e,i){var s=(i(1),i(45));e._cleanNavigation=function(){if(0!=this.navigationHammers.existing.length){for(var t=0;t0){var t,e,i=0,s=!1,o=!1;for(e in this.nodes)this.nodes.hasOwnProperty(e)&&(t=this.nodes[e],-1!=t.level?s=!0:o=!0,is&&(n.xFixed=!1,n.x=i[n.level].minPos,r=!0):n.yFixed&&n.level>s&&(n.yFixed=!1,n.y=i[n.level].minPos,r=!0),1==r&&(i[n.level].minPos+=i[n.level].nodeSpacing,n.edges.length>1&&this._placeBranchNodes(n.edges,n.id,i,n.level))}},e._setLevel=function(t,e,i){for(var s=0;st)&&(o.level=t,o.edges.length>1&&this._setLevel(t+1,o.edges,o.id))}},e._setLevelDirected=function(t,e,i){this.nodes[i].hierarchyEnumerated=!0;for(var s,o,n=0;n1&&s.hierarchyEnumerated===!1&&this._setLevelDirected(s.level,s.edges,s.id)},e._restoreNodes=function(){for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&(this.nodes[t].xFixed=!1,this.nodes[t].yFixed=!1)}},function(t,e,i){function s(){this.constants.smoothCurves.enabled=!this.constants.smoothCurves.enabled;var t=document.getElementById("graph_toggleSmooth");t.style.background=1==this.constants.smoothCurves.enabled?"#A4FF56":"#FF8532",this._configureSmoothCurves(!1)}function o(){for(var t in this.calculationNodes)this.calculationNodes.hasOwnProperty(t)&&(this.calculationNodes[t].vx=0,this.calculationNodes[t].vy=0,this.calculationNodes[t].fx=0,this.calculationNodes[t].fy=0);1==this.constants.hierarchicalLayout.enabled?(this._setupHierarchicalLayout(),a.call(this,"graph_H_nd",1,"physics_hierarchicalRepulsion_nodeDistance"),a.call(this,"graph_H_cg",1,"physics_centralGravity"),a.call(this,"graph_H_sc",1,"physics_springConstant"),a.call(this,"graph_H_sl",1,"physics_springLength"),a.call(this,"graph_H_damp",1,"physics_damping")):this.repositionNodes(),this.moving=!0,this.start()}function n(){var t="No options are required, default values used.",e=[],i=document.getElementById("graph_physicsMethod1"),s=document.getElementById("graph_physicsMethod2");if(1==i.checked){if(this.constants.physics.barnesHut.gravitationalConstant!=this.backupConstants.physics.barnesHut.gravitationalConstant&&e.push("gravitationalConstant: "+this.constants.physics.barnesHut.gravitationalConstant),this.constants.physics.centralGravity!=this.backupConstants.physics.barnesHut.centralGravity&&e.push("centralGravity: "+this.constants.physics.centralGravity),this.constants.physics.springLength!=this.backupConstants.physics.barnesHut.springLength&&e.push("springLength: "+this.constants.physics.springLength),this.constants.physics.springConstant!=this.backupConstants.physics.barnesHut.springConstant&&e.push("springConstant: "+this.constants.physics.springConstant),this.constants.physics.damping!=this.backupConstants.physics.barnesHut.damping&&e.push("damping: "+this.constants.physics.damping),0!=e.length){t="var options = {",t+="physics: {barnesHut: {";for(var o=0;othis.constants.clustering.clusterThreshold&&1==this.constants.clustering.enabled&&this.clusterToFit(this.constants.clustering.reduceToNodes,!1),this._calculateForces())},e._calculateForces=function(){this._calculateGravitationalForces(),this._calculateNodeForces(),this.constants.physics.springConstant>0&&(1==this.constants.smoothCurves.enabled&&1==this.constants.smoothCurves.dynamic?this._calculateSpringForcesWithSupport():1==this.constants.physics.hierarchicalRepulsion.enabled?this._calculateHierarchicalSpringForces():this._calculateSpringForces())},e._updateCalculationNodes=function(){if(1==this.constants.smoothCurves.enabled&&1==this.constants.smoothCurves.dynamic){this.calculationNodes={},this.calculationNodeIndices=[];for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&(this.calculationNodes[t]=this.nodes[t]);var e=this.sectors.support.nodes;for(var i in e)e.hasOwnProperty(i)&&(this.edges.hasOwnProperty(e[i].parentEdgeId)?this.calculationNodes[i]=e[i]:e[i]._setForce(0,0));for(var s in this.calculationNodes)this.calculationNodes.hasOwnProperty(s)&&this.calculationNodeIndices.push(s)}else this.calculationNodes=this.nodes,this.calculationNodeIndices=this.nodeIndices},e._calculateGravitationalForces=function(){var t,e,i,s,o,n=this.calculationNodes,r=this.constants.physics.centralGravity,a=0;for(o=0;oSimulation Mode:Barnes HutRepulsionHierarchical
Options:
',this.containerElement.parentElement.insertBefore(this.physicsConfiguration,this.containerElement),this.optionsDiv=document.createElement("div"),this.optionsDiv.style.fontSize="14px",this.optionsDiv.style.fontFamily="verdana",this.containerElement.parentElement.insertBefore(this.optionsDiv,this.containerElement); +var e;e=document.getElementById("graph_BH_gc"),e.onchange=a.bind(this,"graph_BH_gc",-1,"physics_barnesHut_gravitationalConstant"),e=document.getElementById("graph_BH_cg"),e.onchange=a.bind(this,"graph_BH_cg",1,"physics_centralGravity"),e=document.getElementById("graph_BH_sc"),e.onchange=a.bind(this,"graph_BH_sc",1,"physics_springConstant"),e=document.getElementById("graph_BH_sl"),e.onchange=a.bind(this,"graph_BH_sl",1,"physics_springLength"),e=document.getElementById("graph_BH_damp"),e.onchange=a.bind(this,"graph_BH_damp",1,"physics_damping"),e=document.getElementById("graph_R_nd"),e.onchange=a.bind(this,"graph_R_nd",1,"physics_repulsion_nodeDistance"),e=document.getElementById("graph_R_cg"),e.onchange=a.bind(this,"graph_R_cg",1,"physics_centralGravity"),e=document.getElementById("graph_R_sc"),e.onchange=a.bind(this,"graph_R_sc",1,"physics_springConstant"),e=document.getElementById("graph_R_sl"),e.onchange=a.bind(this,"graph_R_sl",1,"physics_springLength"),e=document.getElementById("graph_R_damp"),e.onchange=a.bind(this,"graph_R_damp",1,"physics_damping"),e=document.getElementById("graph_H_nd"),e.onchange=a.bind(this,"graph_H_nd",1,"physics_hierarchicalRepulsion_nodeDistance"),e=document.getElementById("graph_H_cg"),e.onchange=a.bind(this,"graph_H_cg",1,"physics_centralGravity"),e=document.getElementById("graph_H_sc"),e.onchange=a.bind(this,"graph_H_sc",1,"physics_springConstant"),e=document.getElementById("graph_H_sl"),e.onchange=a.bind(this,"graph_H_sl",1,"physics_springLength"),e=document.getElementById("graph_H_damp"),e.onchange=a.bind(this,"graph_H_damp",1,"physics_damping"),e=document.getElementById("graph_H_direction"),e.onchange=a.bind(this,"graph_H_direction",t,"hierarchicalLayout_direction"),e=document.getElementById("graph_H_levsep"),e.onchange=a.bind(this,"graph_H_levsep",1,"hierarchicalLayout_levelSeparation"),e=document.getElementById("graph_H_nspac"),e.onchange=a.bind(this,"graph_H_nspac",1,"hierarchicalLayout_nodeSpacing");var i=document.getElementById("graph_physicsMethod1"),d=document.getElementById("graph_physicsMethod2"),l=document.getElementById("graph_physicsMethod3");d.checked=!0,this.constants.physics.barnesHut.enabled&&(i.checked=!0),this.constants.hierarchicalLayout.enabled&&(l.checked=!0);var c=document.getElementById("graph_toggleSmooth"),p=document.getElementById("graph_repositionNodes"),u=document.getElementById("graph_generateOptions");c.onclick=s.bind(this),p.onclick=o.bind(this),u.onclick=n.bind(this),c.style.background=1==this.constants.smoothCurves&&0==this.constants.dynamicSmoothCurves?"#A4FF56":"#FF8532",r.apply(this),i.onchange=r.bind(this),d.onchange=r.bind(this),l.onchange=r.bind(this)}},e._overWriteGraphConstants=function(t,e){var i=t.split("_");1==i.length?this.constants[i[0]]=e:2==i.length?this.constants[i[0]][i[1]]=e:3==i.length&&(this.constants[i[0]][i[1]][i[2]]=e)}},function(t){function e(t){throw new Error("Cannot find module '"+t+"'.")}e.keys=function(){return[]},e.resolve=e,t.exports=e,e.id=67},function(t,e){e._calculateNodeForces=function(){var t,e,i,s,o,n,r,a,h,d,l,c=this.calculationNodes,p=this.calculationNodeIndices,u=-2/3,m=4/3,f=this.constants.physics.repulsion.nodeDistance,g=f;for(d=0;di&&(r=.5*g>i?1:v*i+m,r*=0==n?1:1+n*this.constants.clustering.forceAmplification,r/=Math.max(i,.01*g),s=t*r,o=e*r,a.fx-=s,a.fy-=o,h.fx+=s,h.fy+=o)}}},function(t,e){e._calculateNodeForces=function(){var t,e,i,s,o,n,r,a,h,d,l=this.calculationNodes,c=this.calculationNodeIndices,p=this.constants.physics.hierarchicalRepulsion.nodeDistance;for(h=0;hi?-Math.pow(u*i,2)+Math.pow(u*p,2):0,0==i?i=.01:n/=i,s=t*n,o=e*n,r.fx-=s,r.fy-=o,a.fx+=s,a.fy+=o}},e._calculateHierarchicalSpringForces=function(){for(var t,e,i,s,o,n,r,a,h,d=this.edges,l=this.calculationNodes,c=this.calculationNodeIndices,p=0;pn;n++)t=e[i[n]],t.options.mass>0&&(this._getForceContribution(o.root.children.NW,t),this._getForceContribution(o.root.children.NE,t),this._getForceContribution(o.root.children.SW,t),this._getForceContribution(o.root.children.SE,t))}},e._getForceContribution=function(t,e){if(t.childrenCount>0){var i,s,o;if(i=t.centerOfMass.x-e.x,s=t.centerOfMass.y-e.y,o=Math.sqrt(i*i+s*s),o*t.calcSize>this.constants.physics.barnesHut.thetaInverted){0==o&&(o=.1*Math.random(),i=o);var n=this.constants.physics.barnesHut.gravitationalConstant*t.mass*e.options.mass/(o*o*o),r=i*n,a=s*n;e.fx+=r,e.fy+=a}else if(4==t.childrenCount)this._getForceContribution(t.children.NW,e),this._getForceContribution(t.children.NE,e),this._getForceContribution(t.children.SW,e),this._getForceContribution(t.children.SE,e);else if(t.children.data.id!=e.id){0==o&&(o=.5*Math.random(),i=o);var n=this.constants.physics.barnesHut.gravitationalConstant*t.mass*e.options.mass/(o*o*o),r=i*n,a=s*n;e.fx+=r,e.fy+=a}}},e._formBarnesHutTree=function(t,e){for(var i,s=e.length,o=Number.MAX_VALUE,n=Number.MAX_VALUE,r=-Number.MAX_VALUE,a=-Number.MAX_VALUE,h=0;s>h;h++){var d=t[e[h]].x,l=t[e[h]].y;t[e[h]].options.mass>0&&(o>d&&(o=d),d>r&&(r=d),n>l&&(n=l),l>a&&(a=l))}var c=Math.abs(r-o)-Math.abs(a-n);c>0?(n-=.5*c,a+=.5*c):(o+=.5*c,r-=.5*c);var p=1e-5,u=Math.max(p,Math.abs(r-o)),m=.5*u,f=.5*(o+r),g=.5*(n+a),v={root:{centerOfMass:{x:0,y:0},mass:0,range:{minX:f-m,maxX:f+m,minY:g-m,maxY:g+m},size:u,calcSize:1/u,children:{data:null},maxWidth:0,level:0,childrenCount:4}};for(this._splitBranch(v.root),h=0;s>h;h++)i=t[e[h]],i.options.mass>0&&this._placeInTree(v.root,i);this.barnesHutTree=v},e._updateBranchMass=function(t,e){var i=t.mass+e.options.mass,s=1/i;t.centerOfMass.x=t.centerOfMass.x*t.mass+e.x*e.options.mass,t.centerOfMass.x*=s,t.centerOfMass.y=t.centerOfMass.y*t.mass+e.y*e.options.mass,t.centerOfMass.y*=s,t.mass=i;var o=Math.max(Math.max(e.height,e.radius),e.width);t.maxWidth=t.maxWidthe.x?t.children.NW.range.maxY>e.y?this._placeInRegion(t,e,"NW"):this._placeInRegion(t,e,"SW"):t.children.NW.range.maxY>e.y?this._placeInRegion(t,e,"NE"):this._placeInRegion(t,e,"SE")},e._placeInRegion=function(t,e,i){switch(t.children[i].childrenCount){case 0:t.children[i].children.data=e,t.children[i].childrenCount=1,this._updateBranchMass(t.children[i],e);break;case 1:t.children[i].children.data.x==e.x&&t.children[i].children.data.y==e.y?(e.x+=Math.random(),e.y+=Math.random()):(this._splitBranch(t.children[i]),this._placeInTree(t.children[i],e));break;case 4:this._placeInTree(t.children[i],e)}},e._splitBranch=function(t){var e=null;1==t.childrenCount&&(e=t.children.data,t.mass=0,t.centerOfMass.x=0,t.centerOfMass.y=0),t.childrenCount=4,t.children.data=null,this._insertRegion(t,"NW"),this._insertRegion(t,"NE"),this._insertRegion(t,"SW"),this._insertRegion(t,"SE"),null!=e&&this._placeInTree(t,e)},e._insertRegion=function(t,e){var i,s,o,n,r=.5*t.size;switch(e){case"NW":i=t.range.minX,s=t.range.minX+r,o=t.range.minY,n=t.range.minY+r;break;case"NE":i=t.range.minX+r,s=t.range.maxX,o=t.range.minY,n=t.range.minY+r;break;case"SW":i=t.range.minX,s=t.range.minX+r,o=t.range.minY+r,n=t.range.maxY;break;case"SE":i=t.range.minX+r,s=t.range.maxX,o=t.range.minY+r,n=t.range.maxY}t.children[e]={centerOfMass:{x:0,y:0},mass:0,range:{minX:i,maxX:s,minY:o,maxY:n},size:.5*t.size,calcSize:2*t.calcSize,children:{data:null},maxWidth:0,level:t.level+1,childrenCount:0}},e._drawTree=function(t,e){void 0!==this.barnesHutTree&&(t.lineWidth=1,this._drawBranch(this.barnesHutTree.root,t,e))},e._drawBranch=function(t,e,i){void 0===i&&(i="#FF0000"),4==t.childrenCount&&(this._drawBranch(t.children.NW,e),this._drawBranch(t.children.NE,e),this._drawBranch(t.children.SE,e),this._drawBranch(t.children.SW,e)),e.strokeStyle=i,e.beginPath(),e.moveTo(t.range.minX,t.range.minY),e.lineTo(t.range.maxX,t.range.minY),e.stroke(),e.beginPath(),e.moveTo(t.range.maxX,t.range.minY),e.lineTo(t.range.maxX,t.range.maxY),e.stroke(),e.beginPath(),e.moveTo(t.range.maxX,t.range.maxY),e.lineTo(t.range.minX,t.range.maxY),e.stroke(),e.beginPath(),e.moveTo(t.range.minX,t.range.maxY),e.lineTo(t.range.minX,t.range.minY),e.stroke()}},function(t){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children=[],t.webpackPolyfill=1),t}},function(t,e){(function(e){t.exports=e}).call(e,{})}])}); //# sourceMappingURL=vis.map diff --git a/package.json b/package.json index 47bbbe87..7c431d47 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vis", - "version": "3.9.0", + "version": "3.9.1-SNAPSHOT", "description": "A dynamic, browser-based visualization library.", "homepage": "http://visjs.org/", "repository": { From 98cac95dc0a46da329f853940a2b2c7c4e389612 Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Fri, 16 Jan 2015 15:47:52 +0100 Subject: [PATCH 03/16] updated history --- HISTORY.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index d812e31d..5b624d9f 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,12 @@ http://visjs.org +## 2015-01-16, version 3.9.1 SNAPSHOT + +### Network + +- Fixed bug where opening a cluster with smoothCurves off caused one child to go crazy. + ## 2015-01-16, version 3.9.0 ### Network From bfb819df832e48ea3c36972626d91d3bae2f22ea Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Fri, 16 Jan 2015 16:42:48 +0100 Subject: [PATCH 04/16] - Fixed bug where zoomExtent does not work as expected. --- HISTORY.md | 1 + dist/vis.js | 4261 ++++++++++++++++++++-------------------- lib/network/Network.js | 17 +- 3 files changed, 2133 insertions(+), 2146 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 5b624d9f..2a916dc0 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -7,6 +7,7 @@ http://visjs.org ### Network - Fixed bug where opening a cluster with smoothCurves off caused one child to go crazy. +- Fixed bug where zoomExtent does not work as expected. ## 2015-01-16, version 3.9.0 diff --git a/dist/vis.js b/dist/vis.js index 9ca71393..2ccd554a 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -4,7 +4,7 @@ * * A dynamic, browser-based visualization library. * - * @version 3.9.0 + * @version 3.9.1-SNAPSHOT * @date 2015-01-16 * * @license @@ -137,13 +137,13 @@ return /******/ (function(modules) { // webpackBootstrap // Network exports.Network = __webpack_require__(51); exports.network = { - Edge: __webpack_require__(57), + Edge: __webpack_require__(52), Groups: __webpack_require__(54), Images: __webpack_require__(55), - Node: __webpack_require__(56), - Popup: __webpack_require__(58), - dotparser: __webpack_require__(52), - gephiParser: __webpack_require__(53) + Node: __webpack_require__(53), + Popup: __webpack_require__(56), + dotparser: __webpack_require__(57), + gephiParser: __webpack_require__(58) }; // Deprecated since v3.0.0 @@ -22649,13 +22649,13 @@ return /******/ (function(modules) { // webpackBootstrap var hammerUtil = __webpack_require__(22); var DataSet = __webpack_require__(7); var DataView = __webpack_require__(9); - var dotparser = __webpack_require__(52); - var gephiParser = __webpack_require__(53); + var dotparser = __webpack_require__(57); + var gephiParser = __webpack_require__(58); var Groups = __webpack_require__(54); var Images = __webpack_require__(55); - var Node = __webpack_require__(56); - var Edge = __webpack_require__(57); - var Popup = __webpack_require__(58); + var Node = __webpack_require__(53); + var Edge = __webpack_require__(52); + var Popup = __webpack_require__(56); var MixinLoader = __webpack_require__(59); var Activator = __webpack_require__(35); var locales = __webpack_require__(70); @@ -23054,8 +23054,8 @@ return /******/ (function(modules) { // webpackBootstrap node = this.nodes[nodeId]; if (minX > (node.boundingBox.left)) {minX = node.boundingBox.left;} if (maxX < (node.boundingBox.right)) {maxX = node.boundingBox.right;} - if (minY > (node.boundingBox.bottom)) {minY = node.boundingBox.bottom;} - if (maxY < (node.boundingBox.top)) {maxY = node.boundingBox.top;} + if (minY > (node.boundingBox.bottom)) {minY = node.boundingBox.top;} // top is negative, bottom is positive + if (maxY < (node.boundingBox.top)) {maxY = node.boundingBox.bottom;} // top is negative, bottom is positive } } if (minX == 1e9 && maxX == -1e9 && minY == 1e9 && maxY == -1e9) { @@ -23085,15 +23085,9 @@ return /******/ (function(modules) { // webpackBootstrap Network.prototype.zoomExtent = function(animationOptions, initialZoom, disableStart) { this._redraw(true); - if (initialZoom === undefined) { - initialZoom = false; - } - if (disableStart === undefined) { - disableStart = false; - } - if (animationOptions === undefined) { - animationOptions = false; - } + if (initialZoom === undefined) {initialZoom = false;} + if (disableStart === undefined) {disableStart = false;} + if (animationOptions === undefined) {animationOptions = false;} var range = this._getRange(); var zoomLevel; @@ -23129,7 +23123,6 @@ return /******/ (function(modules) { // webpackBootstrap var xZoomLevel = this.frame.canvas.clientWidth / xDistance; var yZoomLevel = this.frame.canvas.clientHeight / yDistance; - zoomLevel = (xZoomLevel <= yZoomLevel) ? xZoomLevel : yZoomLevel; } @@ -25364,1067 +25357,1360 @@ return /******/ (function(modules) { // webpackBootstrap /* 52 */ /***/ function(module, exports, __webpack_require__) { + var util = __webpack_require__(1); + var Node = __webpack_require__(53); + /** - * Parse a text source containing data in DOT language into a JSON object. - * The object contains two lists: one with nodes and one with edges. - * - * DOT language reference: http://www.graphviz.org/doc/info/lang.html + * @class Edge * - * @param {String} data Text containing a graph in DOT-notation - * @return {Object} graph An object containing two parameters: - * {Object[]} nodes - * {Object[]} edges + * A edge connects two nodes + * @param {Object} properties Object with properties. Must contain + * At least properties from and to. + * Available properties: from (number), + * to (number), label (string, color (string), + * width (number), style (string), + * length (number), title (string) + * @param {Network} network A Network object, used to find and edge to + * nodes. + * @param {Object} constants An object with default values for + * example for the color */ - function parseDOT (data) { - dot = data; - return parseGraph(); - } + function Edge (properties, network, networkConstants) { + if (!network) { + throw "No network provided"; + } + var fields = ['edges','physics']; + var constants = util.selectiveBridgeObject(fields,networkConstants); + this.options = constants.edges; + this.physics = constants.physics; + this.options['smoothCurves'] = networkConstants['smoothCurves']; - // token types enumeration - var TOKENTYPE = { - NULL : 0, - DELIMITER : 1, - IDENTIFIER: 2, - UNKNOWN : 3 - }; - // map with all delimiters - var DELIMITERS = { - '{': true, - '}': true, - '[': true, - ']': true, - ';': true, - '=': true, - ',': true, + this.network = network; - '->': true, - '--': true - }; + // initialize variables + this.id = undefined; + this.fromId = undefined; + this.toId = undefined; + this.title = undefined; + this.widthSelected = this.options.width * this.options.widthSelectionMultiplier; + this.value = undefined; + this.selected = false; + this.hover = false; + this.labelDimensions = {top:0,left:0,width:0,height:0,yLine:0}; // could be cached + this.dirtyLabel = true; - var dot = ''; // current dot file - var index = 0; // current index in dot file - var c = ''; // current token character in expr - var token = ''; // current token - var tokenType = TOKENTYPE.NULL; // type of the token + this.from = null; // a node + this.to = null; // a node + this.via = null; // a temp node - /** - * Get the first character from the dot file. - * The character is stored into the char c. If the end of the dot file is - * reached, the function puts an empty string in c. - */ - function first() { - index = 0; - c = dot.charAt(0); - } + this.fromBackup = null; // used to clean up after reconnect + this.toBackup = null;; // used to clean up after reconnect - /** - * Get the next character from the dot file. - * The character is stored into the char c. If the end of the dot file is - * reached, the function puts an empty string in c. - */ - function next() { - index++; - c = dot.charAt(index); - } + // we use this to be able to reconnect the edge to a cluster if its node is put into a cluster + // by storing the original information we can revert to the original connection when the cluser is opened. + this.originalFromId = []; + this.originalToId = []; - /** - * Preview the next character from the dot file. - * @return {String} cNext - */ - function nextPreview() { - return dot.charAt(index + 1); - } + this.connected = false; - /** - * Test whether given character is alphabetic or numeric - * @param {String} c - * @return {Boolean} isAlphaNumeric - */ - var regexAlphaNumeric = /[a-zA-Z_0-9.:#]/; - function isAlphaNumeric(c) { - return regexAlphaNumeric.test(c); + this.widthFixed = false; + this.lengthFixed = false; + + this.setProperties(properties); + + this.controlNodesEnabled = false; + this.controlNodes = {from:null, to:null, positions:{}}; + this.connectedNode = null; } /** - * Merge all properties of object b into object b - * @param {Object} a - * @param {Object} b - * @return {Object} a + * Set or overwrite properties for the edge + * @param {Object} properties an object with properties + * @param {Object} constants and object with default, global properties */ - function merge (a, b) { - if (!a) { - a = {}; + Edge.prototype.setProperties = function(properties) { + if (!properties) { + return; } - if (b) { - for (var name in b) { - if (b.hasOwnProperty(name)) { - a[name] = b[name]; - } - } - } - return a; - } + var fields = ['style','fontSize','fontFace','fontColor','fontFill','fontStrokeWidth','fontStrokeColor','width', + 'widthSelectionMultiplier','hoverWidth','arrowScaleFactor','dash','inheritColor','labelAlignment' + ]; + util.selectiveDeepExtend(fields, this.options, properties); - /** - * Set a value in an object, where the provided parameter name can be a - * path with nested parameters. For example: - * - * var obj = {a: 2}; - * setValue(obj, 'b.c', 3); // obj = {a: 2, b: {c: 3}} - * - * @param {Object} obj - * @param {String} path A parameter name or dot-separated parameter path, - * like "color.highlight.border". - * @param {*} value - */ - function setValue(obj, path, value) { - var keys = path.split('.'); - var o = obj; - while (keys.length) { - var key = keys.shift(); - if (keys.length) { - // this isn't the end point - if (!o[key]) { - o[key] = {}; - } - o = o[key]; + if (properties.from !== undefined) {this.fromId = properties.from;} + if (properties.to !== undefined) {this.toId = properties.to;} + + if (properties.id !== undefined) {this.id = properties.id;} + if (properties.label !== undefined) {this.label = properties.label; this.dirtyLabel = true;} + + if (properties.title !== undefined) {this.title = properties.title;} + if (properties.value !== undefined) {this.value = properties.value;} + if (properties.length !== undefined) {this.physics.springLength = properties.length;} + + if (properties.color !== undefined) { + this.options.inheritColor = false; + if (util.isString(properties.color)) { + this.options.color.color = properties.color; + this.options.color.highlight = properties.color; } else { - // this is the end point - o[key] = value; + if (properties.color.color !== undefined) {this.options.color.color = properties.color.color;} + if (properties.color.highlight !== undefined) {this.options.color.highlight = properties.color.highlight;} + if (properties.color.hover !== undefined) {this.options.color.hover = properties.color.hover;} } } - } - /** - * Add a node to a graph object. If there is already a node with - * the same id, their attributes will be merged. - * @param {Object} graph - * @param {Object} node - */ - function addNode(graph, node) { - var i, len; - var current = null; + // A node is connected when it has a from and to node. + this.connect(); - // find root graph (in case of subgraph) - var graphs = [graph]; // list with all graphs from current graph to root graph - var root = graph; - while (root.parent) { - graphs.push(root.parent); - root = root.parent; - } + this.widthFixed = this.widthFixed || (properties.width !== undefined); + this.lengthFixed = this.lengthFixed || (properties.length !== undefined); - // find existing node (at root level) by its id - if (root.nodes) { - for (i = 0, len = root.nodes.length; i < len; i++) { - if (node.id === root.nodes[i].id) { - current = root.nodes[i]; - break; - } - } - } + this.widthSelected = this.options.width* this.options.widthSelectionMultiplier; - if (!current) { - // this is a new node - current = { - id: node.id - }; - if (graph.node) { - // clone default attributes - current.attr = merge(current.attr, graph.node); - } + // set draw method based on style + switch (this.options.style) { + case 'line': this.draw = this._drawLine; break; + case 'arrow': this.draw = this._drawArrow; break; + case 'arrow-center': this.draw = this._drawArrowCenter; break; + case 'dash-line': this.draw = this._drawDashLine; break; + default: this.draw = this._drawLine; break; } + + }; - // add node to this (sub)graph and all its parent graphs - for (i = graphs.length - 1; i >= 0; i--) { - var g = graphs[i]; + /** + * Connect an edge to its nodes + */ + Edge.prototype.connect = function () { + this.disconnect(); - if (!g.nodes) { - g.nodes = []; + this.from = this.network.nodes[this.fromId] || null; + this.to = this.network.nodes[this.toId] || null; + this.connected = (this.from && this.to); + + if (this.connected) { + this.from.attachEdge(this); + this.to.attachEdge(this); + } + else { + if (this.from) { + this.from.detachEdge(this); } - if (g.nodes.indexOf(current) == -1) { - g.nodes.push(current); + if (this.to) { + this.to.detachEdge(this); } } - - // merge attributes - if (node.attr) { - current.attr = merge(current.attr, node.attr); - } - } + }; /** - * Add an edge to a graph object - * @param {Object} graph - * @param {Object} edge + * Disconnect an edge from its nodes */ - function addEdge(graph, edge) { - if (!graph.edges) { - graph.edges = []; + Edge.prototype.disconnect = function () { + if (this.from) { + this.from.detachEdge(this); + this.from = null; } - graph.edges.push(edge); - if (graph.edge) { - var attr = merge({}, graph.edge); // clone default attributes - edge.attr = merge(attr, edge.attr); // merge attributes + if (this.to) { + this.to.detachEdge(this); + this.to = null; } - } + + this.connected = false; + }; /** - * Create an edge to a graph object - * @param {Object} graph - * @param {String | Number | Object} from - * @param {String | Number | Object} to - * @param {String} type - * @param {Object | null} attr - * @return {Object} edge + * get the title of this edge. + * @return {string} title The title of the edge, or undefined when no title + * has been set. */ - function createEdge(graph, from, to, type, attr) { - var edge = { - from: from, - to: to, - type: type - }; + Edge.prototype.getTitle = function() { + return typeof this.title === "function" ? this.title() : this.title; + }; - if (graph.edge) { - edge.attr = merge({}, graph.edge); // clone default attributes + + /** + * Retrieve the value of the edge. Can be undefined + * @return {Number} value + */ + Edge.prototype.getValue = function() { + return this.value; + }; + + /** + * Adjust the value range of the edge. The edge will adjust it's width + * based on its value. + * @param {Number} min + * @param {Number} max + */ + Edge.prototype.setValueRange = function(min, max) { + if (!this.widthFixed && this.value !== undefined) { + var scale = (this.options.widthMax - this.options.widthMin) / (max - min); + this.options.width= (this.value - min) * scale + this.options.widthMin; + this.widthSelected = this.options.width* this.options.widthSelectionMultiplier; } - edge.attr = merge(edge.attr || {}, attr); // merge attributes + }; - return edge; - } + /** + * Redraw a edge + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + */ + Edge.prototype.draw = function(ctx) { + throw "Method draw not initialized in edge"; + }; /** - * Get next token in the current dot file. - * The token and token type are available as token and tokenType + * Check if this object is overlapping with the provided object + * @param {Object} obj an object with parameters left, top + * @return {boolean} True if location is located on the edge */ - function getToken() { - tokenType = TOKENTYPE.NULL; - token = ''; + Edge.prototype.isOverlappingWith = function(obj) { + if (this.connected) { + var distMax = 10; + var xFrom = this.from.x; + var yFrom = this.from.y; + var xTo = this.to.x; + var yTo = this.to.y; + var xObj = obj.left; + var yObj = obj.top; - // skip over whitespaces - while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter - next(); + var dist = this._getDistanceToEdge(xFrom, yFrom, xTo, yTo, xObj, yObj); + + return (dist < distMax); + } + else { + return false } + }; - do { - var isComment = false; + Edge.prototype._getColor = function() { + var colorObj = this.options.color; + if (this.options.inheritColor == "to") { + colorObj = { + highlight: this.to.options.color.highlight.border, + hover: this.to.options.color.hover.border, + color: this.to.options.color.border + }; + } + else if (this.options.inheritColor == "from" || this.options.inheritColor == true) { + colorObj = { + highlight: this.from.options.color.highlight.border, + hover: this.from.options.color.hover.border, + color: this.from.options.color.border + }; + } - // skip comment - if (c == '#') { - // find the previous non-space character - var i = index - 1; - while (dot.charAt(i) == ' ' || dot.charAt(i) == '\t') { - i--; + if (this.selected == true) {return colorObj.highlight;} + else if (this.hover == true) {return colorObj.hover;} + else {return colorObj.color;} + }; + + + /** + * Redraw a edge as a line + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private + */ + Edge.prototype._drawLine = function(ctx) { + // set style + ctx.strokeStyle = this._getColor(); + ctx.lineWidth = this._getLineWidth(); + + if (this.from != this.to) { + // draw line + var via = this._line(ctx); + + // draw label + var point; + if (this.label) { + if (this.options.smoothCurves.enabled == true && via != null) { + var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); + var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); + point = {x:midpointX, y:midpointY}; } - if (dot.charAt(i) == '\n' || dot.charAt(i) == '') { - // the # is at the start of a line, this is indeed a line comment - while (c != '' && c != '\n') { - next(); - } - isComment = true; + else { + point = this._pointOnLine(0.5); } + this._label(ctx, this.label, point.x, point.y); } - if (c == '/' && nextPreview() == '/') { - // skip line comment - while (c != '' && c != '\n') { - next(); - } - isComment = true; + } + else { + var x, y; + var radius = this.physics.springLength / 4; + var node = this.from; + if (!node.width) { + node.resize(ctx); } - if (c == '/' && nextPreview() == '*') { - // skip block comment - while (c != '') { - if (c == '*' && nextPreview() == '/') { - // end of block comment found. skip these last two characters - next(); - next(); - break; - } - else { - next(); - } - } - isComment = true; + if (node.width > node.height) { + x = node.x + node.width / 2; + y = node.y - radius; } - - // skip over whitespaces - while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter - next(); + else { + x = node.x + radius; + y = node.y - node.height / 2; } + this._circle(ctx, x, y, radius); + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); } - while (isComment); + }; - // check for end of dot file - if (c == '') { - // token is still empty - tokenType = TOKENTYPE.DELIMITER; - return; + /** + * Get the line width of the edge. Depends on width and whether one of the + * connected nodes is selected. + * @return {Number} width + * @private + */ + Edge.prototype._getLineWidth = function() { + if (this.selected == true) { + return Math.max(Math.min(this.widthSelected, this.options.widthMax), 0.3*this.networkScaleInv); + } + else { + if (this.hover == true) { + return Math.max(Math.min(this.options.hoverWidth, this.options.widthMax), 0.3*this.networkScaleInv); + } + else { + return Math.max(this.options.width, 0.3*this.networkScaleInv); + } } + }; - // check for delimiters consisting of 2 characters - var c2 = c + nextPreview(); - if (DELIMITERS[c2]) { - tokenType = TOKENTYPE.DELIMITER; - token = c2; - next(); - next(); - return; + Edge.prototype._getViaCoordinates = function () { + if (this.options.smoothCurves.dynamic == true && this.options.smoothCurves.enabled == true ) { + return this.via; } - - // check for delimiters consisting of 1 character - if (DELIMITERS[c]) { - tokenType = TOKENTYPE.DELIMITER; - token = c; - next(); - return; + else if (this.options.smoothCurves.enabled == false) { + return {x:0,y:0}; } + else { + var xVia = null; + var yVia = null; + var factor = this.options.smoothCurves.roundness; + var type = this.options.smoothCurves.type; - // check for an identifier (number or string) - // TODO: more precise parsing of numbers/strings (and the port separator ':') - if (isAlphaNumeric(c) || c == '-') { - token += c; - next(); - - while (isAlphaNumeric(c)) { - token += c; - next(); + var dx = Math.abs(this.from.x - this.to.x); + var dy = Math.abs(this.from.y - this.to.y); + if (type == 'discrete' || type == 'diagonalCross') { + if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { + if (this.from.y > this.to.y) { + if (this.from.x < this.to.x) { + xVia = this.from.x + factor * dy; + yVia = this.from.y - factor * dy; + } + else if (this.from.x > this.to.x) { + xVia = this.from.x - factor * dy; + yVia = this.from.y - factor * dy; + } + } + else if (this.from.y < this.to.y) { + if (this.from.x < this.to.x) { + xVia = this.from.x + factor * dy; + yVia = this.from.y + factor * dy; + } + else if (this.from.x > this.to.x) { + xVia = this.from.x - factor * dy; + yVia = this.from.y + factor * dy; + } + } + if (type == "discrete") { + xVia = dx < factor * dy ? this.from.x : xVia; + } + } + else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { + if (this.from.y > this.to.y) { + if (this.from.x < this.to.x) { + xVia = this.from.x + factor * dx; + yVia = this.from.y - factor * dx; + } + else if (this.from.x > this.to.x) { + xVia = this.from.x - factor * dx; + yVia = this.from.y - factor * dx; + } + } + else if (this.from.y < this.to.y) { + if (this.from.x < this.to.x) { + xVia = this.from.x + factor * dx; + yVia = this.from.y + factor * dx; + } + else if (this.from.x > this.to.x) { + xVia = this.from.x - factor * dx; + yVia = this.from.y + factor * dx; + } + } + if (type == "discrete") { + yVia = dy < factor * dx ? this.from.y : yVia; + } + } } - if (token == 'false') { - token = false; // convert to boolean + else if (type == "straightCross") { + if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { // up - down + xVia = this.from.x; + if (this.from.y < this.to.y) { + yVia = this.to.y - (1 - factor) * dy; + } + else { + yVia = this.to.y + (1 - factor) * dy; + } + } + else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { // left - right + if (this.from.x < this.to.x) { + xVia = this.to.x - (1 - factor) * dx; + } + else { + xVia = this.to.x + (1 - factor) * dx; + } + yVia = this.from.y; + } } - else if (token == 'true') { - token = true; // convert to boolean + else if (type == 'horizontal') { + if (this.from.x < this.to.x) { + xVia = this.to.x - (1 - factor) * dx; + } + else { + xVia = this.to.x + (1 - factor) * dx; + } + yVia = this.from.y; } - else if (!isNaN(Number(token))) { - token = Number(token); // convert to number + else if (type == 'vertical') { + xVia = this.from.x; + if (this.from.y < this.to.y) { + yVia = this.to.y - (1 - factor) * dy; + } + else { + yVia = this.to.y + (1 - factor) * dy; + } } - tokenType = TOKENTYPE.IDENTIFIER; - return; + else { // continuous + if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { + if (this.from.y > this.to.y) { + if (this.from.x < this.to.x) { + // console.log(1) + xVia = this.from.x + factor * dy; + yVia = this.from.y - factor * dy; + xVia = this.to.x < xVia ? this.to.x : xVia; + } + else if (this.from.x > this.to.x) { + // console.log(2) + xVia = this.from.x - factor * dy; + yVia = this.from.y - factor * dy; + xVia = this.to.x > xVia ? this.to.x : xVia; + } + } + else if (this.from.y < this.to.y) { + if (this.from.x < this.to.x) { + // console.log(3) + xVia = this.from.x + factor * dy; + yVia = this.from.y + factor * dy; + xVia = this.to.x < xVia ? this.to.x : xVia; + } + else if (this.from.x > this.to.x) { + // console.log(4, this.from.x, this.to.x) + xVia = this.from.x - factor * dy; + yVia = this.from.y + factor * dy; + xVia = this.to.x > xVia ? this.to.x : xVia; + } + } + } + else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { + if (this.from.y > this.to.y) { + if (this.from.x < this.to.x) { + // console.log(5) + xVia = this.from.x + factor * dx; + yVia = this.from.y - factor * dx; + yVia = this.to.y > yVia ? this.to.y : yVia; + } + else if (this.from.x > this.to.x) { + // console.log(6) + xVia = this.from.x - factor * dx; + yVia = this.from.y - factor * dx; + yVia = this.to.y > yVia ? this.to.y : yVia; + } + } + else if (this.from.y < this.to.y) { + if (this.from.x < this.to.x) { + // console.log(7) + xVia = this.from.x + factor * dx; + yVia = this.from.y + factor * dx; + yVia = this.to.y < yVia ? this.to.y : yVia; + } + else if (this.from.x > this.to.x) { + // console.log(8) + xVia = this.from.x - factor * dx; + yVia = this.from.y + factor * dx; + yVia = this.to.y < yVia ? this.to.y : yVia; + } + } + } + } + + + return {x: xVia, y: yVia}; } + }; - // check for a string enclosed by double quotes - if (c == '"') { - next(); - while (c != '' && (c != '"' || (c == '"' && nextPreview() == '"'))) { - token += c; - if (c == '"') { // skip the escape character - next(); + /** + * Draw a line between two nodes + * @param {CanvasRenderingContext2D} ctx + * @private + */ + Edge.prototype._line = function (ctx) { + // draw a straight line + ctx.beginPath(); + ctx.moveTo(this.from.x, this.from.y); + if (this.options.smoothCurves.enabled == true) { + if (this.options.smoothCurves.dynamic == false) { + var via = this._getViaCoordinates(); + if (via.x == null) { + ctx.lineTo(this.to.x, this.to.y); + ctx.stroke(); + return null; + } + else { + // this.via.x = via.x; + // this.via.y = via.y; + ctx.quadraticCurveTo(via.x,via.y,this.to.x, this.to.y); + ctx.stroke(); + return via; } - next(); } - if (c != '"') { - throw newSyntaxError('End of string " expected'); + else { + ctx.quadraticCurveTo(this.via.x,this.via.y,this.to.x, this.to.y); + ctx.stroke(); + return this.via; } - next(); - tokenType = TOKENTYPE.IDENTIFIER; - return; } - - // something unknown is found, wrong characters, a syntax error - tokenType = TOKENTYPE.UNKNOWN; - while (c != '') { - token += c; - next(); + else { + ctx.lineTo(this.to.x, this.to.y); + ctx.stroke(); + return null; } - throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"'); - } + }; /** - * Parse a graph. - * @returns {Object} graph + * Draw a line from a node to itself, a circle + * @param {CanvasRenderingContext2D} ctx + * @param {Number} x + * @param {Number} y + * @param {Number} radius + * @private */ - function parseGraph() { - var graph = {}; - - first(); - getToken(); - - // optional strict keyword - if (token == 'strict') { - graph.strict = true; - getToken(); - } + Edge.prototype._circle = function (ctx, x, y, radius) { + // draw a circle + ctx.beginPath(); + ctx.arc(x, y, radius, 0, 2 * Math.PI, false); + ctx.stroke(); + }; - // graph or digraph keyword - if (token == 'graph' || token == 'digraph') { - graph.type = token; - getToken(); - } + /** + * Draw label with white background and with the middle at (x, y) + * @param {CanvasRenderingContext2D} ctx + * @param {String} text + * @param {Number} x + * @param {Number} y + * @private + */ + Edge.prototype._label = function (ctx, text, x, y) { + if (text) { + ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") + + this.options.fontSize + "px " + this.options.fontFace; + var yLine; - // optional graph id - if (tokenType == TOKENTYPE.IDENTIFIER) { - graph.id = token; - getToken(); - } + if (this.dirtyLabel == true) { + var lines = String(text).split('\n'); + var lineCount = lines.length; + var fontSize = Number(this.options.fontSize); + yLine = y + (1 - lineCount) / 2 * fontSize; - // open angle bracket - if (token != '{') { - throw newSyntaxError('Angle bracket { expected'); - } - getToken(); + var width = ctx.measureText(lines[0]).width; + for (var i = 1; i < lineCount; i++) { + var lineWidth = ctx.measureText(lines[i]).width; + width = lineWidth > width ? lineWidth : width; + } + var height = this.options.fontSize * lineCount; + var left = x - width / 2; + var top = y - height / 2; - // statements - parseStatements(graph); + // cache + this.labelDimensions = {top:top,left:left,width:width,height:height,yLine:yLine}; + } - // close angle bracket - if (token != '}') { - throw newSyntaxError('Angle bracket } expected'); - } - getToken(); + var yLine = this.labelDimensions.yLine; + + ctx.save(); + + if (this.options.labelAlignment != "horizontal"){ + ctx.translate(x, yLine); + this._rotateForLabelAlignment(ctx); + x = 0; + yLine = 0; + } - // end of file - if (token !== '') { - throw newSyntaxError('End of file expected'); + + this._drawLabelRect(ctx); + this._drawLabelText(ctx,x,yLine, lines, lineCount, fontSize); + + ctx.restore(); } - getToken(); + }; - // remove temporary default properties - delete graph.node; - delete graph.edge; - delete graph.graph; + /** + * Rotates the canvas so the text is most readable + * @param {CanvasRenderingContext2D} ctx + * @private + */ + Edge.prototype._rotateForLabelAlignment = function(ctx) { + var dy = this.from.y - this.to.y; + var dx = this.from.x - this.to.x; + var angleInDegrees = Math.atan2(dy, dx); - return graph; - } + // rotate so label it is readable + if((angleInDegrees < -1 && dx < 0) || (angleInDegrees > 0 && dx < 0)){ + angleInDegrees = angleInDegrees + Math.PI; + } + + ctx.rotate(angleInDegrees); + }; /** - * Parse a list with statements. - * @param {Object} graph + * Draws the label rectangle + * @param {CanvasRenderingContext2D} ctx + * @param {String} labelAlignment + * @private */ - function parseStatements (graph) { - while (token !== '' && token != '}') { - parseStatement(graph); - if (token == ';') { - getToken(); + Edge.prototype._drawLabelRect = function(ctx) { + if (this.options.fontFill !== undefined && this.options.fontFill !== null && this.options.fontFill !== "none") { + ctx.fillStyle = this.options.fontFill; + + var lineMargin = 2; + + if (this.options.labelAlignment == 'line-center') { + ctx.fillRect(-this.labelDimensions.width * 0.5, -this.labelDimensions.height * 0.5, this.labelDimensions.width, this.labelDimensions.height); + } + else if (this.options.labelAlignment == 'line-above') { + ctx.fillRect(-this.labelDimensions.width * 0.5, -(this.labelDimensions.height + lineMargin), this.labelDimensions.width, this.labelDimensions.height); + } + else if (this.options.labelAlignment == 'line-below') { + ctx.fillRect(-this.labelDimensions.width * 0.5, lineMargin, this.labelDimensions.width, this.labelDimensions.height); + } + else { + ctx.fillRect(this.labelDimensions.left, this.labelDimensions.top, this.labelDimensions.width, this.labelDimensions.height); } } - } + }; /** - * Parse a single statement. Can be a an attribute statement, node - * statement, a series of node statements and edge statements, or a - * parameter. - * @param {Object} graph + * Draws the label text + * @param {CanvasRenderingContext2D} ctx + * @param {Number} x + * @param {Number} yLine + * @param {Array} lines + * @param {Number} lineCount + * @param {Number} fontSize + * @private */ - function parseStatement(graph) { - // parse subgraph - var subgraph = parseSubgraph(graph); - if (subgraph) { - // edge statements - parseEdge(graph, subgraph); + Edge.prototype._drawLabelText = function(ctx, x, yLine, lines, lineCount, fontSize) { + // draw text + ctx.fillStyle = this.options.fontColor || "black"; + ctx.textAlign = "center"; - return; + // check for label alignment + if (this.options.labelAlignment != 'horizontal') { + var lineMargin = 2; + if (this.options.labelAlignment == 'line-above') { + ctx.textBaseline = "alphabetic"; + yLine -= 2 * lineMargin; // distance from edge, required because we use alphabetic. Alphabetic has less difference between browsers + } + else if (this.options.labelAlignment == 'line-below') { + ctx.textBaseline = "hanging"; + yLine += 2 * lineMargin;// distance from edge, required because we use hanging. Hanging has less difference between browsers + } + else { + ctx.textBaseline = "middle"; + } } - - // parse an attribute statement - var attr = parseAttributeStatement(graph); - if (attr) { - return; + else { + ctx.textBaseline = "middle"; } - // parse node - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier expected'); + // check for strokeWidth + if (this.options.fontStrokeWidth > 0){ + ctx.lineWidth = this.options.fontStrokeWidth; + ctx.strokeStyle = this.options.fontStrokeColor; + ctx.lineJoin = 'round'; } - var id = token; // id can be a string or a number - getToken(); - - if (token == '=') { - // id statement - getToken(); - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier expected'); + for (var i = 0; i < lineCount; i++) { + if(this.options.fontStrokeWidth > 0){ + ctx.strokeText(lines[i], x, yLine); } - graph[id] = token; - getToken(); - // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] " - } - else { - parseNodeStatement(graph, id); - } - } + ctx.fillText(lines[i], x, yLine); + yLine += fontSize; + } + }; /** - * Parse a subgraph - * @param {Object} graph parent graph object - * @return {Object | null} subgraph + * Redraw a edge as a dashed line + * Draw this edge in the given canvas + * @author David Jordan + * @date 2012-08-08 + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private */ - function parseSubgraph (graph) { - var subgraph = null; + Edge.prototype._drawDashLine = function(ctx) { + // set style + ctx.strokeStyle = this._getColor(); + ctx.lineWidth = this._getLineWidth(); - // optional subgraph keyword - if (token == 'subgraph') { - subgraph = {}; - subgraph.type = 'subgraph'; - getToken(); + var via = null; + // only firefox and chrome support this method, else we use the legacy one. + if (ctx.setLineDash !== undefined) { + ctx.save(); + // configure the dash pattern + var pattern = [0]; + if (this.options.dash.length !== undefined && this.options.dash.gap !== undefined) { + pattern = [this.options.dash.length,this.options.dash.gap]; + } + else { + pattern = [5,5]; + } - // optional graph id - if (tokenType == TOKENTYPE.IDENTIFIER) { - subgraph.id = token; - getToken(); + // set dash settings for chrome or firefox + ctx.setLineDash(pattern); + ctx.lineDashOffset = 0; + + // draw the line + via = this._line(ctx); + + // restore the dash settings. + ctx.setLineDash([0]); + ctx.lineDashOffset = 0; + ctx.restore(); + } + else { // unsupporting smooth lines + // draw dashed line + ctx.beginPath(); + ctx.lineCap = 'round'; + if (this.options.dash.altLength !== undefined) //If an alt dash value has been set add to the array this value + { + ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, + [this.options.dash.length,this.options.dash.gap,this.options.dash.altLength,this.options.dash.gap]); + } + else if (this.options.dash.length !== undefined && this.options.dash.gap !== undefined) //If a dash and gap value has been set add to the array this value + { + ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, + [this.options.dash.length,this.options.dash.gap]); + } + else //If all else fails draw a line + { + ctx.moveTo(this.from.x, this.from.y); + ctx.lineTo(this.to.x, this.to.y); } + ctx.stroke(); } - // open angle bracket - if (token == '{') { - getToken(); - - if (!subgraph) { - subgraph = {}; + // draw label + if (this.label) { + var point; + if (this.options.smoothCurves.enabled == true && via != null) { + var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); + var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); + point = {x:midpointX, y:midpointY}; } - subgraph.parent = graph; - subgraph.node = graph.node; - subgraph.edge = graph.edge; - subgraph.graph = graph.graph; + else { + point = this._pointOnLine(0.5); + } + this._label(ctx, this.label, point.x, point.y); + } + }; - // statements - parseStatements(subgraph); + /** + * Get a point on a line + * @param {Number} percentage. Value between 0 (line start) and 1 (line end) + * @return {Object} point + * @private + */ + Edge.prototype._pointOnLine = function (percentage) { + return { + x: (1 - percentage) * this.from.x + percentage * this.to.x, + y: (1 - percentage) * this.from.y + percentage * this.to.y + } + }; - // close angle bracket - if (token != '}') { - throw newSyntaxError('Angle bracket } expected'); + /** + * Get a point on a circle + * @param {Number} x + * @param {Number} y + * @param {Number} radius + * @param {Number} percentage. Value between 0 (line start) and 1 (line end) + * @return {Object} point + * @private + */ + Edge.prototype._pointOnCircle = function (x, y, radius, percentage) { + var angle = (percentage - 3/8) * 2 * Math.PI; + return { + x: x + radius * Math.cos(angle), + y: y - radius * Math.sin(angle) + } + }; + + /** + * Redraw a edge as a line with an arrow halfway the line + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private + */ + Edge.prototype._drawArrowCenter = function(ctx) { + var point; + // set style + ctx.strokeStyle = this._getColor(); + ctx.fillStyle = ctx.strokeStyle; + ctx.lineWidth = this._getLineWidth(); + + if (this.from != this.to) { + // draw line + var via = this._line(ctx); + + var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; + // draw an arrow halfway the line + if (this.options.smoothCurves.enabled == true && via != null) { + var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); + var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); + point = {x:midpointX, y:midpointY}; + } + else { + point = this._pointOnLine(0.5); } - getToken(); - // remove temporary default properties - delete subgraph.node; - delete subgraph.edge; - delete subgraph.graph; - delete subgraph.parent; + ctx.arrow(point.x, point.y, angle, length); + ctx.fill(); + ctx.stroke(); - // register at the parent graph - if (!graph.subgraphs) { - graph.subgraphs = []; + // draw label + if (this.label) { + this._label(ctx, this.label, point.x, point.y); } - graph.subgraphs.push(subgraph); } + else { + // draw circle + var x, y; + var radius = 0.25 * Math.max(100,this.physics.springLength); + var node = this.from; + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width * 0.5; + y = node.y - radius; + } + else { + x = node.x + radius; + y = node.y - node.height * 0.5; + } + this._circle(ctx, x, y, radius); - return subgraph; - } - - /** - * parse an attribute statement like "node [shape=circle fontSize=16]". - * Available keywords are 'node', 'edge', 'graph'. - * The previous list with default attributes will be replaced - * @param {Object} graph - * @returns {String | null} keyword Returns the name of the parsed attribute - * (node, edge, graph), or null if nothing - * is parsed. - */ - function parseAttributeStatement (graph) { - // attribute statements - if (token == 'node') { - getToken(); + // draw all arrows + var angle = 0.2 * Math.PI; + var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; + point = this._pointOnCircle(x, y, radius, 0.5); + ctx.arrow(point.x, point.y, angle, length); + ctx.fill(); + ctx.stroke(); - // node attributes - graph.node = parseAttributeList(); - return 'node'; + // draw label + if (this.label) { + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); + } } - else if (token == 'edge') { - getToken(); + }; - // edge attributes - graph.edge = parseAttributeList(); - return 'edge'; - } - else if (token == 'graph') { - getToken(); + Edge.prototype._pointOnBezier = function(t) { + var via = this._getViaCoordinates(); - // graph attributes - graph.graph = parseAttributeList(); - return 'graph'; - } + var x = Math.pow(1-t,2)*this.from.x + (2*t*(1 - t))*via.x + Math.pow(t,2)*this.to.x; + var y = Math.pow(1-t,2)*this.from.y + (2*t*(1 - t))*via.y + Math.pow(t,2)*this.to.y; - return null; + return {x:x,y:y}; } /** - * parse a node statement - * @param {Object} graph - * @param {String | Number} id + * This function uses binary search to look for the point where the bezier curve crosses the border of the node. + * + * @param from + * @param ctx + * @returns {*} + * @private */ - function parseNodeStatement(graph, id) { - // node statement - var node = { - id: id - }; - var attr = parseAttributeList(); - if (attr) { - node.attr = attr; + Edge.prototype._findBorderPosition = function(from,ctx) { + var maxIterations = 10; + var iteration = 0; + var low = 0; + var high = 1; + var pos,angle,distanceToBorder, distanceToNodes, difference; + var threshold = 0.2; + var node = this.to; + if (from == true) { + node = this.from; } - addNode(graph, node); - - // edge statements - parseEdge(graph, id); - } - /** - * Parse an edge or a series of edges - * @param {Object} graph - * @param {String | Number} from Id of the from node - */ - function parseEdge(graph, from) { - while (token == '->' || token == '--') { - var to; - var type = token; - getToken(); + while (low <= high && iteration < maxIterations) { + var middle = (low + high) * 0.5; - var subgraph = parseSubgraph(graph); - if (subgraph) { - to = subgraph; + pos = this._pointOnBezier(middle); + angle = Math.atan2((node.y - pos.y), (node.x - pos.x)); + distanceToBorder = node.distanceToBorder(ctx,angle); + distanceToNodes = Math.sqrt(Math.pow(pos.x-node.x,2) + Math.pow(pos.y-node.y,2)); + difference = distanceToBorder - distanceToNodes; + if (Math.abs(difference) < threshold) { + break; // found + } + else if (difference < 0) { // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node. + if (from == false) { + low = middle; + } + else { + high = middle; + } } else { - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier or subgraph expected'); + if (from == false) { + high = middle; + } + else { + low = middle; } - to = token; - addNode(graph, { - id: to - }); - getToken(); } - // parse edge attributes - var attr = parseAttributeList(); - - // create edge - var edge = createEdge(graph, from, to, type, attr); - addEdge(graph, edge); - - from = to; + iteration++; } - } + pos.t = middle; + + return pos; + }; /** - * Parse a set with attributes, - * for example [label="1.000", shape=solid] - * @return {Object | null} attr + * Redraw a edge as a line with an arrow + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private */ - function parseAttributeList() { - var attr = null; - - while (token == '[') { - getToken(); - attr = {}; - while (token !== '' && token != ']') { - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Attribute name expected'); - } - var name = token; + Edge.prototype._drawArrow = function(ctx) { + // set style + ctx.strokeStyle = this._getColor(); + ctx.fillStyle = ctx.strokeStyle; + ctx.lineWidth = this._getLineWidth(); - getToken(); - if (token != '=') { - throw newSyntaxError('Equal sign = expected'); - } - getToken(); + // set vars + var angle, length, arrowPos; - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Attribute value expected'); - } - var value = token; - setValue(attr, name, value); // name can be a path + // if not connected to itself + if (this.from != this.to) { + // draw line + this._line(ctx); - getToken(); - if (token ==',') { - getToken(); - } + // draw arrow head + if (this.options.smoothCurves.enabled == true) { + var via = this._getViaCoordinates(); + arrowPos = this._findBorderPosition(false, ctx); + var guidePos = this._pointOnBezier(Math.max(0.0, arrowPos.t - 0.1)) + angle = Math.atan2((arrowPos.y - guidePos.y), (arrowPos.x - guidePos.x)); } + else { + angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var dx = (this.to.x - this.from.x); + var dy = (this.to.y - this.from.y); + var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); + var toBorderDist = this.to.distanceToBorder(ctx, angle); + var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; - if (token != ']') { - throw newSyntaxError('Bracket ] expected'); + arrowPos = {}; + arrowPos.x = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x; + arrowPos.y = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y; } - getToken(); - } - - return attr; - } - - /** - * Create a syntax error with extra information on current token and index. - * @param {String} message - * @returns {SyntaxError} err - */ - function newSyntaxError(message) { - return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ')'); - } - /** - * Chop off text after a maximum length - * @param {String} text - * @param {Number} maxLength - * @returns {String} - */ - function chop (text, maxLength) { - return (text.length <= maxLength) ? text : (text.substr(0, 27) + '...'); - } + // draw arrow at the end of the line + length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; + ctx.arrow(arrowPos.x,arrowPos.y, angle, length); + ctx.fill(); + ctx.stroke(); - /** - * Execute a function fn for each pair of elements in two arrays - * @param {Array | *} array1 - * @param {Array | *} array2 - * @param {function} fn - */ - function forEach2(array1, array2, fn) { - if (Array.isArray(array1)) { - array1.forEach(function (elem1) { - if (Array.isArray(array2)) { - array2.forEach(function (elem2) { - fn(elem1, elem2); - }); + // draw label + if (this.label) { + var point; + if (this.options.smoothCurves.enabled == true && via != null) { + point = this._pointOnBezier(0.5); } else { - fn(elem1, array2); + point = this._pointOnLine(0.5); } - }); + this._label(ctx, this.label, point.x, point.y); + } } else { - if (Array.isArray(array2)) { - array2.forEach(function (elem2) { - fn(array1, elem2); - }); + // draw circle + var node = this.from; + var x, y, arrow; + var radius = 0.25 * Math.max(100,this.physics.springLength); + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width * 0.5; + y = node.y - radius; + arrow = { + x: x, + y: node.y, + angle: 0.9 * Math.PI + }; } else { - fn(array1, array2); + x = node.x + radius; + y = node.y - node.height * 0.5; + arrow = { + x: node.x, + y: y, + angle: 0.6 * Math.PI + }; } - } - } - - /** - * Convert a string containing a graph in DOT language into a map containing - * with nodes and edges in the format of graph. - * @param {String} data Text containing a graph in DOT-notation - * @return {Object} graphData - */ - function DOTToGraph (data) { - // parse the DOT file - var dotData = parseDOT(data); - var graphData = { - nodes: [], - edges: [], - options: {} - }; + ctx.beginPath(); + // TODO: similarly, for a line without arrows, draw to the border of the nodes instead of the center + ctx.arc(x, y, radius, 0, 2 * Math.PI, false); + ctx.stroke(); - // copy the nodes - if (dotData.nodes) { - dotData.nodes.forEach(function (dotNode) { - var graphNode = { - id: dotNode.id, - label: String(dotNode.label || dotNode.id) - }; - merge(graphNode, dotNode.attr); - if (graphNode.image) { - graphNode.shape = 'image'; - } - graphData.nodes.push(graphNode); - }); - } + // draw all arrows + var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; + ctx.arrow(arrow.x, arrow.y, arrow.angle, length); + ctx.fill(); + ctx.stroke(); - // copy the edges - if (dotData.edges) { - /** - * Convert an edge in DOT format to an edge with VisGraph format - * @param {Object} dotEdge - * @returns {Object} graphEdge - */ - var convertEdge = function (dotEdge) { - var graphEdge = { - from: dotEdge.from, - to: dotEdge.to - }; - merge(graphEdge, dotEdge.attr); - graphEdge.style = (dotEdge.type == '->') ? 'arrow' : 'line'; - return graphEdge; + // draw label + if (this.label) { + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); } + } + }; - dotData.edges.forEach(function (dotEdge) { - var from, to; - if (dotEdge.from instanceof Object) { - from = dotEdge.from.nodes; + /** + * Calculate the distance between a point (x3,y3) and a line segment from + * (x1,y1) to (x2,y2). + * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment + * @param {number} x1 + * @param {number} y1 + * @param {number} x2 + * @param {number} y2 + * @param {number} x3 + * @param {number} y3 + * @private + */ + Edge.prototype._getDistanceToEdge = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point + var returnValue = 0; + if (this.from != this.to) { + if (this.options.smoothCurves.enabled == true) { + var xVia, yVia; + if (this.options.smoothCurves.enabled == true && this.options.smoothCurves.dynamic == true) { + xVia = this.via.x; + yVia = this.via.y; } else { - from = { - id: dotEdge.from - } - } - - if (dotEdge.to instanceof Object) { - to = dotEdge.to.nodes; + var via = this._getViaCoordinates(); + xVia = via.x; + yVia = via.y; } - else { - to = { - id: dotEdge.to + var minDistance = 1e9; + var distance; + var i,t,x,y, lastX, lastY; + for (i = 0; i < 10; i++) { + t = 0.1*i; + x = Math.pow(1-t,2)*x1 + (2*t*(1 - t))*xVia + Math.pow(t,2)*x2; + y = Math.pow(1-t,2)*y1 + (2*t*(1 - t))*yVia + Math.pow(t,2)*y2; + if (i > 0) { + distance = this._getDistanceToLine(lastX,lastY,x,y, x3,y3); + minDistance = distance < minDistance ? distance : minDistance; } + lastX = x; lastY = y; } - - if (dotEdge.from instanceof Object && dotEdge.from.edges) { - dotEdge.from.edges.forEach(function (subEdge) { - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - } - - forEach2(from, to, function (from, to) { - var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr); - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - - if (dotEdge.to instanceof Object && dotEdge.to.edges) { - dotEdge.to.edges.forEach(function (subEdge) { - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - } - }); - } - - // copy the options - if (dotData.attr) { - graphData.options = dotData.attr; - } - - return graphData; - } - - // exports - exports.parseDOT = parseDOT; - exports.DOTToGraph = DOTToGraph; - - -/***/ }, -/* 53 */ -/***/ function(module, exports, __webpack_require__) { - - - function parseGephi(gephiJSON, options) { - var edges = []; - var nodes = []; - this.options = { - edges: { - inheritColor: true - }, - nodes: { - allowedToMove: false, - parseColor: false + returnValue = minDistance; + } + else { + returnValue = this._getDistanceToLine(x1,y1,x2,y2,x3,y3); } - }; - - if (options !== undefined) { - this.options.nodes['allowedToMove'] = options.allowedToMove | false; - this.options.nodes['parseColor'] = options.parseColor | false; - this.options.edges['inheritColor'] = options.inheritColor | true; - } - - var gEdges = gephiJSON.edges; - var gNodes = gephiJSON.nodes; - for (var i = 0; i < gEdges.length; i++) { - var edge = {}; - var gEdge = gEdges[i]; - edge['id'] = gEdge.id; - edge['from'] = gEdge.source; - edge['to'] = gEdge.target; - edge['attributes'] = gEdge.attributes; - // edge['value'] = gEdge.attributes !== undefined ? gEdge.attributes.Weight : undefined; - // edge['width'] = edge['value'] !== undefined ? undefined : edgegEdge.size; - edge['color'] = gEdge.color; - edge['inheritColor'] = edge['color'] !== undefined ? false : this.options.inheritColor; - edges.push(edge); } - - for (var i = 0; i < gNodes.length; i++) { - var node = {}; - var gNode = gNodes[i]; - node['id'] = gNode.id; - node['attributes'] = gNode.attributes; - node['x'] = gNode.x; - node['y'] = gNode.y; - node['label'] = gNode.label; - if (this.options.nodes.parseColor == true) { - node['color'] = gNode.color; + else { + var x, y, dx, dy; + var radius = 0.25 * this.physics.springLength; + var node = this.from; + if (node.width > node.height) { + x = node.x + 0.5 * node.width; + y = node.y - radius; } else { - node['color'] = gNode.color !== undefined ? {background:gNode.color, border:gNode.color} : undefined; + x = node.x + radius; + y = node.y - 0.5 * node.height; } - node['radius'] = gNode.size; - node['allowedToMoveX'] = this.options.nodes.allowedToMove; - node['allowedToMoveY'] = this.options.nodes.allowedToMove; - nodes.push(node); + dx = x - x3; + dy = y - y3; + returnValue = Math.abs(Math.sqrt(dx*dx + dy*dy) - radius); } - return {nodes:nodes, edges:edges}; - } + if (this.labelDimensions.left < x3 && + this.labelDimensions.left + this.labelDimensions.width > x3 && + this.labelDimensions.top < y3 && + this.labelDimensions.top + this.labelDimensions.height > y3) { + return 0; + } + else { + return returnValue; + } + }; - exports.parseGephi = parseGephi; + Edge.prototype._getDistanceToLine = function(x1,y1,x2,y2,x3,y3) { + var px = x2-x1, + py = y2-y1, + something = px*px + py*py, + u = ((x3 - x1) * px + (y3 - y1) * py) / something; -/***/ }, -/* 54 */ -/***/ function(module, exports, __webpack_require__) { + if (u > 1) { + u = 1; + } + else if (u < 0) { + u = 0; + } - var util = __webpack_require__(1); + var x = x1 + u * px, + y = y1 + u * py, + dx = x - x3, + dy = y - y3; - /** - * @class Groups - * This class can store groups and properties specific for groups. - */ - function Groups() { - this.clear(); - this.defaultIndex = 0; - } + //# Note: If the actual distance does not matter, + //# if you only want to compare what this function + //# returns to other results of this function, you + //# can just return the squared distance instead + //# (i.e. remove the sqrt) to gain a little performance + return Math.sqrt(dx*dx + dy*dy); + }; /** - * default constants for group colors + * This allows the zoom level of the network to influence the rendering + * + * @param scale */ - Groups.DEFAULT = [ - {border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}, hover: {border: "#2B7CE9", background: "#D2E5FF"}}, // blue - {border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}, hover: {border: "#FFA500", background: "#FFFFA3"}}, // yellow - {border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}, hover: {border: "#FA0A10", background: "#FFAFB1"}}, // red - {border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}, hover: {border: "#41A906", background: "#A1EC76"}}, // green - {border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}, hover: {border: "#E129F0", background: "#F0B3F5"}}, // magenta - {border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}, hover: {border: "#7C29F0", background: "#D3BDF0"}}, // purple - {border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}, hover: {border: "#C37F00", background: "#FFCA66"}}, // orange - {border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}, hover: {border: "#4220FB", background: "#9B9BFD"}}, // darkblue - {border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}, hover: {border: "#FD5A77", background: "#FFD1D9"}}, // pink - {border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}, hover: {border: "#4AD63A", background: "#E6FFE3"}} // mint - ]; + Edge.prototype.setScale = function(scale) { + this.networkScaleInv = 1.0/scale; + }; + + + Edge.prototype.select = function() { + this.selected = true; + }; + + Edge.prototype.unselect = function() { + this.selected = false; + }; + Edge.prototype.positionBezierNode = function() { + if (this.via !== null && this.from !== null && this.to !== null) { + this.via.x = 0.5 * (this.from.x + this.to.x); + this.via.y = 0.5 * (this.from.y + this.to.y); + } + else if (this.via !== null) { + this.via.x = 0; + this.via.y = 0; + } + }; /** - * Clear all groups + * This function draws the control nodes for the manipulator. + * In order to enable this, only set the this.controlNodesEnabled to true. + * @param ctx */ - Groups.prototype.clear = function () { - this.groups = {}; - this.groups.length = function() - { - var i = 0; - for ( var p in this ) { - if (this.hasOwnProperty(p)) { - i++; - } + Edge.prototype._drawControlNodes = function(ctx) { + if (this.controlNodesEnabled == true) { + if (this.controlNodes.from === null && this.controlNodes.to === null) { + var nodeIdFrom = "edgeIdFrom:".concat(this.id); + var nodeIdTo = "edgeIdTo:".concat(this.id); + var constants = { + nodes:{group:'', radius:7, borderWidth:2, borderWidthSelected: 2}, + physics:{damping:0}, + clustering: {maxNodeSizeIncrements: 0 ,nodeScaling: {width:0, height: 0, radius:0}} + }; + this.controlNodes.from = new Node( + {id:nodeIdFrom, + shape:'dot', + color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}} + },{},{},constants); + this.controlNodes.to = new Node( + {id:nodeIdTo, + shape:'dot', + color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}} + },{},{},constants); } - return i; + + this.controlNodes.positions = {}; + if (this.controlNodes.from.selected == false) { + this.controlNodes.positions.from = this.getControlNodeFromPosition(ctx); + this.controlNodes.from.x = this.controlNodes.positions.from.x; + this.controlNodes.from.y = this.controlNodes.positions.from.y; + } + if (this.controlNodes.to.selected == false) { + this.controlNodes.positions.to = this.getControlNodeToPosition(ctx); + this.controlNodes.to.x = this.controlNodes.positions.to.x; + this.controlNodes.to.y = this.controlNodes.positions.to.y; + } + + this.controlNodes.from.draw(ctx); + this.controlNodes.to.draw(ctx); + } + else { + this.controlNodes = {from:null, to:null, positions:{}}; } }; + /** + * Enable control nodes. + * @private + */ + Edge.prototype._enableControlNodes = function() { + this.fromBackup = this.from; + this.toBackup = this.to; + this.controlNodesEnabled = true; + }; /** - * get group properties of a groupname. If groupname is not found, a new group - * is added. - * @param {*} groupname Can be a number, string, Date, etc. - * @return {Object} group The created group, containing all group properties + * disable control nodes and remove from dynamicEdges from old node + * @private */ - Groups.prototype.get = function (groupname) { - var group = this.groups[groupname]; - if (group == undefined) { - // create new group - var index = this.defaultIndex % Groups.DEFAULT.length; - this.defaultIndex++; - group = {}; - group.color = Groups.DEFAULT[index]; - this.groups[groupname] = group; + Edge.prototype._disableControlNodes = function() { + this.fromId = this.from.id; + this.toId = this.to.id; + if (this.fromId != this.fromBackup.id) { // from was changed, remove edge from old 'from' node dynamic edges + this.fromBackup.detachEdge(this); + } + else if (this.toId != this.toBackup.id) { // to was changed, remove edge from old 'to' node dynamic edges + this.toBackup.detachEdge(this); } - return group; + this.fromBackup = null; + this.toBackup = null; + this.controlNodesEnabled = false; }; + /** - * Add a custom group style - * @param {String} groupname - * @param {Object} style An object containing borderColor, - * backgroundColor, etc. - * @return {Object} group The created group object + * This checks if one of the control nodes is selected and if so, returns the control node object. Else it returns null. + * @param x + * @param y + * @returns {null} + * @private */ - Groups.prototype.add = function (groupname, style) { - this.groups[groupname] = style; - return style; - }; - - module.exports = Groups; + Edge.prototype._getSelectedControlNode = function(x,y) { + var positions = this.controlNodes.positions; + var fromDistance = Math.sqrt(Math.pow(x - positions.from.x,2) + Math.pow(y - positions.from.y,2)); + var toDistance = Math.sqrt(Math.pow(x - positions.to.x ,2) + Math.pow(y - positions.to.y ,2)); + if (fromDistance < 15) { + this.connectedNode = this.from; + this.from = this.controlNodes.from; + return this.controlNodes.from; + } + else if (toDistance < 15) { + this.connectedNode = this.to; + this.to = this.controlNodes.to; + return this.controlNodes.to; + } + else { + return null; + } + }; -/***/ }, -/* 55 */ -/***/ function(module, exports, __webpack_require__) { /** - * @class Images - * This class loads images and keeps them stored. + * this resets the control nodes to their original position. + * @private */ - function Images() { - this.images = {}; - this.imageBroken = {}; - this.callback = undefined; - } + Edge.prototype._restoreControlNodes = function() { + if (this.controlNodes.from.selected == true) { + this.from = this.connectedNode; + this.connectedNode = null; + this.controlNodes.from.unselect(); + } + else if (this.controlNodes.to.selected == true) { + this.to = this.connectedNode; + this.connectedNode = null; + this.controlNodes.to.unselect(); + } + }; /** - * Set an onload callback function. This will be called each time an image - * is loaded - * @param {function} callback + * this calculates the position of the control nodes on the edges of the parent nodes. + * + * @param ctx + * @returns {x: *, y: *} */ - Images.prototype.setOnloadCallback = function(callback) { - this.callback = callback; + Edge.prototype.getControlNodeFromPosition = function(ctx) { + // draw arrow head + var controlnodeFromPos; + if (this.options.smoothCurves.enabled == true) { + controlnodeFromPos = this._findBorderPosition(true, ctx); + } + else { + var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var dx = (this.to.x - this.from.x); + var dy = (this.to.y - this.from.y); + var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); + + var fromBorderDist = this.from.distanceToBorder(ctx, angle + Math.PI); + var fromBorderPoint = (edgeSegmentLength - fromBorderDist) / edgeSegmentLength; + controlnodeFromPos = {}; + controlnodeFromPos.x = (fromBorderPoint) * this.from.x + (1 - fromBorderPoint) * this.to.x; + controlnodeFromPos.y = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y; + } + + return controlnodeFromPos; }; /** + * this calculates the position of the control nodes on the edges of the parent nodes. * - * @param {string} url Url of the image - * @param {string} url Url of an image to use if the url image is not found - * @return {Image} img The image object + * @param ctx + * @returns {{from: {x: number, y: number}, to: {x: *, y: *}}} */ - Images.prototype.load = function(url, brokenUrl) { - var img = this.images[url]; // make a pointer - if (img === undefined) { - // create the image - var me = this; - img = new Image(); - img.onload = function () { - // IE11 fix -- thanks dponch! - if (this.width == 0) { - document.body.appendChild(this); - this.width = this.offsetWidth; - this.height = this.offsetHeight; - document.body.removeChild(this); - } - - if (me.callback) { - me.images[url] = img; - me.callback(this); - } - }; - - img.onerror = function () { - if (brokenUrl === undefined) { - console.error("Could not load image:", url); - delete this.src; - if (me.callback) { - me.callback(this); - } - } - else if (me.imageBroken[url] === true) { - console.error("Could not load brokenImage:", brokenUrl); - delete this.src; - if (me.callback) { - me.callback(this); - } - } - else { - this.src = brokenUrl; - me.imageBroken[url] = true; - } - }; + Edge.prototype.getControlNodeToPosition = function(ctx) { + // draw arrow head + var controlnodeFromPos,controlnodeToPos; + if (this.options.smoothCurves.enabled == true) { + controlnodeToPos = this._findBorderPosition(false, ctx); + } + else { + var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var dx = (this.to.x - this.from.x); + var dy = (this.to.y - this.from.y); + var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); + var toBorderDist = this.to.distanceToBorder(ctx, angle); + var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; - img.src = url; + controlnodeToPos = {}; + controlnodeToPos.x = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x; + controlnodeToPos.y = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y; } - return img; + return controlnodeToPos; }; - module.exports = Images; - + module.exports = Edge; /***/ }, -/* 56 */ +/* 53 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); @@ -27600,1506 +27886,1213 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 57 */ +/* 54 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); - var Node = __webpack_require__(56); /** - * @class Edge - * - * A edge connects two nodes - * @param {Object} properties Object with properties. Must contain - * At least properties from and to. - * Available properties: from (number), - * to (number), label (string, color (string), - * width (number), style (string), - * length (number), title (string) - * @param {Network} network A Network object, used to find and edge to - * nodes. - * @param {Object} constants An object with default values for - * example for the color + * @class Groups + * This class can store groups and properties specific for groups. */ - function Edge (properties, network, networkConstants) { - if (!network) { - throw "No network provided"; - } - var fields = ['edges','physics']; - var constants = util.selectiveBridgeObject(fields,networkConstants); - this.options = constants.edges; - this.physics = constants.physics; - this.options['smoothCurves'] = networkConstants['smoothCurves']; - - - this.network = network; - - // initialize variables - this.id = undefined; - this.fromId = undefined; - this.toId = undefined; - this.title = undefined; - this.widthSelected = this.options.width * this.options.widthSelectionMultiplier; - this.value = undefined; - this.selected = false; - this.hover = false; - this.labelDimensions = {top:0,left:0,width:0,height:0,yLine:0}; // could be cached - this.dirtyLabel = true; - - this.from = null; // a node - this.to = null; // a node - this.via = null; // a temp node - - this.fromBackup = null; // used to clean up after reconnect - this.toBackup = null;; // used to clean up after reconnect - - // we use this to be able to reconnect the edge to a cluster if its node is put into a cluster - // by storing the original information we can revert to the original connection when the cluser is opened. - this.originalFromId = []; - this.originalToId = []; - - this.connected = false; - - this.widthFixed = false; - this.lengthFixed = false; - - this.setProperties(properties); - - this.controlNodesEnabled = false; - this.controlNodes = {from:null, to:null, positions:{}}; - this.connectedNode = null; + function Groups() { + this.clear(); + this.defaultIndex = 0; } - /** - * Set or overwrite properties for the edge - * @param {Object} properties an object with properties - * @param {Object} constants and object with default, global properties - */ - Edge.prototype.setProperties = function(properties) { - if (!properties) { - return; - } - - var fields = ['style','fontSize','fontFace','fontColor','fontFill','fontStrokeWidth','fontStrokeColor','width', - 'widthSelectionMultiplier','hoverWidth','arrowScaleFactor','dash','inheritColor','labelAlignment' - ]; - util.selectiveDeepExtend(fields, this.options, properties); - - if (properties.from !== undefined) {this.fromId = properties.from;} - if (properties.to !== undefined) {this.toId = properties.to;} - - if (properties.id !== undefined) {this.id = properties.id;} - if (properties.label !== undefined) {this.label = properties.label; this.dirtyLabel = true;} - - if (properties.title !== undefined) {this.title = properties.title;} - if (properties.value !== undefined) {this.value = properties.value;} - if (properties.length !== undefined) {this.physics.springLength = properties.length;} - - if (properties.color !== undefined) { - this.options.inheritColor = false; - if (util.isString(properties.color)) { - this.options.color.color = properties.color; - this.options.color.highlight = properties.color; - } - else { - if (properties.color.color !== undefined) {this.options.color.color = properties.color.color;} - if (properties.color.highlight !== undefined) {this.options.color.highlight = properties.color.highlight;} - if (properties.color.hover !== undefined) {this.options.color.hover = properties.color.hover;} - } - } - - // A node is connected when it has a from and to node. - this.connect(); - - this.widthFixed = this.widthFixed || (properties.width !== undefined); - this.lengthFixed = this.lengthFixed || (properties.length !== undefined); - - this.widthSelected = this.options.width* this.options.widthSelectionMultiplier; - - // set draw method based on style - switch (this.options.style) { - case 'line': this.draw = this._drawLine; break; - case 'arrow': this.draw = this._drawArrow; break; - case 'arrow-center': this.draw = this._drawArrowCenter; break; - case 'dash-line': this.draw = this._drawDashLine; break; - default: this.draw = this._drawLine; break; - } - - }; /** - * Connect an edge to its nodes + * default constants for group colors */ - Edge.prototype.connect = function () { - this.disconnect(); - - this.from = this.network.nodes[this.fromId] || null; - this.to = this.network.nodes[this.toId] || null; - this.connected = (this.from && this.to); + Groups.DEFAULT = [ + {border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}, hover: {border: "#2B7CE9", background: "#D2E5FF"}}, // blue + {border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}, hover: {border: "#FFA500", background: "#FFFFA3"}}, // yellow + {border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}, hover: {border: "#FA0A10", background: "#FFAFB1"}}, // red + {border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}, hover: {border: "#41A906", background: "#A1EC76"}}, // green + {border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}, hover: {border: "#E129F0", background: "#F0B3F5"}}, // magenta + {border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}, hover: {border: "#7C29F0", background: "#D3BDF0"}}, // purple + {border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}, hover: {border: "#C37F00", background: "#FFCA66"}}, // orange + {border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}, hover: {border: "#4220FB", background: "#9B9BFD"}}, // darkblue + {border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}, hover: {border: "#FD5A77", background: "#FFD1D9"}}, // pink + {border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}, hover: {border: "#4AD63A", background: "#E6FFE3"}} // mint + ]; - if (this.connected) { - this.from.attachEdge(this); - this.to.attachEdge(this); - } - else { - if (this.from) { - this.from.detachEdge(this); - } - if (this.to) { - this.to.detachEdge(this); - } - } - }; /** - * Disconnect an edge from its nodes + * Clear all groups */ - Edge.prototype.disconnect = function () { - if (this.from) { - this.from.detachEdge(this); - this.from = null; - } - if (this.to) { - this.to.detachEdge(this); - this.to = null; - } - - this.connected = false; + Groups.prototype.clear = function () { + this.groups = {}; + this.groups.length = function() + { + var i = 0; + for ( var p in this ) { + if (this.hasOwnProperty(p)) { + i++; + } + } + return i; + } }; + /** - * get the title of this edge. - * @return {string} title The title of the edge, or undefined when no title - * has been set. + * get group properties of a groupname. If groupname is not found, a new group + * is added. + * @param {*} groupname Can be a number, string, Date, etc. + * @return {Object} group The created group, containing all group properties */ - Edge.prototype.getTitle = function() { - return typeof this.title === "function" ? this.title() : this.title; - }; + Groups.prototype.get = function (groupname) { + var group = this.groups[groupname]; + if (group == undefined) { + // create new group + var index = this.defaultIndex % Groups.DEFAULT.length; + this.defaultIndex++; + group = {}; + group.color = Groups.DEFAULT[index]; + this.groups[groupname] = group; + } + return group; + }; /** - * Retrieve the value of the edge. Can be undefined - * @return {Number} value + * Add a custom group style + * @param {String} groupname + * @param {Object} style An object containing borderColor, + * backgroundColor, etc. + * @return {Object} group The created group object */ - Edge.prototype.getValue = function() { - return this.value; + Groups.prototype.add = function (groupname, style) { + this.groups[groupname] = style; + return style; }; + module.exports = Groups; + + +/***/ }, +/* 55 */ +/***/ function(module, exports, __webpack_require__) { + /** - * Adjust the value range of the edge. The edge will adjust it's width - * based on its value. - * @param {Number} min - * @param {Number} max + * @class Images + * This class loads images and keeps them stored. */ - Edge.prototype.setValueRange = function(min, max) { - if (!this.widthFixed && this.value !== undefined) { - var scale = (this.options.widthMax - this.options.widthMin) / (max - min); - this.options.width= (this.value - min) * scale + this.options.widthMin; - this.widthSelected = this.options.width* this.options.widthSelectionMultiplier; - } - }; + function Images() { + this.images = {}; + this.imageBroken = {}; + this.callback = undefined; + } /** - * Redraw a edge - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx + * Set an onload callback function. This will be called each time an image + * is loaded + * @param {function} callback */ - Edge.prototype.draw = function(ctx) { - throw "Method draw not initialized in edge"; + Images.prototype.setOnloadCallback = function(callback) { + this.callback = callback; }; /** - * Check if this object is overlapping with the provided object - * @param {Object} obj an object with parameters left, top - * @return {boolean} True if location is located on the edge + * + * @param {string} url Url of the image + * @param {string} url Url of an image to use if the url image is not found + * @return {Image} img The image object */ - Edge.prototype.isOverlappingWith = function(obj) { - if (this.connected) { - var distMax = 10; - var xFrom = this.from.x; - var yFrom = this.from.y; - var xTo = this.to.x; - var yTo = this.to.y; - var xObj = obj.left; - var yObj = obj.top; - - var dist = this._getDistanceToEdge(xFrom, yFrom, xTo, yTo, xObj, yObj); - - return (dist < distMax); - } - else { - return false - } - }; + Images.prototype.load = function(url, brokenUrl) { + var img = this.images[url]; // make a pointer + if (img === undefined) { + // create the image + var me = this; + img = new Image(); + img.onload = function () { + // IE11 fix -- thanks dponch! + if (this.width == 0) { + document.body.appendChild(this); + this.width = this.offsetWidth; + this.height = this.offsetHeight; + document.body.removeChild(this); + } - Edge.prototype._getColor = function() { - var colorObj = this.options.color; - if (this.options.inheritColor == "to") { - colorObj = { - highlight: this.to.options.color.highlight.border, - hover: this.to.options.color.hover.border, - color: this.to.options.color.border + if (me.callback) { + me.images[url] = img; + me.callback(this); + } }; - } - else if (this.options.inheritColor == "from" || this.options.inheritColor == true) { - colorObj = { - highlight: this.from.options.color.highlight.border, - hover: this.from.options.color.hover.border, - color: this.from.options.color.border + + img.onerror = function () { + if (brokenUrl === undefined) { + console.error("Could not load image:", url); + delete this.src; + if (me.callback) { + me.callback(this); + } + } + else if (me.imageBroken[url] === true) { + console.error("Could not load brokenImage:", brokenUrl); + delete this.src; + if (me.callback) { + me.callback(this); + } + } + else { + this.src = brokenUrl; + me.imageBroken[url] = true; + } }; + + img.src = url; } - if (this.selected == true) {return colorObj.highlight;} - else if (this.hover == true) {return colorObj.hover;} - else {return colorObj.color;} + return img; }; + module.exports = Images; + + +/***/ }, +/* 56 */ +/***/ function(module, exports, __webpack_require__) { /** - * Redraw a edge as a line - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private + * Popup is a class to create a popup window with some text + * @param {Element} container The container object. + * @param {Number} [x] + * @param {Number} [y] + * @param {String} [text] + * @param {Object} [style] An object containing borderColor, + * backgroundColor, etc. */ - Edge.prototype._drawLine = function(ctx) { - // set style - ctx.strokeStyle = this._getColor(); - ctx.lineWidth = this._getLineWidth(); - - if (this.from != this.to) { - // draw line - var via = this._line(ctx); + function Popup(container, x, y, text, style) { + if (container) { + this.container = container; + } + else { + this.container = document.body; + } - // draw label - var point; - if (this.label) { - if (this.options.smoothCurves.enabled == true && via != null) { - var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); - var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); - point = {x:midpointX, y:midpointY}; - } - else { - point = this._pointOnLine(0.5); + // x, y and text are optional, see if a style object was passed in their place + if (style === undefined) { + if (typeof x === "object") { + style = x; + x = undefined; + } else if (typeof text === "object") { + style = text; + text = undefined; + } else { + // for backwards compatibility, in case clients other than Network are creating Popup directly + style = { + fontColor: 'black', + fontSize: 14, // px + fontFace: 'verdana', + color: { + border: '#666', + background: '#FFFFC6' + } } - this._label(ctx, this.label, point.x, point.y); } } - else { - var x, y; - var radius = this.physics.springLength / 4; - var node = this.from; - if (!node.width) { - node.resize(ctx); - } - if (node.width > node.height) { - x = node.x + node.width / 2; - y = node.y - radius; - } - else { - x = node.x + radius; - y = node.y - node.height / 2; - } - this._circle(ctx, x, y, radius); - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); + + this.x = 0; + this.y = 0; + this.padding = 5; + + if (x !== undefined && y !== undefined ) { + this.setPosition(x, y); + } + if (text !== undefined) { + this.setText(text); } + + // create the frame + this.frame = document.createElement("div"); + var styleAttr = this.frame.style; + styleAttr.position = "absolute"; + styleAttr.visibility = "hidden"; + styleAttr.border = "1px solid " + style.color.border; + styleAttr.color = style.fontColor; + styleAttr.fontSize = style.fontSize + "px"; + styleAttr.fontFamily = style.fontFace; + styleAttr.padding = this.padding + "px"; + styleAttr.backgroundColor = style.color.background; + styleAttr.borderRadius = "3px"; + styleAttr.MozBorderRadius = "3px"; + styleAttr.WebkitBorderRadius = "3px"; + styleAttr.boxShadow = "3px 3px 10px rgba(128, 128, 128, 0.5)"; + styleAttr.whiteSpace = "nowrap"; + this.container.appendChild(this.frame); + } + + /** + * @param {number} x Horizontal position of the popup window + * @param {number} y Vertical position of the popup window + */ + Popup.prototype.setPosition = function(x, y) { + this.x = parseInt(x); + this.y = parseInt(y); }; /** - * Get the line width of the edge. Depends on width and whether one of the - * connected nodes is selected. - * @return {Number} width - * @private + * Set the content for the popup window. This can be HTML code or text. + * @param {string | Element} content */ - Edge.prototype._getLineWidth = function() { - if (this.selected == true) { - return Math.max(Math.min(this.widthSelected, this.options.widthMax), 0.3*this.networkScaleInv); + Popup.prototype.setText = function(content) { + if (content instanceof Element) { + this.frame.innerHTML = ''; + this.frame.appendChild(content); } else { - if (this.hover == true) { - return Math.max(Math.min(this.options.hoverWidth, this.options.widthMax), 0.3*this.networkScaleInv); - } - else { - return Math.max(this.options.width, 0.3*this.networkScaleInv); - } + this.frame.innerHTML = content; // string containing text or HTML } }; - Edge.prototype._getViaCoordinates = function () { - if (this.options.smoothCurves.dynamic == true && this.options.smoothCurves.enabled == true ) { - return this.via; - } - else if (this.options.smoothCurves.enabled == false) { - return {x:0,y:0}; + /** + * Show the popup window + * @param {boolean} show Optional. Show or hide the window + */ + Popup.prototype.show = function (show) { + if (show === undefined) { + show = true; } - else { - var xVia = null; - var yVia = null; - var factor = this.options.smoothCurves.roundness; - var type = this.options.smoothCurves.type; - var dx = Math.abs(this.from.x - this.to.x); - var dy = Math.abs(this.from.y - this.to.y); - if (type == 'discrete' || type == 'diagonalCross') { - if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { - if (this.from.y > this.to.y) { - if (this.from.x < this.to.x) { - xVia = this.from.x + factor * dy; - yVia = this.from.y - factor * dy; - } - else if (this.from.x > this.to.x) { - xVia = this.from.x - factor * dy; - yVia = this.from.y - factor * dy; - } - } - else if (this.from.y < this.to.y) { - if (this.from.x < this.to.x) { - xVia = this.from.x + factor * dy; - yVia = this.from.y + factor * dy; - } - else if (this.from.x > this.to.x) { - xVia = this.from.x - factor * dy; - yVia = this.from.y + factor * dy; - } - } - if (type == "discrete") { - xVia = dx < factor * dy ? this.from.x : xVia; - } - } - else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { - if (this.from.y > this.to.y) { - if (this.from.x < this.to.x) { - xVia = this.from.x + factor * dx; - yVia = this.from.y - factor * dx; - } - else if (this.from.x > this.to.x) { - xVia = this.from.x - factor * dx; - yVia = this.from.y - factor * dx; - } - } - else if (this.from.y < this.to.y) { - if (this.from.x < this.to.x) { - xVia = this.from.x + factor * dx; - yVia = this.from.y + factor * dx; - } - else if (this.from.x > this.to.x) { - xVia = this.from.x - factor * dx; - yVia = this.from.y + factor * dx; - } - } - if (type == "discrete") { - yVia = dy < factor * dx ? this.from.y : yVia; - } - } - } - else if (type == "straightCross") { - if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { // up - down - xVia = this.from.x; - if (this.from.y < this.to.y) { - yVia = this.to.y - (1 - factor) * dy; - } - else { - yVia = this.to.y + (1 - factor) * dy; - } - } - else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { // left - right - if (this.from.x < this.to.x) { - xVia = this.to.x - (1 - factor) * dx; - } - else { - xVia = this.to.x + (1 - factor) * dx; - } - yVia = this.from.y; - } - } - else if (type == 'horizontal') { - if (this.from.x < this.to.x) { - xVia = this.to.x - (1 - factor) * dx; - } - else { - xVia = this.to.x + (1 - factor) * dx; - } - yVia = this.from.y; - } - else if (type == 'vertical') { - xVia = this.from.x; - if (this.from.y < this.to.y) { - yVia = this.to.y - (1 - factor) * dy; - } - else { - yVia = this.to.y + (1 - factor) * dy; - } + if (show) { + var height = this.frame.clientHeight; + var width = this.frame.clientWidth; + var maxHeight = this.frame.parentNode.clientHeight; + var maxWidth = this.frame.parentNode.clientWidth; + + var top = (this.y - height); + if (top + height + this.padding > maxHeight) { + top = maxHeight - height - this.padding; } - else { // continuous - if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { - if (this.from.y > this.to.y) { - if (this.from.x < this.to.x) { - // console.log(1) - xVia = this.from.x + factor * dy; - yVia = this.from.y - factor * dy; - xVia = this.to.x < xVia ? this.to.x : xVia; - } - else if (this.from.x > this.to.x) { - // console.log(2) - xVia = this.from.x - factor * dy; - yVia = this.from.y - factor * dy; - xVia = this.to.x > xVia ? this.to.x : xVia; - } - } - else if (this.from.y < this.to.y) { - if (this.from.x < this.to.x) { - // console.log(3) - xVia = this.from.x + factor * dy; - yVia = this.from.y + factor * dy; - xVia = this.to.x < xVia ? this.to.x : xVia; - } - else if (this.from.x > this.to.x) { - // console.log(4, this.from.x, this.to.x) - xVia = this.from.x - factor * dy; - yVia = this.from.y + factor * dy; - xVia = this.to.x > xVia ? this.to.x : xVia; - } - } - } - else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { - if (this.from.y > this.to.y) { - if (this.from.x < this.to.x) { - // console.log(5) - xVia = this.from.x + factor * dx; - yVia = this.from.y - factor * dx; - yVia = this.to.y > yVia ? this.to.y : yVia; - } - else if (this.from.x > this.to.x) { - // console.log(6) - xVia = this.from.x - factor * dx; - yVia = this.from.y - factor * dx; - yVia = this.to.y > yVia ? this.to.y : yVia; - } - } - else if (this.from.y < this.to.y) { - if (this.from.x < this.to.x) { - // console.log(7) - xVia = this.from.x + factor * dx; - yVia = this.from.y + factor * dx; - yVia = this.to.y < yVia ? this.to.y : yVia; - } - else if (this.from.x > this.to.x) { - // console.log(8) - xVia = this.from.x - factor * dx; - yVia = this.from.y + factor * dx; - yVia = this.to.y < yVia ? this.to.y : yVia; - } - } - } + if (top < this.padding) { + top = this.padding; } - - return {x: xVia, y: yVia}; - } - }; - - /** - * Draw a line between two nodes - * @param {CanvasRenderingContext2D} ctx - * @private - */ - Edge.prototype._line = function (ctx) { - // draw a straight line - ctx.beginPath(); - ctx.moveTo(this.from.x, this.from.y); - if (this.options.smoothCurves.enabled == true) { - if (this.options.smoothCurves.dynamic == false) { - var via = this._getViaCoordinates(); - if (via.x == null) { - ctx.lineTo(this.to.x, this.to.y); - ctx.stroke(); - return null; - } - else { - // this.via.x = via.x; - // this.via.y = via.y; - ctx.quadraticCurveTo(via.x,via.y,this.to.x, this.to.y); - ctx.stroke(); - return via; - } + var left = this.x; + if (left + width + this.padding > maxWidth) { + left = maxWidth - width - this.padding; } - else { - ctx.quadraticCurveTo(this.via.x,this.via.y,this.to.x, this.to.y); - ctx.stroke(); - return this.via; + if (left < this.padding) { + left = this.padding; } + + this.frame.style.left = left + "px"; + this.frame.style.top = top + "px"; + this.frame.style.visibility = "visible"; } else { - ctx.lineTo(this.to.x, this.to.y); - ctx.stroke(); - return null; + this.hide(); } }; /** - * Draw a line from a node to itself, a circle - * @param {CanvasRenderingContext2D} ctx - * @param {Number} x - * @param {Number} y - * @param {Number} radius - * @private + * Hide the popup window */ - Edge.prototype._circle = function (ctx, x, y, radius) { - // draw a circle - ctx.beginPath(); - ctx.arc(x, y, radius, 0, 2 * Math.PI, false); - ctx.stroke(); + Popup.prototype.hide = function () { + this.frame.style.visibility = "hidden"; }; - /** - * Draw label with white background and with the middle at (x, y) - * @param {CanvasRenderingContext2D} ctx - * @param {String} text - * @param {Number} x - * @param {Number} y - * @private - */ - Edge.prototype._label = function (ctx, text, x, y) { - if (text) { - ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") + - this.options.fontSize + "px " + this.options.fontFace; - var yLine; + module.exports = Popup; - if (this.dirtyLabel == true) { - var lines = String(text).split('\n'); - var lineCount = lines.length; - var fontSize = Number(this.options.fontSize); - yLine = y + (1 - lineCount) / 2 * fontSize; - var width = ctx.measureText(lines[0]).width; - for (var i = 1; i < lineCount; i++) { - var lineWidth = ctx.measureText(lines[i]).width; - width = lineWidth > width ? lineWidth : width; - } - var height = this.options.fontSize * lineCount; - var left = x - width / 2; - var top = y - height / 2; +/***/ }, +/* 57 */ +/***/ function(module, exports, __webpack_require__) { - // cache - this.labelDimensions = {top:top,left:left,width:width,height:height,yLine:yLine}; - } + /** + * Parse a text source containing data in DOT language into a JSON object. + * The object contains two lists: one with nodes and one with edges. + * + * DOT language reference: http://www.graphviz.org/doc/info/lang.html + * + * @param {String} data Text containing a graph in DOT-notation + * @return {Object} graph An object containing two parameters: + * {Object[]} nodes + * {Object[]} edges + */ + function parseDOT (data) { + dot = data; + return parseGraph(); + } - var yLine = this.labelDimensions.yLine; - - ctx.save(); - - if (this.options.labelAlignment != "horizontal"){ - ctx.translate(x, yLine); - this._rotateForLabelAlignment(ctx); - x = 0; - yLine = 0; - } + // token types enumeration + var TOKENTYPE = { + NULL : 0, + DELIMITER : 1, + IDENTIFIER: 2, + UNKNOWN : 3 + }; - - this._drawLabelRect(ctx); - this._drawLabelText(ctx,x,yLine, lines, lineCount, fontSize); - - ctx.restore(); - } + // map with all delimiters + var DELIMITERS = { + '{': true, + '}': true, + '[': true, + ']': true, + ';': true, + '=': true, + ',': true, + + '->': true, + '--': true }; + var dot = ''; // current dot file + var index = 0; // current index in dot file + var c = ''; // current token character in expr + var token = ''; // current token + var tokenType = TOKENTYPE.NULL; // type of the token + /** - * Rotates the canvas so the text is most readable - * @param {CanvasRenderingContext2D} ctx - * @private + * Get the first character from the dot file. + * The character is stored into the char c. If the end of the dot file is + * reached, the function puts an empty string in c. */ - Edge.prototype._rotateForLabelAlignment = function(ctx) { - var dy = this.from.y - this.to.y; - var dx = this.from.x - this.to.x; - var angleInDegrees = Math.atan2(dy, dx); - - // rotate so label it is readable - if((angleInDegrees < -1 && dx < 0) || (angleInDegrees > 0 && dx < 0)){ - angleInDegrees = angleInDegrees + Math.PI; - } - - ctx.rotate(angleInDegrees); - }; + function first() { + index = 0; + c = dot.charAt(0); + } /** - * Draws the label rectangle - * @param {CanvasRenderingContext2D} ctx - * @param {String} labelAlignment - * @private + * Get the next character from the dot file. + * The character is stored into the char c. If the end of the dot file is + * reached, the function puts an empty string in c. */ - Edge.prototype._drawLabelRect = function(ctx) { - if (this.options.fontFill !== undefined && this.options.fontFill !== null && this.options.fontFill !== "none") { - ctx.fillStyle = this.options.fontFill; - - var lineMargin = 2; + function next() { + index++; + c = dot.charAt(index); + } - if (this.options.labelAlignment == 'line-center') { - ctx.fillRect(-this.labelDimensions.width * 0.5, -this.labelDimensions.height * 0.5, this.labelDimensions.width, this.labelDimensions.height); - } - else if (this.options.labelAlignment == 'line-above') { - ctx.fillRect(-this.labelDimensions.width * 0.5, -(this.labelDimensions.height + lineMargin), this.labelDimensions.width, this.labelDimensions.height); - } - else if (this.options.labelAlignment == 'line-below') { - ctx.fillRect(-this.labelDimensions.width * 0.5, lineMargin, this.labelDimensions.width, this.labelDimensions.height); - } - else { - ctx.fillRect(this.labelDimensions.left, this.labelDimensions.top, this.labelDimensions.width, this.labelDimensions.height); - } - } - }; + /** + * Preview the next character from the dot file. + * @return {String} cNext + */ + function nextPreview() { + return dot.charAt(index + 1); + } /** - * Draws the label text - * @param {CanvasRenderingContext2D} ctx - * @param {Number} x - * @param {Number} yLine - * @param {Array} lines - * @param {Number} lineCount - * @param {Number} fontSize - * @private + * Test whether given character is alphabetic or numeric + * @param {String} c + * @return {Boolean} isAlphaNumeric */ - Edge.prototype._drawLabelText = function(ctx, x, yLine, lines, lineCount, fontSize) { - // draw text - ctx.fillStyle = this.options.fontColor || "black"; - ctx.textAlign = "center"; + var regexAlphaNumeric = /[a-zA-Z_0-9.:#]/; + function isAlphaNumeric(c) { + return regexAlphaNumeric.test(c); + } - // check for label alignment - if (this.options.labelAlignment != 'horizontal') { - var lineMargin = 2; - if (this.options.labelAlignment == 'line-above') { - ctx.textBaseline = "alphabetic"; - yLine -= 2 * lineMargin; // distance from edge, required because we use alphabetic. Alphabetic has less difference between browsers - } - else if (this.options.labelAlignment == 'line-below') { - ctx.textBaseline = "hanging"; - yLine += 2 * lineMargin;// distance from edge, required because we use hanging. Hanging has less difference between browsers - } - else { - ctx.textBaseline = "middle"; - } - } - else { - ctx.textBaseline = "middle"; + /** + * Merge all properties of object b into object b + * @param {Object} a + * @param {Object} b + * @return {Object} a + */ + function merge (a, b) { + if (!a) { + a = {}; } - // check for strokeWidth - if (this.options.fontStrokeWidth > 0){ - ctx.lineWidth = this.options.fontStrokeWidth; - ctx.strokeStyle = this.options.fontStrokeColor; - ctx.lineJoin = 'round'; - } - for (var i = 0; i < lineCount; i++) { - if(this.options.fontStrokeWidth > 0){ - ctx.strokeText(lines[i], x, yLine); + if (b) { + for (var name in b) { + if (b.hasOwnProperty(name)) { + a[name] = b[name]; + } } - ctx.fillText(lines[i], x, yLine); - yLine += fontSize; - } - }; + } + return a; + } /** - * Redraw a edge as a dashed line - * Draw this edge in the given canvas - * @author David Jordan - * @date 2012-08-08 - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private + * Set a value in an object, where the provided parameter name can be a + * path with nested parameters. For example: + * + * var obj = {a: 2}; + * setValue(obj, 'b.c', 3); // obj = {a: 2, b: {c: 3}} + * + * @param {Object} obj + * @param {String} path A parameter name or dot-separated parameter path, + * like "color.highlight.border". + * @param {*} value */ - Edge.prototype._drawDashLine = function(ctx) { - // set style - ctx.strokeStyle = this._getColor(); - ctx.lineWidth = this._getLineWidth(); - - var via = null; - // only firefox and chrome support this method, else we use the legacy one. - if (ctx.setLineDash !== undefined) { - ctx.save(); - // configure the dash pattern - var pattern = [0]; - if (this.options.dash.length !== undefined && this.options.dash.gap !== undefined) { - pattern = [this.options.dash.length,this.options.dash.gap]; + function setValue(obj, path, value) { + var keys = path.split('.'); + var o = obj; + while (keys.length) { + var key = keys.shift(); + if (keys.length) { + // this isn't the end point + if (!o[key]) { + o[key] = {}; + } + o = o[key]; } else { - pattern = [5,5]; + // this is the end point + o[key] = value; } + } + } - // set dash settings for chrome or firefox - ctx.setLineDash(pattern); - ctx.lineDashOffset = 0; - - // draw the line - via = this._line(ctx); + /** + * Add a node to a graph object. If there is already a node with + * the same id, their attributes will be merged. + * @param {Object} graph + * @param {Object} node + */ + function addNode(graph, node) { + var i, len; + var current = null; - // restore the dash settings. - ctx.setLineDash([0]); - ctx.lineDashOffset = 0; - ctx.restore(); + // find root graph (in case of subgraph) + var graphs = [graph]; // list with all graphs from current graph to root graph + var root = graph; + while (root.parent) { + graphs.push(root.parent); + root = root.parent; } - else { // unsupporting smooth lines - // draw dashed line - ctx.beginPath(); - ctx.lineCap = 'round'; - if (this.options.dash.altLength !== undefined) //If an alt dash value has been set add to the array this value - { - ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, - [this.options.dash.length,this.options.dash.gap,this.options.dash.altLength,this.options.dash.gap]); - } - else if (this.options.dash.length !== undefined && this.options.dash.gap !== undefined) //If a dash and gap value has been set add to the array this value - { - ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, - [this.options.dash.length,this.options.dash.gap]); + + // find existing node (at root level) by its id + if (root.nodes) { + for (i = 0, len = root.nodes.length; i < len; i++) { + if (node.id === root.nodes[i].id) { + current = root.nodes[i]; + break; + } } - else //If all else fails draw a line - { - ctx.moveTo(this.from.x, this.from.y); - ctx.lineTo(this.to.x, this.to.y); + } + + if (!current) { + // this is a new node + current = { + id: node.id + }; + if (graph.node) { + // clone default attributes + current.attr = merge(current.attr, graph.node); } - ctx.stroke(); } - // draw label - if (this.label) { - var point; - if (this.options.smoothCurves.enabled == true && via != null) { - var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); - var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); - point = {x:midpointX, y:midpointY}; + // add node to this (sub)graph and all its parent graphs + for (i = graphs.length - 1; i >= 0; i--) { + var g = graphs[i]; + + if (!g.nodes) { + g.nodes = []; } - else { - point = this._pointOnLine(0.5); + if (g.nodes.indexOf(current) == -1) { + g.nodes.push(current); } - this._label(ctx, this.label, point.x, point.y); } - }; - /** - * Get a point on a line - * @param {Number} percentage. Value between 0 (line start) and 1 (line end) - * @return {Object} point - * @private - */ - Edge.prototype._pointOnLine = function (percentage) { - return { - x: (1 - percentage) * this.from.x + percentage * this.to.x, - y: (1 - percentage) * this.from.y + percentage * this.to.y + // merge attributes + if (node.attr) { + current.attr = merge(current.attr, node.attr); } - }; + } /** - * Get a point on a circle - * @param {Number} x - * @param {Number} y - * @param {Number} radius - * @param {Number} percentage. Value between 0 (line start) and 1 (line end) - * @return {Object} point - * @private + * Add an edge to a graph object + * @param {Object} graph + * @param {Object} edge */ - Edge.prototype._pointOnCircle = function (x, y, radius, percentage) { - var angle = (percentage - 3/8) * 2 * Math.PI; - return { - x: x + radius * Math.cos(angle), - y: y - radius * Math.sin(angle) + function addEdge(graph, edge) { + if (!graph.edges) { + graph.edges = []; } - }; + graph.edges.push(edge); + if (graph.edge) { + var attr = merge({}, graph.edge); // clone default attributes + edge.attr = merge(attr, edge.attr); // merge attributes + } + } /** - * Redraw a edge as a line with an arrow halfway the line - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private + * Create an edge to a graph object + * @param {Object} graph + * @param {String | Number | Object} from + * @param {String | Number | Object} to + * @param {String} type + * @param {Object | null} attr + * @return {Object} edge */ - Edge.prototype._drawArrowCenter = function(ctx) { - var point; - // set style - ctx.strokeStyle = this._getColor(); - ctx.fillStyle = ctx.strokeStyle; - ctx.lineWidth = this._getLineWidth(); - - if (this.from != this.to) { - // draw line - var via = this._line(ctx); - - var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; - // draw an arrow halfway the line - if (this.options.smoothCurves.enabled == true && via != null) { - var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); - var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); - point = {x:midpointX, y:midpointY}; - } - else { - point = this._pointOnLine(0.5); - } - - ctx.arrow(point.x, point.y, angle, length); - ctx.fill(); - ctx.stroke(); - - // draw label - if (this.label) { - this._label(ctx, this.label, point.x, point.y); - } - } - else { - // draw circle - var x, y; - var radius = 0.25 * Math.max(100,this.physics.springLength); - var node = this.from; - if (!node.width) { - node.resize(ctx); - } - if (node.width > node.height) { - x = node.x + node.width * 0.5; - y = node.y - radius; - } - else { - x = node.x + radius; - y = node.y - node.height * 0.5; - } - this._circle(ctx, x, y, radius); - - // draw all arrows - var angle = 0.2 * Math.PI; - var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; - point = this._pointOnCircle(x, y, radius, 0.5); - ctx.arrow(point.x, point.y, angle, length); - ctx.fill(); - ctx.stroke(); + function createEdge(graph, from, to, type, attr) { + var edge = { + from: from, + to: to, + type: type + }; - // draw label - if (this.label) { - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); - } + if (graph.edge) { + edge.attr = merge({}, graph.edge); // clone default attributes } - }; - - Edge.prototype._pointOnBezier = function(t) { - var via = this._getViaCoordinates(); - - var x = Math.pow(1-t,2)*this.from.x + (2*t*(1 - t))*via.x + Math.pow(t,2)*this.to.x; - var y = Math.pow(1-t,2)*this.from.y + (2*t*(1 - t))*via.y + Math.pow(t,2)*this.to.y; + edge.attr = merge(edge.attr || {}, attr); // merge attributes - return {x:x,y:y}; + return edge; } /** - * This function uses binary search to look for the point where the bezier curve crosses the border of the node. - * - * @param from - * @param ctx - * @returns {*} - * @private + * Get next token in the current dot file. + * The token and token type are available as token and tokenType */ - Edge.prototype._findBorderPosition = function(from,ctx) { - var maxIterations = 10; - var iteration = 0; - var low = 0; - var high = 1; - var pos,angle,distanceToBorder, distanceToNodes, difference; - var threshold = 0.2; - var node = this.to; - if (from == true) { - node = this.from; + function getToken() { + tokenType = TOKENTYPE.NULL; + token = ''; + + // skip over whitespaces + while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter + next(); } - while (low <= high && iteration < maxIterations) { - var middle = (low + high) * 0.5; + do { + var isComment = false; - pos = this._pointOnBezier(middle); - angle = Math.atan2((node.y - pos.y), (node.x - pos.x)); - distanceToBorder = node.distanceToBorder(ctx,angle); - distanceToNodes = Math.sqrt(Math.pow(pos.x-node.x,2) + Math.pow(pos.y-node.y,2)); - difference = distanceToBorder - distanceToNodes; - if (Math.abs(difference) < threshold) { - break; // found - } - else if (difference < 0) { // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node. - if (from == false) { - low = middle; + // skip comment + if (c == '#') { + // find the previous non-space character + var i = index - 1; + while (dot.charAt(i) == ' ' || dot.charAt(i) == '\t') { + i--; } - else { - high = middle; + if (dot.charAt(i) == '\n' || dot.charAt(i) == '') { + // the # is at the start of a line, this is indeed a line comment + while (c != '' && c != '\n') { + next(); + } + isComment = true; } } - else { - if (from == false) { - high = middle; + if (c == '/' && nextPreview() == '/') { + // skip line comment + while (c != '' && c != '\n') { + next(); } - else { - low = middle; + isComment = true; + } + if (c == '/' && nextPreview() == '*') { + // skip block comment + while (c != '') { + if (c == '*' && nextPreview() == '/') { + // end of block comment found. skip these last two characters + next(); + next(); + break; + } + else { + next(); + } } + isComment = true; } - iteration++; + // skip over whitespaces + while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter + next(); + } } - pos.t = middle; + while (isComment); - return pos; - }; + // check for end of dot file + if (c == '') { + // token is still empty + tokenType = TOKENTYPE.DELIMITER; + return; + } - /** - * Redraw a edge as a line with an arrow - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ - Edge.prototype._drawArrow = function(ctx) { - // set style - ctx.strokeStyle = this._getColor(); - ctx.fillStyle = ctx.strokeStyle; - ctx.lineWidth = this._getLineWidth(); + // check for delimiters consisting of 2 characters + var c2 = c + nextPreview(); + if (DELIMITERS[c2]) { + tokenType = TOKENTYPE.DELIMITER; + token = c2; + next(); + next(); + return; + } - // set vars - var angle, length, arrowPos; + // check for delimiters consisting of 1 character + if (DELIMITERS[c]) { + tokenType = TOKENTYPE.DELIMITER; + token = c; + next(); + return; + } - // if not connected to itself - if (this.from != this.to) { - // draw line - this._line(ctx); + // check for an identifier (number or string) + // TODO: more precise parsing of numbers/strings (and the port separator ':') + if (isAlphaNumeric(c) || c == '-') { + token += c; + next(); - // draw arrow head - if (this.options.smoothCurves.enabled == true) { - var via = this._getViaCoordinates(); - arrowPos = this._findBorderPosition(false, ctx); - var guidePos = this._pointOnBezier(Math.max(0.0, arrowPos.t - 0.1)) - angle = Math.atan2((arrowPos.y - guidePos.y), (arrowPos.x - guidePos.x)); + while (isAlphaNumeric(c)) { + token += c; + next(); } - else { - angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var dx = (this.to.x - this.from.x); - var dy = (this.to.y - this.from.y); - var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); - var toBorderDist = this.to.distanceToBorder(ctx, angle); - var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; - - arrowPos = {}; - arrowPos.x = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x; - arrowPos.y = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y; + if (token == 'false') { + token = false; // convert to boolean } - - // draw arrow at the end of the line - length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; - ctx.arrow(arrowPos.x,arrowPos.y, angle, length); - ctx.fill(); - ctx.stroke(); - - // draw label - if (this.label) { - var point; - if (this.options.smoothCurves.enabled == true && via != null) { - point = this._pointOnBezier(0.5); - } - else { - point = this._pointOnLine(0.5); - } - this._label(ctx, this.label, point.x, point.y); + else if (token == 'true') { + token = true; // convert to boolean } - } - else { - // draw circle - var node = this.from; - var x, y, arrow; - var radius = 0.25 * Math.max(100,this.physics.springLength); - if (!node.width) { - node.resize(ctx); + else if (!isNaN(Number(token))) { + token = Number(token); // convert to number } - if (node.width > node.height) { - x = node.x + node.width * 0.5; - y = node.y - radius; - arrow = { - x: x, - y: node.y, - angle: 0.9 * Math.PI - }; + tokenType = TOKENTYPE.IDENTIFIER; + return; + } + + // check for a string enclosed by double quotes + if (c == '"') { + next(); + while (c != '' && (c != '"' || (c == '"' && nextPreview() == '"'))) { + token += c; + if (c == '"') { // skip the escape character + next(); + } + next(); } - else { - x = node.x + radius; - y = node.y - node.height * 0.5; - arrow = { - x: node.x, - y: y, - angle: 0.6 * Math.PI - }; + if (c != '"') { + throw newSyntaxError('End of string " expected'); } - ctx.beginPath(); - // TODO: similarly, for a line without arrows, draw to the border of the nodes instead of the center - ctx.arc(x, y, radius, 0, 2 * Math.PI, false); - ctx.stroke(); - - // draw all arrows - var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; - ctx.arrow(arrow.x, arrow.y, arrow.angle, length); - ctx.fill(); - ctx.stroke(); + next(); + tokenType = TOKENTYPE.IDENTIFIER; + return; + } - // draw label - if (this.label) { - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); - } + // something unknown is found, wrong characters, a syntax error + tokenType = TOKENTYPE.UNKNOWN; + while (c != '') { + token += c; + next(); } - }; + throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"'); + } /** - * Calculate the distance between a point (x3,y3) and a line segment from - * (x1,y1) to (x2,y2). - * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment - * @param {number} x1 - * @param {number} y1 - * @param {number} x2 - * @param {number} y2 - * @param {number} x3 - * @param {number} y3 - * @private + * Parse a graph. + * @returns {Object} graph */ - Edge.prototype._getDistanceToEdge = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point - var returnValue = 0; - if (this.from != this.to) { - if (this.options.smoothCurves.enabled == true) { - var xVia, yVia; - if (this.options.smoothCurves.enabled == true && this.options.smoothCurves.dynamic == true) { - xVia = this.via.x; - yVia = this.via.y; - } - else { - var via = this._getViaCoordinates(); - xVia = via.x; - yVia = via.y; - } - var minDistance = 1e9; - var distance; - var i,t,x,y, lastX, lastY; - for (i = 0; i < 10; i++) { - t = 0.1*i; - x = Math.pow(1-t,2)*x1 + (2*t*(1 - t))*xVia + Math.pow(t,2)*x2; - y = Math.pow(1-t,2)*y1 + (2*t*(1 - t))*yVia + Math.pow(t,2)*y2; - if (i > 0) { - distance = this._getDistanceToLine(lastX,lastY,x,y, x3,y3); - minDistance = distance < minDistance ? distance : minDistance; - } - lastX = x; lastY = y; - } - returnValue = minDistance; - } - else { - returnValue = this._getDistanceToLine(x1,y1,x2,y2,x3,y3); - } + function parseGraph() { + var graph = {}; + + first(); + getToken(); + + // optional strict keyword + if (token == 'strict') { + graph.strict = true; + getToken(); } - else { - var x, y, dx, dy; - var radius = 0.25 * this.physics.springLength; - var node = this.from; - if (node.width > node.height) { - x = node.x + 0.5 * node.width; - y = node.y - radius; - } - else { - x = node.x + radius; - y = node.y - 0.5 * node.height; - } - dx = x - x3; - dy = y - y3; - returnValue = Math.abs(Math.sqrt(dx*dx + dy*dy) - radius); + + // graph or digraph keyword + if (token == 'graph' || token == 'digraph') { + graph.type = token; + getToken(); } - if (this.labelDimensions.left < x3 && - this.labelDimensions.left + this.labelDimensions.width > x3 && - this.labelDimensions.top < y3 && - this.labelDimensions.top + this.labelDimensions.height > y3) { - return 0; + // optional graph id + if (tokenType == TOKENTYPE.IDENTIFIER) { + graph.id = token; + getToken(); } - else { - return returnValue; + + // open angle bracket + if (token != '{') { + throw newSyntaxError('Angle bracket { expected'); } - }; + getToken(); - Edge.prototype._getDistanceToLine = function(x1,y1,x2,y2,x3,y3) { - var px = x2-x1, - py = y2-y1, - something = px*px + py*py, - u = ((x3 - x1) * px + (y3 - y1) * py) / something; + // statements + parseStatements(graph); - if (u > 1) { - u = 1; + // close angle bracket + if (token != '}') { + throw newSyntaxError('Angle bracket } expected'); } - else if (u < 0) { - u = 0; + getToken(); + + // end of file + if (token !== '') { + throw newSyntaxError('End of file expected'); } + getToken(); - var x = x1 + u * px, - y = y1 + u * py, - dx = x - x3, - dy = y - y3; + // remove temporary default properties + delete graph.node; + delete graph.edge; + delete graph.graph; - //# Note: If the actual distance does not matter, - //# if you only want to compare what this function - //# returns to other results of this function, you - //# can just return the squared distance instead - //# (i.e. remove the sqrt) to gain a little performance + return graph; + } - return Math.sqrt(dx*dx + dy*dy); - }; + /** + * Parse a list with statements. + * @param {Object} graph + */ + function parseStatements (graph) { + while (token !== '' && token != '}') { + parseStatement(graph); + if (token == ';') { + getToken(); + } + } + } /** - * This allows the zoom level of the network to influence the rendering - * - * @param scale + * Parse a single statement. Can be a an attribute statement, node + * statement, a series of node statements and edge statements, or a + * parameter. + * @param {Object} graph */ - Edge.prototype.setScale = function(scale) { - this.networkScaleInv = 1.0/scale; - }; + function parseStatement(graph) { + // parse subgraph + var subgraph = parseSubgraph(graph); + if (subgraph) { + // edge statements + parseEdge(graph, subgraph); + return; + } - Edge.prototype.select = function() { - this.selected = true; - }; + // parse an attribute statement + var attr = parseAttributeStatement(graph); + if (attr) { + return; + } - Edge.prototype.unselect = function() { - this.selected = false; - }; + // parse node + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier expected'); + } + var id = token; // id can be a string or a number + getToken(); - Edge.prototype.positionBezierNode = function() { - if (this.via !== null && this.from !== null && this.to !== null) { - this.via.x = 0.5 * (this.from.x + this.to.x); - this.via.y = 0.5 * (this.from.y + this.to.y); + if (token == '=') { + // id statement + getToken(); + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier expected'); + } + graph[id] = token; + getToken(); + // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] " } - else if (this.via !== null) { - this.via.x = 0; - this.via.y = 0; + else { + parseNodeStatement(graph, id); } - }; + } /** - * This function draws the control nodes for the manipulator. - * In order to enable this, only set the this.controlNodesEnabled to true. - * @param ctx + * Parse a subgraph + * @param {Object} graph parent graph object + * @return {Object | null} subgraph */ - Edge.prototype._drawControlNodes = function(ctx) { - if (this.controlNodesEnabled == true) { - if (this.controlNodes.from === null && this.controlNodes.to === null) { - var nodeIdFrom = "edgeIdFrom:".concat(this.id); - var nodeIdTo = "edgeIdTo:".concat(this.id); - var constants = { - nodes:{group:'', radius:7, borderWidth:2, borderWidthSelected: 2}, - physics:{damping:0}, - clustering: {maxNodeSizeIncrements: 0 ,nodeScaling: {width:0, height: 0, radius:0}} - }; - this.controlNodes.from = new Node( - {id:nodeIdFrom, - shape:'dot', - color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}} - },{},{},constants); - this.controlNodes.to = new Node( - {id:nodeIdTo, - shape:'dot', - color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}} - },{},{},constants); - } + function parseSubgraph (graph) { + var subgraph = null; - this.controlNodes.positions = {}; - if (this.controlNodes.from.selected == false) { - this.controlNodes.positions.from = this.getControlNodeFromPosition(ctx); - this.controlNodes.from.x = this.controlNodes.positions.from.x; - this.controlNodes.from.y = this.controlNodes.positions.from.y; + // optional subgraph keyword + if (token == 'subgraph') { + subgraph = {}; + subgraph.type = 'subgraph'; + getToken(); + + // optional graph id + if (tokenType == TOKENTYPE.IDENTIFIER) { + subgraph.id = token; + getToken(); } - if (this.controlNodes.to.selected == false) { - this.controlNodes.positions.to = this.getControlNodeToPosition(ctx); - this.controlNodes.to.x = this.controlNodes.positions.to.x; - this.controlNodes.to.y = this.controlNodes.positions.to.y; + } + + // open angle bracket + if (token == '{') { + getToken(); + + if (!subgraph) { + subgraph = {}; } + subgraph.parent = graph; + subgraph.node = graph.node; + subgraph.edge = graph.edge; + subgraph.graph = graph.graph; - this.controlNodes.from.draw(ctx); - this.controlNodes.to.draw(ctx); - } - else { - this.controlNodes = {from:null, to:null, positions:{}}; - } - }; + // statements + parseStatements(subgraph); - /** - * Enable control nodes. - * @private - */ - Edge.prototype._enableControlNodes = function() { - this.fromBackup = this.from; - this.toBackup = this.to; - this.controlNodesEnabled = true; - }; + // close angle bracket + if (token != '}') { + throw newSyntaxError('Angle bracket } expected'); + } + getToken(); - /** - * disable control nodes and remove from dynamicEdges from old node - * @private - */ - Edge.prototype._disableControlNodes = function() { - this.fromId = this.from.id; - this.toId = this.to.id; - if (this.fromId != this.fromBackup.id) { // from was changed, remove edge from old 'from' node dynamic edges - this.fromBackup.detachEdge(this); - } - else if (this.toId != this.toBackup.id) { // to was changed, remove edge from old 'to' node dynamic edges - this.toBackup.detachEdge(this); - } + // remove temporary default properties + delete subgraph.node; + delete subgraph.edge; + delete subgraph.graph; + delete subgraph.parent; - this.fromBackup = null; - this.toBackup = null; - this.controlNodesEnabled = false; - }; + // register at the parent graph + if (!graph.subgraphs) { + graph.subgraphs = []; + } + graph.subgraphs.push(subgraph); + } + return subgraph; + } /** - * This checks if one of the control nodes is selected and if so, returns the control node object. Else it returns null. - * @param x - * @param y - * @returns {null} - * @private + * parse an attribute statement like "node [shape=circle fontSize=16]". + * Available keywords are 'node', 'edge', 'graph'. + * The previous list with default attributes will be replaced + * @param {Object} graph + * @returns {String | null} keyword Returns the name of the parsed attribute + * (node, edge, graph), or null if nothing + * is parsed. */ - Edge.prototype._getSelectedControlNode = function(x,y) { - var positions = this.controlNodes.positions; - var fromDistance = Math.sqrt(Math.pow(x - positions.from.x,2) + Math.pow(y - positions.from.y,2)); - var toDistance = Math.sqrt(Math.pow(x - positions.to.x ,2) + Math.pow(y - positions.to.y ,2)); + function parseAttributeStatement (graph) { + // attribute statements + if (token == 'node') { + getToken(); - if (fromDistance < 15) { - this.connectedNode = this.from; - this.from = this.controlNodes.from; - return this.controlNodes.from; + // node attributes + graph.node = parseAttributeList(); + return 'node'; } - else if (toDistance < 15) { - this.connectedNode = this.to; - this.to = this.controlNodes.to; - return this.controlNodes.to; + else if (token == 'edge') { + getToken(); + + // edge attributes + graph.edge = parseAttributeList(); + return 'edge'; } - else { - return null; + else if (token == 'graph') { + getToken(); + + // graph attributes + graph.graph = parseAttributeList(); + return 'graph'; } - }; + return null; + } /** - * this resets the control nodes to their original position. - * @private + * parse a node statement + * @param {Object} graph + * @param {String | Number} id */ - Edge.prototype._restoreControlNodes = function() { - if (this.controlNodes.from.selected == true) { - this.from = this.connectedNode; - this.connectedNode = null; - this.controlNodes.from.unselect(); - } - else if (this.controlNodes.to.selected == true) { - this.to = this.connectedNode; - this.connectedNode = null; - this.controlNodes.to.unselect(); + function parseNodeStatement(graph, id) { + // node statement + var node = { + id: id + }; + var attr = parseAttributeList(); + if (attr) { + node.attr = attr; } - }; + addNode(graph, node); + + // edge statements + parseEdge(graph, id); + } /** - * this calculates the position of the control nodes on the edges of the parent nodes. - * - * @param ctx - * @returns {x: *, y: *} + * Parse an edge or a series of edges + * @param {Object} graph + * @param {String | Number} from Id of the from node */ - Edge.prototype.getControlNodeFromPosition = function(ctx) { - // draw arrow head - var controlnodeFromPos; - if (this.options.smoothCurves.enabled == true) { - controlnodeFromPos = this._findBorderPosition(true, ctx); - } - else { - var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var dx = (this.to.x - this.from.x); - var dy = (this.to.y - this.from.y); - var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); + function parseEdge(graph, from) { + while (token == '->' || token == '--') { + var to; + var type = token; + getToken(); - var fromBorderDist = this.from.distanceToBorder(ctx, angle + Math.PI); - var fromBorderPoint = (edgeSegmentLength - fromBorderDist) / edgeSegmentLength; - controlnodeFromPos = {}; - controlnodeFromPos.x = (fromBorderPoint) * this.from.x + (1 - fromBorderPoint) * this.to.x; - controlnodeFromPos.y = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y; - } + var subgraph = parseSubgraph(graph); + if (subgraph) { + to = subgraph; + } + else { + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier or subgraph expected'); + } + to = token; + addNode(graph, { + id: to + }); + getToken(); + } - return controlnodeFromPos; - }; + // parse edge attributes + var attr = parseAttributeList(); - /** - * this calculates the position of the control nodes on the edges of the parent nodes. - * - * @param ctx - * @returns {{from: {x: number, y: number}, to: {x: *, y: *}}} - */ - Edge.prototype.getControlNodeToPosition = function(ctx) { - // draw arrow head - var controlnodeFromPos,controlnodeToPos; - if (this.options.smoothCurves.enabled == true) { - controlnodeToPos = this._findBorderPosition(false, ctx); - } - else { - var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var dx = (this.to.x - this.from.x); - var dy = (this.to.y - this.from.y); - var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); - var toBorderDist = this.to.distanceToBorder(ctx, angle); - var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; + // create edge + var edge = createEdge(graph, from, to, type, attr); + addEdge(graph, edge); - controlnodeToPos = {}; - controlnodeToPos.x = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x; - controlnodeToPos.y = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y; + from = to; } + } - return controlnodeToPos; - }; + /** + * Parse a set with attributes, + * for example [label="1.000", shape=solid] + * @return {Object | null} attr + */ + function parseAttributeList() { + var attr = null; - module.exports = Edge; + while (token == '[') { + getToken(); + attr = {}; + while (token !== '' && token != ']') { + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Attribute name expected'); + } + var name = token; -/***/ }, -/* 58 */ -/***/ function(module, exports, __webpack_require__) { + getToken(); + if (token != '=') { + throw newSyntaxError('Equal sign = expected'); + } + getToken(); - /** - * Popup is a class to create a popup window with some text - * @param {Element} container The container object. - * @param {Number} [x] - * @param {Number} [y] - * @param {String} [text] - * @param {Object} [style] An object containing borderColor, - * backgroundColor, etc. - */ - function Popup(container, x, y, text, style) { - if (container) { - this.container = container; - } - else { - this.container = document.body; - } + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Attribute value expected'); + } + var value = token; + setValue(attr, name, value); // name can be a path - // x, y and text are optional, see if a style object was passed in their place - if (style === undefined) { - if (typeof x === "object") { - style = x; - x = undefined; - } else if (typeof text === "object") { - style = text; - text = undefined; - } else { - // for backwards compatibility, in case clients other than Network are creating Popup directly - style = { - fontColor: 'black', - fontSize: 14, // px - fontFace: 'verdana', - color: { - border: '#666', - background: '#FFFFC6' - } + getToken(); + if (token ==',') { + getToken(); } } - } - - this.x = 0; - this.y = 0; - this.padding = 5; - if (x !== undefined && y !== undefined ) { - this.setPosition(x, y); - } - if (text !== undefined) { - this.setText(text); + if (token != ']') { + throw newSyntaxError('Bracket ] expected'); + } + getToken(); } - // create the frame - this.frame = document.createElement("div"); - var styleAttr = this.frame.style; - styleAttr.position = "absolute"; - styleAttr.visibility = "hidden"; - styleAttr.border = "1px solid " + style.color.border; - styleAttr.color = style.fontColor; - styleAttr.fontSize = style.fontSize + "px"; - styleAttr.fontFamily = style.fontFace; - styleAttr.padding = this.padding + "px"; - styleAttr.backgroundColor = style.color.background; - styleAttr.borderRadius = "3px"; - styleAttr.MozBorderRadius = "3px"; - styleAttr.WebkitBorderRadius = "3px"; - styleAttr.boxShadow = "3px 3px 10px rgba(128, 128, 128, 0.5)"; - styleAttr.whiteSpace = "nowrap"; - this.container.appendChild(this.frame); + return attr; } /** - * @param {number} x Horizontal position of the popup window - * @param {number} y Vertical position of the popup window + * Create a syntax error with extra information on current token and index. + * @param {String} message + * @returns {SyntaxError} err */ - Popup.prototype.setPosition = function(x, y) { - this.x = parseInt(x); - this.y = parseInt(y); - }; + function newSyntaxError(message) { + return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ')'); + } /** - * Set the content for the popup window. This can be HTML code or text. - * @param {string | Element} content + * Chop off text after a maximum length + * @param {String} text + * @param {Number} maxLength + * @returns {String} */ - Popup.prototype.setText = function(content) { - if (content instanceof Element) { - this.frame.innerHTML = ''; - this.frame.appendChild(content); + function chop (text, maxLength) { + return (text.length <= maxLength) ? text : (text.substr(0, 27) + '...'); + } + + /** + * Execute a function fn for each pair of elements in two arrays + * @param {Array | *} array1 + * @param {Array | *} array2 + * @param {function} fn + */ + function forEach2(array1, array2, fn) { + if (Array.isArray(array1)) { + array1.forEach(function (elem1) { + if (Array.isArray(array2)) { + array2.forEach(function (elem2) { + fn(elem1, elem2); + }); + } + else { + fn(elem1, array2); + } + }); } else { - this.frame.innerHTML = content; // string containing text or HTML + if (Array.isArray(array2)) { + array2.forEach(function (elem2) { + fn(array1, elem2); + }); + } + else { + fn(array1, array2); + } } - }; + } /** - * Show the popup window - * @param {boolean} show Optional. Show or hide the window + * Convert a string containing a graph in DOT language into a map containing + * with nodes and edges in the format of graph. + * @param {String} data Text containing a graph in DOT-notation + * @return {Object} graphData */ - Popup.prototype.show = function (show) { - if (show === undefined) { - show = true; - } + function DOTToGraph (data) { + // parse the DOT file + var dotData = parseDOT(data); + var graphData = { + nodes: [], + edges: [], + options: {} + }; - if (show) { - var height = this.frame.clientHeight; - var width = this.frame.clientWidth; - var maxHeight = this.frame.parentNode.clientHeight; - var maxWidth = this.frame.parentNode.clientWidth; + // copy the nodes + if (dotData.nodes) { + dotData.nodes.forEach(function (dotNode) { + var graphNode = { + id: dotNode.id, + label: String(dotNode.label || dotNode.id) + }; + merge(graphNode, dotNode.attr); + if (graphNode.image) { + graphNode.shape = 'image'; + } + graphData.nodes.push(graphNode); + }); + } - var top = (this.y - height); - if (top + height + this.padding > maxHeight) { - top = maxHeight - height - this.padding; - } - if (top < this.padding) { - top = this.padding; + // copy the edges + if (dotData.edges) { + /** + * Convert an edge in DOT format to an edge with VisGraph format + * @param {Object} dotEdge + * @returns {Object} graphEdge + */ + var convertEdge = function (dotEdge) { + var graphEdge = { + from: dotEdge.from, + to: dotEdge.to + }; + merge(graphEdge, dotEdge.attr); + graphEdge.style = (dotEdge.type == '->') ? 'arrow' : 'line'; + return graphEdge; } - var left = this.x; - if (left + width + this.padding > maxWidth) { - left = maxWidth - width - this.padding; - } - if (left < this.padding) { - left = this.padding; + dotData.edges.forEach(function (dotEdge) { + var from, to; + if (dotEdge.from instanceof Object) { + from = dotEdge.from.nodes; + } + else { + from = { + id: dotEdge.from + } + } + + if (dotEdge.to instanceof Object) { + to = dotEdge.to.nodes; + } + else { + to = { + id: dotEdge.to + } + } + + if (dotEdge.from instanceof Object && dotEdge.from.edges) { + dotEdge.from.edges.forEach(function (subEdge) { + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); + } + + forEach2(from, to, function (from, to) { + var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr); + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); + + if (dotEdge.to instanceof Object && dotEdge.to.edges) { + dotEdge.to.edges.forEach(function (subEdge) { + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); + } + }); + } + + // copy the options + if (dotData.attr) { + graphData.options = dotData.attr; + } + + return graphData; + } + + // exports + exports.parseDOT = parseDOT; + exports.DOTToGraph = DOTToGraph; + + +/***/ }, +/* 58 */ +/***/ function(module, exports, __webpack_require__) { + + + function parseGephi(gephiJSON, options) { + var edges = []; + var nodes = []; + this.options = { + edges: { + inheritColor: true + }, + nodes: { + allowedToMove: false, + parseColor: false } + }; - this.frame.style.left = left + "px"; - this.frame.style.top = top + "px"; - this.frame.style.visibility = "visible"; + if (options !== undefined) { + this.options.nodes['allowedToMove'] = options.allowedToMove | false; + this.options.nodes['parseColor'] = options.parseColor | false; + this.options.edges['inheritColor'] = options.inheritColor | true; } - else { - this.hide(); + + var gEdges = gephiJSON.edges; + var gNodes = gephiJSON.nodes; + for (var i = 0; i < gEdges.length; i++) { + var edge = {}; + var gEdge = gEdges[i]; + edge['id'] = gEdge.id; + edge['from'] = gEdge.source; + edge['to'] = gEdge.target; + edge['attributes'] = gEdge.attributes; + // edge['value'] = gEdge.attributes !== undefined ? gEdge.attributes.Weight : undefined; + // edge['width'] = edge['value'] !== undefined ? undefined : edgegEdge.size; + edge['color'] = gEdge.color; + edge['inheritColor'] = edge['color'] !== undefined ? false : this.options.inheritColor; + edges.push(edge); } - }; - /** - * Hide the popup window - */ - Popup.prototype.hide = function () { - this.frame.style.visibility = "hidden"; - }; + for (var i = 0; i < gNodes.length; i++) { + var node = {}; + var gNode = gNodes[i]; + node['id'] = gNode.id; + node['attributes'] = gNode.attributes; + node['x'] = gNode.x; + node['y'] = gNode.y; + node['label'] = gNode.label; + if (this.options.nodes.parseColor == true) { + node['color'] = gNode.color; + } + else { + node['color'] = gNode.color !== undefined ? {background:gNode.color, border:gNode.color} : undefined; + } + node['radius'] = gNode.size; + node['allowedToMoveX'] = this.options.nodes.allowedToMove; + node['allowedToMoveY'] = this.options.nodes.allowedToMove; + nodes.push(node); + } - module.exports = Popup; + return {nodes:nodes, edges:edges}; + } + exports.parseGephi = parseGephi; /***/ }, /* 59 */ @@ -31814,7 +31807,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); - var Node = __webpack_require__(56); + var Node = __webpack_require__(53); /** * Creation of the SectorMixin var. @@ -32372,7 +32365,7 @@ return /******/ (function(modules) { // webpackBootstrap /* 66 */ /***/ function(module, exports, __webpack_require__) { - var Node = __webpack_require__(56); + var Node = __webpack_require__(53); /** * This function can be called from the _doInAllSectors function @@ -33087,8 +33080,8 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); - var Node = __webpack_require__(56); - var Edge = __webpack_require__(57); + var Node = __webpack_require__(53); + var Edge = __webpack_require__(52); /** * clears the toolbar div element of children diff --git a/lib/network/Network.js b/lib/network/Network.js index 3b813974..eaae2ced 100644 --- a/lib/network/Network.js +++ b/lib/network/Network.js @@ -410,8 +410,8 @@ Network.prototype._getRange = function() { node = this.nodes[nodeId]; if (minX > (node.boundingBox.left)) {minX = node.boundingBox.left;} if (maxX < (node.boundingBox.right)) {maxX = node.boundingBox.right;} - if (minY > (node.boundingBox.bottom)) {minY = node.boundingBox.bottom;} - if (maxY < (node.boundingBox.top)) {maxY = node.boundingBox.top;} + if (minY > (node.boundingBox.bottom)) {minY = node.boundingBox.top;} // top is negative, bottom is positive + if (maxY < (node.boundingBox.top)) {maxY = node.boundingBox.bottom;} // top is negative, bottom is positive } } if (minX == 1e9 && maxX == -1e9 && minY == 1e9 && maxY == -1e9) { @@ -441,15 +441,9 @@ Network.prototype._findCenter = function(range) { Network.prototype.zoomExtent = function(animationOptions, initialZoom, disableStart) { this._redraw(true); - if (initialZoom === undefined) { - initialZoom = false; - } - if (disableStart === undefined) { - disableStart = false; - } - if (animationOptions === undefined) { - animationOptions = false; - } + if (initialZoom === undefined) {initialZoom = false;} + if (disableStart === undefined) {disableStart = false;} + if (animationOptions === undefined) {animationOptions = false;} var range = this._getRange(); var zoomLevel; @@ -485,7 +479,6 @@ Network.prototype.zoomExtent = function(animationOptions, initialZoom, disableSt var xZoomLevel = this.frame.canvas.clientWidth / xDistance; var yZoomLevel = this.frame.canvas.clientHeight / yDistance; - zoomLevel = (xZoomLevel <= yZoomLevel) ? xZoomLevel : yZoomLevel; } From 86ec061d913414371160be69872d4209582ffc0b Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Mon, 19 Jan 2015 10:07:39 +0100 Subject: [PATCH 05/16] - Fixed nodes color data being overridden when having a group and a dataset update query --- HISTORY.md | 1 + dist/vis.js | 4244 +++++++++++++++++++++---------------------- dist/vis.map | 2 +- dist/vis.min.js | 30 +- lib/network/Node.js | 6 +- 5 files changed, 2142 insertions(+), 2141 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 2a916dc0..375b8b21 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -8,6 +8,7 @@ http://visjs.org - Fixed bug where opening a cluster with smoothCurves off caused one child to go crazy. - Fixed bug where zoomExtent does not work as expected. +- Fixed nodes color data being overridden when having a group and a dataset update query. ## 2015-01-16, version 3.9.0 diff --git a/dist/vis.js b/dist/vis.js index 2ccd554a..cfe4a98b 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -5,7 +5,7 @@ * A dynamic, browser-based visualization library. * * @version 3.9.1-SNAPSHOT - * @date 2015-01-16 + * @date 2015-01-19 * * @license * Copyright (C) 2011-2014 Almende B.V, http://almende.com @@ -137,13 +137,13 @@ return /******/ (function(modules) { // webpackBootstrap // Network exports.Network = __webpack_require__(51); exports.network = { - Edge: __webpack_require__(52), + Edge: __webpack_require__(57), Groups: __webpack_require__(54), Images: __webpack_require__(55), - Node: __webpack_require__(53), - Popup: __webpack_require__(56), - dotparser: __webpack_require__(57), - gephiParser: __webpack_require__(58) + Node: __webpack_require__(56), + Popup: __webpack_require__(58), + dotparser: __webpack_require__(52), + gephiParser: __webpack_require__(53) }; // Deprecated since v3.0.0 @@ -22649,13 +22649,13 @@ return /******/ (function(modules) { // webpackBootstrap var hammerUtil = __webpack_require__(22); var DataSet = __webpack_require__(7); var DataView = __webpack_require__(9); - var dotparser = __webpack_require__(57); - var gephiParser = __webpack_require__(58); + var dotparser = __webpack_require__(52); + var gephiParser = __webpack_require__(53); var Groups = __webpack_require__(54); var Images = __webpack_require__(55); - var Node = __webpack_require__(53); - var Edge = __webpack_require__(52); - var Popup = __webpack_require__(56); + var Node = __webpack_require__(56); + var Edge = __webpack_require__(57); + var Popup = __webpack_require__(58); var MixinLoader = __webpack_require__(59); var Activator = __webpack_require__(35); var locales = __webpack_require__(70); @@ -25357,1360 +25357,1067 @@ return /******/ (function(modules) { // webpackBootstrap /* 52 */ /***/ function(module, exports, __webpack_require__) { - var util = __webpack_require__(1); - var Node = __webpack_require__(53); - /** - * @class Edge + * Parse a text source containing data in DOT language into a JSON object. + * The object contains two lists: one with nodes and one with edges. * - * A edge connects two nodes - * @param {Object} properties Object with properties. Must contain - * At least properties from and to. - * Available properties: from (number), - * to (number), label (string, color (string), - * width (number), style (string), - * length (number), title (string) - * @param {Network} network A Network object, used to find and edge to - * nodes. - * @param {Object} constants An object with default values for - * example for the color + * DOT language reference: http://www.graphviz.org/doc/info/lang.html + * + * @param {String} data Text containing a graph in DOT-notation + * @return {Object} graph An object containing two parameters: + * {Object[]} nodes + * {Object[]} edges */ - function Edge (properties, network, networkConstants) { - if (!network) { - throw "No network provided"; - } - var fields = ['edges','physics']; - var constants = util.selectiveBridgeObject(fields,networkConstants); - this.options = constants.edges; - this.physics = constants.physics; - this.options['smoothCurves'] = networkConstants['smoothCurves']; - - - this.network = network; + function parseDOT (data) { + dot = data; + return parseGraph(); + } - // initialize variables - this.id = undefined; - this.fromId = undefined; - this.toId = undefined; - this.title = undefined; - this.widthSelected = this.options.width * this.options.widthSelectionMultiplier; - this.value = undefined; - this.selected = false; - this.hover = false; - this.labelDimensions = {top:0,left:0,width:0,height:0,yLine:0}; // could be cached - this.dirtyLabel = true; + // token types enumeration + var TOKENTYPE = { + NULL : 0, + DELIMITER : 1, + IDENTIFIER: 2, + UNKNOWN : 3 + }; - this.from = null; // a node - this.to = null; // a node - this.via = null; // a temp node + // map with all delimiters + var DELIMITERS = { + '{': true, + '}': true, + '[': true, + ']': true, + ';': true, + '=': true, + ',': true, - this.fromBackup = null; // used to clean up after reconnect - this.toBackup = null;; // used to clean up after reconnect + '->': true, + '--': true + }; - // we use this to be able to reconnect the edge to a cluster if its node is put into a cluster - // by storing the original information we can revert to the original connection when the cluser is opened. - this.originalFromId = []; - this.originalToId = []; + var dot = ''; // current dot file + var index = 0; // current index in dot file + var c = ''; // current token character in expr + var token = ''; // current token + var tokenType = TOKENTYPE.NULL; // type of the token - this.connected = false; + /** + * Get the first character from the dot file. + * The character is stored into the char c. If the end of the dot file is + * reached, the function puts an empty string in c. + */ + function first() { + index = 0; + c = dot.charAt(0); + } - this.widthFixed = false; - this.lengthFixed = false; + /** + * Get the next character from the dot file. + * The character is stored into the char c. If the end of the dot file is + * reached, the function puts an empty string in c. + */ + function next() { + index++; + c = dot.charAt(index); + } - this.setProperties(properties); + /** + * Preview the next character from the dot file. + * @return {String} cNext + */ + function nextPreview() { + return dot.charAt(index + 1); + } - this.controlNodesEnabled = false; - this.controlNodes = {from:null, to:null, positions:{}}; - this.connectedNode = null; + /** + * Test whether given character is alphabetic or numeric + * @param {String} c + * @return {Boolean} isAlphaNumeric + */ + var regexAlphaNumeric = /[a-zA-Z_0-9.:#]/; + function isAlphaNumeric(c) { + return regexAlphaNumeric.test(c); } /** - * Set or overwrite properties for the edge - * @param {Object} properties an object with properties - * @param {Object} constants and object with default, global properties + * Merge all properties of object b into object b + * @param {Object} a + * @param {Object} b + * @return {Object} a */ - Edge.prototype.setProperties = function(properties) { - if (!properties) { - return; + function merge (a, b) { + if (!a) { + a = {}; } - var fields = ['style','fontSize','fontFace','fontColor','fontFill','fontStrokeWidth','fontStrokeColor','width', - 'widthSelectionMultiplier','hoverWidth','arrowScaleFactor','dash','inheritColor','labelAlignment' - ]; - util.selectiveDeepExtend(fields, this.options, properties); - - if (properties.from !== undefined) {this.fromId = properties.from;} - if (properties.to !== undefined) {this.toId = properties.to;} - - if (properties.id !== undefined) {this.id = properties.id;} - if (properties.label !== undefined) {this.label = properties.label; this.dirtyLabel = true;} - - if (properties.title !== undefined) {this.title = properties.title;} - if (properties.value !== undefined) {this.value = properties.value;} - if (properties.length !== undefined) {this.physics.springLength = properties.length;} + if (b) { + for (var name in b) { + if (b.hasOwnProperty(name)) { + a[name] = b[name]; + } + } + } + return a; + } - if (properties.color !== undefined) { - this.options.inheritColor = false; - if (util.isString(properties.color)) { - this.options.color.color = properties.color; - this.options.color.highlight = properties.color; + /** + * Set a value in an object, where the provided parameter name can be a + * path with nested parameters. For example: + * + * var obj = {a: 2}; + * setValue(obj, 'b.c', 3); // obj = {a: 2, b: {c: 3}} + * + * @param {Object} obj + * @param {String} path A parameter name or dot-separated parameter path, + * like "color.highlight.border". + * @param {*} value + */ + function setValue(obj, path, value) { + var keys = path.split('.'); + var o = obj; + while (keys.length) { + var key = keys.shift(); + if (keys.length) { + // this isn't the end point + if (!o[key]) { + o[key] = {}; + } + o = o[key]; } else { - if (properties.color.color !== undefined) {this.options.color.color = properties.color.color;} - if (properties.color.highlight !== undefined) {this.options.color.highlight = properties.color.highlight;} - if (properties.color.hover !== undefined) {this.options.color.hover = properties.color.hover;} + // this is the end point + o[key] = value; } } + } - // A node is connected when it has a from and to node. - this.connect(); - - this.widthFixed = this.widthFixed || (properties.width !== undefined); - this.lengthFixed = this.lengthFixed || (properties.length !== undefined); + /** + * Add a node to a graph object. If there is already a node with + * the same id, their attributes will be merged. + * @param {Object} graph + * @param {Object} node + */ + function addNode(graph, node) { + var i, len; + var current = null; - this.widthSelected = this.options.width* this.options.widthSelectionMultiplier; + // find root graph (in case of subgraph) + var graphs = [graph]; // list with all graphs from current graph to root graph + var root = graph; + while (root.parent) { + graphs.push(root.parent); + root = root.parent; + } - // set draw method based on style - switch (this.options.style) { - case 'line': this.draw = this._drawLine; break; - case 'arrow': this.draw = this._drawArrow; break; - case 'arrow-center': this.draw = this._drawArrowCenter; break; - case 'dash-line': this.draw = this._drawDashLine; break; - default: this.draw = this._drawLine; break; + // find existing node (at root level) by its id + if (root.nodes) { + for (i = 0, len = root.nodes.length; i < len; i++) { + if (node.id === root.nodes[i].id) { + current = root.nodes[i]; + break; + } + } } - - }; - /** - * Connect an edge to its nodes - */ - Edge.prototype.connect = function () { - this.disconnect(); + if (!current) { + // this is a new node + current = { + id: node.id + }; + if (graph.node) { + // clone default attributes + current.attr = merge(current.attr, graph.node); + } + } - this.from = this.network.nodes[this.fromId] || null; - this.to = this.network.nodes[this.toId] || null; - this.connected = (this.from && this.to); + // add node to this (sub)graph and all its parent graphs + for (i = graphs.length - 1; i >= 0; i--) { + var g = graphs[i]; - if (this.connected) { - this.from.attachEdge(this); - this.to.attachEdge(this); - } - else { - if (this.from) { - this.from.detachEdge(this); + if (!g.nodes) { + g.nodes = []; } - if (this.to) { - this.to.detachEdge(this); + if (g.nodes.indexOf(current) == -1) { + g.nodes.push(current); } } - }; - /** - * Disconnect an edge from its nodes - */ - Edge.prototype.disconnect = function () { - if (this.from) { - this.from.detachEdge(this); - this.from = null; - } - if (this.to) { - this.to.detachEdge(this); - this.to = null; + // merge attributes + if (node.attr) { + current.attr = merge(current.attr, node.attr); } - - this.connected = false; - }; + } /** - * get the title of this edge. - * @return {string} title The title of the edge, or undefined when no title - * has been set. + * Add an edge to a graph object + * @param {Object} graph + * @param {Object} edge */ - Edge.prototype.getTitle = function() { - return typeof this.title === "function" ? this.title() : this.title; - }; - + function addEdge(graph, edge) { + if (!graph.edges) { + graph.edges = []; + } + graph.edges.push(edge); + if (graph.edge) { + var attr = merge({}, graph.edge); // clone default attributes + edge.attr = merge(attr, edge.attr); // merge attributes + } + } /** - * Retrieve the value of the edge. Can be undefined - * @return {Number} value + * Create an edge to a graph object + * @param {Object} graph + * @param {String | Number | Object} from + * @param {String | Number | Object} to + * @param {String} type + * @param {Object | null} attr + * @return {Object} edge */ - Edge.prototype.getValue = function() { - return this.value; - }; + function createEdge(graph, from, to, type, attr) { + var edge = { + from: from, + to: to, + type: type + }; - /** - * Adjust the value range of the edge. The edge will adjust it's width - * based on its value. - * @param {Number} min - * @param {Number} max - */ - Edge.prototype.setValueRange = function(min, max) { - if (!this.widthFixed && this.value !== undefined) { - var scale = (this.options.widthMax - this.options.widthMin) / (max - min); - this.options.width= (this.value - min) * scale + this.options.widthMin; - this.widthSelected = this.options.width* this.options.widthSelectionMultiplier; + if (graph.edge) { + edge.attr = merge({}, graph.edge); // clone default attributes } - }; + edge.attr = merge(edge.attr || {}, attr); // merge attributes - /** - * Redraw a edge - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - */ - Edge.prototype.draw = function(ctx) { - throw "Method draw not initialized in edge"; - }; + return edge; + } /** - * Check if this object is overlapping with the provided object - * @param {Object} obj an object with parameters left, top - * @return {boolean} True if location is located on the edge + * Get next token in the current dot file. + * The token and token type are available as token and tokenType */ - Edge.prototype.isOverlappingWith = function(obj) { - if (this.connected) { - var distMax = 10; - var xFrom = this.from.x; - var yFrom = this.from.y; - var xTo = this.to.x; - var yTo = this.to.y; - var xObj = obj.left; - var yObj = obj.top; - - var dist = this._getDistanceToEdge(xFrom, yFrom, xTo, yTo, xObj, yObj); - - return (dist < distMax); - } - else { - return false - } - }; + function getToken() { + tokenType = TOKENTYPE.NULL; + token = ''; - Edge.prototype._getColor = function() { - var colorObj = this.options.color; - if (this.options.inheritColor == "to") { - colorObj = { - highlight: this.to.options.color.highlight.border, - hover: this.to.options.color.hover.border, - color: this.to.options.color.border - }; - } - else if (this.options.inheritColor == "from" || this.options.inheritColor == true) { - colorObj = { - highlight: this.from.options.color.highlight.border, - hover: this.from.options.color.hover.border, - color: this.from.options.color.border - }; + // skip over whitespaces + while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter + next(); } - if (this.selected == true) {return colorObj.highlight;} - else if (this.hover == true) {return colorObj.hover;} - else {return colorObj.color;} - }; - - - /** - * Redraw a edge as a line - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ - Edge.prototype._drawLine = function(ctx) { - // set style - ctx.strokeStyle = this._getColor(); - ctx.lineWidth = this._getLineWidth(); - - if (this.from != this.to) { - // draw line - var via = this._line(ctx); + do { + var isComment = false; - // draw label - var point; - if (this.label) { - if (this.options.smoothCurves.enabled == true && via != null) { - var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); - var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); - point = {x:midpointX, y:midpointY}; + // skip comment + if (c == '#') { + // find the previous non-space character + var i = index - 1; + while (dot.charAt(i) == ' ' || dot.charAt(i) == '\t') { + i--; } - else { - point = this._pointOnLine(0.5); + if (dot.charAt(i) == '\n' || dot.charAt(i) == '') { + // the # is at the start of a line, this is indeed a line comment + while (c != '' && c != '\n') { + next(); + } + isComment = true; } - this._label(ctx, this.label, point.x, point.y); } - } - else { - var x, y; - var radius = this.physics.springLength / 4; - var node = this.from; - if (!node.width) { - node.resize(ctx); + if (c == '/' && nextPreview() == '/') { + // skip line comment + while (c != '' && c != '\n') { + next(); + } + isComment = true; } - if (node.width > node.height) { - x = node.x + node.width / 2; - y = node.y - radius; + if (c == '/' && nextPreview() == '*') { + // skip block comment + while (c != '') { + if (c == '*' && nextPreview() == '/') { + // end of block comment found. skip these last two characters + next(); + next(); + break; + } + else { + next(); + } + } + isComment = true; } - else { - x = node.x + radius; - y = node.y - node.height / 2; + + // skip over whitespaces + while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter + next(); } - this._circle(ctx, x, y, radius); - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); } - }; + while (isComment); - /** - * Get the line width of the edge. Depends on width and whether one of the - * connected nodes is selected. - * @return {Number} width - * @private - */ - Edge.prototype._getLineWidth = function() { - if (this.selected == true) { - return Math.max(Math.min(this.widthSelected, this.options.widthMax), 0.3*this.networkScaleInv); + // check for end of dot file + if (c == '') { + // token is still empty + tokenType = TOKENTYPE.DELIMITER; + return; } - else { - if (this.hover == true) { - return Math.max(Math.min(this.options.hoverWidth, this.options.widthMax), 0.3*this.networkScaleInv); - } - else { - return Math.max(this.options.width, 0.3*this.networkScaleInv); - } + + // check for delimiters consisting of 2 characters + var c2 = c + nextPreview(); + if (DELIMITERS[c2]) { + tokenType = TOKENTYPE.DELIMITER; + token = c2; + next(); + next(); + return; } - }; - Edge.prototype._getViaCoordinates = function () { - if (this.options.smoothCurves.dynamic == true && this.options.smoothCurves.enabled == true ) { - return this.via; - } - else if (this.options.smoothCurves.enabled == false) { - return {x:0,y:0}; + // check for delimiters consisting of 1 character + if (DELIMITERS[c]) { + tokenType = TOKENTYPE.DELIMITER; + token = c; + next(); + return; } - else { - var xVia = null; - var yVia = null; - var factor = this.options.smoothCurves.roundness; - var type = this.options.smoothCurves.type; - var dx = Math.abs(this.from.x - this.to.x); - var dy = Math.abs(this.from.y - this.to.y); - if (type == 'discrete' || type == 'diagonalCross') { - if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { - if (this.from.y > this.to.y) { - if (this.from.x < this.to.x) { - xVia = this.from.x + factor * dy; - yVia = this.from.y - factor * dy; - } - else if (this.from.x > this.to.x) { - xVia = this.from.x - factor * dy; - yVia = this.from.y - factor * dy; - } - } - else if (this.from.y < this.to.y) { - if (this.from.x < this.to.x) { - xVia = this.from.x + factor * dy; - yVia = this.from.y + factor * dy; - } - else if (this.from.x > this.to.x) { - xVia = this.from.x - factor * dy; - yVia = this.from.y + factor * dy; - } - } - if (type == "discrete") { - xVia = dx < factor * dy ? this.from.x : xVia; - } - } - else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { - if (this.from.y > this.to.y) { - if (this.from.x < this.to.x) { - xVia = this.from.x + factor * dx; - yVia = this.from.y - factor * dx; - } - else if (this.from.x > this.to.x) { - xVia = this.from.x - factor * dx; - yVia = this.from.y - factor * dx; - } - } - else if (this.from.y < this.to.y) { - if (this.from.x < this.to.x) { - xVia = this.from.x + factor * dx; - yVia = this.from.y + factor * dx; - } - else if (this.from.x > this.to.x) { - xVia = this.from.x - factor * dx; - yVia = this.from.y + factor * dx; - } - } - if (type == "discrete") { - yVia = dy < factor * dx ? this.from.y : yVia; - } - } - } - else if (type == "straightCross") { - if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { // up - down - xVia = this.from.x; - if (this.from.y < this.to.y) { - yVia = this.to.y - (1 - factor) * dy; - } - else { - yVia = this.to.y + (1 - factor) * dy; - } - } - else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { // left - right - if (this.from.x < this.to.x) { - xVia = this.to.x - (1 - factor) * dx; - } - else { - xVia = this.to.x + (1 - factor) * dx; - } - yVia = this.from.y; - } + // check for an identifier (number or string) + // TODO: more precise parsing of numbers/strings (and the port separator ':') + if (isAlphaNumeric(c) || c == '-') { + token += c; + next(); + + while (isAlphaNumeric(c)) { + token += c; + next(); } - else if (type == 'horizontal') { - if (this.from.x < this.to.x) { - xVia = this.to.x - (1 - factor) * dx; - } - else { - xVia = this.to.x + (1 - factor) * dx; - } - yVia = this.from.y; + if (token == 'false') { + token = false; // convert to boolean } - else if (type == 'vertical') { - xVia = this.from.x; - if (this.from.y < this.to.y) { - yVia = this.to.y - (1 - factor) * dy; - } - else { - yVia = this.to.y + (1 - factor) * dy; - } + else if (token == 'true') { + token = true; // convert to boolean } - else { // continuous - if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { - if (this.from.y > this.to.y) { - if (this.from.x < this.to.x) { - // console.log(1) - xVia = this.from.x + factor * dy; - yVia = this.from.y - factor * dy; - xVia = this.to.x < xVia ? this.to.x : xVia; - } - else if (this.from.x > this.to.x) { - // console.log(2) - xVia = this.from.x - factor * dy; - yVia = this.from.y - factor * dy; - xVia = this.to.x > xVia ? this.to.x : xVia; - } - } - else if (this.from.y < this.to.y) { - if (this.from.x < this.to.x) { - // console.log(3) - xVia = this.from.x + factor * dy; - yVia = this.from.y + factor * dy; - xVia = this.to.x < xVia ? this.to.x : xVia; - } - else if (this.from.x > this.to.x) { - // console.log(4, this.from.x, this.to.x) - xVia = this.from.x - factor * dy; - yVia = this.from.y + factor * dy; - xVia = this.to.x > xVia ? this.to.x : xVia; - } - } - } - else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { - if (this.from.y > this.to.y) { - if (this.from.x < this.to.x) { - // console.log(5) - xVia = this.from.x + factor * dx; - yVia = this.from.y - factor * dx; - yVia = this.to.y > yVia ? this.to.y : yVia; - } - else if (this.from.x > this.to.x) { - // console.log(6) - xVia = this.from.x - factor * dx; - yVia = this.from.y - factor * dx; - yVia = this.to.y > yVia ? this.to.y : yVia; - } - } - else if (this.from.y < this.to.y) { - if (this.from.x < this.to.x) { - // console.log(7) - xVia = this.from.x + factor * dx; - yVia = this.from.y + factor * dx; - yVia = this.to.y < yVia ? this.to.y : yVia; - } - else if (this.from.x > this.to.x) { - // console.log(8) - xVia = this.from.x - factor * dx; - yVia = this.from.y + factor * dx; - yVia = this.to.y < yVia ? this.to.y : yVia; - } - } - } + else if (!isNaN(Number(token))) { + token = Number(token); // convert to number } - - - return {x: xVia, y: yVia}; + tokenType = TOKENTYPE.IDENTIFIER; + return; } - }; - /** - * Draw a line between two nodes - * @param {CanvasRenderingContext2D} ctx - * @private - */ - Edge.prototype._line = function (ctx) { - // draw a straight line - ctx.beginPath(); - ctx.moveTo(this.from.x, this.from.y); - if (this.options.smoothCurves.enabled == true) { - if (this.options.smoothCurves.dynamic == false) { - var via = this._getViaCoordinates(); - if (via.x == null) { - ctx.lineTo(this.to.x, this.to.y); - ctx.stroke(); - return null; - } - else { - // this.via.x = via.x; - // this.via.y = via.y; - ctx.quadraticCurveTo(via.x,via.y,this.to.x, this.to.y); - ctx.stroke(); - return via; + // check for a string enclosed by double quotes + if (c == '"') { + next(); + while (c != '' && (c != '"' || (c == '"' && nextPreview() == '"'))) { + token += c; + if (c == '"') { // skip the escape character + next(); } + next(); } - else { - ctx.quadraticCurveTo(this.via.x,this.via.y,this.to.x, this.to.y); - ctx.stroke(); - return this.via; + if (c != '"') { + throw newSyntaxError('End of string " expected'); } + next(); + tokenType = TOKENTYPE.IDENTIFIER; + return; } - else { - ctx.lineTo(this.to.x, this.to.y); - ctx.stroke(); - return null; + + // something unknown is found, wrong characters, a syntax error + tokenType = TOKENTYPE.UNKNOWN; + while (c != '') { + token += c; + next(); } - }; + throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"'); + } /** - * Draw a line from a node to itself, a circle - * @param {CanvasRenderingContext2D} ctx - * @param {Number} x - * @param {Number} y - * @param {Number} radius - * @private + * Parse a graph. + * @returns {Object} graph */ - Edge.prototype._circle = function (ctx, x, y, radius) { - // draw a circle - ctx.beginPath(); - ctx.arc(x, y, radius, 0, 2 * Math.PI, false); - ctx.stroke(); - }; + function parseGraph() { + var graph = {}; - /** - * Draw label with white background and with the middle at (x, y) - * @param {CanvasRenderingContext2D} ctx - * @param {String} text - * @param {Number} x - * @param {Number} y - * @private - */ - Edge.prototype._label = function (ctx, text, x, y) { - if (text) { - ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") + - this.options.fontSize + "px " + this.options.fontFace; - var yLine; + first(); + getToken(); - if (this.dirtyLabel == true) { - var lines = String(text).split('\n'); - var lineCount = lines.length; - var fontSize = Number(this.options.fontSize); - yLine = y + (1 - lineCount) / 2 * fontSize; + // optional strict keyword + if (token == 'strict') { + graph.strict = true; + getToken(); + } - var width = ctx.measureText(lines[0]).width; - for (var i = 1; i < lineCount; i++) { - var lineWidth = ctx.measureText(lines[i]).width; - width = lineWidth > width ? lineWidth : width; - } - var height = this.options.fontSize * lineCount; - var left = x - width / 2; - var top = y - height / 2; + // graph or digraph keyword + if (token == 'graph' || token == 'digraph') { + graph.type = token; + getToken(); + } - // cache - this.labelDimensions = {top:top,left:left,width:width,height:height,yLine:yLine}; - } + // optional graph id + if (tokenType == TOKENTYPE.IDENTIFIER) { + graph.id = token; + getToken(); + } - var yLine = this.labelDimensions.yLine; - - ctx.save(); - - if (this.options.labelAlignment != "horizontal"){ - ctx.translate(x, yLine); - this._rotateForLabelAlignment(ctx); - x = 0; - yLine = 0; - } + // open angle bracket + if (token != '{') { + throw newSyntaxError('Angle bracket { expected'); + } + getToken(); - - this._drawLabelRect(ctx); - this._drawLabelText(ctx,x,yLine, lines, lineCount, fontSize); - - ctx.restore(); + // statements + parseStatements(graph); + + // close angle bracket + if (token != '}') { + throw newSyntaxError('Angle bracket } expected'); } - }; + getToken(); - /** - * Rotates the canvas so the text is most readable - * @param {CanvasRenderingContext2D} ctx - * @private - */ - Edge.prototype._rotateForLabelAlignment = function(ctx) { - var dy = this.from.y - this.to.y; - var dx = this.from.x - this.to.x; - var angleInDegrees = Math.atan2(dy, dx); + // end of file + if (token !== '') { + throw newSyntaxError('End of file expected'); + } + getToken(); - // rotate so label it is readable - if((angleInDegrees < -1 && dx < 0) || (angleInDegrees > 0 && dx < 0)){ - angleInDegrees = angleInDegrees + Math.PI; - } - - ctx.rotate(angleInDegrees); - }; + // remove temporary default properties + delete graph.node; + delete graph.edge; + delete graph.graph; + + return graph; + } /** - * Draws the label rectangle - * @param {CanvasRenderingContext2D} ctx - * @param {String} labelAlignment - * @private + * Parse a list with statements. + * @param {Object} graph */ - Edge.prototype._drawLabelRect = function(ctx) { - if (this.options.fontFill !== undefined && this.options.fontFill !== null && this.options.fontFill !== "none") { - ctx.fillStyle = this.options.fontFill; - - var lineMargin = 2; - - if (this.options.labelAlignment == 'line-center') { - ctx.fillRect(-this.labelDimensions.width * 0.5, -this.labelDimensions.height * 0.5, this.labelDimensions.width, this.labelDimensions.height); - } - else if (this.options.labelAlignment == 'line-above') { - ctx.fillRect(-this.labelDimensions.width * 0.5, -(this.labelDimensions.height + lineMargin), this.labelDimensions.width, this.labelDimensions.height); - } - else if (this.options.labelAlignment == 'line-below') { - ctx.fillRect(-this.labelDimensions.width * 0.5, lineMargin, this.labelDimensions.width, this.labelDimensions.height); - } - else { - ctx.fillRect(this.labelDimensions.left, this.labelDimensions.top, this.labelDimensions.width, this.labelDimensions.height); + function parseStatements (graph) { + while (token !== '' && token != '}') { + parseStatement(graph); + if (token == ';') { + getToken(); } } - }; + } /** - * Draws the label text - * @param {CanvasRenderingContext2D} ctx - * @param {Number} x - * @param {Number} yLine - * @param {Array} lines - * @param {Number} lineCount - * @param {Number} fontSize - * @private + * Parse a single statement. Can be a an attribute statement, node + * statement, a series of node statements and edge statements, or a + * parameter. + * @param {Object} graph */ - Edge.prototype._drawLabelText = function(ctx, x, yLine, lines, lineCount, fontSize) { - // draw text - ctx.fillStyle = this.options.fontColor || "black"; - ctx.textAlign = "center"; + function parseStatement(graph) { + // parse subgraph + var subgraph = parseSubgraph(graph); + if (subgraph) { + // edge statements + parseEdge(graph, subgraph); - // check for label alignment - if (this.options.labelAlignment != 'horizontal') { - var lineMargin = 2; - if (this.options.labelAlignment == 'line-above') { - ctx.textBaseline = "alphabetic"; - yLine -= 2 * lineMargin; // distance from edge, required because we use alphabetic. Alphabetic has less difference between browsers - } - else if (this.options.labelAlignment == 'line-below') { - ctx.textBaseline = "hanging"; - yLine += 2 * lineMargin;// distance from edge, required because we use hanging. Hanging has less difference between browsers - } - else { - ctx.textBaseline = "middle"; - } - } - else { - ctx.textBaseline = "middle"; + return; } - // check for strokeWidth - if (this.options.fontStrokeWidth > 0){ - ctx.lineWidth = this.options.fontStrokeWidth; - ctx.strokeStyle = this.options.fontStrokeColor; - ctx.lineJoin = 'round'; + // parse an attribute statement + var attr = parseAttributeStatement(graph); + if (attr) { + return; } - for (var i = 0; i < lineCount; i++) { - if(this.options.fontStrokeWidth > 0){ - ctx.strokeText(lines[i], x, yLine); - } - ctx.fillText(lines[i], x, yLine); - yLine += fontSize; - } - }; - - /** - * Redraw a edge as a dashed line - * Draw this edge in the given canvas - * @author David Jordan - * @date 2012-08-08 - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ - Edge.prototype._drawDashLine = function(ctx) { - // set style - ctx.strokeStyle = this._getColor(); - ctx.lineWidth = this._getLineWidth(); - - var via = null; - // only firefox and chrome support this method, else we use the legacy one. - if (ctx.setLineDash !== undefined) { - ctx.save(); - // configure the dash pattern - var pattern = [0]; - if (this.options.dash.length !== undefined && this.options.dash.gap !== undefined) { - pattern = [this.options.dash.length,this.options.dash.gap]; - } - else { - pattern = [5,5]; - } - - // set dash settings for chrome or firefox - ctx.setLineDash(pattern); - ctx.lineDashOffset = 0; - - // draw the line - via = this._line(ctx); - // restore the dash settings. - ctx.setLineDash([0]); - ctx.lineDashOffset = 0; - ctx.restore(); - } - else { // unsupporting smooth lines - // draw dashed line - ctx.beginPath(); - ctx.lineCap = 'round'; - if (this.options.dash.altLength !== undefined) //If an alt dash value has been set add to the array this value - { - ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, - [this.options.dash.length,this.options.dash.gap,this.options.dash.altLength,this.options.dash.gap]); - } - else if (this.options.dash.length !== undefined && this.options.dash.gap !== undefined) //If a dash and gap value has been set add to the array this value - { - ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, - [this.options.dash.length,this.options.dash.gap]); - } - else //If all else fails draw a line - { - ctx.moveTo(this.from.x, this.from.y); - ctx.lineTo(this.to.x, this.to.y); - } - ctx.stroke(); + // parse node + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier expected'); } + var id = token; // id can be a string or a number + getToken(); - // draw label - if (this.label) { - var point; - if (this.options.smoothCurves.enabled == true && via != null) { - var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); - var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); - point = {x:midpointX, y:midpointY}; - } - else { - point = this._pointOnLine(0.5); + if (token == '=') { + // id statement + getToken(); + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier expected'); } - this._label(ctx, this.label, point.x, point.y); + graph[id] = token; + getToken(); + // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] " } - }; - - /** - * Get a point on a line - * @param {Number} percentage. Value between 0 (line start) and 1 (line end) - * @return {Object} point - * @private - */ - Edge.prototype._pointOnLine = function (percentage) { - return { - x: (1 - percentage) * this.from.x + percentage * this.to.x, - y: (1 - percentage) * this.from.y + percentage * this.to.y + else { + parseNodeStatement(graph, id); } - }; + } /** - * Get a point on a circle - * @param {Number} x - * @param {Number} y - * @param {Number} radius - * @param {Number} percentage. Value between 0 (line start) and 1 (line end) - * @return {Object} point - * @private + * Parse a subgraph + * @param {Object} graph parent graph object + * @return {Object | null} subgraph */ - Edge.prototype._pointOnCircle = function (x, y, radius, percentage) { - var angle = (percentage - 3/8) * 2 * Math.PI; - return { - x: x + radius * Math.cos(angle), - y: y - radius * Math.sin(angle) - } - }; + function parseSubgraph (graph) { + var subgraph = null; - /** - * Redraw a edge as a line with an arrow halfway the line - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ - Edge.prototype._drawArrowCenter = function(ctx) { - var point; - // set style - ctx.strokeStyle = this._getColor(); - ctx.fillStyle = ctx.strokeStyle; - ctx.lineWidth = this._getLineWidth(); + // optional subgraph keyword + if (token == 'subgraph') { + subgraph = {}; + subgraph.type = 'subgraph'; + getToken(); - if (this.from != this.to) { - // draw line - var via = this._line(ctx); + // optional graph id + if (tokenType == TOKENTYPE.IDENTIFIER) { + subgraph.id = token; + getToken(); + } + } - var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; - // draw an arrow halfway the line - if (this.options.smoothCurves.enabled == true && via != null) { - var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); - var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); - point = {x:midpointX, y:midpointY}; + // open angle bracket + if (token == '{') { + getToken(); + + if (!subgraph) { + subgraph = {}; } - else { - point = this._pointOnLine(0.5); + subgraph.parent = graph; + subgraph.node = graph.node; + subgraph.edge = graph.edge; + subgraph.graph = graph.graph; + + // statements + parseStatements(subgraph); + + // close angle bracket + if (token != '}') { + throw newSyntaxError('Angle bracket } expected'); } + getToken(); - ctx.arrow(point.x, point.y, angle, length); - ctx.fill(); - ctx.stroke(); + // remove temporary default properties + delete subgraph.node; + delete subgraph.edge; + delete subgraph.graph; + delete subgraph.parent; - // draw label - if (this.label) { - this._label(ctx, this.label, point.x, point.y); + // register at the parent graph + if (!graph.subgraphs) { + graph.subgraphs = []; } + graph.subgraphs.push(subgraph); } - else { - // draw circle - var x, y; - var radius = 0.25 * Math.max(100,this.physics.springLength); - var node = this.from; - if (!node.width) { - node.resize(ctx); - } - if (node.width > node.height) { - x = node.x + node.width * 0.5; - y = node.y - radius; - } - else { - x = node.x + radius; - y = node.y - node.height * 0.5; - } - this._circle(ctx, x, y, radius); - // draw all arrows - var angle = 0.2 * Math.PI; - var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; - point = this._pointOnCircle(x, y, radius, 0.5); - ctx.arrow(point.x, point.y, angle, length); - ctx.fill(); - ctx.stroke(); + return subgraph; + } - // draw label - if (this.label) { - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); - } + /** + * parse an attribute statement like "node [shape=circle fontSize=16]". + * Available keywords are 'node', 'edge', 'graph'. + * The previous list with default attributes will be replaced + * @param {Object} graph + * @returns {String | null} keyword Returns the name of the parsed attribute + * (node, edge, graph), or null if nothing + * is parsed. + */ + function parseAttributeStatement (graph) { + // attribute statements + if (token == 'node') { + getToken(); + + // node attributes + graph.node = parseAttributeList(); + return 'node'; } - }; + else if (token == 'edge') { + getToken(); - Edge.prototype._pointOnBezier = function(t) { - var via = this._getViaCoordinates(); + // edge attributes + graph.edge = parseAttributeList(); + return 'edge'; + } + else if (token == 'graph') { + getToken(); - var x = Math.pow(1-t,2)*this.from.x + (2*t*(1 - t))*via.x + Math.pow(t,2)*this.to.x; - var y = Math.pow(1-t,2)*this.from.y + (2*t*(1 - t))*via.y + Math.pow(t,2)*this.to.y; + // graph attributes + graph.graph = parseAttributeList(); + return 'graph'; + } - return {x:x,y:y}; + return null; } /** - * This function uses binary search to look for the point where the bezier curve crosses the border of the node. - * - * @param from - * @param ctx - * @returns {*} - * @private + * parse a node statement + * @param {Object} graph + * @param {String | Number} id */ - Edge.prototype._findBorderPosition = function(from,ctx) { - var maxIterations = 10; - var iteration = 0; - var low = 0; - var high = 1; - var pos,angle,distanceToBorder, distanceToNodes, difference; - var threshold = 0.2; - var node = this.to; - if (from == true) { - node = this.from; + function parseNodeStatement(graph, id) { + // node statement + var node = { + id: id + }; + var attr = parseAttributeList(); + if (attr) { + node.attr = attr; } + addNode(graph, node); - while (low <= high && iteration < maxIterations) { - var middle = (low + high) * 0.5; + // edge statements + parseEdge(graph, id); + } - pos = this._pointOnBezier(middle); - angle = Math.atan2((node.y - pos.y), (node.x - pos.x)); - distanceToBorder = node.distanceToBorder(ctx,angle); - distanceToNodes = Math.sqrt(Math.pow(pos.x-node.x,2) + Math.pow(pos.y-node.y,2)); - difference = distanceToBorder - distanceToNodes; - if (Math.abs(difference) < threshold) { - break; // found - } - else if (difference < 0) { // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node. - if (from == false) { - low = middle; - } - else { - high = middle; - } + /** + * Parse an edge or a series of edges + * @param {Object} graph + * @param {String | Number} from Id of the from node + */ + function parseEdge(graph, from) { + while (token == '->' || token == '--') { + var to; + var type = token; + getToken(); + + var subgraph = parseSubgraph(graph); + if (subgraph) { + to = subgraph; } else { - if (from == false) { - high = middle; - } - else { - low = middle; + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier or subgraph expected'); } + to = token; + addNode(graph, { + id: to + }); + getToken(); } - iteration++; - } - pos.t = middle; + // parse edge attributes + var attr = parseAttributeList(); - return pos; - }; + // create edge + var edge = createEdge(graph, from, to, type, attr); + addEdge(graph, edge); + + from = to; + } + } /** - * Redraw a edge as a line with an arrow - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private + * Parse a set with attributes, + * for example [label="1.000", shape=solid] + * @return {Object | null} attr */ - Edge.prototype._drawArrow = function(ctx) { - // set style - ctx.strokeStyle = this._getColor(); - ctx.fillStyle = ctx.strokeStyle; - ctx.lineWidth = this._getLineWidth(); + function parseAttributeList() { + var attr = null; - // set vars - var angle, length, arrowPos; + while (token == '[') { + getToken(); + attr = {}; + while (token !== '' && token != ']') { + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Attribute name expected'); + } + var name = token; - // if not connected to itself - if (this.from != this.to) { - // draw line - this._line(ctx); + getToken(); + if (token != '=') { + throw newSyntaxError('Equal sign = expected'); + } + getToken(); - // draw arrow head - if (this.options.smoothCurves.enabled == true) { - var via = this._getViaCoordinates(); - arrowPos = this._findBorderPosition(false, ctx); - var guidePos = this._pointOnBezier(Math.max(0.0, arrowPos.t - 0.1)) - angle = Math.atan2((arrowPos.y - guidePos.y), (arrowPos.x - guidePos.x)); + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Attribute value expected'); + } + var value = token; + setValue(attr, name, value); // name can be a path + + getToken(); + if (token ==',') { + getToken(); + } } - else { - angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var dx = (this.to.x - this.from.x); - var dy = (this.to.y - this.from.y); - var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); - var toBorderDist = this.to.distanceToBorder(ctx, angle); - var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; - arrowPos = {}; - arrowPos.x = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x; - arrowPos.y = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y; + if (token != ']') { + throw newSyntaxError('Bracket ] expected'); } + getToken(); + } - // draw arrow at the end of the line - length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; - ctx.arrow(arrowPos.x,arrowPos.y, angle, length); - ctx.fill(); - ctx.stroke(); + return attr; + } - // draw label - if (this.label) { - var point; - if (this.options.smoothCurves.enabled == true && via != null) { - point = this._pointOnBezier(0.5); + /** + * Create a syntax error with extra information on current token and index. + * @param {String} message + * @returns {SyntaxError} err + */ + function newSyntaxError(message) { + return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ')'); + } + + /** + * Chop off text after a maximum length + * @param {String} text + * @param {Number} maxLength + * @returns {String} + */ + function chop (text, maxLength) { + return (text.length <= maxLength) ? text : (text.substr(0, 27) + '...'); + } + + /** + * Execute a function fn for each pair of elements in two arrays + * @param {Array | *} array1 + * @param {Array | *} array2 + * @param {function} fn + */ + function forEach2(array1, array2, fn) { + if (Array.isArray(array1)) { + array1.forEach(function (elem1) { + if (Array.isArray(array2)) { + array2.forEach(function (elem2) { + fn(elem1, elem2); + }); } else { - point = this._pointOnLine(0.5); + fn(elem1, array2); } - this._label(ctx, this.label, point.x, point.y); - } + }); } else { - // draw circle - var node = this.from; - var x, y, arrow; - var radius = 0.25 * Math.max(100,this.physics.springLength); - if (!node.width) { - node.resize(ctx); - } - if (node.width > node.height) { - x = node.x + node.width * 0.5; - y = node.y - radius; - arrow = { - x: x, - y: node.y, - angle: 0.9 * Math.PI - }; + if (Array.isArray(array2)) { + array2.forEach(function (elem2) { + fn(array1, elem2); + }); } else { - x = node.x + radius; - y = node.y - node.height * 0.5; - arrow = { - x: node.x, - y: y, - angle: 0.6 * Math.PI - }; - } - ctx.beginPath(); - // TODO: similarly, for a line without arrows, draw to the border of the nodes instead of the center - ctx.arc(x, y, radius, 0, 2 * Math.PI, false); - ctx.stroke(); - - // draw all arrows - var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; - ctx.arrow(arrow.x, arrow.y, arrow.angle, length); - ctx.fill(); - ctx.stroke(); - - // draw label - if (this.label) { - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); + fn(array1, array2); } } - }; + } /** - * Calculate the distance between a point (x3,y3) and a line segment from - * (x1,y1) to (x2,y2). - * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment - * @param {number} x1 - * @param {number} y1 - * @param {number} x2 - * @param {number} y2 - * @param {number} x3 - * @param {number} y3 - * @private + * Convert a string containing a graph in DOT language into a map containing + * with nodes and edges in the format of graph. + * @param {String} data Text containing a graph in DOT-notation + * @return {Object} graphData */ - Edge.prototype._getDistanceToEdge = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point - var returnValue = 0; - if (this.from != this.to) { - if (this.options.smoothCurves.enabled == true) { - var xVia, yVia; - if (this.options.smoothCurves.enabled == true && this.options.smoothCurves.dynamic == true) { - xVia = this.via.x; - yVia = this.via.y; + function DOTToGraph (data) { + // parse the DOT file + var dotData = parseDOT(data); + var graphData = { + nodes: [], + edges: [], + options: {} + }; + + // copy the nodes + if (dotData.nodes) { + dotData.nodes.forEach(function (dotNode) { + var graphNode = { + id: dotNode.id, + label: String(dotNode.label || dotNode.id) + }; + merge(graphNode, dotNode.attr); + if (graphNode.image) { + graphNode.shape = 'image'; + } + graphData.nodes.push(graphNode); + }); + } + + // copy the edges + if (dotData.edges) { + /** + * Convert an edge in DOT format to an edge with VisGraph format + * @param {Object} dotEdge + * @returns {Object} graphEdge + */ + var convertEdge = function (dotEdge) { + var graphEdge = { + from: dotEdge.from, + to: dotEdge.to + }; + merge(graphEdge, dotEdge.attr); + graphEdge.style = (dotEdge.type == '->') ? 'arrow' : 'line'; + return graphEdge; + } + + dotData.edges.forEach(function (dotEdge) { + var from, to; + if (dotEdge.from instanceof Object) { + from = dotEdge.from.nodes; } else { - var via = this._getViaCoordinates(); - xVia = via.x; - yVia = via.y; + from = { + id: dotEdge.from + } } - var minDistance = 1e9; - var distance; - var i,t,x,y, lastX, lastY; - for (i = 0; i < 10; i++) { - t = 0.1*i; - x = Math.pow(1-t,2)*x1 + (2*t*(1 - t))*xVia + Math.pow(t,2)*x2; - y = Math.pow(1-t,2)*y1 + (2*t*(1 - t))*yVia + Math.pow(t,2)*y2; - if (i > 0) { - distance = this._getDistanceToLine(lastX,lastY,x,y, x3,y3); - minDistance = distance < minDistance ? distance : minDistance; + + if (dotEdge.to instanceof Object) { + to = dotEdge.to.nodes; + } + else { + to = { + id: dotEdge.to } - lastX = x; lastY = y; } - returnValue = minDistance; - } - else { - returnValue = this._getDistanceToLine(x1,y1,x2,y2,x3,y3); - } - } - else { - var x, y, dx, dy; - var radius = 0.25 * this.physics.springLength; - var node = this.from; - if (node.width > node.height) { - x = node.x + 0.5 * node.width; - y = node.y - radius; - } - else { - x = node.x + radius; - y = node.y - 0.5 * node.height; - } - dx = x - x3; - dy = y - y3; - returnValue = Math.abs(Math.sqrt(dx*dx + dy*dy) - radius); - } - if (this.labelDimensions.left < x3 && - this.labelDimensions.left + this.labelDimensions.width > x3 && - this.labelDimensions.top < y3 && - this.labelDimensions.top + this.labelDimensions.height > y3) { - return 0; + if (dotEdge.from instanceof Object && dotEdge.from.edges) { + dotEdge.from.edges.forEach(function (subEdge) { + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); + } + + forEach2(from, to, function (from, to) { + var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr); + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); + + if (dotEdge.to instanceof Object && dotEdge.to.edges) { + dotEdge.to.edges.forEach(function (subEdge) { + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); + } + }); } - else { - return returnValue; + + // copy the options + if (dotData.attr) { + graphData.options = dotData.attr; } - }; - Edge.prototype._getDistanceToLine = function(x1,y1,x2,y2,x3,y3) { - var px = x2-x1, - py = y2-y1, - something = px*px + py*py, - u = ((x3 - x1) * px + (y3 - y1) * py) / something; + return graphData; + } - if (u > 1) { - u = 1; + // exports + exports.parseDOT = parseDOT; + exports.DOTToGraph = DOTToGraph; + + +/***/ }, +/* 53 */ +/***/ function(module, exports, __webpack_require__) { + + + function parseGephi(gephiJSON, options) { + var edges = []; + var nodes = []; + this.options = { + edges: { + inheritColor: true + }, + nodes: { + allowedToMove: false, + parseColor: false + } + }; + + if (options !== undefined) { + this.options.nodes['allowedToMove'] = options.allowedToMove | false; + this.options.nodes['parseColor'] = options.parseColor | false; + this.options.edges['inheritColor'] = options.inheritColor | true; + } + + var gEdges = gephiJSON.edges; + var gNodes = gephiJSON.nodes; + for (var i = 0; i < gEdges.length; i++) { + var edge = {}; + var gEdge = gEdges[i]; + edge['id'] = gEdge.id; + edge['from'] = gEdge.source; + edge['to'] = gEdge.target; + edge['attributes'] = gEdge.attributes; + // edge['value'] = gEdge.attributes !== undefined ? gEdge.attributes.Weight : undefined; + // edge['width'] = edge['value'] !== undefined ? undefined : edgegEdge.size; + edge['color'] = gEdge.color; + edge['inheritColor'] = edge['color'] !== undefined ? false : this.options.inheritColor; + edges.push(edge); } - else if (u < 0) { - u = 0; + + for (var i = 0; i < gNodes.length; i++) { + var node = {}; + var gNode = gNodes[i]; + node['id'] = gNode.id; + node['attributes'] = gNode.attributes; + node['x'] = gNode.x; + node['y'] = gNode.y; + node['label'] = gNode.label; + if (this.options.nodes.parseColor == true) { + node['color'] = gNode.color; + } + else { + node['color'] = gNode.color !== undefined ? {background:gNode.color, border:gNode.color} : undefined; + } + node['radius'] = gNode.size; + node['allowedToMoveX'] = this.options.nodes.allowedToMove; + node['allowedToMoveY'] = this.options.nodes.allowedToMove; + nodes.push(node); } - var x = x1 + u * px, - y = y1 + u * py, - dx = x - x3, - dy = y - y3; + return {nodes:nodes, edges:edges}; + } - //# Note: If the actual distance does not matter, - //# if you only want to compare what this function - //# returns to other results of this function, you - //# can just return the squared distance instead - //# (i.e. remove the sqrt) to gain a little performance + exports.parseGephi = parseGephi; - return Math.sqrt(dx*dx + dy*dy); - }; +/***/ }, +/* 54 */ +/***/ function(module, exports, __webpack_require__) { + + var util = __webpack_require__(1); /** - * This allows the zoom level of the network to influence the rendering - * - * @param scale + * @class Groups + * This class can store groups and properties specific for groups. */ - Edge.prototype.setScale = function(scale) { - this.networkScaleInv = 1.0/scale; - }; - + function Groups() { + this.clear(); + this.defaultIndex = 0; + } - Edge.prototype.select = function() { - this.selected = true; - }; - Edge.prototype.unselect = function() { - this.selected = false; - }; + /** + * default constants for group colors + */ + Groups.DEFAULT = [ + {border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}, hover: {border: "#2B7CE9", background: "#D2E5FF"}}, // blue + {border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}, hover: {border: "#FFA500", background: "#FFFFA3"}}, // yellow + {border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}, hover: {border: "#FA0A10", background: "#FFAFB1"}}, // red + {border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}, hover: {border: "#41A906", background: "#A1EC76"}}, // green + {border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}, hover: {border: "#E129F0", background: "#F0B3F5"}}, // magenta + {border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}, hover: {border: "#7C29F0", background: "#D3BDF0"}}, // purple + {border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}, hover: {border: "#C37F00", background: "#FFCA66"}}, // orange + {border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}, hover: {border: "#4220FB", background: "#9B9BFD"}}, // darkblue + {border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}, hover: {border: "#FD5A77", background: "#FFD1D9"}}, // pink + {border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}, hover: {border: "#4AD63A", background: "#E6FFE3"}} // mint + ]; - Edge.prototype.positionBezierNode = function() { - if (this.via !== null && this.from !== null && this.to !== null) { - this.via.x = 0.5 * (this.from.x + this.to.x); - this.via.y = 0.5 * (this.from.y + this.to.y); - } - else if (this.via !== null) { - this.via.x = 0; - this.via.y = 0; - } - }; /** - * This function draws the control nodes for the manipulator. - * In order to enable this, only set the this.controlNodesEnabled to true. - * @param ctx + * Clear all groups */ - Edge.prototype._drawControlNodes = function(ctx) { - if (this.controlNodesEnabled == true) { - if (this.controlNodes.from === null && this.controlNodes.to === null) { - var nodeIdFrom = "edgeIdFrom:".concat(this.id); - var nodeIdTo = "edgeIdTo:".concat(this.id); - var constants = { - nodes:{group:'', radius:7, borderWidth:2, borderWidthSelected: 2}, - physics:{damping:0}, - clustering: {maxNodeSizeIncrements: 0 ,nodeScaling: {width:0, height: 0, radius:0}} - }; - this.controlNodes.from = new Node( - {id:nodeIdFrom, - shape:'dot', - color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}} - },{},{},constants); - this.controlNodes.to = new Node( - {id:nodeIdTo, - shape:'dot', - color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}} - },{},{},constants); - } - - this.controlNodes.positions = {}; - if (this.controlNodes.from.selected == false) { - this.controlNodes.positions.from = this.getControlNodeFromPosition(ctx); - this.controlNodes.from.x = this.controlNodes.positions.from.x; - this.controlNodes.from.y = this.controlNodes.positions.from.y; - } - if (this.controlNodes.to.selected == false) { - this.controlNodes.positions.to = this.getControlNodeToPosition(ctx); - this.controlNodes.to.x = this.controlNodes.positions.to.x; - this.controlNodes.to.y = this.controlNodes.positions.to.y; + Groups.prototype.clear = function () { + this.groups = {}; + this.groups.length = function() + { + var i = 0; + for ( var p in this ) { + if (this.hasOwnProperty(p)) { + i++; + } } - - this.controlNodes.from.draw(ctx); - this.controlNodes.to.draw(ctx); - } - else { - this.controlNodes = {from:null, to:null, positions:{}}; + return i; } }; - /** - * Enable control nodes. - * @private - */ - Edge.prototype._enableControlNodes = function() { - this.fromBackup = this.from; - this.toBackup = this.to; - this.controlNodesEnabled = true; - }; /** - * disable control nodes and remove from dynamicEdges from old node - * @private + * get group properties of a groupname. If groupname is not found, a new group + * is added. + * @param {*} groupname Can be a number, string, Date, etc. + * @return {Object} group The created group, containing all group properties */ - Edge.prototype._disableControlNodes = function() { - this.fromId = this.from.id; - this.toId = this.to.id; - if (this.fromId != this.fromBackup.id) { // from was changed, remove edge from old 'from' node dynamic edges - this.fromBackup.detachEdge(this); - } - else if (this.toId != this.toBackup.id) { // to was changed, remove edge from old 'to' node dynamic edges - this.toBackup.detachEdge(this); + Groups.prototype.get = function (groupname) { + var group = this.groups[groupname]; + if (group == undefined) { + // create new group + var index = this.defaultIndex % Groups.DEFAULT.length; + this.defaultIndex++; + group = {}; + group.color = Groups.DEFAULT[index]; + this.groups[groupname] = group; } - this.fromBackup = null; - this.toBackup = null; - this.controlNodesEnabled = false; + return group; }; - /** - * This checks if one of the control nodes is selected and if so, returns the control node object. Else it returns null. - * @param x - * @param y - * @returns {null} - * @private + * Add a custom group style + * @param {String} groupname + * @param {Object} style An object containing borderColor, + * backgroundColor, etc. + * @return {Object} group The created group object */ - Edge.prototype._getSelectedControlNode = function(x,y) { - var positions = this.controlNodes.positions; - var fromDistance = Math.sqrt(Math.pow(x - positions.from.x,2) + Math.pow(y - positions.from.y,2)); - var toDistance = Math.sqrt(Math.pow(x - positions.to.x ,2) + Math.pow(y - positions.to.y ,2)); - - if (fromDistance < 15) { - this.connectedNode = this.from; - this.from = this.controlNodes.from; - return this.controlNodes.from; - } - else if (toDistance < 15) { - this.connectedNode = this.to; - this.to = this.controlNodes.to; - return this.controlNodes.to; - } - else { - return null; - } + Groups.prototype.add = function (groupname, style) { + this.groups[groupname] = style; + return style; }; + module.exports = Groups; + + +/***/ }, +/* 55 */ +/***/ function(module, exports, __webpack_require__) { /** - * this resets the control nodes to their original position. - * @private + * @class Images + * This class loads images and keeps them stored. */ - Edge.prototype._restoreControlNodes = function() { - if (this.controlNodes.from.selected == true) { - this.from = this.connectedNode; - this.connectedNode = null; - this.controlNodes.from.unselect(); - } - else if (this.controlNodes.to.selected == true) { - this.to = this.connectedNode; - this.connectedNode = null; - this.controlNodes.to.unselect(); - } - }; + function Images() { + this.images = {}; + this.imageBroken = {}; + this.callback = undefined; + } /** - * this calculates the position of the control nodes on the edges of the parent nodes. - * - * @param ctx - * @returns {x: *, y: *} + * Set an onload callback function. This will be called each time an image + * is loaded + * @param {function} callback */ - Edge.prototype.getControlNodeFromPosition = function(ctx) { - // draw arrow head - var controlnodeFromPos; - if (this.options.smoothCurves.enabled == true) { - controlnodeFromPos = this._findBorderPosition(true, ctx); - } - else { - var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var dx = (this.to.x - this.from.x); - var dy = (this.to.y - this.from.y); - var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); - - var fromBorderDist = this.from.distanceToBorder(ctx, angle + Math.PI); - var fromBorderPoint = (edgeSegmentLength - fromBorderDist) / edgeSegmentLength; - controlnodeFromPos = {}; - controlnodeFromPos.x = (fromBorderPoint) * this.from.x + (1 - fromBorderPoint) * this.to.x; - controlnodeFromPos.y = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y; - } - - return controlnodeFromPos; + Images.prototype.setOnloadCallback = function(callback) { + this.callback = callback; }; /** - * this calculates the position of the control nodes on the edges of the parent nodes. * - * @param ctx - * @returns {{from: {x: number, y: number}, to: {x: *, y: *}}} + * @param {string} url Url of the image + * @param {string} url Url of an image to use if the url image is not found + * @return {Image} img The image object */ - Edge.prototype.getControlNodeToPosition = function(ctx) { - // draw arrow head - var controlnodeFromPos,controlnodeToPos; - if (this.options.smoothCurves.enabled == true) { - controlnodeToPos = this._findBorderPosition(false, ctx); - } - else { - var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var dx = (this.to.x - this.from.x); - var dy = (this.to.y - this.from.y); - var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); - var toBorderDist = this.to.distanceToBorder(ctx, angle); - var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; + Images.prototype.load = function(url, brokenUrl) { + var img = this.images[url]; // make a pointer + if (img === undefined) { + // create the image + var me = this; + img = new Image(); + img.onload = function () { + // IE11 fix -- thanks dponch! + if (this.width == 0) { + document.body.appendChild(this); + this.width = this.offsetWidth; + this.height = this.offsetHeight; + document.body.removeChild(this); + } - controlnodeToPos = {}; - controlnodeToPos.x = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x; - controlnodeToPos.y = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y; + if (me.callback) { + me.images[url] = img; + me.callback(this); + } + }; + + img.onerror = function () { + if (brokenUrl === undefined) { + console.error("Could not load image:", url); + delete this.src; + if (me.callback) { + me.callback(this); + } + } + else if (me.imageBroken[url] === true) { + console.error("Could not load brokenImage:", brokenUrl); + delete this.src; + if (me.callback) { + me.callback(this); + } + } + else { + this.src = brokenUrl; + me.imageBroken[url] = true; + } + }; + + img.src = url; } - return controlnodeToPos; + return img; }; - module.exports = Edge; + module.exports = Images; + /***/ }, -/* 53 */ +/* 56 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); @@ -26895,16 +26602,16 @@ return /******/ (function(modules) { // webpackBootstrap } // copy group properties - if (typeof this.options.group === 'number' || (typeof this.options.group === 'string' && this.options.group != '')) { - var groupObj = this.grouplist.get(this.options.group); + if (typeof properties.group === 'number' || (typeof properties.group === 'string' && properties.group != '')) { + var groupObj = this.grouplist.get(properties.group); util.deepExtend(this.options, groupObj); // the color object needs to be completely defined. Since groups can partially overwrite the colors, we parse it again, just in case. this.options.color = util.parseColor(this.options.color); } - // individual shape properties if (properties.radius !== undefined) {this.baseRadiusValue = this.options.radius;} if (properties.color !== undefined) {this.options.color = util.parseColor(properties.color);} + if (this.options.image !== undefined && this.options.image!= "") { if (this.imagelist) { this.imageObj = this.imagelist.load(this.options.image, this.options.brokenImage); @@ -27886,1213 +27593,1506 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 54 */ +/* 57 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); + var Node = __webpack_require__(56); /** - * @class Groups - * This class can store groups and properties specific for groups. + * @class Edge + * + * A edge connects two nodes + * @param {Object} properties Object with properties. Must contain + * At least properties from and to. + * Available properties: from (number), + * to (number), label (string, color (string), + * width (number), style (string), + * length (number), title (string) + * @param {Network} network A Network object, used to find and edge to + * nodes. + * @param {Object} constants An object with default values for + * example for the color */ - function Groups() { - this.clear(); - this.defaultIndex = 0; - } + function Edge (properties, network, networkConstants) { + if (!network) { + throw "No network provided"; + } + var fields = ['edges','physics']; + var constants = util.selectiveBridgeObject(fields,networkConstants); + this.options = constants.edges; + this.physics = constants.physics; + this.options['smoothCurves'] = networkConstants['smoothCurves']; - /** - * default constants for group colors - */ - Groups.DEFAULT = [ - {border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}, hover: {border: "#2B7CE9", background: "#D2E5FF"}}, // blue - {border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}, hover: {border: "#FFA500", background: "#FFFFA3"}}, // yellow - {border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}, hover: {border: "#FA0A10", background: "#FFAFB1"}}, // red - {border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}, hover: {border: "#41A906", background: "#A1EC76"}}, // green - {border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}, hover: {border: "#E129F0", background: "#F0B3F5"}}, // magenta - {border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}, hover: {border: "#7C29F0", background: "#D3BDF0"}}, // purple - {border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}, hover: {border: "#C37F00", background: "#FFCA66"}}, // orange - {border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}, hover: {border: "#4220FB", background: "#9B9BFD"}}, // darkblue - {border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}, hover: {border: "#FD5A77", background: "#FFD1D9"}}, // pink - {border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}, hover: {border: "#4AD63A", background: "#E6FFE3"}} // mint - ]; + this.network = network; + // initialize variables + this.id = undefined; + this.fromId = undefined; + this.toId = undefined; + this.title = undefined; + this.widthSelected = this.options.width * this.options.widthSelectionMultiplier; + this.value = undefined; + this.selected = false; + this.hover = false; + this.labelDimensions = {top:0,left:0,width:0,height:0,yLine:0}; // could be cached + this.dirtyLabel = true; + + this.from = null; // a node + this.to = null; // a node + this.via = null; // a temp node + + this.fromBackup = null; // used to clean up after reconnect + this.toBackup = null;; // used to clean up after reconnect + + // we use this to be able to reconnect the edge to a cluster if its node is put into a cluster + // by storing the original information we can revert to the original connection when the cluser is opened. + this.originalFromId = []; + this.originalToId = []; + + this.connected = false; + + this.widthFixed = false; + this.lengthFixed = false; + + this.setProperties(properties); + + this.controlNodesEnabled = false; + this.controlNodes = {from:null, to:null, positions:{}}; + this.connectedNode = null; + } /** - * Clear all groups + * Set or overwrite properties for the edge + * @param {Object} properties an object with properties + * @param {Object} constants and object with default, global properties */ - Groups.prototype.clear = function () { - this.groups = {}; - this.groups.length = function() - { - var i = 0; - for ( var p in this ) { - if (this.hasOwnProperty(p)) { - i++; - } + Edge.prototype.setProperties = function(properties) { + if (!properties) { + return; + } + + var fields = ['style','fontSize','fontFace','fontColor','fontFill','fontStrokeWidth','fontStrokeColor','width', + 'widthSelectionMultiplier','hoverWidth','arrowScaleFactor','dash','inheritColor','labelAlignment' + ]; + util.selectiveDeepExtend(fields, this.options, properties); + + if (properties.from !== undefined) {this.fromId = properties.from;} + if (properties.to !== undefined) {this.toId = properties.to;} + + if (properties.id !== undefined) {this.id = properties.id;} + if (properties.label !== undefined) {this.label = properties.label; this.dirtyLabel = true;} + + if (properties.title !== undefined) {this.title = properties.title;} + if (properties.value !== undefined) {this.value = properties.value;} + if (properties.length !== undefined) {this.physics.springLength = properties.length;} + + if (properties.color !== undefined) { + this.options.inheritColor = false; + if (util.isString(properties.color)) { + this.options.color.color = properties.color; + this.options.color.highlight = properties.color; + } + else { + if (properties.color.color !== undefined) {this.options.color.color = properties.color.color;} + if (properties.color.highlight !== undefined) {this.options.color.highlight = properties.color.highlight;} + if (properties.color.hover !== undefined) {this.options.color.hover = properties.color.hover;} } - return i; } - }; + // A node is connected when it has a from and to node. + this.connect(); + + this.widthFixed = this.widthFixed || (properties.width !== undefined); + this.lengthFixed = this.lengthFixed || (properties.length !== undefined); + + this.widthSelected = this.options.width* this.options.widthSelectionMultiplier; + + // set draw method based on style + switch (this.options.style) { + case 'line': this.draw = this._drawLine; break; + case 'arrow': this.draw = this._drawArrow; break; + case 'arrow-center': this.draw = this._drawArrowCenter; break; + case 'dash-line': this.draw = this._drawDashLine; break; + default: this.draw = this._drawLine; break; + } + + }; /** - * get group properties of a groupname. If groupname is not found, a new group - * is added. - * @param {*} groupname Can be a number, string, Date, etc. - * @return {Object} group The created group, containing all group properties + * Connect an edge to its nodes */ - Groups.prototype.get = function (groupname) { - var group = this.groups[groupname]; - if (group == undefined) { - // create new group - var index = this.defaultIndex % Groups.DEFAULT.length; - this.defaultIndex++; - group = {}; - group.color = Groups.DEFAULT[index]; - this.groups[groupname] = group; + Edge.prototype.connect = function () { + this.disconnect(); + + this.from = this.network.nodes[this.fromId] || null; + this.to = this.network.nodes[this.toId] || null; + this.connected = (this.from && this.to); + + if (this.connected) { + this.from.attachEdge(this); + this.to.attachEdge(this); + } + else { + if (this.from) { + this.from.detachEdge(this); + } + if (this.to) { + this.to.detachEdge(this); + } } - - return group; }; /** - * Add a custom group style - * @param {String} groupname - * @param {Object} style An object containing borderColor, - * backgroundColor, etc. - * @return {Object} group The created group object + * Disconnect an edge from its nodes */ - Groups.prototype.add = function (groupname, style) { - this.groups[groupname] = style; - return style; - }; + Edge.prototype.disconnect = function () { + if (this.from) { + this.from.detachEdge(this); + this.from = null; + } + if (this.to) { + this.to.detachEdge(this); + this.to = null; + } - module.exports = Groups; + this.connected = false; + }; + /** + * get the title of this edge. + * @return {string} title The title of the edge, or undefined when no title + * has been set. + */ + Edge.prototype.getTitle = function() { + return typeof this.title === "function" ? this.title() : this.title; + }; -/***/ }, -/* 55 */ -/***/ function(module, exports, __webpack_require__) { /** - * @class Images - * This class loads images and keeps them stored. + * Retrieve the value of the edge. Can be undefined + * @return {Number} value */ - function Images() { - this.images = {}; - this.imageBroken = {}; - this.callback = undefined; - } + Edge.prototype.getValue = function() { + return this.value; + }; /** - * Set an onload callback function. This will be called each time an image - * is loaded - * @param {function} callback + * Adjust the value range of the edge. The edge will adjust it's width + * based on its value. + * @param {Number} min + * @param {Number} max */ - Images.prototype.setOnloadCallback = function(callback) { - this.callback = callback; + Edge.prototype.setValueRange = function(min, max) { + if (!this.widthFixed && this.value !== undefined) { + var scale = (this.options.widthMax - this.options.widthMin) / (max - min); + this.options.width= (this.value - min) * scale + this.options.widthMin; + this.widthSelected = this.options.width* this.options.widthSelectionMultiplier; + } }; /** - * - * @param {string} url Url of the image - * @param {string} url Url of an image to use if the url image is not found - * @return {Image} img The image object + * Redraw a edge + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx */ - Images.prototype.load = function(url, brokenUrl) { - var img = this.images[url]; // make a pointer - if (img === undefined) { - // create the image - var me = this; - img = new Image(); - img.onload = function () { - // IE11 fix -- thanks dponch! - if (this.width == 0) { - document.body.appendChild(this); - this.width = this.offsetWidth; - this.height = this.offsetHeight; - document.body.removeChild(this); - } + Edge.prototype.draw = function(ctx) { + throw "Method draw not initialized in edge"; + }; - if (me.callback) { - me.images[url] = img; - me.callback(this); - } - }; + /** + * Check if this object is overlapping with the provided object + * @param {Object} obj an object with parameters left, top + * @return {boolean} True if location is located on the edge + */ + Edge.prototype.isOverlappingWith = function(obj) { + if (this.connected) { + var distMax = 10; + var xFrom = this.from.x; + var yFrom = this.from.y; + var xTo = this.to.x; + var yTo = this.to.y; + var xObj = obj.left; + var yObj = obj.top; - img.onerror = function () { - if (brokenUrl === undefined) { - console.error("Could not load image:", url); - delete this.src; - if (me.callback) { - me.callback(this); - } - } - else if (me.imageBroken[url] === true) { - console.error("Could not load brokenImage:", brokenUrl); - delete this.src; - if (me.callback) { - me.callback(this); - } - } - else { - this.src = brokenUrl; - me.imageBroken[url] = true; - } - }; + var dist = this._getDistanceToEdge(xFrom, yFrom, xTo, yTo, xObj, yObj); - img.src = url; + return (dist < distMax); + } + else { + return false } - - return img; }; - module.exports = Images; + Edge.prototype._getColor = function() { + var colorObj = this.options.color; + if (this.options.inheritColor == "to") { + colorObj = { + highlight: this.to.options.color.highlight.border, + hover: this.to.options.color.hover.border, + color: this.to.options.color.border + }; + } + else if (this.options.inheritColor == "from" || this.options.inheritColor == true) { + colorObj = { + highlight: this.from.options.color.highlight.border, + hover: this.from.options.color.hover.border, + color: this.from.options.color.border + }; + } + if (this.selected == true) {return colorObj.highlight;} + else if (this.hover == true) {return colorObj.hover;} + else {return colorObj.color;} + }; -/***/ }, -/* 56 */ -/***/ function(module, exports, __webpack_require__) { /** - * Popup is a class to create a popup window with some text - * @param {Element} container The container object. - * @param {Number} [x] - * @param {Number} [y] - * @param {String} [text] - * @param {Object} [style] An object containing borderColor, - * backgroundColor, etc. + * Redraw a edge as a line + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private */ - function Popup(container, x, y, text, style) { - if (container) { - this.container = container; - } - else { - this.container = document.body; - } + Edge.prototype._drawLine = function(ctx) { + // set style + ctx.strokeStyle = this._getColor(); + ctx.lineWidth = this._getLineWidth(); - // x, y and text are optional, see if a style object was passed in their place - if (style === undefined) { - if (typeof x === "object") { - style = x; - x = undefined; - } else if (typeof text === "object") { - style = text; - text = undefined; - } else { - // for backwards compatibility, in case clients other than Network are creating Popup directly - style = { - fontColor: 'black', - fontSize: 14, // px - fontFace: 'verdana', - color: { - border: '#666', - background: '#FFFFC6' - } + if (this.from != this.to) { + // draw line + var via = this._line(ctx); + + // draw label + var point; + if (this.label) { + if (this.options.smoothCurves.enabled == true && via != null) { + var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); + var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); + point = {x:midpointX, y:midpointY}; } + else { + point = this._pointOnLine(0.5); + } + this._label(ctx, this.label, point.x, point.y); } } - - this.x = 0; - this.y = 0; - this.padding = 5; - - if (x !== undefined && y !== undefined ) { - this.setPosition(x, y); - } - if (text !== undefined) { - this.setText(text); + else { + var x, y; + var radius = this.physics.springLength / 4; + var node = this.from; + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width / 2; + y = node.y - radius; + } + else { + x = node.x + radius; + y = node.y - node.height / 2; + } + this._circle(ctx, x, y, radius); + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); } - - // create the frame - this.frame = document.createElement("div"); - var styleAttr = this.frame.style; - styleAttr.position = "absolute"; - styleAttr.visibility = "hidden"; - styleAttr.border = "1px solid " + style.color.border; - styleAttr.color = style.fontColor; - styleAttr.fontSize = style.fontSize + "px"; - styleAttr.fontFamily = style.fontFace; - styleAttr.padding = this.padding + "px"; - styleAttr.backgroundColor = style.color.background; - styleAttr.borderRadius = "3px"; - styleAttr.MozBorderRadius = "3px"; - styleAttr.WebkitBorderRadius = "3px"; - styleAttr.boxShadow = "3px 3px 10px rgba(128, 128, 128, 0.5)"; - styleAttr.whiteSpace = "nowrap"; - this.container.appendChild(this.frame); - } - - /** - * @param {number} x Horizontal position of the popup window - * @param {number} y Vertical position of the popup window - */ - Popup.prototype.setPosition = function(x, y) { - this.x = parseInt(x); - this.y = parseInt(y); }; /** - * Set the content for the popup window. This can be HTML code or text. - * @param {string | Element} content + * Get the line width of the edge. Depends on width and whether one of the + * connected nodes is selected. + * @return {Number} width + * @private */ - Popup.prototype.setText = function(content) { - if (content instanceof Element) { - this.frame.innerHTML = ''; - this.frame.appendChild(content); + Edge.prototype._getLineWidth = function() { + if (this.selected == true) { + return Math.max(Math.min(this.widthSelected, this.options.widthMax), 0.3*this.networkScaleInv); } else { - this.frame.innerHTML = content; // string containing text or HTML + if (this.hover == true) { + return Math.max(Math.min(this.options.hoverWidth, this.options.widthMax), 0.3*this.networkScaleInv); + } + else { + return Math.max(this.options.width, 0.3*this.networkScaleInv); + } } }; - /** - * Show the popup window - * @param {boolean} show Optional. Show or hide the window - */ - Popup.prototype.show = function (show) { - if (show === undefined) { - show = true; + Edge.prototype._getViaCoordinates = function () { + if (this.options.smoothCurves.dynamic == true && this.options.smoothCurves.enabled == true ) { + return this.via; } + else if (this.options.smoothCurves.enabled == false) { + return {x:0,y:0}; + } + else { + var xVia = null; + var yVia = null; + var factor = this.options.smoothCurves.roundness; + var type = this.options.smoothCurves.type; - if (show) { - var height = this.frame.clientHeight; - var width = this.frame.clientWidth; - var maxHeight = this.frame.parentNode.clientHeight; - var maxWidth = this.frame.parentNode.clientWidth; - - var top = (this.y - height); - if (top + height + this.padding > maxHeight) { - top = maxHeight - height - this.padding; + var dx = Math.abs(this.from.x - this.to.x); + var dy = Math.abs(this.from.y - this.to.y); + if (type == 'discrete' || type == 'diagonalCross') { + if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { + if (this.from.y > this.to.y) { + if (this.from.x < this.to.x) { + xVia = this.from.x + factor * dy; + yVia = this.from.y - factor * dy; + } + else if (this.from.x > this.to.x) { + xVia = this.from.x - factor * dy; + yVia = this.from.y - factor * dy; + } + } + else if (this.from.y < this.to.y) { + if (this.from.x < this.to.x) { + xVia = this.from.x + factor * dy; + yVia = this.from.y + factor * dy; + } + else if (this.from.x > this.to.x) { + xVia = this.from.x - factor * dy; + yVia = this.from.y + factor * dy; + } + } + if (type == "discrete") { + xVia = dx < factor * dy ? this.from.x : xVia; + } + } + else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { + if (this.from.y > this.to.y) { + if (this.from.x < this.to.x) { + xVia = this.from.x + factor * dx; + yVia = this.from.y - factor * dx; + } + else if (this.from.x > this.to.x) { + xVia = this.from.x - factor * dx; + yVia = this.from.y - factor * dx; + } + } + else if (this.from.y < this.to.y) { + if (this.from.x < this.to.x) { + xVia = this.from.x + factor * dx; + yVia = this.from.y + factor * dx; + } + else if (this.from.x > this.to.x) { + xVia = this.from.x - factor * dx; + yVia = this.from.y + factor * dx; + } + } + if (type == "discrete") { + yVia = dy < factor * dx ? this.from.y : yVia; + } + } } - if (top < this.padding) { - top = this.padding; + else if (type == "straightCross") { + if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { // up - down + xVia = this.from.x; + if (this.from.y < this.to.y) { + yVia = this.to.y - (1 - factor) * dy; + } + else { + yVia = this.to.y + (1 - factor) * dy; + } + } + else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { // left - right + if (this.from.x < this.to.x) { + xVia = this.to.x - (1 - factor) * dx; + } + else { + xVia = this.to.x + (1 - factor) * dx; + } + yVia = this.from.y; + } } - - var left = this.x; - if (left + width + this.padding > maxWidth) { - left = maxWidth - width - this.padding; + else if (type == 'horizontal') { + if (this.from.x < this.to.x) { + xVia = this.to.x - (1 - factor) * dx; + } + else { + xVia = this.to.x + (1 - factor) * dx; + } + yVia = this.from.y; } - if (left < this.padding) { - left = this.padding; + else if (type == 'vertical') { + xVia = this.from.x; + if (this.from.y < this.to.y) { + yVia = this.to.y - (1 - factor) * dy; + } + else { + yVia = this.to.y + (1 - factor) * dy; + } + } + else { // continuous + if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { + if (this.from.y > this.to.y) { + if (this.from.x < this.to.x) { + // console.log(1) + xVia = this.from.x + factor * dy; + yVia = this.from.y - factor * dy; + xVia = this.to.x < xVia ? this.to.x : xVia; + } + else if (this.from.x > this.to.x) { + // console.log(2) + xVia = this.from.x - factor * dy; + yVia = this.from.y - factor * dy; + xVia = this.to.x > xVia ? this.to.x : xVia; + } + } + else if (this.from.y < this.to.y) { + if (this.from.x < this.to.x) { + // console.log(3) + xVia = this.from.x + factor * dy; + yVia = this.from.y + factor * dy; + xVia = this.to.x < xVia ? this.to.x : xVia; + } + else if (this.from.x > this.to.x) { + // console.log(4, this.from.x, this.to.x) + xVia = this.from.x - factor * dy; + yVia = this.from.y + factor * dy; + xVia = this.to.x > xVia ? this.to.x : xVia; + } + } + } + else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { + if (this.from.y > this.to.y) { + if (this.from.x < this.to.x) { + // console.log(5) + xVia = this.from.x + factor * dx; + yVia = this.from.y - factor * dx; + yVia = this.to.y > yVia ? this.to.y : yVia; + } + else if (this.from.x > this.to.x) { + // console.log(6) + xVia = this.from.x - factor * dx; + yVia = this.from.y - factor * dx; + yVia = this.to.y > yVia ? this.to.y : yVia; + } + } + else if (this.from.y < this.to.y) { + if (this.from.x < this.to.x) { + // console.log(7) + xVia = this.from.x + factor * dx; + yVia = this.from.y + factor * dx; + yVia = this.to.y < yVia ? this.to.y : yVia; + } + else if (this.from.x > this.to.x) { + // console.log(8) + xVia = this.from.x - factor * dx; + yVia = this.from.y + factor * dx; + yVia = this.to.y < yVia ? this.to.y : yVia; + } + } + } } - this.frame.style.left = left + "px"; - this.frame.style.top = top + "px"; - this.frame.style.visibility = "visible"; + + return {x: xVia, y: yVia}; + } + }; + + /** + * Draw a line between two nodes + * @param {CanvasRenderingContext2D} ctx + * @private + */ + Edge.prototype._line = function (ctx) { + // draw a straight line + ctx.beginPath(); + ctx.moveTo(this.from.x, this.from.y); + if (this.options.smoothCurves.enabled == true) { + if (this.options.smoothCurves.dynamic == false) { + var via = this._getViaCoordinates(); + if (via.x == null) { + ctx.lineTo(this.to.x, this.to.y); + ctx.stroke(); + return null; + } + else { + // this.via.x = via.x; + // this.via.y = via.y; + ctx.quadraticCurveTo(via.x,via.y,this.to.x, this.to.y); + ctx.stroke(); + return via; + } + } + else { + ctx.quadraticCurveTo(this.via.x,this.via.y,this.to.x, this.to.y); + ctx.stroke(); + return this.via; + } } else { - this.hide(); + ctx.lineTo(this.to.x, this.to.y); + ctx.stroke(); + return null; } }; /** - * Hide the popup window + * Draw a line from a node to itself, a circle + * @param {CanvasRenderingContext2D} ctx + * @param {Number} x + * @param {Number} y + * @param {Number} radius + * @private */ - Popup.prototype.hide = function () { - this.frame.style.visibility = "hidden"; + Edge.prototype._circle = function (ctx, x, y, radius) { + // draw a circle + ctx.beginPath(); + ctx.arc(x, y, radius, 0, 2 * Math.PI, false); + ctx.stroke(); }; - module.exports = Popup; - - -/***/ }, -/* 57 */ -/***/ function(module, exports, __webpack_require__) { - /** - * Parse a text source containing data in DOT language into a JSON object. - * The object contains two lists: one with nodes and one with edges. - * - * DOT language reference: http://www.graphviz.org/doc/info/lang.html - * - * @param {String} data Text containing a graph in DOT-notation - * @return {Object} graph An object containing two parameters: - * {Object[]} nodes - * {Object[]} edges + * Draw label with white background and with the middle at (x, y) + * @param {CanvasRenderingContext2D} ctx + * @param {String} text + * @param {Number} x + * @param {Number} y + * @private */ - function parseDOT (data) { - dot = data; - return parseGraph(); - } - - // token types enumeration - var TOKENTYPE = { - NULL : 0, - DELIMITER : 1, - IDENTIFIER: 2, - UNKNOWN : 3 - }; + Edge.prototype._label = function (ctx, text, x, y) { + if (text) { + ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") + + this.options.fontSize + "px " + this.options.fontFace; + var yLine; - // map with all delimiters - var DELIMITERS = { - '{': true, - '}': true, - '[': true, - ']': true, - ';': true, - '=': true, - ',': true, + if (this.dirtyLabel == true) { + var lines = String(text).split('\n'); + var lineCount = lines.length; + var fontSize = Number(this.options.fontSize); + yLine = y + (1 - lineCount) / 2 * fontSize; - '->': true, - '--': true - }; + var width = ctx.measureText(lines[0]).width; + for (var i = 1; i < lineCount; i++) { + var lineWidth = ctx.measureText(lines[i]).width; + width = lineWidth > width ? lineWidth : width; + } + var height = this.options.fontSize * lineCount; + var left = x - width / 2; + var top = y - height / 2; - var dot = ''; // current dot file - var index = 0; // current index in dot file - var c = ''; // current token character in expr - var token = ''; // current token - var tokenType = TOKENTYPE.NULL; // type of the token + // cache + this.labelDimensions = {top:top,left:left,width:width,height:height,yLine:yLine}; + } - /** - * Get the first character from the dot file. - * The character is stored into the char c. If the end of the dot file is - * reached, the function puts an empty string in c. - */ - function first() { - index = 0; - c = dot.charAt(0); - } + var yLine = this.labelDimensions.yLine; + + ctx.save(); + + if (this.options.labelAlignment != "horizontal"){ + ctx.translate(x, yLine); + this._rotateForLabelAlignment(ctx); + x = 0; + yLine = 0; + } - /** - * Get the next character from the dot file. - * The character is stored into the char c. If the end of the dot file is - * reached, the function puts an empty string in c. - */ - function next() { - index++; - c = dot.charAt(index); - } + + this._drawLabelRect(ctx); + this._drawLabelText(ctx,x,yLine, lines, lineCount, fontSize); + + ctx.restore(); + } + }; /** - * Preview the next character from the dot file. - * @return {String} cNext + * Rotates the canvas so the text is most readable + * @param {CanvasRenderingContext2D} ctx + * @private */ - function nextPreview() { - return dot.charAt(index + 1); - } + Edge.prototype._rotateForLabelAlignment = function(ctx) { + var dy = this.from.y - this.to.y; + var dx = this.from.x - this.to.x; + var angleInDegrees = Math.atan2(dy, dx); - /** - * Test whether given character is alphabetic or numeric - * @param {String} c - * @return {Boolean} isAlphaNumeric - */ - var regexAlphaNumeric = /[a-zA-Z_0-9.:#]/; - function isAlphaNumeric(c) { - return regexAlphaNumeric.test(c); - } + // rotate so label it is readable + if((angleInDegrees < -1 && dx < 0) || (angleInDegrees > 0 && dx < 0)){ + angleInDegrees = angleInDegrees + Math.PI; + } + + ctx.rotate(angleInDegrees); + }; /** - * Merge all properties of object b into object b - * @param {Object} a - * @param {Object} b - * @return {Object} a + * Draws the label rectangle + * @param {CanvasRenderingContext2D} ctx + * @param {String} labelAlignment + * @private */ - function merge (a, b) { - if (!a) { - a = {}; - } + Edge.prototype._drawLabelRect = function(ctx) { + if (this.options.fontFill !== undefined && this.options.fontFill !== null && this.options.fontFill !== "none") { + ctx.fillStyle = this.options.fontFill; + + var lineMargin = 2; - if (b) { - for (var name in b) { - if (b.hasOwnProperty(name)) { - a[name] = b[name]; - } + if (this.options.labelAlignment == 'line-center') { + ctx.fillRect(-this.labelDimensions.width * 0.5, -this.labelDimensions.height * 0.5, this.labelDimensions.width, this.labelDimensions.height); + } + else if (this.options.labelAlignment == 'line-above') { + ctx.fillRect(-this.labelDimensions.width * 0.5, -(this.labelDimensions.height + lineMargin), this.labelDimensions.width, this.labelDimensions.height); + } + else if (this.options.labelAlignment == 'line-below') { + ctx.fillRect(-this.labelDimensions.width * 0.5, lineMargin, this.labelDimensions.width, this.labelDimensions.height); + } + else { + ctx.fillRect(this.labelDimensions.left, this.labelDimensions.top, this.labelDimensions.width, this.labelDimensions.height); } } - return a; - } + }; /** - * Set a value in an object, where the provided parameter name can be a - * path with nested parameters. For example: - * - * var obj = {a: 2}; - * setValue(obj, 'b.c', 3); // obj = {a: 2, b: {c: 3}} - * - * @param {Object} obj - * @param {String} path A parameter name or dot-separated parameter path, - * like "color.highlight.border". - * @param {*} value + * Draws the label text + * @param {CanvasRenderingContext2D} ctx + * @param {Number} x + * @param {Number} yLine + * @param {Array} lines + * @param {Number} lineCount + * @param {Number} fontSize + * @private */ - function setValue(obj, path, value) { - var keys = path.split('.'); - var o = obj; - while (keys.length) { - var key = keys.shift(); - if (keys.length) { - // this isn't the end point - if (!o[key]) { - o[key] = {}; - } - o = o[key]; + Edge.prototype._drawLabelText = function(ctx, x, yLine, lines, lineCount, fontSize) { + // draw text + ctx.fillStyle = this.options.fontColor || "black"; + ctx.textAlign = "center"; + + // check for label alignment + if (this.options.labelAlignment != 'horizontal') { + var lineMargin = 2; + if (this.options.labelAlignment == 'line-above') { + ctx.textBaseline = "alphabetic"; + yLine -= 2 * lineMargin; // distance from edge, required because we use alphabetic. Alphabetic has less difference between browsers + } + else if (this.options.labelAlignment == 'line-below') { + ctx.textBaseline = "hanging"; + yLine += 2 * lineMargin;// distance from edge, required because we use hanging. Hanging has less difference between browsers } else { - // this is the end point - o[key] = value; + ctx.textBaseline = "middle"; } } - } + else { + ctx.textBaseline = "middle"; + } + + // check for strokeWidth + if (this.options.fontStrokeWidth > 0){ + ctx.lineWidth = this.options.fontStrokeWidth; + ctx.strokeStyle = this.options.fontStrokeColor; + ctx.lineJoin = 'round'; + } + for (var i = 0; i < lineCount; i++) { + if(this.options.fontStrokeWidth > 0){ + ctx.strokeText(lines[i], x, yLine); + } + ctx.fillText(lines[i], x, yLine); + yLine += fontSize; + } + }; /** - * Add a node to a graph object. If there is already a node with - * the same id, their attributes will be merged. - * @param {Object} graph - * @param {Object} node + * Redraw a edge as a dashed line + * Draw this edge in the given canvas + * @author David Jordan + * @date 2012-08-08 + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private */ - function addNode(graph, node) { - var i, len; - var current = null; - - // find root graph (in case of subgraph) - var graphs = [graph]; // list with all graphs from current graph to root graph - var root = graph; - while (root.parent) { - graphs.push(root.parent); - root = root.parent; - } + Edge.prototype._drawDashLine = function(ctx) { + // set style + ctx.strokeStyle = this._getColor(); + ctx.lineWidth = this._getLineWidth(); - // find existing node (at root level) by its id - if (root.nodes) { - for (i = 0, len = root.nodes.length; i < len; i++) { - if (node.id === root.nodes[i].id) { - current = root.nodes[i]; - break; - } + var via = null; + // only firefox and chrome support this method, else we use the legacy one. + if (ctx.setLineDash !== undefined) { + ctx.save(); + // configure the dash pattern + var pattern = [0]; + if (this.options.dash.length !== undefined && this.options.dash.gap !== undefined) { + pattern = [this.options.dash.length,this.options.dash.gap]; } - } - - if (!current) { - // this is a new node - current = { - id: node.id - }; - if (graph.node) { - // clone default attributes - current.attr = merge(current.attr, graph.node); + else { + pattern = [5,5]; } - } - // add node to this (sub)graph and all its parent graphs - for (i = graphs.length - 1; i >= 0; i--) { - var g = graphs[i]; + // set dash settings for chrome or firefox + ctx.setLineDash(pattern); + ctx.lineDashOffset = 0; - if (!g.nodes) { - g.nodes = []; + // draw the line + via = this._line(ctx); + + // restore the dash settings. + ctx.setLineDash([0]); + ctx.lineDashOffset = 0; + ctx.restore(); + } + else { // unsupporting smooth lines + // draw dashed line + ctx.beginPath(); + ctx.lineCap = 'round'; + if (this.options.dash.altLength !== undefined) //If an alt dash value has been set add to the array this value + { + ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, + [this.options.dash.length,this.options.dash.gap,this.options.dash.altLength,this.options.dash.gap]); } - if (g.nodes.indexOf(current) == -1) { - g.nodes.push(current); + else if (this.options.dash.length !== undefined && this.options.dash.gap !== undefined) //If a dash and gap value has been set add to the array this value + { + ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, + [this.options.dash.length,this.options.dash.gap]); + } + else //If all else fails draw a line + { + ctx.moveTo(this.from.x, this.from.y); + ctx.lineTo(this.to.x, this.to.y); } + ctx.stroke(); } - // merge attributes - if (node.attr) { - current.attr = merge(current.attr, node.attr); + // draw label + if (this.label) { + var point; + if (this.options.smoothCurves.enabled == true && via != null) { + var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); + var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); + point = {x:midpointX, y:midpointY}; + } + else { + point = this._pointOnLine(0.5); + } + this._label(ctx, this.label, point.x, point.y); } - } + }; /** - * Add an edge to a graph object - * @param {Object} graph - * @param {Object} edge + * Get a point on a line + * @param {Number} percentage. Value between 0 (line start) and 1 (line end) + * @return {Object} point + * @private */ - function addEdge(graph, edge) { - if (!graph.edges) { - graph.edges = []; + Edge.prototype._pointOnLine = function (percentage) { + return { + x: (1 - percentage) * this.from.x + percentage * this.to.x, + y: (1 - percentage) * this.from.y + percentage * this.to.y } - graph.edges.push(edge); - if (graph.edge) { - var attr = merge({}, graph.edge); // clone default attributes - edge.attr = merge(attr, edge.attr); // merge attributes + }; + + /** + * Get a point on a circle + * @param {Number} x + * @param {Number} y + * @param {Number} radius + * @param {Number} percentage. Value between 0 (line start) and 1 (line end) + * @return {Object} point + * @private + */ + Edge.prototype._pointOnCircle = function (x, y, radius, percentage) { + var angle = (percentage - 3/8) * 2 * Math.PI; + return { + x: x + radius * Math.cos(angle), + y: y - radius * Math.sin(angle) } - } + }; /** - * Create an edge to a graph object - * @param {Object} graph - * @param {String | Number | Object} from - * @param {String | Number | Object} to - * @param {String} type - * @param {Object | null} attr - * @return {Object} edge + * Redraw a edge as a line with an arrow halfway the line + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private */ - function createEdge(graph, from, to, type, attr) { - var edge = { - from: from, - to: to, - type: type - }; + Edge.prototype._drawArrowCenter = function(ctx) { + var point; + // set style + ctx.strokeStyle = this._getColor(); + ctx.fillStyle = ctx.strokeStyle; + ctx.lineWidth = this._getLineWidth(); - if (graph.edge) { - edge.attr = merge({}, graph.edge); // clone default attributes + if (this.from != this.to) { + // draw line + var via = this._line(ctx); + + var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; + // draw an arrow halfway the line + if (this.options.smoothCurves.enabled == true && via != null) { + var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); + var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); + point = {x:midpointX, y:midpointY}; + } + else { + point = this._pointOnLine(0.5); + } + + ctx.arrow(point.x, point.y, angle, length); + ctx.fill(); + ctx.stroke(); + + // draw label + if (this.label) { + this._label(ctx, this.label, point.x, point.y); + } } - edge.attr = merge(edge.attr || {}, attr); // merge attributes + else { + // draw circle + var x, y; + var radius = 0.25 * Math.max(100,this.physics.springLength); + var node = this.from; + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width * 0.5; + y = node.y - radius; + } + else { + x = node.x + radius; + y = node.y - node.height * 0.5; + } + this._circle(ctx, x, y, radius); - return edge; + // draw all arrows + var angle = 0.2 * Math.PI; + var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; + point = this._pointOnCircle(x, y, radius, 0.5); + ctx.arrow(point.x, point.y, angle, length); + ctx.fill(); + ctx.stroke(); + + // draw label + if (this.label) { + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); + } + } + }; + + Edge.prototype._pointOnBezier = function(t) { + var via = this._getViaCoordinates(); + + var x = Math.pow(1-t,2)*this.from.x + (2*t*(1 - t))*via.x + Math.pow(t,2)*this.to.x; + var y = Math.pow(1-t,2)*this.from.y + (2*t*(1 - t))*via.y + Math.pow(t,2)*this.to.y; + + return {x:x,y:y}; } /** - * Get next token in the current dot file. - * The token and token type are available as token and tokenType + * This function uses binary search to look for the point where the bezier curve crosses the border of the node. + * + * @param from + * @param ctx + * @returns {*} + * @private */ - function getToken() { - tokenType = TOKENTYPE.NULL; - token = ''; - - // skip over whitespaces - while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter - next(); + Edge.prototype._findBorderPosition = function(from,ctx) { + var maxIterations = 10; + var iteration = 0; + var low = 0; + var high = 1; + var pos,angle,distanceToBorder, distanceToNodes, difference; + var threshold = 0.2; + var node = this.to; + if (from == true) { + node = this.from; } - do { - var isComment = false; + while (low <= high && iteration < maxIterations) { + var middle = (low + high) * 0.5; - // skip comment - if (c == '#') { - // find the previous non-space character - var i = index - 1; - while (dot.charAt(i) == ' ' || dot.charAt(i) == '\t') { - i--; + pos = this._pointOnBezier(middle); + angle = Math.atan2((node.y - pos.y), (node.x - pos.x)); + distanceToBorder = node.distanceToBorder(ctx,angle); + distanceToNodes = Math.sqrt(Math.pow(pos.x-node.x,2) + Math.pow(pos.y-node.y,2)); + difference = distanceToBorder - distanceToNodes; + if (Math.abs(difference) < threshold) { + break; // found + } + else if (difference < 0) { // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node. + if (from == false) { + low = middle; } - if (dot.charAt(i) == '\n' || dot.charAt(i) == '') { - // the # is at the start of a line, this is indeed a line comment - while (c != '' && c != '\n') { - next(); - } - isComment = true; + else { + high = middle; } } - if (c == '/' && nextPreview() == '/') { - // skip line comment - while (c != '' && c != '\n') { - next(); + else { + if (from == false) { + high = middle; } - isComment = true; - } - if (c == '/' && nextPreview() == '*') { - // skip block comment - while (c != '') { - if (c == '*' && nextPreview() == '/') { - // end of block comment found. skip these last two characters - next(); - next(); - break; - } - else { - next(); - } + else { + low = middle; } - isComment = true; } - // skip over whitespaces - while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter - next(); - } + iteration++; } - while (isComment); + pos.t = middle; - // check for end of dot file - if (c == '') { - // token is still empty - tokenType = TOKENTYPE.DELIMITER; - return; - } + return pos; + }; - // check for delimiters consisting of 2 characters - var c2 = c + nextPreview(); - if (DELIMITERS[c2]) { - tokenType = TOKENTYPE.DELIMITER; - token = c2; - next(); - next(); - return; - } + /** + * Redraw a edge as a line with an arrow + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private + */ + Edge.prototype._drawArrow = function(ctx) { + // set style + ctx.strokeStyle = this._getColor(); + ctx.fillStyle = ctx.strokeStyle; + ctx.lineWidth = this._getLineWidth(); - // check for delimiters consisting of 1 character - if (DELIMITERS[c]) { - tokenType = TOKENTYPE.DELIMITER; - token = c; - next(); - return; - } + // set vars + var angle, length, arrowPos; - // check for an identifier (number or string) - // TODO: more precise parsing of numbers/strings (and the port separator ':') - if (isAlphaNumeric(c) || c == '-') { - token += c; - next(); + // if not connected to itself + if (this.from != this.to) { + // draw line + this._line(ctx); - while (isAlphaNumeric(c)) { - token += c; - next(); - } - if (token == 'false') { - token = false; // convert to boolean - } - else if (token == 'true') { - token = true; // convert to boolean + // draw arrow head + if (this.options.smoothCurves.enabled == true) { + var via = this._getViaCoordinates(); + arrowPos = this._findBorderPosition(false, ctx); + var guidePos = this._pointOnBezier(Math.max(0.0, arrowPos.t - 0.1)) + angle = Math.atan2((arrowPos.y - guidePos.y), (arrowPos.x - guidePos.x)); } - else if (!isNaN(Number(token))) { - token = Number(token); // convert to number + else { + angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var dx = (this.to.x - this.from.x); + var dy = (this.to.y - this.from.y); + var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); + var toBorderDist = this.to.distanceToBorder(ctx, angle); + var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; + + arrowPos = {}; + arrowPos.x = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x; + arrowPos.y = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y; } - tokenType = TOKENTYPE.IDENTIFIER; - return; - } - // check for a string enclosed by double quotes - if (c == '"') { - next(); - while (c != '' && (c != '"' || (c == '"' && nextPreview() == '"'))) { - token += c; - if (c == '"') { // skip the escape character - next(); + // draw arrow at the end of the line + length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; + ctx.arrow(arrowPos.x,arrowPos.y, angle, length); + ctx.fill(); + ctx.stroke(); + + // draw label + if (this.label) { + var point; + if (this.options.smoothCurves.enabled == true && via != null) { + point = this._pointOnBezier(0.5); } - next(); - } - if (c != '"') { - throw newSyntaxError('End of string " expected'); + else { + point = this._pointOnLine(0.5); + } + this._label(ctx, this.label, point.x, point.y); } - next(); - tokenType = TOKENTYPE.IDENTIFIER; - return; } + else { + // draw circle + var node = this.from; + var x, y, arrow; + var radius = 0.25 * Math.max(100,this.physics.springLength); + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width * 0.5; + y = node.y - radius; + arrow = { + x: x, + y: node.y, + angle: 0.9 * Math.PI + }; + } + else { + x = node.x + radius; + y = node.y - node.height * 0.5; + arrow = { + x: node.x, + y: y, + angle: 0.6 * Math.PI + }; + } + ctx.beginPath(); + // TODO: similarly, for a line without arrows, draw to the border of the nodes instead of the center + ctx.arc(x, y, radius, 0, 2 * Math.PI, false); + ctx.stroke(); - // something unknown is found, wrong characters, a syntax error - tokenType = TOKENTYPE.UNKNOWN; - while (c != '') { - token += c; - next(); + // draw all arrows + var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; + ctx.arrow(arrow.x, arrow.y, arrow.angle, length); + ctx.fill(); + ctx.stroke(); + + // draw label + if (this.label) { + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); + } } - throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"'); - } + }; /** - * Parse a graph. - * @returns {Object} graph + * Calculate the distance between a point (x3,y3) and a line segment from + * (x1,y1) to (x2,y2). + * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment + * @param {number} x1 + * @param {number} y1 + * @param {number} x2 + * @param {number} y2 + * @param {number} x3 + * @param {number} y3 + * @private */ - function parseGraph() { - var graph = {}; - - first(); - getToken(); - - // optional strict keyword - if (token == 'strict') { - graph.strict = true; - getToken(); + Edge.prototype._getDistanceToEdge = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point + var returnValue = 0; + if (this.from != this.to) { + if (this.options.smoothCurves.enabled == true) { + var xVia, yVia; + if (this.options.smoothCurves.enabled == true && this.options.smoothCurves.dynamic == true) { + xVia = this.via.x; + yVia = this.via.y; + } + else { + var via = this._getViaCoordinates(); + xVia = via.x; + yVia = via.y; + } + var minDistance = 1e9; + var distance; + var i,t,x,y, lastX, lastY; + for (i = 0; i < 10; i++) { + t = 0.1*i; + x = Math.pow(1-t,2)*x1 + (2*t*(1 - t))*xVia + Math.pow(t,2)*x2; + y = Math.pow(1-t,2)*y1 + (2*t*(1 - t))*yVia + Math.pow(t,2)*y2; + if (i > 0) { + distance = this._getDistanceToLine(lastX,lastY,x,y, x3,y3); + minDistance = distance < minDistance ? distance : minDistance; + } + lastX = x; lastY = y; + } + returnValue = minDistance; + } + else { + returnValue = this._getDistanceToLine(x1,y1,x2,y2,x3,y3); + } } - - // graph or digraph keyword - if (token == 'graph' || token == 'digraph') { - graph.type = token; - getToken(); + else { + var x, y, dx, dy; + var radius = 0.25 * this.physics.springLength; + var node = this.from; + if (node.width > node.height) { + x = node.x + 0.5 * node.width; + y = node.y - radius; + } + else { + x = node.x + radius; + y = node.y - 0.5 * node.height; + } + dx = x - x3; + dy = y - y3; + returnValue = Math.abs(Math.sqrt(dx*dx + dy*dy) - radius); } - // optional graph id - if (tokenType == TOKENTYPE.IDENTIFIER) { - graph.id = token; - getToken(); + if (this.labelDimensions.left < x3 && + this.labelDimensions.left + this.labelDimensions.width > x3 && + this.labelDimensions.top < y3 && + this.labelDimensions.top + this.labelDimensions.height > y3) { + return 0; } - - // open angle bracket - if (token != '{') { - throw newSyntaxError('Angle bracket { expected'); + else { + return returnValue; } - getToken(); + }; - // statements - parseStatements(graph); + Edge.prototype._getDistanceToLine = function(x1,y1,x2,y2,x3,y3) { + var px = x2-x1, + py = y2-y1, + something = px*px + py*py, + u = ((x3 - x1) * px + (y3 - y1) * py) / something; - // close angle bracket - if (token != '}') { - throw newSyntaxError('Angle bracket } expected'); + if (u > 1) { + u = 1; } - getToken(); - - // end of file - if (token !== '') { - throw newSyntaxError('End of file expected'); + else if (u < 0) { + u = 0; } - getToken(); - // remove temporary default properties - delete graph.node; - delete graph.edge; - delete graph.graph; + var x = x1 + u * px, + y = y1 + u * py, + dx = x - x3, + dy = y - y3; - return graph; - } + //# Note: If the actual distance does not matter, + //# if you only want to compare what this function + //# returns to other results of this function, you + //# can just return the squared distance instead + //# (i.e. remove the sqrt) to gain a little performance - /** - * Parse a list with statements. - * @param {Object} graph - */ - function parseStatements (graph) { - while (token !== '' && token != '}') { - parseStatement(graph); - if (token == ';') { - getToken(); - } - } - } + return Math.sqrt(dx*dx + dy*dy); + }; /** - * Parse a single statement. Can be a an attribute statement, node - * statement, a series of node statements and edge statements, or a - * parameter. - * @param {Object} graph + * This allows the zoom level of the network to influence the rendering + * + * @param scale */ - function parseStatement(graph) { - // parse subgraph - var subgraph = parseSubgraph(graph); - if (subgraph) { - // edge statements - parseEdge(graph, subgraph); + Edge.prototype.setScale = function(scale) { + this.networkScaleInv = 1.0/scale; + }; - return; - } - // parse an attribute statement - var attr = parseAttributeStatement(graph); - if (attr) { - return; - } + Edge.prototype.select = function() { + this.selected = true; + }; - // parse node - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier expected'); - } - var id = token; // id can be a string or a number - getToken(); + Edge.prototype.unselect = function() { + this.selected = false; + }; - if (token == '=') { - // id statement - getToken(); - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier expected'); - } - graph[id] = token; - getToken(); - // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] " + Edge.prototype.positionBezierNode = function() { + if (this.via !== null && this.from !== null && this.to !== null) { + this.via.x = 0.5 * (this.from.x + this.to.x); + this.via.y = 0.5 * (this.from.y + this.to.y); } - else { - parseNodeStatement(graph, id); + else if (this.via !== null) { + this.via.x = 0; + this.via.y = 0; } - } + }; /** - * Parse a subgraph - * @param {Object} graph parent graph object - * @return {Object | null} subgraph + * This function draws the control nodes for the manipulator. + * In order to enable this, only set the this.controlNodesEnabled to true. + * @param ctx */ - function parseSubgraph (graph) { - var subgraph = null; - - // optional subgraph keyword - if (token == 'subgraph') { - subgraph = {}; - subgraph.type = 'subgraph'; - getToken(); - - // optional graph id - if (tokenType == TOKENTYPE.IDENTIFIER) { - subgraph.id = token; - getToken(); + Edge.prototype._drawControlNodes = function(ctx) { + if (this.controlNodesEnabled == true) { + if (this.controlNodes.from === null && this.controlNodes.to === null) { + var nodeIdFrom = "edgeIdFrom:".concat(this.id); + var nodeIdTo = "edgeIdTo:".concat(this.id); + var constants = { + nodes:{group:'', radius:7, borderWidth:2, borderWidthSelected: 2}, + physics:{damping:0}, + clustering: {maxNodeSizeIncrements: 0 ,nodeScaling: {width:0, height: 0, radius:0}} + }; + this.controlNodes.from = new Node( + {id:nodeIdFrom, + shape:'dot', + color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}} + },{},{},constants); + this.controlNodes.to = new Node( + {id:nodeIdTo, + shape:'dot', + color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}} + },{},{},constants); } - } - // open angle bracket - if (token == '{') { - getToken(); - - if (!subgraph) { - subgraph = {}; + this.controlNodes.positions = {}; + if (this.controlNodes.from.selected == false) { + this.controlNodes.positions.from = this.getControlNodeFromPosition(ctx); + this.controlNodes.from.x = this.controlNodes.positions.from.x; + this.controlNodes.from.y = this.controlNodes.positions.from.y; } - subgraph.parent = graph; - subgraph.node = graph.node; - subgraph.edge = graph.edge; - subgraph.graph = graph.graph; - - // statements - parseStatements(subgraph); - - // close angle bracket - if (token != '}') { - throw newSyntaxError('Angle bracket } expected'); + if (this.controlNodes.to.selected == false) { + this.controlNodes.positions.to = this.getControlNodeToPosition(ctx); + this.controlNodes.to.x = this.controlNodes.positions.to.x; + this.controlNodes.to.y = this.controlNodes.positions.to.y; } - getToken(); - // remove temporary default properties - delete subgraph.node; - delete subgraph.edge; - delete subgraph.graph; - delete subgraph.parent; + this.controlNodes.from.draw(ctx); + this.controlNodes.to.draw(ctx); + } + else { + this.controlNodes = {from:null, to:null, positions:{}}; + } + }; - // register at the parent graph - if (!graph.subgraphs) { - graph.subgraphs = []; - } - graph.subgraphs.push(subgraph); + /** + * Enable control nodes. + * @private + */ + Edge.prototype._enableControlNodes = function() { + this.fromBackup = this.from; + this.toBackup = this.to; + this.controlNodesEnabled = true; + }; + + /** + * disable control nodes and remove from dynamicEdges from old node + * @private + */ + Edge.prototype._disableControlNodes = function() { + this.fromId = this.from.id; + this.toId = this.to.id; + if (this.fromId != this.fromBackup.id) { // from was changed, remove edge from old 'from' node dynamic edges + this.fromBackup.detachEdge(this); + } + else if (this.toId != this.toBackup.id) { // to was changed, remove edge from old 'to' node dynamic edges + this.toBackup.detachEdge(this); } - return subgraph; - } + this.fromBackup = null; + this.toBackup = null; + this.controlNodesEnabled = false; + }; + /** - * parse an attribute statement like "node [shape=circle fontSize=16]". - * Available keywords are 'node', 'edge', 'graph'. - * The previous list with default attributes will be replaced - * @param {Object} graph - * @returns {String | null} keyword Returns the name of the parsed attribute - * (node, edge, graph), or null if nothing - * is parsed. + * This checks if one of the control nodes is selected and if so, returns the control node object. Else it returns null. + * @param x + * @param y + * @returns {null} + * @private */ - function parseAttributeStatement (graph) { - // attribute statements - if (token == 'node') { - getToken(); + Edge.prototype._getSelectedControlNode = function(x,y) { + var positions = this.controlNodes.positions; + var fromDistance = Math.sqrt(Math.pow(x - positions.from.x,2) + Math.pow(y - positions.from.y,2)); + var toDistance = Math.sqrt(Math.pow(x - positions.to.x ,2) + Math.pow(y - positions.to.y ,2)); - // node attributes - graph.node = parseAttributeList(); - return 'node'; + if (fromDistance < 15) { + this.connectedNode = this.from; + this.from = this.controlNodes.from; + return this.controlNodes.from; } - else if (token == 'edge') { - getToken(); - - // edge attributes - graph.edge = parseAttributeList(); - return 'edge'; + else if (toDistance < 15) { + this.connectedNode = this.to; + this.to = this.controlNodes.to; + return this.controlNodes.to; } - else if (token == 'graph') { - getToken(); - - // graph attributes - graph.graph = parseAttributeList(); - return 'graph'; + else { + return null; } + }; - return null; - } /** - * parse a node statement - * @param {Object} graph - * @param {String | Number} id + * this resets the control nodes to their original position. + * @private */ - function parseNodeStatement(graph, id) { - // node statement - var node = { - id: id - }; - var attr = parseAttributeList(); - if (attr) { - node.attr = attr; + Edge.prototype._restoreControlNodes = function() { + if (this.controlNodes.from.selected == true) { + this.from = this.connectedNode; + this.connectedNode = null; + this.controlNodes.from.unselect(); } - addNode(graph, node); - - // edge statements - parseEdge(graph, id); - } + else if (this.controlNodes.to.selected == true) { + this.to = this.connectedNode; + this.connectedNode = null; + this.controlNodes.to.unselect(); + } + }; /** - * Parse an edge or a series of edges - * @param {Object} graph - * @param {String | Number} from Id of the from node + * this calculates the position of the control nodes on the edges of the parent nodes. + * + * @param ctx + * @returns {x: *, y: *} */ - function parseEdge(graph, from) { - while (token == '->' || token == '--') { - var to; - var type = token; - getToken(); + Edge.prototype.getControlNodeFromPosition = function(ctx) { + // draw arrow head + var controlnodeFromPos; + if (this.options.smoothCurves.enabled == true) { + controlnodeFromPos = this._findBorderPosition(true, ctx); + } + else { + var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var dx = (this.to.x - this.from.x); + var dy = (this.to.y - this.from.y); + var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); - var subgraph = parseSubgraph(graph); - if (subgraph) { - to = subgraph; - } - else { - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier or subgraph expected'); - } - to = token; - addNode(graph, { - id: to - }); - getToken(); - } + var fromBorderDist = this.from.distanceToBorder(ctx, angle + Math.PI); + var fromBorderPoint = (edgeSegmentLength - fromBorderDist) / edgeSegmentLength; + controlnodeFromPos = {}; + controlnodeFromPos.x = (fromBorderPoint) * this.from.x + (1 - fromBorderPoint) * this.to.x; + controlnodeFromPos.y = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y; + } - // parse edge attributes - var attr = parseAttributeList(); + return controlnodeFromPos; + }; - // create edge - var edge = createEdge(graph, from, to, type, attr); - addEdge(graph, edge); + /** + * this calculates the position of the control nodes on the edges of the parent nodes. + * + * @param ctx + * @returns {{from: {x: number, y: number}, to: {x: *, y: *}}} + */ + Edge.prototype.getControlNodeToPosition = function(ctx) { + // draw arrow head + var controlnodeFromPos,controlnodeToPos; + if (this.options.smoothCurves.enabled == true) { + controlnodeToPos = this._findBorderPosition(false, ctx); + } + else { + var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var dx = (this.to.x - this.from.x); + var dy = (this.to.y - this.from.y); + var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); + var toBorderDist = this.to.distanceToBorder(ctx, angle); + var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; - from = to; + controlnodeToPos = {}; + controlnodeToPos.x = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x; + controlnodeToPos.y = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y; } - } - /** - * Parse a set with attributes, - * for example [label="1.000", shape=solid] - * @return {Object | null} attr - */ - function parseAttributeList() { - var attr = null; + return controlnodeToPos; + }; - while (token == '[') { - getToken(); - attr = {}; - while (token !== '' && token != ']') { - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Attribute name expected'); - } - var name = token; + module.exports = Edge; - getToken(); - if (token != '=') { - throw newSyntaxError('Equal sign = expected'); - } - getToken(); +/***/ }, +/* 58 */ +/***/ function(module, exports, __webpack_require__) { - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Attribute value expected'); - } - var value = token; - setValue(attr, name, value); // name can be a path + /** + * Popup is a class to create a popup window with some text + * @param {Element} container The container object. + * @param {Number} [x] + * @param {Number} [y] + * @param {String} [text] + * @param {Object} [style] An object containing borderColor, + * backgroundColor, etc. + */ + function Popup(container, x, y, text, style) { + if (container) { + this.container = container; + } + else { + this.container = document.body; + } - getToken(); - if (token ==',') { - getToken(); + // x, y and text are optional, see if a style object was passed in their place + if (style === undefined) { + if (typeof x === "object") { + style = x; + x = undefined; + } else if (typeof text === "object") { + style = text; + text = undefined; + } else { + // for backwards compatibility, in case clients other than Network are creating Popup directly + style = { + fontColor: 'black', + fontSize: 14, // px + fontFace: 'verdana', + color: { + border: '#666', + background: '#FFFFC6' + } } } - - if (token != ']') { - throw newSyntaxError('Bracket ] expected'); - } - getToken(); } - return attr; - } + this.x = 0; + this.y = 0; + this.padding = 5; - /** - * Create a syntax error with extra information on current token and index. - * @param {String} message - * @returns {SyntaxError} err - */ - function newSyntaxError(message) { - return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ')'); + if (x !== undefined && y !== undefined ) { + this.setPosition(x, y); + } + if (text !== undefined) { + this.setText(text); + } + + // create the frame + this.frame = document.createElement("div"); + var styleAttr = this.frame.style; + styleAttr.position = "absolute"; + styleAttr.visibility = "hidden"; + styleAttr.border = "1px solid " + style.color.border; + styleAttr.color = style.fontColor; + styleAttr.fontSize = style.fontSize + "px"; + styleAttr.fontFamily = style.fontFace; + styleAttr.padding = this.padding + "px"; + styleAttr.backgroundColor = style.color.background; + styleAttr.borderRadius = "3px"; + styleAttr.MozBorderRadius = "3px"; + styleAttr.WebkitBorderRadius = "3px"; + styleAttr.boxShadow = "3px 3px 10px rgba(128, 128, 128, 0.5)"; + styleAttr.whiteSpace = "nowrap"; + this.container.appendChild(this.frame); } /** - * Chop off text after a maximum length - * @param {String} text - * @param {Number} maxLength - * @returns {String} + * @param {number} x Horizontal position of the popup window + * @param {number} y Vertical position of the popup window */ - function chop (text, maxLength) { - return (text.length <= maxLength) ? text : (text.substr(0, 27) + '...'); - } + Popup.prototype.setPosition = function(x, y) { + this.x = parseInt(x); + this.y = parseInt(y); + }; /** - * Execute a function fn for each pair of elements in two arrays - * @param {Array | *} array1 - * @param {Array | *} array2 - * @param {function} fn + * Set the content for the popup window. This can be HTML code or text. + * @param {string | Element} content */ - function forEach2(array1, array2, fn) { - if (Array.isArray(array1)) { - array1.forEach(function (elem1) { - if (Array.isArray(array2)) { - array2.forEach(function (elem2) { - fn(elem1, elem2); - }); - } - else { - fn(elem1, array2); - } - }); + Popup.prototype.setText = function(content) { + if (content instanceof Element) { + this.frame.innerHTML = ''; + this.frame.appendChild(content); } else { - if (Array.isArray(array2)) { - array2.forEach(function (elem2) { - fn(array1, elem2); - }); - } - else { - fn(array1, array2); - } + this.frame.innerHTML = content; // string containing text or HTML } - } + }; /** - * Convert a string containing a graph in DOT language into a map containing - * with nodes and edges in the format of graph. - * @param {String} data Text containing a graph in DOT-notation - * @return {Object} graphData + * Show the popup window + * @param {boolean} show Optional. Show or hide the window */ - function DOTToGraph (data) { - // parse the DOT file - var dotData = parseDOT(data); - var graphData = { - nodes: [], - edges: [], - options: {} - }; - - // copy the nodes - if (dotData.nodes) { - dotData.nodes.forEach(function (dotNode) { - var graphNode = { - id: dotNode.id, - label: String(dotNode.label || dotNode.id) - }; - merge(graphNode, dotNode.attr); - if (graphNode.image) { - graphNode.shape = 'image'; - } - graphData.nodes.push(graphNode); - }); - } - - // copy the edges - if (dotData.edges) { - /** - * Convert an edge in DOT format to an edge with VisGraph format - * @param {Object} dotEdge - * @returns {Object} graphEdge - */ - var convertEdge = function (dotEdge) { - var graphEdge = { - from: dotEdge.from, - to: dotEdge.to - }; - merge(graphEdge, dotEdge.attr); - graphEdge.style = (dotEdge.type == '->') ? 'arrow' : 'line'; - return graphEdge; - } - - dotData.edges.forEach(function (dotEdge) { - var from, to; - if (dotEdge.from instanceof Object) { - from = dotEdge.from.nodes; - } - else { - from = { - id: dotEdge.from - } - } - - if (dotEdge.to instanceof Object) { - to = dotEdge.to.nodes; - } - else { - to = { - id: dotEdge.to - } - } - - if (dotEdge.from instanceof Object && dotEdge.from.edges) { - dotEdge.from.edges.forEach(function (subEdge) { - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - } - - forEach2(from, to, function (from, to) { - var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr); - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - - if (dotEdge.to instanceof Object && dotEdge.to.edges) { - dotEdge.to.edges.forEach(function (subEdge) { - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - } - }); - } - - // copy the options - if (dotData.attr) { - graphData.options = dotData.attr; + Popup.prototype.show = function (show) { + if (show === undefined) { + show = true; } - return graphData; - } - - // exports - exports.parseDOT = parseDOT; - exports.DOTToGraph = DOTToGraph; - + if (show) { + var height = this.frame.clientHeight; + var width = this.frame.clientWidth; + var maxHeight = this.frame.parentNode.clientHeight; + var maxWidth = this.frame.parentNode.clientWidth; -/***/ }, -/* 58 */ -/***/ function(module, exports, __webpack_require__) { + var top = (this.y - height); + if (top + height + this.padding > maxHeight) { + top = maxHeight - height - this.padding; + } + if (top < this.padding) { + top = this.padding; + } - - function parseGephi(gephiJSON, options) { - var edges = []; - var nodes = []; - this.options = { - edges: { - inheritColor: true - }, - nodes: { - allowedToMove: false, - parseColor: false + var left = this.x; + if (left + width + this.padding > maxWidth) { + left = maxWidth - width - this.padding; + } + if (left < this.padding) { + left = this.padding; } - }; - if (options !== undefined) { - this.options.nodes['allowedToMove'] = options.allowedToMove | false; - this.options.nodes['parseColor'] = options.parseColor | false; - this.options.edges['inheritColor'] = options.inheritColor | true; + this.frame.style.left = left + "px"; + this.frame.style.top = top + "px"; + this.frame.style.visibility = "visible"; } - - var gEdges = gephiJSON.edges; - var gNodes = gephiJSON.nodes; - for (var i = 0; i < gEdges.length; i++) { - var edge = {}; - var gEdge = gEdges[i]; - edge['id'] = gEdge.id; - edge['from'] = gEdge.source; - edge['to'] = gEdge.target; - edge['attributes'] = gEdge.attributes; - // edge['value'] = gEdge.attributes !== undefined ? gEdge.attributes.Weight : undefined; - // edge['width'] = edge['value'] !== undefined ? undefined : edgegEdge.size; - edge['color'] = gEdge.color; - edge['inheritColor'] = edge['color'] !== undefined ? false : this.options.inheritColor; - edges.push(edge); + else { + this.hide(); } + }; - for (var i = 0; i < gNodes.length; i++) { - var node = {}; - var gNode = gNodes[i]; - node['id'] = gNode.id; - node['attributes'] = gNode.attributes; - node['x'] = gNode.x; - node['y'] = gNode.y; - node['label'] = gNode.label; - if (this.options.nodes.parseColor == true) { - node['color'] = gNode.color; - } - else { - node['color'] = gNode.color !== undefined ? {background:gNode.color, border:gNode.color} : undefined; - } - node['radius'] = gNode.size; - node['allowedToMoveX'] = this.options.nodes.allowedToMove; - node['allowedToMoveY'] = this.options.nodes.allowedToMove; - nodes.push(node); - } + /** + * Hide the popup window + */ + Popup.prototype.hide = function () { + this.frame.style.visibility = "hidden"; + }; - return {nodes:nodes, edges:edges}; - } + module.exports = Popup; - exports.parseGephi = parseGephi; /***/ }, /* 59 */ @@ -31807,7 +31807,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); - var Node = __webpack_require__(53); + var Node = __webpack_require__(56); /** * Creation of the SectorMixin var. @@ -32365,7 +32365,7 @@ return /******/ (function(modules) { // webpackBootstrap /* 66 */ /***/ function(module, exports, __webpack_require__) { - var Node = __webpack_require__(53); + var Node = __webpack_require__(56); /** * This function can be called from the _doInAllSectors function @@ -33080,8 +33080,8 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); - var Node = __webpack_require__(53); - var Edge = __webpack_require__(52); + var Node = __webpack_require__(56); + var Edge = __webpack_require__(57); /** * clears the toolbar div element of children diff --git a/dist/vis.map b/dist/vis.map index 8981ec42..d6cf4412 100644 --- a/dist/vis.map +++ b/dist/vis.map @@ -1 +1 @@ -{"version":3,"file":"vis.map","sources":["./dist/vis.js"],"names":["root","factory","exports","module","define","amd","this","modules","__webpack_require__","moduleId","installedModules","id","loaded","call","m","c","p","util","DOMutil","DataSet","DataView","Queue","Graph3d","graph3d","Camera","Filter","Point2d","Point3d","Slider","StepNumber","Timeline","Graph2d","timeline","DateUtil","DataStep","Range","stack","TimeStep","components","items","Item","BackgroundItem","BoxItem","PointItem","RangeItem","Component","CurrentTime","CustomTime","DataAxis","GraphGroup","Group","BackgroundGroup","ItemSet","Legend","LineGraph","TimeAxis","Network","network","Edge","Groups","Images","Node","Popup","dotparser","gephiParser","Graph","Error","moment","hammer","isNumber","object","Number","isString","String","isDate","Date","match","ASPDateRegex","exec","isNaN","parse","isDataTable","google","visualization","DataTable","randomUUID","S4","Math","floor","random","toString","extend","a","i","len","arguments","length","other","prop","hasOwnProperty","selectiveExtend","props","Array","isArray","selectiveDeepExtend","b","TypeError","constructor","Object","undefined","deepExtend","selectiveNotDeepExtend","indexOf","equalArray","convert","type","Boolean","valueOf","isMoment","toDate","getType","toISOString","value","getAbsoluteLeft","elem","getBoundingClientRect","left","window","pageXOffset","getAbsoluteTop","top","pageYOffset","addClassName","className","classes","split","push","join","removeClassName","index","splice","forEach","callback","toArray","array","updateProperty","key","addEventListener","element","action","listener","useCapture","navigator","userAgent","attachEvent","removeEventListener","detachEvent","preventDefault","event","returnValue","getTarget","target","srcElement","nodeType","parentNode","option","asBoolean","defaultValue","asNumber","asString","asSize","asElement","hexToRGB","hex","shorthandRegex","replace","r","g","result","parseInt","RGBToHex","red","green","blue","slice","parseColor","color","isValidRGB","rgb","substr","isValidHex","hsv","hexToHSV","lighterColorHSV","h","s","v","min","darkerColorHSV","darkerColorHex","HSVToHex","lighterColorHex","background","border","highlight","hover","RGBToHSV","minRGB","maxRGB","max","d","hue","saturation","cssUtil","cssText","styles","style","trim","parts","keys","map","addCssText","currentStyles","newStyles","removeCssText","removeStyles","HSVToRGB","f","q","t","isOk","test","selectiveBridgeObject","fields","referenceObject","objectTo","create","bridgeObject","mergeOptions","mergeTarget","options","enabled","binarySearchCustom","orderedItems","searchFunction","field","field2","maxIterations","iteration","low","high","middle","item","searchResult","binarySearchValue","sidePreference","prevValue","nextValue","easeInOutQuad","start","end","duration","change","easingFunctions","linear","easeInQuad","easeOutQuad","easeInCubic","easeOutCubic","easeInOutCubic","easeInQuart","easeOutQuart","easeInOutQuart","easeInQuint","easeOutQuint","easeInOutQuint","prepareElements","JSONcontainer","elementType","redundant","used","cleanupElements","removeChild","getSVGElement","svgContainer","shift","document","createElementNS","appendChild","getDOMElement","DOMContainer","insertBefore","createElement","drawPoint","x","y","group","point","drawPoints","setAttributeNS","size","drawBar","width","height","rect","data","_options","_data","_fieldId","fieldId","_type","_subscribers","add","setOptions","prototype","queue","_queue","destroy","on","subscribers","subscribe","off","filter","unsubscribe","_trigger","params","senderId","concat","subscriber","addedIds","me","_addItem","columns","_getColumnNames","row","rows","getNumberOfRows","col","cols","getValue","update","updatedIds","updatedData","addOrUpdate","_updateItem","get","ids","firstType","returnType","allowedValues","itemId","_getItem","order","_sort","_filterFields","_appendRow","getIds","getDataSet","mappedItems","filteredItem","name","sort","av","bv","remove","removedId","removedIds","_remove","clear","maxField","itemField","minField","distinct","values","fieldType","count","exists","types","raw","converted","JSON","stringify","dataTable","getNumberOfColumns","getColumnId","getColumnLabel","addRow","setValue","_ids","_onEvent","apply","setData","viewOptions","getArguments","defaultFilter","dataSet","added","updated","removed","delay","Infinity","_timeout","_extended","_flushIfNeeded","flush","methods","original","method","args","fn","context","entry","clearTimeout","setTimeout","container","SyntaxError","containerElement","margin","defaultXCenter","defaultYCenter","xLabel","yLabel","zLabel","passValueFn","xValueLabel","yValueLabel","zValueLabel","filterLabel","legendLabel","STYLE","DOT","showPerspective","showGrid","keepAspectRatio","showShadow","showGrayBottom","showTooltip","verticalRatio","animationInterval","animationPreload","camera","eye","dataPoints","colX","colY","colZ","colValue","colFilter","xMin","xStep","xMax","yMin","yStep","yMax","zMin","zStep","zMax","valueMin","valueMax","xBarWidth","yBarWidth","colorAxis","colorGrid","colorDot","colorDotBorder","getMouseX","clientX","targetTouches","getMouseY","clientY","Emitter","_setScale","scale","z","xCenter","yCenter","zCenter","setArmLocation","_convert3Dto2D","point3d","translation","_convertPointToTranslation","_convertTranslationToScreen","ax","ay","az","cx","getCameraLocation","cy","cz","sinTx","sin","getCameraRotation","cosTx","cos","sinTy","cosTy","sinTz","cosTz","dx","dy","dz","bx","by","ex","ey","ez","getArmLength","xcenter","frame","canvas","clientWidth","ycenter","_setBackgroundColor","backgroundColor","fill","stroke","strokeWidth","borderColor","borderWidth","borderStyle","BAR","BARCOLOR","BARSIZE","DOTLINE","DOTCOLOR","DOTSIZE","GRID","LINE","SURFACE","_getStyleNumber","styleName","_determineColumnIndexes","counter","column","getDistinctValues","distinctValues","getColumnRange","minMax","_dataInitialize","rawData","_onChange","dataFilter","setOnLoadCallback","redraw","withBars","defaultXBarWidth","dataX","defaultYBarWidth","dataY","xRange","defaultXMin","defaultXMax","defaultXStep","yRange","defaultYMin","defaultYMax","defaultYStep","zRange","defaultZMin","defaultZMax","defaultZStep","valueRange","defaultValueMin","defaultValueMax","_getDataPoints","obj","sortNumber","dataMatrix","xIndex","yIndex","trans","screen","bottom","pointRight","pointTop","pointCross","hasChildNodes","firstChild","position","overflow","noCanvas","fontWeight","padding","innerHTML","onmousedown","_onMouseDown","ontouchstart","_onTouchStart","onmousewheel","_onWheel","ontooltip","_onTooltip","onkeydown","setSize","_resizeCanvas","clientHeight","animationStart","slider","play","animationStop","stop","_resizeCenter","charAt","parseFloat","setCameraPosition","pos","horizontal","vertical","setArmRotation","distance","setArmLength","getCameraPosition","getArmRotation","_readData","_redrawFilter","animationAutoStart","cameraPosition","styleNumber","tooltip","showAnimationControls","_redrawSlider","_redrawClear","_redrawAxis","_redrawDataGrid","_redrawDataLine","_redrawDataBar","_redrawDataDot","_redrawInfo","_redrawLegend","ctx","getContext","clearRect","widthMin","widthMax","dotSize","right","lineWidth","font","ymin","ymax","_hsv2rgb","strokeStyle","beginPath","moveTo","lineTo","strokeRect","fillStyle","closePath","gridLineLen","step","getCurrent","next","textAlign","textBaseline","fillText","label","visible","setValues","setPlayInterval","onchange","getIndex","selectValue","setOnChangeCallback","lineStyle","getLabel","getSelectedValue","from","to","prettyStep","text","xText","yText","zText","offset","xOffset","yOffset","xMin2d","xMax2d","gridLenX","gridLenY","textMargin","armAngle","H","S","V","R","G","B","C","Hi","X","abs","cross","topSideVisible","zAvg","transBottom","dist","sortDepth","aDiff","subtract","bDiff","crossproduct","crossProduct","radius","arc","PI","j","surface","corners","xWidth","yWidth","surfaces","center","avg","transCenter","diff","leftButtonDown","_onMouseUp","which","button","touchDown","startMouseX","startMouseY","startStart","startEnd","startArmRotation","cursor","onmousemove","_onMouseMove","onmouseup","diffX","diffY","horizontalNew","verticalNew","snapAngle","snapValue","round","parameters","emit","boundingRect","mouseX","mouseY","tooltipTimeout","_hideTooltip","dataPoint","_dataPointFromXY","_showTooltip","ontouchmove","_onTouchMove","ontouchend","_onTouchEnd","delta","wheelDelta","detail","oldLength","newLength","_insideTriangle","triangle","sign","as","bs","cs","distMax","closestDataPoint","closestDist","triangle1","triangle2","distX","distY","sqrt","content","line","dot","dom","borderRadius","boxShadow","borderLeft","contentWidth","offsetWidth","contentHeight","offsetHeight","lineHeight","dotWidth","dotHeight","armLocation","armRotation","armLength","cameraLocation","cameraRotation","calculateCameraOrientation","rot","graph","onLoadCallback","loadInBackground","isLoaded","getLoadedProgress","getColumn","getValues","dataView","progress","sub","sum","prev","bar","MozBorderRadius","slide","onclick","togglePlay","onChangeCallback","playTimeout","playInterval","playLoop","setIndex","playNext","interval","clearInterval","getPlayInterval","setPlayLoop","doLoop","onChange","indexToLeft","startClientX","startSlideX","leftToIndex","_start","_end","_step","precision","_current","setRange","setStep","calculatePrettyStep","log10","log","LN10","step1","pow","step2","step5","toPrecision","getStep","groups","forthArgument","defaultOptions","autoResize","orientation","maxHeight","minHeight","_create","body","domProps","emitter","bind","hiddenDates","snap","toScreen","_toScreen","toGlobalScreen","_toGlobalScreen","toTime","_toTime","toGlobalTime","_toGlobalTime","range","timeAxis","currentTime","customTime","itemSet","itemsData","groupsData","setGroups","setItems","Core","newDataSet","initialLoad","dataRange","_getDataRange","setWindow","animate","fit","setSelection","focus","getSelection","itemData","e","getItemRange","dataset","minItem","maxStartItem","maxEndItem","linegraph","getLegend","groupId","isGroupVisible","visibility","convertHiddenOptions","repeat","dateItem","updateHiddenDates","centerContainer","totalRange","pixelTime","startDate","endDate","_d","runUntil","clone","day","dayOfYear","year","dayOffset","date","month","console","removeDuplicates","startHidden","isHidden","endHidden","rangeStart","rangeEnd","hidden","startToFront","endToFront","_applyRange","safeDates","printDates","dates","stepOverHiddenDates","timeStep","previousTime","stepInHidden","currentValue","current","newValue","switchedYear","switchedMonth","switchedDay","time","conversion","getHiddenDurationBetween","correctTimeForHidden","hiddenDuration","totalDuration","partialDuration","accumulatedHiddenDuration","getAccumulatedHiddenDuration","newTime","getHiddenDurationBefore","timeOffset","requiredDuration","previousPoint","snapAwayFromHidden","direction","correctionEnabled","minimumStep","containerHeight","customRange","alignZeros","autoScale","stepIndex","marginStart","marginEnd","deadSpace","majorSteps","minorSteps","setMinimumStep","setFirst","safeSize","minimumStepValue","orderOfMagnitude","minorStepIdx","magnitudefactor","solutionFound","stepSize","niceStart","niceEnd","roundToMinor","marginRange","rounded","hasNext","previous","decimals","exp","cnt","isMajor","now","hours","minutes","seconds","milliseconds","deltaDifference","scaleOffset","moveable","zoomable","zoomMin","zoomMax","touch","animateTimer","_onDragStart","_onDrag","_onDragEnd","_onHold","_onMouseWheel","_onTouch","_onPinch","validateDirection","getPointer","pageX","pageY","hammerUtil","byUser","_cancelAnimation","initStart","initEnd","initTime","anyChanged","dragging","done","changed","newStart","newEnd","getRange","totalHidden","previousDelta","allowDragging","gesture","deltaX","deltaY","diffRange","safeStart","safeEnd","fakeGesture","pointer","pointerDate","_pointerToDate","zoom","touches","centerDate","hiddenDurationBefore","hiddenDurationAfter","move","EPSILON","orderByStart","orderByEnd","aTime","bTime","force","iMax","axis","collidingItem","jj","collision","nostack","subgroups","newTop","subgroup","format","FORMAT","minorLabels","millisecond","second","minute","hour","weekday","majorLabels","setFormat","defaultFormat","first","setFullYear","getFullYear","setMonth","setDate","setHours","setMinutes","setSeconds","setMilliseconds","getMilliseconds","getSeconds","getMinutes","getHours","getDate","getMonth","setScale","newScale","newStep","setAutoScale","enable","stepYear","stepMonth","stepDay","stepHour","stepMinute","stepSecond","stepMillisecond","getLabelMinor","getLabelMajor","getClassName","even","today","isSame","currentWeek","currentMonth","currentYear","locale","lang","toLowerCase","_isResized","resized","_previousWidth","_previousHeight","showCurrentTime","locales","parent","backgroundVertical","title","toUpperCase","substring","currentTimeTimer","setCurrentTime","getCurrentTime","showCustomTime","eventParams","Hammer","drag","prevent_default","setCustomTime","getCustomTime","stopPropagation","svg","linegraphOptions","showMinorLabels","showMajorLabels","icons","majorLinesOffset","minorLinesOffset","labelOffsetX","labelOffsetY","iconWidth","linegraphSVG","DOMelements","lines","labels","conversionFactor","minWidth","stepPixels","stepPixelsForced","zeroCrossing","lineOffset","master","svgElements","iconsRemoved","amountOfGroups","lineContainer","scrollTop","addGroup","graphOptions","updateGroup","removeGroup","hide","show","display","_redrawGroupIcons","iconHeight","iconOffset","drawIcon","_cleanupIcons","backgroundHorizontal","activeGroups","_calculateCharSize","minorLabelHeight","minorCharHeight","majorLabelHeight","majorCharHeight","minorLineWidth","minorLineHeight","majorLineWidth","majorLineHeight","_redrawLabels","_redrawTitle","amountOfSteps","stepDifference","zeroStepDifference","valueAtZero","marginStartPos","maxLabelSize","_redrawLabel","_redrawLine","titleWidth","titleCharHeight","convertValue","invertedValue","convertedValue","characterHeight","largestWidth","majorCharWidth","minorCharWidth","textMinor","createTextNode","measureCharMinor","textMajor","measureCharMajor","textTitle","measureCharTitle","titleCharWidth","groupsUsingDefaultStyles","usingDefaultStyle","zeroPosition","Line","Bar","Points","setZeroPosition","catmullRom","parametrization","alpha","SVGcontainer","path","fillPath","fillHeight","outline","shaded","barWidth","bar1Height","bar2Height","icon","yAxisOrientation","getYRange","groupData","draw","framework","subgroupIndex","subgroupOrderer","subgroupOrder","visibleItems","byStart","byEnd","checkRangedItems","inner","foreground","marker","Element","getLabelWidth","restack","_updateVisibleItems","markerHeight","lastMarkerHeight","dirty","displayed","_calculateHeight","offsetTop","offsetLeft","ii","repositionY","resetSubgroups","labelSet","setParent","orderSubgroups","_checkIfVisible","sortArray","sortField","removeFromDataSet","removeItem","startArray","endArray","oldVisibleItems","visibleItemsLookup","lowerBound","upperBound","_checkIfVisibleWithReference","initialPosByStart","_traceVisible","initialPosByEnd","repositionX","initialPos","breakCondition","isVisible","align","groupOrder","selectable","editable","updateTime","onAdd","onUpdate","onMove","onRemove","onMoving","itemOptions","itemListeners","_onAdd","_onUpdate","_onRemove","groupListeners","_onAddGroups","_onUpdateGroups","_onRemoveGroups","groupIds","selection","stackDirty","touchParams","UNGROUPED","BACKGROUND","box","_updateUngrouped","backgroundGroup","_onSelectItem","_onMultiSelectItem","_onAddItem","addCallback","Function","markDirty","unselect","select","getVisibleItems","rawVisibleItems","_deselect","_orderGroups","visibleInterval","zoomed","lastVisibleInterval","lastWidth","firstGroup","_firstGroup","firstMargin","nonFirstMargin","groupMargin","groupResized","firstGroupIndex","firstGroupId","ungrouped","_getGroupId","getLabelSet","oldItemsData","getItems","_order","getGroups","_getType","_removeItem","groupOptions","oldGroupId","oldGroup","_constructByEndArray","itemFromTarget","selected","dragLeftItem","dragRightItem","initialX","itemProps","newProps","initial","groupFromTarget","_updateItemProps","_moveToGroup","changes","ctrlKey","srcEvent","shiftKey","oldSelection","newSelection","xAbs","newItem","_getItemRange","_item","itemSetFromTarget","side","iconSize","iconSpacing","textArea","scrollableHeight","drawLegendIcons","getComputedStyle","paddingTop","defaultGroup","sampling","graphHeight","barChart","handleOverlap","dataAxis","legend","abortedGraphUpdate","updateSVGheight","updateSVGheightOnResize","lastStart","COUNTER","BarGraphFunctions","yAxisLeft","yAxisRight","legendLeft","legendRight","_updateAllGroupData","_updateGroup","groupsContent","ungroupedCounter","forceGraphUpdate","_updateGraph","rangePerPixelInv","preprocessedGroupData","processedGroupData","groupRanges","changeCalled","minDate","maxDate","_getRelevantData","_applySampling","_convertXcoordinates","_getYRanges","_updateYAxis","MAX_CYCLES","_convertYcoordinates","dataContainer","guess","increment","amountOfPoints","xDistance","pointsPerPixel","ceil","sampledData","barCombinedDataLeft","barCombinedDataRight","getStackedBarYRange","minVal","maxVal","yAxisLeftUsed","yAxisRightUsed","minLeft","minRight","maxLeft","maxRight","ignore","_toggleAxisVisiblity","drawIcons","axisUsed","datapoints","xValue","yValue","extractedData","svgHeight","majorTexts","minorTexts","lineTop","parentChanged","foregroundNextSibling","nextSibling","backgroundNextSibling","_repaintLabels","timeLabelsize","cur","prevLine","xPrev","xFirstMajorLabel","_repaintMinorText","_repaintMajorText","_repaintMajorLine","_repaintMinorLine","leftTime","leftText","widthText","arr","pop","childNodes","nodeValue","_repaintDeleteButton","anchor","deleteButton","_updateContents","template","_updateTitle","removeAttribute","_updateDataAttributes","dataAttributes","attributes","setAttribute","_updateStyle","emptyContent","baseClassName","onTop","itemSubgroup","itemSetHeight","marginLeft","maxWidth","_repaintDragLeft","_repaintDragRight","contentLeft","parentWidth","boxWidth","dragLeft","dragRight","_determineBrowserMethod","_initializeMixinLoaders","renderRefreshRate","renderTimestep","renderTime","physicsTime","runDoubleSpeed","physicsDiscreteStepsize","initializing","triggerFunctions","edit","editEdge","connect","del","nodes","mass","radiusMin","radiusMax","shape","image","fontColor","fontSize","fontFace","fontFill","fontStrokeWidth","fontStrokeColor","level","borderWidthSelected","edges","widthSelectionMultiplier","hoverWidth","labelAlignment","arrowScaleFactor","dash","gap","altLength","inheritColor","configurePhysics","physics","barnesHut","thetaInverted","gravitationalConstant","centralGravity","springLength","springConstant","damping","repulsion","nodeDistance","hierarchicalRepulsion","clustering","initialMaxNodes","clusterThreshold","reduceToNodes","chainThreshold","clusterEdgeThreshold","sectorThreshold","screenSizeThreshold","fontSizeMultiplier","maxFontSize","forceAmplification","distanceAmplification","edgeGrowth","nodeScaling","maxNodeSizeIncrements","activeAreaBoxSize","clusterLevelDifference","navigation","keyboard","speed","dataManipulation","initiallyVisible","hierarchicalLayout","levelSeparation","nodeSpacing","layout","freezeForStabilization","smoothCurves","dynamic","roundness","maxVelocity","minVelocity","stabilize","stabilizationIterations","zoomExtentOnStabilize","dragNetwork","dragNodes","hideEdgesOnDrag","hideNodesOnDrag","constants","pixelRatio","hoverObj","controlNodesActive","navigationHammers","existing","_new","animationSpeed","animationEasingFunction","easingTime","sourceScale","targetScale","sourceTranslation","targetTranslation","lockedOnNodeId","lockedOnNodeOffset","touchTime","images","setOnloadCallback","_redraw","xIncrement","yIncrement","zoomIncrement","_loadPhysicsSystem","_loadSectorSystem","_loadClusterSystem","_loadSelectionSystem","_loadHierarchySystem","_setTranslation","freezeSimulation","cachedFunctions","startedStabilization","stabilized","draggingNodes","calculationNodes","calculationNodeIndices","nodeIndices","canvasTopLeft","canvasBottomRight","pointerPosition","areaCenter","previousScale","nodesData","edgesData","nodesListeners","_addNodes","_updateNodes","_removeNodes","edgesListeners","_addEdges","_updateEdges","_removeEdges","moving","timer","_setupHierarchicalLayout","zoomExtent","startWithClustering","keycharm","MixinLoader","Activator","browserType","requiresTimeout","_getScriptPath","scripts","getElementsByTagName","src","_getRange","node","minY","maxY","minX","maxX","nodeId","boundingBox","_findCenter","animationOptions","initialZoom","disableStart","zoomLevel","numberOfNodes","factor","yDistance","xZoomLevel","yZoomLevel","animation","_updateNodeIndexList","_clearNodeIndexList","idx","_createManipulatorBar","dotData","DOTToGraph","gephi","gephiData","parseGephi","_setNodes","_setEdges","_putDataInSector","_resetLevels","_stabilize","onEdit","onEditEdge","onConnect","onDelete","editMode","newColorObj","groupname","clickToUse","activator","_createKeyBinds","_loadNavigationControls","_loadManipulationSystem","_configureSmoothCurves","devicePixelRatio","webkitBackingStorePixelRatio","mozBackingStorePixelRatio","msBackingStorePixelRatio","oBackingStorePixelRatio","backingStorePixelRatio","setTransform","pinch","_onTap","_onDoubleTap","_onMouseMoveTitle","hammerFrame","_onRelease","reset","isActive","_moveUp","_yStopMoving","_moveDown","_moveLeft","_xStopMoving","_moveRight","_zoomIn","_stopZoom","_zoomOut","_deleteSelected","_cleanupPhysicsConfiguration","dispose","_recursiveDOMDelete","DOMobject","_getPointer","pinched","_getScale","_handleTouch","_handleDragStart","_getNodeAt","_getTranslation","isSelected","_selectObject","nodeIds","objectId","selectionObj","xFixed","yFixed","_handleOnDrag","releaseNode","_XconvertDOMtoCanvas","_XconvertCanvasToDOM","_YconvertDOMtoCanvas","_YconvertCanvasToDOM","_handleDragEnd","_handleTap","_handleDoubleTap","_handleOnHold","_handleOnRelease","_zoom","scaleOld","preScaleDragPointer","DOMtoCanvas","scaleFrac","tx","ty","updateClustersDefault","postScaleDragPointer","canvasToDOM","popupObj","_checkHidePopup","checkShow","_checkShowPopup","popupTimer","edgeId","_getEdgeAt","_hoverObject","_blurObject","lastPopupNode","nodeUnderCursor","overlappingNodes","isOverlappingWith","getTitle","overlappingEdges","edge","connected","popup","setPosition","setText","emitEvent","oldWidth","oldHeight","oldNodesData","_updateSelection","angle","_updateCalculationNodes","_reconnectEdges","_updateValueRange","updateLabels","changedData","setProperties","properties","oldEdgesData","oldEdge","disconnect","showInternalIds","_createBezierNodes","via","sectors","dynamicEdges","setValueRange","w","save","translate","_doInAllSectors","restore","offsetX","offsetY","_drawNodes","alwaysShow","setScaleAndPos","inArea","sMax","_drawEdges","_drawControlNodes","_freezeDefinedNodes","_physicsTick","_restoreFrozenNodes","fixedData","_isMoving","vmin","isMoving","_discreteStepNodes","nodesPresent","discreteStepLimited","discreteStep","vminCorrected","_revertPhysicsState","revertPosition","_revertPhysicsTick","_doInAllActiveSectors","_doInSupportSector","mainMovingStatus","supportMovingStatus","mainMoving","_animationStep","_handleNavigation","startTime","renderStartTime","requestAnimationFrame","mozRequestAnimationFrame","webkitRequestAnimationFrame","msRequestAnimationFrame","iterations","toggleFreeze","parentEdgeId","internalMultiplier","positionBezierNode","mixin","storePosition","storePositions","dataArray","allowedToMoveX","allowedToMoveY","getPositions","focusOnNode","nodePosition","lockedOnNode","easingFunction","animateView","locked","_transitionRedraw","viewCenter","distanceFromCenter","_classicRedraw","_lockedRedraw","active","getScale","getCenterCoordinates","getBoundingBox","networkConstants","fromId","toId","widthSelected","labelDimensions","yLine","dirtyLabel","fromBackup","toBackup","originalFromId","originalToId","widthFixed","lengthFixed","controlNodesEnabled","controlNodes","positions","connectedNode","_drawLine","_drawArrow","_drawArrowCenter","_drawDashLine","attachEdge","detachEdge","xFrom","yFrom","xTo","yTo","xObj","yObj","_getDistanceToEdge","_getColor","colorObj","_getLineWidth","_line","midpointX","midpointY","_pointOnLine","_label","resize","_circle","_pointOnCircle","networkScaleInv","_getViaCoordinates","xVia","yVia","quadraticCurveTo","lineCount","measureText","_rotateForLabelAlignment","_drawLabelRect","_drawLabelText","angleInDegrees","atan2","rotate","lineMargin","fillRect","lineJoin","strokeText","setLineDash","pattern","lineDashOffset","lineCap","dashedLine","percentage","arrow","_pointOnBezier","_findBorderPosition","distanceToBorder","distanceToNodes","difference","threshold","arrowPos","guidePos","edgeSegmentLength","toBorderDist","toBorderPoint","x1","y1","x2","y2","x3","y3","lastX","lastY","minDistance","_getDistanceToLine","px","py","something","u","nodeIdFrom","nodeIdTo","getControlNodeFromPosition","getControlNodeToPosition","_enableControlNodes","_disableControlNodes","_getSelectedControlNode","fromDistance","toDistance","_restoreControlNodes","controlnodeFromPos","fromBorderDist","fromBorderPoint","controlnodeToPos","defaultIndex","DEFAULT","imageBroken","load","url","brokenUrl","img","Image","onload","onerror","error","imagelist","grouplist","reroutedEdges","fontDrawThreshold","horizontalAlignLeft","verticalAlignTop","baseRadiusValue","radiusFixed","preassignedLevel","hierarchyEnumerated","fx","fy","vx","vy","previousState","resetCluster","dynamicEdgesLength","clusterSession","clusterSizeWidthFactor","clusterSizeHeightFactor","clusterSizeRadiusFactor","growthIndicator","networkScale","formationScale","clusterSize","containedNodes","containedEdges","clusterSessions","originalLabel","triggerFunction","groupObj","imageObj","brokenImage","_drawDatabase","_resizeDatabase","_drawBox","_resizeBox","_drawCircle","_resizeCircle","_drawEllipse","_resizeEllipse","_drawImage","_resizeImage","_drawCircularImage","_resizeCircularImage","_drawText","_resizeText","_drawDot","_resizeShape","_drawSquare","_drawTriangle","_drawTriangleDown","_drawStar","_reset","clearSizeCache","_setForce","_addForce","storeState","isFixed","velocity","getDistance","_drawImageAtPosition","globalAlpha","drawImage","_drawImageLabel","getTextSize","_swapToImageResizeWhenImageLoaded","diameter","centerX","centerY","_drawRawCircle","circle","clip","textSize","clusterLineWidth","selectionLineWidth","roundRect","database","defaultSize","ellipse","_drawShape","radiusMultiplier","baseline","labelUnderNode","inView","clearVelocity","updateVelocity","massBeforeClustering","energyBefore","styleAttr","fontFamily","WebkitBorderRadius","whiteSpace","parseDOT","parseGraph","nextPreview","isAlphaNumeric","regexAlphaNumeric","merge","o","addNode","graphs","attr","addEdge","createEdge","getToken","tokenType","TOKENTYPE","NULL","token","isComment","DELIMITER","c2","DELIMITERS","IDENTIFIER","newSyntaxError","UNKNOWN","chop","strict","parseStatements","parseStatement","subgraph","parseSubgraph","parseEdge","parseAttributeStatement","parseNodeStatement","subgraphs","parseAttributeList","message","maxLength","forEach2","array1","array2","elem1","elem2","graphData","dotNode","graphNode","convertEdge","dotEdge","graphEdge","subEdge","{","}","[","]",";","=",",","->","--","gephiJSON","allowedToMove","gEdges","gNodes","gEdge","source","gNode","leftContainer","rightContainer","shadowTop","shadowBottom","shadowTopLeft","shadowBottomLeft","shadowTopRight","shadowBottomRight","_redrawTimer","listeners","events","scrollTopMin","redrawCount","_initAutoResize","component","_stopAutoResize","what","getWindow","borderRootHeight","borderRootWidth","autoHeight","centerWidth","_updateScrollTop","visibilityTop","visibilityBottom","MAX_REDRAWS","repaint","_startAutoResize","_onResize","lastHeight","watchTimer","setInterval","initialScrollTop","oldScrollTop","_getScrollTop","newScrollTop","_setScrollTop","eventType","getTouchList","collectEventData","custom","back","editNode","addDescription","edgeDescription","editEdgeDescription","createEdgeError","deleteClusterError","CanvasRenderingContext2D","square","s2","ir","triangleDown","star","n","r2d","kappa","ox","oy","xe","ye","xm","ym","bezierCurveTo","wEllipse","hEllipse","ymb","yeb","xt","yt","xi","yi","xl","yl","xr","yr","dashArray","dashLength","dashCount","slope","distRemaining","dashIndex","_catmullRom","_linear","dFill","_catmullRomUniform","p0","p1","p2","p3","bp1","bp2","normalization","d1","d2","d3","A","N","M","d3powA","d2powA","d3pow2A","d2pow2A","d1pow2A","d1powA","Bargraph","barCombinedData","coreDistance","drawData","combinedData","intersections","barPoints","_getDataIntersections","heightOffset","_getSafeDrawData","nextKey","amount","resolved","prevKey","accumulated","groupLabel","_getStackedBarYRange","xpos","PhysicsMixin","ClusterMixin","SectorsMixin","SelectionMixin","ManipulationMixin","NavigationMixin","HierarchicalLayoutMixin","_loadMixin","sourceVariable","mixinFunction","_clearMixin","_loadSelectedForceSolver","_loadPhysicsConfiguration","hubThreshold","activeSector","drawingNode","blockConnectingEdgeSelection","forceAppendSelection","manipulationDiv","editModeDiv","closeDiv","_cleanNavigation","_loadNavigationElements","overlay","_onTapOverlay","windowHammer","_hasParent","deactivate","escListener","activate","unbind","_callbacks","once","self","removeListener","removeAllListeners","callbacks","cb","hasListeners","__WEBPACK_AMD_DEFINE_FACTORY__","__WEBPACK_AMD_DEFINE_ARRAY__","__WEBPACK_AMD_DEFINE_RESULT__","_exportFunctions","_bound","keydown","keyup","_keys","fromCharCode","code","down","handleEvent","up","keyCode","bound","bindAll","getKey","newBindings","global","dfl","hasOwnProp","defaultParsingFlags","empty","unusedTokens","unusedInput","charsLeftOver","nullInput","invalidMonth","invalidFormat","userInvalidated","iso","printMsg","msg","suppressDeprecationWarnings","warn","deprecate","firstTime","deprecateSimple","deprecations","padToken","func","leftZeroFill","ordinalizeToken","period","localeData","ordinal","monthDiff","anchor2","adjust","wholeMonthDiff","meridiemFixWrap","meridiem","isPm","meridiemHour","isPM","Locale","Moment","config","skipOverflow","checkOverflow","copyConfig","updateInProgress","updateOffset","Duration","normalizedInput","normalizeObjectUnits","years","quarters","quarter","months","weeks","week","days","_milliseconds","_days","_months","_locale","_bubble","val","_isAMomentObject","_i","_f","_l","_strict","_tzm","_isUTC","_offset","_pf","momentProperties","absRound","number","targetLength","forceSign","output","positiveMomentsDifference","base","res","isAfter","momentsDifference","makeAs","isBefore","createAdder","dur","tmp","addOrSubtractDurationFromMoment","mom","isAdding","setTime","rawSetter","rawGetter","rawMonthSetter","input","compareArrays","dontConvert","lengthDiff","diffs","toInt","normalizeUnits","units","lowered","unitAliases","camelFunctions","inputObject","normalizedProp","makeList","setter","getter","results","utc","set","argumentForCoercion","coercedNumber","isFinite","daysInMonth","UTC","getUTCDate","weeksInYear","dow","doy","weekOfYear","daysInYear","isLeapYear","_a","MONTH","DATE","YEAR","HOUR","MINUTE","SECOND","MILLISECOND","_overflowDayOfYear","isValid","_isValid","getTime","bigHour","normalizeLocale","chooseLocale","names","loadLocale","oldLocale","hasModule","model","local","removeFormattingTokens","makeFormatFunction","formattingTokens","formatTokenFunctions","formatMoment","expandFormat","formatFunctions","invalidDate","replaceLongDateFormatTokens","longDateFormat","localFormattingTokens","lastIndex","getParseRegexForToken","parseTokenOneDigit","parseTokenThreeDigits","parseTokenFourDigits","parseTokenOneToFourDigits","parseTokenSignedNumber","parseTokenSixDigits","parseTokenOneToSixDigits","parseTokenTwoDigits","parseTokenOneToThreeDigits","parseTokenWord","_meridiemParse","parseTokenOffsetMs","parseTokenTimestampMs","parseTokenTimezone","parseTokenT","parseTokenDigits","parseTokenOneOrTwoDigits","_ordinalParse","_ordinalParseLenient","RegExp","regexpEscape","unescapeFormat","utcOffsetFromString","string","possibleTzMatches","tzChunk","parseTimezoneChunker","addTimeToArrayFromToken","datePartArray","monthsParse","_dayOfYear","parseTwoDigitYear","_meridiem","_useUTC","weekdaysParse","_w","invalidWeekday","dayOfYearFromWeekInfo","weekYear","temp","GG","W","E","_week","gg","dayOfYearFromWeeks","dateFromConfig","currentDate","yearToUse","currentDateArray","makeUTCDate","getUTCMonth","_nextDay","makeDate","setUTCMinutes","getUTCMinutes","dateFromObject","getUTCFullYear","makeDateFromStringAndFormat","ISO_8601","parseISO","parsedInput","tokens","skipped","stringLength","totalParsedInputLength","matched","p4","makeDateFromStringAndArray","tempConfig","bestMoment","scoreToBeat","currentScore","NaN","score","l","isoRegex","isoDates","isoTimes","makeDateFromString","createFromInputFallback","makeDateFromInput","aspNetJsonRegex","ms","setUTCFullYear","parseWeekday","substituteTimeAgo","withoutSuffix","isFuture","relativeTime","posNegDuration","relativeTimeThresholds","firstDayOfWeek","firstDayOfWeekOfYear","adjustedMoment","daysToDayOfWeek","daysToAdd","getUTCDay","makeMoment","invalid","preparse","pickBy","moments","dayOfMonth","unit","makeAccessor","keepTime","daysToYears","yearsToDays","makeDurationGetter","makeGlobal","shouldDeprecate","ender","oldGlobalMoment","globalScope","VERSION","aspNetTimeSpanJsonRegex","isoDurationRegex","isoFormat","unitMillisecondFactors","Milliseconds","Seconds","Minutes","Hours","Days","Months","Years","D","Q","DDD","dayofyear","isoweekday","isoweek","weekyear","isoweekyear","ordinalizeTokens","paddedTokens","MMM","monthsShort","MMMM","dd","weekdaysMin","ddd","weekdaysShort","dddd","weekdays","isoWeek","YY","YYYY","YYYYY","YYYYYY","gggg","ggggg","isoWeekYear","GGGG","GGGGG","isoWeekday","SS","SSS","SSSS","Z","utcOffset","ZZ","zoneAbbr","zz","zoneName","unix","lists","DDDD","_monthsShort","monthName","regex","_monthsParse","_longMonthsParse","_shortMonthsParse","_weekdays","_weekdaysShort","_weekdaysMin","weekdayName","_weekdaysParse","_longDateFormat","LTS","LT","L","LL","LLL","LLLL","isLower","_calendar","sameDay","nextDay","nextWeek","lastDay","lastWeek","sameElse","calendar","_relativeTime","future","past","mm","hh","MM","yy","pastFuture","_ordinal","postformat","firstDayOfYear","_invalidDate","ret","parseIso","diffRes","isDuration","inp","version","relativeTimeThreshold","limit","defineLocale","_abbr","abbr","langData","flags","parseZone","isDSTShifted","parsingFlags","invalidAt","keepLocalTime","_dateUtcOffset","inputString","asFloat","that","zoneDiff","humanize","fromNow","sod","startOf","isDST","getDay","endOf","inputMs","isBetween","zone","localAdjust","_changeInProgress","isLocal","isUtcOffset","isUtc","hasAlignedHourOffset","isoWeeksInYear","weekInfo","newLocaleData","getTimezoneOffset","isoWeeks","toJSON","isUTC","withSuffix","toIsoString","asSeconds","asMilliseconds","asMinutes","asHours","asDays","asWeeks","asMonths","asYears","ordinalParse","require","noGlobal","exportName","setTimeoutContext","timeout","bindFn","invokeArrayArg","arg","each","iterator","dest","inherit","child","childP","baseP","_super","boolOrFn","TYPE_FUNCTION","ifUndefined","val1","val2","addEventListeners","handler","splitStr","removeEventListeners","hasParent","inStr","str","find","inArray","findByKey","uniqueArray","prefixed","property","prefix","camelProp","VENDOR_PREFIXES","uniqueId","_uniqueId","getWindowForElement","doc","ownerDocument","defaultView","parentWindow","Input","manager","inputTarget","domHandler","ev","init","createInputInstance","Type","inputClass","SUPPORT_POINTER_EVENTS","PointerEventInput","SUPPORT_ONLY_TOUCH","TouchInput","SUPPORT_TOUCH","TouchMouseInput","MouseInput","inputHandler","pointersLen","pointers","changedPointersLen","changedPointers","isFirst","INPUT_START","isFinal","INPUT_END","INPUT_CANCEL","session","computeInputData","recognize","prevInput","pointersLength","firstInput","simpleCloneInputData","firstMultiple","offsetCenter","getCenter","timeStamp","deltaTime","getAngle","computeDeltaXY","offsetDirection","getDirection","rotation","getRotation","computeIntervalInputData","offsetDelta","prevDelta","velocityX","velocityY","last","lastInterval","COMPUTE_INTERVAL","getVelocity","DIRECTION_NONE","DIRECTION_LEFT","DIRECTION_RIGHT","DIRECTION_UP","DIRECTION_DOWN","PROPS_XY","PROPS_CLIENT_XY","evEl","MOUSE_ELEMENT_EVENTS","evWin","MOUSE_WINDOW_EVENTS","allow","pressed","POINTER_ELEMENT_EVENTS","POINTER_WINDOW_EVENTS","store","pointerEvents","SingleTouchInput","evTarget","SINGLE_TOUCH_TARGET_EVENTS","SINGLE_TOUCH_WINDOW_EVENTS","started","normalizeSingleTouches","all","changedTouches","TOUCH_TARGET_EVENTS","targetIds","getTouches","allTouches","INPUT_MOVE","identifier","changedTargetTouches","mouse","TouchAction","cleanTouchActions","actions","TOUCH_ACTION_NONE","hasPanX","TOUCH_ACTION_PAN_X","hasPanY","TOUCH_ACTION_PAN_Y","TOUCH_ACTION_MANIPULATION","TOUCH_ACTION_AUTO","Recognizer","defaults","state","STATE_POSSIBLE","simultaneous","requireFail","stateStr","STATE_CANCELLED","STATE_ENDED","STATE_CHANGED","STATE_BEGAN","directionStr","getRecognizerByNameIfManager","otherRecognizer","recognizer","AttrRecognizer","PanRecognizer","pX","pY","PinchRecognizer","PressRecognizer","_timer","_input","RotateRecognizer","SwipeRecognizer","TapRecognizer","pTime","pCenter","recognizers","preset","Manager","handlers","touchAction","toggleCssProps","recognizeWith","requireFailure","cssProps","triggerDomEvent","gestureEvent","createEvent","initEvent","dispatchEvent","TEST_ELEMENT","MOBILE_REGEX","INPUT_TYPE_TOUCH","INPUT_TYPE_PEN","INPUT_TYPE_MOUSE","INPUT_TYPE_KINECT","DIRECTION_HORIZONTAL","DIRECTION_VERTICAL","DIRECTION_ALL","MOUSE_INPUT_MAP","mousedown","mousemove","mouseup","pointerType","POINTER_INPUT_MAP","pointerdown","pointermove","pointerup","pointercancel","pointerout","IE10_POINTER_TYPE_ENUM",2,3,4,5,"MSPointerEvent","removePointer","eventTypeNormalized","isTouch","storeIndex","pointerId","SINGLE_TOUCH_INPUT_MAP","touchstart","touchmove","touchend","touchcancel","TOUCH_INPUT_MAP","inputEvent","inputData","isMouse","PREFIXED_TOUCH_ACTION","NATIVE_TOUCH_ACTION","TOUCH_ACTION_COMPUTE","compute","getTouchAction","preventDefaults","prevented","hasNone","preventSrc","STATE_RECOGNIZED","STATE_FAILED","dropRecognizeWith","dropRequireFailure","hasRequireFailures","canRecognizeWith","withState","tryEmit","canEmit","inputDataClone","process","attrTest","optionPointers","isRecognized","directionTest","hasMoved","inOut","validPointers","validMovement","validTime","taps","posThreshold","validTouchTime","failTimeout","validInterval","validMultiTap","tapCount","domEvents","userSelect","touchSelect","touchCallout","contentZooming","userDrag","tapHighlightColor","STOP","FORCED_STOP","stopped","curRecognizer","Tap","Pan","Swipe","Pinch","Rotate","Press","clusterToFit","maxNumberOfNodes","reposition","maxLevels","forceAggregateHubs","normalizeClusterLevels","increaseClusterLevel","repositionNodes","openCluster","isMovingBeforeClustering","_nodeInActiveArea","_sector","_addSector","decreaseClusterLevel","_expandClusterNode","_updateDynamicEdges","updateClusters","zoomDirection","recursive","doNotStart","amountOfNodes","_collapseSector","_formClusters","_openClusters","_openClustersBySize","_aggregateHubs","handleChains","chainPercentage","_getChainFraction","_reduceAmountOfChains","_getHubSize","_formClustersByHub","openAll","containedNodeId","childNode","_expelChildFromParent","_unselectAll","_releaseContainedEdges","_connectEdgeBackToChild","_validateEdges","othersPresent","childNodeId","_repositionBezierNodes","_formClustersByZoom","_forceClustersByZoom","minLength","_addToCluster","_clusterToSmallestNeighbour","smallestNeighbour","smallestNeighbourNode","neighbour","onlyEqual","_formClusterFromHub","hubNode","absorptionSizeOffset","allowCluster","edgesIdarray","amountOfInitialEdges","_addToContainedEdges","_connectEdgeToCluster","_containCircularEdgesFromNode","massBefore","correction","edgeToId","edgeFromId","k","_addToReroutedEdges","maxLevel","minLevel","clusterLevel","targetLevel","average","averageSquared","hubCounter","largestHub","variance","standardDeviation","fraction","reduceAmount","chains","total","_switchToSector","sectorId","sectorType","_switchToActiveSector","_switchToFrozenSector","_switchToSupportSector","_loadLatestSector","_previousSector","_setActiveSector","newId","_forgetLastSector","_createNewSector","_deleteActiveSector","_deleteFrozenSector","_freezeSector","_activateSector","_mergeThisWithFrozen","_collapseThisToSingleCluster","sector","unqiueIdentifier","previousSector","runFunction","argument","returnValues","_doInAllFrozenSectors","_drawSectorNodes","_drawAllSectorNodes","_getNodesOverlappingWith","_getAllNodesOverlappingWith","_pointerToPositionObject","positionObject","_getEdgesOverlappingWith","_getAllEdgesOverlappingWith","_addToSelection","_addToHover","_removeFromSelection","doNotTrigger","_unselectClusters","_getSelectedNodeCount","_getSelectedNode","_getSelectedEdge","_getSelectedEdgeCount","_getSelectedObjectCount","_selectionIsEmpty","_clusterInSelection","_selectConnectedEdges","_hoverConnectedEdges","_unselectConnectedEdges","append","highlightEdges","overrideSelectable","DOM","_manipulationReleaseOverload","_navigationReleaseOverload","getSelectedNodes","edgeIds","getSelectedEdges","idArray","selectNodes","RangeError","selectEdges","_clearManipulatorBar","manipulationDOM","_restoreOverloadedFunctions","functionName","_toggleEditMode","toolbar","boundFunction","edgeBeingEdited","selectedControlNode","_createAddNodeToolbar","_createAddEdgeToolbar","_editNode","_createEditEdgeToolbar","_addNode","_handleConnect","_finishConnect","_selectControlNode","_controlNodeDrag","_releaseControlNode","newNode","_editEdge","alert","supportNodes","targetNode","connectionEdge","connectFromId","_createEdge","defaultData","finalizedData","sourceNodeId","targetNodeId","selectedNodes","selectedEdges","navigationDivs","navigationDivActions","_stopMovement","_zoomExtent","hubsize","definedLevel","undefinedLevel","_changeConstants","_determineLevels","_determineLevelsDirected","distribution","_getDistribution","_placeNodesByHierarchy","minPos","_placeBranchNodes","maxCount","_setLevel","firstNode","_setLevelDirected","parentId","parentLevel","nodeMoved","_restoreNodes","graphToggleSmoothCurves","graph_toggleSmooth","getElementById","graphRepositionNodes","showValueOfRange","graphGenerateOptions","optionsSpecific","radioButton1","radioButton2","checked","backupConstants","optionsDiv","switchConfigurations","radioButton","querySelector","tableId","table","constantsVariableName","valueId","rangeValue","_overWriteGraphConstants","RepulsionMixin","HierarchialRepulsionMixin","BarnesHutMixin","_toggleBarnesHut","barnesHutTree","_initializeForceCalculation","_calculateForces","_calculateGravitationalForces","_calculateNodeForces","_calculateSpringForcesWithSupport","_calculateHierarchicalSpringForces","_calculateSpringForces","supportNodeId","gravity","gravityForce","edgeLength","springForce","combinedClusterSize","node1","node2","node3","_calculateSpringForce","physicsConfiguration","hierarchicalLayoutDirections","parentElement","rangeElement","radioButton3","graph_repositionNodes","graph_generateOptions","dynamicSmoothCurves","nameArray","webpackContext","req","resolve","repulsingForce","a_base","minimumDistance","steepness","springFx","springFy","totalFx","totalFy","correctionFx","correctionFy","nodeCount","_formBarnesHutTree","_getForceContribution","children","NW","NE","SW","SE","parentBranch","childrenCount","centerOfMass","calcSize","MAX_VALUE","sizeDiff","minimumTreeSize","rootSize","halfRootSize","_splitBranch","_placeInTree","_updateBranchMass","totalMass","totalMassInv","biggestSize","skipMassUpdate","_placeInRegion","region","containedNode","_insertRegion","childSize","_drawTree","_drawBranch","branch","webpackPolyfill","paths","__webpack_amd_options__"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"vis.map","sources":["./dist/vis.js"],"names":["root","factory","exports","module","define","amd","this","modules","__webpack_require__","moduleId","installedModules","id","loaded","call","m","c","p","util","DOMutil","DataSet","DataView","Queue","Graph3d","graph3d","Camera","Filter","Point2d","Point3d","Slider","StepNumber","Timeline","Graph2d","timeline","DateUtil","DataStep","Range","stack","TimeStep","components","items","Item","BackgroundItem","BoxItem","PointItem","RangeItem","Component","CurrentTime","CustomTime","DataAxis","GraphGroup","Group","BackgroundGroup","ItemSet","Legend","LineGraph","TimeAxis","Network","network","Edge","Groups","Images","Node","Popup","dotparser","gephiParser","Graph","Error","moment","hammer","isNumber","object","Number","isString","String","isDate","Date","match","ASPDateRegex","exec","isNaN","parse","isDataTable","google","visualization","DataTable","randomUUID","S4","Math","floor","random","toString","extend","a","i","len","arguments","length","other","prop","hasOwnProperty","selectiveExtend","props","Array","isArray","selectiveDeepExtend","b","TypeError","constructor","Object","undefined","deepExtend","selectiveNotDeepExtend","indexOf","equalArray","convert","type","Boolean","valueOf","isMoment","toDate","getType","toISOString","value","getAbsoluteLeft","elem","getBoundingClientRect","left","window","pageXOffset","getAbsoluteTop","top","pageYOffset","addClassName","className","classes","split","push","join","removeClassName","index","splice","forEach","callback","toArray","array","updateProperty","key","addEventListener","element","action","listener","useCapture","navigator","userAgent","attachEvent","removeEventListener","detachEvent","preventDefault","event","returnValue","getTarget","target","srcElement","nodeType","parentNode","option","asBoolean","defaultValue","asNumber","asString","asSize","asElement","hexToRGB","hex","shorthandRegex","replace","r","g","result","parseInt","RGBToHex","red","green","blue","slice","parseColor","color","isValidRGB","rgb","substr","isValidHex","hsv","hexToHSV","lighterColorHSV","h","s","v","min","darkerColorHSV","darkerColorHex","HSVToHex","lighterColorHex","background","border","highlight","hover","RGBToHSV","minRGB","maxRGB","max","d","hue","saturation","cssUtil","cssText","styles","style","trim","parts","keys","map","addCssText","currentStyles","newStyles","removeCssText","removeStyles","HSVToRGB","f","q","t","isOk","test","selectiveBridgeObject","fields","referenceObject","objectTo","create","bridgeObject","mergeOptions","mergeTarget","options","enabled","binarySearchCustom","orderedItems","searchFunction","field","field2","maxIterations","iteration","low","high","middle","item","searchResult","binarySearchValue","sidePreference","prevValue","nextValue","easeInOutQuad","start","end","duration","change","easingFunctions","linear","easeInQuad","easeOutQuad","easeInCubic","easeOutCubic","easeInOutCubic","easeInQuart","easeOutQuart","easeInOutQuart","easeInQuint","easeOutQuint","easeInOutQuint","__WEBPACK_AMD_DEFINE_RESULT__","global","dfl","hasOwnProp","defaultParsingFlags","empty","unusedTokens","unusedInput","overflow","charsLeftOver","nullInput","invalidMonth","invalidFormat","userInvalidated","iso","printMsg","msg","suppressDeprecationWarnings","console","warn","deprecate","fn","firstTime","apply","deprecateSimple","name","deprecations","padToken","func","count","leftZeroFill","ordinalizeToken","period","localeData","ordinal","monthDiff","anchor2","adjust","wholeMonthDiff","year","month","anchor","clone","add","meridiemFixWrap","locale","hour","meridiem","isPm","meridiemHour","isPM","Locale","Moment","config","skipOverflow","checkOverflow","copyConfig","_d","updateInProgress","updateOffset","Duration","normalizedInput","normalizeObjectUnits","years","quarters","quarter","months","weeks","week","days","day","hours","minutes","minute","seconds","second","milliseconds","millisecond","_milliseconds","_days","_months","_data","_locale","_bubble","to","from","val","_isAMomentObject","_i","_f","_l","_strict","_tzm","_isUTC","_offset","_pf","momentProperties","absRound","number","ceil","targetLength","forceSign","output","abs","sign","positiveMomentsDifference","base","res","isAfter","momentsDifference","makeAs","isBefore","createAdder","direction","dur","tmp","addOrSubtractDurationFromMoment","mom","isAdding","setTime","rawSetter","rawGetter","rawMonthSetter","input","prototype","compareArrays","array1","array2","dontConvert","lengthDiff","diffs","toInt","normalizeUnits","units","lowered","toLowerCase","unitAliases","camelFunctions","inputObject","normalizedProp","makeList","setter","format","getter","method","results","utc","set","argumentForCoercion","coercedNumber","isFinite","daysInMonth","UTC","getUTCDate","weeksInYear","dow","doy","weekOfYear","daysInYear","isLeapYear","_a","MONTH","DATE","YEAR","HOUR","MINUTE","SECOND","MILLISECOND","_overflowDayOfYear","isValid","_isValid","getTime","bigHour","normalizeLocale","chooseLocale","names","j","next","loadLocale","oldLocale","locales","hasModule","e","code","model","diff","local","removeFormattingTokens","makeFormatFunction","formattingTokens","formatTokenFunctions","Function","formatMoment","expandFormat","formatFunctions","invalidDate","replaceLongDateFormatTokens","longDateFormat","localFormattingTokens","lastIndex","getParseRegexForToken","token","strict","parseTokenOneDigit","parseTokenThreeDigits","parseTokenFourDigits","parseTokenOneToFourDigits","parseTokenSignedNumber","parseTokenSixDigits","parseTokenOneToSixDigits","parseTokenTwoDigits","parseTokenOneToThreeDigits","parseTokenWord","_meridiemParse","parseTokenOffsetMs","parseTokenTimestampMs","parseTokenTimezone","parseTokenT","parseTokenDigits","parseTokenOneOrTwoDigits","_ordinalParse","_ordinalParseLenient","RegExp","regexpEscape","unescapeFormat","utcOffsetFromString","string","possibleTzMatches","tzChunk","parseTimezoneChunker","addTimeToArrayFromToken","datePartArray","monthsParse","_dayOfYear","parseTwoDigitYear","_meridiem","parseFloat","_useUTC","weekdaysParse","_w","invalidWeekday","dayOfYearFromWeekInfo","w","weekYear","weekday","temp","GG","W","E","_week","gg","dayOfYearFromWeeks","dayOfYear","dateFromConfig","date","currentDate","yearToUse","currentDateArray","makeUTCDate","getUTCMonth","_nextDay","makeDate","setUTCMinutes","getUTCMinutes","dateFromObject","now","getUTCFullYear","getFullYear","getMonth","getDate","makeDateFromStringAndFormat","ISO_8601","parseISO","parsedInput","tokens","skipped","stringLength","totalParsedInputLength","matched","p1","p2","p3","p4","makeDateFromStringAndArray","tempConfig","bestMoment","scoreToBeat","currentScore","NaN","score","l","isoRegex","isoDates","isoTimes","makeDateFromString","createFromInputFallback","arr","makeDateFromInput","aspNetJsonRegex","obj","y","M","ms","setFullYear","setUTCFullYear","parseWeekday","substituteTimeAgo","withoutSuffix","isFuture","relativeTime","posNegDuration","round","as","args","relativeTimeThresholds","firstDayOfWeek","firstDayOfWeekOfYear","adjustedMoment","daysToDayOfWeek","daysToAdd","getUTCDay","makeMoment","invalid","preparse","pickBy","moments","dayOfMonth","unit","makeAccessor","keepTime","daysToYears","yearsToDays","makeDurationGetter","makeGlobal","shouldDeprecate","ender","oldGlobalMoment","globalScope","VERSION","aspNetTimeSpanJsonRegex","isoDurationRegex","isoFormat","unitMillisecondFactors","Milliseconds","Seconds","Minutes","Hours","Days","Months","Years","D","Q","DDD","dayofyear","isoweekday","isoweek","weekyear","isoweekyear","ordinalizeTokens","paddedTokens","MMM","monthsShort","MMMM","dd","weekdaysMin","ddd","weekdaysShort","dddd","weekdays","isoWeek","YY","YYYY","YYYYY","YYYYYY","gggg","ggggg","isoWeekYear","GGGG","GGGGG","isoWeekday","A","H","S","SS","SSS","SSSS","Z","utcOffset","ZZ","z","zoneAbbr","zz","zoneName","x","X","unix","lists","pop","DDDD","source","_monthsShort","monthName","regex","_monthsParse","_longMonthsParse","_shortMonthsParse","_weekdays","_weekdaysShort","_weekdaysMin","weekdayName","_weekdaysParse","_longDateFormat","LTS","LT","L","LL","LLL","LLLL","toUpperCase","charAt","isLower","_calendar","sameDay","nextDay","nextWeek","lastDay","lastWeek","sameElse","calendar","_relativeTime","future","past","mm","hh","MM","yy","pastFuture","_ordinal","postformat","firstDayOfYear","_invalidDate","ret","parseIso","diffRes","isDuration","inp","version","defaultFormat","relativeTimeThreshold","threshold","limit","lang","values","data","defineLocale","_abbr","abbr","langData","flags","parseZone","isDSTShifted","parsingFlags","invalidAt","keepLocalTime","subtract","_dateUtcOffset","inputString","asFloat","that","zoneDiff","time","humanize","fromNow","sod","startOf","isDST","getDay","endOf","inputMs","isBetween","isSame","zone","localAdjust","offset","_changeInProgress","isLocal","isUtcOffset","isUtc","hasAlignedHourOffset","isoWeeksInYear","weekInfo","get","newLocaleData","getTimezoneOffset","dates","isoWeeks","toJSON","isUTC","withSuffix","toIsoString","asSeconds","asMilliseconds","asMinutes","asHours","asDays","asWeeks","asMonths","asYears","ordinalParse","require","noGlobal","webpackContext","req","resolve","webpackPolyfill","paths","children","prepareElements","JSONcontainer","elementType","redundant","used","cleanupElements","removeChild","getSVGElement","svgContainer","shift","document","createElementNS","appendChild","getDOMElement","DOMContainer","insertBefore","createElement","drawPoint","group","point","drawPoints","setAttributeNS","size","drawBar","width","height","rect","_options","_fieldId","fieldId","_type","_subscribers","setOptions","queue","_queue","destroy","on","subscribers","subscribe","off","filter","unsubscribe","_trigger","params","senderId","concat","subscriber","addedIds","me","_addItem","columns","_getColumnNames","row","rows","getNumberOfRows","col","cols","getValue","update","updatedIds","updatedData","addOrUpdate","_updateItem","ids","firstType","returnType","allowedValues","itemId","_getItem","order","_sort","_filterFields","_appendRow","getIds","getDataSet","mappedItems","filteredItem","sort","av","bv","remove","removedId","removedIds","_remove","clear","maxField","itemField","minField","distinct","fieldType","exists","types","raw","converted","JSON","stringify","dataTable","getNumberOfColumns","getColumnId","getColumnLabel","addRow","setValue","delay","Infinity","_timeout","_extended","_flushIfNeeded","flush","methods","original","context","entry","clearTimeout","setTimeout","_ids","_onEvent","setData","viewOptions","getArguments","defaultFilter","dataSet","added","updated","removed","container","SyntaxError","containerElement","margin","defaultXCenter","defaultYCenter","xLabel","yLabel","zLabel","passValueFn","xValueLabel","yValueLabel","zValueLabel","filterLabel","legendLabel","STYLE","DOT","showPerspective","showGrid","keepAspectRatio","showShadow","showGrayBottom","showTooltip","verticalRatio","animationInterval","animationPreload","camera","eye","dataPoints","colX","colY","colZ","colValue","colFilter","xMin","xStep","xMax","yMin","yStep","yMax","zMin","zStep","zMax","valueMin","valueMax","xBarWidth","yBarWidth","colorAxis","colorGrid","colorDot","colorDotBorder","getMouseX","clientX","targetTouches","getMouseY","clientY","Emitter","_setScale","scale","xCenter","yCenter","zCenter","setArmLocation","_convert3Dto2D","point3d","translation","_convertPointToTranslation","_convertTranslationToScreen","ax","ay","az","cx","getCameraLocation","cy","cz","sinTx","sin","getCameraRotation","cosTx","cos","sinTy","cosTy","sinTz","cosTz","dx","dy","dz","bx","by","ex","ey","ez","getArmLength","xcenter","frame","canvas","clientWidth","ycenter","_setBackgroundColor","backgroundColor","fill","stroke","strokeWidth","borderColor","borderWidth","borderStyle","BAR","BARCOLOR","BARSIZE","DOTLINE","DOTCOLOR","DOTSIZE","GRID","LINE","SURFACE","_getStyleNumber","styleName","_determineColumnIndexes","counter","column","getDistinctValues","distinctValues","getColumnRange","minMax","_dataInitialize","rawData","_onChange","dataFilter","setOnLoadCallback","redraw","withBars","defaultXBarWidth","dataX","defaultYBarWidth","dataY","xRange","defaultXMin","defaultXMax","defaultXStep","yRange","defaultYMin","defaultYMax","defaultYStep","zRange","defaultZMin","defaultZMax","defaultZStep","valueRange","defaultValueMin","defaultValueMax","_getDataPoints","sortNumber","dataMatrix","xIndex","yIndex","trans","screen","bottom","pointRight","pointTop","pointCross","hasChildNodes","firstChild","position","noCanvas","fontWeight","padding","innerHTML","onmousedown","_onMouseDown","ontouchstart","_onTouchStart","onmousewheel","_onWheel","ontooltip","_onTooltip","onkeydown","setSize","_resizeCanvas","clientHeight","animationStart","slider","play","animationStop","stop","_resizeCenter","setCameraPosition","pos","horizontal","vertical","setArmRotation","distance","setArmLength","getCameraPosition","getArmRotation","_readData","_redrawFilter","animationAutoStart","cameraPosition","styleNumber","tooltip","showAnimationControls","_redrawSlider","_redrawClear","_redrawAxis","_redrawDataGrid","_redrawDataLine","_redrawDataBar","_redrawDataDot","_redrawInfo","_redrawLegend","ctx","getContext","clearRect","widthMin","widthMax","dotSize","right","lineWidth","font","ymin","ymax","_hsv2rgb","strokeStyle","beginPath","moveTo","lineTo","strokeRect","fillStyle","closePath","gridLineLen","step","getCurrent","textAlign","textBaseline","fillText","label","visible","setValues","setPlayInterval","onchange","getIndex","selectValue","setOnChangeCallback","lineStyle","getLabel","getSelectedValue","prettyStep","text","xText","yText","zText","xOffset","yOffset","xMin2d","xMax2d","gridLenX","gridLenY","textMargin","armAngle","V","R","G","B","C","Hi","cross","topSideVisible","zAvg","transBottom","dist","sortDepth","aDiff","bDiff","crossproduct","crossProduct","radius","arc","PI","surface","corners","xWidth","yWidth","surfaces","center","avg","transCenter","leftButtonDown","_onMouseUp","which","button","touchDown","startMouseX","startMouseY","startStart","startEnd","startArmRotation","cursor","onmousemove","_onMouseMove","onmouseup","diffX","diffY","horizontalNew","verticalNew","snapAngle","snapValue","parameters","emit","boundingRect","mouseX","mouseY","tooltipTimeout","_hideTooltip","dataPoint","_dataPointFromXY","_showTooltip","ontouchmove","_onTouchMove","ontouchend","_onTouchEnd","delta","wheelDelta","detail","oldLength","newLength","_insideTriangle","triangle","bs","cs","distMax","closestDataPoint","closestDist","triangle1","triangle2","distX","distY","sqrt","content","line","dot","dom","borderRadius","boxShadow","borderLeft","contentWidth","offsetWidth","contentHeight","offsetHeight","lineHeight","dotWidth","dotHeight","mixin","_callbacks","once","self","removeListener","removeAllListeners","callbacks","cb","listeners","hasListeners","sub","sum","armLocation","armRotation","armLength","cameraLocation","cameraRotation","calculateCameraOrientation","rot","graph","onLoadCallback","loadInBackground","isLoaded","getLoadedProgress","getColumn","getValues","dataView","progress","prev","bar","MozBorderRadius","slide","onclick","togglePlay","onChangeCallback","playTimeout","playInterval","playLoop","setIndex","playNext","interval","clearInterval","getPlayInterval","setPlayLoop","doLoop","onChange","indexToLeft","startClientX","startSlideX","leftToIndex","_start","_end","_step","precision","_current","setRange","setStep","calculatePrettyStep","log10","log","LN10","step1","pow","step2","step5","toPrecision","getStep","groups","forthArgument","defaultOptions","autoResize","orientation","maxHeight","minHeight","_create","body","domProps","emitter","bind","hiddenDates","snap","toScreen","_toScreen","toGlobalScreen","_toGlobalScreen","toTime","_toTime","toGlobalTime","_toGlobalTime","range","timeAxis","currentTime","customTime","itemSet","itemsData","groupsData","setGroups","setItems","Core","newDataSet","initialLoad","dataRange","_getDataRange","setWindow","animate","fit","setSelection","focus","getSelection","itemData","getItemRange","dataset","minItem","maxStartItem","maxEndItem","setup","Hammer","READY","Event","determineEventTypes","Utils","each","gestures","gesture","Detection","register","onTouch","DOCUMENT","EVENT_MOVE","detect","EVENT_END","Instance","defaults","behavior","userSelect","touchAction","touchCallout","contentZooming","userDrag","tapHighlightColor","HAS_POINTEREVENTS","pointerEnabled","msPointerEnabled","HAS_TOUCHEVENTS","IS_MOBILE","NO_MOUSEEVENTS","CALCULATE_INTERVAL","EVENT_TYPES","DIRECTION_DOWN","DIRECTION_LEFT","DIRECTION_UP","DIRECTION_RIGHT","POINTER_MOUSE","POINTER_TOUCH","POINTER_PEN","EVENT_START","EVENT_RELEASE","EVENT_TOUCH","plugins","utils","dest","src","merge","handler","iterator","inStr","find","inArray","hasParent","node","parent","getCenter","touches","pageX","pageY","touch","getVelocity","deltaTime","deltaX","deltaY","getAngle","touch1","touch2","atan2","getDirection","getDistance","getScale","getRotation","isVertical","setPrefixedCss","toggle","prefixes","toCamelCase","toggleBehavior","falseFn","onselectstart","ondragstart","str","preventMouseEvents","started","shouldDetect","hook","eventType","onTouchHandler","ev","triggerType","srcType","isPointer","isMouse","buttons","PointerEvent","matchType","updatePointer","doDetect","reset","touchList","getTouchList","touchListLength","triggerChange","trigger","changedLength","changedTouches","evData","collectEventData","identifiers","identifier","pointerType","timeStamp","srcEvent","preventManipulation","stopPropagation","stopDetect","pointers","touchlist","pointer","pointerEvent","pointerId","pt","MSPOINTER_TYPE_MOUSE","MSPOINTER_TYPE_TOUCH","MSPOINTER_TYPE_PEN","detection","current","previous","stopped","startDetect","inst","eventData","startEvent","lastEvent","lastCalcEvent","futureCalcEvent","lastCalcData","extendEventData","instOptions","getCalculatedData","cur","recalc","calcEv","calcData","velocity","angle","velocityX","velocityY","interimAngle","interimDirection","startEv","lastEv","rotation","eventStartHandler","eventHandlers","createEvent","initEvent","dispatchEvent","enable","state","dispose","eh","dragGesture","dragMaxTouches","triggered","dragMinDistance","startCenter","dragDistanceCorrection","factor","dragLockToAxis","dragLockMinDistance","lastDirection","dragBlockVertical","dragBlockHorizontal","Drag","Gesture","holdGesture","timer","holdTimeout","holdThreshold","Hold","Release","Swipe","swipeMinTouches","swipeMaxTouches","swipeVelocityX","swipeVelocityY","tapGesture","sincePrev","didDoubleTap","hasMoved","tapMaxDistance","tapMaxTime","doubleTapInterval","doubleTapDistance","tapAlways","Tap","Touch","preventMouse","transformGesture","scaleThreshold","rotationThreshold","transformMinScale","transformMinRotation","Transform","deltaDifference","scaleOffset","startToFront","endToFront","moveable","zoomable","zoomMin","zoomMax","animateTimer","_onDragStart","_onDrag","_onDragEnd","_onHold","_onMouseWheel","_onTouch","_onPinch","validateDirection","getPointer","hammerUtil","byUser","_cancelAnimation","initStart","initEnd","initTime","anyChanged","dragging","done","changed","_applyRange","updateHiddenDates","newStart","newEnd","getRange","conversion","totalHidden","previousDelta","allowDragging","getHiddenDurationBetween","diffRange","safeStart","snapAwayFromHidden","safeEnd","fakeGesture","pointerDate","_pointerToDate","zoom","centerDate","hiddenDuration","hiddenDurationBefore","getHiddenDurationBefore","hiddenDurationAfter","move","_isResized","resized","_previousWidth","_previousHeight","convertHiddenOptions","repeat","dateItem","centerContainer","totalRange","pixelTime","startDate","endDate","runUntil","dayOffset","removeDuplicates","startHidden","isHidden","endHidden","rangeStart","rangeEnd","hidden","safeDates","printDates","stepOverHiddenDates","timeStep","previousTime","stepInHidden","currentValue","newValue","switchedYear","switchedMonth","switchedDay","correctTimeForHidden","totalDuration","partialDuration","accumulatedHiddenDuration","getAccumulatedHiddenDuration","newTime","timeOffset","requiredDuration","previousPoint","correctionEnabled","Activator","backgroundVertical","backgroundHorizontal","leftContainer","rightContainer","shadowTop","shadowBottom","shadowTopLeft","shadowBottomLeft","shadowTopRight","shadowBottomRight","properties","_redrawTimer","events","isActive","scrollTop","scrollTopMin","redrawCount","clickToUse","activator","_initAutoResize","component","active","_stopAutoResize","setCustomTime","getCustomTime","getVisibleItems","what","getWindow","borderRootHeight","borderRootWidth","autoHeight","containerHeight","centerWidth","_updateScrollTop","visibilityTop","visibilityBottom","visibility","MAX_REDRAWS","repaint","setCurrentTime","getCurrentTime","_startAutoResize","_onResize","lastWidth","lastHeight","watchTimer","setInterval","initialScrollTop","oldScrollTop","_getScrollTop","newScrollTop","_setScrollTop","align","groupOrder","selectable","editable","updateTime","updateGroup","onAdd","onUpdate","onMove","onRemove","onMoving","axis","itemOptions","itemListeners","_onAdd","_onUpdate","_onRemove","groupListeners","_onAddGroups","_onUpdateGroups","_onRemoveGroups","groupIds","selection","stackDirty","touchParams","UNGROUPED","BACKGROUND","box","foreground","labelSet","_updateUngrouped","backgroundGroup","show","_onSelectItem","_onMultiSelectItem","_onAddItem","addCallback","markDirty","hide","ii","unselect","select","groupId","rawVisibleItems","visibleItems","_deselect","_orderGroups","visibleInterval","zoomed","lastVisibleInterval","restack","firstGroup","_firstGroup","firstMargin","nonFirstMargin","groupMargin","groupResized","firstGroupIndex","firstGroupId","ungrouped","_getGroupId","getLabelSet","oldItemsData","getItems","_order","getGroups","removeItem","_getType","_removeItem","groupData","groupOptions","oldGroupId","oldGroup","_constructByEndArray","endArray","itemFromTarget","selected","dragLeftItem","dragRightItem","initialX","itemProps","offsetLeft","newProps","initial","groupFromTarget","_updateItemProps","_moveToGroup","changes","ctrlKey","shiftKey","oldSelection","newSelection","xAbs","newItem","_getItemRange","_item","itemSetFromTarget","subgroups","subgroupIndex","subgroupOrderer","subgroupOrder","byStart","byEnd","checkRangedItems","inner","marker","Element","title","getLabelWidth","_updateVisibleItems","markerHeight","lastMarkerHeight","dirty","displayed","nostack","_calculateHeight","offsetTop","repositionY","resetSubgroups","subgroup","setParent","orderSubgroups","_checkIfVisible","sortArray","sortField","removeFromDataSet","startArray","orderByStart","orderByEnd","oldVisibleItems","visibleItemsLookup","lowerBound","upperBound","_checkIfVisibleWithReference","initialPosByStart","_traceVisible","initialPosByEnd","repositionX","initialPos","breakCondition","isVisible","EPSILON","aTime","bTime","force","iMax","collidingItem","jj","collision","newTop","baseClassName","_updateContents","_updateTitle","_updateDataAttributes","_updateStyle","getComputedStyle","maxWidth","_repaintDeleteButton","_repaintDragLeft","_repaintDragRight","contentLeft","parentWidth","boxWidth","dragLeft","dragRight","deleteButton","template","removeAttribute","dataAttributes","attributes","setAttribute","itemSetHeight","marginLeft","emptyContent","onTop","itemSubgroup","overlay","prevent_default","_onTapOverlay","windowHammer","_hasParent","deactivate","keycharm","escListener","activate","display","unbind","__WEBPACK_AMD_DEFINE_FACTORY__","__WEBPACK_AMD_DEFINE_ARRAY__","_exportFunctions","_bound","keydown","keyup","_keys","fromCharCode","down","handleEvent","up","keyCode","bound","bindAll","getKey","newBindings","lines","majorTexts","minorTexts","minimumStep","lineTop","showMinorLabels","showMajorLabels","parentChanged","_calculateCharSize","minorLabelHeight","minorCharHeight","majorLabelHeight","majorCharHeight","minorLineHeight","minorLineWidth","majorLineHeight","majorLineWidth","foregroundNextSibling","nextSibling","backgroundNextSibling","_repaintLabels","timeLabelsize","minorCharWidth","setFormat","isMajor","prevLine","xPrev","xFirstMajorLabel","first","hasNext","getClassName","_repaintMinorText","getLabelMinor","_repaintMajorText","getLabelMajor","_repaintMajorLine","_repaintMinorLine","leftTime","leftText","widthText","majorCharWidth","createTextNode","childNodes","nodeValue","measureCharMinor","measureCharMajor","autoScale","FORMAT","minorLabels","majorLabels","setMinimumStep","roundToMinor","setMonth","setDate","setHours","setMinutes","setSeconds","setMilliseconds","getMilliseconds","getSeconds","getMinutes","getHours","setScale","newScale","newStep","setAutoScale","stepYear","stepMonth","stepDay","stepHour","stepMinute","stepSecond","stepMillisecond","even","today","currentWeek","currentMonth","currentYear","showCurrentTime","substring","currentTimeTimer","custom","showCustomTime","eventParams","drag","linegraph","getLegend","isGroupVisible","yAxisOrientation","defaultGroup","sampling","graphHeight","shaded","barChart","handleOverlap","catmullRom","parametrization","alpha","dataAxis","icons","alignZeros","customRange","legend","abortedGraphUpdate","updateSVGheight","updateSVGheightOnResize","lastStart","svgElements","groupsUsingDefaultStyles","COUNTER","svg","framework","BarGraphFunctions","yAxisLeft","yAxisRight","legendLeft","legendRight","_updateAllGroupData","_updateGroup","removeGroup","addGroup","groupsContent","ungroupedCounter","forceGraphUpdate","_updateGraph","rangePerPixelInv","preprocessedGroupData","processedGroupData","groupRanges","changeCalled","minDate","maxDate","_getRelevantData","_applySampling","_convertXcoordinates","_getYRanges","_updateYAxis","MAX_CYCLES","_convertYcoordinates","draw","dataContainer","guess","increment","amountOfPoints","xDistance","pointsPerPixel","sampledData","barCombinedDataLeft","barCombinedDataRight","getYRange","getStackedBarYRange","minVal","maxVal","yAxisLeftUsed","yAxisRightUsed","minLeft","minRight","maxLeft","maxRight","ignore","_toggleAxisVisiblity","drawIcons","master","lineOffset","stepPixelsForced","stepPixels","zeroCrossing","axisUsed","datapoints","xValue","yValue","extractedData","svgHeight","convertValue","setZeroPosition","linegraphOptions","majorLinesOffset","minorLinesOffset","labelOffsetX","labelOffsetY","iconWidth","decimals","linegraphSVG","DOMelements","labels","conversionFactor","minWidth","iconsRemoved","amountOfGroups","lineContainer","graphOptions","_redrawGroupIcons","iconHeight","iconOffset","drawIcon","_cleanupIcons","activeGroups","_redrawLabels","_redrawTitle","deadSpace","marginRange","amountOfSteps","stepDifference","zeroStepDifference","marginEnd","valueAtZero","marginStartPos","maxLabelSize","_redrawLabel","_redrawLine","titleWidth","titleCharHeight","invertedValue","convertedValue","characterHeight","largestWidth","textMinor","textMajor","textTitle","measureCharTitle","titleCharWidth","stepIndex","marginStart","majorSteps","minorSteps","setFirst","safeSize","minimumStepValue","orderOfMagnitude","minorStepIdx","magnitudefactor","solutionFound","stepSize","niceStart","niceEnd","rounded","exp","cnt","usingDefaultStyle","zeroPosition","Line","Bar","Points","SVGcontainer","path","fillPath","fillHeight","outline","barWidth","bar1Height","bar2Height","icon","_catmullRom","_linear","dFill","_catmullRomUniform","p0","bp1","bp2","normalization","d1","d2","d3","N","d3powA","d2powA","d3pow2A","d2pow2A","d1pow2A","d1powA","Bargraph","barCombinedData","coreDistance","drawData","combinedData","intersections","barPoints","_getDataIntersections","heightOffset","_getSafeDrawData","nextKey","amount","resolved","prevKey","accumulated","groupLabel","_getStackedBarYRange","xpos","side","iconSize","iconSpacing","textArea","scrollableHeight","drawLegendIcons","paddingTop","_determineBrowserMethod","_initializeMixinLoaders","renderRefreshRate","renderTimestep","renderTime","physicsTime","runDoubleSpeed","physicsDiscreteStepsize","initializing","triggerFunctions","edit","editEdge","connect","del","nodes","mass","radiusMin","radiusMax","shape","image","fontColor","fontSize","fontFace","fontFill","fontStrokeWidth","fontStrokeColor","level","borderWidthSelected","edges","widthSelectionMultiplier","hoverWidth","labelAlignment","arrowScaleFactor","dash","gap","altLength","inheritColor","configurePhysics","physics","barnesHut","thetaInverted","gravitationalConstant","centralGravity","springLength","springConstant","damping","repulsion","nodeDistance","hierarchicalRepulsion","clustering","initialMaxNodes","clusterThreshold","reduceToNodes","chainThreshold","clusterEdgeThreshold","sectorThreshold","screenSizeThreshold","fontSizeMultiplier","maxFontSize","forceAmplification","distanceAmplification","edgeGrowth","nodeScaling","maxNodeSizeIncrements","activeAreaBoxSize","clusterLevelDifference","navigation","keyboard","speed","dataManipulation","initiallyVisible","hierarchicalLayout","levelSeparation","nodeSpacing","layout","freezeForStabilization","smoothCurves","dynamic","roundness","maxVelocity","minVelocity","stabilize","stabilizationIterations","zoomExtentOnStabilize","dragNetwork","dragNodes","hideEdgesOnDrag","hideNodesOnDrag","constants","pixelRatio","hoverObj","controlNodesActive","navigationHammers","existing","_new","animationSpeed","animationEasingFunction","easingTime","sourceScale","targetScale","sourceTranslation","targetTranslation","lockedOnNodeId","lockedOnNodeOffset","touchTime","images","setOnloadCallback","_redraw","xIncrement","yIncrement","zoomIncrement","_loadPhysicsSystem","_loadSectorSystem","_loadClusterSystem","_loadSelectionSystem","_loadHierarchySystem","_setTranslation","freezeSimulation","cachedFunctions","startedStabilization","stabilized","draggingNodes","calculationNodes","calculationNodeIndices","nodeIndices","canvasTopLeft","canvasBottomRight","pointerPosition","areaCenter","previousScale","nodesData","edgesData","nodesListeners","_addNodes","_updateNodes","_removeNodes","edgesListeners","_addEdges","_updateEdges","_removeEdges","moving","_setupHierarchicalLayout","zoomExtent","startWithClustering","MixinLoader","browserType","requiresTimeout","_getScriptPath","scripts","getElementsByTagName","_getRange","minY","maxY","minX","maxX","nodeId","boundingBox","_findCenter","animationOptions","initialZoom","disableStart","zoomLevel","numberOfNodes","yDistance","xZoomLevel","yZoomLevel","animation","_updateNodeIndexList","_clearNodeIndexList","idx","_createManipulatorBar","dotData","DOTToGraph","gephi","gephiData","parseGephi","_setNodes","_setEdges","_putDataInSector","_resetLevels","_stabilize","onEdit","onEditEdge","onConnect","onDelete","editMode","newColorObj","groupname","_createKeyBinds","_loadNavigationControls","_loadManipulationSystem","_configureSmoothCurves","devicePixelRatio","webkitBackingStorePixelRatio","mozBackingStorePixelRatio","msBackingStorePixelRatio","oBackingStorePixelRatio","backingStorePixelRatio","setTransform","pinch","_onTap","_onDoubleTap","_onMouseMoveTitle","hammerFrame","_onRelease","_moveUp","_yStopMoving","_moveDown","_moveLeft","_xStopMoving","_moveRight","_zoomIn","_stopZoom","_zoomOut","_deleteSelected","_cleanupPhysicsConfiguration","_recursiveDOMDelete","DOMobject","_getPointer","pinched","_getScale","_handleTouch","_handleDragStart","_getNodeAt","_getTranslation","isSelected","_selectObject","nodeIds","objectId","selectionObj","xFixed","yFixed","_handleOnDrag","releaseNode","_XconvertDOMtoCanvas","_XconvertCanvasToDOM","_YconvertDOMtoCanvas","_YconvertCanvasToDOM","_handleDragEnd","_handleTap","_handleDoubleTap","_handleOnHold","_handleOnRelease","_zoom","scaleOld","preScaleDragPointer","DOMtoCanvas","scaleFrac","tx","ty","updateClustersDefault","postScaleDragPointer","canvasToDOM","popupObj","_checkHidePopup","checkShow","_checkShowPopup","popupTimer","edgeId","_getEdgeAt","_hoverObject","_blurObject","lastPopupNode","nodeUnderCursor","overlappingNodes","isOverlappingWith","getTitle","overlappingEdges","edge","connected","popup","setPosition","setText","emitEvent","oldWidth","oldHeight","oldNodesData","_updateSelection","_updateCalculationNodes","_reconnectEdges","_updateValueRange","updateLabels","changedData","setProperties","oldEdgesData","oldEdge","disconnect","showInternalIds","_createBezierNodes","via","sectors","dynamicEdges","setValueRange","save","translate","_doInAllSectors","restore","offsetX","offsetY","_drawNodes","alwaysShow","setScaleAndPos","inArea","sMax","_drawEdges","_drawControlNodes","_freezeDefinedNodes","_physicsTick","_restoreFrozenNodes","fixedData","_isMoving","vmin","isMoving","_discreteStepNodes","nodesPresent","discreteStepLimited","discreteStep","vminCorrected","_revertPhysicsState","revertPosition","_revertPhysicsTick","_doInAllActiveSectors","_doInSupportSector","mainMovingStatus","supportMovingStatus","mainMoving","_animationStep","_handleNavigation","startTime","renderStartTime","requestAnimationFrame","mozRequestAnimationFrame","webkitRequestAnimationFrame","msRequestAnimationFrame","iterations","toggleFreeze","parentEdgeId","internalMultiplier","positionBezierNode","storePosition","storePositions","dataArray","allowedToMoveX","allowedToMoveY","getPositions","focusOnNode","nodePosition","lockedOnNode","easingFunction","animateView","locked","_transitionRedraw","viewCenter","distanceFromCenter","_classicRedraw","_lockedRedraw","getCenterCoordinates","getBoundingBox","networkConstants","fromId","toId","widthSelected","labelDimensions","yLine","dirtyLabel","fromBackup","toBackup","originalFromId","originalToId","widthFixed","lengthFixed","controlNodesEnabled","controlNodes","positions","connectedNode","_drawLine","_drawArrow","_drawArrowCenter","_drawDashLine","attachEdge","detachEdge","xFrom","yFrom","xTo","yTo","xObj","yObj","_getDistanceToEdge","_getColor","colorObj","_getLineWidth","_line","midpointX","midpointY","_pointOnLine","_label","resize","_circle","_pointOnCircle","networkScaleInv","_getViaCoordinates","xVia","yVia","quadraticCurveTo","lineCount","measureText","_rotateForLabelAlignment","_drawLabelRect","_drawLabelText","angleInDegrees","rotate","lineMargin","fillRect","lineJoin","strokeText","setLineDash","pattern","lineDashOffset","lineCap","dashedLine","percentage","arrow","_pointOnBezier","_findBorderPosition","distanceToBorder","distanceToNodes","difference","arrowPos","guidePos","edgeSegmentLength","toBorderDist","toBorderPoint","x1","y1","x2","y2","x3","y3","lastX","lastY","minDistance","_getDistanceToLine","px","py","something","u","nodeIdFrom","nodeIdTo","getControlNodeFromPosition","getControlNodeToPosition","_enableControlNodes","_disableControlNodes","_getSelectedControlNode","fromDistance","toDistance","_restoreControlNodes","controlnodeFromPos","fromBorderDist","fromBorderPoint","controlnodeToPos","imagelist","grouplist","reroutedEdges","fontDrawThreshold","horizontalAlignLeft","verticalAlignTop","baseRadiusValue","radiusFixed","preassignedLevel","hierarchyEnumerated","fx","fy","vx","vy","previousState","resetCluster","dynamicEdgesLength","clusterSession","clusterSizeWidthFactor","clusterSizeHeightFactor","clusterSizeRadiusFactor","growthIndicator","networkScale","formationScale","clusterSize","containedNodes","containedEdges","clusterSessions","originalLabel","triggerFunction","groupObj","imageObj","load","brokenImage","_drawDatabase","_resizeDatabase","_drawBox","_resizeBox","_drawCircle","_resizeCircle","_drawEllipse","_resizeEllipse","_drawImage","_resizeImage","_drawCircularImage","_resizeCircularImage","_drawText","_resizeText","_drawDot","_resizeShape","_drawSquare","_drawTriangle","_drawTriangleDown","_drawStar","_reset","clearSizeCache","_setForce","_addForce","storeState","isFixed","_drawImageAtPosition","globalAlpha","drawImage","_drawImageLabel","getTextSize","_swapToImageResizeWhenImageLoaded","diameter","centerX","centerY","_drawRawCircle","circle","clip","textSize","clusterLineWidth","selectionLineWidth","roundRect","database","defaultSize","ellipse","_drawShape","radiusMultiplier","baseline","labelUnderNode","inView","clearVelocity","updateVelocity","massBeforeClustering","energyBefore","defaultIndex","DEFAULT","imageBroken","url","brokenUrl","img","Image","onload","onerror","error","styleAttr","fontFamily","WebkitBorderRadius","whiteSpace","parseDOT","parseGraph","nextPreview","isAlphaNumeric","regexAlphaNumeric","o","addNode","graphs","attr","addEdge","createEdge","getToken","tokenType","TOKENTYPE","NULL","isComment","DELIMITER","c2","DELIMITERS","IDENTIFIER","newSyntaxError","UNKNOWN","chop","parseStatements","parseStatement","subgraph","parseSubgraph","parseEdge","parseAttributeStatement","parseNodeStatement","subgraphs","parseAttributeList","message","maxLength","forEach2","elem1","elem2","graphData","dotNode","graphNode","convertEdge","dotEdge","graphEdge","subEdge","{","}","[","]",";","=",",","->","--","gephiJSON","allowedToMove","gEdges","gNodes","gEdge","gNode","PhysicsMixin","ClusterMixin","SectorsMixin","SelectionMixin","ManipulationMixin","NavigationMixin","HierarchicalLayoutMixin","_loadMixin","sourceVariable","mixinFunction","_clearMixin","_loadSelectedForceSolver","_loadPhysicsConfiguration","hubThreshold","activeSector","drawingNode","blockConnectingEdgeSelection","forceAppendSelection","manipulationDiv","editModeDiv","closeDiv","_cleanNavigation","_loadNavigationElements","graphToggleSmoothCurves","graph_toggleSmooth","getElementById","graphRepositionNodes","showValueOfRange","repositionNodes","graphGenerateOptions","optionsSpecific","radioButton1","radioButton2","checked","backupConstants","optionsDiv","switchConfigurations","radioButton","querySelector","tableId","table","_restoreNodes","constantsVariableName","valueId","rangeValue","_overWriteGraphConstants","RepulsionMixin","HierarchialRepulsionMixin","BarnesHutMixin","_toggleBarnesHut","barnesHutTree","_initializeForceCalculation","clusterToFit","_calculateForces","_calculateGravitationalForces","_calculateNodeForces","_calculateSpringForcesWithSupport","_calculateHierarchicalSpringForces","_calculateSpringForces","supportNodes","supportNodeId","gravity","gravityForce","_sector","edgeLength","springForce","combinedClusterSize","node1","node2","node3","_calculateSpringForce","physicsConfiguration","hierarchicalLayoutDirections","parentElement","rangeElement","radioButton3","graph_repositionNodes","graph_generateOptions","dynamicSmoothCurves","nameArray","repulsingForce","a_base","minimumDistance","steepness","springFx","springFy","totalFx","totalFy","correctionFx","correctionFy","nodeCount","_formBarnesHutTree","_getForceContribution","NW","NE","SW","SE","parentBranch","childrenCount","centerOfMass","calcSize","MAX_VALUE","sizeDiff","minimumTreeSize","rootSize","halfRootSize","_splitBranch","_placeInTree","_updateBranchMass","totalMass","totalMassInv","biggestSize","skipMassUpdate","_placeInRegion","region","containedNode","_insertRegion","childSize","_drawTree","_drawBranch","branch","maxNumberOfNodes","reposition","maxLevels","forceAggregateHubs","normalizeClusterLevels","increaseClusterLevel","openCluster","isMovingBeforeClustering","_nodeInActiveArea","_addSector","decreaseClusterLevel","_expandClusterNode","_updateDynamicEdges","updateClusters","zoomDirection","recursive","doNotStart","amountOfNodes","_collapseSector","_formClusters","_openClusters","_openClustersBySize","_aggregateHubs","handleChains","chainPercentage","_getChainFraction","_reduceAmountOfChains","_getHubSize","_formClustersByHub","openAll","containedNodeId","childNode","_expelChildFromParent","_unselectAll","_releaseContainedEdges","_connectEdgeBackToChild","_validateEdges","othersPresent","childNodeId","_repositionBezierNodes","_formClustersByZoom","_forceClustersByZoom","minLength","_addToCluster","_clusterToSmallestNeighbour","smallestNeighbour","smallestNeighbourNode","neighbour","onlyEqual","_formClusterFromHub","hubNode","absorptionSizeOffset","allowCluster","edgesIdarray","amountOfInitialEdges","_addToContainedEdges","_connectEdgeToCluster","_containCircularEdgesFromNode","massBefore","correction","edgeToId","edgeFromId","k","_addToReroutedEdges","maxLevel","minLevel","clusterLevel","targetLevel","average","averageSquared","hubCounter","largestHub","variance","standardDeviation","fraction","reduceAmount","chains","total","_switchToSector","sectorId","sectorType","_switchToActiveSector","_switchToFrozenSector","_switchToSupportSector","_loadLatestSector","_previousSector","_setActiveSector","newId","_forgetLastSector","_createNewSector","_deleteActiveSector","_deleteFrozenSector","_freezeSector","_activateSector","_mergeThisWithFrozen","_collapseThisToSingleCluster","sector","unqiueIdentifier","previousSector","runFunction","argument","returnValues","_doInAllFrozenSectors","_drawSectorNodes","_drawAllSectorNodes","_getNodesOverlappingWith","_getAllNodesOverlappingWith","_pointerToPositionObject","positionObject","_getEdgesOverlappingWith","_getAllEdgesOverlappingWith","_addToSelection","_addToHover","_removeFromSelection","doNotTrigger","_unselectClusters","_getSelectedNodeCount","_getSelectedNode","_getSelectedEdge","_getSelectedEdgeCount","_getSelectedObjectCount","_selectionIsEmpty","_clusterInSelection","_selectConnectedEdges","_hoverConnectedEdges","_unselectConnectedEdges","append","highlightEdges","overrideSelectable","DOM","_manipulationReleaseOverload","_navigationReleaseOverload","getSelectedNodes","edgeIds","getSelectedEdges","idArray","selectNodes","RangeError","selectEdges","_clearManipulatorBar","manipulationDOM","_restoreOverloadedFunctions","functionName","_toggleEditMode","toolbar","boundFunction","edgeBeingEdited","selectedControlNode","_createAddNodeToolbar","_createAddEdgeToolbar","_editNode","_createEditEdgeToolbar","_addNode","_handleConnect","_finishConnect","_selectControlNode","_controlNodeDrag","_releaseControlNode","newNode","_editEdge","alert","targetNode","connectionEdge","connectFromId","_createEdge","defaultData","finalizedData","sourceNodeId","targetNodeId","selectedNodes","selectedEdges","navigationDivs","navigationDivActions","_stopMovement","_zoomExtent","hubsize","definedLevel","undefinedLevel","_changeConstants","_determineLevels","_determineLevelsDirected","distribution","_getDistribution","_placeNodesByHierarchy","minPos","_placeBranchNodes","maxCount","_setLevel","firstNode","_setLevelDirected","parentId","parentLevel","nodeMoved","back","editNode","addDescription","edgeDescription","editEdgeDescription","createEdgeError","deleteClusterError","CanvasRenderingContext2D","square","s2","ir","triangleDown","star","n","r2d","kappa","ox","oy","xe","ye","xm","ym","bezierCurveTo","wEllipse","hEllipse","ymb","yeb","xt","yt","xi","yi","xl","yl","xr","yr","dashArray","dashLength","dashCount","slope","distRemaining","dashIndex"],"mappings":"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"} \ No newline at end of file diff --git a/dist/vis.min.js b/dist/vis.min.js index a4015de6..c54f0138 100644 --- a/dist/vis.min.js +++ b/dist/vis.min.js @@ -5,7 +5,7 @@ * A dynamic, browser-based visualization library. * * @version 3.9.1-SNAPSHOT - * @date 2015-01-16 + * @date 2015-01-17 * * @license * Copyright (C) 2011-2014 Almende B.V, http://almende.com @@ -22,18 +22,18 @@ * * Vis.js may be distributed under either license. */ -"use strict";!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):"object"==typeof exports?exports.vis=e():t.vis=e()}(this,function(){return function(t){function e(s){if(i[s])return i[s].exports;var o=i[s]={exports:{},id:s,loaded:!1};return t[s].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var i={};return e.m=t,e.c=i,e.p="",e(0)}([function(t,e,i){e.util=i(1),e.DOMutil=i(2),e.DataSet=i(3),e.DataView=i(4),e.Queue=i(5),e.Graph3d=i(6),e.graph3d={Camera:i(7),Filter:i(8),Point2d:i(9),Point3d:i(10),Slider:i(11),StepNumber:i(12)},e.Timeline=i(13),e.Graph2d=i(14),e.timeline={DateUtil:i(15),DataStep:i(16),Range:i(17),stack:i(18),TimeStep:i(19),components:{items:{Item:i(31),BackgroundItem:i(32),BoxItem:i(33),PointItem:i(34),RangeItem:i(35)},Component:i(20),CurrentTime:i(21),CustomTime:i(22),DataAxis:i(23),GraphGroup:i(24),Group:i(25),BackgroundGroup:i(26),ItemSet:i(27),Legend:i(28),LineGraph:i(29),TimeAxis:i(30)}},e.Network=i(36),e.network={Edge:i(37),Groups:i(38),Images:i(39),Node:i(40),Popup:i(41),dotparser:i(42),gephiParser:i(43)},e.Graph=function(){throw new Error("Graph is renamed to Network. Please create a graph as new vis.Network(...)")},e.moment=i(44),e.hammer=i(45)},function(t,e,i){var s=i(44);e.isNumber=function(t){return t instanceof Number||"number"==typeof t},e.isString=function(t){return t instanceof String||"string"==typeof t},e.isDate=function(t){if(t instanceof Date)return!0;if(e.isString(t)){var i=o.exec(t);if(i)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},e.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},e.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},e.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var s=arguments[e];for(var o in s)s.hasOwnProperty(o)&&(t[o]=s[o])}return t},e.selectiveExtend=function(t,e){if(!Array.isArray(t))throw new Error("Array with property names expected as first argument");for(var i=2;ii;i++)if(t[i]!=e[i])return!1;return!0},e.convert=function(t,i){var n;if(void 0===t)return void 0;if(null===t)return null;if(!i)return t;if("string"!=typeof i&&!(i instanceof String))throw new Error("Type must be a string");switch(i){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return String(t);case"Date":if(e.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(s.isMoment(t))return new Date(t.valueOf());if(e.isString(t))return n=o.exec(t),n?new Date(Number(n[1])):s(t).toDate();throw new Error("Cannot convert object of type "+e.getType(t)+" to type Date");case"Moment":if(e.isNumber(t))return s(t);if(t instanceof Date)return s(t.valueOf());if(s.isMoment(t))return s(t);if(e.isString(t))return n=o.exec(t),s(n?Number(n[1]):t);throw new Error("Cannot convert object of type "+e.getType(t)+" to type Date");case"ISODate":if(e.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(s.isMoment(t))return t.toDate().toISOString();if(e.isString(t))return n=o.exec(t),n?new Date(Number(n[1])).toISOString():new Date(t).toISOString();throw new Error("Cannot convert object of type "+e.getType(t)+" to type ISODate");case"ASPDate":if(e.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(e.isString(t)){n=o.exec(t);var r;return r=n?new Date(Number(n[1])).valueOf():new Date(t).valueOf(),"/Date("+r+")/"}throw new Error("Cannot convert object of type "+e.getType(t)+" to type ASPDate");default:throw new Error('Unknown type "'+i+'"')}};var o=/^\/?Date\((\-?\d+)/i;e.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":Array.isArray(t)?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},e.getAbsoluteLeft=function(t){return t.getBoundingClientRect().left+window.pageXOffset},e.getAbsoluteTop=function(t){return t.getBoundingClientRect().top+window.pageYOffset},e.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},e.removeClassName=function(t,e){var i=t.className.split(" "),s=i.indexOf(e);-1!=s&&(i.splice(s,1),t.className=i.join(" "))},e.forEach=function(t,e){var i,s;if(Array.isArray(t))for(i=0,s=t.length;s>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},e.toArray=function(t){var e=[];for(var i in t)t.hasOwnProperty(i)&&e.push(t[i]);return e},e.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},e.addEventListener=function(t,e,i,s){t.addEventListener?(void 0===s&&(s=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,s)):t.attachEvent("on"+e,i)},e.removeEventListener=function(t,e,i,s){t.removeEventListener?(void 0===s&&(s=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,s)):t.detachEvent("on"+e,i)},e.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},e.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},e.option={},e.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},e.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},e.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?String(t):e||null},e.option.asSize=function(t,i){return"function"==typeof t&&(t=t()),e.isString(t)?t:e.isNumber(t)?t+"px":i||null},e.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null},e.hexToRGB=function(t){var e=/^#?([a-f\d])([a-f\d])([a-f\d])$/i;t=t.replace(e,function(t,e,i,s){return e+e+i+i+s+s});var i=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(t);return i?{r:parseInt(i[1],16),g:parseInt(i[2],16),b:parseInt(i[3],16)}:null},e.RGBToHex=function(t,e,i){return"#"+((1<<24)+(t<<16)+(e<<8)+i).toString(16).slice(1)},e.parseColor=function(t){var i;if(e.isString(t)){if(e.isValidRGB(t)){var s=t.substr(4).substr(0,t.length-5).split(",");t=e.RGBToHex(s[0],s[1],s[2])}if(e.isValidHex(t)){var o=e.hexToHSV(t),n={h:o.h,s:.45*o.s,v:Math.min(1,1.05*o.v)},r={h:o.h,s:Math.min(1,1.25*o.v),v:.6*o.v},a=e.HSVToHex(r.h,r.h,r.v),h=e.HSVToHex(n.h,n.s,n.v);i={background:t,border:a,highlight:{background:h,border:a},hover:{background:h,border:a}}}else i={background:t,border:t,highlight:{background:t,border:t},hover:{background:t,border:t}}}else i={},i.background=t.background||"white",i.border=t.border||i.background,e.isString(t.highlight)?i.highlight={border:t.highlight,background:t.highlight}:(i.highlight={},i.highlight.background=t.highlight&&t.highlight.background||i.background,i.highlight.border=t.highlight&&t.highlight.border||i.border),e.isString(t.hover)?i.hover={border:t.hover,background:t.hover}:(i.hover={},i.hover.background=t.hover&&t.hover.background||i.background,i.hover.border=t.hover&&t.hover.border||i.border);return i},e.RGBToHSV=function(t,e,i){t/=255,e/=255,i/=255;var s=Math.min(t,Math.min(e,i)),o=Math.max(t,Math.max(e,i));if(s==o)return{h:0,s:0,v:s};var n=t==s?e-i:i==s?t-e:i-t,r=t==s?3:i==s?1:5,a=60*(r-n/(o-s))/360,h=(o-s)/o,d=o;return{h:a,s:h,v:d}};var n={split:function(t){var e={};return t.split(";").forEach(function(t){if(""!=t.trim()){var i=t.split(":"),s=i[0].trim(),o=i[1].trim();e[s]=o}}),e},join:function(t){return Object.keys(t).map(function(e){return e+": "+t[e]}).join("; ")}};e.addCssText=function(t,i){var s=n.split(t.style.cssText),o=n.split(i),r=e.extend(s,o);t.style.cssText=n.join(r)},e.removeCssText=function(t,e){var i=n.split(t.style.cssText),s=n.split(e);for(var o in s)s.hasOwnProperty(o)&&delete i[o];t.style.cssText=n.join(i)},e.HSVToRGB=function(t,e,i){var s,o,n,r=Math.floor(6*t),a=6*t-r,h=i*(1-e),d=i*(1-a*e),l=i*(1-(1-a)*e);switch(r%6){case 0:s=i,o=l,n=h;break;case 1:s=d,o=i,n=h;break;case 2:s=h,o=i,n=l;break;case 3:s=h,o=d,n=i;break;case 4:s=l,o=h,n=i;break;case 5:s=i,o=h,n=d}return{r:Math.floor(255*s),g:Math.floor(255*o),b:Math.floor(255*n)}},e.HSVToHex=function(t,i,s){var o=e.HSVToRGB(t,i,s);return e.RGBToHex(o.r,o.g,o.b)},e.hexToHSV=function(t){var i=e.hexToRGB(t);return e.RGBToHSV(i.r,i.g,i.b)},e.isValidHex=function(t){var e=/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(t);return e},e.isValidRGB=function(t){t=t.replace(" ","");var e=/rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)/i.test(t);return e},e.selectiveBridgeObject=function(t,i){if("object"==typeof i){for(var s=Object.create(i),o=0;o=r&&o>n;){var h=Math.floor((r+a)/2),d=t[h],l=void 0===s?d[i]:d[i][s],c=e(l);if(0==c)return h;-1==c?r=h+1:a=h-1,n++}return-1},e.binarySearchValue=function(t,e,i,s){for(var o,n,r,a,h=1e4,d=0,l=0,c=t.length-1;c>=l&&h>d;){if(a=Math.floor(.5*(c+l)),o=t[Math.max(0,a-1)][i],n=t[a][i],r=t[Math.min(t.length-1,a+1)][i],n==e)return a;if(e>o&&n>e)return"before"==s?Math.max(0,a-1):a;if(e>n&&r>e)return"before"==s?a:Math.min(t.length-1,a+1);e>n?l=a+1:c=a-1,d++}return-1},e.easeInOutQuad=function(t,e,i,s){var o=i-e;return t/=s/2,1>t?o/2*t*t+e:(t--,-o/2*(t*(t-2)-1)+e)},e.easingFunctions={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return t*(2-t)},easeInOutQuad:function(t){return.5>t?2*t*t:-1+(4-2*t)*t},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return--t*t*t+1},easeInOutCubic:function(t){return.5>t?4*t*t*t:(t-1)*(2*t-2)*(2*t-2)+1},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return 1- --t*t*t*t},easeInOutQuart:function(t){return.5>t?8*t*t*t*t:1-8*--t*t*t*t},easeInQuint:function(t){return t*t*t*t*t},easeOutQuint:function(t){return 1+--t*t*t*t*t},easeInOutQuint:function(t){return.5>t?16*t*t*t*t*t:1+16*--t*t*t*t*t}}},function(t,e){e.prepareElements=function(t){for(var e in t)t.hasOwnProperty(e)&&(t[e].redundant=t[e].used,t[e].used=[])},e.cleanupElements=function(t){for(var e in t)if(t.hasOwnProperty(e)&&t[e].redundant){for(var i=0;i0?(s=e[t].redundant[0],e[t].redundant.shift()):(s=document.createElementNS("http://www.w3.org/2000/svg",t),i.appendChild(s)):(s=document.createElementNS("http://www.w3.org/2000/svg",t),e[t]={used:[],redundant:[]},i.appendChild(s)),e[t].used.push(s),s},e.getDOMElement=function(t,e,i,s){var o;return e.hasOwnProperty(t)?e[t].redundant.length>0?(o=e[t].redundant[0],e[t].redundant.shift()):(o=document.createElement(t),void 0!==s?i.insertBefore(o,s):i.appendChild(o)):(o=document.createElement(t),e[t]={used:[],redundant:[]},void 0!==s?i.insertBefore(o,s):i.appendChild(o)),e[t].used.push(o),o},e.drawPoint=function(t,i,s,o,n){var r;return"circle"==s.options.drawPoints.style?(r=e.getSVGElement("circle",o,n),r.setAttributeNS(null,"cx",t),r.setAttributeNS(null,"cy",i),r.setAttributeNS(null,"r",.5*s.options.drawPoints.size)):(r=e.getSVGElement("rect",o,n),r.setAttributeNS(null,"x",t-.5*s.options.drawPoints.size),r.setAttributeNS(null,"y",i-.5*s.options.drawPoints.size),r.setAttributeNS(null,"width",s.options.drawPoints.size),r.setAttributeNS(null,"height",s.options.drawPoints.size)),void 0!==s.options.drawPoints.styles&&r.setAttributeNS(null,"style",s.group.options.drawPoints.styles),r.setAttributeNS(null,"class",s.className+" point"),r},e.drawBar=function(t,i,s,o,n,r,a){if(0!=o){0>o&&(o*=-1,i-=o);var h=e.getSVGElement("rect",r,a);h.setAttributeNS(null,"x",t-.5*s),h.setAttributeNS(null,"y",i),h.setAttributeNS(null,"width",s),h.setAttributeNS(null,"height",o),h.setAttributeNS(null,"class",n)}}},function(t,e,i){function s(t,e){if(!t||Array.isArray(t)||o.isDataTable(t)||(e=t,t=null),this._options=e||{},this._data={},this._fieldId=this._options.fieldId||"id",this._type={},this._options.type)for(var i in this._options.type)if(this._options.type.hasOwnProperty(i)){var s=this._options.type[i];this._type[i]="Date"==s||"ISODate"==s||"ASPDate"==s?"Date":s}if(this._options.convert)throw new Error('Option "convert" is deprecated. Use "type" instead.');this._subscribers={},t&&this.add(t),this.setOptions(e)}var o=i(1),n=i(5);s.prototype.setOptions=function(t){t&&void 0!==t.queue&&(t.queue===!1?this._queue&&(this._queue.destroy(),delete this._queue):(this._queue||(this._queue=n.extend(this,{replace:["add","update","remove"]})),"object"==typeof t.queue&&this._queue.setOptions(t.queue)))},s.prototype.on=function(t,e){var i=this._subscribers[t];i||(i=[],this._subscribers[t]=i),i.push({callback:e})},s.prototype.subscribe=s.prototype.on,s.prototype.off=function(t,e){var i=this._subscribers[t];i&&(this._subscribers[t]=i.filter(function(t){return t.callback!=e}))},s.prototype.unsubscribe=s.prototype.off,s.prototype._trigger=function(t,e,i){if("*"==t)throw new Error("Cannot trigger event *");var s=[];t in this._subscribers&&(s=s.concat(this._subscribers[t])),"*"in this._subscribers&&(s=s.concat(this._subscribers["*"]));for(var o=0;or;r++)i=n._addItem(t[r]),s.push(i);else if(o.isDataTable(t))for(var h=this._getColumnNames(t),d=0,l=t.getNumberOfRows();l>d;d++){for(var c={},p=0,u=h.length;u>p;p++){var m=h[p];c[m]=t.getValue(d,p)}i=n._addItem(c),s.push(i)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");i=n._addItem(t),s.push(i)}return s.length&&this._trigger("add",{items:s},e),s},s.prototype.update=function(t,e){var i=[],s=[],n=[],r=this,a=r._fieldId,h=function(t){var e=t[a];r._data[e]?(e=r._updateItem(t),s.push(e),n.push(t)):(e=r._addItem(t),i.push(e))};if(Array.isArray(t))for(var d=0,l=t.length;l>d;d++)h(t[d]);else if(o.isDataTable(t))for(var c=this._getColumnNames(t),p=0,u=t.getNumberOfRows();u>p;p++){for(var m={},f=0,g=c.length;g>f;f++){var v=c[f];m[v]=t.getValue(p,f)}h(m)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");h(t)}return i.length&&this._trigger("add",{items:i},e),s.length&&this._trigger("update",{items:s,data:n},e),i.concat(s)},s.prototype.get=function(){var t,e,i,s,n=this,r=o.getType(arguments[0]);"String"==r||"Number"==r?(t=arguments[0],i=arguments[1],s=arguments[2]):"Array"==r?(e=arguments[0],i=arguments[1],s=arguments[2]):(i=arguments[0],s=arguments[1]);var a;if(i&&i.returnType){var h=["DataTable","Array","Object"];if(a=-1==h.indexOf(i.returnType)?"Array":i.returnType,s&&a!=o.getType(s))throw new Error('Type of parameter "data" ('+o.getType(s)+") does not correspond with specified options.type ("+i.type+")");if("DataTable"==a&&!o.isDataTable(s))throw new Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else a=s&&"DataTable"==o.getType(s)?"DataTable":"Array";var d,l,c,p,u=i&&i.type||this._options.type,m=i&&i.filter,f=[];if(void 0!=t)d=n._getItem(t,u),m&&!m(d)&&(d=null);else if(void 0!=e)for(c=0,p=e.length;p>c;c++)d=n._getItem(e[c],u),(!m||m(d))&&f.push(d);else for(l in this._data)this._data.hasOwnProperty(l)&&(d=n._getItem(l,u),(!m||m(d))&&f.push(d));if(i&&i.order&&void 0==t&&this._sort(f,i.order),i&&i.fields){var g=i.fields;if(void 0!=t)d=this._filterFields(d,g);else for(c=0,p=f.length;p>c;c++)f[c]=this._filterFields(f[c],g)}if("DataTable"==a){var v=this._getColumnNames(s);if(void 0!=t)n._appendRow(s,v,d);else for(c=0;cc;c++)s.push(f[c]);return s}return f},s.prototype.getIds=function(t){var e,i,s,o,n,r=this._data,a=t&&t.filter,h=t&&t.order,d=t&&t.type||this._options.type,l=[];if(a)if(h){n=[];for(s in r)r.hasOwnProperty(s)&&(o=this._getItem(s,d),a(o)&&n.push(o));for(this._sort(n,h),e=0,i=n.length;i>e;e++)l[e]=n[e][this._fieldId]}else for(s in r)r.hasOwnProperty(s)&&(o=this._getItem(s,d),a(o)&&l.push(o[this._fieldId]));else if(h){n=[];for(s in r)r.hasOwnProperty(s)&&n.push(r[s]);for(this._sort(n,h),e=0,i=n.length;i>e;e++)l[e]=n[e][this._fieldId]}else for(s in r)r.hasOwnProperty(s)&&(o=r[s],l.push(o[this._fieldId]));return l},s.prototype.getDataSet=function(){return this},s.prototype.forEach=function(t,e){var i,s,o=e&&e.filter,n=e&&e.type||this._options.type,r=this._data;if(e&&e.order)for(var a=this.get(e),h=0,d=a.length;d>h;h++)i=a[h],s=i[this._fieldId],t(i,s);else for(s in r)r.hasOwnProperty(s)&&(i=this._getItem(s,n),(!o||o(i))&&t(i,s))},s.prototype.map=function(t,e){var i,s=e&&e.filter,o=e&&e.type||this._options.type,n=[],r=this._data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,o),(!s||s(i))&&n.push(t(i,a)));return e&&e.order&&this._sort(n,e.order),n},s.prototype._filterFields=function(t,e){var i={};for(var s in t)t.hasOwnProperty(s)&&-1!=e.indexOf(s)&&(i[s]=t[s]);return i},s.prototype._sort=function(t,e){if(o.isString(e)){var i=e;t.sort(function(t,e){var s=t[i],o=e[i];return s>o?1:o>s?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},s.prototype.remove=function(t,e){var i,s,o,n=[];if(Array.isArray(t))for(i=0,s=t.length;s>i;i++)o=this._remove(t[i]),null!=o&&n.push(o);else o=this._remove(t),null!=o&&n.push(o);return n.length&&this._trigger("remove",{items:n},e),n},s.prototype._remove=function(t){if(o.isNumber(t)||o.isString(t)){if(this._data[t])return delete this._data[t],t}else if(t instanceof Object){var e=t[this._fieldId];if(e&&this._data[e])return delete this._data[e],e}return null},s.prototype.clear=function(t){var e=Object.keys(this._data);return this._data={},this._trigger("remove",{items:e},t),e},s.prototype.max=function(t){var e=this._data,i=null,s=null;for(var o in e)if(e.hasOwnProperty(o)){var n=e[o],r=n[t];null!=r&&(!i||r>s)&&(i=n,s=r)}return i},s.prototype.min=function(t){var e=this._data,i=null,s=null;for(var o in e)if(e.hasOwnProperty(o)){var n=e[o],r=n[t];null!=r&&(!i||s>r)&&(i=n,s=r)}return i},s.prototype.distinct=function(t){var e,i=this._data,s=[],n=this._options.type&&this._options.type[t]||null,r=0;for(var a in i)if(i.hasOwnProperty(a)){var h=i[a],d=h[t],l=!1;for(e=0;r>e;e++)if(s[e]==d){l=!0;break}l||void 0===d||(s[r]=d,r++)}if(n)for(e=0;ei;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},s.prototype._appendRow=function(t,e,i){for(var s=t.addRow(),o=0,n=e.length;n>o;o++){var r=e[o];t.setValue(s,o,i[r])}},t.exports=s},function(t,e,i){function s(t,e){this._data=null,this._ids={},this._options=e||{},this._fieldId="id",this._subscribers={};var i=this;this.listener=function(){i._onEvent.apply(i,arguments)},this.setData(t)}var o=i(1),n=i(3);s.prototype.setData=function(t){var e,i,s;if(this._data){this._data.unsubscribe&&this._data.unsubscribe("*",this.listener),e=[];for(var o in this._ids)this._ids.hasOwnProperty(o)&&e.push(o);this._ids={},this._trigger("remove",{items:e})}if(this._data=t,this._data){for(this._fieldId=this._options.fieldId||this._data&&this._data.options&&this._data.options.fieldId||"id",e=this._data.getIds({filter:this._options&&this._options.filter}),i=0,s=e.length;s>i;i++)o=e[i],this._ids[o]=!0;this._trigger("add",{items:e}),this._data.on&&this._data.on("*",this.listener)}},s.prototype.get=function(){var t,e,i,s=this,n=o.getType(arguments[0]);"String"==n||"Number"==n||"Array"==n?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var r=o.extend({},this._options,e);this._options.filter&&e&&e.filter&&(r.filter=function(t){return s._options.filter(t)&&e.filter(t)});var a=[];return void 0!=t&&a.push(t),a.push(r),a.push(i),this._data&&this._data.get.apply(this._data,a)},s.prototype.getIds=function(t){var e;if(this._data){var i,s=this._options.filter;i=t&&t.filter?s?function(e){return s(e)&&t.filter(e)}:t.filter:s,e=this._data.getIds({filter:i,order:t&&t.order})}else e=[];return e},s.prototype.getDataSet=function(){for(var t=this;t instanceof s;)t=t._data;return t||null},s.prototype._onEvent=function(t,e,i){var s,o,n,r,a=e&&e.items,h=this._data,d=[],l=[],c=[];if(a&&h){switch(t){case"add":for(s=0,o=a.length;o>s;s++)n=a[s],r=this.get(n),r&&(this._ids[n]=!0,d.push(n));break;case"update":for(s=0,o=a.length;o>s;s++)n=a[s],r=this.get(n),r?this._ids[n]?l.push(n):(this._ids[n]=!0,d.push(n)):this._ids[n]&&(delete this._ids[n],c.push(n));break;case"remove":for(s=0,o=a.length;o>s;s++)n=a[s],this._ids[n]&&(delete this._ids[n],c.push(n))}d.length&&this._trigger("add",{items:d},i),l.length&&this._trigger("update",{items:l},i),c.length&&this._trigger("remove",{items:c},i)}},s.prototype.on=n.prototype.on,s.prototype.off=n.prototype.off,s.prototype._trigger=n.prototype._trigger,s.prototype.subscribe=s.prototype.on,s.prototype.unsubscribe=s.prototype.off,t.exports=s},function(t){function e(t){this.delay=null,this.max=1/0,this._queue=[],this._timeout=null,this._extended=null,this.setOptions(t)}e.prototype.setOptions=function(t){t&&"undefined"!=typeof t.delay&&(this.delay=t.delay),t&&"undefined"!=typeof t.max&&(this.max=t.max),this._flushIfNeeded()},e.extend=function(t,i){var s=new e(i);if(void 0!==t.flush)throw new Error("Target object already has a property flush");t.flush=function(){s.flush()};var o=[{name:"flush",original:void 0}];if(i&&i.replace)for(var n=0;nthis.max&&this.flush(),clearTimeout(this._timeout),this.queue.length>0&&"number"==typeof this.delay){var t=this;this._timeout=setTimeout(function(){t.flush()},this.delay)}},e.prototype.flush=function(){for(;this._queue.length>0;){var t=this._queue.shift();t.fn.apply(t.context||t.fn,t.args||[])}},t.exports=e},function(t,e,i){function s(t,e,i){if(!(this instanceof s))throw new SyntaxError("Constructor must be called with the new operator");this.containerElement=t,this.width="400px",this.height="400px",this.margin=10,this.defaultXCenter="55%",this.defaultYCenter="50%",this.xLabel="x",this.yLabel="y",this.zLabel="z";var o=function(t){return t};this.xValueLabel=o,this.yValueLabel=o,this.zValueLabel=o,this.filterLabel="time",this.legendLabel="value",this.style=s.STYLE.DOT,this.showPerspective=!0,this.showGrid=!0,this.keepAspectRatio=!0,this.showShadow=!1,this.showGrayBottom=!1,this.showTooltip=!1,this.verticalRatio=.5,this.animationInterval=1e3,this.animationPreload=!1,this.camera=new p,this.eye=new l(0,0,-1),this.dataTable=null,this.dataPoints=null,this.colX=void 0,this.colY=void 0,this.colZ=void 0,this.colValue=void 0,this.colFilter=void 0,this.xMin=0,this.xStep=void 0,this.xMax=1,this.yMin=0,this.yStep=void 0,this.yMax=1,this.zMin=0,this.zStep=void 0,this.zMax=1,this.valueMin=0,this.valueMax=1,this.xBarWidth=1,this.yBarWidth=1,this.colorAxis="#4D4D4D",this.colorGrid="#D3D3D3",this.colorDot="#7DC1FF",this.colorDotBorder="#3267D2",this.create(),this.setOptions(i),e&&this.setData(e)}function o(t){return"clientX"in t?t.clientX:t.targetTouches[0]&&t.targetTouches[0].clientX||0}function n(t){return"clientY"in t?t.clientY:t.targetTouches[0]&&t.targetTouches[0].clientY||0}var r=i(56),a=i(3),h=i(4),d=i(1),l=i(10),c=i(9),p=i(7),u=i(8),m=i(11),f=i(12);r(s.prototype),s.prototype._setScale=function(){this.scale=new l(1/(this.xMax-this.xMin),1/(this.yMax-this.yMin),1/(this.zMax-this.zMin)),this.keepAspectRatio&&(this.scale.x3&&(this.colFilter=3);else{if(this.style!==s.STYLE.DOTCOLOR&&this.style!==s.STYLE.DOTSIZE&&this.style!==s.STYLE.BARCOLOR&&this.style!==s.STYLE.BARSIZE)throw'Unknown style "'+this.style+'"';this.colX=0,this.colY=1,this.colZ=2,this.colValue=3,t.getNumberOfColumns()>4&&(this.colFilter=4)}},s.prototype.getNumberOfRows=function(t){return t.length},s.prototype.getNumberOfColumns=function(t){var e=0;for(var i in t[0])t[0].hasOwnProperty(i)&&e++;return e},s.prototype.getDistinctValues=function(t,e){for(var i=[],s=0;st[s][e]&&(i.min=t[s][e]),i.maxt;t++){var m=(t-p)/(u-p),g=240*m,v=this._hsv2rgb(g,1,1);c.strokeStyle=v,c.beginPath(),c.moveTo(h,r+t),c.lineTo(a,r+t),c.stroke()}c.strokeStyle=this.colorAxis,c.strokeRect(h,r,i,n)}if(this.style===s.STYLE.DOTSIZE&&(c.strokeStyle=this.colorAxis,c.fillStyle=this.colorDot,c.beginPath(),c.moveTo(h,r),c.lineTo(a,r),c.lineTo(a-i+e,d),c.lineTo(h,d),c.closePath(),c.fill(),c.stroke()),this.style===s.STYLE.DOTCOLOR||this.style===s.STYLE.DOTSIZE){var y=5,b=new f(this.valueMin,this.valueMax,(this.valueMax-this.valueMin)/5,!0);for(b.start(),b.getCurrent()0?this.yMin:this.yMax,o=this._convert3Dto2D(new l(x,r,this.zMin)),Math.cos(2*_)>0?(g.textAlign="center",g.textBaseline="top",o.y+=b):Math.sin(2*_)<0?(g.textAlign="right",g.textBaseline="middle"):(g.textAlign="left",g.textBaseline="middle"),g.fillStyle=this.colorAxis,g.fillText(" "+this.xValueLabel(i.getCurrent())+" ",o.x,o.y),i.next()}for(g.lineWidth=1,s=void 0===this.defaultYStep,i=new f(this.yMin,this.yMax,this.yStep,s),i.start(),i.getCurrent()0?this.xMin:this.xMax,o=this._convert3Dto2D(new l(n,i.getCurrent(),this.zMin)),Math.cos(2*_)<0?(g.textAlign="center",g.textBaseline="top",o.y+=b):Math.sin(2*_)>0?(g.textAlign="right",g.textBaseline="middle"):(g.textAlign="left",g.textBaseline="middle"),g.fillStyle=this.colorAxis,g.fillText(" "+this.yValueLabel(i.getCurrent())+" ",o.x,o.y),i.next();for(g.lineWidth=1,s=void 0===this.defaultZStep,i=new f(this.zMin,this.zMax,this.zStep,s),i.start(),i.getCurrent()0?this.xMin:this.xMax,r=Math.sin(_)<0?this.yMin:this.yMax;!i.end();)t=this._convert3Dto2D(new l(n,r,i.getCurrent())),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(t.x,t.y),g.lineTo(t.x-b,t.y),g.stroke(),g.textAlign="right",g.textBaseline="middle",g.fillStyle=this.colorAxis,g.fillText(this.zValueLabel(i.getCurrent())+" ",t.x-5,t.y),i.next();g.lineWidth=1,t=this._convert3Dto2D(new l(n,r,this.zMin)),e=this._convert3Dto2D(new l(n,r,this.zMax)),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(t.x,t.y),g.lineTo(e.x,e.y),g.stroke(),g.lineWidth=1,p=this._convert3Dto2D(new l(this.xMin,this.yMin,this.zMin)),u=this._convert3Dto2D(new l(this.xMax,this.yMin,this.zMin)),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(p.x,p.y),g.lineTo(u.x,u.y),g.stroke(),p=this._convert3Dto2D(new l(this.xMin,this.yMax,this.zMin)),u=this._convert3Dto2D(new l(this.xMax,this.yMax,this.zMin)),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(p.x,p.y),g.lineTo(u.x,u.y),g.stroke(),g.lineWidth=1,t=this._convert3Dto2D(new l(this.xMin,this.yMin,this.zMin)),e=this._convert3Dto2D(new l(this.xMin,this.yMax,this.zMin)),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(t.x,t.y),g.lineTo(e.x,e.y),g.stroke(),t=this._convert3Dto2D(new l(this.xMax,this.yMin,this.zMin)),e=this._convert3Dto2D(new l(this.xMax,this.yMax,this.zMin)),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(t.x,t.y),g.lineTo(e.x,e.y),g.stroke();var w=this.xLabel;w.length>0&&(c=.1/this.scale.y,n=(this.xMin+this.xMax)/2,r=Math.cos(_)>0?this.yMin-c:this.yMax+c,o=this._convert3Dto2D(new l(n,r,this.zMin)),Math.cos(2*_)>0?(g.textAlign="center",g.textBaseline="top"):Math.sin(2*_)<0?(g.textAlign="right",g.textBaseline="middle"):(g.textAlign="left",g.textBaseline="middle"),g.fillStyle=this.colorAxis,g.fillText(w,o.x,o.y));var S=this.yLabel;S.length>0&&(d=.1/this.scale.x,n=Math.sin(_)>0?this.xMin-d:this.xMax+d,r=(this.yMin+this.yMax)/2,o=this._convert3Dto2D(new l(n,r,this.zMin)),Math.cos(2*_)<0?(g.textAlign="center",g.textBaseline="top"):Math.sin(2*_)>0?(g.textAlign="right",g.textBaseline="middle"):(g.textAlign="left",g.textBaseline="middle"),g.fillStyle=this.colorAxis,g.fillText(S,o.x,o.y));var M=this.zLabel;M.length>0&&(h=30,n=Math.cos(_)>0?this.xMin:this.xMax,r=Math.sin(_)<0?this.yMin:this.yMax,a=(this.zMin+this.zMax)/2,o=this._convert3Dto2D(new l(n,r,a)),g.textAlign="right",g.textBaseline="middle",g.fillStyle=this.colorAxis,g.fillText(M,o.x-h,o.y))},s.prototype._hsv2rgb=function(t,e,i){var s,o,n,r,a,h;switch(r=i*e,a=Math.floor(t/60),h=r*(1-Math.abs(t/60%2-1)),a){case 0:s=r,o=h,n=0;break;case 1:s=h,o=r,n=0;break;case 2:s=0,o=r,n=h;break;case 3:s=0,o=h,n=r;break;case 4:s=h,o=0,n=r;break;case 5:s=r,o=0,n=h;break;default:s=0,o=0,n=0}return"RGB("+parseInt(255*s)+","+parseInt(255*o)+","+parseInt(255*n)+")"},s.prototype._redrawDataGrid=function(){var t,e,i,o,n,r,a,h,d,c,p,u,m,f=this.frame.canvas,g=f.getContext("2d");if(!(void 0===this.dataPoints||this.dataPoints.length<=0)){for(n=0;n0}else r=!0;r?(m=(t.point.z+e.point.z+i.point.z+o.point.z)/4,c=240*(1-(m-this.zMin)*this.scale.z/this.verticalRatio),p=1,this.showShadow?(u=Math.min(1+S.x/M/2,1),a=this._hsv2rgb(c,p,u),h=a):(u=1,a=this._hsv2rgb(c,p,u),h=this.colorAxis)):(a="gray",h=this.colorAxis),d=.5,g.lineWidth=d,g.fillStyle=a,g.strokeStyle=h,g.beginPath(),g.moveTo(t.screen.x,t.screen.y),g.lineTo(e.screen.x,e.screen.y),g.lineTo(o.screen.x,o.screen.y),g.lineTo(i.screen.x,i.screen.y),g.closePath(),g.fill(),g.stroke()}}else for(n=0;np&&(p=0);var u,m,f;this.style===s.STYLE.DOTCOLOR?(u=240*(1-(d.point.value-this.valueMin)*this.scale.value),m=this._hsv2rgb(u,1,1),f=this._hsv2rgb(u,1,.8)):this.style===s.STYLE.DOTSIZE?(m=this.colorDot,f=this.colorDotBorder):(u=240*(1-(d.point.z-this.zMin)*this.scale.z/this.verticalRatio),m=this._hsv2rgb(u,1,1),f=this._hsv2rgb(u,1,.8)),i.lineWidth=1,i.strokeStyle=f,i.fillStyle=m,i.beginPath(),i.arc(d.screen.x,d.screen.y,p,0,2*Math.PI,!0),i.fill(),i.stroke()}}},s.prototype._redrawDataBar=function(){var t,e,i,o,n=this.frame.canvas,r=n.getContext("2d");if(!(void 0===this.dataPoints||this.dataPoints.length<=0)){for(t=0;t0&&(t=this.dataPoints[0],s.lineWidth=1,s.strokeStyle="blue",s.beginPath(),s.moveTo(t.screen.x,t.screen.y)),e=1;e0&&s.stroke()}},s.prototype._onMouseDown=function(t){if(t=t||window.event,this.leftButtonDown&&this._onMouseUp(t),this.leftButtonDown=t.which?1===t.which:1===t.button,this.leftButtonDown||this.touchDown){this.startMouseX=o(t),this.startMouseY=n(t),this.startStart=new Date(this.start),this.startEnd=new Date(this.end),this.startArmRotation=this.camera.getArmRotation(),this.frame.style.cursor="move";var e=this;this.onmousemove=function(t){e._onMouseMove(t)},this.onmouseup=function(t){e._onMouseUp(t)},d.addEventListener(document,"mousemove",e.onmousemove),d.addEventListener(document,"mouseup",e.onmouseup),d.preventDefault(t)}},s.prototype._onMouseMove=function(t){t=t||window.event;var e=parseFloat(o(t))-this.startMouseX,i=parseFloat(n(t))-this.startMouseY,s=this.startArmRotation.horizontal+e/200,r=this.startArmRotation.vertical+i/200,a=4,h=Math.sin(a/360*2*Math.PI);Math.abs(Math.sin(s))0?1:0>t?-1:0}var s=e[0],o=e[1],n=e[2],r=i((o.x-s.x)*(t.y-s.y)-(o.y-s.y)*(t.x-s.x)),a=i((n.x-o.x)*(t.y-o.y)-(n.y-o.y)*(t.x-o.x)),h=i((s.x-n.x)*(t.y-n.y)-(s.y-n.y)*(t.x-n.x));return!(0!=r&&0!=a&&r!=a||0!=a&&0!=h&&a!=h||0!=r&&0!=h&&r!=h)},s.prototype._dataPointFromXY=function(t,e){var i,o=100,n=null,r=null,a=null,h=new c(t,e);if(this.style===s.STYLE.BAR||this.style===s.STYLE.BARCOLOR||this.style===s.STYLE.BARSIZE)for(i=this.dataPoints.length-1;i>=0;i--){n=this.dataPoints[i];var d=n.surfaces;if(d)for(var l=d.length-1;l>=0;l--){var p=d[l],u=p.corners,m=[u[0].screen,u[1].screen,u[2].screen],f=[u[2].screen,u[3].screen,u[0].screen];if(this._insideTriangle(h,m)||this._insideTriangle(h,f))return n}}else for(i=0;ib)&&o>b&&(a=b,r=n)}}return r},s.prototype._showTooltip=function(t){var e,i,s;this.tooltip?(e=this.tooltip.dom.content,i=this.tooltip.dom.line,s=this.tooltip.dom.dot):(e=document.createElement("div"),e.style.position="absolute",e.style.padding="10px",e.style.border="1px solid #4d4d4d",e.style.color="#1a1a1a",e.style.background="rgba(255,255,255,0.7)",e.style.borderRadius="2px",e.style.boxShadow="5px 5px 10px rgba(128,128,128,0.5)",i=document.createElement("div"),i.style.position="absolute",i.style.height="40px",i.style.width="0",i.style.borderLeft="1px solid #4d4d4d",s=document.createElement("div"),s.style.position="absolute",s.style.height="0",s.style.width="0",s.style.border="5px solid #4d4d4d",s.style.borderRadius="5px",this.tooltip={dataPoint:null,dom:{content:e,line:i,dot:s}}),this._hideTooltip(),this.tooltip.dataPoint=t,e.innerHTML="function"==typeof this.showTooltip?this.showTooltip(t.point):"
x:"+t.point.x+"
y:"+t.point.y+"
z:"+t.point.z+"
",e.style.left="0",e.style.top="0",this.frame.appendChild(e),this.frame.appendChild(i),this.frame.appendChild(s);var o=e.offsetWidth,n=e.offsetHeight,r=i.offsetHeight,a=s.offsetWidth,h=s.offsetHeight,d=t.screen.x-o/2;d=Math.min(Math.max(d,10),this.frame.clientWidth-10-o),i.style.left=t.screen.x+"px",i.style.top=t.screen.y-r+"px",e.style.left=d+"px",e.style.top=t.screen.y-r-n+"px",s.style.left=t.screen.x-a/2+"px",s.style.top=t.screen.y-h/2+"px"},s.prototype._hideTooltip=function(){if(this.tooltip){this.tooltip.dataPoint=null;for(var t in this.tooltip.dom)if(this.tooltip.dom.hasOwnProperty(t)){var e=this.tooltip.dom[t];e&&e.parentNode&&e.parentNode.removeChild(e)}}},t.exports=s},function(t,e,i){function s(){this.armLocation=new o,this.armRotation={},this.armRotation.horizontal=0,this.armRotation.vertical=0,this.armLength=1.7,this.cameraLocation=new o,this.cameraRotation=new o(.5*Math.PI,0,0),this.calculateCameraOrientation()}var o=i(10);s.prototype.setArmLocation=function(t,e,i){this.armLocation.x=t,this.armLocation.y=e,this.armLocation.z=i,this.calculateCameraOrientation()},s.prototype.setArmRotation=function(t,e){void 0!==t&&(this.armRotation.horizontal=t),void 0!==e&&(this.armRotation.vertical=e,this.armRotation.vertical<0&&(this.armRotation.vertical=0),this.armRotation.vertical>.5*Math.PI&&(this.armRotation.vertical=.5*Math.PI)),(void 0!==t||void 0!==e)&&this.calculateCameraOrientation()},s.prototype.getArmRotation=function(){var t={};return t.horizontal=this.armRotation.horizontal,t.vertical=this.armRotation.vertical,t},s.prototype.setArmLength=function(t){void 0!==t&&(this.armLength=t,this.armLength<.71&&(this.armLength=.71),this.armLength>5&&(this.armLength=5),this.calculateCameraOrientation())},s.prototype.getArmLength=function(){return this.armLength},s.prototype.getCameraLocation=function(){return this.cameraLocation},s.prototype.getCameraRotation=function(){return this.cameraRotation},s.prototype.calculateCameraOrientation=function(){this.cameraLocation.x=this.armLocation.x-this.armLength*Math.sin(this.armRotation.horizontal)*Math.cos(this.armRotation.vertical),this.cameraLocation.y=this.armLocation.y-this.armLength*Math.cos(this.armRotation.horizontal)*Math.cos(this.armRotation.vertical),this.cameraLocation.z=this.armLocation.z+this.armLength*Math.sin(this.armRotation.vertical),this.cameraRotation.x=Math.PI/2-this.armRotation.vertical,this.cameraRotation.y=0,this.cameraRotation.z=-this.armRotation.horizontal},t.exports=s},function(t,e,i){function s(t,e,i){this.data=t,this.column=e,this.graph=i,this.index=void 0,this.value=void 0,this.values=i.getDistinctValues(t.get(),this.column),this.values.sort(function(t,e){return t>e?1:e>t?-1:0}),this.values.length>0&&this.selectValue(0),this.dataPoints=[],this.loaded=!1,this.onLoadCallback=void 0,i.animationPreload?(this.loaded=!1,this.loadInBackground()):this.loaded=!0}var o=i(4);s.prototype.isLoaded=function(){return this.loaded},s.prototype.getLoadedProgress=function(){for(var t=this.values.length,e=0;this.dataPoints[e];)e++;return Math.round(e/t*100)},s.prototype.getLabel=function(){return this.graph.filterLabel},s.prototype.getColumn=function(){return this.column},s.prototype.getSelectedValue=function(){return void 0===this.index?void 0:this.values[this.index]},s.prototype.getValues=function(){return this.values},s.prototype.getValue=function(t){if(t>=this.values.length)throw"Error: index out of range";return this.values[t]},s.prototype._getDataPoints=function(t){if(void 0===t&&(t=this.index),void 0===t)return[];var e;if(this.dataPoints[t])e=this.dataPoints[t];else{var i={};i.column=this.column,i.value=this.values[t];var s=new o(this.data,{filter:function(t){return t[i.column]==i.value}}).get();e=this.graph._getDataPoints(s),this.dataPoints[t]=e}return e},s.prototype.setOnLoadCallback=function(t){this.onLoadCallback=t},s.prototype.selectValue=function(t){if(t>=this.values.length)throw"Error: index out of range";this.index=t,this.value=this.values[t]},s.prototype.loadInBackground=function(t){void 0===t&&(t=0);var e=this.graph.frame;if(t0&&(t--,this.setIndex(t))},s.prototype.next=function(){var t=this.getIndex();t0?this.setIndex(0):this.index=void 0},s.prototype.setIndex=function(t){if(!(ts&&(s=0),s>this.values.length-1&&(s=this.values.length-1),s},s.prototype.indexToLeft=function(t){var e=parseFloat(this.frame.bar.style.width)-this.frame.slide.clientWidth-10,i=t/(this.values.length-1)*e,s=i+3;return s},s.prototype._onMouseMove=function(t){var e=t.clientX-this.startClientX,i=this.startSlideX+e,s=this.leftToIndex(i);this.setIndex(s),o.preventDefault()},s.prototype._onMouseUp=function(){this.frame.style.cursor="auto",o.removeEventListener(document,"mousemove",this.onmousemove),o.removeEventListener(document,"mouseup",this.onmouseup),o.preventDefault()},t.exports=s},function(t){function e(t,e,i,s){this._start=0,this._end=0,this._step=1,this.prettyStep=!0,this.precision=5,this._current=0,this.setRange(t,e,i,s)}e.prototype.setRange=function(t,e,i,s){this._start=t?t:0,this._end=e?e:0,this.setStep(i,s)},e.prototype.setStep=function(t,i){void 0===t||0>=t||(void 0!==i&&(this.prettyStep=i),this._step=this.prettyStep===!0?e.calculatePrettyStep(t):t)},e.calculatePrettyStep=function(t){var e=function(t){return Math.log(t)/Math.LN10},i=Math.pow(10,Math.round(e(t))),s=2*Math.pow(10,Math.round(e(t/2))),o=5*Math.pow(10,Math.round(e(t/5))),n=i;return Math.abs(s-t)<=Math.abs(n-t)&&(n=s),Math.abs(o-t)<=Math.abs(n-t)&&(n=o),0>=n&&(n=1),n},e.prototype.getCurrent=function(){return parseFloat(this._current.toPrecision(this.precision))},e.prototype.getStep=function(){return this._step},e.prototype.start=function(){this._current=this._start-this._start%this._step},e.prototype.next=function(){this._current+=this._step},e.prototype.end=function(){return this._current>this._end},t.exports=e},function(t,e,i){function s(t,e,i,r){if(!(this instanceof s))throw new SyntaxError("Constructor must be called with the new operator");if(!(Array.isArray(i)||i instanceof n)&&i instanceof Object){var h=r;r=i,i=h}var u=this;this.defaultOptions={start:null,end:null,autoResize:!0,orientation:"bottom",width:null,height:null,maxHeight:null,minHeight:null},this.options=o.deepExtend({},this.defaultOptions),this._create(t),this.components=[],this.body={dom:this.dom,domProps:this.props,emitter:{on:this.on.bind(this),off:this.off.bind(this),emit:this.emit.bind(this)},hiddenDates:[],util:{snap:null,toScreen:u._toScreen.bind(u),toGlobalScreen:u._toGlobalScreen.bind(u),toTime:u._toTime.bind(u),toGlobalTime:u._toGlobalTime.bind(u)}},this.range=new a(this.body),this.components.push(this.range),this.body.range=this.range,this.timeAxis=new d(this.body),this.components.push(this.timeAxis),this.body.util.snap=this.timeAxis.snap.bind(this.timeAxis),this.currentTime=new l(this.body),this.components.push(this.currentTime),this.customTime=new c(this.body),this.components.push(this.customTime),this.itemSet=new p(this.body),this.components.push(this.itemSet),this.itemsData=null,this.groupsData=null,r&&this.setOptions(r),i&&this.setGroups(i),e?this.setItems(e):this.redraw()}var o=(i(56),i(45),i(1)),n=i(3),r=i(4),a=i(17),h=i(46),d=i(30),l=i(21),c=i(22),p=i(27);s.prototype=new h,s.prototype.setItems=function(t){var e,i=null==this.itemsData;if(e=t?t instanceof n||t instanceof r?t:new n(t,{type:{start:"Date",end:"Date"}}):null,this.itemsData=e,this.itemSet&&this.itemSet.setItems(e),i)if(void 0!=this.options.start||void 0!=this.options.end){if(void 0==this.options.start||void 0==this.options.end)var s=this._getDataRange();var o=void 0!=this.options.start?this.options.start:s.start,a=void 0!=this.options.end?this.options.end:s.end;this.setWindow(o,a,{animate:!1})}else this.fit({animate:!1})},s.prototype.setGroups=function(t){var e;e=t?t instanceof n||t instanceof r?t:new n(t):null,this.groupsData=e,this.itemSet.setGroups(e)},s.prototype.setSelection=function(t,e){this.itemSet&&this.itemSet.setSelection(t),e&&e.focus&&this.focus(t,e)},s.prototype.getSelection=function(){return this.itemSet&&this.itemSet.getSelection()||[]},s.prototype.focus=function(t,e){if(this.itemsData&&void 0!=t){var i=Array.isArray(t)?t:[t],s=this.itemsData.getDataSet().get(i,{type:{start:"Date",end:"Date"}}),o=null,n=null;if(s.forEach(function(t){var e=t.start.valueOf(),i="end"in t?t.end.valueOf():t.start.valueOf();(null===o||o>e)&&(o=e),(null===n||i>n)&&(n=i)}),null!==o&&null!==n){var r=(o+n)/2,a=Math.max(this.range.end-this.range.start,1.1*(n-o)),h=e&&void 0!==e.animate?e.animate:!0;this.range.setRange(r-a/2,r+a/2,h)}}},s.prototype.getItemRange=function(){var t=this.itemsData.getDataSet(),e=null,i=null;if(t){var s=t.min("start");e=s?o.convert(s.start,"Date").valueOf():null;var n=t.max("start");n&&(i=o.convert(n.start,"Date").valueOf());var r=t.max("end");r&&(i=null==i?o.convert(r.end,"Date").valueOf():Math.max(i,o.convert(r.end,"Date").valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},t.exports=s},function(t,e,i){function s(t,e,i,s){if(!(Array.isArray(i)||i instanceof n)&&i instanceof Object){var r=s;s=i,i=r}var h=this;this.defaultOptions={start:null,end:null,autoResize:!0,orientation:"bottom",width:null,height:null,maxHeight:null,minHeight:null},this.options=o.deepExtend({},this.defaultOptions),this._create(t),this.components=[],this.body={dom:this.dom,domProps:this.props,emitter:{on:this.on.bind(this),off:this.off.bind(this),emit:this.emit.bind(this)},hiddenDates:[],util:{snap:null,toScreen:h._toScreen.bind(h),toGlobalScreen:h._toGlobalScreen.bind(h),toTime:h._toTime.bind(h),toGlobalTime:h._toGlobalTime.bind(h)}},this.range=new a(this.body),this.components.push(this.range),this.body.range=this.range,this.timeAxis=new d(this.body),this.components.push(this.timeAxis),this.body.util.snap=this.timeAxis.snap.bind(this.timeAxis),this.currentTime=new l(this.body),this.components.push(this.currentTime),this.customTime=new c(this.body),this.components.push(this.customTime),this.linegraph=new p(this.body),this.components.push(this.linegraph),this.itemsData=null,this.groupsData=null,s&&this.setOptions(s),i&&this.setGroups(i),e?this.setItems(e):this.redraw()}var o=(i(56),i(45),i(1)),n=i(3),r=i(4),a=i(17),h=i(46),d=i(30),l=i(21),c=i(22),p=i(29);s.prototype=new h,s.prototype.setItems=function(t){var e,i=null==this.itemsData;if(e=t?t instanceof n||t instanceof r?t:new n(t,{type:{start:"Date",end:"Date"}}):null,this.itemsData=e,this.linegraph&&this.linegraph.setItems(e),i)if(void 0!=this.options.start||void 0!=this.options.end){var s=void 0!=this.options.start?this.options.start:null,o=void 0!=this.options.end?this.options.end:null;this.setWindow(s,o,{animate:!1})}else this.fit({animate:!1})},s.prototype.setGroups=function(t){var e;e=t?t instanceof n||t instanceof r?t:new n(t):null,this.groupsData=e,this.linegraph.setGroups(e)},s.prototype.getLegend=function(t,e,i){return void 0===e&&(e=15),void 0===i&&(i=15),void 0!==this.linegraph.groups[t]?this.linegraph.groups[t].getLegend(e,i):"cannot find group:"+t},s.prototype.isGroupVisible=function(t){return void 0!==this.linegraph.groups[t]?this.linegraph.groups[t].visible&&(void 0===this.linegraph.options.groups.visibility[t]||1==this.linegraph.options.groups.visibility[t]):!1},s.prototype.getItemRange=function(){var t=null,e=null;for(var i in this.linegraph.groups)if(this.linegraph.groups.hasOwnProperty(i)&&1==this.linegraph.groups[i].visible)for(var s=0;sr?r:t,e=null==e?r:r>e?r:e}return{min:null!=t?new Date(t):null,max:null!=e?new Date(e):null}},t.exports=s},function(t,e,i){var s=i(44);e.convertHiddenOptions=function(t,e){if(t.hiddenDates=[],e&&1==Array.isArray(e)){for(var i=0;i=4*a){var p=0,u=n.clone();switch(i[h].repeat){case"daily":d.day()!=l.day()&&(p=1),d.dayOfYear(o.dayOfYear()),d.year(o.year()),d.subtract(7,"days"),l.dayOfYear(o.dayOfYear()),l.year(o.year()),l.subtract(7-p,"days"),u.add(1,"weeks");break;case"weekly":var m=l.diff(d,"days"),f=d.day();d.date(o.date()),d.month(o.month()),d.year(o.year()),l=d.clone(),d.day(f),l.day(f),l.add(m,"days"),d.subtract(1,"weeks"),l.subtract(1,"weeks"),u.add(1,"weeks");break;case"monthly":d.month()!=l.month()&&(p=1),d.month(o.month()),d.year(o.year()),d.subtract(1,"months"),l.month(o.month()),l.year(o.year()),l.subtract(1,"months"),l.add(p,"months"),u.add(1,"months");break;case"yearly":d.year()!=l.year()&&(p=1),d.year(o.year()),d.subtract(1,"years"),l.year(o.year()),l.subtract(1,"years"),l.add(p,"years"),u.add(1,"years");break;default:return void console.log("Wrong repeat format, allowed are: daily, weekly, monthly, yearly. Given:",i[h].repeat)}for(;u>d;)switch(t.hiddenDates.push({start:d.valueOf(),end:l.valueOf()}),i[h].repeat){case"daily":d.add(1,"days"),l.add(1,"days");break;case"weekly":d.add(1,"weeks"),l.add(1,"weeks");break;case"monthly":d.add(1,"months"),l.add(1,"months");break;case"yearly":d.add(1,"y"),l.add(1,"y");break;default:return void console.log("Wrong repeat format, allowed are: daily, weekly, monthly, yearly. Given:",i[h].repeat)}t.hiddenDates.push({start:d.valueOf(),end:l.valueOf()})}}e.removeDuplicates(t);var g=e.isHidden(t.range.start,t.hiddenDates),v=e.isHidden(t.range.end,t.hiddenDates),y=t.range.start,b=t.range.end;1==g.hidden&&(y=1==t.range.startToFront?g.startDate-1:g.endDate+1),1==v.hidden&&(b=1==t.range.endToFront?v.startDate-1:v.endDate+1),(1==g.hidden||1==v.hidden)&&t.range._applyRange(y,b)}},e.removeDuplicates=function(t){for(var e=t.hiddenDates,i=[],s=0;s=e[s].start&&e[o].end<=e[s].end?e[o].remove=!0:e[o].start>=e[s].start&&e[o].start<=e[s].end?(e[s].end=e[o].end,e[o].remove=!0):e[o].end>=e[s].start&&e[o].end<=e[s].end&&(e[s].start=e[o].start,e[o].remove=!0));for(var s=0;s=r&&a>o){i=!0;break}}if(1==i&&o=e&&i>r&&(s+=r-n)}return s},e.correctTimeForHidden=function(t,i,o){return o=s(o).toDate().valueOf(),o-=e.getHiddenDurationBefore(t,i,o)},e.getHiddenDurationBefore=function(t,e,i){var o=0;i=s(i).toDate().valueOf();for(var n=0;n=e.start&&a=a&&(o+=a-r)}return o},e.getAccumulatedHiddenDuration=function(t,e,i){for(var s=0,o=0,n=e.start,r=0;r=e.start&&h=i)break;s+=h-a}}return s},e.snapAwayFromHidden=function(t,i,s,o){var n=e.isHidden(i,t);return 1==n.hidden?0>s?1==o?n.startDate-(n.endDate-i)-1:n.startDate-1:1==o?n.endDate+(i-n.startDate)+1:n.endDate+1:i},e.isHidden=function(t,e){for(var i=0;i=s&&o>t)return{hidden:!0,startDate:s,endDate:o}}return{hidden:!1,startDate:s,endDate:o}}},function(t){function e(t,e,i,s,o,n){this.current=0,this.autoScale=!0,this.stepIndex=0,this.step=1,this.scale=1,this.marginStart,this.marginEnd,this.deadSpace=0,this.majorSteps=[1,2,5,10],this.minorSteps=[.25,.5,1,2],this.alignZeros=n,this.setRange(t,e,i,s,o)}e.prototype.setRange=function(t,e,i,s,o){this._start=void 0===o.min?t:o.min,this._end=void 0===o.max?e:o.max,this._start==this._end&&(this._start-=.75,this._end+=1),1==this.autoScale&&this.setMinimumStep(i,s),this.setFirst(o)},e.prototype.setMinimumStep=function(t,e){var i=this._end-this._start,s=1.2*i,o=t*(s/e),n=Math.round(Math.log(s)/Math.LN10),r=-1,a=Math.pow(10,n),h=0;0>n&&(h=n);for(var d=!1,l=h;Math.abs(l)<=Math.abs(n);l++){a=Math.pow(10,l);for(var c=0;c=o){d=!0,r=c;break}}if(1==d)break}this.stepIndex=r,this.scale=a,this.step=a*this.minorSteps[r]},e.prototype.setFirst=function(t){void 0===t&&(t={});var e=void 0===t.min?this._start-2*this.scale*this.minorSteps[this.stepIndex]:t.min,i=void 0===t.max?this._end+this.scale*this.minorSteps[this.stepIndex]:t.max;this.marginEnd=void 0===t.max?this.roundToMinor(i):t.max,this.marginStart=void 0===t.min?this.roundToMinor(e):t.min,1==this.alignZeros&&(this.marginEnd-this.marginStart)%this.step!=0&&(this.marginEnd+=this.marginEnd%this.step),this.deadSpace=this.roundToMinor(i)-i+this.roundToMinor(e)-e,this.marginRange=this.marginEnd-this.marginStart,this.current=this.marginEnd},e.prototype.roundToMinor=function(t){var e=t-t%(this.scale*this.minorSteps[this.stepIndex]);return t%(this.scale*this.minorSteps[this.stepIndex])>.5*this.scale*this.minorSteps[this.stepIndex]?e+this.scale*this.minorSteps[this.stepIndex]:e},e.prototype.hasNext=function(){return this.current>=this.marginStart},e.prototype.next=function(){var t=this.current;this.current-=this.step,this.current==t&&(this.current=this._end)},e.prototype.previous=function(){this.current+=this.step,this.marginEnd+=this.step,this.marginRange=this.marginEnd-this.marginStart},e.prototype.getCurrent=function(t){var e=Math.abs(this.current)0;s--){if("0"!=i[s]){if("."==i[s]||","==i[s]){i=i.slice(0,s);break}break}i=i.slice(0,s)}}else{var o="",n=i.indexOf("e");if(-1!=n&&(o=i.slice(n),i=i.slice(0,n)),n=Math.max(i.indexOf(","),i.indexOf(".")),-1===n?(0!==t&&(i+="."),n=i.length+t):0!==t&&(n+=t+1),n>i.length)for(var r=n-i.length;r>0;r--)i+="0";else i=i.slice(0,n);i+=o}return i},e.prototype.snap=function(){},e.prototype.isMajor=function(){return this.current%(this.scale*this.majorSteps[this.stepIndex])==0},t.exports=e},function(t,e,i){function s(t,e){var i=h().hours(0).minutes(0).seconds(0).milliseconds(0);this.start=i.clone().add(-3,"days").valueOf(),this.end=i.clone().add(4,"days").valueOf(),this.body=t,this.deltaDifference=0,this.scaleOffset=0,this.startToFront=!1,this.endToFront=!0,this.defaultOptions={start:null,end:null,direction:"horizontal",moveable:!0,zoomable:!0,min:null,max:null,zoomMin:10,zoomMax:31536e10},this.options=r.extend({},this.defaultOptions),this.props={touch:{}},this.animateTimer=null,this.body.emitter.on("dragstart",this._onDragStart.bind(this)),this.body.emitter.on("drag",this._onDrag.bind(this)),this.body.emitter.on("dragend",this._onDragEnd.bind(this)),this.body.emitter.on("hold",this._onHold.bind(this)),this.body.emitter.on("mousewheel",this._onMouseWheel.bind(this)),this.body.emitter.on("DOMMouseScroll",this._onMouseWheel.bind(this)),this.body.emitter.on("touch",this._onTouch.bind(this)),this.body.emitter.on("pinch",this._onPinch.bind(this)),this.setOptions(e)}function o(t){if("horizontal"!=t&&"vertical"!=t)throw new TypeError('Unknown direction "'+t+'". Choose "horizontal" or "vertical".')}function n(t,e){return{x:t.pageX-r.getAbsoluteLeft(e),y:t.pageY-r.getAbsoluteTop(e)}}var r=i(1),a=i(47),h=i(44),d=i(20),l=i(15);s.prototype=new d,s.prototype.setOptions=function(t){if(t){var e=["direction","min","max","zoomMin","zoomMax","moveable","zoomable","activate","hiddenDates"];r.selectiveExtend(e,this.options,t),("start"in t||"end"in t)&&this.setRange(t.start,t.end)}},s.prototype.setRange=function(t,e,i,s){s!==!0&&(s=!1);var o=void 0!=t?r.convert(t,"Date").valueOf():null,n=void 0!=e?r.convert(e,"Date").valueOf():null;if(this._cancelAnimation(),i){var a=this,h=this.start,d=this.end,c="number"==typeof i?i:500,p=(new Date).valueOf(),u=!1,m=function(){if(!a.props.touch.dragging){var t=(new Date).valueOf(),e=t-p,i=e>c,g=i||null===o?o:r.easeInOutQuad(e,h,o,c),v=i||null===n?n:r.easeInOutQuad(e,d,n,c);f=a._applyRange(g,v),l.updateHiddenDates(a.body,a.options.hiddenDates),u=u||f,f&&a.body.emitter.emit("rangechange",{start:new Date(a.start),end:new Date(a.end),byUser:s}),i?u&&a.body.emitter.emit("rangechanged",{start:new Date(a.start),end:new Date(a.end),byUser:s}):a.animateTimer=setTimeout(m,20)}};return m()}var f=this._applyRange(o,n);if(l.updateHiddenDates(this.body,this.options.hiddenDates),f){var g={start:new Date(this.start),end:new Date(this.end),byUser:s};this.body.emitter.emit("rangechange",g),this.body.emitter.emit("rangechanged",g)}},s.prototype._cancelAnimation=function(){this.animateTimer&&(clearTimeout(this.animateTimer),this.animateTimer=null)},s.prototype._applyRange=function(t,e){var i,s=null!=t?r.convert(t,"Date").valueOf():this.start,o=null!=e?r.convert(e,"Date").valueOf():this.end,n=null!=this.options.max?r.convert(this.options.max,"Date").valueOf():null,a=null!=this.options.min?r.convert(this.options.min,"Date").valueOf():null;if(isNaN(s)||null===s)throw new Error('Invalid start "'+t+'"');if(isNaN(o)||null===o)throw new Error('Invalid end "'+e+'"');if(s>o&&(o=s),null!==a&&a>s&&(i=a-s,s+=i,o+=i,null!=n&&o>n&&(o=n)),null!==n&&o>n&&(i=o-n,s-=i,o-=i,null!=a&&a>s&&(s=a)),null!==this.options.zoomMin){var h=parseFloat(this.options.zoomMin);0>h&&(h=0),h>o-s&&(this.end-this.start===h?(s=this.start,o=this.end):(i=h-(o-s),s-=i/2,o+=i/2))}if(null!==this.options.zoomMax){var d=parseFloat(this.options.zoomMax);0>d&&(d=0),o-s>d&&(this.end-this.start===d?(s=this.start,o=this.end):(i=o-s-d,s+=i/2,o-=i/2))}var l=this.start!=s||this.end!=o;return s>=this.start&&s<=this.end||o>=this.start&&o<=this.end||this.start>=s&&this.start<=o||this.end>=s&&this.end<=o||this.body.emitter.emit("checkRangedItems"),this.start=s,this.end=o,l},s.prototype.getRange=function(){return{start:this.start,end:this.end}},s.prototype.conversion=function(t,e){return s.conversion(this.start,this.end,t,e)},s.conversion=function(t,e,i,s){return void 0===s&&(s=0),0!=i&&e-t!=0?{offset:t,scale:i/(e-t-s)}:{offset:0,scale:1}},s.prototype._onDragStart=function(){this.deltaDifference=0,this.previousDelta=0,this.options.moveable&&this.props.touch.allowDragging&&(this.props.touch.start=this.start,this.props.touch.end=this.end,this.props.touch.dragging=!0,this.body.dom.root&&(this.body.dom.root.style.cursor="move"))},s.prototype._onDrag=function(t){if(this.options.moveable&&this.props.touch.allowDragging){var e=this.options.direction;o(e);var i="horizontal"==e?t.gesture.deltaX:t.gesture.deltaY;i-=this.deltaDifference;var s=this.props.touch.end-this.props.touch.start,n=l.getHiddenDurationBetween(this.body.hiddenDates,this.start,this.end);s-=n;var r="horizontal"==e?this.body.domProps.center.width:this.body.domProps.center.height,a=-i/r*s,h=this.props.touch.start+a,d=this.props.touch.end+a,c=l.snapAwayFromHidden(this.body.hiddenDates,h,this.previousDelta-i,!0),p=l.snapAwayFromHidden(this.body.hiddenDates,d,this.previousDelta-i,!0);if(c!=h||p!=d)return this.deltaDifference+=i,this.props.touch.start=c,this.props.touch.end=p,void this._onDrag(t);this.previousDelta=i,this._applyRange(h,d),this.body.emitter.emit("rangechange",{start:new Date(this.start),end:new Date(this.end),byUser:!0})}},s.prototype._onDragEnd=function(){this.options.moveable&&this.props.touch.allowDragging&&(this.props.touch.dragging=!1,this.body.dom.root&&(this.body.dom.root.style.cursor="auto"),this.body.emitter.emit("rangechanged",{start:new Date(this.start),end:new Date(this.end),byUser:!0}))},s.prototype._onMouseWheel=function(t){if(this.options.zoomable&&this.options.moveable){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){var i;i=0>e?1-e/5:1/(1+e/5);var s=a.fakeGesture(this,t),o=n(s.center,this.body.dom.center),r=this._pointerToDate(o);this.zoom(i,r,e)}t.preventDefault()}},s.prototype._onTouch=function(){this.props.touch.start=this.start,this.props.touch.end=this.end,this.props.touch.allowDragging=!0,this.props.touch.center=null,this.scaleOffset=0,this.deltaDifference=0},s.prototype._onHold=function(){this.props.touch.allowDragging=!1},s.prototype._onPinch=function(t){if(this.options.zoomable&&this.options.moveable&&(this.props.touch.allowDragging=!1,t.gesture.touches.length>1)){this.props.touch.center||(this.props.touch.center=n(t.gesture.center,this.body.dom.center));var e=1/(t.gesture.scale+this.scaleOffset),i=this._pointerToDate(this.props.touch.center),s=l.getHiddenDurationBetween(this.body.hiddenDates,this.start,this.end),o=l.getHiddenDurationBefore(this.body.hiddenDates,this,i),r=s-o,a=i-o+(this.props.touch.start-(i-o))*e,h=i+r+(this.props.touch.end-(i+r))*e;this.startToFront=1-e>0?!1:!0,this.endToFront=e-1>0?!1:!0;var d=l.snapAwayFromHidden(this.body.hiddenDates,a,1-e,!0),c=l.snapAwayFromHidden(this.body.hiddenDates,h,e-1,!0);(d!=a||c!=h)&&(this.props.touch.start=d,this.props.touch.end=c,this.scaleOffset=1-t.gesture.scale,a=d,h=c),this.setRange(a,h,!1,!0),this.startToFront=!1,this.endToFront=!0}},s.prototype._pointerToDate=function(t){var e,i=this.options.direction;if(o(i),"horizontal"==i)return this.body.util.toTime(t.x).valueOf();var s=this.body.domProps.center.height;return e=this.conversion(s),t.y/e.scale+e.offset},s.prototype.zoom=function(t,e,i){null==e&&(e=(this.start+this.end)/2);var s=l.getHiddenDurationBetween(this.body.hiddenDates,this.start,this.end),o=l.getHiddenDurationBefore(this.body.hiddenDates,this,e),n=s-o,r=e-o+(this.start-(e-o))*t,a=e+n+(this.end-(e+n))*t;this.startToFront=i>0?!1:!0,this.endToFront=-i>0?!1:!0;var h=l.snapAwayFromHidden(this.body.hiddenDates,r,i,!0),d=l.snapAwayFromHidden(this.body.hiddenDates,a,-i,!0);(h!=r||d!=a)&&(r=h,a=d),this.setRange(r,a,!1,!0),this.startToFront=!1,this.endToFront=!0},s.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,s=this.end+e*t;this.start=i,this.end=s},s.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,s=this.start-i,o=this.end-i;this.setRange(s,o)},t.exports=s},function(t,e){var i=.001;e.orderByStart=function(t){t.sort(function(t,e){return t.data.start-e.data.start})},e.orderByEnd=function(t){t.sort(function(t,e){var i="end"in t.data?t.data.end:t.data.start,s="end"in e.data?e.data.end:e.data.start;return i-s})},e.stack=function(t,i,s){var o,n;if(s)for(o=0,n=t.length;n>o;o++)t[o].top=null;for(o=0,n=t.length;n>o;o++){var r=t[o];if(r.stack&&null===r.top){r.top=i.axis;do{for(var a=null,h=0,d=t.length;d>h;h++){var l=t[h];if(null!==l.top&&l!==r&&l.stack&&e.collision(r,l,i.item)){a=l;break}}null!=a&&(r.top=a.top+a.height+i.item.vertical)}while(a)}}},e.nostack=function(t,e,i){var s,o,n;for(s=0,o=t.length;o>s;s++)if(void 0!==t[s].data.subgroup){n=e.axis;for(var r in i)i.hasOwnProperty(r)&&1==i[r].visible&&i[r].indexe.left&&t.top-s.vertical+ie.top}},function(t,e,i){function s(t,e,i,o){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale="day",this.step=1,this.setRange(t,e,i),this.switchedDay=!1,this.switchedMonth=!1,this.switchedYear=!1,this.hiddenDates=o,void 0===o&&(this.hiddenDates=[]),this.format=s.FORMAT}var o=i(44),n=i(15),r=i(1);s.FORMAT={minorLabels:{millisecond:"SSS",second:"s",minute:"HH:mm",hour:"HH:mm",weekday:"ddd D",day:"D",month:"MMM",year:"YYYY"},majorLabels:{millisecond:"HH:mm:ss",second:"D MMMM HH:mm",minute:"ddd D MMMM",hour:"ddd D MMMM",weekday:"MMMM YYYY",day:"MMMM YYYY",month:"YYYY",year:""}},s.prototype.setFormat=function(t){var e=r.deepExtend({},s.FORMAT);this.format=r.deepExtend(e,t)},s.prototype.setRange=function(t,e,i){if(!(t instanceof Date&&e instanceof Date))throw"No legal start or end date in method setRange";this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i)},s.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},s.prototype.roundToMinor=function(){switch(this.scale){case"year":this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case"month":this.current.setDate(1);case"day":case"weekday":this.current.setHours(0);case"hour":this.current.setMinutes(0);case"minute":this.current.setSeconds(0);case"second":this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case"millisecond":this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case"second":this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case"minute":this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case"hour":this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case"weekday":case"day":this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case"month":this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step);break;case"year":this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step)}},s.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},s.prototype.next=function(){var t=this.current.valueOf();if(this.current.getMonth()<6)switch(this.scale){case"millisecond":this.current=new Date(this.current.valueOf()+this.step);break;case"second":this.current=new Date(this.current.valueOf()+1e3*this.step);break;case"minute":this.current=new Date(this.current.valueOf()+1e3*this.step*60);break;case"hour":this.current=new Date(this.current.valueOf()+1e3*this.step*60*60);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case"weekday":case"day":this.current.setDate(this.current.getDate()+this.step); -break;case"month":this.current.setMonth(this.current.getMonth()+this.step);break;case"year":this.current.setFullYear(this.current.getFullYear()+this.step)}else switch(this.scale){case"millisecond":this.current=new Date(this.current.valueOf()+this.step);break;case"second":this.current.setSeconds(this.current.getSeconds()+this.step);break;case"minute":this.current.setMinutes(this.current.getMinutes()+this.step);break;case"hour":this.current.setHours(this.current.getHours()+this.step);break;case"weekday":case"day":this.current.setDate(this.current.getDate()+this.step);break;case"month":this.current.setMonth(this.current.getMonth()+this.step);break;case"year":this.current.setFullYear(this.current.getFullYear()+this.step)}if(1!=this.step)switch(this.scale){case"millisecond":this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},s.prototype.setAutoScale=function(t){this.autoScale=t},s.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,s=864e5,o=36e5,n=6e4,r=1e3,a=1;1e3*e>t&&(this.scale="year",this.step=1e3),500*e>t&&(this.scale="year",this.step=500),100*e>t&&(this.scale="year",this.step=100),50*e>t&&(this.scale="year",this.step=50),10*e>t&&(this.scale="year",this.step=10),5*e>t&&(this.scale="year",this.step=5),e>t&&(this.scale="year",this.step=1),3*i>t&&(this.scale="month",this.step=3),i>t&&(this.scale="month",this.step=1),5*s>t&&(this.scale="day",this.step=5),2*s>t&&(this.scale="day",this.step=2),s>t&&(this.scale="day",this.step=1),s/2>t&&(this.scale="weekday",this.step=1),4*o>t&&(this.scale="hour",this.step=4),o>t&&(this.scale="hour",this.step=1),15*n>t&&(this.scale="minute",this.step=15),10*n>t&&(this.scale="minute",this.step=10),5*n>t&&(this.scale="minute",this.step=5),n>t&&(this.scale="minute",this.step=1),15*r>t&&(this.scale="second",this.step=15),10*r>t&&(this.scale="second",this.step=10),5*r>t&&(this.scale="second",this.step=5),r>t&&(this.scale="second",this.step=1),200*a>t&&(this.scale="millisecond",this.step=200),100*a>t&&(this.scale="millisecond",this.step=100),50*a>t&&(this.scale="millisecond",this.step=50),10*a>t&&(this.scale="millisecond",this.step=10),5*a>t&&(this.scale="millisecond",this.step=5),a>t&&(this.scale="millisecond",this.step=1)}},s.prototype.snap=function(t){var e=new Date(t.valueOf());if("year"==this.scale){var i=e.getFullYear()+Math.round(e.getMonth()/12);e.setFullYear(Math.round(i/this.step)*this.step),e.setMonth(0),e.setDate(0),e.setHours(0),e.setMinutes(0),e.setSeconds(0),e.setMilliseconds(0)}else if("month"==this.scale)e.getDate()>15?(e.setDate(1),e.setMonth(e.getMonth()+1)):e.setDate(1),e.setHours(0),e.setMinutes(0),e.setSeconds(0),e.setMilliseconds(0);else if("day"==this.scale){switch(this.step){case 5:case 2:e.setHours(24*Math.round(e.getHours()/24));break;default:e.setHours(12*Math.round(e.getHours()/12))}e.setMinutes(0),e.setSeconds(0),e.setMilliseconds(0)}else if("weekday"==this.scale){switch(this.step){case 5:case 2:e.setHours(12*Math.round(e.getHours()/12));break;default:e.setHours(6*Math.round(e.getHours()/6))}e.setMinutes(0),e.setSeconds(0),e.setMilliseconds(0)}else if("hour"==this.scale){switch(this.step){case 4:e.setMinutes(60*Math.round(e.getMinutes()/60));break;default:e.setMinutes(30*Math.round(e.getMinutes()/30))}e.setSeconds(0),e.setMilliseconds(0)}else if("minute"==this.scale){switch(this.step){case 15:case 10:e.setMinutes(5*Math.round(e.getMinutes()/5)),e.setSeconds(0);break;case 5:e.setSeconds(60*Math.round(e.getSeconds()/60));break;default:e.setSeconds(30*Math.round(e.getSeconds()/30))}e.setMilliseconds(0)}else if("second"==this.scale)switch(this.step){case 15:case 10:e.setSeconds(5*Math.round(e.getSeconds()/5)),e.setMilliseconds(0);break;case 5:e.setMilliseconds(1e3*Math.round(e.getMilliseconds()/1e3));break;default:e.setMilliseconds(500*Math.round(e.getMilliseconds()/500))}else if("millisecond"==this.scale){var s=this.step>5?this.step/2:1;e.setMilliseconds(Math.round(e.getMilliseconds()/s)*s)}return e},s.prototype.isMajor=function(){if(1==this.switchedYear)switch(this.switchedYear=!1,this.scale){case"year":case"month":case"weekday":case"day":case"hour":case"minute":case"second":case"millisecond":return!0;default:return!1}else if(1==this.switchedMonth)switch(this.switchedMonth=!1,this.scale){case"weekday":case"day":case"hour":case"minute":case"second":case"millisecond":return!0;default:return!1}else if(1==this.switchedDay)switch(this.switchedDay=!1,this.scale){case"millisecond":case"second":case"minute":case"hour":return!0;default:return!1}switch(this.scale){case"millisecond":return 0==this.current.getMilliseconds();case"second":return 0==this.current.getSeconds();case"minute":return 0==this.current.getHours()&&0==this.current.getMinutes();case"hour":return 0==this.current.getHours();case"weekday":case"day":return 1==this.current.getDate();case"month":return 0==this.current.getMonth();case"year":return!1;default:return!1}},s.prototype.getLabelMinor=function(t){void 0==t&&(t=this.current);var e=this.format.minorLabels[this.scale];return e&&e.length>0?o(t).format(e):""},s.prototype.getLabelMajor=function(t){void 0==t&&(t=this.current);var e=this.format.majorLabels[this.scale];return e&&e.length>0?o(t).format(e):""},s.prototype.getClassName=function(){function t(t){return t/h%2==0?" even":" odd"}function e(t){return t.isSame(new Date,"day")?" today":t.isSame(o().add(1,"day"),"day")?" tomorrow":t.isSame(o().add(-1,"day"),"day")?" yesterday":""}function i(t){return t.isSame(new Date,"week")?" current-week":""}function s(t){return t.isSame(new Date,"month")?" current-month":""}function n(t){return t.isSame(new Date,"year")?" current-year":""}var r=o(this.current),a=r.locale?r.locale("en"):r.lang("en"),h=this.step;switch(this.scale){case"millisecond":return t(a.milliseconds()).trim();case"second":return t(a.seconds()).trim();case"minute":return t(a.minutes()).trim();case"hour":var d=a.hours();return 4==this.step&&(d=d+"-"+(d+4)),d+"h"+e(a)+t(a.hours());case"weekday":return a.format("dddd").toLowerCase()+e(a)+i(a)+t(a.date());case"day":var l=a.date(),c=a.format("MMMM").toLowerCase();return"day"+l+" "+c+s(a)+t(l-1);case"month":return a.format("MMMM").toLowerCase()+s(a)+t(a.month());case"year":var p=a.year();return"year"+p+n(a)+t(p);default:return""}},t.exports=s},function(t){function e(){this.options=null,this.props=null}e.prototype.setOptions=function(t){t&&util.extend(this.options,t)},e.prototype.redraw=function(){return!1},e.prototype.destroy=function(){},e.prototype._isResized=function(){var t=this.props._previousWidth!==this.props.width||this.props._previousHeight!==this.props.height;return this.props._previousWidth=this.props.width,this.props._previousHeight=this.props.height,t},t.exports=e},function(t,e,i){function s(t,e){this.body=t,this.defaultOptions={showCurrentTime:!0,locales:a,locale:"en"},this.options=o.extend({},this.defaultOptions),this.offset=0,this._create(),this.setOptions(e)}var o=i(1),n=i(20),r=i(44),a=i(48);s.prototype=new n,s.prototype._create=function(){var t=document.createElement("div");t.className="currenttime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",this.bar=t},s.prototype.destroy=function(){this.options.showCurrentTime=!1,this.redraw(),this.body=null},s.prototype.setOptions=function(t){t&&o.selectiveExtend(["showCurrentTime","locale","locales"],this.options,t)},s.prototype.redraw=function(){if(this.options.showCurrentTime){var t=this.body.dom.backgroundVertical;this.bar.parentNode!=t&&(this.bar.parentNode&&this.bar.parentNode.removeChild(this.bar),t.appendChild(this.bar),this.start());var e=new Date((new Date).valueOf()+this.offset),i=this.body.util.toScreen(e),s=this.options.locales[this.options.locale],o=s.current+" "+s.time+": "+r(e).format("dddd, MMMM Do YYYY, H:mm:ss");o=o.charAt(0).toUpperCase()+o.substring(1),this.bar.style.left=i+"px",this.bar.title=o}else this.bar.parentNode&&this.bar.parentNode.removeChild(this.bar),this.stop();return!1},s.prototype.start=function(){function t(){e.stop();var i=e.body.range.conversion(e.body.domProps.center.width).scale,s=1/i/10;30>s&&(s=30),s>1e3&&(s=1e3),e.redraw(),e.currentTimeTimer=setTimeout(t,s)}var e=this;t()},s.prototype.stop=function(){void 0!==this.currentTimeTimer&&(clearTimeout(this.currentTimeTimer),delete this.currentTimeTimer)},s.prototype.setCurrentTime=function(t){var e=o.convert(t,"Date").valueOf(),i=(new Date).valueOf();this.offset=e-i,this.redraw()},s.prototype.getCurrentTime=function(){return new Date((new Date).valueOf()+this.offset)},t.exports=s},function(t,e,i){function s(t,e){this.body=t,this.defaultOptions={showCustomTime:!1,locales:h,locale:"en"},this.options=n.extend({},this.defaultOptions),this.customTime=new Date,this.eventParams={},this._create(),this.setOptions(e)}var o=i(45),n=i(1),r=i(20),a=i(44),h=i(48);s.prototype=new r,s.prototype.setOptions=function(t){t&&n.selectiveExtend(["showCustomTime","locale","locales"],this.options,t)},s.prototype._create=function(){var t=document.createElement("div");t.className="customtime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",this.bar=t;var e=document.createElement("div");e.style.position="relative",e.style.top="0px",e.style.left="-10px",e.style.height="100%",e.style.width="20px",t.appendChild(e),this.hammer=o(t,{prevent_default:!0}),this.hammer.on("dragstart",this._onDragStart.bind(this)),this.hammer.on("drag",this._onDrag.bind(this)),this.hammer.on("dragend",this._onDragEnd.bind(this))},s.prototype.destroy=function(){this.options.showCustomTime=!1,this.redraw(),this.hammer.enable(!1),this.hammer=null,this.body=null},s.prototype.redraw=function(){if(this.options.showCustomTime){var t=this.body.dom.backgroundVertical;this.bar.parentNode!=t&&(this.bar.parentNode&&this.bar.parentNode.removeChild(this.bar),t.appendChild(this.bar));var e=this.body.util.toScreen(this.customTime),i=this.options.locales[this.options.locale],s=i.time+": "+a(this.customTime).format("dddd, MMMM Do YYYY, H:mm:ss");s=s.charAt(0).toUpperCase()+s.substring(1),this.bar.style.left=e+"px",this.bar.title=s}else this.bar.parentNode&&this.bar.parentNode.removeChild(this.bar);return!1},s.prototype.setCustomTime=function(t){this.customTime=n.convert(t,"Date"),this.redraw()},s.prototype.getCustomTime=function(){return new Date(this.customTime.valueOf())},s.prototype._onDragStart=function(t){this.eventParams.dragging=!0,this.eventParams.customTime=this.customTime,t.stopPropagation(),t.preventDefault()},s.prototype._onDrag=function(t){if(this.eventParams.dragging){var e=t.gesture.deltaX,i=this.body.util.toScreen(this.eventParams.customTime)+e,s=this.body.util.toTime(i);this.setCustomTime(s),this.body.emitter.emit("timechange",{time:new Date(this.customTime.valueOf())}),t.stopPropagation(),t.preventDefault()}},s.prototype._onDragEnd=function(t){this.eventParams.dragging&&(this.body.emitter.emit("timechanged",{time:new Date(this.customTime.valueOf())}),t.stopPropagation(),t.preventDefault())},t.exports=s},function(t,e,i){function s(t,e,i,s){this.id=o.randomUUID(),this.body=t,this.defaultOptions={orientation:"left",showMinorLabels:!0,showMajorLabels:!0,icons:!0,majorLinesOffset:7,minorLinesOffset:4,labelOffsetX:10,labelOffsetY:2,iconWidth:20,width:"40px",visible:!0,alignZeros:!0,customRange:{left:{min:void 0,max:void 0},right:{min:void 0,max:void 0}},title:{left:{text:void 0},right:{text:void 0}},format:{left:{decimals:void 0},right:{decimals:void 0}}},this.linegraphOptions=s,this.linegraphSVG=i,this.props={},this.DOMelements={lines:{},labels:{},title:{}},this.dom={},this.range={start:0,end:0},this.options=o.extend({},this.defaultOptions),this.conversionFactor=1,this.setOptions(e),this.width=Number((""+this.options.width).replace("px","")),this.minWidth=this.width,this.height=this.linegraphSVG.offsetHeight,this.hidden=!1,this.stepPixels=25,this.stepPixelsForced=25,this.zeroCrossing=-1,this.lineOffset=0,this.master=!0,this.svgElements={},this.iconsRemoved=!1,this.groups={},this.amountOfGroups=0,this._create();var n=this;this.body.emitter.on("verticalDrag",function(){n.dom.lineContainer.style.top=n.body.domProps.scrollTop+"px"})}var o=i(1),n=i(2),r=i(20),a=i(16);s.prototype=new r,s.prototype.addGroup=function(t,e){this.groups.hasOwnProperty(t)||(this.groups[t]=e),this.amountOfGroups+=1},s.prototype.updateGroup=function(t,e){this.groups[t]=e},s.prototype.removeGroup=function(t){this.groups.hasOwnProperty(t)&&(delete this.groups[t],this.amountOfGroups-=1)},s.prototype.setOptions=function(t){if(t){var e=!1;this.options.orientation!=t.orientation&&void 0!==t.orientation&&(e=!0);var i=["orientation","showMinorLabels","showMajorLabels","icons","majorLinesOffset","minorLinesOffset","labelOffsetX","labelOffsetY","iconWidth","width","visible","customRange","title","format","alignZeros"];o.selectiveExtend(i,this.options,t),this.minWidth=Number((""+this.options.width).replace("px","")),1==e&&this.dom.frame&&(this.hide(),this.show())}},s.prototype._create=function(){this.dom.frame=document.createElement("div"),this.dom.frame.style.width=this.options.width,this.dom.frame.style.height=this.height,this.dom.lineContainer=document.createElement("div"),this.dom.lineContainer.style.width="100%",this.dom.lineContainer.style.height=this.height,this.dom.lineContainer.style.position="relative",this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.style.position="absolute",this.svg.style.top="0px",this.svg.style.height="100%",this.svg.style.width="100%",this.svg.style.display="block",this.dom.frame.appendChild(this.svg)},s.prototype._redrawGroupIcons=function(){n.prepareElements(this.svgElements);var t,e=this.options.iconWidth,i=15,s=4,o=s+.5*i;t="left"==this.options.orientation?s:this.width-e-s;for(var r in this.groups)this.groups.hasOwnProperty(r)&&(1!=this.groups[r].visible||void 0!==this.linegraphOptions.visibility[r]&&1!=this.linegraphOptions.visibility[r]||(this.groups[r].drawIcon(t,o,this.svgElements,this.svg,e,i),o+=i+s));n.cleanupElements(this.svgElements),this.iconsRemoved=!1},s.prototype._cleanupIcons=function(){0==this.iconsRemoved&&(n.prepareElements(this.svgElements),n.cleanupElements(this.svgElements),this.iconsRemoved=!0)},s.prototype.show=function(){this.hidden=!1,this.dom.frame.parentNode||("left"==this.options.orientation?this.body.dom.left.appendChild(this.dom.frame):this.body.dom.right.appendChild(this.dom.frame)),this.dom.lineContainer.parentNode||this.body.dom.backgroundHorizontal.appendChild(this.dom.lineContainer)},s.prototype.hide=function(){this.hidden=!0,this.dom.frame.parentNode&&this.dom.frame.parentNode.removeChild(this.dom.frame),this.dom.lineContainer.parentNode&&this.dom.lineContainer.parentNode.removeChild(this.dom.lineContainer)},s.prototype.setRange=function(t,e){0==this.master&&1==this.options.alignZeros&&-1!=this.zeroCrossing&&t>0&&(t=0),this.range.start=t,this.range.end=e},s.prototype.redraw=function(){var t=!1,e=0;this.dom.lineContainer.style.top=this.body.domProps.scrollTop+"px";for(var i in this.groups)this.groups.hasOwnProperty(i)&&(1!=this.groups[i].visible||void 0!==this.linegraphOptions.visibility[i]&&1!=this.linegraphOptions.visibility[i]||e++);if(0==this.amountOfGroups||0==e)this.hide();else{this.show(),this.height=Number(this.linegraphSVG.style.height.replace("px","")),this.dom.lineContainer.style.height=this.height+"px",this.width=1==this.options.visible?Number((""+this.options.width).replace("px","")):0;var s=this.props,o=this.dom.frame;o.className="dataaxis",this._calculateCharSize();var n=this.options.orientation,r=this.options.showMinorLabels,a=this.options.showMajorLabels;s.minorLabelHeight=r?s.minorCharHeight:0,s.majorLabelHeight=a?s.majorCharHeight:0,s.minorLineWidth=this.body.dom.backgroundHorizontal.offsetWidth-this.lineOffset-this.width+2*this.options.minorLinesOffset,s.minorLineHeight=1,s.majorLineWidth=this.body.dom.backgroundHorizontal.offsetWidth-this.lineOffset-this.width+2*this.options.majorLinesOffset,s.majorLineHeight=1,"left"==n?(o.style.top="0",o.style.left="0",o.style.bottom="",o.style.width=this.width+"px",o.style.height=this.height+"px",this.props.width=this.body.domProps.left.width,this.props.height=this.body.domProps.left.height):(o.style.top="",o.style.bottom="0",o.style.left="0",o.style.width=this.width+"px",o.style.height=this.height+"px",this.props.width=this.body.domProps.right.width,this.props.height=this.body.domProps.right.height),t=this._redrawLabels(),t=this._isResized()||t,1==this.options.icons?this._redrawGroupIcons():this._cleanupIcons(),this._redrawTitle(n)}return t},s.prototype._redrawLabels=function(){var t=!1;n.prepareElements(this.DOMelements.lines),n.prepareElements(this.DOMelements.labels);var e=this.options.orientation,i=this.master?this.props.majorCharHeight||10:this.stepPixelsForced,s=new a(this.range.start,this.range.end,i,this.dom.frame.offsetHeight,this.options.customRange[this.options.orientation],0==this.master&&this.options.alignZeros);this.step=s;var o=(this.dom.frame.offsetHeight-s.deadSpace*(this.dom.frame.offsetHeight/s.marginRange))/((s.marginRange-s.deadSpace)/s.step);this.stepPixels=o;var r=this.height/o,h=0;if(0==this.master){o=this.stepPixelsForced,h=Math.round(this.dom.frame.offsetHeight/o-r);for(var d=0;.5*h>d;d++)s.previous();if(r=this.height/o,-1!=this.zeroCrossing&&1==this.options.alignZeros){var l=s.marginEnd/s.step-this.zeroCrossing;if(l>0)for(var d=0;l>d;d++)s.next();else if(0>l)for(var d=0;-l>d;d++)s.previous()}}else r+=.25;this.valueAtZero=s.marginEnd;var c,p=0,u=1;void 0!==this.options.format[e]&&(c=this.options.format[e].decimals),this.maxLabelSize=0;for(var m=0;u=0&&this._redrawLabel(m-2,s.getCurrent(c),e,"yAxis major",this.props.majorCharHeight),this._redrawLine(m,e,"grid horizontal major",this.options.majorLinesOffset,this.props.majorLineWidth)):this._redrawLine(m,e,"grid horizontal minor",this.options.minorLinesOffset,this.props.minorLineWidth),1==this.master&&0==s.current&&(this.zeroCrossing=u),u++}this.conversionFactor=0==this.master?m/(this.valueAtZero-s.current):this.dom.frame.offsetHeight/s.marginRange;var g=0;void 0!==this.options.title[e]&&void 0!==this.options.title[e].text&&(g=this.props.titleCharHeight);var v=1==this.options.icons?Math.max(this.options.iconWidth,g)+this.options.labelOffsetX+15:g+this.options.labelOffsetX+15;return this.maxLabelSize>this.width-v&&1==this.options.visible?(this.width=this.maxLabelSize+v,this.options.width=this.width+"px",n.cleanupElements(this.DOMelements.lines),n.cleanupElements(this.DOMelements.labels),this.redraw(),t=!0):this.maxLabelSizethis.minWidth?(this.width=Math.max(this.minWidth,this.maxLabelSize+v),this.options.width=this.width+"px",n.cleanupElements(this.DOMelements.lines),n.cleanupElements(this.DOMelements.labels),this.redraw(),t=!0):(n.cleanupElements(this.DOMelements.lines),n.cleanupElements(this.DOMelements.labels),t=!1),t},s.prototype.convertValue=function(t){var e=this.valueAtZero-t,i=e*this.conversionFactor;return i},s.prototype._redrawLabel=function(t,e,i,s,o){var r=n.getDOMElement("div",this.DOMelements.labels,this.dom.frame);r.className=s,r.innerHTML=e,"left"==i?(r.style.left="-"+this.options.labelOffsetX+"px",r.style.textAlign="right"):(r.style.right="-"+this.options.labelOffsetX+"px",r.style.textAlign="left"),r.style.top=t-.5*o+this.options.labelOffsetY+"px",e+="";var a=Math.max(this.props.majorCharWidth,this.props.minorCharWidth);this.maxLabelSized;d++){var c=this.visibleItems[d];c.repositionY(e)}return s},s.prototype._calculateHeight=function(t){var e,i=this.visibleItems;this.resetSubgroups();var s=this;if(i.length){var n=i[0].top,r=i[0].top+i[0].height;if(o.forEach(i,function(t){n=Math.min(n,t.top),r=Math.max(r,t.top+t.height),void 0!==t.data.subgroup&&(s.subgroups[t.data.subgroup].height=Math.max(s.subgroups[t.data.subgroup].height,t.height),s.subgroups[t.data.subgroup].visible=!0)}),n>t.axis){var a=n-t.axis;r-=a,o.forEach(i,function(t){t.top-=a})}e=r+t.item.vertical/2}else e=t.axis+t.item.vertical;return e=Math.max(e,this.props.label.height)},s.prototype.show=function(){this.dom.label.parentNode||this.itemSet.dom.labelSet.appendChild(this.dom.label),this.dom.foreground.parentNode||this.itemSet.dom.foreground.appendChild(this.dom.foreground),this.dom.background.parentNode||this.itemSet.dom.background.appendChild(this.dom.background),this.dom.axis.parentNode||this.itemSet.dom.axis.appendChild(this.dom.axis)},s.prototype.hide=function(){var t=this.dom.label;t.parentNode&&t.parentNode.removeChild(t);var e=this.dom.foreground;e.parentNode&&e.parentNode.removeChild(e);var i=this.dom.background;i.parentNode&&i.parentNode.removeChild(i);var s=this.dom.axis;s.parentNode&&s.parentNode.removeChild(s)},s.prototype.add=function(t){if(this.items[t.id]=t,t.setParent(this),void 0!==t.data.subgroup&&(void 0===this.subgroups[t.data.subgroup]&&(this.subgroups[t.data.subgroup]={height:0,visible:!1,index:this.subgroupIndex,items:[]},this.subgroupIndex++),this.subgroups[t.data.subgroup].items.push(t)),this.orderSubgroups(),-1==this.visibleItems.indexOf(t)){var e=this.itemSet.body.range;this._checkIfVisible(t,this.visibleItems,e)}},s.prototype.orderSubgroups=function(){if(void 0!==this.subgroupOrderer){var t=[];if("string"==typeof this.subgroupOrderer){for(var e in this.subgroups)t.push({subgroup:e,sortField:this.subgroups[e].items[0].data[this.subgroupOrderer]});t.sort(function(t,e){return t.sortField-e.sortField})}else if("function"==typeof this.subgroupOrderer){for(var e in this.subgroups)t.push(this.subgroups[e].items[0].data);t.sort(this.subgroupOrderer)}if(t.length>0)for(var i=0;it?-1:l>=t?0:1};if(e.length>0)for(n=0;nl}),1==this.checkRangedItems)for(this.checkRangedItems=!1,n=0;nl})}for(n=0;n=0&&(n=e[r],!o(n));r--)void 0===s[n.id]&&(s[n.id]=!0,i.push(n)); -for(r=t+1;rs;s++){var n=this.visibleItems[s];n.repositionY(e)}return i},s.prototype.show=function(){this.dom.background.parentNode||this.itemSet.dom.background.appendChild(this.dom.background)},t.exports=s},function(t,e,i){function s(t,e){this.body=t,this.defaultOptions={type:null,orientation:"bottom",align:"auto",stack:!0,groupOrder:null,selectable:!0,editable:{updateTime:!1,updateGroup:!1,add:!1,remove:!1},onAdd:function(t,e){e(t)},onUpdate:function(t,e){e(t)},onMove:function(t,e){e(t)},onRemove:function(t,e){e(t)},onMoving:function(t,e){e(t)},margin:{item:{horizontal:10,vertical:10},axis:20},padding:5},this.options=n.extend({},this.defaultOptions),this.itemOptions={type:{start:"Date",end:"Date"}},this.conversion={toScreen:t.util.toScreen,toTime:t.util.toTime},this.dom={},this.props={},this.hammer=null;var i=this;this.itemsData=null,this.groupsData=null,this.itemListeners={add:function(t,e){i._onAdd(e.items)},update:function(t,e){i._onUpdate(e.items)},remove:function(t,e){i._onRemove(e.items)}},this.groupListeners={add:function(t,e){i._onAddGroups(e.items)},update:function(t,e){i._onUpdateGroups(e.items)},remove:function(t,e){i._onRemoveGroups(e.items)}},this.items={},this.groups={},this.groupIds=[],this.selection=[],this.stackDirty=!0,this.touchParams={},this._create(),this.setOptions(e)}var o=i(45),n=i(1),r=i(3),a=i(4),h=i(20),d=i(25),l=i(26),c=i(33),p=i(34),u=i(35),m=i(32),f="__ungrouped__",g="__background__";s.prototype=new h,s.types={background:m,box:c,range:u,point:p},s.prototype._create=function(){var t=document.createElement("div");t.className="itemset",t["timeline-itemset"]=this,this.dom.frame=t;var e=document.createElement("div");e.className="background",t.appendChild(e),this.dom.background=e;var i=document.createElement("div");i.className="foreground",t.appendChild(i),this.dom.foreground=i;var s=document.createElement("div");s.className="axis",this.dom.axis=s;var n=document.createElement("div");n.className="labelset",this.dom.labelSet=n,this._updateUngrouped();var r=new l(g,null,this);r.show(),this.groups[g]=r,this.hammer=o(this.body.dom.centerContainer,{preventDefault:!0}),this.hammer.on("touch",this._onTouch.bind(this)),this.hammer.on("dragstart",this._onDragStart.bind(this)),this.hammer.on("drag",this._onDrag.bind(this)),this.hammer.on("dragend",this._onDragEnd.bind(this)),this.hammer.on("tap",this._onSelectItem.bind(this)),this.hammer.on("hold",this._onMultiSelectItem.bind(this)),this.hammer.on("doubletap",this._onAddItem.bind(this)),this.show()},s.prototype.setOptions=function(t){if(t){var e=["type","align","orientation","padding","stack","selectable","groupOrder","dataAttributes","template","hide"];n.selectiveExtend(e,this.options,t),"margin"in t&&("number"==typeof t.margin?(this.options.margin.axis=t.margin,this.options.margin.item.horizontal=t.margin,this.options.margin.item.vertical=t.margin):"object"==typeof t.margin&&(n.selectiveExtend(["axis"],this.options.margin,t.margin),"item"in t.margin&&("number"==typeof t.margin.item?(this.options.margin.item.horizontal=t.margin.item,this.options.margin.item.vertical=t.margin.item):"object"==typeof t.margin.item&&n.selectiveExtend(["horizontal","vertical"],this.options.margin.item,t.margin.item)))),"editable"in t&&("boolean"==typeof t.editable?(this.options.editable.updateTime=t.editable,this.options.editable.updateGroup=t.editable,this.options.editable.add=t.editable,this.options.editable.remove=t.editable):"object"==typeof t.editable&&n.selectiveExtend(["updateTime","updateGroup","add","remove"],this.options.editable,t.editable));var i=function(e){var i=t[e];if(i){if(!(i instanceof Function))throw new Error("option "+e+" must be a function "+e+"(item, callback)");this.options[e]=i}}.bind(this);["onAdd","onUpdate","onRemove","onMove","onMoving"].forEach(i),this.markDirty()}},s.prototype.markDirty=function(){this.groupIds=[],this.stackDirty=!0},s.prototype.destroy=function(){this.hide(),this.setItems(null),this.setGroups(null),this.hammer=null,this.body=null,this.conversion=null},s.prototype.hide=function(){this.dom.frame.parentNode&&this.dom.frame.parentNode.removeChild(this.dom.frame),this.dom.axis.parentNode&&this.dom.axis.parentNode.removeChild(this.dom.axis),this.dom.labelSet.parentNode&&this.dom.labelSet.parentNode.removeChild(this.dom.labelSet)},s.prototype.show=function(){this.dom.frame.parentNode||this.body.dom.center.appendChild(this.dom.frame),this.dom.axis.parentNode||this.body.dom.backgroundVertical.appendChild(this.dom.axis),this.dom.labelSet.parentNode||this.body.dom.left.appendChild(this.dom.labelSet)},s.prototype.setSelection=function(t){var e,i,s,o;for(void 0==t&&(t=[]),Array.isArray(t)||(t=[t]),e=0,i=this.selection.length;i>e;e++)s=this.selection[e],o=this.items[s],o&&o.unselect();for(this.selection=[],e=0,i=t.length;i>e;e++)s=t[e],o=this.items[s],o&&(this.selection.push(s),o.select())},s.prototype.getSelection=function(){return this.selection.concat([])},s.prototype.getVisibleItems=function(){var t=this.body.range.getRange(),e=this.body.util.toScreen(t.start),i=this.body.util.toScreen(t.end),s=[];for(var o in this.groups)if(this.groups.hasOwnProperty(o))for(var n=this.groups[o],r=n.visibleItems,a=0;ae&&s.push(h.id)}return s},s.prototype._deselect=function(t){for(var e=this.selection,i=0,s=e.length;s>i;i++)if(e[i]==t){e.splice(i,1);break}},s.prototype.redraw=function(){var t=this.options.margin,e=this.body.range,i=n.option.asSize,s=this.options,o=s.orientation,r=!1,a=this.dom.frame,h=s.editable.updateTime||s.editable.updateGroup;this.props.top=this.body.domProps.top.height+this.body.domProps.border.top,this.props.left=this.body.domProps.left.width+this.body.domProps.border.left,a.className="itemset"+(h?" editable":""),r=this._orderGroups()||r;var d=e.end-e.start,l=d!=this.lastVisibleInterval||this.props.width!=this.props.lastWidth;l&&(this.stackDirty=!0),this.lastVisibleInterval=d,this.props.lastWidth=this.props.width;var c=this.stackDirty,p=this._firstGroup(),u={item:t.item,axis:t.axis},m={item:t.item,axis:t.item.vertical/2},f=0,v=t.axis+t.item.vertical;return this.groups[g].redraw(e,m,c),n.forEach(this.groups,function(t){var i=t==p?u:m,s=t.redraw(e,i,c);r=s||r,f+=t.height}),f=Math.max(f,v),this.stackDirty=!1,a.style.height=i(f),this.props.width=a.offsetWidth,this.props.height=f,this.dom.axis.style.top=i("top"==o?this.body.domProps.top.height+this.body.domProps.border.top:this.body.domProps.top.height+this.body.domProps.centerContainer.height),this.dom.axis.style.left="0",r=this._isResized()||r},s.prototype._firstGroup=function(){var t="top"==this.options.orientation?0:this.groupIds.length-1,e=this.groupIds[t],i=this.groups[e]||this.groups[f];return i||null},s.prototype._updateUngrouped=function(){{var t,e,i=this.groups[f];this.groups[g]}if(this.groupsData){if(i){i.hide(),delete this.groups[f];for(e in this.items)if(this.items.hasOwnProperty(e)){t=this.items[e],t.parent&&t.parent.remove(t);var s=this._getGroupId(t.data),o=this.groups[s];o&&o.add(t)||t.hide()}}}else if(!i){var n=null,r=null;i=new d(n,r,this),this.groups[f]=i;for(e in this.items)this.items.hasOwnProperty(e)&&(t=this.items[e],i.add(t));i.show()}},s.prototype.getLabelSet=function(){return this.dom.labelSet},s.prototype.setItems=function(t){var e,i=this,s=this.itemsData;if(t){if(!(t instanceof r||t instanceof a))throw new TypeError("Data must be an instance of DataSet or DataView");this.itemsData=t}else this.itemsData=null;if(s&&(n.forEach(this.itemListeners,function(t,e){s.off(e,t)}),e=s.getIds(),this._onRemove(e)),this.itemsData){var o=this.id;n.forEach(this.itemListeners,function(t,e){i.itemsData.on(e,t,o)}),e=this.itemsData.getIds(),this._onAdd(e),this._updateUngrouped()}},s.prototype.getItems=function(){return this.itemsData},s.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(n.forEach(this.groupListeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this.groupsData=null,this._onRemoveGroups(e)),t){if(!(t instanceof r||t instanceof a))throw new TypeError("Data must be an instance of DataSet or DataView");this.groupsData=t}else this.groupsData=null;if(this.groupsData){var s=this.id;n.forEach(this.groupListeners,function(t,e){i.groupsData.on(e,t,s)}),e=this.groupsData.getIds(),this._onAddGroups(e)}this._updateUngrouped(),this._order(),this.body.emitter.emit("change",{queue:!0})},s.prototype.getGroups=function(){return this.groupsData},s.prototype.removeItem=function(t){var e=this.itemsData.get(t),i=this.itemsData.getDataSet();e&&this.options.onRemove(e,function(e){e&&i.remove(t)})},s.prototype._getType=function(t){return t.type||this.options.type||(t.end?"range":"box")},s.prototype._getGroupId=function(t){var e=this._getType(t);return"background"==e&&void 0==t.group?g:this.groupsData?t.group:f},s.prototype._onUpdate=function(t){var e=this;t.forEach(function(t){var i=e.itemsData.get(t,e.itemOptions),o=e.items[t],n=e._getType(i),r=s.types[n];if(o&&(r&&o instanceof r?e._updateItem(o,i):(e._removeItem(o),o=null)),!o){if(!r)throw new TypeError("rangeoverflow"==n?'Item type "rangeoverflow" is deprecated. Use css styling instead: .vis.timeline .item.range .content {overflow: visible;}':'Unknown item type "'+n+'"');o=new r(i,e.conversion,e.options),o.id=t,e._addItem(o)}}),this._order(),this.stackDirty=!0,this.body.emitter.emit("change",{queue:!0})},s.prototype._onAdd=s.prototype._onUpdate,s.prototype._onRemove=function(t){var e=0,i=this;t.forEach(function(t){var s=i.items[t];s&&(e++,i._removeItem(s))}),e&&(this._order(),this.stackDirty=!0,this.body.emitter.emit("change",{queue:!0}))},s.prototype._order=function(){n.forEach(this.groups,function(t){t.order()})},s.prototype._onUpdateGroups=function(t){this._onAddGroups(t)},s.prototype._onAddGroups=function(t){var e=this;t.forEach(function(t){var i=e.groupsData.get(t),s=e.groups[t];if(s)s.setData(i);else{if(t==f||t==g)throw new Error("Illegal group id. "+t+" is a reserved id.");var o=Object.create(e.options);n.extend(o,{height:null}),s=new d(t,i,e),e.groups[t]=s;for(var r in e.items)if(e.items.hasOwnProperty(r)){var a=e.items[r];a.data.group==t&&s.add(a)}s.order(),s.show()}}),this.body.emitter.emit("change",{queue:!0})},s.prototype._onRemoveGroups=function(t){var e=this.groups;t.forEach(function(t){var i=e[t];i&&(i.hide(),delete e[t])}),this.markDirty(),this.body.emitter.emit("change",{queue:!0})},s.prototype._orderGroups=function(){if(this.groupsData){var t=this.groupsData.getIds({order:this.options.groupOrder}),e=!n.equalArray(t,this.groupIds);if(e){var i=this.groups;t.forEach(function(t){i[t].hide()}),t.forEach(function(t){i[t].show()}),this.groupIds=t}return e}return!1},s.prototype._addItem=function(t){this.items[t.id]=t;var e=this._getGroupId(t.data),i=this.groups[e];i&&i.add(t)},s.prototype._updateItem=function(t,e){var i=t.data.group;if(t.setData(e),i!=t.data.group){var s=this.groups[i];s&&s.remove(t);var o=this._getGroupId(t.data),n=this.groups[o];n&&n.add(t)}},s.prototype._removeItem=function(t){t.hide(),delete this.items[t.id];var e=this.selection.indexOf(t.id);-1!=e&&this.selection.splice(e,1),t.parent&&t.parent.remove(t)},s.prototype._constructByEndArray=function(t){for(var e=[],i=0;i0||o.length>0)&&this.body.emitter.emit("select",{items:a})}},s.prototype._onAddItem=function(t){if(this.options.selectable&&this.options.editable.add){var e=this,i=this.body.util.snap||null,o=s.itemFromTarget(t);if(o){var r=e.itemsData.get(o.id);this.options.onUpdate(r,function(t){t&&e.itemsData.getDataSet().update(t)})}else{var a=n.getAbsoluteLeft(this.dom.frame),h=t.gesture.center.pageX-a,d=this.body.util.toTime(h),l={start:i?i(d):d,content:"new item"};if("range"===this.options.type){var c=this.body.util.toTime(h+this.props.width/5);l.end=i?i(c):c}l[this.itemsData._fieldId]=n.randomUUID();var p=s.groupFromTarget(t);p&&(l.group=p.groupId),this.options.onAdd(l,function(t){t&&e.itemsData.getDataSet().add(t)})}}},s.prototype._onMultiSelectItem=function(t){if(this.options.selectable){var e,i=s.itemFromTarget(t);if(i){e=this.getSelection();var o=t.gesture.touches[0]&&t.gesture.touches[0].shiftKey||!1;if(o){e.push(i.id);var n=s._getItemRange(this.itemsData.get(e,this.itemOptions));e=[];for(var r in this.items)if(this.items.hasOwnProperty(r)){var a=this.items[r],h=a.data.start,d=void 0!==a.data.end?a.data.end:h;h>=n.min&&d<=n.max&&e.push(a.id)}}else{var l=e.indexOf(i.id);-1==l?e.push(i.id):e.splice(l,1)}this.setSelection(e),this.body.emitter.emit("select",{items:this.getSelection()})}}},s._getItemRange=function(t){var e=null,i=null;return t.forEach(function(t){(null==i||t.starte)&&(e=t.end):(null==e||t.start>e)&&(e=t.start)}),{min:i,max:e}},s.itemFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-item"))return e["timeline-item"];e=e.parentNode}return null},s.groupFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-group"))return e["timeline-group"];e=e.parentNode}return null},s.itemSetFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-itemset"))return e["timeline-itemset"];e=e.parentNode}return null},t.exports=s},function(t,e,i){function s(t,e,i,s){this.body=t,this.defaultOptions={enabled:!0,icons:!0,iconSize:20,iconSpacing:6,left:{visible:!0,position:"top-left"},right:{visible:!0,position:"top-left"}},this.side=i,this.options=o.extend({},this.defaultOptions),this.linegraphOptions=s,this.svgElements={},this.dom={},this.groups={},this.amountOfGroups=0,this._create(),this.setOptions(e)}var o=i(1),n=i(2),r=i(20);s.prototype=new r,s.prototype.clear=function(){this.groups={},this.amountOfGroups=0},s.prototype.addGroup=function(t,e){this.groups.hasOwnProperty(t)||(this.groups[t]=e),this.amountOfGroups+=1},s.prototype.updateGroup=function(t,e){this.groups[t]=e},s.prototype.removeGroup=function(t){this.groups.hasOwnProperty(t)&&(delete this.groups[t],this.amountOfGroups-=1)},s.prototype._create=function(){this.dom.frame=document.createElement("div"),this.dom.frame.className="legend",this.dom.frame.style.position="absolute",this.dom.frame.style.top="10px",this.dom.frame.style.display="block",this.dom.textArea=document.createElement("div"),this.dom.textArea.className="legendText",this.dom.textArea.style.position="relative",this.dom.textArea.style.top="0px",this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.style.position="absolute",this.svg.style.top="0px",this.svg.style.width=this.options.iconSize+5+"px",this.svg.style.height="100%",this.dom.frame.appendChild(this.svg),this.dom.frame.appendChild(this.dom.textArea)},s.prototype.hide=function(){this.dom.frame.parentNode&&this.dom.frame.parentNode.removeChild(this.dom.frame)},s.prototype.show=function(){this.dom.frame.parentNode||this.body.dom.center.appendChild(this.dom.frame)},s.prototype.setOptions=function(t){var e=["enabled","orientation","icons","left","right"];o.selectiveDeepExtend(e,this.options,t)},s.prototype.redraw=function(){var t=0;for(var e in this.groups)this.groups.hasOwnProperty(e)&&(1!=this.groups[e].visible||void 0!==this.linegraphOptions.visibility[e]&&1!=this.linegraphOptions.visibility[e]||t++);if(0==this.options[this.side].visible||0==this.amountOfGroups||0==this.options.enabled||0==t)this.hide();else{if(this.show(),"top-left"==this.options[this.side].position||"bottom-left"==this.options[this.side].position?(this.dom.frame.style.left="4px",this.dom.frame.style.textAlign="left",this.dom.textArea.style.textAlign="left",this.dom.textArea.style.left=this.options.iconSize+15+"px",this.dom.textArea.style.right="",this.svg.style.left="0px",this.svg.style.right=""):(this.dom.frame.style.right="4px",this.dom.frame.style.textAlign="right",this.dom.textArea.style.textAlign="right",this.dom.textArea.style.right=this.options.iconSize+15+"px",this.dom.textArea.style.left="",this.svg.style.right="0px",this.svg.style.left=""),"top-left"==this.options[this.side].position||"top-right"==this.options[this.side].position)this.dom.frame.style.top=4-Number(this.body.dom.center.style.top.replace("px",""))+"px",this.dom.frame.style.bottom="";else{var i=this.body.domProps.center.height-this.body.domProps.centerContainer.height;this.dom.frame.style.bottom=4+i+Number(this.body.dom.center.style.top.replace("px",""))+"px",this.dom.frame.style.top=""}0==this.options.icons?(this.dom.frame.style.width=this.dom.textArea.offsetWidth+10+"px",this.dom.textArea.style.right="",this.dom.textArea.style.left="",this.svg.style.width="0px"):(this.dom.frame.style.width=this.options.iconSize+15+this.dom.textArea.offsetWidth+10+"px",this.drawLegendIcons());var s="";for(var e in this.groups)this.groups.hasOwnProperty(e)&&(1!=this.groups[e].visible||void 0!==this.linegraphOptions.visibility[e]&&1!=this.linegraphOptions.visibility[e]||(s+=this.groups[e].content+"
"));this.dom.textArea.innerHTML=s,this.dom.textArea.style.lineHeight=.75*this.options.iconSize+this.options.iconSpacing+"px"}},s.prototype.drawLegendIcons=function(){if(this.dom.frame.parentNode){n.prepareElements(this.svgElements);var t=window.getComputedStyle(this.dom.frame).paddingTop,e=Number(t.replace("px","")),i=e,s=this.options.iconSize,o=.75*this.options.iconSize,r=e+.5*o+3;this.svg.style.width=s+5+e+"px";for(var a in this.groups)this.groups.hasOwnProperty(a)&&(1!=this.groups[a].visible||void 0!==this.linegraphOptions.visibility[a]&&1!=this.linegraphOptions.visibility[a]||(this.groups[a].drawIcon(i,r,this.svgElements,this.svg,s,o),r+=o+this.options.iconSpacing));n.cleanupElements(this.svgElements)}},t.exports=s},function(t,e,i){function s(t,e){this.id=o.randomUUID(),this.body=t,this.defaultOptions={yAxisOrientation:"left",defaultGroup:"default",sort:!0,sampling:!0,graphHeight:"400px",shaded:{enabled:!1,orientation:"bottom"},style:"line",barChart:{width:50,handleOverlap:"overlap",align:"center"},catmullRom:{enabled:!0,parametrization:"centripetal",alpha:.5},drawPoints:{enabled:!0,size:6,style:"square"},dataAxis:{showMinorLabels:!0,showMajorLabels:!0,icons:!1,width:"40px",visible:!0,alignZeros:!0,customRange:{left:{min:void 0,max:void 0},right:{min:void 0,max:void 0}}},legend:{enabled:!1,icons:!0,left:{visible:!0,position:"top-left"},right:{visible:!0,position:"top-right"}},groups:{visibility:{}}},this.options=o.extend({},this.defaultOptions),this.dom={},this.props={},this.hammer=null,this.groups={},this.abortedGraphUpdate=!1,this.updateSVGheight=!1,this.updateSVGheightOnResize=!1;var i=this;this.itemsData=null,this.groupsData=null,this.itemListeners={add:function(t,e){i._onAdd(e.items)},update:function(t,e){i._onUpdate(e.items)},remove:function(t,e){i._onRemove(e.items)}},this.groupListeners={add:function(t,e){i._onAddGroups(e.items)},update:function(t,e){i._onUpdateGroups(e.items)},remove:function(t,e){i._onRemoveGroups(e.items)}},this.items={},this.selection=[],this.lastStart=this.body.range.start,this.touchParams={},this.svgElements={},this.setOptions(e),this.groupsUsingDefaultStyles=[0],this.COUNTER=0,this.body.emitter.on("rangechanged",function(){i.lastStart=i.body.range.start,i.svg.style.left=o.option.asSize(-i.props.width),i.redraw.call(i,!0)}),this._create(),this.framework={svg:this.svg,svgElements:this.svgElements,options:this.options,groups:this.groups},this.body.emitter.emit("change")}var o=i(1),n=i(2),r=i(3),a=i(4),h=i(20),d=i(23),l=i(24),c=i(28),p=i(52),u="__ungrouped__";s.prototype=new h,s.prototype._create=function(){var t=document.createElement("div");t.className="LineGraph",this.dom.frame=t,this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.style.position="relative",this.svg.style.height=(""+this.options.graphHeight).replace("px","")+"px",this.svg.style.display="block",t.appendChild(this.svg),this.options.dataAxis.orientation="left",this.yAxisLeft=new d(this.body,this.options.dataAxis,this.svg,this.options.groups),this.options.dataAxis.orientation="right",this.yAxisRight=new d(this.body,this.options.dataAxis,this.svg,this.options.groups),delete this.options.dataAxis.orientation,this.legendLeft=new c(this.body,this.options.legend,"left",this.options.groups),this.legendRight=new c(this.body,this.options.legend,"right",this.options.groups),this.show()},s.prototype.setOptions=function(t){if(t){var e=["sampling","defaultGroup","height","graphHeight","yAxisOrientation","style","barChart","dataAxis","sort","groups"];void 0===t.graphHeight&&void 0!==t.height&&void 0!==this.body.domProps.centerContainer.height?(this.updateSVGheight=!0,this.updateSVGheightOnResize=!0):void 0!==this.body.domProps.centerContainer.height&&void 0!==t.graphHeight&&parseInt((t.graphHeight+"").replace("px",""))0){var d=this.body.util.toGlobalTime(-this.body.domProps.root.width),l=this.body.util.toGlobalTime(2*this.body.domProps.root.width),c={};for(this._getRelevantData(a,c,d,l),this._applySampling(a,c),e=0;eu&&console.log("WARNING: there may be an infinite loop in the _updateGraph emitter cycle."),this.COUNTER=0,this.abortedGraphUpdate=!1,e=0;e0)for(r=0;rs){d.push(h);break}d.push(h)}}else for(a=0;ai&&h.x0)for(var s=0;s0){var n=1,r=o.length,a=this.body.util.toGlobalScreen(o[o.length-1].x)-this.body.util.toGlobalScreen(o[0].x),h=r/a;n=Math.min(Math.ceil(.2*r),Math.max(1,Math.round(h)));for(var d=[],l=0;r>l;l+=n)d.push(o[l]);e[t[s]]=d}}},s.prototype._getYRanges=function(t,e,i){var s,o,n,r,a=[],h=[];if(t.length>0){for(n=0;n0&&(o=this.groups[t[n]],"stack"==r.barChart.handleOverlap&&"bar"==r.style?"left"==r.yAxisOrientation?a=a.concat(o.getYRange(s)):h=h.concat(o.getYRange(s)):i[t[n]]=o.getYRange(s,t[n]));p.getStackedBarYRange(a,i,t,"__barchartLeft","left"),p.getStackedBarYRange(h,i,t,"__barchartRight","right")}},s.prototype._updateYAxis=function(t,e){var i,s,o=!1,n=!1,r=!1,a=1e9,h=1e9,d=-1e9,l=-1e9;if(t.length>0){for(var c=0;ci?i:a,d=s>d?s:d):(r=!0,h=h>i?i:h,l=s>l?s:l));1==n&&this.yAxisLeft.setRange(a,d),1==r&&this.yAxisRight.setRange(h,l)}return o=this._toggleAxisVisiblity(n,this.yAxisLeft)||o,o=this._toggleAxisVisiblity(r,this.yAxisRight)||o,1==r&&1==n?(this.yAxisLeft.drawIcons=!0,this.yAxisRight.drawIcons=!0):(this.yAxisLeft.drawIcons=!1,this.yAxisRight.drawIcons=!1),this.yAxisRight.master=!n,0==this.yAxisRight.master?(this.yAxisLeft.lineOffset=1==r?this.yAxisRight.width:0,o=this.yAxisLeft.redraw()||o,this.yAxisRight.stepPixelsForced=this.yAxisLeft.stepPixels,this.yAxisRight.zeroCrossing=this.yAxisLeft.zeroCrossing,o=this.yAxisRight.redraw()||o):o=this.yAxisRight.redraw()||o,-1!=t.indexOf("__barchartLeft")&&t.splice(t.indexOf("__barchartLeft"),1),-1!=t.indexOf("__barchartRight")&&t.splice(t.indexOf("__barchartRight"),1),o},s.prototype._toggleAxisVisiblity=function(t,e){var i=!1;return 0==t?e.dom.frame.parentNode&&0==e.hidden&&(e.hide(),i=!0):e.dom.frame.parentNode||1!=e.hidden||(e.show(),i=!0),i},s.prototype._convertXcoordinates=function(t){for(var e,i,s=[],o=this.body.util.toScreen,n=0;ny;)y++,l=h.getCurrent(),c=h.isMajor(),u=h.getClassName(),f=m,m=this.body.util.toScreen(l),g=m-f,p&&(p.style.width=g+"px"),this.options.showMinorLabels&&this._repaintMinorText(m,h.getLabelMinor(),t,u),c&&this.options.showMajorLabels?(m>0&&(void 0==v&&(v=m),this._repaintMajorText(m,h.getLabelMajor(),t,u)),p=this._repaintMajorLine(m,t,u)):p=this._repaintMinorLine(m,t,u),h.next();if(this.options.showMajorLabels){var b=this.body.util.toTime(0),_=h.getLabelMajor(b),x=_.length*(this.props.majorCharWidth||10)+10;(void 0==v||v>x)&&this._repaintMajorText(0,_,t,u)}o.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},s.prototype._repaintMinorText=function(t,e,i,s){var o=this.dom.redundant.minorTexts.shift();if(!o){var n=document.createTextNode("");o=document.createElement("div"),o.appendChild(n),this.dom.foreground.appendChild(o)}this.dom.minorTexts.push(o),o.childNodes[0].nodeValue=e,o.style.top="top"==i?this.props.majorLabelHeight+"px":"0",o.style.left=t+"px",o.className="text minor "+s},s.prototype._repaintMajorText=function(t,e,i,s){var o=this.dom.redundant.majorTexts.shift();if(!o){var n=document.createTextNode(e);o=document.createElement("div"),o.appendChild(n),this.dom.foreground.appendChild(o)}this.dom.majorTexts.push(o),o.childNodes[0].nodeValue=e,o.className="text major "+s,o.style.top="top"==i?"0":this.props.minorLabelHeight+"px",o.style.left=t+"px"},s.prototype._repaintMinorLine=function(t,e,i){var s=this.dom.redundant.lines.shift();s||(s=document.createElement("div"),this.dom.background.appendChild(s)),this.dom.lines.push(s);var o=this.props;return s.style.top="top"==e?o.majorLabelHeight+"px":this.body.domProps.top.height+"px",s.style.height=o.minorLineHeight+"px",s.style.left=t-o.minorLineWidth/2+"px",s.className="grid vertical minor "+i,s},s.prototype._repaintMajorLine=function(t,e,i){var s=this.dom.redundant.lines.shift();s||(s=document.createElement("div"),this.dom.background.appendChild(s)),this.dom.lines.push(s);var o=this.props;return s.style.top="top"==e?"0":this.body.domProps.top.height+"px",s.style.left=t-o.majorLineWidth/2+"px",s.style.height=o.majorLineHeight+"px",s.className="grid vertical major "+i,s},s.prototype._calculateCharSize=function(){this.dom.measureCharMinor||(this.dom.measureCharMinor=document.createElement("DIV"),this.dom.measureCharMinor.className="text minor measure",this.dom.measureCharMinor.style.position="absolute",this.dom.measureCharMinor.appendChild(document.createTextNode("0")),this.dom.foreground.appendChild(this.dom.measureCharMinor)),this.props.minorCharHeight=this.dom.measureCharMinor.clientHeight,this.props.minorCharWidth=this.dom.measureCharMinor.clientWidth,this.dom.measureCharMajor||(this.dom.measureCharMajor=document.createElement("DIV"),this.dom.measureCharMajor.className="text major measure",this.dom.measureCharMajor.style.position="absolute",this.dom.measureCharMajor.appendChild(document.createTextNode("0")),this.dom.foreground.appendChild(this.dom.measureCharMajor)),this.props.majorCharHeight=this.dom.measureCharMajor.clientHeight,this.props.majorCharWidth=this.dom.measureCharMajor.clientWidth},s.prototype.snap=function(t){return this.step.snap(t)},t.exports=s},function(t,e,i){function s(t,e,i){this.id=null,this.parent=null,this.data=t,this.dom=null,this.conversion=e||{},this.options=i||{},this.selected=!1,this.displayed=!1,this.dirty=!0,this.top=null,this.left=null,this.width=null,this.height=null}var o=i(45),n=i(1);s.prototype.stack=!0,s.prototype.select=function(){this.selected=!0,this.dirty=!0,this.displayed&&this.redraw()},s.prototype.unselect=function(){this.selected=!1,this.dirty=!0,this.displayed&&this.redraw()},s.prototype.setData=function(t){this.data=t,this.dirty=!0,this.displayed&&this.redraw()},s.prototype.setParent=function(t){this.displayed?(this.hide(),this.parent=t,this.parent&&this.show()):this.parent=t},s.prototype.isVisible=function(){return!1},s.prototype.show=function(){return!1},s.prototype.hide=function(){return!1},s.prototype.redraw=function(){},s.prototype.repositionX=function(){},s.prototype.repositionY=function(){},s.prototype._repaintDeleteButton=function(t){if(this.selected&&this.options.editable.remove&&!this.dom.deleteButton){var e=this,i=document.createElement("div");i.className="delete",i.title="Delete this item",o(i,{preventDefault:!0}).on("tap",function(t){e.parent.removeFromDataSet(e),t.stopPropagation()}),t.appendChild(i),this.dom.deleteButton=i}else!this.selected&&this.dom.deleteButton&&(this.dom.deleteButton.parentNode&&this.dom.deleteButton.parentNode.removeChild(this.dom.deleteButton),this.dom.deleteButton=null)},s.prototype._updateContents=function(t){var e;if(this.options.template){var i=this.parent.itemSet.itemsData.get(this.id);e=this.options.template(i)}else e=this.data.content;if(e!==this.content){if(e instanceof Element)t.innerHTML="",t.appendChild(e);else if(void 0!=e)t.innerHTML=e;else if("background"!=this.data.type||void 0!==this.data.content)throw new Error('Property "content" missing in item '+this.id);this.content=e}},s.prototype._updateTitle=function(t){null!=this.data.title?t.title=this.data.title||"":t.removeAttribute("title")},s.prototype._updateDataAttributes=function(t){if(this.options.dataAttributes&&this.options.dataAttributes.length>0){var e=[];if(Array.isArray(this.options.dataAttributes))e=this.options.dataAttributes;else{if("all"!=this.options.dataAttributes)return;e=Object.keys(this.data)}for(var i=0;it.start},s.prototype.redraw=function(){var t=this.dom;if(t||(this.dom={},t=this.dom,t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content),this.dirty=!0),!this.parent)throw new Error("Cannot redraw item: no parent attached");if(!t.box.parentNode){var e=this.parent.dom.background;if(!e)throw new Error("Cannot redraw item: parent has no background container element");e.appendChild(t.box)}if(this.displayed=!0,this.dirty){this._updateContents(this.dom.content),this._updateTitle(this.dom.content),this._updateDataAttributes(this.dom.content),this._updateStyle(this.dom.box);var i=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");t.box.className=this.baseClassName+i,this.overflow="hidden"!==window.getComputedStyle(t.content).overflow,this.props.content.width=this.dom.content.offsetWidth,this.height=0,this.dirty=!1}},s.prototype.show=r.prototype.show,s.prototype.hide=r.prototype.hide,s.prototype.repositionX=r.prototype.repositionX,s.prototype.repositionY=function(t){var e="top"===this.options.orientation;this.dom.content.style.top=e?"":"0",this.dom.content.style.bottom=e?"0":"";var i;if(void 0!==this.data.subgroup){var s=this.data.subgroup,o=this.parent.subgroups,r=o[s].index;if(1==e){i=this.parent.subgroups[s].height+t.item.vertical,i+=0==r?t.axis-.5*t.item.vertical:0;var a=this.parent.top;for(var h in o)o.hasOwnProperty(h)&&1==o[h].visible&&o[h].indexr&&(a+=o[h].height+t.item.vertical);i=this.parent.subgroups[s].height+t.item.vertical,this.dom.box.style.top=a+"px",this.dom.box.style.bottom=""}}else this.parent instanceof n?(i=Math.max(this.parent.height,this.parent.itemSet.body.domProps.center.height,this.parent.itemSet.body.domProps.centerContainer.height),this.dom.box.style.top=e?"0":"",this.dom.box.style.bottom=e?"":"0"):(i=this.parent.height,this.dom.box.style.top=this.parent.top+"px",this.dom.box.style.bottom="");this.dom.box.style.height=i+"px"},t.exports=s},function(t,e,i){function s(t,e,i){if(this.props={dot:{width:0,height:0},line:{width:0,height:0}},t&&void 0==t.start)throw new Error('Property "start" missing in item '+t);o.call(this,t,e,i)}{var o=i(31);i(1)}s.prototype=new o(null,null,null),s.prototype.isVisible=function(t){var e=(t.end-t.start)/4;return this.data.start>t.start-e&&this.data.startt.start-e&&this.data.startt.start},s.prototype.redraw=function(){var t=this.dom;if(t||(this.dom={},t=this.dom,t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content),t.box["timeline-item"]=this,this.dirty=!0),!this.parent)throw new Error("Cannot redraw item: no parent attached");if(!t.box.parentNode){var e=this.parent.dom.foreground;if(!e)throw new Error("Cannot redraw item: parent has no foreground container element");e.appendChild(t.box)}if(this.displayed=!0,this.dirty){this._updateContents(this.dom.content),this._updateTitle(this.dom.box),this._updateDataAttributes(this.dom.box),this._updateStyle(this.dom.box);var i=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");t.box.className=this.baseClassName+i,this.overflow="hidden"!==window.getComputedStyle(t.content).overflow,this.dom.content.style.maxWidth="none",this.props.content.width=this.dom.content.offsetWidth,this.height=this.dom.box.offsetHeight,this.dom.content.style.maxWidth="",this.dirty=!1}this._repaintDeleteButton(t.box),this._repaintDragLeft(),this._repaintDragRight()},s.prototype.show=function(){this.displayed||this.redraw()},s.prototype.hide=function(){if(this.displayed){var t=this.dom.box;t.parentNode&&t.parentNode.removeChild(t),this.top=null,this.left=null,this.displayed=!1}},s.prototype.repositionX=function(){var t,e,i=this.parent.width,s=this.conversion.toScreen(this.data.start),o=this.conversion.toScreen(this.data.end);-i>s&&(s=-i),o>2*i&&(o=2*i);var n=Math.max(o-s,1);switch(this.overflow?(this.left=s,this.width=n+this.props.content.width,e=this.props.content.width):(this.left=s,this.width=n,e=Math.min(o-s-2*this.options.padding,this.props.content.width)),this.dom.box.style.left=this.left+"px",this.dom.box.style.width=n+"px",this.options.align){case"left":this.dom.content.style.left="0";break;case"right":this.dom.content.style.left=Math.max(n-e-2*this.options.padding,0)+"px";break;case"center":this.dom.content.style.left=Math.max((n-e-2*this.options.padding)/2,0)+"px";break;default:t=this.overflow?o>0?Math.max(-s,0):-e:0>s?Math.min(-s,o-s-e-2*this.options.padding):0,this.dom.content.style.left=t+"px"}},s.prototype.repositionY=function(){var t=this.options.orientation,e=this.dom.box;e.style.top="top"==t?this.top+"px":this.parent.height-this.top-this.height+"px"},s.prototype._repaintDragLeft=function(){if(this.selected&&this.options.editable.updateTime&&!this.dom.dragLeft){var t=document.createElement("div");t.className="drag-left",t.dragLeftItem=this,o(t,{preventDefault:!0}).on("drag",function(){}),this.dom.box.appendChild(t),this.dom.dragLeft=t}else!this.selected&&this.dom.dragLeft&&(this.dom.dragLeft.parentNode&&this.dom.dragLeft.parentNode.removeChild(this.dom.dragLeft),this.dom.dragLeft=null)},s.prototype._repaintDragRight=function(){if(this.selected&&this.options.editable.updateTime&&!this.dom.dragRight){var t=document.createElement("div");t.className="drag-right",t.dragRightItem=this,o(t,{preventDefault:!0}).on("drag",function(){}),this.dom.box.appendChild(t),this.dom.dragRight=t}else!this.selected&&this.dom.dragRight&&(this.dom.dragRight.parentNode&&this.dom.dragRight.parentNode.removeChild(this.dom.dragRight),this.dom.dragRight=null)},t.exports=s},function(t,e,i){function s(t,e,i){if(!(this instanceof s))throw new SyntaxError("Constructor must be called with the new operator");this._determineBrowserMethod(),this._initializeMixinLoaders(),this.containerElement=t,this.renderRefreshRate=60,this.renderTimestep=1e3/this.renderRefreshRate,this.renderTime=0,this.physicsTime=0,this.runDoubleSpeed=!1,this.physicsDiscreteStepsize=.5,this.initializing=!0,this.triggerFunctions={add:null,edit:null,editEdge:null,connect:null,del:null},this.defaultOptions={nodes:{mass:1,radiusMin:10,radiusMax:30,radius:10,shape:"ellipse",image:void 0,widthMin:16,widthMax:64,fontColor:"black",fontSize:14,fontFace:"verdana",fontFill:void 0,fontStrokeWidth:0,fontStrokeColor:"white",level:-1,color:{border:"#2B7CE9",background:"#97C2FC",highlight:{border:"#2B7CE9",background:"#D2E5FF"},hover:{border:"#2B7CE9",background:"#D2E5FF"}},group:void 0,borderWidth:1,borderWidthSelected:void 0},edges:{widthMin:1,widthMax:15,width:1,widthSelectionMultiplier:2,hoverWidth:1.5,style:"line",color:{color:"#848484",highlight:"#848484",hover:"#848484"},fontColor:"#343434",fontSize:14,fontFace:"arial",fontFill:"white",fontStrokeWidth:0,fontStrokeColor:"white",labelAlignment:"horizontal",arrowScaleFactor:1,dash:{length:10,gap:5,altLength:void 0},inheritColor:"from"},configurePhysics:!1,physics:{barnesHut:{enabled:!0,thetaInverted:2,gravitationalConstant:-2e3,centralGravity:.3,springLength:95,springConstant:.04,damping:.09},repulsion:{centralGravity:0,springLength:200,springConstant:.05,nodeDistance:100,damping:.09},hierarchicalRepulsion:{enabled:!1,centralGravity:0,springLength:100,springConstant:.01,nodeDistance:150,damping:.09},damping:null,centralGravity:null,springLength:null,springConstant:null},clustering:{enabled:!1,initialMaxNodes:100,clusterThreshold:500,reduceToNodes:300,chainThreshold:.4,clusterEdgeThreshold:20,sectorThreshold:100,screenSizeThreshold:.2,fontSizeMultiplier:4,maxFontSize:1e3,forceAmplification:.1,distanceAmplification:.1,edgeGrowth:20,nodeScaling:{width:1,height:1,radius:1},maxNodeSizeIncrements:600,activeAreaBoxSize:80,clusterLevelDifference:2},navigation:{enabled:!1},keyboard:{enabled:!1,speed:{x:10,y:10,zoom:.02}},dataManipulation:{enabled:!1,initiallyVisible:!1},hierarchicalLayout:{enabled:!1,levelSeparation:150,nodeSpacing:100,direction:"UD",layout:"hubsize"},freezeForStabilization:!1,smoothCurves:{enabled:!0,dynamic:!0,type:"continuous",roundness:.5},maxVelocity:30,minVelocity:.1,stabilize:!0,stabilizationIterations:1e3,zoomExtentOnStabilize:!0,locale:"en",locales:_,tooltip:{delay:300,fontColor:"black",fontSize:14,fontFace:"verdana",color:{border:"#666",background:"#FFFFC6"}},dragNetwork:!0,dragNodes:!0,zoomable:!0,hover:!1,hideEdgesOnDrag:!1,hideNodesOnDrag:!1,width:"100%",height:"100%",selectable:!0},this.constants=a.extend({},this.defaultOptions),this.pixelRatio=1,this.hoverObj={nodes:{},edges:{}},this.controlNodesActive=!1,this.navigationHammers={existing:[],_new:[]},this.animationSpeed=1/this.renderRefreshRate,this.animationEasingFunction="easeInOutQuint",this.easingTime=0,this.sourceScale=0,this.targetScale=0,this.sourceTranslation=0,this.targetTranslation=0,this.lockedOnNodeId=null,this.lockedOnNodeOffset=null,this.touchTime=0;var o=this;this.groups=new u,this.images=new m,this.images.setOnloadCallback(function(){o._redraw()}),this.xIncrement=0,this.yIncrement=0,this.zoomIncrement=0,this._loadPhysicsSystem(),this._create(),this._loadSectorSystem(),this._loadClusterSystem(),this._loadSelectionSystem(),this._loadHierarchySystem(),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1),this.setOptions(i),this.freezeSimulation=!1,this.cachedFunctions={},this.startedStabilization=!1,this.stabilized=!1,this.stabilizationIterations=null,this.draggingNodes=!1,this.calculationNodes={},this.calculationNodeIndices=[],this.nodeIndices=[],this.nodes={},this.edges={},this.canvasTopLeft={x:0,y:0},this.canvasBottomRight={x:0,y:0},this.pointerPosition={x:0,y:0},this.areaCenter={},this.scale=1,this.previousScale=this.scale,this.nodesData=null,this.edgesData=null,this.nodesListeners={add:function(t,e){o._addNodes(e.items),o.start()},update:function(t,e){o._updateNodes(e.items,e.data),o.start()},remove:function(t,e){o._removeNodes(e.items),o.start()}},this.edgesListeners={add:function(t,e){o._addEdges(e.items),o.start()},update:function(t,e){o._updateEdges(e.items),o.start()},remove:function(t,e){o._removeEdges(e.items),o.start()}},this.moving=!0,this.timer=void 0,this.setData(e,this.constants.clustering.enabled||this.constants.hierarchicalLayout.enabled),this.initializing=!1,1==this.constants.hierarchicalLayout.enabled?this._setupHierarchicalLayout():0==this.constants.stabilize&&this.zoomExtent(void 0,!0,this.constants.clustering.enabled),this.constants.clustering.enabled&&this.startWithClustering()}var o=i(56),n=i(45),r=i(57),a=i(1),h=i(47),d=i(3),l=i(4),c=i(42),p=i(43),u=i(38),m=i(39),f=i(40),g=i(37),v=i(41),y=i(54),b=i(55),_=i(49);i(50),o(s.prototype),s.prototype._determineBrowserMethod=function(){var t=navigator.userAgent.toLowerCase();this.requiresTimeout=!1,-1!=t.indexOf("msie 9.0")?this.requiresTimeout=!0:-1!=t.indexOf("safari")&&t.indexOf("chrome")<=-1&&(this.requiresTimeout=!0)},s.prototype._getScriptPath=function(){for(var t=document.getElementsByTagName("script"),e=0;et.boundingBox.left&&(s=t.boundingBox.left),ot.boundingBox.bottom&&(e=t.boundingBox.bottom),i=this.constants.clustering.initialMaxNodes?49.07548/(n+142.05338)+91444e-8:12.662/(n+7.4147)+.0964822:1==this.constants.clustering.enabled&&n>=this.constants.clustering.initialMaxNodes?77.5271985/(n+187.266146)+476710517e-13:30.5062972/(n+19.93597763)+.08413486;var r=Math.min(this.frame.canvas.clientWidth/600,this.frame.canvas.clientHeight/600);s*=r}else{var a=1.1*Math.abs(o.maxX-o.minX),h=1.1*Math.abs(o.maxY-o.minY),d=this.frame.canvas.clientWidth/a,l=this.frame.canvas.clientHeight/h;s=l>=d?d:l}s>1&&(s=1);var c=this._findCenter(o);if(0==i){var p={position:c,scale:s,animation:t};this.moveTo(p),this.moving=!0,this.start()}else c.x*=s,c.y*=s,c.x-=.5*this.frame.canvas.clientWidth,c.y-=.5*this.frame.canvas.clientHeight,this._setScale(s),this._setTranslation(-c.x,-c.y)},s.prototype._updateNodeIndexList=function(){this._clearNodeIndexList();for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodeIndices.push(t)},s.prototype.setData=function(t,e){if(void 0===e&&(e=!1),this.initializing=!0,t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(1==this.constants.dataManipulation.enabled&&this._createManipulatorBar(),this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var i=c.DOTToGraph(t.dot);return void this.setData(i)}}else if(t&&t.gephi){if(t&&t.gephi){var s=p.parseGephi(t.gephi);return void this.setData(s)}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this._putDataInSector(),0==e&&(1==this.constants.hierarchicalLayout.enabled?(this._resetLevels(),this._setupHierarchicalLayout()):this.constants.stabilize&&this._stabilize(),this.start()),this.initializing=!1},s.prototype.setOptions=function(t){if(t){var e,i=["nodes","edges","smoothCurves","hierarchicalLayout","clustering","navigation","keyboard","dataManipulation","onAdd","onEdit","onEditEdge","onConnect","onDelete","clickToUse"];if(a.selectiveNotDeepExtend(i,this.constants,t),a.selectiveNotDeepExtend(["color"],this.constants.nodes,t.nodes),a.selectiveNotDeepExtend(["color","length"],this.constants.edges,t.edges),t.physics&&(a.mergeOptions(this.constants.physics,t.physics,"barnesHut"),a.mergeOptions(this.constants.physics,t.physics,"repulsion"),t.physics.hierarchicalRepulsion)){this.constants.hierarchicalLayout.enabled=!0,this.constants.physics.hierarchicalRepulsion.enabled=!0,this.constants.physics.barnesHut.enabled=!1; -for(e in t.physics.hierarchicalRepulsion)t.physics.hierarchicalRepulsion.hasOwnProperty(e)&&(this.constants.physics.hierarchicalRepulsion[e]=t.physics.hierarchicalRepulsion[e])}if(t.onAdd&&(this.triggerFunctions.add=t.onAdd),t.onEdit&&(this.triggerFunctions.edit=t.onEdit),t.onEditEdge&&(this.triggerFunctions.editEdge=t.onEditEdge),t.onConnect&&(this.triggerFunctions.connect=t.onConnect),t.onDelete&&(this.triggerFunctions.del=t.onDelete),a.mergeOptions(this.constants,t,"smoothCurves"),a.mergeOptions(this.constants,t,"hierarchicalLayout"),a.mergeOptions(this.constants,t,"clustering"),a.mergeOptions(this.constants,t,"navigation"),a.mergeOptions(this.constants,t,"keyboard"),a.mergeOptions(this.constants,t,"dataManipulation"),t.dataManipulation&&(this.editMode=this.constants.dataManipulation.initiallyVisible),t.edges&&(void 0!==t.edges.color&&(a.isString(t.edges.color)?(this.constants.edges.color={},this.constants.edges.color.color=t.edges.color,this.constants.edges.color.highlight=t.edges.color,this.constants.edges.color.hover=t.edges.color):(void 0!==t.edges.color.color&&(this.constants.edges.color.color=t.edges.color.color),void 0!==t.edges.color.highlight&&(this.constants.edges.color.highlight=t.edges.color.highlight),void 0!==t.edges.color.hover&&(this.constants.edges.color.hover=t.edges.color.hover)),this.constants.edges.inheritColor=!1),t.edges.fontColor||void 0!==t.edges.color&&(a.isString(t.edges.color)?this.constants.edges.fontColor=t.edges.color:void 0!==t.edges.color.color&&(this.constants.edges.fontColor=t.edges.color.color))),t.nodes&&t.nodes.color){var s=a.parseColor(t.nodes.color);this.constants.nodes.color.background=s.background,this.constants.nodes.color.border=s.border,this.constants.nodes.color.highlight.background=s.highlight.background,this.constants.nodes.color.highlight.border=s.highlight.border,this.constants.nodes.color.hover.background=s.hover.background,this.constants.nodes.color.hover.border=s.hover.border}if(t.groups)for(var o in t.groups)if(t.groups.hasOwnProperty(o)){var n=t.groups[o];this.groups.add(o,n)}if(t.tooltip){for(e in t.tooltip)t.tooltip.hasOwnProperty(e)&&(this.constants.tooltip[e]=t.tooltip[e]);t.tooltip.color&&(this.constants.tooltip.color=a.parseColor(t.tooltip.color))}if("clickToUse"in t&&(t.clickToUse?this.activator||(this.activator=new b(this.frame),this.activator.on("change",this._createKeyBinds.bind(this))):this.activator&&(this.activator.destroy(),delete this.activator)),t.labels)throw new Error('Option "labels" is deprecated. Use options "locale" and "locales" instead.');this._loadPhysicsSystem(),this._loadNavigationControls(),this._loadManipulationSystem(),this._configureSmoothCurves(),this._createKeyBinds(),this.setSize(this.constants.width,this.constants.height),this.moving=!0,this.start()}},s.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="vis network-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),this.frame.canvas.getContext){var t=this.frame.canvas.getContext("2d");this.pixelRatio=(window.devicePixelRatio||1)/(t.webkitBackingStorePixelRatio||t.mozBackingStorePixelRatio||t.msBackingStorePixelRatio||t.oBackingStorePixelRatio||t.backingStorePixelRatio||1),this.frame.canvas.getContext("2d").setTransform(this.pixelRatio,0,0,this.pixelRatio,0,0)}else{var e=document.createElement("DIV");e.style.color="red",e.style.fontWeight="bold",e.style.padding="10px",e.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(e)}var i=this;this.drag={},this.pinch={},this.hammer=n(this.frame.canvas,{prevent_default:!0}),this.hammer.on("tap",i._onTap.bind(i)),this.hammer.on("doubletap",i._onDoubleTap.bind(i)),this.hammer.on("hold",i._onHold.bind(i)),this.hammer.on("pinch",i._onPinch.bind(i)),this.hammer.on("touch",i._onTouch.bind(i)),this.hammer.on("dragstart",i._onDragStart.bind(i)),this.hammer.on("drag",i._onDrag.bind(i)),this.hammer.on("dragend",i._onDragEnd.bind(i)),this.hammer.on("mousewheel",i._onMouseWheel.bind(i)),this.hammer.on("DOMMouseScroll",i._onMouseWheel.bind(i)),this.hammer.on("mousemove",i._onMouseMoveTitle.bind(i)),this.hammerFrame=n(this.frame,{prevent_default:!0}),this.hammerFrame.on("release",i._onRelease.bind(i)),this.containerElement.appendChild(this.frame)},s.prototype._createKeyBinds=function(){var t=this;void 0!==this.keycharm&&this.keycharm.destroy(),this.keycharm=r(),this.keycharm.reset(),this.constants.keyboard.enabled&&this.isActive()&&(this.keycharm.bind("up",this._moveUp.bind(t),"keydown"),this.keycharm.bind("up",this._yStopMoving.bind(t),"keyup"),this.keycharm.bind("down",this._moveDown.bind(t),"keydown"),this.keycharm.bind("down",this._yStopMoving.bind(t),"keyup"),this.keycharm.bind("left",this._moveLeft.bind(t),"keydown"),this.keycharm.bind("left",this._xStopMoving.bind(t),"keyup"),this.keycharm.bind("right",this._moveRight.bind(t),"keydown"),this.keycharm.bind("right",this._xStopMoving.bind(t),"keyup"),this.keycharm.bind("=",this._zoomIn.bind(t),"keydown"),this.keycharm.bind("=",this._stopZoom.bind(t),"keyup"),this.keycharm.bind("num+",this._zoomIn.bind(t),"keydown"),this.keycharm.bind("num+",this._stopZoom.bind(t),"keyup"),this.keycharm.bind("num-",this._zoomOut.bind(t),"keydown"),this.keycharm.bind("num-",this._stopZoom.bind(t),"keyup"),this.keycharm.bind("-",this._zoomOut.bind(t),"keydown"),this.keycharm.bind("-",this._stopZoom.bind(t),"keyup"),this.keycharm.bind("[",this._zoomIn.bind(t),"keydown"),this.keycharm.bind("[",this._stopZoom.bind(t),"keyup"),this.keycharm.bind("]",this._zoomOut.bind(t),"keydown"),this.keycharm.bind("]",this._stopZoom.bind(t),"keyup"),this.keycharm.bind("pageup",this._zoomIn.bind(t),"keydown"),this.keycharm.bind("pageup",this._stopZoom.bind(t),"keyup"),this.keycharm.bind("pagedown",this._zoomOut.bind(t),"keydown"),this.keycharm.bind("pagedown",this._stopZoom.bind(t),"keyup")),1==this.constants.dataManipulation.enabled&&(this.keycharm.bind("esc",this._createManipulatorBar.bind(t)),this.keycharm.bind("delete",this._deleteSelected.bind(t)))},s.prototype.destroy=function(){this.start=function(){},this.redraw=function(){},this.timer=!1,this._cleanupPhysicsConfiguration(),this.keycharm.reset(),this.hammer.dispose(),this.off(),this._recursiveDOMDelete(this.containerElement)},s.prototype._recursiveDOMDelete=function(t){for(;1==t.hasChildNodes();)this._recursiveDOMDelete(t.firstChild),t.removeChild(t.firstChild)},s.prototype._getPointer=function(t){return{x:t.pageX-a.getAbsoluteLeft(this.frame.canvas),y:t.pageY-a.getAbsoluteTop(this.frame.canvas)}},s.prototype._onTouch=function(t){(new Date).valueOf()-this.touchTime>100&&(this.drag.pointer=this._getPointer(t.gesture.center),this.drag.pinched=!1,this.pinch.scale=this._getScale(),this.touchTime=(new Date).valueOf(),this._handleTouch(this.drag.pointer))},s.prototype._onDragStart=function(t){this._handleDragStart(t)},s.prototype._handleDragStart=function(t){void 0===this.drag.pointer&&this._onTouch(t);var e=this._getNodeAt(this.drag.pointer);if(this.drag.dragging=!0,this.drag.selection=[],this.drag.translation=this._getTranslation(),this.drag.nodeId=null,this.draggingNodes=!1,null!=e&&1==this.constants.dragNodes){this.draggingNodes=!0,this.drag.nodeId=e.id,e.isSelected()||this._selectObject(e,!1),this.emit("dragStart",{nodeIds:this.getSelection().nodes});for(var i in this.selectionObj.nodes)if(this.selectionObj.nodes.hasOwnProperty(i)){var s=this.selectionObj.nodes[i],o={id:s.id,node:s,x:s.x,y:s.y,xFixed:s.xFixed,yFixed:s.yFixed};s.xFixed=!0,s.yFixed=!0,this.drag.selection.push(o)}}},s.prototype._onDrag=function(t){this._handleOnDrag(t)},s.prototype._handleOnDrag=function(t){if(!this.drag.pinched){this.releaseNode();var e=this._getPointer(t.gesture.center),i=this,s=this.drag,o=s.selection;if(o&&o.length&&1==this.constants.dragNodes){var n=e.x-s.pointer.x,r=e.y-s.pointer.y;o.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._XconvertDOMtoCanvas(i._XconvertCanvasToDOM(t.x)+n)),t.yFixed||(e.y=i._YconvertDOMtoCanvas(i._YconvertCanvasToDOM(t.y)+r))}),this.moving||(this.moving=!0,this.start())}else if(1==this.constants.dragNetwork){if(void 0===this.drag.pointer)return void this._handleDragStart(t);var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw()}}},s.prototype._onDragEnd=function(t){this._handleDragEnd(t)},s.prototype._handleDragEnd=function(){this.drag.dragging=!1;var t=this.drag.selection;t&&t.length?(t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed}),this.moving=!0,this.start()):this._redraw(),0==this.draggingNodes?this.emit("dragEnd",{nodeIds:[]}):this.emit("dragEnd",{nodeIds:this.getSelection().nodes})},s.prototype._onTap=function(t){var e=this._getPointer(t.gesture.center);this.pointerPosition=e,this._handleTap(e)},s.prototype._onDoubleTap=function(t){var e=this._getPointer(t.gesture.center);this._handleDoubleTap(e)},s.prototype._onHold=function(t){var e=this._getPointer(t.gesture.center);this.pointerPosition=e,this._handleOnHold(e)},s.prototype._onRelease=function(t){var e=this._getPointer(t.gesture.center);this._handleOnRelease(e)},s.prototype._onPinch=function(t){var e=this._getPointer(t.gesture.center);this.drag.pinched=!0,"scale"in this.pinch||(this.pinch.scale=1);var i=this.pinch.scale*t.gesture.scale;this._zoom(i,e)},s.prototype._zoom=function(t,e){if(1==this.constants.zoomable){var i=this._getScale();1e-5>t&&(t=1e-5),t>10&&(t=10);var s=null;void 0!==this.drag&&1==this.drag.dragging&&(s=this.DOMtoCanvas(this.drag.pointer));var o=this._getTranslation(),n=t/i,r=(1-n)*e.x+o.x*n,a=(1-n)*e.y+o.y*n;if(this.areaCenter={x:this._XconvertDOMtoCanvas(e.x),y:this._YconvertDOMtoCanvas(e.y)},this._setScale(t),this._setTranslation(r,a),this.updateClustersDefault(),null!=s){var h=this.canvasToDOM(s);this.drag.pointer.x=h.x,this.drag.pointer.y=h.y}return this._redraw(),t>i?this.emit("zoom",{direction:"+"}):this.emit("zoom",{direction:"-"}),t}},s.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){var i=this._getScale(),s=e/10;0>e&&(s/=1-s),i*=1+s;var o=h.fakeGesture(this,t),n=this._getPointer(o.center);this._zoom(i,n)}t.preventDefault()},s.prototype._onMouseMoveTitle=function(t){var e=h.fakeGesture(this,t),i=this._getPointer(e.center);this.popupObj&&this._checkHidePopup(i);var s=this,o=function(){s._checkShowPopup(i)};if(this.popupTimer&&clearInterval(this.popupTimer),this.drag.dragging||(this.popupTimer=setTimeout(o,this.constants.tooltip.delay)),1==this.constants.hover){for(var n in this.hoverObj.edges)this.hoverObj.edges.hasOwnProperty(n)&&(this.hoverObj.edges[n].hover=!1,delete this.hoverObj.edges[n]);var r=this._getNodeAt(i);null==r&&(r=this._getEdgeAt(i)),null!=r&&this._hoverObject(r);for(var a in this.hoverObj.nodes)this.hoverObj.nodes.hasOwnProperty(a)&&(r instanceof f&&r.id!=a||r instanceof g||null==r)&&(this._blurObject(this.hoverObj.nodes[a]),delete this.hoverObj.nodes[a]);this.redraw()}},s.prototype._checkShowPopup=function(t){var e,i={left:this._XconvertDOMtoCanvas(t.x),top:this._YconvertDOMtoCanvas(t.y),right:this._XconvertDOMtoCanvas(t.x),bottom:this._YconvertDOMtoCanvas(t.y)},s=this.popupObj,o=!1;if(void 0==this.popupObj){var n=this.nodes,r=[];for(e in n)if(n.hasOwnProperty(e)){var a=n[e];a.isOverlappingWith(i)&&void 0!==a.getTitle()&&r.push(e)}r.length>0&&(this.popupObj=this.nodes[r[r.length-1]],o=!0)}if(void 0===this.popupObj&&0==o){var h=this.edges,d=[];for(e in h)if(h.hasOwnProperty(e)){var l=h[e];l.connected&&void 0!==l.getTitle()&&l.isOverlappingWith(i)&&d.push(e)}d.length>0&&(this.popupObj=this.edges[d[d.length-1]])}if(this.popupObj){if(this.popupObj!=s){var c=this;c.popup||(c.popup=new v(c.frame,c.constants.tooltip)),c.popup.setPosition(t.x-3,t.y-3),c.popup.setText(c.popupObj.getTitle()),c.popup.show()}}else this.popup&&this.popup.hide()},s.prototype._checkHidePopup=function(t){this.popupObj&&this._getNodeAt(t)||(this.popupObj=void 0,this.popup&&this.popup.hide())},s.prototype.setSize=function(t,e){var i=!1,s=this.frame.canvas.width,o=this.frame.canvas.height;t!=this.constants.width||e!=this.constants.height||this.frame.style.width!=t||this.frame.style.height!=e?(this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth*this.pixelRatio,this.frame.canvas.height=this.frame.canvas.clientHeight*this.pixelRatio,this.constants.width=t,this.constants.height=e,i=!0):(this.frame.canvas.width!=this.frame.canvas.clientWidth*this.pixelRatio&&(this.frame.canvas.width=this.frame.canvas.clientWidth*this.pixelRatio,i=!0),this.frame.canvas.height!=this.frame.canvas.clientHeight*this.pixelRatio&&(this.frame.canvas.height=this.frame.canvas.clientHeight*this.pixelRatio,i=!0)),1==i&&this.emit("resize",{width:this.frame.canvas.width*this.pixelRatio,height:this.frame.canvas.height*this.pixelRatio,oldWidth:s*this.pixelRatio,oldHeight:o*this.pixelRatio})},s.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof d||t instanceof l)this.nodesData=t;else if(Array.isArray(t))this.nodesData=new d,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new d}if(e&&a.forEach(this.nodesListeners,function(t,i){e.off(i,t)}),this.nodes={},this.nodesData){var i=this;a.forEach(this.nodesListeners,function(t,e){i.nodesData.on(e,t)});var s=this.nodesData.getIds();this._addNodes(s)}this._updateSelection()},s.prototype._addNodes=function(t){for(var e,i=0,s=t.length;s>i;i++){e=t[i];var o=this.nodesData.get(e),n=new f(o,this.images,this.groups,this.constants);if(this.nodes[e]=n,!(0!=n.xFixed&&0!=n.yFixed||null!==n.x&&null!==n.y)){var r=1*t.length+10,a=2*Math.PI*Math.random();0==n.xFixed&&(n.x=r*Math.cos(a)),0==n.yFixed&&(n.y=r*Math.sin(a))}this.moving=!0}this._updateNodeIndexList(),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this._updateCalculationNodes(),this._reconnectEdges(),this._updateValueRange(this.nodes),this.updateLabels()},s.prototype._updateNodes=function(t,e){for(var i=this.nodes,s=0,o=t.length;o>s;s++){var n=t[s],r=i[n],a=e[s];r?r.setProperties(a,this.constants):(r=new f(properties,this.images,this.groups,this.constants),i[n]=r)}this.moving=!0,1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this._updateNodeIndexList(),this._updateValueRange(i)},s.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,s=t.length;s>i;i++){var o=t[i];delete e[o]}this._updateNodeIndexList(),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this._updateCalculationNodes(),this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},s.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof d||t instanceof l)this.edgesData=t;else if(Array.isArray(t))this.edgesData=new d,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new d}if(e&&a.forEach(this.edgesListeners,function(t,i){e.off(i,t)}),this.edges={},this.edgesData){var i=this;a.forEach(this.edgesListeners,function(t,e){i.edgesData.on(e,t)});var s=this.edgesData.getIds();this._addEdges(s)}this._reconnectEdges()},s.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,s=0,o=t.length;o>s;s++){var n=t[s],r=e[n];r&&r.disconnect();var a=i.get(n,{showInternalIds:!0});e[n]=new g(a,this,this.constants)}this.moving=!0,this._updateValueRange(e),this._createBezierNodes(),this._updateCalculationNodes(),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout())},s.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,s=0,o=t.length;o>s;s++){var n=t[s],r=i.get(n),a=e[n];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new g(r,this,this.constants),this.edges[n]=a)}this._createBezierNodes(),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this.moving=!0,this._updateValueRange(e)},s.prototype._removeEdges=function(t){for(var e=this.edges,i=0,s=t.length;s>i;i++){var o=t[i],n=e[o];n&&(null!=n.via&&delete this.sectors.support.nodes[n.via.id],n.disconnect(),delete e[o])}this.moving=!0,this._updateValueRange(e),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this._updateCalculationNodes()},s.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[],e[t].dynamicEdges=[]);for(t in i)if(i.hasOwnProperty(t)){var s=i[t];s.from=null,s.to=null,s.connect()}},s.prototype._updateValueRange=function(t){var e,i=void 0,s=void 0;for(e in t)if(t.hasOwnProperty(e)){var o=t[e].getValue();void 0!==o&&(i=void 0===i?o:Math.min(o,i),s=void 0===s?o:Math.max(o,s))}if(void 0!==i&&void 0!==s)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,s)},s.prototype.redraw=function(){this.setSize(this.constants.width,this.constants.height),this._redraw()},s.prototype._redraw=function(t){var e=this.frame.canvas.getContext("2d");e.setTransform(this.pixelRatio,0,0,this.pixelRatio,0,0);var i=this.frame.canvas.width*this.pixelRatio,s=this.frame.canvas.height*this.pixelRatio;e.clearRect(0,0,i,s),e.save(),e.translate(this.translation.x,this.translation.y),e.scale(this.scale,this.scale),this.canvasTopLeft={x:this._XconvertDOMtoCanvas(0),y:this._YconvertDOMtoCanvas(0)},this.canvasBottomRight={x:this._XconvertDOMtoCanvas(this.frame.canvas.clientWidth*this.pixelRatio),y:this._YconvertDOMtoCanvas(this.frame.canvas.clientHeight*this.pixelRatio)},1!=t&&(this._doInAllSectors("_drawAllSectorNodes",e),(0==this.drag.dragging||void 0===this.drag.dragging||0==this.constants.hideEdgesOnDrag)&&this._doInAllSectors("_drawEdges",e)),(0==this.drag.dragging||void 0===this.drag.dragging||0==this.constants.hideNodesOnDrag)&&this._doInAllSectors("_drawNodes",e,!1),1!=t&&1==this.controlNodesActive&&this._doInAllSectors("_drawControlNodes",e),e.restore(),1==t&&e.clearRect(0,0,i,s)},s.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e),this.emit("viewChanged")},s.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},s.prototype._setScale=function(t){this.scale=t},s.prototype._getScale=function(){return this.scale},s.prototype._XconvertDOMtoCanvas=function(t){return(t-this.translation.x)/this.scale},s.prototype._XconvertCanvasToDOM=function(t){return t*this.scale+this.translation.x},s.prototype._YconvertDOMtoCanvas=function(t){return(t-this.translation.y)/this.scale},s.prototype._YconvertCanvasToDOM=function(t){return t*this.scale+this.translation.y},s.prototype.canvasToDOM=function(t){return{x:this._XconvertCanvasToDOM(t.x),y:this._YconvertCanvasToDOM(t.y)}},s.prototype.DOMtoCanvas=function(t){return{x:this._XconvertDOMtoCanvas(t.x),y:this._YconvertDOMtoCanvas(t.y)}},s.prototype._drawNodes=function(t,e){void 0===e&&(e=!1);var i=this.nodes,s=[];for(var o in i)i.hasOwnProperty(o)&&(i[o].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight),i[o].isSelected()?s.push(o):(i[o].inArea()||e)&&i[o].draw(t));for(var n=0,r=s.length;r>n;n++)(i[s[n]].inArea()||e)&&i[s[n]].draw(t)},s.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var s=e[i];s.setScale(this.scale),s.connected&&e[i].draw(t)}},s.prototype._drawControlNodes=function(t){var e=this.edges;for(var i in e)e.hasOwnProperty(i)&&e[i]._drawControlNodes(t)},s.prototype._stabilize=function(){1==this.constants.freezeForStabilization&&this._freezeDefinedNodes();for(var t=0;this.moving&&t0)for(t in i)i.hasOwnProperty(t)&&(i[t].discreteStepLimited(e,this.constants.maxVelocity),s=!0);else for(t in i)i.hasOwnProperty(t)&&(i[t].discreteStep(e),s=!0);if(1==s){var o=this.constants.minVelocity/Math.max(this.scale,.05);return o>.5*this.constants.maxVelocity?!0:this._isMoving(o)}return!1},s.prototype._revertPhysicsState=function(){var t=this.nodes;for(var e in t)t.hasOwnProperty(e)&&t[e].revertPosition()},s.prototype._revertPhysicsTick=function(){this._doInAllActiveSectors("_revertPhysicsState"),1==this.constants.smoothCurves.enabled&&1==this.constants.smoothCurves.dynamic&&this._doInSupportSector("_revertPhysicsState")},s.prototype._physicsTick=function(){if(!this.freezeSimulation&&1==this.moving){var t=!1,e=!1;this._doInAllActiveSectors("_initializeForceCalculation");var i=this._doInAllActiveSectors("_discreteStepNodes");1==this.constants.smoothCurves.enabled&&1==this.constants.smoothCurves.dynamic&&(e=this._doInSupportSector("_discreteStepNodes"));for(var s=0;s2*e||1==this.runDoubleSpeed)&&1==this.moving&&(this._physicsTick(),0!=this.renderTime&&(this.runDoubleSpeed=!0));var i=Date.now();this._redraw(),this.renderTime=Date.now()-i,this.start()},"undefined"!=typeof window&&(window.requestAnimationFrame=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame),s.prototype.start=function(){if(1==this.moving||0!=this.xIncrement||0!=this.yIncrement||0!=this.zoomIncrement)this.timer||(this.timer=1==this.requiresTimeout?window.setTimeout(this._animationStep.bind(this),this.renderTimestep):window.requestAnimationFrame(this._animationStep.bind(this)));else if(this._redraw(),this.stabilizationIterations>1){var t=this,e={iterations:t.stabilizationIterations};this.stabilizationIterations=0,this.startedStabilization=!1,setTimeout(function(){t.emit("stabilized",e)},0)}else this.stabilizationIterations=0},s.prototype._handleNavigation=function(){if(0!=this.xIncrement||0!=this.yIncrement){var t=this._getTranslation();this._setTranslation(t.x+this.xIncrement,t.y+this.yIncrement)}if(0!=this.zoomIncrement){var e={x:this.frame.canvas.clientWidth/2,y:this.frame.canvas.clientHeight/2};this._zoom(this.scale*(1+this.zoomIncrement),e)}},s.prototype.toggleFreeze=function(){0==this.freezeSimulation?this.freezeSimulation=!0:(this.freezeSimulation=!1,this.start())},s.prototype._configureSmoothCurves=function(t){if(void 0===t&&(t=!0),1==this.constants.smoothCurves.enabled&&1==this.constants.smoothCurves.dynamic){this._createBezierNodes();for(var e in this.sectors.support.nodes)this.sectors.support.nodes.hasOwnProperty(e)&&void 0===this.edges[this.sectors.support.nodes[e].parentEdgeId]&&delete this.sectors.support.nodes[e]}else{this.sectors.support.nodes={};for(var i in this.edges)this.edges.hasOwnProperty(i)&&(this.edges[i].via=null)}this._updateCalculationNodes(),t||(this.moving=!0,this.start())},s.prototype._createBezierNodes=function(){if(1==this.constants.smoothCurves.enabled&&1==this.constants.smoothCurves.dynamic)for(var t in this.edges)if(this.edges.hasOwnProperty(t)){var e=this.edges[t];if(null==e.via){var i="edgeId:".concat(e.id);this.sectors.support.nodes[i]=new f({id:i,mass:1,shape:"circle",image:"",internalMultiplier:1},{},{},this.constants),e.via=this.sectors.support.nodes[i],e.via.parentEdgeId=e.id,e.positionBezierNode()}}},s.prototype._initializeMixinLoaders=function(){for(var t in y)y.hasOwnProperty(t)&&(s.prototype[t]=y[t])},s.prototype.storePosition=function(){console.log("storePosition is depricated: use .storePositions() from now on."),this.storePositions()},s.prototype.storePositions=function(){var t=[];for(var e in this.nodes)if(this.nodes.hasOwnProperty(e)){var i=this.nodes[e],s=!this.nodes.xFixed,o=!this.nodes.yFixed;(this.nodesData._data[e].x!=Math.round(i.x)||this.nodesData._data[e].y!=Math.round(i.y))&&t.push({id:e,x:Math.round(i.x),y:Math.round(i.y),allowedToMoveX:s,allowedToMoveY:o})}this.nodesData.update(t)},s.prototype.getPositions=function(t){var e={};if(void 0!==t){if(1==Array.isArray(t)){for(var i=0;i=1&&(this.easingTime=0,this._redraw=null!=this.lockedOnNodeId?this._lockedRedraw:this._classicRedraw,this.emit("animationFinished"))},s.prototype._classicRedraw=function(){},s.prototype.isActive=function(){return!this.activator||this.activator.active},s.prototype.setScale=function(){return this._setScale()},s.prototype.getScale=function(){return this._getScale()},s.prototype.getCenterCoordinates=function(){return this.DOMtoCanvas({x:.5*this.frame.canvas.clientWidth,y:.5*this.frame.canvas.clientHeight})},s.prototype.getBoundingBox=function(t){return void 0!==this.nodes[t]?this.nodes[t].boundingBox:void 0},t.exports=s},function(t,e,i){function s(t,e,i){if(!e)throw"No network provided";var s=["edges","physics"],n=o.selectiveBridgeObject(s,i);this.options=n.edges,this.physics=n.physics,this.options.smoothCurves=i.smoothCurves,this.network=e,this.id=void 0,this.fromId=void 0,this.toId=void 0,this.title=void 0,this.widthSelected=this.options.width*this.options.widthSelectionMultiplier,this.value=void 0,this.selected=!1,this.hover=!1,this.labelDimensions={top:0,left:0,width:0,height:0,yLine:0},this.dirtyLabel=!0,this.from=null,this.to=null,this.via=null,this.fromBackup=null,this.toBackup=null,this.originalFromId=[],this.originalToId=[],this.connected=!1,this.widthFixed=!1,this.lengthFixed=!1,this.setProperties(t),this.controlNodesEnabled=!1,this.controlNodes={from:null,to:null,positions:{}},this.connectedNode=null}var o=i(1),n=i(40);s.prototype.setProperties=function(t){if(t){var e=["style","fontSize","fontFace","fontColor","fontFill","fontStrokeWidth","fontStrokeColor","width","widthSelectionMultiplier","hoverWidth","arrowScaleFactor","dash","inheritColor","labelAlignment"];switch(o.selectiveDeepExtend(e,this.options,t),void 0!==t.from&&(this.fromId=t.from),void 0!==t.to&&(this.toId=t.to),void 0!==t.id&&(this.id=t.id),void 0!==t.label&&(this.label=t.label,this.dirtyLabel=!0),void 0!==t.title&&(this.title=t.title),void 0!==t.value&&(this.value=t.value),void 0!==t.length&&(this.physics.springLength=t.length),void 0!==t.color&&(this.options.inheritColor=!1,o.isString(t.color)?(this.options.color.color=t.color,this.options.color.highlight=t.color):(void 0!==t.color.color&&(this.options.color.color=t.color.color),void 0!==t.color.highlight&&(this.options.color.highlight=t.color.highlight),void 0!==t.color.hover&&(this.options.color.hover=t.color.hover))),this.connect(),this.widthFixed=this.widthFixed||void 0!==t.width,this.lengthFixed=this.lengthFixed||void 0!==t.length,this.widthSelected=this.options.width*this.options.widthSelectionMultiplier,this.options.style){case"line":this.draw=this._drawLine;break;case"arrow":this.draw=this._drawArrow;break;case"arrow-center":this.draw=this._drawArrowCenter;break;case"dash-line":this.draw=this._drawDashLine;break;default:this.draw=this._drawLine}}},s.prototype.connect=function(){this.disconnect(),this.from=this.network.nodes[this.fromId]||null,this.to=this.network.nodes[this.toId]||null,this.connected=this.from&&this.to,this.connected?(this.from.attachEdge(this),this.to.attachEdge(this)):(this.from&&this.from.detachEdge(this),this.to&&this.to.detachEdge(this))},s.prototype.disconnect=function(){this.from&&(this.from.detachEdge(this),this.from=null),this.to&&(this.to.detachEdge(this),this.to=null),this.connected=!1 -},s.prototype.getTitle=function(){return"function"==typeof this.title?this.title():this.title},s.prototype.getValue=function(){return this.value},s.prototype.setValueRange=function(t,e){if(!this.widthFixed&&void 0!==this.value){var i=(this.options.widthMax-this.options.widthMin)/(e-t);this.options.width=(this.value-t)*i+this.options.widthMin,this.widthSelected=this.options.width*this.options.widthSelectionMultiplier}},s.prototype.draw=function(){throw"Method draw not initialized in edge"},s.prototype.isOverlappingWith=function(t){if(this.connected){var e=10,i=this.from.x,s=this.from.y,o=this.to.x,n=this.to.y,r=t.left,a=t.top,h=this._getDistanceToEdge(i,s,o,n,r,a);return e>h}return!1},s.prototype._getColor=function(){var t=this.options.color;return"to"==this.options.inheritColor?t={highlight:this.to.options.color.highlight.border,hover:this.to.options.color.hover.border,color:this.to.options.color.border}:("from"==this.options.inheritColor||1==this.options.inheritColor)&&(t={highlight:this.from.options.color.highlight.border,hover:this.from.options.color.hover.border,color:this.from.options.color.border}),1==this.selected?t.highlight:1==this.hover?t.hover:t.color},s.prototype._drawLine=function(t){if(t.strokeStyle=this._getColor(),t.lineWidth=this._getLineWidth(),this.from!=this.to){var e,i=this._line(t);if(this.label){if(1==this.options.smoothCurves.enabled&&null!=i){var s=.5*(.5*(this.from.x+i.x)+.5*(this.to.x+i.x)),o=.5*(.5*(this.from.y+i.y)+.5*(this.to.y+i.y));e={x:s,y:o}}else e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}}else{var n,r,a=this.physics.springLength/4,h=this.from;h.width||h.resize(t),h.width>h.height?(n=h.x+h.width/2,r=h.y-a):(n=h.x+a,r=h.y-h.height/2),this._circle(t,n,r,a),e=this._pointOnCircle(n,r,a,.5),this._label(t,this.label,e.x,e.y)}},s.prototype._getLineWidth=function(){return 1==this.selected?Math.max(Math.min(this.widthSelected,this.options.widthMax),.3*this.networkScaleInv):1==this.hover?Math.max(Math.min(this.options.hoverWidth,this.options.widthMax),.3*this.networkScaleInv):Math.max(this.options.width,.3*this.networkScaleInv)},s.prototype._getViaCoordinates=function(){if(1==this.options.smoothCurves.dynamic&&1==this.options.smoothCurves.enabled)return this.via;if(0==this.options.smoothCurves.enabled)return{x:0,y:0};var t=null,e=null,i=this.options.smoothCurves.roundness,s=this.options.smoothCurves.type,o=Math.abs(this.from.x-this.to.x),n=Math.abs(this.from.y-this.to.y);return"discrete"==s||"diagonalCross"==s?Math.abs(this.from.x-this.to.x)this.to.y?this.from.xthis.to.x&&(t=this.from.x-i*n,e=this.from.y-i*n):this.from.ythis.to.x&&(t=this.from.x-i*n,e=this.from.y+i*n)),"discrete"==s&&(t=i*n>o?this.from.x:t)):Math.abs(this.from.x-this.to.x)>Math.abs(this.from.y-this.to.y)&&(this.from.y>this.to.y?this.from.xthis.to.x&&(t=this.from.x-i*o,e=this.from.y-i*o):this.from.ythis.to.x&&(t=this.from.x-i*o,e=this.from.y+i*o)),"discrete"==s&&(e=i*o>n?this.from.y:e)):"straightCross"==s?Math.abs(this.from.x-this.to.x)Math.abs(this.from.y-this.to.y)&&(t=this.from.xthis.to.y?this.from.xthis.to.x&&(t=this.from.x-i*n,e=this.from.y-i*n,t=this.to.x>t?this.to.x:t):this.from.ythis.to.x&&(t=this.from.x-i*n,e=this.from.y+i*n,t=this.to.x>t?this.to.x:t)):Math.abs(this.from.x-this.to.x)>Math.abs(this.from.y-this.to.y)&&(this.from.y>this.to.y?this.from.xe?this.to.y:e):this.from.x>this.to.x&&(t=this.from.x-i*o,e=this.from.y-i*o,e=this.to.y>e?this.to.y:e):this.from.ythis.to.x&&(t=this.from.x-i*o,e=this.from.y+i*o,e=this.to.yd;d++){var l=t.measureText(n[d]).width;h=l>h?l:h}var c=this.options.fontSize*r,p=i-h/2,u=s-c/2;this.labelDimensions={top:u,left:p,width:h,height:c,yLine:o}}var o=this.labelDimensions.yLine;t.save(),"horizontal"!=this.options.labelAlignment&&(t.translate(i,o),this._rotateForLabelAlignment(t),i=0,o=0),this._drawLabelRect(t),this._drawLabelText(t,i,o,n,r,a),t.restore()}},s.prototype._rotateForLabelAlignment=function(t){var e=this.from.y-this.to.y,i=this.from.x-this.to.x,s=Math.atan2(e,i);(-1>s&&0>i||s>0&&0>i)&&(s+=Math.PI),t.rotate(s)},s.prototype._drawLabelRect=function(t){if(void 0!==this.options.fontFill&&null!==this.options.fontFill&&"none"!==this.options.fontFill){t.fillStyle=this.options.fontFill;var e=2;"line-center"==this.options.labelAlignment?t.fillRect(.5*-this.labelDimensions.width,.5*-this.labelDimensions.height,this.labelDimensions.width,this.labelDimensions.height):"line-above"==this.options.labelAlignment?t.fillRect(.5*-this.labelDimensions.width,-(this.labelDimensions.height+e),this.labelDimensions.width,this.labelDimensions.height):"line-below"==this.options.labelAlignment?t.fillRect(.5*-this.labelDimensions.width,e,this.labelDimensions.width,this.labelDimensions.height):t.fillRect(this.labelDimensions.left,this.labelDimensions.top,this.labelDimensions.width,this.labelDimensions.height)}},s.prototype._drawLabelText=function(t,e,i,s,o,n){if(t.fillStyle=this.options.fontColor||"black",t.textAlign="center","horizontal"!=this.options.labelAlignment){var r=2;"line-above"==this.options.labelAlignment?(t.textBaseline="alphabetic",i-=2*r):"line-below"==this.options.labelAlignment?(t.textBaseline="hanging",i+=2*r):t.textBaseline="middle"}else t.textBaseline="middle";this.options.fontStrokeWidth>0&&(t.lineWidth=this.options.fontStrokeWidth,t.strokeStyle=this.options.fontStrokeColor,t.lineJoin="round");for(var a=0;o>a;a++)this.options.fontStrokeWidth>0&&t.strokeText(s[a],e,i),t.fillText(s[a],e,i),i+=n},s.prototype._drawDashLine=function(t){t.strokeStyle=this._getColor(),t.lineWidth=this._getLineWidth();var e=null;if(void 0!==t.setLineDash){t.save();var i=[0];i=void 0!==this.options.dash.length&&void 0!==this.options.dash.gap?[this.options.dash.length,this.options.dash.gap]:[5,5],t.setLineDash(i),t.lineDashOffset=0,e=this._line(t),t.setLineDash([0]),t.lineDashOffset=0,t.restore()}else t.beginPath(),t.lineCap="round",void 0!==this.options.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.options.dash.length,this.options.dash.gap,this.options.dash.altLength,this.options.dash.gap]):void 0!==this.options.dash.length&&void 0!==this.options.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.options.dash.length,this.options.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke();if(this.label){var s;if(1==this.options.smoothCurves.enabled&&null!=e){var o=.5*(.5*(this.from.x+e.x)+.5*(this.to.x+e.x)),n=.5*(.5*(this.from.y+e.y)+.5*(this.to.y+e.y));s={x:o,y:n}}else s=this._pointOnLine(.5);this._label(t,this.label,s.x,s.y)}},s.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},s.prototype._pointOnCircle=function(t,e,i,s){var o=2*(s-3/8)*Math.PI;return{x:t+i*Math.cos(o),y:e-i*Math.sin(o)}},s.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this._getColor(),t.fillStyle=t.strokeStyle,t.lineWidth=this._getLineWidth(),this.from!=this.to){var i=this._line(t),s=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),o=(10+5*this.options.width)*this.options.arrowScaleFactor;if(1==this.options.smoothCurves.enabled&&null!=i){var n=.5*(.5*(this.from.x+i.x)+.5*(this.to.x+i.x)),r=.5*(.5*(this.from.y+i.y)+.5*(this.to.y+i.y));e={x:n,y:r}}else e=this._pointOnLine(.5);t.arrow(e.x,e.y,s,o),t.fill(),t.stroke(),this.label&&this._label(t,this.label,e.x,e.y)}else{var a,h,d=.25*Math.max(100,this.physics.springLength),l=this.from;l.width||l.resize(t),l.width>l.height?(a=l.x+.5*l.width,h=l.y-d):(a=l.x+d,h=l.y-.5*l.height),this._circle(t,a,h,d);var s=.2*Math.PI,o=(10+5*this.options.width)*this.options.arrowScaleFactor;e=this._pointOnCircle(a,h,d,.5),t.arrow(e.x,e.y,s,o),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(a,h,d,.5),this._label(t,this.label,e.x,e.y))}},s.prototype._pointOnBezier=function(t){var e=this._getViaCoordinates(),i=Math.pow(1-t,2)*this.from.x+2*t*(1-t)*e.x+Math.pow(t,2)*this.to.x,s=Math.pow(1-t,2)*this.from.y+2*t*(1-t)*e.y+Math.pow(t,2)*this.to.y;return{x:i,y:s}},s.prototype._findBorderPosition=function(t,e){var i,s,o,n,r,a=10,h=0,d=0,l=1,c=.2,p=this.to;for(1==t&&(p=this.from);l>=d&&a>h;){var u=.5*(d+l);if(i=this._pointOnBezier(u),s=Math.atan2(p.y-i.y,p.x-i.x),o=p.distanceToBorder(e,s),n=Math.sqrt(Math.pow(i.x-p.x,2)+Math.pow(i.y-p.y,2)),r=o-n,Math.abs(r)r?0==t?d=u:l=u:0==t?l=u:d=u,h++}return i.t=u,i},s.prototype._drawArrow=function(t){t.strokeStyle=this._getColor(),t.fillStyle=t.strokeStyle,t.lineWidth=this._getLineWidth();var e,i,s;if(this.from!=this.to){if(this._line(t),1==this.options.smoothCurves.enabled){var o=this._getViaCoordinates();s=this._findBorderPosition(!1,t);var n=this._pointOnBezier(Math.max(0,s.t-.1));e=Math.atan2(s.y-n.y,s.x-n.x)}else{e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var r=this.to.x-this.from.x,a=this.to.y-this.from.y,h=Math.sqrt(r*r+a*a),d=this.to.distanceToBorder(t,e),l=(h-d)/h;s={},s.x=(1-l)*this.from.x+l*this.to.x,s.y=(1-l)*this.from.y+l*this.to.y}if(i=(10+5*this.options.width)*this.options.arrowScaleFactor,t.arrow(s.x,s.y,e,i),t.fill(),t.stroke(),this.label){var c;c=1==this.options.smoothCurves.enabled&&null!=o?this._pointOnBezier(.5):this._pointOnLine(.5),this._label(t,this.label,c.x,c.y)}}else{var p,u,m,f=this.from,g=.25*Math.max(100,this.physics.springLength);f.width||f.resize(t),f.width>f.height?(p=f.x+.5*f.width,u=f.y-g,m={x:p,y:f.y,angle:.9*Math.PI}):(p=f.x+g,u=f.y-.5*f.height,m={x:f.x,y:u,angle:.6*Math.PI}),t.beginPath(),t.arc(p,u,g,0,2*Math.PI,!1),t.stroke();var i=(10+5*this.options.width)*this.options.arrowScaleFactor;t.arrow(m.x,m.y,m.angle,i),t.fill(),t.stroke(),this.label&&(c=this._pointOnCircle(p,u,g,.5),this._label(t,this.label,c.x,c.y))}},s.prototype._getDistanceToEdge=function(t,e,i,s,o,n){var r=0;if(this.from!=this.to)if(1==this.options.smoothCurves.enabled){var a,h;if(1==this.options.smoothCurves.enabled&&1==this.options.smoothCurves.dynamic)a=this.via.x,h=this.via.y;else{var d=this._getViaCoordinates();a=d.x,h=d.y}var l,c,p,u,m,f,g,v=1e9;for(c=0;10>c;c++)p=.1*c,u=Math.pow(1-p,2)*t+2*p*(1-p)*a+Math.pow(p,2)*i,m=Math.pow(1-p,2)*e+2*p*(1-p)*h+Math.pow(p,2)*s,c>0&&(l=this._getDistanceToLine(f,g,u,m,o,n),v=v>l?l:v),f=u,g=m;r=v}else r=this._getDistanceToLine(t,e,i,s,o,n);else{var u,m,y,b,_=.25*this.physics.springLength,x=this.from;x.width>x.height?(u=x.x+.5*x.width,m=x.y-_):(u=x.x+_,m=x.y-.5*x.height),y=u-o,b=m-n,r=Math.abs(Math.sqrt(y*y+b*b)-_)}return this.labelDimensions.lefto&&this.labelDimensions.topn?0:r},s.prototype._getDistanceToLine=function(t,e,i,s,o,n){var r=i-t,a=s-e,h=r*r+a*a,d=((o-t)*r+(n-e)*a)/h;d>1?d=1:0>d&&(d=0);var l=t+d*r,c=e+d*a,p=l-o,u=c-n;return Math.sqrt(p*p+u*u)},s.prototype.setScale=function(t){this.networkScaleInv=1/t},s.prototype.select=function(){this.selected=!0},s.prototype.unselect=function(){this.selected=!1},s.prototype.positionBezierNode=function(){null!==this.via&&null!==this.from&&null!==this.to?(this.via.x=.5*(this.from.x+this.to.x),this.via.y=.5*(this.from.y+this.to.y)):(this.via.x=0,this.via.y=0)},s.prototype._drawControlNodes=function(t){if(1==this.controlNodesEnabled){if(null===this.controlNodes.from&&null===this.controlNodes.to){var e="edgeIdFrom:".concat(this.id),i="edgeIdTo:".concat(this.id),s={nodes:{group:"",radius:7,borderWidth:2,borderWidthSelected:2},physics:{damping:0},clustering:{maxNodeSizeIncrements:0,nodeScaling:{width:0,height:0,radius:0}}};this.controlNodes.from=new n({id:e,shape:"dot",color:{background:"#ff0000",border:"#3c3c3c",highlight:{background:"#07f968"}}},{},{},s),this.controlNodes.to=new n({id:i,shape:"dot",color:{background:"#ff0000",border:"#3c3c3c",highlight:{background:"#07f968"}}},{},{},s)}this.controlNodes.positions={},0==this.controlNodes.from.selected&&(this.controlNodes.positions.from=this.getControlNodeFromPosition(t),this.controlNodes.from.x=this.controlNodes.positions.from.x,this.controlNodes.from.y=this.controlNodes.positions.from.y),0==this.controlNodes.to.selected&&(this.controlNodes.positions.to=this.getControlNodeToPosition(t),this.controlNodes.to.x=this.controlNodes.positions.to.x,this.controlNodes.to.y=this.controlNodes.positions.to.y),this.controlNodes.from.draw(t),this.controlNodes.to.draw(t)}else this.controlNodes={from:null,to:null,positions:{}}},s.prototype._enableControlNodes=function(){this.fromBackup=this.from,this.toBackup=this.to,this.controlNodesEnabled=!0},s.prototype._disableControlNodes=function(){this.fromId=this.from.id,this.toId=this.to.id,this.fromId!=this.fromBackup.id?this.fromBackup.detachEdge(this):this.toId!=this.toBackup.id&&this.toBackup.detachEdge(this),this.fromBackup=null,this.toBackup=null,this.controlNodesEnabled=!1},s.prototype._getSelectedControlNode=function(t,e){var i=this.controlNodes.positions,s=Math.sqrt(Math.pow(t-i.from.x,2)+Math.pow(e-i.from.y,2)),o=Math.sqrt(Math.pow(t-i.to.x,2)+Math.pow(e-i.to.y,2));return 15>s?(this.connectedNode=this.from,this.from=this.controlNodes.from,this.controlNodes.from):15>o?(this.connectedNode=this.to,this.to=this.controlNodes.to,this.controlNodes.to):null},s.prototype._restoreControlNodes=function(){1==this.controlNodes.from.selected?(this.from=this.connectedNode,this.connectedNode=null,this.controlNodes.from.unselect()):1==this.controlNodes.to.selected&&(this.to=this.connectedNode,this.connectedNode=null,this.controlNodes.to.unselect())},s.prototype.getControlNodeFromPosition=function(t){var e;if(1==this.options.smoothCurves.enabled)e=this._findBorderPosition(!0,t);else{var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),s=this.to.x-this.from.x,o=this.to.y-this.from.y,n=Math.sqrt(s*s+o*o),r=this.from.distanceToBorder(t,i+Math.PI),a=(n-r)/n;e={},e.x=a*this.from.x+(1-a)*this.to.x,e.y=a*this.from.y+(1-a)*this.to.y}return e},s.prototype.getControlNodeToPosition=function(t){var e;if(1==this.options.smoothCurves.enabled)e=this._findBorderPosition(!1,t);else{var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),s=this.to.x-this.from.x,o=this.to.y-this.from.y,n=Math.sqrt(s*s+o*o),r=this.to.distanceToBorder(t,i),a=(n-r)/n;e={},e.x=(1-a)*this.from.x+a*this.to.x,e.y=(1-a)*this.from.y+a*this.to.y}return e},t.exports=s},function(t,e,i){function s(){this.clear(),this.defaultIndex=0}i(1);s.DEFAULT=[{border:"#2B7CE9",background:"#97C2FC",highlight:{border:"#2B7CE9",background:"#D2E5FF"},hover:{border:"#2B7CE9",background:"#D2E5FF"}},{border:"#FFA500",background:"#FFFF00",highlight:{border:"#FFA500",background:"#FFFFA3"},hover:{border:"#FFA500",background:"#FFFFA3"}},{border:"#FA0A10",background:"#FB7E81",highlight:{border:"#FA0A10",background:"#FFAFB1"},hover:{border:"#FA0A10",background:"#FFAFB1"}},{border:"#41A906",background:"#7BE141",highlight:{border:"#41A906",background:"#A1EC76"},hover:{border:"#41A906",background:"#A1EC76"}},{border:"#E129F0",background:"#EB7DF4",highlight:{border:"#E129F0",background:"#F0B3F5"},hover:{border:"#E129F0",background:"#F0B3F5"}},{border:"#7C29F0",background:"#AD85E4",highlight:{border:"#7C29F0",background:"#D3BDF0"},hover:{border:"#7C29F0",background:"#D3BDF0"}},{border:"#C37F00",background:"#FFA807",highlight:{border:"#C37F00",background:"#FFCA66"},hover:{border:"#C37F00",background:"#FFCA66"}},{border:"#4220FB",background:"#6E6EFD",highlight:{border:"#4220FB",background:"#9B9BFD"},hover:{border:"#4220FB",background:"#9B9BFD"}},{border:"#FD5A77",background:"#FFC0CB",highlight:{border:"#FD5A77",background:"#FFD1D9"},hover:{border:"#FD5A77",background:"#FFD1D9"}},{border:"#4AD63A",background:"#C2FABC",highlight:{border:"#4AD63A",background:"#E6FFE3"},hover:{border:"#4AD63A",background:"#E6FFE3"}}],s.prototype.clear=function(){this.groups={},this.groups.length=function(){var t=0;for(var e in this)this.hasOwnProperty(e)&&t++;return t}},s.prototype.get=function(t){var e=this.groups[t];if(void 0==e){var i=this.defaultIndex%s.DEFAULT.length;this.defaultIndex++,e={},e.color=s.DEFAULT[i],this.groups[t]=e}return e},s.prototype.add=function(t,e){return this.groups[t]=e,e},t.exports=s},function(t){function e(){this.images={},this.imageBroken={},this.callback=void 0}e.prototype.setOnloadCallback=function(t){this.callback=t},e.prototype.load=function(t,e){var i=this.images[t];if(void 0===i){var s=this;i=new Image,i.onload=function(){0==this.width&&(document.body.appendChild(this),this.width=this.offsetWidth,this.height=this.offsetHeight,document.body.removeChild(this)),s.callback&&(s.images[t]=i,s.callback(this))},i.onerror=function(){void 0===e?(console.error("Could not load image:",t),delete this.src,s.callback&&s.callback(this)):s.imageBroken[t]===!0?(console.error("Could not load brokenImage:",e),delete this.src,s.callback&&s.callback(this)):(this.src=e,s.imageBroken[t]=!0)},i.src=t}return i},t.exports=e},function(t,e,i){function s(t,e,i,s){var n=o.selectiveBridgeObject(["nodes"],s);this.options=n.nodes,this.selected=!1,this.hover=!1,this.edges=[],this.dynamicEdges=[],this.reroutedEdges={},this.fontDrawThreshold=3,this.id=void 0,this.allowedToMoveX=!1,this.allowedToMoveY=!1,this.xFixed=!1,this.yFixed=!1,this.horizontalAlignLeft=!0,this.verticalAlignTop=!0,this.baseRadiusValue=s.nodes.radius,this.radiusFixed=!1,this.level=-1,this.preassignedLevel=!1,this.hierarchyEnumerated=!1,this.labelDimensions={top:0,left:0,width:0,height:0,yLine:0},this.boundingBox={top:0,left:0,right:0,bottom:0},this.imagelist=e,this.grouplist=i,this.fx=0,this.fy=0,this.vx=0,this.vy=0,this.x=null,this.y=null,this.previousState={vx:0,vy:0,x:0,y:0},this.damping=s.physics.damping,this.fixedData={x:null,y:null},this.setProperties(t,n),this.resetCluster(),this.dynamicEdgesLength=0,this.clusterSession=0,this.clusterSizeWidthFactor=s.clustering.nodeScaling.width,this.clusterSizeHeightFactor=s.clustering.nodeScaling.height,this.clusterSizeRadiusFactor=s.clustering.nodeScaling.radius,this.maxNodeSizeIncrements=s.clustering.maxNodeSizeIncrements,this.growthIndicator=0,this.networkScaleInv=1,this.networkScale=1,this.canvasTopLeft={x:-300,y:-300},this.canvasBottomRight={x:300,y:300},this.parentEdgeId=null}var o=i(1);s.prototype.revertPosition=function(){this.x=this.previousState.x,this.y=this.previousState.y,this.vx=this.previousState.vx,this.vy=this.previousState.vy},s.prototype.resetCluster=function(){this.formationScale=void 0,this.clusterSize=1,this.containedNodes={},this.containedEdges={},this.clusterSessions=[]},s.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),-1==this.dynamicEdges.indexOf(t)&&this.dynamicEdges.push(t),this.dynamicEdgesLength=this.dynamicEdges.length},s.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&this.edges.splice(e,1),e=this.dynamicEdges.indexOf(t),-1!=e&&this.dynamicEdges.splice(e,1),this.dynamicEdgesLength=this.dynamicEdges.length},s.prototype.setProperties=function(t,e){if(t){var i=["borderWidth","borderWidthSelected","shape","image","brokenImage","radius","fontColor","fontSize","fontFace","fontFill","fontStrokeWidth","fontStrokeColor","group","mass"];if(o.selectiveDeepExtend(i,this.options,t),void 0!==t.id&&(this.id=t.id),void 0!==t.label&&(this.label=t.label,this.originalLabel=t.label),void 0!==t.title&&(this.title=t.title),void 0!==t.x&&(this.x=t.x),void 0!==t.y&&(this.y=t.y),void 0!==t.value&&(this.value=t.value),void 0!==t.level&&(this.level=t.level,this.preassignedLevel=!0),void 0!==t.horizontalAlignLeft&&(this.horizontalAlignLeft=t.horizontalAlignLeft),void 0!==t.verticalAlignTop&&(this.verticalAlignTop=t.verticalAlignTop),void 0!==t.triggerFunction&&(this.triggerFunction=t.triggerFunction),void 0===this.id)throw"Node must have an id";if("number"==typeof this.options.group||"string"==typeof this.options.group&&""!=this.options.group){var s=this.grouplist.get(this.options.group);o.deepExtend(this.options,s),this.options.color=o.parseColor(this.options.color)}if(void 0!==t.radius&&(this.baseRadiusValue=this.options.radius),void 0!==t.color&&(this.options.color=o.parseColor(t.color)),void 0!==this.options.image&&""!=this.options.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.options.image,this.options.brokenImage)}switch(void 0!==t.allowedToMoveX?(this.xFixed=!t.allowedToMoveX,this.allowedToMoveX=t.allowedToMoveX):void 0!==t.x&&0==this.allowedToMoveX&&(this.xFixed=!0),void 0!==t.allowedToMoveY?(this.yFixed=!t.allowedToMoveY,this.allowedToMoveY=t.allowedToMoveY):void 0!==t.y&&0==this.allowedToMoveY&&(this.yFixed=!0),this.radiusFixed=this.radiusFixed||void 0!==t.radius,("image"===this.options.shape||"circularImage"===this.options.shape)&&(this.options.radiusMin=e.nodes.widthMin,this.options.radiusMax=e.nodes.widthMax),this.options.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"circularImage":this.draw=this._drawCircularImage,this.resize=this._resizeCircularImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},s.prototype.select=function(){this.selected=!0,this._reset()},s.prototype.unselect=function(){this.selected=!1,this._reset()},s.prototype.clearSizeCache=function(){this._reset()},s.prototype._reset=function(){this.width=void 0,this.height=void 0},s.prototype.getTitle=function(){return"function"==typeof this.title?this.title():this.title},s.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.options.shape){case"circle":case"dot":return this.options.radius+i;case"ellipse":var s=this.width/2,o=this.height/2,n=Math.sin(e)*s,r=Math.cos(e)*o;return s*o/Math.sqrt(n*n+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},s.prototype._setForce=function(t,e){this.fx=t,this.fy=e},s.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},s.prototype.storeState=function(){this.previousState.x=this.x,this.previousState.y=this.y,this.previousState.vx=this.vx,this.previousState.vy=this.vy},s.prototype.discreteStep=function(t){if(this.storeState(),this.xFixed)this.fx=0,this.vx=0;else{var e=this.damping*this.vx,i=(this.fx-e)/this.options.mass;this.vx+=i*t,this.x+=this.vx*t}if(this.yFixed)this.fy=0,this.vy=0;else{var s=this.damping*this.vy,o=(this.fy-s)/this.options.mass;this.vy+=o*t,this.y+=this.vy*t}},s.prototype.discreteStepLimited=function(t,e){if(this.storeState(),this.xFixed)this.fx=0,this.vx=0;else{var i=this.damping*this.vx,s=(this.fx-i)/this.options.mass;this.vx+=s*t,this.vx=Math.abs(this.vx)>e?this.vx>0?e:-e:this.vx,this.x+=this.vx*t}if(this.yFixed)this.fy=0,this.vy=0;else{var o=this.damping*this.vy,n=(this.fy-o)/this.options.mass;this.vy+=n*t,this.vy=Math.abs(this.vy)>e?this.vy>0?e:-e:this.vy,this.y+=this.vy*t}},s.prototype.isFixed=function(){return this.xFixed&&this.yFixed},s.prototype.isMoving=function(t){var e=Math.sqrt(Math.pow(this.vx,2)+Math.pow(this.vy,2));return e>t},s.prototype.isSelected=function(){return this.selected},s.prototype.getValue=function(){return this.value},s.prototype.getDistance=function(t,e){var i=this.x-t,s=this.y-e;return Math.sqrt(i*i+s*s)},s.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value)if(e==t)this.options.radius=(this.options.radiusMin+this.options.radiusMax)/2;else{var i=(this.options.radiusMax-this.options.radiusMin)/(e-t);this.options.radius=(this.value-t)*i+this.options.radiusMin}this.baseRadiusValue=this.options.radius},s.prototype.draw=function(){throw"Draw method not initialized for node"},s.prototype.resize=function(){throw"Resize method not initialized for node"},s.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},s.prototype._resizeImage=function(){if(!this.width||!this.height){var t,e;if(this.value){this.options.radius=this.baseRadiusValue;var i=this.imageObj.height/this.imageObj.width;void 0!==i?(t=this.options.radius||this.imageObj.width,e=this.options.radius*i||this.imageObj.height):(t=0,e=0)}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e,this.growthIndicator=0,this.width>0&&this.height>0&&(this.width+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeWidthFactor,this.height+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeHeightFactor,this.options.radius+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-t)}},s.prototype._drawImageAtPosition=function(t){if(0!=this.imageObj.width){if(this.clusterSize>1){var e=this.clusterSize>1?10:0;e*=this.networkScaleInv,e=Math.min(.2*this.width,e),t.globalAlpha=.5,t.drawImage(this.imageObj,this.left-e,this.top-e,this.width+2*e,this.height+2*e)}t.globalAlpha=1,t.drawImage(this.imageObj,this.left,this.top,this.width,this.height)}},s.prototype._drawImageLabel=function(t){var e,i=0;if(this.height){i=this.height/2;var s=this.getTextSize(t);s.lineCount>=1&&(i+=s.height/2,i+=3)}e=this.y+i,this._label(t,this.label,this.x,e,void 0)},s.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._drawImageAtPosition(t),this.boundingBox.top=this.top,this.boundingBox.left=this.left,this.boundingBox.right=this.left+this.width,this.boundingBox.bottom=this.top+this.height,this._drawImageLabel(t),this.boundingBox.left=Math.min(this.boundingBox.left,this.labelDimensions.left),this.boundingBox.right=Math.max(this.boundingBox.right,this.labelDimensions.left+this.labelDimensions.width),this.boundingBox.bottom=Math.max(this.boundingBox.bottom,this.boundingBox.bottom+this.labelDimensions.height)},s.prototype._resizeCircularImage=function(t){if(this.imageObj.src&&this.imageObj.width&&this.imageObj.height)this._swapToImageResizeWhenImageLoaded&&(this.width=0,this.height=0,delete this._swapToImageResizeWhenImageLoaded),this._resizeImage(t);else if(!this.width){var e=2*this.options.radius;this.width=e,this.height=e,this.options.radius+=.5*Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.options.radius-.5*e,this._swapToImageResizeWhenImageLoaded=!0}},s.prototype._drawCircularImage=function(t){this._resizeCircularImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=this.left+this.width/2,i=this.top+this.height/2,s=Math.abs(this.height/2);this._drawRawCircle(t,e,i,s),t.save(),t.circle(this.x,this.y,s),t.stroke(),t.clip(),this._drawImageAtPosition(t),t.restore(),this.boundingBox.top=this.y-this.options.radius,this.boundingBox.left=this.x-this.options.radius,this.boundingBox.right=this.x+this.options.radius,this.boundingBox.bottom=this.y+this.options.radius,this._drawImageLabel(t),this.boundingBox.left=Math.min(this.boundingBox.left,this.labelDimensions.left),this.boundingBox.right=Math.max(this.boundingBox.right,this.labelDimensions.left+this.labelDimensions.width),this.boundingBox.bottom=Math.max(this.boundingBox.bottom,this.boundingBox.bottom+this.labelDimensions.height)},s.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=.5*Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeWidthFactor,this.height+=.5*Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeHeightFactor,this.growthIndicator=this.width-(i.width+2*e)}},s.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=this.options.borderWidth,s=this.options.borderWidthSelected||2*this.options.borderWidth;t.strokeStyle=this.selected?this.options.color.highlight.border:this.hover?this.options.color.hover.border:this.options.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.roundRect(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth,this.options.radius),t.stroke()),t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.fillStyle=this.selected?this.options.color.highlight.background:this.hover?this.options.color.hover.background:this.options.color.background,t.roundRect(this.left,this.top,this.width,this.height,this.options.radius),t.fill(),t.stroke(),this.boundingBox.top=this.top,this.boundingBox.left=this.left,this.boundingBox.right=this.left+this.width,this.boundingBox.bottom=this.top+this.height,this._label(t,this.label,this.x,this.y)},s.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),s=i.width+2*e;this.width=s,this.height=s,this.width+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeWidthFactor,this.height+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeHeightFactor,this.options.radius+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-s}},s.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=this.options.borderWidth,s=this.options.borderWidthSelected||2*this.options.borderWidth; -t.strokeStyle=this.selected?this.options.color.highlight.border:this.hover?this.options.color.hover.border:this.options.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.database(this.x-this.width/2-2*t.lineWidth,this.y-.5*this.height-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.fillStyle=this.selected?this.options.color.highlight.background:this.hover?this.options.color.hover.background:this.options.color.background,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this.boundingBox.top=this.top,this.boundingBox.left=this.left,this.boundingBox.right=this.left+this.width,this.boundingBox.bottom=this.top+this.height,this._label(t,this.label,this.x,this.y)},s.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),s=Math.max(i.width,i.height)+2*e;this.options.radius=s/2,this.width=s,this.height=s,this.options.radius+=.5*Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.options.radius-.5*s}},s.prototype._drawRawCircle=function(t,e,i,s){var o=2.5,n=this.options.borderWidth,r=this.options.borderWidthSelected||2*this.options.borderWidth;t.strokeStyle=this.selected?this.options.color.highlight.border:this.hover?this.options.color.hover.border:this.options.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?r:n)+(this.clusterSize>1?o:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.circle(e,i,s+2*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?r:n)+(this.clusterSize>1?o:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.fillStyle=this.selected?this.options.color.highlight.background:this.hover?this.options.color.hover.background:this.options.color.background,t.circle(this.x,this.y,s),t.fill(),t.stroke()},s.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._drawRawCircle(t,this.x,this.y,this.options.radius),this.boundingBox.top=this.y-this.options.radius,this.boundingBox.left=this.x-this.options.radius,this.boundingBox.right=this.x+this.options.radius,this.boundingBox.bottom=this.y+this.options.radius,this._label(t,this.label,this.x,this.y)},s.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.width1&&(t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.ellipse(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.fillStyle=this.selected?this.options.color.highlight.background:this.hover?this.options.color.hover.background:this.options.color.background,t.ellipse(this.left,this.top,this.width,this.height),t.fill(),t.stroke(),this.boundingBox.top=this.top,this.boundingBox.left=this.left,this.boundingBox.right=this.left+this.width,this.boundingBox.bottom=this.top+this.height,this._label(t,this.label,this.x,this.y)},s.prototype._drawDot=function(t){this._drawShape(t,"circle")},s.prototype._drawTriangle=function(t){this._drawShape(t,"triangle")},s.prototype._drawTriangleDown=function(t){this._drawShape(t,"triangleDown")},s.prototype._drawSquare=function(t){this._drawShape(t,"square")},s.prototype._drawStar=function(t){this._drawShape(t,"star")},s.prototype._resizeShape=function(){if(!this.width){this.options.radius=this.baseRadiusValue;var t=2*this.options.radius;this.width=t,this.height=t,this.width+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeWidthFactor,this.height+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeHeightFactor,this.options.radius+=.5*Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-t}},s.prototype._drawShape=function(t,e){this._resizeShape(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var i=2.5,s=this.options.borderWidth,o=this.options.borderWidthSelected||2*this.options.borderWidth,n=2;switch(e){case"dot":n=2;break;case"square":n=2;break;case"triangle":n=3;break;case"triangleDown":n=3;break;case"star":n=4}t.strokeStyle=this.selected?this.options.color.highlight.border:this.hover?this.options.color.hover.border:this.options.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?o:s)+(this.clusterSize>1?i:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t[e](this.x,this.y,this.options.radius+n*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?o:s)+(this.clusterSize>1?i:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.fillStyle=this.selected?this.options.color.highlight.background:this.hover?this.options.color.hover.background:this.options.color.background,t[e](this.x,this.y,this.options.radius),t.fill(),t.stroke(),this.boundingBox.top=this.y-this.options.radius,this.boundingBox.left=this.x-this.options.radius,this.boundingBox.right=this.x+this.options.radius,this.boundingBox.bottom=this.y+this.options.radius,this.label&&(this._label(t,this.label,this.x,this.y+this.height/2,void 0,"hanging",!0),this.boundingBox.left=Math.min(this.boundingBox.left,this.labelDimensions.left),this.boundingBox.right=Math.max(this.boundingBox.right,this.labelDimensions.left+this.labelDimensions.width),this.boundingBox.bottom=Math.max(this.boundingBox.bottom,this.boundingBox.bottom+this.labelDimensions.height))},s.prototype._resizeText=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeWidthFactor,this.height+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeHeightFactor,this.options.radius+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-(i.width+2*e)}},s.prototype._drawText=function(t){this._resizeText(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._label(t,this.label,this.x,this.y),this.boundingBox.top=this.top,this.boundingBox.left=this.left,this.boundingBox.right=this.left+this.width,this.boundingBox.bottom=this.top+this.height},s.prototype._label=function(t,e,i,s,o,n,r){if(e&&Number(this.options.fontSize)*this.networkScale>this.fontDrawThreshold){t.font=(this.selected?"bold ":"")+this.options.fontSize+"px "+this.options.fontFace;var a=e.split("\n"),h=a.length,d=Number(this.options.fontSize),l=s+(1-h)/2*d;1==r&&(l=s+(1-h)/(2*d));for(var c=t.measureText(a[0]).width,p=1;h>p;p++){var u=t.measureText(a[p]).width;c=u>c?u:c}var m=this.options.fontSize*h,f=i-c/2,g=s-m/2;"hanging"==n&&(g+=.5*d,g+=4,l+=4),this.labelDimensions={top:g,left:f,width:c,height:m,yLine:l},void 0!==this.options.fontFill&&null!==this.options.fontFill&&"none"!==this.options.fontFill&&(t.fillStyle=this.options.fontFill,t.fillRect(f,g,c,m)),t.fillStyle=this.options.fontColor||"black",t.textAlign=o||"center",t.textBaseline=n||"middle",this.options.fontStrokeWidth>0&&(t.lineWidth=this.options.fontStrokeWidth,t.strokeStyle=this.options.fontStrokeColor,t.lineJoin="round");for(var p=0;h>p;p++)this.options.fontStrokeWidth&&t.strokeText(a[p],i,l),t.fillText(a[p],i,l),l+=d}},s.prototype.getTextSize=function(t){if(void 0!==this.label){t.font=(this.selected?"bold ":"")+this.options.fontSize+"px "+this.options.fontFace;for(var e=this.label.split("\n"),i=(Number(this.options.fontSize)+4)*e.length,s=0,o=0,n=e.length;n>o;o++)s=Math.max(s,t.measureText(e[o]).width);return{width:s,height:i,lineCount:e.length}}return{width:0,height:0,lineCount:0}},s.prototype.inArea=function(){return void 0!==this.width?this.x+this.width*this.networkScaleInv>=this.canvasTopLeft.x&&this.x-this.width*this.networkScaleInv=this.canvasTopLeft.y&&this.y-this.height*this.networkScaleInv=this.canvasTopLeft.x&&this.x=this.canvasTopLeft.y&&this.ys&&(n=s-e-this.padding),no&&(r=o-i-this.padding),ri;i++)if(e.id===r.nodes[i].id){o=r.nodes[i];break}for(o||(o={id:e.id},t.node&&(o.attr=a(o.attr,t.node))),i=n.length-1;i>=0;i--){var h=n[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(o)&&h.nodes.push(o)}e.attr&&(o.attr=a(o.attr,e.attr))}function l(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=a({},t.edge);e.attr=a(i,e.attr)}}function c(t,e,i,s,o){var n={from:e,to:i,type:s};return t.edge&&(n.attr=a({},t.edge)),n.attr=a(n.attr||{},o),n}function p(){for(N=D.NULL,k="";" "==E||" "==E||"\n"==E||"\r"==E;)o();do{var t=!1;if("#"==E){for(var e=O-1;" "==T.charAt(e)||" "==T.charAt(e);)e--;if("\n"==T.charAt(e)||""==T.charAt(e)){for(;""!=E&&"\n"!=E;)o();t=!0}}if("/"==E&&"/"==n()){for(;""!=E&&"\n"!=E;)o();t=!0}if("/"==E&&"*"==n()){for(;""!=E;){if("*"==E&&"/"==n()){o(),o();break}o()}t=!0}for(;" "==E||" "==E||"\n"==E||"\r"==E;)o()}while(t);if(""==E)return void(N=D.DELIMITER);var i=E+n();if(C[i])return N=D.DELIMITER,k=i,o(),void o();if(C[E])return N=D.DELIMITER,k=E,void o();if(r(E)||"-"==E){for(k+=E,o();r(E);)k+=E,o();return"false"==k?k=!1:"true"==k?k=!0:isNaN(Number(k))||(k=Number(k)),void(N=D.IDENTIFIER)}if('"'==E){for(o();""!=E&&('"'!=E||'"'==E&&'"'==n());)k+=E,'"'==E&&o(),o();if('"'!=E)throw x('End of string " expected');return o(),void(N=D.IDENTIFIER)}for(N=D.UNKNOWN;""!=E;)k+=E,o();throw new SyntaxError('Syntax error in part "'+w(k,30)+'"')}function u(){var t={};if(s(),p(),"strict"==k&&(t.strict=!0,p()),("graph"==k||"digraph"==k)&&(t.type=k,p()),N==D.IDENTIFIER&&(t.id=k,p()),"{"!=k)throw x("Angle bracket { expected");if(p(),m(t),"}"!=k)throw x("Angle bracket } expected");if(p(),""!==k)throw x("End of file expected");return p(),delete t.node,delete t.edge,delete t.graph,t}function m(t){for(;""!==k&&"}"!=k;)f(t),";"==k&&p()}function f(t){var e=g(t);if(e)return void b(t,e);var i=v(t);if(!i){if(N!=D.IDENTIFIER)throw x("Identifier expected");var s=k;if(p(),"="==k){if(p(),N!=D.IDENTIFIER)throw x("Identifier expected");t[s]=k,p()}else y(t,s)}}function g(t){var e=null;if("subgraph"==k&&(e={},e.type="subgraph",p(),N==D.IDENTIFIER&&(e.id=k,p())),"{"==k){if(p(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,m(e),"}"!=k)throw x("Angle bracket } expected");p(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function v(t){return"node"==k?(p(),t.node=_(),"node"):"edge"==k?(p(),t.edge=_(),"edge"):"graph"==k?(p(),t.graph=_(),"graph"):null}function y(t,e){var i={id:e},s=_();s&&(i.attr=s),d(t,i),b(t,e)}function b(t,e){for(;"->"==k||"--"==k;){var i,s=k;p();var o=g(t);if(o)i=o;else{if(N!=D.IDENTIFIER)throw x("Identifier or subgraph expected");i=k,d(t,{id:i}),p()}var n=_(),r=c(t,e,i,s,n);l(t,r),e=i}}function _(){for(var t=null;"["==k;){for(p(),t={};""!==k&&"]"!=k;){if(N!=D.IDENTIFIER)throw x("Attribute name expected");var e=k;if(p(),"="!=k)throw x("Equal sign = expected");if(p(),N!=D.IDENTIFIER)throw x("Attribute value expected");var i=k;h(t,e,i),p(),","==k&&p()}if("]"!=k)throw x("Bracket ] expected");p()}return t}function x(t){return new SyntaxError(t+', got "'+w(k,30)+'" (char '+O+")")}function w(t,e){return t.length<=e?t:t.substr(0,27)+"..."}function S(t,e,i){Array.isArray(t)?t.forEach(function(t){Array.isArray(e)?e.forEach(function(e){i(t,e)}):i(t,e)}):Array.isArray(e)?e.forEach(function(e){i(t,e)}):i(t,e)}function M(t){var e=i(t),s={nodes:[],edges:[],options:{}};if(e.nodes&&e.nodes.forEach(function(t){var e={id:t.id,label:String(t.label||t.id)};a(e,t.attr),e.image&&(e.shape="image"),s.nodes.push(e)}),e.edges){var o=function(t){var e={from:t.from,to:t.to};return a(e,t.attr),e.style="->"==t.type?"arrow":"line",e};e.edges.forEach(function(t){var e,i;e=t.from instanceof Object?t.from.nodes:{id:t.from},i=t.to instanceof Object?t.to.nodes:{id:t.to},t.from instanceof Object&&t.from.edges&&t.from.edges.forEach(function(t){var e=o(t);s.edges.push(e)}),S(e,i,function(e,i){var n=c(s,e.id,i.id,t.type,t.attr),r=o(n);s.edges.push(r)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=o(t);s.edges.push(e)})})}return e.attr&&(s.options=e.attr),s}var D={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},C={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},T="",O=0,E="",k="",N=D.NULL,I=/[a-zA-Z_0-9.:#]/;e.parseDOT=i,e.DOTToGraph=M},function(t,e){function i(t,e){var i=[],s=[];this.options={edges:{inheritColor:!0},nodes:{allowedToMove:!1,parseColor:!1}},void 0!==e&&(this.options.nodes.allowedToMove=e.allowedToMove|!1,this.options.nodes.parseColor=e.parseColor|!1,this.options.edges.inheritColor=e.inheritColor|!0);for(var o=t.edges,n=t.nodes,r=0;r=s&&(s=864e5),e=new Date(e.valueOf()-.05*s),i=new Date(i.valueOf()+.05*s)}return{start:e,end:i}},s.prototype.setWindow=function(t,e,i){var s=i&&void 0!==i.animate?i.animate:!0;if(1==arguments.length){var o=arguments[0];this.range.setRange(o.start,o.end,s)}else this.range.setRange(t,e,s)},s.prototype.moveTo=function(t,e){var i=this.range.end-this.range.start,s=r.convert(t,"Date").valueOf(),o=s-i/2,n=s+i/2,a=e&&void 0!==e.animate?e.animate:!0;this.range.setRange(o,n,a)},s.prototype.getWindow=function(){var t=this.range.getRange();return{start:new Date(t.start),end:new Date(t.end)}},s.prototype.redraw=function(){var t=!1,e=this.options,i=this.props,s=this.dom;if(s){h.updateHiddenDates(this.body,this.options.hiddenDates),"top"==e.orientation?(r.addClassName(s.root,"top"),r.removeClassName(s.root,"bottom")):(r.removeClassName(s.root,"top"),r.addClassName(s.root,"bottom")),s.root.style.maxHeight=r.option.asSize(e.maxHeight,""),s.root.style.minHeight=r.option.asSize(e.minHeight,""),s.root.style.width=r.option.asSize(e.width,""),i.border.left=(s.centerContainer.offsetWidth-s.centerContainer.clientWidth)/2,i.border.right=i.border.left,i.border.top=(s.centerContainer.offsetHeight-s.centerContainer.clientHeight)/2,i.border.bottom=i.border.top;var o=s.root.offsetHeight-s.root.clientHeight,n=s.root.offsetWidth-s.root.clientWidth;0===s.centerContainer.clientHeight&&(i.border.left=i.border.top,i.border.right=i.border.left),0===s.root.clientHeight&&(n=o),i.center.height=s.center.offsetHeight,i.left.height=s.left.offsetHeight,i.right.height=s.right.offsetHeight,i.top.height=s.top.clientHeight||-i.border.top,i.bottom.height=s.bottom.clientHeight||-i.border.bottom;var a=Math.max(i.left.height,i.center.height,i.right.height),d=i.top.height+a+i.bottom.height+o+i.border.top+i.border.bottom;s.root.style.height=r.option.asSize(e.height,d+"px"),i.root.height=s.root.offsetHeight,i.background.height=i.root.height-o;var l=i.root.height-i.top.height-i.bottom.height-o;i.centerContainer.height=l,i.leftContainer.height=l,i.rightContainer.height=i.leftContainer.height,i.root.width=s.root.offsetWidth,i.background.width=i.root.width-n,i.left.width=s.leftContainer.clientWidth||-i.border.left,i.leftContainer.width=i.left.width,i.right.width=s.rightContainer.clientWidth||-i.border.right,i.rightContainer.width=i.right.width;var c=i.root.width-i.left.width-i.right.width-n;i.center.width=c,i.centerContainer.width=c,i.top.width=c,i.bottom.width=c,s.background.style.height=i.background.height+"px",s.backgroundVertical.style.height=i.background.height+"px",s.backgroundHorizontal.style.height=i.centerContainer.height+"px",s.centerContainer.style.height=i.centerContainer.height+"px",s.leftContainer.style.height=i.leftContainer.height+"px",s.rightContainer.style.height=i.rightContainer.height+"px",s.background.style.width=i.background.width+"px",s.backgroundVertical.style.width=i.centerContainer.width+"px",s.backgroundHorizontal.style.width=i.background.width+"px",s.centerContainer.style.width=i.center.width+"px",s.top.style.width=i.top.width+"px",s.bottom.style.width=i.bottom.width+"px",s.background.style.left="0",s.background.style.top="0",s.backgroundVertical.style.left=i.left.width+i.border.left+"px",s.backgroundVertical.style.top="0",s.backgroundHorizontal.style.left="0",s.backgroundHorizontal.style.top=i.top.height+"px",s.centerContainer.style.left=i.left.width+"px",s.centerContainer.style.top=i.top.height+"px",s.leftContainer.style.left="0",s.leftContainer.style.top=i.top.height+"px",s.rightContainer.style.left=i.left.width+i.center.width+"px",s.rightContainer.style.top=i.top.height+"px",s.top.style.left=i.left.width+"px",s.top.style.top="0",s.bottom.style.left=i.left.width+"px",s.bottom.style.top=i.top.height+i.centerContainer.height+"px",this._updateScrollTop();var p=this.props.scrollTop;"bottom"==e.orientation&&(p+=Math.max(this.props.centerContainer.height-this.props.center.height-this.props.border.top-this.props.border.bottom,0)),s.center.style.left="0",s.center.style.top=p+"px",s.left.style.left="0",s.left.style.top=p+"px",s.right.style.left="0",s.right.style.top=p+"px";var u=0==this.props.scrollTop?"hidden":"",m=this.props.scrollTop==this.props.scrollTopMin?"hidden":"";if(s.shadowTop.style.visibility=u,s.shadowBottom.style.visibility=m,s.shadowTopLeft.style.visibility=u,s.shadowBottomLeft.style.visibility=m,s.shadowTopRight.style.visibility=u,s.shadowBottomRight.style.visibility=m,this.components.forEach(function(e){t=e.redraw()||t}),t){var f=3;this.redrawCount0&&(this.props.scrollTop=0),this.props.scrollTops;s++){var o=s%2===0?1.3*i:.5*i;this.lineTo(t+o*Math.sin(2*s*Math.PI/10),e-o*Math.cos(2*s*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,s,o){var n=Math.PI/180;0>i-2*o&&(o=i/2),0>s-2*o&&(o=s/2),this.beginPath(),this.moveTo(t+o,e),this.lineTo(t+i-o,e),this.arc(t+i-o,e+o,o,270*n,360*n,!1),this.lineTo(t+i,e+s-o),this.arc(t+i-o,e+s-o,o,0,90*n,!1),this.lineTo(t+o,e+s),this.arc(t+o,e+s-o,o,90*n,180*n,!1),this.lineTo(t,e+o),this.arc(t+o,e+o,o,180*n,270*n,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,s){var o=.5522848,n=i/2*o,r=s/2*o,a=t+i,h=e+s,d=t+i/2,l=e+s/2;this.beginPath(),this.moveTo(t,l),this.bezierCurveTo(t,l-r,d-n,e,d,e),this.bezierCurveTo(d+n,e,a,l-r,a,l),this.bezierCurveTo(a,l+r,d+n,h,d,h),this.bezierCurveTo(d-n,h,t,l+r,t,l)},CanvasRenderingContext2D.prototype.database=function(t,e,i,s){var o=1/3,n=i,r=s*o,a=.5522848,h=n/2*a,d=r/2*a,l=t+n,c=e+r,p=t+n/2,u=e+r/2,m=e+(s-r/2),f=e+s;this.beginPath(),this.moveTo(l,u),this.bezierCurveTo(l,u+d,p+h,c,p,c),this.bezierCurveTo(p-h,c,t,u+d,t,u),this.bezierCurveTo(t,u-d,p-h,e,p,e),this.bezierCurveTo(p+h,e,l,u-d,l,u),this.lineTo(l,m),this.bezierCurveTo(l,m+d,p+h,f,p,f),this.bezierCurveTo(p-h,f,t,m+d,t,m),this.lineTo(t,u)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,s){var o=t-s*Math.cos(i),n=e-s*Math.sin(i),r=t-.9*s*Math.cos(i),a=e-.9*s*Math.sin(i),h=o+s/3*Math.cos(i+.5*Math.PI),d=n+s/3*Math.sin(i+.5*Math.PI),l=o+s/3*Math.cos(i-.5*Math.PI),c=n+s/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,d),this.lineTo(r,a),this.lineTo(l,c),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,s,o){o||(o=[10,5]),0==p&&(p=.001);var n=o.length;this.moveTo(t,e);for(var r=i-t,a=s-e,h=a/r,d=Math.sqrt(r*r+a*a),l=0,c=!0;d>=.1;){var p=o[l++%n];p>d&&(p=d);var u=Math.sqrt(p*p/(1+h*h));0>r&&(u=-u),t+=u,e+=h*u,this[c?"lineTo":"moveTo"](t,e),d-=p,c=!c}})},function(t,e,i){function s(t,e){this.groupId=t,this.options=e}var o=i(2),n=i(53);s.prototype.getYRange=function(t){for(var e=t[0].y,i=t[0].y,s=0;st[s].y?t[s].y:e,i=i0){var r,a,h=Number(i.svg.style.height.replace("px",""));if(r=o.getSVGElement("path",i.svgElements,i.svg),r.setAttributeNS(null,"class",e.className),void 0!==e.style&&r.setAttributeNS(null,"style",e.style),a=1==e.options.catmullRom.enabled?s._catmullRom(t,e):s._linear(t),1==e.options.shaded.enabled){var d,l=o.getSVGElement("path",i.svgElements,i.svg);d="top"==e.options.shaded.orientation?"M"+t[0].x+",0 "+a+"L"+t[t.length-1].x+",0":"M"+t[0].x+","+h+" "+a+"L"+t[t.length-1].x+","+h,l.setAttributeNS(null,"class",e.className+" fill"),void 0!==e.options.shaded.style&&l.setAttributeNS(null,"style",e.options.shaded.style),l.setAttributeNS(null,"d",d)}r.setAttributeNS(null,"d","M"+a),1==e.options.drawPoints.enabled&&n.draw(t,e,i)}},s._catmullRomUniform=function(t){for(var e,i,s,o,n,r,a=Math.round(t[0].x)+","+Math.round(t[0].y)+" ",h=1/6,d=t.length,l=0;d-1>l;l++)e=0==l?t[0]:t[l-1],i=t[l],s=t[l+1],o=d>l+2?t[l+2]:s,n={x:(-e.x+6*i.x+s.x)*h,y:(-e.y+6*i.y+s.y)*h},r={x:(i.x+6*s.x-o.x)*h,y:(i.y+6*s.y-o.y)*h},a+="C"+n.x+","+n.y+" "+r.x+","+r.y+" "+s.x+","+s.y+" ";return a},s._catmullRom=function(t,e){var i=e.options.catmullRom.alpha;if(0==i||void 0===i)return this._catmullRomUniform(t);for(var s,o,n,r,a,h,d,l,c,p,u,m,f,g,v,y,b,_,x,w=Math.round(t[0].x)+","+Math.round(t[0].y)+" ",S=t.length,M=0;S-1>M;M++)s=0==M?t[0]:t[M-1],o=t[M],n=t[M+1],r=S>M+2?t[M+2]:n,d=Math.sqrt(Math.pow(s.x-o.x,2)+Math.pow(s.y-o.y,2)),l=Math.sqrt(Math.pow(o.x-n.x,2)+Math.pow(o.y-n.y,2)),c=Math.sqrt(Math.pow(n.x-r.x,2)+Math.pow(n.y-r.y,2)),g=Math.pow(c,i),y=Math.pow(c,2*i),v=Math.pow(l,i),b=Math.pow(l,2*i),x=Math.pow(d,i),_=Math.pow(d,2*i),p=2*_+3*x*v+b,u=2*y+3*g*v+b,m=3*x*(x+v),m>0&&(m=1/m),f=3*g*(g+v),f>0&&(f=1/f),a={x:(-b*s.x+p*o.x+_*n.x)*m,y:(-b*s.y+p*o.y+_*n.y)*m},h={x:(y*o.x+u*n.x-b*r.x)*f,y:(y*o.y+u*n.y-b*r.y)*f},0==a.x&&0==a.y&&(a=o),0==h.x&&0==h.y&&(h=n),w+="C"+a.x+","+a.y+" "+h.x+","+h.y+" "+n.x+","+n.y+" ";return w},s._linear=function(t){for(var e="",i=0;it[s].y?t[s].y:e,i=i0&&(n=Math.min(n,Math.abs(c[d-1].x-r))),a=s._getSafeDrawData(n,h,m);else{var g=d+(p[r].amount-p[r].resolved),v=d-(p[r].resolved+1);g0&&(n=Math.min(n,Math.abs(c[v].x-r))),a=s._getSafeDrawData(n,h,m),p[r].resolved+=1,"stack"==h.options.barChart.handleOverlap?(f=p[r].accumulated,p[r].accumulated+=h.zeroPosition-c[d].y):"sideBySide"==h.options.barChart.handleOverlap&&(a.width=a.width/p[r].amount,a.offset+=p[r].resolved*a.width-.5*a.width*(p[r].amount+1),"left"==h.options.barChart.align?a.offset-=.5*a.width:"right"==h.options.barChart.align&&(a.offset+=.5*a.width))}o.drawBar(c[d].x+a.offset,c[d].y-f,a.width,h.zeroPosition-c[d].y,h.className+" bar",i.svgElements,i.svg),1==h.options.drawPoints.enabled&&o.drawPoint(c[d].x+a.offset,c[d].y,h,i.svgElements,i.svg)}},s._getDataIntersections=function(t,e){for(var i,s=0;s0&&(i=Math.min(i,Math.abs(e[s-1].x-e[s].x))),0==i&&(void 0===t[e[s].x]&&(t[e[s].x]={amount:0,resolved:0,accumulated:0}),t[e[s].x].amount+=1)},s._getSafeDrawData=function(t,e,i){var s,o;return t0?(s=i>t?i:t,o=0,"left"==e.options.barChart.align?o-=.5*t:"right"==e.options.barChart.align&&(o+=.5*t)):(s=e.options.barChart.width,o=0,"left"==e.options.barChart.align?o-=.5*e.options.barChart.width:"right"==e.options.barChart.align&&(o+=.5*e.options.barChart.width)),{width:s,offset:o}},s.getStackedBarYRange=function(t,e,i,o,n){if(t.length>0){t.sort(function(t,e){return t.x==e.x?t.groupId-e.groupId:t.x-e.x});var r={};s._getDataIntersections(r,t),e[o]=s._getStackedBarYRange(r,t),e[o].yAxisOrientation=n,i.push(o)}},s._getStackedBarYRange=function(t,e){for(var i,s=e[0].y,o=e[0].y,n=0;ne[n].y?e[n].y:s,o=ot[r].accumulated?t[r].accumulated:s,o=ot[s].y?t[s].y:e,i=is;++s)i[s].apply(this,e)}return this},e.prototype.listeners=function(t){return this._callbacks=this._callbacks||{},this._callbacks[t]||[]},e.prototype.hasListeners=function(t){return!!this.listeners(t).length}},function(t,e){var i,s,o;!function(n,r){s=[],i=r,o="function"==typeof i?i.apply(e,s):i,!(void 0!==o&&(t.exports=o))}(this,function(){function t(t){var e,i=t&&t.preventDefault||!1,s=t&&t.container||window,o={},n={keydown:{},keyup:{}},r={};for(e=97;122>=e;e++)r[String.fromCharCode(e)]={code:65+(e-97),shift:!1};for(e=65;90>=e;e++)r[String.fromCharCode(e)]={code:e,shift:!0};for(e=0;9>=e;e++)r[""+e]={code:48+e,shift:!1};for(e=1;12>=e;e++)r["F"+e]={code:111+e,shift:!1};for(e=0;9>=e;e++)r["num"+e]={code:96+e,shift:!1};r["num*"]={code:106,shift:!1},r["num+"]={code:107,shift:!1},r["num-"]={code:109,shift:!1},r["num/"]={code:111,shift:!1},r["num."]={code:110,shift:!1},r.left={code:37,shift:!1},r.up={code:38,shift:!1},r.right={code:39,shift:!1},r.down={code:40,shift:!1},r.space={code:32,shift:!1},r.enter={code:13,shift:!1},r.shift={code:16,shift:void 0},r.esc={code:27,shift:!1},r.backspace={code:8,shift:!1},r.tab={code:9,shift:!1},r.ctrl={code:17,shift:!1},r.alt={code:18,shift:!1},r["delete"]={code:46,shift:!1},r.pageup={code:33,shift:!1},r.pagedown={code:34,shift:!1},r["="]={code:187,shift:!1},r["-"]={code:189,shift:!1},r["]"]={code:221,shift:!1},r["["]={code:219,shift:!1};var a=function(t){d(t,"keydown")},h=function(t){d(t,"keyup")},d=function(t,e){if(void 0!==n[e][t.keyCode]){for(var s=n[e][t.keyCode],o=0;oe-n?(i=t.clone().add(o-1,"months"),s=(e-n)/(n-i)):(i=t.clone().add(o+1,"months"),s=(e-n)/(i-n)),-(o+s)}function f(t,e,i){var s;return null==i?e:null!=t.meridiemHour?t.meridiemHour(e,i):null!=t.isPM?(s=t.isPM(i),s&&12>e&&(e+=12),s||12!==e||(e=0),e):e}function g(){}function v(t,e){e!==!1&&F(t),_(this,t),this._d=new Date(+t._d),Di===!1&&(Di=!0,Ce.updateOffset(this),Di=!1)}function y(t){var e=N(t),i=e.year||0,s=e.quarter||0,o=e.month||0,n=e.week||0,r=e.day||0,a=e.hour||0,h=e.minute||0,d=e.second||0,l=e.millisecond||0;this._milliseconds=+l+1e3*d+6e4*h+36e5*a,this._days=+r+7*n,this._months=+o+3*s+12*i,this._data={},this._locale=Ce.localeData(),this._bubble()}function b(t,e){for(var i in e)a(e,i)&&(t[i]=e[i]);return a(e,"toString")&&(t.toString=e.toString),a(e,"valueOf")&&(t.valueOf=e.valueOf),t}function _(t,e){var i,s,o;if("undefined"!=typeof e._isAMomentObject&&(t._isAMomentObject=e._isAMomentObject),"undefined"!=typeof e._i&&(t._i=e._i),"undefined"!=typeof e._f&&(t._f=e._f),"undefined"!=typeof e._l&&(t._l=e._l),"undefined"!=typeof e._strict&&(t._strict=e._strict),"undefined"!=typeof e._tzm&&(t._tzm=e._tzm),"undefined"!=typeof e._isUTC&&(t._isUTC=e._isUTC),"undefined"!=typeof e._offset&&(t._offset=e._offset),"undefined"!=typeof e._pf&&(t._pf=e._pf),"undefined"!=typeof e._locale&&(t._locale=e._locale),Ye.length>0)for(i in Ye)s=Ye[i],o=e[s],"undefined"!=typeof o&&(t[s]=o);return t}function x(t){return 0>t?Math.ceil(t):Math.floor(t)}function w(t,e,i){for(var s=""+Math.abs(t),o=t>=0;s.lengths;s++)(i&&t[s]!==e[s]||!i&&L(t[s])!==L(e[s]))&&r++;return r+n}function k(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=gi[t]||vi[e]||e}return t}function N(t){var e,i,s={};for(i in t)a(t,i)&&(e=k(i),e&&(s[e]=t[i]));return s}function I(t){var e,i;if(0===t.indexOf("week"))e=7,i="day";else{if(0!==t.indexOf("month"))return;e=12,i="month"}Ce[t]=function(s,o){var r,a,h=Ce._locale[t],d=[];if("number"==typeof s&&(o=s,s=n),a=function(t){var e=Ce().utc().set(i,t);return h.call(Ce._locale,e,s||"")},null!=o)return a(o);for(r=0;e>r;r++)d.push(a(r));return d}}function L(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=e>=0?Math.floor(e):Math.ceil(e)),i}function z(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function A(t,e,i){return me(Ce([t,11,31+e-i]),e,i).week}function P(t){return R(t)?366:365}function R(t){return t%4===0&&t%100!==0||t%400===0}function F(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[ze]<0||t._a[ze]>11?ze:t._a[Ae]<1||t._a[Ae]>z(t._a[Le],t._a[ze])?Ae:t._a[Pe]<0||t._a[Pe]>24||24===t._a[Pe]&&(0!==t._a[Re]||0!==t._a[Fe]||0!==t._a[He])?Pe:t._a[Re]<0||t._a[Re]>59?Re:t._a[Fe]<0||t._a[Fe]>59?Fe:t._a[He]<0||t._a[He]>999?He:-1,t._pf._overflowDayOfYear&&(Le>e||e>Ae)&&(e=Ae),t._pf.overflow=e)}function H(t){return null==t._isValid&&(t._isValid=!isNaN(t._d.getTime())&&t._pf.overflow<0&&!t._pf.empty&&!t._pf.invalidMonth&&!t._pf.nullInput&&!t._pf.invalidFormat&&!t._pf.userInvalidated,t._strict&&(t._isValid=t._isValid&&0===t._pf.charsLeftOver&&0===t._pf.unusedTokens.length&&t._pf.bigHour===n)),t._isValid}function B(t){return t?t.toLowerCase().replace("_","-"):t}function Y(t){for(var e,i,s,o,n=0;n0;){if(s=W(o.slice(0,e).join("-")))return s;if(i&&i.length>=e&&E(o,i,!0)>=e-1)break;e--}n++}return null}function W(t){var e=null;if(!Be[t]&&We)try{e=Ce.locale(),!function(){var t=new Error('Cannot find module "./locale"');throw t.code="MODULE_NOT_FOUND",t}(),Ce.locale(e)}catch(i){}return Be[t]}function G(t,e){var i,s;return e._isUTC?(i=e.clone(),s=(Ce.isMoment(t)||O(t)?+t:+Ce(t))-+i,i._d.setTime(+i._d+s),Ce.updateOffset(i,!1),i):Ce(t).local()}function j(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function U(t){var e,i,s=t.match(Ve);for(e=0,i=s.length;i>e;e++)s[e]=wi[s[e]]?wi[s[e]]:j(s[e]);return function(o){var n="";for(e=0;i>e;e++)n+=s[e]instanceof Function?s[e].call(o,t):s[e];return n}}function V(t,e){return t.isValid()?(e=X(e,t.localeData()),yi[e]||(yi[e]=U(e)),yi[e](t)):t.localeData().invalidDate()}function X(t,e){function i(t){return e.longDateFormat(t)||t}var s=5;for(Xe.lastIndex=0;s>=0&&Xe.test(t);)t=t.replace(Xe,i),Xe.lastIndex=0,s-=1;return t}function q(t,e){var i,s=e._strict;switch(t){case"Q":return oi;case"DDDD":return ri;case"YYYY":case"GGGG":case"gggg":return s?ai:Qe;case"Y":case"G":case"g":return di;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return s?hi:Ke;case"S":if(s)return oi;case"SS":if(s)return ni;case"SSS":if(s)return ri;case"DDD":return Ze;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Je;case"a":case"A":return e._locale._meridiemParse;case"x":return ii;case"X":return si;case"Z":case"ZZ":return ti;case"T":return ei;case"SSSS":return $e;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return s?ni:qe;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return qe;case"Do":return s?e._locale._ordinalParse:e._locale._ordinalParseLenient;default:return i=new RegExp(se(ie(t.replace("\\","")),"i"))}}function Z(t){t=t||"";var e=t.match(ti)||[],i=e[e.length-1]||[],s=(i+"").match(mi)||["-",0,0],o=+(60*s[1])+L(s[2]);return"+"===s[0]?o:-o}function Q(t,e,i){var s,o=i._a;switch(t){case"Q":null!=e&&(o[ze]=3*(L(e)-1));break;case"M":case"MM":null!=e&&(o[ze]=L(e)-1);break;case"MMM":case"MMMM":s=i._locale.monthsParse(e,t,i._strict),null!=s?o[ze]=s:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(o[Ae]=L(e));break;case"Do":null!=e&&(o[Ae]=L(parseInt(e.match(/\d{1,2}/)[0],10)));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=L(e));break;case"YY":o[Le]=Ce.parseTwoDigitYear(e);break;case"YYYY":case"YYYYY":case"YYYYYY":o[Le]=L(e);break;case"a":case"A":i._meridiem=e;break;case"h":case"hh":i._pf.bigHour=!0;case"H":case"HH":o[Pe]=L(e);break;case"m":case"mm":o[Re]=L(e);break;case"s":case"ss":o[Fe]=L(e);break;case"S":case"SS":case"SSS":case"SSSS":o[He]=L(1e3*("0."+e));break;case"x":i._d=new Date(L(e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=Z(e);break;case"dd":case"ddd":case"dddd":s=i._locale.weekdaysParse(e),null!=s?(i._w=i._w||{},i._w.d=s):i._pf.invalidWeekday=e;break;case"w":case"ww":case"W":case"WW":case"d":case"e":case"E":t=t.substr(0,1);case"gggg":case"GGGG":case"GGGGG":t=t.substr(0,2),e&&(i._w=i._w||{},i._w[t]=L(e));break;case"gg":case"GG":i._w=i._w||{},i._w[t]=Ce.parseTwoDigitYear(e)}}function K(t){var e,i,s,o,n,a,h;e=t._w,null!=e.GG||null!=e.W||null!=e.E?(n=1,a=4,i=r(e.GG,t._a[Le],me(Ce(),1,4).year),s=r(e.W,1),o=r(e.E,1)):(n=t._locale._week.dow,a=t._locale._week.doy,i=r(e.gg,t._a[Le],me(Ce(),n,a).year),s=r(e.w,1),null!=e.d?(o=e.d,n>o&&++s):o=null!=e.e?e.e+n:n),h=fe(i,s,o,a,n),t._a[Le]=h.year,t._dayOfYear=h.dayOfYear}function $(t){var e,i,s,o,n=[];if(!t._d){for(s=te(t),t._w&&null==t._a[Ae]&&null==t._a[ze]&&K(t),t._dayOfYear&&(o=r(t._a[Le],s[Le]),t._dayOfYear>P(o)&&(t._pf._overflowDayOfYear=!0),i=le(o,0,t._dayOfYear),t._a[ze]=i.getUTCMonth(),t._a[Ae]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=n[e]=s[e];for(;7>e;e++)t._a[e]=n[e]=null==t._a[e]?2===e?1:0:t._a[e];24===t._a[Pe]&&0===t._a[Re]&&0===t._a[Fe]&&0===t._a[He]&&(t._nextDay=!0,t._a[Pe]=0),t._d=(t._useUTC?le:de).apply(null,n),null!=t._tzm&&t._d.setUTCMinutes(t._d.getUTCMinutes()-t._tzm),t._nextDay&&(t._a[Pe]=24)}}function J(t){var e;t._d||(e=N(t._i),t._a=[e.year,e.month,e.day||e.date,e.hour,e.minute,e.second,e.millisecond],$(t))}function te(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function ee(t){if(t._f===Ce.ISO_8601)return void ne(t);t._a=[],t._pf.empty=!0;var e,i,s,o,r,a=""+t._i,h=a.length,d=0;for(s=X(t._f,t._locale).match(Ve)||[],e=0;e0&&t._pf.unusedInput.push(r),a=a.slice(a.indexOf(i)+i.length),d+=i.length),wi[o]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(o),Q(o,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(o);t._pf.charsLeftOver=h-d,a.length>0&&t._pf.unusedInput.push(a),t._pf.bigHour===!0&&t._a[Pe]<=12&&(t._pf.bigHour=n),t._a[Pe]=f(t._locale,t._a[Pe],t._meridiem),$(t),F(t)}function ie(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,s,o){return e||i||s||o})}function se(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function oe(t){var e,i,s,o,n;if(0===t._f.length)return t._pf.invalidFormat=!0,void(t._d=new Date(0/0));for(o=0;on)&&(s=n,i=e));b(t,i||e)}function ne(t){var e,i,s=t._i,o=li.exec(s);if(o){for(t._pf.iso=!0,e=0,i=pi.length;i>e;e++)if(pi[e][1].exec(s)){t._f=pi[e][0]+(o[6]||" ");break}for(e=0,i=ui.length;i>e;e++)if(ui[e][1].exec(s)){t._f+=ui[e][0];break}s.match(ti)&&(t._f+="Z"),ee(t)}else t._isValid=!1}function re(t){ne(t),t._isValid===!1&&(delete t._isValid,Ce.createFromInputFallback(t))}function ae(t,e){var i,s=[];for(i=0;it&&a.setFullYear(t),a}function le(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function ce(t,e){if("string"==typeof t)if(isNaN(t)){if(t=e.weekdaysParse(t),"number"!=typeof t)return null}else t=parseInt(t,10);return t}function pe(t,e,i,s,o){return o.relativeTime(e||1,!!i,t,s)}function ue(t,e,i){var s=Ce.duration(t).abs(),o=Ne(s.as("s")),n=Ne(s.as("m")),r=Ne(s.as("h")),a=Ne(s.as("d")),h=Ne(s.as("M")),d=Ne(s.as("y")),l=o0,l[4]=i,pe.apply({},l)}function me(t,e,i){var s,o=i-e,n=i-t.day();return n>o&&(n-=7),o-7>n&&(n+=7),s=Ce(t).add(n,"d"),{week:Math.ceil(s.dayOfYear()/7),year:s.year()}}function fe(t,e,i,s,o){var n,r,a=le(t,0,1).getUTCDay();return a=0===a?7:a,i=null!=i?i:o,n=o-a+(a>s?7:0)-(o>a?7:0),r=7*(e-1)+(i-o)+n+1,{year:r>0?t:t-1,dayOfYear:r>0?r:P(t-1)+r}}function ge(t){var e,i=t._i,s=t._f;return t._locale=t._locale||Ce.localeData(t._l),null===i||s===n&&""===i?Ce.invalid({nullInput:!0}):("string"==typeof i&&(t._i=i=t._locale.preparse(i)),Ce.isMoment(i)?new v(i,!0):(s?T(s)?oe(t):ee(t):he(t),e=new v(t),e._nextDay&&(e.add(1,"d"),e._nextDay=n),e))}function ve(t,e){var i,s;if(1===e.length&&T(e[0])&&(e=e[0]),!e.length)return Ce();for(i=e[0],s=1;s=0?"+":"-";return e+w(Math.abs(t),6)},gg:function(){return w(this.weekYear()%100,2)},gggg:function(){return w(this.weekYear(),4)},ggggg:function(){return w(this.weekYear(),5)},GG:function(){return w(this.isoWeekYear()%100,2)},GGGG:function(){return w(this.isoWeekYear(),4)},GGGGG:function(){return w(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.localeData().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.localeData().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return L(this.milliseconds()/100)},SS:function(){return w(L(this.milliseconds()/10),2)},SSS:function(){return w(this.milliseconds(),3)},SSSS:function(){return w(this.milliseconds(),3)},Z:function(){var t=this.utcOffset(),e="+";return 0>t&&(t=-t,e="-"),e+w(L(t/60),2)+":"+w(L(t)%60,2)},ZZ:function(){var t=this.utcOffset(),e="+";return 0>t&&(t=-t,e="-"),e+w(L(t/60),2)+w(L(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},x:function(){return this.valueOf()},X:function(){return this.unix()},Q:function(){return this.quarter()}},Si={},Mi=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"],Di=!1;_i.length;)Oe=_i.pop(),wi[Oe+"o"]=u(wi[Oe],Oe);for(;xi.length;)Oe=xi.pop(),wi[Oe+Oe]=p(wi[Oe],2);wi.DDDD=p(wi.DDD,3),b(g.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e;this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t,e,i){var s,o,n;for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),s=0;12>s;s++){if(o=Ce.utc([2e3,s]),i&&!this._longMonthsParse[s]&&(this._longMonthsParse[s]=new RegExp("^"+this.months(o,"").replace(".","")+"$","i"),this._shortMonthsParse[s]=new RegExp("^"+this.monthsShort(o,"").replace(".","")+"$","i")),i||this._monthsParse[s]||(n="^"+this.months(o,"")+"|^"+this.monthsShort(o,""),this._monthsParse[s]=new RegExp(n.replace(".",""),"i")),i&&"MMMM"===e&&this._longMonthsParse[s].test(t))return s;if(i&&"MMM"===e&&this._shortMonthsParse[s].test(t))return s;if(!i&&this._monthsParse[s].test(t))return s}},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},weekdaysParse:function(t){var e,i,s;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=Ce([2e3,1]).day(e),s="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=new RegExp(s.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e},_longDateFormat:{LTS:"h:mm:ss A",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(t){var e=this._longDateFormat[t];return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},isPM:function(t){return"p"===(t+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(t,e,i){var s=this._calendar[t];return"function"==typeof s?s.apply(e,[i]):s},_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"},relativeTime:function(t,e,i,s){var o=this._relativeTime[i];return"function"==typeof o?o(t,e,i,s):o.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",_ordinalParse:/\d{1,2}/,preparse:function(t){return t},postformat:function(t){return t},week:function(t){return me(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},firstDayOfWeek:function(){return this._week.dow},firstDayOfYear:function(){return this._week.doy},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),Ce=function(t,e,i,s){var o;return"boolean"==typeof i&&(s=i,i=n),o={},o._isAMomentObject=!0,o._i=t,o._f=e,o._l=i,o._strict=s,o._isUTC=!1,o._pf=h(),ge(o)},Ce.suppressDeprecationWarnings=!1,Ce.createFromInputFallback=l("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(t){t._d=new Date(t._i+(t._useUTC?" UTC":""))}),Ce.min=function(){var t=[].slice.call(arguments,0);return ve("isBefore",t)},Ce.max=function(){var t=[].slice.call(arguments,0);return ve("isAfter",t)},Ce.utc=function(t,e,i,s){var o;return"boolean"==typeof i&&(s=i,i=n),o={},o._isAMomentObject=!0,o._useUTC=!0,o._isUTC=!0,o._l=i,o._i=t,o._f=e,o._strict=s,o._pf=h(),ge(o).utc()},Ce.unix=function(t){return Ce(1e3*t)},Ce.duration=function(t,e){var i,s,o,n,r=t,h=null;return Ce.isDuration(t)?r={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(r={},e?r[e]=t:r.milliseconds=t):(h=je.exec(t))?(i="-"===h[1]?-1:1,r={y:0,d:L(h[Ae])*i,h:L(h[Pe])*i,m:L(h[Re])*i,s:L(h[Fe])*i,ms:L(h[He])*i}):(h=Ue.exec(t))?(i="-"===h[1]?-1:1,o=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},r={y:o(h[2]),M:o(h[3]),d:o(h[4]),h:o(h[5]),m:o(h[6]),s:o(h[7]),w:o(h[8])}):null==r?r={}:"object"==typeof r&&("from"in r||"to"in r)&&(n=M(Ce(r.from),Ce(r.to)),r={},r.ms=n.milliseconds,r.M=n.months),s=new y(r),Ce.isDuration(t)&&a(t,"_locale")&&(s._locale=t._locale),s},Ce.version=Ee,Ce.defaultFormat=ci,Ce.ISO_8601=function(){},Ce.momentProperties=Ye,Ce.updateOffset=function(){},Ce.relativeTimeThreshold=function(t,e){return bi[t]===n?!1:e===n?bi[t]:(bi[t]=e,!0)},Ce.lang=l("moment.lang is deprecated. Use moment.locale instead.",function(t,e){return Ce.locale(t,e)}),Ce.locale=function(t,e){var i;return t&&(i="undefined"!=typeof e?Ce.defineLocale(t,e):Ce.localeData(t),i&&(Ce.duration._locale=Ce._locale=i)),Ce._locale._abbr},Ce.defineLocale=function(t,e){return null!==e?(e.abbr=t,Be[t]||(Be[t]=new g),Be[t].set(e),Ce.locale(t),Be[t]):(delete Be[t],null)},Ce.langData=l("moment.langData is deprecated. Use moment.localeData instead.",function(t){return Ce.localeData(t)}),Ce.localeData=function(t){var e;if(t&&t._locale&&t._locale._abbr&&(t=t._locale._abbr),!t)return Ce._locale;if(!T(t)){if(e=W(t))return e;t=[t]}return Y(t)},Ce.isMoment=function(t){return t instanceof v||null!=t&&a(t,"_isAMomentObject")},Ce.isDuration=function(t){return t instanceof y};for(Oe=Mi.length-1;Oe>=0;--Oe)I(Mi[Oe]);Ce.normalizeUnits=function(t){return k(t)},Ce.invalid=function(t){var e=Ce.utc(0/0);return null!=t?b(e._pf,t):e._pf.userInvalidated=!0,e},Ce.parseZone=function(){return Ce.apply(null,arguments).parseZone()},Ce.parseTwoDigitYear=function(t){return L(t)+(L(t)>68?1900:2e3)},Ce.isDate=O,b(Ce.fn=v.prototype,{clone:function(){return Ce(this)},valueOf:function(){return+this._d-6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var t=Ce(this).utc();return 00:!1},parsingFlags:function(){return b({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(t){return this.utcOffset(0,t)},local:function(t){return this._isUTC&&(this.utcOffset(0,t),this._isUTC=!1,t&&this.subtract(this._dateUtcOffset(),"m")),this},format:function(t){var e=V(this,t||Ce.defaultFormat);return this.localeData().postformat(e)},add:D(1,"add"),subtract:D(-1,"subtract"),diff:function(t,e,i){var s,o,n=G(t,this),r=6e4*(n.utcOffset()-this.utcOffset());return e=k(e),"year"===e||"month"===e||"quarter"===e?(o=m(this,n),"quarter"===e?o/=3:"year"===e&&(o/=12)):(s=this-n,o="second"===e?s/1e3:"minute"===e?s/6e4:"hour"===e?s/36e5:"day"===e?(s-r)/864e5:"week"===e?(s-r)/6048e5:s),i?o:x(o)},from:function(t,e){return Ce.duration({to:this,from:t}).locale(this.locale()).humanize(!e)},fromNow:function(t){return this.from(Ce(),t)},calendar:function(t){var e=t||Ce(),i=G(e,this).startOf("day"),s=this.diff(i,"days",!0),o=-6>s?"sameElse":-1>s?"lastWeek":0>s?"lastDay":1>s?"sameDay":2>s?"nextDay":7>s?"nextWeek":"sameElse";return this.format(this.localeData().calendar(o,this,Ce(e)))},isLeapYear:function(){return R(this.year())},isDST:function(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},day:function(t){var e=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=t?(t=ce(t,this.localeData()),this.add(t-e,"d")):e},month:xe("Month",!0),startOf:function(t){switch(t=k(t)){case"year":this.month(0);case"quarter":case"month":this.date(1);case"week":case"isoWeek":case"day":this.hours(0);case"hour":this.minutes(0);case"minute":this.seconds(0);case"second":this.milliseconds(0)}return"week"===t?this.weekday(0):"isoWeek"===t&&this.isoWeekday(1),"quarter"===t&&this.month(3*Math.floor(this.month()/3)),this},endOf:function(t){return t=k(t),t===n||"millisecond"===t?this:this.startOf(t).add(1,"isoWeek"===t?"week":t).subtract(1,"ms")},isAfter:function(t,e){var i;return e=k("undefined"!=typeof e?e:"millisecond"),"millisecond"===e?(t=Ce.isMoment(t)?t:Ce(t),+this>+t):(i=Ce.isMoment(t)?+t:+Ce(t),i<+this.clone().startOf(e))},isBefore:function(t,e){var i;return e=k("undefined"!=typeof e?e:"millisecond"),"millisecond"===e?(t=Ce.isMoment(t)?t:Ce(t),+t>+this):(i=Ce.isMoment(t)?+t:+Ce(t),+this.clone().endOf(e)t?this:t}),max:l("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(t){return t=Ce.apply(null,arguments),t>this?this:t}),zone:l("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779",function(t,e){return null!=t?("string"!=typeof t&&(t=-t),this.utcOffset(t,e),this):-this.utcOffset()}),utcOffset:function(t,e){var i,s=this._offset||0;return null!=t?("string"==typeof t&&(t=Z(t)),Math.abs(t)<16&&(t=60*t),!this._isUTC&&e&&(i=this._dateUtcOffset()),this._offset=t,this._isUTC=!0,null!=i&&this.add(i,"m"),s!==t&&(!e||this._changeInProgress?C(this,Ce.duration(t-s,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,Ce.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?s:this._dateUtcOffset()},isLocal:function(){return!this._isUTC},isUtcOffset:function(){return this._isUTC},isUtc:function(){return this._isUTC&&0===this._offset},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.utcOffset(this._tzm):"string"==typeof this._i&&this.utcOffset(Z(this._i)),this},hasAlignedHourOffset:function(t){return t=t?Ce(t).utcOffset():0,(this.utcOffset()-t)%60===0},daysInMonth:function(){return z(this.year(),this.month())},dayOfYear:function(t){var e=Ne((Ce(this).startOf("day")-Ce(this).startOf("year"))/864e5)+1;return null==t?e:this.add(t-e,"d")},quarter:function(t){return null==t?Math.ceil((this.month()+1)/3):this.month(3*(t-1)+this.month()%3)},weekYear:function(t){var e=me(this,this.localeData()._week.dow,this.localeData()._week.doy).year;return null==t?e:this.add(t-e,"y")},isoWeekYear:function(t){var e=me(this,1,4).year;return null==t?e:this.add(t-e,"y")},week:function(t){var e=this.localeData().week(this);return null==t?e:this.add(7*(t-e),"d")},isoWeek:function(t){var e=me(this,1,4).week;return null==t?e:this.add(7*(t-e),"d")},weekday:function(t){var e=(this.day()+7-this.localeData()._week.dow)%7;return null==t?e:this.add(t-e,"d")},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},isoWeeksInYear:function(){return A(this.year(),1,4)},weeksInYear:function(){var t=this.localeData()._week;return A(this.year(),t.dow,t.doy)},get:function(t){return t=k(t),this[t]()},set:function(t,e){var i;if("object"==typeof t)for(i in t)this.set(i,t[i]);else t=k(t),"function"==typeof this[t]&&this[t](e);return this},locale:function(t){var e;return t===n?this._locale._abbr:(e=Ce.localeData(t),null!=e&&(this._locale=e),this)},lang:l("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(t){return t===n?this.localeData():this.locale(t)}),localeData:function(){return this._locale},_dateUtcOffset:function(){return 15*-Math.round(this._d.getTimezoneOffset()/15)}}),Ce.fn.millisecond=Ce.fn.milliseconds=xe("Milliseconds",!1),Ce.fn.second=Ce.fn.seconds=xe("Seconds",!1),Ce.fn.minute=Ce.fn.minutes=xe("Minutes",!1),Ce.fn.hour=Ce.fn.hours=xe("Hours",!0),Ce.fn.date=xe("Date",!0),Ce.fn.dates=l("dates accessor is deprecated. Use date instead.",xe("Date",!0)),Ce.fn.year=xe("FullYear",!0),Ce.fn.years=l("years accessor is deprecated. Use year instead.",xe("FullYear",!0)),Ce.fn.days=Ce.fn.day,Ce.fn.months=Ce.fn.month,Ce.fn.weeks=Ce.fn.week,Ce.fn.isoWeeks=Ce.fn.isoWeek,Ce.fn.quarters=Ce.fn.quarter,Ce.fn.toJSON=Ce.fn.toISOString,Ce.fn.isUTC=Ce.fn.isUtc,b(Ce.duration.fn=y.prototype,{_bubble:function(){var t,e,i,s=this._milliseconds,o=this._days,n=this._months,r=this._data,a=0;r.milliseconds=s%1e3,t=x(s/1e3),r.seconds=t%60,e=x(t/60),r.minutes=e%60,i=x(e/60),r.hours=i%24,o+=x(i/24),a=x(we(o)),o-=x(Se(a)),n+=x(o/30),o%=30,a+=x(n/12),n%=12,r.days=o,r.months=n,r.years=a},abs:function(){return 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),this},weeks:function(){return x(this.days()/7)},valueOf:function(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*L(this._months/12)},humanize:function(t){var e=ue(this,!t,this.localeData());return t&&(e=this.localeData().pastFuture(+this,e)),this.localeData().postformat(e)},add:function(t,e){var i=Ce.duration(t,e);return this._milliseconds+=i._milliseconds,this._days+=i._days,this._months+=i._months,this._bubble(),this},subtract:function(t,e){var i=Ce.duration(t,e);return this._milliseconds-=i._milliseconds,this._days-=i._days,this._months-=i._months,this._bubble(),this},get:function(t){return t=k(t),this[t.toLowerCase()+"s"]()},as:function(t){var e,i;if(t=k(t),"month"===t||"year"===t)return e=this._days+this._milliseconds/864e5,i=this._months+12*we(e),"month"===t?i:i/12;switch(e=this._days+Math.round(Se(this._months/12)),t){case"week":return e/7+this._milliseconds/6048e5;case"day":return e+this._milliseconds/864e5;case"hour":return 24*e+this._milliseconds/36e5;case"minute":return 24*e*60+this._milliseconds/6e4;case"second":return 24*e*60*60+this._milliseconds/1e3;case"millisecond":return Math.floor(24*e*60*60*1e3)+this._milliseconds;default:throw new Error("Unknown unit "+t)}},lang:Ce.fn.lang,locale:Ce.fn.locale,toIsoString:l("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",function(){return this.toISOString()}),toISOString:function(){var t=Math.abs(this.years()),e=Math.abs(this.months()),i=Math.abs(this.days()),s=Math.abs(this.hours()),o=Math.abs(this.minutes()),n=Math.abs(this.seconds()+this.milliseconds()/1e3);return this.asSeconds()?(this.asSeconds()<0?"-":"")+"P"+(t?t+"Y":"")+(e?e+"M":"")+(i?i+"D":"")+(s||o||n?"T":"")+(s?s+"H":"")+(o?o+"M":"")+(n?n+"S":""):"P0D"},localeData:function(){return this._locale},toJSON:function(){return this.toISOString()}}),Ce.duration.fn.toString=Ce.duration.fn.toISOString;for(Oe in fi)a(fi,Oe)&&Me(Oe.toLowerCase());Ce.duration.fn.asMilliseconds=function(){return this.as("ms")},Ce.duration.fn.asSeconds=function(){return this.as("s")},Ce.duration.fn.asMinutes=function(){return this.as("m")},Ce.duration.fn.asHours=function(){return this.as("h")},Ce.duration.fn.asDays=function(){return this.as("d")},Ce.duration.fn.asWeeks=function(){return this.as("weeks")},Ce.duration.fn.asMonths=function(){return this.as("M")},Ce.duration.fn.asYears=function(){return this.as("y")},Ce.locale("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(t){var e=t%10,i=1===L(t%100/10)?"th":1===e?"st":2===e?"nd":3===e?"rd":"th";return t+i}}),We?o.exports=Ce:(s=function(t,e,i){return i.config&&i.config()&&i.config().noGlobal===!0&&(ke.moment=Te),Ce}.call(e,i,e,o),!(s!==n&&(o.exports=s)),De(!0))}).call(this)}).call(e,function(){return this}(),i(71)(t))},function(t,e,i){var s;!function(o,n,r,a){function h(t,e,i){return setTimeout(m(t,i),e)}function d(t,e,i){return Array.isArray(t)?(l(t,i[e],i),!0):!1}function l(t,e,i){var s;if(t)if(t.forEach)t.forEach(e,i);else if(t.length!==a)for(s=0;s-1}function x(t){return t.trim().split(/\s+/g)}function w(t,e,i){if(t.indexOf&&!i)return t.indexOf(e);for(var s=0;si[e]}):s.sort()),s}function D(t,e){for(var i,s,o=e[0].toUpperCase()+e.slice(1),n=0;n1&&!i.firstMultiple?i.firstMultiple=z(e):1===o&&(i.firstMultiple=!1);var n=i.firstInput,r=i.firstMultiple,a=r?r.center:n.center,h=e.center=A(s);e.timeStamp=ve(),e.deltaTime=e.timeStamp-n.timeStamp,e.angle=H(a,h),e.distance=F(a,h),I(i,e),e.offsetDirection=R(e.deltaX,e.deltaY),e.scale=r?Y(r.pointers,s):1,e.rotation=r?B(r.pointers,s):0,L(i,e);var d=t.element;b(e.srcEvent.target,d)&&(d=e.srcEvent.target),e.target=d}function I(t,e){var i=e.center,s=t.offsetDelta||{},o=t.prevDelta||{},n=t.prevInput||{};(e.eventType===Oe||n.eventType===ke)&&(o=t.prevDelta={x:n.deltaX||0,y:n.deltaY||0},s=t.offsetDelta={x:i.x,y:i.y}),e.deltaX=o.x+(i.x-s.x),e.deltaY=o.y+(i.y-s.y)}function L(t,e){var i,s,o,n,r=t.lastInterval||e,h=e.timeStamp-r.timeStamp;if(e.eventType!=Ne&&(h>Te||r.velocity===a)){var d=r.deltaX-e.deltaX,l=r.deltaY-e.deltaY,c=P(h,d,l);s=c.x,o=c.y,i=ge(c.x)>ge(c.y)?c.x:c.y,n=R(d,l),t.lastInterval=e}else i=r.velocity,s=r.velocityX,o=r.velocityY,n=r.direction;e.velocity=i,e.velocityX=s,e.velocityY=o,e.direction=n}function z(t){for(var e=[],i=0;io;)i+=t[o].clientX,s+=t[o].clientY,o++;return{x:fe(i/e),y:fe(s/e)}}function P(t,e,i){return{x:e/t||0,y:i/t||0}}function R(t,e){return t===e?Ie:ge(t)>=ge(e)?t>0?Le:ze:e>0?Ae:Pe}function F(t,e,i){i||(i=Be);var s=e[i[0]]-t[i[0]],o=e[i[1]]-t[i[1]];return Math.sqrt(s*s+o*o)}function H(t,e,i){i||(i=Be);var s=e[i[0]]-t[i[0]],o=e[i[1]]-t[i[1]];return 180*Math.atan2(o,s)/Math.PI}function B(t,e){return H(e[1],e[0],Ye)-H(t[1],t[0],Ye)}function Y(t,e){return F(e[0],e[1],Ye)/F(t[0],t[1],Ye)}function W(){this.evEl=Ge,this.evWin=je,this.allow=!0,this.pressed=!1,O.apply(this,arguments)}function G(){this.evEl=Xe,this.evWin=qe,O.apply(this,arguments),this.store=this.manager.session.pointerEvents=[]}function j(){this.evTarget=Qe,this.evWin=Ke,this.started=!1,O.apply(this,arguments)}function U(t,e){var i=S(t.touches),s=S(t.changedTouches);return e&(ke|Ne)&&(i=M(i.concat(s),"identifier",!0)),[i,s]}function V(){this.evTarget=Je,this.targetIds={},O.apply(this,arguments)}function X(t,e){var i=S(t.touches),s=this.targetIds;if(e&(Oe|Ee)&&1===i.length)return s[i[0].identifier]=!0,[i,i];var o,n,r=S(t.changedTouches),a=[],h=this.target;if(n=i.filter(function(t){return b(t.target,h)}),e===Oe)for(o=0;oa&&(e.push(t),a=e.length-1):o&(ke|Ne)&&(i=!0),0>a||(e[a]=t,this.callback(this.manager,o,{pointers:e,changedPointers:[t],pointerType:n,srcEvent:t}),i&&e.splice(a,1))}});var Ze={touchstart:Oe,touchmove:Ee,touchend:ke,touchcancel:Ne},Qe="touchstart",Ke="touchstart touchmove touchend touchcancel";u(j,O,{handler:function(t){var e=Ze[t.type];if(e===Oe&&(this.started=!0),this.started){var i=U.call(this,t,e);e&(ke|Ne)&&i[0].length-i[1].length===0&&(this.started=!1),this.callback(this.manager,e,{pointers:i[0],changedPointers:i[1],pointerType:Se,srcEvent:t})}}});var $e={touchstart:Oe,touchmove:Ee,touchend:ke,touchcancel:Ne},Je="touchstart touchmove touchend touchcancel";u(V,O,{handler:function(t){var e=$e[t.type],i=X.call(this,t,e);i&&this.callback(this.manager,e,{pointers:i[0],changedPointers:i[1],pointerType:Se,srcEvent:t})}}),u(q,O,{handler:function(t,e,i){var s=i.pointerType==Se,o=i.pointerType==De;if(s)this.mouse.allow=!1;else if(o&&!this.mouse.allow)return;e&(ke|Ne)&&(this.mouse.allow=!0),this.callback(t,e,i)},destroy:function(){this.touch.destroy(),this.mouse.destroy()}});var ti=D(ue.style,"touchAction"),ei=ti!==a,ii="compute",si="auto",oi="manipulation",ni="none",ri="pan-x",ai="pan-y";Z.prototype={set:function(t){t==ii&&(t=this.compute()),ei&&(this.manager.element.style[ti]=t),this.actions=t.toLowerCase().trim()},update:function(){this.set(this.manager.options.touchAction)},compute:function(){var t=[];return l(this.manager.recognizers,function(e){f(e.options.enable,[e])&&(t=t.concat(e.getTouchAction()))}),Q(t.join(" "))},preventDefaults:function(t){if(!ei){var e=t.srcEvent,i=t.offsetDirection;if(this.manager.session.prevented)return void e.preventDefault();var s=this.actions,o=_(s,ni),n=_(s,ai),r=_(s,ri);return o||n&&i&Re||r&&i&Fe?this.preventSrc(e):void 0}},preventSrc:function(t){this.manager.session.prevented=!0,t.preventDefault()}};var hi=1,di=2,li=4,ci=8,pi=ci,ui=16,mi=32;K.prototype={defaults:{},set:function(t){return c(this.options,t),this.manager&&this.manager.touchAction.update(),this},recognizeWith:function(t){if(d(t,"recognizeWith",this))return this;var e=this.simultaneous;return t=te(t,this),e[t.id]||(e[t.id]=t,t.recognizeWith(this)),this},dropRecognizeWith:function(t){return d(t,"dropRecognizeWith",this)?this:(t=te(t,this),delete this.simultaneous[t.id],this)},requireFailure:function(t){if(d(t,"requireFailure",this))return this;var e=this.requireFail;return t=te(t,this),-1===w(e,t)&&(e.push(t),t.requireFailure(this)),this},dropRequireFailure:function(t){if(d(t,"dropRequireFailure",this))return this;t=te(t,this);var e=w(this.requireFail,t);return e>-1&&this.requireFail.splice(e,1),this},hasRequireFailures:function(){return this.requireFail.length>0},canRecognizeWith:function(t){return!!this.simultaneous[t.id]},emit:function(t){function e(e){i.manager.emit(i.options.event+(e?$(s):""),t)}var i=this,s=this.state;ci>s&&e(!0),e(),s>=ci&&e(!0)},tryEmit:function(t){return this.canEmit()?this.emit(t):void(this.state=mi)},canEmit:function(){for(var t=0;tn?Le:ze,i=n!=this.pX,s=Math.abs(t.deltaX)):(o=0===r?Ie:0>r?Ae:Pe,i=r!=this.pY,s=Math.abs(t.deltaY))),t.direction=o,i&&s>e.threshold&&o&e.direction},attrTest:function(t){return ee.prototype.attrTest.call(this,t)&&(this.state&di||!(this.state&di)&&this.directionTest(t))},emit:function(t){this.pX=t.deltaX,this.pY=t.deltaY;var e=J(t.direction);e&&this.manager.emit(this.options.event+e,t),this._super.emit.call(this,t)}}),u(se,ee,{defaults:{event:"pinch",threshold:0,pointers:2},getTouchAction:function(){return[ni]},attrTest:function(t){return this._super.attrTest.call(this,t)&&(Math.abs(t.scale-1)>this.options.threshold||this.state&di)},emit:function(t){if(this._super.emit.call(this,t),1!==t.scale){var e=t.scale<1?"in":"out";this.manager.emit(this.options.event+e,t)}}}),u(oe,K,{defaults:{event:"press",pointers:1,time:500,threshold:5},getTouchAction:function(){return[si]},process:function(t){var e=this.options,i=t.pointers.length===e.pointers,s=t.distancee.time; -if(this._input=t,!s||!i||t.eventType&(ke|Ne)&&!o)this.reset();else if(t.eventType&Oe)this.reset(),this._timer=h(function(){this.state=pi,this.tryEmit()},e.time,this);else if(t.eventType&ke)return pi;return mi},reset:function(){clearTimeout(this._timer)},emit:function(t){this.state===pi&&(t&&t.eventType&ke?this.manager.emit(this.options.event+"up",t):(this._input.timeStamp=ve(),this.manager.emit(this.options.event,this._input)))}}),u(ne,ee,{defaults:{event:"rotate",threshold:0,pointers:2},getTouchAction:function(){return[ni]},attrTest:function(t){return this._super.attrTest.call(this,t)&&(Math.abs(t.rotation)>this.options.threshold||this.state&di)}}),u(re,ee,{defaults:{event:"swipe",threshold:10,velocity:.65,direction:Re|Fe,pointers:1},getTouchAction:function(){return ie.prototype.getTouchAction.call(this)},attrTest:function(t){var e,i=this.options.direction;return i&(Re|Fe)?e=t.velocity:i&Re?e=t.velocityX:i&Fe&&(e=t.velocityY),this._super.attrTest.call(this,t)&&i&t.direction&&t.distance>this.options.threshold&&ge(e)>this.options.velocity&&t.eventType&ke},emit:function(t){var e=J(t.direction);e&&this.manager.emit(this.options.event+e,t),this.manager.emit(this.options.event,t)}}),u(ae,K,{defaults:{event:"tap",pointers:1,taps:1,interval:300,time:250,threshold:2,posThreshold:10},getTouchAction:function(){return[oi]},process:function(t){var e=this.options,i=t.pointers.length===e.pointers,s=t.distancet&&s>o;)o%3==0?(this.forceAggregateHubs(!0),this.normalizeClusterLevels()):this.increaseClusterLevel(),i=this.nodeIndices.length,o+=1;o>0&&1==e&&this.repositionNodes(),this._updateCalculationNodes()},e.openCluster=function(t){var e=this.moving;if(t.clusterSize>this.constants.clustering.sectorThreshold&&this._nodeInActiveArea(t)&&("default"!=this._sector()||1!=this.nodeIndices.length)){this._addSector(t);for(var i=0;this.nodeIndices.lengthi;)this.decreaseClusterLevel(),i+=1}else this._expandClusterNode(t,!1,!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this._updateCalculationNodes(),this.updateLabels();this.moving!=e&&this.start()},e.updateClustersDefault=function(){1==this.constants.clustering.enabled&&this.updateClusters(0,!1,!1)},e.increaseClusterLevel=function(){this.updateClusters(-1,!1,!0)},e.decreaseClusterLevel=function(){this.updateClusters(1,!1,!0)},e.updateClusters=function(t,e,i,s){var o=this.moving,n=this.nodeIndices.length;this.previousScale>this.scale&&0==t&&this._collapseSector(),this.previousScale>this.scale||-1==t?this._formClusters(i):(this.previousScalethis.scale||-1==t)&&(this._aggregateHubs(i),this._updateNodeIndexList()),(this.previousScale>this.scale||-1==t)&&(this.handleChains(),this._updateNodeIndexList()),this.previousScale=this.scale,this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.lengththis.constants.clustering.chainThreshold&&this._reduceAmountOfChains(1-this.constants.clustering.chainThreshold/t)},e._aggregateHubs=function(t){this._getHubSize(),this._formClustersByHub(t,!1)},e.forceAggregateHubs=function(t){var e=this.moving,i=this.nodeIndices.length;this._aggregateHubs(!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.length!=i&&(this.clusterSession+=1),(0==t||void 0===t)&&this.moving!=e&&this.start()},e._openClustersBySize=function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];1==e.inView()&&(e.width*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientWidth||e.height*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientHeight)&&this.openCluster(e)}},e._openClusters=function(t,e){for(var i=0;i1&&(t.clusterSizei)){var r=n.from,a=n.to;n.to.options.mass>n.from.options.mass&&(r=n.to,a=n.from),1==a.dynamicEdgesLength?this._addToCluster(r,a,!1):1==r.dynamicEdgesLength&&this._addToCluster(a,r,!1)}}},e._forceClustersByZoom=function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];if(1==e.dynamicEdgesLength&&0!=e.dynamicEdges.length){var i=e.dynamicEdges[0],s=i.toId==e.id?this.nodes[i.fromId]:this.nodes[i.toId];e.id!=s.id&&(s.options.mass>e.options.mass?this._addToCluster(s,e,!0):this._addToCluster(e,s,!0))}}},e._clusterToSmallestNeighbour=function(t){for(var e=-1,i=null,s=0;so.clusterSessions.length&&(e=o.clusterSessions.length,i=o)}null!=o&&void 0!==this.nodes[o.id]&&this._addToCluster(o,t,!0)},e._formClustersByHub=function(t,e){for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&this._formClusterFromHub(this.nodes[i],t,e)},e._formClusterFromHub=function(t,e,i,s){if(void 0===s&&(s=0),t.dynamicEdgesLength>=this.hubThreshold&&0==i||t.dynamicEdgesLength==this.hubThreshold&&1==i){for(var o,n,r,a=this.constants.clustering.clusterEdgeThreshold/this.scale,h=!1,d=[],l=t.dynamicEdges.length,c=0;l>c;c++)d.push(t.dynamicEdges[c].id);if(0==e)for(h=!1,c=0;l>c;c++){var p=this.edges[d[c]];if(void 0!==p&&p.connected&&p.toId!=p.fromId&&(o=p.to.x-p.from.x,n=p.to.y-p.from.y,r=Math.sqrt(o*o+n*n),a>r)){h=!0;break}}if(!e&&h||e)for(c=0;l>c;c++)if(p=this.edges[d[c]],void 0!==p){var u=this.nodes[p.fromId==t.id?p.toId:p.fromId];u.dynamicEdges.length<=this.hubThreshold+s&&u.id!=t.id&&this._addToCluster(t,u,e)}}},e._addToCluster=function(t,e,i){t.containedNodes[e.id]=e;for(var s=0;s1)for(var s=0;s1&&(e.label="[".concat(String(e.clusterSize),"]"))}for(t in this.nodes)this.nodes.hasOwnProperty(t)&&(e=this.nodes[t],1==e.clusterSize&&(e.label=void 0!==e.originalLabel?e.originalLabel:String(e.id)))},e.normalizeClusterLevels=function(){var t,e=0,i=1e9,s=0;for(t in this.nodes)this.nodes.hasOwnProperty(t)&&(s=this.nodes[t].clusterSessions.length,s>e&&(e=s),i>s&&(i=s));if(e-i>this.constants.clustering.clusterLevelDifference){var o=this.nodeIndices.length,n=e-this.constants.clustering.clusterLevelDifference;for(t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodes[t].clusterSessions.lengths&&(s=n.dynamicEdgesLength),t+=n.dynamicEdgesLength,e+=Math.pow(n.dynamicEdgesLength,2),i+=1}t/=i,e/=i;var r=e-Math.pow(t,2),a=Math.sqrt(r);this.hubThreshold=Math.floor(t+2*a),this.hubThreshold>s&&(this.hubThreshold=s)},e._reduceAmountOfChains=function(t){this.hubThreshold=2;var e=Math.floor(this.nodeIndices.length*t);for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&e>0&&(this._formClusterFromHub(this.nodes[i],!0,!0,1),e-=1)},e._getChainFraction=function(){var t=0,e=0;for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&(2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&(t+=1),e+=1);return t/e}},function(t,e,i){var s=i(1),o=i(40);e._putDataInSector=function(){this.sectors.active[this._sector()].nodes=this.nodes,this.sectors.active[this._sector()].edges=this.edges,this.sectors.active[this._sector()].nodeIndices=this.nodeIndices},e._switchToSector=function(t,e){void 0===e||"active"==e?this._switchToActiveSector(t):this._switchToFrozenSector(t)},e._switchToActiveSector=function(t){this.nodeIndices=this.sectors.active[t].nodeIndices,this.nodes=this.sectors.active[t].nodes,this.edges=this.sectors.active[t].edges},e._switchToSupportSector=function(){this.nodeIndices=this.sectors.support.nodeIndices,this.nodes=this.sectors.support.nodes,this.edges=this.sectors.support.edges},e._switchToFrozenSector=function(t){this.nodeIndices=this.sectors.frozen[t].nodeIndices,this.nodes=this.sectors.frozen[t].nodes,this.edges=this.sectors.frozen[t].edges},e._loadLatestSector=function(){this._switchToSector(this._sector())},e._sector=function(){return this.activeSector[this.activeSector.length-1]},e._previousSector=function(){if(this.activeSector.length>1)return this.activeSector[this.activeSector.length-2];throw new TypeError("there are not enough sectors in the this.activeSector array.")},e._setActiveSector=function(t){this.activeSector.push(t)},e._forgetLastSector=function(){this.activeSector.pop()},e._createNewSector=function(t){this.sectors.active[t]={nodes:{},edges:{},nodeIndices:[],formationScale:this.scale,drawingNode:void 0},this.sectors.active[t].drawingNode=new o({id:t,color:{background:"#eaefef",border:"495c5e"}},{},{},this.constants),this.sectors.active[t].drawingNode.clusterSize=2},e._deleteActiveSector=function(t){delete this.sectors.active[t]},e._deleteFrozenSector=function(t){delete this.sectors.frozen[t]},e._freezeSector=function(t){this.sectors.frozen[t]=this.sectors.active[t],this._deleteActiveSector(t)},e._activateSector=function(t){this.sectors.active[t]=this.sectors.frozen[t],this._deleteFrozenSector(t)},e._mergeThisWithFrozen=function(t){for(var e in this.nodes)this.nodes.hasOwnProperty(e)&&(this.sectors.frozen[t].nodes[e]=this.nodes[e]);for(var i in this.edges)this.edges.hasOwnProperty(i)&&(this.sectors.frozen[t].edges[i]=this.edges[i]);for(var s=0;s1?this[t](o[0],o[1]):this[t](e))}return this._loadLatestSector(),i},e._doInSupportSector=function(t,e){var i=!1;if(void 0===e)this._switchToSupportSector(),i=this[t]();else{this._switchToSupportSector();var s=Array.prototype.splice.call(arguments,1);i=s.length>1?this[t](s[0],s[1]):this[t](e)}return this._loadLatestSector(),i},e._doInAllFrozenSectors=function(t,e){if(void 0===e)for(var i in this.sectors.frozen)this.sectors.frozen.hasOwnProperty(i)&&(this._switchToFrozenSector(i),this[t]());else for(var i in this.sectors.frozen)if(this.sectors.frozen.hasOwnProperty(i)){this._switchToFrozenSector(i);var s=Array.prototype.splice.call(arguments,1);s.length>1?this[t](s[0],s[1]):this[t](e)}this._loadLatestSector()},e._doInAllSectors=function(t,e){var i=Array.prototype.splice.call(arguments,1);void 0===e?(this._doInAllActiveSectors(t),this._doInAllFrozenSectors(t)):i.length>1?(this._doInAllActiveSectors(t,i[0],i[1]),this._doInAllFrozenSectors(t,i[0],i[1])):(this._doInAllActiveSectors(t,e),this._doInAllFrozenSectors(t,e))},e._clearNodeIndexList=function(){var t=this._sector();this.sectors.active[t].nodeIndices=[],this.nodeIndices=this.sectors.active[t].nodeIndices},e._drawSectorNodes=function(t,e){var i,s=1e9,o=-1e9,n=1e9,r=-1e9;for(var a in this.sectors[e])if(this.sectors[e].hasOwnProperty(a)&&void 0!==this.sectors[e][a].drawingNode){this._switchToSector(a,e),s=1e9,o=-1e9,n=1e9,r=-1e9;for(var h in this.nodes)this.nodes.hasOwnProperty(h)&&(i=this.nodes[h],i.resize(t),n>i.x-.5*i.width&&(n=i.x-.5*i.width),ri.y-.5*i.height&&(s=i.y-.5*i.height),o0?this.nodes[i[i.length-1]]:null},e._getEdgesOverlappingWith=function(t,e){var i=this.edges;for(var s in i)i.hasOwnProperty(s)&&i[s].isOverlappingWith(t)&&e.push(s)},e._getAllEdgesOverlappingWith=function(t){var e=[];return this._doInAllActiveSectors("_getEdgesOverlappingWith",t,e),e},e._getEdgeAt=function(t){var e=this._pointerToPositionObject(t),i=this._getAllEdgesOverlappingWith(e);return i.length>0?this.edges[i[i.length-1]]:null},e._addToSelection=function(t){t instanceof s?this.selectionObj.nodes[t.id]=t:this.selectionObj.edges[t.id]=t},e._addToHover=function(t){t instanceof s?this.hoverObj.nodes[t.id]=t:this.hoverObj.edges[t.id]=t},e._removeFromSelection=function(t){t instanceof s?delete this.selectionObj.nodes[t.id]:delete this.selectionObj.edges[t.id]},e._unselectAll=function(t){void 0===t&&(t=!1);for(var e in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(e)&&this.selectionObj.nodes[e].unselect();for(var i in this.selectionObj.edges)this.selectionObj.edges.hasOwnProperty(i)&&this.selectionObj.edges[i].unselect();this.selectionObj={nodes:{},edges:{}},0==t&&this.emit("select",this.getSelection())},e._unselectClusters=function(t){void 0===t&&(t=!1);for(var e in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(e)&&this.selectionObj.nodes[e].clusterSize>1&&(this.selectionObj.nodes[e].unselect(),this._removeFromSelection(this.selectionObj.nodes[e]));0==t&&this.emit("select",this.getSelection())},e._getSelectedNodeCount=function(){var t=0;for(var e in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(e)&&(t+=1);return t},e._getSelectedNode=function(){for(var t in this.selectionObj.nodes)if(this.selectionObj.nodes.hasOwnProperty(t))return this.selectionObj.nodes[t];return null},e._getSelectedEdge=function(){for(var t in this.selectionObj.edges)if(this.selectionObj.edges.hasOwnProperty(t))return this.selectionObj.edges[t];return null},e._getSelectedEdgeCount=function(){var t=0;for(var e in this.selectionObj.edges)this.selectionObj.edges.hasOwnProperty(e)&&(t+=1);return t},e._getSelectedObjectCount=function(){var t=0;for(var e in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(e)&&(t+=1);for(var i in this.selectionObj.edges)this.selectionObj.edges.hasOwnProperty(i)&&(t+=1);return t},e._selectionIsEmpty=function(){for(var t in this.selectionObj.nodes)if(this.selectionObj.nodes.hasOwnProperty(t))return!1;for(var e in this.selectionObj.edges)if(this.selectionObj.edges.hasOwnProperty(e))return!1;return!0},e._clusterInSelection=function(){for(var t in this.selectionObj.nodes)if(this.selectionObj.nodes.hasOwnProperty(t)&&this.selectionObj.nodes[t].clusterSize>1)return!0;return!1},e._selectConnectedEdges=function(t){for(var e=0;ei;i++){o=t[i];var n=this.nodes[o];if(!n)throw new RangeError('Node with id "'+o+'" not found');this._selectObject(n,!0,!0,e,!0)}this.redraw()},e.selectEdges=function(t){var e,i,s;if(!t||void 0==t.length)throw"Selection must be an array with ids";for(this._unselectAll(!0),e=0,i=t.length;i>e;e++){s=t[e];var o=this.edges[s];if(!o)throw new RangeError('Edge with id "'+s+'" not found');this._selectObject(o,!0,!0,!1,!0)}this.redraw()},e._updateSelection=function(){for(var t in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(t)&&(this.nodes.hasOwnProperty(t)||delete this.selectionObj.nodes[t]);for(var e in this.selectionObj.edges)this.selectionObj.edges.hasOwnProperty(e)&&(this.edges.hasOwnProperty(e)||delete this.selectionObj.edges[e])}},function(t,e,i){var s=i(1),o=i(40),n=i(37);e._clearManipulatorBar=function(){this._recursiveDOMDelete(this.manipulationDiv),this.manipulationDOM={},this._manipulationReleaseOverload=function(){},delete this.sectors.support.nodes.targetNode,delete this.sectors.support.nodes.targetViaNode,this.controlNodesActive=!1,this.freezeSimulation=!1},e._restoreOverloadedFunctions=function(){for(var t in this.cachedFunctions)this.cachedFunctions.hasOwnProperty(t)&&(this[t]=this.cachedFunctions[t],delete this.cachedFunctions[t])},e._toggleEditMode=function(){this.editMode=!this.editMode;var t=this.manipulationDiv,e=this.closeDiv,i=this.editModeDiv;1==this.editMode?(t.style.display="block",e.style.display="block",i.style.display="none",e.onclick=this._toggleEditMode.bind(this)):(t.style.display="none",e.style.display="none",i.style.display="block",e.onclick=null),this._createManipulatorBar()},e._createManipulatorBar=function(){this.boundFunction&&this.off("select",this.boundFunction);var t=this.constants.locales[this.constants.locale];if(void 0!==this.edgeBeingEdited&&(this.edgeBeingEdited._disableControlNodes(),this.edgeBeingEdited=void 0,this.selectedControlNode=null,this.controlNodesActive=!1,this._redraw()),this._restoreOverloadedFunctions(),this.freezeSimulation=!1,this.blockConnectingEdgeSelection=!1,this.forceAppendSelection=!1,this.manipulationDOM={},1==this.editMode){for(;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);this.manipulationDOM.addNodeSpan=document.createElement("span"),this.manipulationDOM.addNodeSpan.className="network-manipulationUI add",this.manipulationDOM.addNodeLabelSpan=document.createElement("span"),this.manipulationDOM.addNodeLabelSpan.className="network-manipulationLabel",this.manipulationDOM.addNodeLabelSpan.innerHTML=t.addNode,this.manipulationDOM.addNodeSpan.appendChild(this.manipulationDOM.addNodeLabelSpan),this.manipulationDOM.seperatorLineDiv1=document.createElement("div"),this.manipulationDOM.seperatorLineDiv1.className="network-seperatorLine",this.manipulationDOM.addEdgeSpan=document.createElement("span"),this.manipulationDOM.addEdgeSpan.className="network-manipulationUI connect",this.manipulationDOM.addEdgeLabelSpan=document.createElement("span"),this.manipulationDOM.addEdgeLabelSpan.className="network-manipulationLabel",this.manipulationDOM.addEdgeLabelSpan.innerHTML=t.addEdge,this.manipulationDOM.addEdgeSpan.appendChild(this.manipulationDOM.addEdgeLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.addNodeSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv1),this.manipulationDiv.appendChild(this.manipulationDOM.addEdgeSpan),1==this._getSelectedNodeCount()&&this.triggerFunctions.edit?(this.manipulationDOM.seperatorLineDiv2=document.createElement("div"),this.manipulationDOM.seperatorLineDiv2.className="network-seperatorLine",this.manipulationDOM.editNodeSpan=document.createElement("span"),this.manipulationDOM.editNodeSpan.className="network-manipulationUI edit",this.manipulationDOM.editNodeLabelSpan=document.createElement("span"),this.manipulationDOM.editNodeLabelSpan.className="network-manipulationLabel",this.manipulationDOM.editNodeLabelSpan.innerHTML=t.editNode,this.manipulationDOM.editNodeSpan.appendChild(this.manipulationDOM.editNodeLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv2),this.manipulationDiv.appendChild(this.manipulationDOM.editNodeSpan)):1==this._getSelectedEdgeCount()&&0==this._getSelectedNodeCount()&&(this.manipulationDOM.seperatorLineDiv3=document.createElement("div"),this.manipulationDOM.seperatorLineDiv3.className="network-seperatorLine",this.manipulationDOM.editEdgeSpan=document.createElement("span"),this.manipulationDOM.editEdgeSpan.className="network-manipulationUI edit",this.manipulationDOM.editEdgeLabelSpan=document.createElement("span"),this.manipulationDOM.editEdgeLabelSpan.className="network-manipulationLabel",this.manipulationDOM.editEdgeLabelSpan.innerHTML=t.editEdge,this.manipulationDOM.editEdgeSpan.appendChild(this.manipulationDOM.editEdgeLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv3),this.manipulationDiv.appendChild(this.manipulationDOM.editEdgeSpan)),0==this._selectionIsEmpty()&&(this.manipulationDOM.seperatorLineDiv4=document.createElement("div"),this.manipulationDOM.seperatorLineDiv4.className="network-seperatorLine",this.manipulationDOM.deleteSpan=document.createElement("span"),this.manipulationDOM.deleteSpan.className="network-manipulationUI delete",this.manipulationDOM.deleteLabelSpan=document.createElement("span"),this.manipulationDOM.deleteLabelSpan.className="network-manipulationLabel",this.manipulationDOM.deleteLabelSpan.innerHTML=t.del,this.manipulationDOM.deleteSpan.appendChild(this.manipulationDOM.deleteLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv4),this.manipulationDiv.appendChild(this.manipulationDOM.deleteSpan)),this.manipulationDOM.addNodeSpan.onclick=this._createAddNodeToolbar.bind(this),this.manipulationDOM.addEdgeSpan.onclick=this._createAddEdgeToolbar.bind(this),1==this._getSelectedNodeCount()&&this.triggerFunctions.edit?this.manipulationDOM.editNodeSpan.onclick=this._editNode.bind(this):1==this._getSelectedEdgeCount()&&0==this._getSelectedNodeCount()&&(this.manipulationDOM.editEdgeSpan.onclick=this._createEditEdgeToolbar.bind(this)),0==this._selectionIsEmpty()&&(this.manipulationDOM.deleteSpan.onclick=this._deleteSelected.bind(this)),this.closeDiv.onclick=this._toggleEditMode.bind(this); -var e=this;this.boundFunction=e._createManipulatorBar,this.on("select",this.boundFunction)}else{for(;this.editModeDiv.hasChildNodes();)this.editModeDiv.removeChild(this.editModeDiv.firstChild);this.manipulationDOM.editModeSpan=document.createElement("span"),this.manipulationDOM.editModeSpan.className="network-manipulationUI edit editmode",this.manipulationDOM.editModeLabelSpan=document.createElement("span"),this.manipulationDOM.editModeLabelSpan.className="network-manipulationLabel",this.manipulationDOM.editModeLabelSpan.innerHTML=t.edit,this.manipulationDOM.editModeSpan.appendChild(this.manipulationDOM.editModeLabelSpan),this.editModeDiv.appendChild(this.manipulationDOM.editModeSpan),this.manipulationDOM.editModeSpan.onclick=this._toggleEditMode.bind(this)}},e._createAddNodeToolbar=function(){this._clearManipulatorBar(),this.boundFunction&&this.off("select",this.boundFunction);var t=this.constants.locales[this.constants.locale];this.manipulationDOM={},this.manipulationDOM.backSpan=document.createElement("span"),this.manipulationDOM.backSpan.className="network-manipulationUI back",this.manipulationDOM.backLabelSpan=document.createElement("span"),this.manipulationDOM.backLabelSpan.className="network-manipulationLabel",this.manipulationDOM.backLabelSpan.innerHTML=t.back,this.manipulationDOM.backSpan.appendChild(this.manipulationDOM.backLabelSpan),this.manipulationDOM.seperatorLineDiv1=document.createElement("div"),this.manipulationDOM.seperatorLineDiv1.className="network-seperatorLine",this.manipulationDOM.descriptionSpan=document.createElement("span"),this.manipulationDOM.descriptionSpan.className="network-manipulationUI none",this.manipulationDOM.descriptionLabelSpan=document.createElement("span"),this.manipulationDOM.descriptionLabelSpan.className="network-manipulationLabel",this.manipulationDOM.descriptionLabelSpan.innerHTML=t.addDescription,this.manipulationDOM.descriptionSpan.appendChild(this.manipulationDOM.descriptionLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.backSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv1),this.manipulationDiv.appendChild(this.manipulationDOM.descriptionSpan),this.manipulationDOM.backSpan.onclick=this._createManipulatorBar.bind(this);var e=this;this.boundFunction=e._addNode,this.on("select",this.boundFunction)},e._createAddEdgeToolbar=function(){this._clearManipulatorBar(),this._unselectAll(!0),this.freezeSimulation=!0,this.boundFunction&&this.off("select",this.boundFunction);var t=this.constants.locales[this.constants.locale];this._unselectAll(),this.forceAppendSelection=!1,this.blockConnectingEdgeSelection=!0,this.manipulationDOM={},this.manipulationDOM.backSpan=document.createElement("span"),this.manipulationDOM.backSpan.className="network-manipulationUI back",this.manipulationDOM.backLabelSpan=document.createElement("span"),this.manipulationDOM.backLabelSpan.className="network-manipulationLabel",this.manipulationDOM.backLabelSpan.innerHTML=t.back,this.manipulationDOM.backSpan.appendChild(this.manipulationDOM.backLabelSpan),this.manipulationDOM.seperatorLineDiv1=document.createElement("div"),this.manipulationDOM.seperatorLineDiv1.className="network-seperatorLine",this.manipulationDOM.descriptionSpan=document.createElement("span"),this.manipulationDOM.descriptionSpan.className="network-manipulationUI none",this.manipulationDOM.descriptionLabelSpan=document.createElement("span"),this.manipulationDOM.descriptionLabelSpan.className="network-manipulationLabel",this.manipulationDOM.descriptionLabelSpan.innerHTML=t.edgeDescription,this.manipulationDOM.descriptionSpan.appendChild(this.manipulationDOM.descriptionLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.backSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv1),this.manipulationDiv.appendChild(this.manipulationDOM.descriptionSpan),this.manipulationDOM.backSpan.onclick=this._createManipulatorBar.bind(this);var e=this;this.boundFunction=e._handleConnect,this.on("select",this.boundFunction),this.cachedFunctions._handleTouch=this._handleTouch,this.cachedFunctions._manipulationReleaseOverload=this._manipulationReleaseOverload,this.cachedFunctions._handleDragStart=this._handleDragStart,this.cachedFunctions._handleDragEnd=this._handleDragEnd,this._handleTouch=this._handleConnect,this._manipulationReleaseOverload=function(){},this._handleDragStart=function(){},this._handleDragEnd=this._finishConnect,this._redraw()},e._createEditEdgeToolbar=function(){this._clearManipulatorBar(),this.controlNodesActive=!0,this.boundFunction&&this.off("select",this.boundFunction),this.edgeBeingEdited=this._getSelectedEdge(),this.edgeBeingEdited._enableControlNodes();var t=this.constants.locales[this.constants.locale];this.manipulationDOM={},this.manipulationDOM.backSpan=document.createElement("span"),this.manipulationDOM.backSpan.className="network-manipulationUI back",this.manipulationDOM.backLabelSpan=document.createElement("span"),this.manipulationDOM.backLabelSpan.className="network-manipulationLabel",this.manipulationDOM.backLabelSpan.innerHTML=t.back,this.manipulationDOM.backSpan.appendChild(this.manipulationDOM.backLabelSpan),this.manipulationDOM.seperatorLineDiv1=document.createElement("div"),this.manipulationDOM.seperatorLineDiv1.className="network-seperatorLine",this.manipulationDOM.descriptionSpan=document.createElement("span"),this.manipulationDOM.descriptionSpan.className="network-manipulationUI none",this.manipulationDOM.descriptionLabelSpan=document.createElement("span"),this.manipulationDOM.descriptionLabelSpan.className="network-manipulationLabel",this.manipulationDOM.descriptionLabelSpan.innerHTML=t.editEdgeDescription,this.manipulationDOM.descriptionSpan.appendChild(this.manipulationDOM.descriptionLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.backSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv1),this.manipulationDiv.appendChild(this.manipulationDOM.descriptionSpan),this.manipulationDOM.backSpan.onclick=this._createManipulatorBar.bind(this),this.cachedFunctions._handleTouch=this._handleTouch,this.cachedFunctions._manipulationReleaseOverload=this._manipulationReleaseOverload,this.cachedFunctions._handleTap=this._handleTap,this.cachedFunctions._handleDragStart=this._handleDragStart,this.cachedFunctions._handleOnDrag=this._handleOnDrag,this._handleTouch=this._selectControlNode,this._handleTap=function(){},this._handleOnDrag=this._controlNodeDrag,this._handleDragStart=function(){},this._manipulationReleaseOverload=this._releaseControlNode,this._redraw()},e._selectControlNode=function(t){this.edgeBeingEdited.controlNodes.from.unselect(),this.edgeBeingEdited.controlNodes.to.unselect(),this.selectedControlNode=this.edgeBeingEdited._getSelectedControlNode(this._XconvertDOMtoCanvas(t.x),this._YconvertDOMtoCanvas(t.y)),null!==this.selectedControlNode&&(this.selectedControlNode.select(),this.freezeSimulation=!0),this._redraw()},e._controlNodeDrag=function(t){var e=this._getPointer(t.gesture.center);null!==this.selectedControlNode&&void 0!==this.selectedControlNode&&(this.selectedControlNode.x=this._XconvertDOMtoCanvas(e.x),this.selectedControlNode.y=this._YconvertDOMtoCanvas(e.y)),this._redraw()},e._releaseControlNode=function(t){var e=this._getNodeAt(t);null!==e?(1==this.edgeBeingEdited.controlNodes.from.selected&&(this.edgeBeingEdited._restoreControlNodes(),this._editEdge(e.id,this.edgeBeingEdited.to.id),this.edgeBeingEdited.controlNodes.from.unselect()),1==this.edgeBeingEdited.controlNodes.to.selected&&(this.edgeBeingEdited._restoreControlNodes(),this._editEdge(this.edgeBeingEdited.from.id,e.id),this.edgeBeingEdited.controlNodes.to.unselect())):this.edgeBeingEdited._restoreControlNodes(),this.freezeSimulation=!1,this._redraw()},e._handleConnect=function(t){if(0==this._getSelectedNodeCount()){var e=this._getNodeAt(t);if(null!=e)if(e.clusterSize>1)alert(this.constants.locales[this.constants.locale].createEdgeError);else{this._selectObject(e,!1);var i=this.sectors.support.nodes;i.targetNode=new o({id:"targetNode"},{},{},this.constants);var s=i.targetNode;s.x=e.x,s.y=e.y,this.edges.connectionEdge=new n({id:"connectionEdge",from:e.id,to:s.id},this,this.constants);var r=this.edges.connectionEdge;r.from=e,r.connected=!0,r.options.smoothCurves={enabled:!0,dynamic:!1,type:"continuous",roundness:.5},r.selected=!0,r.to=s,this.cachedFunctions._handleOnDrag=this._handleOnDrag,this._handleOnDrag=function(t){var e=this._getPointer(t.gesture.center),i=this.edges.connectionEdge;i.to.x=this._XconvertDOMtoCanvas(e.x),i.to.y=this._YconvertDOMtoCanvas(e.y)},this.moving=!0,this.start()}}},e._finishConnect=function(t){if(1==this._getSelectedNodeCount()){var e=this._getPointer(t.gesture.center);this._handleOnDrag=this.cachedFunctions._handleOnDrag,delete this.cachedFunctions._handleOnDrag;var i=this.edges.connectionEdge.fromId;delete this.edges.connectionEdge,delete this.sectors.support.nodes.targetNode,delete this.sectors.support.nodes.targetViaNode;var s=this._getNodeAt(e);null!=s&&(s.clusterSize>1?alert(this.constants.locales[this.constants.locale].createEdgeError):(this._createEdge(i,s.id),this._createManipulatorBar())),this._unselectAll()}},e._addNode=function(){if(this._selectionIsEmpty()&&1==this.editMode){var t=this._pointerToPositionObject(this.pointerPosition),e={id:s.randomUUID(),x:t.left,y:t.top,label:"new",allowedToMoveX:!0,allowedToMoveY:!0};if(this.triggerFunctions.add){if(2!=this.triggerFunctions.add.length)throw new Error("The function for add does not support two arguments (data,callback)");var i=this;this.triggerFunctions.add(e,function(t){i.nodesData.add(t),i._createManipulatorBar(),i.moving=!0,i.start()})}else this.nodesData.add(e),this._createManipulatorBar(),this.moving=!0,this.start()}},e._createEdge=function(t,e){if(1==this.editMode){var i={from:t,to:e};if(this.triggerFunctions.connect){if(2!=this.triggerFunctions.connect.length)throw new Error("The function for connect does not support two arguments (data,callback)");var s=this;this.triggerFunctions.connect(i,function(t){s.edgesData.add(t),s.moving=!0,s.start()})}else this.edgesData.add(i),this.moving=!0,this.start()}},e._editEdge=function(t,e){if(1==this.editMode){var i={id:this.edgeBeingEdited.id,from:t,to:e};if(this.triggerFunctions.editEdge){if(2!=this.triggerFunctions.editEdge.length)throw new Error("The function for edit does not support two arguments (data, callback)");var s=this;this.triggerFunctions.editEdge(i,function(t){s.edgesData.update(t),s.moving=!0,s.start()})}else this.edgesData.update(i),this.moving=!0,this.start()}},e._editNode=function(){if(!this.triggerFunctions.edit||1!=this.editMode)throw new Error("No edit function has been bound to this button");var t=this._getSelectedNode(),e={id:t.id,label:t.label,group:t.options.group,shape:t.options.shape,color:{background:t.options.color.background,border:t.options.color.border,highlight:{background:t.options.color.highlight.background,border:t.options.color.highlight.border}}};if(2!=this.triggerFunctions.edit.length)throw new Error("The function for edit does not support two arguments (data, callback)");var i=this;this.triggerFunctions.edit(e,function(t){i.nodesData.update(t),i._createManipulatorBar(),i.moving=!0,i.start()})},e._deleteSelected=function(){if(!this._selectionIsEmpty()&&1==this.editMode)if(this._clusterInSelection())alert(this.constants.locales[this.constants.locale].deleteClusterError);else{var t=this.getSelectedNodes(),e=this.getSelectedEdges();if(this.triggerFunctions.del){var i=this,s={nodes:t,edges:e};if(2!=this.triggerFunctions.del.length)throw new Error("The function for delete does not support two arguments (data, callback)");this.triggerFunctions.del(s,function(t){i.edgesData.remove(t.edges),i.nodesData.remove(t.nodes),i._unselectAll(),i.moving=!0,i.start()})}else this.edgesData.remove(e),this.nodesData.remove(t),this._unselectAll(),this.moving=!0,this.start()}}},function(t,e,i){var s=(i(1),i(45));e._cleanNavigation=function(){if(0!=this.navigationHammers.existing.length){for(var t=0;t0){var t,e,i=0,s=!1,o=!1;for(e in this.nodes)this.nodes.hasOwnProperty(e)&&(t=this.nodes[e],-1!=t.level?s=!0:o=!0,is&&(n.xFixed=!1,n.x=i[n.level].minPos,r=!0):n.yFixed&&n.level>s&&(n.yFixed=!1,n.y=i[n.level].minPos,r=!0),1==r&&(i[n.level].minPos+=i[n.level].nodeSpacing,n.edges.length>1&&this._placeBranchNodes(n.edges,n.id,i,n.level))}},e._setLevel=function(t,e,i){for(var s=0;st)&&(o.level=t,o.edges.length>1&&this._setLevel(t+1,o.edges,o.id))}},e._setLevelDirected=function(t,e,i){this.nodes[i].hierarchyEnumerated=!0;for(var s,o,n=0;n1&&s.hierarchyEnumerated===!1&&this._setLevelDirected(s.level,s.edges,s.id)},e._restoreNodes=function(){for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&(this.nodes[t].xFixed=!1,this.nodes[t].yFixed=!1)}},function(t,e,i){function s(){this.constants.smoothCurves.enabled=!this.constants.smoothCurves.enabled;var t=document.getElementById("graph_toggleSmooth");t.style.background=1==this.constants.smoothCurves.enabled?"#A4FF56":"#FF8532",this._configureSmoothCurves(!1)}function o(){for(var t in this.calculationNodes)this.calculationNodes.hasOwnProperty(t)&&(this.calculationNodes[t].vx=0,this.calculationNodes[t].vy=0,this.calculationNodes[t].fx=0,this.calculationNodes[t].fy=0);1==this.constants.hierarchicalLayout.enabled?(this._setupHierarchicalLayout(),a.call(this,"graph_H_nd",1,"physics_hierarchicalRepulsion_nodeDistance"),a.call(this,"graph_H_cg",1,"physics_centralGravity"),a.call(this,"graph_H_sc",1,"physics_springConstant"),a.call(this,"graph_H_sl",1,"physics_springLength"),a.call(this,"graph_H_damp",1,"physics_damping")):this.repositionNodes(),this.moving=!0,this.start()}function n(){var t="No options are required, default values used.",e=[],i=document.getElementById("graph_physicsMethod1"),s=document.getElementById("graph_physicsMethod2");if(1==i.checked){if(this.constants.physics.barnesHut.gravitationalConstant!=this.backupConstants.physics.barnesHut.gravitationalConstant&&e.push("gravitationalConstant: "+this.constants.physics.barnesHut.gravitationalConstant),this.constants.physics.centralGravity!=this.backupConstants.physics.barnesHut.centralGravity&&e.push("centralGravity: "+this.constants.physics.centralGravity),this.constants.physics.springLength!=this.backupConstants.physics.barnesHut.springLength&&e.push("springLength: "+this.constants.physics.springLength),this.constants.physics.springConstant!=this.backupConstants.physics.barnesHut.springConstant&&e.push("springConstant: "+this.constants.physics.springConstant),this.constants.physics.damping!=this.backupConstants.physics.barnesHut.damping&&e.push("damping: "+this.constants.physics.damping),0!=e.length){t="var options = {",t+="physics: {barnesHut: {";for(var o=0;othis.constants.clustering.clusterThreshold&&1==this.constants.clustering.enabled&&this.clusterToFit(this.constants.clustering.reduceToNodes,!1),this._calculateForces())},e._calculateForces=function(){this._calculateGravitationalForces(),this._calculateNodeForces(),this.constants.physics.springConstant>0&&(1==this.constants.smoothCurves.enabled&&1==this.constants.smoothCurves.dynamic?this._calculateSpringForcesWithSupport():1==this.constants.physics.hierarchicalRepulsion.enabled?this._calculateHierarchicalSpringForces():this._calculateSpringForces())},e._updateCalculationNodes=function(){if(1==this.constants.smoothCurves.enabled&&1==this.constants.smoothCurves.dynamic){this.calculationNodes={},this.calculationNodeIndices=[];for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&(this.calculationNodes[t]=this.nodes[t]);var e=this.sectors.support.nodes;for(var i in e)e.hasOwnProperty(i)&&(this.edges.hasOwnProperty(e[i].parentEdgeId)?this.calculationNodes[i]=e[i]:e[i]._setForce(0,0));for(var s in this.calculationNodes)this.calculationNodes.hasOwnProperty(s)&&this.calculationNodeIndices.push(s)}else this.calculationNodes=this.nodes,this.calculationNodeIndices=this.nodeIndices},e._calculateGravitationalForces=function(){var t,e,i,s,o,n=this.calculationNodes,r=this.constants.physics.centralGravity,a=0;for(o=0;oSimulation Mode:Barnes HutRepulsionHierarchical
Options:
',this.containerElement.parentElement.insertBefore(this.physicsConfiguration,this.containerElement),this.optionsDiv=document.createElement("div"),this.optionsDiv.style.fontSize="14px",this.optionsDiv.style.fontFamily="verdana",this.containerElement.parentElement.insertBefore(this.optionsDiv,this.containerElement); -var e;e=document.getElementById("graph_BH_gc"),e.onchange=a.bind(this,"graph_BH_gc",-1,"physics_barnesHut_gravitationalConstant"),e=document.getElementById("graph_BH_cg"),e.onchange=a.bind(this,"graph_BH_cg",1,"physics_centralGravity"),e=document.getElementById("graph_BH_sc"),e.onchange=a.bind(this,"graph_BH_sc",1,"physics_springConstant"),e=document.getElementById("graph_BH_sl"),e.onchange=a.bind(this,"graph_BH_sl",1,"physics_springLength"),e=document.getElementById("graph_BH_damp"),e.onchange=a.bind(this,"graph_BH_damp",1,"physics_damping"),e=document.getElementById("graph_R_nd"),e.onchange=a.bind(this,"graph_R_nd",1,"physics_repulsion_nodeDistance"),e=document.getElementById("graph_R_cg"),e.onchange=a.bind(this,"graph_R_cg",1,"physics_centralGravity"),e=document.getElementById("graph_R_sc"),e.onchange=a.bind(this,"graph_R_sc",1,"physics_springConstant"),e=document.getElementById("graph_R_sl"),e.onchange=a.bind(this,"graph_R_sl",1,"physics_springLength"),e=document.getElementById("graph_R_damp"),e.onchange=a.bind(this,"graph_R_damp",1,"physics_damping"),e=document.getElementById("graph_H_nd"),e.onchange=a.bind(this,"graph_H_nd",1,"physics_hierarchicalRepulsion_nodeDistance"),e=document.getElementById("graph_H_cg"),e.onchange=a.bind(this,"graph_H_cg",1,"physics_centralGravity"),e=document.getElementById("graph_H_sc"),e.onchange=a.bind(this,"graph_H_sc",1,"physics_springConstant"),e=document.getElementById("graph_H_sl"),e.onchange=a.bind(this,"graph_H_sl",1,"physics_springLength"),e=document.getElementById("graph_H_damp"),e.onchange=a.bind(this,"graph_H_damp",1,"physics_damping"),e=document.getElementById("graph_H_direction"),e.onchange=a.bind(this,"graph_H_direction",t,"hierarchicalLayout_direction"),e=document.getElementById("graph_H_levsep"),e.onchange=a.bind(this,"graph_H_levsep",1,"hierarchicalLayout_levelSeparation"),e=document.getElementById("graph_H_nspac"),e.onchange=a.bind(this,"graph_H_nspac",1,"hierarchicalLayout_nodeSpacing");var i=document.getElementById("graph_physicsMethod1"),d=document.getElementById("graph_physicsMethod2"),l=document.getElementById("graph_physicsMethod3");d.checked=!0,this.constants.physics.barnesHut.enabled&&(i.checked=!0),this.constants.hierarchicalLayout.enabled&&(l.checked=!0);var c=document.getElementById("graph_toggleSmooth"),p=document.getElementById("graph_repositionNodes"),u=document.getElementById("graph_generateOptions");c.onclick=s.bind(this),p.onclick=o.bind(this),u.onclick=n.bind(this),c.style.background=1==this.constants.smoothCurves&&0==this.constants.dynamicSmoothCurves?"#A4FF56":"#FF8532",r.apply(this),i.onchange=r.bind(this),d.onchange=r.bind(this),l.onchange=r.bind(this)}},e._overWriteGraphConstants=function(t,e){var i=t.split("_");1==i.length?this.constants[i[0]]=e:2==i.length?this.constants[i[0]][i[1]]=e:3==i.length&&(this.constants[i[0]][i[1]][i[2]]=e)}},function(t){function e(t){throw new Error("Cannot find module '"+t+"'.")}e.keys=function(){return[]},e.resolve=e,t.exports=e,e.id=67},function(t,e){e._calculateNodeForces=function(){var t,e,i,s,o,n,r,a,h,d,l,c=this.calculationNodes,p=this.calculationNodeIndices,u=-2/3,m=4/3,f=this.constants.physics.repulsion.nodeDistance,g=f;for(d=0;di&&(r=.5*g>i?1:v*i+m,r*=0==n?1:1+n*this.constants.clustering.forceAmplification,r/=Math.max(i,.01*g),s=t*r,o=e*r,a.fx-=s,a.fy-=o,h.fx+=s,h.fy+=o)}}},function(t,e){e._calculateNodeForces=function(){var t,e,i,s,o,n,r,a,h,d,l=this.calculationNodes,c=this.calculationNodeIndices,p=this.constants.physics.hierarchicalRepulsion.nodeDistance;for(h=0;hi?-Math.pow(u*i,2)+Math.pow(u*p,2):0,0==i?i=.01:n/=i,s=t*n,o=e*n,r.fx-=s,r.fy-=o,a.fx+=s,a.fy+=o}},e._calculateHierarchicalSpringForces=function(){for(var t,e,i,s,o,n,r,a,h,d=this.edges,l=this.calculationNodes,c=this.calculationNodeIndices,p=0;pn;n++)t=e[i[n]],t.options.mass>0&&(this._getForceContribution(o.root.children.NW,t),this._getForceContribution(o.root.children.NE,t),this._getForceContribution(o.root.children.SW,t),this._getForceContribution(o.root.children.SE,t))}},e._getForceContribution=function(t,e){if(t.childrenCount>0){var i,s,o;if(i=t.centerOfMass.x-e.x,s=t.centerOfMass.y-e.y,o=Math.sqrt(i*i+s*s),o*t.calcSize>this.constants.physics.barnesHut.thetaInverted){0==o&&(o=.1*Math.random(),i=o);var n=this.constants.physics.barnesHut.gravitationalConstant*t.mass*e.options.mass/(o*o*o),r=i*n,a=s*n;e.fx+=r,e.fy+=a}else if(4==t.childrenCount)this._getForceContribution(t.children.NW,e),this._getForceContribution(t.children.NE,e),this._getForceContribution(t.children.SW,e),this._getForceContribution(t.children.SE,e);else if(t.children.data.id!=e.id){0==o&&(o=.5*Math.random(),i=o);var n=this.constants.physics.barnesHut.gravitationalConstant*t.mass*e.options.mass/(o*o*o),r=i*n,a=s*n;e.fx+=r,e.fy+=a}}},e._formBarnesHutTree=function(t,e){for(var i,s=e.length,o=Number.MAX_VALUE,n=Number.MAX_VALUE,r=-Number.MAX_VALUE,a=-Number.MAX_VALUE,h=0;s>h;h++){var d=t[e[h]].x,l=t[e[h]].y;t[e[h]].options.mass>0&&(o>d&&(o=d),d>r&&(r=d),n>l&&(n=l),l>a&&(a=l))}var c=Math.abs(r-o)-Math.abs(a-n);c>0?(n-=.5*c,a+=.5*c):(o+=.5*c,r-=.5*c);var p=1e-5,u=Math.max(p,Math.abs(r-o)),m=.5*u,f=.5*(o+r),g=.5*(n+a),v={root:{centerOfMass:{x:0,y:0},mass:0,range:{minX:f-m,maxX:f+m,minY:g-m,maxY:g+m},size:u,calcSize:1/u,children:{data:null},maxWidth:0,level:0,childrenCount:4}};for(this._splitBranch(v.root),h=0;s>h;h++)i=t[e[h]],i.options.mass>0&&this._placeInTree(v.root,i);this.barnesHutTree=v},e._updateBranchMass=function(t,e){var i=t.mass+e.options.mass,s=1/i;t.centerOfMass.x=t.centerOfMass.x*t.mass+e.x*e.options.mass,t.centerOfMass.x*=s,t.centerOfMass.y=t.centerOfMass.y*t.mass+e.y*e.options.mass,t.centerOfMass.y*=s,t.mass=i;var o=Math.max(Math.max(e.height,e.radius),e.width);t.maxWidth=t.maxWidthe.x?t.children.NW.range.maxY>e.y?this._placeInRegion(t,e,"NW"):this._placeInRegion(t,e,"SW"):t.children.NW.range.maxY>e.y?this._placeInRegion(t,e,"NE"):this._placeInRegion(t,e,"SE")},e._placeInRegion=function(t,e,i){switch(t.children[i].childrenCount){case 0:t.children[i].children.data=e,t.children[i].childrenCount=1,this._updateBranchMass(t.children[i],e);break;case 1:t.children[i].children.data.x==e.x&&t.children[i].children.data.y==e.y?(e.x+=Math.random(),e.y+=Math.random()):(this._splitBranch(t.children[i]),this._placeInTree(t.children[i],e));break;case 4:this._placeInTree(t.children[i],e)}},e._splitBranch=function(t){var e=null;1==t.childrenCount&&(e=t.children.data,t.mass=0,t.centerOfMass.x=0,t.centerOfMass.y=0),t.childrenCount=4,t.children.data=null,this._insertRegion(t,"NW"),this._insertRegion(t,"NE"),this._insertRegion(t,"SW"),this._insertRegion(t,"SE"),null!=e&&this._placeInTree(t,e)},e._insertRegion=function(t,e){var i,s,o,n,r=.5*t.size;switch(e){case"NW":i=t.range.minX,s=t.range.minX+r,o=t.range.minY,n=t.range.minY+r;break;case"NE":i=t.range.minX+r,s=t.range.maxX,o=t.range.minY,n=t.range.minY+r;break;case"SW":i=t.range.minX,s=t.range.minX+r,o=t.range.minY+r,n=t.range.maxY;break;case"SE":i=t.range.minX+r,s=t.range.maxX,o=t.range.minY+r,n=t.range.maxY}t.children[e]={centerOfMass:{x:0,y:0},mass:0,range:{minX:i,maxX:s,minY:o,maxY:n},size:.5*t.size,calcSize:2*t.calcSize,children:{data:null},maxWidth:0,level:t.level+1,childrenCount:0}},e._drawTree=function(t,e){void 0!==this.barnesHutTree&&(t.lineWidth=1,this._drawBranch(this.barnesHutTree.root,t,e))},e._drawBranch=function(t,e,i){void 0===i&&(i="#FF0000"),4==t.childrenCount&&(this._drawBranch(t.children.NW,e),this._drawBranch(t.children.NE,e),this._drawBranch(t.children.SE,e),this._drawBranch(t.children.SW,e)),e.strokeStyle=i,e.beginPath(),e.moveTo(t.range.minX,t.range.minY),e.lineTo(t.range.maxX,t.range.minY),e.stroke(),e.beginPath(),e.moveTo(t.range.maxX,t.range.minY),e.lineTo(t.range.maxX,t.range.maxY),e.stroke(),e.beginPath(),e.moveTo(t.range.maxX,t.range.maxY),e.lineTo(t.range.minX,t.range.maxY),e.stroke(),e.beginPath(),e.moveTo(t.range.minX,t.range.maxY),e.lineTo(t.range.minX,t.range.minY),e.stroke()}},function(t){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children=[],t.webpackPolyfill=1),t}},function(t,e){(function(e){t.exports=e}).call(e,{})}])}); +"use strict";!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):"object"==typeof exports?exports.vis=e():t.vis=e()}(this,function(){return function(t){function e(s){if(i[s])return i[s].exports;var o=i[s]={exports:{},id:s,loaded:!1};return t[s].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var i={};return e.m=t,e.c=i,e.p="",e(0)}([function(t,e,i){e.util=i(1),e.DOMutil=i(6),e.DataSet=i(7),e.DataView=i(9),e.Queue=i(8),e.Graph3d=i(10),e.graph3d={Camera:i(14),Filter:i(15),Point2d:i(13),Point3d:i(12),Slider:i(16),StepNumber:i(17)},e.Timeline=i(18),e.Graph2d=i(42),e.timeline={DateUtil:i(24),DataStep:i(45),Range:i(21),stack:i(28),TimeStep:i(38),components:{items:{Item:i(30),BackgroundItem:i(34),BoxItem:i(32),PointItem:i(33),RangeItem:i(29)},Component:i(23),CurrentTime:i(39),CustomTime:i(41),DataAxis:i(44),GraphGroup:i(46),Group:i(27),BackgroundGroup:i(31),ItemSet:i(26),Legend:i(50),LineGraph:i(43),TimeAxis:i(37)}},e.Network=i(51),e.network={Edge:i(52),Groups:i(54),Images:i(55),Node:i(53),Popup:i(56),dotparser:i(57),gephiParser:i(58)},e.Graph=function(){throw new Error("Graph is renamed to Network. Please create a graph as new vis.Network(...)")},e.moment=i(2),e.hammer=i(19)},function(t,e,i){var s=i(2);e.isNumber=function(t){return t instanceof Number||"number"==typeof t},e.isString=function(t){return t instanceof String||"string"==typeof t},e.isDate=function(t){if(t instanceof Date)return!0;if(e.isString(t)){var i=o.exec(t);if(i)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},e.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},e.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},e.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var s=arguments[e];for(var o in s)s.hasOwnProperty(o)&&(t[o]=s[o])}return t},e.selectiveExtend=function(t,e){if(!Array.isArray(t))throw new Error("Array with property names expected as first argument");for(var i=2;ii;i++)if(t[i]!=e[i])return!1;return!0},e.convert=function(t,i){var n;if(void 0===t)return void 0;if(null===t)return null;if(!i)return t;if("string"!=typeof i&&!(i instanceof String))throw new Error("Type must be a string");switch(i){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return Number(t.valueOf());case"string":case"String":return String(t);case"Date":if(e.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(s.isMoment(t))return new Date(t.valueOf());if(e.isString(t))return n=o.exec(t),n?new Date(Number(n[1])):s(t).toDate();throw new Error("Cannot convert object of type "+e.getType(t)+" to type Date");case"Moment":if(e.isNumber(t))return s(t);if(t instanceof Date)return s(t.valueOf());if(s.isMoment(t))return s(t);if(e.isString(t))return n=o.exec(t),s(n?Number(n[1]):t);throw new Error("Cannot convert object of type "+e.getType(t)+" to type Date");case"ISODate":if(e.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(s.isMoment(t))return t.toDate().toISOString();if(e.isString(t))return n=o.exec(t),n?new Date(Number(n[1])).toISOString():new Date(t).toISOString();throw new Error("Cannot convert object of type "+e.getType(t)+" to type ISODate");case"ASPDate":if(e.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(e.isString(t)){n=o.exec(t);var r;return r=n?new Date(Number(n[1])).valueOf():new Date(t).valueOf(),"/Date("+r+")/"}throw new Error("Cannot convert object of type "+e.getType(t)+" to type ASPDate");default:throw new Error('Unknown type "'+i+'"')}};var o=/^\/?Date\((\-?\d+)/i;e.getType=function(t){var e=typeof t;return"object"==e?null==t?"null":t instanceof Boolean?"Boolean":t instanceof Number?"Number":t instanceof String?"String":Array.isArray(t)?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},e.getAbsoluteLeft=function(t){return t.getBoundingClientRect().left+window.pageXOffset},e.getAbsoluteTop=function(t){return t.getBoundingClientRect().top+window.pageYOffset},e.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},e.removeClassName=function(t,e){var i=t.className.split(" "),s=i.indexOf(e);-1!=s&&(i.splice(s,1),t.className=i.join(" "))},e.forEach=function(t,e){var i,s;if(Array.isArray(t))for(i=0,s=t.length;s>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},e.toArray=function(t){var e=[];for(var i in t)t.hasOwnProperty(i)&&e.push(t[i]);return e},e.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},e.addEventListener=function(t,e,i,s){t.addEventListener?(void 0===s&&(s=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,s)):t.attachEvent("on"+e,i)},e.removeEventListener=function(t,e,i,s){t.removeEventListener?(void 0===s&&(s=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,s)):t.detachEvent("on"+e,i)},e.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},e.getTarget=function(t){t||(t=window.event);var e;return t.target?e=t.target:t.srcElement&&(e=t.srcElement),void 0!=e.nodeType&&3==e.nodeType&&(e=e.parentNode),e},e.option={},e.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},e.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},e.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?String(t):e||null},e.option.asSize=function(t,i){return"function"==typeof t&&(t=t()),e.isString(t)?t:e.isNumber(t)?t+"px":i||null},e.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null},e.hexToRGB=function(t){var e=/^#?([a-f\d])([a-f\d])([a-f\d])$/i;t=t.replace(e,function(t,e,i,s){return e+e+i+i+s+s});var i=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(t);return i?{r:parseInt(i[1],16),g:parseInt(i[2],16),b:parseInt(i[3],16)}:null},e.RGBToHex=function(t,e,i){return"#"+((1<<24)+(t<<16)+(e<<8)+i).toString(16).slice(1)},e.parseColor=function(t){var i;if(e.isString(t)){if(e.isValidRGB(t)){var s=t.substr(4).substr(0,t.length-5).split(",");t=e.RGBToHex(s[0],s[1],s[2])}if(e.isValidHex(t)){var o=e.hexToHSV(t),n={h:o.h,s:.45*o.s,v:Math.min(1,1.05*o.v)},r={h:o.h,s:Math.min(1,1.25*o.v),v:.6*o.v},a=e.HSVToHex(r.h,r.h,r.v),h=e.HSVToHex(n.h,n.s,n.v);i={background:t,border:a,highlight:{background:h,border:a},hover:{background:h,border:a}}}else i={background:t,border:t,highlight:{background:t,border:t},hover:{background:t,border:t}}}else i={},i.background=t.background||"white",i.border=t.border||i.background,e.isString(t.highlight)?i.highlight={border:t.highlight,background:t.highlight}:(i.highlight={},i.highlight.background=t.highlight&&t.highlight.background||i.background,i.highlight.border=t.highlight&&t.highlight.border||i.border),e.isString(t.hover)?i.hover={border:t.hover,background:t.hover}:(i.hover={},i.hover.background=t.hover&&t.hover.background||i.background,i.hover.border=t.hover&&t.hover.border||i.border);return i},e.RGBToHSV=function(t,e,i){t/=255,e/=255,i/=255;var s=Math.min(t,Math.min(e,i)),o=Math.max(t,Math.max(e,i));if(s==o)return{h:0,s:0,v:s};var n=t==s?e-i:i==s?t-e:i-t,r=t==s?3:i==s?1:5,a=60*(r-n/(o-s))/360,h=(o-s)/o,d=o;return{h:a,s:h,v:d}};var n={split:function(t){var e={};return t.split(";").forEach(function(t){if(""!=t.trim()){var i=t.split(":"),s=i[0].trim(),o=i[1].trim();e[s]=o}}),e},join:function(t){return Object.keys(t).map(function(e){return e+": "+t[e]}).join("; ")}};e.addCssText=function(t,i){var s=n.split(t.style.cssText),o=n.split(i),r=e.extend(s,o);t.style.cssText=n.join(r)},e.removeCssText=function(t,e){var i=n.split(t.style.cssText),s=n.split(e);for(var o in s)s.hasOwnProperty(o)&&delete i[o];t.style.cssText=n.join(i)},e.HSVToRGB=function(t,e,i){var s,o,n,r=Math.floor(6*t),a=6*t-r,h=i*(1-e),d=i*(1-a*e),l=i*(1-(1-a)*e);switch(r%6){case 0:s=i,o=l,n=h;break;case 1:s=d,o=i,n=h;break;case 2:s=h,o=i,n=l;break;case 3:s=h,o=d,n=i;break;case 4:s=l,o=h,n=i;break;case 5:s=i,o=h,n=d}return{r:Math.floor(255*s),g:Math.floor(255*o),b:Math.floor(255*n)}},e.HSVToHex=function(t,i,s){var o=e.HSVToRGB(t,i,s);return e.RGBToHex(o.r,o.g,o.b)},e.hexToHSV=function(t){var i=e.hexToRGB(t);return e.RGBToHSV(i.r,i.g,i.b)},e.isValidHex=function(t){var e=/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(t);return e},e.isValidRGB=function(t){t=t.replace(" ","");var e=/rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)/i.test(t);return e},e.selectiveBridgeObject=function(t,i){if("object"==typeof i){for(var s=Object.create(i),o=0;o=r&&o>n;){var h=Math.floor((r+a)/2),d=t[h],l=void 0===s?d[i]:d[i][s],c=e(l);if(0==c)return h;-1==c?r=h+1:a=h-1,n++}return-1},e.binarySearchValue=function(t,e,i,s){for(var o,n,r,a,h=1e4,d=0,l=0,c=t.length-1;c>=l&&h>d;){if(a=Math.floor(.5*(c+l)),o=t[Math.max(0,a-1)][i],n=t[a][i],r=t[Math.min(t.length-1,a+1)][i],n==e)return a;if(e>o&&n>e)return"before"==s?Math.max(0,a-1):a;if(e>n&&r>e)return"before"==s?a:Math.min(t.length-1,a+1);e>n?l=a+1:c=a-1,d++}return-1},e.easeInOutQuad=function(t,e,i,s){var o=i-e;return t/=s/2,1>t?o/2*t*t+e:(t--,-o/2*(t*(t-2)-1)+e)},e.easingFunctions={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return t*(2-t)},easeInOutQuad:function(t){return.5>t?2*t*t:-1+(4-2*t)*t},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return--t*t*t+1},easeInOutCubic:function(t){return.5>t?4*t*t*t:(t-1)*(2*t-2)*(2*t-2)+1},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return 1- --t*t*t*t},easeInOutQuart:function(t){return.5>t?8*t*t*t*t:1-8*--t*t*t*t},easeInQuint:function(t){return t*t*t*t*t},easeOutQuint:function(t){return 1+--t*t*t*t*t},easeInOutQuint:function(t){return.5>t?16*t*t*t*t*t:1+16*--t*t*t*t*t}}},function(t,e,i){t.exports="undefined"!=typeof window&&window.moment||i(3)},function(t,e,i){var s;(function(t,o){(function(n){function r(t,e,i){switch(arguments.length){case 2:return null!=t?t:e;case 3:return null!=t?t:null!=e?e:i;default:throw new Error("Implement me")}}function a(t,e){return Le.call(t,e)}function h(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function d(t){Ce.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+t)}function l(t,e){var i=!0;return b(function(){return i&&(d(t),i=!1),e.apply(this,arguments)},e)}function c(t,e){Mi[t]||(d(e),Mi[t]=!0)}function p(t,e){return function(i){return w(t.call(this,i),e)}}function u(t,e){return function(i){return this.localeData().ordinal(t.call(this,i),e)}}function m(t,e){var i,s,o=12*(e.year()-t.year())+(e.month()-t.month()),n=t.clone().add(o,"months");return 0>e-n?(i=t.clone().add(o-1,"months"),s=(e-n)/(n-i)):(i=t.clone().add(o+1,"months"),s=(e-n)/(i-n)),-(o+s)}function f(t,e,i){var s;return null==i?e:null!=t.meridiemHour?t.meridiemHour(e,i):null!=t.isPM?(s=t.isPM(i),s&&12>e&&(e+=12),s||12!==e||(e=0),e):e}function g(){}function v(t,e){e!==!1&&F(t),_(this,t),this._d=new Date(+t._d),Di===!1&&(Di=!0,Ce.updateOffset(this),Di=!1)}function y(t){var e=N(t),i=e.year||0,s=e.quarter||0,o=e.month||0,n=e.week||0,r=e.day||0,a=e.hour||0,h=e.minute||0,d=e.second||0,l=e.millisecond||0;this._milliseconds=+l+1e3*d+6e4*h+36e5*a,this._days=+r+7*n,this._months=+o+3*s+12*i,this._data={},this._locale=Ce.localeData(),this._bubble()}function b(t,e){for(var i in e)a(e,i)&&(t[i]=e[i]);return a(e,"toString")&&(t.toString=e.toString),a(e,"valueOf")&&(t.valueOf=e.valueOf),t}function _(t,e){var i,s,o;if("undefined"!=typeof e._isAMomentObject&&(t._isAMomentObject=e._isAMomentObject),"undefined"!=typeof e._i&&(t._i=e._i),"undefined"!=typeof e._f&&(t._f=e._f),"undefined"!=typeof e._l&&(t._l=e._l),"undefined"!=typeof e._strict&&(t._strict=e._strict),"undefined"!=typeof e._tzm&&(t._tzm=e._tzm),"undefined"!=typeof e._isUTC&&(t._isUTC=e._isUTC),"undefined"!=typeof e._offset&&(t._offset=e._offset),"undefined"!=typeof e._pf&&(t._pf=e._pf),"undefined"!=typeof e._locale&&(t._locale=e._locale),Ye.length>0)for(i in Ye)s=Ye[i],o=e[s],"undefined"!=typeof o&&(t[s]=o);return t}function x(t){return 0>t?Math.ceil(t):Math.floor(t)}function w(t,e,i){for(var s=""+Math.abs(t),o=t>=0;s.lengths;s++)(i&&t[s]!==e[s]||!i&&I(t[s])!==I(e[s]))&&r++;return r+n}function k(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=gi[t]||vi[e]||e}return t}function N(t){var e,i,s={};for(i in t)a(t,i)&&(e=k(i),e&&(s[e]=t[i]));return s}function L(t){var e,i;if(0===t.indexOf("week"))e=7,i="day";else{if(0!==t.indexOf("month"))return;e=12,i="month"}Ce[t]=function(s,o){var r,a,h=Ce._locale[t],d=[];if("number"==typeof s&&(o=s,s=n),a=function(t){var e=Ce().utc().set(i,t);return h.call(Ce._locale,e,s||"")},null!=o)return a(o);for(r=0;e>r;r++)d.push(a(r));return d}}function I(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=e>=0?Math.floor(e):Math.ceil(e)),i}function z(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function P(t,e,i){return me(Ce([t,11,31+e-i]),e,i).week}function A(t){return R(t)?366:365}function R(t){return t%4===0&&t%100!==0||t%400===0}function F(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[ze]<0||t._a[ze]>11?ze:t._a[Pe]<1||t._a[Pe]>z(t._a[Ie],t._a[ze])?Pe:t._a[Ae]<0||t._a[Ae]>24||24===t._a[Ae]&&(0!==t._a[Re]||0!==t._a[Fe]||0!==t._a[He])?Ae:t._a[Re]<0||t._a[Re]>59?Re:t._a[Fe]<0||t._a[Fe]>59?Fe:t._a[He]<0||t._a[He]>999?He:-1,t._pf._overflowDayOfYear&&(Ie>e||e>Pe)&&(e=Pe),t._pf.overflow=e)}function H(t){return null==t._isValid&&(t._isValid=!isNaN(t._d.getTime())&&t._pf.overflow<0&&!t._pf.empty&&!t._pf.invalidMonth&&!t._pf.nullInput&&!t._pf.invalidFormat&&!t._pf.userInvalidated,t._strict&&(t._isValid=t._isValid&&0===t._pf.charsLeftOver&&0===t._pf.unusedTokens.length&&t._pf.bigHour===n)),t._isValid}function B(t){return t?t.toLowerCase().replace("_","-"):t}function Y(t){for(var e,i,s,o,n=0;n0;){if(s=W(o.slice(0,e).join("-")))return s;if(i&&i.length>=e&&E(o,i,!0)>=e-1)break;e--}n++}return null}function W(t){var e=null;if(!Be[t]&&We)try{e=Ce.locale(),!function(){var t=new Error('Cannot find module "./locale"');throw t.code="MODULE_NOT_FOUND",t}(),Ce.locale(e)}catch(i){}return Be[t]}function G(t,e){var i,s;return e._isUTC?(i=e.clone(),s=(Ce.isMoment(t)||O(t)?+t:+Ce(t))-+i,i._d.setTime(+i._d+s),Ce.updateOffset(i,!1),i):Ce(t).local()}function j(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function V(t){var e,i,s=t.match(Ue);for(e=0,i=s.length;i>e;e++)s[e]=wi[s[e]]?wi[s[e]]:j(s[e]);return function(o){var n="";for(e=0;i>e;e++)n+=s[e]instanceof Function?s[e].call(o,t):s[e];return n}}function U(t,e){return t.isValid()?(e=X(e,t.localeData()),yi[e]||(yi[e]=V(e)),yi[e](t)):t.localeData().invalidDate()}function X(t,e){function i(t){return e.longDateFormat(t)||t}var s=5;for(Xe.lastIndex=0;s>=0&&Xe.test(t);)t=t.replace(Xe,i),Xe.lastIndex=0,s-=1;return t}function q(t,e){var i,s=e._strict;switch(t){case"Q":return oi;case"DDDD":return ri;case"YYYY":case"GGGG":case"gggg":return s?ai:Qe;case"Y":case"G":case"g":return di;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return s?hi:Ke;case"S":if(s)return oi;case"SS":if(s)return ni;case"SSS":if(s)return ri;case"DDD":return Ze;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Je;case"a":case"A":return e._locale._meridiemParse;case"x":return ii;case"X":return si;case"Z":case"ZZ":return ti;case"T":return ei;case"SSSS":return $e;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return s?ni:qe;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return qe;case"Do":return s?e._locale._ordinalParse:e._locale._ordinalParseLenient;default:return i=new RegExp(se(ie(t.replace("\\","")),"i"))}}function Z(t){t=t||"";var e=t.match(ti)||[],i=e[e.length-1]||[],s=(i+"").match(mi)||["-",0,0],o=+(60*s[1])+I(s[2]);return"+"===s[0]?o:-o}function Q(t,e,i){var s,o=i._a;switch(t){case"Q":null!=e&&(o[ze]=3*(I(e)-1));break;case"M":case"MM":null!=e&&(o[ze]=I(e)-1);break;case"MMM":case"MMMM":s=i._locale.monthsParse(e,t,i._strict),null!=s?o[ze]=s:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(o[Pe]=I(e));break;case"Do":null!=e&&(o[Pe]=I(parseInt(e.match(/\d{1,2}/)[0],10)));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=I(e));break;case"YY":o[Ie]=Ce.parseTwoDigitYear(e);break;case"YYYY":case"YYYYY":case"YYYYYY":o[Ie]=I(e);break;case"a":case"A":i._meridiem=e;break;case"h":case"hh":i._pf.bigHour=!0;case"H":case"HH":o[Ae]=I(e);break;case"m":case"mm":o[Re]=I(e);break;case"s":case"ss":o[Fe]=I(e);break;case"S":case"SS":case"SSS":case"SSSS":o[He]=I(1e3*("0."+e));break;case"x":i._d=new Date(I(e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=Z(e);break;case"dd":case"ddd":case"dddd":s=i._locale.weekdaysParse(e),null!=s?(i._w=i._w||{},i._w.d=s):i._pf.invalidWeekday=e;break;case"w":case"ww":case"W":case"WW":case"d":case"e":case"E":t=t.substr(0,1);case"gggg":case"GGGG":case"GGGGG":t=t.substr(0,2),e&&(i._w=i._w||{},i._w[t]=I(e));break;case"gg":case"GG":i._w=i._w||{},i._w[t]=Ce.parseTwoDigitYear(e)}}function K(t){var e,i,s,o,n,a,h;e=t._w,null!=e.GG||null!=e.W||null!=e.E?(n=1,a=4,i=r(e.GG,t._a[Ie],me(Ce(),1,4).year),s=r(e.W,1),o=r(e.E,1)):(n=t._locale._week.dow,a=t._locale._week.doy,i=r(e.gg,t._a[Ie],me(Ce(),n,a).year),s=r(e.w,1),null!=e.d?(o=e.d,n>o&&++s):o=null!=e.e?e.e+n:n),h=fe(i,s,o,a,n),t._a[Ie]=h.year,t._dayOfYear=h.dayOfYear}function $(t){var e,i,s,o,n=[];if(!t._d){for(s=te(t),t._w&&null==t._a[Pe]&&null==t._a[ze]&&K(t),t._dayOfYear&&(o=r(t._a[Ie],s[Ie]),t._dayOfYear>A(o)&&(t._pf._overflowDayOfYear=!0),i=le(o,0,t._dayOfYear),t._a[ze]=i.getUTCMonth(),t._a[Pe]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=n[e]=s[e];for(;7>e;e++)t._a[e]=n[e]=null==t._a[e]?2===e?1:0:t._a[e];24===t._a[Ae]&&0===t._a[Re]&&0===t._a[Fe]&&0===t._a[He]&&(t._nextDay=!0,t._a[Ae]=0),t._d=(t._useUTC?le:de).apply(null,n),null!=t._tzm&&t._d.setUTCMinutes(t._d.getUTCMinutes()-t._tzm),t._nextDay&&(t._a[Ae]=24)}}function J(t){var e;t._d||(e=N(t._i),t._a=[e.year,e.month,e.day||e.date,e.hour,e.minute,e.second,e.millisecond],$(t))}function te(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function ee(t){if(t._f===Ce.ISO_8601)return void ne(t);t._a=[],t._pf.empty=!0;var e,i,s,o,r,a=""+t._i,h=a.length,d=0;for(s=X(t._f,t._locale).match(Ue)||[],e=0;e0&&t._pf.unusedInput.push(r),a=a.slice(a.indexOf(i)+i.length),d+=i.length),wi[o]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(o),Q(o,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(o);t._pf.charsLeftOver=h-d,a.length>0&&t._pf.unusedInput.push(a),t._pf.bigHour===!0&&t._a[Ae]<=12&&(t._pf.bigHour=n),t._a[Ae]=f(t._locale,t._a[Ae],t._meridiem),$(t),F(t)}function ie(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,s,o){return e||i||s||o})}function se(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function oe(t){var e,i,s,o,n;if(0===t._f.length)return t._pf.invalidFormat=!0,void(t._d=new Date(0/0));for(o=0;on)&&(s=n,i=e));b(t,i||e)}function ne(t){var e,i,s=t._i,o=li.exec(s);if(o){for(t._pf.iso=!0,e=0,i=pi.length;i>e;e++)if(pi[e][1].exec(s)){t._f=pi[e][0]+(o[6]||" ");break}for(e=0,i=ui.length;i>e;e++)if(ui[e][1].exec(s)){t._f+=ui[e][0];break}s.match(ti)&&(t._f+="Z"),ee(t)}else t._isValid=!1}function re(t){ne(t),t._isValid===!1&&(delete t._isValid,Ce.createFromInputFallback(t))}function ae(t,e){var i,s=[];for(i=0;it&&a.setFullYear(t),a}function le(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function ce(t,e){if("string"==typeof t)if(isNaN(t)){if(t=e.weekdaysParse(t),"number"!=typeof t)return null}else t=parseInt(t,10);return t}function pe(t,e,i,s,o){return o.relativeTime(e||1,!!i,t,s)}function ue(t,e,i){var s=Ce.duration(t).abs(),o=Ne(s.as("s")),n=Ne(s.as("m")),r=Ne(s.as("h")),a=Ne(s.as("d")),h=Ne(s.as("M")),d=Ne(s.as("y")),l=o0,l[4]=i,pe.apply({},l)}function me(t,e,i){var s,o=i-e,n=i-t.day();return n>o&&(n-=7),o-7>n&&(n+=7),s=Ce(t).add(n,"d"),{week:Math.ceil(s.dayOfYear()/7),year:s.year()}}function fe(t,e,i,s,o){var n,r,a=le(t,0,1).getUTCDay();return a=0===a?7:a,i=null!=i?i:o,n=o-a+(a>s?7:0)-(o>a?7:0),r=7*(e-1)+(i-o)+n+1,{year:r>0?t:t-1,dayOfYear:r>0?r:A(t-1)+r}}function ge(t){var e,i=t._i,s=t._f;return t._locale=t._locale||Ce.localeData(t._l),null===i||s===n&&""===i?Ce.invalid({nullInput:!0}):("string"==typeof i&&(t._i=i=t._locale.preparse(i)),Ce.isMoment(i)?new v(i,!0):(s?T(s)?oe(t):ee(t):he(t),e=new v(t),e._nextDay&&(e.add(1,"d"),e._nextDay=n),e))}function ve(t,e){var i,s;if(1===e.length&&T(e[0])&&(e=e[0]),!e.length)return Ce();for(i=e[0],s=1;s=0?"+":"-";return e+w(Math.abs(t),6)},gg:function(){return w(this.weekYear()%100,2)},gggg:function(){return w(this.weekYear(),4)},ggggg:function(){return w(this.weekYear(),5)},GG:function(){return w(this.isoWeekYear()%100,2)},GGGG:function(){return w(this.isoWeekYear(),4)},GGGGG:function(){return w(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.localeData().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.localeData().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return I(this.milliseconds()/100)},SS:function(){return w(I(this.milliseconds()/10),2)},SSS:function(){return w(this.milliseconds(),3)},SSSS:function(){return w(this.milliseconds(),3)},Z:function(){var t=this.utcOffset(),e="+";return 0>t&&(t=-t,e="-"),e+w(I(t/60),2)+":"+w(I(t)%60,2)},ZZ:function(){var t=this.utcOffset(),e="+";return 0>t&&(t=-t,e="-"),e+w(I(t/60),2)+w(I(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},x:function(){return this.valueOf()},X:function(){return this.unix()},Q:function(){return this.quarter()}},Mi={},Si=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"],Di=!1;_i.length;)Oe=_i.pop(),wi[Oe+"o"]=u(wi[Oe],Oe);for(;xi.length;)Oe=xi.pop(),wi[Oe+Oe]=p(wi[Oe],2);wi.DDDD=p(wi.DDD,3),b(g.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e;this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(t){return this._months[t.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(t){return this._monthsShort[t.month()]},monthsParse:function(t,e,i){var s,o,n;for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),s=0;12>s;s++){if(o=Ce.utc([2e3,s]),i&&!this._longMonthsParse[s]&&(this._longMonthsParse[s]=new RegExp("^"+this.months(o,"").replace(".","")+"$","i"),this._shortMonthsParse[s]=new RegExp("^"+this.monthsShort(o,"").replace(".","")+"$","i")),i||this._monthsParse[s]||(n="^"+this.months(o,"")+"|^"+this.monthsShort(o,""),this._monthsParse[s]=new RegExp(n.replace(".",""),"i")),i&&"MMMM"===e&&this._longMonthsParse[s].test(t))return s;if(i&&"MMM"===e&&this._shortMonthsParse[s].test(t))return s;if(!i&&this._monthsParse[s].test(t))return s}},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(t){return this._weekdays[t.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(t){return this._weekdaysShort[t.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(t){return this._weekdaysMin[t.day()]},weekdaysParse:function(t){var e,i,s;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=Ce([2e3,1]).day(e),s="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=new RegExp(s.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e},_longDateFormat:{LTS:"h:mm:ss A",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(t){var e=this._longDateFormat[t]; +return!e&&this._longDateFormat[t.toUpperCase()]&&(e=this._longDateFormat[t.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t]=e),e},isPM:function(t){return"p"===(t+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(t,e,i){return t>11?i?"pm":"PM":i?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(t,e,i){var s=this._calendar[t];return"function"==typeof s?s.apply(e,[i]):s},_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"},relativeTime:function(t,e,i,s){var o=this._relativeTime[i];return"function"==typeof o?o(t,e,i,s):o.replace(/%d/i,t)},pastFuture:function(t,e){var i=this._relativeTime[t>0?"future":"past"];return"function"==typeof i?i(e):i.replace(/%s/i,e)},ordinal:function(t){return this._ordinal.replace("%d",t)},_ordinal:"%d",_ordinalParse:/\d{1,2}/,preparse:function(t){return t},postformat:function(t){return t},week:function(t){return me(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},firstDayOfWeek:function(){return this._week.dow},firstDayOfYear:function(){return this._week.doy},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),Ce=function(t,e,i,s){var o;return"boolean"==typeof i&&(s=i,i=n),o={},o._isAMomentObject=!0,o._i=t,o._f=e,o._l=i,o._strict=s,o._isUTC=!1,o._pf=h(),ge(o)},Ce.suppressDeprecationWarnings=!1,Ce.createFromInputFallback=l("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(t){t._d=new Date(t._i+(t._useUTC?" UTC":""))}),Ce.min=function(){var t=[].slice.call(arguments,0);return ve("isBefore",t)},Ce.max=function(){var t=[].slice.call(arguments,0);return ve("isAfter",t)},Ce.utc=function(t,e,i,s){var o;return"boolean"==typeof i&&(s=i,i=n),o={},o._isAMomentObject=!0,o._useUTC=!0,o._isUTC=!0,o._l=i,o._i=t,o._f=e,o._strict=s,o._pf=h(),ge(o).utc()},Ce.unix=function(t){return Ce(1e3*t)},Ce.duration=function(t,e){var i,s,o,n,r=t,h=null;return Ce.isDuration(t)?r={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(r={},e?r[e]=t:r.milliseconds=t):(h=je.exec(t))?(i="-"===h[1]?-1:1,r={y:0,d:I(h[Pe])*i,h:I(h[Ae])*i,m:I(h[Re])*i,s:I(h[Fe])*i,ms:I(h[He])*i}):(h=Ve.exec(t))?(i="-"===h[1]?-1:1,o=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},r={y:o(h[2]),M:o(h[3]),d:o(h[4]),h:o(h[5]),m:o(h[6]),s:o(h[7]),w:o(h[8])}):null==r?r={}:"object"==typeof r&&("from"in r||"to"in r)&&(n=S(Ce(r.from),Ce(r.to)),r={},r.ms=n.milliseconds,r.M=n.months),s=new y(r),Ce.isDuration(t)&&a(t,"_locale")&&(s._locale=t._locale),s},Ce.version=Ee,Ce.defaultFormat=ci,Ce.ISO_8601=function(){},Ce.momentProperties=Ye,Ce.updateOffset=function(){},Ce.relativeTimeThreshold=function(t,e){return bi[t]===n?!1:e===n?bi[t]:(bi[t]=e,!0)},Ce.lang=l("moment.lang is deprecated. Use moment.locale instead.",function(t,e){return Ce.locale(t,e)}),Ce.locale=function(t,e){var i;return t&&(i="undefined"!=typeof e?Ce.defineLocale(t,e):Ce.localeData(t),i&&(Ce.duration._locale=Ce._locale=i)),Ce._locale._abbr},Ce.defineLocale=function(t,e){return null!==e?(e.abbr=t,Be[t]||(Be[t]=new g),Be[t].set(e),Ce.locale(t),Be[t]):(delete Be[t],null)},Ce.langData=l("moment.langData is deprecated. Use moment.localeData instead.",function(t){return Ce.localeData(t)}),Ce.localeData=function(t){var e;if(t&&t._locale&&t._locale._abbr&&(t=t._locale._abbr),!t)return Ce._locale;if(!T(t)){if(e=W(t))return e;t=[t]}return Y(t)},Ce.isMoment=function(t){return t instanceof v||null!=t&&a(t,"_isAMomentObject")},Ce.isDuration=function(t){return t instanceof y};for(Oe=Si.length-1;Oe>=0;--Oe)L(Si[Oe]);Ce.normalizeUnits=function(t){return k(t)},Ce.invalid=function(t){var e=Ce.utc(0/0);return null!=t?b(e._pf,t):e._pf.userInvalidated=!0,e},Ce.parseZone=function(){return Ce.apply(null,arguments).parseZone()},Ce.parseTwoDigitYear=function(t){return I(t)+(I(t)>68?1900:2e3)},Ce.isDate=O,b(Ce.fn=v.prototype,{clone:function(){return Ce(this)},valueOf:function(){return+this._d-6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var t=Ce(this).utc();return 00:!1},parsingFlags:function(){return b({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(t){return this.utcOffset(0,t)},local:function(t){return this._isUTC&&(this.utcOffset(0,t),this._isUTC=!1,t&&this.subtract(this._dateUtcOffset(),"m")),this},format:function(t){var e=U(this,t||Ce.defaultFormat);return this.localeData().postformat(e)},add:D(1,"add"),subtract:D(-1,"subtract"),diff:function(t,e,i){var s,o,n=G(t,this),r=6e4*(n.utcOffset()-this.utcOffset());return e=k(e),"year"===e||"month"===e||"quarter"===e?(o=m(this,n),"quarter"===e?o/=3:"year"===e&&(o/=12)):(s=this-n,o="second"===e?s/1e3:"minute"===e?s/6e4:"hour"===e?s/36e5:"day"===e?(s-r)/864e5:"week"===e?(s-r)/6048e5:s),i?o:x(o)},from:function(t,e){return Ce.duration({to:this,from:t}).locale(this.locale()).humanize(!e)},fromNow:function(t){return this.from(Ce(),t)},calendar:function(t){var e=t||Ce(),i=G(e,this).startOf("day"),s=this.diff(i,"days",!0),o=-6>s?"sameElse":-1>s?"lastWeek":0>s?"lastDay":1>s?"sameDay":2>s?"nextDay":7>s?"nextWeek":"sameElse";return this.format(this.localeData().calendar(o,this,Ce(e)))},isLeapYear:function(){return R(this.year())},isDST:function(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},day:function(t){var e=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=t?(t=ce(t,this.localeData()),this.add(t-e,"d")):e},month:xe("Month",!0),startOf:function(t){switch(t=k(t)){case"year":this.month(0);case"quarter":case"month":this.date(1);case"week":case"isoWeek":case"day":this.hours(0);case"hour":this.minutes(0);case"minute":this.seconds(0);case"second":this.milliseconds(0)}return"week"===t?this.weekday(0):"isoWeek"===t&&this.isoWeekday(1),"quarter"===t&&this.month(3*Math.floor(this.month()/3)),this},endOf:function(t){return t=k(t),t===n||"millisecond"===t?this:this.startOf(t).add(1,"isoWeek"===t?"week":t).subtract(1,"ms")},isAfter:function(t,e){var i;return e=k("undefined"!=typeof e?e:"millisecond"),"millisecond"===e?(t=Ce.isMoment(t)?t:Ce(t),+this>+t):(i=Ce.isMoment(t)?+t:+Ce(t),i<+this.clone().startOf(e))},isBefore:function(t,e){var i;return e=k("undefined"!=typeof e?e:"millisecond"),"millisecond"===e?(t=Ce.isMoment(t)?t:Ce(t),+t>+this):(i=Ce.isMoment(t)?+t:+Ce(t),+this.clone().endOf(e)t?this:t}),max:l("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(t){return t=Ce.apply(null,arguments),t>this?this:t}),zone:l("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779",function(t,e){return null!=t?("string"!=typeof t&&(t=-t),this.utcOffset(t,e),this):-this.utcOffset()}),utcOffset:function(t,e){var i,s=this._offset||0;return null!=t?("string"==typeof t&&(t=Z(t)),Math.abs(t)<16&&(t=60*t),!this._isUTC&&e&&(i=this._dateUtcOffset()),this._offset=t,this._isUTC=!0,null!=i&&this.add(i,"m"),s!==t&&(!e||this._changeInProgress?C(this,Ce.duration(t-s,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,Ce.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?s:this._dateUtcOffset()},isLocal:function(){return!this._isUTC},isUtcOffset:function(){return this._isUTC},isUtc:function(){return this._isUTC&&0===this._offset},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.utcOffset(this._tzm):"string"==typeof this._i&&this.utcOffset(Z(this._i)),this},hasAlignedHourOffset:function(t){return t=t?Ce(t).utcOffset():0,(this.utcOffset()-t)%60===0},daysInMonth:function(){return z(this.year(),this.month())},dayOfYear:function(t){var e=Ne((Ce(this).startOf("day")-Ce(this).startOf("year"))/864e5)+1;return null==t?e:this.add(t-e,"d")},quarter:function(t){return null==t?Math.ceil((this.month()+1)/3):this.month(3*(t-1)+this.month()%3)},weekYear:function(t){var e=me(this,this.localeData()._week.dow,this.localeData()._week.doy).year;return null==t?e:this.add(t-e,"y")},isoWeekYear:function(t){var e=me(this,1,4).year;return null==t?e:this.add(t-e,"y")},week:function(t){var e=this.localeData().week(this);return null==t?e:this.add(7*(t-e),"d")},isoWeek:function(t){var e=me(this,1,4).week;return null==t?e:this.add(7*(t-e),"d")},weekday:function(t){var e=(this.day()+7-this.localeData()._week.dow)%7;return null==t?e:this.add(t-e,"d")},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},isoWeeksInYear:function(){return P(this.year(),1,4)},weeksInYear:function(){var t=this.localeData()._week;return P(this.year(),t.dow,t.doy)},get:function(t){return t=k(t),this[t]()},set:function(t,e){var i;if("object"==typeof t)for(i in t)this.set(i,t[i]);else t=k(t),"function"==typeof this[t]&&this[t](e);return this},locale:function(t){var e;return t===n?this._locale._abbr:(e=Ce.localeData(t),null!=e&&(this._locale=e),this)},lang:l("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(t){return t===n?this.localeData():this.locale(t)}),localeData:function(){return this._locale},_dateUtcOffset:function(){return 15*-Math.round(this._d.getTimezoneOffset()/15)}}),Ce.fn.millisecond=Ce.fn.milliseconds=xe("Milliseconds",!1),Ce.fn.second=Ce.fn.seconds=xe("Seconds",!1),Ce.fn.minute=Ce.fn.minutes=xe("Minutes",!1),Ce.fn.hour=Ce.fn.hours=xe("Hours",!0),Ce.fn.date=xe("Date",!0),Ce.fn.dates=l("dates accessor is deprecated. Use date instead.",xe("Date",!0)),Ce.fn.year=xe("FullYear",!0),Ce.fn.years=l("years accessor is deprecated. Use year instead.",xe("FullYear",!0)),Ce.fn.days=Ce.fn.day,Ce.fn.months=Ce.fn.month,Ce.fn.weeks=Ce.fn.week,Ce.fn.isoWeeks=Ce.fn.isoWeek,Ce.fn.quarters=Ce.fn.quarter,Ce.fn.toJSON=Ce.fn.toISOString,Ce.fn.isUTC=Ce.fn.isUtc,b(Ce.duration.fn=y.prototype,{_bubble:function(){var t,e,i,s=this._milliseconds,o=this._days,n=this._months,r=this._data,a=0;r.milliseconds=s%1e3,t=x(s/1e3),r.seconds=t%60,e=x(t/60),r.minutes=e%60,i=x(e/60),r.hours=i%24,o+=x(i/24),a=x(we(o)),o-=x(Me(a)),n+=x(o/30),o%=30,a+=x(n/12),n%=12,r.days=o,r.months=n,r.years=a},abs:function(){return 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),this},weeks:function(){return x(this.days()/7)},valueOf:function(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*I(this._months/12)},humanize:function(t){var e=ue(this,!t,this.localeData());return t&&(e=this.localeData().pastFuture(+this,e)),this.localeData().postformat(e)},add:function(t,e){var i=Ce.duration(t,e);return this._milliseconds+=i._milliseconds,this._days+=i._days,this._months+=i._months,this._bubble(),this},subtract:function(t,e){var i=Ce.duration(t,e);return this._milliseconds-=i._milliseconds,this._days-=i._days,this._months-=i._months,this._bubble(),this},get:function(t){return t=k(t),this[t.toLowerCase()+"s"]()},as:function(t){var e,i;if(t=k(t),"month"===t||"year"===t)return e=this._days+this._milliseconds/864e5,i=this._months+12*we(e),"month"===t?i:i/12;switch(e=this._days+Math.round(Me(this._months/12)),t){case"week":return e/7+this._milliseconds/6048e5;case"day":return e+this._milliseconds/864e5;case"hour":return 24*e+this._milliseconds/36e5;case"minute":return 24*e*60+this._milliseconds/6e4;case"second":return 24*e*60*60+this._milliseconds/1e3;case"millisecond":return Math.floor(24*e*60*60*1e3)+this._milliseconds;default:throw new Error("Unknown unit "+t)}},lang:Ce.fn.lang,locale:Ce.fn.locale,toIsoString:l("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",function(){return this.toISOString()}),toISOString:function(){var t=Math.abs(this.years()),e=Math.abs(this.months()),i=Math.abs(this.days()),s=Math.abs(this.hours()),o=Math.abs(this.minutes()),n=Math.abs(this.seconds()+this.milliseconds()/1e3);return this.asSeconds()?(this.asSeconds()<0?"-":"")+"P"+(t?t+"Y":"")+(e?e+"M":"")+(i?i+"D":"")+(s||o||n?"T":"")+(s?s+"H":"")+(o?o+"M":"")+(n?n+"S":""):"P0D"},localeData:function(){return this._locale},toJSON:function(){return this.toISOString()}}),Ce.duration.fn.toString=Ce.duration.fn.toISOString;for(Oe in fi)a(fi,Oe)&&Se(Oe.toLowerCase());Ce.duration.fn.asMilliseconds=function(){return this.as("ms")},Ce.duration.fn.asSeconds=function(){return this.as("s")},Ce.duration.fn.asMinutes=function(){return this.as("m")},Ce.duration.fn.asHours=function(){return this.as("h")},Ce.duration.fn.asDays=function(){return this.as("d")},Ce.duration.fn.asWeeks=function(){return this.as("weeks")},Ce.duration.fn.asMonths=function(){return this.as("M")},Ce.duration.fn.asYears=function(){return this.as("y")},Ce.locale("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(t){var e=t%10,i=1===I(t%100/10)?"th":1===e?"st":2===e?"nd":3===e?"rd":"th";return t+i}}),We?o.exports=Ce:(s=function(t,e,i){return i.config&&i.config()&&i.config().noGlobal===!0&&(ke.moment=Te),Ce}.call(e,i,e,o),!(s!==n&&(o.exports=s)),De(!0))}).call(this)}).call(e,function(){return this}(),i(5)(t))},function(t){function e(t){throw new Error("Cannot find module '"+t+"'.")}e.keys=function(){return[]},e.resolve=e,t.exports=e,e.id=4},function(t){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children=[],t.webpackPolyfill=1),t}},function(t,e){e.prepareElements=function(t){for(var e in t)t.hasOwnProperty(e)&&(t[e].redundant=t[e].used,t[e].used=[])},e.cleanupElements=function(t){for(var e in t)if(t.hasOwnProperty(e)&&t[e].redundant){for(var i=0;i0?(s=e[t].redundant[0],e[t].redundant.shift()):(s=document.createElementNS("http://www.w3.org/2000/svg",t),i.appendChild(s)):(s=document.createElementNS("http://www.w3.org/2000/svg",t),e[t]={used:[],redundant:[]},i.appendChild(s)),e[t].used.push(s),s},e.getDOMElement=function(t,e,i,s){var o;return e.hasOwnProperty(t)?e[t].redundant.length>0?(o=e[t].redundant[0],e[t].redundant.shift()):(o=document.createElement(t),void 0!==s?i.insertBefore(o,s):i.appendChild(o)):(o=document.createElement(t),e[t]={used:[],redundant:[]},void 0!==s?i.insertBefore(o,s):i.appendChild(o)),e[t].used.push(o),o},e.drawPoint=function(t,i,s,o,n){var r;return"circle"==s.options.drawPoints.style?(r=e.getSVGElement("circle",o,n),r.setAttributeNS(null,"cx",t),r.setAttributeNS(null,"cy",i),r.setAttributeNS(null,"r",.5*s.options.drawPoints.size)):(r=e.getSVGElement("rect",o,n),r.setAttributeNS(null,"x",t-.5*s.options.drawPoints.size),r.setAttributeNS(null,"y",i-.5*s.options.drawPoints.size),r.setAttributeNS(null,"width",s.options.drawPoints.size),r.setAttributeNS(null,"height",s.options.drawPoints.size)),void 0!==s.options.drawPoints.styles&&r.setAttributeNS(null,"style",s.group.options.drawPoints.styles),r.setAttributeNS(null,"class",s.className+" point"),r},e.drawBar=function(t,i,s,o,n,r,a){if(0!=o){0>o&&(o*=-1,i-=o);var h=e.getSVGElement("rect",r,a);h.setAttributeNS(null,"x",t-.5*s),h.setAttributeNS(null,"y",i),h.setAttributeNS(null,"width",s),h.setAttributeNS(null,"height",o),h.setAttributeNS(null,"class",n)}}},function(t,e,i){function s(t,e){if(!t||Array.isArray(t)||o.isDataTable(t)||(e=t,t=null),this._options=e||{},this._data={},this._fieldId=this._options.fieldId||"id",this._type={},this._options.type)for(var i in this._options.type)if(this._options.type.hasOwnProperty(i)){var s=this._options.type[i];this._type[i]="Date"==s||"ISODate"==s||"ASPDate"==s?"Date":s}if(this._options.convert)throw new Error('Option "convert" is deprecated. Use "type" instead.');this._subscribers={},t&&this.add(t),this.setOptions(e)}var o=i(1),n=i(8);s.prototype.setOptions=function(t){t&&void 0!==t.queue&&(t.queue===!1?this._queue&&(this._queue.destroy(),delete this._queue):(this._queue||(this._queue=n.extend(this,{replace:["add","update","remove"]})),"object"==typeof t.queue&&this._queue.setOptions(t.queue)))},s.prototype.on=function(t,e){var i=this._subscribers[t];i||(i=[],this._subscribers[t]=i),i.push({callback:e})},s.prototype.subscribe=s.prototype.on,s.prototype.off=function(t,e){var i=this._subscribers[t];i&&(this._subscribers[t]=i.filter(function(t){return t.callback!=e}))},s.prototype.unsubscribe=s.prototype.off,s.prototype._trigger=function(t,e,i){if("*"==t)throw new Error("Cannot trigger event *");var s=[];t in this._subscribers&&(s=s.concat(this._subscribers[t])),"*"in this._subscribers&&(s=s.concat(this._subscribers["*"]));for(var o=0;or;r++)i=n._addItem(t[r]),s.push(i);else if(o.isDataTable(t))for(var h=this._getColumnNames(t),d=0,l=t.getNumberOfRows();l>d;d++){for(var c={},p=0,u=h.length;u>p;p++){var m=h[p];c[m]=t.getValue(d,p)}i=n._addItem(c),s.push(i)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");i=n._addItem(t),s.push(i)}return s.length&&this._trigger("add",{items:s},e),s},s.prototype.update=function(t,e){var i=[],s=[],n=[],r=this,a=r._fieldId,h=function(t){var e=t[a];r._data[e]?(e=r._updateItem(t),s.push(e),n.push(t)):(e=r._addItem(t),i.push(e))};if(Array.isArray(t))for(var d=0,l=t.length;l>d;d++)h(t[d]);else if(o.isDataTable(t))for(var c=this._getColumnNames(t),p=0,u=t.getNumberOfRows();u>p;p++){for(var m={},f=0,g=c.length;g>f;f++){var v=c[f];m[v]=t.getValue(p,f)}h(m)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");h(t)}return i.length&&this._trigger("add",{items:i},e),s.length&&this._trigger("update",{items:s,data:n},e),i.concat(s)},s.prototype.get=function(){var t,e,i,s,n=this,r=o.getType(arguments[0]);"String"==r||"Number"==r?(t=arguments[0],i=arguments[1],s=arguments[2]):"Array"==r?(e=arguments[0],i=arguments[1],s=arguments[2]):(i=arguments[0],s=arguments[1]);var a;if(i&&i.returnType){var h=["DataTable","Array","Object"];if(a=-1==h.indexOf(i.returnType)?"Array":i.returnType,s&&a!=o.getType(s))throw new Error('Type of parameter "data" ('+o.getType(s)+") does not correspond with specified options.type ("+i.type+")");if("DataTable"==a&&!o.isDataTable(s))throw new Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else a=s&&"DataTable"==o.getType(s)?"DataTable":"Array";var d,l,c,p,u=i&&i.type||this._options.type,m=i&&i.filter,f=[];if(void 0!=t)d=n._getItem(t,u),m&&!m(d)&&(d=null);else if(void 0!=e)for(c=0,p=e.length;p>c;c++)d=n._getItem(e[c],u),(!m||m(d))&&f.push(d);else for(l in this._data)this._data.hasOwnProperty(l)&&(d=n._getItem(l,u),(!m||m(d))&&f.push(d));if(i&&i.order&&void 0==t&&this._sort(f,i.order),i&&i.fields){var g=i.fields;if(void 0!=t)d=this._filterFields(d,g);else for(c=0,p=f.length;p>c;c++)f[c]=this._filterFields(f[c],g)}if("DataTable"==a){var v=this._getColumnNames(s);if(void 0!=t)n._appendRow(s,v,d);else for(c=0;cc;c++)s.push(f[c]);return s}return f},s.prototype.getIds=function(t){var e,i,s,o,n,r=this._data,a=t&&t.filter,h=t&&t.order,d=t&&t.type||this._options.type,l=[];if(a)if(h){n=[];for(s in r)r.hasOwnProperty(s)&&(o=this._getItem(s,d),a(o)&&n.push(o));for(this._sort(n,h),e=0,i=n.length;i>e;e++)l[e]=n[e][this._fieldId]}else for(s in r)r.hasOwnProperty(s)&&(o=this._getItem(s,d),a(o)&&l.push(o[this._fieldId]));else if(h){n=[];for(s in r)r.hasOwnProperty(s)&&n.push(r[s]);for(this._sort(n,h),e=0,i=n.length;i>e;e++)l[e]=n[e][this._fieldId]}else for(s in r)r.hasOwnProperty(s)&&(o=r[s],l.push(o[this._fieldId]));return l},s.prototype.getDataSet=function(){return this},s.prototype.forEach=function(t,e){var i,s,o=e&&e.filter,n=e&&e.type||this._options.type,r=this._data;if(e&&e.order)for(var a=this.get(e),h=0,d=a.length;d>h;h++)i=a[h],s=i[this._fieldId],t(i,s);else for(s in r)r.hasOwnProperty(s)&&(i=this._getItem(s,n),(!o||o(i))&&t(i,s))},s.prototype.map=function(t,e){var i,s=e&&e.filter,o=e&&e.type||this._options.type,n=[],r=this._data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,o),(!s||s(i))&&n.push(t(i,a)));return e&&e.order&&this._sort(n,e.order),n},s.prototype._filterFields=function(t,e){var i={};for(var s in t)t.hasOwnProperty(s)&&-1!=e.indexOf(s)&&(i[s]=t[s]);return i},s.prototype._sort=function(t,e){if(o.isString(e)){var i=e;t.sort(function(t,e){var s=t[i],o=e[i];return s>o?1:o>s?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},s.prototype.remove=function(t,e){var i,s,o,n=[];if(Array.isArray(t))for(i=0,s=t.length;s>i;i++)o=this._remove(t[i]),null!=o&&n.push(o);else o=this._remove(t),null!=o&&n.push(o);return n.length&&this._trigger("remove",{items:n},e),n},s.prototype._remove=function(t){if(o.isNumber(t)||o.isString(t)){if(this._data[t])return delete this._data[t],t}else if(t instanceof Object){var e=t[this._fieldId];if(e&&this._data[e])return delete this._data[e],e}return null},s.prototype.clear=function(t){var e=Object.keys(this._data);return this._data={},this._trigger("remove",{items:e},t),e},s.prototype.max=function(t){var e=this._data,i=null,s=null;for(var o in e)if(e.hasOwnProperty(o)){var n=e[o],r=n[t];null!=r&&(!i||r>s)&&(i=n,s=r)}return i},s.prototype.min=function(t){var e=this._data,i=null,s=null;for(var o in e)if(e.hasOwnProperty(o)){var n=e[o],r=n[t];null!=r&&(!i||s>r)&&(i=n,s=r)}return i},s.prototype.distinct=function(t){var e,i=this._data,s=[],n=this._options.type&&this._options.type[t]||null,r=0;for(var a in i)if(i.hasOwnProperty(a)){var h=i[a],d=h[t],l=!1;for(e=0;r>e;e++)if(s[e]==d){l=!0;break}l||void 0===d||(s[r]=d,r++)}if(n)for(e=0;ei;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},s.prototype._appendRow=function(t,e,i){for(var s=t.addRow(),o=0,n=e.length;n>o;o++){var r=e[o];t.setValue(s,o,i[r])}},t.exports=s},function(t){function e(t){this.delay=null,this.max=1/0,this._queue=[],this._timeout=null,this._extended=null,this.setOptions(t)}e.prototype.setOptions=function(t){t&&"undefined"!=typeof t.delay&&(this.delay=t.delay),t&&"undefined"!=typeof t.max&&(this.max=t.max),this._flushIfNeeded()},e.extend=function(t,i){var s=new e(i);if(void 0!==t.flush)throw new Error("Target object already has a property flush");t.flush=function(){s.flush()};var o=[{name:"flush",original:void 0}];if(i&&i.replace)for(var n=0;nthis.max&&this.flush(),clearTimeout(this._timeout),this.queue.length>0&&"number"==typeof this.delay){var t=this;this._timeout=setTimeout(function(){t.flush()},this.delay)}},e.prototype.flush=function(){for(;this._queue.length>0;){var t=this._queue.shift();t.fn.apply(t.context||t.fn,t.args||[])}},t.exports=e},function(t,e,i){function s(t,e){this._data=null,this._ids={},this._options=e||{},this._fieldId="id",this._subscribers={};var i=this;this.listener=function(){i._onEvent.apply(i,arguments)},this.setData(t)}var o=i(1),n=i(7);s.prototype.setData=function(t){var e,i,s;if(this._data){this._data.unsubscribe&&this._data.unsubscribe("*",this.listener),e=[];for(var o in this._ids)this._ids.hasOwnProperty(o)&&e.push(o);this._ids={},this._trigger("remove",{items:e})}if(this._data=t,this._data){for(this._fieldId=this._options.fieldId||this._data&&this._data.options&&this._data.options.fieldId||"id",e=this._data.getIds({filter:this._options&&this._options.filter}),i=0,s=e.length;s>i;i++)o=e[i],this._ids[o]=!0;this._trigger("add",{items:e}),this._data.on&&this._data.on("*",this.listener)}},s.prototype.get=function(){var t,e,i,s=this,n=o.getType(arguments[0]);"String"==n||"Number"==n||"Array"==n?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var r=o.extend({},this._options,e);this._options.filter&&e&&e.filter&&(r.filter=function(t){return s._options.filter(t)&&e.filter(t)});var a=[];return void 0!=t&&a.push(t),a.push(r),a.push(i),this._data&&this._data.get.apply(this._data,a)},s.prototype.getIds=function(t){var e;if(this._data){var i,s=this._options.filter;i=t&&t.filter?s?function(e){return s(e)&&t.filter(e)}:t.filter:s,e=this._data.getIds({filter:i,order:t&&t.order})}else e=[];return e},s.prototype.getDataSet=function(){for(var t=this;t instanceof s;)t=t._data;return t||null},s.prototype._onEvent=function(t,e,i){var s,o,n,r,a=e&&e.items,h=this._data,d=[],l=[],c=[];if(a&&h){switch(t){case"add":for(s=0,o=a.length;o>s;s++)n=a[s],r=this.get(n),r&&(this._ids[n]=!0,d.push(n));break;case"update":for(s=0,o=a.length;o>s;s++)n=a[s],r=this.get(n),r?this._ids[n]?l.push(n):(this._ids[n]=!0,d.push(n)):this._ids[n]&&(delete this._ids[n],c.push(n));break;case"remove":for(s=0,o=a.length;o>s;s++)n=a[s],this._ids[n]&&(delete this._ids[n],c.push(n))}d.length&&this._trigger("add",{items:d},i),l.length&&this._trigger("update",{items:l},i),c.length&&this._trigger("remove",{items:c},i)}},s.prototype.on=n.prototype.on,s.prototype.off=n.prototype.off,s.prototype._trigger=n.prototype._trigger,s.prototype.subscribe=s.prototype.on,s.prototype.unsubscribe=s.prototype.off,t.exports=s},function(t,e,i){function s(t,e,i){if(!(this instanceof s))throw new SyntaxError("Constructor must be called with the new operator");this.containerElement=t,this.width="400px",this.height="400px",this.margin=10,this.defaultXCenter="55%",this.defaultYCenter="50%",this.xLabel="x",this.yLabel="y",this.zLabel="z";var o=function(t){return t};this.xValueLabel=o,this.yValueLabel=o,this.zValueLabel=o,this.filterLabel="time",this.legendLabel="value",this.style=s.STYLE.DOT,this.showPerspective=!0,this.showGrid=!0,this.keepAspectRatio=!0,this.showShadow=!1,this.showGrayBottom=!1,this.showTooltip=!1,this.verticalRatio=.5,this.animationInterval=1e3,this.animationPreload=!1,this.camera=new p,this.eye=new l(0,0,-1),this.dataTable=null,this.dataPoints=null,this.colX=void 0,this.colY=void 0,this.colZ=void 0,this.colValue=void 0,this.colFilter=void 0,this.xMin=0,this.xStep=void 0,this.xMax=1,this.yMin=0,this.yStep=void 0,this.yMax=1,this.zMin=0,this.zStep=void 0,this.zMax=1,this.valueMin=0,this.valueMax=1,this.xBarWidth=1,this.yBarWidth=1,this.colorAxis="#4D4D4D",this.colorGrid="#D3D3D3",this.colorDot="#7DC1FF",this.colorDotBorder="#3267D2",this.create(),this.setOptions(i),e&&this.setData(e)}function o(t){return"clientX"in t?t.clientX:t.targetTouches[0]&&t.targetTouches[0].clientX||0}function n(t){return"clientY"in t?t.clientY:t.targetTouches[0]&&t.targetTouches[0].clientY||0}var r=i(11),a=i(7),h=i(9),d=i(1),l=i(12),c=i(13),p=i(14),u=i(15),m=i(16),f=i(17);r(s.prototype),s.prototype._setScale=function(){this.scale=new l(1/(this.xMax-this.xMin),1/(this.yMax-this.yMin),1/(this.zMax-this.zMin)),this.keepAspectRatio&&(this.scale.x3&&(this.colFilter=3);else{if(this.style!==s.STYLE.DOTCOLOR&&this.style!==s.STYLE.DOTSIZE&&this.style!==s.STYLE.BARCOLOR&&this.style!==s.STYLE.BARSIZE)throw'Unknown style "'+this.style+'"';this.colX=0,this.colY=1,this.colZ=2,this.colValue=3,t.getNumberOfColumns()>4&&(this.colFilter=4)}},s.prototype.getNumberOfRows=function(t){return t.length},s.prototype.getNumberOfColumns=function(t){var e=0;for(var i in t[0])t[0].hasOwnProperty(i)&&e++;return e},s.prototype.getDistinctValues=function(t,e){for(var i=[],s=0;st[s][e]&&(i.min=t[s][e]),i.maxt;t++){var m=(t-p)/(u-p),g=240*m,v=this._hsv2rgb(g,1,1);c.strokeStyle=v,c.beginPath(),c.moveTo(h,r+t),c.lineTo(a,r+t),c.stroke()}c.strokeStyle=this.colorAxis,c.strokeRect(h,r,i,n)}if(this.style===s.STYLE.DOTSIZE&&(c.strokeStyle=this.colorAxis,c.fillStyle=this.colorDot,c.beginPath(),c.moveTo(h,r),c.lineTo(a,r),c.lineTo(a-i+e,d),c.lineTo(h,d),c.closePath(),c.fill(),c.stroke()),this.style===s.STYLE.DOTCOLOR||this.style===s.STYLE.DOTSIZE){var y=5,b=new f(this.valueMin,this.valueMax,(this.valueMax-this.valueMin)/5,!0);for(b.start(),b.getCurrent()0?this.yMin:this.yMax,o=this._convert3Dto2D(new l(x,r,this.zMin)),Math.cos(2*_)>0?(g.textAlign="center",g.textBaseline="top",o.y+=b):Math.sin(2*_)<0?(g.textAlign="right",g.textBaseline="middle"):(g.textAlign="left",g.textBaseline="middle"),g.fillStyle=this.colorAxis,g.fillText(" "+this.xValueLabel(i.getCurrent())+" ",o.x,o.y),i.next()}for(g.lineWidth=1,s=void 0===this.defaultYStep,i=new f(this.yMin,this.yMax,this.yStep,s),i.start(),i.getCurrent()0?this.xMin:this.xMax,o=this._convert3Dto2D(new l(n,i.getCurrent(),this.zMin)),Math.cos(2*_)<0?(g.textAlign="center",g.textBaseline="top",o.y+=b):Math.sin(2*_)>0?(g.textAlign="right",g.textBaseline="middle"):(g.textAlign="left",g.textBaseline="middle"),g.fillStyle=this.colorAxis,g.fillText(" "+this.yValueLabel(i.getCurrent())+" ",o.x,o.y),i.next();for(g.lineWidth=1,s=void 0===this.defaultZStep,i=new f(this.zMin,this.zMax,this.zStep,s),i.start(),i.getCurrent()0?this.xMin:this.xMax,r=Math.sin(_)<0?this.yMin:this.yMax;!i.end();)t=this._convert3Dto2D(new l(n,r,i.getCurrent())),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(t.x,t.y),g.lineTo(t.x-b,t.y),g.stroke(),g.textAlign="right",g.textBaseline="middle",g.fillStyle=this.colorAxis,g.fillText(this.zValueLabel(i.getCurrent())+" ",t.x-5,t.y),i.next();g.lineWidth=1,t=this._convert3Dto2D(new l(n,r,this.zMin)),e=this._convert3Dto2D(new l(n,r,this.zMax)),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(t.x,t.y),g.lineTo(e.x,e.y),g.stroke(),g.lineWidth=1,p=this._convert3Dto2D(new l(this.xMin,this.yMin,this.zMin)),u=this._convert3Dto2D(new l(this.xMax,this.yMin,this.zMin)),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(p.x,p.y),g.lineTo(u.x,u.y),g.stroke(),p=this._convert3Dto2D(new l(this.xMin,this.yMax,this.zMin)),u=this._convert3Dto2D(new l(this.xMax,this.yMax,this.zMin)),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(p.x,p.y),g.lineTo(u.x,u.y),g.stroke(),g.lineWidth=1,t=this._convert3Dto2D(new l(this.xMin,this.yMin,this.zMin)),e=this._convert3Dto2D(new l(this.xMin,this.yMax,this.zMin)),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(t.x,t.y),g.lineTo(e.x,e.y),g.stroke(),t=this._convert3Dto2D(new l(this.xMax,this.yMin,this.zMin)),e=this._convert3Dto2D(new l(this.xMax,this.yMax,this.zMin)),g.strokeStyle=this.colorAxis,g.beginPath(),g.moveTo(t.x,t.y),g.lineTo(e.x,e.y),g.stroke();var w=this.xLabel;w.length>0&&(c=.1/this.scale.y,n=(this.xMin+this.xMax)/2,r=Math.cos(_)>0?this.yMin-c:this.yMax+c,o=this._convert3Dto2D(new l(n,r,this.zMin)),Math.cos(2*_)>0?(g.textAlign="center",g.textBaseline="top"):Math.sin(2*_)<0?(g.textAlign="right",g.textBaseline="middle"):(g.textAlign="left",g.textBaseline="middle"),g.fillStyle=this.colorAxis,g.fillText(w,o.x,o.y));var M=this.yLabel;M.length>0&&(d=.1/this.scale.x,n=Math.sin(_)>0?this.xMin-d:this.xMax+d,r=(this.yMin+this.yMax)/2,o=this._convert3Dto2D(new l(n,r,this.zMin)),Math.cos(2*_)<0?(g.textAlign="center",g.textBaseline="top"):Math.sin(2*_)>0?(g.textAlign="right",g.textBaseline="middle"):(g.textAlign="left",g.textBaseline="middle"),g.fillStyle=this.colorAxis,g.fillText(M,o.x,o.y));var S=this.zLabel;S.length>0&&(h=30,n=Math.cos(_)>0?this.xMin:this.xMax,r=Math.sin(_)<0?this.yMin:this.yMax,a=(this.zMin+this.zMax)/2,o=this._convert3Dto2D(new l(n,r,a)),g.textAlign="right",g.textBaseline="middle",g.fillStyle=this.colorAxis,g.fillText(S,o.x-h,o.y))},s.prototype._hsv2rgb=function(t,e,i){var s,o,n,r,a,h;switch(r=i*e,a=Math.floor(t/60),h=r*(1-Math.abs(t/60%2-1)),a){case 0:s=r,o=h,n=0;break;case 1:s=h,o=r,n=0;break;case 2:s=0,o=r,n=h;break;case 3:s=0,o=h,n=r;break;case 4:s=h,o=0,n=r;break;case 5:s=r,o=0,n=h;break;default:s=0,o=0,n=0}return"RGB("+parseInt(255*s)+","+parseInt(255*o)+","+parseInt(255*n)+")"},s.prototype._redrawDataGrid=function(){var t,e,i,o,n,r,a,h,d,c,p,u,m,f=this.frame.canvas,g=f.getContext("2d");if(!(void 0===this.dataPoints||this.dataPoints.length<=0)){for(n=0;n0}else r=!0;r?(m=(t.point.z+e.point.z+i.point.z+o.point.z)/4,c=240*(1-(m-this.zMin)*this.scale.z/this.verticalRatio),p=1,this.showShadow?(u=Math.min(1+M.x/S/2,1),a=this._hsv2rgb(c,p,u),h=a):(u=1,a=this._hsv2rgb(c,p,u),h=this.colorAxis)):(a="gray",h=this.colorAxis),d=.5,g.lineWidth=d,g.fillStyle=a,g.strokeStyle=h,g.beginPath(),g.moveTo(t.screen.x,t.screen.y),g.lineTo(e.screen.x,e.screen.y),g.lineTo(o.screen.x,o.screen.y),g.lineTo(i.screen.x,i.screen.y),g.closePath(),g.fill(),g.stroke()}}else for(n=0;np&&(p=0);var u,m,f;this.style===s.STYLE.DOTCOLOR?(u=240*(1-(d.point.value-this.valueMin)*this.scale.value),m=this._hsv2rgb(u,1,1),f=this._hsv2rgb(u,1,.8)):this.style===s.STYLE.DOTSIZE?(m=this.colorDot,f=this.colorDotBorder):(u=240*(1-(d.point.z-this.zMin)*this.scale.z/this.verticalRatio),m=this._hsv2rgb(u,1,1),f=this._hsv2rgb(u,1,.8)),i.lineWidth=1,i.strokeStyle=f,i.fillStyle=m,i.beginPath(),i.arc(d.screen.x,d.screen.y,p,0,2*Math.PI,!0),i.fill(),i.stroke()}}},s.prototype._redrawDataBar=function(){var t,e,i,o,n=this.frame.canvas,r=n.getContext("2d");if(!(void 0===this.dataPoints||this.dataPoints.length<=0)){for(t=0;t0&&(t=this.dataPoints[0],s.lineWidth=1,s.strokeStyle="blue",s.beginPath(),s.moveTo(t.screen.x,t.screen.y)),e=1;e0&&s.stroke()}},s.prototype._onMouseDown=function(t){if(t=t||window.event,this.leftButtonDown&&this._onMouseUp(t),this.leftButtonDown=t.which?1===t.which:1===t.button,this.leftButtonDown||this.touchDown){this.startMouseX=o(t),this.startMouseY=n(t),this.startStart=new Date(this.start),this.startEnd=new Date(this.end),this.startArmRotation=this.camera.getArmRotation(),this.frame.style.cursor="move";var e=this;this.onmousemove=function(t){e._onMouseMove(t)},this.onmouseup=function(t){e._onMouseUp(t)},d.addEventListener(document,"mousemove",e.onmousemove),d.addEventListener(document,"mouseup",e.onmouseup),d.preventDefault(t)}},s.prototype._onMouseMove=function(t){t=t||window.event;var e=parseFloat(o(t))-this.startMouseX,i=parseFloat(n(t))-this.startMouseY,s=this.startArmRotation.horizontal+e/200,r=this.startArmRotation.vertical+i/200,a=4,h=Math.sin(a/360*2*Math.PI);Math.abs(Math.sin(s))0?1:0>t?-1:0}var s=e[0],o=e[1],n=e[2],r=i((o.x-s.x)*(t.y-s.y)-(o.y-s.y)*(t.x-s.x)),a=i((n.x-o.x)*(t.y-o.y)-(n.y-o.y)*(t.x-o.x)),h=i((s.x-n.x)*(t.y-n.y)-(s.y-n.y)*(t.x-n.x));return!(0!=r&&0!=a&&r!=a||0!=a&&0!=h&&a!=h||0!=r&&0!=h&&r!=h)},s.prototype._dataPointFromXY=function(t,e){var i,o=100,n=null,r=null,a=null,h=new c(t,e);if(this.style===s.STYLE.BAR||this.style===s.STYLE.BARCOLOR||this.style===s.STYLE.BARSIZE)for(i=this.dataPoints.length-1;i>=0;i--){n=this.dataPoints[i];var d=n.surfaces;if(d)for(var l=d.length-1;l>=0;l--){var p=d[l],u=p.corners,m=[u[0].screen,u[1].screen,u[2].screen],f=[u[2].screen,u[3].screen,u[0].screen];if(this._insideTriangle(h,m)||this._insideTriangle(h,f))return n}}else for(i=0;ib)&&o>b&&(a=b,r=n)}}return r},s.prototype._showTooltip=function(t){var e,i,s;this.tooltip?(e=this.tooltip.dom.content,i=this.tooltip.dom.line,s=this.tooltip.dom.dot):(e=document.createElement("div"),e.style.position="absolute",e.style.padding="10px",e.style.border="1px solid #4d4d4d",e.style.color="#1a1a1a",e.style.background="rgba(255,255,255,0.7)",e.style.borderRadius="2px",e.style.boxShadow="5px 5px 10px rgba(128,128,128,0.5)",i=document.createElement("div"),i.style.position="absolute",i.style.height="40px",i.style.width="0",i.style.borderLeft="1px solid #4d4d4d",s=document.createElement("div"),s.style.position="absolute",s.style.height="0",s.style.width="0",s.style.border="5px solid #4d4d4d",s.style.borderRadius="5px",this.tooltip={dataPoint:null,dom:{content:e,line:i,dot:s}}),this._hideTooltip(),this.tooltip.dataPoint=t,e.innerHTML="function"==typeof this.showTooltip?this.showTooltip(t.point):"
x:"+t.point.x+"
y:"+t.point.y+"
z:"+t.point.z+"
",e.style.left="0",e.style.top="0",this.frame.appendChild(e),this.frame.appendChild(i),this.frame.appendChild(s);var o=e.offsetWidth,n=e.offsetHeight,r=i.offsetHeight,a=s.offsetWidth,h=s.offsetHeight,d=t.screen.x-o/2;d=Math.min(Math.max(d,10),this.frame.clientWidth-10-o),i.style.left=t.screen.x+"px",i.style.top=t.screen.y-r+"px",e.style.left=d+"px",e.style.top=t.screen.y-r-n+"px",s.style.left=t.screen.x-a/2+"px",s.style.top=t.screen.y-h/2+"px"},s.prototype._hideTooltip=function(){if(this.tooltip){this.tooltip.dataPoint=null;for(var t in this.tooltip.dom)if(this.tooltip.dom.hasOwnProperty(t)){var e=this.tooltip.dom[t];e&&e.parentNode&&e.parentNode.removeChild(e)}}},t.exports=s},function(t){function e(t){return t?i(t):void 0}function i(t){for(var i in e.prototype)t[i]=e.prototype[i];return t}t.exports=e,e.prototype.on=e.prototype.addEventListener=function(t,e){return this._callbacks=this._callbacks||{},(this._callbacks[t]=this._callbacks[t]||[]).push(e),this},e.prototype.once=function(t,e){function i(){s.off(t,i),e.apply(this,arguments)}var s=this;return this._callbacks=this._callbacks||{},i.fn=e,this.on(t,i),this},e.prototype.off=e.prototype.removeListener=e.prototype.removeAllListeners=e.prototype.removeEventListener=function(t,e){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var i=this._callbacks[t];if(!i)return this;if(1==arguments.length)return delete this._callbacks[t],this;for(var s,o=0;os;++s)i[s].apply(this,e)}return this},e.prototype.listeners=function(t){return this._callbacks=this._callbacks||{},this._callbacks[t]||[]},e.prototype.hasListeners=function(t){return!!this.listeners(t).length}},function(t){function e(t,e,i){this.x=void 0!==t?t:0,this.y=void 0!==e?e:0,this.z=void 0!==i?i:0}e.subtract=function(t,i){var s=new e;return s.x=t.x-i.x,s.y=t.y-i.y,s.z=t.z-i.z,s},e.add=function(t,i){var s=new e;return s.x=t.x+i.x,s.y=t.y+i.y,s.z=t.z+i.z,s},e.avg=function(t,i){return new e((t.x+i.x)/2,(t.y+i.y)/2,(t.z+i.z)/2)},e.crossProduct=function(t,i){var s=new e;return s.x=t.y*i.z-t.z*i.y,s.y=t.z*i.x-t.x*i.z,s.z=t.x*i.y-t.y*i.x,s},e.prototype.length=function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)},t.exports=e},function(t){function e(t,e){this.x=void 0!==t?t:0,this.y=void 0!==e?e:0}t.exports=e},function(t,e,i){function s(){this.armLocation=new o,this.armRotation={},this.armRotation.horizontal=0,this.armRotation.vertical=0,this.armLength=1.7,this.cameraLocation=new o,this.cameraRotation=new o(.5*Math.PI,0,0),this.calculateCameraOrientation()}var o=i(12);s.prototype.setArmLocation=function(t,e,i){this.armLocation.x=t,this.armLocation.y=e,this.armLocation.z=i,this.calculateCameraOrientation()},s.prototype.setArmRotation=function(t,e){void 0!==t&&(this.armRotation.horizontal=t),void 0!==e&&(this.armRotation.vertical=e,this.armRotation.vertical<0&&(this.armRotation.vertical=0),this.armRotation.vertical>.5*Math.PI&&(this.armRotation.vertical=.5*Math.PI)),(void 0!==t||void 0!==e)&&this.calculateCameraOrientation()},s.prototype.getArmRotation=function(){var t={};return t.horizontal=this.armRotation.horizontal,t.vertical=this.armRotation.vertical,t},s.prototype.setArmLength=function(t){void 0!==t&&(this.armLength=t,this.armLength<.71&&(this.armLength=.71),this.armLength>5&&(this.armLength=5),this.calculateCameraOrientation())},s.prototype.getArmLength=function(){return this.armLength},s.prototype.getCameraLocation=function(){return this.cameraLocation},s.prototype.getCameraRotation=function(){return this.cameraRotation},s.prototype.calculateCameraOrientation=function(){this.cameraLocation.x=this.armLocation.x-this.armLength*Math.sin(this.armRotation.horizontal)*Math.cos(this.armRotation.vertical),this.cameraLocation.y=this.armLocation.y-this.armLength*Math.cos(this.armRotation.horizontal)*Math.cos(this.armRotation.vertical),this.cameraLocation.z=this.armLocation.z+this.armLength*Math.sin(this.armRotation.vertical),this.cameraRotation.x=Math.PI/2-this.armRotation.vertical,this.cameraRotation.y=0,this.cameraRotation.z=-this.armRotation.horizontal},t.exports=s},function(t,e,i){function s(t,e,i){this.data=t,this.column=e,this.graph=i,this.index=void 0,this.value=void 0,this.values=i.getDistinctValues(t.get(),this.column),this.values.sort(function(t,e){return t>e?1:e>t?-1:0}),this.values.length>0&&this.selectValue(0),this.dataPoints=[],this.loaded=!1,this.onLoadCallback=void 0,i.animationPreload?(this.loaded=!1,this.loadInBackground()):this.loaded=!0}var o=i(9);s.prototype.isLoaded=function(){return this.loaded},s.prototype.getLoadedProgress=function(){for(var t=this.values.length,e=0;this.dataPoints[e];)e++;return Math.round(e/t*100)},s.prototype.getLabel=function(){return this.graph.filterLabel},s.prototype.getColumn=function(){return this.column},s.prototype.getSelectedValue=function(){return void 0===this.index?void 0:this.values[this.index]},s.prototype.getValues=function(){return this.values},s.prototype.getValue=function(t){if(t>=this.values.length)throw"Error: index out of range";return this.values[t]},s.prototype._getDataPoints=function(t){if(void 0===t&&(t=this.index),void 0===t)return[];var e;if(this.dataPoints[t])e=this.dataPoints[t];else{var i={};i.column=this.column,i.value=this.values[t];var s=new o(this.data,{filter:function(t){return t[i.column]==i.value}}).get();e=this.graph._getDataPoints(s),this.dataPoints[t]=e}return e},s.prototype.setOnLoadCallback=function(t){this.onLoadCallback=t},s.prototype.selectValue=function(t){if(t>=this.values.length)throw"Error: index out of range";this.index=t,this.value=this.values[t]},s.prototype.loadInBackground=function(t){void 0===t&&(t=0);var e=this.graph.frame;if(t0&&(t--,this.setIndex(t))},s.prototype.next=function(){var t=this.getIndex();t0?this.setIndex(0):this.index=void 0},s.prototype.setIndex=function(t){if(!(ts&&(s=0),s>this.values.length-1&&(s=this.values.length-1),s},s.prototype.indexToLeft=function(t){var e=parseFloat(this.frame.bar.style.width)-this.frame.slide.clientWidth-10,i=t/(this.values.length-1)*e,s=i+3;return s},s.prototype._onMouseMove=function(t){var e=t.clientX-this.startClientX,i=this.startSlideX+e,s=this.leftToIndex(i);this.setIndex(s),o.preventDefault()},s.prototype._onMouseUp=function(){this.frame.style.cursor="auto",o.removeEventListener(document,"mousemove",this.onmousemove),o.removeEventListener(document,"mouseup",this.onmouseup),o.preventDefault()},t.exports=s},function(t){function e(t,e,i,s){this._start=0,this._end=0,this._step=1,this.prettyStep=!0,this.precision=5,this._current=0,this.setRange(t,e,i,s)}e.prototype.setRange=function(t,e,i,s){this._start=t?t:0,this._end=e?e:0,this.setStep(i,s)},e.prototype.setStep=function(t,i){void 0===t||0>=t||(void 0!==i&&(this.prettyStep=i),this._step=this.prettyStep===!0?e.calculatePrettyStep(t):t)},e.calculatePrettyStep=function(t){var e=function(t){return Math.log(t)/Math.LN10},i=Math.pow(10,Math.round(e(t))),s=2*Math.pow(10,Math.round(e(t/2))),o=5*Math.pow(10,Math.round(e(t/5))),n=i;return Math.abs(s-t)<=Math.abs(n-t)&&(n=s),Math.abs(o-t)<=Math.abs(n-t)&&(n=o),0>=n&&(n=1),n},e.prototype.getCurrent=function(){return parseFloat(this._current.toPrecision(this.precision))},e.prototype.getStep=function(){return this._step},e.prototype.start=function(){this._current=this._start-this._start%this._step},e.prototype.next=function(){this._current+=this._step},e.prototype.end=function(){return this._current>this._end},t.exports=e},function(t,e,i){function s(t,e,i,r){if(!(this instanceof s))throw new SyntaxError("Constructor must be called with the new operator");if(!(Array.isArray(i)||i instanceof n)&&i instanceof Object){var h=r;r=i,i=h}var u=this;this.defaultOptions={start:null,end:null,autoResize:!0,orientation:"bottom",width:null,height:null,maxHeight:null,minHeight:null},this.options=o.deepExtend({},this.defaultOptions),this._create(t),this.components=[],this.body={dom:this.dom,domProps:this.props,emitter:{on:this.on.bind(this),off:this.off.bind(this),emit:this.emit.bind(this)},hiddenDates:[],util:{snap:null,toScreen:u._toScreen.bind(u),toGlobalScreen:u._toGlobalScreen.bind(u),toTime:u._toTime.bind(u),toGlobalTime:u._toGlobalTime.bind(u)}},this.range=new a(this.body),this.components.push(this.range),this.body.range=this.range,this.timeAxis=new d(this.body),this.components.push(this.timeAxis),this.body.util.snap=this.timeAxis.snap.bind(this.timeAxis),this.currentTime=new l(this.body),this.components.push(this.currentTime),this.customTime=new c(this.body),this.components.push(this.customTime),this.itemSet=new p(this.body),this.components.push(this.itemSet),this.itemsData=null,this.groupsData=null,r&&this.setOptions(r),i&&this.setGroups(i),e?this.setItems(e):this.redraw()}var o=(i(11),i(19),i(1)),n=i(7),r=i(9),a=i(21),h=i(25),d=i(37),l=i(39),c=i(41),p=i(26);s.prototype=new h,s.prototype.setItems=function(t){var e,i=null==this.itemsData;if(e=t?t instanceof n||t instanceof r?t:new n(t,{type:{start:"Date",end:"Date"}}):null,this.itemsData=e,this.itemSet&&this.itemSet.setItems(e),i)if(void 0!=this.options.start||void 0!=this.options.end){if(void 0==this.options.start||void 0==this.options.end)var s=this._getDataRange();var o=void 0!=this.options.start?this.options.start:s.start,a=void 0!=this.options.end?this.options.end:s.end;this.setWindow(o,a,{animate:!1})}else this.fit({animate:!1})},s.prototype.setGroups=function(t){var e;e=t?t instanceof n||t instanceof r?t:new n(t):null,this.groupsData=e,this.itemSet.setGroups(e)},s.prototype.setSelection=function(t,e){this.itemSet&&this.itemSet.setSelection(t),e&&e.focus&&this.focus(t,e)},s.prototype.getSelection=function(){return this.itemSet&&this.itemSet.getSelection()||[]},s.prototype.focus=function(t,e){if(this.itemsData&&void 0!=t){var i=Array.isArray(t)?t:[t],s=this.itemsData.getDataSet().get(i,{type:{start:"Date",end:"Date"}}),o=null,n=null;if(s.forEach(function(t){var e=t.start.valueOf(),i="end"in t?t.end.valueOf():t.start.valueOf();(null===o||o>e)&&(o=e),(null===n||i>n)&&(n=i)}),null!==o&&null!==n){var r=(o+n)/2,a=Math.max(this.range.end-this.range.start,1.1*(n-o)),h=e&&void 0!==e.animate?e.animate:!0;this.range.setRange(r-a/2,r+a/2,h)}}},s.prototype.getItemRange=function(){var t=this.itemsData.getDataSet(),e=null,i=null;if(t){var s=t.min("start");e=s?o.convert(s.start,"Date").valueOf():null;var n=t.max("start");n&&(i=o.convert(n.start,"Date").valueOf());var r=t.max("end");r&&(i=null==i?o.convert(r.end,"Date").valueOf():Math.max(i,o.convert(r.end,"Date").valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},t.exports=s},function(t,e,i){t.exports="undefined"!=typeof window?window.Hammer||i(20):function(){throw Error("hammer.js is only available in a browser, not in node.js.")}},function(t,e,i){var s;!function(o,n){function r(){a.READY||(w.determineEventTypes(),x.each(a.gestures,function(t){S.register(t)}),w.onTouch(a.DOCUMENT,v,S.detect),w.onTouch(a.DOCUMENT,y,S.detect),a.READY=!0)}var a=function D(t,e){return new D.Instance(t,e||{})};a.VERSION="1.1.3",a.defaults={behavior:{userSelect:"none",touchAction:"pan-y",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}},a.DOCUMENT=document,a.HAS_POINTEREVENTS=navigator.pointerEnabled||navigator.msPointerEnabled,a.HAS_TOUCHEVENTS="ontouchstart"in o,a.IS_MOBILE=/mobile|tablet|ip(ad|hone|od)|android|silk/i.test(navigator.userAgent),a.NO_MOUSEEVENTS=a.HAS_TOUCHEVENTS&&a.IS_MOBILE||a.HAS_POINTEREVENTS,a.CALCULATE_INTERVAL=25;var h={},d=a.DIRECTION_DOWN="down",l=a.DIRECTION_LEFT="left",c=a.DIRECTION_UP="up",p=a.DIRECTION_RIGHT="right",u=a.POINTER_MOUSE="mouse",m=a.POINTER_TOUCH="touch",f=a.POINTER_PEN="pen",g=a.EVENT_START="start",v=a.EVENT_MOVE="move",y=a.EVENT_END="end",b=a.EVENT_RELEASE="release",_=a.EVENT_TOUCH="touch";a.READY=!1,a.plugins=a.plugins||{},a.gestures=a.gestures||{};var x=a.utils={extend:function(t,e,i){for(var s in e)!e.hasOwnProperty(s)||t[s]!==n&&i||(t[s]=e[s]);return t},on:function(t,e,i){t.addEventListener(e,i,!1)},off:function(t,e,i){t.removeEventListener(e,i,!1)},each:function(t,e,i){var s,o;if("forEach"in t)t.forEach(e,i);else if(t.length!==n){for(s=0,o=t.length;o>s;s++)if(e.call(i,t[s],s,t)===!1)return}else for(s in t)if(t.hasOwnProperty(s)&&e.call(i,t[s],s,t)===!1)return},inStr:function(t,e){return t.indexOf(e)>-1},inArray:function(t,e){if(t.indexOf){var i=t.indexOf(e);return-1===i?!1:i}for(var s=0,o=t.length;o>s;s++)if(t[s]===e)return s;return!1},toArray:function(t){return Array.prototype.slice.call(t,0)},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){var e=[],i=[],s=[],o=[],n=Math.min,r=Math.max;return 1===t.length?{pageX:t[0].pageX,pageY:t[0].pageY,clientX:t[0].clientX,clientY:t[0].clientY}:(x.each(t,function(t){e.push(t.pageX),i.push(t.pageY),s.push(t.clientX),o.push(t.clientY)}),{pageX:(n.apply(Math,e)+r.apply(Math,e))/2,pageY:(n.apply(Math,i)+r.apply(Math,i))/2,clientX:(n.apply(Math,s)+r.apply(Math,s))/2,clientY:(n.apply(Math,o)+r.apply(Math,o))/2})},getVelocity:function(t,e,i){return{x:Math.abs(e/t)||0,y:Math.abs(i/t)||0}},getAngle:function(t,e){var i=e.clientX-t.clientX,s=e.clientY-t.clientY;return 180*Math.atan2(s,i)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.clientX-e.clientX),s=Math.abs(t.clientY-e.clientY);return i>=s?t.clientX-e.clientX>0?l:p:t.clientY-e.clientY>0?c:d},getDistance:function(t,e){var i=e.clientX-t.clientX,s=e.clientY-t.clientY;return Math.sqrt(i*i+s*s)},getScale:function(t,e){return t.length>=2&&e.length>=2?this.getDistance(e[0],e[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,e){return t.length>=2&&e.length>=2?this.getAngle(e[1],e[0])-this.getAngle(t[1],t[0]):0},isVertical:function(t){return t==c||t==d},setPrefixedCss:function(t,e,i,s){var o=["","Webkit","Moz","O","ms"];e=x.toCamelCase(e);for(var n=0;n0&&this.started&&(r=v),this.started=!0;var d=this.collectEventData(i,r,o,t);return e!=y&&s.call(S,d),a&&(d.changedLength=h,d.eventType=a,s.call(S,d),d.eventType=r,delete d.changedLength),r==y&&(s.call(S,d),this.started=!1),r},determineEventTypes:function(){var t;return t=a.HAS_POINTEREVENTS?o.PointerEvent?["pointerdown","pointermove","pointerup pointercancel lostpointercapture"]:["MSPointerDown","MSPointerMove","MSPointerUp MSPointerCancel MSLostPointerCapture"]:a.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],h[g]=t[0],h[v]=t[1],h[y]=t[2],h},getTouchList:function(t,e){if(a.HAS_POINTEREVENTS)return M.getTouchList();if(t.touches){if(e==v)return t.touches;var i=[],s=[].concat(x.toArray(t.touches),x.toArray(t.changedTouches)),o=[];return x.each(s,function(t){x.inArray(i,t.identifier)===!1&&o.push(t),i.push(t.identifier)}),o}return t.identifier=1,[t]},collectEventData:function(t,e,i,s){var o=m;return x.inStr(s.type,"mouse")||M.matchType(u,s)?o=u:M.matchType(f,s)&&(o=f),{center:x.getCenter(i),timeStamp:Date.now(),target:s.target,touches:i,eventType:e,pointerType:o,srcEvent:s,preventDefault:function(){var t=this.srcEvent;t.preventManipulation&&t.preventManipulation(),t.preventDefault&&t.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return S.stopDetect()}}}},M=a.PointerEvent={pointers:{},getTouchList:function(){var t=[];return x.each(this.pointers,function(e){t.push(e)}),t},updatePointer:function(t,e){t==y||t!=y&&1!==e.buttons?delete this.pointers[e.pointerId]:(e.identifier=e.pointerId,this.pointers[e.pointerId]=e)},matchType:function(t,e){if(!e.pointerType)return!1;var i=e.pointerType,s={};return s[u]=i===(e.MSPOINTER_TYPE_MOUSE||u),s[m]=i===(e.MSPOINTER_TYPE_TOUCH||m),s[f]=i===(e.MSPOINTER_TYPE_PEN||f),s[t]},reset:function(){this.pointers={}}},S=a.detection={gestures:[],current:null,previous:null,stopped:!1,startDetect:function(t,e){this.current||(this.stopped=!1,this.current={inst:t,startEvent:x.extend({},e),lastEvent:!1,lastCalcEvent:!1,futureCalcEvent:!1,lastCalcData:{},name:""},this.detect(e))},detect:function(t){if(this.current&&!this.stopped){t=this.extendEventData(t);var e=this.current.inst,i=e.options;return x.each(this.gestures,function(s){!this.stopped&&e.enabled&&i[s.name]&&s.handler.call(s,t,e)},this),this.current&&(this.current.lastEvent=t),t.eventType==y&&this.stopDetect(),t}},stopDetect:function(){this.previous=x.extend({},this.current),this.current=null,this.stopped=!0},getCalculatedData:function(t,e,i,s,o){var n=this.current,r=!1,h=n.lastCalcEvent,d=n.lastCalcData;h&&t.timeStamp-h.timeStamp>a.CALCULATE_INTERVAL&&(e=h.center,i=t.timeStamp-h.timeStamp,s=t.center.clientX-h.center.clientX,o=t.center.clientY-h.center.clientY,r=!0),(t.eventType==_||t.eventType==b)&&(n.futureCalcEvent=t),(!n.lastCalcEvent||r)&&(d.velocity=x.getVelocity(i,s,o),d.angle=x.getAngle(e,t.center),d.direction=x.getDirection(e,t.center),n.lastCalcEvent=n.futureCalcEvent||t,n.futureCalcEvent=t),t.velocityX=d.velocity.x,t.velocityY=d.velocity.y,t.interimAngle=d.angle,t.interimDirection=d.direction},extendEventData:function(t){var e=this.current,i=e.startEvent,s=e.lastEvent||i;(t.eventType==_||t.eventType==b)&&(i.touches=[],x.each(t.touches,function(t){i.touches.push({clientX:t.clientX,clientY:t.clientY})}));var o=t.timeStamp-i.timeStamp,n=t.center.clientX-i.center.clientX,r=t.center.clientY-i.center.clientY;return this.getCalculatedData(t,s.center,o,n,r),x.extend(t,{startEvent:i,deltaTime:o,deltaX:n,deltaY:r,distance:x.getDistance(i.center,t.center),angle:x.getAngle(i.center,t.center),direction:x.getDirection(i.center,t.center),scale:x.getScale(i.touches,t.touches),rotation:x.getRotation(i.touches,t.touches)}),t},register:function(t){var e=t.defaults||{};return e[t.name]===n&&(e[t.name]=!0),x.extend(a.defaults,e,!0),t.index=t.index||1e3,this.gestures.push(t),this.gestures.sort(function(t,e){return t.indexe.index?1:0}),this.gestures}};a.Instance=function(t,e){var i=this;r(),this.element=t,this.enabled=!0,x.each(e,function(t,i){delete e[i],e[x.toCamelCase(i)]=t}),this.options=x.extend(x.extend({},a.defaults),e||{}),this.options.behavior&&x.toggleBehavior(this.element,this.options.behavior,!0),this.eventStartHandler=w.onTouch(t,g,function(t){i.enabled&&t.eventType==g?S.startDetect(i,t):t.eventType==_&&S.detect(t)}),this.eventHandlers=[]},a.Instance.prototype={on:function(t,e){var i=this;return w.on(i.element,t,e,function(t){i.eventHandlers.push({gesture:t,handler:e})}),i},off:function(t,e){var i=this;return w.off(i.element,t,e,function(t){var s=x.inArray({gesture:t,handler:e});s!==!1&&i.eventHandlers.splice(s,1)}),i},trigger:function(t,e){e||(e={});var i=a.DOCUMENT.createEvent("Event");i.initEvent(t,!0,!0),i.gesture=e;var s=this.element;return x.hasParent(e.target,s)&&(s=e.target),s.dispatchEvent(i),this},enable:function(t){return this.enabled=t,this},dispose:function(){var t,e;for(x.toggleBehavior(this.element,this.options.behavior,!1),t=-1;e=this.eventHandlers[++t];)x.off(this.element,e.gesture,e.handler);return this.eventHandlers=[],w.off(this.element,h[g],this.eventStartHandler),null}},function(t){function e(e,s){var o=S.current;if(!(s.options.dragMaxTouches>0&&e.touches.length>s.options.dragMaxTouches))switch(e.eventType){case g:i=!1;break;case v:if(e.distance0)){var r=Math.abs(s.options.dragMinDistance/e.distance);n.pageX+=e.deltaX*r,n.pageY+=e.deltaY*r,n.clientX+=e.deltaX*r,n.clientY+=e.deltaY*r,e=S.extendEventData(e)}(o.lastEvent.dragLockToAxis||s.options.dragLockToAxis&&s.options.dragLockMinDistance<=e.distance)&&(e.dragLockToAxis=!0);var a=o.lastEvent.direction;e.dragLockToAxis&&a!==e.direction&&(e.direction=x.isVertical(a)?e.deltaY<0?c:d:e.deltaX<0?l:p),i||(s.trigger(t+"start",e),i=!0),s.trigger(t,e),s.trigger(t+e.direction,e);var h=x.isVertical(e.direction);(s.options.dragBlockVertical&&h||s.options.dragBlockHorizontal&&!h)&&e.preventDefault();break;case b:i&&e.changedLength<=s.options.dragMaxTouches&&(s.trigger(t+"end",e),i=!1);break;case y:i=!1}}var i=!1;a.gestures.Drag={name:t,index:50,handler:e,defaults:{dragMinDistance:10,dragDistanceCorrection:!0,dragMaxTouches:1,dragBlockHorizontal:!1,dragBlockVertical:!1,dragLockToAxis:!1,dragLockMinDistance:25}}}("drag"),a.gestures.Gesture={name:"gesture",index:1337,handler:function(t,e){e.trigger(this.name,t)}},function(t){function e(e,s){var o=s.options,n=S.current;switch(e.eventType){case g:clearTimeout(i),n.name=t,i=setTimeout(function(){n&&n.name==t&&s.trigger(t,e)},o.holdTimeout);break;case v:e.distance>o.holdThreshold&&clearTimeout(i);break;case b:clearTimeout(i)}}var i;a.gestures.Hold={name:t,index:10,defaults:{holdTimeout:500,holdThreshold:2},handler:e}}("hold"),a.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==b&&e.trigger(this.name,t)}},a.gestures.Swipe={name:"swipe",index:40,defaults:{swipeMinTouches:1,swipeMaxTouches:1,swipeVelocityX:.6,swipeVelocityY:.6},handler:function(t,e){if(t.eventType==b){var i=t.touches.length,s=e.options;if(is.swipeMaxTouches)return;(t.velocityX>s.swipeVelocityX||t.velocityY>s.swipeVelocityY)&&(e.trigger(this.name,t),e.trigger(this.name+t.direction,t))}}},function(t){function e(e,s){var o,n,r=s.options,a=S.current,h=S.previous;switch(e.eventType){case g:i=!1;break;case v:i=i||e.distance>r.tapMaxDistance;break;case y:!x.inStr(e.srcEvent.type,"cancel")&&e.deltaTimes.options.transformMinRotation&&s.trigger("rotate",e),o>s.options.transformMinScale&&(s.trigger("pinch",e),s.trigger("pinch"+(e.scale<1?"in":"out"),e));break;case b:i&&e.changedLength<2&&(s.trigger(t+"end",e),i=!1)}}var i=!1;a.gestures.Transform={name:t,index:45,defaults:{transformMinScale:.01,transformMinRotation:1},handler:e}}("transform"),s=function(){return a}.call(e,i,e,t),!(s!==n&&(t.exports=s))}(window)},function(t,e,i){function s(t,e){var i=h().hours(0).minutes(0).seconds(0).milliseconds(0);this.start=i.clone().add(-3,"days").valueOf(),this.end=i.clone().add(4,"days").valueOf(),this.body=t,this.deltaDifference=0,this.scaleOffset=0,this.startToFront=!1,this.endToFront=!0,this.defaultOptions={start:null,end:null,direction:"horizontal",moveable:!0,zoomable:!0,min:null,max:null,zoomMin:10,zoomMax:31536e10},this.options=r.extend({},this.defaultOptions),this.props={touch:{}},this.animateTimer=null,this.body.emitter.on("dragstart",this._onDragStart.bind(this)),this.body.emitter.on("drag",this._onDrag.bind(this)),this.body.emitter.on("dragend",this._onDragEnd.bind(this)),this.body.emitter.on("hold",this._onHold.bind(this)),this.body.emitter.on("mousewheel",this._onMouseWheel.bind(this)),this.body.emitter.on("DOMMouseScroll",this._onMouseWheel.bind(this)),this.body.emitter.on("touch",this._onTouch.bind(this)),this.body.emitter.on("pinch",this._onPinch.bind(this)),this.setOptions(e)}function o(t){if("horizontal"!=t&&"vertical"!=t)throw new TypeError('Unknown direction "'+t+'". Choose "horizontal" or "vertical".')}function n(t,e){return{x:t.pageX-r.getAbsoluteLeft(e),y:t.pageY-r.getAbsoluteTop(e)}}var r=i(1),a=i(22),h=i(2),d=i(23),l=i(24);s.prototype=new d,s.prototype.setOptions=function(t){if(t){var e=["direction","min","max","zoomMin","zoomMax","moveable","zoomable","activate","hiddenDates"];r.selectiveExtend(e,this.options,t),("start"in t||"end"in t)&&this.setRange(t.start,t.end)}},s.prototype.setRange=function(t,e,i,s){s!==!0&&(s=!1);var o=void 0!=t?r.convert(t,"Date").valueOf():null,n=void 0!=e?r.convert(e,"Date").valueOf():null;if(this._cancelAnimation(),i){var a=this,h=this.start,d=this.end,c="number"==typeof i?i:500,p=(new Date).valueOf(),u=!1,m=function(){if(!a.props.touch.dragging){var t=(new Date).valueOf(),e=t-p,i=e>c,g=i||null===o?o:r.easeInOutQuad(e,h,o,c),v=i||null===n?n:r.easeInOutQuad(e,d,n,c);f=a._applyRange(g,v),l.updateHiddenDates(a.body,a.options.hiddenDates),u=u||f,f&&a.body.emitter.emit("rangechange",{start:new Date(a.start),end:new Date(a.end),byUser:s}),i?u&&a.body.emitter.emit("rangechanged",{start:new Date(a.start),end:new Date(a.end),byUser:s}):a.animateTimer=setTimeout(m,20)}};return m()}var f=this._applyRange(o,n);if(l.updateHiddenDates(this.body,this.options.hiddenDates),f){var g={start:new Date(this.start),end:new Date(this.end),byUser:s};this.body.emitter.emit("rangechange",g),this.body.emitter.emit("rangechanged",g)}},s.prototype._cancelAnimation=function(){this.animateTimer&&(clearTimeout(this.animateTimer),this.animateTimer=null)},s.prototype._applyRange=function(t,e){var i,s=null!=t?r.convert(t,"Date").valueOf():this.start,o=null!=e?r.convert(e,"Date").valueOf():this.end,n=null!=this.options.max?r.convert(this.options.max,"Date").valueOf():null,a=null!=this.options.min?r.convert(this.options.min,"Date").valueOf():null;if(isNaN(s)||null===s)throw new Error('Invalid start "'+t+'"');if(isNaN(o)||null===o)throw new Error('Invalid end "'+e+'"');if(s>o&&(o=s),null!==a&&a>s&&(i=a-s,s+=i,o+=i,null!=n&&o>n&&(o=n)),null!==n&&o>n&&(i=o-n,s-=i,o-=i,null!=a&&a>s&&(s=a)),null!==this.options.zoomMin){var h=parseFloat(this.options.zoomMin);0>h&&(h=0),h>o-s&&(this.end-this.start===h?(s=this.start,o=this.end):(i=h-(o-s),s-=i/2,o+=i/2))}if(null!==this.options.zoomMax){var d=parseFloat(this.options.zoomMax);0>d&&(d=0),o-s>d&&(this.end-this.start===d?(s=this.start,o=this.end):(i=o-s-d,s+=i/2,o-=i/2))}var l=this.start!=s||this.end!=o;return s>=this.start&&s<=this.end||o>=this.start&&o<=this.end||this.start>=s&&this.start<=o||this.end>=s&&this.end<=o||this.body.emitter.emit("checkRangedItems"),this.start=s,this.end=o,l},s.prototype.getRange=function(){return{start:this.start,end:this.end}},s.prototype.conversion=function(t,e){return s.conversion(this.start,this.end,t,e)},s.conversion=function(t,e,i,s){return void 0===s&&(s=0),0!=i&&e-t!=0?{offset:t,scale:i/(e-t-s)}:{offset:0,scale:1}},s.prototype._onDragStart=function(){this.deltaDifference=0,this.previousDelta=0,this.options.moveable&&this.props.touch.allowDragging&&(this.props.touch.start=this.start,this.props.touch.end=this.end,this.props.touch.dragging=!0,this.body.dom.root&&(this.body.dom.root.style.cursor="move"))},s.prototype._onDrag=function(t){if(this.options.moveable&&this.props.touch.allowDragging){var e=this.options.direction;o(e);var i="horizontal"==e?t.gesture.deltaX:t.gesture.deltaY;i-=this.deltaDifference;var s=this.props.touch.end-this.props.touch.start,n=l.getHiddenDurationBetween(this.body.hiddenDates,this.start,this.end);s-=n;var r="horizontal"==e?this.body.domProps.center.width:this.body.domProps.center.height,a=-i/r*s,h=this.props.touch.start+a,d=this.props.touch.end+a,c=l.snapAwayFromHidden(this.body.hiddenDates,h,this.previousDelta-i,!0),p=l.snapAwayFromHidden(this.body.hiddenDates,d,this.previousDelta-i,!0); +if(c!=h||p!=d)return this.deltaDifference+=i,this.props.touch.start=c,this.props.touch.end=p,void this._onDrag(t);this.previousDelta=i,this._applyRange(h,d),this.body.emitter.emit("rangechange",{start:new Date(this.start),end:new Date(this.end),byUser:!0})}},s.prototype._onDragEnd=function(){this.options.moveable&&this.props.touch.allowDragging&&(this.props.touch.dragging=!1,this.body.dom.root&&(this.body.dom.root.style.cursor="auto"),this.body.emitter.emit("rangechanged",{start:new Date(this.start),end:new Date(this.end),byUser:!0}))},s.prototype._onMouseWheel=function(t){if(this.options.zoomable&&this.options.moveable){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){var i;i=0>e?1-e/5:1/(1+e/5);var s=a.fakeGesture(this,t),o=n(s.center,this.body.dom.center),r=this._pointerToDate(o);this.zoom(i,r,e)}t.preventDefault()}},s.prototype._onTouch=function(){this.props.touch.start=this.start,this.props.touch.end=this.end,this.props.touch.allowDragging=!0,this.props.touch.center=null,this.scaleOffset=0,this.deltaDifference=0},s.prototype._onHold=function(){this.props.touch.allowDragging=!1},s.prototype._onPinch=function(t){if(this.options.zoomable&&this.options.moveable&&(this.props.touch.allowDragging=!1,t.gesture.touches.length>1)){this.props.touch.center||(this.props.touch.center=n(t.gesture.center,this.body.dom.center));var e=1/(t.gesture.scale+this.scaleOffset),i=this._pointerToDate(this.props.touch.center),s=l.getHiddenDurationBetween(this.body.hiddenDates,this.start,this.end),o=l.getHiddenDurationBefore(this.body.hiddenDates,this,i),r=s-o,a=i-o+(this.props.touch.start-(i-o))*e,h=i+r+(this.props.touch.end-(i+r))*e;this.startToFront=1-e>0?!1:!0,this.endToFront=e-1>0?!1:!0;var d=l.snapAwayFromHidden(this.body.hiddenDates,a,1-e,!0),c=l.snapAwayFromHidden(this.body.hiddenDates,h,e-1,!0);(d!=a||c!=h)&&(this.props.touch.start=d,this.props.touch.end=c,this.scaleOffset=1-t.gesture.scale,a=d,h=c),this.setRange(a,h,!1,!0),this.startToFront=!1,this.endToFront=!0}},s.prototype._pointerToDate=function(t){var e,i=this.options.direction;if(o(i),"horizontal"==i)return this.body.util.toTime(t.x).valueOf();var s=this.body.domProps.center.height;return e=this.conversion(s),t.y/e.scale+e.offset},s.prototype.zoom=function(t,e,i){null==e&&(e=(this.start+this.end)/2);var s=l.getHiddenDurationBetween(this.body.hiddenDates,this.start,this.end),o=l.getHiddenDurationBefore(this.body.hiddenDates,this,e),n=s-o,r=e-o+(this.start-(e-o))*t,a=e+n+(this.end-(e+n))*t;this.startToFront=i>0?!1:!0,this.endToFront=-i>0?!1:!0;var h=l.snapAwayFromHidden(this.body.hiddenDates,r,i,!0),d=l.snapAwayFromHidden(this.body.hiddenDates,a,-i,!0);(h!=r||d!=a)&&(r=h,a=d),this.setRange(r,a,!1,!0),this.startToFront=!1,this.endToFront=!0},s.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,s=this.end+e*t;this.start=i,this.end=s},s.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,s=this.start-i,o=this.end-i;this.setRange(s,o)},t.exports=s},function(t,e,i){var s=i(19);e.fakeGesture=function(t,e){var i=null,o=s.event.getTouchList(e,i),n=s.event.collectEventData(this,i,o,e);return isNaN(n.center.pageX)&&(n.center.pageX=e.pageX),isNaN(n.center.pageY)&&(n.center.pageY=e.pageY),n}},function(t){function e(){this.options=null,this.props=null}e.prototype.setOptions=function(t){t&&util.extend(this.options,t)},e.prototype.redraw=function(){return!1},e.prototype.destroy=function(){},e.prototype._isResized=function(){var t=this.props._previousWidth!==this.props.width||this.props._previousHeight!==this.props.height;return this.props._previousWidth=this.props.width,this.props._previousHeight=this.props.height,t},t.exports=e},function(t,e,i){var s=i(2);e.convertHiddenOptions=function(t,e){if(t.hiddenDates=[],e&&1==Array.isArray(e)){for(var i=0;i=4*a){var p=0,u=n.clone();switch(i[h].repeat){case"daily":d.day()!=l.day()&&(p=1),d.dayOfYear(o.dayOfYear()),d.year(o.year()),d.subtract(7,"days"),l.dayOfYear(o.dayOfYear()),l.year(o.year()),l.subtract(7-p,"days"),u.add(1,"weeks");break;case"weekly":var m=l.diff(d,"days"),f=d.day();d.date(o.date()),d.month(o.month()),d.year(o.year()),l=d.clone(),d.day(f),l.day(f),l.add(m,"days"),d.subtract(1,"weeks"),l.subtract(1,"weeks"),u.add(1,"weeks");break;case"monthly":d.month()!=l.month()&&(p=1),d.month(o.month()),d.year(o.year()),d.subtract(1,"months"),l.month(o.month()),l.year(o.year()),l.subtract(1,"months"),l.add(p,"months"),u.add(1,"months");break;case"yearly":d.year()!=l.year()&&(p=1),d.year(o.year()),d.subtract(1,"years"),l.year(o.year()),l.subtract(1,"years"),l.add(p,"years"),u.add(1,"years");break;default:return void console.log("Wrong repeat format, allowed are: daily, weekly, monthly, yearly. Given:",i[h].repeat)}for(;u>d;)switch(t.hiddenDates.push({start:d.valueOf(),end:l.valueOf()}),i[h].repeat){case"daily":d.add(1,"days"),l.add(1,"days");break;case"weekly":d.add(1,"weeks"),l.add(1,"weeks");break;case"monthly":d.add(1,"months"),l.add(1,"months");break;case"yearly":d.add(1,"y"),l.add(1,"y");break;default:return void console.log("Wrong repeat format, allowed are: daily, weekly, monthly, yearly. Given:",i[h].repeat)}t.hiddenDates.push({start:d.valueOf(),end:l.valueOf()})}}e.removeDuplicates(t);var g=e.isHidden(t.range.start,t.hiddenDates),v=e.isHidden(t.range.end,t.hiddenDates),y=t.range.start,b=t.range.end;1==g.hidden&&(y=1==t.range.startToFront?g.startDate-1:g.endDate+1),1==v.hidden&&(b=1==t.range.endToFront?v.startDate-1:v.endDate+1),(1==g.hidden||1==v.hidden)&&t.range._applyRange(y,b)}},e.removeDuplicates=function(t){for(var e=t.hiddenDates,i=[],s=0;s=e[s].start&&e[o].end<=e[s].end?e[o].remove=!0:e[o].start>=e[s].start&&e[o].start<=e[s].end?(e[s].end=e[o].end,e[o].remove=!0):e[o].end>=e[s].start&&e[o].end<=e[s].end&&(e[s].start=e[o].start,e[o].remove=!0));for(var s=0;s=r&&a>o){i=!0;break}}if(1==i&&o=e&&i>r&&(s+=r-n)}return s},e.correctTimeForHidden=function(t,i,o){return o=s(o).toDate().valueOf(),o-=e.getHiddenDurationBefore(t,i,o)},e.getHiddenDurationBefore=function(t,e,i){var o=0;i=s(i).toDate().valueOf();for(var n=0;n=e.start&&a=a&&(o+=a-r)}return o},e.getAccumulatedHiddenDuration=function(t,e,i){for(var s=0,o=0,n=e.start,r=0;r=e.start&&h=i)break;s+=h-a}}return s},e.snapAwayFromHidden=function(t,i,s,o){var n=e.isHidden(i,t);return 1==n.hidden?0>s?1==o?n.startDate-(n.endDate-i)-1:n.startDate-1:1==o?n.endDate+(i-n.startDate)+1:n.endDate+1:i},e.isHidden=function(t,e){for(var i=0;i=s&&o>t)return{hidden:!0,startDate:s,endDate:o}}return{hidden:!1,startDate:s,endDate:o}}},function(t,e,i){function s(){}var o=i(11),n=i(19),r=i(1),a=(i(7),i(9),i(21),i(26),i(35)),h=i(24);o(s.prototype),s.prototype._create=function(t){this.dom={},this.dom.root=document.createElement("div"),this.dom.background=document.createElement("div"),this.dom.backgroundVertical=document.createElement("div"),this.dom.backgroundHorizontal=document.createElement("div"),this.dom.centerContainer=document.createElement("div"),this.dom.leftContainer=document.createElement("div"),this.dom.rightContainer=document.createElement("div"),this.dom.center=document.createElement("div"),this.dom.left=document.createElement("div"),this.dom.right=document.createElement("div"),this.dom.top=document.createElement("div"),this.dom.bottom=document.createElement("div"),this.dom.shadowTop=document.createElement("div"),this.dom.shadowBottom=document.createElement("div"),this.dom.shadowTopLeft=document.createElement("div"),this.dom.shadowBottomLeft=document.createElement("div"),this.dom.shadowTopRight=document.createElement("div"),this.dom.shadowBottomRight=document.createElement("div"),this.dom.root.className="vis timeline root",this.dom.background.className="vispanel background",this.dom.backgroundVertical.className="vispanel background vertical",this.dom.backgroundHorizontal.className="vispanel background horizontal",this.dom.centerContainer.className="vispanel center",this.dom.leftContainer.className="vispanel left",this.dom.rightContainer.className="vispanel right",this.dom.top.className="vispanel top",this.dom.bottom.className="vispanel bottom",this.dom.left.className="content",this.dom.center.className="content",this.dom.right.className="content",this.dom.shadowTop.className="shadow top",this.dom.shadowBottom.className="shadow bottom",this.dom.shadowTopLeft.className="shadow top",this.dom.shadowBottomLeft.className="shadow bottom",this.dom.shadowTopRight.className="shadow top",this.dom.shadowBottomRight.className="shadow bottom",this.dom.root.appendChild(this.dom.background),this.dom.root.appendChild(this.dom.backgroundVertical),this.dom.root.appendChild(this.dom.backgroundHorizontal),this.dom.root.appendChild(this.dom.centerContainer),this.dom.root.appendChild(this.dom.leftContainer),this.dom.root.appendChild(this.dom.rightContainer),this.dom.root.appendChild(this.dom.top),this.dom.root.appendChild(this.dom.bottom),this.dom.centerContainer.appendChild(this.dom.center),this.dom.leftContainer.appendChild(this.dom.left),this.dom.rightContainer.appendChild(this.dom.right),this.dom.centerContainer.appendChild(this.dom.shadowTop),this.dom.centerContainer.appendChild(this.dom.shadowBottom),this.dom.leftContainer.appendChild(this.dom.shadowTopLeft),this.dom.leftContainer.appendChild(this.dom.shadowBottomLeft),this.dom.rightContainer.appendChild(this.dom.shadowTopRight),this.dom.rightContainer.appendChild(this.dom.shadowBottomRight),this.on("rangechange",this.redraw.bind(this)),this.on("touch",this._onTouch.bind(this)),this.on("pinch",this._onPinch.bind(this)),this.on("dragstart",this._onDragStart.bind(this)),this.on("drag",this._onDrag.bind(this));var e=this;this.on("change",function(t){t&&1==t.queue?e._redrawTimer||(e._redrawTimer=setTimeout(function(){e._redrawTimer=null,e.redraw()},0)):e.redraw()}),this.hammer=n(this.dom.root,{preventDefault:!0}),this.listeners={};var i=["touch","pinch","tap","doubletap","hold","dragstart","drag","dragend","mousewheel","DOMMouseScroll"];if(i.forEach(function(t){var i=function(){var i=[t].concat(Array.prototype.slice.call(arguments,0));e.isActive()&&e.emit.apply(e,i)};e.hammer.on(t,i),e.listeners[t]=i}),this.props={root:{},background:{},centerContainer:{},leftContainer:{},rightContainer:{},center:{},left:{},right:{},top:{},bottom:{},border:{},scrollTop:0,scrollTopMin:0},this.touch={},this.redrawCount=0,!t)throw new Error("No container provided");t.appendChild(this.dom.root)},s.prototype.setOptions=function(t){if(t){var e=["width","height","minHeight","maxHeight","autoResize","start","end","orientation","clickToUse","dataAttributes","hiddenDates"];r.selectiveExtend(e,this.options,t),"hiddenDates"in this.options&&h.convertHiddenOptions(this.body,this.options.hiddenDates),"clickToUse"in t&&(t.clickToUse?this.activator||(this.activator=new a(this.dom.root)):this.activator&&(this.activator.destroy(),delete this.activator)),this._initAutoResize()}if(this.components.forEach(function(e){e.setOptions(t)}),t&&t.order)throw new Error("Option order is deprecated. There is no replacement for this feature.");this.redraw()},s.prototype.isActive=function(){return!this.activator||this.activator.active},s.prototype.destroy=function(){this.clear(),this.off(),this._stopAutoResize(),this.dom.root.parentNode&&this.dom.root.parentNode.removeChild(this.dom.root),this.dom=null,this.activator&&(this.activator.destroy(),delete this.activator);for(var t in this.listeners)this.listeners.hasOwnProperty(t)&&delete this.listeners[t];this.listeners=null,this.hammer=null,this.components.forEach(function(t){t.destroy()}),this.body=null},s.prototype.setCustomTime=function(t){if(!this.customTime)throw new Error("Cannot get custom time: Custom time bar is not enabled");this.customTime.setCustomTime(t)},s.prototype.getCustomTime=function(){if(!this.customTime)throw new Error("Cannot get custom time: Custom time bar is not enabled");return this.customTime.getCustomTime()},s.prototype.getVisibleItems=function(){return this.itemSet&&this.itemSet.getVisibleItems()||[]},s.prototype.clear=function(t){(!t||t.items)&&this.setItems(null),(!t||t.groups)&&this.setGroups(null),(!t||t.options)&&(this.components.forEach(function(t){t.setOptions(t.defaultOptions)}),this.setOptions(this.defaultOptions))},s.prototype.fit=function(t){var e=this._getDataRange();if(null!==e.start||null!==e.end){var i=t&&void 0!==t.animate?t.animate:!0;this.range.setRange(e.start,e.end,i)}},s.prototype._getDataRange=function(){var t=this.getItemRange(),e=t.min,i=t.max;if(null!=e&&null!=i){var s=i.valueOf()-e.valueOf();0>=s&&(s=864e5),e=new Date(e.valueOf()-.05*s),i=new Date(i.valueOf()+.05*s)}return{start:e,end:i}},s.prototype.setWindow=function(t,e,i){var s=i&&void 0!==i.animate?i.animate:!0;if(1==arguments.length){var o=arguments[0];this.range.setRange(o.start,o.end,s)}else this.range.setRange(t,e,s)},s.prototype.moveTo=function(t,e){var i=this.range.end-this.range.start,s=r.convert(t,"Date").valueOf(),o=s-i/2,n=s+i/2,a=e&&void 0!==e.animate?e.animate:!0;this.range.setRange(o,n,a)},s.prototype.getWindow=function(){var t=this.range.getRange();return{start:new Date(t.start),end:new Date(t.end)}},s.prototype.redraw=function(){var t=!1,e=this.options,i=this.props,s=this.dom;if(s){h.updateHiddenDates(this.body,this.options.hiddenDates),"top"==e.orientation?(r.addClassName(s.root,"top"),r.removeClassName(s.root,"bottom")):(r.removeClassName(s.root,"top"),r.addClassName(s.root,"bottom")),s.root.style.maxHeight=r.option.asSize(e.maxHeight,""),s.root.style.minHeight=r.option.asSize(e.minHeight,""),s.root.style.width=r.option.asSize(e.width,""),i.border.left=(s.centerContainer.offsetWidth-s.centerContainer.clientWidth)/2,i.border.right=i.border.left,i.border.top=(s.centerContainer.offsetHeight-s.centerContainer.clientHeight)/2,i.border.bottom=i.border.top;var o=s.root.offsetHeight-s.root.clientHeight,n=s.root.offsetWidth-s.root.clientWidth;0===s.centerContainer.clientHeight&&(i.border.left=i.border.top,i.border.right=i.border.left),0===s.root.clientHeight&&(n=o),i.center.height=s.center.offsetHeight,i.left.height=s.left.offsetHeight,i.right.height=s.right.offsetHeight,i.top.height=s.top.clientHeight||-i.border.top,i.bottom.height=s.bottom.clientHeight||-i.border.bottom;var a=Math.max(i.left.height,i.center.height,i.right.height),d=i.top.height+a+i.bottom.height+o+i.border.top+i.border.bottom;s.root.style.height=r.option.asSize(e.height,d+"px"),i.root.height=s.root.offsetHeight,i.background.height=i.root.height-o;var l=i.root.height-i.top.height-i.bottom.height-o;i.centerContainer.height=l,i.leftContainer.height=l,i.rightContainer.height=i.leftContainer.height,i.root.width=s.root.offsetWidth,i.background.width=i.root.width-n,i.left.width=s.leftContainer.clientWidth||-i.border.left,i.leftContainer.width=i.left.width,i.right.width=s.rightContainer.clientWidth||-i.border.right,i.rightContainer.width=i.right.width;var c=i.root.width-i.left.width-i.right.width-n;i.center.width=c,i.centerContainer.width=c,i.top.width=c,i.bottom.width=c,s.background.style.height=i.background.height+"px",s.backgroundVertical.style.height=i.background.height+"px",s.backgroundHorizontal.style.height=i.centerContainer.height+"px",s.centerContainer.style.height=i.centerContainer.height+"px",s.leftContainer.style.height=i.leftContainer.height+"px",s.rightContainer.style.height=i.rightContainer.height+"px",s.background.style.width=i.background.width+"px",s.backgroundVertical.style.width=i.centerContainer.width+"px",s.backgroundHorizontal.style.width=i.background.width+"px",s.centerContainer.style.width=i.center.width+"px",s.top.style.width=i.top.width+"px",s.bottom.style.width=i.bottom.width+"px",s.background.style.left="0",s.background.style.top="0",s.backgroundVertical.style.left=i.left.width+i.border.left+"px",s.backgroundVertical.style.top="0",s.backgroundHorizontal.style.left="0",s.backgroundHorizontal.style.top=i.top.height+"px",s.centerContainer.style.left=i.left.width+"px",s.centerContainer.style.top=i.top.height+"px",s.leftContainer.style.left="0",s.leftContainer.style.top=i.top.height+"px",s.rightContainer.style.left=i.left.width+i.center.width+"px",s.rightContainer.style.top=i.top.height+"px",s.top.style.left=i.left.width+"px",s.top.style.top="0",s.bottom.style.left=i.left.width+"px",s.bottom.style.top=i.top.height+i.centerContainer.height+"px",this._updateScrollTop();var p=this.props.scrollTop;"bottom"==e.orientation&&(p+=Math.max(this.props.centerContainer.height-this.props.center.height-this.props.border.top-this.props.border.bottom,0)),s.center.style.left="0",s.center.style.top=p+"px",s.left.style.left="0",s.left.style.top=p+"px",s.right.style.left="0",s.right.style.top=p+"px";var u=0==this.props.scrollTop?"hidden":"",m=this.props.scrollTop==this.props.scrollTopMin?"hidden":"";if(s.shadowTop.style.visibility=u,s.shadowBottom.style.visibility=m,s.shadowTopLeft.style.visibility=u,s.shadowBottomLeft.style.visibility=m,s.shadowTopRight.style.visibility=u,s.shadowBottomRight.style.visibility=m,this.components.forEach(function(e){t=e.redraw()||t}),t){var f=3;this.redrawCount0&&(this.props.scrollTop=0),this.props.scrollTope;e++)s=this.selection[e],o=this.items[s],o&&o.unselect();for(this.selection=[],e=0,i=t.length;i>e;e++)s=t[e],o=this.items[s],o&&(this.selection.push(s),o.select())},s.prototype.getSelection=function(){return this.selection.concat([])},s.prototype.getVisibleItems=function(){var t=this.body.range.getRange(),e=this.body.util.toScreen(t.start),i=this.body.util.toScreen(t.end),s=[];for(var o in this.groups)if(this.groups.hasOwnProperty(o))for(var n=this.groups[o],r=n.visibleItems,a=0;ae&&s.push(h.id)}return s},s.prototype._deselect=function(t){for(var e=this.selection,i=0,s=e.length;s>i;i++)if(e[i]==t){e.splice(i,1);break}},s.prototype.redraw=function(){var t=this.options.margin,e=this.body.range,i=n.option.asSize,s=this.options,o=s.orientation,r=!1,a=this.dom.frame,h=s.editable.updateTime||s.editable.updateGroup;this.props.top=this.body.domProps.top.height+this.body.domProps.border.top,this.props.left=this.body.domProps.left.width+this.body.domProps.border.left,a.className="itemset"+(h?" editable":""),r=this._orderGroups()||r;var d=e.end-e.start,l=d!=this.lastVisibleInterval||this.props.width!=this.props.lastWidth;l&&(this.stackDirty=!0),this.lastVisibleInterval=d,this.props.lastWidth=this.props.width;var c=this.stackDirty,p=this._firstGroup(),u={item:t.item,axis:t.axis},m={item:t.item,axis:t.item.vertical/2},f=0,v=t.axis+t.item.vertical;return this.groups[g].redraw(e,m,c),n.forEach(this.groups,function(t){var i=t==p?u:m,s=t.redraw(e,i,c);r=s||r,f+=t.height}),f=Math.max(f,v),this.stackDirty=!1,a.style.height=i(f),this.props.width=a.offsetWidth,this.props.height=f,this.dom.axis.style.top=i("top"==o?this.body.domProps.top.height+this.body.domProps.border.top:this.body.domProps.top.height+this.body.domProps.centerContainer.height),this.dom.axis.style.left="0",r=this._isResized()||r},s.prototype._firstGroup=function(){var t="top"==this.options.orientation?0:this.groupIds.length-1,e=this.groupIds[t],i=this.groups[e]||this.groups[f];return i||null},s.prototype._updateUngrouped=function(){{var t,e,i=this.groups[f];this.groups[g]}if(this.groupsData){if(i){i.hide(),delete this.groups[f];for(e in this.items)if(this.items.hasOwnProperty(e)){t=this.items[e],t.parent&&t.parent.remove(t);var s=this._getGroupId(t.data),o=this.groups[s];o&&o.add(t)||t.hide()}}}else if(!i){var n=null,r=null;i=new d(n,r,this),this.groups[f]=i;for(e in this.items)this.items.hasOwnProperty(e)&&(t=this.items[e],i.add(t));i.show()}},s.prototype.getLabelSet=function(){return this.dom.labelSet},s.prototype.setItems=function(t){var e,i=this,s=this.itemsData;if(t){if(!(t instanceof r||t instanceof a))throw new TypeError("Data must be an instance of DataSet or DataView");this.itemsData=t}else this.itemsData=null;if(s&&(n.forEach(this.itemListeners,function(t,e){s.off(e,t)}),e=s.getIds(),this._onRemove(e)),this.itemsData){var o=this.id;n.forEach(this.itemListeners,function(t,e){i.itemsData.on(e,t,o)}),e=this.itemsData.getIds(),this._onAdd(e),this._updateUngrouped()}},s.prototype.getItems=function(){return this.itemsData},s.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(n.forEach(this.groupListeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this.groupsData=null,this._onRemoveGroups(e)),t){if(!(t instanceof r||t instanceof a))throw new TypeError("Data must be an instance of DataSet or DataView");this.groupsData=t}else this.groupsData=null;if(this.groupsData){var s=this.id;n.forEach(this.groupListeners,function(t,e){i.groupsData.on(e,t,s)}),e=this.groupsData.getIds(),this._onAddGroups(e)}this._updateUngrouped(),this._order(),this.body.emitter.emit("change",{queue:!0})},s.prototype.getGroups=function(){return this.groupsData},s.prototype.removeItem=function(t){var e=this.itemsData.get(t),i=this.itemsData.getDataSet();e&&this.options.onRemove(e,function(e){e&&i.remove(t)})},s.prototype._getType=function(t){return t.type||this.options.type||(t.end?"range":"box")},s.prototype._getGroupId=function(t){var e=this._getType(t);return"background"==e&&void 0==t.group?g:this.groupsData?t.group:f},s.prototype._onUpdate=function(t){var e=this;t.forEach(function(t){var i=e.itemsData.get(t,e.itemOptions),o=e.items[t],n=e._getType(i),r=s.types[n];if(o&&(r&&o instanceof r?e._updateItem(o,i):(e._removeItem(o),o=null)),!o){if(!r)throw new TypeError("rangeoverflow"==n?'Item type "rangeoverflow" is deprecated. Use css styling instead: .vis.timeline .item.range .content {overflow: visible;}':'Unknown item type "'+n+'"');o=new r(i,e.conversion,e.options),o.id=t,e._addItem(o)}}),this._order(),this.stackDirty=!0,this.body.emitter.emit("change",{queue:!0})},s.prototype._onAdd=s.prototype._onUpdate,s.prototype._onRemove=function(t){var e=0,i=this;t.forEach(function(t){var s=i.items[t];s&&(e++,i._removeItem(s))}),e&&(this._order(),this.stackDirty=!0,this.body.emitter.emit("change",{queue:!0}))},s.prototype._order=function(){n.forEach(this.groups,function(t){t.order()})},s.prototype._onUpdateGroups=function(t){this._onAddGroups(t)},s.prototype._onAddGroups=function(t){var e=this;t.forEach(function(t){var i=e.groupsData.get(t),s=e.groups[t];if(s)s.setData(i);else{if(t==f||t==g)throw new Error("Illegal group id. "+t+" is a reserved id.");var o=Object.create(e.options);n.extend(o,{height:null}),s=new d(t,i,e),e.groups[t]=s;for(var r in e.items)if(e.items.hasOwnProperty(r)){var a=e.items[r];a.data.group==t&&s.add(a)}s.order(),s.show() +}}),this.body.emitter.emit("change",{queue:!0})},s.prototype._onRemoveGroups=function(t){var e=this.groups;t.forEach(function(t){var i=e[t];i&&(i.hide(),delete e[t])}),this.markDirty(),this.body.emitter.emit("change",{queue:!0})},s.prototype._orderGroups=function(){if(this.groupsData){var t=this.groupsData.getIds({order:this.options.groupOrder}),e=!n.equalArray(t,this.groupIds);if(e){var i=this.groups;t.forEach(function(t){i[t].hide()}),t.forEach(function(t){i[t].show()}),this.groupIds=t}return e}return!1},s.prototype._addItem=function(t){this.items[t.id]=t;var e=this._getGroupId(t.data),i=this.groups[e];i&&i.add(t)},s.prototype._updateItem=function(t,e){var i=t.data.group;if(t.setData(e),i!=t.data.group){var s=this.groups[i];s&&s.remove(t);var o=this._getGroupId(t.data),n=this.groups[o];n&&n.add(t)}},s.prototype._removeItem=function(t){t.hide(),delete this.items[t.id];var e=this.selection.indexOf(t.id);-1!=e&&this.selection.splice(e,1),t.parent&&t.parent.remove(t)},s.prototype._constructByEndArray=function(t){for(var e=[],i=0;i0||o.length>0)&&this.body.emitter.emit("select",{items:a})}},s.prototype._onAddItem=function(t){if(this.options.selectable&&this.options.editable.add){var e=this,i=this.body.util.snap||null,o=s.itemFromTarget(t);if(o){var r=e.itemsData.get(o.id);this.options.onUpdate(r,function(t){t&&e.itemsData.getDataSet().update(t)})}else{var a=n.getAbsoluteLeft(this.dom.frame),h=t.gesture.center.pageX-a,d=this.body.util.toTime(h),l={start:i?i(d):d,content:"new item"};if("range"===this.options.type){var c=this.body.util.toTime(h+this.props.width/5);l.end=i?i(c):c}l[this.itemsData._fieldId]=n.randomUUID();var p=s.groupFromTarget(t);p&&(l.group=p.groupId),this.options.onAdd(l,function(t){t&&e.itemsData.getDataSet().add(t)})}}},s.prototype._onMultiSelectItem=function(t){if(this.options.selectable){var e,i=s.itemFromTarget(t);if(i){e=this.getSelection();var o=t.gesture.touches[0]&&t.gesture.touches[0].shiftKey||!1;if(o){e.push(i.id);var n=s._getItemRange(this.itemsData.get(e,this.itemOptions));e=[];for(var r in this.items)if(this.items.hasOwnProperty(r)){var a=this.items[r],h=a.data.start,d=void 0!==a.data.end?a.data.end:h;h>=n.min&&d<=n.max&&e.push(a.id)}}else{var l=e.indexOf(i.id);-1==l?e.push(i.id):e.splice(l,1)}this.setSelection(e),this.body.emitter.emit("select",{items:this.getSelection()})}}},s._getItemRange=function(t){var e=null,i=null;return t.forEach(function(t){(null==i||t.starte)&&(e=t.end):(null==e||t.start>e)&&(e=t.start)}),{min:i,max:e}},s.itemFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-item"))return e["timeline-item"];e=e.parentNode}return null},s.groupFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-group"))return e["timeline-group"];e=e.parentNode}return null},s.itemSetFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-itemset"))return e["timeline-itemset"];e=e.parentNode}return null},t.exports=s},function(t,e,i){function s(t,e,i){this.groupId=t,this.subgroups={},this.subgroupIndex=0,this.subgroupOrderer=e&&e.subgroupOrder,this.itemSet=i,this.dom={},this.props={label:{width:0,height:0}},this.className=null,this.items={},this.visibleItems=[],this.orderedItems={byStart:[],byEnd:[]},this.checkRangedItems=!1;var s=this;this.itemSet.body.emitter.on("checkRangedItems",function(){s.checkRangedItems=!0}),this._create(),this.setData(e)}{var o=i(1),n=i(28);i(29)}s.prototype._create=function(){var t=document.createElement("div");t.className="vlabel",this.dom.label=t;var e=document.createElement("div");e.className="inner",t.appendChild(e),this.dom.inner=e;var i=document.createElement("div");i.className="group",i["timeline-group"]=this,this.dom.foreground=i,this.dom.background=document.createElement("div"),this.dom.background.className="group",this.dom.axis=document.createElement("div"),this.dom.axis.className="group",this.dom.marker=document.createElement("div"),this.dom.marker.style.visibility="hidden",this.dom.marker.innerHTML="?",this.dom.background.appendChild(this.dom.marker)},s.prototype.setData=function(t){var e=t&&t.content;e instanceof Element?this.dom.inner.appendChild(e):this.dom.inner.innerHTML=void 0!==e&&null!==e?e:this.groupId||"",this.dom.label.title=t&&t.title||"",this.dom.inner.firstChild?o.removeClassName(this.dom.inner,"hidden"):o.addClassName(this.dom.inner,"hidden");var i=t&&t.className||null;i!=this.className&&(this.className&&(o.removeClassName(this.dom.label,this.className),o.removeClassName(this.dom.foreground,this.className),o.removeClassName(this.dom.background,this.className),o.removeClassName(this.dom.axis,this.className)),o.addClassName(this.dom.label,i),o.addClassName(this.dom.foreground,i),o.addClassName(this.dom.background,i),o.addClassName(this.dom.axis,i),this.className=i),this.style&&(o.removeCssText(this.dom.label,this.style),this.style=null),t&&t.style&&(o.addCssText(this.dom.label,t.style),this.style=t.style)},s.prototype.getLabelWidth=function(){return this.props.label.width},s.prototype.redraw=function(t,e,i){var s=!1;this.visibleItems=this._updateVisibleItems(this.orderedItems,this.visibleItems,t);var r=this.dom.marker.clientHeight;r!=this.lastMarkerHeight&&(this.lastMarkerHeight=r,o.forEach(this.items,function(t){t.dirty=!0,t.displayed&&t.redraw()}),i=!0),this.itemSet.options.stack?n.stack(this.visibleItems,e,i):n.nostack(this.visibleItems,e,this.subgroups);var a=this._calculateHeight(e),h=this.dom.foreground;this.top=h.offsetTop,this.left=h.offsetLeft,this.width=h.offsetWidth,s=o.updateProperty(this,"height",a)||s,s=o.updateProperty(this.props.label,"width",this.dom.inner.clientWidth)||s,s=o.updateProperty(this.props.label,"height",this.dom.inner.clientHeight)||s,this.dom.background.style.height=a+"px",this.dom.foreground.style.height=a+"px",this.dom.label.style.height=a+"px";for(var d=0,l=this.visibleItems.length;l>d;d++){var c=this.visibleItems[d];c.repositionY(e)}return s},s.prototype._calculateHeight=function(t){var e,i=this.visibleItems;this.resetSubgroups();var s=this;if(i.length){var n=i[0].top,r=i[0].top+i[0].height;if(o.forEach(i,function(t){n=Math.min(n,t.top),r=Math.max(r,t.top+t.height),void 0!==t.data.subgroup&&(s.subgroups[t.data.subgroup].height=Math.max(s.subgroups[t.data.subgroup].height,t.height),s.subgroups[t.data.subgroup].visible=!0)}),n>t.axis){var a=n-t.axis;r-=a,o.forEach(i,function(t){t.top-=a})}e=r+t.item.vertical/2}else e=t.axis+t.item.vertical;return e=Math.max(e,this.props.label.height)},s.prototype.show=function(){this.dom.label.parentNode||this.itemSet.dom.labelSet.appendChild(this.dom.label),this.dom.foreground.parentNode||this.itemSet.dom.foreground.appendChild(this.dom.foreground),this.dom.background.parentNode||this.itemSet.dom.background.appendChild(this.dom.background),this.dom.axis.parentNode||this.itemSet.dom.axis.appendChild(this.dom.axis)},s.prototype.hide=function(){var t=this.dom.label;t.parentNode&&t.parentNode.removeChild(t);var e=this.dom.foreground;e.parentNode&&e.parentNode.removeChild(e);var i=this.dom.background;i.parentNode&&i.parentNode.removeChild(i);var s=this.dom.axis;s.parentNode&&s.parentNode.removeChild(s)},s.prototype.add=function(t){if(this.items[t.id]=t,t.setParent(this),void 0!==t.data.subgroup&&(void 0===this.subgroups[t.data.subgroup]&&(this.subgroups[t.data.subgroup]={height:0,visible:!1,index:this.subgroupIndex,items:[]},this.subgroupIndex++),this.subgroups[t.data.subgroup].items.push(t)),this.orderSubgroups(),-1==this.visibleItems.indexOf(t)){var e=this.itemSet.body.range;this._checkIfVisible(t,this.visibleItems,e)}},s.prototype.orderSubgroups=function(){if(void 0!==this.subgroupOrderer){var t=[];if("string"==typeof this.subgroupOrderer){for(var e in this.subgroups)t.push({subgroup:e,sortField:this.subgroups[e].items[0].data[this.subgroupOrderer]});t.sort(function(t,e){return t.sortField-e.sortField})}else if("function"==typeof this.subgroupOrderer){for(var e in this.subgroups)t.push(this.subgroups[e].items[0].data);t.sort(this.subgroupOrderer)}if(t.length>0)for(var i=0;it?-1:l>=t?0:1};if(e.length>0)for(n=0;nl}),1==this.checkRangedItems)for(this.checkRangedItems=!1,n=0;nl})}for(n=0;n=0&&(n=e[r],!o(n));r--)void 0===s[n.id]&&(s[n.id]=!0,i.push(n));for(r=t+1;ro;o++)t[o].top=null;for(o=0,n=t.length;n>o;o++){var r=t[o];if(r.stack&&null===r.top){r.top=i.axis;do{for(var a=null,h=0,d=t.length;d>h;h++){var l=t[h];if(null!==l.top&&l!==r&&l.stack&&e.collision(r,l,i.item)){a=l;break}}null!=a&&(r.top=a.top+a.height+i.item.vertical)}while(a)}}},e.nostack=function(t,e,i){var s,o,n;for(s=0,o=t.length;o>s;s++)if(void 0!==t[s].data.subgroup){n=e.axis;for(var r in i)i.hasOwnProperty(r)&&1==i[r].visible&&i[r].indexe.left&&t.top-s.vertical+ie.top}},function(t,e,i){function s(t,e,i){if(this.props={content:{width:0}},this.overflow=!1,t){if(void 0==t.start)throw new Error('Property "start" missing in item '+t.id);if(void 0==t.end)throw new Error('Property "end" missing in item '+t.id)}n.call(this,t,e,i)}var o=i(19),n=i(30);s.prototype=new n(null,null,null),s.prototype.baseClassName="item range",s.prototype.isVisible=function(t){return this.data.startt.start},s.prototype.redraw=function(){var t=this.dom;if(t||(this.dom={},t=this.dom,t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content),t.box["timeline-item"]=this,this.dirty=!0),!this.parent)throw new Error("Cannot redraw item: no parent attached");if(!t.box.parentNode){var e=this.parent.dom.foreground;if(!e)throw new Error("Cannot redraw item: parent has no foreground container element");e.appendChild(t.box)}if(this.displayed=!0,this.dirty){this._updateContents(this.dom.content),this._updateTitle(this.dom.box),this._updateDataAttributes(this.dom.box),this._updateStyle(this.dom.box);var i=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");t.box.className=this.baseClassName+i,this.overflow="hidden"!==window.getComputedStyle(t.content).overflow,this.dom.content.style.maxWidth="none",this.props.content.width=this.dom.content.offsetWidth,this.height=this.dom.box.offsetHeight,this.dom.content.style.maxWidth="",this.dirty=!1}this._repaintDeleteButton(t.box),this._repaintDragLeft(),this._repaintDragRight()},s.prototype.show=function(){this.displayed||this.redraw()},s.prototype.hide=function(){if(this.displayed){var t=this.dom.box;t.parentNode&&t.parentNode.removeChild(t),this.top=null,this.left=null,this.displayed=!1}},s.prototype.repositionX=function(){var t,e,i=this.parent.width,s=this.conversion.toScreen(this.data.start),o=this.conversion.toScreen(this.data.end);-i>s&&(s=-i),o>2*i&&(o=2*i);var n=Math.max(o-s,1);switch(this.overflow?(this.left=s,this.width=n+this.props.content.width,e=this.props.content.width):(this.left=s,this.width=n,e=Math.min(o-s-2*this.options.padding,this.props.content.width)),this.dom.box.style.left=this.left+"px",this.dom.box.style.width=n+"px",this.options.align){case"left":this.dom.content.style.left="0";break;case"right":this.dom.content.style.left=Math.max(n-e-2*this.options.padding,0)+"px";break;case"center":this.dom.content.style.left=Math.max((n-e-2*this.options.padding)/2,0)+"px";break;default:t=this.overflow?o>0?Math.max(-s,0):-e:0>s?Math.min(-s,o-s-e-2*this.options.padding):0,this.dom.content.style.left=t+"px"}},s.prototype.repositionY=function(){var t=this.options.orientation,e=this.dom.box;e.style.top="top"==t?this.top+"px":this.parent.height-this.top-this.height+"px"},s.prototype._repaintDragLeft=function(){if(this.selected&&this.options.editable.updateTime&&!this.dom.dragLeft){var t=document.createElement("div");t.className="drag-left",t.dragLeftItem=this,o(t,{preventDefault:!0}).on("drag",function(){}),this.dom.box.appendChild(t),this.dom.dragLeft=t}else!this.selected&&this.dom.dragLeft&&(this.dom.dragLeft.parentNode&&this.dom.dragLeft.parentNode.removeChild(this.dom.dragLeft),this.dom.dragLeft=null)},s.prototype._repaintDragRight=function(){if(this.selected&&this.options.editable.updateTime&&!this.dom.dragRight){var t=document.createElement("div");t.className="drag-right",t.dragRightItem=this,o(t,{preventDefault:!0}).on("drag",function(){}),this.dom.box.appendChild(t),this.dom.dragRight=t}else!this.selected&&this.dom.dragRight&&(this.dom.dragRight.parentNode&&this.dom.dragRight.parentNode.removeChild(this.dom.dragRight),this.dom.dragRight=null)},t.exports=s},function(t,e,i){function s(t,e,i){this.id=null,this.parent=null,this.data=t,this.dom=null,this.conversion=e||{},this.options=i||{},this.selected=!1,this.displayed=!1,this.dirty=!0,this.top=null,this.left=null,this.width=null,this.height=null}var o=i(19),n=i(1);s.prototype.stack=!0,s.prototype.select=function(){this.selected=!0,this.dirty=!0,this.displayed&&this.redraw()},s.prototype.unselect=function(){this.selected=!1,this.dirty=!0,this.displayed&&this.redraw()},s.prototype.setData=function(t){this.data=t,this.dirty=!0,this.displayed&&this.redraw()},s.prototype.setParent=function(t){this.displayed?(this.hide(),this.parent=t,this.parent&&this.show()):this.parent=t},s.prototype.isVisible=function(){return!1},s.prototype.show=function(){return!1},s.prototype.hide=function(){return!1},s.prototype.redraw=function(){},s.prototype.repositionX=function(){},s.prototype.repositionY=function(){},s.prototype._repaintDeleteButton=function(t){if(this.selected&&this.options.editable.remove&&!this.dom.deleteButton){var e=this,i=document.createElement("div");i.className="delete",i.title="Delete this item",o(i,{preventDefault:!0}).on("tap",function(t){e.parent.removeFromDataSet(e),t.stopPropagation()}),t.appendChild(i),this.dom.deleteButton=i}else!this.selected&&this.dom.deleteButton&&(this.dom.deleteButton.parentNode&&this.dom.deleteButton.parentNode.removeChild(this.dom.deleteButton),this.dom.deleteButton=null)},s.prototype._updateContents=function(t){var e;if(this.options.template){var i=this.parent.itemSet.itemsData.get(this.id);e=this.options.template(i)}else e=this.data.content;if(e!==this.content){if(e instanceof Element)t.innerHTML="",t.appendChild(e);else if(void 0!=e)t.innerHTML=e;else if("background"!=this.data.type||void 0!==this.data.content)throw new Error('Property "content" missing in item '+this.id);this.content=e}},s.prototype._updateTitle=function(t){null!=this.data.title?t.title=this.data.title||"":t.removeAttribute("title")},s.prototype._updateDataAttributes=function(t){if(this.options.dataAttributes&&this.options.dataAttributes.length>0){var e=[];if(Array.isArray(this.options.dataAttributes))e=this.options.dataAttributes;else{if("all"!=this.options.dataAttributes)return;e=Object.keys(this.data)}for(var i=0;is;s++){var n=this.visibleItems[s];n.repositionY(e)}return i},s.prototype.show=function(){this.dom.background.parentNode||this.itemSet.dom.background.appendChild(this.dom.background)},t.exports=s},function(t,e,i){function s(t,e,i){if(this.props={dot:{width:0,height:0},line:{width:0,height:0}},t&&void 0==t.start)throw new Error('Property "start" missing in item '+t);o.call(this,t,e,i)}{var o=i(30);i(1)}s.prototype=new o(null,null,null),s.prototype.isVisible=function(t){var e=(t.end-t.start)/4;return this.data.start>t.start-e&&this.data.startt.start-e&&this.data.startt.start},s.prototype.redraw=function(){var t=this.dom;if(t||(this.dom={},t=this.dom,t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content),this.dirty=!0),!this.parent)throw new Error("Cannot redraw item: no parent attached");if(!t.box.parentNode){var e=this.parent.dom.background;if(!e)throw new Error("Cannot redraw item: parent has no background container element");e.appendChild(t.box)}if(this.displayed=!0,this.dirty){this._updateContents(this.dom.content),this._updateTitle(this.dom.content),this._updateDataAttributes(this.dom.content),this._updateStyle(this.dom.box);var i=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");t.box.className=this.baseClassName+i,this.overflow="hidden"!==window.getComputedStyle(t.content).overflow,this.props.content.width=this.dom.content.offsetWidth,this.height=0,this.dirty=!1}},s.prototype.show=r.prototype.show,s.prototype.hide=r.prototype.hide,s.prototype.repositionX=r.prototype.repositionX,s.prototype.repositionY=function(t){var e="top"===this.options.orientation;this.dom.content.style.top=e?"":"0",this.dom.content.style.bottom=e?"0":"";var i;if(void 0!==this.data.subgroup){var s=this.data.subgroup,o=this.parent.subgroups,r=o[s].index;if(1==e){i=this.parent.subgroups[s].height+t.item.vertical,i+=0==r?t.axis-.5*t.item.vertical:0;var a=this.parent.top;for(var h in o)o.hasOwnProperty(h)&&1==o[h].visible&&o[h].indexr&&(a+=o[h].height+t.item.vertical);i=this.parent.subgroups[s].height+t.item.vertical,this.dom.box.style.top=a+"px",this.dom.box.style.bottom=""}}else this.parent instanceof n?(i=Math.max(this.parent.height,this.parent.itemSet.body.domProps.center.height,this.parent.itemSet.body.domProps.centerContainer.height),this.dom.box.style.top=e?"0":"",this.dom.box.style.bottom=e?"":"0"):(i=this.parent.height,this.dom.box.style.top=this.parent.top+"px",this.dom.box.style.bottom="");this.dom.box.style.height=i+"px"},t.exports=s},function(t,e,i){function s(t){this.active=!1,this.dom={container:t},this.dom.overlay=document.createElement("div"),this.dom.overlay.className="overlay",this.dom.container.appendChild(this.dom.overlay),this.hammer=a(this.dom.overlay,{prevent_default:!1}),this.hammer.on("tap",this._onTapOverlay.bind(this));var e=this,i=["touch","pinch","doubletap","hold","dragstart","drag","dragend","mousewheel","DOMMouseScroll"];i.forEach(function(t){e.hammer.on(t,function(t){t.stopPropagation()})}),this.windowHammer=a(window,{prevent_default:!1}),this.windowHammer.on("tap",function(i){o(i.target,t)||e.deactivate()}),void 0!==this.keycharm&&this.keycharm.destroy(),this.keycharm=n(),this.escListener=this.deactivate.bind(this)}function o(t,e){for(;t;){if(t===e)return!0;t=t.parentNode}return!1}var n=i(36),r=i(11),a=i(19),h=i(1);r(s.prototype),s.current=null,s.prototype.destroy=function(){this.deactivate(),this.dom.overlay.parentNode.removeChild(this.dom.overlay),this.hammer=null,this.windowHammer=null},s.prototype.activate=function(){s.current&&s.current.deactivate(),s.current=this,this.active=!0,this.dom.overlay.style.display="none",h.addClassName(this.dom.container,"vis-active"),this.emit("change"),this.emit("activate"),this.keycharm.bind("esc",this.escListener)},s.prototype.deactivate=function(){this.active=!1,this.dom.overlay.style.display="",h.removeClassName(this.dom.container,"vis-active"),this.keycharm.unbind("esc",this.escListener),this.emit("change"),this.emit("deactivate")},s.prototype._onTapOverlay=function(t){this.activate(),t.stopPropagation()},t.exports=s},function(t,e){var i,s,o;!function(n,r){s=[],i=r,o="function"==typeof i?i.apply(e,s):i,!(void 0!==o&&(t.exports=o))}(this,function(){function t(t){var e,i=t&&t.preventDefault||!1,s=t&&t.container||window,o={},n={keydown:{},keyup:{}},r={};for(e=97;122>=e;e++)r[String.fromCharCode(e)]={code:65+(e-97),shift:!1};for(e=65;90>=e;e++)r[String.fromCharCode(e)]={code:e,shift:!0};for(e=0;9>=e;e++)r[""+e]={code:48+e,shift:!1};for(e=1;12>=e;e++)r["F"+e]={code:111+e,shift:!1};for(e=0;9>=e;e++)r["num"+e]={code:96+e,shift:!1};r["num*"]={code:106,shift:!1},r["num+"]={code:107,shift:!1},r["num-"]={code:109,shift:!1},r["num/"]={code:111,shift:!1},r["num."]={code:110,shift:!1},r.left={code:37,shift:!1},r.up={code:38,shift:!1},r.right={code:39,shift:!1},r.down={code:40,shift:!1},r.space={code:32,shift:!1},r.enter={code:13,shift:!1},r.shift={code:16,shift:void 0},r.esc={code:27,shift:!1},r.backspace={code:8,shift:!1},r.tab={code:9,shift:!1},r.ctrl={code:17,shift:!1},r.alt={code:18,shift:!1},r["delete"]={code:46,shift:!1},r.pageup={code:33,shift:!1},r.pagedown={code:34,shift:!1},r["="]={code:187,shift:!1},r["-"]={code:189,shift:!1},r["]"]={code:221,shift:!1},r["["]={code:219,shift:!1};var a=function(t){d(t,"keydown")},h=function(t){d(t,"keyup")},d=function(t,e){if(void 0!==n[e][t.keyCode]){for(var s=n[e][t.keyCode],o=0;oy;)y++,l=h.getCurrent(),c=h.isMajor(),u=h.getClassName(),f=m,m=this.body.util.toScreen(l),g=m-f,p&&(p.style.width=g+"px"),this.options.showMinorLabels&&this._repaintMinorText(m,h.getLabelMinor(),t,u),c&&this.options.showMajorLabels?(m>0&&(void 0==v&&(v=m),this._repaintMajorText(m,h.getLabelMajor(),t,u)),p=this._repaintMajorLine(m,t,u)):p=this._repaintMinorLine(m,t,u),h.next();if(this.options.showMajorLabels){var b=this.body.util.toTime(0),_=h.getLabelMajor(b),x=_.length*(this.props.majorCharWidth||10)+10;(void 0==v||v>x)&&this._repaintMajorText(0,_,t,u)}o.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},s.prototype._repaintMinorText=function(t,e,i,s){var o=this.dom.redundant.minorTexts.shift();if(!o){var n=document.createTextNode("");o=document.createElement("div"),o.appendChild(n),this.dom.foreground.appendChild(o)}this.dom.minorTexts.push(o),o.childNodes[0].nodeValue=e,o.style.top="top"==i?this.props.majorLabelHeight+"px":"0",o.style.left=t+"px",o.className="text minor "+s},s.prototype._repaintMajorText=function(t,e,i,s){var o=this.dom.redundant.majorTexts.shift();if(!o){var n=document.createTextNode(e);o=document.createElement("div"),o.appendChild(n),this.dom.foreground.appendChild(o)}this.dom.majorTexts.push(o),o.childNodes[0].nodeValue=e,o.className="text major "+s,o.style.top="top"==i?"0":this.props.minorLabelHeight+"px",o.style.left=t+"px"},s.prototype._repaintMinorLine=function(t,e,i){var s=this.dom.redundant.lines.shift();s||(s=document.createElement("div"),this.dom.background.appendChild(s)),this.dom.lines.push(s);var o=this.props;return s.style.top="top"==e?o.majorLabelHeight+"px":this.body.domProps.top.height+"px",s.style.height=o.minorLineHeight+"px",s.style.left=t-o.minorLineWidth/2+"px",s.className="grid vertical minor "+i,s},s.prototype._repaintMajorLine=function(t,e,i){var s=this.dom.redundant.lines.shift();s||(s=document.createElement("div"),this.dom.background.appendChild(s)),this.dom.lines.push(s);var o=this.props;return s.style.top="top"==e?"0":this.body.domProps.top.height+"px",s.style.left=t-o.majorLineWidth/2+"px",s.style.height=o.majorLineHeight+"px",s.className="grid vertical major "+i,s},s.prototype._calculateCharSize=function(){this.dom.measureCharMinor||(this.dom.measureCharMinor=document.createElement("DIV"),this.dom.measureCharMinor.className="text minor measure",this.dom.measureCharMinor.style.position="absolute",this.dom.measureCharMinor.appendChild(document.createTextNode("0")),this.dom.foreground.appendChild(this.dom.measureCharMinor)),this.props.minorCharHeight=this.dom.measureCharMinor.clientHeight,this.props.minorCharWidth=this.dom.measureCharMinor.clientWidth,this.dom.measureCharMajor||(this.dom.measureCharMajor=document.createElement("DIV"),this.dom.measureCharMajor.className="text major measure",this.dom.measureCharMajor.style.position="absolute",this.dom.measureCharMajor.appendChild(document.createTextNode("0")),this.dom.foreground.appendChild(this.dom.measureCharMajor)),this.props.majorCharHeight=this.dom.measureCharMajor.clientHeight,this.props.majorCharWidth=this.dom.measureCharMajor.clientWidth},s.prototype.snap=function(t){return this.step.snap(t)},t.exports=s},function(t,e,i){function s(t,e,i,o){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale="day",this.step=1,this.setRange(t,e,i),this.switchedDay=!1,this.switchedMonth=!1,this.switchedYear=!1,this.hiddenDates=o,void 0===o&&(this.hiddenDates=[]),this.format=s.FORMAT}var o=i(2),n=i(24),r=i(1);s.FORMAT={minorLabels:{millisecond:"SSS",second:"s",minute:"HH:mm",hour:"HH:mm",weekday:"ddd D",day:"D",month:"MMM",year:"YYYY"},majorLabels:{millisecond:"HH:mm:ss",second:"D MMMM HH:mm",minute:"ddd D MMMM",hour:"ddd D MMMM",weekday:"MMMM YYYY",day:"MMMM YYYY",month:"YYYY",year:""}},s.prototype.setFormat=function(t){var e=r.deepExtend({},s.FORMAT);this.format=r.deepExtend(e,t)},s.prototype.setRange=function(t,e,i){if(!(t instanceof Date&&e instanceof Date))throw"No legal start or end date in method setRange";this._start=void 0!=t?new Date(t.valueOf()):new Date,this._end=void 0!=e?new Date(e.valueOf()):new Date,this.autoScale&&this.setMinimumStep(i)},s.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},s.prototype.roundToMinor=function(){switch(this.scale){case"year":this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case"month":this.current.setDate(1);case"day":case"weekday":this.current.setHours(0);case"hour":this.current.setMinutes(0);case"minute":this.current.setSeconds(0);case"second":this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case"millisecond":this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case"second":this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case"minute":this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case"hour":this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case"weekday":case"day":this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case"month":this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step);break;case"year":this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step)}},s.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},s.prototype.next=function(){var t=this.current.valueOf();if(this.current.getMonth()<6)switch(this.scale){case"millisecond":this.current=new Date(this.current.valueOf()+this.step);break;case"second":this.current=new Date(this.current.valueOf()+1e3*this.step);break;case"minute":this.current=new Date(this.current.valueOf()+1e3*this.step*60);break;case"hour":this.current=new Date(this.current.valueOf()+1e3*this.step*60*60);var e=this.current.getHours();this.current.setHours(e-e%this.step);break;case"weekday":case"day":this.current.setDate(this.current.getDate()+this.step);break;case"month":this.current.setMonth(this.current.getMonth()+this.step);break;case"year":this.current.setFullYear(this.current.getFullYear()+this.step)}else switch(this.scale){case"millisecond":this.current=new Date(this.current.valueOf()+this.step);break;case"second":this.current.setSeconds(this.current.getSeconds()+this.step);break;case"minute":this.current.setMinutes(this.current.getMinutes()+this.step);break;case"hour":this.current.setHours(this.current.getHours()+this.step);break;case"weekday":case"day":this.current.setDate(this.current.getDate()+this.step);break;case"month":this.current.setMonth(this.current.getMonth()+this.step);break;case"year":this.current.setFullYear(this.current.getFullYear()+this.step)}if(1!=this.step)switch(this.scale){case"millisecond":this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},s.prototype.setAutoScale=function(t){this.autoScale=t},s.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,s=864e5,o=36e5,n=6e4,r=1e3,a=1;1e3*e>t&&(this.scale="year",this.step=1e3),500*e>t&&(this.scale="year",this.step=500),100*e>t&&(this.scale="year",this.step=100),50*e>t&&(this.scale="year",this.step=50),10*e>t&&(this.scale="year",this.step=10),5*e>t&&(this.scale="year",this.step=5),e>t&&(this.scale="year",this.step=1),3*i>t&&(this.scale="month",this.step=3),i>t&&(this.scale="month",this.step=1),5*s>t&&(this.scale="day",this.step=5),2*s>t&&(this.scale="day",this.step=2),s>t&&(this.scale="day",this.step=1),s/2>t&&(this.scale="weekday",this.step=1),4*o>t&&(this.scale="hour",this.step=4),o>t&&(this.scale="hour",this.step=1),15*n>t&&(this.scale="minute",this.step=15),10*n>t&&(this.scale="minute",this.step=10),5*n>t&&(this.scale="minute",this.step=5),n>t&&(this.scale="minute",this.step=1),15*r>t&&(this.scale="second",this.step=15),10*r>t&&(this.scale="second",this.step=10),5*r>t&&(this.scale="second",this.step=5),r>t&&(this.scale="second",this.step=1),200*a>t&&(this.scale="millisecond",this.step=200),100*a>t&&(this.scale="millisecond",this.step=100),50*a>t&&(this.scale="millisecond",this.step=50),10*a>t&&(this.scale="millisecond",this.step=10),5*a>t&&(this.scale="millisecond",this.step=5),a>t&&(this.scale="millisecond",this.step=1)}},s.prototype.snap=function(t){var e=new Date(t.valueOf());if("year"==this.scale){var i=e.getFullYear()+Math.round(e.getMonth()/12);e.setFullYear(Math.round(i/this.step)*this.step),e.setMonth(0),e.setDate(0),e.setHours(0),e.setMinutes(0),e.setSeconds(0),e.setMilliseconds(0)}else if("month"==this.scale)e.getDate()>15?(e.setDate(1),e.setMonth(e.getMonth()+1)):e.setDate(1),e.setHours(0),e.setMinutes(0),e.setSeconds(0),e.setMilliseconds(0);else if("day"==this.scale){switch(this.step){case 5:case 2:e.setHours(24*Math.round(e.getHours()/24));break;default:e.setHours(12*Math.round(e.getHours()/12))}e.setMinutes(0),e.setSeconds(0),e.setMilliseconds(0)}else if("weekday"==this.scale){switch(this.step){case 5:case 2:e.setHours(12*Math.round(e.getHours()/12));break;default:e.setHours(6*Math.round(e.getHours()/6))}e.setMinutes(0),e.setSeconds(0),e.setMilliseconds(0)}else if("hour"==this.scale){switch(this.step){case 4:e.setMinutes(60*Math.round(e.getMinutes()/60));break;default:e.setMinutes(30*Math.round(e.getMinutes()/30))}e.setSeconds(0),e.setMilliseconds(0)}else if("minute"==this.scale){switch(this.step){case 15:case 10:e.setMinutes(5*Math.round(e.getMinutes()/5)),e.setSeconds(0);break;case 5:e.setSeconds(60*Math.round(e.getSeconds()/60));break;default:e.setSeconds(30*Math.round(e.getSeconds()/30))}e.setMilliseconds(0)}else if("second"==this.scale)switch(this.step){case 15:case 10:e.setSeconds(5*Math.round(e.getSeconds()/5)),e.setMilliseconds(0);break;case 5:e.setMilliseconds(1e3*Math.round(e.getMilliseconds()/1e3));break;default:e.setMilliseconds(500*Math.round(e.getMilliseconds()/500))}else if("millisecond"==this.scale){var s=this.step>5?this.step/2:1;e.setMilliseconds(Math.round(e.getMilliseconds()/s)*s)}return e},s.prototype.isMajor=function(){if(1==this.switchedYear)switch(this.switchedYear=!1,this.scale){case"year":case"month":case"weekday":case"day":case"hour":case"minute":case"second":case"millisecond":return!0;default:return!1}else if(1==this.switchedMonth)switch(this.switchedMonth=!1,this.scale){case"weekday":case"day":case"hour":case"minute":case"second":case"millisecond":return!0;default:return!1}else if(1==this.switchedDay)switch(this.switchedDay=!1,this.scale){case"millisecond":case"second":case"minute":case"hour":return!0;default:return!1}switch(this.scale){case"millisecond":return 0==this.current.getMilliseconds();case"second":return 0==this.current.getSeconds();case"minute":return 0==this.current.getHours()&&0==this.current.getMinutes();case"hour":return 0==this.current.getHours();case"weekday":case"day":return 1==this.current.getDate();case"month":return 0==this.current.getMonth();case"year":return!1;default:return!1}},s.prototype.getLabelMinor=function(t){void 0==t&&(t=this.current);var e=this.format.minorLabels[this.scale];return e&&e.length>0?o(t).format(e):""},s.prototype.getLabelMajor=function(t){void 0==t&&(t=this.current);var e=this.format.majorLabels[this.scale];return e&&e.length>0?o(t).format(e):""},s.prototype.getClassName=function(){function t(t){return t/h%2==0?" even":" odd"}function e(t){return t.isSame(new Date,"day")?" today":t.isSame(o().add(1,"day"),"day")?" tomorrow":t.isSame(o().add(-1,"day"),"day")?" yesterday":""}function i(t){return t.isSame(new Date,"week")?" current-week":""}function s(t){return t.isSame(new Date,"month")?" current-month":""}function n(t){return t.isSame(new Date,"year")?" current-year":""}var r=o(this.current),a=r.locale?r.locale("en"):r.lang("en"),h=this.step;switch(this.scale){case"millisecond":return t(a.milliseconds()).trim();case"second":return t(a.seconds()).trim();case"minute":return t(a.minutes()).trim();case"hour":var d=a.hours();return 4==this.step&&(d=d+"-"+(d+4)),d+"h"+e(a)+t(a.hours());case"weekday":return a.format("dddd").toLowerCase()+e(a)+i(a)+t(a.date());case"day":var l=a.date(),c=a.format("MMMM").toLowerCase();return"day"+l+" "+c+s(a)+t(l-1);case"month":return a.format("MMMM").toLowerCase()+s(a)+t(a.month());case"year":var p=a.year();return"year"+p+n(a)+t(p);default:return""}},t.exports=s},function(t,e,i){function s(t,e){this.body=t,this.defaultOptions={showCurrentTime:!0,locales:a,locale:"en"},this.options=o.extend({},this.defaultOptions),this.offset=0,this._create(),this.setOptions(e)}var o=i(1),n=i(23),r=i(2),a=i(40);s.prototype=new n,s.prototype._create=function(){var t=document.createElement("div");t.className="currenttime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",this.bar=t},s.prototype.destroy=function(){this.options.showCurrentTime=!1,this.redraw(),this.body=null},s.prototype.setOptions=function(t){t&&o.selectiveExtend(["showCurrentTime","locale","locales"],this.options,t)},s.prototype.redraw=function(){if(this.options.showCurrentTime){var t=this.body.dom.backgroundVertical;this.bar.parentNode!=t&&(this.bar.parentNode&&this.bar.parentNode.removeChild(this.bar),t.appendChild(this.bar),this.start());var e=new Date((new Date).valueOf()+this.offset),i=this.body.util.toScreen(e),s=this.options.locales[this.options.locale],o=s.current+" "+s.time+": "+r(e).format("dddd, MMMM Do YYYY, H:mm:ss");o=o.charAt(0).toUpperCase()+o.substring(1),this.bar.style.left=i+"px",this.bar.title=o}else this.bar.parentNode&&this.bar.parentNode.removeChild(this.bar),this.stop();return!1},s.prototype.start=function(){function t(){e.stop();var i=e.body.range.conversion(e.body.domProps.center.width).scale,s=1/i/10;30>s&&(s=30),s>1e3&&(s=1e3),e.redraw(),e.currentTimeTimer=setTimeout(t,s)}var e=this;t()},s.prototype.stop=function(){void 0!==this.currentTimeTimer&&(clearTimeout(this.currentTimeTimer),delete this.currentTimeTimer)},s.prototype.setCurrentTime=function(t){var e=o.convert(t,"Date").valueOf(),i=(new Date).valueOf();this.offset=e-i,this.redraw()},s.prototype.getCurrentTime=function(){return new Date((new Date).valueOf()+this.offset)},t.exports=s},function(t,e){e.en={current:"current",time:"time"},e.en_EN=e.en,e.en_US=e.en,e.nl={custom:"aangepaste",time:"tijd"},e.nl_NL=e.nl,e.nl_BE=e.nl},function(t,e,i){function s(t,e){this.body=t,this.defaultOptions={showCustomTime:!1,locales:h,locale:"en"},this.options=n.extend({},this.defaultOptions),this.customTime=new Date,this.eventParams={},this._create(),this.setOptions(e)}var o=i(19),n=i(1),r=i(23),a=i(2),h=i(40);s.prototype=new r,s.prototype.setOptions=function(t){t&&n.selectiveExtend(["showCustomTime","locale","locales"],this.options,t)},s.prototype._create=function(){var t=document.createElement("div");t.className="customtime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",this.bar=t;var e=document.createElement("div");e.style.position="relative",e.style.top="0px",e.style.left="-10px",e.style.height="100%",e.style.width="20px",t.appendChild(e),this.hammer=o(t,{prevent_default:!0}),this.hammer.on("dragstart",this._onDragStart.bind(this)),this.hammer.on("drag",this._onDrag.bind(this)),this.hammer.on("dragend",this._onDragEnd.bind(this))},s.prototype.destroy=function(){this.options.showCustomTime=!1,this.redraw(),this.hammer.enable(!1),this.hammer=null,this.body=null},s.prototype.redraw=function(){if(this.options.showCustomTime){var t=this.body.dom.backgroundVertical;this.bar.parentNode!=t&&(this.bar.parentNode&&this.bar.parentNode.removeChild(this.bar),t.appendChild(this.bar));var e=this.body.util.toScreen(this.customTime),i=this.options.locales[this.options.locale],s=i.time+": "+a(this.customTime).format("dddd, MMMM Do YYYY, H:mm:ss");s=s.charAt(0).toUpperCase()+s.substring(1),this.bar.style.left=e+"px",this.bar.title=s}else this.bar.parentNode&&this.bar.parentNode.removeChild(this.bar);return!1},s.prototype.setCustomTime=function(t){this.customTime=n.convert(t,"Date"),this.redraw()},s.prototype.getCustomTime=function(){return new Date(this.customTime.valueOf())},s.prototype._onDragStart=function(t){this.eventParams.dragging=!0,this.eventParams.customTime=this.customTime,t.stopPropagation(),t.preventDefault()},s.prototype._onDrag=function(t){if(this.eventParams.dragging){var e=t.gesture.deltaX,i=this.body.util.toScreen(this.eventParams.customTime)+e,s=this.body.util.toTime(i);this.setCustomTime(s),this.body.emitter.emit("timechange",{time:new Date(this.customTime.valueOf())}),t.stopPropagation(),t.preventDefault()}},s.prototype._onDragEnd=function(t){this.eventParams.dragging&&(this.body.emitter.emit("timechanged",{time:new Date(this.customTime.valueOf())}),t.stopPropagation(),t.preventDefault())},t.exports=s},function(t,e,i){function s(t,e,i,s){if(!(Array.isArray(i)||i instanceof n)&&i instanceof Object){var r=s;s=i,i=r}var h=this;this.defaultOptions={start:null,end:null,autoResize:!0,orientation:"bottom",width:null,height:null,maxHeight:null,minHeight:null},this.options=o.deepExtend({},this.defaultOptions),this._create(t),this.components=[],this.body={dom:this.dom,domProps:this.props,emitter:{on:this.on.bind(this),off:this.off.bind(this),emit:this.emit.bind(this)},hiddenDates:[],util:{snap:null,toScreen:h._toScreen.bind(h),toGlobalScreen:h._toGlobalScreen.bind(h),toTime:h._toTime.bind(h),toGlobalTime:h._toGlobalTime.bind(h)}},this.range=new a(this.body),this.components.push(this.range),this.body.range=this.range,this.timeAxis=new d(this.body),this.components.push(this.timeAxis),this.body.util.snap=this.timeAxis.snap.bind(this.timeAxis),this.currentTime=new l(this.body),this.components.push(this.currentTime),this.customTime=new c(this.body),this.components.push(this.customTime),this.linegraph=new p(this.body),this.components.push(this.linegraph),this.itemsData=null,this.groupsData=null,s&&this.setOptions(s),i&&this.setGroups(i),e?this.setItems(e):this.redraw()}var o=(i(11),i(19),i(1)),n=i(7),r=i(9),a=i(21),h=i(25),d=i(37),l=i(39),c=i(41),p=i(43);s.prototype=new h,s.prototype.setItems=function(t){var e,i=null==this.itemsData;if(e=t?t instanceof n||t instanceof r?t:new n(t,{type:{start:"Date",end:"Date"}}):null,this.itemsData=e,this.linegraph&&this.linegraph.setItems(e),i)if(void 0!=this.options.start||void 0!=this.options.end){var s=void 0!=this.options.start?this.options.start:null,o=void 0!=this.options.end?this.options.end:null;this.setWindow(s,o,{animate:!1})}else this.fit({animate:!1})},s.prototype.setGroups=function(t){var e;e=t?t instanceof n||t instanceof r?t:new n(t):null,this.groupsData=e,this.linegraph.setGroups(e)},s.prototype.getLegend=function(t,e,i){return void 0===e&&(e=15),void 0===i&&(i=15),void 0!==this.linegraph.groups[t]?this.linegraph.groups[t].getLegend(e,i):"cannot find group:"+t},s.prototype.isGroupVisible=function(t){return void 0!==this.linegraph.groups[t]?this.linegraph.groups[t].visible&&(void 0===this.linegraph.options.groups.visibility[t]||1==this.linegraph.options.groups.visibility[t]):!1},s.prototype.getItemRange=function(){var t=null,e=null;for(var i in this.linegraph.groups)if(this.linegraph.groups.hasOwnProperty(i)&&1==this.linegraph.groups[i].visible)for(var s=0;sr?r:t,e=null==e?r:r>e?r:e}return{min:null!=t?new Date(t):null,max:null!=e?new Date(e):null}},t.exports=s},function(t,e,i){function s(t,e){this.id=o.randomUUID(),this.body=t,this.defaultOptions={yAxisOrientation:"left",defaultGroup:"default",sort:!0,sampling:!0,graphHeight:"400px",shaded:{enabled:!1,orientation:"bottom"},style:"line",barChart:{width:50,handleOverlap:"overlap",align:"center"},catmullRom:{enabled:!0,parametrization:"centripetal",alpha:.5},drawPoints:{enabled:!0,size:6,style:"square"},dataAxis:{showMinorLabels:!0,showMajorLabels:!0,icons:!1,width:"40px",visible:!0,alignZeros:!0,customRange:{left:{min:void 0,max:void 0},right:{min:void 0,max:void 0}}},legend:{enabled:!1,icons:!0,left:{visible:!0,position:"top-left"},right:{visible:!0,position:"top-right"}},groups:{visibility:{}}},this.options=o.extend({},this.defaultOptions),this.dom={},this.props={},this.hammer=null,this.groups={},this.abortedGraphUpdate=!1,this.updateSVGheight=!1,this.updateSVGheightOnResize=!1;var i=this;this.itemsData=null,this.groupsData=null,this.itemListeners={add:function(t,e){i._onAdd(e.items)},update:function(t,e){i._onUpdate(e.items)},remove:function(t,e){i._onRemove(e.items)}},this.groupListeners={add:function(t,e){i._onAddGroups(e.items)},update:function(t,e){i._onUpdateGroups(e.items)},remove:function(t,e){i._onRemoveGroups(e.items)}},this.items={},this.selection=[],this.lastStart=this.body.range.start,this.touchParams={},this.svgElements={},this.setOptions(e),this.groupsUsingDefaultStyles=[0],this.COUNTER=0,this.body.emitter.on("rangechanged",function(){i.lastStart=i.body.range.start,i.svg.style.left=o.option.asSize(-i.props.width),i.redraw.call(i,!0)}),this._create(),this.framework={svg:this.svg,svgElements:this.svgElements,options:this.options,groups:this.groups},this.body.emitter.emit("change")}var o=i(1),n=i(6),r=i(7),a=i(9),h=i(23),d=i(44),l=i(46),c=i(50),p=i(49),u="__ungrouped__";s.prototype=new h,s.prototype._create=function(){var t=document.createElement("div");t.className="LineGraph",this.dom.frame=t,this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.style.position="relative",this.svg.style.height=(""+this.options.graphHeight).replace("px","")+"px",this.svg.style.display="block",t.appendChild(this.svg),this.options.dataAxis.orientation="left",this.yAxisLeft=new d(this.body,this.options.dataAxis,this.svg,this.options.groups),this.options.dataAxis.orientation="right",this.yAxisRight=new d(this.body,this.options.dataAxis,this.svg,this.options.groups),delete this.options.dataAxis.orientation,this.legendLeft=new c(this.body,this.options.legend,"left",this.options.groups),this.legendRight=new c(this.body,this.options.legend,"right",this.options.groups),this.show()},s.prototype.setOptions=function(t){if(t){var e=["sampling","defaultGroup","height","graphHeight","yAxisOrientation","style","barChart","dataAxis","sort","groups"];void 0===t.graphHeight&&void 0!==t.height&&void 0!==this.body.domProps.centerContainer.height?(this.updateSVGheight=!0,this.updateSVGheightOnResize=!0):void 0!==this.body.domProps.centerContainer.height&&void 0!==t.graphHeight&&parseInt((t.graphHeight+"").replace("px",""))0){var d=this.body.util.toGlobalTime(-this.body.domProps.root.width),l=this.body.util.toGlobalTime(2*this.body.domProps.root.width),c={};for(this._getRelevantData(a,c,d,l),this._applySampling(a,c),e=0;eu&&console.log("WARNING: there may be an infinite loop in the _updateGraph emitter cycle."),this.COUNTER=0,this.abortedGraphUpdate=!1,e=0;e0)for(r=0;rs){d.push(h);break}d.push(h)}}else for(a=0;ai&&h.x0)for(var s=0;s0){var n=1,r=o.length,a=this.body.util.toGlobalScreen(o[o.length-1].x)-this.body.util.toGlobalScreen(o[0].x),h=r/a;n=Math.min(Math.ceil(.2*r),Math.max(1,Math.round(h)));for(var d=[],l=0;r>l;l+=n)d.push(o[l]);e[t[s]]=d}}},s.prototype._getYRanges=function(t,e,i){var s,o,n,r,a=[],h=[];if(t.length>0){for(n=0;n0&&(o=this.groups[t[n]],"stack"==r.barChart.handleOverlap&&"bar"==r.style?"left"==r.yAxisOrientation?a=a.concat(o.getYRange(s)):h=h.concat(o.getYRange(s)):i[t[n]]=o.getYRange(s,t[n]));p.getStackedBarYRange(a,i,t,"__barchartLeft","left"),p.getStackedBarYRange(h,i,t,"__barchartRight","right")}},s.prototype._updateYAxis=function(t,e){var i,s,o=!1,n=!1,r=!1,a=1e9,h=1e9,d=-1e9,l=-1e9;if(t.length>0){for(var c=0;ci?i:a,d=s>d?s:d):(r=!0,h=h>i?i:h,l=s>l?s:l));1==n&&this.yAxisLeft.setRange(a,d),1==r&&this.yAxisRight.setRange(h,l)}return o=this._toggleAxisVisiblity(n,this.yAxisLeft)||o,o=this._toggleAxisVisiblity(r,this.yAxisRight)||o,1==r&&1==n?(this.yAxisLeft.drawIcons=!0,this.yAxisRight.drawIcons=!0):(this.yAxisLeft.drawIcons=!1,this.yAxisRight.drawIcons=!1),this.yAxisRight.master=!n,0==this.yAxisRight.master?(this.yAxisLeft.lineOffset=1==r?this.yAxisRight.width:0,o=this.yAxisLeft.redraw()||o,this.yAxisRight.stepPixelsForced=this.yAxisLeft.stepPixels,this.yAxisRight.zeroCrossing=this.yAxisLeft.zeroCrossing,o=this.yAxisRight.redraw()||o):o=this.yAxisRight.redraw()||o,-1!=t.indexOf("__barchartLeft")&&t.splice(t.indexOf("__barchartLeft"),1),-1!=t.indexOf("__barchartRight")&&t.splice(t.indexOf("__barchartRight"),1),o},s.prototype._toggleAxisVisiblity=function(t,e){var i=!1;return 0==t?e.dom.frame.parentNode&&0==e.hidden&&(e.hide(),i=!0):e.dom.frame.parentNode||1!=e.hidden||(e.show(),i=!0),i},s.prototype._convertXcoordinates=function(t){for(var e,i,s=[],o=this.body.util.toScreen,n=0;n0&&(t=0),this.range.start=t,this.range.end=e},s.prototype.redraw=function(){var t=!1,e=0;this.dom.lineContainer.style.top=this.body.domProps.scrollTop+"px";for(var i in this.groups)this.groups.hasOwnProperty(i)&&(1!=this.groups[i].visible||void 0!==this.linegraphOptions.visibility[i]&&1!=this.linegraphOptions.visibility[i]||e++);if(0==this.amountOfGroups||0==e)this.hide();else{this.show(),this.height=Number(this.linegraphSVG.style.height.replace("px","")),this.dom.lineContainer.style.height=this.height+"px",this.width=1==this.options.visible?Number((""+this.options.width).replace("px","")):0;var s=this.props,o=this.dom.frame;o.className="dataaxis",this._calculateCharSize();var n=this.options.orientation,r=this.options.showMinorLabels,a=this.options.showMajorLabels;s.minorLabelHeight=r?s.minorCharHeight:0,s.majorLabelHeight=a?s.majorCharHeight:0,s.minorLineWidth=this.body.dom.backgroundHorizontal.offsetWidth-this.lineOffset-this.width+2*this.options.minorLinesOffset,s.minorLineHeight=1,s.majorLineWidth=this.body.dom.backgroundHorizontal.offsetWidth-this.lineOffset-this.width+2*this.options.majorLinesOffset,s.majorLineHeight=1,"left"==n?(o.style.top="0",o.style.left="0",o.style.bottom="",o.style.width=this.width+"px",o.style.height=this.height+"px",this.props.width=this.body.domProps.left.width,this.props.height=this.body.domProps.left.height):(o.style.top="",o.style.bottom="0",o.style.left="0",o.style.width=this.width+"px",o.style.height=this.height+"px",this.props.width=this.body.domProps.right.width,this.props.height=this.body.domProps.right.height),t=this._redrawLabels(),t=this._isResized()||t,1==this.options.icons?this._redrawGroupIcons():this._cleanupIcons(),this._redrawTitle(n)}return t},s.prototype._redrawLabels=function(){var t=!1;n.prepareElements(this.DOMelements.lines),n.prepareElements(this.DOMelements.labels);var e=this.options.orientation,i=this.master?this.props.majorCharHeight||10:this.stepPixelsForced,s=new a(this.range.start,this.range.end,i,this.dom.frame.offsetHeight,this.options.customRange[this.options.orientation],0==this.master&&this.options.alignZeros);this.step=s;var o=(this.dom.frame.offsetHeight-s.deadSpace*(this.dom.frame.offsetHeight/s.marginRange))/((s.marginRange-s.deadSpace)/s.step);this.stepPixels=o;var r=this.height/o,h=0;if(0==this.master){o=this.stepPixelsForced,h=Math.round(this.dom.frame.offsetHeight/o-r);for(var d=0;.5*h>d;d++)s.previous();if(r=this.height/o,-1!=this.zeroCrossing&&1==this.options.alignZeros){var l=s.marginEnd/s.step-this.zeroCrossing;if(l>0)for(var d=0;l>d;d++)s.next();else if(0>l)for(var d=0;-l>d;d++)s.previous()}}else r+=.25;this.valueAtZero=s.marginEnd;var c,p=0,u=1;void 0!==this.options.format[e]&&(c=this.options.format[e].decimals),this.maxLabelSize=0;for(var m=0;u=0&&this._redrawLabel(m-2,s.getCurrent(c),e,"yAxis major",this.props.majorCharHeight),this._redrawLine(m,e,"grid horizontal major",this.options.majorLinesOffset,this.props.majorLineWidth)):this._redrawLine(m,e,"grid horizontal minor",this.options.minorLinesOffset,this.props.minorLineWidth),1==this.master&&0==s.current&&(this.zeroCrossing=u),u++}this.conversionFactor=0==this.master?m/(this.valueAtZero-s.current):this.dom.frame.offsetHeight/s.marginRange;var g=0;void 0!==this.options.title[e]&&void 0!==this.options.title[e].text&&(g=this.props.titleCharHeight);var v=1==this.options.icons?Math.max(this.options.iconWidth,g)+this.options.labelOffsetX+15:g+this.options.labelOffsetX+15;return this.maxLabelSize>this.width-v&&1==this.options.visible?(this.width=this.maxLabelSize+v,this.options.width=this.width+"px",n.cleanupElements(this.DOMelements.lines),n.cleanupElements(this.DOMelements.labels),this.redraw(),t=!0):this.maxLabelSizethis.minWidth?(this.width=Math.max(this.minWidth,this.maxLabelSize+v),this.options.width=this.width+"px",n.cleanupElements(this.DOMelements.lines),n.cleanupElements(this.DOMelements.labels),this.redraw(),t=!0):(n.cleanupElements(this.DOMelements.lines),n.cleanupElements(this.DOMelements.labels),t=!1),t},s.prototype.convertValue=function(t){var e=this.valueAtZero-t,i=e*this.conversionFactor;return i},s.prototype._redrawLabel=function(t,e,i,s,o){var r=n.getDOMElement("div",this.DOMelements.labels,this.dom.frame);r.className=s,r.innerHTML=e,"left"==i?(r.style.left="-"+this.options.labelOffsetX+"px",r.style.textAlign="right"):(r.style.right="-"+this.options.labelOffsetX+"px",r.style.textAlign="left"),r.style.top=t-.5*o+this.options.labelOffsetY+"px",e+="";var a=Math.max(this.props.majorCharWidth,this.props.minorCharWidth);this.maxLabelSizen&&(h=n);for(var d=!1,l=h;Math.abs(l)<=Math.abs(n);l++){a=Math.pow(10,l);for(var c=0;c=o){d=!0,r=c;break}}if(1==d)break}this.stepIndex=r,this.scale=a,this.step=a*this.minorSteps[r]},e.prototype.setFirst=function(t){void 0===t&&(t={});var e=void 0===t.min?this._start-2*this.scale*this.minorSteps[this.stepIndex]:t.min,i=void 0===t.max?this._end+this.scale*this.minorSteps[this.stepIndex]:t.max;this.marginEnd=void 0===t.max?this.roundToMinor(i):t.max,this.marginStart=void 0===t.min?this.roundToMinor(e):t.min,1==this.alignZeros&&(this.marginEnd-this.marginStart)%this.step!=0&&(this.marginEnd+=this.marginEnd%this.step),this.deadSpace=this.roundToMinor(i)-i+this.roundToMinor(e)-e,this.marginRange=this.marginEnd-this.marginStart,this.current=this.marginEnd},e.prototype.roundToMinor=function(t){var e=t-t%(this.scale*this.minorSteps[this.stepIndex]);return t%(this.scale*this.minorSteps[this.stepIndex])>.5*this.scale*this.minorSteps[this.stepIndex]?e+this.scale*this.minorSteps[this.stepIndex]:e},e.prototype.hasNext=function(){return this.current>=this.marginStart},e.prototype.next=function(){var t=this.current;this.current-=this.step,this.current==t&&(this.current=this._end)},e.prototype.previous=function(){this.current+=this.step,this.marginEnd+=this.step,this.marginRange=this.marginEnd-this.marginStart},e.prototype.getCurrent=function(t){var e=Math.abs(this.current)0;s--){if("0"!=i[s]){if("."==i[s]||","==i[s]){i=i.slice(0,s);break}break}i=i.slice(0,s)}}else{var o="",n=i.indexOf("e");if(-1!=n&&(o=i.slice(n),i=i.slice(0,n)),n=Math.max(i.indexOf(","),i.indexOf(".")),-1===n?(0!==t&&(i+="."),n=i.length+t):0!==t&&(n+=t+1),n>i.length)for(var r=n-i.length;r>0;r--)i+="0";else i=i.slice(0,n);i+=o}return i},e.prototype.snap=function(){},e.prototype.isMajor=function(){return this.current%(this.scale*this.majorSteps[this.stepIndex])==0},t.exports=e},function(t,e,i){function s(t,e,i,s){this.id=e;var n=["sampling","style","sort","yAxisOrientation","barChart","drawPoints","shaded","catmullRom"];this.options=o.selectiveBridgeObject(n,i),this.usingDefaultStyle=void 0===t.className,this.groupsUsingDefaultStyles=s,this.zeroPosition=0,this.update(t),1==this.usingDefaultStyle&&(this.groupsUsingDefaultStyles[0]+=1),this.itemsData=[],this.visible=void 0===t.visible?!0:t.visible}var o=i(1),n=i(6),r=i(47),a=i(49),h=i(48);s.prototype.setItems=function(t){null!=t?(this.itemsData=t,1==this.options.sort&&this.itemsData.sort(function(t,e){return t.x-e.x})):this.itemsData=[]},s.prototype.setZeroPosition=function(t){this.zeroPosition=t},s.prototype.setOptions=function(t){if(void 0!==t){var e=["sampling","style","sort","yAxisOrientation","barChart"];o.selectiveDeepExtend(e,this.options,t),o.mergeOptions(this.options,t,"catmullRom"),o.mergeOptions(this.options,t,"drawPoints"),o.mergeOptions(this.options,t,"shaded"),t.catmullRom&&"object"==typeof t.catmullRom&&t.catmullRom.parametrization&&("uniform"==t.catmullRom.parametrization?this.options.catmullRom.alpha=0:"chordal"==t.catmullRom.parametrization?this.options.catmullRom.alpha=1:(this.options.catmullRom.parametrization="centripetal",this.options.catmullRom.alpha=.5))}"line"==this.options.style?this.type=new r(this.id,this.options):"bar"==this.options.style?this.type=new a(this.id,this.options):"points"==this.options.style&&(this.type=new h(this.id,this.options))},s.prototype.update=function(t){this.group=t,this.content=t.content||"graph",this.className=t.className||this.className||"graphGroup"+this.groupsUsingDefaultStyles[0]%10,this.visible=void 0===t.visible?!0:t.visible,this.style=t.style,this.setOptions(t.options)},s.prototype.drawIcon=function(t,e,i,s,o,r){var a,h,d=.5*r,l=n.getSVGElement("rect",i,s);if(l.setAttributeNS(null,"x",t),l.setAttributeNS(null,"y",e-d),l.setAttributeNS(null,"width",o),l.setAttributeNS(null,"height",2*d),l.setAttributeNS(null,"class","outline"),"line"==this.options.style)a=n.getSVGElement("path",i,s),a.setAttributeNS(null,"class",this.className),void 0!==this.style&&a.setAttributeNS(null,"style",this.style),a.setAttributeNS(null,"d","M"+t+","+e+" L"+(t+o)+","+e),1==this.options.shaded.enabled&&(h=n.getSVGElement("path",i,s),"top"==this.options.shaded.orientation?h.setAttributeNS(null,"d","M"+t+", "+(e-d)+"L"+t+","+e+" L"+(t+o)+","+e+" L"+(t+o)+","+(e-d)):h.setAttributeNS(null,"d","M"+t+","+e+" L"+t+","+(e+d)+" L"+(t+o)+","+(e+d)+"L"+(t+o)+","+e),h.setAttributeNS(null,"class",this.className+" iconFill")),1==this.options.drawPoints.enabled&&n.drawPoint(t+.5*o,e,this,i,s);else{var c=Math.round(.3*o),p=Math.round(.4*r),u=Math.round(.75*r),m=Math.round((o-2*c)/3);n.drawBar(t+.5*c+m,e+d-p-1,c,p,this.className+" bar",i,s),n.drawBar(t+1.5*c+m+2,e+d-u-1,c,u,this.className+" bar",i,s)}},s.prototype.getLegend=function(t,e){var i=document.createElementNS("http://www.w3.org/2000/svg","svg");return this.drawIcon(0,.5*e,[],i,t,e),{icon:i,label:this.content,orientation:this.options.yAxisOrientation}},s.prototype.getYRange=function(t){return this.type.getYRange(t)},s.prototype.draw=function(t,e,i){this.type.draw(t,e,i)},t.exports=s},function(t,e,i){function s(t,e){this.groupId=t,this.options=e}var o=i(6),n=i(48);s.prototype.getYRange=function(t){for(var e=t[0].y,i=t[0].y,s=0;st[s].y?t[s].y:e,i=i0){var r,a,h=Number(i.svg.style.height.replace("px",""));if(r=o.getSVGElement("path",i.svgElements,i.svg),r.setAttributeNS(null,"class",e.className),void 0!==e.style&&r.setAttributeNS(null,"style",e.style),a=1==e.options.catmullRom.enabled?s._catmullRom(t,e):s._linear(t),1==e.options.shaded.enabled){var d,l=o.getSVGElement("path",i.svgElements,i.svg);d="top"==e.options.shaded.orientation?"M"+t[0].x+",0 "+a+"L"+t[t.length-1].x+",0":"M"+t[0].x+","+h+" "+a+"L"+t[t.length-1].x+","+h,l.setAttributeNS(null,"class",e.className+" fill"),void 0!==e.options.shaded.style&&l.setAttributeNS(null,"style",e.options.shaded.style),l.setAttributeNS(null,"d",d)}r.setAttributeNS(null,"d","M"+a),1==e.options.drawPoints.enabled&&n.draw(t,e,i)}},s._catmullRomUniform=function(t){for(var e,i,s,o,n,r,a=Math.round(t[0].x)+","+Math.round(t[0].y)+" ",h=1/6,d=t.length,l=0;d-1>l;l++)e=0==l?t[0]:t[l-1],i=t[l],s=t[l+1],o=d>l+2?t[l+2]:s,n={x:(-e.x+6*i.x+s.x)*h,y:(-e.y+6*i.y+s.y)*h},r={x:(i.x+6*s.x-o.x)*h,y:(i.y+6*s.y-o.y)*h},a+="C"+n.x+","+n.y+" "+r.x+","+r.y+" "+s.x+","+s.y+" ";return a},s._catmullRom=function(t,e){var i=e.options.catmullRom.alpha;if(0==i||void 0===i)return this._catmullRomUniform(t);for(var s,o,n,r,a,h,d,l,c,p,u,m,f,g,v,y,b,_,x,w=Math.round(t[0].x)+","+Math.round(t[0].y)+" ",M=t.length,S=0;M-1>S;S++)s=0==S?t[0]:t[S-1],o=t[S],n=t[S+1],r=M>S+2?t[S+2]:n,d=Math.sqrt(Math.pow(s.x-o.x,2)+Math.pow(s.y-o.y,2)),l=Math.sqrt(Math.pow(o.x-n.x,2)+Math.pow(o.y-n.y,2)),c=Math.sqrt(Math.pow(n.x-r.x,2)+Math.pow(n.y-r.y,2)),g=Math.pow(c,i),y=Math.pow(c,2*i),v=Math.pow(l,i),b=Math.pow(l,2*i),x=Math.pow(d,i),_=Math.pow(d,2*i),p=2*_+3*x*v+b,u=2*y+3*g*v+b,m=3*x*(x+v),m>0&&(m=1/m),f=3*g*(g+v),f>0&&(f=1/f),a={x:(-b*s.x+p*o.x+_*n.x)*m,y:(-b*s.y+p*o.y+_*n.y)*m},h={x:(y*o.x+u*n.x-b*r.x)*f,y:(y*o.y+u*n.y-b*r.y)*f},0==a.x&&0==a.y&&(a=o),0==h.x&&0==h.y&&(h=n),w+="C"+a.x+","+a.y+" "+h.x+","+h.y+" "+n.x+","+n.y+" ";return w},s._linear=function(t){for(var e="",i=0;it[s].y?t[s].y:e,i=it[s].y?t[s].y:e,i=i0&&(n=Math.min(n,Math.abs(c[d-1].x-r))),a=s._getSafeDrawData(n,h,m);else{var g=d+(p[r].amount-p[r].resolved),v=d-(p[r].resolved+1);g0&&(n=Math.min(n,Math.abs(c[v].x-r))),a=s._getSafeDrawData(n,h,m),p[r].resolved+=1,"stack"==h.options.barChart.handleOverlap?(f=p[r].accumulated,p[r].accumulated+=h.zeroPosition-c[d].y):"sideBySide"==h.options.barChart.handleOverlap&&(a.width=a.width/p[r].amount,a.offset+=p[r].resolved*a.width-.5*a.width*(p[r].amount+1),"left"==h.options.barChart.align?a.offset-=.5*a.width:"right"==h.options.barChart.align&&(a.offset+=.5*a.width))}o.drawBar(c[d].x+a.offset,c[d].y-f,a.width,h.zeroPosition-c[d].y,h.className+" bar",i.svgElements,i.svg),1==h.options.drawPoints.enabled&&o.drawPoint(c[d].x+a.offset,c[d].y,h,i.svgElements,i.svg)}},s._getDataIntersections=function(t,e){for(var i,s=0;s0&&(i=Math.min(i,Math.abs(e[s-1].x-e[s].x))),0==i&&(void 0===t[e[s].x]&&(t[e[s].x]={amount:0,resolved:0,accumulated:0}),t[e[s].x].amount+=1)},s._getSafeDrawData=function(t,e,i){var s,o;return t0?(s=i>t?i:t,o=0,"left"==e.options.barChart.align?o-=.5*t:"right"==e.options.barChart.align&&(o+=.5*t)):(s=e.options.barChart.width,o=0,"left"==e.options.barChart.align?o-=.5*e.options.barChart.width:"right"==e.options.barChart.align&&(o+=.5*e.options.barChart.width)),{width:s,offset:o}},s.getStackedBarYRange=function(t,e,i,o,n){if(t.length>0){t.sort(function(t,e){return t.x==e.x?t.groupId-e.groupId:t.x-e.x});var r={};s._getDataIntersections(r,t),e[o]=s._getStackedBarYRange(r,t),e[o].yAxisOrientation=n,i.push(o)}},s._getStackedBarYRange=function(t,e){for(var i,s=e[0].y,o=e[0].y,n=0;ne[n].y?e[n].y:s,o=ot[r].accumulated?t[r].accumulated:s,o=o"));this.dom.textArea.innerHTML=s,this.dom.textArea.style.lineHeight=.75*this.options.iconSize+this.options.iconSpacing+"px" +}},s.prototype.drawLegendIcons=function(){if(this.dom.frame.parentNode){n.prepareElements(this.svgElements);var t=window.getComputedStyle(this.dom.frame).paddingTop,e=Number(t.replace("px","")),i=e,s=this.options.iconSize,o=.75*this.options.iconSize,r=e+.5*o+3;this.svg.style.width=s+5+e+"px";for(var a in this.groups)this.groups.hasOwnProperty(a)&&(1!=this.groups[a].visible||void 0!==this.linegraphOptions.visibility[a]&&1!=this.linegraphOptions.visibility[a]||(this.groups[a].drawIcon(i,r,this.svgElements,this.svg,s,o),r+=o+this.options.iconSpacing));n.cleanupElements(this.svgElements)}},t.exports=s},function(t,e,i){function s(t,e,i){if(!(this instanceof s))throw new SyntaxError("Constructor must be called with the new operator");this._determineBrowserMethod(),this._initializeMixinLoaders(),this.containerElement=t,this.renderRefreshRate=60,this.renderTimestep=1e3/this.renderRefreshRate,this.renderTime=0,this.physicsTime=0,this.runDoubleSpeed=!1,this.physicsDiscreteStepsize=.5,this.initializing=!0,this.triggerFunctions={add:null,edit:null,editEdge:null,connect:null,del:null},this.defaultOptions={nodes:{mass:1,radiusMin:10,radiusMax:30,radius:10,shape:"ellipse",image:void 0,widthMin:16,widthMax:64,fontColor:"black",fontSize:14,fontFace:"verdana",fontFill:void 0,fontStrokeWidth:0,fontStrokeColor:"white",level:-1,color:{border:"#2B7CE9",background:"#97C2FC",highlight:{border:"#2B7CE9",background:"#D2E5FF"},hover:{border:"#2B7CE9",background:"#D2E5FF"}},group:void 0,borderWidth:1,borderWidthSelected:void 0},edges:{widthMin:1,widthMax:15,width:1,widthSelectionMultiplier:2,hoverWidth:1.5,style:"line",color:{color:"#848484",highlight:"#848484",hover:"#848484"},fontColor:"#343434",fontSize:14,fontFace:"arial",fontFill:"white",fontStrokeWidth:0,fontStrokeColor:"white",labelAlignment:"horizontal",arrowScaleFactor:1,dash:{length:10,gap:5,altLength:void 0},inheritColor:"from"},configurePhysics:!1,physics:{barnesHut:{enabled:!0,thetaInverted:2,gravitationalConstant:-2e3,centralGravity:.3,springLength:95,springConstant:.04,damping:.09},repulsion:{centralGravity:0,springLength:200,springConstant:.05,nodeDistance:100,damping:.09},hierarchicalRepulsion:{enabled:!1,centralGravity:0,springLength:100,springConstant:.01,nodeDistance:150,damping:.09},damping:null,centralGravity:null,springLength:null,springConstant:null},clustering:{enabled:!1,initialMaxNodes:100,clusterThreshold:500,reduceToNodes:300,chainThreshold:.4,clusterEdgeThreshold:20,sectorThreshold:100,screenSizeThreshold:.2,fontSizeMultiplier:4,maxFontSize:1e3,forceAmplification:.1,distanceAmplification:.1,edgeGrowth:20,nodeScaling:{width:1,height:1,radius:1},maxNodeSizeIncrements:600,activeAreaBoxSize:80,clusterLevelDifference:2},navigation:{enabled:!1},keyboard:{enabled:!1,speed:{x:10,y:10,zoom:.02}},dataManipulation:{enabled:!1,initiallyVisible:!1},hierarchicalLayout:{enabled:!1,levelSeparation:150,nodeSpacing:100,direction:"UD",layout:"hubsize"},freezeForStabilization:!1,smoothCurves:{enabled:!0,dynamic:!0,type:"continuous",roundness:.5},maxVelocity:30,minVelocity:.1,stabilize:!0,stabilizationIterations:1e3,zoomExtentOnStabilize:!0,locale:"en",locales:_,tooltip:{delay:300,fontColor:"black",fontSize:14,fontFace:"verdana",color:{border:"#666",background:"#FFFFC6"}},dragNetwork:!0,dragNodes:!0,zoomable:!0,hover:!1,hideEdgesOnDrag:!1,hideNodesOnDrag:!1,width:"100%",height:"100%",selectable:!0},this.constants=a.extend({},this.defaultOptions),this.pixelRatio=1,this.hoverObj={nodes:{},edges:{}},this.controlNodesActive=!1,this.navigationHammers={existing:[],_new:[]},this.animationSpeed=1/this.renderRefreshRate,this.animationEasingFunction="easeInOutQuint",this.easingTime=0,this.sourceScale=0,this.targetScale=0,this.sourceTranslation=0,this.targetTranslation=0,this.lockedOnNodeId=null,this.lockedOnNodeOffset=null,this.touchTime=0;var o=this;this.groups=new u,this.images=new m,this.images.setOnloadCallback(function(){o._redraw()}),this.xIncrement=0,this.yIncrement=0,this.zoomIncrement=0,this._loadPhysicsSystem(),this._create(),this._loadSectorSystem(),this._loadClusterSystem(),this._loadSelectionSystem(),this._loadHierarchySystem(),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1),this.setOptions(i),this.freezeSimulation=!1,this.cachedFunctions={},this.startedStabilization=!1,this.stabilized=!1,this.stabilizationIterations=null,this.draggingNodes=!1,this.calculationNodes={},this.calculationNodeIndices=[],this.nodeIndices=[],this.nodes={},this.edges={},this.canvasTopLeft={x:0,y:0},this.canvasBottomRight={x:0,y:0},this.pointerPosition={x:0,y:0},this.areaCenter={},this.scale=1,this.previousScale=this.scale,this.nodesData=null,this.edgesData=null,this.nodesListeners={add:function(t,e){o._addNodes(e.items),o.start()},update:function(t,e){o._updateNodes(e.items,e.data),o.start()},remove:function(t,e){o._removeNodes(e.items),o.start()}},this.edgesListeners={add:function(t,e){o._addEdges(e.items),o.start()},update:function(t,e){o._updateEdges(e.items),o.start()},remove:function(t,e){o._removeEdges(e.items),o.start()}},this.moving=!0,this.timer=void 0,this.setData(e,this.constants.clustering.enabled||this.constants.hierarchicalLayout.enabled),this.initializing=!1,1==this.constants.hierarchicalLayout.enabled?this._setupHierarchicalLayout():0==this.constants.stabilize&&this.zoomExtent(void 0,!0,this.constants.clustering.enabled),this.constants.clustering.enabled&&this.startWithClustering()}var o=i(11),n=i(19),r=i(36),a=i(1),h=i(22),d=i(7),l=i(9),c=i(57),p=i(58),u=i(54),m=i(55),f=i(53),g=i(52),v=i(56),y=i(59),b=i(35),_=i(70);i(71),o(s.prototype),s.prototype._determineBrowserMethod=function(){var t=navigator.userAgent.toLowerCase();this.requiresTimeout=!1,-1!=t.indexOf("msie 9.0")?this.requiresTimeout=!0:-1!=t.indexOf("safari")&&t.indexOf("chrome")<=-1&&(this.requiresTimeout=!0)},s.prototype._getScriptPath=function(){for(var t=document.getElementsByTagName("script"),e=0;et.boundingBox.left&&(s=t.boundingBox.left),ot.boundingBox.bottom&&(e=t.boundingBox.top),i=this.constants.clustering.initialMaxNodes?49.07548/(n+142.05338)+91444e-8:12.662/(n+7.4147)+.0964822:1==this.constants.clustering.enabled&&n>=this.constants.clustering.initialMaxNodes?77.5271985/(n+187.266146)+476710517e-13:30.5062972/(n+19.93597763)+.08413486;var r=Math.min(this.frame.canvas.clientWidth/600,this.frame.canvas.clientHeight/600);s*=r}else{var a=1.1*Math.abs(o.maxX-o.minX),h=1.1*Math.abs(o.maxY-o.minY),d=this.frame.canvas.clientWidth/a,l=this.frame.canvas.clientHeight/h;s=l>=d?d:l}s>1&&(s=1);var c=this._findCenter(o);if(0==i){var p={position:c,scale:s,animation:t};this.moveTo(p),this.moving=!0,this.start()}else c.x*=s,c.y*=s,c.x-=.5*this.frame.canvas.clientWidth,c.y-=.5*this.frame.canvas.clientHeight,this._setScale(s),this._setTranslation(-c.x,-c.y)},s.prototype._updateNodeIndexList=function(){this._clearNodeIndexList();for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodeIndices.push(t)},s.prototype.setData=function(t,e){if(void 0===e&&(e=!1),this.initializing=!0,t&&t.dot&&(t.nodes||t.edges))throw new SyntaxError('Data must contain either parameter "dot" or parameter pair "nodes" and "edges", but not both.');if(1==this.constants.dataManipulation.enabled&&this._createManipulatorBar(),this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var i=c.DOTToGraph(t.dot);return void this.setData(i)}}else if(t&&t.gephi){if(t&&t.gephi){var s=p.parseGephi(t.gephi);return void this.setData(s)}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this._putDataInSector(),0==e&&(1==this.constants.hierarchicalLayout.enabled?(this._resetLevels(),this._setupHierarchicalLayout()):this.constants.stabilize&&this._stabilize(),this.start()),this.initializing=!1},s.prototype.setOptions=function(t){if(t){var e,i=["nodes","edges","smoothCurves","hierarchicalLayout","clustering","navigation","keyboard","dataManipulation","onAdd","onEdit","onEditEdge","onConnect","onDelete","clickToUse"];if(a.selectiveNotDeepExtend(i,this.constants,t),a.selectiveNotDeepExtend(["color"],this.constants.nodes,t.nodes),a.selectiveNotDeepExtend(["color","length"],this.constants.edges,t.edges),t.physics&&(a.mergeOptions(this.constants.physics,t.physics,"barnesHut"),a.mergeOptions(this.constants.physics,t.physics,"repulsion"),t.physics.hierarchicalRepulsion)){this.constants.hierarchicalLayout.enabled=!0,this.constants.physics.hierarchicalRepulsion.enabled=!0,this.constants.physics.barnesHut.enabled=!1;for(e in t.physics.hierarchicalRepulsion)t.physics.hierarchicalRepulsion.hasOwnProperty(e)&&(this.constants.physics.hierarchicalRepulsion[e]=t.physics.hierarchicalRepulsion[e])}if(t.onAdd&&(this.triggerFunctions.add=t.onAdd),t.onEdit&&(this.triggerFunctions.edit=t.onEdit),t.onEditEdge&&(this.triggerFunctions.editEdge=t.onEditEdge),t.onConnect&&(this.triggerFunctions.connect=t.onConnect),t.onDelete&&(this.triggerFunctions.del=t.onDelete),a.mergeOptions(this.constants,t,"smoothCurves"),a.mergeOptions(this.constants,t,"hierarchicalLayout"),a.mergeOptions(this.constants,t,"clustering"),a.mergeOptions(this.constants,t,"navigation"),a.mergeOptions(this.constants,t,"keyboard"),a.mergeOptions(this.constants,t,"dataManipulation"),t.dataManipulation&&(this.editMode=this.constants.dataManipulation.initiallyVisible),t.edges&&(void 0!==t.edges.color&&(a.isString(t.edges.color)?(this.constants.edges.color={},this.constants.edges.color.color=t.edges.color,this.constants.edges.color.highlight=t.edges.color,this.constants.edges.color.hover=t.edges.color):(void 0!==t.edges.color.color&&(this.constants.edges.color.color=t.edges.color.color),void 0!==t.edges.color.highlight&&(this.constants.edges.color.highlight=t.edges.color.highlight),void 0!==t.edges.color.hover&&(this.constants.edges.color.hover=t.edges.color.hover)),this.constants.edges.inheritColor=!1),t.edges.fontColor||void 0!==t.edges.color&&(a.isString(t.edges.color)?this.constants.edges.fontColor=t.edges.color:void 0!==t.edges.color.color&&(this.constants.edges.fontColor=t.edges.color.color))),t.nodes&&t.nodes.color){var s=a.parseColor(t.nodes.color);this.constants.nodes.color.background=s.background,this.constants.nodes.color.border=s.border,this.constants.nodes.color.highlight.background=s.highlight.background,this.constants.nodes.color.highlight.border=s.highlight.border,this.constants.nodes.color.hover.background=s.hover.background,this.constants.nodes.color.hover.border=s.hover.border}if(t.groups)for(var o in t.groups)if(t.groups.hasOwnProperty(o)){var n=t.groups[o];this.groups.add(o,n)}if(t.tooltip){for(e in t.tooltip)t.tooltip.hasOwnProperty(e)&&(this.constants.tooltip[e]=t.tooltip[e]);t.tooltip.color&&(this.constants.tooltip.color=a.parseColor(t.tooltip.color))}if("clickToUse"in t&&(t.clickToUse?this.activator||(this.activator=new b(this.frame),this.activator.on("change",this._createKeyBinds.bind(this))):this.activator&&(this.activator.destroy(),delete this.activator)),t.labels)throw new Error('Option "labels" is deprecated. Use options "locale" and "locales" instead.');this._loadPhysicsSystem(),this._loadNavigationControls(),this._loadManipulationSystem(),this._configureSmoothCurves(),this._createKeyBinds(),this.setSize(this.constants.width,this.constants.height),this.moving=!0,this.start()}},s.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="vis network-frame",this.frame.style.position="relative",this.frame.style.overflow="hidden",this.frame.canvas=document.createElement("canvas"),this.frame.canvas.style.position="relative",this.frame.appendChild(this.frame.canvas),this.frame.canvas.getContext){var t=this.frame.canvas.getContext("2d");this.pixelRatio=(window.devicePixelRatio||1)/(t.webkitBackingStorePixelRatio||t.mozBackingStorePixelRatio||t.msBackingStorePixelRatio||t.oBackingStorePixelRatio||t.backingStorePixelRatio||1),this.frame.canvas.getContext("2d").setTransform(this.pixelRatio,0,0,this.pixelRatio,0,0)}else{var e=document.createElement("DIV");e.style.color="red",e.style.fontWeight="bold",e.style.padding="10px",e.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(e)}var i=this;this.drag={},this.pinch={},this.hammer=n(this.frame.canvas,{prevent_default:!0}),this.hammer.on("tap",i._onTap.bind(i)),this.hammer.on("doubletap",i._onDoubleTap.bind(i)),this.hammer.on("hold",i._onHold.bind(i)),this.hammer.on("pinch",i._onPinch.bind(i)),this.hammer.on("touch",i._onTouch.bind(i)),this.hammer.on("dragstart",i._onDragStart.bind(i)),this.hammer.on("drag",i._onDrag.bind(i)),this.hammer.on("dragend",i._onDragEnd.bind(i)),this.hammer.on("mousewheel",i._onMouseWheel.bind(i)),this.hammer.on("DOMMouseScroll",i._onMouseWheel.bind(i)),this.hammer.on("mousemove",i._onMouseMoveTitle.bind(i)),this.hammerFrame=n(this.frame,{prevent_default:!0}),this.hammerFrame.on("release",i._onRelease.bind(i)),this.containerElement.appendChild(this.frame)},s.prototype._createKeyBinds=function(){var t=this;void 0!==this.keycharm&&this.keycharm.destroy(),this.keycharm=r(),this.keycharm.reset(),this.constants.keyboard.enabled&&this.isActive()&&(this.keycharm.bind("up",this._moveUp.bind(t),"keydown"),this.keycharm.bind("up",this._yStopMoving.bind(t),"keyup"),this.keycharm.bind("down",this._moveDown.bind(t),"keydown"),this.keycharm.bind("down",this._yStopMoving.bind(t),"keyup"),this.keycharm.bind("left",this._moveLeft.bind(t),"keydown"),this.keycharm.bind("left",this._xStopMoving.bind(t),"keyup"),this.keycharm.bind("right",this._moveRight.bind(t),"keydown"),this.keycharm.bind("right",this._xStopMoving.bind(t),"keyup"),this.keycharm.bind("=",this._zoomIn.bind(t),"keydown"),this.keycharm.bind("=",this._stopZoom.bind(t),"keyup"),this.keycharm.bind("num+",this._zoomIn.bind(t),"keydown"),this.keycharm.bind("num+",this._stopZoom.bind(t),"keyup"),this.keycharm.bind("num-",this._zoomOut.bind(t),"keydown"),this.keycharm.bind("num-",this._stopZoom.bind(t),"keyup"),this.keycharm.bind("-",this._zoomOut.bind(t),"keydown"),this.keycharm.bind("-",this._stopZoom.bind(t),"keyup"),this.keycharm.bind("[",this._zoomIn.bind(t),"keydown"),this.keycharm.bind("[",this._stopZoom.bind(t),"keyup"),this.keycharm.bind("]",this._zoomOut.bind(t),"keydown"),this.keycharm.bind("]",this._stopZoom.bind(t),"keyup"),this.keycharm.bind("pageup",this._zoomIn.bind(t),"keydown"),this.keycharm.bind("pageup",this._stopZoom.bind(t),"keyup"),this.keycharm.bind("pagedown",this._zoomOut.bind(t),"keydown"),this.keycharm.bind("pagedown",this._stopZoom.bind(t),"keyup")),1==this.constants.dataManipulation.enabled&&(this.keycharm.bind("esc",this._createManipulatorBar.bind(t)),this.keycharm.bind("delete",this._deleteSelected.bind(t)))},s.prototype.destroy=function(){this.start=function(){},this.redraw=function(){},this.timer=!1,this._cleanupPhysicsConfiguration(),this.keycharm.reset(),this.hammer.dispose(),this.off(),this._recursiveDOMDelete(this.containerElement)},s.prototype._recursiveDOMDelete=function(t){for(;1==t.hasChildNodes();)this._recursiveDOMDelete(t.firstChild),t.removeChild(t.firstChild)},s.prototype._getPointer=function(t){return{x:t.pageX-a.getAbsoluteLeft(this.frame.canvas),y:t.pageY-a.getAbsoluteTop(this.frame.canvas)}},s.prototype._onTouch=function(t){(new Date).valueOf()-this.touchTime>100&&(this.drag.pointer=this._getPointer(t.gesture.center),this.drag.pinched=!1,this.pinch.scale=this._getScale(),this.touchTime=(new Date).valueOf(),this._handleTouch(this.drag.pointer))},s.prototype._onDragStart=function(t){this._handleDragStart(t)},s.prototype._handleDragStart=function(t){void 0===this.drag.pointer&&this._onTouch(t);var e=this._getNodeAt(this.drag.pointer);if(this.drag.dragging=!0,this.drag.selection=[],this.drag.translation=this._getTranslation(),this.drag.nodeId=null,this.draggingNodes=!1,null!=e&&1==this.constants.dragNodes){this.draggingNodes=!0,this.drag.nodeId=e.id,e.isSelected()||this._selectObject(e,!1),this.emit("dragStart",{nodeIds:this.getSelection().nodes});for(var i in this.selectionObj.nodes)if(this.selectionObj.nodes.hasOwnProperty(i)){var s=this.selectionObj.nodes[i],o={id:s.id,node:s,x:s.x,y:s.y,xFixed:s.xFixed,yFixed:s.yFixed};s.xFixed=!0,s.yFixed=!0,this.drag.selection.push(o)}}},s.prototype._onDrag=function(t){this._handleOnDrag(t)},s.prototype._handleOnDrag=function(t){if(!this.drag.pinched){this.releaseNode();var e=this._getPointer(t.gesture.center),i=this,s=this.drag,o=s.selection;if(o&&o.length&&1==this.constants.dragNodes){var n=e.x-s.pointer.x,r=e.y-s.pointer.y;o.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._XconvertDOMtoCanvas(i._XconvertCanvasToDOM(t.x)+n)),t.yFixed||(e.y=i._YconvertDOMtoCanvas(i._YconvertCanvasToDOM(t.y)+r))}),this.moving||(this.moving=!0,this.start())}else if(1==this.constants.dragNetwork){if(void 0===this.drag.pointer)return void this._handleDragStart(t);var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw()}}},s.prototype._onDragEnd=function(t){this._handleDragEnd(t)},s.prototype._handleDragEnd=function(){this.drag.dragging=!1;var t=this.drag.selection;t&&t.length?(t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed}),this.moving=!0,this.start()):this._redraw(),0==this.draggingNodes?this.emit("dragEnd",{nodeIds:[]}):this.emit("dragEnd",{nodeIds:this.getSelection().nodes})},s.prototype._onTap=function(t){var e=this._getPointer(t.gesture.center);this.pointerPosition=e,this._handleTap(e)},s.prototype._onDoubleTap=function(t){var e=this._getPointer(t.gesture.center);this._handleDoubleTap(e)},s.prototype._onHold=function(t){var e=this._getPointer(t.gesture.center);this.pointerPosition=e,this._handleOnHold(e)},s.prototype._onRelease=function(t){var e=this._getPointer(t.gesture.center);this._handleOnRelease(e)},s.prototype._onPinch=function(t){var e=this._getPointer(t.gesture.center);this.drag.pinched=!0,"scale"in this.pinch||(this.pinch.scale=1);var i=this.pinch.scale*t.gesture.scale;this._zoom(i,e)},s.prototype._zoom=function(t,e){if(1==this.constants.zoomable){var i=this._getScale();1e-5>t&&(t=1e-5),t>10&&(t=10);var s=null;void 0!==this.drag&&1==this.drag.dragging&&(s=this.DOMtoCanvas(this.drag.pointer));var o=this._getTranslation(),n=t/i,r=(1-n)*e.x+o.x*n,a=(1-n)*e.y+o.y*n;if(this.areaCenter={x:this._XconvertDOMtoCanvas(e.x),y:this._YconvertDOMtoCanvas(e.y)},this._setScale(t),this._setTranslation(r,a),this.updateClustersDefault(),null!=s){var h=this.canvasToDOM(s);this.drag.pointer.x=h.x,this.drag.pointer.y=h.y}return this._redraw(),t>i?this.emit("zoom",{direction:"+"}):this.emit("zoom",{direction:"-"}),t}},s.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){var i=this._getScale(),s=e/10;0>e&&(s/=1-s),i*=1+s;var o=h.fakeGesture(this,t),n=this._getPointer(o.center);this._zoom(i,n)}t.preventDefault()},s.prototype._onMouseMoveTitle=function(t){var e=h.fakeGesture(this,t),i=this._getPointer(e.center);this.popupObj&&this._checkHidePopup(i);var s=this,o=function(){s._checkShowPopup(i)};if(this.popupTimer&&clearInterval(this.popupTimer),this.drag.dragging||(this.popupTimer=setTimeout(o,this.constants.tooltip.delay)),1==this.constants.hover){for(var n in this.hoverObj.edges)this.hoverObj.edges.hasOwnProperty(n)&&(this.hoverObj.edges[n].hover=!1,delete this.hoverObj.edges[n]);var r=this._getNodeAt(i);null==r&&(r=this._getEdgeAt(i)),null!=r&&this._hoverObject(r);for(var a in this.hoverObj.nodes)this.hoverObj.nodes.hasOwnProperty(a)&&(r instanceof f&&r.id!=a||r instanceof g||null==r)&&(this._blurObject(this.hoverObj.nodes[a]),delete this.hoverObj.nodes[a]);this.redraw()}},s.prototype._checkShowPopup=function(t){var e,i={left:this._XconvertDOMtoCanvas(t.x),top:this._YconvertDOMtoCanvas(t.y),right:this._XconvertDOMtoCanvas(t.x),bottom:this._YconvertDOMtoCanvas(t.y)},s=this.popupObj,o=!1;if(void 0==this.popupObj){var n=this.nodes,r=[];for(e in n)if(n.hasOwnProperty(e)){var a=n[e];a.isOverlappingWith(i)&&void 0!==a.getTitle()&&r.push(e)}r.length>0&&(this.popupObj=this.nodes[r[r.length-1]],o=!0)}if(void 0===this.popupObj&&0==o){var h=this.edges,d=[];for(e in h)if(h.hasOwnProperty(e)){var l=h[e];l.connected&&void 0!==l.getTitle()&&l.isOverlappingWith(i)&&d.push(e)}d.length>0&&(this.popupObj=this.edges[d[d.length-1]])}if(this.popupObj){if(this.popupObj!=s){var c=this;c.popup||(c.popup=new v(c.frame,c.constants.tooltip)),c.popup.setPosition(t.x-3,t.y-3),c.popup.setText(c.popupObj.getTitle()),c.popup.show()}}else this.popup&&this.popup.hide()},s.prototype._checkHidePopup=function(t){this.popupObj&&this._getNodeAt(t)||(this.popupObj=void 0,this.popup&&this.popup.hide())},s.prototype.setSize=function(t,e){var i=!1,s=this.frame.canvas.width,o=this.frame.canvas.height;t!=this.constants.width||e!=this.constants.height||this.frame.style.width!=t||this.frame.style.height!=e?(this.frame.style.width=t,this.frame.style.height=e,this.frame.canvas.style.width="100%",this.frame.canvas.style.height="100%",this.frame.canvas.width=this.frame.canvas.clientWidth*this.pixelRatio,this.frame.canvas.height=this.frame.canvas.clientHeight*this.pixelRatio,this.constants.width=t,this.constants.height=e,i=!0):(this.frame.canvas.width!=this.frame.canvas.clientWidth*this.pixelRatio&&(this.frame.canvas.width=this.frame.canvas.clientWidth*this.pixelRatio,i=!0),this.frame.canvas.height!=this.frame.canvas.clientHeight*this.pixelRatio&&(this.frame.canvas.height=this.frame.canvas.clientHeight*this.pixelRatio,i=!0)),1==i&&this.emit("resize",{width:this.frame.canvas.width*this.pixelRatio,height:this.frame.canvas.height*this.pixelRatio,oldWidth:s*this.pixelRatio,oldHeight:o*this.pixelRatio})},s.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof d||t instanceof l)this.nodesData=t;else if(Array.isArray(t))this.nodesData=new d,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new d}if(e&&a.forEach(this.nodesListeners,function(t,i){e.off(i,t)}),this.nodes={},this.nodesData){var i=this;a.forEach(this.nodesListeners,function(t,e){i.nodesData.on(e,t)});var s=this.nodesData.getIds();this._addNodes(s)}this._updateSelection()},s.prototype._addNodes=function(t){for(var e,i=0,s=t.length;s>i;i++){e=t[i];var o=this.nodesData.get(e),n=new f(o,this.images,this.groups,this.constants);if(this.nodes[e]=n,!(0!=n.xFixed&&0!=n.yFixed||null!==n.x&&null!==n.y)){var r=1*t.length+10,a=2*Math.PI*Math.random();0==n.xFixed&&(n.x=r*Math.cos(a)),0==n.yFixed&&(n.y=r*Math.sin(a))}this.moving=!0}this._updateNodeIndexList(),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this._updateCalculationNodes(),this._reconnectEdges(),this._updateValueRange(this.nodes),this.updateLabels()},s.prototype._updateNodes=function(t,e){for(var i=this.nodes,s=0,o=t.length;o>s;s++){var n=t[s],r=i[n],a=e[s];r?r.setProperties(a,this.constants):(r=new f(properties,this.images,this.groups,this.constants),i[n]=r)}this.moving=!0,1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this._updateNodeIndexList(),this._updateValueRange(i)},s.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,s=t.length;s>i;i++){var o=t[i];delete e[o]}this._updateNodeIndexList(),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this._updateCalculationNodes(),this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},s.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof d||t instanceof l)this.edgesData=t;else if(Array.isArray(t))this.edgesData=new d,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new d}if(e&&a.forEach(this.edgesListeners,function(t,i){e.off(i,t)}),this.edges={},this.edgesData){var i=this;a.forEach(this.edgesListeners,function(t,e){i.edgesData.on(e,t)});var s=this.edgesData.getIds();this._addEdges(s)}this._reconnectEdges()},s.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,s=0,o=t.length;o>s;s++){var n=t[s],r=e[n];r&&r.disconnect();var a=i.get(n,{showInternalIds:!0});e[n]=new g(a,this,this.constants)}this.moving=!0,this._updateValueRange(e),this._createBezierNodes(),this._updateCalculationNodes(),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout())},s.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,s=0,o=t.length;o>s;s++){var n=t[s],r=i.get(n),a=e[n];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new g(r,this,this.constants),this.edges[n]=a)}this._createBezierNodes(),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this.moving=!0,this._updateValueRange(e)},s.prototype._removeEdges=function(t){for(var e=this.edges,i=0,s=t.length;s>i;i++){var o=t[i],n=e[o];n&&(null!=n.via&&delete this.sectors.support.nodes[n.via.id],n.disconnect(),delete e[o])}this.moving=!0,this._updateValueRange(e),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this._updateCalculationNodes()},s.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[],e[t].dynamicEdges=[]);for(t in i)if(i.hasOwnProperty(t)){var s=i[t];s.from=null,s.to=null,s.connect()}},s.prototype._updateValueRange=function(t){var e,i=void 0,s=void 0;for(e in t)if(t.hasOwnProperty(e)){var o=t[e].getValue();void 0!==o&&(i=void 0===i?o:Math.min(o,i),s=void 0===s?o:Math.max(o,s))}if(void 0!==i&&void 0!==s)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,s)},s.prototype.redraw=function(){this.setSize(this.constants.width,this.constants.height),this._redraw()},s.prototype._redraw=function(t){var e=this.frame.canvas.getContext("2d");e.setTransform(this.pixelRatio,0,0,this.pixelRatio,0,0);var i=this.frame.canvas.width*this.pixelRatio,s=this.frame.canvas.height*this.pixelRatio;e.clearRect(0,0,i,s),e.save(),e.translate(this.translation.x,this.translation.y),e.scale(this.scale,this.scale),this.canvasTopLeft={x:this._XconvertDOMtoCanvas(0),y:this._YconvertDOMtoCanvas(0)},this.canvasBottomRight={x:this._XconvertDOMtoCanvas(this.frame.canvas.clientWidth*this.pixelRatio),y:this._YconvertDOMtoCanvas(this.frame.canvas.clientHeight*this.pixelRatio)},1!=t&&(this._doInAllSectors("_drawAllSectorNodes",e),(0==this.drag.dragging||void 0===this.drag.dragging||0==this.constants.hideEdgesOnDrag)&&this._doInAllSectors("_drawEdges",e)),(0==this.drag.dragging||void 0===this.drag.dragging||0==this.constants.hideNodesOnDrag)&&this._doInAllSectors("_drawNodes",e,!1),1!=t&&1==this.controlNodesActive&&this._doInAllSectors("_drawControlNodes",e),e.restore(),1==t&&e.clearRect(0,0,i,s)},s.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e),this.emit("viewChanged")},s.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},s.prototype._setScale=function(t){this.scale=t},s.prototype._getScale=function(){return this.scale},s.prototype._XconvertDOMtoCanvas=function(t){return(t-this.translation.x)/this.scale},s.prototype._XconvertCanvasToDOM=function(t){return t*this.scale+this.translation.x},s.prototype._YconvertDOMtoCanvas=function(t){return(t-this.translation.y)/this.scale},s.prototype._YconvertCanvasToDOM=function(t){return t*this.scale+this.translation.y},s.prototype.canvasToDOM=function(t){return{x:this._XconvertCanvasToDOM(t.x),y:this._YconvertCanvasToDOM(t.y)}},s.prototype.DOMtoCanvas=function(t){return{x:this._XconvertDOMtoCanvas(t.x),y:this._YconvertDOMtoCanvas(t.y)}},s.prototype._drawNodes=function(t,e){void 0===e&&(e=!1);var i=this.nodes,s=[];for(var o in i)i.hasOwnProperty(o)&&(i[o].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight),i[o].isSelected()?s.push(o):(i[o].inArea()||e)&&i[o].draw(t));for(var n=0,r=s.length;r>n;n++)(i[s[n]].inArea()||e)&&i[s[n]].draw(t)},s.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var s=e[i];s.setScale(this.scale),s.connected&&e[i].draw(t)}},s.prototype._drawControlNodes=function(t){var e=this.edges;for(var i in e)e.hasOwnProperty(i)&&e[i]._drawControlNodes(t)},s.prototype._stabilize=function(){1==this.constants.freezeForStabilization&&this._freezeDefinedNodes();for(var t=0;this.moving&&t0)for(t in i)i.hasOwnProperty(t)&&(i[t].discreteStepLimited(e,this.constants.maxVelocity),s=!0);else for(t in i)i.hasOwnProperty(t)&&(i[t].discreteStep(e),s=!0);if(1==s){var o=this.constants.minVelocity/Math.max(this.scale,.05);return o>.5*this.constants.maxVelocity?!0:this._isMoving(o)}return!1},s.prototype._revertPhysicsState=function(){var t=this.nodes;for(var e in t)t.hasOwnProperty(e)&&t[e].revertPosition()},s.prototype._revertPhysicsTick=function(){this._doInAllActiveSectors("_revertPhysicsState"),1==this.constants.smoothCurves.enabled&&1==this.constants.smoothCurves.dynamic&&this._doInSupportSector("_revertPhysicsState")},s.prototype._physicsTick=function(){if(!this.freezeSimulation&&1==this.moving){var t=!1,e=!1;this._doInAllActiveSectors("_initializeForceCalculation");var i=this._doInAllActiveSectors("_discreteStepNodes");1==this.constants.smoothCurves.enabled&&1==this.constants.smoothCurves.dynamic&&(e=this._doInSupportSector("_discreteStepNodes"));for(var s=0;s2*e||1==this.runDoubleSpeed)&&1==this.moving&&(this._physicsTick(),0!=this.renderTime&&(this.runDoubleSpeed=!0));var i=Date.now();this._redraw(),this.renderTime=Date.now()-i,this.start()},"undefined"!=typeof window&&(window.requestAnimationFrame=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame),s.prototype.start=function(){if(1==this.moving||0!=this.xIncrement||0!=this.yIncrement||0!=this.zoomIncrement)this.timer||(this.timer=1==this.requiresTimeout?window.setTimeout(this._animationStep.bind(this),this.renderTimestep):window.requestAnimationFrame(this._animationStep.bind(this))); +else if(this._redraw(),this.stabilizationIterations>1){var t=this,e={iterations:t.stabilizationIterations};this.stabilizationIterations=0,this.startedStabilization=!1,setTimeout(function(){t.emit("stabilized",e)},0)}else this.stabilizationIterations=0},s.prototype._handleNavigation=function(){if(0!=this.xIncrement||0!=this.yIncrement){var t=this._getTranslation();this._setTranslation(t.x+this.xIncrement,t.y+this.yIncrement)}if(0!=this.zoomIncrement){var e={x:this.frame.canvas.clientWidth/2,y:this.frame.canvas.clientHeight/2};this._zoom(this.scale*(1+this.zoomIncrement),e)}},s.prototype.toggleFreeze=function(){0==this.freezeSimulation?this.freezeSimulation=!0:(this.freezeSimulation=!1,this.start())},s.prototype._configureSmoothCurves=function(t){if(void 0===t&&(t=!0),1==this.constants.smoothCurves.enabled&&1==this.constants.smoothCurves.dynamic){this._createBezierNodes();for(var e in this.sectors.support.nodes)this.sectors.support.nodes.hasOwnProperty(e)&&void 0===this.edges[this.sectors.support.nodes[e].parentEdgeId]&&delete this.sectors.support.nodes[e]}else{this.sectors.support.nodes={};for(var i in this.edges)this.edges.hasOwnProperty(i)&&(this.edges[i].via=null)}this._updateCalculationNodes(),t||(this.moving=!0,this.start())},s.prototype._createBezierNodes=function(){if(1==this.constants.smoothCurves.enabled&&1==this.constants.smoothCurves.dynamic)for(var t in this.edges)if(this.edges.hasOwnProperty(t)){var e=this.edges[t];if(null==e.via){var i="edgeId:".concat(e.id);this.sectors.support.nodes[i]=new f({id:i,mass:1,shape:"circle",image:"",internalMultiplier:1},{},{},this.constants),e.via=this.sectors.support.nodes[i],e.via.parentEdgeId=e.id,e.positionBezierNode()}}},s.prototype._initializeMixinLoaders=function(){for(var t in y)y.hasOwnProperty(t)&&(s.prototype[t]=y[t])},s.prototype.storePosition=function(){console.log("storePosition is depricated: use .storePositions() from now on."),this.storePositions()},s.prototype.storePositions=function(){var t=[];for(var e in this.nodes)if(this.nodes.hasOwnProperty(e)){var i=this.nodes[e],s=!this.nodes.xFixed,o=!this.nodes.yFixed;(this.nodesData._data[e].x!=Math.round(i.x)||this.nodesData._data[e].y!=Math.round(i.y))&&t.push({id:e,x:Math.round(i.x),y:Math.round(i.y),allowedToMoveX:s,allowedToMoveY:o})}this.nodesData.update(t)},s.prototype.getPositions=function(t){var e={};if(void 0!==t){if(1==Array.isArray(t)){for(var i=0;i=1&&(this.easingTime=0,this._redraw=null!=this.lockedOnNodeId?this._lockedRedraw:this._classicRedraw,this.emit("animationFinished"))},s.prototype._classicRedraw=function(){},s.prototype.isActive=function(){return!this.activator||this.activator.active},s.prototype.setScale=function(){return this._setScale()},s.prototype.getScale=function(){return this._getScale()},s.prototype.getCenterCoordinates=function(){return this.DOMtoCanvas({x:.5*this.frame.canvas.clientWidth,y:.5*this.frame.canvas.clientHeight})},s.prototype.getBoundingBox=function(t){return void 0!==this.nodes[t]?this.nodes[t].boundingBox:void 0},t.exports=s},function(t,e,i){function s(t,e,i){if(!e)throw"No network provided";var s=["edges","physics"],n=o.selectiveBridgeObject(s,i);this.options=n.edges,this.physics=n.physics,this.options.smoothCurves=i.smoothCurves,this.network=e,this.id=void 0,this.fromId=void 0,this.toId=void 0,this.title=void 0,this.widthSelected=this.options.width*this.options.widthSelectionMultiplier,this.value=void 0,this.selected=!1,this.hover=!1,this.labelDimensions={top:0,left:0,width:0,height:0,yLine:0},this.dirtyLabel=!0,this.from=null,this.to=null,this.via=null,this.fromBackup=null,this.toBackup=null,this.originalFromId=[],this.originalToId=[],this.connected=!1,this.widthFixed=!1,this.lengthFixed=!1,this.setProperties(t),this.controlNodesEnabled=!1,this.controlNodes={from:null,to:null,positions:{}},this.connectedNode=null}var o=i(1),n=i(53);s.prototype.setProperties=function(t){if(t){var e=["style","fontSize","fontFace","fontColor","fontFill","fontStrokeWidth","fontStrokeColor","width","widthSelectionMultiplier","hoverWidth","arrowScaleFactor","dash","inheritColor","labelAlignment"];switch(o.selectiveDeepExtend(e,this.options,t),void 0!==t.from&&(this.fromId=t.from),void 0!==t.to&&(this.toId=t.to),void 0!==t.id&&(this.id=t.id),void 0!==t.label&&(this.label=t.label,this.dirtyLabel=!0),void 0!==t.title&&(this.title=t.title),void 0!==t.value&&(this.value=t.value),void 0!==t.length&&(this.physics.springLength=t.length),void 0!==t.color&&(this.options.inheritColor=!1,o.isString(t.color)?(this.options.color.color=t.color,this.options.color.highlight=t.color):(void 0!==t.color.color&&(this.options.color.color=t.color.color),void 0!==t.color.highlight&&(this.options.color.highlight=t.color.highlight),void 0!==t.color.hover&&(this.options.color.hover=t.color.hover))),this.connect(),this.widthFixed=this.widthFixed||void 0!==t.width,this.lengthFixed=this.lengthFixed||void 0!==t.length,this.widthSelected=this.options.width*this.options.widthSelectionMultiplier,this.options.style){case"line":this.draw=this._drawLine;break;case"arrow":this.draw=this._drawArrow;break;case"arrow-center":this.draw=this._drawArrowCenter;break;case"dash-line":this.draw=this._drawDashLine;break;default:this.draw=this._drawLine}}},s.prototype.connect=function(){this.disconnect(),this.from=this.network.nodes[this.fromId]||null,this.to=this.network.nodes[this.toId]||null,this.connected=this.from&&this.to,this.connected?(this.from.attachEdge(this),this.to.attachEdge(this)):(this.from&&this.from.detachEdge(this),this.to&&this.to.detachEdge(this))},s.prototype.disconnect=function(){this.from&&(this.from.detachEdge(this),this.from=null),this.to&&(this.to.detachEdge(this),this.to=null),this.connected=!1},s.prototype.getTitle=function(){return"function"==typeof this.title?this.title():this.title},s.prototype.getValue=function(){return this.value},s.prototype.setValueRange=function(t,e){if(!this.widthFixed&&void 0!==this.value){var i=(this.options.widthMax-this.options.widthMin)/(e-t);this.options.width=(this.value-t)*i+this.options.widthMin,this.widthSelected=this.options.width*this.options.widthSelectionMultiplier}},s.prototype.draw=function(){throw"Method draw not initialized in edge"},s.prototype.isOverlappingWith=function(t){if(this.connected){var e=10,i=this.from.x,s=this.from.y,o=this.to.x,n=this.to.y,r=t.left,a=t.top,h=this._getDistanceToEdge(i,s,o,n,r,a);return e>h}return!1},s.prototype._getColor=function(){var t=this.options.color;return"to"==this.options.inheritColor?t={highlight:this.to.options.color.highlight.border,hover:this.to.options.color.hover.border,color:this.to.options.color.border}:("from"==this.options.inheritColor||1==this.options.inheritColor)&&(t={highlight:this.from.options.color.highlight.border,hover:this.from.options.color.hover.border,color:this.from.options.color.border}),1==this.selected?t.highlight:1==this.hover?t.hover:t.color},s.prototype._drawLine=function(t){if(t.strokeStyle=this._getColor(),t.lineWidth=this._getLineWidth(),this.from!=this.to){var e,i=this._line(t);if(this.label){if(1==this.options.smoothCurves.enabled&&null!=i){var s=.5*(.5*(this.from.x+i.x)+.5*(this.to.x+i.x)),o=.5*(.5*(this.from.y+i.y)+.5*(this.to.y+i.y));e={x:s,y:o}}else e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}}else{var n,r,a=this.physics.springLength/4,h=this.from;h.width||h.resize(t),h.width>h.height?(n=h.x+h.width/2,r=h.y-a):(n=h.x+a,r=h.y-h.height/2),this._circle(t,n,r,a),e=this._pointOnCircle(n,r,a,.5),this._label(t,this.label,e.x,e.y)}},s.prototype._getLineWidth=function(){return 1==this.selected?Math.max(Math.min(this.widthSelected,this.options.widthMax),.3*this.networkScaleInv):1==this.hover?Math.max(Math.min(this.options.hoverWidth,this.options.widthMax),.3*this.networkScaleInv):Math.max(this.options.width,.3*this.networkScaleInv)},s.prototype._getViaCoordinates=function(){if(1==this.options.smoothCurves.dynamic&&1==this.options.smoothCurves.enabled)return this.via;if(0==this.options.smoothCurves.enabled)return{x:0,y:0};var t=null,e=null,i=this.options.smoothCurves.roundness,s=this.options.smoothCurves.type,o=Math.abs(this.from.x-this.to.x),n=Math.abs(this.from.y-this.to.y);return"discrete"==s||"diagonalCross"==s?Math.abs(this.from.x-this.to.x)this.to.y?this.from.xthis.to.x&&(t=this.from.x-i*n,e=this.from.y-i*n):this.from.ythis.to.x&&(t=this.from.x-i*n,e=this.from.y+i*n)),"discrete"==s&&(t=i*n>o?this.from.x:t)):Math.abs(this.from.x-this.to.x)>Math.abs(this.from.y-this.to.y)&&(this.from.y>this.to.y?this.from.xthis.to.x&&(t=this.from.x-i*o,e=this.from.y-i*o):this.from.ythis.to.x&&(t=this.from.x-i*o,e=this.from.y+i*o)),"discrete"==s&&(e=i*o>n?this.from.y:e)):"straightCross"==s?Math.abs(this.from.x-this.to.x)Math.abs(this.from.y-this.to.y)&&(t=this.from.xthis.to.y?this.from.xthis.to.x&&(t=this.from.x-i*n,e=this.from.y-i*n,t=this.to.x>t?this.to.x:t):this.from.ythis.to.x&&(t=this.from.x-i*n,e=this.from.y+i*n,t=this.to.x>t?this.to.x:t)):Math.abs(this.from.x-this.to.x)>Math.abs(this.from.y-this.to.y)&&(this.from.y>this.to.y?this.from.xe?this.to.y:e):this.from.x>this.to.x&&(t=this.from.x-i*o,e=this.from.y-i*o,e=this.to.y>e?this.to.y:e):this.from.ythis.to.x&&(t=this.from.x-i*o,e=this.from.y+i*o,e=this.to.yd;d++){var l=t.measureText(n[d]).width;h=l>h?l:h}var c=this.options.fontSize*r,p=i-h/2,u=s-c/2;this.labelDimensions={top:u,left:p,width:h,height:c,yLine:o}}var o=this.labelDimensions.yLine;t.save(),"horizontal"!=this.options.labelAlignment&&(t.translate(i,o),this._rotateForLabelAlignment(t),i=0,o=0),this._drawLabelRect(t),this._drawLabelText(t,i,o,n,r,a),t.restore()}},s.prototype._rotateForLabelAlignment=function(t){var e=this.from.y-this.to.y,i=this.from.x-this.to.x,s=Math.atan2(e,i);(-1>s&&0>i||s>0&&0>i)&&(s+=Math.PI),t.rotate(s)},s.prototype._drawLabelRect=function(t){if(void 0!==this.options.fontFill&&null!==this.options.fontFill&&"none"!==this.options.fontFill){t.fillStyle=this.options.fontFill;var e=2;"line-center"==this.options.labelAlignment?t.fillRect(.5*-this.labelDimensions.width,.5*-this.labelDimensions.height,this.labelDimensions.width,this.labelDimensions.height):"line-above"==this.options.labelAlignment?t.fillRect(.5*-this.labelDimensions.width,-(this.labelDimensions.height+e),this.labelDimensions.width,this.labelDimensions.height):"line-below"==this.options.labelAlignment?t.fillRect(.5*-this.labelDimensions.width,e,this.labelDimensions.width,this.labelDimensions.height):t.fillRect(this.labelDimensions.left,this.labelDimensions.top,this.labelDimensions.width,this.labelDimensions.height)}},s.prototype._drawLabelText=function(t,e,i,s,o,n){if(t.fillStyle=this.options.fontColor||"black",t.textAlign="center","horizontal"!=this.options.labelAlignment){var r=2;"line-above"==this.options.labelAlignment?(t.textBaseline="alphabetic",i-=2*r):"line-below"==this.options.labelAlignment?(t.textBaseline="hanging",i+=2*r):t.textBaseline="middle"}else t.textBaseline="middle";this.options.fontStrokeWidth>0&&(t.lineWidth=this.options.fontStrokeWidth,t.strokeStyle=this.options.fontStrokeColor,t.lineJoin="round");for(var a=0;o>a;a++)this.options.fontStrokeWidth>0&&t.strokeText(s[a],e,i),t.fillText(s[a],e,i),i+=n},s.prototype._drawDashLine=function(t){t.strokeStyle=this._getColor(),t.lineWidth=this._getLineWidth();var e=null;if(void 0!==t.setLineDash){t.save();var i=[0];i=void 0!==this.options.dash.length&&void 0!==this.options.dash.gap?[this.options.dash.length,this.options.dash.gap]:[5,5],t.setLineDash(i),t.lineDashOffset=0,e=this._line(t),t.setLineDash([0]),t.lineDashOffset=0,t.restore()}else t.beginPath(),t.lineCap="round",void 0!==this.options.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.options.dash.length,this.options.dash.gap,this.options.dash.altLength,this.options.dash.gap]):void 0!==this.options.dash.length&&void 0!==this.options.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.options.dash.length,this.options.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke();if(this.label){var s;if(1==this.options.smoothCurves.enabled&&null!=e){var o=.5*(.5*(this.from.x+e.x)+.5*(this.to.x+e.x)),n=.5*(.5*(this.from.y+e.y)+.5*(this.to.y+e.y));s={x:o,y:n}}else s=this._pointOnLine(.5);this._label(t,this.label,s.x,s.y)}},s.prototype._pointOnLine=function(t){return{x:(1-t)*this.from.x+t*this.to.x,y:(1-t)*this.from.y+t*this.to.y}},s.prototype._pointOnCircle=function(t,e,i,s){var o=2*(s-3/8)*Math.PI;return{x:t+i*Math.cos(o),y:e-i*Math.sin(o)}},s.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this._getColor(),t.fillStyle=t.strokeStyle,t.lineWidth=this._getLineWidth(),this.from!=this.to){var i=this._line(t),s=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),o=(10+5*this.options.width)*this.options.arrowScaleFactor;if(1==this.options.smoothCurves.enabled&&null!=i){var n=.5*(.5*(this.from.x+i.x)+.5*(this.to.x+i.x)),r=.5*(.5*(this.from.y+i.y)+.5*(this.to.y+i.y));e={x:n,y:r}}else e=this._pointOnLine(.5);t.arrow(e.x,e.y,s,o),t.fill(),t.stroke(),this.label&&this._label(t,this.label,e.x,e.y)}else{var a,h,d=.25*Math.max(100,this.physics.springLength),l=this.from;l.width||l.resize(t),l.width>l.height?(a=l.x+.5*l.width,h=l.y-d):(a=l.x+d,h=l.y-.5*l.height),this._circle(t,a,h,d);var s=.2*Math.PI,o=(10+5*this.options.width)*this.options.arrowScaleFactor;e=this._pointOnCircle(a,h,d,.5),t.arrow(e.x,e.y,s,o),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(a,h,d,.5),this._label(t,this.label,e.x,e.y))}},s.prototype._pointOnBezier=function(t){var e=this._getViaCoordinates(),i=Math.pow(1-t,2)*this.from.x+2*t*(1-t)*e.x+Math.pow(t,2)*this.to.x,s=Math.pow(1-t,2)*this.from.y+2*t*(1-t)*e.y+Math.pow(t,2)*this.to.y;return{x:i,y:s}},s.prototype._findBorderPosition=function(t,e){var i,s,o,n,r,a=10,h=0,d=0,l=1,c=.2,p=this.to;for(1==t&&(p=this.from);l>=d&&a>h;){var u=.5*(d+l);if(i=this._pointOnBezier(u),s=Math.atan2(p.y-i.y,p.x-i.x),o=p.distanceToBorder(e,s),n=Math.sqrt(Math.pow(i.x-p.x,2)+Math.pow(i.y-p.y,2)),r=o-n,Math.abs(r)r?0==t?d=u:l=u:0==t?l=u:d=u,h++}return i.t=u,i},s.prototype._drawArrow=function(t){t.strokeStyle=this._getColor(),t.fillStyle=t.strokeStyle,t.lineWidth=this._getLineWidth();var e,i,s;if(this.from!=this.to){if(this._line(t),1==this.options.smoothCurves.enabled){var o=this._getViaCoordinates();s=this._findBorderPosition(!1,t);var n=this._pointOnBezier(Math.max(0,s.t-.1));e=Math.atan2(s.y-n.y,s.x-n.x)}else{e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var r=this.to.x-this.from.x,a=this.to.y-this.from.y,h=Math.sqrt(r*r+a*a),d=this.to.distanceToBorder(t,e),l=(h-d)/h;s={},s.x=(1-l)*this.from.x+l*this.to.x,s.y=(1-l)*this.from.y+l*this.to.y}if(i=(10+5*this.options.width)*this.options.arrowScaleFactor,t.arrow(s.x,s.y,e,i),t.fill(),t.stroke(),this.label){var c;c=1==this.options.smoothCurves.enabled&&null!=o?this._pointOnBezier(.5):this._pointOnLine(.5),this._label(t,this.label,c.x,c.y)}}else{var p,u,m,f=this.from,g=.25*Math.max(100,this.physics.springLength);f.width||f.resize(t),f.width>f.height?(p=f.x+.5*f.width,u=f.y-g,m={x:p,y:f.y,angle:.9*Math.PI}):(p=f.x+g,u=f.y-.5*f.height,m={x:f.x,y:u,angle:.6*Math.PI}),t.beginPath(),t.arc(p,u,g,0,2*Math.PI,!1),t.stroke();var i=(10+5*this.options.width)*this.options.arrowScaleFactor;t.arrow(m.x,m.y,m.angle,i),t.fill(),t.stroke(),this.label&&(c=this._pointOnCircle(p,u,g,.5),this._label(t,this.label,c.x,c.y))}},s.prototype._getDistanceToEdge=function(t,e,i,s,o,n){var r=0;if(this.from!=this.to)if(1==this.options.smoothCurves.enabled){var a,h;if(1==this.options.smoothCurves.enabled&&1==this.options.smoothCurves.dynamic)a=this.via.x,h=this.via.y;else{var d=this._getViaCoordinates();a=d.x,h=d.y}var l,c,p,u,m,f,g,v=1e9;for(c=0;10>c;c++)p=.1*c,u=Math.pow(1-p,2)*t+2*p*(1-p)*a+Math.pow(p,2)*i,m=Math.pow(1-p,2)*e+2*p*(1-p)*h+Math.pow(p,2)*s,c>0&&(l=this._getDistanceToLine(f,g,u,m,o,n),v=v>l?l:v),f=u,g=m;r=v}else r=this._getDistanceToLine(t,e,i,s,o,n);else{var u,m,y,b,_=.25*this.physics.springLength,x=this.from;x.width>x.height?(u=x.x+.5*x.width,m=x.y-_):(u=x.x+_,m=x.y-.5*x.height),y=u-o,b=m-n,r=Math.abs(Math.sqrt(y*y+b*b)-_)}return this.labelDimensions.lefto&&this.labelDimensions.topn?0:r},s.prototype._getDistanceToLine=function(t,e,i,s,o,n){var r=i-t,a=s-e,h=r*r+a*a,d=((o-t)*r+(n-e)*a)/h;d>1?d=1:0>d&&(d=0);var l=t+d*r,c=e+d*a,p=l-o,u=c-n;return Math.sqrt(p*p+u*u)},s.prototype.setScale=function(t){this.networkScaleInv=1/t},s.prototype.select=function(){this.selected=!0},s.prototype.unselect=function(){this.selected=!1},s.prototype.positionBezierNode=function(){null!==this.via&&null!==this.from&&null!==this.to?(this.via.x=.5*(this.from.x+this.to.x),this.via.y=.5*(this.from.y+this.to.y)):null!==this.via&&(this.via.x=0,this.via.y=0)},s.prototype._drawControlNodes=function(t){if(1==this.controlNodesEnabled){if(null===this.controlNodes.from&&null===this.controlNodes.to){var e="edgeIdFrom:".concat(this.id),i="edgeIdTo:".concat(this.id),s={nodes:{group:"",radius:7,borderWidth:2,borderWidthSelected:2},physics:{damping:0},clustering:{maxNodeSizeIncrements:0,nodeScaling:{width:0,height:0,radius:0}}};this.controlNodes.from=new n({id:e,shape:"dot",color:{background:"#ff0000",border:"#3c3c3c",highlight:{background:"#07f968"}}},{},{},s),this.controlNodes.to=new n({id:i,shape:"dot",color:{background:"#ff0000",border:"#3c3c3c",highlight:{background:"#07f968"}}},{},{},s)}this.controlNodes.positions={},0==this.controlNodes.from.selected&&(this.controlNodes.positions.from=this.getControlNodeFromPosition(t),this.controlNodes.from.x=this.controlNodes.positions.from.x,this.controlNodes.from.y=this.controlNodes.positions.from.y),0==this.controlNodes.to.selected&&(this.controlNodes.positions.to=this.getControlNodeToPosition(t),this.controlNodes.to.x=this.controlNodes.positions.to.x,this.controlNodes.to.y=this.controlNodes.positions.to.y),this.controlNodes.from.draw(t),this.controlNodes.to.draw(t)}else this.controlNodes={from:null,to:null,positions:{}}},s.prototype._enableControlNodes=function(){this.fromBackup=this.from,this.toBackup=this.to,this.controlNodesEnabled=!0},s.prototype._disableControlNodes=function(){this.fromId=this.from.id,this.toId=this.to.id,this.fromId!=this.fromBackup.id?this.fromBackup.detachEdge(this):this.toId!=this.toBackup.id&&this.toBackup.detachEdge(this),this.fromBackup=null,this.toBackup=null,this.controlNodesEnabled=!1},s.prototype._getSelectedControlNode=function(t,e){var i=this.controlNodes.positions,s=Math.sqrt(Math.pow(t-i.from.x,2)+Math.pow(e-i.from.y,2)),o=Math.sqrt(Math.pow(t-i.to.x,2)+Math.pow(e-i.to.y,2));return 15>s?(this.connectedNode=this.from,this.from=this.controlNodes.from,this.controlNodes.from):15>o?(this.connectedNode=this.to,this.to=this.controlNodes.to,this.controlNodes.to):null},s.prototype._restoreControlNodes=function(){1==this.controlNodes.from.selected?(this.from=this.connectedNode,this.connectedNode=null,this.controlNodes.from.unselect()):1==this.controlNodes.to.selected&&(this.to=this.connectedNode,this.connectedNode=null,this.controlNodes.to.unselect())},s.prototype.getControlNodeFromPosition=function(t){var e;if(1==this.options.smoothCurves.enabled)e=this._findBorderPosition(!0,t);else{var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),s=this.to.x-this.from.x,o=this.to.y-this.from.y,n=Math.sqrt(s*s+o*o),r=this.from.distanceToBorder(t,i+Math.PI),a=(n-r)/n;e={},e.x=a*this.from.x+(1-a)*this.to.x,e.y=a*this.from.y+(1-a)*this.to.y}return e},s.prototype.getControlNodeToPosition=function(t){var e;if(1==this.options.smoothCurves.enabled)e=this._findBorderPosition(!1,t);else{var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),s=this.to.x-this.from.x,o=this.to.y-this.from.y,n=Math.sqrt(s*s+o*o),r=this.to.distanceToBorder(t,i),a=(n-r)/n;e={},e.x=(1-a)*this.from.x+a*this.to.x,e.y=(1-a)*this.from.y+a*this.to.y}return e},t.exports=s},function(t,e,i){function s(t,e,i,s){var n=o.selectiveBridgeObject(["nodes"],s);this.options=n.nodes,this.selected=!1,this.hover=!1,this.edges=[],this.dynamicEdges=[],this.reroutedEdges={},this.fontDrawThreshold=3,this.id=void 0,this.allowedToMoveX=!1,this.allowedToMoveY=!1,this.xFixed=!1,this.yFixed=!1,this.horizontalAlignLeft=!0,this.verticalAlignTop=!0,this.baseRadiusValue=s.nodes.radius,this.radiusFixed=!1,this.level=-1,this.preassignedLevel=!1,this.hierarchyEnumerated=!1,this.labelDimensions={top:0,left:0,width:0,height:0,yLine:0},this.boundingBox={top:0,left:0,right:0,bottom:0},this.imagelist=e,this.grouplist=i,this.fx=0,this.fy=0,this.vx=0,this.vy=0,this.x=null,this.y=null,this.previousState={vx:0,vy:0,x:0,y:0},this.damping=s.physics.damping,this.fixedData={x:null,y:null},this.setProperties(t,n),this.resetCluster(),this.dynamicEdgesLength=0,this.clusterSession=0,this.clusterSizeWidthFactor=s.clustering.nodeScaling.width,this.clusterSizeHeightFactor=s.clustering.nodeScaling.height,this.clusterSizeRadiusFactor=s.clustering.nodeScaling.radius,this.maxNodeSizeIncrements=s.clustering.maxNodeSizeIncrements,this.growthIndicator=0,this.networkScaleInv=1,this.networkScale=1,this.canvasTopLeft={x:-300,y:-300},this.canvasBottomRight={x:300,y:300},this.parentEdgeId=null}var o=i(1);s.prototype.revertPosition=function(){this.x=this.previousState.x,this.y=this.previousState.y,this.vx=this.previousState.vx,this.vy=this.previousState.vy},s.prototype.resetCluster=function(){this.formationScale=void 0,this.clusterSize=1,this.containedNodes={},this.containedEdges={},this.clusterSessions=[]},s.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),-1==this.dynamicEdges.indexOf(t)&&this.dynamicEdges.push(t),this.dynamicEdgesLength=this.dynamicEdges.length},s.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&this.edges.splice(e,1),e=this.dynamicEdges.indexOf(t),-1!=e&&this.dynamicEdges.splice(e,1),this.dynamicEdgesLength=this.dynamicEdges.length},s.prototype.setProperties=function(t,e){if(t){var i=["borderWidth","borderWidthSelected","shape","image","brokenImage","radius","fontColor","fontSize","fontFace","fontFill","fontStrokeWidth","fontStrokeColor","group","mass"];if(o.selectiveDeepExtend(i,this.options,t),void 0!==t.id&&(this.id=t.id),void 0!==t.label&&(this.label=t.label,this.originalLabel=t.label),void 0!==t.title&&(this.title=t.title),void 0!==t.x&&(this.x=t.x),void 0!==t.y&&(this.y=t.y),void 0!==t.value&&(this.value=t.value),void 0!==t.level&&(this.level=t.level,this.preassignedLevel=!0),void 0!==t.horizontalAlignLeft&&(this.horizontalAlignLeft=t.horizontalAlignLeft),void 0!==t.verticalAlignTop&&(this.verticalAlignTop=t.verticalAlignTop),void 0!==t.triggerFunction&&(this.triggerFunction=t.triggerFunction),void 0===this.id)throw"Node must have an id";if("number"==typeof this.options.group||"string"==typeof this.options.group&&""!=this.options.group){var s=this.grouplist.get(this.options.group);o.deepExtend(this.options,s),this.options.color=o.parseColor(this.options.color)}if(void 0!==t.radius&&(this.baseRadiusValue=this.options.radius),void 0!==t.color&&(this.options.color=o.parseColor(t.color)),void 0!==this.options.image&&""!=this.options.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.options.image,this.options.brokenImage)}switch(void 0!==t.allowedToMoveX?(this.xFixed=!t.allowedToMoveX,this.allowedToMoveX=t.allowedToMoveX):void 0!==t.x&&0==this.allowedToMoveX&&(this.xFixed=!0),void 0!==t.allowedToMoveY?(this.yFixed=!t.allowedToMoveY,this.allowedToMoveY=t.allowedToMoveY):void 0!==t.y&&0==this.allowedToMoveY&&(this.yFixed=!0),this.radiusFixed=this.radiusFixed||void 0!==t.radius,("image"===this.options.shape||"circularImage"===this.options.shape)&&(this.options.radiusMin=e.nodes.widthMin,this.options.radiusMax=e.nodes.widthMax),this.options.shape){case"database":this.draw=this._drawDatabase,this.resize=this._resizeDatabase;break;case"box":this.draw=this._drawBox,this.resize=this._resizeBox;break;case"circle":this.draw=this._drawCircle,this.resize=this._resizeCircle;break;case"ellipse":this.draw=this._drawEllipse,this.resize=this._resizeEllipse;break;case"image":this.draw=this._drawImage,this.resize=this._resizeImage;break;case"circularImage":this.draw=this._drawCircularImage,this.resize=this._resizeCircularImage;break;case"text":this.draw=this._drawText,this.resize=this._resizeText;break;case"dot":this.draw=this._drawDot,this.resize=this._resizeShape;break;case"square":this.draw=this._drawSquare,this.resize=this._resizeShape;break;case"triangle":this.draw=this._drawTriangle,this.resize=this._resizeShape;break;case"triangleDown":this.draw=this._drawTriangleDown,this.resize=this._resizeShape;break;case"star":this.draw=this._drawStar,this.resize=this._resizeShape;break;default:this.draw=this._drawEllipse,this.resize=this._resizeEllipse}this._reset()}},s.prototype.select=function(){this.selected=!0,this._reset()},s.prototype.unselect=function(){this.selected=!1,this._reset()},s.prototype.clearSizeCache=function(){this._reset()},s.prototype._reset=function(){this.width=void 0,this.height=void 0},s.prototype.getTitle=function(){return"function"==typeof this.title?this.title():this.title},s.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.options.shape){case"circle":case"dot":return this.options.radius+i;case"ellipse":var s=this.width/2,o=this.height/2,n=Math.sin(e)*s,r=Math.cos(e)*o;return s*o/Math.sqrt(n*n+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},s.prototype._setForce=function(t,e){this.fx=t,this.fy=e},s.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},s.prototype.storeState=function(){this.previousState.x=this.x,this.previousState.y=this.y,this.previousState.vx=this.vx,this.previousState.vy=this.vy},s.prototype.discreteStep=function(t){if(this.storeState(),this.xFixed)this.fx=0,this.vx=0;else{var e=this.damping*this.vx,i=(this.fx-e)/this.options.mass;this.vx+=i*t,this.x+=this.vx*t}if(this.yFixed)this.fy=0,this.vy=0;else{var s=this.damping*this.vy,o=(this.fy-s)/this.options.mass;this.vy+=o*t,this.y+=this.vy*t}},s.prototype.discreteStepLimited=function(t,e){if(this.storeState(),this.xFixed)this.fx=0,this.vx=0;else{var i=this.damping*this.vx,s=(this.fx-i)/this.options.mass;this.vx+=s*t,this.vx=Math.abs(this.vx)>e?this.vx>0?e:-e:this.vx,this.x+=this.vx*t}if(this.yFixed)this.fy=0,this.vy=0;else{var o=this.damping*this.vy,n=(this.fy-o)/this.options.mass;this.vy+=n*t,this.vy=Math.abs(this.vy)>e?this.vy>0?e:-e:this.vy,this.y+=this.vy*t +}},s.prototype.isFixed=function(){return this.xFixed&&this.yFixed},s.prototype.isMoving=function(t){var e=Math.sqrt(Math.pow(this.vx,2)+Math.pow(this.vy,2));return e>t},s.prototype.isSelected=function(){return this.selected},s.prototype.getValue=function(){return this.value},s.prototype.getDistance=function(t,e){var i=this.x-t,s=this.y-e;return Math.sqrt(i*i+s*s)},s.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value)if(e==t)this.options.radius=(this.options.radiusMin+this.options.radiusMax)/2;else{var i=(this.options.radiusMax-this.options.radiusMin)/(e-t);this.options.radius=(this.value-t)*i+this.options.radiusMin}this.baseRadiusValue=this.options.radius},s.prototype.draw=function(){throw"Draw method not initialized for node"},s.prototype.resize=function(){throw"Resize method not initialized for node"},s.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},s.prototype._resizeImage=function(){if(!this.width||!this.height){var t,e;if(this.value){this.options.radius=this.baseRadiusValue;var i=this.imageObj.height/this.imageObj.width;void 0!==i?(t=this.options.radius||this.imageObj.width,e=this.options.radius*i||this.imageObj.height):(t=0,e=0)}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e,this.growthIndicator=0,this.width>0&&this.height>0&&(this.width+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeWidthFactor,this.height+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeHeightFactor,this.options.radius+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-t)}},s.prototype._drawImageAtPosition=function(t){if(0!=this.imageObj.width){if(this.clusterSize>1){var e=this.clusterSize>1?10:0;e*=this.networkScaleInv,e=Math.min(.2*this.width,e),t.globalAlpha=.5,t.drawImage(this.imageObj,this.left-e,this.top-e,this.width+2*e,this.height+2*e)}t.globalAlpha=1,t.drawImage(this.imageObj,this.left,this.top,this.width,this.height)}},s.prototype._drawImageLabel=function(t){var e,i=0;if(this.height){i=this.height/2;var s=this.getTextSize(t);s.lineCount>=1&&(i+=s.height/2,i+=3)}e=this.y+i,this._label(t,this.label,this.x,e,void 0)},s.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._drawImageAtPosition(t),this.boundingBox.top=this.top,this.boundingBox.left=this.left,this.boundingBox.right=this.left+this.width,this.boundingBox.bottom=this.top+this.height,this._drawImageLabel(t),this.boundingBox.left=Math.min(this.boundingBox.left,this.labelDimensions.left),this.boundingBox.right=Math.max(this.boundingBox.right,this.labelDimensions.left+this.labelDimensions.width),this.boundingBox.bottom=Math.max(this.boundingBox.bottom,this.boundingBox.bottom+this.labelDimensions.height)},s.prototype._resizeCircularImage=function(t){if(this.imageObj.src&&this.imageObj.width&&this.imageObj.height)this._swapToImageResizeWhenImageLoaded&&(this.width=0,this.height=0,delete this._swapToImageResizeWhenImageLoaded),this._resizeImage(t);else if(!this.width){var e=2*this.options.radius;this.width=e,this.height=e,this.options.radius+=.5*Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.options.radius-.5*e,this._swapToImageResizeWhenImageLoaded=!0}},s.prototype._drawCircularImage=function(t){this._resizeCircularImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=this.left+this.width/2,i=this.top+this.height/2,s=Math.abs(this.height/2);this._drawRawCircle(t,e,i,s),t.save(),t.circle(this.x,this.y,s),t.stroke(),t.clip(),this._drawImageAtPosition(t),t.restore(),this.boundingBox.top=this.y-this.options.radius,this.boundingBox.left=this.x-this.options.radius,this.boundingBox.right=this.x+this.options.radius,this.boundingBox.bottom=this.y+this.options.radius,this._drawImageLabel(t),this.boundingBox.left=Math.min(this.boundingBox.left,this.labelDimensions.left),this.boundingBox.right=Math.max(this.boundingBox.right,this.labelDimensions.left+this.labelDimensions.width),this.boundingBox.bottom=Math.max(this.boundingBox.bottom,this.boundingBox.bottom+this.labelDimensions.height)},s.prototype._resizeBox=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=.5*Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeWidthFactor,this.height+=.5*Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeHeightFactor,this.growthIndicator=this.width-(i.width+2*e)}},s.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=this.options.borderWidth,s=this.options.borderWidthSelected||2*this.options.borderWidth;t.strokeStyle=this.selected?this.options.color.highlight.border:this.hover?this.options.color.hover.border:this.options.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.roundRect(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth,this.options.radius),t.stroke()),t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.fillStyle=this.selected?this.options.color.highlight.background:this.hover?this.options.color.hover.background:this.options.color.background,t.roundRect(this.left,this.top,this.width,this.height,this.options.radius),t.fill(),t.stroke(),this.boundingBox.top=this.top,this.boundingBox.left=this.left,this.boundingBox.right=this.left+this.width,this.boundingBox.bottom=this.top+this.height,this._label(t,this.label,this.x,this.y)},s.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),s=i.width+2*e;this.width=s,this.height=s,this.width+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeWidthFactor,this.height+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeHeightFactor,this.options.radius+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-s}},s.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=this.options.borderWidth,s=this.options.borderWidthSelected||2*this.options.borderWidth;t.strokeStyle=this.selected?this.options.color.highlight.border:this.hover?this.options.color.hover.border:this.options.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.database(this.x-this.width/2-2*t.lineWidth,this.y-.5*this.height-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.fillStyle=this.selected?this.options.color.highlight.background:this.hover?this.options.color.hover.background:this.options.color.background,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this.boundingBox.top=this.top,this.boundingBox.left=this.left,this.boundingBox.right=this.left+this.width,this.boundingBox.bottom=this.top+this.height,this._label(t,this.label,this.x,this.y)},s.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),s=Math.max(i.width,i.height)+2*e;this.options.radius=s/2,this.width=s,this.height=s,this.options.radius+=.5*Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.options.radius-.5*s}},s.prototype._drawRawCircle=function(t,e,i,s){var o=2.5,n=this.options.borderWidth,r=this.options.borderWidthSelected||2*this.options.borderWidth;t.strokeStyle=this.selected?this.options.color.highlight.border:this.hover?this.options.color.hover.border:this.options.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?r:n)+(this.clusterSize>1?o:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.circle(e,i,s+2*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?r:n)+(this.clusterSize>1?o:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.fillStyle=this.selected?this.options.color.highlight.background:this.hover?this.options.color.hover.background:this.options.color.background,t.circle(this.x,this.y,s),t.fill(),t.stroke()},s.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._drawRawCircle(t,this.x,this.y,this.options.radius),this.boundingBox.top=this.y-this.options.radius,this.boundingBox.left=this.x-this.options.radius,this.boundingBox.right=this.x+this.options.radius,this.boundingBox.bottom=this.y+this.options.radius,this._label(t,this.label,this.x,this.y)},s.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.width1&&(t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.ellipse(this.left-2*t.lineWidth,this.top-2*t.lineWidth,this.width+4*t.lineWidth,this.height+4*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?s:i)+(this.clusterSize>1?e:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.fillStyle=this.selected?this.options.color.highlight.background:this.hover?this.options.color.hover.background:this.options.color.background,t.ellipse(this.left,this.top,this.width,this.height),t.fill(),t.stroke(),this.boundingBox.top=this.top,this.boundingBox.left=this.left,this.boundingBox.right=this.left+this.width,this.boundingBox.bottom=this.top+this.height,this._label(t,this.label,this.x,this.y)},s.prototype._drawDot=function(t){this._drawShape(t,"circle")},s.prototype._drawTriangle=function(t){this._drawShape(t,"triangle")},s.prototype._drawTriangleDown=function(t){this._drawShape(t,"triangleDown")},s.prototype._drawSquare=function(t){this._drawShape(t,"square")},s.prototype._drawStar=function(t){this._drawShape(t,"star")},s.prototype._resizeShape=function(){if(!this.width){this.options.radius=this.baseRadiusValue;var t=2*this.options.radius;this.width=t,this.height=t,this.width+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeWidthFactor,this.height+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeHeightFactor,this.options.radius+=.5*Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-t}},s.prototype._drawShape=function(t,e){this._resizeShape(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var i=2.5,s=this.options.borderWidth,o=this.options.borderWidthSelected||2*this.options.borderWidth,n=2;switch(e){case"dot":n=2;break;case"square":n=2;break;case"triangle":n=3;break;case"triangleDown":n=3;break;case"star":n=4}t.strokeStyle=this.selected?this.options.color.highlight.border:this.hover?this.options.color.hover.border:this.options.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?o:s)+(this.clusterSize>1?i:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t[e](this.x,this.y,this.options.radius+n*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?o:s)+(this.clusterSize>1?i:0),t.lineWidth*=this.networkScaleInv,t.lineWidth=Math.min(this.width,t.lineWidth),t.fillStyle=this.selected?this.options.color.highlight.background:this.hover?this.options.color.hover.background:this.options.color.background,t[e](this.x,this.y,this.options.radius),t.fill(),t.stroke(),this.boundingBox.top=this.y-this.options.radius,this.boundingBox.left=this.x-this.options.radius,this.boundingBox.right=this.x+this.options.radius,this.boundingBox.bottom=this.y+this.options.radius,this.label&&(this._label(t,this.label,this.x,this.y+this.height/2,void 0,"hanging",!0),this.boundingBox.left=Math.min(this.boundingBox.left,this.labelDimensions.left),this.boundingBox.right=Math.max(this.boundingBox.right,this.labelDimensions.left+this.labelDimensions.width),this.boundingBox.bottom=Math.max(this.boundingBox.bottom,this.boundingBox.bottom+this.labelDimensions.height))},s.prototype._resizeText=function(t){if(!this.width){var e=5,i=this.getTextSize(t);this.width=i.width+2*e,this.height=i.height+2*e,this.width+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeWidthFactor,this.height+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeHeightFactor,this.options.radius+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-(i.width+2*e)}},s.prototype._drawText=function(t){this._resizeText(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,this._label(t,this.label,this.x,this.y),this.boundingBox.top=this.top,this.boundingBox.left=this.left,this.boundingBox.right=this.left+this.width,this.boundingBox.bottom=this.top+this.height},s.prototype._label=function(t,e,i,s,o,n,r){if(e&&Number(this.options.fontSize)*this.networkScale>this.fontDrawThreshold){t.font=(this.selected?"bold ":"")+this.options.fontSize+"px "+this.options.fontFace;var a=e.split("\n"),h=a.length,d=Number(this.options.fontSize),l=s+(1-h)/2*d;1==r&&(l=s+(1-h)/(2*d));for(var c=t.measureText(a[0]).width,p=1;h>p;p++){var u=t.measureText(a[p]).width;c=u>c?u:c}var m=this.options.fontSize*h,f=i-c/2,g=s-m/2;"hanging"==n&&(g+=.5*d,g+=4,l+=4),this.labelDimensions={top:g,left:f,width:c,height:m,yLine:l},void 0!==this.options.fontFill&&null!==this.options.fontFill&&"none"!==this.options.fontFill&&(t.fillStyle=this.options.fontFill,t.fillRect(f,g,c,m)),t.fillStyle=this.options.fontColor||"black",t.textAlign=o||"center",t.textBaseline=n||"middle",this.options.fontStrokeWidth>0&&(t.lineWidth=this.options.fontStrokeWidth,t.strokeStyle=this.options.fontStrokeColor,t.lineJoin="round");for(var p=0;h>p;p++)this.options.fontStrokeWidth&&t.strokeText(a[p],i,l),t.fillText(a[p],i,l),l+=d}},s.prototype.getTextSize=function(t){if(void 0!==this.label){t.font=(this.selected?"bold ":"")+this.options.fontSize+"px "+this.options.fontFace;for(var e=this.label.split("\n"),i=(Number(this.options.fontSize)+4)*e.length,s=0,o=0,n=e.length;n>o;o++)s=Math.max(s,t.measureText(e[o]).width);return{width:s,height:i,lineCount:e.length}}return{width:0,height:0,lineCount:0}},s.prototype.inArea=function(){return void 0!==this.width?this.x+this.width*this.networkScaleInv>=this.canvasTopLeft.x&&this.x-this.width*this.networkScaleInv=this.canvasTopLeft.y&&this.y-this.height*this.networkScaleInv=this.canvasTopLeft.x&&this.x=this.canvasTopLeft.y&&this.ys&&(n=s-e-this.padding),no&&(r=o-i-this.padding),ri;i++)if(e.id===r.nodes[i].id){o=r.nodes[i];break}for(o||(o={id:e.id},t.node&&(o.attr=a(o.attr,t.node))),i=n.length-1;i>=0;i--){var h=n[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(o)&&h.nodes.push(o)}e.attr&&(o.attr=a(o.attr,e.attr))}function l(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=a({},t.edge);e.attr=a(i,e.attr)}}function c(t,e,i,s,o){var n={from:e,to:i,type:s};return t.edge&&(n.attr=a({},t.edge)),n.attr=a(n.attr||{},o),n}function p(){for(N=D.NULL,k="";" "==E||" "==E||"\n"==E||"\r"==E;)o();do{var t=!1;if("#"==E){for(var e=O-1;" "==T.charAt(e)||" "==T.charAt(e);)e--;if("\n"==T.charAt(e)||""==T.charAt(e)){for(;""!=E&&"\n"!=E;)o();t=!0}}if("/"==E&&"/"==n()){for(;""!=E&&"\n"!=E;)o();t=!0}if("/"==E&&"*"==n()){for(;""!=E;){if("*"==E&&"/"==n()){o(),o();break}o()}t=!0}for(;" "==E||" "==E||"\n"==E||"\r"==E;)o()}while(t);if(""==E)return void(N=D.DELIMITER);var i=E+n();if(C[i])return N=D.DELIMITER,k=i,o(),void o();if(C[E])return N=D.DELIMITER,k=E,void o();if(r(E)||"-"==E){for(k+=E,o();r(E);)k+=E,o();return"false"==k?k=!1:"true"==k?k=!0:isNaN(Number(k))||(k=Number(k)),void(N=D.IDENTIFIER)}if('"'==E){for(o();""!=E&&('"'!=E||'"'==E&&'"'==n());)k+=E,'"'==E&&o(),o();if('"'!=E)throw x('End of string " expected');return o(),void(N=D.IDENTIFIER)}for(N=D.UNKNOWN;""!=E;)k+=E,o();throw new SyntaxError('Syntax error in part "'+w(k,30)+'"')}function u(){var t={};if(s(),p(),"strict"==k&&(t.strict=!0,p()),("graph"==k||"digraph"==k)&&(t.type=k,p()),N==D.IDENTIFIER&&(t.id=k,p()),"{"!=k)throw x("Angle bracket { expected");if(p(),m(t),"}"!=k)throw x("Angle bracket } expected");if(p(),""!==k)throw x("End of file expected");return p(),delete t.node,delete t.edge,delete t.graph,t}function m(t){for(;""!==k&&"}"!=k;)f(t),";"==k&&p()}function f(t){var e=g(t);if(e)return void b(t,e);var i=v(t);if(!i){if(N!=D.IDENTIFIER)throw x("Identifier expected");var s=k;if(p(),"="==k){if(p(),N!=D.IDENTIFIER)throw x("Identifier expected");t[s]=k,p()}else y(t,s)}}function g(t){var e=null;if("subgraph"==k&&(e={},e.type="subgraph",p(),N==D.IDENTIFIER&&(e.id=k,p())),"{"==k){if(p(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,m(e),"}"!=k)throw x("Angle bracket } expected");p(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function v(t){return"node"==k?(p(),t.node=_(),"node"):"edge"==k?(p(),t.edge=_(),"edge"):"graph"==k?(p(),t.graph=_(),"graph"):null}function y(t,e){var i={id:e},s=_();s&&(i.attr=s),d(t,i),b(t,e)}function b(t,e){for(;"->"==k||"--"==k;){var i,s=k;p();var o=g(t);if(o)i=o;else{if(N!=D.IDENTIFIER)throw x("Identifier or subgraph expected");i=k,d(t,{id:i}),p()}var n=_(),r=c(t,e,i,s,n);l(t,r),e=i}}function _(){for(var t=null;"["==k;){for(p(),t={};""!==k&&"]"!=k;){if(N!=D.IDENTIFIER)throw x("Attribute name expected");var e=k;if(p(),"="!=k)throw x("Equal sign = expected");if(p(),N!=D.IDENTIFIER)throw x("Attribute value expected");var i=k;h(t,e,i),p(),","==k&&p()}if("]"!=k)throw x("Bracket ] expected");p()}return t}function x(t){return new SyntaxError(t+', got "'+w(k,30)+'" (char '+O+")")}function w(t,e){return t.length<=e?t:t.substr(0,27)+"..."}function M(t,e,i){Array.isArray(t)?t.forEach(function(t){Array.isArray(e)?e.forEach(function(e){i(t,e)}):i(t,e)}):Array.isArray(e)?e.forEach(function(e){i(t,e)}):i(t,e)}function S(t){var e=i(t),s={nodes:[],edges:[],options:{}};if(e.nodes&&e.nodes.forEach(function(t){var e={id:t.id,label:String(t.label||t.id)};a(e,t.attr),e.image&&(e.shape="image"),s.nodes.push(e)}),e.edges){var o=function(t){var e={from:t.from,to:t.to};return a(e,t.attr),e.style="->"==t.type?"arrow":"line",e};e.edges.forEach(function(t){var e,i;e=t.from instanceof Object?t.from.nodes:{id:t.from},i=t.to instanceof Object?t.to.nodes:{id:t.to},t.from instanceof Object&&t.from.edges&&t.from.edges.forEach(function(t){var e=o(t);s.edges.push(e)}),M(e,i,function(e,i){var n=c(s,e.id,i.id,t.type,t.attr),r=o(n);s.edges.push(r)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=o(t);s.edges.push(e)})})}return e.attr&&(s.options=e.attr),s}var D={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},C={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},T="",O=0,E="",k="",N=D.NULL,L=/[a-zA-Z_0-9.:#]/;e.parseDOT=i,e.DOTToGraph=S},function(t,e){function i(t,e){var i=[],s=[];this.options={edges:{inheritColor:!0},nodes:{allowedToMove:!1,parseColor:!1}},void 0!==e&&(this.options.nodes.allowedToMove=e.allowedToMove|!1,this.options.nodes.parseColor=e.parseColor|!1,this.options.edges.inheritColor=e.inheritColor|!0);for(var o=t.edges,n=t.nodes,r=0;rthis.constants.clustering.clusterThreshold&&1==this.constants.clustering.enabled&&this.clusterToFit(this.constants.clustering.reduceToNodes,!1),this._calculateForces())},e._calculateForces=function(){this._calculateGravitationalForces(),this._calculateNodeForces(),this.constants.physics.springConstant>0&&(1==this.constants.smoothCurves.enabled&&1==this.constants.smoothCurves.dynamic?this._calculateSpringForcesWithSupport():1==this.constants.physics.hierarchicalRepulsion.enabled?this._calculateHierarchicalSpringForces():this._calculateSpringForces())},e._updateCalculationNodes=function(){if(1==this.constants.smoothCurves.enabled&&1==this.constants.smoothCurves.dynamic){this.calculationNodes={},this.calculationNodeIndices=[];for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&(this.calculationNodes[t]=this.nodes[t]);var e=this.sectors.support.nodes;for(var i in e)e.hasOwnProperty(i)&&(this.edges.hasOwnProperty(e[i].parentEdgeId)?this.calculationNodes[i]=e[i]:e[i]._setForce(0,0));for(var s in this.calculationNodes)this.calculationNodes.hasOwnProperty(s)&&this.calculationNodeIndices.push(s)}else this.calculationNodes=this.nodes,this.calculationNodeIndices=this.nodeIndices},e._calculateGravitationalForces=function(){var t,e,i,s,o,n=this.calculationNodes,r=this.constants.physics.centralGravity,a=0;for(o=0;oSimulation Mode:Barnes HutRepulsionHierarchical
Options:
',this.containerElement.parentElement.insertBefore(this.physicsConfiguration,this.containerElement),this.optionsDiv=document.createElement("div"),this.optionsDiv.style.fontSize="14px",this.optionsDiv.style.fontFamily="verdana",this.containerElement.parentElement.insertBefore(this.optionsDiv,this.containerElement);var e;e=document.getElementById("graph_BH_gc"),e.onchange=a.bind(this,"graph_BH_gc",-1,"physics_barnesHut_gravitationalConstant"),e=document.getElementById("graph_BH_cg"),e.onchange=a.bind(this,"graph_BH_cg",1,"physics_centralGravity"),e=document.getElementById("graph_BH_sc"),e.onchange=a.bind(this,"graph_BH_sc",1,"physics_springConstant"),e=document.getElementById("graph_BH_sl"),e.onchange=a.bind(this,"graph_BH_sl",1,"physics_springLength"),e=document.getElementById("graph_BH_damp"),e.onchange=a.bind(this,"graph_BH_damp",1,"physics_damping"),e=document.getElementById("graph_R_nd"),e.onchange=a.bind(this,"graph_R_nd",1,"physics_repulsion_nodeDistance"),e=document.getElementById("graph_R_cg"),e.onchange=a.bind(this,"graph_R_cg",1,"physics_centralGravity"),e=document.getElementById("graph_R_sc"),e.onchange=a.bind(this,"graph_R_sc",1,"physics_springConstant"),e=document.getElementById("graph_R_sl"),e.onchange=a.bind(this,"graph_R_sl",1,"physics_springLength"),e=document.getElementById("graph_R_damp"),e.onchange=a.bind(this,"graph_R_damp",1,"physics_damping"),e=document.getElementById("graph_H_nd"),e.onchange=a.bind(this,"graph_H_nd",1,"physics_hierarchicalRepulsion_nodeDistance"),e=document.getElementById("graph_H_cg"),e.onchange=a.bind(this,"graph_H_cg",1,"physics_centralGravity"),e=document.getElementById("graph_H_sc"),e.onchange=a.bind(this,"graph_H_sc",1,"physics_springConstant"),e=document.getElementById("graph_H_sl"),e.onchange=a.bind(this,"graph_H_sl",1,"physics_springLength"),e=document.getElementById("graph_H_damp"),e.onchange=a.bind(this,"graph_H_damp",1,"physics_damping"),e=document.getElementById("graph_H_direction"),e.onchange=a.bind(this,"graph_H_direction",t,"hierarchicalLayout_direction"),e=document.getElementById("graph_H_levsep"),e.onchange=a.bind(this,"graph_H_levsep",1,"hierarchicalLayout_levelSeparation"),e=document.getElementById("graph_H_nspac"),e.onchange=a.bind(this,"graph_H_nspac",1,"hierarchicalLayout_nodeSpacing");var i=document.getElementById("graph_physicsMethod1"),d=document.getElementById("graph_physicsMethod2"),l=document.getElementById("graph_physicsMethod3");d.checked=!0,this.constants.physics.barnesHut.enabled&&(i.checked=!0),this.constants.hierarchicalLayout.enabled&&(l.checked=!0);var c=document.getElementById("graph_toggleSmooth"),p=document.getElementById("graph_repositionNodes"),u=document.getElementById("graph_generateOptions");c.onclick=s.bind(this),p.onclick=o.bind(this),u.onclick=n.bind(this),c.style.background=1==this.constants.smoothCurves&&0==this.constants.dynamicSmoothCurves?"#A4FF56":"#FF8532",r.apply(this),i.onchange=r.bind(this),d.onchange=r.bind(this),l.onchange=r.bind(this)}},e._overWriteGraphConstants=function(t,e){var i=t.split("_");1==i.length?this.constants[i[0]]=e:2==i.length?this.constants[i[0]][i[1]]=e:3==i.length&&(this.constants[i[0]][i[1]][i[2]]=e)}},function(t,e){e._calculateNodeForces=function(){var t,e,i,s,o,n,r,a,h,d,l,c=this.calculationNodes,p=this.calculationNodeIndices,u=-2/3,m=4/3,f=this.constants.physics.repulsion.nodeDistance,g=f;for(d=0;di&&(r=.5*g>i?1:v*i+m,r*=0==n?1:1+n*this.constants.clustering.forceAmplification,r/=Math.max(i,.01*g),s=t*r,o=e*r,a.fx-=s,a.fy-=o,h.fx+=s,h.fy+=o)}}},function(t,e){e._calculateNodeForces=function(){var t,e,i,s,o,n,r,a,h,d,l=this.calculationNodes,c=this.calculationNodeIndices,p=this.constants.physics.hierarchicalRepulsion.nodeDistance;for(h=0;hi?-Math.pow(u*i,2)+Math.pow(u*p,2):0,0==i?i=.01:n/=i,s=t*n,o=e*n,r.fx-=s,r.fy-=o,a.fx+=s,a.fy+=o}},e._calculateHierarchicalSpringForces=function(){for(var t,e,i,s,o,n,r,a,h,d=this.edges,l=this.calculationNodes,c=this.calculationNodeIndices,p=0;pn;n++)t=e[i[n]],t.options.mass>0&&(this._getForceContribution(o.root.children.NW,t),this._getForceContribution(o.root.children.NE,t),this._getForceContribution(o.root.children.SW,t),this._getForceContribution(o.root.children.SE,t))}},e._getForceContribution=function(t,e){if(t.childrenCount>0){var i,s,o;if(i=t.centerOfMass.x-e.x,s=t.centerOfMass.y-e.y,o=Math.sqrt(i*i+s*s),o*t.calcSize>this.constants.physics.barnesHut.thetaInverted){0==o&&(o=.1*Math.random(),i=o);var n=this.constants.physics.barnesHut.gravitationalConstant*t.mass*e.options.mass/(o*o*o),r=i*n,a=s*n;e.fx+=r,e.fy+=a}else if(4==t.childrenCount)this._getForceContribution(t.children.NW,e),this._getForceContribution(t.children.NE,e),this._getForceContribution(t.children.SW,e),this._getForceContribution(t.children.SE,e);else if(t.children.data.id!=e.id){0==o&&(o=.5*Math.random(),i=o);var n=this.constants.physics.barnesHut.gravitationalConstant*t.mass*e.options.mass/(o*o*o),r=i*n,a=s*n;e.fx+=r,e.fy+=a}}},e._formBarnesHutTree=function(t,e){for(var i,s=e.length,o=Number.MAX_VALUE,n=Number.MAX_VALUE,r=-Number.MAX_VALUE,a=-Number.MAX_VALUE,h=0;s>h;h++){var d=t[e[h]].x,l=t[e[h]].y;t[e[h]].options.mass>0&&(o>d&&(o=d),d>r&&(r=d),n>l&&(n=l),l>a&&(a=l))}var c=Math.abs(r-o)-Math.abs(a-n);c>0?(n-=.5*c,a+=.5*c):(o+=.5*c,r-=.5*c);var p=1e-5,u=Math.max(p,Math.abs(r-o)),m=.5*u,f=.5*(o+r),g=.5*(n+a),v={root:{centerOfMass:{x:0,y:0},mass:0,range:{minX:f-m,maxX:f+m,minY:g-m,maxY:g+m},size:u,calcSize:1/u,children:{data:null},maxWidth:0,level:0,childrenCount:4}};for(this._splitBranch(v.root),h=0;s>h;h++)i=t[e[h]],i.options.mass>0&&this._placeInTree(v.root,i);this.barnesHutTree=v},e._updateBranchMass=function(t,e){var i=t.mass+e.options.mass,s=1/i;t.centerOfMass.x=t.centerOfMass.x*t.mass+e.x*e.options.mass,t.centerOfMass.x*=s,t.centerOfMass.y=t.centerOfMass.y*t.mass+e.y*e.options.mass,t.centerOfMass.y*=s,t.mass=i;var o=Math.max(Math.max(e.height,e.radius),e.width);t.maxWidth=t.maxWidthe.x?t.children.NW.range.maxY>e.y?this._placeInRegion(t,e,"NW"):this._placeInRegion(t,e,"SW"):t.children.NW.range.maxY>e.y?this._placeInRegion(t,e,"NE"):this._placeInRegion(t,e,"SE")},e._placeInRegion=function(t,e,i){switch(t.children[i].childrenCount){case 0:t.children[i].children.data=e,t.children[i].childrenCount=1,this._updateBranchMass(t.children[i],e);break;case 1:t.children[i].children.data.x==e.x&&t.children[i].children.data.y==e.y?(e.x+=Math.random(),e.y+=Math.random()):(this._splitBranch(t.children[i]),this._placeInTree(t.children[i],e));break;case 4:this._placeInTree(t.children[i],e)}},e._splitBranch=function(t){var e=null;1==t.childrenCount&&(e=t.children.data,t.mass=0,t.centerOfMass.x=0,t.centerOfMass.y=0),t.childrenCount=4,t.children.data=null,this._insertRegion(t,"NW"),this._insertRegion(t,"NE"),this._insertRegion(t,"SW"),this._insertRegion(t,"SE"),null!=e&&this._placeInTree(t,e)},e._insertRegion=function(t,e){var i,s,o,n,r=.5*t.size;switch(e){case"NW":i=t.range.minX,s=t.range.minX+r,o=t.range.minY,n=t.range.minY+r;break;case"NE":i=t.range.minX+r,s=t.range.maxX,o=t.range.minY,n=t.range.minY+r;break;case"SW":i=t.range.minX,s=t.range.minX+r,o=t.range.minY+r,n=t.range.maxY;break;case"SE":i=t.range.minX+r,s=t.range.maxX,o=t.range.minY+r,n=t.range.maxY}t.children[e]={centerOfMass:{x:0,y:0},mass:0,range:{minX:i,maxX:s,minY:o,maxY:n},size:.5*t.size,calcSize:2*t.calcSize,children:{data:null},maxWidth:0,level:t.level+1,childrenCount:0}},e._drawTree=function(t,e){void 0!==this.barnesHutTree&&(t.lineWidth=1,this._drawBranch(this.barnesHutTree.root,t,e))},e._drawBranch=function(t,e,i){void 0===i&&(i="#FF0000"),4==t.childrenCount&&(this._drawBranch(t.children.NW,e),this._drawBranch(t.children.NE,e),this._drawBranch(t.children.SE,e),this._drawBranch(t.children.SW,e)),e.strokeStyle=i,e.beginPath(),e.moveTo(t.range.minX,t.range.minY),e.lineTo(t.range.maxX,t.range.minY),e.stroke(),e.beginPath(),e.moveTo(t.range.maxX,t.range.minY),e.lineTo(t.range.maxX,t.range.maxY),e.stroke(),e.beginPath(),e.moveTo(t.range.maxX,t.range.maxY),e.lineTo(t.range.minX,t.range.maxY),e.stroke(),e.beginPath(),e.moveTo(t.range.minX,t.range.maxY),e.lineTo(t.range.minX,t.range.minY),e.stroke()}},function(t,e){e.startWithClustering=function(){this.clusterToFit(this.constants.clustering.initialMaxNodes,!0),this.updateLabels(),this.stabilize&&this._stabilize(),this.start()},e.clusterToFit=function(t,e){for(var i=this.nodeIndices.length,s=50,o=0;i>t&&s>o;)o%3==0?(this.forceAggregateHubs(!0),this.normalizeClusterLevels()):this.increaseClusterLevel(),i=this.nodeIndices.length,o+=1;o>0&&1==e&&this.repositionNodes(),this._updateCalculationNodes()},e.openCluster=function(t){var e=this.moving;if(t.clusterSize>this.constants.clustering.sectorThreshold&&this._nodeInActiveArea(t)&&("default"!=this._sector()||1!=this.nodeIndices.length)){this._addSector(t);for(var i=0;this.nodeIndices.lengthi;)this.decreaseClusterLevel(),i+=1}else this._expandClusterNode(t,!1,!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this._updateCalculationNodes(),this.updateLabels();this.moving!=e&&this.start()},e.updateClustersDefault=function(){1==this.constants.clustering.enabled&&this.updateClusters(0,!1,!1)},e.increaseClusterLevel=function(){this.updateClusters(-1,!1,!0)},e.decreaseClusterLevel=function(){this.updateClusters(1,!1,!0)},e.updateClusters=function(t,e,i,s){var o=this.moving,n=this.nodeIndices.length;this.previousScale>this.scale&&0==t&&this._collapseSector(),this.previousScale>this.scale||-1==t?this._formClusters(i):(this.previousScalethis.scale||-1==t)&&(this._aggregateHubs(i),this._updateNodeIndexList()),(this.previousScale>this.scale||-1==t)&&(this.handleChains(),this._updateNodeIndexList()),this.previousScale=this.scale,this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.lengththis.constants.clustering.chainThreshold&&this._reduceAmountOfChains(1-this.constants.clustering.chainThreshold/t)},e._aggregateHubs=function(t){this._getHubSize(),this._formClustersByHub(t,!1)},e.forceAggregateHubs=function(t){var e=this.moving,i=this.nodeIndices.length;this._aggregateHubs(!0),this._updateNodeIndexList(),this._updateDynamicEdges(),this.updateLabels(),this.nodeIndices.length!=i&&(this.clusterSession+=1),(0==t||void 0===t)&&this.moving!=e&&this.start()},e._openClustersBySize=function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];1==e.inView()&&(e.width*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientWidth||e.height*this.scale>this.constants.clustering.screenSizeThreshold*this.frame.canvas.clientHeight)&&this.openCluster(e)}},e._openClusters=function(t,e){for(var i=0;i1&&(t.clusterSizei)){var r=n.from,a=n.to;n.to.options.mass>n.from.options.mass&&(r=n.to,a=n.from),1==a.dynamicEdgesLength?this._addToCluster(r,a,!1):1==r.dynamicEdgesLength&&this._addToCluster(a,r,!1)}}},e._forceClustersByZoom=function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];if(1==e.dynamicEdgesLength&&0!=e.dynamicEdges.length){var i=e.dynamicEdges[0],s=i.toId==e.id?this.nodes[i.fromId]:this.nodes[i.toId];e.id!=s.id&&(s.options.mass>e.options.mass?this._addToCluster(s,e,!0):this._addToCluster(e,s,!0))}}},e._clusterToSmallestNeighbour=function(t){for(var e=-1,i=null,s=0;so.clusterSessions.length&&(e=o.clusterSessions.length,i=o)}null!=o&&void 0!==this.nodes[o.id]&&this._addToCluster(o,t,!0)},e._formClustersByHub=function(t,e){for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&this._formClusterFromHub(this.nodes[i],t,e)},e._formClusterFromHub=function(t,e,i,s){if(void 0===s&&(s=0),t.dynamicEdgesLength>=this.hubThreshold&&0==i||t.dynamicEdgesLength==this.hubThreshold&&1==i){for(var o,n,r,a=this.constants.clustering.clusterEdgeThreshold/this.scale,h=!1,d=[],l=t.dynamicEdges.length,c=0;l>c;c++)d.push(t.dynamicEdges[c].id);if(0==e)for(h=!1,c=0;l>c;c++){var p=this.edges[d[c]];if(void 0!==p&&p.connected&&p.toId!=p.fromId&&(o=p.to.x-p.from.x,n=p.to.y-p.from.y,r=Math.sqrt(o*o+n*n),a>r)){h=!0;break}}if(!e&&h||e)for(c=0;l>c;c++)if(p=this.edges[d[c]],void 0!==p){var u=this.nodes[p.fromId==t.id?p.toId:p.fromId];u.dynamicEdges.length<=this.hubThreshold+s&&u.id!=t.id&&this._addToCluster(t,u,e)}}},e._addToCluster=function(t,e,i){t.containedNodes[e.id]=e;for(var s=0;s1)for(var s=0;s1&&(e.label="[".concat(String(e.clusterSize),"]"))}for(t in this.nodes)this.nodes.hasOwnProperty(t)&&(e=this.nodes[t],1==e.clusterSize&&(e.label=void 0!==e.originalLabel?e.originalLabel:String(e.id)))},e.normalizeClusterLevels=function(){var t,e=0,i=1e9,s=0;for(t in this.nodes)this.nodes.hasOwnProperty(t)&&(s=this.nodes[t].clusterSessions.length,s>e&&(e=s),i>s&&(i=s));if(e-i>this.constants.clustering.clusterLevelDifference){var o=this.nodeIndices.length,n=e-this.constants.clustering.clusterLevelDifference;for(t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodes[t].clusterSessions.lengths&&(s=n.dynamicEdgesLength),t+=n.dynamicEdgesLength,e+=Math.pow(n.dynamicEdgesLength,2),i+=1}t/=i,e/=i;var r=e-Math.pow(t,2),a=Math.sqrt(r);this.hubThreshold=Math.floor(t+2*a),this.hubThreshold>s&&(this.hubThreshold=s)},e._reduceAmountOfChains=function(t){this.hubThreshold=2;var e=Math.floor(this.nodeIndices.length*t);for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&e>0&&(this._formClusterFromHub(this.nodes[i],!0,!0,1),e-=1)},e._getChainFraction=function(){var t=0,e=0;for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&(2==this.nodes[i].dynamicEdgesLength&&this.nodes[i].dynamicEdges.length>=2&&(t+=1),e+=1);return t/e}},function(t,e,i){var s=i(1),o=i(53);e._putDataInSector=function(){this.sectors.active[this._sector()].nodes=this.nodes,this.sectors.active[this._sector()].edges=this.edges,this.sectors.active[this._sector()].nodeIndices=this.nodeIndices},e._switchToSector=function(t,e){void 0===e||"active"==e?this._switchToActiveSector(t):this._switchToFrozenSector(t)},e._switchToActiveSector=function(t){this.nodeIndices=this.sectors.active[t].nodeIndices,this.nodes=this.sectors.active[t].nodes,this.edges=this.sectors.active[t].edges},e._switchToSupportSector=function(){this.nodeIndices=this.sectors.support.nodeIndices,this.nodes=this.sectors.support.nodes,this.edges=this.sectors.support.edges},e._switchToFrozenSector=function(t){this.nodeIndices=this.sectors.frozen[t].nodeIndices,this.nodes=this.sectors.frozen[t].nodes,this.edges=this.sectors.frozen[t].edges},e._loadLatestSector=function(){this._switchToSector(this._sector())},e._sector=function(){return this.activeSector[this.activeSector.length-1]},e._previousSector=function(){if(this.activeSector.length>1)return this.activeSector[this.activeSector.length-2];throw new TypeError("there are not enough sectors in the this.activeSector array.")},e._setActiveSector=function(t){this.activeSector.push(t)},e._forgetLastSector=function(){this.activeSector.pop()},e._createNewSector=function(t){this.sectors.active[t]={nodes:{},edges:{},nodeIndices:[],formationScale:this.scale,drawingNode:void 0},this.sectors.active[t].drawingNode=new o({id:t,color:{background:"#eaefef",border:"495c5e"}},{},{},this.constants),this.sectors.active[t].drawingNode.clusterSize=2},e._deleteActiveSector=function(t){delete this.sectors.active[t]},e._deleteFrozenSector=function(t){delete this.sectors.frozen[t]},e._freezeSector=function(t){this.sectors.frozen[t]=this.sectors.active[t],this._deleteActiveSector(t)},e._activateSector=function(t){this.sectors.active[t]=this.sectors.frozen[t],this._deleteFrozenSector(t)},e._mergeThisWithFrozen=function(t){for(var e in this.nodes)this.nodes.hasOwnProperty(e)&&(this.sectors.frozen[t].nodes[e]=this.nodes[e]);for(var i in this.edges)this.edges.hasOwnProperty(i)&&(this.sectors.frozen[t].edges[i]=this.edges[i]);for(var s=0;s1?this[t](o[0],o[1]):this[t](e))}return this._loadLatestSector(),i},e._doInSupportSector=function(t,e){var i=!1;if(void 0===e)this._switchToSupportSector(),i=this[t]();else{this._switchToSupportSector();var s=Array.prototype.splice.call(arguments,1);i=s.length>1?this[t](s[0],s[1]):this[t](e)}return this._loadLatestSector(),i},e._doInAllFrozenSectors=function(t,e){if(void 0===e)for(var i in this.sectors.frozen)this.sectors.frozen.hasOwnProperty(i)&&(this._switchToFrozenSector(i),this[t]());else for(var i in this.sectors.frozen)if(this.sectors.frozen.hasOwnProperty(i)){this._switchToFrozenSector(i);var s=Array.prototype.splice.call(arguments,1);s.length>1?this[t](s[0],s[1]):this[t](e)}this._loadLatestSector()},e._doInAllSectors=function(t,e){var i=Array.prototype.splice.call(arguments,1);void 0===e?(this._doInAllActiveSectors(t),this._doInAllFrozenSectors(t)):i.length>1?(this._doInAllActiveSectors(t,i[0],i[1]),this._doInAllFrozenSectors(t,i[0],i[1])):(this._doInAllActiveSectors(t,e),this._doInAllFrozenSectors(t,e))},e._clearNodeIndexList=function(){var t=this._sector();this.sectors.active[t].nodeIndices=[],this.nodeIndices=this.sectors.active[t].nodeIndices},e._drawSectorNodes=function(t,e){var i,s=1e9,o=-1e9,n=1e9,r=-1e9;for(var a in this.sectors[e])if(this.sectors[e].hasOwnProperty(a)&&void 0!==this.sectors[e][a].drawingNode){this._switchToSector(a,e),s=1e9,o=-1e9,n=1e9,r=-1e9;for(var h in this.nodes)this.nodes.hasOwnProperty(h)&&(i=this.nodes[h],i.resize(t),n>i.x-.5*i.width&&(n=i.x-.5*i.width),ri.y-.5*i.height&&(s=i.y-.5*i.height),o0?this.nodes[i[i.length-1]]:null},e._getEdgesOverlappingWith=function(t,e){var i=this.edges;for(var s in i)i.hasOwnProperty(s)&&i[s].isOverlappingWith(t)&&e.push(s)},e._getAllEdgesOverlappingWith=function(t){var e=[];return this._doInAllActiveSectors("_getEdgesOverlappingWith",t,e),e},e._getEdgeAt=function(t){var e=this._pointerToPositionObject(t),i=this._getAllEdgesOverlappingWith(e);return i.length>0?this.edges[i[i.length-1]]:null},e._addToSelection=function(t){t instanceof s?this.selectionObj.nodes[t.id]=t:this.selectionObj.edges[t.id]=t},e._addToHover=function(t){t instanceof s?this.hoverObj.nodes[t.id]=t:this.hoverObj.edges[t.id]=t},e._removeFromSelection=function(t){t instanceof s?delete this.selectionObj.nodes[t.id]:delete this.selectionObj.edges[t.id]},e._unselectAll=function(t){void 0===t&&(t=!1);for(var e in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(e)&&this.selectionObj.nodes[e].unselect();for(var i in this.selectionObj.edges)this.selectionObj.edges.hasOwnProperty(i)&&this.selectionObj.edges[i].unselect();this.selectionObj={nodes:{},edges:{}},0==t&&this.emit("select",this.getSelection())},e._unselectClusters=function(t){void 0===t&&(t=!1);for(var e in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(e)&&this.selectionObj.nodes[e].clusterSize>1&&(this.selectionObj.nodes[e].unselect(),this._removeFromSelection(this.selectionObj.nodes[e]));0==t&&this.emit("select",this.getSelection())},e._getSelectedNodeCount=function(){var t=0;for(var e in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(e)&&(t+=1);return t},e._getSelectedNode=function(){for(var t in this.selectionObj.nodes)if(this.selectionObj.nodes.hasOwnProperty(t))return this.selectionObj.nodes[t];return null},e._getSelectedEdge=function(){for(var t in this.selectionObj.edges)if(this.selectionObj.edges.hasOwnProperty(t))return this.selectionObj.edges[t];return null},e._getSelectedEdgeCount=function(){var t=0;for(var e in this.selectionObj.edges)this.selectionObj.edges.hasOwnProperty(e)&&(t+=1);return t},e._getSelectedObjectCount=function(){var t=0;for(var e in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(e)&&(t+=1);for(var i in this.selectionObj.edges)this.selectionObj.edges.hasOwnProperty(i)&&(t+=1);return t},e._selectionIsEmpty=function(){for(var t in this.selectionObj.nodes)if(this.selectionObj.nodes.hasOwnProperty(t))return!1;for(var e in this.selectionObj.edges)if(this.selectionObj.edges.hasOwnProperty(e))return!1;return!0},e._clusterInSelection=function(){for(var t in this.selectionObj.nodes)if(this.selectionObj.nodes.hasOwnProperty(t)&&this.selectionObj.nodes[t].clusterSize>1)return!0;return!1},e._selectConnectedEdges=function(t){for(var e=0;ei;i++){o=t[i];var n=this.nodes[o];if(!n)throw new RangeError('Node with id "'+o+'" not found');this._selectObject(n,!0,!0,e,!0)}this.redraw()},e.selectEdges=function(t){var e,i,s;if(!t||void 0==t.length)throw"Selection must be an array with ids";for(this._unselectAll(!0),e=0,i=t.length;i>e;e++){s=t[e];var o=this.edges[s];if(!o)throw new RangeError('Edge with id "'+s+'" not found');this._selectObject(o,!0,!0,!1,!0)}this.redraw()},e._updateSelection=function(){for(var t in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(t)&&(this.nodes.hasOwnProperty(t)||delete this.selectionObj.nodes[t]);for(var e in this.selectionObj.edges)this.selectionObj.edges.hasOwnProperty(e)&&(this.edges.hasOwnProperty(e)||delete this.selectionObj.edges[e])}},function(t,e,i){var s=i(1),o=i(53),n=i(52);e._clearManipulatorBar=function(){this._recursiveDOMDelete(this.manipulationDiv),this.manipulationDOM={},this._manipulationReleaseOverload=function(){},delete this.sectors.support.nodes.targetNode,delete this.sectors.support.nodes.targetViaNode,this.controlNodesActive=!1,this.freezeSimulation=!1},e._restoreOverloadedFunctions=function(){for(var t in this.cachedFunctions)this.cachedFunctions.hasOwnProperty(t)&&(this[t]=this.cachedFunctions[t],delete this.cachedFunctions[t])},e._toggleEditMode=function(){this.editMode=!this.editMode;var t=this.manipulationDiv,e=this.closeDiv,i=this.editModeDiv;1==this.editMode?(t.style.display="block",e.style.display="block",i.style.display="none",e.onclick=this._toggleEditMode.bind(this)):(t.style.display="none",e.style.display="none",i.style.display="block",e.onclick=null),this._createManipulatorBar()},e._createManipulatorBar=function(){this.boundFunction&&this.off("select",this.boundFunction);var t=this.constants.locales[this.constants.locale];if(void 0!==this.edgeBeingEdited&&(this.edgeBeingEdited._disableControlNodes(),this.edgeBeingEdited=void 0,this.selectedControlNode=null,this.controlNodesActive=!1,this._redraw()),this._restoreOverloadedFunctions(),this.freezeSimulation=!1,this.blockConnectingEdgeSelection=!1,this.forceAppendSelection=!1,this.manipulationDOM={},1==this.editMode){for(;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);this.manipulationDOM.addNodeSpan=document.createElement("span"),this.manipulationDOM.addNodeSpan.className="network-manipulationUI add",this.manipulationDOM.addNodeLabelSpan=document.createElement("span"),this.manipulationDOM.addNodeLabelSpan.className="network-manipulationLabel",this.manipulationDOM.addNodeLabelSpan.innerHTML=t.addNode,this.manipulationDOM.addNodeSpan.appendChild(this.manipulationDOM.addNodeLabelSpan),this.manipulationDOM.seperatorLineDiv1=document.createElement("div"),this.manipulationDOM.seperatorLineDiv1.className="network-seperatorLine",this.manipulationDOM.addEdgeSpan=document.createElement("span"),this.manipulationDOM.addEdgeSpan.className="network-manipulationUI connect",this.manipulationDOM.addEdgeLabelSpan=document.createElement("span"),this.manipulationDOM.addEdgeLabelSpan.className="network-manipulationLabel",this.manipulationDOM.addEdgeLabelSpan.innerHTML=t.addEdge,this.manipulationDOM.addEdgeSpan.appendChild(this.manipulationDOM.addEdgeLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.addNodeSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv1),this.manipulationDiv.appendChild(this.manipulationDOM.addEdgeSpan),1==this._getSelectedNodeCount()&&this.triggerFunctions.edit?(this.manipulationDOM.seperatorLineDiv2=document.createElement("div"),this.manipulationDOM.seperatorLineDiv2.className="network-seperatorLine",this.manipulationDOM.editNodeSpan=document.createElement("span"),this.manipulationDOM.editNodeSpan.className="network-manipulationUI edit",this.manipulationDOM.editNodeLabelSpan=document.createElement("span"),this.manipulationDOM.editNodeLabelSpan.className="network-manipulationLabel",this.manipulationDOM.editNodeLabelSpan.innerHTML=t.editNode,this.manipulationDOM.editNodeSpan.appendChild(this.manipulationDOM.editNodeLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv2),this.manipulationDiv.appendChild(this.manipulationDOM.editNodeSpan)):1==this._getSelectedEdgeCount()&&0==this._getSelectedNodeCount()&&(this.manipulationDOM.seperatorLineDiv3=document.createElement("div"),this.manipulationDOM.seperatorLineDiv3.className="network-seperatorLine",this.manipulationDOM.editEdgeSpan=document.createElement("span"),this.manipulationDOM.editEdgeSpan.className="network-manipulationUI edit",this.manipulationDOM.editEdgeLabelSpan=document.createElement("span"),this.manipulationDOM.editEdgeLabelSpan.className="network-manipulationLabel",this.manipulationDOM.editEdgeLabelSpan.innerHTML=t.editEdge,this.manipulationDOM.editEdgeSpan.appendChild(this.manipulationDOM.editEdgeLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv3),this.manipulationDiv.appendChild(this.manipulationDOM.editEdgeSpan)),0==this._selectionIsEmpty()&&(this.manipulationDOM.seperatorLineDiv4=document.createElement("div"),this.manipulationDOM.seperatorLineDiv4.className="network-seperatorLine",this.manipulationDOM.deleteSpan=document.createElement("span"),this.manipulationDOM.deleteSpan.className="network-manipulationUI delete",this.manipulationDOM.deleteLabelSpan=document.createElement("span"),this.manipulationDOM.deleteLabelSpan.className="network-manipulationLabel",this.manipulationDOM.deleteLabelSpan.innerHTML=t.del,this.manipulationDOM.deleteSpan.appendChild(this.manipulationDOM.deleteLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv4),this.manipulationDiv.appendChild(this.manipulationDOM.deleteSpan)),this.manipulationDOM.addNodeSpan.onclick=this._createAddNodeToolbar.bind(this),this.manipulationDOM.addEdgeSpan.onclick=this._createAddEdgeToolbar.bind(this),1==this._getSelectedNodeCount()&&this.triggerFunctions.edit?this.manipulationDOM.editNodeSpan.onclick=this._editNode.bind(this):1==this._getSelectedEdgeCount()&&0==this._getSelectedNodeCount()&&(this.manipulationDOM.editEdgeSpan.onclick=this._createEditEdgeToolbar.bind(this)),0==this._selectionIsEmpty()&&(this.manipulationDOM.deleteSpan.onclick=this._deleteSelected.bind(this)),this.closeDiv.onclick=this._toggleEditMode.bind(this);var e=this;this.boundFunction=e._createManipulatorBar,this.on("select",this.boundFunction)}else{for(;this.editModeDiv.hasChildNodes();)this.editModeDiv.removeChild(this.editModeDiv.firstChild);this.manipulationDOM.editModeSpan=document.createElement("span"),this.manipulationDOM.editModeSpan.className="network-manipulationUI edit editmode",this.manipulationDOM.editModeLabelSpan=document.createElement("span"),this.manipulationDOM.editModeLabelSpan.className="network-manipulationLabel",this.manipulationDOM.editModeLabelSpan.innerHTML=t.edit,this.manipulationDOM.editModeSpan.appendChild(this.manipulationDOM.editModeLabelSpan),this.editModeDiv.appendChild(this.manipulationDOM.editModeSpan),this.manipulationDOM.editModeSpan.onclick=this._toggleEditMode.bind(this)}},e._createAddNodeToolbar=function(){this._clearManipulatorBar(),this.boundFunction&&this.off("select",this.boundFunction);var t=this.constants.locales[this.constants.locale];this.manipulationDOM={},this.manipulationDOM.backSpan=document.createElement("span"),this.manipulationDOM.backSpan.className="network-manipulationUI back",this.manipulationDOM.backLabelSpan=document.createElement("span"),this.manipulationDOM.backLabelSpan.className="network-manipulationLabel",this.manipulationDOM.backLabelSpan.innerHTML=t.back,this.manipulationDOM.backSpan.appendChild(this.manipulationDOM.backLabelSpan),this.manipulationDOM.seperatorLineDiv1=document.createElement("div"),this.manipulationDOM.seperatorLineDiv1.className="network-seperatorLine",this.manipulationDOM.descriptionSpan=document.createElement("span"),this.manipulationDOM.descriptionSpan.className="network-manipulationUI none",this.manipulationDOM.descriptionLabelSpan=document.createElement("span"),this.manipulationDOM.descriptionLabelSpan.className="network-manipulationLabel",this.manipulationDOM.descriptionLabelSpan.innerHTML=t.addDescription,this.manipulationDOM.descriptionSpan.appendChild(this.manipulationDOM.descriptionLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.backSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv1),this.manipulationDiv.appendChild(this.manipulationDOM.descriptionSpan),this.manipulationDOM.backSpan.onclick=this._createManipulatorBar.bind(this);var e=this;this.boundFunction=e._addNode,this.on("select",this.boundFunction)},e._createAddEdgeToolbar=function(){this._clearManipulatorBar(),this._unselectAll(!0),this.freezeSimulation=!0,this.boundFunction&&this.off("select",this.boundFunction);var t=this.constants.locales[this.constants.locale];this._unselectAll(),this.forceAppendSelection=!1,this.blockConnectingEdgeSelection=!0,this.manipulationDOM={},this.manipulationDOM.backSpan=document.createElement("span"),this.manipulationDOM.backSpan.className="network-manipulationUI back",this.manipulationDOM.backLabelSpan=document.createElement("span"),this.manipulationDOM.backLabelSpan.className="network-manipulationLabel",this.manipulationDOM.backLabelSpan.innerHTML=t.back,this.manipulationDOM.backSpan.appendChild(this.manipulationDOM.backLabelSpan),this.manipulationDOM.seperatorLineDiv1=document.createElement("div"),this.manipulationDOM.seperatorLineDiv1.className="network-seperatorLine",this.manipulationDOM.descriptionSpan=document.createElement("span"),this.manipulationDOM.descriptionSpan.className="network-manipulationUI none",this.manipulationDOM.descriptionLabelSpan=document.createElement("span"),this.manipulationDOM.descriptionLabelSpan.className="network-manipulationLabel",this.manipulationDOM.descriptionLabelSpan.innerHTML=t.edgeDescription,this.manipulationDOM.descriptionSpan.appendChild(this.manipulationDOM.descriptionLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.backSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv1),this.manipulationDiv.appendChild(this.manipulationDOM.descriptionSpan),this.manipulationDOM.backSpan.onclick=this._createManipulatorBar.bind(this);var e=this;this.boundFunction=e._handleConnect,this.on("select",this.boundFunction),this.cachedFunctions._handleTouch=this._handleTouch,this.cachedFunctions._manipulationReleaseOverload=this._manipulationReleaseOverload,this.cachedFunctions._handleDragStart=this._handleDragStart,this.cachedFunctions._handleDragEnd=this._handleDragEnd,this._handleTouch=this._handleConnect,this._manipulationReleaseOverload=function(){},this._handleDragStart=function(){},this._handleDragEnd=this._finishConnect,this._redraw()},e._createEditEdgeToolbar=function(){this._clearManipulatorBar(),this.controlNodesActive=!0,this.boundFunction&&this.off("select",this.boundFunction),this.edgeBeingEdited=this._getSelectedEdge(),this.edgeBeingEdited._enableControlNodes();var t=this.constants.locales[this.constants.locale];this.manipulationDOM={},this.manipulationDOM.backSpan=document.createElement("span"),this.manipulationDOM.backSpan.className="network-manipulationUI back",this.manipulationDOM.backLabelSpan=document.createElement("span"),this.manipulationDOM.backLabelSpan.className="network-manipulationLabel",this.manipulationDOM.backLabelSpan.innerHTML=t.back,this.manipulationDOM.backSpan.appendChild(this.manipulationDOM.backLabelSpan),this.manipulationDOM.seperatorLineDiv1=document.createElement("div"),this.manipulationDOM.seperatorLineDiv1.className="network-seperatorLine",this.manipulationDOM.descriptionSpan=document.createElement("span"),this.manipulationDOM.descriptionSpan.className="network-manipulationUI none",this.manipulationDOM.descriptionLabelSpan=document.createElement("span"),this.manipulationDOM.descriptionLabelSpan.className="network-manipulationLabel",this.manipulationDOM.descriptionLabelSpan.innerHTML=t.editEdgeDescription,this.manipulationDOM.descriptionSpan.appendChild(this.manipulationDOM.descriptionLabelSpan),this.manipulationDiv.appendChild(this.manipulationDOM.backSpan),this.manipulationDiv.appendChild(this.manipulationDOM.seperatorLineDiv1),this.manipulationDiv.appendChild(this.manipulationDOM.descriptionSpan),this.manipulationDOM.backSpan.onclick=this._createManipulatorBar.bind(this),this.cachedFunctions._handleTouch=this._handleTouch,this.cachedFunctions._manipulationReleaseOverload=this._manipulationReleaseOverload,this.cachedFunctions._handleTap=this._handleTap,this.cachedFunctions._handleDragStart=this._handleDragStart,this.cachedFunctions._handleOnDrag=this._handleOnDrag,this._handleTouch=this._selectControlNode,this._handleTap=function(){},this._handleOnDrag=this._controlNodeDrag,this._handleDragStart=function(){},this._manipulationReleaseOverload=this._releaseControlNode,this._redraw()},e._selectControlNode=function(t){this.edgeBeingEdited.controlNodes.from.unselect(),this.edgeBeingEdited.controlNodes.to.unselect(),this.selectedControlNode=this.edgeBeingEdited._getSelectedControlNode(this._XconvertDOMtoCanvas(t.x),this._YconvertDOMtoCanvas(t.y)),null!==this.selectedControlNode&&(this.selectedControlNode.select(),this.freezeSimulation=!0),this._redraw()},e._controlNodeDrag=function(t){var e=this._getPointer(t.gesture.center);null!==this.selectedControlNode&&void 0!==this.selectedControlNode&&(this.selectedControlNode.x=this._XconvertDOMtoCanvas(e.x),this.selectedControlNode.y=this._YconvertDOMtoCanvas(e.y)),this._redraw()},e._releaseControlNode=function(t){var e=this._getNodeAt(t);null!==e?(1==this.edgeBeingEdited.controlNodes.from.selected&&(this.edgeBeingEdited._restoreControlNodes(),this._editEdge(e.id,this.edgeBeingEdited.to.id),this.edgeBeingEdited.controlNodes.from.unselect()),1==this.edgeBeingEdited.controlNodes.to.selected&&(this.edgeBeingEdited._restoreControlNodes(),this._editEdge(this.edgeBeingEdited.from.id,e.id),this.edgeBeingEdited.controlNodes.to.unselect())):this.edgeBeingEdited._restoreControlNodes(),this.freezeSimulation=!1,this._redraw()},e._handleConnect=function(t){if(0==this._getSelectedNodeCount()){var e=this._getNodeAt(t);if(null!=e)if(e.clusterSize>1)alert(this.constants.locales[this.constants.locale].createEdgeError);else{this._selectObject(e,!1);var i=this.sectors.support.nodes;i.targetNode=new o({id:"targetNode"},{},{},this.constants);var s=i.targetNode;s.x=e.x,s.y=e.y,this.edges.connectionEdge=new n({id:"connectionEdge",from:e.id,to:s.id},this,this.constants);var r=this.edges.connectionEdge;r.from=e,r.connected=!0,r.options.smoothCurves={enabled:!0,dynamic:!1,type:"continuous",roundness:.5},r.selected=!0,r.to=s,this.cachedFunctions._handleOnDrag=this._handleOnDrag,this._handleOnDrag=function(t){var e=this._getPointer(t.gesture.center),i=this.edges.connectionEdge;i.to.x=this._XconvertDOMtoCanvas(e.x),i.to.y=this._YconvertDOMtoCanvas(e.y)},this.moving=!0,this.start()}}},e._finishConnect=function(t){if(1==this._getSelectedNodeCount()){var e=this._getPointer(t.gesture.center);this._handleOnDrag=this.cachedFunctions._handleOnDrag,delete this.cachedFunctions._handleOnDrag;var i=this.edges.connectionEdge.fromId;delete this.edges.connectionEdge,delete this.sectors.support.nodes.targetNode,delete this.sectors.support.nodes.targetViaNode;var s=this._getNodeAt(e);null!=s&&(s.clusterSize>1?alert(this.constants.locales[this.constants.locale].createEdgeError):(this._createEdge(i,s.id),this._createManipulatorBar())),this._unselectAll()}},e._addNode=function(){if(this._selectionIsEmpty()&&1==this.editMode){var t=this._pointerToPositionObject(this.pointerPosition),e={id:s.randomUUID(),x:t.left,y:t.top,label:"new",allowedToMoveX:!0,allowedToMoveY:!0};if(this.triggerFunctions.add){if(2!=this.triggerFunctions.add.length)throw new Error("The function for add does not support two arguments (data,callback)");var i=this;this.triggerFunctions.add(e,function(t){i.nodesData.add(t),i._createManipulatorBar(),i.moving=!0,i.start()})}else this.nodesData.add(e),this._createManipulatorBar(),this.moving=!0,this.start() +}},e._createEdge=function(t,e){if(1==this.editMode){var i={from:t,to:e};if(this.triggerFunctions.connect){if(2!=this.triggerFunctions.connect.length)throw new Error("The function for connect does not support two arguments (data,callback)");var s=this;this.triggerFunctions.connect(i,function(t){s.edgesData.add(t),s.moving=!0,s.start()})}else this.edgesData.add(i),this.moving=!0,this.start()}},e._editEdge=function(t,e){if(1==this.editMode){var i={id:this.edgeBeingEdited.id,from:t,to:e};if(this.triggerFunctions.editEdge){if(2!=this.triggerFunctions.editEdge.length)throw new Error("The function for edit does not support two arguments (data, callback)");var s=this;this.triggerFunctions.editEdge(i,function(t){s.edgesData.update(t),s.moving=!0,s.start()})}else this.edgesData.update(i),this.moving=!0,this.start()}},e._editNode=function(){if(!this.triggerFunctions.edit||1!=this.editMode)throw new Error("No edit function has been bound to this button");var t=this._getSelectedNode(),e={id:t.id,label:t.label,group:t.options.group,shape:t.options.shape,color:{background:t.options.color.background,border:t.options.color.border,highlight:{background:t.options.color.highlight.background,border:t.options.color.highlight.border}}};if(2!=this.triggerFunctions.edit.length)throw new Error("The function for edit does not support two arguments (data, callback)");var i=this;this.triggerFunctions.edit(e,function(t){i.nodesData.update(t),i._createManipulatorBar(),i.moving=!0,i.start()})},e._deleteSelected=function(){if(!this._selectionIsEmpty()&&1==this.editMode)if(this._clusterInSelection())alert(this.constants.locales[this.constants.locale].deleteClusterError);else{var t=this.getSelectedNodes(),e=this.getSelectedEdges();if(this.triggerFunctions.del){var i=this,s={nodes:t,edges:e};if(2!=this.triggerFunctions.del.length)throw new Error("The function for delete does not support two arguments (data, callback)");this.triggerFunctions.del(s,function(t){i.edgesData.remove(t.edges),i.nodesData.remove(t.nodes),i._unselectAll(),i.moving=!0,i.start()})}else this.edgesData.remove(e),this.nodesData.remove(t),this._unselectAll(),this.moving=!0,this.start()}}},function(t,e,i){var s=(i(1),i(19));e._cleanNavigation=function(){if(0!=this.navigationHammers.existing.length){for(var t=0;t0){var t,e,i=0,s=!1,o=!1;for(e in this.nodes)this.nodes.hasOwnProperty(e)&&(t=this.nodes[e],-1!=t.level?s=!0:o=!0,is&&(n.xFixed=!1,n.x=i[n.level].minPos,r=!0):n.yFixed&&n.level>s&&(n.yFixed=!1,n.y=i[n.level].minPos,r=!0),1==r&&(i[n.level].minPos+=i[n.level].nodeSpacing,n.edges.length>1&&this._placeBranchNodes(n.edges,n.id,i,n.level))}},e._setLevel=function(t,e,i){for(var s=0;st)&&(o.level=t,o.edges.length>1&&this._setLevel(t+1,o.edges,o.id))}},e._setLevelDirected=function(t,e,i){this.nodes[i].hierarchyEnumerated=!0;for(var s,o,n=0;n1&&s.hierarchyEnumerated===!1&&this._setLevelDirected(s.level,s.edges,s.id)},e._restoreNodes=function(){for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&(this.nodes[t].xFixed=!1,this.nodes[t].yFixed=!1)}},function(t,e){e.en={edit:"Edit",del:"Delete selected",back:"Back",addNode:"Add Node",addEdge:"Add Edge",editNode:"Edit Node",editEdge:"Edit Edge",addDescription:"Click in an empty space to place a new node.",edgeDescription:"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."},e.en_EN=e.en,e.en_US=e.en,e.nl={edit:"Wijzigen",del:"Selectie verwijderen",back:"Terug",addNode:"Node toevoegen",addEdge:"Link toevoegen",editNode:"Node wijzigen",editEdge:"Link wijzigen",addDescription:"Klik op een leeg gebied om een nieuwe node te maken.",edgeDescription:"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."},e.nl_NL=e.nl,e.nl_BE=e.nl},function(){"undefined"!=typeof CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.circle=function(t,e,i){this.beginPath(),this.arc(t,e,i,0,2*Math.PI,!1)},CanvasRenderingContext2D.prototype.square=function(t,e,i){this.beginPath(),this.rect(t-i,e-i,2*i,2*i)},CanvasRenderingContext2D.prototype.triangle=function(t,e,i){this.beginPath();var s=2*i,o=s/2,n=Math.sqrt(3)/6*s,r=Math.sqrt(s*s-o*o);this.moveTo(t,e-(r-n)),this.lineTo(t+o,e+n),this.lineTo(t-o,e+n),this.lineTo(t,e-(r-n)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var s=2*i,o=s/2,n=Math.sqrt(3)/6*s,r=Math.sqrt(s*s-o*o);this.moveTo(t,e+(r-n)),this.lineTo(t+o,e-n),this.lineTo(t-o,e-n),this.lineTo(t,e+(r-n)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var s=0;10>s;s++){var o=s%2===0?1.3*i:.5*i;this.lineTo(t+o*Math.sin(2*s*Math.PI/10),e-o*Math.cos(2*s*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,s,o){var n=Math.PI/180;0>i-2*o&&(o=i/2),0>s-2*o&&(o=s/2),this.beginPath(),this.moveTo(t+o,e),this.lineTo(t+i-o,e),this.arc(t+i-o,e+o,o,270*n,360*n,!1),this.lineTo(t+i,e+s-o),this.arc(t+i-o,e+s-o,o,0,90*n,!1),this.lineTo(t+o,e+s),this.arc(t+o,e+s-o,o,90*n,180*n,!1),this.lineTo(t,e+o),this.arc(t+o,e+o,o,180*n,270*n,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,s){var o=.5522848,n=i/2*o,r=s/2*o,a=t+i,h=e+s,d=t+i/2,l=e+s/2;this.beginPath(),this.moveTo(t,l),this.bezierCurveTo(t,l-r,d-n,e,d,e),this.bezierCurveTo(d+n,e,a,l-r,a,l),this.bezierCurveTo(a,l+r,d+n,h,d,h),this.bezierCurveTo(d-n,h,t,l+r,t,l)},CanvasRenderingContext2D.prototype.database=function(t,e,i,s){var o=1/3,n=i,r=s*o,a=.5522848,h=n/2*a,d=r/2*a,l=t+n,c=e+r,p=t+n/2,u=e+r/2,m=e+(s-r/2),f=e+s;this.beginPath(),this.moveTo(l,u),this.bezierCurveTo(l,u+d,p+h,c,p,c),this.bezierCurveTo(p-h,c,t,u+d,t,u),this.bezierCurveTo(t,u-d,p-h,e,p,e),this.bezierCurveTo(p+h,e,l,u-d,l,u),this.lineTo(l,m),this.bezierCurveTo(l,m+d,p+h,f,p,f),this.bezierCurveTo(p-h,f,t,m+d,t,m),this.lineTo(t,u)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,s){var o=t-s*Math.cos(i),n=e-s*Math.sin(i),r=t-.9*s*Math.cos(i),a=e-.9*s*Math.sin(i),h=o+s/3*Math.cos(i+.5*Math.PI),d=n+s/3*Math.sin(i+.5*Math.PI),l=o+s/3*Math.cos(i-.5*Math.PI),c=n+s/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,d),this.lineTo(r,a),this.lineTo(l,c),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,s,o){o||(o=[10,5]),0==p&&(p=.001);var n=o.length;this.moveTo(t,e);for(var r=i-t,a=s-e,h=a/r,d=Math.sqrt(r*r+a*a),l=0,c=!0;d>=.1;){var p=o[l++%n];p>d&&(p=d);var u=Math.sqrt(p*p/(1+h*h));0>r&&(u=-u),t+=u,e+=h*u,this[c?"lineTo":"moveTo"](t,e),d-=p,c=!c}})}])}); //# sourceMappingURL=vis.map diff --git a/lib/network/Node.js b/lib/network/Node.js index 15e21bfe..28dd5548 100644 --- a/lib/network/Node.js +++ b/lib/network/Node.js @@ -180,16 +180,16 @@ Node.prototype.setProperties = function(properties, constants) { } // copy group properties - if (typeof this.options.group === 'number' || (typeof this.options.group === 'string' && this.options.group != '')) { - var groupObj = this.grouplist.get(this.options.group); + if (typeof properties.group === 'number' || (typeof properties.group === 'string' && properties.group != '')) { + var groupObj = this.grouplist.get(properties.group); util.deepExtend(this.options, groupObj); // the color object needs to be completely defined. Since groups can partially overwrite the colors, we parse it again, just in case. this.options.color = util.parseColor(this.options.color); } - // individual shape properties if (properties.radius !== undefined) {this.baseRadiusValue = this.options.radius;} if (properties.color !== undefined) {this.options.color = util.parseColor(properties.color);} + if (this.options.image !== undefined && this.options.image!= "") { if (this.imagelist) { this.imageObj = this.imagelist.load(this.options.image, this.options.brokenImage); From 429a475c6315c58cdbcf05620794e5ade6d1879d Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Mon, 19 Jan 2015 13:54:11 +0100 Subject: [PATCH 06/16] - Decoupled animation from physics simulation --- HISTORY.md | 1 + dist/vis.js | 53832 ++++++++++++++++++++------------------- lib/network/Network.js | 28 +- 3 files changed, 26935 insertions(+), 26926 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 375b8b21..a1fc9a65 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -9,6 +9,7 @@ http://visjs.org - Fixed bug where opening a cluster with smoothCurves off caused one child to go crazy. - Fixed bug where zoomExtent does not work as expected. - Fixed nodes color data being overridden when having a group and a dataset update query. +- Decoupled animation from physics simulation ## 2015-01-16, version 3.9.0 diff --git a/dist/vis.js b/dist/vis.js index cfe4a98b..8663b2f0 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -83,67 +83,67 @@ return /******/ (function(modules) { // webpackBootstrap // utils exports.util = __webpack_require__(1); - exports.DOMutil = __webpack_require__(6); + exports.DOMutil = __webpack_require__(2); // data - exports.DataSet = __webpack_require__(7); - exports.DataView = __webpack_require__(9); - exports.Queue = __webpack_require__(8); + exports.DataSet = __webpack_require__(3); + exports.DataView = __webpack_require__(4); + exports.Queue = __webpack_require__(5); // Graph3d - exports.Graph3d = __webpack_require__(10); + exports.Graph3d = __webpack_require__(6); exports.graph3d = { - Camera: __webpack_require__(14), - Filter: __webpack_require__(15), - Point2d: __webpack_require__(13), - Point3d: __webpack_require__(12), - Slider: __webpack_require__(16), - StepNumber: __webpack_require__(17) + Camera: __webpack_require__(7), + Filter: __webpack_require__(8), + Point2d: __webpack_require__(9), + Point3d: __webpack_require__(10), + Slider: __webpack_require__(11), + StepNumber: __webpack_require__(12) }; // Timeline - exports.Timeline = __webpack_require__(18); - exports.Graph2d = __webpack_require__(42); + exports.Timeline = __webpack_require__(13); + exports.Graph2d = __webpack_require__(14); exports.timeline = { - DateUtil: __webpack_require__(24), - DataStep: __webpack_require__(45), - Range: __webpack_require__(21), - stack: __webpack_require__(28), - TimeStep: __webpack_require__(38), + DateUtil: __webpack_require__(15), + DataStep: __webpack_require__(16), + Range: __webpack_require__(17), + stack: __webpack_require__(18), + TimeStep: __webpack_require__(19), components: { items: { - Item: __webpack_require__(30), - BackgroundItem: __webpack_require__(34), - BoxItem: __webpack_require__(32), - PointItem: __webpack_require__(33), - RangeItem: __webpack_require__(29) + Item: __webpack_require__(31), + BackgroundItem: __webpack_require__(32), + BoxItem: __webpack_require__(33), + PointItem: __webpack_require__(34), + RangeItem: __webpack_require__(35) }, - Component: __webpack_require__(23), - CurrentTime: __webpack_require__(39), - CustomTime: __webpack_require__(41), - DataAxis: __webpack_require__(44), - GraphGroup: __webpack_require__(46), - Group: __webpack_require__(27), - BackgroundGroup: __webpack_require__(31), - ItemSet: __webpack_require__(26), - Legend: __webpack_require__(50), - LineGraph: __webpack_require__(43), - TimeAxis: __webpack_require__(37) + Component: __webpack_require__(20), + CurrentTime: __webpack_require__(21), + CustomTime: __webpack_require__(22), + DataAxis: __webpack_require__(23), + GraphGroup: __webpack_require__(24), + Group: __webpack_require__(25), + BackgroundGroup: __webpack_require__(26), + ItemSet: __webpack_require__(27), + Legend: __webpack_require__(28), + LineGraph: __webpack_require__(29), + TimeAxis: __webpack_require__(30) } }; // Network - exports.Network = __webpack_require__(51); + exports.Network = __webpack_require__(36); exports.network = { - Edge: __webpack_require__(57), - Groups: __webpack_require__(54), - Images: __webpack_require__(55), - Node: __webpack_require__(56), - Popup: __webpack_require__(58), - dotparser: __webpack_require__(52), - gephiParser: __webpack_require__(53) + Edge: __webpack_require__(37), + Groups: __webpack_require__(38), + Images: __webpack_require__(39), + Node: __webpack_require__(40), + Popup: __webpack_require__(41), + dotparser: __webpack_require__(42), + gephiParser: __webpack_require__(43) }; // Deprecated since v3.0.0 @@ -152,8 +152,8 @@ return /******/ (function(modules) { // webpackBootstrap }; // bundled external libraries - exports.moment = __webpack_require__(2); - exports.hammer = __webpack_require__(19); + exports.moment = __webpack_require__(44); + exports.hammer = __webpack_require__(45); /***/ }, @@ -164,7 +164,7 @@ return /******/ (function(modules) { // webpackBootstrap // first check if moment.js is already loaded in the browser window, if so, // use this instance. Else, load via commonjs. - var moment = __webpack_require__(2); + var moment = __webpack_require__(44); /** * Test whether given object is a number @@ -1396,28761 +1396,28426 @@ return /******/ (function(modules) { // webpackBootstrap /* 2 */ /***/ function(module, exports, __webpack_require__) { - // first check if moment.js is already loaded in the browser window, if so, - // use this instance. Else, load via commonjs. - module.exports = (typeof window !== 'undefined') && window['moment'] || __webpack_require__(3); - - -/***/ }, -/* 3 */ -/***/ function(module, exports, __webpack_require__) { - - var __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(global, module) {//! moment.js - //! version : 2.9.0 - //! authors : Tim Wood, Iskren Chernev, Moment.js contributors - //! license : MIT - //! momentjs.com - - (function (undefined) { - /************************************ - Constants - ************************************/ - - var moment, - VERSION = '2.9.0', - // the global-scope this is NOT the global object in Node.js - globalScope = (typeof global !== 'undefined' && (typeof window === 'undefined' || window === global.window)) ? global : this, - oldGlobalMoment, - round = Math.round, - hasOwnProperty = Object.prototype.hasOwnProperty, - i, - - YEAR = 0, - MONTH = 1, - DATE = 2, - HOUR = 3, - MINUTE = 4, - SECOND = 5, - MILLISECOND = 6, - - // internal storage for locale config files - locales = {}, - - // extra moment internal properties (plugins register props here) - momentProperties = [], - - // check for nodeJS - hasModule = (typeof module !== 'undefined' && module && module.exports), - - // ASP.NET json date format regex - aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, - aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/, - - // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html - // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere - isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/, - - // format tokens - formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|x|X|zz?|ZZ?|.)/g, - localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, - - // parsing token regexes - parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 - parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 - parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999 - parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 - parseTokenDigits = /\d+/, // nonzero number of digits - parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic. - parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z - parseTokenT = /T/i, // T (ISO separator) - parseTokenOffsetMs = /[\+\-]?\d+/, // 1234567890123 - parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 - - //strict parsing regexes - parseTokenOneDigit = /\d/, // 0 - 9 - parseTokenTwoDigits = /\d\d/, // 00 - 99 - parseTokenThreeDigits = /\d{3}/, // 000 - 999 - parseTokenFourDigits = /\d{4}/, // 0000 - 9999 - parseTokenSixDigits = /[+-]?\d{6}/, // -999,999 - 999,999 - parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf - - // iso 8601 regex - // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) - isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/, - - isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', - - isoDates = [ - ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/], - ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/], - ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/], - ['GGGG-[W]WW', /\d{4}-W\d{2}/], - ['YYYY-DDD', /\d{4}-\d{3}/] - ], - - // iso time formats and regexes - isoTimes = [ - ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d+/], - ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], - ['HH:mm', /(T| )\d\d:\d\d/], - ['HH', /(T| )\d\d/] - ], - - // timezone chunker '+10:00' > ['10', '00'] or '-1530' > ['-', '15', '30'] - parseTimezoneChunker = /([\+\-]|\d\d)/gi, - - // getter and setter names - proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), - unitMillisecondFactors = { - 'Milliseconds' : 1, - 'Seconds' : 1e3, - 'Minutes' : 6e4, - 'Hours' : 36e5, - 'Days' : 864e5, - 'Months' : 2592e6, - 'Years' : 31536e6 - }, - - unitAliases = { - ms : 'millisecond', - s : 'second', - m : 'minute', - h : 'hour', - d : 'day', - D : 'date', - w : 'week', - W : 'isoWeek', - M : 'month', - Q : 'quarter', - y : 'year', - DDD : 'dayOfYear', - e : 'weekday', - E : 'isoWeekday', - gg: 'weekYear', - GG: 'isoWeekYear' - }, - - camelFunctions = { - dayofyear : 'dayOfYear', - isoweekday : 'isoWeekday', - isoweek : 'isoWeek', - weekyear : 'weekYear', - isoweekyear : 'isoWeekYear' - }, - - // format function strings - formatFunctions = {}, - - // default relative time thresholds - relativeTimeThresholds = { - 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 - ordinalizeTokens = 'DDD w W M D d'.split(' '), - paddedTokens = 'M D H h m s w W'.split(' '), - - formatTokenFunctions = { - M : function () { - return this.month() + 1; - }, - MMM : function (format) { - return this.localeData().monthsShort(this, format); - }, - MMMM : function (format) { - return this.localeData().months(this, format); - }, - D : function () { - return this.date(); - }, - DDD : function () { - return this.dayOfYear(); - }, - d : function () { - return this.day(); - }, - dd : function (format) { - return this.localeData().weekdaysMin(this, format); - }, - ddd : function (format) { - return this.localeData().weekdaysShort(this, format); - }, - dddd : function (format) { - return this.localeData().weekdays(this, format); - }, - w : function () { - return this.week(); - }, - W : function () { - return this.isoWeek(); - }, - YY : function () { - return leftZeroFill(this.year() % 100, 2); - }, - YYYY : function () { - return leftZeroFill(this.year(), 4); - }, - YYYYY : function () { - return leftZeroFill(this.year(), 5); - }, - YYYYYY : function () { - var y = this.year(), sign = y >= 0 ? '+' : '-'; - return sign + leftZeroFill(Math.abs(y), 6); - }, - gg : function () { - return leftZeroFill(this.weekYear() % 100, 2); - }, - gggg : function () { - return leftZeroFill(this.weekYear(), 4); - }, - ggggg : function () { - return leftZeroFill(this.weekYear(), 5); - }, - GG : function () { - return leftZeroFill(this.isoWeekYear() % 100, 2); - }, - GGGG : function () { - return leftZeroFill(this.isoWeekYear(), 4); - }, - GGGGG : function () { - return leftZeroFill(this.isoWeekYear(), 5); - }, - e : function () { - return this.weekday(); - }, - E : function () { - return this.isoWeekday(); - }, - a : function () { - return this.localeData().meridiem(this.hours(), this.minutes(), true); - }, - A : function () { - return this.localeData().meridiem(this.hours(), this.minutes(), false); - }, - H : function () { - return this.hours(); - }, - h : function () { - return this.hours() % 12 || 12; - }, - m : function () { - return this.minutes(); - }, - s : function () { - return this.seconds(); - }, - S : function () { - return toInt(this.milliseconds() / 100); - }, - SS : function () { - return leftZeroFill(toInt(this.milliseconds() / 10), 2); - }, - SSS : function () { - return leftZeroFill(this.milliseconds(), 3); - }, - SSSS : function () { - return leftZeroFill(this.milliseconds(), 3); - }, - Z : function () { - var a = this.utcOffset(), - b = '+'; - if (a < 0) { - a = -a; - b = '-'; - } - return b + leftZeroFill(toInt(a / 60), 2) + ':' + leftZeroFill(toInt(a) % 60, 2); - }, - ZZ : function () { - var a = this.utcOffset(), - b = '+'; - if (a < 0) { - a = -a; - b = '-'; - } - return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2); - }, - z : function () { - return this.zoneAbbr(); - }, - zz : function () { - return this.zoneName(); - }, - x : function () { - return this.valueOf(); - }, - X : function () { - return this.unix(); - }, - Q : function () { - return this.quarter(); - } - }, - - deprecations = {}, - - lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin'], - - updateInProgress = false; - - // Pick the first defined of two or three arguments. dfl comes from - // default. - function dfl(a, b, c) { - 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'); - } - } - - function hasOwnProp(a, b) { - return hasOwnProperty.call(a, b); - } - - function defaultParsingFlags() { - // We need to deep clone this object, and es5 standard is not very - // helpful. - return { - empty : false, - unusedTokens : [], - unusedInput : [], - overflow : -2, - charsLeftOver : 0, - nullInput : false, - invalidMonth : null, - invalidFormat : false, - userInvalidated : false, - iso: false - }; - } - - function printMsg(msg) { - if (moment.suppressDeprecationWarnings === false && - typeof console !== 'undefined' && console.warn) { - console.warn('Deprecation warning: ' + msg); - } - } + // DOM utility methods - function deprecate(msg, fn) { - var firstTime = true; - return extend(function () { - if (firstTime) { - printMsg(msg); - firstTime = false; - } - return fn.apply(this, arguments); - }, fn); + /** + * this prepares the JSON container for allocating SVG elements + * @param JSONcontainer + * @private + */ + exports.prepareElements = function(JSONcontainer) { + // cleanup the redundant svgElements; + for (var elementType in JSONcontainer) { + if (JSONcontainer.hasOwnProperty(elementType)) { + JSONcontainer[elementType].redundant = JSONcontainer[elementType].used; + JSONcontainer[elementType].used = []; } + } + }; - function deprecateSimple(name, msg) { - if (!deprecations[name]) { - printMsg(msg); - deprecations[name] = true; + /** + * this cleans up all the unused SVG elements. By asking for the parentNode, we only need to supply the JSON container from + * which to remove the redundant elements. + * + * @param JSONcontainer + * @private + */ + exports.cleanupElements = function(JSONcontainer) { + // cleanup the redundant svgElements; + for (var elementType in JSONcontainer) { + if (JSONcontainer.hasOwnProperty(elementType)) { + if (JSONcontainer[elementType].redundant) { + for (var i = 0; i < JSONcontainer[elementType].redundant.length; i++) { + JSONcontainer[elementType].redundant[i].parentNode.removeChild(JSONcontainer[elementType].redundant[i]); } + JSONcontainer[elementType].redundant = []; + } } + } + }; - function padToken(func, count) { - return function (a) { - return leftZeroFill(func.call(this, a), count); - }; + /** + * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer + * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this. + * + * @param elementType + * @param JSONcontainer + * @param svgContainer + * @returns {*} + * @private + */ + exports.getSVGElement = function (elementType, JSONcontainer, svgContainer) { + var element; + // allocate SVG element, if it doesnt yet exist, create one. + if (JSONcontainer.hasOwnProperty(elementType)) { // this element has been created before + // check if there is an redundant element + if (JSONcontainer[elementType].redundant.length > 0) { + element = JSONcontainer[elementType].redundant[0]; + JSONcontainer[elementType].redundant.shift(); } - function ordinalizeToken(func, period) { - return function (a) { - return this.localeData().ordinal(func.call(this, a), period); - }; + else { + // create a new element and add it to the SVG + element = document.createElementNS('http://www.w3.org/2000/svg', elementType); + svgContainer.appendChild(element); } + } + else { + // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it. + element = document.createElementNS('http://www.w3.org/2000/svg', elementType); + JSONcontainer[elementType] = {used: [], redundant: []}; + svgContainer.appendChild(element); + } + JSONcontainer[elementType].used.push(element); + return element; + }; - function monthDiff(a, b) { - // difference in months - var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()), - // b is in (anchor - 1 month, anchor + 1 month) - anchor = a.clone().add(wholeMonthDiff, 'months'), - anchor2, adjust; - - if (b - anchor < 0) { - anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); - // linear across the month - adjust = (b - anchor) / (anchor - anchor2); - } else { - anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); - // linear across the month - adjust = (b - anchor) / (anchor2 - anchor); - } - return -(wholeMonthDiff + adjust); + /** + * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer + * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this. + * + * @param elementType + * @param JSONcontainer + * @param DOMContainer + * @returns {*} + * @private + */ + exports.getDOMElement = function (elementType, JSONcontainer, DOMContainer, insertBefore) { + var element; + // allocate DOM element, if it doesnt yet exist, create one. + if (JSONcontainer.hasOwnProperty(elementType)) { // this element has been created before + // check if there is an redundant element + if (JSONcontainer[elementType].redundant.length > 0) { + element = JSONcontainer[elementType].redundant[0]; + JSONcontainer[elementType].redundant.shift(); } - - while (ordinalizeTokens.length) { - i = ordinalizeTokens.pop(); - formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i); + else { + // create a new element and add it to the SVG + element = document.createElement(elementType); + if (insertBefore !== undefined) { + DOMContainer.insertBefore(element, insertBefore); + } + else { + DOMContainer.appendChild(element); + } } - while (paddedTokens.length) { - i = paddedTokens.pop(); - formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); + } + else { + // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it. + element = document.createElement(elementType); + JSONcontainer[elementType] = {used: [], redundant: []}; + if (insertBefore !== undefined) { + DOMContainer.insertBefore(element, insertBefore); } - formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); - - - function meridiemFixWrap(locale, hour, meridiem) { - var isPm; - - if (meridiem == null) { - // nothing to do - return hour; - } - if (locale.meridiemHour != null) { - return locale.meridiemHour(hour, meridiem); - } else if (locale.isPM != null) { - // Fallback - isPm = locale.isPM(meridiem); - if (isPm && hour < 12) { - hour += 12; - } - if (!isPm && hour === 12) { - hour = 0; - } - return hour; - } else { - // thie is not supposed to happen - return hour; - } + else { + DOMContainer.appendChild(element); } + } + JSONcontainer[elementType].used.push(element); + return element; + }; - /************************************ - Constructors - ************************************/ - function Locale() { - } - // Moment prototype object - function Moment(config, skipOverflow) { - if (skipOverflow !== false) { - checkOverflow(config); - } - copyConfig(this, config); - this._d = new Date(+config._d); - // Prevent infinite loop in case updateOffset creates new moment - // objects. - if (updateInProgress === false) { - updateInProgress = true; - moment.updateOffset(this); - updateInProgress = false; - } - } - - // Duration Constructor - function Duration(duration) { - var normalizedInput = normalizeObjectUnits(duration), - years = normalizedInput.year || 0, - quarters = normalizedInput.quarter || 0, - months = normalizedInput.month || 0, - weeks = normalizedInput.week || 0, - days = normalizedInput.day || 0, - hours = normalizedInput.hour || 0, - minutes = normalizedInput.minute || 0, - seconds = normalizedInput.second || 0, - milliseconds = normalizedInput.millisecond || 0; - // representation for dateAddRemove - this._milliseconds = +milliseconds + - seconds * 1e3 + // 1000 - minutes * 6e4 + // 1000 * 60 - hours * 36e5; // 1000 * 60 * 60 - // Because of dateAddRemove treats 24 hours as different from a - // day when working around DST, we need to store them separately - this._days = +days + - weeks * 7; - // It is impossible translate months into days without knowing - // which months you are are talking about, so we have to store - // it separately. - this._months = +months + - quarters * 3 + - years * 12; - - this._data = {}; + /** + * draw a point object. this is a seperate function because it can also be called by the legend. + * The reason the JSONcontainer and the target SVG svgContainer have to be supplied is so the legend can use these functions + * as well. + * + * @param x + * @param y + * @param group + * @param JSONcontainer + * @param svgContainer + * @returns {*} + */ + exports.drawPoint = function(x, y, group, JSONcontainer, svgContainer) { + var point; + if (group.options.drawPoints.style == 'circle') { + point = exports.getSVGElement('circle',JSONcontainer,svgContainer); + point.setAttributeNS(null, "cx", x); + point.setAttributeNS(null, "cy", y); + point.setAttributeNS(null, "r", 0.5 * group.options.drawPoints.size); + } + else { + point = exports.getSVGElement('rect',JSONcontainer,svgContainer); + point.setAttributeNS(null, "x", x - 0.5*group.options.drawPoints.size); + point.setAttributeNS(null, "y", y - 0.5*group.options.drawPoints.size); + point.setAttributeNS(null, "width", group.options.drawPoints.size); + point.setAttributeNS(null, "height", group.options.drawPoints.size); + } - this._locale = moment.localeData(); + if(group.options.drawPoints.styles !== undefined) { + point.setAttributeNS(null, "style", group.group.options.drawPoints.styles); + } + point.setAttributeNS(null, "class", group.className + " point"); + return point; + }; - this._bubble(); + /** + * draw a bar SVG element centered on the X coordinate + * + * @param x + * @param y + * @param className + */ + exports.drawBar = function (x, y, width, height, className, JSONcontainer, svgContainer) { + if (height != 0) { + if (height < 0) { + height *= -1; + y -= height; } + var rect = exports.getSVGElement('rect',JSONcontainer, svgContainer); + rect.setAttributeNS(null, "x", x - 0.5 * width); + rect.setAttributeNS(null, "y", y); + rect.setAttributeNS(null, "width", width); + rect.setAttributeNS(null, "height", height); + rect.setAttributeNS(null, "class", className); + } + }; - /************************************ - Helpers - ************************************/ +/***/ }, +/* 3 */ +/***/ function(module, exports, __webpack_require__) { + var util = __webpack_require__(1); + var Queue = __webpack_require__(5); - function extend(a, b) { - for (var i in b) { - if (hasOwnProp(b, i)) { - a[i] = b[i]; - } - } + /** + * DataSet + * + * Usage: + * var dataSet = new DataSet({ + * fieldId: '_id', + * type: { + * // ... + * } + * }); + * + * dataSet.add(item); + * dataSet.add(data); + * dataSet.update(item); + * dataSet.update(data); + * dataSet.remove(id); + * dataSet.remove(ids); + * var data = dataSet.get(); + * var data = dataSet.get(id); + * var data = dataSet.get(ids); + * var data = dataSet.get(ids, options, data); + * dataSet.clear(); + * + * A data set can: + * - add/remove/update data + * - gives triggers upon changes in the data + * - can import/export data in various data formats + * + * @param {Array | DataTable} [data] Optional array with initial data + * @param {Object} [options] Available options: + * {String} fieldId Field name of the id in the + * items, 'id' by default. + * {Object. 0) { - for (i in momentProperties) { - prop = momentProperties[i]; - val = from[prop]; - if (typeof val !== 'undefined') { - to[prop] = val; - } - } - } + // add initial data when provided + if (data) { + this.add(data); + } - return to; - } + this.setOptions(options); + } - function absRound(number) { - if (number < 0) { - return Math.ceil(number); - } else { - return Math.floor(number); - } + /** + * @param {Object} [options] Available options: + * {Object} queue Queue changes to the DataSet, + * flush them all at once. + * Queue options: + * - {number} delay Delay in ms, null by default + * - {number} max Maximum number of entries in the queue, Infinity by default + * @param options + */ + DataSet.prototype.setOptions = function(options) { + if (options && options.queue !== undefined) { + if (options.queue === false) { + // delete queue if loaded + if (this._queue) { + this._queue.destroy(); + delete this._queue; + } } + else { + // create queue and update its options + if (!this._queue) { + this._queue = Queue.extend(this, { + replace: ['add', 'update', 'remove'] + }); + } - // left zero fill a number - // see http://jsperf.com/left-zero-filling for performance comparison - function leftZeroFill(number, targetLength, forceSign) { - var output = '' + Math.abs(number), - sign = number >= 0; - - while (output.length < targetLength) { - output = '0' + output; - } - return (sign ? (forceSign ? '+' : '') : '-') + output; + if (typeof options.queue === 'object') { + this._queue.setOptions(options.queue); + } } + } + }; - function positiveMomentsDifference(base, other) { - var res = {milliseconds: 0, months: 0}; + /** + * Subscribe to an event, add an event listener + * @param {String} event Event name. Available events: 'put', 'update', + * 'remove' + * @param {function} callback Callback method. Called with three parameters: + * {String} event + * {Object | null} params + * {String | Number} senderId + */ + DataSet.prototype.on = function(event, callback) { + var subscribers = this._subscribers[event]; + if (!subscribers) { + subscribers = []; + this._subscribers[event] = subscribers; + } - res.months = other.month() - base.month() + - (other.year() - base.year()) * 12; - if (base.clone().add(res.months, 'M').isAfter(other)) { - --res.months; - } + subscribers.push({ + callback: callback + }); + }; - res.milliseconds = +other - +(base.clone().add(res.months, 'M')); + // TODO: make this function deprecated (replaced with `on` since version 0.5) + DataSet.prototype.subscribe = DataSet.prototype.on; - return res; - } + /** + * Unsubscribe from an event, remove an event listener + * @param {String} event + * @param {function} callback + */ + DataSet.prototype.off = function(event, callback) { + var subscribers = this._subscribers[event]; + if (subscribers) { + this._subscribers[event] = subscribers.filter(function (listener) { + return (listener.callback != callback); + }); + } + }; - 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; - } + // TODO: make this function deprecated (replaced with `on` since version 0.5) + DataSet.prototype.unsubscribe = DataSet.prototype.off; - return res; - } + /** + * Trigger an event + * @param {String} event + * @param {Object | null} params + * @param {String} [senderId] Optional id of the sender. + * @private + */ + DataSet.prototype._trigger = function (event, params, senderId) { + if (event == '*') { + throw new Error('Cannot trigger event *'); + } - // 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; - } + var subscribers = []; + if (event in this._subscribers) { + subscribers = subscribers.concat(this._subscribers[event]); + } + if ('*' in this._subscribers) { + subscribers = subscribers.concat(this._subscribers['*']); + } - val = typeof val === 'string' ? +val : val; - dur = moment.duration(val, period); - addOrSubtractDurationFromMoment(this, dur, direction); - return this; - }; + for (var i = 0; i < subscribers.length; i++) { + var subscriber = subscribers[i]; + if (subscriber.callback) { + subscriber.callback(event, params, senderId || null); } + } + }; - function addOrSubtractDurationFromMoment(mom, duration, isAdding, updateOffset) { - var milliseconds = duration._milliseconds, - days = duration._days, - months = duration._months; - updateOffset = updateOffset == null ? true : updateOffset; + /** + * Add data. + * Adding an item will fail when there already is an item with the same id. + * @param {Object | Array | DataTable} data + * @param {String} [senderId] Optional sender id + * @return {Array} addedIds Array with the ids of the added items + */ + DataSet.prototype.add = function (data, senderId) { + var addedIds = [], + id, + me = this; - if (milliseconds) { - mom._d.setTime(+mom._d + milliseconds * isAdding); - } - if (days) { - rawSetter(mom, 'Date', rawGetter(mom, 'Date') + days * isAdding); - } - if (months) { - rawMonthSetter(mom, rawGetter(mom, 'Month') + months * isAdding); - } - if (updateOffset) { - moment.updateOffset(mom, days || months); - } + if (Array.isArray(data)) { + // Array + for (var i = 0, len = data.length; i < len; i++) { + id = me._addItem(data[i]); + addedIds.push(id); } + } + else if (util.isDataTable(data)) { + // Google DataTable + var columns = this._getColumnNames(data); + for (var row = 0, rows = data.getNumberOfRows(); row < rows; row++) { + var item = {}; + for (var col = 0, cols = columns.length; col < cols; col++) { + var field = columns[col]; + item[field] = data.getValue(row, col); + } - // check if is an array - function isArray(input) { - return Object.prototype.toString.call(input) === '[object Array]'; + id = me._addItem(item); + addedIds.push(id); } + } + else if (data instanceof Object) { + // Single item + id = me._addItem(data); + addedIds.push(id); + } + else { + throw new Error('Unknown dataType'); + } - function isDate(input) { - return Object.prototype.toString.call(input) === '[object Date]' || - input instanceof Date; - } + if (addedIds.length) { + this._trigger('add', {items: addedIds}, senderId); + } - // compare two arrays, return the number of differences - function compareArrays(array1, array2, dontConvert) { - var len = Math.min(array1.length, array2.length), - lengthDiff = Math.abs(array1.length - array2.length), - diffs = 0, - i; - for (i = 0; i < len; i++) { - if ((dontConvert && array1[i] !== array2[i]) || - (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { - diffs++; - } - } - return diffs + lengthDiff; - } + return addedIds; + }; - function normalizeUnits(units) { - if (units) { - var lowered = units.toLowerCase().replace(/(.)s$/, '$1'); - units = unitAliases[units] || camelFunctions[lowered] || lowered; - } - return units; - } + /** + * Update existing items. When an item does not exist, it will be created + * @param {Object | Array | DataTable} data + * @param {String} [senderId] Optional sender id + * @return {Array} updatedIds The ids of the added or updated items + */ + DataSet.prototype.update = function (data, senderId) { + var addedIds = []; + var updatedIds = []; + var updatedData = []; + var me = this; + var fieldId = me._fieldId; - function normalizeObjectUnits(inputObject) { - var normalizedInput = {}, - normalizedProp, - prop; + var addOrUpdate = function (item) { + var id = item[fieldId]; + if (me._data[id]) { + // update item + id = me._updateItem(item); + updatedIds.push(id); + updatedData.push(item); + } + else { + // add new item + id = me._addItem(item); + addedIds.push(id); + } + }; - for (prop in inputObject) { - if (hasOwnProp(inputObject, prop)) { - normalizedProp = normalizeUnits(prop); - if (normalizedProp) { - normalizedInput[normalizedProp] = inputObject[prop]; - } - } - } + if (Array.isArray(data)) { + // Array + for (var i = 0, len = data.length; i < len; i++) { + addOrUpdate(data[i]); + } + } + else if (util.isDataTable(data)) { + // Google DataTable + var columns = this._getColumnNames(data); + for (var row = 0, rows = data.getNumberOfRows(); row < rows; row++) { + var item = {}; + for (var col = 0, cols = columns.length; col < cols; col++) { + var field = columns[col]; + item[field] = data.getValue(row, col); + } - return normalizedInput; + addOrUpdate(item); } + } + else if (data instanceof Object) { + // Single item + addOrUpdate(data); + } + else { + throw new Error('Unknown dataType'); + } - function makeList(field) { - var count, setter; + if (addedIds.length) { + this._trigger('add', {items: addedIds}, senderId); + } + if (updatedIds.length) { + this._trigger('update', {items: updatedIds, data: updatedData}, senderId); + } - if (field.indexOf('week') === 0) { - count = 7; - setter = 'day'; - } - else if (field.indexOf('month') === 0) { - count = 12; - setter = 'month'; - } - else { - return; - } + return addedIds.concat(updatedIds); + }; - moment[field] = function (format, index) { - var i, getter, - method = moment._locale[field], - results = []; + /** + * Get a data item or multiple items. + * + * Usage: + * + * get() + * get(options: Object) + * get(options: Object, data: Array | DataTable) + * + * get(id: Number | String) + * get(id: Number | String, options: Object) + * get(id: Number | String, options: Object, data: Array | DataTable) + * + * get(ids: Number[] | String[]) + * get(ids: Number[] | String[], options: Object) + * get(ids: Number[] | String[], options: Object, data: Array | DataTable) + * + * Where: + * + * {Number | String} id The id of an item + * {Number[] | String{}} ids An array with ids of items + * {Object} options An Object with options. Available options: + * {String} [returnType] Type of data to be + * returned. Can be 'DataTable' or 'Array' (default) + * {Object.} [type] + * {String[]} [fields] field names to be returned + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * {Array | DataTable} [data] If provided, items will be appended to this + * array or table. Required in case of Google + * DataTable. + * + * @throws Error + */ + DataSet.prototype.get = function (args) { + var me = this; - if (typeof format === 'number') { - index = format; - format = undefined; - } + // parse the arguments + var id, ids, options, data; + var firstType = util.getType(arguments[0]); + if (firstType == 'String' || firstType == 'Number') { + // get(id [, options] [, data]) + id = arguments[0]; + options = arguments[1]; + data = arguments[2]; + } + else if (firstType == 'Array') { + // get(ids [, options] [, data]) + ids = arguments[0]; + options = arguments[1]; + data = arguments[2]; + } + else { + // get([, options] [, data]) + options = arguments[0]; + data = arguments[1]; + } - getter = function (i) { - var m = moment().utc().set(setter, i); - return method.call(moment._locale, m, format || ''); - }; + // determine the return type + var returnType; + if (options && options.returnType) { + var allowedValues = ["DataTable", "Array", "Object"]; + returnType = allowedValues.indexOf(options.returnType) == -1 ? "Array" : options.returnType; - if (index != null) { - return getter(index); - } - else { - for (i = 0; i < count; i++) { - results.push(getter(i)); - } - return results; - } - }; + if (data && (returnType != util.getType(data))) { + throw new Error('Type of parameter "data" (' + util.getType(data) + ') ' + + 'does not correspond with specified options.type (' + options.type + ')'); + } + if (returnType == 'DataTable' && !util.isDataTable(data)) { + throw new Error('Parameter "data" must be a DataTable ' + + 'when options.type is "DataTable"'); } + } + else if (data) { + returnType = (util.getType(data) == 'DataTable') ? 'DataTable' : 'Array'; + } + else { + returnType = 'Array'; + } - function toInt(argumentForCoercion) { - var coercedNumber = +argumentForCoercion, - value = 0; + // build options + var type = options && options.type || this._options.type; + var filter = options && options.filter; + var items = [], item, itemId, i, len; - if (coercedNumber !== 0 && isFinite(coercedNumber)) { - if (coercedNumber >= 0) { - value = Math.floor(coercedNumber); - } else { - value = Math.ceil(coercedNumber); - } + // convert items + if (id != undefined) { + // return a single item + item = me._getItem(id, type); + if (filter && !filter(item)) { + item = null; + } + } + else if (ids != undefined) { + // return a subset of items + for (i = 0, len = ids.length; i < len; i++) { + item = me._getItem(ids[i], type); + if (!filter || filter(item)) { + items.push(item); + } + } + } + else { + // return all items + for (itemId in this._data) { + if (this._data.hasOwnProperty(itemId)) { + item = me._getItem(itemId, type); + if (!filter || filter(item)) { + items.push(item); } + } + } + } + + // order the results + if (options && options.order && id == undefined) { + this._sort(items, options.order); + } - return value; + // filter fields of the items + if (options && options.fields) { + var fields = options.fields; + if (id != undefined) { + item = this._filterFields(item, fields); } - - function daysInMonth(year, month) { - return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); + else { + for (i = 0, len = items.length; i < len; i++) { + items[i] = this._filterFields(items[i], fields); + } } + } - function weeksInYear(year, dow, doy) { - return weekOfYear(moment([year, 11, 31 + dow - doy]), dow, doy).week; + // return the results + if (returnType == 'DataTable') { + var columns = this._getColumnNames(data); + if (id != undefined) { + // append a single item to the data table + me._appendRow(data, columns, item); } - - function daysInYear(year) { - return isLeapYear(year) ? 366 : 365; + else { + // copy the items to the provided data table + for (i = 0; i < items.length; i++) { + me._appendRow(data, columns, items[i]); + } } - - function isLeapYear(year) { - return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; + return data; + } + else if (returnType == "Object") { + var result = {}; + for (i = 0; i < items.length; i++) { + result[items[i].id] = items[i]; } - - function checkOverflow(m) { - var overflow; - if (m._a && m._pf.overflow === -2) { - overflow = - m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH : - m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE : - m._a[HOUR] < 0 || m._a[HOUR] > 24 || - (m._a[HOUR] === 24 && (m._a[MINUTE] !== 0 || - m._a[SECOND] !== 0 || - m._a[MILLISECOND] !== 0)) ? HOUR : - m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE : - m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND : - m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND : - -1; - - if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { - overflow = DATE; - } - - m._pf.overflow = overflow; + return result; + } + else { + // return an array + if (id != undefined) { + // a single item + return item; + } + else { + // multiple items + if (data) { + // copy the items to the provided array + for (i = 0, len = items.length; i < len; i++) { + data.push(items[i]); } + return data; + } + else { + // just return our array + return items; + } } + } + }; - function isValid(m) { - if (m._isValid == null) { - m._isValid = !isNaN(m._d.getTime()) && - m._pf.overflow < 0 && - !m._pf.empty && - !m._pf.invalidMonth && - !m._pf.nullInput && - !m._pf.invalidFormat && - !m._pf.userInvalidated; + /** + * Get ids of all items or from a filtered set of items. + * @param {Object} [options] An Object with options. Available options: + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * @return {Array} ids + */ + DataSet.prototype.getIds = function (options) { + var data = this._data, + filter = options && options.filter, + order = options && options.order, + type = options && options.type || this._options.type, + i, + len, + id, + item, + items, + ids = []; - if (m._strict) { - m._isValid = m._isValid && - m._pf.charsLeftOver === 0 && - m._pf.unusedTokens.length === 0 && - m._pf.bigHour === undefined; - } + if (filter) { + // get filtered items + if (order) { + // create ordered list + items = []; + for (id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, type); + if (filter(item)) { + items.push(item); + } } - return m._isValid; - } - - 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; + this._sort(items, order); - 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; + for (i = 0, len = items.length; i < len; i++) { + ids[i] = items[i][this._fieldId]; + } } - - 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) { } + else { + // create unordered list + for (id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, type); + if (filter(item)) { + ids.push(item[this._fieldId]); + } } - return locales[name]; + } } - - // Return a moment from input, that is local/utc/utcOffset equivalent to - // model. - function makeAs(input, model) { - var res, diff; - if (model._isUTC) { - res = model.clone(); - diff = (moment.isMoment(input) || isDate(input) ? - +input : +moment(input)) - (+res); - // Use low-level api, because this fn is low-level api. - res._d.setTime(+res._d + diff); - moment.updateOffset(res, false); - return res; - } else { - return moment(input).local(); + } + else { + // get all items + if (order) { + // create an ordered list + items = []; + for (id in data) { + if (data.hasOwnProperty(id)) { + items.push(data[id]); } - } - - /************************************ - Locale - ************************************/ - - - extend(Locale.prototype, { - - set : function (config) { - var prop, i; - for (i in config) { - prop = config[i]; - if (typeof prop === 'function') { - this[i] = prop; - } else { - this['_' + i] = prop; - } - } - // Lenient ordinal parsing accepts just a number in addition to - // number + (possibly) stuff coming from _ordinalParseLenient. - this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + /\d{1,2}/.source); - }, - - _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 : function (m) { - return this._monthsShort[m.month()]; - }, - - monthsParse : function (monthName, format, strict) { - var i, mom, regex; - - if (!this._monthsParse) { - this._monthsParse = []; - this._longMonthsParse = []; - this._shortMonthsParse = []; - } - - for (i = 0; i < 12; i++) { - // make the regex if we don't have it already - mom = moment.utc([2000, i]); - if (strict && !this._longMonthsParse[i]) { - this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i'); - this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i'); - } - if (!strict && !this._monthsParse[i]) { - regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); - this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) { - return i; - } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) { - return i; - } else if (!strict && this._monthsParse[i].test(monthName)) { - return i; - } - } - }, + } - _weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), - weekdays : function (m) { - return this._weekdays[m.day()]; - }, + this._sort(items, order); - _weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), - weekdaysShort : function (m) { - return this._weekdaysShort[m.day()]; - }, + for (i = 0, len = items.length; i < len; i++) { + ids[i] = items[i][this._fieldId]; + } + } + else { + // create unordered list + for (id in data) { + if (data.hasOwnProperty(id)) { + item = data[id]; + ids.push(item[this._fieldId]); + } + } + } + } - _weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), - weekdaysMin : function (m) { - return this._weekdaysMin[m.day()]; - }, + return ids; + }; - weekdaysParse : function (weekdayName) { - var i, mom, regex; + /** + * Returns the DataSet itself. Is overwritten for example by the DataView, + * which returns the DataSet it is connected to instead. + */ + DataSet.prototype.getDataSet = function () { + return this; + }; - if (!this._weekdaysParse) { - this._weekdaysParse = []; - } + /** + * Execute a callback function for every item in the dataset. + * @param {function} callback + * @param {Object} [options] Available options: + * {Object.} [type] + * {String[]} [fields] filter fields + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + */ + DataSet.prototype.forEach = function (callback, options) { + var filter = options && options.filter, + type = options && options.type || this._options.type, + data = this._data, + item, + id; - for (i = 0; i < 7; i++) { - // make the regex if we don't have it already - if (!this._weekdaysParse[i]) { - mom = moment([2000, 1]).day(i); - regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); - this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (this._weekdaysParse[i].test(weekdayName)) { - return i; - } - } - }, + if (options && options.order) { + // execute forEach on ordered list + var items = this.get(options); - _longDateFormat : { - LTS : 'h:mm:ss A', - 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]; - if (!output && this._longDateFormat[key.toUpperCase()]) { - output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { - return val.slice(1); - }); - this._longDateFormat[key] = output; - } - return output; - }, + for (var i = 0, len = items.length; i < len; i++) { + item = items[i]; + id = item[this._fieldId]; + callback(item, id); + } + } + else { + // unordered + for (id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, type); + if (!filter || filter(item)) { + callback(item, id); + } + } + } + } + }; - isPM : function (input) { - // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays - // Using charAt should be more compatible. - return ((input + '').toLowerCase().charAt(0) === 'p'); - }, + /** + * Map every item in the dataset. + * @param {function} callback + * @param {Object} [options] Available options: + * {Object.} [type] + * {String[]} [fields] filter fields + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * @return {Object[]} mappedItems + */ + DataSet.prototype.map = function (callback, options) { + var filter = options && options.filter, + type = options && options.type || this._options.type, + mappedItems = [], + data = this._data, + item; - _meridiemParse : /[ap]\.?m?\.?/i, - meridiem : function (hours, minutes, isLower) { - if (hours > 11) { - return isLower ? 'pm' : 'PM'; - } else { - return isLower ? 'am' : 'AM'; - } - }, + // convert and filter items + for (var id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, type); + if (!filter || filter(item)) { + mappedItems.push(callback(item, id)); + } + } + } + // order items + if (options && options.order) { + this._sort(mappedItems, options.order); + } - _calendar : { - sameDay : '[Today at] LT', - nextDay : '[Tomorrow at] LT', - nextWeek : 'dddd [at] LT', - lastDay : '[Yesterday at] LT', - lastWeek : '[Last] dddd [at] LT', - sameElse : 'L' - }, - calendar : function (key, mom, now) { - var output = this._calendar[key]; - return typeof output === 'function' ? output.apply(mom, [now]) : output; - }, + return mappedItems; + }; - _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' - }, + /** + * Filter the fields of an item + * @param {Object} item + * @param {String[]} fields Field names + * @return {Object} filteredItem + * @private + */ + DataSet.prototype._filterFields = function (item, fields) { + var filteredItem = {}; - 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); - }, + for (var field in item) { + if (item.hasOwnProperty(field) && (fields.indexOf(field) != -1)) { + filteredItem[field] = item[field]; + } + } - pastFuture : function (diff, output) { - var format = this._relativeTime[diff > 0 ? 'future' : 'past']; - return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); - }, + return filteredItem; + }; - ordinal : function (number) { - return this._ordinal.replace('%d', number); - }, - _ordinal : '%d', - _ordinalParse : /\d{1,2}/, + /** + * Sort the provided array with items + * @param {Object[]} items + * @param {String | function} order A field name or custom sort function. + * @private + */ + DataSet.prototype._sort = function (items, order) { + if (util.isString(order)) { + // order by provided field name + var name = order; // field name + items.sort(function (a, b) { + var av = a[name]; + var bv = b[name]; + return (av > bv) ? 1 : ((av < bv) ? -1 : 0); + }); + } + else if (typeof order === 'function') { + // order by sort function + items.sort(order); + } + // TODO: extend order by an Object {field:String, direction:String} + // where direction can be 'asc' or 'desc' + else { + throw new TypeError('Order must be a function or a string'); + } + }; - preparse : function (string) { - return string; - }, + /** + * Remove an object by pointer or by id + * @param {String | Number | Object | Array} id Object or id, or an array with + * objects or ids to be removed + * @param {String} [senderId] Optional sender id + * @return {Array} removedIds + */ + DataSet.prototype.remove = function (id, senderId) { + var removedIds = [], + i, len, removedId; - postformat : function (string) { - return string; - }, + if (Array.isArray(id)) { + for (i = 0, len = id.length; i < len; i++) { + removedId = this._remove(id[i]); + if (removedId != null) { + removedIds.push(removedId); + } + } + } + else { + removedId = this._remove(id); + if (removedId != null) { + removedIds.push(removedId); + } + } - week : function (mom) { - return weekOfYear(mom, this._week.dow, this._week.doy).week; - }, + if (removedIds.length) { + this._trigger('remove', {items: removedIds}, senderId); + } - _week : { - dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. - }, + return removedIds; + }; - firstDayOfWeek : function () { - return this._week.dow; - }, + /** + * Remove an item by its id + * @param {Number | String | Object} id id or item + * @returns {Number | String | null} id + * @private + */ + DataSet.prototype._remove = function (id) { + if (util.isNumber(id) || util.isString(id)) { + if (this._data[id]) { + delete this._data[id]; + return id; + } + } + else if (id instanceof Object) { + var itemId = id[this._fieldId]; + if (itemId && this._data[itemId]) { + delete this._data[itemId]; + return itemId; + } + } + return null; + }; - firstDayOfYear : function () { - return this._week.doy; - }, + /** + * Clear the data + * @param {String} [senderId] Optional sender id + * @return {Array} removedIds The ids of all removed items + */ + DataSet.prototype.clear = function (senderId) { + var ids = Object.keys(this._data); - _invalidDate: 'Invalid date', - invalidDate: function () { - return this._invalidDate; - } - }); + this._data = {}; - /************************************ - Formatting - ************************************/ + this._trigger('remove', {items: ids}, senderId); + return ids; + }; - function removeFormattingTokens(input) { - if (input.match(/\[[\s\S]/)) { - return input.replace(/^\[|\]$/g, ''); - } - return input.replace(/\\/g, ''); + /** + * Find the item with maximum value of a specified field + * @param {String} field + * @return {Object | null} item Item containing max value, or null if no items + */ + DataSet.prototype.max = function (field) { + var data = this._data, + max = null, + maxField = null; + + for (var id in data) { + if (data.hasOwnProperty(id)) { + var item = data[id]; + var itemField = item[field]; + if (itemField != null && (!max || itemField > maxField)) { + max = item; + maxField = itemField; + } } + } - function makeFormatFunction(format) { - var array = format.match(formattingTokens), i, length; + return max; + }; - for (i = 0, length = array.length; i < length; i++) { - if (formatTokenFunctions[array[i]]) { - array[i] = formatTokenFunctions[array[i]]; - } else { - array[i] = removeFormattingTokens(array[i]); - } - } + /** + * Find the item with minimum value of a specified field + * @param {String} field + * @return {Object | null} item Item containing max value, or null if no items + */ + DataSet.prototype.min = function (field) { + var data = this._data, + min = null, + minField = null; - return function (mom) { - var output = ''; - for (i = 0; i < length; i++) { - output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; - } - return output; - }; + for (var id in data) { + if (data.hasOwnProperty(id)) { + var item = data[id]; + var itemField = item[field]; + if (itemField != null && (!min || itemField < minField)) { + min = item; + minField = itemField; + } } + } - // format date using native date object - function formatMoment(m, format) { - if (!m.isValid()) { - return m.localeData().invalidDate(); - } + return min; + }; - format = expandFormat(format, m.localeData()); + /** + * Find all distinct values of a specified field + * @param {String} field + * @return {Array} values Array containing all distinct values. If data items + * do not contain the specified field are ignored. + * The returned array is unordered. + */ + DataSet.prototype.distinct = function (field) { + var data = this._data; + var values = []; + var fieldType = this._options.type && this._options.type[field] || null; + var count = 0; + var i; - if (!formatFunctions[format]) { - formatFunctions[format] = makeFormatFunction(format); + for (var prop in data) { + if (data.hasOwnProperty(prop)) { + var item = data[prop]; + var value = item[field]; + var exists = false; + for (i = 0; i < count; i++) { + if (values[i] == value) { + exists = true; + break; } + } + if (!exists && (value !== undefined)) { + values[count] = value; + count++; + } + } + } - return formatFunctions[format](m); + if (fieldType) { + for (i = 0; i < values.length; i++) { + values[i] = util.convert(values[i], fieldType); } + } - function expandFormat(format, locale) { - var i = 5; + return values; + }; - function replaceLongDateFormatTokens(input) { - return locale.longDateFormat(input) || input; - } + /** + * Add a single item. Will fail when an item with the same id already exists. + * @param {Object} item + * @return {String} id + * @private + */ + DataSet.prototype._addItem = function (item) { + var id = item[this._fieldId]; - localFormattingTokens.lastIndex = 0; - while (i >= 0 && localFormattingTokens.test(format)) { - format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); - localFormattingTokens.lastIndex = 0; - i -= 1; - } + if (id != undefined) { + // check whether this id is already taken + if (this._data[id]) { + // item already exists + throw new Error('Cannot add item: item with id ' + id + ' already exists'); + } + } + else { + // generate an id + id = util.randomUUID(); + item[this._fieldId] = id; + } - return format; + var d = {}; + for (var field in item) { + if (item.hasOwnProperty(field)) { + var fieldType = this._type[field]; // type may be undefined + d[field] = util.convert(item[field], fieldType); } + } + this._data[id] = d; + return id; + }; - /************************************ - Parsing - ************************************/ + /** + * Get an item. Fields can be converted to a specific type + * @param {String} id + * @param {Object.} [types] field types to convert + * @return {Object | null} item + * @private + */ + DataSet.prototype._getItem = function (id, types) { + var field, value; + // get the item from the dataset + var raw = this._data[id]; + if (!raw) { + return null; + } - // get the regex to find the next token - function getParseRegexForToken(token, config) { - var a, strict = config._strict; - switch (token) { - case 'Q': - return parseTokenOneDigit; - case 'DDDD': - return parseTokenThreeDigits; - case 'YYYY': - case 'GGGG': - case 'gggg': - return strict ? parseTokenFourDigits : parseTokenOneToFourDigits; - case 'Y': - case 'G': - case 'g': - return parseTokenSignedNumber; - case 'YYYYYY': - case 'YYYYY': - case 'GGGGG': - case 'ggggg': - return strict ? parseTokenSixDigits : parseTokenOneToSixDigits; - case 'S': - if (strict) { - return parseTokenOneDigit; - } - /* falls through */ - case 'SS': - if (strict) { - return parseTokenTwoDigits; - } - /* falls through */ - case 'SSS': - if (strict) { - return parseTokenThreeDigits; - } - /* falls through */ - case 'DDD': - return parseTokenOneToThreeDigits; - case 'MMM': - case 'MMMM': - case 'dd': - case 'ddd': - case 'dddd': - return parseTokenWord; - case 'a': - case 'A': - return config._locale._meridiemParse; - case 'x': - return parseTokenOffsetMs; - case 'X': - return parseTokenTimestampMs; - case 'Z': - case 'ZZ': - return parseTokenTimezone; - case 'T': - return parseTokenT; - case 'SSSS': - return parseTokenDigits; - case 'MM': - case 'DD': - case 'YY': - case 'GG': - case 'gg': - case 'HH': - case 'hh': - case 'mm': - case 'ss': - case 'ww': - case 'WW': - return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits; - case 'M': - case 'D': - case 'd': - case 'H': - case 'h': - case 'm': - case 's': - case 'w': - case 'W': - case 'e': - case 'E': - return parseTokenOneOrTwoDigits; - case 'Do': - return strict ? config._locale._ordinalParse : config._locale._ordinalParseLenient; - default : - a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), 'i')); - return a; - } + // convert the items field types + var converted = {}; + if (types) { + for (field in raw) { + if (raw.hasOwnProperty(field)) { + value = raw[field]; + converted[field] = util.convert(value, types[field]); + } } - - function utcOffsetFromString(string) { - string = string || ''; - var possibleTzMatches = (string.match(parseTokenTimezone) || []), - tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [], - parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0], - minutes = +(parts[1] * 60) + toInt(parts[2]); - - return parts[0] === '+' ? minutes : -minutes; + } + else { + // no field types specified, no converting needed + for (field in raw) { + if (raw.hasOwnProperty(field)) { + value = raw[field]; + converted[field] = value; + } } - - // function to convert string input to date - function addTimeToArrayFromToken(token, input, config) { - var a, datePartArray = config._a; - - switch (token) { - // QUARTER - case 'Q': - if (input != null) { - datePartArray[MONTH] = (toInt(input) - 1) * 3; - } - break; - // MONTH - case 'M' : // fall through to MM - case 'MM' : - if (input != null) { - datePartArray[MONTH] = toInt(input) - 1; - } - break; - case 'MMM' : // fall through to MMMM - case 'MMMM' : - a = config._locale.monthsParse(input, token, config._strict); - // if we didn't find a month name, mark the date as invalid. - if (a != null) { - datePartArray[MONTH] = a; - } else { - config._pf.invalidMonth = input; - } - break; - // DAY OF MONTH - case 'D' : // fall through to DD - case 'DD' : - if (input != null) { - datePartArray[DATE] = toInt(input); - } - break; - case 'Do' : - if (input != null) { - datePartArray[DATE] = toInt(parseInt( - input.match(/\d{1,2}/)[0], 10)); - } - break; - // DAY OF YEAR - case 'DDD' : // fall through to DDDD - case 'DDDD' : - if (input != null) { - config._dayOfYear = toInt(input); - } - - break; - // YEAR - case 'YY' : - datePartArray[YEAR] = moment.parseTwoDigitYear(input); - break; - case 'YYYY' : - case 'YYYYY' : - case 'YYYYYY' : - datePartArray[YEAR] = toInt(input); - break; - // AM / PM - case 'a' : // fall through to A - case 'A' : - config._meridiem = input; - // config._isPm = config._locale.isPM(input); - break; - // HOUR - case 'h' : // fall through to hh - case 'hh' : - config._pf.bigHour = true; - /* falls through */ - case 'H' : // fall through to HH - case 'HH' : - datePartArray[HOUR] = toInt(input); - break; - // MINUTE - case 'm' : // fall through to mm - case 'mm' : - datePartArray[MINUTE] = toInt(input); - break; - // SECOND - case 's' : // fall through to ss - case 'ss' : - datePartArray[SECOND] = toInt(input); - break; - // MILLISECOND - case 'S' : - case 'SS' : - case 'SSS' : - case 'SSSS' : - datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000); - break; - // UNIX OFFSET (MILLISECONDS) - case 'x': - config._d = new Date(toInt(input)); - break; - // UNIX TIMESTAMP WITH MS - case 'X': - config._d = new Date(parseFloat(input) * 1000); - break; - // TIMEZONE - case 'Z' : // fall through to ZZ - case 'ZZ' : - config._useUTC = true; - config._tzm = utcOffsetFromString(input); - break; - // WEEKDAY - human - case 'dd': - case 'ddd': - case 'dddd': - 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 || {}; - config._w['d'] = a; - } else { - config._pf.invalidWeekday = input; - } - break; - // WEEK, WEEK DAY - numeric - case 'w': - case 'ww': - case 'W': - case 'WW': - case 'd': - case 'e': - case 'E': - token = token.substr(0, 1); - /* falls through */ - case 'gggg': - case 'GGGG': - case 'GGGGG': - token = token.substr(0, 2); - if (input) { - config._w = config._w || {}; - config._w[token] = toInt(input); - } - break; - case 'gg': - case 'GG': - config._w = config._w || {}; - config._w[token] = moment.parseTwoDigitYear(input); - } + } + return converted; + }; + + /** + * Update a single item: merge with existing item. + * Will fail when the item has no id, or when there does not exist an item + * with the same id. + * @param {Object} item + * @return {String} id + * @private + */ + DataSet.prototype._updateItem = function (item) { + var id = item[this._fieldId]; + if (id == undefined) { + throw new Error('Cannot update item: item has no id (item: ' + JSON.stringify(item) + ')'); + } + var d = this._data[id]; + if (!d) { + // item doesn't exist + throw new Error('Cannot update item: no item with id ' + id + ' found'); + } + + // merge with current item + for (var field in item) { + if (item.hasOwnProperty(field)) { + var fieldType = this._type[field]; // type may be undefined + d[field] = util.convert(item[field], fieldType); } + } - function dayOfYearFromWeekInfo(config) { - var w, weekYear, week, weekday, dow, doy, temp; + return id; + }; - w = config._w; - if (w.GG != null || w.W != null || w.E != null) { - dow = 1; - doy = 4; + /** + * Get an array with the column names of a Google DataTable + * @param {DataTable} dataTable + * @return {String[]} columnNames + * @private + */ + DataSet.prototype._getColumnNames = function (dataTable) { + var columns = []; + for (var col = 0, cols = dataTable.getNumberOfColumns(); col < cols; col++) { + columns[col] = dataTable.getColumnId(col) || dataTable.getColumnLabel(col); + } + return columns; + }; - // TODO: We need to take the current isoWeekYear, but that depends on - // how we interpret now (local, utc, fixed offset). So create - // a now version of current config (take local/utc/offset flags, and - // create now). - weekYear = dfl(w.GG, config._a[YEAR], weekOfYear(moment(), 1, 4).year); - week = dfl(w.W, 1); - weekday = dfl(w.E, 1); - } else { - dow = config._locale._week.dow; - doy = config._locale._week.doy; + /** + * Append an item as a row to the dataTable + * @param dataTable + * @param columns + * @param item + * @private + */ + DataSet.prototype._appendRow = function (dataTable, columns, item) { + var row = dataTable.addRow(); - weekYear = dfl(w.gg, config._a[YEAR], weekOfYear(moment(), dow, doy).year); - week = dfl(w.w, 1); + for (var col = 0, cols = columns.length; col < cols; col++) { + var field = columns[col]; + dataTable.setValue(row, col, item[field]); + } + }; - if (w.d != null) { - // weekday -- low day numbers are considered next week - weekday = w.d; - if (weekday < dow) { - ++week; - } - } else if (w.e != null) { - // local weekday -- counting starts from begining of week - weekday = w.e + dow; - } else { - // default to begining of week - weekday = dow; - } - } - temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow); + module.exports = DataSet; - config._a[YEAR] = temp.year; - config._dayOfYear = temp.dayOfYear; - } - // convert an array to a date. - // the array should mirror the parameters below - // note: all values past the year are optional and will default to the lowest possible value. - // [year, month, day , hour, minute, second, millisecond] - function dateFromConfig(config) { - var i, date, input = [], currentDate, yearToUse; +/***/ }, +/* 4 */ +/***/ function(module, exports, __webpack_require__) { - if (config._d) { - return; - } + var util = __webpack_require__(1); + var DataSet = __webpack_require__(3); - currentDate = currentDateArray(config); + /** + * DataView + * + * a dataview offers a filtered view on a dataset or an other dataview. + * + * @param {DataSet | DataView} data + * @param {Object} [options] Available options: see method get + * + * @constructor DataView + */ + function DataView (data, options) { + this._data = null; + this._ids = {}; // ids of the items currently in memory (just contains a boolean true) + this._options = options || {}; + this._fieldId = 'id'; // name of the field containing id + this._subscribers = {}; // event subscribers - //compute day of the year from weeks and weekdays - if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { - dayOfYearFromWeekInfo(config); - } + var me = this; + this.listener = function () { + me._onEvent.apply(me, arguments); + }; - //if the day of the year is set, figure out what it is - if (config._dayOfYear) { - yearToUse = dfl(config._a[YEAR], currentDate[YEAR]); + this.setData(data); + } - if (config._dayOfYear > daysInYear(yearToUse)) { - config._pf._overflowDayOfYear = true; - } + // TODO: implement a function .config() to dynamically update things like configured filter + // and trigger changes accordingly - date = makeUTCDate(yearToUse, 0, config._dayOfYear); - config._a[MONTH] = date.getUTCMonth(); - config._a[DATE] = date.getUTCDate(); - } + /** + * Set a data source for the view + * @param {DataSet | DataView} data + */ + DataView.prototype.setData = function (data) { + var ids, i, len; - // Default to current date. - // * if no year, month, day of month are given, default to today - // * if day of month is given, default month and year - // * if month is given, default only year - // * if year is given, don't default anything - for (i = 0; i < 3 && config._a[i] == null; ++i) { - config._a[i] = input[i] = currentDate[i]; - } + if (this._data) { + // unsubscribe from current dataset + if (this._data.unsubscribe) { + this._data.unsubscribe('*', this.listener); + } - // Zero out whatever was not defaulted, including time - for (; i < 7; i++) { - config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; - } + // trigger a remove of all items in memory + ids = []; + for (var id in this._ids) { + if (this._ids.hasOwnProperty(id)) { + ids.push(id); + } + } + this._ids = {}; + this._trigger('remove', {items: ids}); + } - // Check for 24:00:00.000 - if (config._a[HOUR] === 24 && - config._a[MINUTE] === 0 && - config._a[SECOND] === 0 && - config._a[MILLISECOND] === 0) { - config._nextDay = true; - config._a[HOUR] = 0; - } + this._data = data; - config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input); - // Apply timezone offset from input. The actual utcOffset can be changed - // with parseZone. - if (config._tzm != null) { - config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); - } + if (this._data) { + // update fieldId + this._fieldId = this._options.fieldId || + (this._data && this._data.options && this._data.options.fieldId) || + 'id'; - if (config._nextDay) { - config._a[HOUR] = 24; - } + // trigger an add of all added items + ids = this._data.getIds({filter: this._options && this._options.filter}); + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + this._ids[id] = true; } + this._trigger('add', {items: ids}); - function dateFromObject(config) { - var normalizedInput; + // subscribe to new dataset + if (this._data.on) { + this._data.on('*', this.listener); + } + } + }; - if (config._d) { - return; - } + /** + * Get data from the data view + * + * Usage: + * + * get() + * get(options: Object) + * get(options: Object, data: Array | DataTable) + * + * get(id: Number) + * get(id: Number, options: Object) + * get(id: Number, options: Object, data: Array | DataTable) + * + * get(ids: Number[]) + * get(ids: Number[], options: Object) + * get(ids: Number[], options: Object, data: Array | DataTable) + * + * Where: + * + * {Number | String} id The id of an item + * {Number[] | String{}} ids An array with ids of items + * {Object} options An Object with options. Available options: + * {String} [type] Type of data to be returned. Can + * be 'DataTable' or 'Array' (default) + * {Object.} [convert] + * {String[]} [fields] field names to be returned + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * {Array | DataTable} [data] If provided, items will be appended to this + * array or table. Required in case of Google + * DataTable. + * @param args + */ + DataView.prototype.get = function (args) { + var me = this; - normalizedInput = normalizeObjectUnits(config._i); - config._a = [ - normalizedInput.year, - normalizedInput.month, - normalizedInput.day || normalizedInput.date, - normalizedInput.hour, - normalizedInput.minute, - normalizedInput.second, - normalizedInput.millisecond - ]; + // parse the arguments + var ids, options, data; + var firstType = util.getType(arguments[0]); + if (firstType == 'String' || firstType == 'Number' || firstType == 'Array') { + // get(id(s) [, options] [, data]) + ids = arguments[0]; // can be a single id or an array with ids + options = arguments[1]; + data = arguments[2]; + } + else { + // get([, options] [, data]) + options = arguments[0]; + data = arguments[1]; + } - dateFromConfig(config); + // extend the options with the default options and provided options + var viewOptions = util.extend({}, this._options, options); + + // create a combined filter method when needed + if (this._options.filter && options && options.filter) { + viewOptions.filter = function (item) { + return me._options.filter(item) && options.filter(item); } + } - function currentDateArray(config) { - var now = new Date(); - if (config._useUTC) { - return [ - now.getUTCFullYear(), - now.getUTCMonth(), - now.getUTCDate() - ]; - } else { - return [now.getFullYear(), now.getMonth(), now.getDate()]; + // build up the call to the linked data set + var getArguments = []; + if (ids != undefined) { + getArguments.push(ids); + } + getArguments.push(viewOptions); + getArguments.push(data); + + return this._data && this._data.get.apply(this._data, getArguments); + }; + + /** + * Get ids of all items or from a filtered set of items. + * @param {Object} [options] An Object with options. Available options: + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * @return {Array} ids + */ + DataView.prototype.getIds = function (options) { + var ids; + + if (this._data) { + var defaultFilter = this._options.filter; + var filter; + + if (options && options.filter) { + if (defaultFilter) { + filter = function (item) { + return defaultFilter(item) && options.filter(item); } + } + else { + filter = options.filter; + } + } + else { + filter = defaultFilter; } - // date from string and format string - function makeDateFromStringAndFormat(config) { - if (config._f === moment.ISO_8601) { - parseISO(config); - return; - } + ids = this._data.getIds({ + filter: filter, + order: options && options.order + }); + } + else { + ids = []; + } - config._a = []; - config._pf.empty = true; + return ids; + }; - // This array is used to make a Date, either with `new Date` or `Date.UTC` - var string = '' + config._i, - i, parsedInput, tokens, token, skipped, - stringLength = string.length, - totalParsedInputLength = 0; + /** + * Get the DataSet to which this DataView is connected. In case there is a chain + * of multiple DataViews, the root DataSet of this chain is returned. + * @return {DataSet} dataSet + */ + DataView.prototype.getDataSet = function () { + var dataSet = this; + while (dataSet instanceof DataView) { + dataSet = dataSet._data; + } + return dataSet || null; + }; - tokens = expandFormat(config._f, config._locale).match(formattingTokens) || []; + /** + * Event listener. Will propagate all events from the connected data set to + * the subscribers of the DataView, but will filter the items and only trigger + * when there are changes in the filtered data set. + * @param {String} event + * @param {Object | null} params + * @param {String} senderId + * @private + */ + DataView.prototype._onEvent = function (event, params, senderId) { + var i, len, id, item, + ids = params && params.items, + data = this._data, + added = [], + updated = [], + removed = []; - for (i = 0; i < tokens.length; i++) { - token = tokens[i]; - parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; - if (parsedInput) { - skipped = string.substr(0, string.indexOf(parsedInput)); - if (skipped.length > 0) { - config._pf.unusedInput.push(skipped); - } - string = string.slice(string.indexOf(parsedInput) + parsedInput.length); - totalParsedInputLength += parsedInput.length; + if (ids && data) { + switch (event) { + case 'add': + // filter the ids of the added items + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + item = this.get(id); + if (item) { + this._ids[id] = true; + added.push(id); + } + } + + break; + + case 'update': + // determine the event from the views viewpoint: an updated + // item can be added, updated, or removed from this view. + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + item = this.get(id); + + if (item) { + if (this._ids[id]) { + updated.push(id); } - // don't parse if it's not a known token - if (formatTokenFunctions[token]) { - if (parsedInput) { - config._pf.empty = false; - } - else { - config._pf.unusedTokens.push(token); - } - addTimeToArrayFromToken(token, parsedInput, config); + else { + this._ids[id] = true; + added.push(id); } - else if (config._strict && !parsedInput) { - config._pf.unusedTokens.push(token); + } + else { + if (this._ids[id]) { + delete this._ids[id]; + removed.push(id); + } + else { + // nothing interesting for me :-( } + } } - // add remaining unparsed input length to the string - config._pf.charsLeftOver = stringLength - totalParsedInputLength; - if (string.length > 0) { - config._pf.unusedInput.push(string); - } + break; - // clear _12h flag if hour is <= 12 - if (config._pf.bigHour === true && config._a[HOUR] <= 12) { - config._pf.bigHour = undefined; + case 'remove': + // filter the ids of the removed items + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + if (this._ids[id]) { + delete this._ids[id]; + removed.push(id); + } } - // handle meridiem - config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], - config._meridiem); - dateFromConfig(config); - checkOverflow(config); - } - function unescapeFormat(s) { - return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { - return p1 || p2 || p3 || p4; - }); + break; } - // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript - function regexpEscape(s) { - return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + if (added.length) { + this._trigger('add', {items: added}, senderId); + } + if (updated.length) { + this._trigger('update', {items: updated}, senderId); + } + if (removed.length) { + this._trigger('remove', {items: removed}, senderId); } + } + }; + + // copy subscription functionality from DataSet + DataView.prototype.on = DataSet.prototype.on; + DataView.prototype.off = DataSet.prototype.off; + DataView.prototype._trigger = DataSet.prototype._trigger; + + // TODO: make these functions deprecated (replaced with `on` and `off` since version 0.5) + DataView.prototype.subscribe = DataView.prototype.on; + DataView.prototype.unsubscribe = DataView.prototype.off; + + module.exports = DataView; + +/***/ }, +/* 5 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * A queue + * @param {Object} options + * Available options: + * - delay: number When provided, the queue will be flushed + * automatically after an inactivity of this delay + * in milliseconds. + * Default value is null. + * - max: number When the queue exceeds the given maximum number + * of entries, the queue is flushed automatically. + * Default value of max is Infinity. + * @constructor + */ + function Queue(options) { + // options + this.delay = null; + this.max = Infinity; - // date from string and array of format strings - function makeDateFromStringAndArray(config) { - var tempConfig, - bestMoment, + // properties + this._queue = []; + this._timeout = null; + this._extended = null; - scoreToBeat, - i, - currentScore; + this.setOptions(options); + } - if (config._f.length === 0) { - config._pf.invalidFormat = true; - config._d = new Date(NaN); - return; - } + /** + * Update the configuration of the queue + * @param {Object} options + * Available options: + * - delay: number When provided, the queue will be flushed + * automatically after an inactivity of this delay + * in milliseconds. + * Default value is null. + * - max: number When the queue exceeds the given maximum number + * of entries, the queue is flushed automatically. + * Default value of max is Infinity. + * @param options + */ + Queue.prototype.setOptions = function (options) { + if (options && typeof options.delay !== 'undefined') { + this.delay = options.delay; + } + if (options && typeof options.max !== 'undefined') { + this.max = options.max; + } - for (i = 0; i < config._f.length; i++) { - currentScore = 0; - tempConfig = copyConfig({}, config); - if (config._useUTC != null) { - tempConfig._useUTC = config._useUTC; - } - tempConfig._pf = defaultParsingFlags(); - tempConfig._f = config._f[i]; - makeDateFromStringAndFormat(tempConfig); + this._flushIfNeeded(); + }; - if (!isValid(tempConfig)) { - continue; - } + /** + * Extend an object with queuing functionality. + * The object will be extended with a function flush, and the methods provided + * in options.replace will be replaced with queued ones. + * @param {Object} object + * @param {Object} options + * Available options: + * - replace: Array. + * A list with method names of the methods + * on the object to be replaced with queued ones. + * - delay: number When provided, the queue will be flushed + * automatically after an inactivity of this delay + * in milliseconds. + * Default value is null. + * - max: number When the queue exceeds the given maximum number + * of entries, the queue is flushed automatically. + * Default value of max is Infinity. + * @return {Queue} Returns the created queue + */ + Queue.extend = function (object, options) { + var queue = new Queue(options); - // if there is any input that was not parsed add a penalty for that format - currentScore += tempConfig._pf.charsLeftOver; + if (object.flush !== undefined) { + throw new Error('Target object already has a property flush'); + } + object.flush = function () { + queue.flush(); + }; - //or tokens - currentScore += tempConfig._pf.unusedTokens.length * 10; + var methods = [{ + name: 'flush', + original: undefined + }]; - tempConfig._pf.score = currentScore; + if (options && options.replace) { + for (var i = 0; i < options.replace.length; i++) { + var name = options.replace[i]; + methods.push({ + name: name, + original: object[name] + }); + queue.replace(object, name); + } + } - if (scoreToBeat == null || currentScore < scoreToBeat) { - scoreToBeat = currentScore; - bestMoment = tempConfig; - } - } + queue._extended = { + object: object, + methods: methods + }; - extend(config, bestMoment || tempConfig); - } + return queue; + }; - // date from iso format - function parseISO(config) { - var i, l, - string = config._i, - match = isoRegex.exec(string); + /** + * Destroy the queue. The queue will first flush all queued actions, and in + * case it has extended an object, will restore the original object. + */ + Queue.prototype.destroy = function () { + this.flush(); - if (match) { - config._pf.iso = true; - for (i = 0, l = isoDates.length; i < l; i++) { - if (isoDates[i][1].exec(string)) { - // match[5] should be 'T' or undefined - config._f = isoDates[i][0] + (match[6] || ' '); - break; - } - } - for (i = 0, l = isoTimes.length; i < l; i++) { - if (isoTimes[i][1].exec(string)) { - config._f += isoTimes[i][0]; - break; - } - } - if (string.match(parseTokenTimezone)) { - config._f += 'Z'; - } - makeDateFromStringAndFormat(config); - } else { - config._isValid = false; - } + if (this._extended) { + var object = this._extended.object; + var methods = this._extended.methods; + for (var i = 0; i < methods.length; i++) { + var method = methods[i]; + if (method.original) { + object[method.name] = method.original; + } + else { + delete object[method.name]; + } } + this._extended = null; + } + }; - // date from iso format or fallback - function makeDateFromString(config) { - parseISO(config); - if (config._isValid === false) { - delete config._isValid; - moment.createFromInputFallback(config); - } - } + /** + * Replace a method on an object with a queued version + * @param {Object} object Object having the method + * @param {string} method The method name + */ + Queue.prototype.replace = function(object, method) { + var me = this; + var original = object[method]; + if (!original) { + throw new Error('Method ' + method + ' undefined'); + } - function map(arr, fn) { - var res = [], i; - for (i = 0; i < arr.length; ++i) { - res.push(fn(arr[i], i)); - } - return res; + object[method] = function () { + // create an Array with the arguments + var args = []; + for (var i = 0; i < arguments.length; i++) { + args[i] = arguments[i]; } - function makeDateFromInput(config) { - var input = config._i, matched; - if (input === undefined) { - config._d = new Date(); - } 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 = map(input.slice(0), function (obj) { - return parseInt(obj, 10); - }); - dateFromConfig(config); - } else if (typeof(input) === 'object') { - dateFromObject(config); - } else if (typeof(input) === 'number') { - // from milliseconds - config._d = new Date(input); - } else { - moment.createFromInputFallback(config); - } - } + // add this call to the queue + me.queue({ + args: args, + fn: original, + context: this + }); + }; + }; - function makeDate(y, m, d, h, M, s, ms) { - //can't just apply() to create a date: - //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply - var date = new Date(y, m, d, h, M, s, ms); + /** + * Queue a call + * @param {function | {fn: function, args: Array} | {fn: function, args: Array, context: Object}} entry + */ + Queue.prototype.queue = function(entry) { + if (typeof entry === 'function') { + this._queue.push({fn: entry}); + } + else { + this._queue.push(entry); + } - //the date constructor doesn't accept years < 1970 - if (y < 1970) { - date.setFullYear(y); - } - return date; - } + this._flushIfNeeded(); + }; - function makeUTCDate(y) { - var date = new Date(Date.UTC.apply(null, arguments)); - if (y < 1970) { - date.setUTCFullYear(y); - } - return date; - } + /** + * Check whether the queue needs to be flushed + * @private + */ + Queue.prototype._flushIfNeeded = function () { + // flush when the maximum is exceeded. + if (this._queue.length > this.max) { + this.flush(); + } - function parseWeekday(input, locale) { - if (typeof input === 'string') { - if (!isNaN(input)) { - input = parseInt(input, 10); - } - else { - input = locale.weekdaysParse(input); - if (typeof input !== 'number') { - return null; - } - } - } - return input; - } + // flush after a period of inactivity when a delay is configured + clearTimeout(this._timeout); + if (this.queue.length > 0 && typeof this.delay === 'number') { + var me = this; + this._timeout = setTimeout(function () { + me.flush(); + }, this.delay); + } + }; - /************************************ - Relative Time - ************************************/ + /** + * Flush all queued calls + */ + Queue.prototype.flush = function () { + while (this._queue.length > 0) { + var entry = this._queue.shift(); + entry.fn.apply(entry.context || entry.fn, entry.args || []); + } + }; + module.exports = Queue; - // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize - function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { - return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); - } - 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')), +/***/ }, +/* 6 */ +/***/ function(module, exports, __webpack_require__) { - 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.d && ['dd', days] || - months === 1 && ['M'] || - months < relativeTimeThresholds.M && ['MM', months] || - years === 1 && ['y'] || ['yy', years]; + var Emitter = __webpack_require__(56); + var DataSet = __webpack_require__(3); + var DataView = __webpack_require__(4); + var util = __webpack_require__(1); + var Point3d = __webpack_require__(10); + var Point2d = __webpack_require__(9); + var Camera = __webpack_require__(7); + var Filter = __webpack_require__(8); + var Slider = __webpack_require__(11); + var StepNumber = __webpack_require__(12); - args[2] = withoutSuffix; - args[3] = +posNegDuration > 0; - args[4] = locale; - return substituteTimeAgo.apply({}, args); - } + /** + * @constructor Graph3d + * Graph3d displays data in 3d. + * + * Graph3d is developed in javascript as a Google Visualization Chart. + * + * @param {Element} container The DOM element in which the Graph3d will + * be created. Normally a div element. + * @param {DataSet | DataView | Array} [data] + * @param {Object} [options] + */ + function Graph3d(container, data, options) { + if (!(this instanceof Graph3d)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } + // create variables and set default values + this.containerElement = container; + this.width = '400px'; + this.height = '400px'; + this.margin = 10; // px + this.defaultXCenter = '55%'; + this.defaultYCenter = '50%'; - /************************************ - Week of Year - ************************************/ + this.xLabel = 'x'; + this.yLabel = 'y'; + this.zLabel = 'z'; + var passValueFn = function(v) { return v; }; + this.xValueLabel = passValueFn; + this.yValueLabel = passValueFn; + this.zValueLabel = passValueFn; + + this.filterLabel = 'time'; + this.legendLabel = 'value'; - // firstDayOfWeek 0 = sun, 6 = sat - // the day of the week that starts the week - // (usually sunday or monday) - // firstDayOfWeekOfYear 0 = sun, 6 = sat - // the first week is the week that contains the first - // of this day of the week - // (eg. ISO weeks use thursday (4)) - function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { - var end = firstDayOfWeekOfYear - firstDayOfWeek, - daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), - adjustedMoment; + this.style = Graph3d.STYLE.DOT; + this.showPerspective = true; + this.showGrid = true; + this.keepAspectRatio = true; + this.showShadow = false; + this.showGrayBottom = false; // TODO: this does not work correctly + this.showTooltip = false; + this.verticalRatio = 0.5; // 0.1 to 1.0, where 1.0 results in a 'cube' + this.animationInterval = 1000; // milliseconds + this.animationPreload = false; - if (daysToDayOfWeek > end) { - daysToDayOfWeek -= 7; - } + this.camera = new Camera(); + this.eye = new Point3d(0, 0, -1); // TODO: set eye.z about 3/4 of the width of the window? - if (daysToDayOfWeek < end - 7) { - daysToDayOfWeek += 7; - } + this.dataTable = null; // The original data table + this.dataPoints = null; // The table with point objects - adjustedMoment = moment(mom).add(daysToDayOfWeek, 'd'); - return { - week: Math.ceil(adjustedMoment.dayOfYear() / 7), - year: adjustedMoment.year() - }; - } + // the column indexes + this.colX = undefined; + this.colY = undefined; + this.colZ = undefined; + this.colValue = undefined; + this.colFilter = undefined; - //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday - function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { - var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear; + this.xMin = 0; + this.xStep = undefined; // auto by default + this.xMax = 1; + this.yMin = 0; + this.yStep = undefined; // auto by default + this.yMax = 1; + this.zMin = 0; + this.zStep = undefined; // auto by default + this.zMax = 1; + this.valueMin = 0; + this.valueMax = 1; + this.xBarWidth = 1; + this.yBarWidth = 1; + // TODO: customize axis range - d = d === 0 ? 7 : d; - weekday = weekday != null ? weekday : firstDayOfWeek; - daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0); - dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; + // constants + this.colorAxis = '#4D4D4D'; + this.colorGrid = '#D3D3D3'; + this.colorDot = '#7DC1FF'; + this.colorDotBorder = '#3267D2'; - return { - year: dayOfYear > 0 ? year : year - 1, - dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear - }; - } + // create a frame and canvas + this.create(); - /************************************ - Top Level Functions - ************************************/ + // apply options (also when undefined) + this.setOptions(options); - function makeMoment(config) { - var input = config._i, - format = config._f, - res; + // apply data + if (data) { + this.setData(data); + } + } - config._locale = config._locale || moment.localeData(config._l); + // Extend Graph3d with an Emitter mixin + Emitter(Graph3d.prototype); - if (input === null || (format === undefined && input === '')) { - return moment.invalid({nullInput: true}); - } + /** + * Calculate the scaling values, dependent on the range in x, y, and z direction + */ + Graph3d.prototype._setScale = function() { + this.scale = new Point3d(1 / (this.xMax - this.xMin), + 1 / (this.yMax - this.yMin), + 1 / (this.zMax - this.zMin)); - if (typeof input === 'string') { - config._i = input = config._locale.preparse(input); - } + // keep aspect ration between x and y scale if desired + if (this.keepAspectRatio) { + if (this.scale.x < this.scale.y) { + //noinspection JSSuspiciousNameCombination + this.scale.y = this.scale.x; + } + else { + //noinspection JSSuspiciousNameCombination + this.scale.x = this.scale.y; + } + } - if (moment.isMoment(input)) { - return new Moment(input, true); - } else if (format) { - if (isArray(format)) { - makeDateFromStringAndArray(config); - } else { - makeDateFromStringAndFormat(config); - } - } else { - makeDateFromInput(config); - } + // scale the vertical axis + this.scale.z *= this.verticalRatio; + // TODO: can this be automated? verticalRatio? - res = new Moment(config); - if (res._nextDay) { - // Adding is smart enough around DST - res.add(1, 'd'); - res._nextDay = undefined; - } + // determine scale for (optional) value + this.scale.value = 1 / (this.valueMax - this.valueMin); + + // position the camera arm + var xCenter = (this.xMax + this.xMin) / 2 * this.scale.x; + var yCenter = (this.yMax + this.yMin) / 2 * this.scale.y; + var zCenter = (this.zMax + this.zMin) / 2 * this.scale.z; + this.camera.setArmLocation(xCenter, yCenter, zCenter); + }; - return res; - } - moment = function (input, format, locale, strict) { - var c; + /** + * Convert a 3D location to a 2D location on screen + * http://en.wikipedia.org/wiki/3D_projection + * @param {Point3d} point3d A 3D point with parameters x, y, z + * @return {Point2d} point2d A 2D point with parameters x, y + */ + Graph3d.prototype._convert3Dto2D = function(point3d) { + var translation = this._convertPointToTranslation(point3d); + return this._convertTranslationToScreen(translation); + }; - if (typeof(locale) === 'boolean') { - strict = locale; - locale = undefined; - } - // object construction must be done this way. - // https://github.com/moment/moment/issues/1423 - c = {}; - c._isAMomentObject = true; - c._i = input; - c._f = format; - c._l = locale; - c._strict = strict; - c._isUTC = false; - c._pf = defaultParsingFlags(); + /** + * Convert a 3D location its translation seen from the camera + * http://en.wikipedia.org/wiki/3D_projection + * @param {Point3d} point3d A 3D point with parameters x, y, z + * @return {Point3d} translation A 3D point with parameters x, y, z This is + * the translation of the point, seen from the + * camera + */ + Graph3d.prototype._convertPointToTranslation = function(point3d) { + var ax = point3d.x * this.scale.x, + ay = point3d.y * this.scale.y, + az = point3d.z * this.scale.z, - return makeMoment(c); - }; + cx = this.camera.getCameraLocation().x, + cy = this.camera.getCameraLocation().y, + cz = this.camera.getCameraLocation().z, - moment.suppressDeprecationWarnings = false; + // calculate angles + sinTx = Math.sin(this.camera.getCameraRotation().x), + cosTx = Math.cos(this.camera.getCameraRotation().x), + sinTy = Math.sin(this.camera.getCameraRotation().y), + cosTy = Math.cos(this.camera.getCameraRotation().y), + sinTz = Math.sin(this.camera.getCameraRotation().z), + cosTz = Math.cos(this.camera.getCameraRotation().z), - 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 + (config._useUTC ? ' UTC' : '')); - } - ); + // calculate translation + dx = cosTy * (sinTz * (ay - cy) + cosTz * (ax - cx)) - sinTy * (az - cz), + dy = sinTx * (cosTy * (az - cz) + sinTy * (sinTz * (ay - cy) + cosTz * (ax - cx))) + cosTx * (cosTz * (ay - cy) - sinTz * (ax-cx)), + dz = cosTx * (cosTy * (az - cz) + sinTy * (sinTz * (ay - cy) + cosTz * (ax - cx))) - sinTx * (cosTz * (ay - cy) - sinTz * (ax-cx)); - // 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. - // - // moments should either be an array of moment objects or an array, whose - // first element is an array of moment objects. - function pickBy(fn, moments) { - var res, i; - if (moments.length === 1 && isArray(moments[0])) { - moments = moments[0]; - } - if (!moments.length) { - return moment(); - } - res = moments[0]; - for (i = 1; i < moments.length; ++i) { - if (moments[i][fn](res)) { - res = moments[i]; - } - } - return res; - } + return new Point3d(dx, dy, dz); + }; - moment.min = function () { - var args = [].slice.call(arguments, 0); + /** + * Convert a translation point to a point on the screen + * @param {Point3d} translation A 3D point with parameters x, y, z This is + * the translation of the point, seen from the + * camera + * @return {Point2d} point2d A 2D point with parameters x, y + */ + Graph3d.prototype._convertTranslationToScreen = function(translation) { + var ex = this.eye.x, + ey = this.eye.y, + ez = this.eye.z, + dx = translation.x, + dy = translation.y, + dz = translation.z; - return pickBy('isBefore', args); - }; + // calculate position on screen from translation + var bx; + var by; + if (this.showPerspective) { + bx = (dx - ex) * (ez / dz); + by = (dy - ey) * (ez / dz); + } + else { + bx = dx * -(ez / this.camera.getArmLength()); + by = dy * -(ez / this.camera.getArmLength()); + } - moment.max = function () { - var args = [].slice.call(arguments, 0); + // shift and scale the point to the center of the screen + // use the width of the graph to scale both horizontally and vertically. + return new Point2d( + this.xcenter + bx * this.frame.canvas.clientWidth, + this.ycenter - by * this.frame.canvas.clientWidth); + }; - return pickBy('isAfter', args); - }; + /** + * Set the background styling for the graph + * @param {string | {fill: string, stroke: string, strokeWidth: string}} backgroundColor + */ + Graph3d.prototype._setBackgroundColor = function(backgroundColor) { + var fill = 'white'; + var stroke = 'gray'; + var strokeWidth = 1; - // creating with utc - moment.utc = function (input, format, locale, strict) { - var c; + if (typeof(backgroundColor) === 'string') { + fill = backgroundColor; + stroke = 'none'; + strokeWidth = 0; + } + else if (typeof(backgroundColor) === 'object') { + if (backgroundColor.fill !== undefined) fill = backgroundColor.fill; + if (backgroundColor.stroke !== undefined) stroke = backgroundColor.stroke; + if (backgroundColor.strokeWidth !== undefined) strokeWidth = backgroundColor.strokeWidth; + } + else if (backgroundColor === undefined) { + // use use defaults + } + else { + throw 'Unsupported type of backgroundColor'; + } - if (typeof(locale) === 'boolean') { - strict = locale; - locale = undefined; - } - // object construction must be done this way. - // https://github.com/moment/moment/issues/1423 - c = {}; - c._isAMomentObject = true; - c._useUTC = true; - c._isUTC = true; - c._l = locale; - c._i = input; - c._f = format; - c._strict = strict; - c._pf = defaultParsingFlags(); + this.frame.style.backgroundColor = fill; + this.frame.style.borderColor = stroke; + this.frame.style.borderWidth = strokeWidth + 'px'; + this.frame.style.borderStyle = 'solid'; + }; - return makeMoment(c).utc(); - }; - // creating with unix timestamp (in seconds) - moment.unix = function (input) { - return moment(input * 1000); - }; + /// enumerate the available styles + Graph3d.STYLE = { + BAR: 0, + BARCOLOR: 1, + BARSIZE: 2, + DOT : 3, + DOTLINE : 4, + DOTCOLOR: 5, + DOTSIZE: 6, + GRID : 7, + LINE: 8, + SURFACE : 9 + }; - // duration - moment.duration = function (input, key) { - var duration = input, - // matching against regexp is expensive, do it on demand - match = null, - sign, - ret, - parseIso, - diffRes; + /** + * Retrieve the style index from given styleName + * @param {string} styleName Style name such as 'dot', 'grid', 'dot-line' + * @return {Number} styleNumber Enumeration value representing the style, or -1 + * when not found + */ + Graph3d.prototype._getStyleNumber = function(styleName) { + switch (styleName) { + case 'dot': return Graph3d.STYLE.DOT; + case 'dot-line': return Graph3d.STYLE.DOTLINE; + case 'dot-color': return Graph3d.STYLE.DOTCOLOR; + case 'dot-size': return Graph3d.STYLE.DOTSIZE; + case 'line': return Graph3d.STYLE.LINE; + case 'grid': return Graph3d.STYLE.GRID; + case 'surface': return Graph3d.STYLE.SURFACE; + case 'bar': return Graph3d.STYLE.BAR; + case 'bar-color': return Graph3d.STYLE.BARCOLOR; + case 'bar-size': return Graph3d.STYLE.BARSIZE; + } - if (moment.isDuration(input)) { - duration = { - ms: input._milliseconds, - d: input._days, - M: input._months - }; - } else if (typeof input === 'number') { - duration = {}; - if (key) { - duration[key] = input; - } else { - duration.milliseconds = input; - } - } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) { - sign = (match[1] === '-') ? -1 : 1; - duration = { - y: 0, - d: toInt(match[DATE]) * sign, - h: toInt(match[HOUR]) * sign, - m: toInt(match[MINUTE]) * sign, - s: toInt(match[SECOND]) * sign, - ms: toInt(match[MILLISECOND]) * sign - }; - } else if (!!(match = isoDurationRegex.exec(input))) { - sign = (match[1] === '-') ? -1 : 1; - parseIso = function (inp) { - // We'd normally use ~~inp for this, but unfortunately it also - // converts floats to ints. - // inp may be undefined, so careful calling replace on it. - var res = inp && parseFloat(inp.replace(',', '.')); - // apply sign while we're at it - return (isNaN(res) ? 0 : res) * sign; - }; - duration = { - y: parseIso(match[2]), - M: parseIso(match[3]), - d: parseIso(match[4]), - h: parseIso(match[5]), - m: parseIso(match[6]), - s: parseIso(match[7]), - w: parseIso(match[8]) - }; - } else if (duration == null) {// checks for null or undefined - duration = {}; - } else if (typeof duration === 'object' && - ('from' in duration || 'to' in duration)) { - diffRes = momentsDifference(moment(duration.from), moment(duration.to)); + return -1; + }; - duration = {}; - duration.ms = diffRes.milliseconds; - duration.M = diffRes.months; - } + /** + * Determine the indexes of the data columns, based on the given style and data + * @param {DataSet} data + * @param {Number} style + */ + Graph3d.prototype._determineColumnIndexes = function(data, style) { + if (this.style === Graph3d.STYLE.DOT || + this.style === Graph3d.STYLE.DOTLINE || + this.style === Graph3d.STYLE.LINE || + this.style === Graph3d.STYLE.GRID || + this.style === Graph3d.STYLE.SURFACE || + this.style === Graph3d.STYLE.BAR) { + // 3 columns expected, and optionally a 4th with filter values + this.colX = 0; + this.colY = 1; + this.colZ = 2; + this.colValue = undefined; - ret = new Duration(duration); + if (data.getNumberOfColumns() > 3) { + this.colFilter = 3; + } + } + else if (this.style === Graph3d.STYLE.DOTCOLOR || + this.style === Graph3d.STYLE.DOTSIZE || + this.style === Graph3d.STYLE.BARCOLOR || + this.style === Graph3d.STYLE.BARSIZE) { + // 4 columns expected, and optionally a 5th with filter values + this.colX = 0; + this.colY = 1; + this.colZ = 2; + this.colValue = 3; - if (moment.isDuration(input) && hasOwnProp(input, '_locale')) { - ret._locale = input._locale; - } + if (data.getNumberOfColumns() > 4) { + this.colFilter = 4; + } + } + else { + throw 'Unknown style "' + this.style + '"'; + } + }; - return ret; - }; + Graph3d.prototype.getNumberOfRows = function(data) { + return data.length; + } - // version number - moment.version = VERSION; - // default format - moment.defaultFormat = isoFormat; + Graph3d.prototype.getNumberOfColumns = function(data) { + var counter = 0; + for (var column in data[0]) { + if (data[0].hasOwnProperty(column)) { + counter++; + } + } + return counter; + } - // constant that refers to the ISO standard - moment.ISO_8601 = function () {}; - // Plugins that add properties should also add the key here (null value), - // so we can properly clone ourselves. - moment.momentProperties = momentProperties; + Graph3d.prototype.getDistinctValues = function(data, column) { + var distinctValues = []; + for (var i = 0; i < data.length; i++) { + if (distinctValues.indexOf(data[i][column]) == -1) { + distinctValues.push(data[i][column]); + } + } + return distinctValues; + } - // This function will be called whenever a moment is mutated. - // It is intended to keep the offset in sync with the timezone. - 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; - } - if (limit === undefined) { - return relativeTimeThresholds[threshold]; - } - relativeTimeThresholds[threshold] = limit; - return true; - }; + Graph3d.prototype.getColumnRange = function(data,column) { + var minMax = {min:data[0][column],max:data[0][column]}; + for (var i = 0; i < data.length; i++) { + if (minMax.min > data[i][column]) { minMax.min = data[i][column]; } + if (minMax.max < data[i][column]) { minMax.max = data[i][column]; } + } + return minMax; + }; - moment.lang = deprecate( - 'moment.lang is deprecated. Use moment.locale instead.', - function (key, value) { - return moment.locale(key, value); - } - ); + /** + * Initialize the data from the data table. Calculate minimum and maximum values + * and column index values + * @param {Array | DataSet | DataView} rawData The data containing the items for the Graph. + * @param {Number} style Style Number + */ + Graph3d.prototype._dataInitialize = function (rawData, style) { + var me = this; - // This function will load locale and then set the global locale. If - // no arguments are passed in, it will simply return the current global - // 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); - } + // unsubscribe from the dataTable + if (this.dataSet) { + this.dataSet.off('*', this._onChange); + } - if (data) { - moment.duration._locale = moment._locale = data; - } - } + if (rawData === undefined) + return; - return moment._locale._abbr; - }; + if (Array.isArray(rawData)) { + rawData = new DataSet(rawData); + } - moment.defineLocale = function (name, values) { - if (values !== null) { - values.abbr = name; - if (!locales[name]) { - locales[name] = new Locale(); - } - locales[name].set(values); + var data; + if (rawData instanceof DataSet || rawData instanceof DataView) { + data = rawData.get(); + } + else { + throw new Error('Array, DataSet, or DataView expected'); + } - // backwards compat for now: also set the locale - moment.locale(name); + if (data.length == 0) + return; - return locales[name]; - } else { - // useful for testing - delete locales[name]; - return null; - } - }; + this.dataSet = rawData; + this.dataTable = data; - moment.langData = deprecate( - 'moment.langData is deprecated. Use moment.localeData instead.', - function (key) { - return moment.localeData(key); - } - ); + // subscribe to changes in the dataset + this._onChange = function () { + me.setData(me.dataSet); + }; + this.dataSet.on('*', this._onChange); - // returns locale data - moment.localeData = function (key) { - var locale; + // _determineColumnIndexes + // getNumberOfRows (points) + // getNumberOfColumns (x,y,z,v,t,t1,t2...) + // getDistinctValues (unique values?) + // getColumnRange - if (key && key._locale && key._locale._abbr) { - key = key._locale._abbr; - } + // determine the location of x,y,z,value,filter columns + this.colX = 'x'; + this.colY = 'y'; + this.colZ = 'z'; + this.colValue = 'style'; + this.colFilter = 'filter'; - if (!key) { - return moment._locale; - } - if (!isArray(key)) { - //short-circuit everything else - locale = loadLocale(key); - if (locale) { - return locale; - } - key = [key]; - } - return chooseLocale(key); - }; + // check if a filter column is provided + if (data[0].hasOwnProperty('filter')) { + if (this.dataFilter === undefined) { + this.dataFilter = new Filter(rawData, this.colFilter, this); + this.dataFilter.setOnLoadCallback(function() {me.redraw();}); + } + } - // compare moment object - moment.isMoment = function (obj) { - return obj instanceof Moment || - (obj != null && hasOwnProp(obj, '_isAMomentObject')); - }; - // for typechecking Duration objects - moment.isDuration = function (obj) { - return obj instanceof Duration; - }; + var withBars = this.style == Graph3d.STYLE.BAR || + this.style == Graph3d.STYLE.BARCOLOR || + this.style == Graph3d.STYLE.BARSIZE; - for (i = lists.length - 1; i >= 0; --i) { - makeList(lists[i]); + // determine barWidth from data + if (withBars) { + if (this.defaultXBarWidth !== undefined) { + this.xBarWidth = this.defaultXBarWidth; + } + else { + var dataX = this.getDistinctValues(data,this.colX); + this.xBarWidth = (dataX[1] - dataX[0]) || 1; + } + + if (this.defaultYBarWidth !== undefined) { + this.yBarWidth = this.defaultYBarWidth; } + else { + var dataY = this.getDistinctValues(data,this.colY); + this.yBarWidth = (dataY[1] - dataY[0]) || 1; + } + } - moment.normalizeUnits = function (units) { - return normalizeUnits(units); - }; - - moment.invalid = function (flags) { - var m = moment.utc(NaN); - if (flags != null) { - extend(m._pf, flags); - } - else { - m._pf.userInvalidated = true; - } + // calculate minimums and maximums + var xRange = this.getColumnRange(data,this.colX); + if (withBars) { + xRange.min -= this.xBarWidth / 2; + xRange.max += this.xBarWidth / 2; + } + this.xMin = (this.defaultXMin !== undefined) ? this.defaultXMin : xRange.min; + this.xMax = (this.defaultXMax !== undefined) ? this.defaultXMax : xRange.max; + if (this.xMax <= this.xMin) this.xMax = this.xMin + 1; + this.xStep = (this.defaultXStep !== undefined) ? this.defaultXStep : (this.xMax-this.xMin)/5; - return m; - }; + var yRange = this.getColumnRange(data,this.colY); + if (withBars) { + yRange.min -= this.yBarWidth / 2; + yRange.max += this.yBarWidth / 2; + } + this.yMin = (this.defaultYMin !== undefined) ? this.defaultYMin : yRange.min; + this.yMax = (this.defaultYMax !== undefined) ? this.defaultYMax : yRange.max; + if (this.yMax <= this.yMin) this.yMax = this.yMin + 1; + this.yStep = (this.defaultYStep !== undefined) ? this.defaultYStep : (this.yMax-this.yMin)/5; - moment.parseZone = function () { - return moment.apply(null, arguments).parseZone(); - }; + var zRange = this.getColumnRange(data,this.colZ); + this.zMin = (this.defaultZMin !== undefined) ? this.defaultZMin : zRange.min; + this.zMax = (this.defaultZMax !== undefined) ? this.defaultZMax : zRange.max; + if (this.zMax <= this.zMin) this.zMax = this.zMin + 1; + this.zStep = (this.defaultZStep !== undefined) ? this.defaultZStep : (this.zMax-this.zMin)/5; - moment.parseTwoDigitYear = function (input) { - return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); - }; + if (this.colValue !== undefined) { + var valueRange = this.getColumnRange(data,this.colValue); + this.valueMin = (this.defaultValueMin !== undefined) ? this.defaultValueMin : valueRange.min; + this.valueMax = (this.defaultValueMax !== undefined) ? this.defaultValueMax : valueRange.max; + if (this.valueMax <= this.valueMin) this.valueMax = this.valueMin + 1; + } - moment.isDate = isDate; + // set the scale dependent on the ranges. + this._setScale(); + }; - /************************************ - Moment Prototype - ************************************/ - extend(moment.fn = Moment.prototype, { + /** + * Filter the data based on the current filter + * @param {Array} data + * @return {Array} dataPoints Array with point objects which can be drawn on screen + */ + Graph3d.prototype._getDataPoints = function (data) { + // TODO: store the created matrix dataPoints in the filters instead of reloading each time + var x, y, i, z, obj, point; - clone : function () { - return moment(this); - }, + var dataPoints = []; - valueOf : function () { - return +this._d - ((this._offset || 0) * 60000); - }, + if (this.style === Graph3d.STYLE.GRID || + this.style === Graph3d.STYLE.SURFACE) { + // copy all values from the google data table to a matrix + // the provided values are supposed to form a grid of (x,y) positions - unix : function () { - return Math.floor(+this / 1000); - }, + // create two lists with all present x and y values + var dataX = []; + var dataY = []; + for (i = 0; i < this.getNumberOfRows(data); i++) { + x = data[i][this.colX] || 0; + y = data[i][this.colY] || 0; - toString : function () { - return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); - }, + if (dataX.indexOf(x) === -1) { + dataX.push(x); + } + if (dataY.indexOf(y) === -1) { + dataY.push(y); + } + } - toDate : function () { - return this._offset ? new Date(+this) : this._d; - }, + var sortNumber = function (a, b) { + return a - b; + }; + dataX.sort(sortNumber); + dataY.sort(sortNumber); - toISOString : function () { - var m = moment(this).utc(); - if (0 < m.year() && m.year() <= 9999) { - if ('function' === typeof Date.prototype.toISOString) { - // native implementation is ~50x faster, use it when we can - return this.toDate().toISOString(); - } else { - return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); - } - } else { - return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); - } - }, + // create a grid, a 2d matrix, with all values. + var dataMatrix = []; // temporary data matrix + for (i = 0; i < data.length; i++) { + x = data[i][this.colX] || 0; + y = data[i][this.colY] || 0; + z = data[i][this.colZ] || 0; - toArray : function () { - var m = this; - return [ - m.year(), - m.month(), - m.date(), - m.hours(), - m.minutes(), - m.seconds(), - m.milliseconds() - ]; - }, + var xIndex = dataX.indexOf(x); // TODO: implement Array().indexOf() for Internet Explorer + var yIndex = dataY.indexOf(y); - isValid : function () { - return isValid(this); - }, + if (dataMatrix[xIndex] === undefined) { + dataMatrix[xIndex] = []; + } - isDSTShifted : function () { - if (this._a) { - return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0; - } + var point3d = new Point3d(); + point3d.x = x; + point3d.y = y; + point3d.z = z; - return false; - }, + obj = {}; + obj.point = point3d; + obj.trans = undefined; + obj.screen = undefined; + obj.bottom = new Point3d(x, y, this.zMin); - parsingFlags : function () { - return extend({}, this._pf); - }, + dataMatrix[xIndex][yIndex] = obj; - invalidAt: function () { - return this._pf.overflow; - }, + dataPoints.push(obj); + } - utc : function (keepLocalTime) { - return this.utcOffset(0, keepLocalTime); - }, + // fill in the pointers to the neighbors. + for (x = 0; x < dataMatrix.length; x++) { + for (y = 0; y < dataMatrix[x].length; y++) { + if (dataMatrix[x][y]) { + dataMatrix[x][y].pointRight = (x < dataMatrix.length-1) ? dataMatrix[x+1][y] : undefined; + dataMatrix[x][y].pointTop = (y < dataMatrix[x].length-1) ? dataMatrix[x][y+1] : undefined; + dataMatrix[x][y].pointCross = + (x < dataMatrix.length-1 && y < dataMatrix[x].length-1) ? + dataMatrix[x+1][y+1] : + undefined; + } + } + } + } + else { // 'dot', 'dot-line', etc. + // copy all values from the google data table to a list with Point3d objects + for (i = 0; i < data.length; i++) { + point = new Point3d(); + point.x = data[i][this.colX] || 0; + point.y = data[i][this.colY] || 0; + point.z = data[i][this.colZ] || 0; - local : function (keepLocalTime) { - if (this._isUTC) { - this.utcOffset(0, keepLocalTime); - this._isUTC = false; + if (this.colValue !== undefined) { + point.value = data[i][this.colValue] || 0; + } - if (keepLocalTime) { - this.subtract(this._dateUtcOffset(), 'm'); - } - } - return this; - }, + obj = {}; + obj.point = point; + obj.bottom = new Point3d(point.x, point.y, this.zMin); + obj.trans = undefined; + obj.screen = undefined; - format : function (inputString) { - var output = formatMoment(this, inputString || moment.defaultFormat); - return this.localeData().postformat(output); - }, + dataPoints.push(obj); + } + } - add : createAdder(1, 'add'), + return dataPoints; + }; - subtract : createAdder(-1, 'subtract'), + /** + * Create the main frame for the Graph3d. + * This function is executed once when a Graph3d object is created. The frame + * contains a canvas, and this canvas contains all objects like the axis and + * nodes. + */ + Graph3d.prototype.create = function () { + // remove all elements from the container element. + while (this.containerElement.hasChildNodes()) { + this.containerElement.removeChild(this.containerElement.firstChild); + } - diff : function (input, units, asFloat) { - var that = makeAs(input, this), - zoneDiff = (that.utcOffset() - this.utcOffset()) * 6e4, - anchor, diff, output, daysAdjust; + this.frame = document.createElement('div'); + this.frame.style.position = 'relative'; + this.frame.style.overflow = 'hidden'; - units = normalizeUnits(units); + // create the graph canvas (HTML canvas element) + this.frame.canvas = document.createElement( 'canvas' ); + this.frame.canvas.style.position = 'relative'; + this.frame.appendChild(this.frame.canvas); + //if (!this.frame.canvas.getContext) { + { + var noCanvas = document.createElement( 'DIV' ); + noCanvas.style.color = 'red'; + noCanvas.style.fontWeight = 'bold' ; + noCanvas.style.padding = '10px'; + noCanvas.innerHTML = 'Error: your browser does not support HTML canvas'; + this.frame.canvas.appendChild(noCanvas); + } - if (units === 'year' || units === 'month' || units === 'quarter') { - output = monthDiff(this, that); - if (units === 'quarter') { - output = output / 3; - } else if (units === 'year') { - output = output / 12; - } - } else { - diff = this - that; - output = units === 'second' ? diff / 1e3 : // 1000 - units === 'minute' ? diff / 6e4 : // 1000 * 60 - units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 - units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst - units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst - diff; - } - return asFloat ? output : absRound(output); - }, + this.frame.filter = document.createElement( 'div' ); + this.frame.filter.style.position = 'absolute'; + this.frame.filter.style.bottom = '0px'; + this.frame.filter.style.left = '0px'; + this.frame.filter.style.width = '100%'; + this.frame.appendChild(this.frame.filter); - from : function (time, withoutSuffix) { - return moment.duration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix); - }, + // add event listeners to handle moving and zooming the contents + var me = this; + var onmousedown = function (event) {me._onMouseDown(event);}; + var ontouchstart = function (event) {me._onTouchStart(event);}; + var onmousewheel = function (event) {me._onWheel(event);}; + var ontooltip = function (event) {me._onTooltip(event);}; + // TODO: these events are never cleaned up... can give a 'memory leakage' - fromNow : function (withoutSuffix) { - return this.from(moment(), withoutSuffix); - }, + util.addEventListener(this.frame.canvas, 'keydown', onkeydown); + util.addEventListener(this.frame.canvas, 'mousedown', onmousedown); + util.addEventListener(this.frame.canvas, 'touchstart', ontouchstart); + util.addEventListener(this.frame.canvas, 'mousewheel', onmousewheel); + util.addEventListener(this.frame.canvas, 'mousemove', ontooltip); - calendar : function (time) { - // We want to compare the start of today, vs this. - // Getting start-of-today depends on whether we're locat/utc/offset - // or not. - var now = time || moment(), - sod = makeAs(now, this).startOf('day'), - diff = this.diff(sod, 'days', true), - format = diff < -6 ? 'sameElse' : - diff < -1 ? 'lastWeek' : - diff < 0 ? 'lastDay' : - diff < 1 ? 'sameDay' : - diff < 2 ? 'nextDay' : - diff < 7 ? 'nextWeek' : 'sameElse'; - return this.format(this.localeData().calendar(format, this, moment(now))); - }, + // add the new graph to the container element + this.containerElement.appendChild(this.frame); + }; - isLeapYear : function () { - return isLeapYear(this.year()); - }, - isDST : function () { - return (this.utcOffset() > this.clone().month(0).utcOffset() || - this.utcOffset() > this.clone().month(5).utcOffset()); - }, + /** + * Set a new size for the graph + * @param {string} width Width in pixels or percentage (for example '800px' + * or '50%') + * @param {string} height Height in pixels or percentage (for example '400px' + * or '30%') + */ + Graph3d.prototype.setSize = function(width, height) { + this.frame.style.width = width; + this.frame.style.height = height; - day : function (input) { - var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); - if (input != null) { - input = parseWeekday(input, this.localeData()); - return this.add(input - day, 'd'); - } else { - return day; - } - }, + this._resizeCanvas(); + }; - month : makeAccessor('Month', true), + /** + * Resize the canvas to the current size of the frame + */ + Graph3d.prototype._resizeCanvas = function() { + this.frame.canvas.style.width = '100%'; + this.frame.canvas.style.height = '100%'; - startOf : function (units) { - units = normalizeUnits(units); - // the following switch intentionally omits break keywords - // to utilize falling through the cases. - switch (units) { - case 'year': - this.month(0); - /* falls through */ - case 'quarter': - case 'month': - this.date(1); - /* falls through */ - case 'week': - case 'isoWeek': - case 'day': - this.hours(0); - /* falls through */ - case 'hour': - this.minutes(0); - /* falls through */ - case 'minute': - this.seconds(0); - /* falls through */ - case 'second': - this.milliseconds(0); - /* falls through */ - } + this.frame.canvas.width = this.frame.canvas.clientWidth; + this.frame.canvas.height = this.frame.canvas.clientHeight; - // weeks are a special case - if (units === 'week') { - this.weekday(0); - } else if (units === 'isoWeek') { - this.isoWeekday(1); - } + // adjust with for margin + this.frame.filter.style.width = (this.frame.canvas.clientWidth - 2 * 10) + 'px'; + }; - // quarters are also special - if (units === 'quarter') { - this.month(Math.floor(this.month() / 3) * 3); - } + /** + * Start animation + */ + Graph3d.prototype.animationStart = function() { + if (!this.frame.filter || !this.frame.filter.slider) + throw 'No animation available'; - return this; - }, + this.frame.filter.slider.play(); + }; - endOf: function (units) { - units = normalizeUnits(units); - if (units === undefined || units === 'millisecond') { - return this; - } - return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms'); - }, - isAfter: function (input, units) { - var inputMs; - units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); - if (units === 'millisecond') { - input = moment.isMoment(input) ? input : moment(input); - return +this > +input; - } else { - inputMs = moment.isMoment(input) ? +input : +moment(input); - return inputMs < +this.clone().startOf(units); - } - }, + /** + * Stop animation + */ + Graph3d.prototype.animationStop = function() { + if (!this.frame.filter || !this.frame.filter.slider) return; - isBefore: function (input, units) { - var inputMs; - units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); - if (units === 'millisecond') { - input = moment.isMoment(input) ? input : moment(input); - return +this < +input; - } else { - inputMs = moment.isMoment(input) ? +input : +moment(input); - return +this.clone().endOf(units) < inputMs; - } - }, + this.frame.filter.slider.stop(); + }; - isBetween: function (from, to, units) { - return this.isAfter(from, units) && this.isBefore(to, units); - }, - isSame: function (input, units) { - var inputMs; - units = normalizeUnits(units || 'millisecond'); - if (units === 'millisecond') { - input = moment.isMoment(input) ? input : moment(input); - return +this === +input; - } else { - inputMs = +moment(input); - return +(this.clone().startOf(units)) <= inputMs && inputMs <= +(this.clone().endOf(units)); - } - }, + /** + * Resize the center position based on the current values in this.defaultXCenter + * and this.defaultYCenter (which are strings with a percentage or a value + * in pixels). The center positions are the variables this.xCenter + * and this.yCenter + */ + Graph3d.prototype._resizeCenter = function() { + // calculate the horizontal center position + if (this.defaultXCenter.charAt(this.defaultXCenter.length-1) === '%') { + this.xcenter = + parseFloat(this.defaultXCenter) / 100 * + this.frame.canvas.clientWidth; + } + else { + this.xcenter = parseFloat(this.defaultXCenter); // supposed to be in px + } - min: deprecate( - '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; - } - ), + // calculate the vertical center position + if (this.defaultYCenter.charAt(this.defaultYCenter.length-1) === '%') { + this.ycenter = + parseFloat(this.defaultYCenter) / 100 * + (this.frame.canvas.clientHeight - this.frame.filter.clientHeight); + } + else { + this.ycenter = parseFloat(this.defaultYCenter); // supposed to be in px + } + }; - max: deprecate( - '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; - } - ), + /** + * Set the rotation and distance of the camera + * @param {Object} pos An object with the camera position. The object + * contains three parameters: + * - horizontal {Number} + * The horizontal rotation, between 0 and 2*PI. + * Optional, can be left undefined. + * - vertical {Number} + * The vertical rotation, between 0 and 0.5*PI + * if vertical=0.5*PI, the graph is shown from the + * top. Optional, can be left undefined. + * - distance {Number} + * The (normalized) distance of the camera to the + * center of the graph, a value between 0.71 and 5.0. + * Optional, can be left undefined. + */ + Graph3d.prototype.setCameraPosition = function(pos) { + if (pos === undefined) { + return; + } - zone : deprecate( - 'moment().zone is deprecated, use moment().utcOffset instead. ' + - 'https://github.com/moment/moment/issues/1779', - function (input, keepLocalTime) { - if (input != null) { - if (typeof input !== 'string') { - input = -input; - } + if (pos.horizontal !== undefined && pos.vertical !== undefined) { + this.camera.setArmRotation(pos.horizontal, pos.vertical); + } - this.utcOffset(input, keepLocalTime); + if (pos.distance !== undefined) { + this.camera.setArmLength(pos.distance); + } - return this; - } else { - return -this.utcOffset(); - } - } - ), + this.redraw(); + }; - // keepLocalTime = true means only change the timezone, without - // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]--> - // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset - // +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. - utcOffset : function (input, keepLocalTime) { - var offset = this._offset || 0, - localAdjust; - if (input != null) { - if (typeof input === 'string') { - input = utcOffsetFromString(input); - } - if (Math.abs(input) < 16) { - input = input * 60; - } - if (!this._isUTC && keepLocalTime) { - localAdjust = this._dateUtcOffset(); - } - this._offset = input; - this._isUTC = true; - if (localAdjust != null) { - this.add(localAdjust, 'm'); - } - if (offset !== input) { - if (!keepLocalTime || this._changeInProgress) { - addOrSubtractDurationFromMoment(this, - moment.duration(input - offset, 'm'), 1, false); - } else if (!this._changeInProgress) { - this._changeInProgress = true; - moment.updateOffset(this, true); - this._changeInProgress = null; - } - } - return this; - } else { - return this._isUTC ? offset : this._dateUtcOffset(); - } - }, + /** + * Retrieve the current camera rotation + * @return {object} An object with parameters horizontal, vertical, and + * distance + */ + Graph3d.prototype.getCameraPosition = function() { + var pos = this.camera.getArmRotation(); + pos.distance = this.camera.getArmLength(); + return pos; + }; - isLocal : function () { - return !this._isUTC; - }, + /** + * Load data into the 3D Graph + */ + Graph3d.prototype._readData = function(data) { + // read the data + this._dataInitialize(data, this.style); - isUtcOffset : function () { - return this._isUTC; - }, - isUtc : function () { - return this._isUTC && this._offset === 0; - }, + if (this.dataFilter) { + // apply filtering + this.dataPoints = this.dataFilter._getDataPoints(); + } + else { + // no filtering. load all data + this.dataPoints = this._getDataPoints(this.dataTable); + } - zoneAbbr : function () { - return this._isUTC ? 'UTC' : ''; - }, + // draw the filter + this._redrawFilter(); + }; - zoneName : function () { - return this._isUTC ? 'Coordinated Universal Time' : ''; - }, + /** + * Replace the dataset of the Graph3d + * @param {Array | DataSet | DataView} data + */ + Graph3d.prototype.setData = function (data) { + this._readData(data); + this.redraw(); - parseZone : function () { - if (this._tzm) { - this.utcOffset(this._tzm); - } else if (typeof this._i === 'string') { - this.utcOffset(utcOffsetFromString(this._i)); - } - return this; - }, + // start animation when option is true + if (this.animationAutoStart && this.dataFilter) { + this.animationStart(); + } + }; - hasAlignedHourOffset : function (input) { - if (!input) { - input = 0; - } - else { - input = moment(input).utcOffset(); - } + /** + * Update the options. Options will be merged with current options + * @param {Object} options + */ + Graph3d.prototype.setOptions = function (options) { + var cameraPosition = undefined; - return (this.utcOffset() - input) % 60 === 0; - }, + this.animationStop(); - daysInMonth : function () { - return daysInMonth(this.year(), this.month()); - }, + if (options !== undefined) { + // retrieve parameter values + if (options.width !== undefined) this.width = options.width; + if (options.height !== undefined) this.height = options.height; - dayOfYear : function (input) { - var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; - return input == null ? dayOfYear : this.add((input - dayOfYear), 'd'); - }, + if (options.xCenter !== undefined) this.defaultXCenter = options.xCenter; + if (options.yCenter !== undefined) this.defaultYCenter = options.yCenter; - quarter : function (input) { - return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3); - }, + if (options.filterLabel !== undefined) this.filterLabel = options.filterLabel; + if (options.legendLabel !== undefined) this.legendLabel = options.legendLabel; + if (options.xLabel !== undefined) this.xLabel = options.xLabel; + if (options.yLabel !== undefined) this.yLabel = options.yLabel; + if (options.zLabel !== undefined) this.zLabel = options.zLabel; - weekYear : function (input) { - var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year; - return input == null ? year : this.add((input - year), 'y'); - }, + if (options.xValueLabel !== undefined) this.xValueLabel = options.xValueLabel; + if (options.yValueLabel !== undefined) this.yValueLabel = options.yValueLabel; + if (options.zValueLabel !== undefined) this.zValueLabel = options.zValueLabel; - isoWeekYear : function (input) { - var year = weekOfYear(this, 1, 4).year; - return input == null ? year : this.add((input - year), 'y'); - }, + if (options.style !== undefined) { + var styleNumber = this._getStyleNumber(options.style); + if (styleNumber !== -1) { + this.style = styleNumber; + } + } + if (options.showGrid !== undefined) this.showGrid = options.showGrid; + if (options.showPerspective !== undefined) this.showPerspective = options.showPerspective; + if (options.showShadow !== undefined) this.showShadow = options.showShadow; + if (options.tooltip !== undefined) this.showTooltip = options.tooltip; + if (options.showAnimationControls !== undefined) this.showAnimationControls = options.showAnimationControls; + if (options.keepAspectRatio !== undefined) this.keepAspectRatio = options.keepAspectRatio; + if (options.verticalRatio !== undefined) this.verticalRatio = options.verticalRatio; - week : function (input) { - var week = this.localeData().week(this); - return input == null ? week : this.add((input - week) * 7, 'd'); - }, + if (options.animationInterval !== undefined) this.animationInterval = options.animationInterval; + if (options.animationPreload !== undefined) this.animationPreload = options.animationPreload; + if (options.animationAutoStart !== undefined)this.animationAutoStart = options.animationAutoStart; - isoWeek : function (input) { - var week = weekOfYear(this, 1, 4).week; - return input == null ? week : this.add((input - week) * 7, 'd'); - }, + if (options.xBarWidth !== undefined) this.defaultXBarWidth = options.xBarWidth; + if (options.yBarWidth !== undefined) this.defaultYBarWidth = options.yBarWidth; - weekday : function (input) { - var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; - return input == null ? weekday : this.add(input - weekday, 'd'); - }, + if (options.xMin !== undefined) this.defaultXMin = options.xMin; + if (options.xStep !== undefined) this.defaultXStep = options.xStep; + if (options.xMax !== undefined) this.defaultXMax = options.xMax; + if (options.yMin !== undefined) this.defaultYMin = options.yMin; + if (options.yStep !== undefined) this.defaultYStep = options.yStep; + if (options.yMax !== undefined) this.defaultYMax = options.yMax; + if (options.zMin !== undefined) this.defaultZMin = options.zMin; + if (options.zStep !== undefined) this.defaultZStep = options.zStep; + if (options.zMax !== undefined) this.defaultZMax = options.zMax; + if (options.valueMin !== undefined) this.defaultValueMin = options.valueMin; + if (options.valueMax !== undefined) this.defaultValueMax = options.valueMax; - isoWeekday : function (input) { - // behaves the same as moment#day except - // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) - // as a setter, sunday should belong to the previous week. - return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); - }, + if (options.cameraPosition !== undefined) cameraPosition = options.cameraPosition; - isoWeeksInYear : function () { - return weeksInYear(this.year(), 1, 4); - }, + if (cameraPosition !== undefined) { + this.camera.setArmRotation(cameraPosition.horizontal, cameraPosition.vertical); + this.camera.setArmLength(cameraPosition.distance); + } + else { + this.camera.setArmRotation(1.0, 0.5); + this.camera.setArmLength(1.7); + } + } - weeksInYear : function () { - var weekInfo = this.localeData()._week; - return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); - }, + this._setBackgroundColor(options && options.backgroundColor); - get : function (units) { - units = normalizeUnits(units); - return this[units](); - }, + this.setSize(this.width, this.height); - set : function (units, value) { - var unit; - if (typeof units === 'object') { - for (unit in units) { - this.set(unit, units[unit]); - } - } - else { - units = normalizeUnits(units); - if (typeof this[units] === 'function') { - this[units](value); - } - } - return this; - }, + // re-load the data + if (this.dataTable) { + this.setData(this.dataTable); + } - // If passed a locale key, it will set the locale for this - // instance. Otherwise, it will return the locale configuration - // variables for this instance. - locale : function (key) { - var newLocaleData; + // start animation when option is true + if (this.animationAutoStart && this.dataFilter) { + this.animationStart(); + } + }; - if (key === undefined) { - return this._locale._abbr; - } else { - newLocaleData = moment.localeData(key); - if (newLocaleData != null) { - this._locale = newLocaleData; - } - return this; - } - }, + /** + * Redraw the Graph. + */ + Graph3d.prototype.redraw = function() { + if (this.dataPoints === undefined) { + throw 'Error: graph data not initialized'; + } - lang : deprecate( - 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', - function (key) { - if (key === undefined) { - return this.localeData(); - } else { - return this.locale(key); - } - } - ), + this._resizeCanvas(); + this._resizeCenter(); + this._redrawSlider(); + this._redrawClear(); + this._redrawAxis(); - localeData : function () { - return this._locale; - }, + if (this.style === Graph3d.STYLE.GRID || + this.style === Graph3d.STYLE.SURFACE) { + this._redrawDataGrid(); + } + else if (this.style === Graph3d.STYLE.LINE) { + this._redrawDataLine(); + } + else if (this.style === Graph3d.STYLE.BAR || + this.style === Graph3d.STYLE.BARCOLOR || + this.style === Graph3d.STYLE.BARSIZE) { + this._redrawDataBar(); + } + else { + // style is DOT, DOTLINE, DOTCOLOR, DOTSIZE + this._redrawDataDot(); + } - _dateUtcOffset : function () { - // On Firefox.24 Date#getTimezoneOffset returns a floating point. - // https://github.com/moment/moment/pull/1871 - return -Math.round(this._d.getTimezoneOffset() / 15) * 15; - } + this._redrawInfo(); + this._redrawLegend(); + }; - }); + /** + * Clear the canvas before redrawing + */ + Graph3d.prototype._redrawClear = function() { + var canvas = this.frame.canvas; + var ctx = canvas.getContext('2d'); - function rawMonthSetter(mom, value) { - var dayOfMonth; + ctx.clearRect(0, 0, canvas.width, canvas.height); + }; - // TODO: Move this out of here! - if (typeof value === 'string') { - value = mom.localeData().monthsParse(value); - // TODO: Another silent failure? - if (typeof value !== 'number') { - return mom; - } - } - dayOfMonth = Math.min(mom.date(), - daysInMonth(mom.year(), value)); - mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); - return mom; - } + /** + * Redraw the legend showing the colors + */ + Graph3d.prototype._redrawLegend = function() { + var y; - function rawGetter(mom, unit) { - return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit](); - } + if (this.style === Graph3d.STYLE.DOTCOLOR || + this.style === Graph3d.STYLE.DOTSIZE) { - function rawSetter(mom, unit, value) { - if (unit === 'Month') { - return rawMonthSetter(mom, value); - } else { - return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); - } - } + var dotSize = this.frame.clientWidth * 0.02; - function makeAccessor(unit, keepTime) { - return function (value) { - if (value != null) { - rawSetter(this, unit, value); - moment.updateOffset(this, keepTime); - return this; - } else { - return rawGetter(this, unit); - } - }; + var widthMin, widthMax; + if (this.style === Graph3d.STYLE.DOTSIZE) { + widthMin = dotSize / 2; // px + widthMax = dotSize / 2 + dotSize * 2; // Todo: put this in one function + } + else { + widthMin = 20; // px + widthMax = 20; // px } - moment.fn.millisecond = moment.fn.milliseconds = makeAccessor('Milliseconds', false); - moment.fn.second = moment.fn.seconds = makeAccessor('Seconds', false); - moment.fn.minute = moment.fn.minutes = makeAccessor('Minutes', false); - // Setting the hour should keep the time, because the user explicitly - // specified which hour he wants. So trying to maintain the same hour (in - // a new timezone) makes sense. Adding/subtracting hours does not follow - // this rule. - 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.year = 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; - moment.fn.months = moment.fn.month; - moment.fn.weeks = moment.fn.week; - moment.fn.isoWeeks = moment.fn.isoWeek; - moment.fn.quarters = moment.fn.quarter; - - // add aliased format methods - moment.fn.toJSON = moment.fn.toISOString; - - // alias isUtc for dev-friendliness - moment.fn.isUTC = moment.fn.isUtc; + var height = Math.max(this.frame.clientHeight * 0.25, 100); + var top = this.margin; + var right = this.frame.clientWidth - this.margin; + var left = right - widthMax; + var bottom = top + height; + } - /************************************ - Duration Prototype - ************************************/ + var canvas = this.frame.canvas; + var ctx = canvas.getContext('2d'); + ctx.lineWidth = 1; + ctx.font = '14px arial'; // TODO: put in options + if (this.style === Graph3d.STYLE.DOTCOLOR) { + // draw the color bar + var ymin = 0; + var ymax = height; // Todo: make height customizable + for (y = ymin; y < ymax; y++) { + var f = (y - ymin) / (ymax - ymin); - function daysToYears (days) { - // 400 years have 146097 days (taking into account leap year rules) - return days * 400 / 146097; - } + //var width = (dotSize / 2 + (1-f) * dotSize * 2); // Todo: put this in one function + var hue = f * 240; + var color = this._hsv2rgb(hue, 1, 1); - function yearsToDays (years) { - // years * 365 + absRound(years / 4) - - // absRound(years / 100) + absRound(years / 400); - return years * 146097 / 400; + ctx.strokeStyle = color; + ctx.beginPath(); + ctx.moveTo(left, top + y); + ctx.lineTo(right, top + y); + ctx.stroke(); } - extend(moment.duration.fn = Duration.prototype, { - - _bubble : function () { - var milliseconds = this._milliseconds, - days = this._days, - months = this._months, - data = this._data, - seconds, minutes, hours, years = 0; + ctx.strokeStyle = this.colorAxis; + ctx.strokeRect(left, top, widthMax, height); + } - // The following code bubbles up values, see the tests for - // examples of what that means. - data.milliseconds = milliseconds % 1000; + if (this.style === Graph3d.STYLE.DOTSIZE) { + // draw border around color bar + ctx.strokeStyle = this.colorAxis; + ctx.fillStyle = this.colorDot; + ctx.beginPath(); + ctx.moveTo(left, top); + ctx.lineTo(right, top); + ctx.lineTo(right - widthMax + widthMin, bottom); + ctx.lineTo(left, bottom); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + } - seconds = absRound(milliseconds / 1000); - data.seconds = seconds % 60; + if (this.style === Graph3d.STYLE.DOTCOLOR || + this.style === Graph3d.STYLE.DOTSIZE) { + // print values along the color bar + var gridLineLen = 5; // px + var step = new StepNumber(this.valueMin, this.valueMax, (this.valueMax-this.valueMin)/5, true); + step.start(); + if (step.getCurrent() < this.valueMin) { + step.next(); + } + while (!step.end()) { + y = bottom - (step.getCurrent() - this.valueMin) / (this.valueMax - this.valueMin) * height; - minutes = absRound(seconds / 60); - data.minutes = minutes % 60; + ctx.beginPath(); + ctx.moveTo(left - gridLineLen, y); + ctx.lineTo(left, y); + ctx.stroke(); - hours = absRound(minutes / 60); - data.hours = hours % 24; + ctx.textAlign = 'right'; + ctx.textBaseline = 'middle'; + ctx.fillStyle = this.colorAxis; + ctx.fillText(step.getCurrent(), left - 2 * gridLineLen, y); - days += absRound(hours / 24); + step.next(); + } - // Accurately convert days to years, assume start from year 0. - years = absRound(daysToYears(days)); - days -= absRound(yearsToDays(years)); + ctx.textAlign = 'right'; + ctx.textBaseline = 'top'; + var label = this.legendLabel; + ctx.fillText(label, right, bottom + this.margin); + } + }; - // 30 days to a month - // TODO (iskren): Use anchor date (like 1st Jan) to compute this. - months += absRound(days / 30); - days %= 30; + /** + * Redraw the filter + */ + Graph3d.prototype._redrawFilter = function() { + this.frame.filter.innerHTML = ''; - // 12 months -> 1 year - years += absRound(months / 12); - months %= 12; + if (this.dataFilter) { + var options = { + 'visible': this.showAnimationControls + }; + var slider = new Slider(this.frame.filter, options); + this.frame.filter.slider = slider; - data.days = days; - data.months = months; - data.years = years; - }, + // TODO: css here is not nice here... + this.frame.filter.style.padding = '10px'; + //this.frame.filter.style.backgroundColor = '#EFEFEF'; - abs : function () { - this._milliseconds = Math.abs(this._milliseconds); - this._days = Math.abs(this._days); - this._months = Math.abs(this._months); + slider.setValues(this.dataFilter.values); + slider.setPlayInterval(this.animationInterval); - 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); + // create an event handler + var me = this; + var onchange = function () { + var index = slider.getIndex(); - return this; - }, + me.dataFilter.selectValue(index); + me.dataPoints = me.dataFilter._getDataPoints(); - weeks : function () { - return absRound(this.days() / 7); - }, + me.redraw(); + }; + slider.setOnChangeCallback(onchange); + } + else { + this.frame.filter.slider = undefined; + } + }; - valueOf : function () { - return this._milliseconds + - this._days * 864e5 + - (this._months % 12) * 2592e6 + - toInt(this._months / 12) * 31536e6; - }, + /** + * Redraw the slider + */ + Graph3d.prototype._redrawSlider = function() { + if ( this.frame.filter.slider !== undefined) { + this.frame.filter.slider.redraw(); + } + }; - humanize : function (withSuffix) { - var output = relativeTime(this, !withSuffix, this.localeData()); - if (withSuffix) { - output = this.localeData().pastFuture(+this, output); - } + /** + * Redraw common information + */ + Graph3d.prototype._redrawInfo = function() { + if (this.dataFilter) { + var canvas = this.frame.canvas; + var ctx = canvas.getContext('2d'); - return this.localeData().postformat(output); - }, + ctx.font = '14px arial'; // TODO: put in options + ctx.lineStyle = 'gray'; + ctx.fillStyle = 'gray'; + ctx.textAlign = 'left'; + ctx.textBaseline = 'top'; - add : function (input, val) { - // supports only 2.0-style add(1, 's') or add(moment) - var dur = moment.duration(input, val); + var x = this.margin; + var y = this.margin; + ctx.fillText(this.dataFilter.getLabel() + ': ' + this.dataFilter.getSelectedValue(), x, y); + } + }; - this._milliseconds += dur._milliseconds; - this._days += dur._days; - this._months += dur._months; - this._bubble(); + /** + * Redraw the axis + */ + Graph3d.prototype._redrawAxis = function() { + var canvas = this.frame.canvas, + ctx = canvas.getContext('2d'), + from, to, step, prettyStep, + text, xText, yText, zText, + offset, xOffset, yOffset, + xMin2d, xMax2d; - return this; - }, + // TODO: get the actual rendered style of the containerElement + //ctx.font = this.containerElement.style.font; + ctx.font = 24 / this.camera.getArmLength() + 'px arial'; - subtract : function (input, val) { - var dur = moment.duration(input, val); + // calculate the length for the short grid lines + var gridLenX = 0.025 / this.scale.x; + var gridLenY = 0.025 / this.scale.y; + var textMargin = 5 / this.camera.getArmLength(); // px + var armAngle = this.camera.getArmRotation().horizontal; - this._milliseconds -= dur._milliseconds; - this._days -= dur._days; - this._months -= dur._months; + // draw x-grid lines + ctx.lineWidth = 1; + prettyStep = (this.defaultXStep === undefined); + step = new StepNumber(this.xMin, this.xMax, this.xStep, prettyStep); + step.start(); + if (step.getCurrent() < this.xMin) { + step.next(); + } + while (!step.end()) { + var x = step.getCurrent(); - this._bubble(); + if (this.showGrid) { + from = this._convert3Dto2D(new Point3d(x, this.yMin, this.zMin)); + to = this._convert3Dto2D(new Point3d(x, this.yMax, this.zMin)); + ctx.strokeStyle = this.colorGrid; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + ctx.stroke(); + } + else { + from = this._convert3Dto2D(new Point3d(x, this.yMin, this.zMin)); + to = this._convert3Dto2D(new Point3d(x, this.yMin+gridLenX, this.zMin)); + ctx.strokeStyle = this.colorAxis; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + ctx.stroke(); - return this; - }, + from = this._convert3Dto2D(new Point3d(x, this.yMax, this.zMin)); + to = this._convert3Dto2D(new Point3d(x, this.yMax-gridLenX, this.zMin)); + ctx.strokeStyle = this.colorAxis; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + ctx.stroke(); + } - get : function (units) { - units = normalizeUnits(units); - return this[units.toLowerCase() + 's'](); - }, + yText = (Math.cos(armAngle) > 0) ? this.yMin : this.yMax; + text = this._convert3Dto2D(new Point3d(x, yText, this.zMin)); + if (Math.cos(armAngle * 2) > 0) { + ctx.textAlign = 'center'; + ctx.textBaseline = 'top'; + text.y += textMargin; + } + else if (Math.sin(armAngle * 2) < 0){ + ctx.textAlign = 'right'; + ctx.textBaseline = 'middle'; + } + else { + ctx.textAlign = 'left'; + ctx.textBaseline = 'middle'; + } + ctx.fillStyle = this.colorAxis; + ctx.fillText(' ' + this.xValueLabel(step.getCurrent()) + ' ', text.x, text.y); - as : function (units) { - var days, months; - units = normalizeUnits(units); + step.next(); + } - if (units === 'month' || units === 'year') { - days = this._days + this._milliseconds / 864e5; - months = this._months + daysToYears(days) * 12; - return units === 'month' ? months : months / 12; - } else { - // handle milliseconds separately because of floating point math errors (issue #1867) - days = this._days + Math.round(yearsToDays(this._months / 12)); - switch (units) { - case 'week': return days / 7 + this._milliseconds / 6048e5; - case 'day': return days + this._milliseconds / 864e5; - case 'hour': return days * 24 + this._milliseconds / 36e5; - case 'minute': return days * 24 * 60 + this._milliseconds / 6e4; - case 'second': return days * 24 * 60 * 60 + this._milliseconds / 1000; - // Math.floor prevents floating point math errors here - case 'millisecond': return Math.floor(days * 24 * 60 * 60 * 1000) + this._milliseconds; - default: throw new Error('Unknown unit ' + units); - } - } - }, + // draw y-grid lines + ctx.lineWidth = 1; + prettyStep = (this.defaultYStep === undefined); + step = new StepNumber(this.yMin, this.yMax, this.yStep, prettyStep); + step.start(); + if (step.getCurrent() < this.yMin) { + step.next(); + } + while (!step.end()) { + if (this.showGrid) { + from = this._convert3Dto2D(new Point3d(this.xMin, step.getCurrent(), this.zMin)); + to = this._convert3Dto2D(new Point3d(this.xMax, step.getCurrent(), this.zMin)); + ctx.strokeStyle = this.colorGrid; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + ctx.stroke(); + } + else { + from = this._convert3Dto2D(new Point3d(this.xMin, step.getCurrent(), this.zMin)); + to = this._convert3Dto2D(new Point3d(this.xMin+gridLenY, step.getCurrent(), this.zMin)); + ctx.strokeStyle = this.colorAxis; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + ctx.stroke(); - lang : moment.fn.lang, - locale : moment.fn.locale, + from = this._convert3Dto2D(new Point3d(this.xMax, step.getCurrent(), this.zMin)); + to = this._convert3Dto2D(new Point3d(this.xMax-gridLenY, step.getCurrent(), this.zMin)); + ctx.strokeStyle = this.colorAxis; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + ctx.stroke(); + } - toIsoString : deprecate( - 'toIsoString() is deprecated. Please use toISOString() instead ' + - '(notice the capitals)', - function () { - return this.toISOString(); - } - ), + xText = (Math.sin(armAngle ) > 0) ? this.xMin : this.xMax; + text = this._convert3Dto2D(new Point3d(xText, step.getCurrent(), this.zMin)); + if (Math.cos(armAngle * 2) < 0) { + ctx.textAlign = 'center'; + ctx.textBaseline = 'top'; + text.y += textMargin; + } + else if (Math.sin(armAngle * 2) > 0){ + ctx.textAlign = 'right'; + ctx.textBaseline = 'middle'; + } + else { + ctx.textAlign = 'left'; + ctx.textBaseline = 'middle'; + } + ctx.fillStyle = this.colorAxis; + ctx.fillText(' ' + this.yValueLabel(step.getCurrent()) + ' ', text.x, text.y); - 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()), - days = Math.abs(this.days()), - hours = Math.abs(this.hours()), - minutes = Math.abs(this.minutes()), - seconds = Math.abs(this.seconds() + this.milliseconds() / 1000); + step.next(); + } - if (!this.asSeconds()) { - // this is the same as C#'s (Noda) and python (isodate)... - // but not other JS (goog.date) - return 'P0D'; - } + // draw z-grid lines and axis + ctx.lineWidth = 1; + prettyStep = (this.defaultZStep === undefined); + step = new StepNumber(this.zMin, this.zMax, this.zStep, prettyStep); + step.start(); + if (step.getCurrent() < this.zMin) { + step.next(); + } + xText = (Math.cos(armAngle ) > 0) ? this.xMin : this.xMax; + yText = (Math.sin(armAngle ) < 0) ? this.yMin : this.yMax; + while (!step.end()) { + // TODO: make z-grid lines really 3d? + from = this._convert3Dto2D(new Point3d(xText, yText, step.getCurrent())); + ctx.strokeStyle = this.colorAxis; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(from.x - textMargin, from.y); + ctx.stroke(); - return (this.asSeconds() < 0 ? '-' : '') + - 'P' + - (years ? years + 'Y' : '') + - (months ? months + 'M' : '') + - (days ? days + 'D' : '') + - ((hours || minutes || seconds) ? 'T' : '') + - (hours ? hours + 'H' : '') + - (minutes ? minutes + 'M' : '') + - (seconds ? seconds + 'S' : ''); - }, + ctx.textAlign = 'right'; + ctx.textBaseline = 'middle'; + ctx.fillStyle = this.colorAxis; + ctx.fillText(this.zValueLabel(step.getCurrent()) + ' ', from.x - 5, from.y); - localeData : function () { - return this._locale; - }, + step.next(); + } + ctx.lineWidth = 1; + from = this._convert3Dto2D(new Point3d(xText, yText, this.zMin)); + to = this._convert3Dto2D(new Point3d(xText, yText, this.zMax)); + ctx.strokeStyle = this.colorAxis; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + ctx.stroke(); - toJSON : function () { - return this.toISOString(); - } - }); + // draw x-axis + ctx.lineWidth = 1; + // line at yMin + xMin2d = this._convert3Dto2D(new Point3d(this.xMin, this.yMin, this.zMin)); + xMax2d = this._convert3Dto2D(new Point3d(this.xMax, this.yMin, this.zMin)); + ctx.strokeStyle = this.colorAxis; + ctx.beginPath(); + ctx.moveTo(xMin2d.x, xMin2d.y); + ctx.lineTo(xMax2d.x, xMax2d.y); + ctx.stroke(); + // line at ymax + xMin2d = this._convert3Dto2D(new Point3d(this.xMin, this.yMax, this.zMin)); + xMax2d = this._convert3Dto2D(new Point3d(this.xMax, this.yMax, this.zMin)); + ctx.strokeStyle = this.colorAxis; + ctx.beginPath(); + ctx.moveTo(xMin2d.x, xMin2d.y); + ctx.lineTo(xMax2d.x, xMax2d.y); + ctx.stroke(); - moment.duration.fn.toString = moment.duration.fn.toISOString; + // draw y-axis + ctx.lineWidth = 1; + // line at xMin + from = this._convert3Dto2D(new Point3d(this.xMin, this.yMin, this.zMin)); + to = this._convert3Dto2D(new Point3d(this.xMin, this.yMax, this.zMin)); + ctx.strokeStyle = this.colorAxis; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + ctx.stroke(); + // line at xMax + from = this._convert3Dto2D(new Point3d(this.xMax, this.yMin, this.zMin)); + to = this._convert3Dto2D(new Point3d(this.xMax, this.yMax, this.zMin)); + ctx.strokeStyle = this.colorAxis; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + ctx.stroke(); - function makeDurationGetter(name) { - moment.duration.fn[name] = function () { - return this._data[name]; - }; + // draw x-label + var xLabel = this.xLabel; + if (xLabel.length > 0) { + yOffset = 0.1 / this.scale.y; + xText = (this.xMin + this.xMax) / 2; + yText = (Math.cos(armAngle) > 0) ? this.yMin - yOffset: this.yMax + yOffset; + text = this._convert3Dto2D(new Point3d(xText, yText, this.zMin)); + if (Math.cos(armAngle * 2) > 0) { + ctx.textAlign = 'center'; + ctx.textBaseline = 'top'; + } + else if (Math.sin(armAngle * 2) < 0){ + ctx.textAlign = 'right'; + ctx.textBaseline = 'middle'; + } + else { + ctx.textAlign = 'left'; + ctx.textBaseline = 'middle'; } + ctx.fillStyle = this.colorAxis; + ctx.fillText(xLabel, text.x, text.y); + } - for (i in unitMillisecondFactors) { - if (hasOwnProp(unitMillisecondFactors, i)) { - makeDurationGetter(i.toLowerCase()); - } + // draw y-label + var yLabel = this.yLabel; + if (yLabel.length > 0) { + xOffset = 0.1 / this.scale.x; + xText = (Math.sin(armAngle ) > 0) ? this.xMin - xOffset : this.xMax + xOffset; + yText = (this.yMin + this.yMax) / 2; + text = this._convert3Dto2D(new Point3d(xText, yText, this.zMin)); + if (Math.cos(armAngle * 2) < 0) { + ctx.textAlign = 'center'; + ctx.textBaseline = 'top'; + } + else if (Math.sin(armAngle * 2) > 0){ + ctx.textAlign = 'right'; + ctx.textBaseline = 'middle'; + } + else { + ctx.textAlign = 'left'; + ctx.textBaseline = 'middle'; } + ctx.fillStyle = this.colorAxis; + ctx.fillText(yLabel, text.x, text.y); + } - 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.as('M'); - }; - moment.duration.fn.asYears = function () { - return this.as('y'); - }; + // draw z-label + var zLabel = this.zLabel; + if (zLabel.length > 0) { + offset = 30; // pixels. // TODO: relate to the max width of the values on the z axis? + xText = (Math.cos(armAngle ) > 0) ? this.xMin : this.xMax; + yText = (Math.sin(armAngle ) < 0) ? this.yMin : this.yMax; + zText = (this.zMin + this.zMax) / 2; + text = this._convert3Dto2D(new Point3d(xText, yText, zText)); + ctx.textAlign = 'right'; + ctx.textBaseline = 'middle'; + ctx.fillStyle = this.colorAxis; + ctx.fillText(zLabel, text.x - offset, text.y); + } + }; - /************************************ - Default Locale - ************************************/ + /** + * Calculate the color based on the given value. + * @param {Number} H Hue, a value be between 0 and 360 + * @param {Number} S Saturation, a value between 0 and 1 + * @param {Number} V Value, a value between 0 and 1 + */ + Graph3d.prototype._hsv2rgb = function(H, S, V) { + var R, G, B, C, Hi, X; + + C = V * S; + Hi = Math.floor(H/60); // hi = 0,1,2,3,4,5 + X = C * (1 - Math.abs(((H/60) % 2) - 1)); + switch (Hi) { + case 0: R = C; G = X; B = 0; break; + case 1: R = X; G = C; B = 0; break; + case 2: R = 0; G = C; B = X; break; + case 3: R = 0; G = X; B = C; break; + case 4: R = X; G = 0; B = C; break; + case 5: R = C; G = 0; B = X; break; - // Set default locale, other locale will inherit from English. - moment.locale('en', { - ordinalParse: /\d{1,2}(th|st|nd|rd)/, - ordinal : function (number) { - var b = number % 10, - output = (toInt(number % 100 / 10) === 1) ? 'th' : - (b === 1) ? 'st' : - (b === 2) ? 'nd' : - (b === 3) ? 'rd' : 'th'; - return number + output; - } - }); + default: R = 0; G = 0; B = 0; break; + } - /* EMBED_LOCALES */ + return 'RGB(' + parseInt(R*255) + ',' + parseInt(G*255) + ',' + parseInt(B*255) + ')'; + }; + + + /** + * Draw all datapoints as a grid + * This function can be used when the style is 'grid' + */ + Graph3d.prototype._redrawDataGrid = function() { + var canvas = this.frame.canvas, + ctx = canvas.getContext('2d'), + point, right, top, cross, + i, + topSideVisible, fillStyle, strokeStyle, lineWidth, + h, s, v, zAvg; - /************************************ - Exposing Moment - ************************************/ - function makeGlobal(shouldDeprecate) { - /*global ender:false */ - if (typeof ender !== 'undefined') { - return; - } - oldGlobalMoment = globalScope.moment; - if (shouldDeprecate) { - globalScope.moment = deprecate( - 'Accessing Moment through the global scope is ' + - 'deprecated, and will be removed in an upcoming ' + - 'release.', - moment); - } else { - globalScope.moment = moment; - } - } + if (this.dataPoints === undefined || this.dataPoints.length <= 0) + return; // TODO: throw exception? - // CommonJS module is defined - if (hasModule) { - module.exports = moment; - } else if (true) { - !(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) { - if (module.config && module.config() && module.config().noGlobal === true) { - // release the global variable - globalScope.moment = oldGlobalMoment; - } + // calculate the translations and screen position of all points + for (i = 0; i < this.dataPoints.length; i++) { + var trans = this._convertPointToTranslation(this.dataPoints[i].point); + var screen = this._convertTranslationToScreen(trans); - return moment; - }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - makeGlobal(true); - } else { - makeGlobal(); - } - }).call(this); - - /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()), __webpack_require__(5)(module))) + this.dataPoints[i].trans = trans; + this.dataPoints[i].screen = screen; -/***/ }, -/* 4 */ -/***/ function(module, exports, __webpack_require__) { + // calculate the translation of the point at the bottom (needed for sorting) + var transBottom = this._convertPointToTranslation(this.dataPoints[i].bottom); + this.dataPoints[i].dist = this.showPerspective ? transBottom.length() : -transBottom.z; + } - function webpackContext(req) { - throw new Error("Cannot find module '" + req + "'."); - } - webpackContext.keys = function() { return []; }; - webpackContext.resolve = webpackContext; - module.exports = webpackContext; - webpackContext.id = 4; + // sort the points on depth of their (x,y) position (not on z) + var sortDepth = function (a, b) { + return b.dist - a.dist; + }; + this.dataPoints.sort(sortDepth); + if (this.style === Graph3d.STYLE.SURFACE) { + for (i = 0; i < this.dataPoints.length; i++) { + point = this.dataPoints[i]; + right = this.dataPoints[i].pointRight; + top = this.dataPoints[i].pointTop; + cross = this.dataPoints[i].pointCross; -/***/ }, -/* 5 */ -/***/ function(module, exports, __webpack_require__) { + if (point !== undefined && right !== undefined && top !== undefined && cross !== undefined) { - module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - module.children = []; - module.webpackPolyfill = 1; - } - return module; - } + if (this.showGrayBottom || this.showShadow) { + // calculate the cross product of the two vectors from center + // to left and right, in order to know whether we are looking at the + // bottom or at the top side. We can also use the cross product + // for calculating light intensity + var aDiff = Point3d.subtract(cross.trans, point.trans); + var bDiff = Point3d.subtract(top.trans, right.trans); + var crossproduct = Point3d.crossProduct(aDiff, bDiff); + var len = crossproduct.length(); + // FIXME: there is a bug with determining the surface side (shadow or colored) + topSideVisible = (crossproduct.z > 0); + } + else { + topSideVisible = true; + } -/***/ }, -/* 6 */ -/***/ function(module, exports, __webpack_require__) { + if (topSideVisible) { + // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 + zAvg = (point.point.z + right.point.z + top.point.z + cross.point.z) / 4; + h = (1 - (zAvg - this.zMin) * this.scale.z / this.verticalRatio) * 240; + s = 1; // saturation - // DOM utility methods + if (this.showShadow) { + v = Math.min(1 + (crossproduct.x / len) / 2, 1); // value. TODO: scale + fillStyle = this._hsv2rgb(h, s, v); + strokeStyle = fillStyle; + } + else { + v = 1; + fillStyle = this._hsv2rgb(h, s, v); + strokeStyle = this.colorAxis; + } + } + else { + fillStyle = 'gray'; + strokeStyle = this.colorAxis; + } + lineWidth = 0.5; - /** - * this prepares the JSON container for allocating SVG elements - * @param JSONcontainer - * @private - */ - exports.prepareElements = function(JSONcontainer) { - // cleanup the redundant svgElements; - for (var elementType in JSONcontainer) { - if (JSONcontainer.hasOwnProperty(elementType)) { - JSONcontainer[elementType].redundant = JSONcontainer[elementType].used; - JSONcontainer[elementType].used = []; + ctx.lineWidth = lineWidth; + ctx.fillStyle = fillStyle; + ctx.strokeStyle = strokeStyle; + ctx.beginPath(); + ctx.moveTo(point.screen.x, point.screen.y); + ctx.lineTo(right.screen.x, right.screen.y); + ctx.lineTo(cross.screen.x, cross.screen.y); + ctx.lineTo(top.screen.x, top.screen.y); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + } } } - }; + else { // grid style + for (i = 0; i < this.dataPoints.length; i++) { + point = this.dataPoints[i]; + right = this.dataPoints[i].pointRight; + top = this.dataPoints[i].pointTop; - /** - * this cleans up all the unused SVG elements. By asking for the parentNode, we only need to supply the JSON container from - * which to remove the redundant elements. - * - * @param JSONcontainer - * @private - */ - exports.cleanupElements = function(JSONcontainer) { - // cleanup the redundant svgElements; - for (var elementType in JSONcontainer) { - if (JSONcontainer.hasOwnProperty(elementType)) { - if (JSONcontainer[elementType].redundant) { - for (var i = 0; i < JSONcontainer[elementType].redundant.length; i++) { - JSONcontainer[elementType].redundant[i].parentNode.removeChild(JSONcontainer[elementType].redundant[i]); + if (point !== undefined) { + if (this.showPerspective) { + lineWidth = 2 / -point.trans.z; } - JSONcontainer[elementType].redundant = []; + else { + lineWidth = 2 * -(this.eye.z / this.camera.getArmLength()); + } + } + + if (point !== undefined && right !== undefined) { + // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 + zAvg = (point.point.z + right.point.z) / 2; + h = (1 - (zAvg - this.zMin) * this.scale.z / this.verticalRatio) * 240; + + ctx.lineWidth = lineWidth; + ctx.strokeStyle = this._hsv2rgb(h, 1, 1); + ctx.beginPath(); + ctx.moveTo(point.screen.x, point.screen.y); + ctx.lineTo(right.screen.x, right.screen.y); + ctx.stroke(); + } + + if (point !== undefined && top !== undefined) { + // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 + zAvg = (point.point.z + top.point.z) / 2; + h = (1 - (zAvg - this.zMin) * this.scale.z / this.verticalRatio) * 240; + + ctx.lineWidth = lineWidth; + ctx.strokeStyle = this._hsv2rgb(h, 1, 1); + ctx.beginPath(); + ctx.moveTo(point.screen.x, point.screen.y); + ctx.lineTo(top.screen.x, top.screen.y); + ctx.stroke(); } } } }; + /** - * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer - * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this. - * - * @param elementType - * @param JSONcontainer - * @param svgContainer - * @returns {*} - * @private + * Draw all datapoints as dots. + * This function can be used when the style is 'dot' or 'dot-line' */ - exports.getSVGElement = function (elementType, JSONcontainer, svgContainer) { - var element; - // allocate SVG element, if it doesnt yet exist, create one. - if (JSONcontainer.hasOwnProperty(elementType)) { // this element has been created before - // check if there is an redundant element - if (JSONcontainer[elementType].redundant.length > 0) { - element = JSONcontainer[elementType].redundant[0]; - JSONcontainer[elementType].redundant.shift(); - } - else { - // create a new element and add it to the SVG - element = document.createElementNS('http://www.w3.org/2000/svg', elementType); - svgContainer.appendChild(element); - } - } - else { - // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it. - element = document.createElementNS('http://www.w3.org/2000/svg', elementType); - JSONcontainer[elementType] = {used: [], redundant: []}; - svgContainer.appendChild(element); + Graph3d.prototype._redrawDataDot = function() { + var canvas = this.frame.canvas; + var ctx = canvas.getContext('2d'); + var i; + + if (this.dataPoints === undefined || this.dataPoints.length <= 0) + return; // TODO: throw exception? + + // calculate the translations of all points + for (i = 0; i < this.dataPoints.length; i++) { + var trans = this._convertPointToTranslation(this.dataPoints[i].point); + var screen = this._convertTranslationToScreen(trans); + this.dataPoints[i].trans = trans; + this.dataPoints[i].screen = screen; + + // calculate the distance from the point at the bottom to the camera + var transBottom = this._convertPointToTranslation(this.dataPoints[i].bottom); + this.dataPoints[i].dist = this.showPerspective ? transBottom.length() : -transBottom.z; } - JSONcontainer[elementType].used.push(element); - return element; - }; + // order the translated points by depth + var sortDepth = function (a, b) { + return b.dist - a.dist; + }; + this.dataPoints.sort(sortDepth); - /** - * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer - * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this. - * - * @param elementType - * @param JSONcontainer - * @param DOMContainer - * @returns {*} - * @private - */ - exports.getDOMElement = function (elementType, JSONcontainer, DOMContainer, insertBefore) { - var element; - // allocate DOM element, if it doesnt yet exist, create one. - if (JSONcontainer.hasOwnProperty(elementType)) { // this element has been created before - // check if there is an redundant element - if (JSONcontainer[elementType].redundant.length > 0) { - element = JSONcontainer[elementType].redundant[0]; - JSONcontainer[elementType].redundant.shift(); + // draw the datapoints as colored circles + var dotSize = this.frame.clientWidth * 0.02; // px + for (i = 0; i < this.dataPoints.length; i++) { + var point = this.dataPoints[i]; + + if (this.style === Graph3d.STYLE.DOTLINE) { + // draw a vertical line from the bottom to the graph value + //var from = this._convert3Dto2D(new Point3d(point.point.x, point.point.y, this.zMin)); + var from = this._convert3Dto2D(point.bottom); + ctx.lineWidth = 1; + ctx.strokeStyle = this.colorGrid; + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(point.screen.x, point.screen.y); + ctx.stroke(); + } + + // calculate radius for the circle + var size; + if (this.style === Graph3d.STYLE.DOTSIZE) { + size = dotSize/2 + 2*dotSize * (point.point.value - this.valueMin) / (this.valueMax - this.valueMin); } else { - // create a new element and add it to the SVG - element = document.createElement(elementType); - if (insertBefore !== undefined) { - DOMContainer.insertBefore(element, insertBefore); - } - else { - DOMContainer.appendChild(element); - } + size = dotSize; } - } - else { - // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it. - element = document.createElement(elementType); - JSONcontainer[elementType] = {used: [], redundant: []}; - if (insertBefore !== undefined) { - DOMContainer.insertBefore(element, insertBefore); + + var radius; + if (this.showPerspective) { + radius = size / -point.trans.z; } else { - DOMContainer.appendChild(element); + radius = size * -(this.eye.z / this.camera.getArmLength()); + } + if (radius < 0) { + radius = 0; } - } - JSONcontainer[elementType].used.push(element); - return element; - }; - - - - /** - * draw a point object. this is a seperate function because it can also be called by the legend. - * The reason the JSONcontainer and the target SVG svgContainer have to be supplied is so the legend can use these functions - * as well. - * - * @param x - * @param y - * @param group - * @param JSONcontainer - * @param svgContainer - * @returns {*} - */ - exports.drawPoint = function(x, y, group, JSONcontainer, svgContainer) { - var point; - if (group.options.drawPoints.style == 'circle') { - point = exports.getSVGElement('circle',JSONcontainer,svgContainer); - point.setAttributeNS(null, "cx", x); - point.setAttributeNS(null, "cy", y); - point.setAttributeNS(null, "r", 0.5 * group.options.drawPoints.size); - } - else { - point = exports.getSVGElement('rect',JSONcontainer,svgContainer); - point.setAttributeNS(null, "x", x - 0.5*group.options.drawPoints.size); - point.setAttributeNS(null, "y", y - 0.5*group.options.drawPoints.size); - point.setAttributeNS(null, "width", group.options.drawPoints.size); - point.setAttributeNS(null, "height", group.options.drawPoints.size); - } + var hue, color, borderColor; + if (this.style === Graph3d.STYLE.DOTCOLOR ) { + // calculate the color based on the value + hue = (1 - (point.point.value - this.valueMin) * this.scale.value) * 240; + color = this._hsv2rgb(hue, 1, 1); + borderColor = this._hsv2rgb(hue, 1, 0.8); + } + else if (this.style === Graph3d.STYLE.DOTSIZE) { + color = this.colorDot; + borderColor = this.colorDotBorder; + } + else { + // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 + hue = (1 - (point.point.z - this.zMin) * this.scale.z / this.verticalRatio) * 240; + color = this._hsv2rgb(hue, 1, 1); + borderColor = this._hsv2rgb(hue, 1, 0.8); + } - if(group.options.drawPoints.styles !== undefined) { - point.setAttributeNS(null, "style", group.group.options.drawPoints.styles); + // draw the circle + ctx.lineWidth = 1.0; + ctx.strokeStyle = borderColor; + ctx.fillStyle = color; + ctx.beginPath(); + ctx.arc(point.screen.x, point.screen.y, radius, 0, Math.PI*2, true); + ctx.fill(); + ctx.stroke(); } - point.setAttributeNS(null, "class", group.className + " point"); - return point; }; /** - * draw a bar SVG element centered on the X coordinate - * - * @param x - * @param y - * @param className + * Draw all datapoints as bars. + * This function can be used when the style is 'bar', 'bar-color', or 'bar-size' */ - exports.drawBar = function (x, y, width, height, className, JSONcontainer, svgContainer) { - if (height != 0) { - if (height < 0) { - height *= -1; - y -= height; - } - var rect = exports.getSVGElement('rect',JSONcontainer, svgContainer); - rect.setAttributeNS(null, "x", x - 0.5 * width); - rect.setAttributeNS(null, "y", y); - rect.setAttributeNS(null, "width", width); - rect.setAttributeNS(null, "height", height); - rect.setAttributeNS(null, "class", className); - } - }; + Graph3d.prototype._redrawDataBar = function() { + var canvas = this.frame.canvas; + var ctx = canvas.getContext('2d'); + var i, j, surface, corners; -/***/ }, -/* 7 */ -/***/ function(module, exports, __webpack_require__) { + if (this.dataPoints === undefined || this.dataPoints.length <= 0) + return; // TODO: throw exception? - var util = __webpack_require__(1); - var Queue = __webpack_require__(8); + // calculate the translations of all points + for (i = 0; i < this.dataPoints.length; i++) { + var trans = this._convertPointToTranslation(this.dataPoints[i].point); + var screen = this._convertTranslationToScreen(trans); + this.dataPoints[i].trans = trans; + this.dataPoints[i].screen = screen; - /** - * DataSet - * - * Usage: - * var dataSet = new DataSet({ - * fieldId: '_id', - * type: { - * // ... - * } - * }); - * - * dataSet.add(item); - * dataSet.add(data); - * dataSet.update(item); - * dataSet.update(data); - * dataSet.remove(id); - * dataSet.remove(ids); - * var data = dataSet.get(); - * var data = dataSet.get(id); - * var data = dataSet.get(ids); - * var data = dataSet.get(ids, options, data); - * dataSet.clear(); - * - * A data set can: - * - add/remove/update data - * - gives triggers upon changes in the data - * - can import/export data in various data formats - * - * @param {Array | DataTable} [data] Optional array with initial data - * @param {Object} [options] Available options: - * {String} fieldId Field name of the id in the - * items, 'id' by default. - * {Object. 0) { + point = this.dataPoints[0]; - /** - * Trigger an event - * @param {String} event - * @param {Object | null} params - * @param {String} [senderId] Optional id of the sender. - * @private - */ - DataSet.prototype._trigger = function (event, params, senderId) { - if (event == '*') { - throw new Error('Cannot trigger event *'); + ctx.lineWidth = 1; // TODO: make customizable + ctx.strokeStyle = 'blue'; // TODO: make customizable + ctx.beginPath(); + ctx.moveTo(point.screen.x, point.screen.y); } - var subscribers = []; - if (event in this._subscribers) { - subscribers = subscribers.concat(this._subscribers[event]); - } - if ('*' in this._subscribers) { - subscribers = subscribers.concat(this._subscribers['*']); + // draw the datapoints as colored circles + for (i = 1; i < this.dataPoints.length; i++) { + point = this.dataPoints[i]; + ctx.lineTo(point.screen.x, point.screen.y); } - for (var i = 0; i < subscribers.length; i++) { - var subscriber = subscribers[i]; - if (subscriber.callback) { - subscriber.callback(event, params, senderId || null); - } + // finish the line + if (this.dataPoints.length > 0) { + ctx.stroke(); } }; /** - * Add data. - * Adding an item will fail when there already is an item with the same id. - * @param {Object | Array | DataTable} data - * @param {String} [senderId] Optional sender id - * @return {Array} addedIds Array with the ids of the added items + * Start a moving operation inside the provided parent element + * @param {Event} event The event that occurred (required for + * retrieving the mouse position) */ - DataSet.prototype.add = function (data, senderId) { - var addedIds = [], - id, - me = this; + Graph3d.prototype._onMouseDown = function(event) { + event = event || window.event; - if (Array.isArray(data)) { - // Array - for (var i = 0, len = data.length; i < len; i++) { - id = me._addItem(data[i]); - addedIds.push(id); - } + // check if mouse is still down (may be up when focus is lost for example + // in an iframe) + if (this.leftButtonDown) { + this._onMouseUp(event); } - else if (util.isDataTable(data)) { - // Google DataTable - var columns = this._getColumnNames(data); - for (var row = 0, rows = data.getNumberOfRows(); row < rows; row++) { - var item = {}; - for (var col = 0, cols = columns.length; col < cols; col++) { - var field = columns[col]; - item[field] = data.getValue(row, col); - } - id = me._addItem(item); - addedIds.push(id); - } - } - else if (data instanceof Object) { - // Single item - id = me._addItem(data); - addedIds.push(id); - } - else { - throw new Error('Unknown dataType'); - } + // only react on left mouse button down + this.leftButtonDown = event.which ? (event.which === 1) : (event.button === 1); + if (!this.leftButtonDown && !this.touchDown) return; - if (addedIds.length) { - this._trigger('add', {items: addedIds}, senderId); - } + // get mouse position (different code for IE and all other browsers) + this.startMouseX = getMouseX(event); + this.startMouseY = getMouseY(event); - return addedIds; + this.startStart = new Date(this.start); + this.startEnd = new Date(this.end); + this.startArmRotation = this.camera.getArmRotation(); + + this.frame.style.cursor = 'move'; + + // add event listeners to handle moving the contents + // we store the function onmousemove and onmouseup in the graph, so we can + // remove the eventlisteners lateron in the function mouseUp() + var me = this; + this.onmousemove = function (event) {me._onMouseMove(event);}; + this.onmouseup = function (event) {me._onMouseUp(event);}; + util.addEventListener(document, 'mousemove', me.onmousemove); + util.addEventListener(document, 'mouseup', me.onmouseup); + util.preventDefault(event); }; + /** - * Update existing items. When an item does not exist, it will be created - * @param {Object | Array | DataTable} data - * @param {String} [senderId] Optional sender id - * @return {Array} updatedIds The ids of the added or updated items + * Perform moving operating. + * This function activated from within the funcion Graph.mouseDown(). + * @param {Event} event Well, eehh, the event */ - DataSet.prototype.update = function (data, senderId) { - var addedIds = []; - var updatedIds = []; - var updatedData = []; - var me = this; - var fieldId = me._fieldId; + Graph3d.prototype._onMouseMove = function (event) { + event = event || window.event; - var addOrUpdate = function (item) { - var id = item[fieldId]; - if (me._data[id]) { - // update item - id = me._updateItem(item); - updatedIds.push(id); - updatedData.push(item); - } - else { - // add new item - id = me._addItem(item); - addedIds.push(id); - } - }; + // calculate change in mouse position + var diffX = parseFloat(getMouseX(event)) - this.startMouseX; + var diffY = parseFloat(getMouseY(event)) - this.startMouseY; - if (Array.isArray(data)) { - // Array - for (var i = 0, len = data.length; i < len; i++) { - addOrUpdate(data[i]); - } - } - else if (util.isDataTable(data)) { - // Google DataTable - var columns = this._getColumnNames(data); - for (var row = 0, rows = data.getNumberOfRows(); row < rows; row++) { - var item = {}; - for (var col = 0, cols = columns.length; col < cols; col++) { - var field = columns[col]; - item[field] = data.getValue(row, col); - } + var horizontalNew = this.startArmRotation.horizontal + diffX / 200; + var verticalNew = this.startArmRotation.vertical + diffY / 200; - addOrUpdate(item); - } - } - else if (data instanceof Object) { - // Single item - addOrUpdate(data); + var snapAngle = 4; // degrees + var snapValue = Math.sin(snapAngle / 360 * 2 * Math.PI); + + // snap horizontally to nice angles at 0pi, 0.5pi, 1pi, 1.5pi, etc... + // the -0.001 is to take care that the vertical axis is always drawn at the left front corner + if (Math.abs(Math.sin(horizontalNew)) < snapValue) { + horizontalNew = Math.round((horizontalNew / Math.PI)) * Math.PI - 0.001; } - else { - throw new Error('Unknown dataType'); + if (Math.abs(Math.cos(horizontalNew)) < snapValue) { + horizontalNew = (Math.round((horizontalNew/ Math.PI - 0.5)) + 0.5) * Math.PI - 0.001; } - if (addedIds.length) { - this._trigger('add', {items: addedIds}, senderId); + // snap vertically to nice angles + if (Math.abs(Math.sin(verticalNew)) < snapValue) { + verticalNew = Math.round((verticalNew / Math.PI)) * Math.PI; } - if (updatedIds.length) { - this._trigger('update', {items: updatedIds, data: updatedData}, senderId); + if (Math.abs(Math.cos(verticalNew)) < snapValue) { + verticalNew = (Math.round((verticalNew/ Math.PI - 0.5)) + 0.5) * Math.PI; } - return addedIds.concat(updatedIds); + this.camera.setArmRotation(horizontalNew, verticalNew); + this.redraw(); + + // fire a cameraPositionChange event + var parameters = this.getCameraPosition(); + this.emit('cameraPositionChange', parameters); + + util.preventDefault(event); }; + /** - * Get a data item or multiple items. - * - * Usage: - * - * get() - * get(options: Object) - * get(options: Object, data: Array | DataTable) - * - * get(id: Number | String) - * get(id: Number | String, options: Object) - * get(id: Number | String, options: Object, data: Array | DataTable) - * - * get(ids: Number[] | String[]) - * get(ids: Number[] | String[], options: Object) - * get(ids: Number[] | String[], options: Object, data: Array | DataTable) - * - * Where: - * - * {Number | String} id The id of an item - * {Number[] | String{}} ids An array with ids of items - * {Object} options An Object with options. Available options: - * {String} [returnType] Type of data to be - * returned. Can be 'DataTable' or 'Array' (default) - * {Object.} [type] - * {String[]} [fields] field names to be returned - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * {Array | DataTable} [data] If provided, items will be appended to this - * array or table. Required in case of Google - * DataTable. - * - * @throws Error + * Stop moving operating. + * This function activated from within the funcion Graph.mouseDown(). + * @param {event} event The event */ - DataSet.prototype.get = function (args) { - var me = this; - - // parse the arguments - var id, ids, options, data; - var firstType = util.getType(arguments[0]); - if (firstType == 'String' || firstType == 'Number') { - // get(id [, options] [, data]) - id = arguments[0]; - options = arguments[1]; - data = arguments[2]; - } - else if (firstType == 'Array') { - // get(ids [, options] [, data]) - ids = arguments[0]; - options = arguments[1]; - data = arguments[2]; - } - else { - // get([, options] [, data]) - options = arguments[0]; - data = arguments[1]; - } - - // determine the return type - var returnType; - if (options && options.returnType) { - var allowedValues = ["DataTable", "Array", "Object"]; - returnType = allowedValues.indexOf(options.returnType) == -1 ? "Array" : options.returnType; + Graph3d.prototype._onMouseUp = function (event) { + this.frame.style.cursor = 'auto'; + this.leftButtonDown = false; - if (data && (returnType != util.getType(data))) { - throw new Error('Type of parameter "data" (' + util.getType(data) + ') ' + - 'does not correspond with specified options.type (' + options.type + ')'); - } - if (returnType == 'DataTable' && !util.isDataTable(data)) { - throw new Error('Parameter "data" must be a DataTable ' + - 'when options.type is "DataTable"'); - } - } - else if (data) { - returnType = (util.getType(data) == 'DataTable') ? 'DataTable' : 'Array'; - } - else { - returnType = 'Array'; - } + // remove event listeners here + util.removeEventListener(document, 'mousemove', this.onmousemove); + util.removeEventListener(document, 'mouseup', this.onmouseup); + util.preventDefault(event); + }; - // build options - var type = options && options.type || this._options.type; - var filter = options && options.filter; - var items = [], item, itemId, i, len; + /** + * After having moved the mouse, a tooltip should pop up when the mouse is resting on a data point + * @param {Event} event A mouse move event + */ + Graph3d.prototype._onTooltip = function (event) { + var delay = 300; // ms + var boundingRect = this.frame.getBoundingClientRect(); + var mouseX = getMouseX(event) - boundingRect.left; + var mouseY = getMouseY(event) - boundingRect.top; - // convert items - if (id != undefined) { - // return a single item - item = me._getItem(id, type); - if (filter && !filter(item)) { - item = null; - } - } - else if (ids != undefined) { - // return a subset of items - for (i = 0, len = ids.length; i < len; i++) { - item = me._getItem(ids[i], type); - if (!filter || filter(item)) { - items.push(item); - } - } - } - else { - // return all items - for (itemId in this._data) { - if (this._data.hasOwnProperty(itemId)) { - item = me._getItem(itemId, type); - if (!filter || filter(item)) { - items.push(item); - } - } - } + if (!this.showTooltip) { + return; } - // order the results - if (options && options.order && id == undefined) { - this._sort(items, options.order); + if (this.tooltipTimeout) { + clearTimeout(this.tooltipTimeout); } - // filter fields of the items - if (options && options.fields) { - var fields = options.fields; - if (id != undefined) { - item = this._filterFields(item, fields); - } - else { - for (i = 0, len = items.length; i < len; i++) { - items[i] = this._filterFields(items[i], fields); - } - } + // (delayed) display of a tooltip only if no mouse button is down + if (this.leftButtonDown) { + this._hideTooltip(); + return; } - // return the results - if (returnType == 'DataTable') { - var columns = this._getColumnNames(data); - if (id != undefined) { - // append a single item to the data table - me._appendRow(data, columns, item); - } - else { - // copy the items to the provided data table - for (i = 0; i < items.length; i++) { - me._appendRow(data, columns, items[i]); + if (this.tooltip && this.tooltip.dataPoint) { + // tooltip is currently visible + var dataPoint = this._dataPointFromXY(mouseX, mouseY); + if (dataPoint !== this.tooltip.dataPoint) { + // datapoint changed + if (dataPoint) { + this._showTooltip(dataPoint); + } + else { + this._hideTooltip(); } } - return data; - } - else if (returnType == "Object") { - var result = {}; - for (i = 0; i < items.length; i++) { - result[items[i].id] = items[i]; - } - return result; } else { - // return an array - if (id != undefined) { - // a single item - return item; - } - else { - // multiple items - if (data) { - // copy the items to the provided array - for (i = 0, len = items.length; i < len; i++) { - data.push(items[i]); - } - return data; - } - else { - // just return our array - return items; + // tooltip is currently not visible + var me = this; + this.tooltipTimeout = setTimeout(function () { + me.tooltipTimeout = null; + + // show a tooltip if we have a data point + var dataPoint = me._dataPointFromXY(mouseX, mouseY); + if (dataPoint) { + me._showTooltip(dataPoint); } - } + }, delay); } }; /** - * Get ids of all items or from a filtered set of items. - * @param {Object} [options] An Object with options. Available options: - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * @return {Array} ids + * Event handler for touchstart event on mobile devices */ - DataSet.prototype.getIds = function (options) { - var data = this._data, - filter = options && options.filter, - order = options && options.order, - type = options && options.type || this._options.type, - i, - len, - id, - item, - items, - ids = []; + Graph3d.prototype._onTouchStart = function(event) { + this.touchDown = true; - if (filter) { - // get filtered items - if (order) { - // create ordered list - items = []; - for (id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, type); - if (filter(item)) { - items.push(item); - } - } - } + var me = this; + this.ontouchmove = function (event) {me._onTouchMove(event);}; + this.ontouchend = function (event) {me._onTouchEnd(event);}; + util.addEventListener(document, 'touchmove', me.ontouchmove); + util.addEventListener(document, 'touchend', me.ontouchend); - this._sort(items, order); + this._onMouseDown(event); + }; - for (i = 0, len = items.length; i < len; i++) { - ids[i] = items[i][this._fieldId]; - } - } - else { - // create unordered list - for (id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, type); - if (filter(item)) { - ids.push(item[this._fieldId]); - } - } - } - } + /** + * Event handler for touchmove event on mobile devices + */ + Graph3d.prototype._onTouchMove = function(event) { + this._onMouseMove(event); + }; + + /** + * Event handler for touchend event on mobile devices + */ + Graph3d.prototype._onTouchEnd = function(event) { + this.touchDown = false; + + util.removeEventListener(document, 'touchmove', this.ontouchmove); + util.removeEventListener(document, 'touchend', this.ontouchend); + + this._onMouseUp(event); + }; + + + /** + * Event handler for mouse wheel event, used to zoom the graph + * Code from http://adomas.org/javascript-mouse-wheel/ + * @param {event} event The event + */ + Graph3d.prototype._onWheel = function(event) { + if (!event) /* For IE. */ + event = window.event; + + // retrieve delta + var delta = 0; + if (event.wheelDelta) { /* IE/Opera. */ + delta = event.wheelDelta/120; + } else if (event.detail) { /* Mozilla case. */ + // In Mozilla, sign of delta is different than in IE. + // Also, delta is multiple of 3. + delta = -event.detail/3; } - else { - // get all items - if (order) { - // create an ordered list - items = []; - for (id in data) { - if (data.hasOwnProperty(id)) { - items.push(data[id]); - } - } - this._sort(items, order); + // If delta is nonzero, handle it. + // Basically, delta is now positive if wheel was scrolled up, + // and negative, if wheel was scrolled down. + if (delta) { + var oldLength = this.camera.getArmLength(); + var newLength = oldLength * (1 - delta / 10); - for (i = 0, len = items.length; i < len; i++) { - ids[i] = items[i][this._fieldId]; - } - } - else { - // create unordered list - for (id in data) { - if (data.hasOwnProperty(id)) { - item = data[id]; - ids.push(item[this._fieldId]); - } - } - } + this.camera.setArmLength(newLength); + this.redraw(); + + this._hideTooltip(); } - return ids; + // fire a cameraPositionChange event + var parameters = this.getCameraPosition(); + this.emit('cameraPositionChange', parameters); + + // Prevent default actions caused by mouse wheel. + // That might be ugly, but we handle scrolls somehow + // anyway, so don't bother here.. + util.preventDefault(event); }; /** - * Returns the DataSet itself. Is overwritten for example by the DataView, - * which returns the DataSet it is connected to instead. + * Test whether a point lies inside given 2D triangle + * @param {Point2d} point + * @param {Point2d[]} triangle + * @return {boolean} Returns true if given point lies inside or on the edge of the triangle + * @private */ - DataSet.prototype.getDataSet = function () { - return this; + Graph3d.prototype._insideTriangle = function (point, triangle) { + var a = triangle[0], + b = triangle[1], + c = triangle[2]; + + function sign (x) { + return x > 0 ? 1 : x < 0 ? -1 : 0; + } + + var as = sign((b.x - a.x) * (point.y - a.y) - (b.y - a.y) * (point.x - a.x)); + var bs = sign((c.x - b.x) * (point.y - b.y) - (c.y - b.y) * (point.x - b.x)); + var cs = sign((a.x - c.x) * (point.y - c.y) - (a.y - c.y) * (point.x - c.x)); + + // each of the three signs must be either equal to each other or zero + return (as == 0 || bs == 0 || as == bs) && + (bs == 0 || cs == 0 || bs == cs) && + (as == 0 || cs == 0 || as == cs); }; /** - * Execute a callback function for every item in the dataset. - * @param {function} callback - * @param {Object} [options] Available options: - * {Object.} [type] - * {String[]} [fields] filter fields - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. + * Find a data point close to given screen position (x, y) + * @param {Number} x + * @param {Number} y + * @return {Object | null} The closest data point or null if not close to any data point + * @private */ - DataSet.prototype.forEach = function (callback, options) { - var filter = options && options.filter, - type = options && options.type || this._options.type, - data = this._data, - item, - id; - - if (options && options.order) { - // execute forEach on ordered list - var items = this.get(options); + Graph3d.prototype._dataPointFromXY = function (x, y) { + var i, + distMax = 100, // px + dataPoint = null, + closestDataPoint = null, + closestDist = null, + center = new Point2d(x, y); - for (var i = 0, len = items.length; i < len; i++) { - item = items[i]; - id = item[this._fieldId]; - callback(item, id); + if (this.style === Graph3d.STYLE.BAR || + this.style === Graph3d.STYLE.BARCOLOR || + this.style === Graph3d.STYLE.BARSIZE) { + // the data points are ordered from far away to closest + for (i = this.dataPoints.length - 1; i >= 0; i--) { + dataPoint = this.dataPoints[i]; + var surfaces = dataPoint.surfaces; + if (surfaces) { + for (var s = surfaces.length - 1; s >= 0; s--) { + // split each surface in two triangles, and see if the center point is inside one of these + var surface = surfaces[s]; + var corners = surface.corners; + var triangle1 = [corners[0].screen, corners[1].screen, corners[2].screen]; + var triangle2 = [corners[2].screen, corners[3].screen, corners[0].screen]; + if (this._insideTriangle(center, triangle1) || + this._insideTriangle(center, triangle2)) { + // return immediately at the first hit + return dataPoint; + } + } + } } } else { - // unordered - for (id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, type); - if (!filter || filter(item)) { - callback(item, id); + // find the closest data point, using distance to the center of the point on 2d screen + for (i = 0; i < this.dataPoints.length; i++) { + dataPoint = this.dataPoints[i]; + var point = dataPoint.screen; + if (point) { + var distX = Math.abs(x - point.x); + var distY = Math.abs(y - point.y); + var dist = Math.sqrt(distX * distX + distY * distY); + + if ((closestDist === null || dist < closestDist) && dist < distMax) { + closestDist = dist; + closestDataPoint = dataPoint; } } } } + + + return closestDataPoint; }; /** - * Map every item in the dataset. - * @param {function} callback - * @param {Object} [options] Available options: - * {Object.} [type] - * {String[]} [fields] filter fields - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * @return {Object[]} mappedItems + * Display a tooltip for given data point + * @param {Object} dataPoint + * @private */ - DataSet.prototype.map = function (callback, options) { - var filter = options && options.filter, - type = options && options.type || this._options.type, - mappedItems = [], - data = this._data, - item; + Graph3d.prototype._showTooltip = function (dataPoint) { + var content, line, dot; - // convert and filter items - for (var id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, type); - if (!filter || filter(item)) { - mappedItems.push(callback(item, id)); + if (!this.tooltip) { + content = document.createElement('div'); + content.style.position = 'absolute'; + content.style.padding = '10px'; + content.style.border = '1px solid #4d4d4d'; + content.style.color = '#1a1a1a'; + content.style.background = 'rgba(255,255,255,0.7)'; + content.style.borderRadius = '2px'; + content.style.boxShadow = '5px 5px 10px rgba(128,128,128,0.5)'; + + line = document.createElement('div'); + line.style.position = 'absolute'; + line.style.height = '40px'; + line.style.width = '0'; + line.style.borderLeft = '1px solid #4d4d4d'; + + dot = document.createElement('div'); + dot.style.position = 'absolute'; + dot.style.height = '0'; + dot.style.width = '0'; + dot.style.border = '5px solid #4d4d4d'; + dot.style.borderRadius = '5px'; + + this.tooltip = { + dataPoint: null, + dom: { + content: content, + line: line, + dot: dot } - } + }; + } + else { + content = this.tooltip.dom.content; + line = this.tooltip.dom.line; + dot = this.tooltip.dom.dot; } - // order items - if (options && options.order) { - this._sort(mappedItems, options.order); + this._hideTooltip(); + + this.tooltip.dataPoint = dataPoint; + if (typeof this.showTooltip === 'function') { + content.innerHTML = this.showTooltip(dataPoint.point); + } + else { + content.innerHTML = '' + + '' + + '' + + '' + + '
x:' + dataPoint.point.x + '
y:' + dataPoint.point.y + '
z:' + dataPoint.point.z + '
'; } - return mappedItems; + content.style.left = '0'; + content.style.top = '0'; + this.frame.appendChild(content); + this.frame.appendChild(line); + this.frame.appendChild(dot); + + // calculate sizes + var contentWidth = content.offsetWidth; + var contentHeight = content.offsetHeight; + var lineHeight = line.offsetHeight; + var dotWidth = dot.offsetWidth; + var dotHeight = dot.offsetHeight; + + var left = dataPoint.screen.x - contentWidth / 2; + left = Math.min(Math.max(left, 10), this.frame.clientWidth - 10 - contentWidth); + + line.style.left = dataPoint.screen.x + 'px'; + line.style.top = (dataPoint.screen.y - lineHeight) + 'px'; + content.style.left = left + 'px'; + content.style.top = (dataPoint.screen.y - lineHeight - contentHeight) + 'px'; + dot.style.left = (dataPoint.screen.x - dotWidth / 2) + 'px'; + dot.style.top = (dataPoint.screen.y - dotHeight / 2) + 'px'; }; /** - * Filter the fields of an item - * @param {Object} item - * @param {String[]} fields Field names - * @return {Object} filteredItem + * Hide the tooltip when displayed * @private */ - DataSet.prototype._filterFields = function (item, fields) { - var filteredItem = {}; + Graph3d.prototype._hideTooltip = function () { + if (this.tooltip) { + this.tooltip.dataPoint = null; - for (var field in item) { - if (item.hasOwnProperty(field) && (fields.indexOf(field) != -1)) { - filteredItem[field] = item[field]; + for (var prop in this.tooltip.dom) { + if (this.tooltip.dom.hasOwnProperty(prop)) { + var elem = this.tooltip.dom[prop]; + if (elem && elem.parentNode) { + elem.parentNode.removeChild(elem); + } + } } } - - return filteredItem; }; + /**--------------------------------------------------------------------------**/ + + /** - * Sort the provided array with items - * @param {Object[]} items - * @param {String | function} order A field name or custom sort function. - * @private + * Get the horizontal mouse position from a mouse event + * @param {Event} event + * @return {Number} mouse x */ - DataSet.prototype._sort = function (items, order) { - if (util.isString(order)) { - // order by provided field name - var name = order; // field name - items.sort(function (a, b) { - var av = a[name]; - var bv = b[name]; - return (av > bv) ? 1 : ((av < bv) ? -1 : 0); - }); - } - else if (typeof order === 'function') { - // order by sort function - items.sort(order); - } - // TODO: extend order by an Object {field:String, direction:String} - // where direction can be 'asc' or 'desc' - else { - throw new TypeError('Order must be a function or a string'); - } + function getMouseX (event) { + if ('clientX' in event) return event.clientX; + return event.targetTouches[0] && event.targetTouches[0].clientX || 0; + } + + /** + * Get the vertical mouse position from a mouse event + * @param {Event} event + * @return {Number} mouse y + */ + function getMouseY (event) { + if ('clientY' in event) return event.clientY; + return event.targetTouches[0] && event.targetTouches[0].clientY || 0; + } + + module.exports = Graph3d; + + +/***/ }, +/* 7 */ +/***/ function(module, exports, __webpack_require__) { + + var Point3d = __webpack_require__(10); + + /** + * @class Camera + * The camera is mounted on a (virtual) camera arm. The camera arm can rotate + * The camera is always looking in the direction of the origin of the arm. + * This way, the camera always rotates around one fixed point, the location + * of the camera arm. + * + * Documentation: + * http://en.wikipedia.org/wiki/3D_projection + */ + function Camera() { + this.armLocation = new Point3d(); + this.armRotation = {}; + this.armRotation.horizontal = 0; + this.armRotation.vertical = 0; + this.armLength = 1.7; + + this.cameraLocation = new Point3d(); + this.cameraRotation = new Point3d(0.5*Math.PI, 0, 0); + + this.calculateCameraOrientation(); + } + + /** + * Set the location (origin) of the arm + * @param {Number} x Normalized value of x + * @param {Number} y Normalized value of y + * @param {Number} z Normalized value of z + */ + Camera.prototype.setArmLocation = function(x, y, z) { + this.armLocation.x = x; + this.armLocation.y = y; + this.armLocation.z = z; + + this.calculateCameraOrientation(); }; /** - * Remove an object by pointer or by id - * @param {String | Number | Object | Array} id Object or id, or an array with - * objects or ids to be removed - * @param {String} [senderId] Optional sender id - * @return {Array} removedIds + * Set the rotation of the camera arm + * @param {Number} horizontal The horizontal rotation, between 0 and 2*PI. + * Optional, can be left undefined. + * @param {Number} vertical The vertical rotation, between 0 and 0.5*PI + * if vertical=0.5*PI, the graph is shown from the + * top. Optional, can be left undefined. */ - DataSet.prototype.remove = function (id, senderId) { - var removedIds = [], - i, len, removedId; - - if (Array.isArray(id)) { - for (i = 0, len = id.length; i < len; i++) { - removedId = this._remove(id[i]); - if (removedId != null) { - removedIds.push(removedId); - } - } - } - else { - removedId = this._remove(id); - if (removedId != null) { - removedIds.push(removedId); - } + Camera.prototype.setArmRotation = function(horizontal, vertical) { + if (horizontal !== undefined) { + this.armRotation.horizontal = horizontal; } - if (removedIds.length) { - this._trigger('remove', {items: removedIds}, senderId); + if (vertical !== undefined) { + this.armRotation.vertical = vertical; + if (this.armRotation.vertical < 0) this.armRotation.vertical = 0; + if (this.armRotation.vertical > 0.5*Math.PI) this.armRotation.vertical = 0.5*Math.PI; } - return removedIds; + if (horizontal !== undefined || vertical !== undefined) { + this.calculateCameraOrientation(); + } }; /** - * Remove an item by its id - * @param {Number | String | Object} id id or item - * @returns {Number | String | null} id - * @private + * Retrieve the current arm rotation + * @return {object} An object with parameters horizontal and vertical */ - DataSet.prototype._remove = function (id) { - if (util.isNumber(id) || util.isString(id)) { - if (this._data[id]) { - delete this._data[id]; - return id; - } - } - else if (id instanceof Object) { - var itemId = id[this._fieldId]; - if (itemId && this._data[itemId]) { - delete this._data[itemId]; - return itemId; - } - } - return null; + Camera.prototype.getArmRotation = function() { + var rot = {}; + rot.horizontal = this.armRotation.horizontal; + rot.vertical = this.armRotation.vertical; + + return rot; }; /** - * Clear the data - * @param {String} [senderId] Optional sender id - * @return {Array} removedIds The ids of all removed items + * Set the (normalized) length of the camera arm. + * @param {Number} length A length between 0.71 and 5.0 */ - DataSet.prototype.clear = function (senderId) { - var ids = Object.keys(this._data); + Camera.prototype.setArmLength = function(length) { + if (length === undefined) + return; - this._data = {}; + this.armLength = length; - this._trigger('remove', {items: ids}, senderId); + // Radius must be larger than the corner of the graph, + // which has a distance of sqrt(0.5^2+0.5^2) = 0.71 from the center of the + // graph + if (this.armLength < 0.71) this.armLength = 0.71; + if (this.armLength > 5.0) this.armLength = 5.0; - return ids; + this.calculateCameraOrientation(); }; /** - * Find the item with maximum value of a specified field - * @param {String} field - * @return {Object | null} item Item containing max value, or null if no items + * Retrieve the arm length + * @return {Number} length */ - DataSet.prototype.max = function (field) { - var data = this._data, - max = null, - maxField = null; - - for (var id in data) { - if (data.hasOwnProperty(id)) { - var item = data[id]; - var itemField = item[field]; - if (itemField != null && (!max || itemField > maxField)) { - max = item; - maxField = itemField; - } - } - } + Camera.prototype.getArmLength = function() { + return this.armLength; + }; - return max; + /** + * Retrieve the camera location + * @return {Point3d} cameraLocation + */ + Camera.prototype.getCameraLocation = function() { + return this.cameraLocation; }; /** - * Find the item with minimum value of a specified field - * @param {String} field - * @return {Object | null} item Item containing max value, or null if no items + * Retrieve the camera rotation + * @return {Point3d} cameraRotation */ - DataSet.prototype.min = function (field) { - var data = this._data, - min = null, - minField = null; + Camera.prototype.getCameraRotation = function() { + return this.cameraRotation; + }; - for (var id in data) { - if (data.hasOwnProperty(id)) { - var item = data[id]; - var itemField = item[field]; - if (itemField != null && (!min || itemField < minField)) { - min = item; - minField = itemField; - } - } - } + /** + * Calculate the location and rotation of the camera based on the + * position and orientation of the camera arm + */ + Camera.prototype.calculateCameraOrientation = function() { + // calculate location of the camera + this.cameraLocation.x = this.armLocation.x - this.armLength * Math.sin(this.armRotation.horizontal) * Math.cos(this.armRotation.vertical); + this.cameraLocation.y = this.armLocation.y - this.armLength * Math.cos(this.armRotation.horizontal) * Math.cos(this.armRotation.vertical); + this.cameraLocation.z = this.armLocation.z + this.armLength * Math.sin(this.armRotation.vertical); - return min; + // calculate rotation of the camera + this.cameraRotation.x = Math.PI/2 - this.armRotation.vertical; + this.cameraRotation.y = 0; + this.cameraRotation.z = -this.armRotation.horizontal; }; + module.exports = Camera; + +/***/ }, +/* 8 */ +/***/ function(module, exports, __webpack_require__) { + + var DataView = __webpack_require__(4); + /** - * Find all distinct values of a specified field - * @param {String} field - * @return {Array} values Array containing all distinct values. If data items - * do not contain the specified field are ignored. - * The returned array is unordered. + * @class Filter + * + * @param {DataSet} data The google data table + * @param {Number} column The index of the column to be filtered + * @param {Graph} graph The graph */ - DataSet.prototype.distinct = function (field) { - var data = this._data; - var values = []; - var fieldType = this._options.type && this._options.type[field] || null; - var count = 0; - var i; + function Filter (data, column, graph) { + this.data = data; + this.column = column; + this.graph = graph; // the parent graph - for (var prop in data) { - if (data.hasOwnProperty(prop)) { - var item = data[prop]; - var value = item[field]; - var exists = false; - for (i = 0; i < count; i++) { - if (values[i] == value) { - exists = true; - break; - } - } - if (!exists && (value !== undefined)) { - values[count] = value; - count++; - } - } - } + this.index = undefined; + this.value = undefined; - if (fieldType) { - for (i = 0; i < values.length; i++) { - values[i] = util.convert(values[i], fieldType); - } + // read all distinct values and select the first one + this.values = graph.getDistinctValues(data.get(), this.column); + + // sort both numeric and string values correctly + this.values.sort(function (a, b) { + return a > b ? 1 : a < b ? -1 : 0; + }); + + if (this.values.length > 0) { + this.selectValue(0); } - return values; - }; + // create an array with the filtered datapoints. this will be loaded afterwards + this.dataPoints = []; - /** - * Add a single item. Will fail when an item with the same id already exists. - * @param {Object} item - * @return {String} id - * @private - */ - DataSet.prototype._addItem = function (item) { - var id = item[this._fieldId]; + this.loaded = false; + this.onLoadCallback = undefined; - if (id != undefined) { - // check whether this id is already taken - if (this._data[id]) { - // item already exists - throw new Error('Cannot add item: item with id ' + id + ' already exists'); - } + if (graph.animationPreload) { + this.loaded = false; + this.loadInBackground(); } else { - // generate an id - id = util.randomUUID(); - item[this._fieldId] = id; + this.loaded = true; } + }; - var d = {}; - for (var field in item) { - if (item.hasOwnProperty(field)) { - var fieldType = this._type[field]; // type may be undefined - d[field] = util.convert(item[field], fieldType); - } - } - this._data[id] = d; - return id; + /** + * Return the label + * @return {string} label + */ + Filter.prototype.isLoaded = function() { + return this.loaded; }; + /** - * Get an item. Fields can be converted to a specific type - * @param {String} id - * @param {Object.} [types] field types to convert - * @return {Object | null} item - * @private + * Return the loaded progress + * @return {Number} percentage between 0 and 100 */ - DataSet.prototype._getItem = function (id, types) { - var field, value; + Filter.prototype.getLoadedProgress = function() { + var len = this.values.length; - // get the item from the dataset - var raw = this._data[id]; - if (!raw) { - return null; + var i = 0; + while (this.dataPoints[i]) { + i++; } - // convert the items field types - var converted = {}; - if (types) { - for (field in raw) { - if (raw.hasOwnProperty(field)) { - value = raw[field]; - converted[field] = util.convert(value, types[field]); - } - } - } - else { - // no field types specified, no converting needed - for (field in raw) { - if (raw.hasOwnProperty(field)) { - value = raw[field]; - converted[field] = value; - } - } - } - return converted; + return Math.round(i / len * 100); }; + /** - * Update a single item: merge with existing item. - * Will fail when the item has no id, or when there does not exist an item - * with the same id. - * @param {Object} item - * @return {String} id - * @private + * Return the label + * @return {string} label */ - DataSet.prototype._updateItem = function (item) { - var id = item[this._fieldId]; - if (id == undefined) { - throw new Error('Cannot update item: item has no id (item: ' + JSON.stringify(item) + ')'); - } - var d = this._data[id]; - if (!d) { - // item doesn't exist - throw new Error('Cannot update item: no item with id ' + id + ' found'); - } + Filter.prototype.getLabel = function() { + return this.graph.filterLabel; + }; - // merge with current item - for (var field in item) { - if (item.hasOwnProperty(field)) { - var fieldType = this._type[field]; // type may be undefined - d[field] = util.convert(item[field], fieldType); - } - } - return id; + /** + * Return the columnIndex of the filter + * @return {Number} columnIndex + */ + Filter.prototype.getColumn = function() { + return this.column; }; /** - * Get an array with the column names of a Google DataTable - * @param {DataTable} dataTable - * @return {String[]} columnNames - * @private + * Return the currently selected value. Returns undefined if there is no selection + * @return {*} value */ - DataSet.prototype._getColumnNames = function (dataTable) { - var columns = []; - for (var col = 0, cols = dataTable.getNumberOfColumns(); col < cols; col++) { - columns[col] = dataTable.getColumnId(col) || dataTable.getColumnLabel(col); - } - return columns; + Filter.prototype.getSelectedValue = function() { + if (this.index === undefined) + return undefined; + + return this.values[this.index]; }; /** - * Append an item as a row to the dataTable - * @param dataTable - * @param columns - * @param item - * @private + * Retrieve all values of the filter + * @return {Array} values */ - DataSet.prototype._appendRow = function (dataTable, columns, item) { - var row = dataTable.addRow(); - - for (var col = 0, cols = columns.length; col < cols; col++) { - var field = columns[col]; - dataTable.setValue(row, col, item[field]); - } + Filter.prototype.getValues = function() { + return this.values; }; - module.exports = DataSet; + /** + * Retrieve one value of the filter + * @param {Number} index + * @return {*} value + */ + Filter.prototype.getValue = function(index) { + if (index >= this.values.length) + throw 'Error: index out of range'; + return this.values[index]; + }; -/***/ }, -/* 8 */ -/***/ function(module, exports, __webpack_require__) { /** - * A queue - * @param {Object} options - * Available options: - * - delay: number When provided, the queue will be flushed - * automatically after an inactivity of this delay - * in milliseconds. - * Default value is null. - * - max: number When the queue exceeds the given maximum number - * of entries, the queue is flushed automatically. - * Default value of max is Infinity. - * @constructor + * Retrieve the (filtered) dataPoints for the currently selected filter index + * @param {Number} [index] (optional) + * @return {Array} dataPoints */ - function Queue(options) { - // options - this.delay = null; - this.max = Infinity; + Filter.prototype._getDataPoints = function(index) { + if (index === undefined) + index = this.index; + + if (index === undefined) + return []; + + var dataPoints; + if (this.dataPoints[index]) { + dataPoints = this.dataPoints[index]; + } + else { + var f = {}; + f.column = this.column; + f.value = this.values[index]; + + var dataView = new DataView(this.data,{filter: function (item) {return (item[f.column] == f.value);}}).get(); + dataPoints = this.graph._getDataPoints(dataView); + + this.dataPoints[index] = dataPoints; + } + + return dataPoints; + }; - // properties - this._queue = []; - this._timeout = null; - this._extended = null; - this.setOptions(options); - } /** - * Update the configuration of the queue - * @param {Object} options - * Available options: - * - delay: number When provided, the queue will be flushed - * automatically after an inactivity of this delay - * in milliseconds. - * Default value is null. - * - max: number When the queue exceeds the given maximum number - * of entries, the queue is flushed automatically. - * Default value of max is Infinity. - * @param options + * Set a callback function when the filter is fully loaded. */ - Queue.prototype.setOptions = function (options) { - if (options && typeof options.delay !== 'undefined') { - this.delay = options.delay; - } - if (options && typeof options.max !== 'undefined') { - this.max = options.max; - } + Filter.prototype.setOnLoadCallback = function(callback) { + this.onLoadCallback = callback; + }; - this._flushIfNeeded(); + + /** + * Add a value to the list with available values for this filter + * No double entries will be created. + * @param {Number} index + */ + Filter.prototype.selectValue = function(index) { + if (index >= this.values.length) + throw 'Error: index out of range'; + + this.index = index; + this.value = this.values[index]; }; /** - * Extend an object with queuing functionality. - * The object will be extended with a function flush, and the methods provided - * in options.replace will be replaced with queued ones. - * @param {Object} object - * @param {Object} options - * Available options: - * - replace: Array. - * A list with method names of the methods - * on the object to be replaced with queued ones. - * - delay: number When provided, the queue will be flushed - * automatically after an inactivity of this delay - * in milliseconds. - * Default value is null. - * - max: number When the queue exceeds the given maximum number - * of entries, the queue is flushed automatically. - * Default value of max is Infinity. - * @return {Queue} Returns the created queue + * Load all filtered rows in the background one by one + * Start this method without providing an index! */ - Queue.extend = function (object, options) { - var queue = new Queue(options); + Filter.prototype.loadInBackground = function(index) { + if (index === undefined) + index = 0; - if (object.flush !== undefined) { - throw new Error('Target object already has a property flush'); - } - object.flush = function () { - queue.flush(); - }; + var frame = this.graph.frame; - var methods = [{ - name: 'flush', - original: undefined - }]; + if (index < this.values.length) { + var dataPointsTemp = this._getDataPoints(index); + //this.graph.redrawInfo(); // TODO: not neat - if (options && options.replace) { - for (var i = 0; i < options.replace.length; i++) { - var name = options.replace[i]; - methods.push({ - name: name, - original: object[name] - }); - queue.replace(object, name); + // create a progress box + if (frame.progress === undefined) { + frame.progress = document.createElement('DIV'); + frame.progress.style.position = 'absolute'; + frame.progress.style.color = 'gray'; + frame.appendChild(frame.progress); } + var progress = this.getLoadedProgress(); + frame.progress.innerHTML = 'Loading animation... ' + progress + '%'; + // TODO: this is no nice solution... + frame.progress.style.bottom = 60 + 'px'; // TODO: use height of slider + frame.progress.style.left = 10 + 'px'; + + var me = this; + setTimeout(function() {me.loadInBackground(index+1);}, 10); + this.loaded = false; } + else { + this.loaded = true; - queue._extended = { - object: object, - methods: methods - }; + // remove the progress box + if (frame.progress !== undefined) { + frame.removeChild(frame.progress); + frame.progress = undefined; + } - return queue; + if (this.onLoadCallback) + this.onLoadCallback(); + } }; + module.exports = Filter; + + +/***/ }, +/* 9 */ +/***/ function(module, exports, __webpack_require__) { + /** - * Destroy the queue. The queue will first flush all queued actions, and in - * case it has extended an object, will restore the original object. + * @prototype Point2d + * @param {Number} [x] + * @param {Number} [y] */ - Queue.prototype.destroy = function () { - this.flush(); + function Point2d (x, y) { + this.x = x !== undefined ? x : 0; + this.y = y !== undefined ? y : 0; + } - if (this._extended) { - var object = this._extended.object; - var methods = this._extended.methods; - for (var i = 0; i < methods.length; i++) { - var method = methods[i]; - if (method.original) { - object[method.name] = method.original; - } - else { - delete object[method.name]; - } - } - this._extended = null; - } - }; + module.exports = Point2d; + + +/***/ }, +/* 10 */ +/***/ function(module, exports, __webpack_require__) { /** - * Replace a method on an object with a queued version - * @param {Object} object Object having the method - * @param {string} method The method name + * @prototype Point3d + * @param {Number} [x] + * @param {Number} [y] + * @param {Number} [z] */ - Queue.prototype.replace = function(object, method) { - var me = this; - var original = object[method]; - if (!original) { - throw new Error('Method ' + method + ' undefined'); - } - - object[method] = function () { - // create an Array with the arguments - var args = []; - for (var i = 0; i < arguments.length; i++) { - args[i] = arguments[i]; - } + function Point3d(x, y, z) { + this.x = x !== undefined ? x : 0; + this.y = y !== undefined ? y : 0; + this.z = z !== undefined ? z : 0; + }; - // add this call to the queue - me.queue({ - args: args, - fn: original, - context: this - }); - }; + /** + * Subtract the two provided points, returns a-b + * @param {Point3d} a + * @param {Point3d} b + * @return {Point3d} a-b + */ + Point3d.subtract = function(a, b) { + var sub = new Point3d(); + sub.x = a.x - b.x; + sub.y = a.y - b.y; + sub.z = a.z - b.z; + return sub; }; /** - * Queue a call - * @param {function | {fn: function, args: Array} | {fn: function, args: Array, context: Object}} entry + * Add the two provided points, returns a+b + * @param {Point3d} a + * @param {Point3d} b + * @return {Point3d} a+b */ - Queue.prototype.queue = function(entry) { - if (typeof entry === 'function') { - this._queue.push({fn: entry}); - } - else { - this._queue.push(entry); - } + Point3d.add = function(a, b) { + var sum = new Point3d(); + sum.x = a.x + b.x; + sum.y = a.y + b.y; + sum.z = a.z + b.z; + return sum; + }; - this._flushIfNeeded(); + /** + * Calculate the average of two 3d points + * @param {Point3d} a + * @param {Point3d} b + * @return {Point3d} The average, (a+b)/2 + */ + Point3d.avg = function(a, b) { + return new Point3d( + (a.x + b.x) / 2, + (a.y + b.y) / 2, + (a.z + b.z) / 2 + ); }; /** - * Check whether the queue needs to be flushed - * @private + * Calculate the cross product of the two provided points, returns axb + * Documentation: http://en.wikipedia.org/wiki/Cross_product + * @param {Point3d} a + * @param {Point3d} b + * @return {Point3d} cross product axb */ - Queue.prototype._flushIfNeeded = function () { - // flush when the maximum is exceeded. - if (this._queue.length > this.max) { - this.flush(); - } + Point3d.crossProduct = function(a, b) { + var crossproduct = new Point3d(); - // flush after a period of inactivity when a delay is configured - clearTimeout(this._timeout); - if (this.queue.length > 0 && typeof this.delay === 'number') { - var me = this; - this._timeout = setTimeout(function () { - me.flush(); - }, this.delay); - } + crossproduct.x = a.y * b.z - a.z * b.y; + crossproduct.y = a.z * b.x - a.x * b.z; + crossproduct.z = a.x * b.y - a.y * b.x; + + return crossproduct; }; + /** - * Flush all queued calls + * Rtrieve the length of the vector (or the distance from this point to the origin + * @return {Number} length */ - Queue.prototype.flush = function () { - while (this._queue.length > 0) { - var entry = this._queue.shift(); - entry.fn.apply(entry.context || entry.fn, entry.args || []); - } + Point3d.prototype.length = function() { + return Math.sqrt( + this.x * this.x + + this.y * this.y + + this.z * this.z + ); }; - module.exports = Queue; + module.exports = Point3d; /***/ }, -/* 9 */ +/* 11 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); - var DataSet = __webpack_require__(7); /** - * DataView - * - * a dataview offers a filtered view on a dataset or an other dataview. - * - * @param {DataSet | DataView} data - * @param {Object} [options] Available options: see method get + * @constructor Slider * - * @constructor DataView + * An html slider control with start/stop/prev/next buttons + * @param {Element} container The element where the slider will be created + * @param {Object} options Available options: + * {boolean} visible If true (default) the + * slider is visible. */ - function DataView (data, options) { - this._data = null; - this._ids = {}; // ids of the items currently in memory (just contains a boolean true) - this._options = options || {}; - this._fieldId = 'id'; // name of the field containing id - this._subscribers = {}; // event subscribers + function Slider(container, options) { + if (container === undefined) { + throw 'Error: No container element defined'; + } + this.container = container; + this.visible = (options && options.visible != undefined) ? options.visible : true; - var me = this; - this.listener = function () { - me._onEvent.apply(me, arguments); - }; + if (this.visible) { + this.frame = document.createElement('DIV'); + //this.frame.style.backgroundColor = '#E5E5E5'; + this.frame.style.width = '100%'; + this.frame.style.position = 'relative'; + this.container.appendChild(this.frame); - this.setData(data); - } + this.frame.prev = document.createElement('INPUT'); + this.frame.prev.type = 'BUTTON'; + this.frame.prev.value = 'Prev'; + this.frame.appendChild(this.frame.prev); - // TODO: implement a function .config() to dynamically update things like configured filter - // and trigger changes accordingly + this.frame.play = document.createElement('INPUT'); + this.frame.play.type = 'BUTTON'; + this.frame.play.value = 'Play'; + this.frame.appendChild(this.frame.play); - /** - * Set a data source for the view - * @param {DataSet | DataView} data - */ - DataView.prototype.setData = function (data) { - var ids, i, len; + this.frame.next = document.createElement('INPUT'); + this.frame.next.type = 'BUTTON'; + this.frame.next.value = 'Next'; + this.frame.appendChild(this.frame.next); - if (this._data) { - // unsubscribe from current dataset - if (this._data.unsubscribe) { - this._data.unsubscribe('*', this.listener); - } + this.frame.bar = document.createElement('INPUT'); + this.frame.bar.type = 'BUTTON'; + this.frame.bar.style.position = 'absolute'; + this.frame.bar.style.border = '1px solid red'; + this.frame.bar.style.width = '100px'; + this.frame.bar.style.height = '6px'; + this.frame.bar.style.borderRadius = '2px'; + this.frame.bar.style.MozBorderRadius = '2px'; + this.frame.bar.style.border = '1px solid #7F7F7F'; + this.frame.bar.style.backgroundColor = '#E5E5E5'; + this.frame.appendChild(this.frame.bar); - // trigger a remove of all items in memory - ids = []; - for (var id in this._ids) { - if (this._ids.hasOwnProperty(id)) { - ids.push(id); - } - } - this._ids = {}; - this._trigger('remove', {items: ids}); + this.frame.slide = document.createElement('INPUT'); + this.frame.slide.type = 'BUTTON'; + this.frame.slide.style.margin = '0px'; + this.frame.slide.value = ' '; + this.frame.slide.style.position = 'relative'; + this.frame.slide.style.left = '-100px'; + this.frame.appendChild(this.frame.slide); + + // create events + var me = this; + this.frame.slide.onmousedown = function (event) {me._onMouseDown(event);}; + this.frame.prev.onclick = function (event) {me.prev(event);}; + this.frame.play.onclick = function (event) {me.togglePlay(event);}; + this.frame.next.onclick = function (event) {me.next(event);}; } - this._data = data; + this.onChangeCallback = undefined; - if (this._data) { - // update fieldId - this._fieldId = this._options.fieldId || - (this._data && this._data.options && this._data.options.fieldId) || - 'id'; + this.values = []; + this.index = undefined; - // trigger an add of all added items - ids = this._data.getIds({filter: this._options && this._options.filter}); - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - this._ids[id] = true; - } - this._trigger('add', {items: ids}); + this.playTimeout = undefined; + this.playInterval = 1000; // milliseconds + this.playLoop = true; + } - // subscribe to new dataset - if (this._data.on) { - this._data.on('*', this.listener); - } + /** + * Select the previous index + */ + Slider.prototype.prev = function() { + var index = this.getIndex(); + if (index > 0) { + index--; + this.setIndex(index); } }; /** - * Get data from the data view - * - * Usage: - * - * get() - * get(options: Object) - * get(options: Object, data: Array | DataTable) - * - * get(id: Number) - * get(id: Number, options: Object) - * get(id: Number, options: Object, data: Array | DataTable) - * - * get(ids: Number[]) - * get(ids: Number[], options: Object) - * get(ids: Number[], options: Object, data: Array | DataTable) - * - * Where: - * - * {Number | String} id The id of an item - * {Number[] | String{}} ids An array with ids of items - * {Object} options An Object with options. Available options: - * {String} [type] Type of data to be returned. Can - * be 'DataTable' or 'Array' (default) - * {Object.} [convert] - * {String[]} [fields] field names to be returned - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * {Array | DataTable} [data] If provided, items will be appended to this - * array or table. Required in case of Google - * DataTable. - * @param args + * Select the next index */ - DataView.prototype.get = function (args) { - var me = this; - - // parse the arguments - var ids, options, data; - var firstType = util.getType(arguments[0]); - if (firstType == 'String' || firstType == 'Number' || firstType == 'Array') { - // get(id(s) [, options] [, data]) - ids = arguments[0]; // can be a single id or an array with ids - options = arguments[1]; - data = arguments[2]; - } - else { - // get([, options] [, data]) - options = arguments[0]; - data = arguments[1]; - } - - // extend the options with the default options and provided options - var viewOptions = util.extend({}, this._options, options); - - // create a combined filter method when needed - if (this._options.filter && options && options.filter) { - viewOptions.filter = function (item) { - return me._options.filter(item) && options.filter(item); - } - } - - // build up the call to the linked data set - var getArguments = []; - if (ids != undefined) { - getArguments.push(ids); + Slider.prototype.next = function() { + var index = this.getIndex(); + if (index < this.values.length - 1) { + index++; + this.setIndex(index); } - getArguments.push(viewOptions); - getArguments.push(data); - - return this._data && this._data.get.apply(this._data, getArguments); }; /** - * Get ids of all items or from a filtered set of items. - * @param {Object} [options] An Object with options. Available options: - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * @return {Array} ids + * Select the next index */ - DataView.prototype.getIds = function (options) { - var ids; - - if (this._data) { - var defaultFilter = this._options.filter; - var filter; - - if (options && options.filter) { - if (defaultFilter) { - filter = function (item) { - return defaultFilter(item) && options.filter(item); - } - } - else { - filter = options.filter; - } - } - else { - filter = defaultFilter; - } + Slider.prototype.playNext = function() { + var start = new Date(); - ids = this._data.getIds({ - filter: filter, - order: options && options.order - }); + var index = this.getIndex(); + if (index < this.values.length - 1) { + index++; + this.setIndex(index); } - else { - ids = []; + else if (this.playLoop) { + // jump to the start + index = 0; + this.setIndex(index); } - return ids; + var end = new Date(); + var diff = (end - start); + + // calculate how much time it to to set the index and to execute the callback + // function. + var interval = Math.max(this.playInterval - diff, 0); + // document.title = diff // TODO: cleanup + + var me = this; + this.playTimeout = setTimeout(function() {me.playNext();}, interval); }; /** - * Get the DataSet to which this DataView is connected. In case there is a chain - * of multiple DataViews, the root DataSet of this chain is returned. - * @return {DataSet} dataSet + * Toggle start or stop playing */ - DataView.prototype.getDataSet = function () { - var dataSet = this; - while (dataSet instanceof DataView) { - dataSet = dataSet._data; + Slider.prototype.togglePlay = function() { + if (this.playTimeout === undefined) { + this.play(); + } else { + this.stop(); } - return dataSet || null; }; /** - * Event listener. Will propagate all events from the connected data set to - * the subscribers of the DataView, but will filter the items and only trigger - * when there are changes in the filtered data set. - * @param {String} event - * @param {Object | null} params - * @param {String} senderId - * @private + * Start playing */ - DataView.prototype._onEvent = function (event, params, senderId) { - var i, len, id, item, - ids = params && params.items, - data = this._data, - added = [], - updated = [], - removed = []; - - if (ids && data) { - switch (event) { - case 'add': - // filter the ids of the added items - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - item = this.get(id); - if (item) { - this._ids[id] = true; - added.push(id); - } - } - - break; - - case 'update': - // determine the event from the views viewpoint: an updated - // item can be added, updated, or removed from this view. - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - item = this.get(id); - - if (item) { - if (this._ids[id]) { - updated.push(id); - } - else { - this._ids[id] = true; - added.push(id); - } - } - else { - if (this._ids[id]) { - delete this._ids[id]; - removed.push(id); - } - else { - // nothing interesting for me :-( - } - } - } + Slider.prototype.play = function() { + // Test whether already playing + if (this.playTimeout) return; - break; + this.playNext(); - case 'remove': - // filter the ids of the removed items - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - if (this._ids[id]) { - delete this._ids[id]; - removed.push(id); - } - } + if (this.frame) { + this.frame.play.value = 'Stop'; + } + }; - break; - } + /** + * Stop playing + */ + Slider.prototype.stop = function() { + clearInterval(this.playTimeout); + this.playTimeout = undefined; - if (added.length) { - this._trigger('add', {items: added}, senderId); - } - if (updated.length) { - this._trigger('update', {items: updated}, senderId); - } - if (removed.length) { - this._trigger('remove', {items: removed}, senderId); - } + if (this.frame) { + this.frame.play.value = 'Play'; } }; - // copy subscription functionality from DataSet - DataView.prototype.on = DataSet.prototype.on; - DataView.prototype.off = DataSet.prototype.off; - DataView.prototype._trigger = DataSet.prototype._trigger; + /** + * Set a callback function which will be triggered when the value of the + * slider bar has changed. + */ + Slider.prototype.setOnChangeCallback = function(callback) { + this.onChangeCallback = callback; + }; - // TODO: make these functions deprecated (replaced with `on` and `off` since version 0.5) - DataView.prototype.subscribe = DataView.prototype.on; - DataView.prototype.unsubscribe = DataView.prototype.off; + /** + * Set the interval for playing the list + * @param {Number} interval The interval in milliseconds + */ + Slider.prototype.setPlayInterval = function(interval) { + this.playInterval = interval; + }; - module.exports = DataView; + /** + * Retrieve the current play interval + * @return {Number} interval The interval in milliseconds + */ + Slider.prototype.getPlayInterval = function(interval) { + return this.playInterval; + }; -/***/ }, -/* 10 */ -/***/ function(module, exports, __webpack_require__) { + /** + * Set looping on or off + * @pararm {boolean} doLoop If true, the slider will jump to the start when + * the end is passed, and will jump to the end + * when the start is passed. + */ + Slider.prototype.setPlayLoop = function(doLoop) { + this.playLoop = doLoop; + }; - var Emitter = __webpack_require__(11); - var DataSet = __webpack_require__(7); - var DataView = __webpack_require__(9); - var util = __webpack_require__(1); - var Point3d = __webpack_require__(12); - var Point2d = __webpack_require__(13); - var Camera = __webpack_require__(14); - var Filter = __webpack_require__(15); - var Slider = __webpack_require__(16); - var StepNumber = __webpack_require__(17); /** - * @constructor Graph3d - * Graph3d displays data in 3d. - * - * Graph3d is developed in javascript as a Google Visualization Chart. - * - * @param {Element} container The DOM element in which the Graph3d will - * be created. Normally a div element. - * @param {DataSet | DataView | Array} [data] - * @param {Object} [options] + * Execute the onchange callback function */ - function Graph3d(container, data, options) { - if (!(this instanceof Graph3d)) { - throw new SyntaxError('Constructor must be called with the new operator'); + Slider.prototype.onChange = function() { + if (this.onChangeCallback !== undefined) { + this.onChangeCallback(); } + }; - // create variables and set default values - this.containerElement = container; - this.width = '400px'; - this.height = '400px'; - this.margin = 10; // px - this.defaultXCenter = '55%'; - this.defaultYCenter = '50%'; + /** + * redraw the slider on the correct place + */ + Slider.prototype.redraw = function() { + if (this.frame) { + // resize the bar + this.frame.bar.style.top = (this.frame.clientHeight/2 - + this.frame.bar.offsetHeight/2) + 'px'; + this.frame.bar.style.width = (this.frame.clientWidth - + this.frame.prev.clientWidth - + this.frame.play.clientWidth - + this.frame.next.clientWidth - 30) + 'px'; - this.xLabel = 'x'; - this.yLabel = 'y'; - this.zLabel = 'z'; + // position the slider button + var left = this.indexToLeft(this.index); + this.frame.slide.style.left = (left) + 'px'; + } + }; - var passValueFn = function(v) { return v; }; - this.xValueLabel = passValueFn; - this.yValueLabel = passValueFn; - this.zValueLabel = passValueFn; - - this.filterLabel = 'time'; - this.legendLabel = 'value'; - this.style = Graph3d.STYLE.DOT; - this.showPerspective = true; - this.showGrid = true; - this.keepAspectRatio = true; - this.showShadow = false; - this.showGrayBottom = false; // TODO: this does not work correctly - this.showTooltip = false; - this.verticalRatio = 0.5; // 0.1 to 1.0, where 1.0 results in a 'cube' + /** + * Set the list with values for the slider + * @param {Array} values A javascript array with values (any type) + */ + Slider.prototype.setValues = function(values) { + this.values = values; - this.animationInterval = 1000; // milliseconds - this.animationPreload = false; + if (this.values.length > 0) + this.setIndex(0); + else + this.index = undefined; + }; - this.camera = new Camera(); - this.eye = new Point3d(0, 0, -1); // TODO: set eye.z about 3/4 of the width of the window? + /** + * Select a value by its index + * @param {Number} index + */ + Slider.prototype.setIndex = function(index) { + if (index < this.values.length) { + this.index = index; - this.dataTable = null; // The original data table - this.dataPoints = null; // The table with point objects + this.redraw(); + this.onChange(); + } + else { + throw 'Error: index out of range'; + } + }; - // the column indexes - this.colX = undefined; - this.colY = undefined; - this.colZ = undefined; - this.colValue = undefined; - this.colFilter = undefined; + /** + * retrieve the index of the currently selected vaue + * @return {Number} index + */ + Slider.prototype.getIndex = function() { + return this.index; + }; - this.xMin = 0; - this.xStep = undefined; // auto by default - this.xMax = 1; - this.yMin = 0; - this.yStep = undefined; // auto by default - this.yMax = 1; - this.zMin = 0; - this.zStep = undefined; // auto by default - this.zMax = 1; - this.valueMin = 0; - this.valueMax = 1; - this.xBarWidth = 1; - this.yBarWidth = 1; - // TODO: customize axis range - // constants - this.colorAxis = '#4D4D4D'; - this.colorGrid = '#D3D3D3'; - this.colorDot = '#7DC1FF'; - this.colorDotBorder = '#3267D2'; + /** + * retrieve the currently selected value + * @return {*} value + */ + Slider.prototype.get = function() { + return this.values[this.index]; + }; - // create a frame and canvas - this.create(); - // apply options (also when undefined) - this.setOptions(options); + Slider.prototype._onMouseDown = function(event) { + // only react on left mouse button down + var leftButtonDown = event.which ? (event.which === 1) : (event.button === 1); + if (!leftButtonDown) return; - // apply data - if (data) { - this.setData(data); - } - } + this.startClientX = event.clientX; + this.startSlideX = parseFloat(this.frame.slide.style.left); - // Extend Graph3d with an Emitter mixin - Emitter(Graph3d.prototype); + this.frame.style.cursor = 'move'; - /** - * Calculate the scaling values, dependent on the range in x, y, and z direction - */ - Graph3d.prototype._setScale = function() { - this.scale = new Point3d(1 / (this.xMax - this.xMin), - 1 / (this.yMax - this.yMin), - 1 / (this.zMax - this.zMin)); + // add event listeners to handle moving the contents + // we store the function onmousemove and onmouseup in the graph, so we can + // remove the eventlisteners lateron in the function mouseUp() + var me = this; + this.onmousemove = function (event) {me._onMouseMove(event);}; + this.onmouseup = function (event) {me._onMouseUp(event);}; + util.addEventListener(document, 'mousemove', this.onmousemove); + util.addEventListener(document, 'mouseup', this.onmouseup); + util.preventDefault(event); + }; - // keep aspect ration between x and y scale if desired - if (this.keepAspectRatio) { - if (this.scale.x < this.scale.y) { - //noinspection JSSuspiciousNameCombination - this.scale.y = this.scale.x; - } - else { - //noinspection JSSuspiciousNameCombination - this.scale.x = this.scale.y; - } - } - // scale the vertical axis - this.scale.z *= this.verticalRatio; - // TODO: can this be automated? verticalRatio? + Slider.prototype.leftToIndex = function (left) { + var width = parseFloat(this.frame.bar.style.width) - + this.frame.slide.clientWidth - 10; + var x = left - 3; - // determine scale for (optional) value - this.scale.value = 1 / (this.valueMax - this.valueMin); + var index = Math.round(x / width * (this.values.length-1)); + if (index < 0) index = 0; + if (index > this.values.length-1) index = this.values.length-1; - // position the camera arm - var xCenter = (this.xMax + this.xMin) / 2 * this.scale.x; - var yCenter = (this.yMax + this.yMin) / 2 * this.scale.y; - var zCenter = (this.zMax + this.zMin) / 2 * this.scale.z; - this.camera.setArmLocation(xCenter, yCenter, zCenter); + return index; }; + Slider.prototype.indexToLeft = function (index) { + var width = parseFloat(this.frame.bar.style.width) - + this.frame.slide.clientWidth - 10; - /** - * Convert a 3D location to a 2D location on screen - * http://en.wikipedia.org/wiki/3D_projection - * @param {Point3d} point3d A 3D point with parameters x, y, z - * @return {Point2d} point2d A 2D point with parameters x, y - */ - Graph3d.prototype._convert3Dto2D = function(point3d) { - var translation = this._convertPointToTranslation(point3d); - return this._convertTranslationToScreen(translation); + var x = index / (this.values.length-1) * width; + var left = x + 3; + + return left; }; - /** - * Convert a 3D location its translation seen from the camera - * http://en.wikipedia.org/wiki/3D_projection - * @param {Point3d} point3d A 3D point with parameters x, y, z - * @return {Point3d} translation A 3D point with parameters x, y, z This is - * the translation of the point, seen from the - * camera - */ - Graph3d.prototype._convertPointToTranslation = function(point3d) { - var ax = point3d.x * this.scale.x, - ay = point3d.y * this.scale.y, - az = point3d.z * this.scale.z, - cx = this.camera.getCameraLocation().x, - cy = this.camera.getCameraLocation().y, - cz = this.camera.getCameraLocation().z, - // calculate angles - sinTx = Math.sin(this.camera.getCameraRotation().x), - cosTx = Math.cos(this.camera.getCameraRotation().x), - sinTy = Math.sin(this.camera.getCameraRotation().y), - cosTy = Math.cos(this.camera.getCameraRotation().y), - sinTz = Math.sin(this.camera.getCameraRotation().z), - cosTz = Math.cos(this.camera.getCameraRotation().z), + Slider.prototype._onMouseMove = function (event) { + var diff = event.clientX - this.startClientX; + var x = this.startSlideX + diff; - // calculate translation - dx = cosTy * (sinTz * (ay - cy) + cosTz * (ax - cx)) - sinTy * (az - cz), - dy = sinTx * (cosTy * (az - cz) + sinTy * (sinTz * (ay - cy) + cosTz * (ax - cx))) + cosTx * (cosTz * (ay - cy) - sinTz * (ax-cx)), - dz = cosTx * (cosTy * (az - cz) + sinTy * (sinTz * (ay - cy) + cosTz * (ax - cx))) - sinTx * (cosTz * (ay - cy) - sinTz * (ax-cx)); + var index = this.leftToIndex(x); - return new Point3d(dx, dy, dz); + this.setIndex(index); + + util.preventDefault(); }; - /** - * Convert a translation point to a point on the screen - * @param {Point3d} translation A 3D point with parameters x, y, z This is - * the translation of the point, seen from the - * camera - * @return {Point2d} point2d A 2D point with parameters x, y - */ - Graph3d.prototype._convertTranslationToScreen = function(translation) { - var ex = this.eye.x, - ey = this.eye.y, - ez = this.eye.z, - dx = translation.x, - dy = translation.y, - dz = translation.z; - // calculate position on screen from translation - var bx; - var by; - if (this.showPerspective) { - bx = (dx - ex) * (ez / dz); - by = (dy - ey) * (ez / dz); - } - else { - bx = dx * -(ez / this.camera.getArmLength()); - by = dy * -(ez / this.camera.getArmLength()); - } + Slider.prototype._onMouseUp = function (event) { + this.frame.style.cursor = 'auto'; - // shift and scale the point to the center of the screen - // use the width of the graph to scale both horizontally and vertically. - return new Point2d( - this.xcenter + bx * this.frame.canvas.clientWidth, - this.ycenter - by * this.frame.canvas.clientWidth); + // remove event listeners + util.removeEventListener(document, 'mousemove', this.onmousemove); + util.removeEventListener(document, 'mouseup', this.onmouseup); + + util.preventDefault(); }; - /** - * Set the background styling for the graph - * @param {string | {fill: string, stroke: string, strokeWidth: string}} backgroundColor - */ - Graph3d.prototype._setBackgroundColor = function(backgroundColor) { - var fill = 'white'; - var stroke = 'gray'; - var strokeWidth = 1; + module.exports = Slider; - if (typeof(backgroundColor) === 'string') { - fill = backgroundColor; - stroke = 'none'; - strokeWidth = 0; - } - else if (typeof(backgroundColor) === 'object') { - if (backgroundColor.fill !== undefined) fill = backgroundColor.fill; - if (backgroundColor.stroke !== undefined) stroke = backgroundColor.stroke; - if (backgroundColor.strokeWidth !== undefined) strokeWidth = backgroundColor.strokeWidth; - } - else if (backgroundColor === undefined) { - // use use defaults - } - else { - throw 'Unsupported type of backgroundColor'; - } - this.frame.style.backgroundColor = fill; - this.frame.style.borderColor = stroke; - this.frame.style.borderWidth = strokeWidth + 'px'; - this.frame.style.borderStyle = 'solid'; - }; +/***/ }, +/* 12 */ +/***/ function(module, exports, __webpack_require__) { + /** + * @prototype StepNumber + * The class StepNumber is an iterator for Numbers. You provide a start and end + * value, and a best step size. StepNumber itself rounds to fixed values and + * a finds the step that best fits the provided step. + * + * If prettyStep is true, the step size is chosen as close as possible to the + * provided step, but being a round value like 1, 2, 5, 10, 20, 50, .... + * + * Example usage: + * var step = new StepNumber(0, 10, 2.5, true); + * step.start(); + * while (!step.end()) { + * alert(step.getCurrent()); + * step.next(); + * } + * + * Version: 1.0 + * + * @param {Number} start The start value + * @param {Number} end The end value + * @param {Number} step Optional. Step size. Must be a positive value. + * @param {boolean} prettyStep Optional. If true, the step size is rounded + * To a pretty step size (like 1, 2, 5, 10, 20, 50, ...) + */ + function StepNumber(start, end, step, prettyStep) { + // set default values + this._start = 0; + this._end = 0; + this._step = 1; + this.prettyStep = true; + this.precision = 5; - /// enumerate the available styles - Graph3d.STYLE = { - BAR: 0, - BARCOLOR: 1, - BARSIZE: 2, - DOT : 3, - DOTLINE : 4, - DOTCOLOR: 5, - DOTSIZE: 6, - GRID : 7, - LINE: 8, - SURFACE : 9 + this._current = 0; + this.setRange(start, end, step, prettyStep); }; /** - * Retrieve the style index from given styleName - * @param {string} styleName Style name such as 'dot', 'grid', 'dot-line' - * @return {Number} styleNumber Enumeration value representing the style, or -1 - * when not found + * Set a new range: start, end and step. + * + * @param {Number} start The start value + * @param {Number} end The end value + * @param {Number} step Optional. Step size. Must be a positive value. + * @param {boolean} prettyStep Optional. If true, the step size is rounded + * To a pretty step size (like 1, 2, 5, 10, 20, 50, ...) */ - Graph3d.prototype._getStyleNumber = function(styleName) { - switch (styleName) { - case 'dot': return Graph3d.STYLE.DOT; - case 'dot-line': return Graph3d.STYLE.DOTLINE; - case 'dot-color': return Graph3d.STYLE.DOTCOLOR; - case 'dot-size': return Graph3d.STYLE.DOTSIZE; - case 'line': return Graph3d.STYLE.LINE; - case 'grid': return Graph3d.STYLE.GRID; - case 'surface': return Graph3d.STYLE.SURFACE; - case 'bar': return Graph3d.STYLE.BAR; - case 'bar-color': return Graph3d.STYLE.BARCOLOR; - case 'bar-size': return Graph3d.STYLE.BARSIZE; - } + StepNumber.prototype.setRange = function(start, end, step, prettyStep) { + this._start = start ? start : 0; + this._end = end ? end : 0; - return -1; + this.setStep(step, prettyStep); }; /** - * Determine the indexes of the data columns, based on the given style and data - * @param {DataSet} data - * @param {Number} style + * Set a new step size + * @param {Number} step New step size. Must be a positive value + * @param {boolean} prettyStep Optional. If true, the provided step is rounded + * to a pretty step size (like 1, 2, 5, 10, 20, 50, ...) */ - Graph3d.prototype._determineColumnIndexes = function(data, style) { - if (this.style === Graph3d.STYLE.DOT || - this.style === Graph3d.STYLE.DOTLINE || - this.style === Graph3d.STYLE.LINE || - this.style === Graph3d.STYLE.GRID || - this.style === Graph3d.STYLE.SURFACE || - this.style === Graph3d.STYLE.BAR) { - // 3 columns expected, and optionally a 4th with filter values - this.colX = 0; - this.colY = 1; - this.colZ = 2; - this.colValue = undefined; + StepNumber.prototype.setStep = function(step, prettyStep) { + if (step === undefined || step <= 0) + return; - if (data.getNumberOfColumns() > 3) { - this.colFilter = 3; - } - } - else if (this.style === Graph3d.STYLE.DOTCOLOR || - this.style === Graph3d.STYLE.DOTSIZE || - this.style === Graph3d.STYLE.BARCOLOR || - this.style === Graph3d.STYLE.BARSIZE) { - // 4 columns expected, and optionally a 5th with filter values - this.colX = 0; - this.colY = 1; - this.colZ = 2; - this.colValue = 3; + if (prettyStep !== undefined) + this.prettyStep = prettyStep; - if (data.getNumberOfColumns() > 4) { - this.colFilter = 4; - } - } - else { - throw 'Unknown style "' + this.style + '"'; - } + if (this.prettyStep === true) + this._step = StepNumber.calculatePrettyStep(step); + else + this._step = step; }; - Graph3d.prototype.getNumberOfRows = function(data) { - return data.length; - } + /** + * Calculate a nice step size, closest to the desired step size. + * Returns a value in one of the ranges 1*10^n, 2*10^n, or 5*10^n, where n is an + * integer Number. For example 1, 2, 5, 10, 20, 50, etc... + * @param {Number} step Desired step size + * @return {Number} Nice step size + */ + StepNumber.calculatePrettyStep = function (step) { + var log10 = function (x) {return Math.log(x) / Math.LN10;}; + + // try three steps (multiple of 1, 2, or 5 + var step1 = Math.pow(10, Math.round(log10(step))), + step2 = 2 * Math.pow(10, Math.round(log10(step / 2))), + step5 = 5 * Math.pow(10, Math.round(log10(step / 5))); + // choose the best step (closest to minimum step) + var prettyStep = step1; + if (Math.abs(step2 - step) <= Math.abs(prettyStep - step)) prettyStep = step2; + if (Math.abs(step5 - step) <= Math.abs(prettyStep - step)) prettyStep = step5; - Graph3d.prototype.getNumberOfColumns = function(data) { - var counter = 0; - for (var column in data[0]) { - if (data[0].hasOwnProperty(column)) { - counter++; - } + // for safety + if (prettyStep <= 0) { + prettyStep = 1; } - return counter; - } + return prettyStep; + }; - Graph3d.prototype.getDistinctValues = function(data, column) { - var distinctValues = []; - for (var i = 0; i < data.length; i++) { - if (distinctValues.indexOf(data[i][column]) == -1) { - distinctValues.push(data[i][column]); - } - } - return distinctValues; - } + /** + * returns the current value of the step + * @return {Number} current value + */ + StepNumber.prototype.getCurrent = function () { + return parseFloat(this._current.toPrecision(this.precision)); + }; + /** + * returns the current step size + * @return {Number} current step size + */ + StepNumber.prototype.getStep = function () { + return this._step; + }; - Graph3d.prototype.getColumnRange = function(data,column) { - var minMax = {min:data[0][column],max:data[0][column]}; - for (var i = 0; i < data.length; i++) { - if (minMax.min > data[i][column]) { minMax.min = data[i][column]; } - if (minMax.max < data[i][column]) { minMax.max = data[i][column]; } - } - return minMax; + /** + * Set the current value to the largest value smaller than start, which + * is a multiple of the step size + */ + StepNumber.prototype.start = function() { + this._current = this._start - this._start % this._step; }; /** - * Initialize the data from the data table. Calculate minimum and maximum values - * and column index values - * @param {Array | DataSet | DataView} rawData The data containing the items for the Graph. - * @param {Number} style Style Number + * Do a step, add the step size to the current value */ - Graph3d.prototype._dataInitialize = function (rawData, style) { - var me = this; + StepNumber.prototype.next = function () { + this._current += this._step; + }; - // unsubscribe from the dataTable - if (this.dataSet) { - this.dataSet.off('*', this._onChange); - } + /** + * Returns true whether the end is reached + * @return {boolean} True if the current value has passed the end value. + */ + StepNumber.prototype.end = function () { + return (this._current > this._end); + }; - if (rawData === undefined) - return; + module.exports = StepNumber; - if (Array.isArray(rawData)) { - rawData = new DataSet(rawData); - } - var data; - if (rawData instanceof DataSet || rawData instanceof DataView) { - data = rawData.get(); +/***/ }, +/* 13 */ +/***/ function(module, exports, __webpack_require__) { + + var Emitter = __webpack_require__(56); + var Hammer = __webpack_require__(45); + var util = __webpack_require__(1); + var DataSet = __webpack_require__(3); + var DataView = __webpack_require__(4); + var Range = __webpack_require__(17); + var Core = __webpack_require__(46); + var TimeAxis = __webpack_require__(30); + var CurrentTime = __webpack_require__(21); + var CustomTime = __webpack_require__(22); + var ItemSet = __webpack_require__(27); + + /** + * Create a timeline visualization + * @param {HTMLElement} container + * @param {vis.DataSet | Array | google.visualization.DataTable} [items] + * @param {vis.DataSet | Array | google.visualization.DataTable} [groups] + * @param {Object} [options] See Timeline.setOptions for the available options. + * @constructor + * @extends Core + */ + function Timeline (container, items, groups, options) { + if (!(this instanceof Timeline)) { + throw new SyntaxError('Constructor must be called with the new operator'); } - else { - throw new Error('Array, DataSet, or DataView expected'); + + // if the third element is options, the forth is groups (optionally); + if (!(Array.isArray(groups) || groups instanceof DataSet) && groups instanceof Object) { + var forthArgument = options; + options = groups; + groups = forthArgument; } - if (data.length == 0) - return; + var me = this; + this.defaultOptions = { + start: null, + end: null, - this.dataSet = rawData; - this.dataTable = data; + autoResize: true, - // subscribe to changes in the dataset - this._onChange = function () { - me.setData(me.dataSet); + orientation: 'bottom', + width: null, + height: null, + maxHeight: null, + minHeight: null }; - this.dataSet.on('*', this._onChange); + this.options = util.deepExtend({}, this.defaultOptions); - // _determineColumnIndexes - // getNumberOfRows (points) - // getNumberOfColumns (x,y,z,v,t,t1,t2...) - // getDistinctValues (unique values?) - // getColumnRange + // Create the DOM, props, and emitter + this._create(container); - // determine the location of x,y,z,value,filter columns - this.colX = 'x'; - this.colY = 'y'; - this.colZ = 'z'; - this.colValue = 'style'; - this.colFilter = 'filter'; + // all components listed here will be repainted automatically + this.components = []; + this.body = { + dom: this.dom, + domProps: this.props, + emitter: { + on: this.on.bind(this), + off: this.off.bind(this), + emit: this.emit.bind(this) + }, + hiddenDates: [], + util: { + snap: null, // will be specified after TimeAxis is created + toScreen: me._toScreen.bind(me), + toGlobalScreen: me._toGlobalScreen.bind(me), // this refers to the root.width + toTime: me._toTime.bind(me), + toGlobalTime : me._toGlobalTime.bind(me) + } + }; + // range + this.range = new Range(this.body); + this.components.push(this.range); + this.body.range = this.range; - // check if a filter column is provided - if (data[0].hasOwnProperty('filter')) { - if (this.dataFilter === undefined) { - this.dataFilter = new Filter(rawData, this.colFilter, this); - this.dataFilter.setOnLoadCallback(function() {me.redraw();}); - } - } + // time axis + this.timeAxis = new TimeAxis(this.body); + this.components.push(this.timeAxis); + this.body.util.snap = this.timeAxis.snap.bind(this.timeAxis); + // current time bar + this.currentTime = new CurrentTime(this.body); + this.components.push(this.currentTime); - var withBars = this.style == Graph3d.STYLE.BAR || - this.style == Graph3d.STYLE.BARCOLOR || - this.style == Graph3d.STYLE.BARSIZE; + // custom time bar + // Note: time bar will be attached in this.setOptions when selected + this.customTime = new CustomTime(this.body); + this.components.push(this.customTime); - // determine barWidth from data - if (withBars) { - if (this.defaultXBarWidth !== undefined) { - this.xBarWidth = this.defaultXBarWidth; - } - else { - var dataX = this.getDistinctValues(data,this.colX); - this.xBarWidth = (dataX[1] - dataX[0]) || 1; - } + // item set + this.itemSet = new ItemSet(this.body); + this.components.push(this.itemSet); - if (this.defaultYBarWidth !== undefined) { - this.yBarWidth = this.defaultYBarWidth; - } - else { - var dataY = this.getDistinctValues(data,this.colY); - this.yBarWidth = (dataY[1] - dataY[0]) || 1; - } - } + this.itemsData = null; // DataSet + this.groupsData = null; // DataSet - // calculate minimums and maximums - var xRange = this.getColumnRange(data,this.colX); - if (withBars) { - xRange.min -= this.xBarWidth / 2; - xRange.max += this.xBarWidth / 2; + // apply options + if (options) { + this.setOptions(options); } - this.xMin = (this.defaultXMin !== undefined) ? this.defaultXMin : xRange.min; - this.xMax = (this.defaultXMax !== undefined) ? this.defaultXMax : xRange.max; - if (this.xMax <= this.xMin) this.xMax = this.xMin + 1; - this.xStep = (this.defaultXStep !== undefined) ? this.defaultXStep : (this.xMax-this.xMin)/5; - var yRange = this.getColumnRange(data,this.colY); - if (withBars) { - yRange.min -= this.yBarWidth / 2; - yRange.max += this.yBarWidth / 2; + // IMPORTANT: THIS HAPPENS BEFORE SET ITEMS! + if (groups) { + this.setGroups(groups); } - this.yMin = (this.defaultYMin !== undefined) ? this.defaultYMin : yRange.min; - this.yMax = (this.defaultYMax !== undefined) ? this.defaultYMax : yRange.max; - if (this.yMax <= this.yMin) this.yMax = this.yMin + 1; - this.yStep = (this.defaultYStep !== undefined) ? this.defaultYStep : (this.yMax-this.yMin)/5; - - var zRange = this.getColumnRange(data,this.colZ); - this.zMin = (this.defaultZMin !== undefined) ? this.defaultZMin : zRange.min; - this.zMax = (this.defaultZMax !== undefined) ? this.defaultZMax : zRange.max; - if (this.zMax <= this.zMin) this.zMax = this.zMin + 1; - this.zStep = (this.defaultZStep !== undefined) ? this.defaultZStep : (this.zMax-this.zMin)/5; - if (this.colValue !== undefined) { - var valueRange = this.getColumnRange(data,this.colValue); - this.valueMin = (this.defaultValueMin !== undefined) ? this.defaultValueMin : valueRange.min; - this.valueMax = (this.defaultValueMax !== undefined) ? this.defaultValueMax : valueRange.max; - if (this.valueMax <= this.valueMin) this.valueMax = this.valueMin + 1; + // create itemset + if (items) { + this.setItems(items); } + else { + this.redraw(); + } + } - // set the scale dependent on the ranges. - this._setScale(); - }; - - + // Extend the functionality from Core + Timeline.prototype = new Core(); /** - * Filter the data based on the current filter - * @param {Array} data - * @return {Array} dataPoints Array with point objects which can be drawn on screen + * Set items + * @param {vis.DataSet | Array | google.visualization.DataTable | null} items */ - Graph3d.prototype._getDataPoints = function (data) { - // TODO: store the created matrix dataPoints in the filters instead of reloading each time - var x, y, i, z, obj, point; - - var dataPoints = []; + Timeline.prototype.setItems = function(items) { + var initialLoad = (this.itemsData == null); - if (this.style === Graph3d.STYLE.GRID || - this.style === Graph3d.STYLE.SURFACE) { - // copy all values from the google data table to a matrix - // the provided values are supposed to form a grid of (x,y) positions + // convert to type DataSet when needed + var newDataSet; + if (!items) { + newDataSet = null; + } + else if (items instanceof DataSet || items instanceof DataView) { + newDataSet = items; + } + else { + // turn an array into a dataset + newDataSet = new DataSet(items, { + type: { + start: 'Date', + end: 'Date' + } + }); + } - // create two lists with all present x and y values - var dataX = []; - var dataY = []; - for (i = 0; i < this.getNumberOfRows(data); i++) { - x = data[i][this.colX] || 0; - y = data[i][this.colY] || 0; + // set items + this.itemsData = newDataSet; + this.itemSet && this.itemSet.setItems(newDataSet); - if (dataX.indexOf(x) === -1) { - dataX.push(x); - } - if (dataY.indexOf(y) === -1) { - dataY.push(y); + if (initialLoad) { + if (this.options.start != undefined || this.options.end != undefined) { + if (this.options.start == undefined || this.options.end == undefined) { + var dataRange = this._getDataRange(); } + + var start = this.options.start != undefined ? this.options.start : dataRange.start; + var end = this.options.end != undefined ? this.options.end : dataRange.end; + + this.setWindow(start, end, {animate: false}); + } + else { + this.fit({animate: false}); } + } + }; - var sortNumber = function (a, b) { - return a - b; - }; - dataX.sort(sortNumber); - dataY.sort(sortNumber); + /** + * Set groups + * @param {vis.DataSet | Array | google.visualization.DataTable} groups + */ + Timeline.prototype.setGroups = function(groups) { + // convert to type DataSet when needed + var newDataSet; + if (!groups) { + newDataSet = null; + } + else if (groups instanceof DataSet || groups instanceof DataView) { + newDataSet = groups; + } + else { + // turn an array into a dataset + newDataSet = new DataSet(groups); + } - // create a grid, a 2d matrix, with all values. - var dataMatrix = []; // temporary data matrix - for (i = 0; i < data.length; i++) { - x = data[i][this.colX] || 0; - y = data[i][this.colY] || 0; - z = data[i][this.colZ] || 0; + this.groupsData = newDataSet; + this.itemSet.setGroups(newDataSet); + }; - var xIndex = dataX.indexOf(x); // TODO: implement Array().indexOf() for Internet Explorer - var yIndex = dataY.indexOf(y); + /** + * Set selected items by their id. Replaces the current selection + * Unknown id's are silently ignored. + * @param {string[] | string} [ids] An array with zero or more id's of the items to be + * selected. If ids is an empty array, all items will be + * unselected. + * @param {Object} [options] Available options: + * `focus: boolean` + * If true, focus will be set to the selected item(s) + * `animate: boolean | number` + * If true (default), the range is animated + * smoothly to the new window. + * If a number, the number is taken as duration + * for the animation. Default duration is 500 ms. + * Only applicable when option focus is true. + */ + Timeline.prototype.setSelection = function(ids, options) { + this.itemSet && this.itemSet.setSelection(ids); - if (dataMatrix[xIndex] === undefined) { - dataMatrix[xIndex] = []; - } + if (options && options.focus) { + this.focus(ids, options); + } + }; - var point3d = new Point3d(); - point3d.x = x; - point3d.y = y; - point3d.z = z; + /** + * Get the selected items by their id + * @return {Array} ids The ids of the selected items + */ + Timeline.prototype.getSelection = function() { + return this.itemSet && this.itemSet.getSelection() || []; + }; - obj = {}; - obj.point = point3d; - obj.trans = undefined; - obj.screen = undefined; - obj.bottom = new Point3d(x, y, this.zMin); + /** + * Adjust the visible window such that the selected item (or multiple items) + * are centered on screen. + * @param {String | String[]} id An item id or array with item ids + * @param {Object} [options] Available options: + * `animate: boolean | number` + * If true (default), the range is animated + * smoothly to the new window. + * If a number, the number is taken as duration + * for the animation. Default duration is 500 ms. + * Only applicable when option focus is true + */ + Timeline.prototype.focus = function(id, options) { + if (!this.itemsData || id == undefined) return; - dataMatrix[xIndex][yIndex] = obj; + var ids = Array.isArray(id) ? id : [id]; - dataPoints.push(obj); + // get the specified item(s) + var itemsData = this.itemsData.getDataSet().get(ids, { + type: { + start: 'Date', + end: 'Date' } + }); - // fill in the pointers to the neighbors. - for (x = 0; x < dataMatrix.length; x++) { - for (y = 0; y < dataMatrix[x].length; y++) { - if (dataMatrix[x][y]) { - dataMatrix[x][y].pointRight = (x < dataMatrix.length-1) ? dataMatrix[x+1][y] : undefined; - dataMatrix[x][y].pointTop = (y < dataMatrix[x].length-1) ? dataMatrix[x][y+1] : undefined; - dataMatrix[x][y].pointCross = - (x < dataMatrix.length-1 && y < dataMatrix[x].length-1) ? - dataMatrix[x+1][y+1] : - undefined; - } - } + // calculate minimum start and maximum end of specified items + var start = null; + var end = null; + itemsData.forEach(function (itemData) { + var s = itemData.start.valueOf(); + var e = 'end' in itemData ? itemData.end.valueOf() : itemData.start.valueOf(); + + if (start === null || s < start) { + start = s; } - } - else { // 'dot', 'dot-line', etc. - // copy all values from the google data table to a list with Point3d objects - for (i = 0; i < data.length; i++) { - point = new Point3d(); - point.x = data[i][this.colX] || 0; - point.y = data[i][this.colY] || 0; - point.z = data[i][this.colZ] || 0; - if (this.colValue !== undefined) { - point.value = data[i][this.colValue] || 0; - } + if (end === null || e > end) { + end = e; + } + }); - obj = {}; - obj.point = point; - obj.bottom = new Point3d(point.x, point.y, this.zMin); - obj.trans = undefined; - obj.screen = undefined; + if (start !== null && end !== null) { + // calculate the new middle and interval for the window + var middle = (start + end) / 2; + var interval = Math.max((this.range.end - this.range.start), (end - start) * 1.1); - dataPoints.push(obj); - } + var animate = (options && options.animate !== undefined) ? options.animate : true; + this.range.setRange(middle - interval / 2, middle + interval / 2, animate); } - - return dataPoints; }; /** - * Create the main frame for the Graph3d. - * This function is executed once when a Graph3d object is created. The frame - * contains a canvas, and this canvas contains all objects like the axis and - * nodes. + * Get the data range of the item set. + * @returns {{min: Date, max: Date}} range A range with a start and end Date. + * When no minimum is found, min==null + * When no maximum is found, max==null */ - Graph3d.prototype.create = function () { - // remove all elements from the container element. - while (this.containerElement.hasChildNodes()) { - this.containerElement.removeChild(this.containerElement.firstChild); + Timeline.prototype.getItemRange = function() { + // calculate min from start filed + var dataset = this.itemsData.getDataSet(), + min = null, + max = null; + + if (dataset) { + // calculate the minimum value of the field 'start' + var minItem = dataset.min('start'); + min = minItem ? util.convert(minItem.start, 'Date').valueOf() : null; + // Note: we convert first to Date and then to number because else + // a conversion from ISODate to Number will fail + + // calculate maximum value of fields 'start' and 'end' + var maxStartItem = dataset.max('start'); + if (maxStartItem) { + max = util.convert(maxStartItem.start, 'Date').valueOf(); + } + var maxEndItem = dataset.max('end'); + if (maxEndItem) { + if (max == null) { + max = util.convert(maxEndItem.end, 'Date').valueOf(); + } + else { + max = Math.max(max, util.convert(maxEndItem.end, 'Date').valueOf()); + } + } } - this.frame = document.createElement('div'); - this.frame.style.position = 'relative'; - this.frame.style.overflow = 'hidden'; - - // create the graph canvas (HTML canvas element) - this.frame.canvas = document.createElement( 'canvas' ); - this.frame.canvas.style.position = 'relative'; - this.frame.appendChild(this.frame.canvas); - //if (!this.frame.canvas.getContext) { - { - var noCanvas = document.createElement( 'DIV' ); - noCanvas.style.color = 'red'; - noCanvas.style.fontWeight = 'bold' ; - noCanvas.style.padding = '10px'; - noCanvas.innerHTML = 'Error: your browser does not support HTML canvas'; - this.frame.canvas.appendChild(noCanvas); - } + return { + min: (min != null) ? new Date(min) : null, + max: (max != null) ? new Date(max) : null + }; + }; - this.frame.filter = document.createElement( 'div' ); - this.frame.filter.style.position = 'absolute'; - this.frame.filter.style.bottom = '0px'; - this.frame.filter.style.left = '0px'; - this.frame.filter.style.width = '100%'; - this.frame.appendChild(this.frame.filter); - // add event listeners to handle moving and zooming the contents - var me = this; - var onmousedown = function (event) {me._onMouseDown(event);}; - var ontouchstart = function (event) {me._onTouchStart(event);}; - var onmousewheel = function (event) {me._onWheel(event);}; - var ontooltip = function (event) {me._onTooltip(event);}; - // TODO: these events are never cleaned up... can give a 'memory leakage' + module.exports = Timeline; - util.addEventListener(this.frame.canvas, 'keydown', onkeydown); - util.addEventListener(this.frame.canvas, 'mousedown', onmousedown); - util.addEventListener(this.frame.canvas, 'touchstart', ontouchstart); - util.addEventListener(this.frame.canvas, 'mousewheel', onmousewheel); - util.addEventListener(this.frame.canvas, 'mousemove', ontooltip); - // add the new graph to the container element - this.containerElement.appendChild(this.frame); - }; +/***/ }, +/* 14 */ +/***/ function(module, exports, __webpack_require__) { + var Emitter = __webpack_require__(56); + var Hammer = __webpack_require__(45); + var util = __webpack_require__(1); + var DataSet = __webpack_require__(3); + var DataView = __webpack_require__(4); + var Range = __webpack_require__(17); + var Core = __webpack_require__(46); + var TimeAxis = __webpack_require__(30); + var CurrentTime = __webpack_require__(21); + var CustomTime = __webpack_require__(22); + var LineGraph = __webpack_require__(29); /** - * Set a new size for the graph - * @param {string} width Width in pixels or percentage (for example '800px' - * or '50%') - * @param {string} height Height in pixels or percentage (for example '400px' - * or '30%') + * Create a timeline visualization + * @param {HTMLElement} container + * @param {vis.DataSet | Array | google.visualization.DataTable} [items] + * @param {Object} [options] See Graph2d.setOptions for the available options. + * @constructor + * @extends Core */ - Graph3d.prototype.setSize = function(width, height) { - this.frame.style.width = width; - this.frame.style.height = height; + function Graph2d (container, items, groups, options) { + // if the third element is options, the forth is groups (optionally); + if (!(Array.isArray(groups) || groups instanceof DataSet) && groups instanceof Object) { + var forthArgument = options; + options = groups; + groups = forthArgument; + } - this._resizeCanvas(); - }; + var me = this; + this.defaultOptions = { + start: null, + end: null, - /** - * Resize the canvas to the current size of the frame - */ - Graph3d.prototype._resizeCanvas = function() { - this.frame.canvas.style.width = '100%'; - this.frame.canvas.style.height = '100%'; + autoResize: true, - this.frame.canvas.width = this.frame.canvas.clientWidth; - this.frame.canvas.height = this.frame.canvas.clientHeight; + orientation: 'bottom', + width: null, + height: null, + maxHeight: null, + minHeight: null + }; + this.options = util.deepExtend({}, this.defaultOptions); - // adjust with for margin - this.frame.filter.style.width = (this.frame.canvas.clientWidth - 2 * 10) + 'px'; - }; + // Create the DOM, props, and emitter + this._create(container); - /** - * Start animation - */ - Graph3d.prototype.animationStart = function() { - if (!this.frame.filter || !this.frame.filter.slider) - throw 'No animation available'; + // all components listed here will be repainted automatically + this.components = []; - this.frame.filter.slider.play(); - }; + this.body = { + dom: this.dom, + domProps: this.props, + emitter: { + on: this.on.bind(this), + off: this.off.bind(this), + emit: this.emit.bind(this) + }, + hiddenDates: [], + util: { + snap: null, // will be specified after TimeAxis is created + toScreen: me._toScreen.bind(me), + toGlobalScreen: me._toGlobalScreen.bind(me), // this refers to the root.width + toTime: me._toTime.bind(me), + toGlobalTime : me._toGlobalTime.bind(me) + } + }; + // range + this.range = new Range(this.body); + this.components.push(this.range); + this.body.range = this.range; - /** - * Stop animation - */ - Graph3d.prototype.animationStop = function() { - if (!this.frame.filter || !this.frame.filter.slider) return; + // time axis + this.timeAxis = new TimeAxis(this.body); + this.components.push(this.timeAxis); + this.body.util.snap = this.timeAxis.snap.bind(this.timeAxis); - this.frame.filter.slider.stop(); - }; + // current time bar + this.currentTime = new CurrentTime(this.body); + this.components.push(this.currentTime); + // custom time bar + // Note: time bar will be attached in this.setOptions when selected + this.customTime = new CustomTime(this.body); + this.components.push(this.customTime); - /** - * Resize the center position based on the current values in this.defaultXCenter - * and this.defaultYCenter (which are strings with a percentage or a value - * in pixels). The center positions are the variables this.xCenter - * and this.yCenter - */ - Graph3d.prototype._resizeCenter = function() { - // calculate the horizontal center position - if (this.defaultXCenter.charAt(this.defaultXCenter.length-1) === '%') { - this.xcenter = - parseFloat(this.defaultXCenter) / 100 * - this.frame.canvas.clientWidth; + // item set + this.linegraph = new LineGraph(this.body); + this.components.push(this.linegraph); + + this.itemsData = null; // DataSet + this.groupsData = null; // DataSet + + // apply options + if (options) { + this.setOptions(options); } - else { - this.xcenter = parseFloat(this.defaultXCenter); // supposed to be in px + + // IMPORTANT: THIS HAPPENS BEFORE SET ITEMS! + if (groups) { + this.setGroups(groups); } - // calculate the vertical center position - if (this.defaultYCenter.charAt(this.defaultYCenter.length-1) === '%') { - this.ycenter = - parseFloat(this.defaultYCenter) / 100 * - (this.frame.canvas.clientHeight - this.frame.filter.clientHeight); + // create itemset + if (items) { + this.setItems(items); } else { - this.ycenter = parseFloat(this.defaultYCenter); // supposed to be in px + this.redraw(); } - }; + } + + // Extend the functionality from Core + Graph2d.prototype = new Core(); /** - * Set the rotation and distance of the camera - * @param {Object} pos An object with the camera position. The object - * contains three parameters: - * - horizontal {Number} - * The horizontal rotation, between 0 and 2*PI. - * Optional, can be left undefined. - * - vertical {Number} - * The vertical rotation, between 0 and 0.5*PI - * if vertical=0.5*PI, the graph is shown from the - * top. Optional, can be left undefined. - * - distance {Number} - * The (normalized) distance of the camera to the - * center of the graph, a value between 0.71 and 5.0. - * Optional, can be left undefined. + * Set items + * @param {vis.DataSet | Array | google.visualization.DataTable | null} items */ - Graph3d.prototype.setCameraPosition = function(pos) { - if (pos === undefined) { - return; - } + Graph2d.prototype.setItems = function(items) { + var initialLoad = (this.itemsData == null); - if (pos.horizontal !== undefined && pos.vertical !== undefined) { - this.camera.setArmRotation(pos.horizontal, pos.vertical); + // convert to type DataSet when needed + var newDataSet; + if (!items) { + newDataSet = null; } - - if (pos.distance !== undefined) { - this.camera.setArmLength(pos.distance); + else if (items instanceof DataSet || items instanceof DataView) { + newDataSet = items; + } + else { + // turn an array into a dataset + newDataSet = new DataSet(items, { + type: { + start: 'Date', + end: 'Date' + } + }); } - this.redraw(); - }; + // set items + this.itemsData = newDataSet; + this.linegraph && this.linegraph.setItems(newDataSet); + if (initialLoad) { + if (this.options.start != undefined || this.options.end != undefined) { + var start = this.options.start != undefined ? this.options.start : null; + var end = this.options.end != undefined ? this.options.end : null; - /** - * Retrieve the current camera rotation - * @return {object} An object with parameters horizontal, vertical, and - * distance - */ - Graph3d.prototype.getCameraPosition = function() { - var pos = this.camera.getArmRotation(); - pos.distance = this.camera.getArmLength(); - return pos; + this.setWindow(start, end, {animate: false}); + } + else { + this.fit({animate: false}); + } + } }; /** - * Load data into the 3D Graph + * Set groups + * @param {vis.DataSet | Array | google.visualization.DataTable} groups */ - Graph3d.prototype._readData = function(data) { - // read the data - this._dataInitialize(data, this.style); - - - if (this.dataFilter) { - // apply filtering - this.dataPoints = this.dataFilter._getDataPoints(); + Graph2d.prototype.setGroups = function(groups) { + // convert to type DataSet when needed + var newDataSet; + if (!groups) { + newDataSet = null; + } + else if (groups instanceof DataSet || groups instanceof DataView) { + newDataSet = groups; } else { - // no filtering. load all data - this.dataPoints = this._getDataPoints(this.dataTable); + // turn an array into a dataset + newDataSet = new DataSet(groups); } - // draw the filter - this._redrawFilter(); + this.groupsData = newDataSet; + this.linegraph.setGroups(newDataSet); }; /** - * Replace the dataset of the Graph3d - * @param {Array | DataSet | DataView} data + * Returns an object containing an SVG element with the icon of the group (size determined by iconWidth and iconHeight), the label of the group (content) and the yAxisOrientation of the group (left or right). + * @param groupId + * @param width + * @param height */ - Graph3d.prototype.setData = function (data) { - this._readData(data); - this.redraw(); - - // start animation when option is true - if (this.animationAutoStart && this.dataFilter) { - this.animationStart(); + Graph2d.prototype.getLegend = function(groupId, width, height) { + if (width === undefined) {width = 15;} + if (height === undefined) {height = 15;} + if (this.linegraph.groups[groupId] !== undefined) { + return this.linegraph.groups[groupId].getLegend(width,height); } - }; + else { + return "cannot find group:" + groupId; + } + } /** - * Update the options. Options will be merged with current options - * @param {Object} options + * This checks if the visible option of the supplied group (by ID) is true or false. + * @param groupId + * @returns {*} */ - Graph3d.prototype.setOptions = function (options) { - var cameraPosition = undefined; - - this.animationStop(); - - if (options !== undefined) { - // retrieve parameter values - if (options.width !== undefined) this.width = options.width; - if (options.height !== undefined) this.height = options.height; - - if (options.xCenter !== undefined) this.defaultXCenter = options.xCenter; - if (options.yCenter !== undefined) this.defaultYCenter = options.yCenter; + Graph2d.prototype.isGroupVisible = function(groupId) { + if (this.linegraph.groups[groupId] !== undefined) { + return (this.linegraph.groups[groupId].visible && (this.linegraph.options.groups.visibility[groupId] === undefined || this.linegraph.options.groups.visibility[groupId] == true)); + } + else { + return false; + } + } - if (options.filterLabel !== undefined) this.filterLabel = options.filterLabel; - if (options.legendLabel !== undefined) this.legendLabel = options.legendLabel; - if (options.xLabel !== undefined) this.xLabel = options.xLabel; - if (options.yLabel !== undefined) this.yLabel = options.yLabel; - if (options.zLabel !== undefined) this.zLabel = options.zLabel; - if (options.xValueLabel !== undefined) this.xValueLabel = options.xValueLabel; - if (options.yValueLabel !== undefined) this.yValueLabel = options.yValueLabel; - if (options.zValueLabel !== undefined) this.zValueLabel = options.zValueLabel; + /** + * Get the data range of the item set. + * @returns {{min: Date, max: Date}} range A range with a start and end Date. + * When no minimum is found, min==null + * When no maximum is found, max==null + */ + Graph2d.prototype.getItemRange = function() { + var min = null; + var max = null; - if (options.style !== undefined) { - var styleNumber = this._getStyleNumber(options.style); - if (styleNumber !== -1) { - this.style = styleNumber; + // calculate min from start filed + for (var groupId in this.linegraph.groups) { + if (this.linegraph.groups.hasOwnProperty(groupId)) { + if (this.linegraph.groups[groupId].visible == true) { + for (var i = 0; i < this.linegraph.groups[groupId].itemsData.length; i++) { + var item = this.linegraph.groups[groupId].itemsData[i]; + var value = util.convert(item.x, 'Date').valueOf(); + min = min == null ? value : min > value ? value : min; + max = max == null ? value : max < value ? value : max; + } } } - if (options.showGrid !== undefined) this.showGrid = options.showGrid; - if (options.showPerspective !== undefined) this.showPerspective = options.showPerspective; - if (options.showShadow !== undefined) this.showShadow = options.showShadow; - if (options.tooltip !== undefined) this.showTooltip = options.tooltip; - if (options.showAnimationControls !== undefined) this.showAnimationControls = options.showAnimationControls; - if (options.keepAspectRatio !== undefined) this.keepAspectRatio = options.keepAspectRatio; - if (options.verticalRatio !== undefined) this.verticalRatio = options.verticalRatio; + } - if (options.animationInterval !== undefined) this.animationInterval = options.animationInterval; - if (options.animationPreload !== undefined) this.animationPreload = options.animationPreload; - if (options.animationAutoStart !== undefined)this.animationAutoStart = options.animationAutoStart; + return { + min: (min != null) ? new Date(min) : null, + max: (max != null) ? new Date(max) : null + }; + }; - if (options.xBarWidth !== undefined) this.defaultXBarWidth = options.xBarWidth; - if (options.yBarWidth !== undefined) this.defaultYBarWidth = options.yBarWidth; - if (options.xMin !== undefined) this.defaultXMin = options.xMin; - if (options.xStep !== undefined) this.defaultXStep = options.xStep; - if (options.xMax !== undefined) this.defaultXMax = options.xMax; - if (options.yMin !== undefined) this.defaultYMin = options.yMin; - if (options.yStep !== undefined) this.defaultYStep = options.yStep; - if (options.yMax !== undefined) this.defaultYMax = options.yMax; - if (options.zMin !== undefined) this.defaultZMin = options.zMin; - if (options.zStep !== undefined) this.defaultZStep = options.zStep; - if (options.zMax !== undefined) this.defaultZMax = options.zMax; - if (options.valueMin !== undefined) this.defaultValueMin = options.valueMin; - if (options.valueMax !== undefined) this.defaultValueMax = options.valueMax; - if (options.cameraPosition !== undefined) cameraPosition = options.cameraPosition; + module.exports = Graph2d; - if (cameraPosition !== undefined) { - this.camera.setArmRotation(cameraPosition.horizontal, cameraPosition.vertical); - this.camera.setArmLength(cameraPosition.distance); - } - else { - this.camera.setArmRotation(1.0, 0.5); - this.camera.setArmLength(1.7); - } - } - this._setBackgroundColor(options && options.backgroundColor); +/***/ }, +/* 15 */ +/***/ function(module, exports, __webpack_require__) { - this.setSize(this.width, this.height); + /** + * Created by Alex on 10/3/2014. + */ + var moment = __webpack_require__(44); - // re-load the data - if (this.dataTable) { - this.setData(this.dataTable); - } - // start animation when option is true - if (this.animationAutoStart && this.dataFilter) { - this.animationStart(); + /** + * used in Core to convert the options into a volatile variable + * + * @param Core + */ + exports.convertHiddenOptions = function(body, hiddenDates) { + body.hiddenDates = []; + if (hiddenDates) { + if (Array.isArray(hiddenDates) == true) { + for (var i = 0; i < hiddenDates.length; i++) { + if (hiddenDates[i].repeat === undefined) { + var dateItem = {}; + dateItem.start = moment(hiddenDates[i].start).toDate().valueOf(); + dateItem.end = moment(hiddenDates[i].end).toDate().valueOf(); + body.hiddenDates.push(dateItem); + } + } + body.hiddenDates.sort(function (a, b) { + return a.start - b.start; + }); // sort by start time + } } }; + /** - * Redraw the Graph. + * create new entrees for the repeating hidden dates + * @param body + * @param hiddenDates */ - Graph3d.prototype.redraw = function() { - if (this.dataPoints === undefined) { - throw 'Error: graph data not initialized'; - } + exports.updateHiddenDates = function (body, hiddenDates) { + if (hiddenDates && body.domProps.centerContainer.width !== undefined) { + exports.convertHiddenOptions(body, hiddenDates); - this._resizeCanvas(); - this._resizeCenter(); - this._redrawSlider(); - this._redrawClear(); - this._redrawAxis(); + var start = moment(body.range.start); + var end = moment(body.range.end); - if (this.style === Graph3d.STYLE.GRID || - this.style === Graph3d.STYLE.SURFACE) { - this._redrawDataGrid(); - } - else if (this.style === Graph3d.STYLE.LINE) { - this._redrawDataLine(); - } - else if (this.style === Graph3d.STYLE.BAR || - this.style === Graph3d.STYLE.BARCOLOR || - this.style === Graph3d.STYLE.BARSIZE) { - this._redrawDataBar(); - } - else { - // style is DOT, DOTLINE, DOTCOLOR, DOTSIZE - this._redrawDataDot(); - } + var totalRange = (body.range.end - body.range.start); + var pixelTime = totalRange / body.domProps.centerContainer.width; - this._redrawInfo(); - this._redrawLegend(); - }; + for (var i = 0; i < hiddenDates.length; i++) { + if (hiddenDates[i].repeat !== undefined) { + var startDate = moment(hiddenDates[i].start); + var endDate = moment(hiddenDates[i].end); + + if (startDate._d == "Invalid Date") { + throw new Error("Supplied start date is not valid: " + hiddenDates[i].start); + } + if (endDate._d == "Invalid Date") { + throw new Error("Supplied end date is not valid: " + hiddenDates[i].end); + } + + var duration = endDate - startDate; + if (duration >= 4 * pixelTime) { + + var offset = 0; + var runUntil = end.clone(); + switch (hiddenDates[i].repeat) { + case "daily": // case of time + if (startDate.day() != endDate.day()) { + offset = 1; + } + startDate.dayOfYear(start.dayOfYear()); + startDate.year(start.year()); + startDate.subtract(7,'days'); + + endDate.dayOfYear(start.dayOfYear()); + endDate.year(start.year()); + endDate.subtract(7 - offset,'days'); - /** - * Clear the canvas before redrawing - */ - Graph3d.prototype._redrawClear = function() { - var canvas = this.frame.canvas; - var ctx = canvas.getContext('2d'); + runUntil.add(1, 'weeks'); + break; + case "weekly": + var dayOffset = endDate.diff(startDate,'days') + var day = startDate.day(); - ctx.clearRect(0, 0, canvas.width, canvas.height); - }; + // set the start date to the range.start + startDate.date(start.date()); + startDate.month(start.month()); + startDate.year(start.year()); + endDate = startDate.clone(); + // force + startDate.day(day); + endDate.day(day); + endDate.add(dayOffset,'days'); - /** - * Redraw the legend showing the colors - */ - Graph3d.prototype._redrawLegend = function() { - var y; + startDate.subtract(1,'weeks'); + endDate.subtract(1,'weeks'); - if (this.style === Graph3d.STYLE.DOTCOLOR || - this.style === Graph3d.STYLE.DOTSIZE) { + runUntil.add(1, 'weeks'); + break + case "monthly": + if (startDate.month() != endDate.month()) { + offset = 1; + } + startDate.month(start.month()); + startDate.year(start.year()); + startDate.subtract(1,'months'); - var dotSize = this.frame.clientWidth * 0.02; + endDate.month(start.month()); + endDate.year(start.year()); + endDate.subtract(1,'months'); + endDate.add(offset,'months'); - var widthMin, widthMax; - if (this.style === Graph3d.STYLE.DOTSIZE) { - widthMin = dotSize / 2; // px - widthMax = dotSize / 2 + dotSize * 2; // Todo: put this in one function + runUntil.add(1, 'months'); + break; + case "yearly": + if (startDate.year() != endDate.year()) { + offset = 1; + } + startDate.year(start.year()); + startDate.subtract(1,'years'); + endDate.year(start.year()); + endDate.subtract(1,'years'); + endDate.add(offset,'years'); + + runUntil.add(1, 'years'); + break; + default: + console.log("Wrong repeat format, allowed are: daily, weekly, monthly, yearly. Given:", hiddenDates[i].repeat); + return; + } + while (startDate < runUntil) { + body.hiddenDates.push({start: startDate.valueOf(), end: endDate.valueOf()}); + switch (hiddenDates[i].repeat) { + case "daily": + startDate.add(1, 'days'); + endDate.add(1, 'days'); + break; + case "weekly": + startDate.add(1, 'weeks'); + endDate.add(1, 'weeks'); + break + case "monthly": + startDate.add(1, 'months'); + endDate.add(1, 'months'); + break; + case "yearly": + startDate.add(1, 'y'); + endDate.add(1, 'y'); + break; + default: + console.log("Wrong repeat format, allowed are: daily, weekly, monthly, yearly. Given:", hiddenDates[i].repeat); + return; + } + } + body.hiddenDates.push({start: startDate.valueOf(), end: endDate.valueOf()}); + } + } } - else { - widthMin = 20; // px - widthMax = 20; // px + // remove duplicates, merge where possible + exports.removeDuplicates(body); + // ensure the new positions are not on hidden dates + var startHidden = exports.isHidden(body.range.start, body.hiddenDates); + var endHidden = exports.isHidden(body.range.end,body.hiddenDates); + var rangeStart = body.range.start; + var rangeEnd = body.range.end; + if (startHidden.hidden == true) {rangeStart = body.range.startToFront == true ? startHidden.startDate - 1 : startHidden.endDate + 1;} + if (endHidden.hidden == true) {rangeEnd = body.range.endToFront == true ? endHidden.startDate - 1 : endHidden.endDate + 1;} + if (startHidden.hidden == true || endHidden.hidden == true) { + body.range._applyRange(rangeStart, rangeEnd); } - - var height = Math.max(this.frame.clientHeight * 0.25, 100); - var top = this.margin; - var right = this.frame.clientWidth - this.margin; - var left = right - widthMax; - var bottom = top + height; } - var canvas = this.frame.canvas; - var ctx = canvas.getContext('2d'); - ctx.lineWidth = 1; - ctx.font = '14px arial'; // TODO: put in options - - if (this.style === Graph3d.STYLE.DOTCOLOR) { - // draw the color bar - var ymin = 0; - var ymax = height; // Todo: make height customizable - for (y = ymin; y < ymax; y++) { - var f = (y - ymin) / (ymax - ymin); + } - //var width = (dotSize / 2 + (1-f) * dotSize * 2); // Todo: put this in one function - var hue = f * 240; - var color = this._hsv2rgb(hue, 1, 1); - ctx.strokeStyle = color; - ctx.beginPath(); - ctx.moveTo(left, top + y); - ctx.lineTo(right, top + y); - ctx.stroke(); + /** + * remove duplicates from the hidden dates list. Duplicates are evil. They mess everything up. + * Scales with N^2 + * @param body + */ + exports.removeDuplicates = function(body) { + var hiddenDates = body.hiddenDates; + var safeDates = []; + for (var i = 0; i < hiddenDates.length; i++) { + for (var j = 0; j < hiddenDates.length; j++) { + if (i != j && hiddenDates[j].remove != true && hiddenDates[i].remove != true) { + // j inside i + if (hiddenDates[j].start >= hiddenDates[i].start && hiddenDates[j].end <= hiddenDates[i].end) { + hiddenDates[j].remove = true; + } + // j start inside i + else if (hiddenDates[j].start >= hiddenDates[i].start && hiddenDates[j].start <= hiddenDates[i].end) { + hiddenDates[i].end = hiddenDates[j].end; + hiddenDates[j].remove = true; + } + // j end inside i + else if (hiddenDates[j].end >= hiddenDates[i].start && hiddenDates[j].end <= hiddenDates[i].end) { + hiddenDates[i].start = hiddenDates[j].start; + hiddenDates[j].remove = true; + } + } } - - ctx.strokeStyle = this.colorAxis; - ctx.strokeRect(left, top, widthMax, height); - } - - if (this.style === Graph3d.STYLE.DOTSIZE) { - // draw border around color bar - ctx.strokeStyle = this.colorAxis; - ctx.fillStyle = this.colorDot; - ctx.beginPath(); - ctx.moveTo(left, top); - ctx.lineTo(right, top); - ctx.lineTo(right - widthMax + widthMin, bottom); - ctx.lineTo(left, bottom); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); } - if (this.style === Graph3d.STYLE.DOTCOLOR || - this.style === Graph3d.STYLE.DOTSIZE) { - // print values along the color bar - var gridLineLen = 5; // px - var step = new StepNumber(this.valueMin, this.valueMax, (this.valueMax-this.valueMin)/5, true); - step.start(); - if (step.getCurrent() < this.valueMin) { - step.next(); + for (var i = 0; i < hiddenDates.length; i++) { + if (hiddenDates[i].remove !== true) { + safeDates.push(hiddenDates[i]); } - while (!step.end()) { - y = bottom - (step.getCurrent() - this.valueMin) / (this.valueMax - this.valueMin) * height; - - ctx.beginPath(); - ctx.moveTo(left - gridLineLen, y); - ctx.lineTo(left, y); - ctx.stroke(); - - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - ctx.fillStyle = this.colorAxis; - ctx.fillText(step.getCurrent(), left - 2 * gridLineLen, y); + } - step.next(); - } + body.hiddenDates = safeDates; + body.hiddenDates.sort(function (a, b) { + return a.start - b.start; + }); // sort by start time + } - ctx.textAlign = 'right'; - ctx.textBaseline = 'top'; - var label = this.legendLabel; - ctx.fillText(label, right, bottom + this.margin); + exports.printDates = function(dates) { + for (var i =0; i < dates.length; i++) { + console.log(i, new Date(dates[i].start),new Date(dates[i].end), dates[i].start, dates[i].end, dates[i].remove); } - }; + } /** - * Redraw the filter + * Used in TimeStep to avoid the hidden times. + * @param timeStep + * @param previousTime */ - Graph3d.prototype._redrawFilter = function() { - this.frame.filter.innerHTML = ''; - - if (this.dataFilter) { - var options = { - 'visible': this.showAnimationControls - }; - var slider = new Slider(this.frame.filter, options); - this.frame.filter.slider = slider; + exports.stepOverHiddenDates = function(timeStep, previousTime) { + var stepInHidden = false; + var currentValue = timeStep.current.valueOf(); + for (var i = 0; i < timeStep.hiddenDates.length; i++) { + var startDate = timeStep.hiddenDates[i].start; + var endDate = timeStep.hiddenDates[i].end; + if (currentValue >= startDate && currentValue < endDate) { + stepInHidden = true; + break; + } + } - // TODO: css here is not nice here... - this.frame.filter.style.padding = '10px'; - //this.frame.filter.style.backgroundColor = '#EFEFEF'; + if (stepInHidden == true && currentValue < timeStep._end.valueOf() && currentValue != previousTime) { + var prevValue = moment(previousTime); + var newValue = moment(endDate); + //check if the next step should be major + if (prevValue.year() != newValue.year()) {timeStep.switchedYear = true;} + else if (prevValue.month() != newValue.month()) {timeStep.switchedMonth = true;} + else if (prevValue.dayOfYear() != newValue.dayOfYear()) {timeStep.switchedDay = true;} - slider.setValues(this.dataFilter.values); - slider.setPlayInterval(this.animationInterval); + timeStep.current = newValue.toDate(); + } + }; - // create an event handler - var me = this; - var onchange = function () { - var index = slider.getIndex(); - me.dataFilter.selectValue(index); - me.dataPoints = me.dataFilter._getDataPoints(); + ///** + // * Used in TimeStep to avoid the hidden times. + // * @param timeStep + // * @param previousTime + // */ + //exports.checkFirstStep = function(timeStep) { + // var stepInHidden = false; + // var currentValue = timeStep.current.valueOf(); + // for (var i = 0; i < timeStep.hiddenDates.length; i++) { + // var startDate = timeStep.hiddenDates[i].start; + // var endDate = timeStep.hiddenDates[i].end; + // if (currentValue >= startDate && currentValue < endDate) { + // stepInHidden = true; + // break; + // } + // } + // + // if (stepInHidden == true && currentValue <= timeStep._end.valueOf()) { + // var newValue = moment(endDate); + // timeStep.current = newValue.toDate(); + // } + //}; - me.redraw(); - }; - slider.setOnChangeCallback(onchange); + /** + * replaces the Core toScreen methods + * @param Core + * @param time + * @param width + * @returns {number} + */ + exports.toScreen = function(Core, time, width) { + if (Core.body.hiddenDates.length == 0) { + var conversion = Core.range.conversion(width); + return (time.valueOf() - conversion.offset) * conversion.scale; } else { - this.frame.filter.slider = undefined; + var hidden = exports.isHidden(time, Core.body.hiddenDates) + if (hidden.hidden == true) { + time = hidden.startDate; + } + + var duration = exports.getHiddenDurationBetween(Core.body.hiddenDates, Core.range.start, Core.range.end); + time = exports.correctTimeForHidden(Core.body.hiddenDates, Core.range, time); + + var conversion = Core.range.conversion(width, duration); + return (time.valueOf() - conversion.offset) * conversion.scale; } }; + /** - * Redraw the slider + * Replaces the core toTime methods + * @param body + * @param range + * @param x + * @param width + * @returns {Date} */ - Graph3d.prototype._redrawSlider = function() { - if ( this.frame.filter.slider !== undefined) { - this.frame.filter.slider.redraw(); + exports.toTime = function(Core, x, width) { + if (Core.body.hiddenDates.length == 0) { + var conversion = Core.range.conversion(width); + return new Date(x / conversion.scale + conversion.offset); + } + else { + var hiddenDuration = exports.getHiddenDurationBetween(Core.body.hiddenDates, Core.range.start, Core.range.end); + var totalDuration = Core.range.end - Core.range.start - hiddenDuration; + var partialDuration = totalDuration * x / width; + var accumulatedHiddenDuration = exports.getAccumulatedHiddenDuration(Core.body.hiddenDates, Core.range, partialDuration); + + var newTime = new Date(accumulatedHiddenDuration + partialDuration + Core.range.start); + return newTime; } }; /** - * Redraw common information + * Support function + * + * @param hiddenDates + * @param range + * @returns {number} */ - Graph3d.prototype._redrawInfo = function() { - if (this.dataFilter) { - var canvas = this.frame.canvas; - var ctx = canvas.getContext('2d'); - - ctx.font = '14px arial'; // TODO: put in options - ctx.lineStyle = 'gray'; - ctx.fillStyle = 'gray'; - ctx.textAlign = 'left'; - ctx.textBaseline = 'top'; - - var x = this.margin; - var y = this.margin; - ctx.fillText(this.dataFilter.getLabel() + ': ' + this.dataFilter.getSelectedValue(), x, y); + exports.getHiddenDurationBetween = function(hiddenDates, start, end) { + var duration = 0; + for (var i = 0; i < hiddenDates.length; i++) { + var startDate = hiddenDates[i].start; + var endDate = hiddenDates[i].end; + // if time after the cutout, and the + if (startDate >= start && endDate < end) { + duration += endDate - startDate; + } } + return duration; }; /** - * Redraw the axis + * Support function + * @param hiddenDates + * @param range + * @param time + * @returns {{duration: number, time: *, offset: number}} */ - Graph3d.prototype._redrawAxis = function() { - var canvas = this.frame.canvas, - ctx = canvas.getContext('2d'), - from, to, step, prettyStep, - text, xText, yText, zText, - offset, xOffset, yOffset, - xMin2d, xMax2d; - - // TODO: get the actual rendered style of the containerElement - //ctx.font = this.containerElement.style.font; - ctx.font = 24 / this.camera.getArmLength() + 'px arial'; - - // calculate the length for the short grid lines - var gridLenX = 0.025 / this.scale.x; - var gridLenY = 0.025 / this.scale.y; - var textMargin = 5 / this.camera.getArmLength(); // px - var armAngle = this.camera.getArmRotation().horizontal; - - // draw x-grid lines - ctx.lineWidth = 1; - prettyStep = (this.defaultXStep === undefined); - step = new StepNumber(this.xMin, this.xMax, this.xStep, prettyStep); - step.start(); - if (step.getCurrent() < this.xMin) { - step.next(); - } - while (!step.end()) { - var x = step.getCurrent(); - - if (this.showGrid) { - from = this._convert3Dto2D(new Point3d(x, this.yMin, this.zMin)); - to = this._convert3Dto2D(new Point3d(x, this.yMax, this.zMin)); - ctx.strokeStyle = this.colorGrid; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); - } - else { - from = this._convert3Dto2D(new Point3d(x, this.yMin, this.zMin)); - to = this._convert3Dto2D(new Point3d(x, this.yMin+gridLenX, this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); + exports.correctTimeForHidden = function(hiddenDates, range, time) { + time = moment(time).toDate().valueOf(); + time -= exports.getHiddenDurationBefore(hiddenDates,range,time); + return time; + }; - from = this._convert3Dto2D(new Point3d(x, this.yMax, this.zMin)); - to = this._convert3Dto2D(new Point3d(x, this.yMax-gridLenX, this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); - } + exports.getHiddenDurationBefore = function(hiddenDates, range, time) { + var timeOffset = 0; + time = moment(time).toDate().valueOf(); - yText = (Math.cos(armAngle) > 0) ? this.yMin : this.yMax; - text = this._convert3Dto2D(new Point3d(x, yText, this.zMin)); - if (Math.cos(armAngle * 2) > 0) { - ctx.textAlign = 'center'; - ctx.textBaseline = 'top'; - text.y += textMargin; - } - else if (Math.sin(armAngle * 2) < 0){ - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - } - else { - ctx.textAlign = 'left'; - ctx.textBaseline = 'middle'; + for (var i = 0; i < hiddenDates.length; i++) { + var startDate = hiddenDates[i].start; + var endDate = hiddenDates[i].end; + // if time after the cutout, and the + if (startDate >= range.start && endDate < range.end) { + if (time >= endDate) { + timeOffset += (endDate - startDate); + } } - ctx.fillStyle = this.colorAxis; - ctx.fillText(' ' + this.xValueLabel(step.getCurrent()) + ' ', text.x, text.y); - - step.next(); - } - - // draw y-grid lines - ctx.lineWidth = 1; - prettyStep = (this.defaultYStep === undefined); - step = new StepNumber(this.yMin, this.yMax, this.yStep, prettyStep); - step.start(); - if (step.getCurrent() < this.yMin) { - step.next(); } - while (!step.end()) { - if (this.showGrid) { - from = this._convert3Dto2D(new Point3d(this.xMin, step.getCurrent(), this.zMin)); - to = this._convert3Dto2D(new Point3d(this.xMax, step.getCurrent(), this.zMin)); - ctx.strokeStyle = this.colorGrid; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); - } - else { - from = this._convert3Dto2D(new Point3d(this.xMin, step.getCurrent(), this.zMin)); - to = this._convert3Dto2D(new Point3d(this.xMin+gridLenY, step.getCurrent(), this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); + return timeOffset; + } - from = this._convert3Dto2D(new Point3d(this.xMax, step.getCurrent(), this.zMin)); - to = this._convert3Dto2D(new Point3d(this.xMax-gridLenY, step.getCurrent(), this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); + /** + * sum the duration from start to finish, including the hidden duration, + * until the required amount has been reached, return the accumulated hidden duration + * @param hiddenDates + * @param range + * @param time + * @returns {{duration: number, time: *, offset: number}} + */ + exports.getAccumulatedHiddenDuration = function(hiddenDates, range, requiredDuration) { + var hiddenDuration = 0; + var duration = 0; + var previousPoint = range.start; + //exports.printDates(hiddenDates) + for (var i = 0; i < hiddenDates.length; i++) { + var startDate = hiddenDates[i].start; + var endDate = hiddenDates[i].end; + // if time after the cutout, and the + if (startDate >= range.start && endDate < range.end) { + duration += startDate - previousPoint; + previousPoint = endDate; + if (duration >= requiredDuration) { + break; + } + else { + hiddenDuration += endDate - startDate; + } } + } - xText = (Math.sin(armAngle ) > 0) ? this.xMin : this.xMax; - text = this._convert3Dto2D(new Point3d(xText, step.getCurrent(), this.zMin)); - if (Math.cos(armAngle * 2) < 0) { - ctx.textAlign = 'center'; - ctx.textBaseline = 'top'; - text.y += textMargin; - } - else if (Math.sin(armAngle * 2) > 0){ - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; + return hiddenDuration; + }; + + + + /** + * used to step over to either side of a hidden block. Correction is disabled on tablets, might be set to true + * @param hiddenDates + * @param time + * @param direction + * @param correctionEnabled + * @returns {*} + */ + exports.snapAwayFromHidden = function(hiddenDates, time, direction, correctionEnabled) { + var isHidden = exports.isHidden(time, hiddenDates); + if (isHidden.hidden == true) { + if (direction < 0) { + if (correctionEnabled == true) { + return isHidden.startDate - (isHidden.endDate - time) - 1; + } + else { + return isHidden.startDate - 1; + } } else { - ctx.textAlign = 'left'; - ctx.textBaseline = 'middle'; + if (correctionEnabled == true) { + return isHidden.endDate + (time - isHidden.startDate) + 1; + } + else { + return isHidden.endDate + 1; + } } - ctx.fillStyle = this.colorAxis; - ctx.fillText(' ' + this.yValueLabel(step.getCurrent()) + ' ', text.x, text.y); - - step.next(); } - - // draw z-grid lines and axis - ctx.lineWidth = 1; - prettyStep = (this.defaultZStep === undefined); - step = new StepNumber(this.zMin, this.zMax, this.zStep, prettyStep); - step.start(); - if (step.getCurrent() < this.zMin) { - step.next(); + else { + return time; } - xText = (Math.cos(armAngle ) > 0) ? this.xMin : this.xMax; - yText = (Math.sin(armAngle ) < 0) ? this.yMin : this.yMax; - while (!step.end()) { - // TODO: make z-grid lines really 3d? - from = this._convert3Dto2D(new Point3d(xText, yText, step.getCurrent())); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(from.x - textMargin, from.y); - ctx.stroke(); - - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - ctx.fillStyle = this.colorAxis; - ctx.fillText(this.zValueLabel(step.getCurrent()) + ' ', from.x - 5, from.y); - step.next(); - } - ctx.lineWidth = 1; - from = this._convert3Dto2D(new Point3d(xText, yText, this.zMin)); - to = this._convert3Dto2D(new Point3d(xText, yText, this.zMax)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); + } - // draw x-axis - ctx.lineWidth = 1; - // line at yMin - xMin2d = this._convert3Dto2D(new Point3d(this.xMin, this.yMin, this.zMin)); - xMax2d = this._convert3Dto2D(new Point3d(this.xMax, this.yMin, this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(xMin2d.x, xMin2d.y); - ctx.lineTo(xMax2d.x, xMax2d.y); - ctx.stroke(); - // line at ymax - xMin2d = this._convert3Dto2D(new Point3d(this.xMin, this.yMax, this.zMin)); - xMax2d = this._convert3Dto2D(new Point3d(this.xMax, this.yMax, this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(xMin2d.x, xMin2d.y); - ctx.lineTo(xMax2d.x, xMax2d.y); - ctx.stroke(); - // draw y-axis - ctx.lineWidth = 1; - // line at xMin - from = this._convert3Dto2D(new Point3d(this.xMin, this.yMin, this.zMin)); - to = this._convert3Dto2D(new Point3d(this.xMin, this.yMax, this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); - // line at xMax - from = this._convert3Dto2D(new Point3d(this.xMax, this.yMin, this.zMin)); - to = this._convert3Dto2D(new Point3d(this.xMax, this.yMax, this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); + /** + * Check if a time is hidden + * + * @param time + * @param hiddenDates + * @returns {{hidden: boolean, startDate: Window.start, endDate: *}} + */ + exports.isHidden = function(time, hiddenDates) { + for (var i = 0; i < hiddenDates.length; i++) { + var startDate = hiddenDates[i].start; + var endDate = hiddenDates[i].end; - // draw x-label - var xLabel = this.xLabel; - if (xLabel.length > 0) { - yOffset = 0.1 / this.scale.y; - xText = (this.xMin + this.xMax) / 2; - yText = (Math.cos(armAngle) > 0) ? this.yMin - yOffset: this.yMax + yOffset; - text = this._convert3Dto2D(new Point3d(xText, yText, this.zMin)); - if (Math.cos(armAngle * 2) > 0) { - ctx.textAlign = 'center'; - ctx.textBaseline = 'top'; - } - else if (Math.sin(armAngle * 2) < 0){ - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - } - else { - ctx.textAlign = 'left'; - ctx.textBaseline = 'middle'; + if (time >= startDate && time < endDate) { // if the start is entering a hidden zone + return {hidden: true, startDate: startDate, endDate: endDate}; + break; } - ctx.fillStyle = this.colorAxis; - ctx.fillText(xLabel, text.x, text.y); } + return {hidden: false, startDate: startDate, endDate: endDate}; + } - // draw y-label - var yLabel = this.yLabel; - if (yLabel.length > 0) { - xOffset = 0.1 / this.scale.x; - xText = (Math.sin(armAngle ) > 0) ? this.xMin - xOffset : this.xMax + xOffset; - yText = (this.yMin + this.yMax) / 2; - text = this._convert3Dto2D(new Point3d(xText, yText, this.zMin)); - if (Math.cos(armAngle * 2) < 0) { - ctx.textAlign = 'center'; - ctx.textBaseline = 'top'; - } - else if (Math.sin(armAngle * 2) > 0){ - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - } - else { - ctx.textAlign = 'left'; - ctx.textBaseline = 'middle'; - } - ctx.fillStyle = this.colorAxis; - ctx.fillText(yLabel, text.x, text.y); +/***/ }, +/* 16 */ +/***/ 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, alignZeros) { + // 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.alignZeros = alignZeros; + + 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 (this._start == this._end) { + this._start -= 0.75; + this._end += 1; } - // draw z-label - var zLabel = this.zLabel; - if (zLabel.length > 0) { - offset = 30; // pixels. // TODO: relate to the max width of the values on the z axis? - xText = (Math.cos(armAngle ) > 0) ? this.xMin : this.xMax; - yText = (Math.sin(armAngle ) < 0) ? this.yMin : this.yMax; - zText = (this.zMin + this.zMax) / 2; - text = this._convert3Dto2D(new Point3d(xText, yText, zText)); - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - ctx.fillStyle = this.colorAxis; - ctx.fillText(zLabel, text.x - offset, text.y); + if (this.autoScale == true) { + this.setMinimumStep(minimumStep, containerHeight); } + + this.setFirst(customRange); }; /** - * Calculate the color based on the given value. - * @param {Number} H Hue, a value be between 0 and 360 - * @param {Number} S Saturation, a value between 0 and 1 - * @param {Number} V Value, a value between 0 and 1 + * Automatically determine the scale that bests fits the provided minimum step + * @param {Number} [minimumStep] The minimum step size in milliseconds */ - Graph3d.prototype._hsv2rgb = function(H, S, V) { - var R, G, B, C, Hi, X; - - C = V * S; - Hi = Math.floor(H/60); // hi = 0,1,2,3,4,5 - X = C * (1 - Math.abs(((H/60) % 2) - 1)); + 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); - switch (Hi) { - case 0: R = C; G = X; B = 0; break; - case 1: R = X; G = C; B = 0; break; - case 2: R = 0; G = C; B = X; break; - case 3: R = 0; G = X; B = C; break; - case 4: R = X; G = 0; B = C; break; - case 5: R = C; G = 0; B = X; break; + var minorStepIdx = -1; + var magnitudefactor = Math.pow(10,orderOfMagnitude); - default: R = 0; G = 0; B = 0; break; + var start = 0; + if (orderOfMagnitude < 0) { + start = orderOfMagnitude; } - return 'RGB(' + parseInt(R*255) + ',' + parseInt(G*255) + ',' + parseInt(B*255) + ')'; + 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]; }; + /** - * Draw all datapoints as a grid - * This function can be used when the style is 'grid' + * Round the current date to the first minor date value + * This must be executed once when the current date is set to start Date */ - Graph3d.prototype._redrawDataGrid = function() { - var canvas = this.frame.canvas, - ctx = canvas.getContext('2d'), - point, right, top, cross, - i, - topSideVisible, fillStyle, strokeStyle, lineWidth, - h, s, v, zAvg; + 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; - if (this.dataPoints === undefined || this.dataPoints.length <= 0) - return; // TODO: throw exception? + this.marginEnd = customRange.max === undefined ? this.roundToMinor(niceEnd) : customRange.max; + this.marginStart = customRange.min === undefined ? this.roundToMinor(niceStart) : customRange.min; - // calculate the translations and screen position of all points - for (i = 0; i < this.dataPoints.length; i++) { - var trans = this._convertPointToTranslation(this.dataPoints[i].point); - var screen = this._convertTranslationToScreen(trans); + // if we need to align the zero's we need to make sure that there is a zero to use. + if (this.alignZeros == true && (this.marginEnd - this.marginStart) % this.step != 0) { + this.marginEnd += this.marginEnd % this.step; + } - this.dataPoints[i].trans = trans; - this.dataPoints[i].screen = screen; + this.deadSpace = this.roundToMinor(niceEnd) - niceEnd + this.roundToMinor(niceStart) - niceStart; + this.marginRange = this.marginEnd - this.marginStart; - // calculate the translation of the point at the bottom (needed for sorting) - var transBottom = this._convertPointToTranslation(this.dataPoints[i].bottom); - this.dataPoints[i].dist = this.showPerspective ? transBottom.length() : -transBottom.z; + + 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; } + } - // sort the points on depth of their (x,y) position (not on z) - var sortDepth = function (a, b) { - return b.dist - a.dist; - }; - this.dataPoints.sort(sortDepth); - if (this.style === Graph3d.STYLE.SURFACE) { - for (i = 0; i < this.dataPoints.length; i++) { - point = this.dataPoints[i]; - right = this.dataPoints[i].pointRight; - top = this.dataPoints[i].pointTop; - cross = this.dataPoints[i].pointCross; + /** + * 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); + }; - if (point !== undefined && right !== undefined && top !== undefined && cross !== undefined) { + /** + * Do the next step + */ + DataStep.prototype.next = function() { + var prev = this.current; + this.current -= this.step; - if (this.showGrayBottom || this.showShadow) { - // calculate the cross product of the two vectors from center - // to left and right, in order to know whether we are looking at the - // bottom or at the top side. We can also use the cross product - // for calculating light intensity - var aDiff = Point3d.subtract(cross.trans, point.trans); - var bDiff = Point3d.subtract(top.trans, right.trans); - var crossproduct = Point3d.crossProduct(aDiff, bDiff); - var len = crossproduct.length(); - // FIXME: there is a bug with determining the surface side (shadow or colored) + // safety mechanism: if current time is still unchanged, move to the end + if (this.current == prev) { + this.current = this._end; + } + }; - topSideVisible = (crossproduct.z > 0); - } - else { - topSideVisible = true; - } + /** + * Do the next step + */ + DataStep.prototype.previous = function() { + this.current += this.step; + this.marginEnd += this.step; + this.marginRange = this.marginEnd - this.marginStart; + }; - if (topSideVisible) { - // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 - zAvg = (point.point.z + right.point.z + top.point.z + cross.point.z) / 4; - h = (1 - (zAvg - this.zMin) * this.scale.z / this.verticalRatio) * 240; - s = 1; // saturation - if (this.showShadow) { - v = Math.min(1 + (crossproduct.x / len) / 2, 1); // value. TODO: scale - fillStyle = this._hsv2rgb(h, s, v); - strokeStyle = fillStyle; - } - else { - v = 1; - fillStyle = this._hsv2rgb(h, s, v); - strokeStyle = this.colorAxis; - } - } - else { - fillStyle = 'gray'; - strokeStyle = this.colorAxis; - } - lineWidth = 0.5; - ctx.lineWidth = lineWidth; - ctx.fillStyle = fillStyle; - ctx.strokeStyle = strokeStyle; - ctx.beginPath(); - ctx.moveTo(point.screen.x, point.screen.y); - ctx.lineTo(right.screen.x, right.screen.y); - ctx.lineTo(cross.screen.x, cross.screen.y); - ctx.lineTo(top.screen.x, top.screen.y); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); + /** + * Get the current datetime + * @return {String} current The current date + */ + DataStep.prototype.getCurrent = function(decimals) { + // prevent round-off errors when close to zero + var current = (Math.abs(this.current) < this.step / 2) ? 0 : this.current; + var toPrecision = '' + Number(current).toPrecision(5); + + // If decimals is specified, then limit or extend the string as required + if(decimals !== undefined && !isNaN(Number(decimals))) { + // If string includes exponent, then we need to add it to the end + var exp = ""; + var index = toPrecision.indexOf("e"); + if(index != -1) { + // Get the exponent + exp = toPrecision.slice(index); + // Remove the exponent in case we need to zero-extend + toPrecision = toPrecision.slice(0, index); + } + index = Math.max(toPrecision.indexOf(","), toPrecision.indexOf(".")); + if(index === -1) { + // No decimal found - if we want decimals, then we need to add it + if(decimals !== 0) { + toPrecision += '.'; + } + // Calculate how long the string should be + index = toPrecision.length + decimals; + } + else if(decimals !== 0) { + // Calculate how long the string should be - accounting for the decimal place + index += decimals + 1; + } + if(index > toPrecision.length) { + // We need to add zeros! + for(var cnt = index - toPrecision.length; cnt > 0; cnt--) { + toPrecision += '0'; } } + else { + // we need to remove characters + toPrecision = toPrecision.slice(0, index); + } + // Add the exponent if there is one + toPrecision += exp; } - else { // grid style - for (i = 0; i < this.dataPoints.length; i++) { - point = this.dataPoints[i]; - right = this.dataPoints[i].pointRight; - top = this.dataPoints[i].pointTop; - - if (point !== undefined) { - if (this.showPerspective) { - lineWidth = 2 / -point.trans.z; + else { + if (toPrecision.indexOf(",") != -1 || toPrecision.indexOf(".") != -1) { + // If no decimal is specified, and there are decimal places, remove trailing zeros + 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 { - lineWidth = 2 * -(this.eye.z / this.camera.getArmLength()); + break; } } - - if (point !== undefined && right !== undefined) { - // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 - zAvg = (point.point.z + right.point.z) / 2; - h = (1 - (zAvg - this.zMin) * this.scale.z / this.verticalRatio) * 240; - - ctx.lineWidth = lineWidth; - ctx.strokeStyle = this._hsv2rgb(h, 1, 1); - ctx.beginPath(); - ctx.moveTo(point.screen.x, point.screen.y); - ctx.lineTo(right.screen.x, right.screen.y); - ctx.stroke(); - } - - if (point !== undefined && top !== undefined) { - // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 - zAvg = (point.point.z + top.point.z) / 2; - h = (1 - (zAvg - this.zMin) * this.scale.z / this.verticalRatio) * 240; - - ctx.lineWidth = lineWidth; - ctx.strokeStyle = this._hsv2rgb(h, 1, 1); - ctx.beginPath(); - ctx.moveTo(point.screen.x, point.screen.y); - ctx.lineTo(top.screen.x, top.screen.y); - ctx.stroke(); - } } } + + return toPrecision; }; + /** - * Draw all datapoints as dots. - * This function can be used when the style is 'dot' or 'dot-line' + * 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 */ - Graph3d.prototype._redrawDataDot = function() { - var canvas = this.frame.canvas; - var ctx = canvas.getContext('2d'); - var i; - - if (this.dataPoints === undefined || this.dataPoints.length <= 0) - return; // TODO: throw exception? - - // calculate the translations of all points - for (i = 0; i < this.dataPoints.length; i++) { - var trans = this._convertPointToTranslation(this.dataPoints[i].point); - var screen = this._convertTranslationToScreen(trans); - this.dataPoints[i].trans = trans; - this.dataPoints[i].screen = screen; - - // calculate the distance from the point at the bottom to the camera - var transBottom = this._convertPointToTranslation(this.dataPoints[i].bottom); - this.dataPoints[i].dist = this.showPerspective ? transBottom.length() : -transBottom.z; - } - - // order the translated points by depth - var sortDepth = function (a, b) { - return b.dist - a.dist; - }; - this.dataPoints.sort(sortDepth); + DataStep.prototype.snap = function(date) { - // draw the datapoints as colored circles - var dotSize = this.frame.clientWidth * 0.02; // px - for (i = 0; i < this.dataPoints.length; i++) { - var point = this.dataPoints[i]; + }; - if (this.style === Graph3d.STYLE.DOTLINE) { - // draw a vertical line from the bottom to the graph value - //var from = this._convert3Dto2D(new Point3d(point.point.x, point.point.y, this.zMin)); - var from = this._convert3Dto2D(point.bottom); - ctx.lineWidth = 1; - ctx.strokeStyle = this.colorGrid; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(point.screen.x, point.screen.y); - ctx.stroke(); - } + /** + * 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); + }; - // calculate radius for the circle - var size; - if (this.style === Graph3d.STYLE.DOTSIZE) { - size = dotSize/2 + 2*dotSize * (point.point.value - this.valueMin) / (this.valueMax - this.valueMin); - } - else { - size = dotSize; - } + module.exports = DataStep; - var radius; - if (this.showPerspective) { - radius = size / -point.trans.z; - } - else { - radius = size * -(this.eye.z / this.camera.getArmLength()); - } - if (radius < 0) { - radius = 0; - } - var hue, color, borderColor; - if (this.style === Graph3d.STYLE.DOTCOLOR ) { - // calculate the color based on the value - hue = (1 - (point.point.value - this.valueMin) * this.scale.value) * 240; - color = this._hsv2rgb(hue, 1, 1); - borderColor = this._hsv2rgb(hue, 1, 0.8); - } - else if (this.style === Graph3d.STYLE.DOTSIZE) { - color = this.colorDot; - borderColor = this.colorDotBorder; - } - else { - // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 - hue = (1 - (point.point.z - this.zMin) * this.scale.z / this.verticalRatio) * 240; - color = this._hsv2rgb(hue, 1, 1); - borderColor = this._hsv2rgb(hue, 1, 0.8); - } +/***/ }, +/* 17 */ +/***/ function(module, exports, __webpack_require__) { - // draw the circle - ctx.lineWidth = 1.0; - ctx.strokeStyle = borderColor; - ctx.fillStyle = color; - ctx.beginPath(); - ctx.arc(point.screen.x, point.screen.y, radius, 0, Math.PI*2, true); - ctx.fill(); - ctx.stroke(); - } - }; + var util = __webpack_require__(1); + var hammerUtil = __webpack_require__(47); + var moment = __webpack_require__(44); + var Component = __webpack_require__(20); + var DateUtil = __webpack_require__(15); /** - * Draw all datapoints as bars. - * This function can be used when the style is 'bar', 'bar-color', or 'bar-size' + * @constructor Range + * A Range controls a numeric range with a start and end value. + * The Range adjusts the range based on mouse events or programmatic changes, + * and triggers events when the range is changing or has been changed. + * @param {{dom: Object, domProps: Object, emitter: Emitter}} body + * @param {Object} [options] See description at Range.setOptions */ - Graph3d.prototype._redrawDataBar = function() { - var canvas = this.frame.canvas; - var ctx = canvas.getContext('2d'); - var i, j, surface, corners; - - if (this.dataPoints === undefined || this.dataPoints.length <= 0) - return; // TODO: throw exception? - - // calculate the translations of all points - for (i = 0; i < this.dataPoints.length; i++) { - var trans = this._convertPointToTranslation(this.dataPoints[i].point); - var screen = this._convertTranslationToScreen(trans); - this.dataPoints[i].trans = trans; - this.dataPoints[i].screen = screen; + function Range(body, options) { + var now = moment().hours(0).minutes(0).seconds(0).milliseconds(0); + this.start = now.clone().add(-3, 'days').valueOf(); // Number + this.end = now.clone().add(4, 'days').valueOf(); // Number - // calculate the distance from the point at the bottom to the camera - var transBottom = this._convertPointToTranslation(this.dataPoints[i].bottom); - this.dataPoints[i].dist = this.showPerspective ? transBottom.length() : -transBottom.z; - } + this.body = body; + this.deltaDifference = 0; + this.scaleOffset = 0; + this.startToFront = false; + this.endToFront = true; - // order the translated points by depth - var sortDepth = function (a, b) { - return b.dist - a.dist; + // default options + this.defaultOptions = { + start: null, + end: null, + direction: 'horizontal', // 'horizontal' or 'vertical' + moveable: true, + zoomable: true, + min: null, + max: null, + zoomMin: 10, // milliseconds + zoomMax: 1000 * 60 * 60 * 24 * 365 * 10000 // milliseconds }; - this.dataPoints.sort(sortDepth); - - // draw the datapoints as bars - var xWidth = this.xBarWidth / 2; - var yWidth = this.yBarWidth / 2; - for (i = 0; i < this.dataPoints.length; i++) { - var point = this.dataPoints[i]; - - // determine color - var hue, color, borderColor; - if (this.style === Graph3d.STYLE.BARCOLOR ) { - // calculate the color based on the value - hue = (1 - (point.point.value - this.valueMin) * this.scale.value) * 240; - color = this._hsv2rgb(hue, 1, 1); - borderColor = this._hsv2rgb(hue, 1, 0.8); - } - else if (this.style === Graph3d.STYLE.BARSIZE) { - color = this.colorDot; - borderColor = this.colorDotBorder; - } - else { - // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 - hue = (1 - (point.point.z - this.zMin) * this.scale.z / this.verticalRatio) * 240; - color = this._hsv2rgb(hue, 1, 1); - borderColor = this._hsv2rgb(hue, 1, 0.8); - } + this.options = util.extend({}, this.defaultOptions); - // calculate size for the bar - if (this.style === Graph3d.STYLE.BARSIZE) { - xWidth = (this.xBarWidth / 2) * ((point.point.value - this.valueMin) / (this.valueMax - this.valueMin) * 0.8 + 0.2); - yWidth = (this.yBarWidth / 2) * ((point.point.value - this.valueMin) / (this.valueMax - this.valueMin) * 0.8 + 0.2); - } + this.props = { + touch: {} + }; + this.animateTimer = null; - // calculate all corner points - var me = this; - var point3d = point.point; - var top = [ - {point: new Point3d(point3d.x - xWidth, point3d.y - yWidth, point3d.z)}, - {point: new Point3d(point3d.x + xWidth, point3d.y - yWidth, point3d.z)}, - {point: new Point3d(point3d.x + xWidth, point3d.y + yWidth, point3d.z)}, - {point: new Point3d(point3d.x - xWidth, point3d.y + yWidth, point3d.z)} - ]; - var bottom = [ - {point: new Point3d(point3d.x - xWidth, point3d.y - yWidth, this.zMin)}, - {point: new Point3d(point3d.x + xWidth, point3d.y - yWidth, this.zMin)}, - {point: new Point3d(point3d.x + xWidth, point3d.y + yWidth, this.zMin)}, - {point: new Point3d(point3d.x - xWidth, point3d.y + yWidth, this.zMin)} - ]; + // drag listeners for dragging + this.body.emitter.on('dragstart', this._onDragStart.bind(this)); + this.body.emitter.on('drag', this._onDrag.bind(this)); + this.body.emitter.on('dragend', this._onDragEnd.bind(this)); - // calculate screen location of the points - top.forEach(function (obj) { - obj.screen = me._convert3Dto2D(obj.point); - }); - bottom.forEach(function (obj) { - obj.screen = me._convert3Dto2D(obj.point); - }); + // ignore dragging when holding + this.body.emitter.on('hold', this._onHold.bind(this)); - // create five sides, calculate both corner points and center points - var surfaces = [ - {corners: top, center: Point3d.avg(bottom[0].point, bottom[2].point)}, - {corners: [top[0], top[1], bottom[1], bottom[0]], center: Point3d.avg(bottom[1].point, bottom[0].point)}, - {corners: [top[1], top[2], bottom[2], bottom[1]], center: Point3d.avg(bottom[2].point, bottom[1].point)}, - {corners: [top[2], top[3], bottom[3], bottom[2]], center: Point3d.avg(bottom[3].point, bottom[2].point)}, - {corners: [top[3], top[0], bottom[0], bottom[3]], center: Point3d.avg(bottom[0].point, bottom[3].point)} - ]; - point.surfaces = surfaces; + // mouse wheel for zooming + this.body.emitter.on('mousewheel', this._onMouseWheel.bind(this)); + this.body.emitter.on('DOMMouseScroll', this._onMouseWheel.bind(this)); // For FF - // calculate the distance of each of the surface centers to the camera - for (j = 0; j < surfaces.length; j++) { - surface = surfaces[j]; - var transCenter = this._convertPointToTranslation(surface.center); - surface.dist = this.showPerspective ? transCenter.length() : -transCenter.z; - // TODO: this dept calculation doesn't work 100% of the cases due to perspective, - // but the current solution is fast/simple and works in 99.9% of all cases - // the issue is visible in example 14, with graph.setCameraPosition({horizontal: 2.97, vertical: 0.5, distance: 0.9}) - } + // pinch to zoom + this.body.emitter.on('touch', this._onTouch.bind(this)); + this.body.emitter.on('pinch', this._onPinch.bind(this)); - // order the surfaces by their (translated) depth - surfaces.sort(function (a, b) { - var diff = b.dist - a.dist; - if (diff) return diff; + this.setOptions(options); + } - // if equal depth, sort the top surface last - if (a.corners === top) return 1; - if (b.corners === top) return -1; + Range.prototype = new Component(); - // both are equal - return 0; - }); + /** + * Set options for the range controller + * @param {Object} options Available options: + * {Number | Date | String} start Start date for the range + * {Number | Date | String} end End date for the range + * {Number} min Minimum value for start + * {Number} max Maximum value for end + * {Number} zoomMin Set a minimum value for + * (end - start). + * {Number} zoomMax Set a maximum value for + * (end - start). + * {Boolean} moveable Enable moving of the range + * by dragging. True by default + * {Boolean} zoomable Enable zooming of the range + * by pinching/scrolling. True by default + */ + Range.prototype.setOptions = function (options) { + if (options) { + // copy the options that we know + var fields = ['direction', 'min', 'max', 'zoomMin', 'zoomMax', 'moveable', 'zoomable', 'activate', 'hiddenDates']; + util.selectiveExtend(fields, this.options, options); - // draw the ordered surfaces - ctx.lineWidth = 1; - ctx.strokeStyle = borderColor; - ctx.fillStyle = color; - // NOTE: we start at j=2 instead of j=0 as we don't need to draw the two surfaces at the backside - for (j = 2; j < surfaces.length; j++) { - surface = surfaces[j]; - corners = surface.corners; - ctx.beginPath(); - ctx.moveTo(corners[3].screen.x, corners[3].screen.y); - ctx.lineTo(corners[0].screen.x, corners[0].screen.y); - ctx.lineTo(corners[1].screen.x, corners[1].screen.y); - ctx.lineTo(corners[2].screen.x, corners[2].screen.y); - ctx.lineTo(corners[3].screen.x, corners[3].screen.y); - ctx.fill(); - ctx.stroke(); + if ('start' in options || 'end' in options) { + // apply a new range. both start and end are optional + this.setRange(options.start, options.end); } } }; - /** - * Draw a line through all datapoints. - * This function can be used when the style is 'line' + * Test whether direction has a valid value + * @param {String} direction 'horizontal' or 'vertical' */ - Graph3d.prototype._redrawDataLine = function() { - var canvas = this.frame.canvas, - ctx = canvas.getContext('2d'), - point, i; + function validateDirection (direction) { + if (direction != 'horizontal' && direction != 'vertical') { + throw new TypeError('Unknown direction "' + direction + '". ' + + 'Choose "horizontal" or "vertical".'); + } + } - if (this.dataPoints === undefined || this.dataPoints.length <= 0) - return; // TODO: throw exception? + /** + * Set a new start and end range + * @param {Date | Number | String} [start] + * @param {Date | Number | String} [end] + * @param {boolean | number} [animate=false] If true, the range is animated + * smoothly to the new window. + * If animate is a number, the + * number is taken as duration + * Default duration is 500 ms. + * @param {Boolean} [byUser=false] + * + */ + Range.prototype.setRange = function(start, end, animate, byUser) { + if (byUser !== true) { + byUser = false; + } + var _start = start != undefined ? util.convert(start, 'Date').valueOf() : null; + var _end = end != undefined ? util.convert(end, 'Date').valueOf() : null; + this._cancelAnimation(); - // calculate the translations of all points - for (i = 0; i < this.dataPoints.length; i++) { - var trans = this._convertPointToTranslation(this.dataPoints[i].point); - var screen = this._convertTranslationToScreen(trans); + if (animate) { + var me = this; + var initStart = this.start; + var initEnd = this.end; + var duration = typeof animate === 'number' ? animate : 500; + var initTime = new Date().valueOf(); + var anyChanged = false; - this.dataPoints[i].trans = trans; - this.dataPoints[i].screen = screen; - } + var next = function () { + if (!me.props.touch.dragging) { + var now = new Date().valueOf(); + var time = now - initTime; + var done = time > duration; + var s = (done || _start === null) ? _start : util.easeInOutQuad(time, initStart, _start, duration); + var e = (done || _end === null) ? _end : util.easeInOutQuad(time, initEnd, _end, duration); - // start the line - if (this.dataPoints.length > 0) { - point = this.dataPoints[0]; + changed = me._applyRange(s, e); + DateUtil.updateHiddenDates(me.body, me.options.hiddenDates); + anyChanged = anyChanged || changed; + if (changed) { + me.body.emitter.emit('rangechange', {start: new Date(me.start), end: new Date(me.end), byUser:byUser}); + } - ctx.lineWidth = 1; // TODO: make customizable - ctx.strokeStyle = 'blue'; // TODO: make customizable - ctx.beginPath(); - ctx.moveTo(point.screen.x, point.screen.y); - } + if (done) { + if (anyChanged) { + me.body.emitter.emit('rangechanged', {start: new Date(me.start), end: new Date(me.end), byUser:byUser}); + } + } + else { + // animate with as high as possible frame rate, leave 20 ms in between + // each to prevent the browser from blocking + me.animateTimer = setTimeout(next, 20); + } + } + } - // draw the datapoints as colored circles - for (i = 1; i < this.dataPoints.length; i++) { - point = this.dataPoints[i]; - ctx.lineTo(point.screen.x, point.screen.y); + return next(); } - - // finish the line - if (this.dataPoints.length > 0) { - ctx.stroke(); + else { + var changed = this._applyRange(_start, _end); + DateUtil.updateHiddenDates(this.body, this.options.hiddenDates); + if (changed) { + var params = {start: new Date(this.start), end: new Date(this.end), byUser:byUser}; + this.body.emitter.emit('rangechange', params); + this.body.emitter.emit('rangechanged', params); + } } }; /** - * Start a moving operation inside the provided parent element - * @param {Event} event The event that occurred (required for - * retrieving the mouse position) + * Stop an animation + * @private */ - Graph3d.prototype._onMouseDown = function(event) { - event = event || window.event; - - // check if mouse is still down (may be up when focus is lost for example - // in an iframe) - if (this.leftButtonDown) { - this._onMouseUp(event); + Range.prototype._cancelAnimation = function () { + if (this.animateTimer) { + clearTimeout(this.animateTimer); + this.animateTimer = null; } - - // only react on left mouse button down - this.leftButtonDown = event.which ? (event.which === 1) : (event.button === 1); - if (!this.leftButtonDown && !this.touchDown) return; - - // get mouse position (different code for IE and all other browsers) - this.startMouseX = getMouseX(event); - this.startMouseY = getMouseY(event); - - this.startStart = new Date(this.start); - this.startEnd = new Date(this.end); - this.startArmRotation = this.camera.getArmRotation(); - - this.frame.style.cursor = 'move'; - - // add event listeners to handle moving the contents - // we store the function onmousemove and onmouseup in the graph, so we can - // remove the eventlisteners lateron in the function mouseUp() - var me = this; - this.onmousemove = function (event) {me._onMouseMove(event);}; - this.onmouseup = function (event) {me._onMouseUp(event);}; - util.addEventListener(document, 'mousemove', me.onmousemove); - util.addEventListener(document, 'mouseup', me.onmouseup); - util.preventDefault(event); }; - /** - * Perform moving operating. - * This function activated from within the funcion Graph.mouseDown(). - * @param {Event} event Well, eehh, the event + * Set a new start and end range. This method is the same as setRange, but + * does not trigger a range change and range changed event, and it returns + * true when the range is changed + * @param {Number} [start] + * @param {Number} [end] + * @return {Boolean} changed + * @private */ - Graph3d.prototype._onMouseMove = function (event) { - event = event || window.event; + Range.prototype._applyRange = function(start, end) { + var newStart = (start != null) ? util.convert(start, 'Date').valueOf() : this.start, + newEnd = (end != null) ? util.convert(end, 'Date').valueOf() : this.end, + max = (this.options.max != null) ? util.convert(this.options.max, 'Date').valueOf() : null, + min = (this.options.min != null) ? util.convert(this.options.min, 'Date').valueOf() : null, + diff; - // calculate change in mouse position - var diffX = parseFloat(getMouseX(event)) - this.startMouseX; - var diffY = parseFloat(getMouseY(event)) - this.startMouseY; + // check for valid number + if (isNaN(newStart) || newStart === null) { + throw new Error('Invalid start "' + start + '"'); + } + if (isNaN(newEnd) || newEnd === null) { + throw new Error('Invalid end "' + end + '"'); + } - var horizontalNew = this.startArmRotation.horizontal + diffX / 200; - var verticalNew = this.startArmRotation.vertical + diffY / 200; + // prevent start < end + if (newEnd < newStart) { + newEnd = newStart; + } - var snapAngle = 4; // degrees - var snapValue = Math.sin(snapAngle / 360 * 2 * Math.PI); + // prevent start < min + if (min !== null) { + if (newStart < min) { + diff = (min - newStart); + newStart += diff; + newEnd += diff; - // snap horizontally to nice angles at 0pi, 0.5pi, 1pi, 1.5pi, etc... - // the -0.001 is to take care that the vertical axis is always drawn at the left front corner - if (Math.abs(Math.sin(horizontalNew)) < snapValue) { - horizontalNew = Math.round((horizontalNew / Math.PI)) * Math.PI - 0.001; + // prevent end > max + if (max != null) { + if (newEnd > max) { + newEnd = max; + } + } + } } - if (Math.abs(Math.cos(horizontalNew)) < snapValue) { - horizontalNew = (Math.round((horizontalNew/ Math.PI - 0.5)) + 0.5) * Math.PI - 0.001; + + // prevent end > max + if (max !== null) { + if (newEnd > max) { + diff = (newEnd - max); + newStart -= diff; + newEnd -= diff; + + // prevent start < min + if (min != null) { + if (newStart < min) { + newStart = min; + } + } + } } - // snap vertically to nice angles - if (Math.abs(Math.sin(verticalNew)) < snapValue) { - verticalNew = Math.round((verticalNew / Math.PI)) * Math.PI; + // prevent (end-start) < zoomMin + if (this.options.zoomMin !== null) { + var zoomMin = parseFloat(this.options.zoomMin); + if (zoomMin < 0) { + zoomMin = 0; + } + if ((newEnd - newStart) < zoomMin) { + if ((this.end - this.start) === zoomMin) { + // ignore this action, we are already zoomed to the minimum + newStart = this.start; + newEnd = this.end; + } + else { + // zoom to the minimum + diff = (zoomMin - (newEnd - newStart)); + newStart -= diff / 2; + newEnd += diff / 2; + } + } } - if (Math.abs(Math.cos(verticalNew)) < snapValue) { - verticalNew = (Math.round((verticalNew/ Math.PI - 0.5)) + 0.5) * Math.PI; + + // prevent (end-start) > zoomMax + if (this.options.zoomMax !== null) { + var zoomMax = parseFloat(this.options.zoomMax); + if (zoomMax < 0) { + zoomMax = 0; + } + if ((newEnd - newStart) > zoomMax) { + if ((this.end - this.start) === zoomMax) { + // ignore this action, we are already zoomed to the maximum + newStart = this.start; + newEnd = this.end; + } + else { + // zoom to the maximum + diff = ((newEnd - newStart) - zoomMax); + newStart += diff / 2; + newEnd -= diff / 2; + } + } } - this.camera.setArmRotation(horizontalNew, verticalNew); - this.redraw(); + var changed = (this.start != newStart || this.end != newEnd); - // fire a cameraPositionChange event - var parameters = this.getCameraPosition(); - this.emit('cameraPositionChange', parameters); + // if the new range does NOT overlap with the old range, emit checkRangedItems to avoid not showing ranged items (ranged meaning has end time, not neccesarily of type Range) + if (!((newStart >= this.start && newStart <= this.end) || (newEnd >= this.start && newEnd <= this.end)) && + !((this.start >= newStart && this.start <= newEnd) || (this.end >= newStart && this.end <= newEnd) )) { + this.body.emitter.emit('checkRangedItems'); + } - util.preventDefault(event); + this.start = newStart; + this.end = newEnd; + return changed; }; - /** - * Stop moving operating. - * This function activated from within the funcion Graph.mouseDown(). - * @param {event} event The event + * Retrieve the current range. + * @return {Object} An object with start and end properties */ - Graph3d.prototype._onMouseUp = function (event) { - this.frame.style.cursor = 'auto'; - this.leftButtonDown = false; - - // remove event listeners here - util.removeEventListener(document, 'mousemove', this.onmousemove); - util.removeEventListener(document, 'mouseup', this.onmouseup); - util.preventDefault(event); + Range.prototype.getRange = function() { + return { + start: this.start, + end: this.end + }; }; /** - * After having moved the mouse, a tooltip should pop up when the mouse is resting on a data point - * @param {Event} event A mouse move event + * Calculate the conversion offset and scale for current range, based on + * the provided width + * @param {Number} width + * @returns {{offset: number, scale: number}} conversion */ - Graph3d.prototype._onTooltip = function (event) { - var delay = 300; // ms - var boundingRect = this.frame.getBoundingClientRect(); - var mouseX = getMouseX(event) - boundingRect.left; - var mouseY = getMouseY(event) - boundingRect.top; - - if (!this.showTooltip) { - return; - } - - if (this.tooltipTimeout) { - clearTimeout(this.tooltipTimeout); - } + Range.prototype.conversion = function (width, totalHidden) { + return Range.conversion(this.start, this.end, width, totalHidden); + }; - // (delayed) display of a tooltip only if no mouse button is down - if (this.leftButtonDown) { - this._hideTooltip(); - return; + /** + * Static method to calculate the conversion offset and scale for a range, + * based on the provided start, end, and width + * @param {Number} start + * @param {Number} end + * @param {Number} width + * @returns {{offset: number, scale: number}} conversion + */ + Range.conversion = function (start, end, width, totalHidden) { + if (totalHidden === undefined) { + totalHidden = 0; } - - if (this.tooltip && this.tooltip.dataPoint) { - // tooltip is currently visible - var dataPoint = this._dataPointFromXY(mouseX, mouseY); - if (dataPoint !== this.tooltip.dataPoint) { - // datapoint changed - if (dataPoint) { - this._showTooltip(dataPoint); - } - else { - this._hideTooltip(); - } + if (width != 0 && (end - start != 0)) { + return { + offset: start, + scale: width / (end - start - totalHidden) } } else { - // tooltip is currently not visible - var me = this; - this.tooltipTimeout = setTimeout(function () { - me.tooltipTimeout = null; - - // show a tooltip if we have a data point - var dataPoint = me._dataPointFromXY(mouseX, mouseY); - if (dataPoint) { - me._showTooltip(dataPoint); - } - }, delay); + return { + offset: 0, + scale: 1 + }; } }; /** - * Event handler for touchstart event on mobile devices + * Start dragging horizontally or vertically + * @param {Event} event + * @private */ - Graph3d.prototype._onTouchStart = function(event) { - this.touchDown = true; + Range.prototype._onDragStart = function(event) { + this.deltaDifference = 0; + this.previousDelta = 0; + // only allow dragging when configured as movable + if (!this.options.moveable) return; - var me = this; - this.ontouchmove = function (event) {me._onTouchMove(event);}; - this.ontouchend = function (event) {me._onTouchEnd(event);}; - util.addEventListener(document, 'touchmove', me.ontouchmove); - util.addEventListener(document, 'touchend', me.ontouchend); + // refuse to drag when we where pinching to prevent the timeline make a jump + // when releasing the fingers in opposite order from the touch screen + if (!this.props.touch.allowDragging) return; - this._onMouseDown(event); + this.props.touch.start = this.start; + this.props.touch.end = this.end; + this.props.touch.dragging = true; + + if (this.body.dom.root) { + this.body.dom.root.style.cursor = 'move'; + } }; /** - * Event handler for touchmove event on mobile devices + * Perform dragging operation + * @param {Event} event + * @private */ - Graph3d.prototype._onTouchMove = function(event) { - this._onMouseMove(event); + Range.prototype._onDrag = function (event) { + // only allow dragging when configured as movable + if (!this.options.moveable) return; + // refuse to drag when we where pinching to prevent the timeline make a jump + // when releasing the fingers in opposite order from the touch screen + if (!this.props.touch.allowDragging) return; + + var direction = this.options.direction; + validateDirection(direction); + + var delta = (direction == 'horizontal') ? event.gesture.deltaX : event.gesture.deltaY; + delta -= this.deltaDifference; + var interval = (this.props.touch.end - this.props.touch.start); + + // normalize dragging speed if cutout is in between. + var duration = DateUtil.getHiddenDurationBetween(this.body.hiddenDates, this.start, this.end); + interval -= duration; + + var width = (direction == 'horizontal') ? this.body.domProps.center.width : this.body.domProps.center.height; + var diffRange = -delta / width * interval; + var newStart = this.props.touch.start + diffRange; + var newEnd = this.props.touch.end + diffRange; + + + // snapping times away from hidden zones + var safeStart = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newStart, this.previousDelta-delta, true); + var safeEnd = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newEnd, this.previousDelta-delta, true); + if (safeStart != newStart || safeEnd != newEnd) { + this.deltaDifference += delta; + this.props.touch.start = safeStart; + this.props.touch.end = safeEnd; + this._onDrag(event); + return; + } + + this.previousDelta = delta; + this._applyRange(newStart, newEnd); + + // fire a rangechange event + this.body.emitter.emit('rangechange', { + start: new Date(this.start), + end: new Date(this.end), + byUser: true + }); }; /** - * Event handler for touchend event on mobile devices + * Stop dragging operation + * @param {event} event + * @private */ - Graph3d.prototype._onTouchEnd = function(event) { - this.touchDown = false; + Range.prototype._onDragEnd = function (event) { + // only allow dragging when configured as movable + if (!this.options.moveable) return; - util.removeEventListener(document, 'touchmove', this.ontouchmove); - util.removeEventListener(document, 'touchend', this.ontouchend); + // refuse to drag when we where pinching to prevent the timeline make a jump + // when releasing the fingers in opposite order from the touch screen + if (!this.props.touch.allowDragging) return; - this._onMouseUp(event); - }; + this.props.touch.dragging = false; + if (this.body.dom.root) { + this.body.dom.root.style.cursor = 'auto'; + } + // fire a rangechanged event + this.body.emitter.emit('rangechanged', { + start: new Date(this.start), + end: new Date(this.end), + byUser: true + }); + }; /** - * Event handler for mouse wheel event, used to zoom the graph + * Event handler for mouse wheel event, used to zoom * Code from http://adomas.org/javascript-mouse-wheel/ - * @param {event} event The event + * @param {Event} event + * @private */ - Graph3d.prototype._onWheel = function(event) { - if (!event) /* For IE. */ - event = window.event; + Range.prototype._onMouseWheel = function(event) { + // only allow zooming when configured as zoomable and moveable + if (!(this.options.zoomable && this.options.moveable)) return; // retrieve delta var delta = 0; if (event.wheelDelta) { /* IE/Opera. */ - delta = event.wheelDelta/120; + delta = event.wheelDelta / 120; } else if (event.detail) { /* Mozilla case. */ // In Mozilla, sign of delta is different than in IE. // Also, delta is multiple of 3. - delta = -event.detail/3; + delta = -event.detail / 3; } // If delta is nonzero, handle it. // Basically, delta is now positive if wheel was scrolled up, // and negative, if wheel was scrolled down. if (delta) { - var oldLength = this.camera.getArmLength(); - var newLength = oldLength * (1 - delta / 10); + // perform the zoom action. Delta is normally 1 or -1 - this.camera.setArmLength(newLength); - this.redraw(); + // adjust a negative delta such that zooming in with delta 0.1 + // equals zooming out with a delta -0.1 + var scale; + if (delta < 0) { + scale = 1 - (delta / 5); + } + else { + scale = 1 / (1 + (delta / 5)) ; + } - this._hideTooltip(); - } + // calculate center, the date to zoom around + var gesture = hammerUtil.fakeGesture(this, event), + pointer = getPointer(gesture.center, this.body.dom.center), + pointerDate = this._pointerToDate(pointer); - // fire a cameraPositionChange event - var parameters = this.getCameraPosition(); - this.emit('cameraPositionChange', parameters); + this.zoom(scale, pointerDate, delta); + } - // Prevent default actions caused by mouse wheel. - // That might be ugly, but we handle scrolls somehow - // anyway, so don't bother here.. - util.preventDefault(event); + // Prevent default actions caused by mouse wheel + // (else the page and timeline both zoom and scroll) + event.preventDefault(); }; /** - * Test whether a point lies inside given 2D triangle - * @param {Point2d} point - * @param {Point2d[]} triangle - * @return {boolean} Returns true if given point lies inside or on the edge of the triangle + * Start of a touch gesture * @private */ - Graph3d.prototype._insideTriangle = function (point, triangle) { - var a = triangle[0], - b = triangle[1], - c = triangle[2]; - - function sign (x) { - return x > 0 ? 1 : x < 0 ? -1 : 0; - } - - var as = sign((b.x - a.x) * (point.y - a.y) - (b.y - a.y) * (point.x - a.x)); - var bs = sign((c.x - b.x) * (point.y - b.y) - (c.y - b.y) * (point.x - b.x)); - var cs = sign((a.x - c.x) * (point.y - c.y) - (a.y - c.y) * (point.x - c.x)); - - // each of the three signs must be either equal to each other or zero - return (as == 0 || bs == 0 || as == bs) && - (bs == 0 || cs == 0 || bs == cs) && - (as == 0 || cs == 0 || as == cs); + Range.prototype._onTouch = function (event) { + this.props.touch.start = this.start; + this.props.touch.end = this.end; + this.props.touch.allowDragging = true; + this.props.touch.center = null; + this.scaleOffset = 0; + this.deltaDifference = 0; }; /** - * Find a data point close to given screen position (x, y) - * @param {Number} x - * @param {Number} y - * @return {Object | null} The closest data point or null if not close to any data point + * On start of a hold gesture * @private */ - Graph3d.prototype._dataPointFromXY = function (x, y) { - var i, - distMax = 100, // px - dataPoint = null, - closestDataPoint = null, - closestDist = null, - center = new Point2d(x, y); - - if (this.style === Graph3d.STYLE.BAR || - this.style === Graph3d.STYLE.BARCOLOR || - this.style === Graph3d.STYLE.BARSIZE) { - // the data points are ordered from far away to closest - for (i = this.dataPoints.length - 1; i >= 0; i--) { - dataPoint = this.dataPoints[i]; - var surfaces = dataPoint.surfaces; - if (surfaces) { - for (var s = surfaces.length - 1; s >= 0; s--) { - // split each surface in two triangles, and see if the center point is inside one of these - var surface = surfaces[s]; - var corners = surface.corners; - var triangle1 = [corners[0].screen, corners[1].screen, corners[2].screen]; - var triangle2 = [corners[2].screen, corners[3].screen, corners[0].screen]; - if (this._insideTriangle(center, triangle1) || - this._insideTriangle(center, triangle2)) { - // return immediately at the first hit - return dataPoint; - } - } - } - } - } - else { - // find the closest data point, using distance to the center of the point on 2d screen - for (i = 0; i < this.dataPoints.length; i++) { - dataPoint = this.dataPoints[i]; - var point = dataPoint.screen; - if (point) { - var distX = Math.abs(x - point.x); - var distY = Math.abs(y - point.y); - var dist = Math.sqrt(distX * distX + distY * distY); - - if ((closestDist === null || dist < closestDist) && dist < distMax) { - closestDist = dist; - closestDataPoint = dataPoint; - } - } - } - } - - - return closestDataPoint; + Range.prototype._onHold = function () { + this.props.touch.allowDragging = false; }; /** - * Display a tooltip for given data point - * @param {Object} dataPoint + * Handle pinch event + * @param {Event} event * @private */ - Graph3d.prototype._showTooltip = function (dataPoint) { - var content, line, dot; - - if (!this.tooltip) { - content = document.createElement('div'); - content.style.position = 'absolute'; - content.style.padding = '10px'; - content.style.border = '1px solid #4d4d4d'; - content.style.color = '#1a1a1a'; - content.style.background = 'rgba(255,255,255,0.7)'; - content.style.borderRadius = '2px'; - content.style.boxShadow = '5px 5px 10px rgba(128,128,128,0.5)'; - - line = document.createElement('div'); - line.style.position = 'absolute'; - line.style.height = '40px'; - line.style.width = '0'; - line.style.borderLeft = '1px solid #4d4d4d'; - - dot = document.createElement('div'); - dot.style.position = 'absolute'; - dot.style.height = '0'; - dot.style.width = '0'; - dot.style.border = '5px solid #4d4d4d'; - dot.style.borderRadius = '5px'; + Range.prototype._onPinch = function (event) { + // only allow zooming when configured as zoomable and moveable + if (!(this.options.zoomable && this.options.moveable)) return; - this.tooltip = { - dataPoint: null, - dom: { - content: content, - line: line, - dot: dot - } - }; - } - else { - content = this.tooltip.dom.content; - line = this.tooltip.dom.line; - dot = this.tooltip.dom.dot; - } + this.props.touch.allowDragging = false; - this._hideTooltip(); + if (event.gesture.touches.length > 1) { + if (!this.props.touch.center) { + this.props.touch.center = getPointer(event.gesture.center, this.body.dom.center); + } - this.tooltip.dataPoint = dataPoint; - if (typeof this.showTooltip === 'function') { - content.innerHTML = this.showTooltip(dataPoint.point); - } - else { - content.innerHTML = '' + - '' + - '' + - '' + - '
x:' + dataPoint.point.x + '
y:' + dataPoint.point.y + '
z:' + dataPoint.point.z + '
'; - } + var scale = 1 / (event.gesture.scale + this.scaleOffset); + var centerDate = this._pointerToDate(this.props.touch.center); - content.style.left = '0'; - content.style.top = '0'; - this.frame.appendChild(content); - this.frame.appendChild(line); - this.frame.appendChild(dot); + var hiddenDuration = DateUtil.getHiddenDurationBetween(this.body.hiddenDates, this.start, this.end); + var hiddenDurationBefore = DateUtil.getHiddenDurationBefore(this.body.hiddenDates, this, centerDate); + var hiddenDurationAfter = hiddenDuration - hiddenDurationBefore; - // calculate sizes - var contentWidth = content.offsetWidth; - var contentHeight = content.offsetHeight; - var lineHeight = line.offsetHeight; - var dotWidth = dot.offsetWidth; - var dotHeight = dot.offsetHeight; + // calculate new start and end + var newStart = (centerDate - hiddenDurationBefore) + (this.props.touch.start - (centerDate - hiddenDurationBefore)) * scale; + var newEnd = (centerDate + hiddenDurationAfter) + (this.props.touch.end - (centerDate + hiddenDurationAfter)) * scale; - var left = dataPoint.screen.x - contentWidth / 2; - left = Math.min(Math.max(left, 10), this.frame.clientWidth - 10 - contentWidth); + // snapping times away from hidden zones + this.startToFront = 1 - scale > 0 ? false : true; // used to do the right autocorrection with periodic hidden times + this.endToFront = scale - 1 > 0 ? false : true; // used to do the right autocorrection with periodic hidden times - line.style.left = dataPoint.screen.x + 'px'; - line.style.top = (dataPoint.screen.y - lineHeight) + 'px'; - content.style.left = left + 'px'; - content.style.top = (dataPoint.screen.y - lineHeight - contentHeight) + 'px'; - dot.style.left = (dataPoint.screen.x - dotWidth / 2) + 'px'; - dot.style.top = (dataPoint.screen.y - dotHeight / 2) + 'px'; + var safeStart = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newStart, 1 - scale, true); + var safeEnd = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newEnd, scale - 1, true); + if (safeStart != newStart || safeEnd != newEnd) { + this.props.touch.start = safeStart; + this.props.touch.end = safeEnd; + this.scaleOffset = 1 - event.gesture.scale; + newStart = safeStart; + newEnd = safeEnd; + } + + this.setRange(newStart, newEnd, false, true); + + this.startToFront = false; // revert to default + this.endToFront = true; // revert to default + } }; /** - * Hide the tooltip when displayed + * Helper function to calculate the center date for zooming + * @param {{x: Number, y: Number}} pointer + * @return {number} date * @private */ - Graph3d.prototype._hideTooltip = function () { - if (this.tooltip) { - this.tooltip.dataPoint = null; + Range.prototype._pointerToDate = function (pointer) { + var conversion; + var direction = this.options.direction; - for (var prop in this.tooltip.dom) { - if (this.tooltip.dom.hasOwnProperty(prop)) { - var elem = this.tooltip.dom[prop]; - if (elem && elem.parentNode) { - elem.parentNode.removeChild(elem); - } - } - } + validateDirection(direction); + + if (direction == 'horizontal') { + return this.body.util.toTime(pointer.x).valueOf(); + } + else { + var height = this.body.domProps.center.height; + conversion = this.conversion(height); + return pointer.y / conversion.scale + conversion.offset; } }; - /**--------------------------------------------------------------------------**/ - - /** - * Get the horizontal mouse position from a mouse event - * @param {Event} event - * @return {Number} mouse x + * Get the pointer location relative to the location of the dom element + * @param {{pageX: Number, pageY: Number}} touch + * @param {Element} element HTML DOM element + * @return {{x: Number, y: Number}} pointer + * @private */ - function getMouseX (event) { - if ('clientX' in event) return event.clientX; - return event.targetTouches[0] && event.targetTouches[0].clientX || 0; + function getPointer (touch, element) { + return { + x: touch.pageX - util.getAbsoluteLeft(element), + y: touch.pageY - util.getAbsoluteTop(element) + }; } /** - * Get the vertical mouse position from a mouse event - * @param {Event} event - * @return {Number} mouse y + * Zoom the range the given scale in or out. Start and end date will + * be adjusted, and the timeline will be redrawn. You can optionally give a + * date around which to zoom. + * For example, try scale = 0.9 or 1.1 + * @param {Number} scale Scaling factor. Values above 1 will zoom out, + * values below 1 will zoom in. + * @param {Number} [center] Value representing a date around which will + * be zoomed. */ - function getMouseY (event) { - if ('clientY' in event) return event.clientY; - return event.targetTouches[0] && event.targetTouches[0].clientY || 0; - } + Range.prototype.zoom = function(scale, center, delta) { + // if centerDate is not provided, take it half between start Date and end Date + if (center == null) { + center = (this.start + this.end) / 2; + } - module.exports = Graph3d; + var hiddenDuration = DateUtil.getHiddenDurationBetween(this.body.hiddenDates, this.start, this.end); + var hiddenDurationBefore = DateUtil.getHiddenDurationBefore(this.body.hiddenDates, this, center); + var hiddenDurationAfter = hiddenDuration - hiddenDurationBefore; + // calculate new start and end + var newStart = (center-hiddenDurationBefore) + (this.start - (center-hiddenDurationBefore)) * scale; + var newEnd = (center+hiddenDurationAfter) + (this.end - (center+hiddenDurationAfter)) * scale; -/***/ }, -/* 11 */ -/***/ function(module, exports, __webpack_require__) { + // snapping times away from hidden zones + this.startToFront = delta > 0 ? false : true; // used to do the right autocorrection with periodic hidden times + this.endToFront = -delta > 0 ? false : true; // used to do the right autocorrection with periodic hidden times + var safeStart = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newStart, delta, true); + var safeEnd = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newEnd, -delta, true); + if (safeStart != newStart || safeEnd != newEnd) { + newStart = safeStart; + newEnd = safeEnd; + } + + this.setRange(newStart, newEnd, false, true); + + this.startToFront = false; // revert to default + this.endToFront = true; // revert to default + }; - - /** - * Expose `Emitter`. - */ - module.exports = Emitter; /** - * Initialize a new `Emitter`. - * - * @api public + * Move the range with a given delta to the left or right. Start and end + * value will be adjusted. For example, try delta = 0.1 or -0.1 + * @param {Number} delta Moving amount. Positive value will move right, + * negative value will move left */ + Range.prototype.move = function(delta) { + // zoom start Date and end Date relative to the centerDate + var diff = (this.end - this.start); - function Emitter(obj) { - if (obj) return mixin(obj); + // apply new values + var newStart = this.start + diff * delta; + var newEnd = this.end + diff * delta; + + // TODO: reckon with min and max range + + this.start = newStart; + this.end = newEnd; }; /** - * Mixin the emitter properties. - * - * @param {Object} obj - * @return {Object} - * @api private + * Move the range to a new center point + * @param {Number} moveTo New center point of the range */ + Range.prototype.moveTo = function(moveTo) { + var center = (this.start + this.end) / 2; - function mixin(obj) { - for (var key in Emitter.prototype) { - obj[key] = Emitter.prototype[key]; - } - return obj; - } + var diff = center - moveTo; - /** - * Listen on the given `event` with `fn`. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ + // calculate new start and end + var newStart = this.start - diff; + var newEnd = this.end - diff; - Emitter.prototype.on = - Emitter.prototype.addEventListener = function(event, fn){ - this._callbacks = this._callbacks || {}; - (this._callbacks[event] = this._callbacks[event] || []) - .push(fn); - return this; + this.setRange(newStart, newEnd); }; - /** - * Adds an `event` listener that will be invoked a single - * time then automatically removed. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ + module.exports = Range; - Emitter.prototype.once = function(event, fn){ - var self = this; - this._callbacks = this._callbacks || {}; - function on() { - self.off(event, on); - fn.apply(this, arguments); - } +/***/ }, +/* 18 */ +/***/ function(module, exports, __webpack_require__) { - on.fn = fn; - this.on(event, on); - return this; + // Utility functions for ordering and stacking of items + var EPSILON = 0.001; // used when checking collisions, to prevent round-off errors + + /** + * Order items by their start data + * @param {Item[]} items + */ + exports.orderByStart = function(items) { + items.sort(function (a, b) { + return a.data.start - b.data.start; + }); }; /** - * Remove the given callback for `event` or all - * registered callbacks. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public + * Order items by their end date. If they have no end date, their start date + * is used. + * @param {Item[]} items */ + exports.orderByEnd = function(items) { + items.sort(function (a, b) { + var aTime = ('end' in a.data) ? a.data.end : a.data.start, + bTime = ('end' in b.data) ? b.data.end : b.data.start; - Emitter.prototype.off = - Emitter.prototype.removeListener = - Emitter.prototype.removeAllListeners = - Emitter.prototype.removeEventListener = function(event, fn){ - this._callbacks = this._callbacks || {}; + return aTime - bTime; + }); + }; - // all - if (0 == arguments.length) { - this._callbacks = {}; - return this; + /** + * Adjust vertical positions of the items such that they don't overlap each + * other. + * @param {Item[]} items + * All visible items + * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin + * Margins between items and between items and the axis. + * @param {boolean} [force=false] + * If true, all items will be repositioned. If false (default), only + * items having a top===null will be re-stacked + */ + exports.stack = function(items, margin, force) { + var i, iMax; + + if (force) { + // reset top position of all items + for (i = 0, iMax = items.length; i < iMax; i++) { + items[i].top = null; + } } - // specific event - var callbacks = this._callbacks[event]; - if (!callbacks) return this; + // calculate new, non-overlapping positions + for (i = 0, iMax = items.length; i < iMax; i++) { + var item = items[i]; + if (item.stack && item.top === null) { + // initialize top position + item.top = margin.axis; - // remove all handlers - if (1 == arguments.length) { - delete this._callbacks[event]; - return this; - } + do { + // TODO: optimize checking for overlap. when there is a gap without items, + // you only need to check for items from the next item on, not from zero + var collidingItem = null; + for (var j = 0, jj = items.length; j < jj; j++) { + var other = items[j]; + if (other.top !== null && other !== item && other.stack && exports.collision(item, other, margin.item)) { + collidingItem = other; + break; + } + } - // remove specific handler - var cb; - for (var i = 0; i < callbacks.length; i++) { - cb = callbacks[i]; - if (cb === fn || cb.fn === fn) { - callbacks.splice(i, 1); - break; + if (collidingItem != null) { + // There is a collision. Reposition the items above the colliding element + item.top = collidingItem.top + collidingItem.height + margin.item.vertical; + } + } while (collidingItem); } } - return this; }; + /** - * Emit `event` with the given args. - * - * @param {String} event - * @param {Mixed} ... - * @return {Emitter} + * Adjust vertical positions of the items without stacking them + * @param {Item[]} items + * All visible items + * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin + * Margins between items and between items and the axis. */ + exports.nostack = function(items, margin, subgroups) { + var i, iMax, newTop; - Emitter.prototype.emit = function(event){ - this._callbacks = this._callbacks || {}; - var args = [].slice.call(arguments, 1) - , callbacks = this._callbacks[event]; - - if (callbacks) { - callbacks = callbacks.slice(0); - for (var i = 0, len = callbacks.length; i < len; ++i) { - callbacks[i].apply(this, args); + // reset top position of all items + for (i = 0, iMax = items.length; i < iMax; i++) { + if (items[i].data.subgroup !== undefined) { + newTop = margin.axis; + for (var subgroup in subgroups) { + if (subgroups.hasOwnProperty(subgroup)) { + if (subgroups[subgroup].visible == true && subgroups[subgroup].index < subgroups[items[i].data.subgroup].index) { + newTop += subgroups[subgroup].height + margin.item.vertical; + } + } + } + items[i].top = newTop; + } + else { + items[i].top = margin.axis; } } - - return this; }; /** - * Return array of callbacks for `event`. - * - * @param {String} event - * @return {Array} - * @api public + * Test if the two provided items collide + * The items must have parameters left, width, top, and height. + * @param {Item} a The first item + * @param {Item} b The second item + * @param {{horizontal: number, vertical: number}} margin + * An object containing a horizontal and vertical + * minimum required margin. + * @return {boolean} true if a and b collide, else false */ - - Emitter.prototype.listeners = function(event){ - this._callbacks = this._callbacks || {}; - return this._callbacks[event] || []; + exports.collision = function(a, b, margin) { + return ((a.left - margin.horizontal + EPSILON) < (b.left + b.width) && + (a.left + a.width + margin.horizontal - EPSILON) > b.left && + (a.top - margin.vertical + EPSILON) < (b.top + b.height) && + (a.top + a.height + margin.vertical - EPSILON) > b.top); }; + +/***/ }, +/* 19 */ +/***/ function(module, exports, __webpack_require__) { + + var moment = __webpack_require__(44); + var DateUtil = __webpack_require__(15); + var util = __webpack_require__(1); + /** - * Check if this emitter has `event` handlers. + * @constructor TimeStep + * The class TimeStep is an iterator for dates. You provide a start date and an + * end date. The class itself determines the best scale (step size) based on the + * provided start Date, end Date, and minimumStep. * - * @param {String} event - * @return {Boolean} - * @api public + * If minimumStep is provided, the step size is chosen as close as possible + * to the minimumStep but larger than minimumStep. If minimumStep is not + * provided, the scale is set to 1 DAY. + * The minimumStep should correspond with the onscreen size of about 6 characters + * + * Alternatively, you can set a scale by hand. + * After creation, you can initialize the class by executing first(). Then you + * can iterate from the start date to the end date via next(). You can check if + * the end date is reached with the function hasNext(). After each step, you can + * retrieve the current date via getCurrent(). + * The TimeStep has scales ranging from milliseconds, seconds, minutes, hours, + * days, to years. + * + * Version: 1.2 + * + * @param {Date} [start] The start date, for example new Date(2010, 9, 21) + * or new Date(2010, 9, 21, 23, 45, 00) + * @param {Date} [end] The end date + * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds */ + function TimeStep(start, end, minimumStep, hiddenDates) { + // variables + this.current = new Date(); + this._start = new Date(); + this._end = new Date(); - Emitter.prototype.hasListeners = function(event){ - return !! this.listeners(event).length; - }; + this.autoScale = true; + this.scale = 'day'; + this.step = 1; + // initialize the range + this.setRange(start, end, minimumStep); -/***/ }, -/* 12 */ -/***/ function(module, exports, __webpack_require__) { + // hidden Dates options + this.switchedDay = false; + this.switchedMonth = false; + this.switchedYear = false; + this.hiddenDates = hiddenDates; + if (hiddenDates === undefined) { + this.hiddenDates = []; + } + + this.format = TimeStep.FORMAT; // default formatting + } + + // Time formatting + TimeStep.FORMAT = { + minorLabels: { + millisecond:'SSS', + second: 's', + minute: 'HH:mm', + hour: 'HH:mm', + weekday: 'ddd D', + day: 'D', + month: 'MMM', + year: 'YYYY' + }, + majorLabels: { + millisecond:'HH:mm:ss', + second: 'D MMMM HH:mm', + minute: 'ddd D MMMM', + hour: 'ddd D MMMM', + weekday: 'MMMM YYYY', + day: 'MMMM YYYY', + month: 'YYYY', + year: '' + } + }; /** - * @prototype Point3d - * @param {Number} [x] - * @param {Number} [y] - * @param {Number} [z] + * Set custom formatting for the minor an major labels of the TimeStep. + * Both `minorLabels` and `majorLabels` are an Object with properties: + * 'millisecond, 'second, 'minute', 'hour', 'weekday, 'day, 'month, 'year'. + * @param {{minorLabels: Object, majorLabels: Object}} format */ - function Point3d(x, y, z) { - this.x = x !== undefined ? x : 0; - this.y = y !== undefined ? y : 0; - this.z = z !== undefined ? z : 0; + TimeStep.prototype.setFormat = function (format) { + var defaultFormat = util.deepExtend({}, TimeStep.FORMAT); + this.format = util.deepExtend(defaultFormat, format); }; /** - * Subtract the two provided points, returns a-b - * @param {Point3d} a - * @param {Point3d} b - * @return {Point3d} a-b + * Set a new range + * If minimumStep is provided, the step size is chosen as close as possible + * to the minimumStep but larger than minimumStep. If minimumStep is not + * provided, the scale is set to 1 DAY. + * The minimumStep should correspond with the onscreen size of about 6 characters + * @param {Date} [start] The start date and time. + * @param {Date} [end] The end date and time. + * @param {int} [minimumStep] Optional. Minimum step size in milliseconds */ - Point3d.subtract = function(a, b) { - var sub = new Point3d(); - sub.x = a.x - b.x; - sub.y = a.y - b.y; - sub.z = a.z - b.z; - return sub; + TimeStep.prototype.setRange = function(start, end, minimumStep) { + if (!(start instanceof Date) || !(end instanceof Date)) { + throw "No legal start or end date in method setRange"; + } + + this._start = (start != undefined) ? new Date(start.valueOf()) : new Date(); + this._end = (end != undefined) ? new Date(end.valueOf()) : new Date(); + + if (this.autoScale) { + this.setMinimumStep(minimumStep); + } }; /** - * Add the two provided points, returns a+b - * @param {Point3d} a - * @param {Point3d} b - * @return {Point3d} a+b + * Set the range iterator to the start date. */ - Point3d.add = function(a, b) { - var sum = new Point3d(); - sum.x = a.x + b.x; - sum.y = a.y + b.y; - sum.z = a.z + b.z; - return sum; + TimeStep.prototype.first = function() { + this.current = new Date(this._start.valueOf()); + this.roundToMinor(); + }; + + /** + * Round the current date to the first minor date value + * This must be executed once when the current date is set to start Date + */ + TimeStep.prototype.roundToMinor = function() { + // round to floor + // IMPORTANT: we have no breaks in this switch! (this is no bug) + // noinspection FallThroughInSwitchStatementJS + switch (this.scale) { + case 'year': + this.current.setFullYear(this.step * Math.floor(this.current.getFullYear() / this.step)); + this.current.setMonth(0); + case 'month': this.current.setDate(1); + case 'day': // intentional fall through + case 'weekday': this.current.setHours(0); + case 'hour': this.current.setMinutes(0); + case 'minute': this.current.setSeconds(0); + case 'second': this.current.setMilliseconds(0); + //case 'millisecond': // nothing to do for milliseconds + } + + if (this.step != 1) { + // round down to the first minor value that is a multiple of the current step size + switch (this.scale) { + case 'millisecond': this.current.setMilliseconds(this.current.getMilliseconds() - this.current.getMilliseconds() % this.step); break; + case 'second': this.current.setSeconds(this.current.getSeconds() - this.current.getSeconds() % this.step); break; + case 'minute': this.current.setMinutes(this.current.getMinutes() - this.current.getMinutes() % this.step); break; + case 'hour': this.current.setHours(this.current.getHours() - this.current.getHours() % this.step); break; + case 'weekday': // intentional fall through + case 'day': this.current.setDate((this.current.getDate()-1) - (this.current.getDate()-1) % this.step + 1); break; + case 'month': this.current.setMonth(this.current.getMonth() - this.current.getMonth() % this.step); break; + case 'year': this.current.setFullYear(this.current.getFullYear() - this.current.getFullYear() % this.step); break; + default: break; + } + } }; /** - * Calculate the average of two 3d points - * @param {Point3d} a - * @param {Point3d} b - * @return {Point3d} The average, (a+b)/2 + * Check if the there is a next step + * @return {boolean} true if the current date has not passed the end date */ - Point3d.avg = function(a, b) { - return new Point3d( - (a.x + b.x) / 2, - (a.y + b.y) / 2, - (a.z + b.z) / 2 - ); + TimeStep.prototype.hasNext = function () { + return (this.current.valueOf() <= this._end.valueOf()); }; /** - * Calculate the cross product of the two provided points, returns axb - * Documentation: http://en.wikipedia.org/wiki/Cross_product - * @param {Point3d} a - * @param {Point3d} b - * @return {Point3d} cross product axb + * Do the next step */ - Point3d.crossProduct = function(a, b) { - var crossproduct = new Point3d(); + TimeStep.prototype.next = function() { + var prev = this.current.valueOf(); - crossproduct.x = a.y * b.z - a.z * b.y; - crossproduct.y = a.z * b.x - a.x * b.z; - crossproduct.z = a.x * b.y - a.y * b.x; + // Two cases, needed to prevent issues with switching daylight savings + // (end of March and end of October) + if (this.current.getMonth() < 6) { + switch (this.scale) { + case 'millisecond': - return crossproduct; + this.current = new Date(this.current.valueOf() + this.step); break; + case 'second': this.current = new Date(this.current.valueOf() + this.step * 1000); break; + case 'minute': this.current = new Date(this.current.valueOf() + this.step * 1000 * 60); break; + case 'hour': + this.current = new Date(this.current.valueOf() + this.step * 1000 * 60 * 60); + // in case of skipping an hour for daylight savings, adjust the hour again (else you get: 0h 5h 9h ... instead of 0h 4h 8h ...) + var h = this.current.getHours(); + this.current.setHours(h - (h % this.step)); + break; + case 'weekday': // intentional fall through + case 'day': this.current.setDate(this.current.getDate() + this.step); break; + case 'month': this.current.setMonth(this.current.getMonth() + this.step); break; + case 'year': this.current.setFullYear(this.current.getFullYear() + this.step); break; + default: break; + } + } + else { + switch (this.scale) { + case 'millisecond': this.current = new Date(this.current.valueOf() + this.step); break; + case 'second': this.current.setSeconds(this.current.getSeconds() + this.step); break; + case 'minute': this.current.setMinutes(this.current.getMinutes() + this.step); break; + case 'hour': this.current.setHours(this.current.getHours() + this.step); break; + case 'weekday': // intentional fall through + case 'day': this.current.setDate(this.current.getDate() + this.step); break; + case 'month': this.current.setMonth(this.current.getMonth() + this.step); break; + case 'year': this.current.setFullYear(this.current.getFullYear() + this.step); break; + default: break; + } + } + + if (this.step != 1) { + // round down to the correct major value + switch (this.scale) { + case 'millisecond': if(this.current.getMilliseconds() < this.step) this.current.setMilliseconds(0); break; + case 'second': if(this.current.getSeconds() < this.step) this.current.setSeconds(0); break; + case 'minute': if(this.current.getMinutes() < this.step) this.current.setMinutes(0); break; + case 'hour': if(this.current.getHours() < this.step) this.current.setHours(0); break; + case 'weekday': // intentional fall through + case 'day': if(this.current.getDate() < this.step+1) this.current.setDate(1); break; + case 'month': if(this.current.getMonth() < this.step) this.current.setMonth(0); break; + case 'year': break; // nothing to do for year + default: break; + } + } + + // safety mechanism: if current time is still unchanged, move to the end + if (this.current.valueOf() == prev) { + this.current = new Date(this._end.valueOf()); + } + + DateUtil.stepOverHiddenDates(this, prev); }; /** - * Rtrieve the length of the vector (or the distance from this point to the origin - * @return {Number} length + * Get the current datetime + * @return {Date} current The current date */ - Point3d.prototype.length = function() { - return Math.sqrt( - this.x * this.x + - this.y * this.y + - this.z * this.z - ); + TimeStep.prototype.getCurrent = function() { + return this.current; }; - module.exports = Point3d; - - -/***/ }, -/* 13 */ -/***/ function(module, exports, __webpack_require__) { - /** - * @prototype Point2d - * @param {Number} [x] - * @param {Number} [y] + * Set a custom scale. Autoscaling will be disabled. + * For example setScale(SCALE.MINUTES, 5) will result + * in minor steps of 5 minutes, and major steps of an hour. + * + * @param {string} newScale + * A scale. Choose from 'millisecond, 'second, + * 'minute', 'hour', 'weekday, 'day, 'month, 'year'. + * @param {Number} newStep A step size, by default 1. Choose for + * example 1, 2, 5, or 10. */ - function Point2d (x, y) { - this.x = x !== undefined ? x : 0; - this.y = y !== undefined ? y : 0; - } - - module.exports = Point2d; - + TimeStep.prototype.setScale = function(newScale, newStep) { + this.scale = newScale; -/***/ }, -/* 14 */ -/***/ function(module, exports, __webpack_require__) { + if (newStep > 0) { + this.step = newStep; + } - var Point3d = __webpack_require__(12); + this.autoScale = false; + }; /** - * @class Camera - * The camera is mounted on a (virtual) camera arm. The camera arm can rotate - * The camera is always looking in the direction of the origin of the arm. - * This way, the camera always rotates around one fixed point, the location - * of the camera arm. - * - * Documentation: - * http://en.wikipedia.org/wiki/3D_projection + * Enable or disable autoscaling + * @param {boolean} enable If true, autoascaling is set true */ - function Camera() { - this.armLocation = new Point3d(); - this.armRotation = {}; - this.armRotation.horizontal = 0; - this.armRotation.vertical = 0; - this.armLength = 1.7; - - this.cameraLocation = new Point3d(); - this.cameraRotation = new Point3d(0.5*Math.PI, 0, 0); + TimeStep.prototype.setAutoScale = function (enable) { + this.autoScale = enable; + }; - this.calculateCameraOrientation(); - } /** - * Set the location (origin) of the arm - * @param {Number} x Normalized value of x - * @param {Number} y Normalized value of y - * @param {Number} z Normalized value of z + * Automatically determine the scale that bests fits the provided minimum step + * @param {Number} [minimumStep] The minimum step size in milliseconds */ - Camera.prototype.setArmLocation = function(x, y, z) { - this.armLocation.x = x; - this.armLocation.y = y; - this.armLocation.z = z; + TimeStep.prototype.setMinimumStep = function(minimumStep) { + if (minimumStep == undefined) { + return; + } - this.calculateCameraOrientation(); + //var b = asc + ds; + + var stepYear = (1000 * 60 * 60 * 24 * 30 * 12); + var stepMonth = (1000 * 60 * 60 * 24 * 30); + var stepDay = (1000 * 60 * 60 * 24); + var stepHour = (1000 * 60 * 60); + var stepMinute = (1000 * 60); + var stepSecond = (1000); + var stepMillisecond= (1); + + // find the smallest step that is larger than the provided minimumStep + if (stepYear*1000 > minimumStep) {this.scale = 'year'; this.step = 1000;} + if (stepYear*500 > minimumStep) {this.scale = 'year'; this.step = 500;} + if (stepYear*100 > minimumStep) {this.scale = 'year'; this.step = 100;} + if (stepYear*50 > minimumStep) {this.scale = 'year'; this.step = 50;} + if (stepYear*10 > minimumStep) {this.scale = 'year'; this.step = 10;} + if (stepYear*5 > minimumStep) {this.scale = 'year'; this.step = 5;} + if (stepYear > minimumStep) {this.scale = 'year'; this.step = 1;} + if (stepMonth*3 > minimumStep) {this.scale = 'month'; this.step = 3;} + if (stepMonth > minimumStep) {this.scale = 'month'; this.step = 1;} + if (stepDay*5 > minimumStep) {this.scale = 'day'; this.step = 5;} + if (stepDay*2 > minimumStep) {this.scale = 'day'; this.step = 2;} + if (stepDay > minimumStep) {this.scale = 'day'; this.step = 1;} + if (stepDay/2 > minimumStep) {this.scale = 'weekday'; this.step = 1;} + if (stepHour*4 > minimumStep) {this.scale = 'hour'; this.step = 4;} + if (stepHour > minimumStep) {this.scale = 'hour'; this.step = 1;} + if (stepMinute*15 > minimumStep) {this.scale = 'minute'; this.step = 15;} + if (stepMinute*10 > minimumStep) {this.scale = 'minute'; this.step = 10;} + if (stepMinute*5 > minimumStep) {this.scale = 'minute'; this.step = 5;} + if (stepMinute > minimumStep) {this.scale = 'minute'; this.step = 1;} + if (stepSecond*15 > minimumStep) {this.scale = 'second'; this.step = 15;} + if (stepSecond*10 > minimumStep) {this.scale = 'second'; this.step = 10;} + if (stepSecond*5 > minimumStep) {this.scale = 'second'; this.step = 5;} + if (stepSecond > minimumStep) {this.scale = 'second'; this.step = 1;} + if (stepMillisecond*200 > minimumStep) {this.scale = 'millisecond'; this.step = 200;} + if (stepMillisecond*100 > minimumStep) {this.scale = 'millisecond'; this.step = 100;} + if (stepMillisecond*50 > minimumStep) {this.scale = 'millisecond'; this.step = 50;} + if (stepMillisecond*10 > minimumStep) {this.scale = 'millisecond'; this.step = 10;} + if (stepMillisecond*5 > minimumStep) {this.scale = 'millisecond'; this.step = 5;} + if (stepMillisecond > minimumStep) {this.scale = 'millisecond'; this.step = 1;} }; /** - * Set the rotation of the camera arm - * @param {Number} horizontal The horizontal rotation, between 0 and 2*PI. - * Optional, can be left undefined. - * @param {Number} vertical The vertical rotation, between 0 and 0.5*PI - * if vertical=0.5*PI, the graph is shown from the - * top. Optional, can be left undefined. + * 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 */ - Camera.prototype.setArmRotation = function(horizontal, vertical) { - if (horizontal !== undefined) { - this.armRotation.horizontal = horizontal; - } + TimeStep.prototype.snap = function(date) { + var clone = new Date(date.valueOf()); - if (vertical !== undefined) { - this.armRotation.vertical = vertical; - if (this.armRotation.vertical < 0) this.armRotation.vertical = 0; - if (this.armRotation.vertical > 0.5*Math.PI) this.armRotation.vertical = 0.5*Math.PI; + if (this.scale == 'year') { + var year = clone.getFullYear() + Math.round(clone.getMonth() / 12); + clone.setFullYear(Math.round(year / this.step) * this.step); + clone.setMonth(0); + clone.setDate(0); + clone.setHours(0); + clone.setMinutes(0); + clone.setSeconds(0); + clone.setMilliseconds(0); } + else if (this.scale == 'month') { + if (clone.getDate() > 15) { + clone.setDate(1); + clone.setMonth(clone.getMonth() + 1); + // important: first set Date to 1, after that change the month. + } + else { + clone.setDate(1); + } - if (horizontal !== undefined || vertical !== undefined) { - this.calculateCameraOrientation(); + clone.setHours(0); + clone.setMinutes(0); + clone.setSeconds(0); + clone.setMilliseconds(0); + } + else if (this.scale == 'day') { + //noinspection FallthroughInSwitchStatementJS + switch (this.step) { + case 5: + case 2: + clone.setHours(Math.round(clone.getHours() / 24) * 24); break; + default: + clone.setHours(Math.round(clone.getHours() / 12) * 12); break; + } + clone.setMinutes(0); + clone.setSeconds(0); + clone.setMilliseconds(0); + } + else if (this.scale == 'weekday') { + //noinspection FallthroughInSwitchStatementJS + switch (this.step) { + case 5: + case 2: + clone.setHours(Math.round(clone.getHours() / 12) * 12); break; + default: + clone.setHours(Math.round(clone.getHours() / 6) * 6); break; + } + clone.setMinutes(0); + clone.setSeconds(0); + clone.setMilliseconds(0); + } + else if (this.scale == 'hour') { + switch (this.step) { + case 4: + clone.setMinutes(Math.round(clone.getMinutes() / 60) * 60); break; + default: + clone.setMinutes(Math.round(clone.getMinutes() / 30) * 30); break; + } + clone.setSeconds(0); + clone.setMilliseconds(0); + } else if (this.scale == 'minute') { + //noinspection FallthroughInSwitchStatementJS + switch (this.step) { + case 15: + case 10: + clone.setMinutes(Math.round(clone.getMinutes() / 5) * 5); + clone.setSeconds(0); + break; + case 5: + clone.setSeconds(Math.round(clone.getSeconds() / 60) * 60); break; + default: + clone.setSeconds(Math.round(clone.getSeconds() / 30) * 30); break; + } + clone.setMilliseconds(0); + } + else if (this.scale == 'second') { + //noinspection FallthroughInSwitchStatementJS + switch (this.step) { + case 15: + case 10: + clone.setSeconds(Math.round(clone.getSeconds() / 5) * 5); + clone.setMilliseconds(0); + break; + case 5: + clone.setMilliseconds(Math.round(clone.getMilliseconds() / 1000) * 1000); break; + default: + clone.setMilliseconds(Math.round(clone.getMilliseconds() / 500) * 500); break; + } + } + else if (this.scale == 'millisecond') { + var step = this.step > 5 ? this.step / 2 : 1; + clone.setMilliseconds(Math.round(clone.getMilliseconds() / step) * step); } + + return clone; }; /** - * Retrieve the current arm rotation - * @return {object} An object with parameters horizontal and vertical + * 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. */ - Camera.prototype.getArmRotation = function() { - var rot = {}; - rot.horizontal = this.armRotation.horizontal; - rot.vertical = this.armRotation.vertical; + TimeStep.prototype.isMajor = function() { + if (this.switchedYear == true) { + this.switchedYear = false; + switch (this.scale) { + case 'year': + case 'month': + case 'weekday': + case 'day': + case 'hour': + case 'minute': + case 'second': + case 'millisecond': + return true; + default: + return false; + } + } + else if (this.switchedMonth == true) { + this.switchedMonth = false; + switch (this.scale) { + case 'weekday': + case 'day': + case 'hour': + case 'minute': + case 'second': + case 'millisecond': + return true; + default: + return false; + } + } + else if (this.switchedDay == true) { + this.switchedDay = false; + switch (this.scale) { + case 'millisecond': + case 'second': + case 'minute': + case 'hour': + return true; + default: + return false; + } + } - return rot; + switch (this.scale) { + case 'millisecond': + return (this.current.getMilliseconds() == 0); + case 'second': + return (this.current.getSeconds() == 0); + case 'minute': + return (this.current.getHours() == 0) && (this.current.getMinutes() == 0); + case 'hour': + return (this.current.getHours() == 0); + case 'weekday': // intentional fall through + case 'day': + return (this.current.getDate() == 1); + case 'month': + return (this.current.getMonth() == 0); + case 'year': + return false; + default: + return false; + } }; + /** - * Set the (normalized) length of the camera arm. - * @param {Number} length A length between 0.71 and 5.0 + * Returns formatted text for the minor axislabel, depending on the current + * date and the scale. For example when scale is MINUTE, the current time is + * formatted as "hh:mm". + * @param {Date} [date] custom date. if not provided, current date is taken */ - Camera.prototype.setArmLength = function(length) { - if (length === undefined) - return; - - this.armLength = length; - - // Radius must be larger than the corner of the graph, - // which has a distance of sqrt(0.5^2+0.5^2) = 0.71 from the center of the - // graph - if (this.armLength < 0.71) this.armLength = 0.71; - if (this.armLength > 5.0) this.armLength = 5.0; + TimeStep.prototype.getLabelMinor = function(date) { + if (date == undefined) { + date = this.current; + } - this.calculateCameraOrientation(); + var format = this.format.minorLabels[this.scale]; + return (format && format.length > 0) ? moment(date).format(format) : ''; }; /** - * Retrieve the arm length - * @return {Number} length + * Returns formatted text for the major axis label, depending on the current + * date and the scale. For example when scale is MINUTE, the major scale is + * hours, and the hour will be formatted as "hh". + * @param {Date} [date] custom date. if not provided, current date is taken */ - Camera.prototype.getArmLength = function() { - return this.armLength; - }; + TimeStep.prototype.getLabelMajor = function(date) { + if (date == undefined) { + date = this.current; + } - /** - * Retrieve the camera location - * @return {Point3d} cameraLocation - */ - Camera.prototype.getCameraLocation = function() { - return this.cameraLocation; + var format = this.format.majorLabels[this.scale]; + return (format && format.length > 0) ? moment(date).format(format) : ''; }; - /** - * Retrieve the camera rotation - * @return {Point3d} cameraRotation - */ - Camera.prototype.getCameraRotation = function() { - return this.cameraRotation; - }; + TimeStep.prototype.getClassName = function() { + var m = moment(this.current); + var date = m.locale ? m.locale('en') : m.lang('en'); // old versions of moment have .lang() function + var step = this.step; - /** - * Calculate the location and rotation of the camera based on the - * position and orientation of the camera arm - */ - Camera.prototype.calculateCameraOrientation = function() { - // calculate location of the camera - this.cameraLocation.x = this.armLocation.x - this.armLength * Math.sin(this.armRotation.horizontal) * Math.cos(this.armRotation.vertical); - this.cameraLocation.y = this.armLocation.y - this.armLength * Math.cos(this.armRotation.horizontal) * Math.cos(this.armRotation.vertical); - this.cameraLocation.z = this.armLocation.z + this.armLength * Math.sin(this.armRotation.vertical); + function even(value) { + return (value / step % 2 == 0) ? ' even' : ' odd'; + } - // calculate rotation of the camera - this.cameraRotation.x = Math.PI/2 - this.armRotation.vertical; - this.cameraRotation.y = 0; - this.cameraRotation.z = -this.armRotation.horizontal; - }; + function today(date) { + if (date.isSame(new Date(), 'day')) { + return ' today'; + } + if (date.isSame(moment().add(1, 'day'), 'day')) { + return ' tomorrow'; + } + if (date.isSame(moment().add(-1, 'day'), 'day')) { + return ' yesterday'; + } + return ''; + } - module.exports = Camera; + function currentWeek(date) { + return date.isSame(new Date(), 'week') ? ' current-week' : ''; + } -/***/ }, -/* 15 */ -/***/ function(module, exports, __webpack_require__) { + function currentMonth(date) { + return date.isSame(new Date(), 'month') ? ' current-month' : ''; + } - var DataView = __webpack_require__(9); + function currentYear(date) { + return date.isSame(new Date(), 'year') ? ' current-year' : ''; + } - /** - * @class Filter - * - * @param {DataSet} data The google data table - * @param {Number} column The index of the column to be filtered - * @param {Graph} graph The graph - */ - function Filter (data, column, graph) { - this.data = data; - this.column = column; - this.graph = graph; // the parent graph + switch (this.scale) { + case 'millisecond': + return even(date.milliseconds()).trim(); - this.index = undefined; - this.value = undefined; + case 'second': + return even(date.seconds()).trim(); - // read all distinct values and select the first one - this.values = graph.getDistinctValues(data.get(), this.column); + case 'minute': + return even(date.minutes()).trim(); - // sort both numeric and string values correctly - this.values.sort(function (a, b) { - return a > b ? 1 : a < b ? -1 : 0; - }); + case 'hour': + var hours = date.hours(); + if (this.step == 4) { + hours = hours + '-' + (hours + 4); + } + return hours + 'h' + today(date) + even(date.hours()); - if (this.values.length > 0) { - this.selectValue(0); - } + case 'weekday': + return date.format('dddd').toLowerCase() + + today(date) + currentWeek(date) + even(date.date()); - // create an array with the filtered datapoints. this will be loaded afterwards - this.dataPoints = []; + case 'day': + var day = date.date(); + var month = date.format('MMMM').toLowerCase(); + return 'day' + day + ' ' + month + currentMonth(date) + even(day - 1); - this.loaded = false; - this.onLoadCallback = undefined; + case 'month': + return date.format('MMMM').toLowerCase() + + currentMonth(date) + even(date.month()); - if (graph.animationPreload) { - this.loaded = false; - this.loadInBackground(); - } - else { - this.loaded = true; + case 'year': + var year = date.year(); + return 'year' + year + currentYear(date)+ even(year); + + default: + return ''; } }; + module.exports = TimeStep; - /** - * Return the label - * @return {string} label - */ - Filter.prototype.isLoaded = function() { - return this.loaded; - }; +/***/ }, +/* 20 */ +/***/ function(module, exports, __webpack_require__) { /** - * Return the loaded progress - * @return {Number} percentage between 0 and 100 + * Prototype for visual components + * @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} [body] + * @param {Object} [options] */ - Filter.prototype.getLoadedProgress = function() { - var len = this.values.length; + function Component (body, options) { + this.options = null; + this.props = null; + } - var i = 0; - while (this.dataPoints[i]) { - i++; + /** + * Set options for the component. The new options will be merged into the + * current options. + * @param {Object} options + */ + Component.prototype.setOptions = function(options) { + if (options) { + util.extend(this.options, options); } - - return Math.round(i / len * 100); }; - /** - * Return the label - * @return {string} label + * Repaint the component + * @return {boolean} Returns true if the component is resized */ - Filter.prototype.getLabel = function() { - return this.graph.filterLabel; + Component.prototype.redraw = function() { + // should be implemented by the component + return false; }; - /** - * Return the columnIndex of the filter - * @return {Number} columnIndex + * Destroy the component. Cleanup DOM and event listeners */ - Filter.prototype.getColumn = function() { - return this.column; + Component.prototype.destroy = function() { + // should be implemented by the component }; /** - * Return the currently selected value. Returns undefined if there is no selection - * @return {*} value + * Test whether the component is resized since the last time _isResized() was + * called. + * @return {Boolean} Returns true if the component is resized + * @protected */ - Filter.prototype.getSelectedValue = function() { - if (this.index === undefined) - return undefined; + Component.prototype._isResized = function() { + var resized = (this.props._previousWidth !== this.props.width || + this.props._previousHeight !== this.props.height); - return this.values[this.index]; - }; + this.props._previousWidth = this.props.width; + this.props._previousHeight = this.props.height; - /** - * Retrieve all values of the filter - * @return {Array} values - */ - Filter.prototype.getValues = function() { - return this.values; + return resized; }; - /** - * Retrieve one value of the filter - * @param {Number} index - * @return {*} value - */ - Filter.prototype.getValue = function(index) { - if (index >= this.values.length) - throw 'Error: index out of range'; + module.exports = Component; - return this.values[index]; - }; +/***/ }, +/* 21 */ +/***/ function(module, exports, __webpack_require__) { + + var util = __webpack_require__(1); + var Component = __webpack_require__(20); + var moment = __webpack_require__(44); + var locales = __webpack_require__(48); /** - * Retrieve the (filtered) dataPoints for the currently selected filter index - * @param {Number} [index] (optional) - * @return {Array} dataPoints + * A current time bar + * @param {{range: Range, dom: Object, domProps: Object}} body + * @param {Object} [options] Available parameters: + * {Boolean} [showCurrentTime] + * @constructor CurrentTime + * @extends Component */ - Filter.prototype._getDataPoints = function(index) { - if (index === undefined) - index = this.index; + function CurrentTime (body, options) { + this.body = body; - if (index === undefined) - return []; + // default options + this.defaultOptions = { + showCurrentTime: true, - var dataPoints; - if (this.dataPoints[index]) { - dataPoints = this.dataPoints[index]; - } - else { - var f = {}; - f.column = this.column; - f.value = this.values[index]; + locales: locales, + locale: 'en' + }; + this.options = util.extend({}, this.defaultOptions); + this.offset = 0; - var dataView = new DataView(this.data,{filter: function (item) {return (item[f.column] == f.value);}}).get(); - dataPoints = this.graph._getDataPoints(dataView); + this._create(); - this.dataPoints[index] = dataPoints; - } + this.setOptions(options); + } - return dataPoints; - }; + CurrentTime.prototype = new Component(); + /** + * Create the HTML DOM for the current time bar + * @private + */ + CurrentTime.prototype._create = function() { + var bar = document.createElement('div'); + bar.className = 'currenttime'; + bar.style.position = 'absolute'; + bar.style.top = '0px'; + bar.style.height = '100%'; + this.bar = bar; + }; /** - * Set a callback function when the filter is fully loaded. + * Destroy the CurrentTime bar */ - Filter.prototype.setOnLoadCallback = function(callback) { - this.onLoadCallback = callback; - }; + CurrentTime.prototype.destroy = function () { + this.options.showCurrentTime = false; + this.redraw(); // will remove the bar from the DOM and stop refreshing + this.body = null; + }; /** - * Add a value to the list with available values for this filter - * No double entries will be created. - * @param {Number} index + * Set options for the component. Options will be merged in current options. + * @param {Object} options Available parameters: + * {boolean} [showCurrentTime] */ - Filter.prototype.selectValue = function(index) { - if (index >= this.values.length) - throw 'Error: index out of range'; - - this.index = index; - this.value = this.values[index]; + CurrentTime.prototype.setOptions = function(options) { + if (options) { + // copy all options that we know + util.selectiveExtend(['showCurrentTime', 'locale', 'locales'], this.options, options); + } }; /** - * Load all filtered rows in the background one by one - * Start this method without providing an index! + * Repaint the component + * @return {boolean} Returns true if the component is resized */ - Filter.prototype.loadInBackground = function(index) { - if (index === undefined) - index = 0; + CurrentTime.prototype.redraw = function() { + if (this.options.showCurrentTime) { + var parent = this.body.dom.backgroundVertical; + if (this.bar.parentNode != parent) { + // attach to the dom + if (this.bar.parentNode) { + this.bar.parentNode.removeChild(this.bar); + } + parent.appendChild(this.bar); - var frame = this.graph.frame; + this.start(); + } - if (index < this.values.length) { - var dataPointsTemp = this._getDataPoints(index); - //this.graph.redrawInfo(); // TODO: not neat + var now = new Date(new Date().valueOf() + this.offset); + var x = this.body.util.toScreen(now); - // create a progress box - if (frame.progress === undefined) { - frame.progress = document.createElement('DIV'); - frame.progress.style.position = 'absolute'; - frame.progress.style.color = 'gray'; - frame.appendChild(frame.progress); - } - var progress = this.getLoadedProgress(); - frame.progress.innerHTML = 'Loading animation... ' + progress + '%'; - // TODO: this is no nice solution... - frame.progress.style.bottom = 60 + 'px'; // TODO: use height of slider - frame.progress.style.left = 10 + 'px'; + 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); - var me = this; - setTimeout(function() {me.loadInBackground(index+1);}, 10); - this.loaded = false; + this.bar.style.left = x + 'px'; + this.bar.title = title; } else { - this.loaded = true; - - // remove the progress box - if (frame.progress !== undefined) { - frame.removeChild(frame.progress); - frame.progress = undefined; + // remove the line from the DOM + if (this.bar.parentNode) { + this.bar.parentNode.removeChild(this.bar); } - - if (this.onLoadCallback) - this.onLoadCallback(); + this.stop(); } - }; - module.exports = Filter; - - -/***/ }, -/* 16 */ -/***/ function(module, exports, __webpack_require__) { - - var util = __webpack_require__(1); + return false; + }; /** - * @constructor Slider - * - * An html slider control with start/stop/prev/next buttons - * @param {Element} container The element where the slider will be created - * @param {Object} options Available options: - * {boolean} visible If true (default) the - * slider is visible. + * Start auto refreshing the current time bar */ - function Slider(container, options) { - if (container === undefined) { - throw 'Error: No container element defined'; - } - this.container = container; - this.visible = (options && options.visible != undefined) ? options.visible : true; - - if (this.visible) { - this.frame = document.createElement('DIV'); - //this.frame.style.backgroundColor = '#E5E5E5'; - this.frame.style.width = '100%'; - this.frame.style.position = 'relative'; - this.container.appendChild(this.frame); - - this.frame.prev = document.createElement('INPUT'); - this.frame.prev.type = 'BUTTON'; - this.frame.prev.value = 'Prev'; - this.frame.appendChild(this.frame.prev); - - this.frame.play = document.createElement('INPUT'); - this.frame.play.type = 'BUTTON'; - this.frame.play.value = 'Play'; - this.frame.appendChild(this.frame.play); + CurrentTime.prototype.start = function() { + var me = this; - this.frame.next = document.createElement('INPUT'); - this.frame.next.type = 'BUTTON'; - this.frame.next.value = 'Next'; - this.frame.appendChild(this.frame.next); + function update () { + me.stop(); - this.frame.bar = document.createElement('INPUT'); - this.frame.bar.type = 'BUTTON'; - this.frame.bar.style.position = 'absolute'; - this.frame.bar.style.border = '1px solid red'; - this.frame.bar.style.width = '100px'; - this.frame.bar.style.height = '6px'; - this.frame.bar.style.borderRadius = '2px'; - this.frame.bar.style.MozBorderRadius = '2px'; - this.frame.bar.style.border = '1px solid #7F7F7F'; - this.frame.bar.style.backgroundColor = '#E5E5E5'; - this.frame.appendChild(this.frame.bar); + // determine interval to refresh + var scale = me.body.range.conversion(me.body.domProps.center.width).scale; + var interval = 1 / scale / 10; + if (interval < 30) interval = 30; + if (interval > 1000) interval = 1000; - this.frame.slide = document.createElement('INPUT'); - this.frame.slide.type = 'BUTTON'; - this.frame.slide.style.margin = '0px'; - this.frame.slide.value = ' '; - this.frame.slide.style.position = 'relative'; - this.frame.slide.style.left = '-100px'; - this.frame.appendChild(this.frame.slide); + me.redraw(); - // create events - var me = this; - this.frame.slide.onmousedown = function (event) {me._onMouseDown(event);}; - this.frame.prev.onclick = function (event) {me.prev(event);}; - this.frame.play.onclick = function (event) {me.togglePlay(event);}; - this.frame.next.onclick = function (event) {me.next(event);}; + // start a timer to adjust for the new time + me.currentTimeTimer = setTimeout(update, interval); } - this.onChangeCallback = undefined; - - this.values = []; - this.index = undefined; - - this.playTimeout = undefined; - this.playInterval = 1000; // milliseconds - this.playLoop = true; - } + update(); + }; /** - * Select the previous index + * Stop auto refreshing the current time bar */ - Slider.prototype.prev = function() { - var index = this.getIndex(); - if (index > 0) { - index--; - this.setIndex(index); + CurrentTime.prototype.stop = function() { + if (this.currentTimeTimer !== undefined) { + clearTimeout(this.currentTimeTimer); + delete this.currentTimeTimer; } }; /** - * Select the next index + * Set a current time. This can be used for example to ensure that a client's + * time is synchronized with a shared server time. + * @param {Date | String | Number} time A Date, unix timestamp, or + * ISO date string. */ - Slider.prototype.next = function() { - var index = this.getIndex(); - if (index < this.values.length - 1) { - index++; - this.setIndex(index); - } + CurrentTime.prototype.setCurrentTime = function(time) { + var t = util.convert(time, 'Date').valueOf(); + var now = new Date().valueOf(); + this.offset = t - now; + this.redraw(); }; /** - * Select the next index + * Get the current time. + * @return {Date} Returns the current time. */ - Slider.prototype.playNext = function() { - var start = new Date(); + CurrentTime.prototype.getCurrentTime = function() { + return new Date(new Date().valueOf() + this.offset); + }; - var index = this.getIndex(); - if (index < this.values.length - 1) { - index++; - this.setIndex(index); - } - else if (this.playLoop) { - // jump to the start - index = 0; - this.setIndex(index); - } + module.exports = CurrentTime; - var end = new Date(); - var diff = (end - start); - // calculate how much time it to to set the index and to execute the callback - // function. - var interval = Math.max(this.playInterval - diff, 0); - // document.title = diff // TODO: cleanup +/***/ }, +/* 22 */ +/***/ function(module, exports, __webpack_require__) { - var me = this; - this.playTimeout = setTimeout(function() {me.playNext();}, interval); - }; + var Hammer = __webpack_require__(45); + var util = __webpack_require__(1); + var Component = __webpack_require__(20); + var moment = __webpack_require__(44); + var locales = __webpack_require__(48); /** - * Toggle start or stop playing + * A custom time bar + * @param {{range: Range, dom: Object}} body + * @param {Object} [options] Available parameters: + * {Boolean} [showCustomTime] + * @constructor CustomTime + * @extends Component */ - Slider.prototype.togglePlay = function() { - if (this.playTimeout === undefined) { - this.play(); - } else { - this.stop(); - } - }; - /** - * Start playing - */ - Slider.prototype.play = function() { - // Test whether already playing - if (this.playTimeout) return; + function CustomTime (body, options) { + this.body = body; - this.playNext(); + // default options + this.defaultOptions = { + showCustomTime: false, + locales: locales, + locale: 'en' + }; + this.options = util.extend({}, this.defaultOptions); - if (this.frame) { - this.frame.play.value = 'Stop'; + this.customTime = new Date(); + this.eventParams = {}; // stores state parameters while dragging the bar + + // create the DOM + this._create(); + + this.setOptions(options); + } + + CustomTime.prototype = new Component(); + + /** + * Set options for the component. Options will be merged in current options. + * @param {Object} options Available parameters: + * {boolean} [showCustomTime] + */ + CustomTime.prototype.setOptions = function(options) { + if (options) { + // copy all options that we know + util.selectiveExtend(['showCustomTime', 'locale', 'locales'], this.options, options); } }; /** - * Stop playing + * Create the DOM for the custom time + * @private */ - Slider.prototype.stop = function() { - clearInterval(this.playTimeout); - this.playTimeout = undefined; + CustomTime.prototype._create = function() { + var bar = document.createElement('div'); + bar.className = 'customtime'; + bar.style.position = 'absolute'; + bar.style.top = '0px'; + bar.style.height = '100%'; + this.bar = bar; - if (this.frame) { - this.frame.play.value = 'Play'; - } + var drag = document.createElement('div'); + drag.style.position = 'relative'; + drag.style.top = '0px'; + drag.style.left = '-10px'; + drag.style.height = '100%'; + drag.style.width = '20px'; + bar.appendChild(drag); + + // attach event listeners + this.hammer = Hammer(bar, { + prevent_default: true + }); + this.hammer.on('dragstart', this._onDragStart.bind(this)); + this.hammer.on('drag', this._onDrag.bind(this)); + this.hammer.on('dragend', this._onDragEnd.bind(this)); }; /** - * Set a callback function which will be triggered when the value of the - * slider bar has changed. + * Destroy the CustomTime bar */ - Slider.prototype.setOnChangeCallback = function(callback) { - this.onChangeCallback = callback; + CustomTime.prototype.destroy = function () { + this.options.showCustomTime = false; + this.redraw(); // will remove the bar from the DOM + + this.hammer.enable(false); + this.hammer = null; + + this.body = null; }; /** - * Set the interval for playing the list - * @param {Number} interval The interval in milliseconds + * Repaint the component + * @return {boolean} Returns true if the component is resized */ - Slider.prototype.setPlayInterval = function(interval) { - this.playInterval = interval; + CustomTime.prototype.redraw = function () { + if (this.options.showCustomTime) { + var parent = this.body.dom.backgroundVertical; + if (this.bar.parentNode != parent) { + // attach to the dom + if (this.bar.parentNode) { + this.bar.parentNode.removeChild(this.bar); + } + parent.appendChild(this.bar); + } + + 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 = title; + } + else { + // remove the line from the DOM + if (this.bar.parentNode) { + this.bar.parentNode.removeChild(this.bar); + } + } + + return false; }; /** - * Retrieve the current play interval - * @return {Number} interval The interval in milliseconds + * Set custom time. + * @param {Date | number | string} time */ - Slider.prototype.getPlayInterval = function(interval) { - return this.playInterval; + CustomTime.prototype.setCustomTime = function(time) { + this.customTime = util.convert(time, 'Date'); + this.redraw(); }; /** - * Set looping on or off - * @pararm {boolean} doLoop If true, the slider will jump to the start when - * the end is passed, and will jump to the end - * when the start is passed. + * Retrieve the current custom time. + * @return {Date} customTime */ - Slider.prototype.setPlayLoop = function(doLoop) { - this.playLoop = doLoop; + CustomTime.prototype.getCustomTime = function() { + return new Date(this.customTime.valueOf()); }; - /** - * Execute the onchange callback function + * Start moving horizontally + * @param {Event} event + * @private */ - Slider.prototype.onChange = function() { - if (this.onChangeCallback !== undefined) { - this.onChangeCallback(); - } + CustomTime.prototype._onDragStart = function(event) { + this.eventParams.dragging = true; + this.eventParams.customTime = this.customTime; + + event.stopPropagation(); + event.preventDefault(); }; /** - * redraw the slider on the correct place + * Perform moving operating. + * @param {Event} event + * @private */ - Slider.prototype.redraw = function() { - if (this.frame) { - // resize the bar - this.frame.bar.style.top = (this.frame.clientHeight/2 - - this.frame.bar.offsetHeight/2) + 'px'; - this.frame.bar.style.width = (this.frame.clientWidth - - this.frame.prev.clientWidth - - this.frame.play.clientWidth - - this.frame.next.clientWidth - 30) + 'px'; + CustomTime.prototype._onDrag = function (event) { + if (!this.eventParams.dragging) return; - // position the slider button - var left = this.indexToLeft(this.index); - this.frame.slide.style.left = (left) + 'px'; - } - }; + var deltaX = event.gesture.deltaX, + x = this.body.util.toScreen(this.eventParams.customTime) + deltaX, + time = this.body.util.toTime(x); + this.setCustomTime(time); - /** - * Set the list with values for the slider - * @param {Array} values A javascript array with values (any type) - */ - Slider.prototype.setValues = function(values) { - this.values = values; + // fire a timechange event + this.body.emitter.emit('timechange', { + time: new Date(this.customTime.valueOf()) + }); - if (this.values.length > 0) - this.setIndex(0); - else - this.index = undefined; + event.stopPropagation(); + event.preventDefault(); }; /** - * Select a value by its index - * @param {Number} index + * Stop moving operating. + * @param {event} event + * @private */ - Slider.prototype.setIndex = function(index) { - if (index < this.values.length) { - this.index = index; + CustomTime.prototype._onDragEnd = function (event) { + if (!this.eventParams.dragging) return; - this.redraw(); - this.onChange(); - } - else { - throw 'Error: index out of range'; - } - }; + // fire a timechanged event + this.body.emitter.emit('timechanged', { + time: new Date(this.customTime.valueOf()) + }); - /** - * retrieve the index of the currently selected vaue - * @return {Number} index - */ - Slider.prototype.getIndex = function() { - return this.index; + event.stopPropagation(); + event.preventDefault(); }; + module.exports = CustomTime; + + +/***/ }, +/* 23 */ +/***/ function(module, exports, __webpack_require__) { + + var util = __webpack_require__(1); + var DOMutil = __webpack_require__(2); + var Component = __webpack_require__(20); + var DataStep = __webpack_require__(16); /** - * retrieve the currently selected value - * @return {*} value + * A horizontal time axis + * @param {Object} [options] See DataAxis.setOptions for the available + * options. + * @constructor DataAxis + * @extends Component + * @param body */ - Slider.prototype.get = function() { - return this.values[this.index]; - }; + function DataAxis (body, options, svg, linegraphOptions) { + this.id = util.randomUUID(); + this.body = body; + this.defaultOptions = { + orientation: 'left', // supported: 'left', 'right' + showMinorLabels: true, + showMajorLabels: true, + icons: true, + majorLinesOffset: 7, + minorLinesOffset: 4, + labelOffsetX: 10, + labelOffsetY: 2, + iconWidth: 20, + width: '40px', + visible: true, + alignZeros: true, + customRange: { + left: {min:undefined, max:undefined}, + right: {min:undefined, max:undefined} + }, + title: { + left: {text:undefined}, + right: {text:undefined} + }, + format: { + left: {decimals: undefined}, + right: {decimals: undefined} + } + }; - Slider.prototype._onMouseDown = function(event) { - // only react on left mouse button down - var leftButtonDown = event.which ? (event.which === 1) : (event.button === 1); - if (!leftButtonDown) return; + this.linegraphOptions = linegraphOptions; + this.linegraphSVG = svg; + this.props = {}; + this.DOMelements = { // dynamic elements + lines: {}, + labels: {}, + title: {} + }; - this.startClientX = event.clientX; - this.startSlideX = parseFloat(this.frame.slide.style.left); + this.dom = {}; - this.frame.style.cursor = 'move'; + this.range = {start:0, end:0}; - // add event listeners to handle moving the contents - // we store the function onmousemove and onmouseup in the graph, so we can - // remove the eventlisteners lateron in the function mouseUp() - var me = this; - this.onmousemove = function (event) {me._onMouseMove(event);}; - this.onmouseup = function (event) {me._onMouseUp(event);}; - util.addEventListener(document, 'mousemove', this.onmousemove); - util.addEventListener(document, 'mouseup', this.onmouseup); - util.preventDefault(event); - }; + this.options = util.extend({}, this.defaultOptions); + this.conversionFactor = 1; + this.setOptions(options); + this.width = Number(('' + this.options.width).replace("px","")); + this.minWidth = this.width; + this.height = this.linegraphSVG.offsetHeight; + this.hidden = false; - Slider.prototype.leftToIndex = function (left) { - var width = parseFloat(this.frame.bar.style.width) - - this.frame.slide.clientWidth - 10; - var x = left - 3; + this.stepPixels = 25; + this.stepPixelsForced = 25; + this.zeroCrossing = -1; - var index = Math.round(x / width * (this.values.length-1)); - if (index < 0) index = 0; - if (index > this.values.length-1) index = this.values.length-1; + this.lineOffset = 0; + this.master = true; + this.svgElements = {}; + this.iconsRemoved = false; - return index; - }; - Slider.prototype.indexToLeft = function (index) { - var width = parseFloat(this.frame.bar.style.width) - - this.frame.slide.clientWidth - 10; + this.groups = {}; + this.amountOfGroups = 0; - var x = index / (this.values.length-1) * width; - var left = x + 3; + // create the HTML DOM + this._create(); - return left; + var me = this; + this.body.emitter.on("verticalDrag", function() { + me.dom.lineContainer.style.top = me.body.domProps.scrollTop + 'px'; + }); + } + + DataAxis.prototype = new Component(); + + + DataAxis.prototype.addGroup = function(label, graphOptions) { + if (!this.groups.hasOwnProperty(label)) { + this.groups[label] = graphOptions; + } + this.amountOfGroups += 1; }; + DataAxis.prototype.updateGroup = function(label, graphOptions) { + this.groups[label] = graphOptions; + }; + DataAxis.prototype.removeGroup = function(label) { + if (this.groups.hasOwnProperty(label)) { + delete this.groups[label]; + this.amountOfGroups -= 1; + } + }; - Slider.prototype._onMouseMove = function (event) { - var diff = event.clientX - this.startClientX; - var x = this.startSlideX + diff; - var index = this.leftToIndex(x); + DataAxis.prototype.setOptions = function (options) { + if (options) { + var redraw = false; + if (this.options.orientation != options.orientation && options.orientation !== undefined) { + redraw = true; + } + var fields = [ + 'orientation', + 'showMinorLabels', + 'showMajorLabels', + 'icons', + 'majorLinesOffset', + 'minorLinesOffset', + 'labelOffsetX', + 'labelOffsetY', + 'iconWidth', + 'width', + 'visible', + 'customRange', + 'title', + 'format', + 'alignZeros' + ]; + util.selectiveExtend(fields, this.options, options); - this.setIndex(index); + this.minWidth = Number(('' + this.options.width).replace("px","")); - util.preventDefault(); + if (redraw == true && this.dom.frame) { + this.hide(); + this.show(); + } + } }; - Slider.prototype._onMouseUp = function (event) { - this.frame.style.cursor = 'auto'; + /** + * Create the HTML DOM for the DataAxis + */ + DataAxis.prototype._create = function() { + this.dom.frame = document.createElement('div'); + this.dom.frame.style.width = this.options.width; + this.dom.frame.style.height = this.height; - // remove event listeners - util.removeEventListener(document, 'mousemove', this.onmousemove); - util.removeEventListener(document, 'mouseup', this.onmouseup); + this.dom.lineContainer = document.createElement('div'); + this.dom.lineContainer.style.width = '100%'; + this.dom.lineContainer.style.height = this.height; + this.dom.lineContainer.style.position = 'relative'; - util.preventDefault(); + // create svg element for graph drawing. + this.svg = document.createElementNS('http://www.w3.org/2000/svg',"svg"); + this.svg.style.position = "absolute"; + this.svg.style.top = '0px'; + this.svg.style.height = '100%'; + this.svg.style.width = '100%'; + this.svg.style.display = "block"; + this.dom.frame.appendChild(this.svg); }; - module.exports = Slider; + DataAxis.prototype._redrawGroupIcons = function () { + DOMutil.prepareElements(this.svgElements); + var x; + var iconWidth = this.options.iconWidth; + var iconHeight = 15; + var iconOffset = 4; + var y = iconOffset + 0.5 * iconHeight; -/***/ }, -/* 17 */ -/***/ function(module, exports, __webpack_require__) { + if (this.options.orientation == 'left') { + x = iconOffset; + } + else { + x = this.width - iconWidth - iconOffset; + } - /** - * @prototype StepNumber - * The class StepNumber is an iterator for Numbers. You provide a start and end - * value, and a best step size. StepNumber itself rounds to fixed values and - * a finds the step that best fits the provided step. - * - * If prettyStep is true, the step size is chosen as close as possible to the - * provided step, but being a round value like 1, 2, 5, 10, 20, 50, .... - * - * Example usage: - * var step = new StepNumber(0, 10, 2.5, true); - * step.start(); - * while (!step.end()) { - * alert(step.getCurrent()); - * step.next(); - * } - * - * Version: 1.0 - * - * @param {Number} start The start value - * @param {Number} end The end value - * @param {Number} step Optional. Step size. Must be a positive value. - * @param {boolean} prettyStep Optional. If true, the step size is rounded - * To a pretty step size (like 1, 2, 5, 10, 20, 50, ...) - */ - function StepNumber(start, end, step, prettyStep) { - // set default values - this._start = 0; - this._end = 0; - this._step = 1; - this.prettyStep = true; - this.precision = 5; + for (var groupId in this.groups) { + if (this.groups.hasOwnProperty(groupId)) { + if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) { + this.groups[groupId].drawIcon(x, y, this.svgElements, this.svg, iconWidth, iconHeight); + y += iconHeight + iconOffset; + } + } + } - this._current = 0; - this.setRange(start, end, step, prettyStep); + DOMutil.cleanupElements(this.svgElements); + this.iconsRemoved = false; }; + DataAxis.prototype._cleanupIcons = function() { + if (this.iconsRemoved == false) { + DOMutil.prepareElements(this.svgElements); + DOMutil.cleanupElements(this.svgElements); + this.iconsRemoved = true; + } + } + /** - * Set a new range: start, end and step. - * - * @param {Number} start The start value - * @param {Number} end The end value - * @param {Number} step Optional. Step size. Must be a positive value. - * @param {boolean} prettyStep Optional. If true, the step size is rounded - * To a pretty step size (like 1, 2, 5, 10, 20, 50, ...) + * Create the HTML DOM for the DataAxis */ - StepNumber.prototype.setRange = function(start, end, step, prettyStep) { - this._start = start ? start : 0; - this._end = end ? end : 0; + DataAxis.prototype.show = function() { + this.hidden = false; + if (!this.dom.frame.parentNode) { + if (this.options.orientation == 'left') { + this.body.dom.left.appendChild(this.dom.frame); + } + else { + this.body.dom.right.appendChild(this.dom.frame); + } + } - this.setStep(step, prettyStep); + if (!this.dom.lineContainer.parentNode) { + this.body.dom.backgroundHorizontal.appendChild(this.dom.lineContainer); + } }; /** - * Set a new step size - * @param {Number} step New step size. Must be a positive value - * @param {boolean} prettyStep Optional. If true, the provided step is rounded - * to a pretty step size (like 1, 2, 5, 10, 20, 50, ...) + * Create the HTML DOM for the DataAxis */ - StepNumber.prototype.setStep = function(step, prettyStep) { - if (step === undefined || step <= 0) - return; - - if (prettyStep !== undefined) - this.prettyStep = prettyStep; + DataAxis.prototype.hide = function() { + this.hidden = true; + if (this.dom.frame.parentNode) { + this.dom.frame.parentNode.removeChild(this.dom.frame); + } - if (this.prettyStep === true) - this._step = StepNumber.calculatePrettyStep(step); - else - this._step = step; + if (this.dom.lineContainer.parentNode) { + this.dom.lineContainer.parentNode.removeChild(this.dom.lineContainer); + } }; /** - * Calculate a nice step size, closest to the desired step size. - * Returns a value in one of the ranges 1*10^n, 2*10^n, or 5*10^n, where n is an - * integer Number. For example 1, 2, 5, 10, 20, 50, etc... - * @param {Number} step Desired step size - * @return {Number} Nice step size + * Set a range (start and end) + * @param end + * @param start + * @param end */ - StepNumber.calculatePrettyStep = function (step) { - var log10 = function (x) {return Math.log(x) / Math.LN10;}; - - // try three steps (multiple of 1, 2, or 5 - var step1 = Math.pow(10, Math.round(log10(step))), - step2 = 2 * Math.pow(10, Math.round(log10(step / 2))), - step5 = 5 * Math.pow(10, Math.round(log10(step / 5))); + DataAxis.prototype.setRange = function (start, end) { + if (this.master == false && this.options.alignZeros == true && this.zeroCrossing != -1) { + if (start > 0) { + start = 0; + } + } + this.range.start = start; + this.range.end = end; + }; - // choose the best step (closest to minimum step) - var prettyStep = step1; - if (Math.abs(step2 - step) <= Math.abs(prettyStep - step)) prettyStep = step2; - if (Math.abs(step5 - step) <= Math.abs(prettyStep - step)) prettyStep = step5; + /** + * Repaint the component + * @return {boolean} Returns true if the component is resized + */ + DataAxis.prototype.redraw = function () { + var resized = false; + var activeGroups = 0; + + // Make sure the line container adheres to the vertical scrolling. + this.dom.lineContainer.style.top = this.body.domProps.scrollTop + 'px'; - // for safety - if (prettyStep <= 0) { - prettyStep = 1; + for (var groupId in this.groups) { + if (this.groups.hasOwnProperty(groupId)) { + if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) { + activeGroups++; + } + } + } + if (this.amountOfGroups == 0 || activeGroups == 0) { + this.hide(); } + else { + this.show(); + this.height = Number(this.linegraphSVG.style.height.replace("px","")); - return prettyStep; - }; + // svg offsetheight did not work in firefox and explorer... + this.dom.lineContainer.style.height = this.height + 'px'; + this.width = this.options.visible == true ? Number(('' + this.options.width).replace("px","")) : 0; - /** - * returns the current value of the step - * @return {Number} current value - */ - StepNumber.prototype.getCurrent = function () { - return parseFloat(this._current.toPrecision(this.precision)); - }; + var props = this.props; + var frame = this.dom.frame; - /** - * returns the current step size - * @return {Number} current step size - */ - StepNumber.prototype.getStep = function () { - return this._step; - }; + // update classname + frame.className = 'dataaxis'; - /** - * Set the current value to the largest value smaller than start, which - * is a multiple of the step size - */ - StepNumber.prototype.start = function() { - this._current = this._start - this._start % this._step; - }; + // calculate character width and height + this._calculateCharSize(); - /** - * Do a step, add the step size to the current value - */ - StepNumber.prototype.next = function () { - this._current += this._step; - }; + var orientation = this.options.orientation; + var showMinorLabels = this.options.showMinorLabels; + var showMajorLabels = this.options.showMajorLabels; - /** - * Returns true whether the end is reached - * @return {boolean} True if the current value has passed the end value. - */ - StepNumber.prototype.end = function () { - return (this._current > this._end); - }; + // determine the width and height of the elements for the axis + props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; + props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; - module.exports = StepNumber; + props.minorLineWidth = this.body.dom.backgroundHorizontal.offsetWidth - this.lineOffset - this.width + 2 * this.options.minorLinesOffset; + props.minorLineHeight = 1; + props.majorLineWidth = this.body.dom.backgroundHorizontal.offsetWidth - this.lineOffset - this.width + 2 * this.options.majorLinesOffset; + props.majorLineHeight = 1; + + // take frame offline while updating (is almost twice as fast) + if (orientation == 'left') { + frame.style.top = '0'; + frame.style.left = '0'; + frame.style.bottom = ''; + frame.style.width = this.width + 'px'; + frame.style.height = this.height + "px"; + this.props.width = this.body.domProps.left.width; + this.props.height = this.body.domProps.left.height; + } + else { // right + frame.style.top = ''; + frame.style.bottom = '0'; + frame.style.left = '0'; + frame.style.width = this.width + 'px'; + frame.style.height = this.height + "px"; + this.props.width = this.body.domProps.right.width; + this.props.height = this.body.domProps.right.height; + } + resized = this._redrawLabels(); + resized = this._isResized() || resized; -/***/ }, -/* 18 */ -/***/ function(module, exports, __webpack_require__) { + if (this.options.icons == true) { + this._redrawGroupIcons(); + } + else { + this._cleanupIcons(); + } - var Emitter = __webpack_require__(11); - var Hammer = __webpack_require__(19); - var util = __webpack_require__(1); - var DataSet = __webpack_require__(7); - var DataView = __webpack_require__(9); - var Range = __webpack_require__(21); - var Core = __webpack_require__(25); - var TimeAxis = __webpack_require__(37); - var CurrentTime = __webpack_require__(39); - var CustomTime = __webpack_require__(41); - var ItemSet = __webpack_require__(26); + this._redrawTitle(orientation); + } + return resized; + }; /** - * Create a timeline visualization - * @param {HTMLElement} container - * @param {vis.DataSet | Array | google.visualization.DataTable} [items] - * @param {vis.DataSet | Array | google.visualization.DataTable} [groups] - * @param {Object} [options] See Timeline.setOptions for the available options. - * @constructor - * @extends Core + * Repaint major and minor text labels and vertical grid lines + * @private */ - function Timeline (container, items, groups, options) { - if (!(this instanceof Timeline)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } + DataAxis.prototype._redrawLabels = function () { + var resized = false; + DOMutil.prepareElements(this.DOMelements.lines); + DOMutil.prepareElements(this.DOMelements.labels); - // if the third element is options, the forth is groups (optionally); - if (!(Array.isArray(groups) || groups instanceof DataSet) && groups instanceof Object) { - var forthArgument = options; - options = groups; - groups = forthArgument; - } + var orientation = this.options['orientation']; - var me = this; - this.defaultOptions = { - start: null, - end: null, + // calculate range and step (step such that we have space for 7 characters per label) + var minimumStep = this.master ? this.props.majorCharHeight || 10 : this.stepPixelsForced; - autoResize: true, + var step = new DataStep( + this.range.start, + this.range.end, + minimumStep, + this.dom.frame.offsetHeight, + this.options.customRange[this.options.orientation], + this.master == false && this.options.alignZeros // doess the step have to align zeros? only if not master and the options is on + ); - orientation: 'bottom', - width: null, - height: null, - maxHeight: null, - minHeight: null - }; - this.options = util.deepExtend({}, this.defaultOptions); + this.step = step; + // get the distance in pixels for a step + // dead space is space that is "left over" after a step + var stepPixels = (this.dom.frame.offsetHeight - (step.deadSpace * (this.dom.frame.offsetHeight / step.marginRange))) / (((step.marginRange - step.deadSpace) / step.step)); - // Create the DOM, props, and emitter - this._create(container); + this.stepPixels = stepPixels; - // all components listed here will be repainted automatically - this.components = []; + var amountOfSteps = this.height / stepPixels; + var stepDifference = 0; - this.body = { - dom: this.dom, - domProps: this.props, - emitter: { - on: this.on.bind(this), - off: this.off.bind(this), - emit: this.emit.bind(this) - }, - hiddenDates: [], - util: { - snap: null, // will be specified after TimeAxis is created - toScreen: me._toScreen.bind(me), - toGlobalScreen: me._toGlobalScreen.bind(me), // this refers to the root.width - toTime: me._toTime.bind(me), - toGlobalTime : me._toGlobalTime.bind(me) + // the slave axis needs to use the same horizontal lines as the master axis. + if (this.master == false) { + stepPixels = this.stepPixelsForced; + stepDifference = Math.round((this.dom.frame.offsetHeight / stepPixels) - amountOfSteps); + for (var i = 0; i < 0.5 * stepDifference; i++) { + step.previous(); } - }; + amountOfSteps = this.height / stepPixels; - // range - this.range = new Range(this.body); - this.components.push(this.range); - this.body.range = this.range; + if (this.zeroCrossing != -1 && this.options.alignZeros == true) { + var zeroStepDifference = (step.marginEnd / step.step) - this.zeroCrossing; + if (zeroStepDifference > 0) { + for (var i = 0; i < zeroStepDifference; i++) {step.next();} + } + else if (zeroStepDifference < 0) { + for (var i = 0; i < -zeroStepDifference; i++) {step.previous();} + } + } + } + else { + amountOfSteps += 0.25; + } - // time axis - this.timeAxis = new TimeAxis(this.body); - this.components.push(this.timeAxis); - this.body.util.snap = this.timeAxis.snap.bind(this.timeAxis); - // current time bar - this.currentTime = new CurrentTime(this.body); - this.components.push(this.currentTime); + this.valueAtZero = step.marginEnd; + var marginStartPos = 0; - // custom time bar - // Note: time bar will be attached in this.setOptions when selected - this.customTime = new CustomTime(this.body); - this.components.push(this.customTime); + // do not draw the first label + var max = 1; - // item set - this.itemSet = new ItemSet(this.body); - this.components.push(this.itemSet); + // Get the number of decimal places + var decimals; + if(this.options.format[orientation] !== undefined) { + decimals = this.options.format[orientation].decimals; + } - this.itemsData = null; // DataSet - this.groupsData = null; // DataSet + this.maxLabelSize = 0; + var y = 0; + while (max < Math.round(amountOfSteps)) { + step.next(); + y = Math.round(max * stepPixels); + marginStartPos = max * stepPixels; + var isMajor = step.isMajor(); - // apply options - if (options) { - this.setOptions(options); - } + if (this.options['showMinorLabels'] && isMajor == false || this.master == false && this.options['showMinorLabels'] == true) { + this._redrawLabel(y - 2, step.getCurrent(decimals), orientation, 'yAxis minor', this.props.minorCharHeight); + } - // IMPORTANT: THIS HAPPENS BEFORE SET ITEMS! - if (groups) { - this.setGroups(groups); + if (isMajor && this.options['showMajorLabels'] && this.master == true || + this.options['showMinorLabels'] == false && this.master == false && isMajor == true) { + if (y >= 0) { + this._redrawLabel(y - 2, step.getCurrent(decimals), orientation, 'yAxis major', this.props.majorCharHeight); + } + this._redrawLine(y, orientation, 'grid horizontal major', this.options.majorLinesOffset, this.props.majorLineWidth); + } + else { + this._redrawLine(y, orientation, 'grid horizontal minor', this.options.minorLinesOffset, this.props.minorLineWidth); + } + + if (this.master == true && step.current == 0) { + this.zeroCrossing = max; + } + + max++; } - // create itemset - if (items) { - this.setItems(items); + if (this.master == false) { + this.conversionFactor = y / (this.valueAtZero - step.current); } else { - this.redraw(); + this.conversionFactor = this.dom.frame.offsetHeight / step.marginRange; } - } - - // Extend the functionality from Core - Timeline.prototype = new Core(); - /** - * Set items - * @param {vis.DataSet | Array | google.visualization.DataTable | null} items - */ - Timeline.prototype.setItems = function(items) { - var initialLoad = (this.itemsData == null); + // Note that title is rotated, so we're using the height, not width! + var titleWidth = 0; + if (this.options.title[orientation] !== undefined && this.options.title[orientation].text !== undefined) { + titleWidth = this.props.titleCharHeight; + } + var offset = this.options.icons == true ? Math.max(this.options.iconWidth, titleWidth) + this.options.labelOffsetX + 15 : titleWidth + this.options.labelOffsetX + 15; - // convert to type DataSet when needed - var newDataSet; - if (!items) { - newDataSet = null; + // this will resize the yAxis to accommodate the labels. + if (this.maxLabelSize > (this.width - offset) && this.options.visible == true) { + this.width = this.maxLabelSize + offset; + this.options.width = this.width + "px"; + DOMutil.cleanupElements(this.DOMelements.lines); + DOMutil.cleanupElements(this.DOMelements.labels); + this.redraw(); + resized = true; } - else if (items instanceof DataSet || items instanceof DataView) { - newDataSet = items; + // this will resize the yAxis if it is too big for the labels. + else if (this.maxLabelSize < (this.width - offset) && this.options.visible == true && this.width > this.minWidth) { + this.width = Math.max(this.minWidth,this.maxLabelSize + offset); + this.options.width = this.width + "px"; + DOMutil.cleanupElements(this.DOMelements.lines); + DOMutil.cleanupElements(this.DOMelements.labels); + this.redraw(); + resized = true; } else { - // turn an array into a dataset - newDataSet = new DataSet(items, { - type: { - start: 'Date', - end: 'Date' - } - }); + DOMutil.cleanupElements(this.DOMelements.lines); + DOMutil.cleanupElements(this.DOMelements.labels); + resized = false; } - // set items - this.itemsData = newDataSet; - this.itemSet && this.itemSet.setItems(newDataSet); - - if (initialLoad) { - if (this.options.start != undefined || this.options.end != undefined) { - if (this.options.start == undefined || this.options.end == undefined) { - var dataRange = this._getDataRange(); - } - - var start = this.options.start != undefined ? this.options.start : dataRange.start; - var end = this.options.end != undefined ? this.options.end : dataRange.end; + return resized; + }; - this.setWindow(start, end, {animate: false}); - } - else { - this.fit({animate: false}); - } - } + DataAxis.prototype.convertValue = function (value) { + var invertedValue = this.valueAtZero - value; + var convertedValue = invertedValue * this.conversionFactor; + return convertedValue; }; /** - * Set groups - * @param {vis.DataSet | Array | google.visualization.DataTable} groups + * Create a label for the axis at position x + * @private + * @param y + * @param text + * @param orientation + * @param className + * @param characterHeight */ - Timeline.prototype.setGroups = function(groups) { - // convert to type DataSet when needed - var newDataSet; - if (!groups) { - newDataSet = null; - } - else if (groups instanceof DataSet || groups instanceof DataView) { - newDataSet = groups; + DataAxis.prototype._redrawLabel = function (y, text, orientation, className, characterHeight) { + // reuse redundant label + var label = DOMutil.getDOMElement('div',this.DOMelements.labels, this.dom.frame); //this.dom.redundant.labels.shift(); + label.className = className; + label.innerHTML = text; + if (orientation == 'left') { + label.style.left = '-' + this.options.labelOffsetX + 'px'; + label.style.textAlign = "right"; } else { - // turn an array into a dataset - newDataSet = new DataSet(groups); + label.style.right = '-' + this.options.labelOffsetX + 'px'; + label.style.textAlign = "left"; } - this.groupsData = newDataSet; - this.itemSet.setGroups(newDataSet); - }; + label.style.top = y - 0.5 * characterHeight + this.options.labelOffsetY + 'px'; - /** - * Set selected items by their id. Replaces the current selection - * Unknown id's are silently ignored. - * @param {string[] | string} [ids] An array with zero or more id's of the items to be - * selected. If ids is an empty array, all items will be - * unselected. - * @param {Object} [options] Available options: - * `focus: boolean` - * If true, focus will be set to the selected item(s) - * `animate: boolean | number` - * If true (default), the range is animated - * smoothly to the new window. - * If a number, the number is taken as duration - * for the animation. Default duration is 500 ms. - * Only applicable when option focus is true. - */ - Timeline.prototype.setSelection = function(ids, options) { - this.itemSet && this.itemSet.setSelection(ids); + text += ''; - if (options && options.focus) { - this.focus(ids, options); + var largestWidth = Math.max(this.props.majorCharWidth,this.props.minorCharWidth); + if (this.maxLabelSize < text.length * largestWidth) { + this.maxLabelSize = text.length * largestWidth; } }; /** - * Get the selected items by their id - * @return {Array} ids The ids of the selected items + * Create a minor line for the axis at position y + * @param y + * @param orientation + * @param className + * @param offset + * @param width */ - Timeline.prototype.getSelection = function() { - return this.itemSet && this.itemSet.getSelection() || []; + DataAxis.prototype._redrawLine = function (y, orientation, className, offset, width) { + if (this.master == true) { + var line = DOMutil.getDOMElement('div',this.DOMelements.lines, this.dom.lineContainer);//this.dom.redundant.lines.shift(); + line.className = className; + line.innerHTML = ''; + + if (orientation == 'left') { + line.style.left = (this.width - offset) + 'px'; + } + else { + line.style.right = (this.width - offset) + 'px'; + } + + line.style.width = width + 'px'; + line.style.top = y + 'px'; + } }; /** - * Adjust the visible window such that the selected item (or multiple items) - * are centered on screen. - * @param {String | String[]} id An item id or array with item ids - * @param {Object} [options] Available options: - * `animate: boolean | number` - * If true (default), the range is animated - * smoothly to the new window. - * If a number, the number is taken as duration - * for the animation. Default duration is 500 ms. - * Only applicable when option focus is true + * Create a title for the axis + * @private + * @param orientation */ - Timeline.prototype.focus = function(id, options) { - if (!this.itemsData || id == undefined) return; + DataAxis.prototype._redrawTitle = function (orientation) { + DOMutil.prepareElements(this.DOMelements.title); - var ids = Array.isArray(id) ? id : [id]; + // Check if the title is defined for this axes + if (this.options.title[orientation] !== undefined && this.options.title[orientation].text !== undefined) { + var title = DOMutil.getDOMElement('div', this.DOMelements.title, this.dom.frame); + title.className = 'yAxis title ' + orientation; + title.innerHTML = this.options.title[orientation].text; - // get the specified item(s) - var itemsData = this.itemsData.getDataSet().get(ids, { - type: { - start: 'Date', - end: 'Date' + // Add style - if provided + if (this.options.title[orientation].style !== undefined) { + util.addCssText(title, this.options.title[orientation].style); } - }); - - // calculate minimum start and maximum end of specified items - var start = null; - var end = null; - itemsData.forEach(function (itemData) { - var s = itemData.start.valueOf(); - var e = 'end' in itemData ? itemData.end.valueOf() : itemData.start.valueOf(); - if (start === null || s < start) { - start = s; + if (orientation == 'left') { + title.style.left = this.props.titleCharHeight + 'px'; } - - if (end === null || e > end) { - end = e; + else { + title.style.right = this.props.titleCharHeight + 'px'; } - }); - - if (start !== null && end !== null) { - // calculate the new middle and interval for the window - var middle = (start + end) / 2; - var interval = Math.max((this.range.end - this.range.start), (end - start) * 1.1); - var animate = (options && options.animate !== undefined) ? options.animate : true; - this.range.setRange(middle - interval / 2, middle + interval / 2, animate); + title.style.width = this.height + 'px'; } + + // we need to clean up in case we did not use all elements. + DOMutil.cleanupElements(this.DOMelements.title); }; - /** - * Get the data range of the item set. - * @returns {{min: Date, max: Date}} range A range with a start and end Date. - * When no minimum is found, min==null - * When no maximum is found, max==null - */ - Timeline.prototype.getItemRange = function() { - // calculate min from start filed - var dataset = this.itemsData.getDataSet(), - min = null, - max = null; - if (dataset) { - // calculate the minimum value of the field 'start' - var minItem = dataset.min('start'); - min = minItem ? util.convert(minItem.start, 'Date').valueOf() : null; - // Note: we convert first to Date and then to number because else - // a conversion from ISODate to Number will fail - // calculate maximum value of fields 'start' and 'end' - var maxStartItem = dataset.max('start'); - if (maxStartItem) { - max = util.convert(maxStartItem.start, 'Date').valueOf(); - } - var maxEndItem = dataset.max('end'); - if (maxEndItem) { - if (max == null) { - max = util.convert(maxEndItem.end, 'Date').valueOf(); - } - else { - max = Math.max(max, util.convert(maxEndItem.end, 'Date').valueOf()); - } - } + + /** + * Determine the size of text on the axis (both major and minor axis). + * The size is calculated only once and then cached in this.props. + * @private + */ + DataAxis.prototype._calculateCharSize = function () { + // determine the char width and height on the minor axis + if (!('minorCharHeight' in this.props)) { + var textMinor = document.createTextNode('0'); + var measureCharMinor = document.createElement('div'); + measureCharMinor.className = 'yAxis minor measure'; + measureCharMinor.appendChild(textMinor); + this.dom.frame.appendChild(measureCharMinor); + + this.props.minorCharHeight = measureCharMinor.clientHeight; + this.props.minorCharWidth = measureCharMinor.clientWidth; + + this.dom.frame.removeChild(measureCharMinor); } - return { - min: (min != null) ? new Date(min) : null, - max: (max != null) ? new Date(max) : null - }; - }; + if (!('majorCharHeight' in this.props)) { + var textMajor = document.createTextNode('0'); + var measureCharMajor = document.createElement('div'); + measureCharMajor.className = 'yAxis major measure'; + measureCharMajor.appendChild(textMajor); + this.dom.frame.appendChild(measureCharMajor); + this.props.majorCharHeight = measureCharMajor.clientHeight; + this.props.majorCharWidth = measureCharMajor.clientWidth; - module.exports = Timeline; + this.dom.frame.removeChild(measureCharMajor); + } + if (!('titleCharHeight' in this.props)) { + var textTitle = document.createTextNode('0'); + var measureCharTitle = document.createElement('div'); + measureCharTitle.className = 'yAxis title measure'; + measureCharTitle.appendChild(textTitle); + this.dom.frame.appendChild(measureCharTitle); -/***/ }, -/* 19 */ -/***/ function(module, exports, __webpack_require__) { + this.props.titleCharHeight = measureCharTitle.clientHeight; + this.props.titleCharWidth = measureCharTitle.clientWidth; - // Only load hammer.js when in a browser environment - // (loading hammer.js in a node.js environment gives errors) - if (typeof window !== 'undefined') { - module.exports = window['Hammer'] || __webpack_require__(20); - } - else { - module.exports = function () { - throw Error('hammer.js is only available in a browser, not in node.js.'); + this.dom.frame.removeChild(measureCharTitle); } - } + }; + + /** + * 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 + */ + DataAxis.prototype.snap = function(date) { + return this.step.snap(date); + }; + + module.exports = DataAxis; /***/ }, -/* 20 */ +/* 24 */ /***/ function(module, exports, __webpack_require__) { - var __WEBPACK_AMD_DEFINE_RESULT__;/*! Hammer.JS - v1.1.3 - 2014-05-20 - * http://eightmedia.github.io/hammer.js - * - * Copyright (c) 2014 Jorik Tangelder ; - * Licensed under the MIT license */ - - (function(window, undefined) { - 'use strict'; + var util = __webpack_require__(1); + var DOMutil = __webpack_require__(2); + var Line = __webpack_require__(49); + var Bar = __webpack_require__(50); + var Points = __webpack_require__(51); /** - * @main - * @module hammer - * - * @class Hammer - * @static + * /** + * @param {object} group | the object of the group from the dataset + * @param {string} groupId | ID of the group + * @param {object} options | the default options + * @param {array} groupsUsingDefaultStyles | this array has one entree. + * It is passed as an array so it is passed by reference. + * It enumerates through the default styles + * @constructor */ + function GraphGroup (group, groupId, options, groupsUsingDefaultStyles) { + this.id = groupId; + var fields = ['sampling','style','sort','yAxisOrientation','barChart','drawPoints','shaded','catmullRom'] + this.options = util.selectiveBridgeObject(fields,options); + this.usingDefaultStyle = group.className === undefined; + this.groupsUsingDefaultStyles = groupsUsingDefaultStyles; + this.zeroPosition = 0; + this.update(group); + if (this.usingDefaultStyle == true) { + this.groupsUsingDefaultStyles[0] += 1; + } + this.itemsData = []; + this.visible = group.visible === undefined ? true : group.visible; + } + /** - * Hammer, use this to create instances - * ```` - * var hammertime = new Hammer(myElement); - * ```` - * - * @method Hammer - * @param {HTMLElement} element - * @param {Object} [options={}] - * @return {Hammer.Instance} + * this loads a reference to all items in this group into this group. + * @param {array} items */ - var Hammer = function Hammer(element, options) { - return new Hammer.Instance(element, options || {}); + GraphGroup.prototype.setItems = function(items) { + if (items != null) { + this.itemsData = items; + if (this.options.sort == true) { + this.itemsData.sort(function (a,b) {return a.x - b.x;}) + } + } + else { + this.itemsData = []; + } }; - /** - * version, as defined in package.json - * the value will be set at each build - * @property VERSION - * @final - * @type {String} - */ - Hammer.VERSION = '1.1.3'; /** - * default settings. - * more settings are defined per gesture at `/gestures`. Each gesture can be disabled/enabled - * by setting it's name (like `swipe`) to false. - * You can set the defaults for all instances by changing this object before creating an instance. - * @example - * ```` - * Hammer.defaults.drag = false; - * Hammer.defaults.behavior.touchAction = 'pan-y'; - * delete Hammer.defaults.behavior.userSelect; - * ```` - * @property defaults - * @type {Object} + * this is used for plotting barcharts, this way, we only have to calculate it once. + * @param pos */ - Hammer.defaults = { - /** - * this setting object adds styles and attributes to the element to prevent the browser from doing - * its native behavior. The css properties are auto prefixed for the browsers when needed. - * @property defaults.behavior - * @type {Object} - */ - behavior: { - /** - * Disables text selection to improve the dragging gesture. When the value is `none` it also sets - * `onselectstart=false` for IE on the element. Mainly for desktop browsers. - * @property defaults.behavior.userSelect - * @type {String} - * @default 'none' - */ - userSelect: 'none', - - /** - * Specifies whether and how a given region can be manipulated by the user (for instance, by panning or zooming). - * Used by Chrome 35> and IE10>. By default this makes the element blocking any touch event. - * @property defaults.behavior.touchAction - * @type {String} - * @default: 'pan-y' - */ - touchAction: 'pan-y', + GraphGroup.prototype.setZeroPosition = function(pos) { + this.zeroPosition = pos; + }; - /** - * Disables the default callout shown when you touch and hold a touch target. - * On iOS, when you touch and hold a touch target such as a link, Safari displays - * a callout containing information about the link. This property allows you to disable that callout. - * @property defaults.behavior.touchCallout - * @type {String} - * @default 'none' - */ - touchCallout: 'none', - /** - * Specifies whether zooming is enabled. Used by IE10> - * @property defaults.behavior.contentZooming - * @type {String} - * @default 'none' - */ - contentZooming: 'none', + /** + * set the options of the graph group over the default options. + * @param options + */ + GraphGroup.prototype.setOptions = function(options) { + if (options !== undefined) { + var fields = ['sampling','style','sort','yAxisOrientation','barChart']; + util.selectiveDeepExtend(fields, this.options, options); - /** - * Specifies that an entire element should be draggable instead of its contents. - * Mainly for desktop browsers. - * @property defaults.behavior.userDrag - * @type {String} - * @default 'none' - */ - userDrag: 'none', + util.mergeOptions(this.options, options,'catmullRom'); + util.mergeOptions(this.options, options,'drawPoints'); + util.mergeOptions(this.options, options,'shaded'); - /** - * Overrides the highlight color shown when the user taps a link or a JavaScript - * clickable element in Safari on iPhone. This property obeys the alpha value, if specified. - * - * If you don't specify an alpha value, Safari on iPhone applies a default alpha value - * to the color. To disable tap highlighting, set the alpha value to 0 (invisible). - * If you set the alpha value to 1.0 (opaque), the element is not visible when tapped. - * @property defaults.behavior.tapHighlightColor - * @type {String} - * @default 'rgba(0,0,0,0)' - */ - tapHighlightColor: 'rgba(0,0,0,0)' + if (options.catmullRom) { + if (typeof options.catmullRom == 'object') { + if (options.catmullRom.parametrization) { + if (options.catmullRom.parametrization == 'uniform') { + this.options.catmullRom.alpha = 0; + } + else if (options.catmullRom.parametrization == 'chordal') { + this.options.catmullRom.alpha = 1.0; + } + else { + this.options.catmullRom.parametrization = 'centripetal'; + this.options.catmullRom.alpha = 0.5; + } + } + } } + } + + if (this.options.style == 'line') { + this.type = new Line(this.id, this.options); + } + else if (this.options.style == 'bar') { + this.type = new Bar(this.id, this.options); + } + else if (this.options.style == 'points') { + this.type = new Points(this.id, this.options); + } }; - /** - * hammer document where the base events are added at - * @property DOCUMENT - * @type {HTMLElement} - * @default window.document - */ - Hammer.DOCUMENT = document; /** - * detect support for pointer events - * @property HAS_POINTEREVENTS - * @type {Boolean} + * this updates the current group class with the latest group dataset entree, used in _updateGroup in linegraph + * @param group */ - Hammer.HAS_POINTEREVENTS = navigator.pointerEnabled || navigator.msPointerEnabled; + GraphGroup.prototype.update = function(group) { + this.group = group; + this.content = group.content || 'graph'; + this.className = group.className || this.className || "graphGroup" + this.groupsUsingDefaultStyles[0] % 10; + this.visible = group.visible === undefined ? true : group.visible; + this.style = group.style; + this.setOptions(group.options); + }; - /** - * detect support for touch events - * @property HAS_TOUCHEVENTS - * @type {Boolean} - */ - Hammer.HAS_TOUCHEVENTS = ('ontouchstart' in window); /** - * detect mobile browsers - * @property IS_MOBILE - * @type {Boolean} + * draw the icon for the legend. + * + * @param x + * @param y + * @param JSONcontainer + * @param SVGcontainer + * @param iconWidth + * @param iconHeight */ - Hammer.IS_MOBILE = /mobile|tablet|ip(ad|hone|od)|android|silk/i.test(navigator.userAgent); + GraphGroup.prototype.drawIcon = function(x, y, JSONcontainer, SVGcontainer, iconWidth, iconHeight) { + var fillHeight = iconHeight * 0.5; + var path, fillPath; - /** - * detect if we want to support mouseevents at all - * @property NO_MOUSEEVENTS - * @type {Boolean} - */ - Hammer.NO_MOUSEEVENTS = (Hammer.HAS_TOUCHEVENTS && Hammer.IS_MOBILE) || Hammer.HAS_POINTEREVENTS; + var outline = DOMutil.getSVGElement("rect", JSONcontainer, SVGcontainer); + outline.setAttributeNS(null, "x", x); + outline.setAttributeNS(null, "y", y - fillHeight); + outline.setAttributeNS(null, "width", iconWidth); + outline.setAttributeNS(null, "height", 2*fillHeight); + outline.setAttributeNS(null, "class", "outline"); - /** - * interval in which Hammer recalculates current velocity/direction/angle in ms - * @property CALCULATE_INTERVAL - * @type {Number} - * @default 25 - */ - Hammer.CALCULATE_INTERVAL = 25; + if (this.options.style == 'line') { + path = DOMutil.getSVGElement("path", JSONcontainer, SVGcontainer); + path.setAttributeNS(null, "class", this.className); + if(this.style !== undefined) { + path.setAttributeNS(null, "style", this.style); + } - /** - * eventtypes per touchevent (start, move, end) are filled by `Event.determineEventTypes` on `setup` - * the object contains the DOM event names per type (`EVENT_START`, `EVENT_MOVE`, `EVENT_END`) - * @property EVENT_TYPES - * @private - * @writeOnce - * @type {Object} - */ - var EVENT_TYPES = {}; + path.setAttributeNS(null, "d", "M" + x + ","+y+" L" + (x + iconWidth) + ","+y+""); + if (this.options.shaded.enabled == true) { + fillPath = DOMutil.getSVGElement("path", JSONcontainer, SVGcontainer); + if (this.options.shaded.orientation == 'top') { + fillPath.setAttributeNS(null, "d", "M"+x+", " + (y - fillHeight) + + "L"+x+","+y+" L"+ (x + iconWidth) + ","+y+" L"+ (x + iconWidth) + "," + (y - fillHeight)); + } + else { + fillPath.setAttributeNS(null, "d", "M"+x+","+y+" " + + "L"+x+"," + (y + fillHeight) + " " + + "L"+ (x + iconWidth) + "," + (y + fillHeight) + + "L"+ (x + iconWidth) + ","+y); + } + fillPath.setAttributeNS(null, "class", this.className + " iconFill"); + } - /** - * direction strings, for safe comparisons - * @property DIRECTION_DOWN|LEFT|UP|RIGHT - * @final - * @type {String} - * @default 'down' 'left' 'up' 'right' - */ - var DIRECTION_DOWN = Hammer.DIRECTION_DOWN = 'down'; - var DIRECTION_LEFT = Hammer.DIRECTION_LEFT = 'left'; - var DIRECTION_UP = Hammer.DIRECTION_UP = 'up'; - var DIRECTION_RIGHT = Hammer.DIRECTION_RIGHT = 'right'; + if (this.options.drawPoints.enabled == true) { + DOMutil.drawPoint(x + 0.5 * iconWidth,y, this, JSONcontainer, SVGcontainer); + } + } + else { + var barWidth = Math.round(0.3 * iconWidth); + var bar1Height = Math.round(0.4 * iconHeight); + var bar2Height = Math.round(0.75 * iconHeight); - /** - * pointertype strings, for safe comparisons - * @property POINTER_MOUSE|TOUCH|PEN - * @final - * @type {String} - * @default 'mouse' 'touch' 'pen' - */ - var POINTER_MOUSE = Hammer.POINTER_MOUSE = 'mouse'; - var POINTER_TOUCH = Hammer.POINTER_TOUCH = 'touch'; - var POINTER_PEN = Hammer.POINTER_PEN = 'pen'; + var offset = Math.round((iconWidth - (2 * barWidth))/3); - /** - * eventtypes - * @property EVENT_START|MOVE|END|RELEASE|TOUCH - * @final - * @type {String} - * @default 'start' 'change' 'move' 'end' 'release' 'touch' - */ - var EVENT_START = Hammer.EVENT_START = 'start'; - var EVENT_MOVE = Hammer.EVENT_MOVE = 'move'; - var EVENT_END = Hammer.EVENT_END = 'end'; - var EVENT_RELEASE = Hammer.EVENT_RELEASE = 'release'; - var EVENT_TOUCH = Hammer.EVENT_TOUCH = 'touch'; + DOMutil.drawBar(x + 0.5*barWidth + offset , y + fillHeight - bar1Height - 1, barWidth, bar1Height, this.className + ' bar', JSONcontainer, SVGcontainer); + DOMutil.drawBar(x + 1.5*barWidth + offset + 2, y + fillHeight - bar2Height - 1, barWidth, bar2Height, this.className + ' bar', JSONcontainer, SVGcontainer); + } + }; - /** - * if the window events are set... - * @property READY - * @writeOnce - * @type {Boolean} - * @default false - */ - Hammer.READY = false; /** - * plugins namespace - * @property plugins - * @type {Object} + * return the legend entree for this group. + * + * @param iconWidth + * @param iconHeight + * @returns {{icon: HTMLElement, label: (group.content|*|string), orientation: (.options.yAxisOrientation|*)}} */ - Hammer.plugins = Hammer.plugins || {}; + GraphGroup.prototype.getLegend = function(iconWidth, iconHeight) { + var svg = document.createElementNS('http://www.w3.org/2000/svg',"svg"); + this.drawIcon(0,0.5*iconHeight,[],svg,iconWidth,iconHeight); + return {icon: svg, label: this.content, orientation:this.options.yAxisOrientation}; + } - /** - * gestures namespace - * see `/gestures` for the definitions - * @property gestures - * @type {Object} - */ - Hammer.gestures = Hammer.gestures || {}; + GraphGroup.prototype.getYRange = function(groupData) { + return this.type.getYRange(groupData); + } - /** - * setup events to detect gestures on the document - * this function is called when creating an new instance - * @private - */ - function setup() { - if(Hammer.READY) { - return; - } + GraphGroup.prototype.draw = function(dataset, group, framework) { + this.type.draw(dataset, group, framework); + } - // find what eventtypes we add listeners to - Event.determineEventTypes(); - // Register all gestures inside Hammer.gestures - Utils.each(Hammer.gestures, function(gesture) { - Detection.register(gesture); - }); + module.exports = GraphGroup; - // Add touch events on the document - Event.onTouch(Hammer.DOCUMENT, EVENT_MOVE, Detection.detect); - Event.onTouch(Hammer.DOCUMENT, EVENT_END, Detection.detect); - // Hammer is ready...! - Hammer.READY = true; - } +/***/ }, +/* 25 */ +/***/ function(module, exports, __webpack_require__) { + + var util = __webpack_require__(1); + var stack = __webpack_require__(18); + var RangeItem = __webpack_require__(35); /** - * @module hammer - * - * @class Utils - * @static + * @constructor Group + * @param {Number | String} groupId + * @param {Object} data + * @param {ItemSet} itemSet */ - var Utils = Hammer.utils = { - /** - * extend method, could also be used for cloning when `dest` is an empty object. - * changes the dest object - * @method extend - * @param {Object} dest - * @param {Object} src - * @param {Boolean} [merge=false] do a merge - * @return {Object} dest - */ - extend: function extend(dest, src, merge) { - for(var key in src) { - if(!src.hasOwnProperty(key) || (dest[key] !== undefined && merge)) { - continue; - } - dest[key] = src[key]; - } - return dest; - }, - - /** - * simple addEventListener wrapper - * @method on - * @param {HTMLElement} element - * @param {String} type - * @param {Function} handler - */ - on: function on(element, type, handler) { - element.addEventListener(type, handler, false); - }, - - /** - * simple removeEventListener wrapper - * @method off - * @param {HTMLElement} element - * @param {String} type - * @param {Function} handler - */ - off: function off(element, type, handler) { - element.removeEventListener(type, handler, false); - }, + function Group (groupId, data, itemSet) { + this.groupId = groupId; + this.subgroups = {}; + this.subgroupIndex = 0; + this.subgroupOrderer = data && data.subgroupOrder; + this.itemSet = itemSet; - /** - * forEach over arrays and objects - * @method each - * @param {Object|Array} obj - * @param {Function} iterator - * @param {any} iterator.item - * @param {Number} iterator.index - * @param {Object|Array} iterator.obj the source object - * @param {Object} context value to use as `this` in the iterator - */ - each: function each(obj, iterator, context) { - var i, len; + this.dom = {}; + this.props = { + label: { + width: 0, + height: 0 + } + }; + this.className = null; - // native forEach on arrays - if('forEach' in obj) { - obj.forEach(iterator, context); - // arrays - } else if(obj.length !== undefined) { - for(i = 0, len = obj.length; i < len; i++) { - if(iterator.call(context, obj[i], i, obj) === false) { - return; - } - } - // objects - } else { - for(i in obj) { - if(obj.hasOwnProperty(i) && - iterator.call(context, obj[i], i, obj) === false) { - return; - } - } - } - }, + this.items = {}; // items filtered by groupId of this group + this.visibleItems = []; // items currently visible in window + this.orderedItems = { + byStart: [], + byEnd: [] + }; + this.checkRangedItems = false; // needed to refresh the ranged items if the window is programatically changed with NO overlap. + var me = this; + this.itemSet.body.emitter.on("checkRangedItems", function () { + me.checkRangedItems = true; + }) - /** - * find if a string contains the string using indexOf - * @method inStr - * @param {String} src - * @param {String} find - * @return {Boolean} found - */ - inStr: function inStr(src, find) { - return src.indexOf(find) > -1; - }, + this._create(); - /** - * find if a array contains the object using indexOf or a simple polyfill - * @method inArray - * @param {String} src - * @param {String} find - * @return {Boolean|Number} false when not found, or the index - */ - inArray: function inArray(src, find) { - if(src.indexOf) { - var index = src.indexOf(find); - return (index === -1) ? false : index; - } else { - for(var i = 0, len = src.length; i < len; i++) { - if(src[i] === find) { - return i; - } - } - return false; - } - }, + this.setData(data); + } - /** - * convert an array-like object (`arguments`, `touchlist`) to an array - * @method toArray - * @param {Object} obj - * @return {Array} - */ - toArray: function toArray(obj) { - return Array.prototype.slice.call(obj, 0); - }, + /** + * Create DOM elements for the group + * @private + */ + Group.prototype._create = function() { + var label = document.createElement('div'); + label.className = 'vlabel'; + this.dom.label = label; - /** - * find if a node is in the given parent - * @method hasParent - * @param {HTMLElement} node - * @param {HTMLElement} parent - * @return {Boolean} found - */ - hasParent: function hasParent(node, parent) { - while(node) { - if(node == parent) { - return true; - } - node = node.parentNode; - } - return false; - }, + var inner = document.createElement('div'); + inner.className = 'inner'; + label.appendChild(inner); + this.dom.inner = inner; - /** - * get the center of all the touches - * @method getCenter - * @param {Array} touches - * @return {Object} center contains `pageX`, `pageY`, `clientX` and `clientY` properties - */ - getCenter: function getCenter(touches) { - var pageX = [], - pageY = [], - clientX = [], - clientY = [], - min = Math.min, - max = Math.max; + var foreground = document.createElement('div'); + foreground.className = 'group'; + foreground['timeline-group'] = this; + this.dom.foreground = foreground; - // no need to loop when only one touch - if(touches.length === 1) { - return { - pageX: touches[0].pageX, - pageY: touches[0].pageY, - clientX: touches[0].clientX, - clientY: touches[0].clientY - }; - } + this.dom.background = document.createElement('div'); + this.dom.background.className = 'group'; - Utils.each(touches, function(touch) { - pageX.push(touch.pageX); - pageY.push(touch.pageY); - clientX.push(touch.clientX); - clientY.push(touch.clientY); - }); + this.dom.axis = document.createElement('div'); + this.dom.axis.className = 'group'; - return { - pageX: (min.apply(Math, pageX) + max.apply(Math, pageX)) / 2, - pageY: (min.apply(Math, pageY) + max.apply(Math, pageY)) / 2, - clientX: (min.apply(Math, clientX) + max.apply(Math, clientX)) / 2, - clientY: (min.apply(Math, clientY) + max.apply(Math, clientY)) / 2 - }; - }, + // create a hidden marker to detect when the Timelines container is attached + // to the DOM, or the style of a parent of the Timeline is changed from + // display:none is changed to visible. + this.dom.marker = document.createElement('div'); + this.dom.marker.style.visibility = 'hidden'; // TODO: ask jos why this is not none? + this.dom.marker.innerHTML = '?'; + this.dom.background.appendChild(this.dom.marker); + }; - /** - * calculate the velocity between two points. unit is in px per ms. - * @method getVelocity - * @param {Number} deltaTime - * @param {Number} deltaX - * @param {Number} deltaY - * @return {Object} velocity `x` and `y` - */ - getVelocity: function getVelocity(deltaTime, deltaX, deltaY) { - return { - x: Math.abs(deltaX / deltaTime) || 0, - y: Math.abs(deltaY / deltaTime) || 0 - }; - }, + /** + * Set the group data for this group + * @param {Object} data Group data, can contain properties content and className + */ + Group.prototype.setData = function(data) { + // update contents + var content = data && data.content; + if (content instanceof Element) { + this.dom.inner.appendChild(content); + } + else if (content !== undefined && content !== null) { + this.dom.inner.innerHTML = content; + } + else { + this.dom.inner.innerHTML = this.groupId || ''; // groupId can be null + } - /** - * calculate the angle between two coordinates - * @method getAngle - * @param {Touch} touch1 - * @param {Touch} touch2 - * @return {Number} angle - */ - getAngle: function getAngle(touch1, touch2) { - var x = touch2.clientX - touch1.clientX, - y = touch2.clientY - touch1.clientY; + // update title + this.dom.label.title = data && data.title || ''; - return Math.atan2(y, x) * 180 / Math.PI; - }, + if (!this.dom.inner.firstChild) { + util.addClassName(this.dom.inner, 'hidden'); + } + else { + util.removeClassName(this.dom.inner, 'hidden'); + } - /** - * do a small comparision to get the direction between two touches. - * @method getDirection - * @param {Touch} touch1 - * @param {Touch} touch2 - * @return {String} direction matches `DIRECTION_LEFT|RIGHT|UP|DOWN` - */ - getDirection: function getDirection(touch1, touch2) { - var x = Math.abs(touch1.clientX - touch2.clientX), - y = Math.abs(touch1.clientY - touch2.clientY); + // update className + var className = data && data.className || null; + if (className != this.className) { + if (this.className) { + util.removeClassName(this.dom.label, this.className); + util.removeClassName(this.dom.foreground, this.className); + util.removeClassName(this.dom.background, this.className); + util.removeClassName(this.dom.axis, this.className); + } + util.addClassName(this.dom.label, className); + util.addClassName(this.dom.foreground, className); + util.addClassName(this.dom.background, className); + util.addClassName(this.dom.axis, className); + this.className = className; + } - if(x >= y) { - return touch1.clientX - touch2.clientX > 0 ? DIRECTION_LEFT : DIRECTION_RIGHT; - } - return touch1.clientY - touch2.clientY > 0 ? DIRECTION_UP : DIRECTION_DOWN; - }, + // update style + if (this.style) { + util.removeCssText(this.dom.label, this.style); + this.style = null; + } + if (data && data.style) { + util.addCssText(this.dom.label, data.style); + this.style = data.style; + } + }; - /** - * calculate the distance between two touches - * @method getDistance - * @param {Touch}touch1 - * @param {Touch} touch2 - * @return {Number} distance - */ - getDistance: function getDistance(touch1, touch2) { - var x = touch2.clientX - touch1.clientX, - y = touch2.clientY - touch1.clientY; + /** + * Get the width of the group label + * @return {number} width + */ + Group.prototype.getLabelWidth = function() { + return this.props.label.width; + }; - return Math.sqrt((x * x) + (y * y)); - }, - /** - * calculate the scale factor between two touchLists - * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out - * @method getScale - * @param {Array} start array of touches - * @param {Array} end array of touches - * @return {Number} scale - */ - getScale: function getScale(start, end) { - // need two fingers... - if(start.length >= 2 && end.length >= 2) { - return this.getDistance(end[0], end[1]) / this.getDistance(start[0], start[1]); - } - return 1; - }, + /** + * Repaint this group + * @param {{start: number, end: number}} range + * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin + * @param {boolean} [restack=false] Force restacking of all items + * @return {boolean} Returns true if the group is resized + */ + Group.prototype.redraw = function(range, margin, restack) { + var resized = false; - /** - * calculate the rotation degrees between two touchLists - * @method getRotation - * @param {Array} start array of touches - * @param {Array} end array of touches - * @return {Number} rotation - */ - getRotation: function getRotation(start, end) { - // need two fingers - if(start.length >= 2 && end.length >= 2) { - return this.getAngle(end[1], end[0]) - this.getAngle(start[1], start[0]); - } - return 0; - }, + this.visibleItems = this._updateVisibleItems(this.orderedItems, this.visibleItems, range); - /** - * find out if the direction is vertical * - * @method isVertical - * @param {String} direction matches `DIRECTION_UP|DOWN` - * @return {Boolean} is_vertical - */ - isVertical: function isVertical(direction) { - return direction == DIRECTION_UP || direction == DIRECTION_DOWN; - }, + // force recalculation of the height of the items when the marker height changed + // (due to the Timeline being attached to the DOM or changed from display:none to visible) + var markerHeight = this.dom.marker.clientHeight; + if (markerHeight != this.lastMarkerHeight) { + this.lastMarkerHeight = markerHeight; - /** - * set css properties with their prefixes - * @param {HTMLElement} element - * @param {String} prop - * @param {String} value - * @param {Boolean} [toggle=true] - * @return {Boolean} - */ - setPrefixedCss: function setPrefixedCss(element, prop, value, toggle) { - var prefixes = ['', 'Webkit', 'Moz', 'O', 'ms']; - prop = Utils.toCamelCase(prop); + util.forEach(this.items, function (item) { + item.dirty = true; + if (item.displayed) item.redraw(); + }); - for(var i = 0; i < prefixes.length; i++) { - var p = prop; - // prefixes - if(prefixes[i]) { - p = prefixes[i] + p.slice(0, 1).toUpperCase() + p.slice(1); - } + restack = true; + } - // test the style - if(p in element.style) { - element.style[p] = (toggle == null || toggle) && value || ''; - break; - } - } - }, + // reposition visible items vertically + if (this.itemSet.options.stack) { // TODO: ugly way to access options... + stack.stack(this.visibleItems, margin, restack); + } + else { // no stacking + stack.nostack(this.visibleItems, margin, this.subgroups); + } - /** - * toggle browser default behavior by setting css properties. - * `userSelect='none'` also sets `element.onselectstart` to false - * `userDrag='none'` also sets `element.ondragstart` to false - * - * @method toggleBehavior - * @param {HtmlElement} element - * @param {Object} props - * @param {Boolean} [toggle=true] - */ - toggleBehavior: function toggleBehavior(element, props, toggle) { - if(!props || !element || !element.style) { - return; - } + // recalculate the height of the group + var height = this._calculateHeight(margin); - // set the css properties - Utils.each(props, function(value, prop) { - Utils.setPrefixedCss(element, prop, value, toggle); - }); + // calculate actual size and position + var foreground = this.dom.foreground; + this.top = foreground.offsetTop; + this.left = foreground.offsetLeft; + this.width = foreground.offsetWidth; + resized = util.updateProperty(this, 'height', height) || resized; - var falseFn = toggle && function() { - return false; - }; + // recalculate size of label + resized = util.updateProperty(this.props.label, 'width', this.dom.inner.clientWidth) || resized; + resized = util.updateProperty(this.props.label, 'height', this.dom.inner.clientHeight) || resized; - // also the disable onselectstart - if(props.userSelect == 'none') { - element.onselectstart = falseFn; - } - // and disable ondragstart - if(props.userDrag == 'none') { - element.ondragstart = falseFn; - } - }, + // apply new height + this.dom.background.style.height = height + 'px'; + this.dom.foreground.style.height = height + 'px'; + this.dom.label.style.height = height + 'px'; - /** - * convert a string with underscores to camelCase - * so prevent_default becomes preventDefault - * @param {String} str - * @return {String} camelCaseStr - */ - toCamelCase: function toCamelCase(str) { - return str.replace(/[_-]([a-z])/g, function(s) { - return s[1].toUpperCase(); - }); - } - }; + // update vertical position of items after they are re-stacked and the height of the group is calculated + for (var i = 0, ii = this.visibleItems.length; i < ii; i++) { + var item = this.visibleItems[i]; + item.repositionY(margin); + } + return resized; + }; /** - * @module hammer + * recalculate the height of the group + * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin + * @returns {number} Returns the height + * @private */ + Group.prototype._calculateHeight = function (margin) { + // recalculate the height of the group + var height; + var visibleItems = this.visibleItems; + //var visibleSubgroups = []; + //this.visibleSubgroups = 0; + this.resetSubgroups(); + var me = this; + if (visibleItems.length) { + var min = visibleItems[0].top; + var max = visibleItems[0].top + visibleItems[0].height; + util.forEach(visibleItems, function (item) { + min = Math.min(min, item.top); + max = Math.max(max, (item.top + item.height)); + if (item.data.subgroup !== undefined) { + me.subgroups[item.data.subgroup].height = Math.max(me.subgroups[item.data.subgroup].height,item.height); + me.subgroups[item.data.subgroup].visible = true; + //if (visibleSubgroups.indexOf(item.data.subgroup) == -1){ + // visibleSubgroups.push(item.data.subgroup); + // me.visibleSubgroups += 1; + //} + } + }); + if (min > margin.axis) { + // there is an empty gap between the lowest item and the axis + var offset = min - margin.axis; + max -= offset; + util.forEach(visibleItems, function (item) { + item.top -= offset; + }); + } + height = max + margin.item.vertical / 2; + } + else { + height = margin.axis + margin.item.vertical; + } + height = Math.max(height, this.props.label.height); + + return height; + }; + /** - * @class Event - * @static + * Show this group: attach to the DOM */ - var Event = Hammer.event = { - /** - * when touch events have been fired, this is true - * this is used to stop mouse events - * @property prevent_mouseevents - * @private - * @type {Boolean} - */ - preventMouseEvents: false, + Group.prototype.show = function() { + if (!this.dom.label.parentNode) { + this.itemSet.dom.labelSet.appendChild(this.dom.label); + } - /** - * if EVENT_START has been fired - * @property started - * @private - * @type {Boolean} - */ - started: false, + if (!this.dom.foreground.parentNode) { + this.itemSet.dom.foreground.appendChild(this.dom.foreground); + } - /** - * when the mouse is hold down, this is true - * @property should_detect - * @private - * @type {Boolean} - */ - shouldDetect: false, + if (!this.dom.background.parentNode) { + this.itemSet.dom.background.appendChild(this.dom.background); + } + + if (!this.dom.axis.parentNode) { + this.itemSet.dom.axis.appendChild(this.dom.axis); + } + }; + + /** + * Hide this group: remove from the DOM + */ + Group.prototype.hide = function() { + var label = this.dom.label; + if (label.parentNode) { + label.parentNode.removeChild(label); + } - /** - * simple event binder with a hook and support for multiple types - * @method on - * @param {HTMLElement} element - * @param {String} type - * @param {Function} handler - * @param {Function} [hook] - * @param {Object} hook.type - */ - on: function on(element, type, handler, hook) { - var types = type.split(' '); - Utils.each(types, function(type) { - Utils.on(element, type, handler); - hook && hook(type); - }); - }, + var foreground = this.dom.foreground; + if (foreground.parentNode) { + foreground.parentNode.removeChild(foreground); + } - /** - * simple event unbinder with a hook and support for multiple types - * @method off - * @param {HTMLElement} element - * @param {String} type - * @param {Function} handler - * @param {Function} [hook] - * @param {Object} hook.type - */ - off: function off(element, type, handler, hook) { - var types = type.split(' '); - Utils.each(types, function(type) { - Utils.off(element, type, handler); - hook && hook(type); - }); - }, + var background = this.dom.background; + if (background.parentNode) { + background.parentNode.removeChild(background); + } - /** - * the core touch event handler. - * this finds out if we should to detect gestures - * @method onTouch - * @param {HTMLElement} element - * @param {String} eventType matches `EVENT_START|MOVE|END` - * @param {Function} handler - * @return onTouchHandler {Function} the core event handler - */ - onTouch: function onTouch(element, eventType, handler) { - var self = this; + var axis = this.dom.axis; + if (axis.parentNode) { + axis.parentNode.removeChild(axis); + } + }; - var onTouchHandler = function onTouchHandler(ev) { - var srcType = ev.type.toLowerCase(), - isPointer = Hammer.HAS_POINTEREVENTS, - isMouse = Utils.inStr(srcType, 'mouse'), - triggerType; + /** + * Add an item to the group + * @param {Item} item + */ + Group.prototype.add = function(item) { + this.items[item.id] = item; + item.setParent(this); - // if we are in a mouseevent, but there has been a touchevent triggered in this session - // we want to do nothing. simply break out of the event. - if(isMouse && self.preventMouseEvents) { - return; + // add to + if (item.data.subgroup !== undefined) { + if (this.subgroups[item.data.subgroup] === undefined) { + this.subgroups[item.data.subgroup] = {height:0, visible: false, index:this.subgroupIndex, items: []}; + this.subgroupIndex++; + } + this.subgroups[item.data.subgroup].items.push(item); + } + this.orderSubgroups(); - // mousebutton must be down - } else if(isMouse && eventType == EVENT_START && ev.button === 0) { - self.preventMouseEvents = false; - self.shouldDetect = true; - } else if(isPointer && eventType == EVENT_START) { - self.shouldDetect = (ev.buttons === 1 || PointerEvent.matchType(POINTER_TOUCH, ev)); - // just a valid start event, but no mouse - } else if(!isMouse && eventType == EVENT_START) { - self.preventMouseEvents = true; - self.shouldDetect = true; - } + if (this.visibleItems.indexOf(item) == -1) { + var range = this.itemSet.body.range; // TODO: not nice accessing the range like this + this._checkIfVisible(item, this.visibleItems, range); + } + }; - // update the pointer event before entering the detection - if(isPointer && eventType != EVENT_END) { - PointerEvent.updatePointer(eventType, ev); - } + Group.prototype.orderSubgroups = function() { + if (this.subgroupOrderer !== undefined) { + var sortArray = []; + if (typeof this.subgroupOrderer == 'string') { + for (var subgroup in this.subgroups) { + sortArray.push({subgroup: subgroup, sortField: this.subgroups[subgroup].items[0].data[this.subgroupOrderer]}) + } + sortArray.sort(function (a, b) { + return a.sortField - b.sortField; + }) + } + else if (typeof this.subgroupOrderer == 'function') { + for (var subgroup in this.subgroups) { + sortArray.push(this.subgroups[subgroup].items[0].data); + } + sortArray.sort(this.subgroupOrderer); + } - // we are in a touch/down state, so allowed detection of gestures - if(self.shouldDetect) { - triggerType = self.doDetect.call(self, ev, eventType, element, handler); - } + if (sortArray.length > 0) { + for (var i = 0; i < sortArray.length; i++) { + this.subgroups[sortArray[i].subgroup].index = i; + } + } + } + }; - // ...and we are done with the detection - // so reset everything to start each detection totally fresh - if(triggerType == EVENT_END) { - self.preventMouseEvents = false; - self.shouldDetect = false; - PointerEvent.reset(); - // update the pointerevent object after the detection - } + Group.prototype.resetSubgroups = function() { + for (var subgroup in this.subgroups) { + if (this.subgroups.hasOwnProperty(subgroup)) { + this.subgroups[subgroup].visible = false; + } + } + }; - if(isPointer && eventType == EVENT_END) { - PointerEvent.updatePointer(eventType, ev); - } - }; + /** + * Remove an item from the group + * @param {Item} item + */ + Group.prototype.remove = function(item) { + delete this.items[item.id]; + item.setParent(null); - this.on(element, EVENT_TYPES[eventType], onTouchHandler); - return onTouchHandler; - }, + // remove from visible items + var index = this.visibleItems.indexOf(item); + if (index != -1) this.visibleItems.splice(index, 1); - /** - * the core detection method - * this finds out what hammer-touch-events to trigger - * @method doDetect - * @param {Object} ev - * @param {String} eventType matches `EVENT_START|MOVE|END` - * @param {HTMLElement} element - * @param {Function} handler - * @return {String} triggerType matches `EVENT_START|MOVE|END` - */ - doDetect: function doDetect(ev, eventType, element, handler) { - var touchList = this.getTouchList(ev, eventType); - var touchListLength = touchList.length; - var triggerType = eventType; - var triggerChange = touchList.trigger; // used by fakeMultitouch plugin - var changedLength = touchListLength; + // TODO: also remove from ordered items? + }; - // at each touchstart-like event we want also want to trigger a TOUCH event... - if(eventType == EVENT_START) { - triggerChange = EVENT_TOUCH; - // ...the same for a touchend-like event - } else if(eventType == EVENT_END) { - triggerChange = EVENT_RELEASE; - // keep track of how many touches have been removed - changedLength = touchList.length - ((ev.changedTouches) ? ev.changedTouches.length : 1); - } + /** + * Remove an item from the corresponding DataSet + * @param {Item} item + */ + Group.prototype.removeFromDataSet = function(item) { + this.itemSet.removeItem(item.id); + }; - // after there are still touches on the screen, - // we just want to trigger a MOVE event. so change the START or END to a MOVE - // but only after detection has been started, the first time we actualy want a START - if(changedLength > 0 && this.started) { - triggerType = EVENT_MOVE; - } - // detection has been started, we keep track of this, see above - this.started = true; + /** + * Reorder the items + */ + Group.prototype.order = function() { + var array = util.toArray(this.items); + var startArray = []; + var endArray = []; - // generate some event data, some basic information - var evData = this.collectEventData(element, triggerType, touchList, ev); + for (var i = 0; i < array.length; i++) { + if (array[i].data.end !== undefined) { + endArray.push(array[i]); + } + startArray.push(array[i]); + } + this.orderedItems = { + byStart: startArray, + byEnd: endArray + }; - // trigger the triggerType event before the change (TOUCH, RELEASE) events - // but the END event should be at last - if(eventType != EVENT_END) { - handler.call(Detection, evData); - } + stack.orderByStart(this.orderedItems.byStart); + stack.orderByEnd(this.orderedItems.byEnd); + }; - // trigger a change (TOUCH, RELEASE) event, this means the length of the touches changed - if(triggerChange) { - evData.changedLength = changedLength; - evData.eventType = triggerChange; - handler.call(Detection, evData); + /** + * Update the visible items + * @param {{byStart: Item[], byEnd: Item[]}} orderedItems All items ordered by start date and by end date + * @param {Item[]} visibleItems The previously visible items. + * @param {{start: number, end: number}} range Visible range + * @return {Item[]} visibleItems The new visible items. + * @private + */ + Group.prototype._updateVisibleItems = function(orderedItems, oldVisibleItems, range) { + var visibleItems = []; + var visibleItemsLookup = {}; // we keep this to quickly look up if an item already exists in the list without using indexOf on visibleItems + var interval = (range.end - range.start) / 4; + var lowerBound = range.start - interval; + var upperBound = range.end + interval; + var item, i; - evData.eventType = triggerType; - delete evData.changedLength; - } + // this function is used to do the binary search. + var searchFunction = function (value) { + if (value < lowerBound) {return -1;} + else if (value <= upperBound) {return 0;} + else {return 1;} + } - // trigger the END event - if(triggerType == EVENT_END) { - handler.call(Detection, evData); + // first check if the items that were in view previously are still in view. + // IMPORTANT: this handles the case for the items with startdate before the window and enddate after the window! + // also cleans up invisible items. + if (oldVisibleItems.length > 0) { + for (i = 0; i < oldVisibleItems.length; i++) { + this._checkIfVisibleWithReference(oldVisibleItems[i], visibleItems, visibleItemsLookup, range); + } + } - // ...and we are done with the detection - // so reset everything to start each detection totally fresh - this.started = false; - } + // we do a binary search for the items that have only start values. + var initialPosByStart = util.binarySearchCustom(orderedItems.byStart, searchFunction, 'data','start'); - return triggerType; - }, + // trace the visible items from the inital start pos both ways until an invisible item is found, we only look at the start values. + this._traceVisible(initialPosByStart, orderedItems.byStart, visibleItems, visibleItemsLookup, function (item) { + return (item.data.start < lowerBound || item.data.start > upperBound); + }); - /** - * we have different events for each device/browser - * determine what we need and set them in the EVENT_TYPES constant - * the `onTouch` method is bind to these properties. - * @method determineEventTypes - * @return {Object} events - */ - determineEventTypes: function determineEventTypes() { - var types; - if(Hammer.HAS_POINTEREVENTS) { - if(window.PointerEvent) { - types = [ - 'pointerdown', - 'pointermove', - 'pointerup pointercancel lostpointercapture' - ]; - } else { - types = [ - 'MSPointerDown', - 'MSPointerMove', - 'MSPointerUp MSPointerCancel MSLostPointerCapture' - ]; - } - } else if(Hammer.NO_MOUSEEVENTS) { - types = [ - 'touchstart', - 'touchmove', - 'touchend touchcancel' - ]; - } else { - types = [ - 'touchstart mousedown', - 'touchmove mousemove', - 'touchend touchcancel mouseup' - ]; - } + // if the window has changed programmatically without overlapping the old window, the ranged items with start < lowerBound and end > upperbound are not shown. + // We therefore have to brute force check all items in the byEnd list + if (this.checkRangedItems == true) { + this.checkRangedItems = false; + for (i = 0; i < orderedItems.byEnd.length; i++) { + this._checkIfVisibleWithReference(orderedItems.byEnd[i], visibleItems, visibleItemsLookup, range); + } + } + else { + // we do a binary search for the items that have defined end times. + var initialPosByEnd = util.binarySearchCustom(orderedItems.byEnd, searchFunction, 'data','end'); - EVENT_TYPES[EVENT_START] = types[0]; - EVENT_TYPES[EVENT_MOVE] = types[1]; - EVENT_TYPES[EVENT_END] = types[2]; - return EVENT_TYPES; - }, + // trace the visible items from the inital start pos both ways until an invisible item is found, we only look at the end values. + this._traceVisible(initialPosByEnd, orderedItems.byEnd, visibleItems, visibleItemsLookup, function (item) { + return (item.data.end < lowerBound || item.data.end > upperBound); + }); + } - /** - * create touchList depending on the event - * @method getTouchList - * @param {Object} ev - * @param {String} eventType - * @return {Array} touches - */ - getTouchList: function getTouchList(ev, eventType) { - // get the fake pointerEvent touchlist - if(Hammer.HAS_POINTEREVENTS) { - return PointerEvent.getTouchList(); - } - // get the touchlist - if(ev.touches) { - if(eventType == EVENT_MOVE) { - return ev.touches; - } + // finally, we reposition all the visible items. + for (i = 0; i < visibleItems.length; i++) { + item = visibleItems[i]; + if (!item.displayed) item.show(); + // reposition item horizontally + item.repositionX(); + } - var identifiers = []; - var concat = [].concat(Utils.toArray(ev.touches), Utils.toArray(ev.changedTouches)); - var touchList = []; + // debug + //console.log("new line") + //if (this.groupId == null) { + // for (i = 0; i < orderedItems.byStart.length; i++) { + // item = orderedItems.byStart[i].data; + // console.log('start',i,initialPosByStart, item.start.valueOf(), item.content, item.start >= lowerBound && item.start <= upperBound,i == initialPosByStart ? "<------------------- HEREEEE" : "") + // } + // for (i = 0; i < orderedItems.byEnd.length; i++) { + // item = orderedItems.byEnd[i].data; + // console.log('rangeEnd',i,initialPosByEnd, item.end.valueOf(), item.content, item.end >= range.start && item.end <= range.end,i == initialPosByEnd ? "<------------------- HEREEEE" : "") + // } + //} - Utils.each(concat, function(touch) { - if(Utils.inArray(identifiers, touch.identifier) === false) { - touchList.push(touch); - } - identifiers.push(touch.identifier); - }); + return visibleItems; + }; - return touchList; - } + Group.prototype._traceVisible = function (initialPos, items, visibleItems, visibleItemsLookup, breakCondition) { + var item; + var i; - // make fake touchList from mouse position - ev.identifier = 1; - return [ev]; - }, + if (initialPos != -1) { + for (i = initialPos; i >= 0; i--) { + item = items[i]; + if (breakCondition(item)) { + break; + } + else { + if (visibleItemsLookup[item.id] === undefined) { + visibleItemsLookup[item.id] = true; + visibleItems.push(item); + } + } + } - /** - * collect basic event data - * @method collectEventData - * @param {HTMLElement} element - * @param {String} eventType matches `EVENT_START|MOVE|END` - * @param {Array} touches - * @param {Object} ev - * @return {Object} ev - */ - collectEventData: function collectEventData(element, eventType, touches, ev) { - // find out pointerType - var pointerType = POINTER_TOUCH; - if(Utils.inStr(ev.type, 'mouse') || PointerEvent.matchType(POINTER_MOUSE, ev)) { - pointerType = POINTER_MOUSE; - } else if(PointerEvent.matchType(POINTER_PEN, ev)) { - pointerType = POINTER_PEN; + for (i = initialPos + 1; i < items.length; i++) { + item = items[i]; + if (breakCondition(item)) { + break; + } + else { + if (visibleItemsLookup[item.id] === undefined) { + visibleItemsLookup[item.id] = true; + visibleItems.push(item); } + } + } + } + } - return { - center: Utils.getCenter(touches), - timeStamp: Date.now(), - target: ev.target, - touches: touches, - eventType: eventType, - pointerType: pointerType, - srcEvent: ev, - /** - * prevent the browser default actions - * mostly used to disable scrolling of the browser - */ - preventDefault: function() { - var srcEvent = this.srcEvent; - srcEvent.preventManipulation && srcEvent.preventManipulation(); - srcEvent.preventDefault && srcEvent.preventDefault(); - }, + /** + * this function is very similar to the _checkIfInvisible() but it does not + * return booleans, hides the item if it should not be seen and always adds to + * the visibleItems. + * this one is for brute forcing and hiding. + * + * @param {Item} item + * @param {Array} visibleItems + * @param {{start:number, end:number}} range + * @private + */ + Group.prototype._checkIfVisible = function(item, visibleItems, range) { + if (item.isVisible(range)) { + if (!item.displayed) item.show(); + // reposition item horizontally + item.repositionX(); + visibleItems.push(item); + } + else { + if (item.displayed) item.hide(); + } + }; - /** - * stop bubbling the event up to its parents - */ - stopPropagation: function() { - this.srcEvent.stopPropagation(); - }, - /** - * immediately stop gesture detection - * might be useful after a swipe was detected - * @return {*} - */ - stopDetect: function() { - return Detection.stopDetect(); - } - }; + /** + * this function is very similar to the _checkIfInvisible() but it does not + * return booleans, hides the item if it should not be seen and always adds to + * the visibleItems. + * this one is for brute forcing and hiding. + * + * @param {Item} item + * @param {Array} visibleItems + * @param {{start:number, end:number}} range + * @private + */ + Group.prototype._checkIfVisibleWithReference = function(item, visibleItems, visibleItemsLookup, range) { + if (item.isVisible(range)) { + if (visibleItemsLookup[item.id] === undefined) { + visibleItemsLookup[item.id] = true; + visibleItems.push(item); } + } + else { + if (item.displayed) item.hide(); + } }; + + module.exports = Group; + + +/***/ }, +/* 26 */ +/***/ function(module, exports, __webpack_require__) { + + var util = __webpack_require__(1); + var Group = __webpack_require__(25); + /** - * @module hammer - * - * @class PointerEvent - * @static + * @constructor BackgroundGroup + * @param {Number | String} groupId + * @param {Object} data + * @param {ItemSet} itemSet */ - var PointerEvent = Hammer.PointerEvent = { - /** - * holds all pointers, by `identifier` - * @property pointers - * @type {Object} - */ - pointers: {}, + function BackgroundGroup (groupId, data, itemSet) { + Group.call(this, groupId, data, itemSet); - /** - * get the pointers as an array - * @method getTouchList - * @return {Array} touchlist - */ - getTouchList: function getTouchList() { - var touchlist = []; - // we can use forEach since pointerEvents only is in IE10 - Utils.each(this.pointers, function(pointer) { - touchlist.push(pointer); - }); - return touchlist; - }, + this.width = 0; + this.height = 0; + this.top = 0; + this.left = 0; + } - /** - * update the position of a pointer - * @method updatePointer - * @param {String} eventType matches `EVENT_START|MOVE|END` - * @param {Object} pointerEvent - */ - updatePointer: function updatePointer(eventType, pointerEvent) { - if(eventType == EVENT_END || (eventType != EVENT_END && pointerEvent.buttons !== 1)) { - delete this.pointers[pointerEvent.pointerId]; - } else { - pointerEvent.identifier = pointerEvent.pointerId; - this.pointers[pointerEvent.pointerId] = pointerEvent; - } - }, + BackgroundGroup.prototype = Object.create(Group.prototype); - /** - * check if ev matches pointertype - * @method matchType - * @param {String} pointerType matches `POINTER_MOUSE|TOUCH|PEN` - * @param {PointerEvent} ev - */ - matchType: function matchType(pointerType, ev) { - if(!ev.pointerType) { - return false; - } + /** + * Repaint this group + * @param {{start: number, end: number}} range + * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin + * @param {boolean} [restack=false] Force restacking of all items + * @return {boolean} Returns true if the group is resized + */ + BackgroundGroup.prototype.redraw = function(range, margin, restack) { + var resized = false; - var pt = ev.pointerType, - types = {}; + this.visibleItems = this._updateVisibleItems(this.orderedItems, this.visibleItems, range); - types[POINTER_MOUSE] = (pt === (ev.MSPOINTER_TYPE_MOUSE || POINTER_MOUSE)); - types[POINTER_TOUCH] = (pt === (ev.MSPOINTER_TYPE_TOUCH || POINTER_TOUCH)); - types[POINTER_PEN] = (pt === (ev.MSPOINTER_TYPE_PEN || POINTER_PEN)); - return types[pointerType]; - }, + // calculate actual size + this.width = this.dom.background.offsetWidth; - /** - * reset the stored pointers - * @method reset - */ - reset: function resetList() { - this.pointers = {}; - } - }; + // apply new height (just always zero for BackgroundGroup + this.dom.background.style.height = '0'; + + // update vertical position of items after they are re-stacked and the height of the group is calculated + for (var i = 0, ii = this.visibleItems.length; i < ii; i++) { + var item = this.visibleItems[i]; + item.repositionY(margin); + } + return resized; + }; /** - * @module hammer - * - * @class Detection - * @static + * Show this group: attach to the DOM */ - var Detection = Hammer.detection = { - // contains all registred Hammer.gestures in the correct order - gestures: [], + BackgroundGroup.prototype.show = function() { + if (!this.dom.background.parentNode) { + this.itemSet.dom.background.appendChild(this.dom.background); + } + }; - // data of the current Hammer.gesture detection session - current: null, + module.exports = BackgroundGroup; - // the previous Hammer.gesture session data - // is a full clone of the previous gesture.current object - previous: null, - // when this becomes true, no gestures are fired - stopped: false, +/***/ }, +/* 27 */ +/***/ function(module, exports, __webpack_require__) { - /** - * start Hammer.gesture detection - * @method startDetect - * @param {Hammer.Instance} inst - * @param {Object} eventData - */ - startDetect: function startDetect(inst, eventData) { - // already busy with a Hammer.gesture detection on an element - if(this.current) { - return; - } + var Hammer = __webpack_require__(45); + var util = __webpack_require__(1); + var DataSet = __webpack_require__(3); + var DataView = __webpack_require__(4); + var Component = __webpack_require__(20); + var Group = __webpack_require__(25); + var BackgroundGroup = __webpack_require__(26); + var BoxItem = __webpack_require__(33); + var PointItem = __webpack_require__(34); + var RangeItem = __webpack_require__(35); + var BackgroundItem = __webpack_require__(32); - this.stopped = false; - // holds current session - this.current = { - inst: inst, // reference to HammerInstance we're working for - startEvent: Utils.extend({}, eventData), // start eventData for distances, timing etc - lastEvent: false, // last eventData - lastCalcEvent: false, // last eventData for calculations. - futureCalcEvent: false, // last eventData for calculations. - lastCalcData: {}, // last lastCalcData - name: '' // current gesture we're in/detected, can be 'tap', 'hold' etc - }; + var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items + var BACKGROUND = '__background__'; // reserved group id for background items without group - this.detect(eventData); + /** + * An ItemSet holds a set of items and ranges which can be displayed in a + * range. The width is determined by the parent of the ItemSet, and the height + * is determined by the size of the items. + * @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} body + * @param {Object} [options] See ItemSet.setOptions for the available options. + * @constructor ItemSet + * @extends Component + */ + function ItemSet(body, options) { + this.body = body; + + this.defaultOptions = { + type: null, // 'box', 'point', 'range', 'background' + orientation: 'bottom', // 'top' or 'bottom' + align: 'auto', // alignment of box items + stack: true, + groupOrder: null, + + selectable: true, + editable: { + updateTime: false, + updateGroup: false, + add: false, + remove: false }, - /** - * Hammer.gesture detection - * @method detect - * @param {Object} eventData - * @return {any} - */ - detect: function detect(eventData) { - if(!this.current || this.stopped) { - return; - } + onAdd: function (item, callback) { + callback(item); + }, + onUpdate: function (item, callback) { + callback(item); + }, + onMove: function (item, callback) { + callback(item); + }, + onRemove: function (item, callback) { + callback(item); + }, + onMoving: function (item, callback) { + callback(item); + }, - // extend event data with calculations about scale, distance etc - eventData = this.extendEventData(eventData); + margin: { + item: { + horizontal: 10, + vertical: 10 + }, + axis: 20 + }, + padding: 5 + }; - // hammer instance and instance options - var inst = this.current.inst, - instOptions = inst.options; + // options is shared by this ItemSet and all its items + this.options = util.extend({}, this.defaultOptions); - // call Hammer.gesture handlers - Utils.each(this.gestures, function triggerGesture(gesture) { - // only when the instance options have enabled this gesture - if(!this.stopped && inst.enabled && instOptions[gesture.name]) { - gesture.handler.call(gesture, eventData, inst); - } - }, this); + // options for getting items from the DataSet with the correct type + this.itemOptions = { + type: {start: 'Date', end: 'Date'} + }; - // store as previous event event - if(this.current) { - this.current.lastEvent = eventData; - } + this.conversion = { + toScreen: body.util.toScreen, + toTime: body.util.toTime + }; + this.dom = {}; + this.props = {}; + this.hammer = null; - if(eventData.eventType == EVENT_END) { - this.stopDetect(); - } + var me = this; + this.itemsData = null; // DataSet + this.groupsData = null; // DataSet - return eventData; + // listeners for the DataSet of the items + this.itemListeners = { + 'add': function (event, params, senderId) { + me._onAdd(params.items); }, + 'update': function (event, params, senderId) { + me._onUpdate(params.items); + }, + 'remove': function (event, params, senderId) { + me._onRemove(params.items); + } + }; - /** - * clear the Hammer.gesture vars - * this is called on endDetect, but can also be used when a final Hammer.gesture has been detected - * to stop other Hammer.gestures from being fired - * @method stopDetect - */ - stopDetect: function stopDetect() { - // clone current data to the store as the previous gesture - // used for the double tap gesture, since this is an other gesture detect session - this.previous = Utils.extend({}, this.current); - - // reset the current - this.current = null; - this.stopped = true; + // listeners for the DataSet of the groups + this.groupListeners = { + 'add': function (event, params, senderId) { + me._onAddGroups(params.items); + }, + 'update': function (event, params, senderId) { + me._onUpdateGroups(params.items); }, + 'remove': function (event, params, senderId) { + me._onRemoveGroups(params.items); + } + }; - /** - * calculate velocity, angle and direction - * @method getVelocityData - * @param {Object} ev - * @param {Object} center - * @param {Number} deltaTime - * @param {Number} deltaX - * @param {Number} deltaY - */ - getCalculatedData: function getCalculatedData(ev, center, deltaTime, deltaX, deltaY) { - var cur = this.current, - recalc = false, - calcEv = cur.lastCalcEvent, - calcData = cur.lastCalcData; + this.items = {}; // object with an Item for every data item + this.groups = {}; // Group object for every group + this.groupIds = []; - if(calcEv && ev.timeStamp - calcEv.timeStamp > Hammer.CALCULATE_INTERVAL) { - center = calcEv.center; - deltaTime = ev.timeStamp - calcEv.timeStamp; - deltaX = ev.center.clientX - calcEv.center.clientX; - deltaY = ev.center.clientY - calcEv.center.clientY; - recalc = true; - } + this.selection = []; // list with the ids of all selected nodes + this.stackDirty = true; // if true, all items will be restacked on next redraw - if(ev.eventType == EVENT_TOUCH || ev.eventType == EVENT_RELEASE) { - cur.futureCalcEvent = ev; - } + this.touchParams = {}; // stores properties while dragging + // create the HTML DOM - if(!cur.lastCalcEvent || recalc) { - calcData.velocity = Utils.getVelocity(deltaTime, deltaX, deltaY); - calcData.angle = Utils.getAngle(center, ev.center); - calcData.direction = Utils.getDirection(center, ev.center); + this._create(); - cur.lastCalcEvent = cur.futureCalcEvent || ev; - cur.futureCalcEvent = ev; - } + this.setOptions(options); + } - ev.velocityX = calcData.velocity.x; - ev.velocityY = calcData.velocity.y; - ev.interimAngle = calcData.angle; - ev.interimDirection = calcData.direction; - }, + ItemSet.prototype = new Component(); - /** - * extend eventData for Hammer.gestures - * @method extendEventData - * @param {Object} ev - * @return {Object} ev - */ - extendEventData: function extendEventData(ev) { - var cur = this.current, - startEv = cur.startEvent, - lastEv = cur.lastEvent || startEv; + // available item types will be registered here + ItemSet.types = { + background: BackgroundItem, + box: BoxItem, + range: RangeItem, + point: PointItem + }; - // update the start touchlist to calculate the scale/rotation - if(ev.eventType == EVENT_TOUCH || ev.eventType == EVENT_RELEASE) { - startEv.touches = []; - Utils.each(ev.touches, function(touch) { - startEv.touches.push({ - clientX: touch.clientX, - clientY: touch.clientY - }); - }); - } + /** + * Create the HTML DOM for the ItemSet + */ + ItemSet.prototype._create = function(){ + var frame = document.createElement('div'); + frame.className = 'itemset'; + frame['timeline-itemset'] = this; + this.dom.frame = frame; - var deltaTime = ev.timeStamp - startEv.timeStamp, - deltaX = ev.center.clientX - startEv.center.clientX, - deltaY = ev.center.clientY - startEv.center.clientY; + // create background panel + var background = document.createElement('div'); + background.className = 'background'; + frame.appendChild(background); + this.dom.background = background; - this.getCalculatedData(ev, lastEv.center, deltaTime, deltaX, deltaY); + // create foreground panel + var foreground = document.createElement('div'); + foreground.className = 'foreground'; + frame.appendChild(foreground); + this.dom.foreground = foreground; - Utils.extend(ev, { - startEvent: startEv, + // create axis panel + var axis = document.createElement('div'); + axis.className = 'axis'; + this.dom.axis = axis; - deltaTime: deltaTime, - deltaX: deltaX, - deltaY: deltaY, + // create labelset + var labelSet = document.createElement('div'); + labelSet.className = 'labelset'; + this.dom.labelSet = labelSet; - distance: Utils.getDistance(startEv.center, ev.center), - angle: Utils.getAngle(startEv.center, ev.center), - direction: Utils.getDirection(startEv.center, ev.center), - scale: Utils.getScale(startEv.touches, ev.touches), - rotation: Utils.getRotation(startEv.touches, ev.touches) - }); + // create ungrouped Group + this._updateUngrouped(); - return ev; - }, + // create background Group + var backgroundGroup = new BackgroundGroup(BACKGROUND, null, this); + backgroundGroup.show(); + this.groups[BACKGROUND] = backgroundGroup; - /** - * register new gesture - * @method register - * @param {Object} gesture object, see `gestures/` for documentation - * @return {Array} gestures - */ - register: function register(gesture) { - // add an enable gesture options if there is no given - var options = gesture.defaults || {}; - if(options[gesture.name] === undefined) { - options[gesture.name] = true; - } + // attach event listeners + // Note: we bind to the centerContainer for the case where the height + // of the center container is larger than of the ItemSet, so we + // can click in the empty area to create a new item or deselect an item. + this.hammer = Hammer(this.body.dom.centerContainer, { + preventDefault: true + }); - // extend Hammer default options with the Hammer.gesture options - Utils.extend(Hammer.defaults, options, true); + // drag items when selected + this.hammer.on('touch', this._onTouch.bind(this)); + this.hammer.on('dragstart', this._onDragStart.bind(this)); + this.hammer.on('drag', this._onDrag.bind(this)); + this.hammer.on('dragend', this._onDragEnd.bind(this)); + + // single select (or unselect) when tapping an item + this.hammer.on('tap', this._onSelectItem.bind(this)); + + // multi select when holding mouse/touch, or on ctrl+click + this.hammer.on('hold', this._onMultiSelectItem.bind(this)); + + // add item on doubletap + this.hammer.on('doubletap', this._onAddItem.bind(this)); + + // attach to the DOM + this.show(); + }; + + /** + * Set options for the ItemSet. Existing options will be extended/overwritten. + * @param {Object} [options] The following options are available: + * {String} type + * Default type for the items. Choose from 'box' + * (default), 'point', 'range', or 'background'. + * The default style can be overwritten by + * individual items. + * {String} align + * Alignment for the items, only applicable for + * BoxItem. Choose 'center' (default), 'left', or + * 'right'. + * {String} orientation + * Orientation of the item set. Choose 'top' or + * 'bottom' (default). + * {Function} groupOrder + * A sorting function for ordering groups + * {Boolean} stack + * If true (deafult), items will be stacked on + * top of each other. + * {Number} margin.axis + * Margin between the axis and the items in pixels. + * Default is 20. + * {Number} margin.item.horizontal + * Horizontal margin between items in pixels. + * Default is 10. + * {Number} margin.item.vertical + * Vertical Margin between items in pixels. + * Default is 10. + * {Number} margin.item + * Margin between items in pixels in both horizontal + * and vertical direction. Default is 10. + * {Number} margin + * Set margin for both axis and items in pixels. + * {Number} padding + * Padding of the contents of an item in pixels. + * Must correspond with the items css. Default is 5. + * {Boolean} selectable + * If true (default), items can be selected. + * {Boolean} editable + * Set all editable options to true or false + * {Boolean} editable.updateTime + * Allow dragging an item to an other moment in time + * {Boolean} editable.updateGroup + * Allow dragging an item to an other group + * {Boolean} editable.add + * Allow creating new items on double tap + * {Boolean} editable.remove + * Allow removing items by clicking the delete button + * top right of a selected item. + * {Function(item: Item, callback: Function)} onAdd + * Callback function triggered when an item is about to be added: + * when the user double taps an empty space in the Timeline. + * {Function(item: Item, callback: Function)} onUpdate + * Callback function fired when an item is about to be updated. + * This function typically has to show a dialog where the user + * change the item. If not implemented, nothing happens. + * {Function(item: Item, callback: Function)} onMove + * Fired when an item has been moved. If not implemented, + * the move action will be accepted. + * {Function(item: Item, callback: Function)} onRemove + * Fired when an item is about to be deleted. + * If not implemented, the item will be always removed. + */ + ItemSet.prototype.setOptions = function(options) { + if (options) { + // copy all options that we know + var fields = ['type', 'align', 'orientation', 'padding', 'stack', 'selectable', 'groupOrder', 'dataAttributes', 'template','hide']; + util.selectiveExtend(fields, this.options, options); - // set its index - gesture.index = gesture.index || 1000; + if ('margin' in options) { + if (typeof options.margin === 'number') { + this.options.margin.axis = options.margin; + this.options.margin.item.horizontal = options.margin; + this.options.margin.item.vertical = options.margin; + } + else if (typeof options.margin === 'object') { + util.selectiveExtend(['axis'], this.options.margin, options.margin); + if ('item' in options.margin) { + if (typeof options.margin.item === 'number') { + this.options.margin.item.horizontal = options.margin.item; + this.options.margin.item.vertical = options.margin.item; + } + else if (typeof options.margin.item === 'object') { + util.selectiveExtend(['horizontal', 'vertical'], this.options.margin.item, options.margin.item); + } + } + } + } - // add Hammer.gesture to the list - this.gestures.push(gesture); + if ('editable' in options) { + if (typeof options.editable === 'boolean') { + this.options.editable.updateTime = options.editable; + this.options.editable.updateGroup = options.editable; + this.options.editable.add = options.editable; + this.options.editable.remove = options.editable; + } + else if (typeof options.editable === 'object') { + util.selectiveExtend(['updateTime', 'updateGroup', 'add', 'remove'], this.options.editable, options.editable); + } + } - // sort the list by index - this.gestures.sort(function(a, b) { - if(a.index < b.index) { - return -1; - } - if(a.index > b.index) { - return 1; - } - return 0; - }); + // callback functions + var addCallback = (function (name) { + var fn = options[name]; + if (fn) { + if (!(fn instanceof Function)) { + throw new Error('option ' + name + ' must be a function ' + name + '(item, callback)'); + } + this.options[name] = fn; + } + }).bind(this); + ['onAdd', 'onUpdate', 'onRemove', 'onMove', 'onMoving'].forEach(addCallback); - return this.gestures; - } + // force the itemSet to refresh: options like orientation and margins may be changed + this.markDirty(); + } }; - /** - * @module hammer + * Mark the ItemSet dirty so it will refresh everything with next redraw */ + ItemSet.prototype.markDirty = function() { + this.groupIds = []; + this.stackDirty = true; + }; /** - * create new hammer instance - * all methods should return the instance itself, so it is chainable. - * - * @class Instance - * @constructor - * @param {HTMLElement} element - * @param {Object} [options={}] options are merged with `Hammer.defaults` - * @return {Hammer.Instance} + * Destroy the ItemSet */ - Hammer.Instance = function(element, options) { - var self = this; - - // setup HammerJS window events and register all gestures - // this also sets up the default options - setup(); - - /** - * @property element - * @type {HTMLElement} - */ - this.element = element; - - /** - * @property enabled - * @type {Boolean} - * @protected - */ - this.enabled = true; - - /** - * options, merged with the defaults - * options with an _ are converted to camelCase - * @property options - * @type {Object} - */ - Utils.each(options, function(value, name) { - delete options[name]; - options[Utils.toCamelCase(name)] = value; - }); - - this.options = Utils.extend(Utils.extend({}, Hammer.defaults), options || {}); - - // add some css to the element to prevent the browser from doing its native behavoir - if(this.options.behavior) { - Utils.toggleBehavior(this.element, this.options.behavior, true); - } + ItemSet.prototype.destroy = function() { + this.hide(); + this.setItems(null); + this.setGroups(null); - /** - * event start handler on the element to start the detection - * @property eventStartHandler - * @type {Object} - */ - this.eventStartHandler = Event.onTouch(element, EVENT_START, function(ev) { - if(self.enabled && ev.eventType == EVENT_START) { - Detection.startDetect(self, ev); - } else if(ev.eventType == EVENT_TOUCH) { - Detection.detect(ev); - } - }); + this.hammer = null; - /** - * keep a list of user event handlers which needs to be removed when calling 'dispose' - * @property eventHandlers - * @type {Array} - */ - this.eventHandlers = []; + this.body = null; + this.conversion = null; }; - Hammer.Instance.prototype = { - /** - * bind events to the instance - * @method on - * @chainable - * @param {String} gestures multiple gestures by splitting with a space - * @param {Function} handler - * @param {Object} handler.ev event object - */ - on: function onEvent(gestures, handler) { - var self = this; - Event.on(self.element, gestures, handler, function(type) { - self.eventHandlers.push({ gesture: type, handler: handler }); - }); - return self; - }, - - /** - * unbind events to the instance - * @method off - * @chainable - * @param {String} gestures - * @param {Function} handler - */ - off: function offEvent(gestures, handler) { - var self = this; - - Event.off(self.element, gestures, handler, function(type) { - var index = Utils.inArray({ gesture: type, handler: handler }); - if(index !== false) { - self.eventHandlers.splice(index, 1); - } - }); - return self; - }, - - /** - * trigger gesture event - * @method trigger - * @chainable - * @param {String} gesture - * @param {Object} [eventData] - */ - trigger: function triggerEvent(gesture, eventData) { - // optional - if(!eventData) { - eventData = {}; - } - - // create DOM event - var event = Hammer.DOCUMENT.createEvent('Event'); - event.initEvent(gesture, true, true); - event.gesture = eventData; + /** + * Hide the component from the DOM + */ + ItemSet.prototype.hide = function() { + // remove the frame containing the items + if (this.dom.frame.parentNode) { + this.dom.frame.parentNode.removeChild(this.dom.frame); + } - // trigger on the target if it is in the instance element, - // this is for event delegation tricks - var element = this.element; - if(Utils.hasParent(eventData.target, element)) { - element = eventData.target; - } + // remove the axis with dots + if (this.dom.axis.parentNode) { + this.dom.axis.parentNode.removeChild(this.dom.axis); + } - element.dispatchEvent(event); - return this; - }, + // remove the labelset containing all group labels + if (this.dom.labelSet.parentNode) { + this.dom.labelSet.parentNode.removeChild(this.dom.labelSet); + } + }; - /** - * enable of disable hammer.js detection - * @method enable - * @chainable - * @param {Boolean} state - */ - enable: function enable(state) { - this.enabled = state; - return this; - }, + /** + * Show the component in the DOM (when not already visible). + * @return {Boolean} changed + */ + ItemSet.prototype.show = function() { + // show frame containing the items + if (!this.dom.frame.parentNode) { + this.body.dom.center.appendChild(this.dom.frame); + } - /** - * dispose this hammer instance - * @method dispose - * @return {Null} - */ - dispose: function dispose() { - var i, eh; + // show axis with dots + if (!this.dom.axis.parentNode) { + this.body.dom.backgroundVertical.appendChild(this.dom.axis); + } - // undo all changes made by stop_browser_behavior - Utils.toggleBehavior(this.element, this.options.behavior, false); + // show labelset containing labels + if (!this.dom.labelSet.parentNode) { + this.body.dom.left.appendChild(this.dom.labelSet); + } + }; - // unbind all custom event handlers - for(i = -1; (eh = this.eventHandlers[++i]);) { - Utils.off(this.element, eh.gesture, eh.handler); - } + /** + * Set selected items by their id. Replaces the current selection + * Unknown id's are silently ignored. + * @param {string[] | string} [ids] An array with zero or more id's of the items to be + * selected, or a single item id. If ids is undefined + * or an empty array, all items will be unselected. + */ + ItemSet.prototype.setSelection = function(ids) { + var i, ii, id, item; - this.eventHandlers = []; + if (ids == undefined) ids = []; + if (!Array.isArray(ids)) ids = [ids]; - // unbind the start event listener - Event.off(this.element, EVENT_TYPES[EVENT_START], this.eventStartHandler); + // unselect currently selected items + for (i = 0, ii = this.selection.length; i < ii; i++) { + id = this.selection[i]; + item = this.items[id]; + if (item) item.unselect(); + } - return null; + // select items + this.selection = []; + for (i = 0, ii = ids.length; i < ii; i++) { + id = ids[i]; + item = this.items[id]; + if (item) { + this.selection.push(id); + item.select(); } + } }; - - /** - * @module gestures - */ - /** - * Move with x fingers (default 1) around on the page. - * Preventing the default browser behavior is a good way to improve feel and working. - * ```` - * hammertime.on("drag", function(ev) { - * console.log(ev); - * ev.gesture.preventDefault(); - * }); - * ```` - * - * @class Drag - * @static - */ - /** - * @event drag - * @param {Object} ev - */ - /** - * @event dragstart - * @param {Object} ev - */ - /** - * @event dragend - * @param {Object} ev - */ - /** - * @event drapleft - * @param {Object} ev - */ - /** - * @event dragright - * @param {Object} ev - */ - /** - * @event dragup - * @param {Object} ev - */ /** - * @event dragdown - * @param {Object} ev + * Get the selected items by their id + * @return {Array} ids The ids of the selected items */ + ItemSet.prototype.getSelection = function() { + return this.selection.concat([]); + }; /** - * @param {String} name + * Get the id's of the currently visible items. + * @returns {Array} The ids of the visible items */ - (function(name) { - var triggered = false; + ItemSet.prototype.getVisibleItems = function() { + var range = this.body.range.getRange(); + var left = this.body.util.toScreen(range.start); + var right = this.body.util.toScreen(range.end); - function dragGesture(ev, inst) { - var cur = Detection.current; + var ids = []; + for (var groupId in this.groups) { + if (this.groups.hasOwnProperty(groupId)) { + var group = this.groups[groupId]; + var rawVisibleItems = group.visibleItems; - // max touches - if(inst.options.dragMaxTouches > 0 && - ev.touches.length > inst.options.dragMaxTouches) { - return; + // filter the "raw" set with visibleItems into a set which is really + // visible by pixels + for (var i = 0; i < rawVisibleItems.length; i++) { + var item = rawVisibleItems[i]; + // TODO: also check whether visible vertically + if ((item.left < right) && (item.left + item.width > left)) { + ids.push(item.id); } + } + } + } - switch(ev.eventType) { - case EVENT_START: - triggered = false; - break; - - case EVENT_MOVE: - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(ev.distance < inst.options.dragMinDistance && - cur.name != name) { - return; - } - - var startCenter = cur.startEvent.center; - - // we are dragging! - if(cur.name != name) { - cur.name = name; - if(inst.options.dragDistanceCorrection && ev.distance > 0) { - // When a drag is triggered, set the event center to dragMinDistance pixels from the original event center. - // Without this correction, the dragged distance would jumpstart at dragMinDistance pixels instead of at 0. - // It might be useful to save the original start point somewhere - var factor = Math.abs(inst.options.dragMinDistance / ev.distance); - startCenter.pageX += ev.deltaX * factor; - startCenter.pageY += ev.deltaY * factor; - startCenter.clientX += ev.deltaX * factor; - startCenter.clientY += ev.deltaY * factor; - - // recalculate event data using new start point - ev = Detection.extendEventData(ev); - } - } - - // lock drag to axis? - if(cur.lastEvent.dragLockToAxis || - ( inst.options.dragLockToAxis && - inst.options.dragLockMinDistance <= ev.distance - )) { - ev.dragLockToAxis = true; - } - - // keep direction on the axis that the drag gesture started on - var lastDirection = cur.lastEvent.direction; - if(ev.dragLockToAxis && lastDirection !== ev.direction) { - if(Utils.isVertical(lastDirection)) { - ev.direction = (ev.deltaY < 0) ? DIRECTION_UP : DIRECTION_DOWN; - } else { - ev.direction = (ev.deltaX < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT; - } - } + return ids; + }; - // first time, trigger dragstart event - if(!triggered) { - inst.trigger(name + 'start', ev); - triggered = true; - } + /** + * Deselect a selected item + * @param {String | Number} id + * @private + */ + ItemSet.prototype._deselect = function(id) { + var selection = this.selection; + for (var i = 0, ii = selection.length; i < ii; i++) { + if (selection[i] == id) { // non-strict comparison! + selection.splice(i, 1); + break; + } + } + }; - // trigger events - inst.trigger(name, ev); - inst.trigger(name + ev.direction, ev); + /** + * Repaint the component + * @return {boolean} Returns true if the component is resized + */ + ItemSet.prototype.redraw = function() { + var margin = this.options.margin, + range = this.body.range, + asSize = util.option.asSize, + options = this.options, + orientation = options.orientation, + resized = false, + frame = this.dom.frame, + editable = options.editable.updateTime || options.editable.updateGroup; - var isVertical = Utils.isVertical(ev.direction); + // recalculate absolute position (before redrawing groups) + this.props.top = this.body.domProps.top.height + this.body.domProps.border.top; + this.props.left = this.body.domProps.left.width + this.body.domProps.border.left; - // block the browser events - if((inst.options.dragBlockVertical && isVertical) || - (inst.options.dragBlockHorizontal && !isVertical)) { - ev.preventDefault(); - } - break; + // update class name + frame.className = 'itemset' + (editable ? ' editable' : ''); - case EVENT_RELEASE: - if(triggered && ev.changedLength <= inst.options.dragMaxTouches) { - inst.trigger(name + 'end', ev); - triggered = false; - } - break; + // reorder the groups (if needed) + resized = this._orderGroups() || resized; - case EVENT_END: - triggered = false; - break; - } - } + // check whether zoomed (in that case we need to re-stack everything) + // TODO: would be nicer to get this as a trigger from Range + var visibleInterval = range.end - range.start; + var zoomed = (visibleInterval != this.lastVisibleInterval) || (this.props.width != this.props.lastWidth); + if (zoomed) this.stackDirty = true; + this.lastVisibleInterval = visibleInterval; + this.props.lastWidth = this.props.width; - Hammer.gestures.Drag = { - name: name, - index: 50, - handler: dragGesture, - defaults: { - /** - * minimal movement that have to be made before the drag event gets triggered - * @property dragMinDistance - * @type {Number} - * @default 10 - */ - dragMinDistance: 10, + var restack = this.stackDirty; + var firstGroup = this._firstGroup(); + var firstMargin = { + item: margin.item, + axis: margin.axis + }; + var nonFirstMargin = { + item: margin.item, + axis: margin.item.vertical / 2 + }; + var height = 0; + var minHeight = margin.axis + margin.item.vertical; - /** - * Set dragDistanceCorrection to true to make the starting point of the drag - * be calculated from where the drag was triggered, not from where the touch started. - * Useful to avoid a jerk-starting drag, which can make fine-adjustments - * through dragging difficult, and be visually unappealing. - * @property dragDistanceCorrection - * @type {Boolean} - * @default true - */ - dragDistanceCorrection: true, + // redraw the background group + this.groups[BACKGROUND].redraw(range, nonFirstMargin, restack); - /** - * set 0 for unlimited, but this can conflict with transform - * @property dragMaxTouches - * @type {Number} - * @default 1 - */ - dragMaxTouches: 1, + // redraw all regular groups + util.forEach(this.groups, function (group) { + var groupMargin = (group == firstGroup) ? firstMargin : nonFirstMargin; + var groupResized = group.redraw(range, groupMargin, restack); + resized = groupResized || resized; + height += group.height; + }); + height = Math.max(height, minHeight); + this.stackDirty = false; - /** - * prevent default browser behavior when dragging occurs - * be careful with it, it makes the element a blocking element - * when you are using the drag gesture, it is a good practice to set this true - * @property dragBlockHorizontal - * @type {Boolean} - * @default false - */ - dragBlockHorizontal: false, + // update frame height + frame.style.height = asSize(height); - /** - * same as `dragBlockHorizontal`, but for vertical movement - * @property dragBlockVertical - * @type {Boolean} - * @default false - */ - dragBlockVertical: false, + // calculate actual size + this.props.width = frame.offsetWidth; + this.props.height = height; - /** - * dragLockToAxis keeps the drag gesture on the axis that it started on, - * It disallows vertical directions if the initial direction was horizontal, and vice versa. - * @property dragLockToAxis - * @type {Boolean} - * @default false - */ - dragLockToAxis: false, + // reposition axis + this.dom.axis.style.top = asSize((orientation == 'top') ? + (this.body.domProps.top.height + this.body.domProps.border.top) : + (this.body.domProps.top.height + this.body.domProps.centerContainer.height)); + this.dom.axis.style.left = '0'; - /** - * drag lock only kicks in when distance > dragLockMinDistance - * This way, locking occurs only when the distance has become large enough to reliably determine the direction - * @property dragLockMinDistance - * @type {Number} - * @default 25 - */ - dragLockMinDistance: 25 - } - }; - })('drag'); + // check if this component is resized + resized = this._isResized() || resized; + + return resized; + }; /** - * @module gestures - */ - /** - * trigger a simple gesture event, so you can do anything in your handler. - * only usable if you know what your doing... - * - * @class Gesture - * @static + * Get the first group, aligned with the axis + * @return {Group | null} firstGroup + * @private */ + ItemSet.prototype._firstGroup = function() { + var firstGroupIndex = (this.options.orientation == 'top') ? 0 : (this.groupIds.length - 1); + var firstGroupId = this.groupIds[firstGroupIndex]; + var firstGroup = this.groups[firstGroupId] || this.groups[UNGROUPED]; + + return firstGroup || null; + }; + /** - * @event gesture - * @param {Object} ev + * Create or delete the group holding all ungrouped items. This group is used when + * there are no groups specified. + * @protected */ - Hammer.gestures.Gesture = { - name: 'gesture', - index: 1337, - handler: function releaseGesture(ev, inst) { - inst.trigger(this.name, ev); + ItemSet.prototype._updateUngrouped = function() { + var ungrouped = this.groups[UNGROUPED]; + var background = this.groups[BACKGROUND]; + var item, itemId; + + if (this.groupsData) { + // remove the group holding all ungrouped items + if (ungrouped) { + ungrouped.hide(); + delete this.groups[UNGROUPED]; + + for (itemId in this.items) { + if (this.items.hasOwnProperty(itemId)) { + item = this.items[itemId]; + item.parent && item.parent.remove(item); + var groupId = this._getGroupId(item.data); + var group = this.groups[groupId]; + group && group.add(item) || item.hide(); + } + } + } + } + else { + // create a group holding all (unfiltered) items + if (!ungrouped) { + var id = null; + var data = null; + ungrouped = new Group(id, data, this); + this.groups[UNGROUPED] = ungrouped; + + for (itemId in this.items) { + if (this.items.hasOwnProperty(itemId)) { + item = this.items[itemId]; + ungrouped.add(item); + } + } + + ungrouped.show(); } + } }; /** - * @module gestures + * Get the element for the labelset + * @return {HTMLElement} labelSet */ + ItemSet.prototype.getLabelSet = function() { + return this.dom.labelSet; + }; + /** - * Touch stays at the same place for x time - * - * @class Hold - * @static + * Set items + * @param {vis.DataSet | null} items */ + ItemSet.prototype.setItems = function(items) { + var me = this, + ids, + oldItemsData = this.itemsData; + + // replace the dataset + if (!items) { + this.itemsData = null; + } + else if (items instanceof DataSet || items instanceof DataView) { + this.itemsData = items; + } + else { + throw new TypeError('Data must be an instance of DataSet or DataView'); + } + + if (oldItemsData) { + // unsubscribe from old dataset + util.forEach(this.itemListeners, function (callback, event) { + oldItemsData.off(event, callback); + }); + + // remove all drawn items + ids = oldItemsData.getIds(); + this._onRemove(ids); + } + + if (this.itemsData) { + // subscribe to new dataset + var id = this.id; + util.forEach(this.itemListeners, function (callback, event) { + me.itemsData.on(event, callback, id); + }); + + // add all new items + ids = this.itemsData.getIds(); + this._onAdd(ids); + + // update the group holding all ungrouped items + this._updateUngrouped(); + } + }; + /** - * @event hold - * @param {Object} ev + * Get the current items + * @returns {vis.DataSet | null} */ + ItemSet.prototype.getItems = function() { + return this.itemsData; + }; /** - * @param {String} name + * Set groups + * @param {vis.DataSet} groups */ - (function(name) { - var timer; + ItemSet.prototype.setGroups = function(groups) { + var me = this, + ids; - function holdGesture(ev, inst) { - var options = inst.options, - current = Detection.current; + // unsubscribe from current dataset + if (this.groupsData) { + util.forEach(this.groupListeners, function (callback, event) { + me.groupsData.unsubscribe(event, callback); + }); - switch(ev.eventType) { - case EVENT_START: - clearTimeout(timer); + // remove all drawn groups + ids = this.groupsData.getIds(); + this.groupsData = null; + this._onRemoveGroups(ids); // note: this will cause a redraw + } - // set the gesture so we can check in the timeout if it still is - current.name = name; + // replace the dataset + if (!groups) { + this.groupsData = null; + } + else if (groups instanceof DataSet || groups instanceof DataView) { + this.groupsData = groups; + } + else { + throw new TypeError('Data must be an instance of DataSet or DataView'); + } - // set timer and if after the timeout it still is hold, - // we trigger the hold event - timer = setTimeout(function() { - if(current && current.name == name) { - inst.trigger(name, ev); - } - }, options.holdTimeout); - break; + if (this.groupsData) { + // subscribe to new dataset + var id = this.id; + util.forEach(this.groupListeners, function (callback, event) { + me.groupsData.on(event, callback, id); + }); - case EVENT_MOVE: - if(ev.distance > options.holdThreshold) { - clearTimeout(timer); - } - break; + // draw all ms + ids = this.groupsData.getIds(); + this._onAddGroups(ids); + } - case EVENT_RELEASE: - clearTimeout(timer); - break; - } - } + // update the group holding all ungrouped items + this._updateUngrouped(); - Hammer.gestures.Hold = { - name: name, - index: 10, - defaults: { - /** - * @property holdTimeout - * @type {Number} - * @default 500 - */ - holdTimeout: 500, + // update the order of all items in each group + this._order(); - /** - * movement allowed while holding - * @property holdThreshold - * @type {Number} - * @default 2 - */ - holdThreshold: 2 - }, - handler: holdGesture - }; - })('hold'); + this.body.emitter.emit('change', {queue: true}); + }; /** - * @module gestures - */ - /** - * when a touch is being released from the page - * - * @class Release - * @static - */ - /** - * @event release - * @param {Object} ev + * Get the current groups + * @returns {vis.DataSet | null} groups */ - Hammer.gestures.Release = { - name: 'release', - index: Infinity, - handler: function releaseGesture(ev, inst) { - if(ev.eventType == EVENT_RELEASE) { - inst.trigger(this.name, ev); - } - } + ItemSet.prototype.getGroups = function() { + return this.groupsData; }; /** - * @module gestures - */ - /** - * triggers swipe events when the end velocity is above the threshold - * for best usage, set `preventDefault` (on the drag gesture) to `true` - * ```` - * hammertime.on("dragleft swipeleft", function(ev) { - * console.log(ev); - * ev.gesture.preventDefault(); - * }); - * ```` - * - * @class Swipe - * @static - */ - /** - * @event swipe - * @param {Object} ev - */ - /** - * @event swipeleft - * @param {Object} ev + * Remove an item by its id + * @param {String | Number} id */ + ItemSet.prototype.removeItem = function(id) { + var item = this.itemsData.get(id), + dataset = this.itemsData.getDataSet(); + + if (item) { + // confirm deletion + this.options.onRemove(item, function (item) { + if (item) { + // remove by id here, it is possible that an item has no id defined + // itself, so better not delete by the item itself + dataset.remove(id); + } + }); + } + }; + /** - * @event swiperight - * @param {Object} ev + * Get the time of an item based on it's data and options.type + * @param {Object} itemData + * @returns {string} Returns the type + * @private */ + ItemSet.prototype._getType = function (itemData) { + return itemData.type || this.options.type || (itemData.end ? 'range' : 'box'); + }; + + /** - * @event swipeup - * @param {Object} ev + * Get the group id for an item + * @param {Object} itemData + * @returns {string} Returns the groupId + * @private */ + ItemSet.prototype._getGroupId = function (itemData) { + var type = this._getType(itemData); + if (type == 'background' && itemData.group == undefined) { + return BACKGROUND; + } + else { + return this.groupsData ? itemData.group : UNGROUPED; + } + }; + /** - * @event swipedown - * @param {Object} ev + * Handle updated items + * @param {Number[]} ids + * @protected */ - Hammer.gestures.Swipe = { - name: 'swipe', - index: 40, - defaults: { - /** - * @property swipeMinTouches - * @type {Number} - * @default 1 - */ - swipeMinTouches: 1, + ItemSet.prototype._onUpdate = function(ids) { + var me = this; - /** - * @property swipeMaxTouches - * @type {Number} - * @default 1 - */ - swipeMaxTouches: 1, + ids.forEach(function (id) { + var itemData = me.itemsData.get(id, me.itemOptions); + var item = me.items[id]; + var type = me._getType(itemData); - /** - * horizontal swipe velocity - * @property swipeVelocityX - * @type {Number} - * @default 0.6 - */ - swipeVelocityX: 0.6, + var constructor = ItemSet.types[type]; - /** - * vertical swipe velocity - * @property swipeVelocityY - * @type {Number} - * @default 0.6 - */ - swipeVelocityY: 0.6 - }, + if (item) { + // update item + if (!constructor || !(item instanceof constructor)) { + // item type has changed, delete the item and recreate it + me._removeItem(item); + item = null; + } + else { + me._updateItem(item, itemData); + } + } - handler: function swipeGesture(ev, inst) { - if(ev.eventType == EVENT_RELEASE) { - var touches = ev.touches.length, - options = inst.options; + if (!item) { + // create item + if (constructor) { + item = new constructor(itemData, me.conversion, me.options); + item.id = id; // TODO: not so nice setting id afterwards + me._addItem(item); + } + else if (type == 'rangeoverflow') { + // TODO: deprecated since version 2.1.0 (or 3.0.0?). cleanup some day + throw new TypeError('Item type "rangeoverflow" is deprecated. Use css styling instead: ' + + '.vis.timeline .item.range .content {overflow: visible;}'); + } + else { + throw new TypeError('Unknown item type "' + type + '"'); + } + } + }); - // max touches - if(touches < options.swipeMinTouches || - touches > options.swipeMaxTouches) { - return; - } + this._order(); + this.stackDirty = true; // force re-stacking of all items next redraw + this.body.emitter.emit('change', {queue: true}); + }; - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(ev.velocityX > options.swipeVelocityX || - ev.velocityY > options.swipeVelocityY) { - // trigger swipe events - inst.trigger(this.name, ev); - inst.trigger(this.name + ev.direction, ev); - } - } + /** + * Handle added items + * @param {Number[]} ids + * @protected + */ + ItemSet.prototype._onAdd = ItemSet.prototype._onUpdate; + + /** + * Handle removed items + * @param {Number[]} ids + * @protected + */ + ItemSet.prototype._onRemove = function(ids) { + var count = 0; + var me = this; + ids.forEach(function (id) { + var item = me.items[id]; + if (item) { + count++; + me._removeItem(item); } + }); + + if (count) { + // update order + this._order(); + this.stackDirty = true; // force re-stacking of all items next redraw + this.body.emitter.emit('change', {queue: true}); + } }; /** - * @module gestures - */ - /** - * Single tap and a double tap on a place - * - * @class Tap - * @static - */ - /** - * @event tap - * @param {Object} ev + * Update the order of item in all groups + * @private */ + ItemSet.prototype._order = function() { + // reorder the items in all groups + // TODO: optimization: only reorder groups affected by the changed items + util.forEach(this.groups, function (group) { + group.order(); + }); + }; + /** - * @event doubletap - * @param {Object} ev + * Handle updated groups + * @param {Number[]} ids + * @private */ + ItemSet.prototype._onUpdateGroups = function(ids) { + this._onAddGroups(ids); + }; /** - * @param {String} name + * Handle changed groups (added or updated) + * @param {Number[]} ids + * @private */ - (function(name) { - var hasMoved = false; - - function tapGesture(ev, inst) { - var options = inst.options, - current = Detection.current, - prev = Detection.previous, - sincePrev, - didDoubleTap; + ItemSet.prototype._onAddGroups = function(ids) { + var me = this; - switch(ev.eventType) { - case EVENT_START: - hasMoved = false; - break; + ids.forEach(function (id) { + var groupData = me.groupsData.get(id); + var group = me.groups[id]; - case EVENT_MOVE: - hasMoved = hasMoved || (ev.distance > options.tapMaxDistance); - break; + if (!group) { + // check for reserved ids + if (id == UNGROUPED || id == BACKGROUND) { + throw new Error('Illegal group id. ' + id + ' is a reserved id.'); + } - case EVENT_END: - if(!Utils.inStr(ev.srcEvent.type, 'cancel') && ev.deltaTime < options.tapMaxTime && !hasMoved) { - // previous gesture, for the double tap since these are two different gesture detections - sincePrev = prev && prev.lastEvent && ev.timeStamp - prev.lastEvent.timeStamp; - didDoubleTap = false; + var groupOptions = Object.create(me.options); + util.extend(groupOptions, { + height: null + }); - // check if double tap - if(prev && prev.name == name && - (sincePrev && sincePrev < options.doubleTapInterval) && - ev.distance < options.doubleTapDistance) { - inst.trigger('doubletap', ev); - didDoubleTap = true; - } + group = new Group(id, groupData, me); + me.groups[id] = group; - // do a single tap - if(!didDoubleTap || options.tapAlways) { - current.name = name; - inst.trigger(current.name, ev); - } - } - break; + // add items with this groupId to the new group + for (var itemId in me.items) { + if (me.items.hasOwnProperty(itemId)) { + var item = me.items[itemId]; + if (item.data.group == id) { + group.add(item); + } } + } + + group.order(); + group.show(); + } + else { + // update group + group.setData(groupData); } + }); - Hammer.gestures.Tap = { - name: name, - index: 100, - handler: tapGesture, - defaults: { - /** - * max time of a tap, this is for the slow tappers - * @property tapMaxTime - * @type {Number} - * @default 250 - */ - tapMaxTime: 250, + this.body.emitter.emit('change', {queue: true}); + }; - /** - * max distance of movement of a tap, this is for the slow tappers - * @property tapMaxDistance - * @type {Number} - * @default 10 - */ - tapMaxDistance: 10, + /** + * Handle removed groups + * @param {Number[]} ids + * @private + */ + ItemSet.prototype._onRemoveGroups = function(ids) { + var groups = this.groups; + ids.forEach(function (id) { + var group = groups[id]; - /** - * always trigger the `tap` event, even while double-tapping - * @property tapAlways - * @type {Boolean} - * @default true - */ - tapAlways: true, + if (group) { + group.hide(); + delete groups[id]; + } + }); - /** - * max distance between two taps - * @property doubleTapDistance - * @type {Number} - * @default 20 - */ - doubleTapDistance: 20, + this.markDirty(); - /** - * max time between two taps - * @property doubleTapInterval - * @type {Number} - * @default 300 - */ - doubleTapInterval: 300 - } - }; - })('tap'); + this.body.emitter.emit('change', {queue: true}); + }; /** - * @module gestures - */ - /** - * when a touch is being touched at the page - * - * @class Touch - * @static - */ - /** - * @event touch - * @param {Object} ev + * Reorder the groups if needed + * @return {boolean} changed + * @private */ - Hammer.gestures.Touch = { - name: 'touch', - index: -Infinity, - defaults: { - /** - * call preventDefault at touchstart, and makes the element blocking by disabling the scrolling of the page, - * but it improves gestures like transforming and dragging. - * be careful with using this, it can be very annoying for users to be stuck on the page - * @property preventDefault - * @type {Boolean} - * @default false - */ - preventDefault: false, + ItemSet.prototype._orderGroups = function () { + if (this.groupsData) { + // reorder the groups + var groupIds = this.groupsData.getIds({ + order: this.options.groupOrder + }); - /** - * disable mouse events, so only touch (or pen!) input triggers events - * @property preventMouse - * @type {Boolean} - * @default false - */ - preventMouse: false - }, - handler: function touchGesture(ev, inst) { - if(inst.options.preventMouse && ev.pointerType == POINTER_MOUSE) { - ev.stopDetect(); - return; - } + var changed = !util.equalArray(groupIds, this.groupIds); + if (changed) { + // hide all groups, removes them from the DOM + var groups = this.groups; + groupIds.forEach(function (groupId) { + groups[groupId].hide(); + }); - if(inst.options.preventDefault) { - ev.preventDefault(); - } + // show the groups again, attach them to the DOM in correct order + groupIds.forEach(function (groupId) { + groups[groupId].show(); + }); - if(ev.eventType == EVENT_TOUCH) { - inst.trigger('touch', ev); - } + this.groupIds = groupIds; } + + return changed; + } + else { + return false; + } }; /** - * @module gestures - */ - /** - * User want to scale or rotate with 2 fingers - * Preventing the default browser behavior is a good way to improve feel and working. This can be done with the - * `preventDefault` option. - * - * @class Transform - * @static - */ - /** - * @event transform - * @param {Object} ev - */ - /** - * @event transformstart - * @param {Object} ev - */ - /** - * @event transformend - * @param {Object} ev - */ - /** - * @event pinchin - * @param {Object} ev - */ - /** - * @event pinchout - * @param {Object} ev - */ - /** - * @event rotate - * @param {Object} ev + * Add a new item + * @param {Item} item + * @private */ + ItemSet.prototype._addItem = function(item) { + this.items[item.id] = item; + + // add to group + var groupId = this._getGroupId(item.data); + var group = this.groups[groupId]; + if (group) group.add(item); + }; /** - * @param {String} name + * Update an existing item + * @param {Item} item + * @param {Object} itemData + * @private */ - (function(name) { - var triggered = false; - - function transformGesture(ev, inst) { - switch(ev.eventType) { - case EVENT_START: - triggered = false; - break; + ItemSet.prototype._updateItem = function(item, itemData) { + var oldGroupId = item.data.group; - case EVENT_MOVE: - // at least multitouch - if(ev.touches.length < 2) { - return; - } + // update the items data (will redraw the item when displayed) + item.setData(itemData); - var scaleThreshold = Math.abs(1 - ev.scale); - var rotationThreshold = Math.abs(ev.rotation); + // update group + if (oldGroupId != item.data.group) { + var oldGroup = this.groups[oldGroupId]; + if (oldGroup) oldGroup.remove(item); - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(scaleThreshold < inst.options.transformMinScale && - rotationThreshold < inst.options.transformMinRotation) { - return; - } + var groupId = this._getGroupId(item.data); + var group = this.groups[groupId]; + if (group) group.add(item); + } + }; - // we are transforming! - Detection.current.name = name; + /** + * Delete an item from the ItemSet: remove it from the DOM, from the map + * with items, and from the map with visible items, and from the selection + * @param {Item} item + * @private + */ + ItemSet.prototype._removeItem = function(item) { + // remove from DOM + item.hide(); - // first time, trigger dragstart event - if(!triggered) { - inst.trigger(name + 'start', ev); - triggered = true; - } + // remove from items + delete this.items[item.id]; - inst.trigger(name, ev); // basic transform event + // remove from selection + var index = this.selection.indexOf(item.id); + if (index != -1) this.selection.splice(index, 1); - // trigger rotate event - if(rotationThreshold > inst.options.transformMinRotation) { - inst.trigger('rotate', ev); - } + // remove from group + item.parent && item.parent.remove(item); + }; - // trigger pinch event - if(scaleThreshold > inst.options.transformMinScale) { - inst.trigger('pinch', ev); - inst.trigger('pinch' + (ev.scale < 1 ? 'in' : 'out'), ev); - } - break; + /** + * Create an array containing all items being a range (having an end date) + * @param array + * @returns {Array} + * @private + */ + ItemSet.prototype._constructByEndArray = function(array) { + var endArray = []; - case EVENT_RELEASE: - if(triggered && ev.changedLength < 2) { - inst.trigger(name + 'end', ev); - triggered = false; - } - break; - } + for (var i = 0; i < array.length; i++) { + if (array[i] instanceof RangeItem) { + endArray.push(array[i]); } + } + return endArray; + }; - Hammer.gestures.Transform = { - name: name, - index: 45, - defaults: { - /** - * minimal scale factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1 - * @property transformMinScale - * @type {Number} - * @default 0.01 - */ - transformMinScale: 0.01, - - /** - * rotation in degrees - * @property transformMinRotation - * @type {Number} - * @default 1 - */ - transformMinRotation: 1 - }, - - handler: transformGesture - }; - })('transform'); + /** + * Register the clicked item on touch, before dragStart is initiated. + * + * dragStart is initiated from a mousemove event, which can have left the item + * already resulting in an item == null + * + * @param {Event} event + * @private + */ + ItemSet.prototype._onTouch = function (event) { + // store the touched item, used in _onDragStart + this.touchParams.item = ItemSet.itemFromTarget(event); + }; /** - * @module hammer + * Start dragging the selected events + * @param {Event} event + * @private */ + ItemSet.prototype._onDragStart = function (event) { + if (!this.options.editable.updateTime && !this.options.editable.updateGroup) { + return; + } - // AMD export - if(true) { - !(__WEBPACK_AMD_DEFINE_RESULT__ = function() { - return Hammer; - }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - // commonjs export - } else if(typeof module !== 'undefined' && module.exports) { - module.exports = Hammer; - // browser export - } else { - window.Hammer = Hammer; - } + var item = this.touchParams.item || null; + var me = this; + var props; - })(window); + if (item && item.selected) { + var dragLeftItem = event.target.dragLeftItem; + var dragRightItem = event.target.dragRightItem; -/***/ }, -/* 21 */ -/***/ function(module, exports, __webpack_require__) { + if (dragLeftItem) { + props = { + item: dragLeftItem, + initialX: event.gesture.center.clientX + }; - var util = __webpack_require__(1); - var hammerUtil = __webpack_require__(22); - var moment = __webpack_require__(2); - var Component = __webpack_require__(23); - var DateUtil = __webpack_require__(24); + if (me.options.editable.updateTime) { + props.start = item.data.start.valueOf(); + } + if (me.options.editable.updateGroup) { + if ('group' in item.data) props.group = item.data.group; + } - /** - * @constructor Range - * A Range controls a numeric range with a start and end value. - * The Range adjusts the range based on mouse events or programmatic changes, - * and triggers events when the range is changing or has been changed. - * @param {{dom: Object, domProps: Object, emitter: Emitter}} body - * @param {Object} [options] See description at Range.setOptions - */ - function Range(body, options) { - var now = moment().hours(0).minutes(0).seconds(0).milliseconds(0); - this.start = now.clone().add(-3, 'days').valueOf(); // Number - this.end = now.clone().add(4, 'days').valueOf(); // Number + this.touchParams.itemProps = [props]; + } + else if (dragRightItem) { + props = { + item: dragRightItem, + initialX: event.gesture.center.clientX + }; - this.body = body; - this.deltaDifference = 0; - this.scaleOffset = 0; - this.startToFront = false; - this.endToFront = true; + if (me.options.editable.updateTime) { + props.end = item.data.end.valueOf(); + } + if (me.options.editable.updateGroup) { + if ('group' in item.data) props.group = item.data.group; + } + + this.touchParams.itemProps = [props]; + } + else { + this.touchParams.itemProps = this.getSelection().map(function (id) { + var item = me.items[id]; + var props = { + item: item, + initialX: event.gesture.center.clientX + }; + + if (me.options.editable.updateTime) { + if ('start' in item.data) props.start = item.data.start.valueOf(); + if ('end' in item.data) props.end = item.data.end.valueOf(); + } + if (me.options.editable.updateGroup) { + if ('group' in item.data) props.group = item.data.group; + } + + return props; + }); + } + + event.stopPropagation(); + } + }; - // default options - this.defaultOptions = { - start: null, - end: null, - direction: 'horizontal', // 'horizontal' or 'vertical' - moveable: true, - zoomable: true, - min: null, - max: null, - zoomMin: 10, // milliseconds - zoomMax: 1000 * 60 * 60 * 24 * 365 * 10000 // milliseconds - }; - this.options = util.extend({}, this.defaultOptions); + /** + * Drag selected items + * @param {Event} event + * @private + */ + ItemSet.prototype._onDrag = function (event) { + event.preventDefault() - this.props = { - touch: {} - }; - this.animateTimer = null; + if (this.touchParams.itemProps) { + var me = this; + var snap = this.body.util.snap || null; + var xOffset = this.body.dom.root.offsetLeft + this.body.domProps.left.width; - // drag listeners for dragging - this.body.emitter.on('dragstart', this._onDragStart.bind(this)); - this.body.emitter.on('drag', this._onDrag.bind(this)); - this.body.emitter.on('dragend', this._onDragEnd.bind(this)); + // move + this.touchParams.itemProps.forEach(function (props) { + var newProps = {}; + var current = me.body.util.toTime(event.gesture.center.clientX - xOffset); + var initial = me.body.util.toTime(props.initialX - xOffset); + var offset = current - initial; - // ignore dragging when holding - this.body.emitter.on('hold', this._onHold.bind(this)); + if ('start' in props) { + var start = new Date(props.start + offset); + newProps.start = snap ? snap(start) : start; + } - // mouse wheel for zooming - this.body.emitter.on('mousewheel', this._onMouseWheel.bind(this)); - this.body.emitter.on('DOMMouseScroll', this._onMouseWheel.bind(this)); // For FF + if ('end' in props) { + var end = new Date(props.end + offset); + newProps.end = snap ? snap(end) : end; + } - // pinch to zoom - this.body.emitter.on('touch', this._onTouch.bind(this)); - this.body.emitter.on('pinch', this._onPinch.bind(this)); + if ('group' in props) { + // drag from one group to another + var group = ItemSet.groupFromTarget(event); + newProps.group = group && group.groupId; + } - this.setOptions(options); - } + // confirm moving the item + var itemData = util.extend({}, props.item.data, newProps); + me.options.onMoving(itemData, function (itemData) { + if (itemData) { + me._updateItemProps(props.item, itemData); + } + }); + }); - Range.prototype = new Component(); + this.stackDirty = true; // force re-stacking of all items next redraw + this.body.emitter.emit('change'); + + event.stopPropagation(); + } + }; /** - * Set options for the range controller - * @param {Object} options Available options: - * {Number | Date | String} start Start date for the range - * {Number | Date | String} end End date for the range - * {Number} min Minimum value for start - * {Number} max Maximum value for end - * {Number} zoomMin Set a minimum value for - * (end - start). - * {Number} zoomMax Set a maximum value for - * (end - start). - * {Boolean} moveable Enable moving of the range - * by dragging. True by default - * {Boolean} zoomable Enable zooming of the range - * by pinching/scrolling. True by default + * Update an items properties + * @param {Item} item + * @param {Object} props Can contain properties start, end, and group. + * @private */ - Range.prototype.setOptions = function (options) { - if (options) { - // copy the options that we know - var fields = ['direction', 'min', 'max', 'zoomMin', 'zoomMax', 'moveable', 'zoomable', 'activate', 'hiddenDates']; - util.selectiveExtend(fields, this.options, options); - - if ('start' in options || 'end' in options) { - // apply a new range. both start and end are optional - this.setRange(options.start, options.end); - } + ItemSet.prototype._updateItemProps = function(item, props) { + // TODO: copy all properties from props to item? (also new ones) + if ('start' in props) item.data.start = props.start; + if ('end' in props) item.data.end = props.end; + if ('group' in props && item.data.group != props.group) { + this._moveToGroup(item, props.group) } }; /** - * Test whether direction has a valid value - * @param {String} direction 'horizontal' or 'vertical' + * Move an item to another group + * @param {Item} item + * @param {String | Number} groupId + * @private */ - function validateDirection (direction) { - if (direction != 'horizontal' && direction != 'vertical') { - throw new TypeError('Unknown direction "' + direction + '". ' + - 'Choose "horizontal" or "vertical".'); + ItemSet.prototype._moveToGroup = function(item, groupId) { + var group = this.groups[groupId]; + if (group && group.groupId != item.data.group) { + var oldGroup = item.parent; + oldGroup.remove(item); + oldGroup.order(); + group.add(item); + group.order(); + + item.data.group = group.groupId; } - } + }; /** - * Set a new start and end range - * @param {Date | Number | String} [start] - * @param {Date | Number | String} [end] - * @param {boolean | number} [animate=false] If true, the range is animated - * smoothly to the new window. - * If animate is a number, the - * number is taken as duration - * Default duration is 500 ms. - * @param {Boolean} [byUser=false] - * + * End of dragging selected items + * @param {Event} event + * @private */ - Range.prototype.setRange = function(start, end, animate, byUser) { - if (byUser !== true) { - byUser = false; - } - var _start = start != undefined ? util.convert(start, 'Date').valueOf() : null; - var _end = end != undefined ? util.convert(end, 'Date').valueOf() : null; - this._cancelAnimation(); + ItemSet.prototype._onDragEnd = function (event) { + event.preventDefault() - if (animate) { - var me = this; - var initStart = this.start; - var initEnd = this.end; - var duration = typeof animate === 'number' ? animate : 500; - var initTime = new Date().valueOf(); - var anyChanged = false; + if (this.touchParams.itemProps) { + // prepare a change set for the changed items + var changes = [], + me = this, + dataset = this.itemsData.getDataSet(); - var next = function () { - if (!me.props.touch.dragging) { - var now = new Date().valueOf(); - var time = now - initTime; - var done = time > duration; - var s = (done || _start === null) ? _start : util.easeInOutQuad(time, initStart, _start, duration); - var e = (done || _end === null) ? _end : util.easeInOutQuad(time, initEnd, _end, duration); + var itemProps = this.touchParams.itemProps ; + this.touchParams.itemProps = null; + itemProps.forEach(function (props) { + var id = props.item.id, + itemData = me.itemsData.get(id, me.itemOptions); - changed = me._applyRange(s, e); - DateUtil.updateHiddenDates(me.body, me.options.hiddenDates); - anyChanged = anyChanged || changed; - if (changed) { - me.body.emitter.emit('rangechange', {start: new Date(me.start), end: new Date(me.end), byUser:byUser}); - } + var changed = false; + if ('start' in props.item.data) { + changed = (props.start != props.item.data.start.valueOf()); + itemData.start = util.convert(props.item.data.start, + dataset._options.type && dataset._options.type.start || 'Date'); + } + if ('end' in props.item.data) { + changed = changed || (props.end != props.item.data.end.valueOf()); + itemData.end = util.convert(props.item.data.end, + dataset._options.type && dataset._options.type.end || 'Date'); + } + if ('group' in props.item.data) { + changed = changed || (props.group != props.item.data.group); + itemData.group = props.item.data.group; + } - if (done) { - if (anyChanged) { - me.body.emitter.emit('rangechanged', {start: new Date(me.start), end: new Date(me.end), byUser:byUser}); + // only apply changes when start or end is actually changed + if (changed) { + me.options.onMove(itemData, function (itemData) { + if (itemData) { + // apply changes + itemData[dataset._fieldId] = id; // ensure the item contains its id (can be undefined) + changes.push(itemData); } - } - else { - // animate with as high as possible frame rate, leave 20 ms in between - // each to prevent the browser from blocking - me.animateTimer = setTimeout(next, 20); - } + else { + // restore original values + me._updateItemProps(props.item, props); + + me.stackDirty = true; // force re-stacking of all items next redraw + me.body.emitter.emit('change'); + } + }); } - } + }); - return next(); - } - else { - var changed = this._applyRange(_start, _end); - DateUtil.updateHiddenDates(this.body, this.options.hiddenDates); - if (changed) { - var params = {start: new Date(this.start), end: new Date(this.end), byUser:byUser}; - this.body.emitter.emit('rangechange', params); - this.body.emitter.emit('rangechanged', params); + // apply the changes to the data (if there are changes) + if (changes.length) { + dataset.update(changes); } + + event.stopPropagation(); } }; /** - * Stop an animation + * Handle selecting/deselecting an item when tapping it + * @param {Event} event * @private */ - Range.prototype._cancelAnimation = function () { - if (this.animateTimer) { - clearTimeout(this.animateTimer); - this.animateTimer = null; + ItemSet.prototype._onSelectItem = function (event) { + if (!this.options.selectable) return; + + var ctrlKey = event.gesture.srcEvent && event.gesture.srcEvent.ctrlKey; + var shiftKey = event.gesture.srcEvent && event.gesture.srcEvent.shiftKey; + if (ctrlKey || shiftKey) { + this._onMultiSelectItem(event); + return; + } + + var oldSelection = this.getSelection(); + + var item = ItemSet.itemFromTarget(event); + var selection = item ? [item.id] : []; + this.setSelection(selection); + + var newSelection = this.getSelection(); + + // emit a select event, + // except when old selection is empty and new selection is still empty + if (newSelection.length > 0 || oldSelection.length > 0) { + this.body.emitter.emit('select', { + items: newSelection + }); } }; /** - * Set a new start and end range. This method is the same as setRange, but - * does not trigger a range change and range changed event, and it returns - * true when the range is changed - * @param {Number} [start] - * @param {Number} [end] - * @return {Boolean} changed + * Handle creation and updates of an item on double tap + * @param event * @private */ - Range.prototype._applyRange = function(start, end) { - var newStart = (start != null) ? util.convert(start, 'Date').valueOf() : this.start, - newEnd = (end != null) ? util.convert(end, 'Date').valueOf() : this.end, - max = (this.options.max != null) ? util.convert(this.options.max, 'Date').valueOf() : null, - min = (this.options.min != null) ? util.convert(this.options.min, 'Date').valueOf() : null, - diff; - - // check for valid number - if (isNaN(newStart) || newStart === null) { - throw new Error('Invalid start "' + start + '"'); - } - if (isNaN(newEnd) || newEnd === null) { - throw new Error('Invalid end "' + end + '"'); - } + ItemSet.prototype._onAddItem = function (event) { + if (!this.options.selectable) return; + if (!this.options.editable.add) return; - // prevent start < end - if (newEnd < newStart) { - newEnd = newStart; - } + var me = this, + snap = this.body.util.snap || null, + item = ItemSet.itemFromTarget(event); - // prevent start < min - if (min !== null) { - if (newStart < min) { - diff = (min - newStart); - newStart += diff; - newEnd += diff; + if (item) { + // update item - // prevent end > max - if (max != null) { - if (newEnd > max) { - newEnd = max; - } + // execute async handler to update the item (or cancel it) + var itemData = me.itemsData.get(item.id); // get a clone of the data from the dataset + this.options.onUpdate(itemData, function (itemData) { + if (itemData) { + me.itemsData.getDataSet().update(itemData); } - } + }); } + else { + // add item + var xAbs = util.getAbsoluteLeft(this.dom.frame); + var x = event.gesture.center.pageX - xAbs; + var start = this.body.util.toTime(x); + var newItem = { + start: snap ? snap(start) : start, + content: 'new item' + }; - // prevent end > max - if (max !== null) { - if (newEnd > max) { - diff = (newEnd - max); - newStart -= diff; - newEnd -= diff; - - // prevent start < min - if (min != null) { - if (newStart < min) { - newStart = min; - } - } + // when default type is a range, add a default end date to the new item + if (this.options.type === 'range') { + var end = this.body.util.toTime(x + this.props.width / 5); + newItem.end = snap ? snap(end) : end; } - } - // prevent (end-start) < zoomMin - if (this.options.zoomMin !== null) { - var zoomMin = parseFloat(this.options.zoomMin); - if (zoomMin < 0) { - zoomMin = 0; + newItem[this.itemsData._fieldId] = util.randomUUID(); + + var group = ItemSet.groupFromTarget(event); + if (group) { + newItem.group = group.groupId; } - if ((newEnd - newStart) < zoomMin) { - if ((this.end - this.start) === zoomMin) { - // ignore this action, we are already zoomed to the minimum - newStart = this.start; - newEnd = this.end; - } - else { - // zoom to the minimum - diff = (zoomMin - (newEnd - newStart)); - newStart -= diff / 2; - newEnd += diff / 2; + + // execute async handler to customize (or cancel) adding an item + this.options.onAdd(newItem, function (item) { + if (item) { + me.itemsData.getDataSet().add(item); + // TODO: need to trigger a redraw? } - } + }); } + }; - // prevent (end-start) > zoomMax - if (this.options.zoomMax !== null) { - var zoomMax = parseFloat(this.options.zoomMax); - if (zoomMax < 0) { - zoomMax = 0; + /** + * Handle selecting/deselecting multiple items when holding an item + * @param {Event} event + * @private + */ + ItemSet.prototype._onMultiSelectItem = function (event) { + if (!this.options.selectable) return; + + var selection, + item = ItemSet.itemFromTarget(event); + + if (item) { + // multi select items + selection = this.getSelection(); // current selection + + var shiftKey = event.gesture.touches[0] && event.gesture.touches[0].shiftKey || false; + if (shiftKey) { + // select all items between the old selection and the tapped item + + // determine the selection range + selection.push(item.id); + var range = ItemSet._getItemRange(this.itemsData.get(selection, this.itemOptions)); + + // select all items within the selection range + selection = []; + for (var id in this.items) { + if (this.items.hasOwnProperty(id)) { + var _item = this.items[id]; + var start = _item.data.start; + var end = (_item.data.end !== undefined) ? _item.data.end : start; + + if (start >= range.min && end <= range.max) { + selection.push(_item.id); // do not use id but item.id, id itself is stringified + } + } + } } - if ((newEnd - newStart) > zoomMax) { - if ((this.end - this.start) === zoomMax) { - // ignore this action, we are already zoomed to the maximum - newStart = this.start; - newEnd = this.end; + else { + // add/remove this item from the current selection + var index = selection.indexOf(item.id); + if (index == -1) { + // item is not yet selected -> select it + selection.push(item.id); } else { - // zoom to the maximum - diff = ((newEnd - newStart) - zoomMax); - newStart += diff / 2; - newEnd -= diff / 2; + // item is already selected -> deselect it + selection.splice(index, 1); } } - } - var changed = (this.start != newStart || this.end != newEnd); + this.setSelection(selection); - // if the new range does NOT overlap with the old range, emit checkRangedItems to avoid not showing ranged items (ranged meaning has end time, not neccesarily of type Range) - if (!((newStart >= this.start && newStart <= this.end) || (newEnd >= this.start && newEnd <= this.end)) && - !((this.start >= newStart && this.start <= newEnd) || (this.end >= newStart && this.end <= newEnd) )) { - this.body.emitter.emit('checkRangedItems'); + this.body.emitter.emit('select', { + items: this.getSelection() + }); } - - this.start = newStart; - this.end = newEnd; - return changed; }; /** - * Retrieve the current range. - * @return {Object} An object with start and end properties + * Calculate the time range of a list of items + * @param {Array.} itemsData + * @return {{min: Date, max: Date}} Returns the range of the provided items + * @private */ - Range.prototype.getRange = function() { - return { - start: this.start, - end: this.end - }; - }; + ItemSet._getItemRange = function(itemsData) { + var max = null; + var min = null; - /** - * Calculate the conversion offset and scale for current range, based on - * the provided width - * @param {Number} width - * @returns {{offset: number, scale: number}} conversion - */ - Range.prototype.conversion = function (width, totalHidden) { - return Range.conversion(this.start, this.end, width, totalHidden); - }; + itemsData.forEach(function (data) { + if (min == null || data.start < min) { + min = data.start; + } - /** - * Static method to calculate the conversion offset and scale for a range, - * based on the provided start, end, and width - * @param {Number} start - * @param {Number} end - * @param {Number} width - * @returns {{offset: number, scale: number}} conversion - */ - Range.conversion = function (start, end, width, totalHidden) { - if (totalHidden === undefined) { - totalHidden = 0; - } - if (width != 0 && (end - start != 0)) { - return { - offset: start, - scale: width / (end - start - totalHidden) + if (data.end != undefined) { + if (max == null || data.end > max) { + max = data.end; + } } - } - else { - return { - offset: 0, - scale: 1 - }; + else { + if (max == null || data.start > max) { + max = data.start; + } + } + }); + + return { + min: min, + max: max } }; /** - * Start dragging horizontally or vertically + * Find an item from an event target: + * searches for the attribute 'timeline-item' in the event target's element tree * @param {Event} event - * @private + * @return {Item | null} item */ - Range.prototype._onDragStart = function(event) { - this.deltaDifference = 0; - this.previousDelta = 0; - // only allow dragging when configured as movable - if (!this.options.moveable) return; - - // refuse to drag when we where pinching to prevent the timeline make a jump - // when releasing the fingers in opposite order from the touch screen - if (!this.props.touch.allowDragging) return; + ItemSet.itemFromTarget = function(event) { + var target = event.target; + while (target) { + if (target.hasOwnProperty('timeline-item')) { + return target['timeline-item']; + } + target = target.parentNode; + } - this.props.touch.start = this.start; - this.props.touch.end = this.end; - this.props.touch.dragging = true; + return null; + }; - if (this.body.dom.root) { - this.body.dom.root.style.cursor = 'move'; + /** + * Find the Group from an event target: + * searches for the attribute 'timeline-group' in the event target's element tree + * @param {Event} event + * @return {Group | null} group + */ + ItemSet.groupFromTarget = function(event) { + var target = event.target; + while (target) { + if (target.hasOwnProperty('timeline-group')) { + return target['timeline-group']; + } + target = target.parentNode; } + + return null; }; /** - * Perform dragging operation + * Find the ItemSet from an event target: + * searches for the attribute 'timeline-itemset' in the event target's element tree * @param {Event} event - * @private + * @return {ItemSet | null} item */ - Range.prototype._onDrag = function (event) { - // only allow dragging when configured as movable - if (!this.options.moveable) return; - // refuse to drag when we where pinching to prevent the timeline make a jump - // when releasing the fingers in opposite order from the touch screen - if (!this.props.touch.allowDragging) return; + ItemSet.itemSetFromTarget = function(event) { + var target = event.target; + while (target) { + if (target.hasOwnProperty('timeline-itemset')) { + return target['timeline-itemset']; + } + target = target.parentNode; + } - var direction = this.options.direction; - validateDirection(direction); + return null; + }; - var delta = (direction == 'horizontal') ? event.gesture.deltaX : event.gesture.deltaY; - delta -= this.deltaDifference; - var interval = (this.props.touch.end - this.props.touch.start); + module.exports = ItemSet; - // normalize dragging speed if cutout is in between. - var duration = DateUtil.getHiddenDurationBetween(this.body.hiddenDates, this.start, this.end); - interval -= duration; - var width = (direction == 'horizontal') ? this.body.domProps.center.width : this.body.domProps.center.height; - var diffRange = -delta / width * interval; - var newStart = this.props.touch.start + diffRange; - var newEnd = this.props.touch.end + diffRange; +/***/ }, +/* 28 */ +/***/ function(module, exports, __webpack_require__) { + var util = __webpack_require__(1); + var DOMutil = __webpack_require__(2); + var Component = __webpack_require__(20); - // snapping times away from hidden zones - var safeStart = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newStart, this.previousDelta-delta, true); - var safeEnd = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newEnd, this.previousDelta-delta, true); - if (safeStart != newStart || safeEnd != newEnd) { - this.deltaDifference += delta; - this.props.touch.start = safeStart; - this.props.touch.end = safeEnd; - this._onDrag(event); - return; + /** + * Legend for Graph2d + */ + function Legend(body, options, side, linegraphOptions) { + this.body = body; + this.defaultOptions = { + enabled: true, + icons: true, + iconSize: 20, + iconSpacing: 6, + left: { + visible: true, + position: 'top-left' // top/bottom - left,center,right + }, + right: { + visible: true, + position: 'top-left' // top/bottom - left,center,right + } } + this.side = side; + this.options = util.extend({},this.defaultOptions); + this.linegraphOptions = linegraphOptions; - this.previousDelta = delta; - this._applyRange(newStart, newEnd); + this.svgElements = {}; + this.dom = {}; + this.groups = {}; + this.amountOfGroups = 0; + this._create(); - // fire a rangechange event - this.body.emitter.emit('rangechange', { - start: new Date(this.start), - end: new Date(this.end), - byUser: true - }); - }; + this.setOptions(options); + } - /** - * Stop dragging operation - * @param {event} event - * @private - */ - Range.prototype._onDragEnd = function (event) { - // only allow dragging when configured as movable - if (!this.options.moveable) return; + Legend.prototype = new Component(); - // refuse to drag when we where pinching to prevent the timeline make a jump - // when releasing the fingers in opposite order from the touch screen - if (!this.props.touch.allowDragging) return; + Legend.prototype.clear = function() { + this.groups = {}; + this.amountOfGroups = 0; + } - this.props.touch.dragging = false; - if (this.body.dom.root) { - this.body.dom.root.style.cursor = 'auto'; - } + Legend.prototype.addGroup = function(label, graphOptions) { - // fire a rangechanged event - this.body.emitter.emit('rangechanged', { - start: new Date(this.start), - end: new Date(this.end), - byUser: true - }); + if (!this.groups.hasOwnProperty(label)) { + this.groups[label] = graphOptions; + } + this.amountOfGroups += 1; }; - /** - * Event handler for mouse wheel event, used to zoom - * Code from http://adomas.org/javascript-mouse-wheel/ - * @param {Event} event - * @private - */ - Range.prototype._onMouseWheel = function(event) { - // only allow zooming when configured as zoomable and moveable - if (!(this.options.zoomable && this.options.moveable)) return; + Legend.prototype.updateGroup = function(label, graphOptions) { + this.groups[label] = graphOptions; + }; - // retrieve delta - var delta = 0; - if (event.wheelDelta) { /* IE/Opera. */ - delta = event.wheelDelta / 120; - } else if (event.detail) { /* Mozilla case. */ - // In Mozilla, sign of delta is different than in IE. - // Also, delta is multiple of 3. - delta = -event.detail / 3; + Legend.prototype.removeGroup = function(label) { + if (this.groups.hasOwnProperty(label)) { + delete this.groups[label]; + this.amountOfGroups -= 1; } + }; - // If delta is nonzero, handle it. - // Basically, delta is now positive if wheel was scrolled up, - // and negative, if wheel was scrolled down. - if (delta) { - // perform the zoom action. Delta is normally 1 or -1 - - // adjust a negative delta such that zooming in with delta 0.1 - // equals zooming out with a delta -0.1 - var scale; - if (delta < 0) { - scale = 1 - (delta / 5); - } - else { - scale = 1 / (1 + (delta / 5)) ; - } + Legend.prototype._create = function() { + this.dom.frame = document.createElement('div'); + this.dom.frame.className = 'legend'; + this.dom.frame.style.position = "absolute"; + this.dom.frame.style.top = "10px"; + this.dom.frame.style.display = "block"; - // calculate center, the date to zoom around - var gesture = hammerUtil.fakeGesture(this, event), - pointer = getPointer(gesture.center, this.body.dom.center), - pointerDate = this._pointerToDate(pointer); + this.dom.textArea = document.createElement('div'); + this.dom.textArea.className = 'legendText'; + this.dom.textArea.style.position = "relative"; + this.dom.textArea.style.top = "0px"; - this.zoom(scale, pointerDate, delta); - } + this.svg = document.createElementNS('http://www.w3.org/2000/svg',"svg"); + this.svg.style.position = 'absolute'; + this.svg.style.top = 0 +'px'; + this.svg.style.width = this.options.iconSize + 5 + 'px'; + this.svg.style.height = '100%'; - // Prevent default actions caused by mouse wheel - // (else the page and timeline both zoom and scroll) - event.preventDefault(); + this.dom.frame.appendChild(this.svg); + this.dom.frame.appendChild(this.dom.textArea); }; /** - * Start of a touch gesture - * @private + * Hide the component from the DOM */ - Range.prototype._onTouch = function (event) { - this.props.touch.start = this.start; - this.props.touch.end = this.end; - this.props.touch.allowDragging = true; - this.props.touch.center = null; - this.scaleOffset = 0; - this.deltaDifference = 0; + Legend.prototype.hide = function() { + // remove the frame containing the items + if (this.dom.frame.parentNode) { + this.dom.frame.parentNode.removeChild(this.dom.frame); + } }; /** - * On start of a hold gesture - * @private + * Show the component in the DOM (when not already visible). + * @return {Boolean} changed */ - Range.prototype._onHold = function () { - this.props.touch.allowDragging = false; + Legend.prototype.show = function() { + // show frame containing the items + if (!this.dom.frame.parentNode) { + this.body.dom.center.appendChild(this.dom.frame); + } }; - /** - * Handle pinch event - * @param {Event} event - * @private - */ - Range.prototype._onPinch = function (event) { - // only allow zooming when configured as zoomable and moveable - if (!(this.options.zoomable && this.options.moveable)) return; + Legend.prototype.setOptions = function(options) { + var fields = ['enabled','orientation','icons','left','right']; + util.selectiveDeepExtend(fields, this.options, options); + }; - this.props.touch.allowDragging = false; + Legend.prototype.redraw = function() { + var activeGroups = 0; + for (var groupId in this.groups) { + if (this.groups.hasOwnProperty(groupId)) { + if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) { + activeGroups++; + } + } + } - if (event.gesture.touches.length > 1) { - if (!this.props.touch.center) { - this.props.touch.center = getPointer(event.gesture.center, this.body.dom.center); + if (this.options[this.side].visible == false || this.amountOfGroups == 0 || this.options.enabled == false || activeGroups == 0) { + this.hide(); + } + else { + this.show(); + if (this.options[this.side].position == 'top-left' || this.options[this.side].position == 'bottom-left') { + this.dom.frame.style.left = '4px'; + this.dom.frame.style.textAlign = "left"; + this.dom.textArea.style.textAlign = "left"; + this.dom.textArea.style.left = (this.options.iconSize + 15) + 'px'; + this.dom.textArea.style.right = ''; + this.svg.style.left = 0 +'px'; + this.svg.style.right = ''; + } + else { + this.dom.frame.style.right = '4px'; + this.dom.frame.style.textAlign = "right"; + this.dom.textArea.style.textAlign = "right"; + this.dom.textArea.style.right = (this.options.iconSize + 15) + 'px'; + this.dom.textArea.style.left = ''; + this.svg.style.right = 0 +'px'; + this.svg.style.left = ''; } - var scale = 1 / (event.gesture.scale + this.scaleOffset); - var centerDate = this._pointerToDate(this.props.touch.center); + if (this.options[this.side].position == 'top-left' || this.options[this.side].position == 'top-right') { + this.dom.frame.style.top = 4 - Number(this.body.dom.center.style.top.replace("px","")) + 'px'; + this.dom.frame.style.bottom = ''; + } + else { + var scrollableHeight = this.body.domProps.center.height - this.body.domProps.centerContainer.height; + this.dom.frame.style.bottom = 4 + scrollableHeight + Number(this.body.dom.center.style.top.replace("px","")) + 'px'; + this.dom.frame.style.top = ''; + } - var hiddenDuration = DateUtil.getHiddenDurationBetween(this.body.hiddenDates, this.start, this.end); - var hiddenDurationBefore = DateUtil.getHiddenDurationBefore(this.body.hiddenDates, this, centerDate); - var hiddenDurationAfter = hiddenDuration - hiddenDurationBefore; + if (this.options.icons == false) { + this.dom.frame.style.width = this.dom.textArea.offsetWidth + 10 + 'px'; + this.dom.textArea.style.right = ''; + this.dom.textArea.style.left = ''; + this.svg.style.width = '0px'; + } + else { + this.dom.frame.style.width = this.options.iconSize + 15 + this.dom.textArea.offsetWidth + 10 + 'px' + this.drawLegendIcons(); + } - // calculate new start and end - var newStart = (centerDate - hiddenDurationBefore) + (this.props.touch.start - (centerDate - hiddenDurationBefore)) * scale; - var newEnd = (centerDate + hiddenDurationAfter) + (this.props.touch.end - (centerDate + hiddenDurationAfter)) * scale; + var content = ''; + for (var groupId in this.groups) { + if (this.groups.hasOwnProperty(groupId)) { + if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) { + content += this.groups[groupId].content + '
'; + } + } + } + this.dom.textArea.innerHTML = content; + this.dom.textArea.style.lineHeight = ((0.75 * this.options.iconSize) + this.options.iconSpacing) + 'px'; + } + }; - // snapping times away from hidden zones - this.startToFront = 1 - scale > 0 ? false : true; // used to do the right autocorrection with periodic hidden times - this.endToFront = scale - 1 > 0 ? false : true; // used to do the right autocorrection with periodic hidden times + Legend.prototype.drawLegendIcons = function() { + if (this.dom.frame.parentNode) { + DOMutil.prepareElements(this.svgElements); + var padding = window.getComputedStyle(this.dom.frame).paddingTop; + var iconOffset = Number(padding.replace('px','')); + var x = iconOffset; + var iconWidth = this.options.iconSize; + var iconHeight = 0.75 * this.options.iconSize; + var y = iconOffset + 0.5 * iconHeight + 3; - var safeStart = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newStart, 1 - scale, true); - var safeEnd = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newEnd, scale - 1, true); - if (safeStart != newStart || safeEnd != newEnd) { - this.props.touch.start = safeStart; - this.props.touch.end = safeEnd; - this.scaleOffset = 1 - event.gesture.scale; - newStart = safeStart; - newEnd = safeEnd; - } + this.svg.style.width = iconWidth + 5 + iconOffset + 'px'; - this.setRange(newStart, newEnd, false, true); + for (var groupId in this.groups) { + if (this.groups.hasOwnProperty(groupId)) { + if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) { + this.groups[groupId].drawIcon(x, y, this.svgElements, this.svg, iconWidth, iconHeight); + y += iconHeight + this.options.iconSpacing; + } + } + } - this.startToFront = false; // revert to default - this.endToFront = true; // revert to default + DOMutil.cleanupElements(this.svgElements); } }; + module.exports = Legend; + + +/***/ }, +/* 29 */ +/***/ function(module, exports, __webpack_require__) { + + var util = __webpack_require__(1); + var DOMutil = __webpack_require__(2); + var DataSet = __webpack_require__(3); + var DataView = __webpack_require__(4); + var Component = __webpack_require__(20); + var DataAxis = __webpack_require__(23); + var GraphGroup = __webpack_require__(24); + var Legend = __webpack_require__(28); + var BarGraphFunctions = __webpack_require__(50); + + var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items + /** - * Helper function to calculate the center date for zooming - * @param {{x: Number, y: Number}} pointer - * @return {number} date - * @private + * This is the constructor of the LineGraph. It requires a Timeline body and options. + * + * @param body + * @param options + * @constructor */ - Range.prototype._pointerToDate = function (pointer) { - var conversion; - var direction = this.options.direction; + function LineGraph(body, options) { + this.id = util.randomUUID(); + this.body = body; + + this.defaultOptions = { + yAxisOrientation: 'left', + defaultGroup: 'default', + sort: true, + sampling: true, + graphHeight: '400px', + shaded: { + enabled: false, + orientation: 'bottom' // top, bottom + }, + style: 'line', // line, bar + barChart: { + width: 50, + handleOverlap: 'overlap', + align: 'center' // left, center, right + }, + catmullRom: { + enabled: true, + parametrization: 'centripetal', // uniform (alpha = 0.0), chordal (alpha = 1.0), centripetal (alpha = 0.5) + alpha: 0.5 + }, + drawPoints: { + enabled: true, + size: 6, + style: 'square' // square, circle + }, + dataAxis: { + showMinorLabels: true, + showMajorLabels: true, + icons: false, + width: '40px', + visible: true, + alignZeros: true, + customRange: { + left: {min:undefined, max:undefined}, + right: {min:undefined, max:undefined} + } + //, these options are not set by default, but this shows the format they will be in + //format: { + // left: {decimals: 2}, + // right: {decimals: 2} + //}, + //title: { + // left: { + // text: 'left', + // style: 'color:black;' + // }, + // right: { + // text: 'right', + // style: 'color:black;' + // } + //} + }, + legend: { + enabled: false, + icons: true, + left: { + visible: true, + position: 'top-left' // top/bottom - left,right + }, + right: { + visible: true, + position: 'top-right' // top/bottom - left,right + } + }, + groups: { + visibility: {} + } + }; + + // options is shared by this ItemSet and all its items + this.options = util.extend({}, this.defaultOptions); + this.dom = {}; + this.props = {}; + this.hammer = null; + this.groups = {}; + this.abortedGraphUpdate = false; + this.updateSVGheight = false; + this.updateSVGheightOnResize = false; + + var me = this; + this.itemsData = null; // DataSet + this.groupsData = null; // DataSet + + // listeners for the DataSet of the items + this.itemListeners = { + 'add': function (event, params, senderId) { + me._onAdd(params.items); + }, + 'update': function (event, params, senderId) { + me._onUpdate(params.items); + }, + 'remove': function (event, params, senderId) { + me._onRemove(params.items); + } + }; + + // listeners for the DataSet of the groups + this.groupListeners = { + 'add': function (event, params, senderId) { + me._onAddGroups(params.items); + }, + 'update': function (event, params, senderId) { + me._onUpdateGroups(params.items); + }, + 'remove': function (event, params, senderId) { + me._onRemoveGroups(params.items); + } + }; - validateDirection(direction); + this.items = {}; // object with an Item for every data item + this.selection = []; // list with the ids of all selected nodes + this.lastStart = this.body.range.start; + this.touchParams = {}; // stores properties while dragging - if (direction == 'horizontal') { - return this.body.util.toTime(pointer.x).valueOf(); - } - else { - var height = this.body.domProps.center.height; - conversion = this.conversion(height); - return pointer.y / conversion.scale + conversion.offset; - } - }; + this.svgElements = {}; + this.setOptions(options); + this.groupsUsingDefaultStyles = [0]; + this.COUNTER = 0; + this.body.emitter.on('rangechanged', function() { + me.lastStart = me.body.range.start; + me.svg.style.left = util.option.asSize(-me.props.width); + me.redraw.call(me,true); + }); + + // create the HTML DOM + this._create(); + this.framework = {svg: this.svg, svgElements: this.svgElements, options: this.options, groups: this.groups}; + this.body.emitter.emit('change'); - /** - * Get the pointer location relative to the location of the dom element - * @param {{pageX: Number, pageY: Number}} touch - * @param {Element} element HTML DOM element - * @return {{x: Number, y: Number}} pointer - * @private - */ - function getPointer (touch, element) { - return { - x: touch.pageX - util.getAbsoluteLeft(element), - y: touch.pageY - util.getAbsoluteTop(element) - }; } + LineGraph.prototype = new Component(); + /** - * Zoom the range the given scale in or out. Start and end date will - * be adjusted, and the timeline will be redrawn. You can optionally give a - * date around which to zoom. - * For example, try scale = 0.9 or 1.1 - * @param {Number} scale Scaling factor. Values above 1 will zoom out, - * values below 1 will zoom in. - * @param {Number} [center] Value representing a date around which will - * be zoomed. + * Create the HTML DOM for the ItemSet */ - Range.prototype.zoom = function(scale, center, delta) { - // if centerDate is not provided, take it half between start Date and end Date - if (center == null) { - center = (this.start + this.end) / 2; - } + LineGraph.prototype._create = function(){ + var frame = document.createElement('div'); + frame.className = 'LineGraph'; + this.dom.frame = frame; - var hiddenDuration = DateUtil.getHiddenDurationBetween(this.body.hiddenDates, this.start, this.end); - var hiddenDurationBefore = DateUtil.getHiddenDurationBefore(this.body.hiddenDates, this, center); - var hiddenDurationAfter = hiddenDuration - hiddenDurationBefore; + // create svg element for graph drawing. + this.svg = document.createElementNS('http://www.w3.org/2000/svg','svg'); + this.svg.style.position = 'relative'; + this.svg.style.height = ('' + this.options.graphHeight).replace('px','') + 'px'; + this.svg.style.display = 'block'; + frame.appendChild(this.svg); - // calculate new start and end - var newStart = (center-hiddenDurationBefore) + (this.start - (center-hiddenDurationBefore)) * scale; - var newEnd = (center+hiddenDurationAfter) + (this.end - (center+hiddenDurationAfter)) * scale; + // data axis + this.options.dataAxis.orientation = 'left'; + this.yAxisLeft = new DataAxis(this.body, this.options.dataAxis, this.svg, this.options.groups); - // snapping times away from hidden zones - this.startToFront = delta > 0 ? false : true; // used to do the right autocorrection with periodic hidden times - this.endToFront = -delta > 0 ? false : true; // used to do the right autocorrection with periodic hidden times - var safeStart = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newStart, delta, true); - var safeEnd = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newEnd, -delta, true); - if (safeStart != newStart || safeEnd != newEnd) { - newStart = safeStart; - newEnd = safeEnd; - } + this.options.dataAxis.orientation = 'right'; + this.yAxisRight = new DataAxis(this.body, this.options.dataAxis, this.svg, this.options.groups); + delete this.options.dataAxis.orientation; - this.setRange(newStart, newEnd, false, true); + // legends + this.legendLeft = new Legend(this.body, this.options.legend, 'left', this.options.groups); + this.legendRight = new Legend(this.body, this.options.legend, 'right', this.options.groups); - this.startToFront = false; // revert to default - this.endToFront = true; // revert to default + this.show(); }; - - /** - * Move the range with a given delta to the left or right. Start and end - * value will be adjusted. For example, try delta = 0.1 or -0.1 - * @param {Number} delta Moving amount. Positive value will move right, - * negative value will move left + * set the options of the LineGraph. the mergeOptions is used for subObjects that have an enabled element. + * @param {object} options */ - Range.prototype.move = function(delta) { - // zoom start Date and end Date relative to the centerDate - var diff = (this.end - this.start); + LineGraph.prototype.setOptions = function(options) { + if (options) { + var fields = ['sampling','defaultGroup','height','graphHeight','yAxisOrientation','style','barChart','dataAxis','sort','groups']; + if (options.graphHeight === undefined && options.height !== undefined && this.body.domProps.centerContainer.height !== undefined) { + this.updateSVGheight = true; + this.updateSVGheightOnResize = true; + } + else if (this.body.domProps.centerContainer.height !== undefined && options.graphHeight !== undefined) { + if (parseInt((options.graphHeight + '').replace("px",'')) < this.body.domProps.centerContainer.height) { + this.updateSVGheight = true; + } + } + util.selectiveDeepExtend(fields, this.options, options); + util.mergeOptions(this.options, options,'catmullRom'); + util.mergeOptions(this.options, options,'drawPoints'); + util.mergeOptions(this.options, options,'shaded'); + util.mergeOptions(this.options, options,'legend'); - // apply new values - var newStart = this.start + diff * delta; - var newEnd = this.end + diff * delta; + if (options.catmullRom) { + if (typeof options.catmullRom == 'object') { + if (options.catmullRom.parametrization) { + if (options.catmullRom.parametrization == 'uniform') { + this.options.catmullRom.alpha = 0; + } + else if (options.catmullRom.parametrization == 'chordal') { + this.options.catmullRom.alpha = 1.0; + } + else { + this.options.catmullRom.parametrization = 'centripetal'; + this.options.catmullRom.alpha = 0.5; + } + } + } + } - // TODO: reckon with min and max range + if (this.yAxisLeft) { + if (options.dataAxis !== undefined) { + this.yAxisLeft.setOptions(this.options.dataAxis); + this.yAxisRight.setOptions(this.options.dataAxis); + } + } - this.start = newStart; - this.end = newEnd; + if (this.legendLeft) { + if (options.legend !== undefined) { + this.legendLeft.setOptions(this.options.legend); + this.legendRight.setOptions(this.options.legend); + } + } + + if (this.groups.hasOwnProperty(UNGROUPED)) { + this.groups[UNGROUPED].setOptions(options); + } + } + + // this is used to redraw the graph if the visibility of the groups is changed. + if (this.dom.frame) { + this.redraw(true); + } }; /** - * Move the range to a new center point - * @param {Number} moveTo New center point of the range + * Hide the component from the DOM */ - Range.prototype.moveTo = function(moveTo) { - var center = (this.start + this.end) / 2; - - var diff = center - moveTo; - - // calculate new start and end - var newStart = this.start - diff; - var newEnd = this.end - diff; - - this.setRange(newStart, newEnd); + LineGraph.prototype.hide = function() { + // remove the frame containing the items + if (this.dom.frame.parentNode) { + this.dom.frame.parentNode.removeChild(this.dom.frame); + } }; - module.exports = Range; - - -/***/ }, -/* 22 */ -/***/ function(module, exports, __webpack_require__) { - - var Hammer = __webpack_require__(19); /** - * Fake a hammer.js gesture. Event can be a ScrollEvent or MouseMoveEvent - * @param {Element} element - * @param {Event} event + * Show the component in the DOM (when not already visible). + * @return {Boolean} changed */ - exports.fakeGesture = function(element, event) { - var eventType = null; + LineGraph.prototype.show = function() { + // show frame containing the items + if (!this.dom.frame.parentNode) { + this.body.dom.center.appendChild(this.dom.frame); + } + }; - // for hammer.js 1.0.5 - // var gesture = Hammer.event.collectEventData(this, eventType, event); - // for hammer.js 1.0.6+ - var touches = Hammer.event.getTouchList(event, eventType); - var gesture = Hammer.event.collectEventData(this, eventType, touches, event); + /** + * Set items + * @param {vis.DataSet | null} items + */ + LineGraph.prototype.setItems = function(items) { + var me = this, + ids, + oldItemsData = this.itemsData; - // on IE in standards mode, no touches are recognized by hammer.js, - // resulting in NaN values for center.pageX and center.pageY - if (isNaN(gesture.center.pageX)) { - gesture.center.pageX = event.pageX; + // replace the dataset + if (!items) { + this.itemsData = null; } - if (isNaN(gesture.center.pageY)) { - gesture.center.pageY = event.pageY; + else if (items instanceof DataSet || items instanceof DataView) { + this.itemsData = items; + } + else { + throw new TypeError('Data must be an instance of DataSet or DataView'); } - return gesture; - }; - + if (oldItemsData) { + // unsubscribe from old dataset + util.forEach(this.itemListeners, function (callback, event) { + oldItemsData.off(event, callback); + }); -/***/ }, -/* 23 */ -/***/ function(module, exports, __webpack_require__) { + // remove all drawn items + ids = oldItemsData.getIds(); + this._onRemove(ids); + } - /** - * Prototype for visual components - * @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} [body] - * @param {Object} [options] - */ - function Component (body, options) { - this.options = null; - this.props = null; - } + if (this.itemsData) { + // subscribe to new dataset + var id = this.id; + util.forEach(this.itemListeners, function (callback, event) { + me.itemsData.on(event, callback, id); + }); - /** - * Set options for the component. The new options will be merged into the - * current options. - * @param {Object} options - */ - Component.prototype.setOptions = function(options) { - if (options) { - util.extend(this.options, options); + // add all new items + ids = this.itemsData.getIds(); + this._onAdd(ids); } + this._updateUngrouped(); + //this._updateGraph(); + this.redraw(true); }; - /** - * Repaint the component - * @return {boolean} Returns true if the component is resized - */ - Component.prototype.redraw = function() { - // should be implemented by the component - return false; - }; /** - * Destroy the component. Cleanup DOM and event listeners + * Set groups + * @param {vis.DataSet} groups */ - Component.prototype.destroy = function() { - // should be implemented by the component - }; + LineGraph.prototype.setGroups = function(groups) { + var me = this; + var ids; - /** - * Test whether the component is resized since the last time _isResized() was - * called. - * @return {Boolean} Returns true if the component is resized - * @protected - */ - Component.prototype._isResized = function() { - var resized = (this.props._previousWidth !== this.props.width || - this.props._previousHeight !== this.props.height); + // unsubscribe from current dataset + if (this.groupsData) { + util.forEach(this.groupListeners, function (callback, event) { + me.groupsData.unsubscribe(event, callback); + }); - this.props._previousWidth = this.props.width; - this.props._previousHeight = this.props.height; + // remove all drawn groups + ids = this.groupsData.getIds(); + this.groupsData = null; + this._onRemoveGroups(ids); // note: this will cause a redraw + } - return resized; - }; + // replace the dataset + if (!groups) { + this.groupsData = null; + } + else if (groups instanceof DataSet || groups instanceof DataView) { + this.groupsData = groups; + } + else { + throw new TypeError('Data must be an instance of DataSet or DataView'); + } - module.exports = Component; + if (this.groupsData) { + // subscribe to new dataset + var id = this.id; + util.forEach(this.groupListeners, function (callback, event) { + me.groupsData.on(event, callback, id); + }); + // draw all ms + ids = this.groupsData.getIds(); + this._onAddGroups(ids); + } + this._onUpdate(); + }; -/***/ }, -/* 24 */ -/***/ function(module, exports, __webpack_require__) { /** - * Created by Alex on 10/3/2014. + * Update the data + * @param [ids] + * @private */ - var moment = __webpack_require__(2); + LineGraph.prototype._onUpdate = function(ids) { + this._updateUngrouped(); + this._updateAllGroupData(); + //this._updateGraph(); + this.redraw(true); + }; + LineGraph.prototype._onAdd = function (ids) {this._onUpdate(ids);}; + LineGraph.prototype._onRemove = function (ids) {this._onUpdate(ids);}; + LineGraph.prototype._onUpdateGroups = function (groupIds) { + for (var i = 0; i < groupIds.length; i++) { + var group = this.groupsData.get(groupIds[i]); + this._updateGroup(group, groupIds[i]); + } + + //this._updateGraph(); + this.redraw(true); + }; + LineGraph.prototype._onAddGroups = function (groupIds) {this._onUpdateGroups(groupIds);}; /** - * used in Core to convert the options into a volatile variable - * - * @param Core + * this cleans the group out off the legends and the dataaxis, updates the ungrouped and updates the graph + * @param {Array} groupIds + * @private */ - exports.convertHiddenOptions = function(body, hiddenDates) { - body.hiddenDates = []; - if (hiddenDates) { - if (Array.isArray(hiddenDates) == true) { - for (var i = 0; i < hiddenDates.length; i++) { - if (hiddenDates[i].repeat === undefined) { - var dateItem = {}; - dateItem.start = moment(hiddenDates[i].start).toDate().valueOf(); - dateItem.end = moment(hiddenDates[i].end).toDate().valueOf(); - body.hiddenDates.push(dateItem); - } + LineGraph.prototype._onRemoveGroups = function (groupIds) { + for (var i = 0; i < groupIds.length; i++) { + if (this.groups.hasOwnProperty(groupIds[i])) { + if (this.groups[groupIds[i]].options.yAxisOrientation == 'right') { + this.yAxisRight.removeGroup(groupIds[i]); + this.legendRight.removeGroup(groupIds[i]); + this.legendRight.redraw(); } - body.hiddenDates.sort(function (a, b) { - return a.start - b.start; - }); // sort by start time + else { + this.yAxisLeft.removeGroup(groupIds[i]); + this.legendLeft.removeGroup(groupIds[i]); + this.legendLeft.redraw(); + } + delete this.groups[groupIds[i]]; } } + this._updateUngrouped(); + //this._updateGraph(); + this.redraw(true); }; /** - * create new entrees for the repeating hidden dates - * @param body - * @param hiddenDates + * update a group object with the group dataset entree + * + * @param group + * @param groupId + * @private */ - exports.updateHiddenDates = function (body, hiddenDates) { - if (hiddenDates && body.domProps.centerContainer.width !== undefined) { - exports.convertHiddenOptions(body, hiddenDates); - - var start = moment(body.range.start); - var end = moment(body.range.end); - - var totalRange = (body.range.end - body.range.start); - var pixelTime = totalRange / body.domProps.centerContainer.width; - - for (var i = 0; i < hiddenDates.length; i++) { - if (hiddenDates[i].repeat !== undefined) { - var startDate = moment(hiddenDates[i].start); - var endDate = moment(hiddenDates[i].end); - - if (startDate._d == "Invalid Date") { - throw new Error("Supplied start date is not valid: " + hiddenDates[i].start); - } - if (endDate._d == "Invalid Date") { - throw new Error("Supplied end date is not valid: " + hiddenDates[i].end); - } - - var duration = endDate - startDate; - if (duration >= 4 * pixelTime) { - - var offset = 0; - var runUntil = end.clone(); - switch (hiddenDates[i].repeat) { - case "daily": // case of time - if (startDate.day() != endDate.day()) { - offset = 1; - } - startDate.dayOfYear(start.dayOfYear()); - startDate.year(start.year()); - startDate.subtract(7,'days'); - - endDate.dayOfYear(start.dayOfYear()); - endDate.year(start.year()); - endDate.subtract(7 - offset,'days'); - - runUntil.add(1, 'weeks'); - break; - case "weekly": - var dayOffset = endDate.diff(startDate,'days') - var day = startDate.day(); - - // set the start date to the range.start - startDate.date(start.date()); - startDate.month(start.month()); - startDate.year(start.year()); - endDate = startDate.clone(); - - // force - startDate.day(day); - endDate.day(day); - endDate.add(dayOffset,'days'); - - startDate.subtract(1,'weeks'); - endDate.subtract(1,'weeks'); - - runUntil.add(1, 'weeks'); - break - case "monthly": - if (startDate.month() != endDate.month()) { - offset = 1; - } - startDate.month(start.month()); - startDate.year(start.year()); - startDate.subtract(1,'months'); - - endDate.month(start.month()); - endDate.year(start.year()); - endDate.subtract(1,'months'); - endDate.add(offset,'months'); - - runUntil.add(1, 'months'); - break; - case "yearly": - if (startDate.year() != endDate.year()) { - offset = 1; - } - startDate.year(start.year()); - startDate.subtract(1,'years'); - endDate.year(start.year()); - endDate.subtract(1,'years'); - endDate.add(offset,'years'); + LineGraph.prototype._updateGroup = function (group, groupId) { + if (!this.groups.hasOwnProperty(groupId)) { + this.groups[groupId] = new GraphGroup(group, groupId, this.options, this.groupsUsingDefaultStyles); + if (this.groups[groupId].options.yAxisOrientation == 'right') { + this.yAxisRight.addGroup(groupId, this.groups[groupId]); + this.legendRight.addGroup(groupId, this.groups[groupId]); + } + else { + this.yAxisLeft.addGroup(groupId, this.groups[groupId]); + this.legendLeft.addGroup(groupId, this.groups[groupId]); + } + } + else { + this.groups[groupId].update(group); + if (this.groups[groupId].options.yAxisOrientation == 'right') { + this.yAxisRight.updateGroup(groupId, this.groups[groupId]); + this.legendRight.updateGroup(groupId, this.groups[groupId]); + } + else { + this.yAxisLeft.updateGroup(groupId, this.groups[groupId]); + this.legendLeft.updateGroup(groupId, this.groups[groupId]); + } + } + this.legendLeft.redraw(); + this.legendRight.redraw(); + }; - runUntil.add(1, 'years'); - break; - default: - console.log("Wrong repeat format, allowed are: daily, weekly, monthly, yearly. Given:", hiddenDates[i].repeat); - return; - } - while (startDate < runUntil) { - body.hiddenDates.push({start: startDate.valueOf(), end: endDate.valueOf()}); - switch (hiddenDates[i].repeat) { - case "daily": - startDate.add(1, 'days'); - endDate.add(1, 'days'); - break; - case "weekly": - startDate.add(1, 'weeks'); - endDate.add(1, 'weeks'); - break - case "monthly": - startDate.add(1, 'months'); - endDate.add(1, 'months'); - break; - case "yearly": - startDate.add(1, 'y'); - endDate.add(1, 'y'); - break; - default: - console.log("Wrong repeat format, allowed are: daily, weekly, monthly, yearly. Given:", hiddenDates[i].repeat); - return; - } - } - body.hiddenDates.push({start: startDate.valueOf(), end: endDate.valueOf()}); + + /** + * this updates all groups, it is used when there is an update the the itemset. + * + * @private + */ + LineGraph.prototype._updateAllGroupData = function () { + if (this.itemsData != null) { + var groupsContent = {}; + var groupId; + for (groupId in this.groups) { + if (this.groups.hasOwnProperty(groupId)) { + groupsContent[groupId] = []; + } + } + for (var itemId in this.itemsData._data) { + if (this.itemsData._data.hasOwnProperty(itemId)) { + var item = this.itemsData._data[itemId]; + if (groupsContent[item.group] === undefined) { + throw new Error('Cannot find referenced group. Possible reason: items added before groups? Groups need to be added before items, as items refer to groups.') } + item.x = util.convert(item.x,'Date'); + groupsContent[item.group].push(item); } } - // remove duplicates, merge where possible - exports.removeDuplicates(body); - // ensure the new positions are not on hidden dates - var startHidden = exports.isHidden(body.range.start, body.hiddenDates); - var endHidden = exports.isHidden(body.range.end,body.hiddenDates); - var rangeStart = body.range.start; - var rangeEnd = body.range.end; - if (startHidden.hidden == true) {rangeStart = body.range.startToFront == true ? startHidden.startDate - 1 : startHidden.endDate + 1;} - if (endHidden.hidden == true) {rangeEnd = body.range.endToFront == true ? endHidden.startDate - 1 : endHidden.endDate + 1;} - if (startHidden.hidden == true || endHidden.hidden == true) { - body.range._applyRange(rangeStart, rangeEnd); + for (groupId in this.groups) { + if (this.groups.hasOwnProperty(groupId)) { + this.groups[groupId].setItems(groupsContent[groupId]); + } } } - - } + }; /** - * remove duplicates from the hidden dates list. Duplicates are evil. They mess everything up. - * Scales with N^2 - * @param body + * Create or delete the group holding all ungrouped items. This group is used when + * there are no groups specified. This anonymous group is called 'graph'. + * @protected */ - exports.removeDuplicates = function(body) { - var hiddenDates = body.hiddenDates; - var safeDates = []; - for (var i = 0; i < hiddenDates.length; i++) { - for (var j = 0; j < hiddenDates.length; j++) { - if (i != j && hiddenDates[j].remove != true && hiddenDates[i].remove != true) { - // j inside i - if (hiddenDates[j].start >= hiddenDates[i].start && hiddenDates[j].end <= hiddenDates[i].end) { - hiddenDates[j].remove = true; - } - // j start inside i - else if (hiddenDates[j].start >= hiddenDates[i].start && hiddenDates[j].start <= hiddenDates[i].end) { - hiddenDates[i].end = hiddenDates[j].end; - hiddenDates[j].remove = true; - } - // j end inside i - else if (hiddenDates[j].end >= hiddenDates[i].start && hiddenDates[j].end <= hiddenDates[i].end) { - hiddenDates[i].start = hiddenDates[j].start; - hiddenDates[j].remove = true; + LineGraph.prototype._updateUngrouped = function() { + if (this.itemsData && this.itemsData != null) { + var ungroupedCounter = 0; + for (var itemId in this.itemsData._data) { + if (this.itemsData._data.hasOwnProperty(itemId)) { + var item = this.itemsData._data[itemId]; + if (item != undefined) { + if (item.hasOwnProperty('group')) { + if (item.group === undefined) { + item.group = UNGROUPED; + } + } + else { + item.group = UNGROUPED; + } + ungroupedCounter = item.group == UNGROUPED ? ungroupedCounter + 1 : ungroupedCounter; } } } - } - for (var i = 0; i < hiddenDates.length; i++) { - if (hiddenDates[i].remove !== true) { - safeDates.push(hiddenDates[i]); + if (ungroupedCounter == 0) { + delete this.groups[UNGROUPED]; + this.legendLeft.removeGroup(UNGROUPED); + this.legendRight.removeGroup(UNGROUPED); + this.yAxisLeft.removeGroup(UNGROUPED); + this.yAxisRight.removeGroup(UNGROUPED); + } + else { + var group = {id: UNGROUPED, content: this.options.defaultGroup}; + this._updateGroup(group, UNGROUPED); } } + else { + delete this.groups[UNGROUPED]; + this.legendLeft.removeGroup(UNGROUPED); + this.legendRight.removeGroup(UNGROUPED); + this.yAxisLeft.removeGroup(UNGROUPED); + this.yAxisRight.removeGroup(UNGROUPED); + } - body.hiddenDates = safeDates; - body.hiddenDates.sort(function (a, b) { - return a.start - b.start; - }); // sort by start time - } + this.legendLeft.redraw(); + this.legendRight.redraw(); + }; - exports.printDates = function(dates) { - for (var i =0; i < dates.length; i++) { - console.log(i, new Date(dates[i].start),new Date(dates[i].end), dates[i].start, dates[i].end, dates[i].remove); - } - } /** - * Used in TimeStep to avoid the hidden times. - * @param timeStep - * @param previousTime + * Redraw the component, mandatory function + * @return {boolean} Returns true if the component is resized */ - exports.stepOverHiddenDates = function(timeStep, previousTime) { - var stepInHidden = false; - var currentValue = timeStep.current.valueOf(); - for (var i = 0; i < timeStep.hiddenDates.length; i++) { - var startDate = timeStep.hiddenDates[i].start; - var endDate = timeStep.hiddenDates[i].end; - if (currentValue >= startDate && currentValue < endDate) { - stepInHidden = true; - break; - } - } + LineGraph.prototype.redraw = function(forceGraphUpdate) { + var resized = false; - if (stepInHidden == true && currentValue < timeStep._end.valueOf() && currentValue != previousTime) { - var prevValue = moment(previousTime); - var newValue = moment(endDate); - //check if the next step should be major - if (prevValue.year() != newValue.year()) {timeStep.switchedYear = true;} - else if (prevValue.month() != newValue.month()) {timeStep.switchedMonth = true;} - else if (prevValue.dayOfYear() != newValue.dayOfYear()) {timeStep.switchedDay = true;} + // calculate actual size and position + this.props.width = this.dom.frame.offsetWidth; + this.props.height = this.body.domProps.centerContainer.height; - timeStep.current = newValue.toDate(); + // update the graph if there is no lastWidth or with, used for the initial draw + if (this.lastWidth === undefined && this.props.width) { + forceGraphUpdate = true; } - }; + // check if this component is resized + resized = this._isResized() || resized; - ///** - // * Used in TimeStep to avoid the hidden times. - // * @param timeStep - // * @param previousTime - // */ - //exports.checkFirstStep = function(timeStep) { - // var stepInHidden = false; - // var currentValue = timeStep.current.valueOf(); - // for (var i = 0; i < timeStep.hiddenDates.length; i++) { - // var startDate = timeStep.hiddenDates[i].start; - // var endDate = timeStep.hiddenDates[i].end; - // if (currentValue >= startDate && currentValue < endDate) { - // stepInHidden = true; - // break; - // } - // } - // - // if (stepInHidden == true && currentValue <= timeStep._end.valueOf()) { - // var newValue = moment(endDate); - // timeStep.current = newValue.toDate(); - // } - //}; + // check whether zoomed (in that case we need to re-stack everything) + var visibleInterval = this.body.range.end - this.body.range.start; + var zoomed = (visibleInterval != this.lastVisibleInterval); + this.lastVisibleInterval = visibleInterval; - /** - * replaces the Core toScreen methods - * @param Core - * @param time - * @param width - * @returns {number} - */ - exports.toScreen = function(Core, time, width) { - if (Core.body.hiddenDates.length == 0) { - var conversion = Core.range.conversion(width); - return (time.valueOf() - conversion.offset) * conversion.scale; - } - else { - var hidden = exports.isHidden(time, Core.body.hiddenDates) - if (hidden.hidden == true) { - time = hidden.startDate; + + // the svg element is three times as big as the width, this allows for fully dragging left and right + // without reloading the graph. the controls for this are bound to events in the constructor + if (resized == true) { + this.svg.style.width = util.option.asSize(3*this.props.width); + this.svg.style.left = util.option.asSize(-this.props.width); + + // if the height of the graph is set as proportional, change the height of the svg + if ((this.options.height + '').indexOf("%") != -1 || this.updateSVGheightOnResize == true) { + this.updateSVGheight = true; } + } - var duration = exports.getHiddenDurationBetween(Core.body.hiddenDates, Core.range.start, Core.range.end); - time = exports.correctTimeForHidden(Core.body.hiddenDates, Core.range, time); + // update the height of the graph on each redraw of the graph. + if (this.updateSVGheight == true) { + if (this.options.graphHeight != this.body.domProps.centerContainer.height + 'px') { + this.options.graphHeight = this.body.domProps.centerContainer.height + 'px'; + this.svg.style.height = this.body.domProps.centerContainer.height + 'px'; + } + this.updateSVGheight = false; + } + else { + this.svg.style.height = ('' + this.options.graphHeight).replace('px','') + 'px'; + } - var conversion = Core.range.conversion(width, duration); - return (time.valueOf() - conversion.offset) * conversion.scale; + // zoomed is here to ensure that animations are shown correctly. + if (resized == true || zoomed == true || this.abortedGraphUpdate == true || forceGraphUpdate == true) { + resized = this._updateGraph() || resized; + } + else { + // move the whole svg while dragging + if (this.lastStart != 0) { + var offset = this.body.range.start - this.lastStart; + var range = this.body.range.end - this.body.range.start; + if (this.props.width != 0) { + var rangePerPixelInv = this.props.width/range; + var xOffset = offset * rangePerPixelInv; + this.svg.style.left = (-this.props.width - xOffset) + 'px'; + } + } } + + this.legendLeft.redraw(); + this.legendRight.redraw(); + return resized; }; /** - * Replaces the core toTime methods - * @param body - * @param range - * @param x - * @param width - * @returns {Date} + * Update and redraw the graph. + * */ - exports.toTime = function(Core, x, width) { - if (Core.body.hiddenDates.length == 0) { - var conversion = Core.range.conversion(width); - return new Date(x / conversion.scale + conversion.offset); - } - else { - var hiddenDuration = exports.getHiddenDurationBetween(Core.body.hiddenDates, Core.range.start, Core.range.end); - var totalDuration = Core.range.end - Core.range.start - hiddenDuration; - var partialDuration = totalDuration * x / width; - var accumulatedHiddenDuration = exports.getAccumulatedHiddenDuration(Core.body.hiddenDates, Core.range, partialDuration); + LineGraph.prototype._updateGraph = function () { + // reset the svg elements + DOMutil.prepareElements(this.svgElements); + if (this.props.width != 0 && this.itemsData != null) { + var group, i; + var preprocessedGroupData = {}; + var processedGroupData = {}; + var groupRanges = {}; + var changeCalled = false; - var newTime = new Date(accumulatedHiddenDuration + partialDuration + Core.range.start); - return newTime; + // getting group Ids + var groupIds = []; + for (var groupId in this.groups) { + if (this.groups.hasOwnProperty(groupId)) { + group = this.groups[groupId]; + if (group.visible == true && (this.options.groups.visibility[groupId] === undefined || this.options.groups.visibility[groupId] == true)) { + groupIds.push(groupId); + } + } + } + if (groupIds.length > 0) { + // this is the range of the SVG canvas + var minDate = this.body.util.toGlobalTime(-this.body.domProps.root.width); + var maxDate = this.body.util.toGlobalTime(2 * this.body.domProps.root.width); + var groupsData = {}; + // fill groups data, this only loads the data we require based on the timewindow + this._getRelevantData(groupIds, groupsData, minDate, maxDate); + + // apply sampling, if disabled, it will pass through this function. + this._applySampling(groupIds, groupsData); + + // we transform the X coordinates to detect collisions + for (i = 0; i < groupIds.length; i++) { + preprocessedGroupData[groupIds[i]] = this._convertXcoordinates(groupsData[groupIds[i]]); + } + + // now all needed data has been collected we start the processing. + this._getYRanges(groupIds, preprocessedGroupData, groupRanges); + + // update the Y axis first, we use this data to draw at the correct Y points + // changeCalled is required to clean the SVG on a change emit. + changeCalled = this._updateYAxis(groupIds, groupRanges); + var MAX_CYCLES = 5; + if (changeCalled == true && this.COUNTER < MAX_CYCLES) { + DOMutil.cleanupElements(this.svgElements); + this.abortedGraphUpdate = true; + this.COUNTER++; + this.body.emitter.emit('change'); + return true; + } + else { + if (this.COUNTER > MAX_CYCLES) { + console.log("WARNING: there may be an infinite loop in the _updateGraph emitter cycle.") + } + this.COUNTER = 0; + this.abortedGraphUpdate = false; + + // With the yAxis scaled correctly, use this to get the Y values of the points. + for (i = 0; i < groupIds.length; i++) { + group = this.groups[groupIds[i]]; + processedGroupData[groupIds[i]] = this._convertYcoordinates(groupsData[groupIds[i]], group); + } + + // draw the groups + for (i = 0; i < groupIds.length; i++) { + group = this.groups[groupIds[i]]; + if (group.options.style != 'bar') { // bar needs to be drawn enmasse + group.draw(processedGroupData[groupIds[i]], group, this.framework); + } + } + BarGraphFunctions.draw(groupIds, processedGroupData, this.framework); + } + } } + + // cleanup unused svg elements + DOMutil.cleanupElements(this.svgElements); + return false; }; /** - * Support function + * first select and preprocess the data from the datasets. + * the groups have their preselection of data, we now loop over this data to see + * what data we need to draw. Sorted data is much faster. + * more optimization is possible by doing the sampling before and using the binary search + * to find the end date to determine the increment. * - * @param hiddenDates - * @param range - * @returns {number} + * @param {array} groupIds + * @param {object} groupsData + * @param {date} minDate + * @param {date} maxDate + * @private */ - exports.getHiddenDurationBetween = function(hiddenDates, start, end) { - var duration = 0; - for (var i = 0; i < hiddenDates.length; i++) { - var startDate = hiddenDates[i].start; - var endDate = hiddenDates[i].end; - // if time after the cutout, and the - if (startDate >= start && endDate < end) { - duration += endDate - startDate; + LineGraph.prototype._getRelevantData = function (groupIds, groupsData, minDate, maxDate) { + var group, i, j, item; + if (groupIds.length > 0) { + for (i = 0; i < groupIds.length; i++) { + group = this.groups[groupIds[i]]; + groupsData[groupIds[i]] = []; + var dataContainer = groupsData[groupIds[i]]; + // optimization for sorted data + if (group.options.sort == true) { + var guess = Math.max(0, util.binarySearchValue(group.itemsData, minDate, 'x', 'before')); + for (j = guess; j < group.itemsData.length; j++) { + item = group.itemsData[j]; + if (item !== undefined) { + if (item.x > maxDate) { + dataContainer.push(item); + break; + } + else { + dataContainer.push(item); + } + } + } + } + else { + for (j = 0; j < group.itemsData.length; j++) { + item = group.itemsData[j]; + if (item !== undefined) { + if (item.x > minDate && item.x < maxDate) { + dataContainer.push(item); + } + } + } + } } } - return duration; }; /** - * Support function - * @param hiddenDates - * @param range - * @param time - * @returns {{duration: number, time: *, offset: number}} + * + * @param groupIds + * @param groupsData + * @private */ - exports.correctTimeForHidden = function(hiddenDates, range, time) { - time = moment(time).toDate().valueOf(); - time -= exports.getHiddenDurationBefore(hiddenDates,range,time); - return time; - }; + LineGraph.prototype._applySampling = function (groupIds, groupsData) { + var group; + if (groupIds.length > 0) { + for (var i = 0; i < groupIds.length; i++) { + group = this.groups[groupIds[i]]; + if (group.options.sampling == true) { + var dataContainer = groupsData[groupIds[i]]; + if (dataContainer.length > 0) { + var increment = 1; + var amountOfPoints = dataContainer.length; - exports.getHiddenDurationBefore = function(hiddenDates, range, time) { - var timeOffset = 0; - time = moment(time).toDate().valueOf(); + // the global screen is used because changing the width of the yAxis may affect the increment, resulting in an endless loop + // of width changing of the yAxis. + var xDistance = this.body.util.toGlobalScreen(dataContainer[dataContainer.length - 1].x) - this.body.util.toGlobalScreen(dataContainer[0].x); + var pointsPerPixel = amountOfPoints / xDistance; + increment = Math.min(Math.ceil(0.2 * amountOfPoints), Math.max(1, Math.round(pointsPerPixel))); - for (var i = 0; i < hiddenDates.length; i++) { - var startDate = hiddenDates[i].start; - var endDate = hiddenDates[i].end; - // if time after the cutout, and the - if (startDate >= range.start && endDate < range.end) { - if (time >= endDate) { - timeOffset += (endDate - startDate); + var sampledData = []; + for (var j = 0; j < amountOfPoints; j += increment) { + sampledData.push(dataContainer[j]); + + } + groupsData[groupIds[i]] = sampledData; + } } } } - return timeOffset; - } + }; + /** - * sum the duration from start to finish, including the hidden duration, - * until the required amount has been reached, return the accumulated hidden duration - * @param hiddenDates - * @param range - * @param time - * @returns {{duration: number, time: *, offset: number}} + * + * + * @param {array} groupIds + * @param {object} groupsData + * @param {object} groupRanges | this is being filled here + * @private */ - exports.getAccumulatedHiddenDuration = function(hiddenDates, range, requiredDuration) { - var hiddenDuration = 0; - var duration = 0; - var previousPoint = range.start; - //exports.printDates(hiddenDates) - for (var i = 0; i < hiddenDates.length; i++) { - var startDate = hiddenDates[i].start; - var endDate = hiddenDates[i].end; - // if time after the cutout, and the - if (startDate >= range.start && endDate < range.end) { - duration += startDate - previousPoint; - previousPoint = endDate; - if (duration >= requiredDuration) { - break; - } - else { - hiddenDuration += endDate - startDate; + LineGraph.prototype._getYRanges = function (groupIds, groupsData, groupRanges) { + var groupData, group, i; + var barCombinedDataLeft = []; + var barCombinedDataRight = []; + var options; + if (groupIds.length > 0) { + for (i = 0; i < groupIds.length; i++) { + groupData = groupsData[groupIds[i]]; + options = this.groups[groupIds[i]].options; + if (groupData.length > 0) { + group = this.groups[groupIds[i]]; + // if bar graphs are stacked, their range need to be handled differently and accumulated over all groups. + if (options.barChart.handleOverlap == 'stack' && options.style == 'bar') { + if (options.yAxisOrientation == 'left') {barCombinedDataLeft = barCombinedDataLeft.concat(group.getYRange(groupData)) ;} + else {barCombinedDataRight = barCombinedDataRight.concat(group.getYRange(groupData));} + } + else { + groupRanges[groupIds[i]] = group.getYRange(groupData,groupIds[i]); + } } } - } - return hiddenDuration; + // if bar graphs are stacked, their range need to be handled differently and accumulated over all groups. + BarGraphFunctions.getStackedBarYRange(barCombinedDataLeft , groupRanges, groupIds, '__barchartLeft' , 'left' ); + BarGraphFunctions.getStackedBarYRange(barCombinedDataRight, groupRanges, groupIds, '__barchartRight', 'right'); + } }; - /** - * used to step over to either side of a hidden block. Correction is disabled on tablets, might be set to true - * @param hiddenDates - * @param time - * @param direction - * @param correctionEnabled - * @returns {*} + * this sets the Y ranges for the Y axis. It also determines which of the axis should be shown or hidden. + * @param {Array} groupIds + * @param {Object} groupRanges + * @private */ - exports.snapAwayFromHidden = function(hiddenDates, time, direction, correctionEnabled) { - var isHidden = exports.isHidden(time, hiddenDates); - if (isHidden.hidden == true) { - if (direction < 0) { - if (correctionEnabled == true) { - return isHidden.startDate - (isHidden.endDate - time) - 1; + LineGraph.prototype._updateYAxis = function (groupIds, groupRanges) { + var resized = false; + var yAxisLeftUsed = false; + var yAxisRightUsed = false; + var minLeft = 1e9, minRight = 1e9, maxLeft = -1e9, maxRight = -1e9, minVal, maxVal; + // if groups are present + if (groupIds.length > 0) { + // this is here to make sure that if there are no items in the axis but there are groups, that there is no infinite draw/redraw loop. + for (var i = 0; i < groupIds.length; i++) { + var group = this.groups[groupIds[i]]; + if (group && group.options.yAxisOrientation != 'right') { + yAxisLeftUsed = true; + minLeft = 0; + maxLeft = 0; } - else { - return isHidden.startDate - 1; + else if (group && group.options.yAxisOrientation) { + yAxisRightUsed = true; + minRight = 0; + maxRight = 0; } } - else { - if (correctionEnabled == true) { - return isHidden.endDate + (time - isHidden.startDate) + 1; - } - else { - return isHidden.endDate + 1; + + // if there are items: + for (var i = 0; i < groupIds.length; i++) { + if (groupRanges.hasOwnProperty(groupIds[i])) { + if (groupRanges[groupIds[i]].ignore !== true) { + minVal = groupRanges[groupIds[i]].min; + maxVal = groupRanges[groupIds[i]].max; + + if (groupRanges[groupIds[i]].yAxisOrientation != 'right') { + yAxisLeftUsed = true; + minLeft = minLeft > minVal ? minVal : minLeft; + maxLeft = maxLeft < maxVal ? maxVal : maxLeft; + } + else { + yAxisRightUsed = true; + minRight = minRight > minVal ? minVal : minRight; + maxRight = maxRight < maxVal ? maxVal : maxRight; + } + } } } + + if (yAxisLeftUsed == true) { + this.yAxisLeft.setRange(minLeft, maxLeft); + } + if (yAxisRightUsed == true) { + this.yAxisRight.setRange(minRight, maxRight); + } + } + resized = this._toggleAxisVisiblity(yAxisLeftUsed , this.yAxisLeft) || resized; + resized = this._toggleAxisVisiblity(yAxisRightUsed, this.yAxisRight) || resized; + + if (yAxisRightUsed == true && yAxisLeftUsed == true) { + this.yAxisLeft.drawIcons = true; + this.yAxisRight.drawIcons = true; } else { - return time; + this.yAxisLeft.drawIcons = false; + this.yAxisRight.drawIcons = false; } + this.yAxisRight.master = !yAxisLeftUsed; + if (this.yAxisRight.master == false) { + if (yAxisRightUsed == true) {this.yAxisLeft.lineOffset = this.yAxisRight.width;} + else {this.yAxisLeft.lineOffset = 0;} - } + resized = this.yAxisLeft.redraw() || resized; + this.yAxisRight.stepPixelsForced = this.yAxisLeft.stepPixels; + this.yAxisRight.zeroCrossing = this.yAxisLeft.zeroCrossing; + resized = this.yAxisRight.redraw() || resized; + } + else { + resized = this.yAxisRight.redraw() || resized; + } + + // clean the accumulated lists + if (groupIds.indexOf('__barchartLeft') != -1) { + groupIds.splice(groupIds.indexOf('__barchartLeft'),1); + } + if (groupIds.indexOf('__barchartRight') != -1) { + groupIds.splice(groupIds.indexOf('__barchartRight'),1); + } + + return resized; + }; /** - * Check if a time is hidden + * This shows or hides the Y axis if needed. If there is a change, the changed event is emitted by the updateYAxis function * - * @param time - * @param hiddenDates - * @returns {{hidden: boolean, startDate: Window.start, endDate: *}} + * @param {boolean} axisUsed + * @returns {boolean} + * @private + * @param axis */ - exports.isHidden = function(time, hiddenDates) { - for (var i = 0; i < hiddenDates.length; i++) { - var startDate = hiddenDates[i].start; - var endDate = hiddenDates[i].end; - - if (time >= startDate && time < endDate) { // if the start is entering a hidden zone - return {hidden: true, startDate: startDate, endDate: endDate}; - break; + LineGraph.prototype._toggleAxisVisiblity = function (axisUsed, axis) { + var changed = false; + if (axisUsed == false) { + if (axis.dom.frame.parentNode && axis.hidden == false) { + axis.hide() + changed = true; } } - return {hidden: false, startDate: startDate, endDate: endDate}; - } - -/***/ }, -/* 25 */ -/***/ function(module, exports, __webpack_require__) { + else { + if (!axis.dom.frame.parentNode && axis.hidden == true) { + axis.show(); + changed = true; + } + } + return changed; + }; - var Emitter = __webpack_require__(11); - var Hammer = __webpack_require__(19); - var util = __webpack_require__(1); - var DataSet = __webpack_require__(7); - var DataView = __webpack_require__(9); - var Range = __webpack_require__(21); - var ItemSet = __webpack_require__(26); - var Activator = __webpack_require__(35); - var DateUtil = __webpack_require__(24); /** - * Create a timeline visualization - * @param {HTMLElement} container - * @param {vis.DataSet | Array | google.visualization.DataTable} [items] - * @param {Object} [options] See Core.setOptions for the available options. - * @constructor + * This uses the DataAxis object to generate the correct X coordinate on the SVG window. It uses the + * util function toScreen to get the x coordinate from the timestamp. It also pre-filters the data and get the minMax ranges for + * the yAxis. + * + * @param datapoints + * @returns {Array} + * @private */ - function Core () {} + LineGraph.prototype._convertXcoordinates = function (datapoints) { + var extractedData = []; + var xValue, yValue; + var toScreen = this.body.util.toScreen; + + for (var i = 0; i < datapoints.length; i++) { + xValue = toScreen(datapoints[i].x) + this.props.width; + yValue = datapoints[i].y; + extractedData.push({x: xValue, y: yValue}); + } + + return extractedData; + }; - // turn Core into an event emitter - Emitter(Core.prototype); /** - * Create the main DOM for the Core: a root panel containing left, right, - * top, bottom, content, and background panel. - * @param {Element} container The container element where the Core will - * be attached. + * This uses the DataAxis object to generate the correct X coordinate on the SVG window. It uses the + * util function toScreen to get the x coordinate from the timestamp. It also pre-filters the data and get the minMax ranges for + * the yAxis. + * + * @param datapoints + * @param group + * @returns {Array} * @private */ - Core.prototype._create = function (container) { - this.dom = {}; - - this.dom.root = document.createElement('div'); - this.dom.background = document.createElement('div'); - this.dom.backgroundVertical = document.createElement('div'); - this.dom.backgroundHorizontal = document.createElement('div'); - this.dom.centerContainer = document.createElement('div'); - this.dom.leftContainer = document.createElement('div'); - this.dom.rightContainer = document.createElement('div'); - this.dom.center = document.createElement('div'); - this.dom.left = document.createElement('div'); - this.dom.right = document.createElement('div'); - this.dom.top = document.createElement('div'); - this.dom.bottom = document.createElement('div'); - this.dom.shadowTop = document.createElement('div'); - this.dom.shadowBottom = document.createElement('div'); - this.dom.shadowTopLeft = document.createElement('div'); - this.dom.shadowBottomLeft = document.createElement('div'); - this.dom.shadowTopRight = document.createElement('div'); - this.dom.shadowBottomRight = document.createElement('div'); + LineGraph.prototype._convertYcoordinates = function (datapoints, group) { + var extractedData = []; + var xValue, yValue; + var toScreen = this.body.util.toScreen; + var axis = this.yAxisLeft; + var svgHeight = Number(this.svg.style.height.replace('px','')); + if (group.options.yAxisOrientation == 'right') { + axis = this.yAxisRight; + } - this.dom.root.className = 'vis timeline root'; - this.dom.background.className = 'vispanel background'; - this.dom.backgroundVertical.className = 'vispanel background vertical'; - this.dom.backgroundHorizontal.className = 'vispanel background horizontal'; - this.dom.centerContainer.className = 'vispanel center'; - this.dom.leftContainer.className = 'vispanel left'; - this.dom.rightContainer.className = 'vispanel right'; - this.dom.top.className = 'vispanel top'; - this.dom.bottom.className = 'vispanel bottom'; - this.dom.left.className = 'content'; - this.dom.center.className = 'content'; - this.dom.right.className = 'content'; - this.dom.shadowTop.className = 'shadow top'; - this.dom.shadowBottom.className = 'shadow bottom'; - this.dom.shadowTopLeft.className = 'shadow top'; - this.dom.shadowBottomLeft.className = 'shadow bottom'; - this.dom.shadowTopRight.className = 'shadow top'; - this.dom.shadowBottomRight.className = 'shadow bottom'; + for (var i = 0; i < datapoints.length; i++) { + xValue = toScreen(datapoints[i].x) + this.props.width; + yValue = Math.round(axis.convertValue(datapoints[i].y)); + extractedData.push({x: xValue, y: yValue}); + } - this.dom.root.appendChild(this.dom.background); - this.dom.root.appendChild(this.dom.backgroundVertical); - this.dom.root.appendChild(this.dom.backgroundHorizontal); - this.dom.root.appendChild(this.dom.centerContainer); - this.dom.root.appendChild(this.dom.leftContainer); - this.dom.root.appendChild(this.dom.rightContainer); - this.dom.root.appendChild(this.dom.top); - this.dom.root.appendChild(this.dom.bottom); + group.setZeroPosition(Math.min(svgHeight, axis.convertValue(0))); - this.dom.centerContainer.appendChild(this.dom.center); - this.dom.leftContainer.appendChild(this.dom.left); - this.dom.rightContainer.appendChild(this.dom.right); + return extractedData; + }; - this.dom.centerContainer.appendChild(this.dom.shadowTop); - this.dom.centerContainer.appendChild(this.dom.shadowBottom); - this.dom.leftContainer.appendChild(this.dom.shadowTopLeft); - this.dom.leftContainer.appendChild(this.dom.shadowBottomLeft); - this.dom.rightContainer.appendChild(this.dom.shadowTopRight); - this.dom.rightContainer.appendChild(this.dom.shadowBottomRight); - this.on('rangechange', this.redraw.bind(this)); - this.on('touch', this._onTouch.bind(this)); - this.on('pinch', this._onPinch.bind(this)); - this.on('dragstart', this._onDragStart.bind(this)); - this.on('drag', this._onDrag.bind(this)); + module.exports = LineGraph; - var me = this; - this.on('change', function (properties) { - if (properties && properties.queue == true) { - // redraw once on next tick - if (!me._redrawTimer) { - me._redrawTimer = setTimeout(function () { - me._redrawTimer = null; - me.redraw(); - }, 0) - } - } - else { - // redraw immediately - me.redraw(); - } - }); - // create event listeners for all interesting events, these events will be - // emitted via emitter - this.hammer = Hammer(this.dom.root, { - preventDefault: true - }); - this.listeners = {}; +/***/ }, +/* 30 */ +/***/ function(module, exports, __webpack_require__) { - var events = [ - 'touch', 'pinch', - 'tap', 'doubletap', 'hold', - 'dragstart', 'drag', 'dragend', - 'mousewheel', 'DOMMouseScroll' // DOMMouseScroll is needed for Firefox - ]; - events.forEach(function (event) { - var listener = function () { - var args = [event].concat(Array.prototype.slice.call(arguments, 0)); - if (me.isActive()) { - me.emit.apply(me, args); - } - }; - me.hammer.on(event, listener); - me.listeners[event] = listener; - }); + var util = __webpack_require__(1); + var Component = __webpack_require__(20); + var TimeStep = __webpack_require__(19); + var DateUtil = __webpack_require__(15); + var moment = __webpack_require__(44); - // size properties of each of the panels + /** + * A horizontal time axis + * @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} body + * @param {Object} [options] See TimeAxis.setOptions for the available + * options. + * @constructor TimeAxis + * @extends Component + */ + function TimeAxis (body, options) { + this.dom = { + foreground: null, + lines: [], + majorTexts: [], + minorTexts: [], + redundant: { + lines: [], + majorTexts: [], + minorTexts: [] + } + }; this.props = { - root: {}, - background: {}, - centerContainer: {}, - leftContainer: {}, - rightContainer: {}, - center: {}, - left: {}, - right: {}, - top: {}, - bottom: {}, - border: {}, - scrollTop: 0, - scrollTopMin: 0 + range: { + start: 0, + end: 0, + minimumStep: 0 + }, + lineTop: 0 }; - this.touch = {}; // store state information needed for touch events - this.redrawCount = 0; + this.defaultOptions = { + orientation: 'bottom', // supported: 'top', 'bottom' + // TODO: implement timeaxis orientations 'left' and 'right' + showMinorLabels: true, + showMajorLabels: true, + format: null + }; + this.options = util.extend({}, this.defaultOptions); - // attach the root panel to the provided container - if (!container) throw new Error('No container provided'); - container.appendChild(this.dom.root); - }; + this.body = body; + + // create the HTML DOM + this._create(); + + this.setOptions(options); + } + + TimeAxis.prototype = new Component(); /** - * Set options. Options will be passed to all components loaded in the Timeline. - * @param {Object} [options] - * {String} orientation - * Vertical orientation for the Timeline, - * can be 'bottom' (default) or 'top'. - * {String | Number} width - * Width for the timeline, a number in pixels or - * a css string like '1000px' or '75%'. '100%' by default. - * {String | Number} height - * Fixed height for the Timeline, a number in pixels or - * a css string like '400px' or '75%'. If undefined, - * The Timeline will automatically size such that - * its contents fit. - * {String | Number} minHeight - * Minimum height for the Timeline, a number in pixels or - * a css string like '400px' or '75%'. - * {String | Number} maxHeight - * Maximum height for the Timeline, a number in pixels or - * a css string like '400px' or '75%'. - * {Number | Date | String} start - * Start date for the visible window - * {Number | Date | String} end - * End date for the visible window + * Set options for the TimeAxis. + * Parameters will be merged in current options. + * @param {Object} options Available options: + * {string} [orientation] + * {boolean} [showMinorLabels] + * {boolean} [showMajorLabels] */ - Core.prototype.setOptions = function (options) { + TimeAxis.prototype.setOptions = function(options) { if (options) { - // copy the known options - var fields = ['width', 'height', 'minHeight', 'maxHeight', 'autoResize', 'start', 'end', 'orientation', 'clickToUse', 'dataAttributes', 'hiddenDates']; - util.selectiveExtend(fields, this.options, options); - - if ('hiddenDates' in this.options) { - DateUtil.convertHiddenOptions(this.body, this.options.hiddenDates); - } + // copy all options that we know + util.selectiveExtend([ + 'orientation', + 'showMinorLabels', + 'showMajorLabels', + 'hiddenDates', + 'format' + ], this.options, options); - if ('clickToUse' in options) { - if (options.clickToUse) { - if (!this.activator) { - this.activator = new Activator(this.dom.root); - } + // 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 { - if (this.activator) { - this.activator.destroy(); - delete this.activator; - } + moment.lang(options.locale); } } - - // enable/disable autoResize - this._initAutoResize(); } + }; - // propagate options to all components - this.components.forEach(function (component) { - component.setOptions(options); - }); + /** + * Create the HTML DOM for the TimeAxis + */ + TimeAxis.prototype._create = function() { + this.dom.foreground = document.createElement('div'); + this.dom.background = document.createElement('div'); - // TODO: remove deprecation error one day (deprecated since version 0.8.0) - if (options && options.order) { - throw new Error('Option order is deprecated. There is no replacement for this feature.'); + this.dom.foreground.className = 'timeaxis foreground'; + this.dom.background.className = 'timeaxis background'; + }; + + /** + * Destroy the TimeAxis + */ + TimeAxis.prototype.destroy = function() { + // remove from DOM + if (this.dom.foreground.parentNode) { + this.dom.foreground.parentNode.removeChild(this.dom.foreground); + } + if (this.dom.background.parentNode) { + this.dom.background.parentNode.removeChild(this.dom.background); } - // redraw everything - this.redraw(); + this.body = null; }; /** - * Returns true when the Timeline is active. - * @returns {boolean} + * Repaint the component + * @return {boolean} Returns true if the component is resized */ - Core.prototype.isActive = function () { - return !this.activator || this.activator.active; - }; + TimeAxis.prototype.redraw = function () { + var options = this.options; + var props = this.props; + var foreground = this.dom.foreground; + var background = this.dom.background; + + // determine the correct parent DOM element (depending on option orientation) + var parent = (options.orientation == 'top') ? this.body.dom.top : this.body.dom.bottom; + var parentChanged = (foreground.parentNode !== parent); + + // calculate character width and height + this._calculateCharSize(); + + // TODO: recalculate sizes only needed when parent is resized or options is changed + var orientation = this.options.orientation, + showMinorLabels = this.options.showMinorLabels, + showMajorLabels = this.options.showMajorLabels; + + // determine the width and height of the elemens for the axis + props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; + props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; + props.height = props.minorLabelHeight + props.majorLabelHeight; + props.width = foreground.offsetWidth; + + props.minorLineHeight = this.body.domProps.root.height - props.majorLabelHeight - + (options.orientation == 'top' ? this.body.domProps.bottom.height : this.body.domProps.top.height); + props.minorLineWidth = 1; // TODO: really calculate width + props.majorLineHeight = props.minorLineHeight + props.majorLabelHeight; + props.majorLineWidth = 1; // TODO: really calculate width - /** - * Destroy the Core, clean up all DOM elements and event listeners. - */ - Core.prototype.destroy = function () { - // unbind datasets - this.clear(); + // take foreground and background offline while updating (is almost twice as fast) + var foregroundNextSibling = foreground.nextSibling; + var backgroundNextSibling = background.nextSibling; + foreground.parentNode && foreground.parentNode.removeChild(foreground); + background.parentNode && background.parentNode.removeChild(background); - // remove all event listeners - this.off(); + foreground.style.height = this.props.height + 'px'; - // stop checking for changed size - this._stopAutoResize(); + this._repaintLabels(); - // remove from DOM - if (this.dom.root.parentNode) { - this.dom.root.parentNode.removeChild(this.dom.root); + // put DOM online again (at the same place) + if (foregroundNextSibling) { + parent.insertBefore(foreground, foregroundNextSibling); } - this.dom = null; - - // remove Activator - if (this.activator) { - this.activator.destroy(); - delete this.activator; + else { + parent.appendChild(foreground) } - - // cleanup hammer touch events - for (var event in this.listeners) { - if (this.listeners.hasOwnProperty(event)) { - delete this.listeners[event]; - } + if (backgroundNextSibling) { + this.body.dom.backgroundVertical.insertBefore(background, backgroundNextSibling); + } + else { + this.body.dom.backgroundVertical.appendChild(background) } - this.listeners = null; - this.hammer = null; - - // give all components the opportunity to cleanup - this.components.forEach(function (component) { - component.destroy(); - }); - this.body = null; + return this._isResized() || parentChanged; }; - /** - * Set a custom time bar - * @param {Date} time + * Repaint major and minor text labels and vertical grid lines + * @private */ - Core.prototype.setCustomTime = function (time) { - if (!this.customTime) { - throw new Error('Cannot get custom time: Custom time bar is not enabled'); - } + TimeAxis.prototype._repaintLabels = function () { + var orientation = this.options.orientation; - this.customTime.setCustomTime(time); - }; + // calculate range and step (step such that we have space for 7 characters per label) + var start = util.convert(this.body.range.start, 'Number'); + var end = util.convert(this.body.range.end, 'Number'); + var timeLabelsize = this.body.util.toTime((this.props.minorCharWidth || 10) * 7).valueOf(); + var minimumStep = timeLabelsize - DateUtil.getHiddenDurationBefore(this.body.hiddenDates, this.body.range, timeLabelsize); + minimumStep -= this.body.util.toTime(0).valueOf(); - /** - * Retrieve the current custom time. - * @return {Date} customTime - */ - Core.prototype.getCustomTime = function() { - if (!this.customTime) { - throw new Error('Cannot get custom time: Custom time bar is not enabled'); + var step = new TimeStep(new Date(start), new Date(end), minimumStep, this.body.hiddenDates); + if (this.options.format) { + step.setFormat(this.options.format); } + this.step = step; - return this.customTime.getCustomTime(); - }; + // Move all DOM elements to a "redundant" list, where they + // can be picked for re-use, and clear the lists with lines and texts. + // At the end of the function _repaintLabels, left over elements will be cleaned up + var dom = this.dom; + dom.redundant.lines = dom.lines; + dom.redundant.majorTexts = dom.majorTexts; + dom.redundant.minorTexts = dom.minorTexts; + dom.lines = []; + dom.majorTexts = []; + dom.minorTexts = []; + var cur; + var x = 0; + var isMajor; + var xPrev = 0; + var width = 0; + var prevLine; + var xFirstMajorLabel = undefined; + var max = 0; + var className; - /** - * Get the id's of the currently visible items. - * @returns {Array} The ids of the visible items - */ - Core.prototype.getVisibleItems = function() { - return this.itemSet && this.itemSet.getVisibleItems() || []; - }; + step.first(); + while (step.hasNext() && max < 1000) { + max++; + cur = step.getCurrent(); + isMajor = step.isMajor(); + className = step.getClassName(); + xPrev = x; + x = this.body.util.toScreen(cur); + width = x - xPrev; + if (prevLine) { + prevLine.style.width = width + 'px'; + } - /** - * Clear the Core. By Default, items, groups and options are cleared. - * Example usage: - * - * timeline.clear(); // clear items, groups, and options - * timeline.clear({options: true}); // clear options only - * - * @param {Object} [what] Optionally specify what to clear. By default: - * {items: true, groups: true, options: true} - */ - Core.prototype.clear = function(what) { - // clear items - if (!what || what.items) { - this.setItems(null); - } + if (this.options.showMinorLabels) { + this._repaintMinorText(x, step.getLabelMinor(), orientation, className); + } - // clear groups - if (!what || what.groups) { - this.setGroups(null); + if (isMajor && this.options.showMajorLabels) { + if (x > 0) { + if (xFirstMajorLabel == undefined) { + xFirstMajorLabel = x; + } + this._repaintMajorText(x, step.getLabelMajor(), orientation, className); + } + prevLine = this._repaintMajorLine(x, orientation, className); + } + else { + prevLine = this._repaintMinorLine(x, orientation, className); + } + + step.next(); } - // clear options of timeline and of each of the components - if (!what || what.options) { - this.components.forEach(function (component) { - component.setOptions(component.defaultOptions); - }); + // create a major label on the left when needed + if (this.options.showMajorLabels) { + var leftTime = this.body.util.toTime(0), + leftText = step.getLabelMajor(leftTime), + widthText = leftText.length * (this.props.majorCharWidth || 10) + 10; // upper bound estimation - this.setOptions(this.defaultOptions); // this will also do a redraw + if (xFirstMajorLabel == undefined || widthText < xFirstMajorLabel) { + this._repaintMajorText(0, leftText, orientation, className); + } } + + // Cleanup leftover DOM elements from the redundant list + util.forEach(this.dom.redundant, function (arr) { + while (arr.length) { + var elem = arr.pop(); + if (elem && elem.parentNode) { + elem.parentNode.removeChild(elem); + } + } + }); }; /** - * Set Core window such that it fits all items - * @param {Object} [options] Available options: - * `animate: boolean | number` - * If true (default), the range is animated - * smoothly to the new window. - * If a number, the number is taken as duration - * for the animation. Default duration is 500 ms. + * Create a minor label for the axis at position x + * @param {Number} x + * @param {String} text + * @param {String} orientation "top" or "bottom" (default) + * @param {String} className + * @private */ - Core.prototype.fit = function(options) { - var range = this._getDataRange(); + TimeAxis.prototype._repaintMinorText = function (x, text, orientation, className) { + // reuse redundant label + var label = this.dom.redundant.minorTexts.shift(); - // skip range set if there is no start and end date - if (range.start === null && range.end === null) { - return; + if (!label) { + // create new label + var content = document.createTextNode(''); + label = document.createElement('div'); + label.appendChild(content); + this.dom.foreground.appendChild(label); } + this.dom.minorTexts.push(label); - var animate = (options && options.animate !== undefined) ? options.animate : true; - this.range.setRange(range.start, range.end, animate); + label.childNodes[0].nodeValue = text; + + label.style.top = (orientation == 'top') ? (this.props.majorLabelHeight + 'px') : '0'; + label.style.left = x + 'px'; + label.className = 'text minor ' + className; + //label.title = title; // TODO: this is a heavy operation }; /** - * Calculate the data range of the items and applies a 5% window around it. - * @returns {{start: Date | null, end: Date | null}} - * @protected + * Create a Major label for the axis at position x + * @param {Number} x + * @param {String} text + * @param {String} orientation "top" or "bottom" (default) + * @param {String} className + * @private */ - Core.prototype._getDataRange = function() { - // apply the data range as range - var dataRange = this.getItemRange(); + TimeAxis.prototype._repaintMajorText = function (x, text, orientation, className) { + // reuse redundant label + var label = this.dom.redundant.majorTexts.shift(); - // add 5% space on both sides - var start = dataRange.min; - var end = dataRange.max; - if (start != null && end != null) { - var interval = (end.valueOf() - start.valueOf()); - if (interval <= 0) { - // prevent an empty interval - interval = 24 * 60 * 60 * 1000; // 1 day - } - start = new Date(start.valueOf() - interval * 0.05); - end = new Date(end.valueOf() + interval * 0.05); + if (!label) { + // create label + var content = document.createTextNode(text); + label = document.createElement('div'); + label.appendChild(content); + this.dom.foreground.appendChild(label); } + this.dom.majorTexts.push(label); - return { - start: start, - end: end - } + label.childNodes[0].nodeValue = text; + label.className = 'text major ' + className; + //label.title = title; // TODO: this is a heavy operation + + label.style.top = (orientation == 'top') ? '0' : (this.props.minorLabelHeight + 'px'); + label.style.left = x + 'px'; }; /** - * Set the visible window. Both parameters are optional, you can change only - * start or only end. Syntax: - * - * TimeLine.setWindow(start, end) - * TimeLine.setWindow(range) - * - * Where start and end can be a Date, number, or string, and range is an - * object with properties start and end. - * - * @param {Date | Number | String | Object} [start] Start date of visible window - * @param {Date | Number | String} [end] End date of visible window - * @param {Object} [options] Available options: - * `animate: boolean | number` - * If true (default), the range is animated - * smoothly to the new window. - * If a number, the number is taken as duration - * for the animation. Default duration is 500 ms. + * Create a minor line for the axis at position x + * @param {Number} x + * @param {String} orientation "top" or "bottom" (default) + * @param {String} className + * @return {Element} Returns the created line + * @private */ - Core.prototype.setWindow = function(start, end, options) { - var animate = (options && options.animate !== undefined) ? options.animate : true; - if (arguments.length == 1) { - var range = arguments[0]; - this.range.setRange(range.start, range.end, animate); + TimeAxis.prototype._repaintMinorLine = function (x, orientation, className) { + // reuse redundant line + var line = this.dom.redundant.lines.shift(); + if (!line) { + // create vertical line + line = document.createElement('div'); + this.dom.background.appendChild(line); + } + this.dom.lines.push(line); + + var props = this.props; + if (orientation == 'top') { + line.style.top = props.majorLabelHeight + 'px'; } else { - this.range.setRange(start, end, animate); + line.style.top = this.body.domProps.top.height + 'px'; } - }; - - /** - * Move the window such that given time is centered on screen. - * @param {Date | Number | String} time - * @param {Object} [options] Available options: - * `animate: boolean | number` - * If true (default), the range is animated - * smoothly to the new window. - * If a number, the number is taken as duration - * for the animation. Default duration is 500 ms. - */ - Core.prototype.moveTo = function(time, options) { - var interval = this.range.end - this.range.start; - var t = util.convert(time, 'Date').valueOf(); + line.style.height = props.minorLineHeight + 'px'; + line.style.left = (x - props.minorLineWidth / 2) + 'px'; - var start = t - interval / 2; - var end = t + interval / 2; - var animate = (options && options.animate !== undefined) ? options.animate : true; + line.className = 'grid vertical minor ' + className; - this.range.setRange(start, end, animate); + return line; }; /** - * Get the visible window - * @return {{start: Date, end: Date}} Visible range + * Create a Major line for the axis at position x + * @param {Number} x + * @param {String} orientation "top" or "bottom" (default) + * @param {String} className + * @return {Element} Returns the created line + * @private */ - Core.prototype.getWindow = function() { - var range = this.range.getRange(); - return { - start: new Date(range.start), - end: new Date(range.end) - }; - }; + TimeAxis.prototype._repaintMajorLine = function (x, orientation, className) { + // reuse redundant line + var line = this.dom.redundant.lines.shift(); + if (!line) { + // create vertical line + line = document.createElement('div'); + this.dom.background.appendChild(line); + } + this.dom.lines.push(line); - /** - * Force a redraw of the Core. Can be useful to manually redraw when - * option autoResize=false - */ - Core.prototype.redraw = function() { - var resized = false; - var options = this.options; var props = this.props; - var dom = this.dom; - - if (!dom) return; // when destroyed - - DateUtil.updateHiddenDates(this.body, this.options.hiddenDates); - - // update class names - if (options.orientation == 'top') { - util.addClassName(dom.root, 'top'); - util.removeClassName(dom.root, 'bottom'); + if (orientation == 'top') { + line.style.top = '0'; } else { - util.removeClassName(dom.root, 'top'); - util.addClassName(dom.root, 'bottom'); + line.style.top = this.body.domProps.top.height + 'px'; } + line.style.left = (x - props.majorLineWidth / 2) + 'px'; + line.style.height = props.majorLineHeight + 'px'; - // update root width and height options - dom.root.style.maxHeight = util.option.asSize(options.maxHeight, ''); - dom.root.style.minHeight = util.option.asSize(options.minHeight, ''); - dom.root.style.width = util.option.asSize(options.width, ''); + line.className = 'grid vertical major ' + className; - // calculate border widths - props.border.left = (dom.centerContainer.offsetWidth - dom.centerContainer.clientWidth) / 2; - props.border.right = props.border.left; - props.border.top = (dom.centerContainer.offsetHeight - dom.centerContainer.clientHeight) / 2; - props.border.bottom = props.border.top; - var borderRootHeight= dom.root.offsetHeight - dom.root.clientHeight; - var borderRootWidth = dom.root.offsetWidth - dom.root.clientWidth; + return line; + }; - // workaround for a bug in IE: the clientWidth of an element with - // a height:0px and overflow:hidden is not calculated and always has value 0 - if (dom.centerContainer.clientHeight === 0) { - props.border.left = props.border.top; - props.border.right = props.border.left; - } - if (dom.root.clientHeight === 0) { - borderRootWidth = borderRootHeight; + /** + * Determine the size of text on the axis (both major and minor axis). + * The size is calculated only once and then cached in this.props. + * @private + */ + TimeAxis.prototype._calculateCharSize = function () { + // Note: We calculate char size with every redraw. Size may change, for + // example when any of the timelines parents had display:none for example. + + // determine the char width and height on the minor axis + if (!this.dom.measureCharMinor) { + this.dom.measureCharMinor = document.createElement('DIV'); + this.dom.measureCharMinor.className = 'text minor measure'; + this.dom.measureCharMinor.style.position = 'absolute'; + + this.dom.measureCharMinor.appendChild(document.createTextNode('0')); + this.dom.foreground.appendChild(this.dom.measureCharMinor); } + this.props.minorCharHeight = this.dom.measureCharMinor.clientHeight; + this.props.minorCharWidth = this.dom.measureCharMinor.clientWidth; - // calculate the heights. If any of the side panels is empty, we set the height to - // minus the border width, such that the border will be invisible - props.center.height = dom.center.offsetHeight; - props.left.height = dom.left.offsetHeight; - props.right.height = dom.right.offsetHeight; - props.top.height = dom.top.clientHeight || -props.border.top; - props.bottom.height = dom.bottom.clientHeight || -props.border.bottom; + // determine the char width and height on the major axis + if (!this.dom.measureCharMajor) { + this.dom.measureCharMajor = document.createElement('DIV'); + this.dom.measureCharMajor.className = 'text major measure'; + this.dom.measureCharMajor.style.position = 'absolute'; - // TODO: compensate borders when any of the panels is empty. + this.dom.measureCharMajor.appendChild(document.createTextNode('0')); + this.dom.foreground.appendChild(this.dom.measureCharMajor); + } + this.props.majorCharHeight = this.dom.measureCharMajor.clientHeight; + this.props.majorCharWidth = this.dom.measureCharMajor.clientWidth; + }; - // apply auto height - // TODO: only calculate autoHeight when needed (else we cause an extra reflow/repaint of the DOM) - var contentHeight = Math.max(props.left.height, props.center.height, props.right.height); - var autoHeight = props.top.height + contentHeight + props.bottom.height + - borderRootHeight + props.border.top + props.border.bottom; - dom.root.style.height = util.option.asSize(options.height, autoHeight + 'px'); + /** + * 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 + */ + TimeAxis.prototype.snap = function(date) { + return this.step.snap(date); + }; - // calculate heights of the content panels - props.root.height = dom.root.offsetHeight; - props.background.height = props.root.height - borderRootHeight; - var containerHeight = props.root.height - props.top.height - props.bottom.height - - borderRootHeight; - props.centerContainer.height = containerHeight; - props.leftContainer.height = containerHeight; - props.rightContainer.height = props.leftContainer.height; + module.exports = TimeAxis; - // calculate the widths of the panels - props.root.width = dom.root.offsetWidth; - props.background.width = props.root.width - borderRootWidth; - props.left.width = dom.leftContainer.clientWidth || -props.border.left; - props.leftContainer.width = props.left.width; - props.right.width = dom.rightContainer.clientWidth || -props.border.right; - props.rightContainer.width = props.right.width; - var centerWidth = props.root.width - props.left.width - props.right.width - borderRootWidth; - props.center.width = centerWidth; - props.centerContainer.width = centerWidth; - props.top.width = centerWidth; - props.bottom.width = centerWidth; - // resize the panels - dom.background.style.height = props.background.height + 'px'; - dom.backgroundVertical.style.height = props.background.height + 'px'; - dom.backgroundHorizontal.style.height = props.centerContainer.height + 'px'; - dom.centerContainer.style.height = props.centerContainer.height + 'px'; - dom.leftContainer.style.height = props.leftContainer.height + 'px'; - dom.rightContainer.style.height = props.rightContainer.height + 'px'; +/***/ }, +/* 31 */ +/***/ function(module, exports, __webpack_require__) { - dom.background.style.width = props.background.width + 'px'; - dom.backgroundVertical.style.width = props.centerContainer.width + 'px'; - dom.backgroundHorizontal.style.width = props.background.width + 'px'; - dom.centerContainer.style.width = props.center.width + 'px'; - dom.top.style.width = props.top.width + 'px'; - dom.bottom.style.width = props.bottom.width + 'px'; + var Hammer = __webpack_require__(45); + var util = __webpack_require__(1); - // reposition the panels - dom.background.style.left = '0'; - dom.background.style.top = '0'; - dom.backgroundVertical.style.left = (props.left.width + props.border.left) + 'px'; - dom.backgroundVertical.style.top = '0'; - dom.backgroundHorizontal.style.left = '0'; - dom.backgroundHorizontal.style.top = props.top.height + 'px'; - dom.centerContainer.style.left = props.left.width + 'px'; - dom.centerContainer.style.top = props.top.height + 'px'; - dom.leftContainer.style.left = '0'; - dom.leftContainer.style.top = props.top.height + 'px'; - dom.rightContainer.style.left = (props.left.width + props.center.width) + 'px'; - dom.rightContainer.style.top = props.top.height + 'px'; - dom.top.style.left = props.left.width + 'px'; - dom.top.style.top = '0'; - dom.bottom.style.left = props.left.width + 'px'; - dom.bottom.style.top = (props.top.height + props.centerContainer.height) + 'px'; + /** + * @constructor Item + * @param {Object} data Object containing (optional) parameters type, + * start, end, content, group, className. + * @param {{toScreen: function, toTime: function}} conversion + * Conversion functions from time to screen and vice versa + * @param {Object} options Configuration options + * // TODO: describe available options + */ + function Item (data, conversion, options) { + this.id = null; + this.parent = null; + this.data = data; + this.dom = null; + this.conversion = conversion || {}; + this.options = options || {}; - // update the scrollTop, feasible range for the offset can be changed - // when the height of the Core or of the contents of the center changed - this._updateScrollTop(); + this.selected = false; + this.displayed = false; + this.dirty = true; - // reposition the scrollable contents - var offset = this.props.scrollTop; - if (options.orientation == 'bottom') { - offset += Math.max(this.props.centerContainer.height - this.props.center.height - - this.props.border.top - this.props.border.bottom, 0); - } - dom.center.style.left = '0'; - dom.center.style.top = offset + 'px'; - dom.left.style.left = '0'; - dom.left.style.top = offset + 'px'; - dom.right.style.left = '0'; - dom.right.style.top = offset + 'px'; + this.top = null; + this.left = null; + this.width = null; + this.height = null; + } - // show shadows when vertical scrolling is available - var visibilityTop = this.props.scrollTop == 0 ? 'hidden' : ''; - var visibilityBottom = this.props.scrollTop == this.props.scrollTopMin ? 'hidden' : ''; - dom.shadowTop.style.visibility = visibilityTop; - dom.shadowBottom.style.visibility = visibilityBottom; - dom.shadowTopLeft.style.visibility = visibilityTop; - dom.shadowBottomLeft.style.visibility = visibilityBottom; - dom.shadowTopRight.style.visibility = visibilityTop; - dom.shadowBottomRight.style.visibility = visibilityBottom; + Item.prototype.stack = true; - // redraw all components - this.components.forEach(function (component) { - resized = component.redraw() || resized; - }); - if (resized) { - // keep repainting until all sizes are settled - var MAX_REDRAWS = 3; // maximum number of consecutive redraws - if (this.redrawCount < MAX_REDRAWS) { - this.redrawCount++; - this.redraw(); - } - else { - console.log('WARNING: infinite loop in redraw?'); - } - this.redrawCount = 0; - } + /** + * Select current item + */ + Item.prototype.select = function() { + this.selected = true; + this.dirty = true; + if (this.displayed) this.redraw(); + }; - this.emit("finishedRedraw"); + /** + * Unselect current item + */ + Item.prototype.unselect = function() { + this.selected = false; + this.dirty = true; + if (this.displayed) this.redraw(); }; - // TODO: deprecated since version 1.1.0, remove some day - Core.prototype.repaint = function () { - throw new Error('Function repaint is deprecated. Use redraw instead.'); + /** + * Set data for the item. Existing data will be updated. The id should not + * be changed. When the item is displayed, it will be redrawn immediately. + * @param {Object} data + */ + Item.prototype.setData = function(data) { + this.data = data; + this.dirty = true; + if (this.displayed) this.redraw(); }; /** - * Set a current time. This can be used for example to ensure that a client's - * time is synchronized with a shared server time. - * Only applicable when option `showCurrentTime` is true. - * @param {Date | String | Number} time A Date, unix timestamp, or - * ISO date string. + * Set a parent for the item + * @param {ItemSet | Group} parent */ - Core.prototype.setCurrentTime = function(time) { - if (!this.currentTime) { - throw new Error('Option showCurrentTime must be true'); + Item.prototype.setParent = function(parent) { + if (this.displayed) { + this.hide(); + this.parent = parent; + if (this.parent) { + this.show(); + } } + else { + this.parent = parent; + } + }; - this.currentTime.setCurrentTime(time); + /** + * Check whether this item is visible inside given range + * @returns {{start: Number, end: Number}} range with a timestamp for start and end + * @returns {boolean} True if visible + */ + Item.prototype.isVisible = function(range) { + // Should be implemented by Item implementations + return false; }; /** - * Get the current time. - * Only applicable when option `showCurrentTime` is true. - * @return {Date} Returns the current time. + * Show the Item in the DOM (when not already visible) + * @return {Boolean} changed */ - Core.prototype.getCurrentTime = function() { - if (!this.currentTime) { - throw new Error('Option showCurrentTime must be true'); - } + Item.prototype.show = function() { + return false; + }; - return this.currentTime.getCurrentTime(); + /** + * Hide the Item from the DOM (when visible) + * @return {Boolean} changed + */ + Item.prototype.hide = function() { + return false; }; /** - * Convert a position on screen (pixels) to a datetime - * @param {int} x Position on the screen in pixels - * @return {Date} time The datetime the corresponds with given position x - * @private + * Repaint the item */ - // TODO: move this function to Range - Core.prototype._toTime = function(x) { - return DateUtil.toTime(this, x, this.props.center.width); + Item.prototype.redraw = function() { + // should be implemented by the item }; /** - * Convert a position on the global screen (pixels) to a datetime - * @param {int} x Position on the screen in pixels - * @return {Date} time The datetime the corresponds with given position x - * @private + * Reposition the Item horizontally */ - // TODO: move this function to Range - Core.prototype._toGlobalTime = function(x) { - return DateUtil.toTime(this, x, this.props.root.width); - //var conversion = this.range.conversion(this.props.root.width); - //return new Date(x / conversion.scale + conversion.offset); + Item.prototype.repositionX = function() { + // should be implemented by the item }; /** - * Convert a datetime (Date object) into a position on the screen - * @param {Date} time A date - * @return {int} x The position on the screen in pixels which corresponds - * with the given date. - * @private + * Reposition the Item vertically */ - // TODO: move this function to Range - Core.prototype._toScreen = function(time) { - return DateUtil.toScreen(this, time, this.props.center.width); + Item.prototype.repositionY = function() { + // should be implemented by the item }; + /** + * Repaint a delete button on the top right of the item when the item is selected + * @param {HTMLElement} anchor + * @protected + */ + Item.prototype._repaintDeleteButton = function (anchor) { + if (this.selected && this.options.editable.remove && !this.dom.deleteButton) { + // create and show button + var me = this; + + var deleteButton = document.createElement('div'); + deleteButton.className = 'delete'; + deleteButton.title = 'Delete this item'; + + Hammer(deleteButton, { + preventDefault: true + }).on('tap', function (event) { + me.parent.removeFromDataSet(me); + event.stopPropagation(); + }); + anchor.appendChild(deleteButton); + this.dom.deleteButton = deleteButton; + } + else if (!this.selected && this.dom.deleteButton) { + // remove button + if (this.dom.deleteButton.parentNode) { + this.dom.deleteButton.parentNode.removeChild(this.dom.deleteButton); + } + this.dom.deleteButton = null; + } + }; /** - * Convert a datetime (Date object) into a position on the root - * This is used to get the pixel density estimate for the screen, not the center panel - * @param {Date} time A date - * @return {int} x The position on root in pixels which corresponds - * with the given date. + * Set HTML contents for the item + * @param {Element} element HTML element to fill with the contents * @private */ - // TODO: move this function to Range - Core.prototype._toGlobalScreen = function(time) { - return DateUtil.toScreen(this, time, this.props.root.width); - //var conversion = this.range.conversion(this.props.root.width); - //return (time.valueOf() - conversion.offset) * conversion.scale; - }; + Item.prototype._updateContents = function (element) { + var content; + if (this.options.template) { + var itemData = this.parent.itemSet.itemsData.get(this.id); // get a clone of the data from the dataset + content = this.options.template(itemData); + } + else { + content = this.data.content; + } + + if(content !== this.content) { + // only replace the content when changed + if (content instanceof Element) { + element.innerHTML = ''; + element.appendChild(content); + } + else if (content != undefined) { + element.innerHTML = content; + } + else { + if (!(this.data.type == 'background' && this.data.content === undefined)) { + throw new Error('Property "content" missing in item ' + this.id); + } + } + this.content = content; + } + }; /** - * Initialize watching when option autoResize is true + * Set HTML contents for the item + * @param {Element} element HTML element to fill with the contents * @private */ - Core.prototype._initAutoResize = function () { - if (this.options.autoResize == true) { - this._startAutoResize(); + Item.prototype._updateTitle = function (element) { + if (this.data.title != null) { + element.title = this.data.title || ''; } else { - this._stopAutoResize(); + element.removeAttribute('title'); } }; /** - * Watch for changes in the size of the container. On resize, the Panel will - * automatically redraw itself. + * Process dataAttributes timeline option and set as data- attributes on dom.content + * @param {Element} element HTML element to which the attributes will be attached * @private */ - Core.prototype._startAutoResize = function () { - var me = this; - - this._stopAutoResize(); + Item.prototype._updateDataAttributes = function(element) { + if (this.options.dataAttributes && this.options.dataAttributes.length > 0) { + var attributes = []; - this._onResize = function() { - if (me.options.autoResize != true) { - // stop watching when the option autoResize is changed to false - me._stopAutoResize(); + if (Array.isArray(this.options.dataAttributes)) { + attributes = this.options.dataAttributes; + } + else if (this.options.dataAttributes == 'all') { + attributes = Object.keys(this.data); + } + else { return; } - if (me.dom.root) { - // check whether the frame is resized - // Note: we compare offsetWidth here, not clientWidth. For some reason, - // IE does not restore the clientWidth from 0 to the actual width after - // changing the timeline's container display style from none to visible - if ((me.dom.root.offsetWidth != me.props.lastWidth) || - (me.dom.root.offsetHeight != me.props.lastHeight)) { - me.props.lastWidth = me.dom.root.offsetWidth; - me.props.lastHeight = me.dom.root.offsetHeight; + for (var i = 0; i < attributes.length; i++) { + var name = attributes[i]; + var value = this.data[name]; - me.emit('change'); + if (value != null) { + element.setAttribute('data-' + name, value); + } + else { + element.removeAttribute('data-' + name); } } - }; - - // add event listener to window resize - util.addEventListener(window, 'resize', this._onResize); - - this.watchTimer = setInterval(this._onResize, 1000); + } }; /** - * Stop watching for a resize of the frame. + * Update custom styles of the element + * @param element * @private */ - Core.prototype._stopAutoResize = function () { - if (this.watchTimer) { - clearInterval(this.watchTimer); - this.watchTimer = undefined; + Item.prototype._updateStyle = function(element) { + // remove old styles + if (this.style) { + util.removeCssText(element, this.style); + this.style = null; } - // remove event listener on window.resize - util.removeEventListener(window, 'resize', this._onResize); - this._onResize = null; + // append new styles + if (this.data.style) { + util.addCssText(element, this.data.style); + this.style = this.data.style; + } }; - /** - * Start moving the timeline vertically - * @param {Event} event - * @private - */ - Core.prototype._onTouch = function (event) { - this.touch.allowDragging = true; - }; + module.exports = Item; + + +/***/ }, +/* 32 */ +/***/ function(module, exports, __webpack_require__) { + + var Hammer = __webpack_require__(45); + var Item = __webpack_require__(31); + var BackgroundGroup = __webpack_require__(26); + var RangeItem = __webpack_require__(35); /** - * Start moving the timeline vertically - * @param {Event} event - * @private + * @constructor BackgroundItem + * @extends Item + * @param {Object} data Object containing parameters start, end + * content, className. + * @param {{toScreen: function, toTime: function}} conversion + * Conversion functions from time to screen and vice versa + * @param {Object} [options] Configuration options + * // TODO: describe options */ - Core.prototype._onPinch = function (event) { - this.touch.allowDragging = false; - }; + // TODO: implement support for the BackgroundItem just having a start, then being displayed as a sort of an annotation + function BackgroundItem (data, conversion, options) { + this.props = { + content: { + width: 0 + } + }; + this.overflow = false; // if contents can overflow (css styling), this flag is set to true + + // validate data + if (data) { + if (data.start == undefined) { + throw new Error('Property "start" missing in item ' + data.id); + } + if (data.end == undefined) { + throw new Error('Property "end" missing in item ' + data.id); + } + } + + Item.call(this, data, conversion, options); + + this.emptyContent = false; + } + + BackgroundItem.prototype = new Item (null, null, null); + + BackgroundItem.prototype.baseClassName = 'item background'; + BackgroundItem.prototype.stack = false; /** - * Start moving the timeline vertically - * @param {Event} event - * @private + * Check whether this item is visible inside given range + * @returns {{start: Number, end: Number}} range with a timestamp for start and end + * @returns {boolean} True if visible */ - Core.prototype._onDragStart = function (event) { - this.touch.initialScrollTop = this.props.scrollTop; + BackgroundItem.prototype.isVisible = function(range) { + // determine visibility + return (this.data.start < range.end) && (this.data.end > range.start); }; /** - * Move the timeline vertically - * @param {Event} event - * @private + * Repaint the item */ - Core.prototype._onDrag = function (event) { - // refuse to drag when we where pinching to prevent the timeline make a jump - // when releasing the fingers in opposite order from the touch screen - if (!this.touch.allowDragging) return; + BackgroundItem.prototype.redraw = function() { + var dom = this.dom; + if (!dom) { + // create DOM + this.dom = {}; + dom = this.dom; - var delta = event.gesture.deltaY; + // background box + dom.box = document.createElement('div'); + // className is updated in redraw() - var oldScrollTop = this._getScrollTop(); - var newScrollTop = this._setScrollTop(this.touch.initialScrollTop + delta); + // contents box + dom.content = document.createElement('div'); + dom.content.className = 'content'; + dom.box.appendChild(dom.content); + // Note: we do NOT attach this item as attribute to the DOM, + // such that background items cannot be selected + //dom.box['timeline-item'] = this; - if (newScrollTop != oldScrollTop) { - this.redraw(); // TODO: this causes two redraws when dragging, the other is triggered by rangechange already - this.emit("verticalDrag"); + this.dirty = true; + } + + // append DOM to parent DOM + if (!this.parent) { + throw new Error('Cannot redraw item: no parent attached'); + } + if (!dom.box.parentNode) { + var background = this.parent.dom.background; + if (!background) { + throw new Error('Cannot redraw item: parent has no background container element'); + } + background.appendChild(dom.box); + } + this.displayed = true; + + // Update DOM when item is marked dirty. An item is marked dirty when: + // - the item is not yet rendered + // - the item's data is changed + // - the item is selected/deselected + if (this.dirty) { + this._updateContents(this.dom.content); + this._updateTitle(this.dom.content); + this._updateDataAttributes(this.dom.content); + this._updateStyle(this.dom.box); + + // update class + var className = (this.data.className ? (' ' + this.data.className) : '') + + (this.selected ? ' selected' : ''); + dom.box.className = this.baseClassName + className; + + // determine from css whether this box has overflow + this.overflow = window.getComputedStyle(dom.content).overflow !== 'hidden'; + + // recalculate size + this.props.content.width = this.dom.content.offsetWidth; + this.height = 0; // set height zero, so this item will be ignored when stacking items + + this.dirty = false; } }; /** - * Apply a scrollTop - * @param {Number} scrollTop - * @returns {Number} scrollTop Returns the applied scrollTop - * @private + * Show the item in the DOM (when not already visible). The items DOM will + * be created when needed. */ - Core.prototype._setScrollTop = function (scrollTop) { - this.props.scrollTop = scrollTop; - this._updateScrollTop(); - return this.props.scrollTop; - }; + BackgroundItem.prototype.show = RangeItem.prototype.show; /** - * Update the current scrollTop when the height of the containers has been changed - * @returns {Number} scrollTop Returns the applied scrollTop - * @private + * Hide the item from the DOM (when visible) + * @return {Boolean} changed */ - Core.prototype._updateScrollTop = function () { - // recalculate the scrollTopMin - var scrollTopMin = Math.min(this.props.centerContainer.height - this.props.center.height, 0); // is negative or zero - if (scrollTopMin != this.props.scrollTopMin) { - // in case of bottom orientation, change the scrollTop such that the contents - // do not move relative to the time axis at the bottom - if (this.options.orientation == 'bottom') { - this.props.scrollTop += (scrollTopMin - this.props.scrollTopMin); + BackgroundItem.prototype.hide = RangeItem.prototype.hide; + + /** + * Reposition the item horizontally + * @Override + */ + BackgroundItem.prototype.repositionX = RangeItem.prototype.repositionX; + + /** + * Reposition the item vertically + * @Override + */ + BackgroundItem.prototype.repositionY = function(margin) { + var onTop = this.options.orientation === 'top'; + this.dom.content.style.top = onTop ? '' : '0'; + this.dom.content.style.bottom = onTop ? '0' : ''; + var height; + + // special positioning for subgroups + if (this.data.subgroup !== undefined) { + var itemSubgroup = this.data.subgroup; + var subgroups = this.parent.subgroups; + var subgroupIndex = subgroups[itemSubgroup].index; + // if the orientation is top, we need to take the difference in height into account. + if (onTop == true) { + // the first subgroup will have to account for the distance from the top to the first item. + height = this.parent.subgroups[itemSubgroup].height + margin.item.vertical; + height += subgroupIndex == 0 ? margin.axis - 0.5*margin.item.vertical : 0; + var newTop = this.parent.top; + for (var subgroup in subgroups) { + if (subgroups.hasOwnProperty(subgroup)) { + if (subgroups[subgroup].visible == true && subgroups[subgroup].index < subgroupIndex) { + newTop += subgroups[subgroup].height + margin.item.vertical; + } + } + } + + // the others will have to be offset downwards with this same distance. + newTop += subgroupIndex != 0 ? margin.axis - 0.5 * margin.item.vertical : 0; + this.dom.box.style.top = newTop + 'px'; + this.dom.box.style.bottom = ''; + } + // and when the orientation is bottom: + else { + var newTop = this.parent.top; + for (var subgroup in subgroups) { + if (subgroups.hasOwnProperty(subgroup)) { + if (subgroups[subgroup].visible == true && subgroups[subgroup].index > subgroupIndex) { + newTop += subgroups[subgroup].height + margin.item.vertical; + } + } + } + height = this.parent.subgroups[itemSubgroup].height + margin.item.vertical; + this.dom.box.style.top = newTop + 'px'; + this.dom.box.style.bottom = ''; } - this.props.scrollTopMin = scrollTopMin; } - - // limit the scrollTop to the feasible scroll range - if (this.props.scrollTop > 0) this.props.scrollTop = 0; - if (this.props.scrollTop < scrollTopMin) this.props.scrollTop = scrollTopMin; - - return this.props.scrollTop; - }; - - /** - * Get the current scrollTop - * @returns {number} scrollTop - * @private - */ - Core.prototype._getScrollTop = function () { - return this.props.scrollTop; + // and in the case of no subgroups: + else { + // we want backgrounds with groups to only show in groups. + if (this.parent instanceof BackgroundGroup) { + // if the item is not in a group: + height = Math.max(this.parent.height, + this.parent.itemSet.body.domProps.center.height, + this.parent.itemSet.body.domProps.centerContainer.height); + this.dom.box.style.top = onTop ? '0' : ''; + this.dom.box.style.bottom = onTop ? '' : '0'; + } + else { + height = this.parent.height; + // same alignment for items when orientation is top or bottom + this.dom.box.style.top = this.parent.top + 'px'; + this.dom.box.style.bottom = ''; + } + } + this.dom.box.style.height = height + 'px'; }; - module.exports = Core; + module.exports = BackgroundItem; /***/ }, -/* 26 */ +/* 33 */ /***/ function(module, exports, __webpack_require__) { - var Hammer = __webpack_require__(19); + var Item = __webpack_require__(31); var util = __webpack_require__(1); - var DataSet = __webpack_require__(7); - var DataView = __webpack_require__(9); - var Component = __webpack_require__(23); - var Group = __webpack_require__(27); - var BackgroundGroup = __webpack_require__(31); - var BoxItem = __webpack_require__(32); - var PointItem = __webpack_require__(33); - var RangeItem = __webpack_require__(29); - var BackgroundItem = __webpack_require__(34); - - - var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items - var BACKGROUND = '__background__'; // reserved group id for background items without group /** - * An ItemSet holds a set of items and ranges which can be displayed in a - * range. The width is determined by the parent of the ItemSet, and the height - * is determined by the size of the items. - * @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} body - * @param {Object} [options] See ItemSet.setOptions for the available options. - * @constructor ItemSet - * @extends Component + * @constructor BoxItem + * @extends Item + * @param {Object} data Object containing parameters start + * content, className. + * @param {{toScreen: function, toTime: function}} conversion + * Conversion functions from time to screen and vice versa + * @param {Object} [options] Configuration options + * // TODO: describe available options */ - function ItemSet(body, options) { - this.body = body; - - this.defaultOptions = { - type: null, // 'box', 'point', 'range', 'background' - orientation: 'bottom', // 'top' or 'bottom' - align: 'auto', // alignment of box items - stack: true, - groupOrder: null, - - selectable: true, - editable: { - updateTime: false, - updateGroup: false, - add: false, - remove: false - }, - - onAdd: function (item, callback) { - callback(item); - }, - onUpdate: function (item, callback) { - callback(item); - }, - onMove: function (item, callback) { - callback(item); - }, - onRemove: function (item, callback) { - callback(item); - }, - onMoving: function (item, callback) { - callback(item); - }, - - margin: { - item: { - horizontal: 10, - vertical: 10 - }, - axis: 20 - }, - padding: 5 - }; - - // options is shared by this ItemSet and all its items - this.options = util.extend({}, this.defaultOptions); - - // options for getting items from the DataSet with the correct type - this.itemOptions = { - type: {start: 'Date', end: 'Date'} - }; - - this.conversion = { - toScreen: body.util.toScreen, - toTime: body.util.toTime - }; - this.dom = {}; - this.props = {}; - this.hammer = null; - - var me = this; - this.itemsData = null; // DataSet - this.groupsData = null; // DataSet - - // listeners for the DataSet of the items - this.itemListeners = { - 'add': function (event, params, senderId) { - me._onAdd(params.items); - }, - 'update': function (event, params, senderId) { - me._onUpdate(params.items); + function BoxItem (data, conversion, options) { + this.props = { + dot: { + width: 0, + height: 0 }, - 'remove': function (event, params, senderId) { - me._onRemove(params.items); + line: { + width: 0, + height: 0 } }; - // listeners for the DataSet of the groups - this.groupListeners = { - 'add': function (event, params, senderId) { - me._onAddGroups(params.items); - }, - 'update': function (event, params, senderId) { - me._onUpdateGroups(params.items); - }, - 'remove': function (event, params, senderId) { - me._onRemoveGroups(params.items); + // validate data + if (data) { + if (data.start == undefined) { + throw new Error('Property "start" missing in item ' + data); } - }; - - this.items = {}; // object with an Item for every data item - this.groups = {}; // Group object for every group - this.groupIds = []; - - this.selection = []; // list with the ids of all selected nodes - this.stackDirty = true; // if true, all items will be restacked on next redraw - - this.touchParams = {}; // stores properties while dragging - // create the HTML DOM - - this._create(); + } - this.setOptions(options); + Item.call(this, data, conversion, options); } - ItemSet.prototype = new Component(); + BoxItem.prototype = new Item (null, null, null); - // available item types will be registered here - ItemSet.types = { - background: BackgroundItem, - box: BoxItem, - range: RangeItem, - point: PointItem + /** + * Check whether this item is visible inside given range + * @returns {{start: Number, end: Number}} range with a timestamp for start and end + * @returns {boolean} True if visible + */ + BoxItem.prototype.isVisible = function(range) { + // determine visibility + // TODO: account for the real width of the item. Right now we just add 1/4 to the window + var interval = (range.end - range.start) / 4; + return (this.data.start > range.start - interval) && (this.data.start < range.end + interval); }; /** - * Create the HTML DOM for the ItemSet + * Repaint the item */ - ItemSet.prototype._create = function(){ - var frame = document.createElement('div'); - frame.className = 'itemset'; - frame['timeline-itemset'] = this; - this.dom.frame = frame; + BoxItem.prototype.redraw = function() { + var dom = this.dom; + if (!dom) { + // create DOM + this.dom = {}; + dom = this.dom; - // create background panel - var background = document.createElement('div'); - background.className = 'background'; - frame.appendChild(background); - this.dom.background = background; + // create main box + dom.box = document.createElement('DIV'); - // create foreground panel - var foreground = document.createElement('div'); - foreground.className = 'foreground'; - frame.appendChild(foreground); - this.dom.foreground = foreground; + // contents box (inside the background box). used for making margins + dom.content = document.createElement('DIV'); + dom.content.className = 'content'; + dom.box.appendChild(dom.content); - // create axis panel - var axis = document.createElement('div'); - axis.className = 'axis'; - this.dom.axis = axis; + // line to axis + dom.line = document.createElement('DIV'); + dom.line.className = 'line'; - // create labelset - var labelSet = document.createElement('div'); - labelSet.className = 'labelset'; - this.dom.labelSet = labelSet; + // dot on axis + dom.dot = document.createElement('DIV'); + dom.dot.className = 'dot'; - // create ungrouped Group - this._updateUngrouped(); + // attach this item as attribute + dom.box['timeline-item'] = this; - // create background Group - var backgroundGroup = new BackgroundGroup(BACKGROUND, null, this); - backgroundGroup.show(); - this.groups[BACKGROUND] = backgroundGroup; + this.dirty = true; + } - // attach event listeners - // Note: we bind to the centerContainer for the case where the height - // of the center container is larger than of the ItemSet, so we - // can click in the empty area to create a new item or deselect an item. - this.hammer = Hammer(this.body.dom.centerContainer, { - preventDefault: true - }); + // append DOM to parent DOM + if (!this.parent) { + throw new Error('Cannot redraw item: no parent attached'); + } + if (!dom.box.parentNode) { + var foreground = this.parent.dom.foreground; + if (!foreground) throw new Error('Cannot redraw item: parent has no foreground container element'); + foreground.appendChild(dom.box); + } + if (!dom.line.parentNode) { + var background = this.parent.dom.background; + if (!background) throw new Error('Cannot redraw item: parent has no background container element'); + background.appendChild(dom.line); + } + if (!dom.dot.parentNode) { + var axis = this.parent.dom.axis; + if (!background) throw new Error('Cannot redraw item: parent has no axis container element'); + axis.appendChild(dom.dot); + } + this.displayed = true; - // drag items when selected - this.hammer.on('touch', this._onTouch.bind(this)); - this.hammer.on('dragstart', this._onDragStart.bind(this)); - this.hammer.on('drag', this._onDrag.bind(this)); - this.hammer.on('dragend', this._onDragEnd.bind(this)); + // Update DOM when item is marked dirty. An item is marked dirty when: + // - the item is not yet rendered + // - the item's data is changed + // - the item is selected/deselected + if (this.dirty) { + this._updateContents(this.dom.content); + this._updateTitle(this.dom.box); + this._updateDataAttributes(this.dom.box); + this._updateStyle(this.dom.box); - // single select (or unselect) when tapping an item - this.hammer.on('tap', this._onSelectItem.bind(this)); + // update class + var className = (this.data.className? ' ' + this.data.className : '') + + (this.selected ? ' selected' : ''); + dom.box.className = 'item box' + className; + dom.line.className = 'item line' + className; + dom.dot.className = 'item dot' + className; - // multi select when holding mouse/touch, or on ctrl+click - this.hammer.on('hold', this._onMultiSelectItem.bind(this)); + // recalculate size + this.props.dot.height = dom.dot.offsetHeight; + this.props.dot.width = dom.dot.offsetWidth; + this.props.line.width = dom.line.offsetWidth; + this.width = dom.box.offsetWidth; + this.height = dom.box.offsetHeight; - // add item on doubletap - this.hammer.on('doubletap', this._onAddItem.bind(this)); + this.dirty = false; + } - // attach to the DOM - this.show(); + this._repaintDeleteButton(dom.box); }; /** - * Set options for the ItemSet. Existing options will be extended/overwritten. - * @param {Object} [options] The following options are available: - * {String} type - * Default type for the items. Choose from 'box' - * (default), 'point', 'range', or 'background'. - * The default style can be overwritten by - * individual items. - * {String} align - * Alignment for the items, only applicable for - * BoxItem. Choose 'center' (default), 'left', or - * 'right'. - * {String} orientation - * Orientation of the item set. Choose 'top' or - * 'bottom' (default). - * {Function} groupOrder - * A sorting function for ordering groups - * {Boolean} stack - * If true (deafult), items will be stacked on - * top of each other. - * {Number} margin.axis - * Margin between the axis and the items in pixels. - * Default is 20. - * {Number} margin.item.horizontal - * Horizontal margin between items in pixels. - * Default is 10. - * {Number} margin.item.vertical - * Vertical Margin between items in pixels. - * Default is 10. - * {Number} margin.item - * Margin between items in pixels in both horizontal - * and vertical direction. Default is 10. - * {Number} margin - * Set margin for both axis and items in pixels. - * {Number} padding - * Padding of the contents of an item in pixels. - * Must correspond with the items css. Default is 5. - * {Boolean} selectable - * If true (default), items can be selected. - * {Boolean} editable - * Set all editable options to true or false - * {Boolean} editable.updateTime - * Allow dragging an item to an other moment in time - * {Boolean} editable.updateGroup - * Allow dragging an item to an other group - * {Boolean} editable.add - * Allow creating new items on double tap - * {Boolean} editable.remove - * Allow removing items by clicking the delete button - * top right of a selected item. - * {Function(item: Item, callback: Function)} onAdd - * Callback function triggered when an item is about to be added: - * when the user double taps an empty space in the Timeline. - * {Function(item: Item, callback: Function)} onUpdate - * Callback function fired when an item is about to be updated. - * This function typically has to show a dialog where the user - * change the item. If not implemented, nothing happens. - * {Function(item: Item, callback: Function)} onMove - * Fired when an item has been moved. If not implemented, - * the move action will be accepted. - * {Function(item: Item, callback: Function)} onRemove - * Fired when an item is about to be deleted. - * If not implemented, the item will be always removed. + * Show the item in the DOM (when not already displayed). The items DOM will + * be created when needed. */ - ItemSet.prototype.setOptions = function(options) { - if (options) { - // copy all options that we know - var fields = ['type', 'align', 'orientation', 'padding', 'stack', 'selectable', 'groupOrder', 'dataAttributes', 'template','hide']; - util.selectiveExtend(fields, this.options, options); - - if ('margin' in options) { - if (typeof options.margin === 'number') { - this.options.margin.axis = options.margin; - this.options.margin.item.horizontal = options.margin; - this.options.margin.item.vertical = options.margin; - } - else if (typeof options.margin === 'object') { - util.selectiveExtend(['axis'], this.options.margin, options.margin); - if ('item' in options.margin) { - if (typeof options.margin.item === 'number') { - this.options.margin.item.horizontal = options.margin.item; - this.options.margin.item.vertical = options.margin.item; - } - else if (typeof options.margin.item === 'object') { - util.selectiveExtend(['horizontal', 'vertical'], this.options.margin.item, options.margin.item); - } - } - } - } - - if ('editable' in options) { - if (typeof options.editable === 'boolean') { - this.options.editable.updateTime = options.editable; - this.options.editable.updateGroup = options.editable; - this.options.editable.add = options.editable; - this.options.editable.remove = options.editable; - } - else if (typeof options.editable === 'object') { - util.selectiveExtend(['updateTime', 'updateGroup', 'add', 'remove'], this.options.editable, options.editable); - } - } - - // callback functions - var addCallback = (function (name) { - var fn = options[name]; - if (fn) { - if (!(fn instanceof Function)) { - throw new Error('option ' + name + ' must be a function ' + name + '(item, callback)'); - } - this.options[name] = fn; - } - }).bind(this); - ['onAdd', 'onUpdate', 'onRemove', 'onMove', 'onMoving'].forEach(addCallback); - - // force the itemSet to refresh: options like orientation and margins may be changed - this.markDirty(); + BoxItem.prototype.show = function() { + if (!this.displayed) { + this.redraw(); } }; /** - * Mark the ItemSet dirty so it will refresh everything with next redraw + * Hide the item from the DOM (when visible) */ - ItemSet.prototype.markDirty = function() { - this.groupIds = []; - this.stackDirty = true; - }; + BoxItem.prototype.hide = function() { + if (this.displayed) { + var dom = this.dom; - /** - * Destroy the ItemSet - */ - ItemSet.prototype.destroy = function() { - this.hide(); - this.setItems(null); - this.setGroups(null); + if (dom.box.parentNode) dom.box.parentNode.removeChild(dom.box); + if (dom.line.parentNode) dom.line.parentNode.removeChild(dom.line); + if (dom.dot.parentNode) dom.dot.parentNode.removeChild(dom.dot); - this.hammer = null; + this.top = null; + this.left = null; - this.body = null; - this.conversion = null; + this.displayed = false; + } }; /** - * Hide the component from the DOM + * Reposition the item horizontally + * @Override */ - ItemSet.prototype.hide = function() { - // remove the frame containing the items - if (this.dom.frame.parentNode) { - this.dom.frame.parentNode.removeChild(this.dom.frame); - } + BoxItem.prototype.repositionX = function() { + var start = this.conversion.toScreen(this.data.start); + var align = this.options.align; + var left; + var box = this.dom.box; + var line = this.dom.line; + var dot = this.dom.dot; - // remove the axis with dots - if (this.dom.axis.parentNode) { - this.dom.axis.parentNode.removeChild(this.dom.axis); + // calculate left position of the box + if (align == 'right') { + this.left = start - this.width; } - - // remove the labelset containing all group labels - if (this.dom.labelSet.parentNode) { - this.dom.labelSet.parentNode.removeChild(this.dom.labelSet); + else if (align == 'left') { + this.left = start; } - }; - - /** - * Show the component in the DOM (when not already visible). - * @return {Boolean} changed - */ - ItemSet.prototype.show = function() { - // show frame containing the items - if (!this.dom.frame.parentNode) { - this.body.dom.center.appendChild(this.dom.frame); + else { + // default or 'center' + this.left = start - this.width / 2; } - // show axis with dots - if (!this.dom.axis.parentNode) { - this.body.dom.backgroundVertical.appendChild(this.dom.axis); - } + // reposition box + box.style.left = this.left + 'px'; - // show labelset containing labels - if (!this.dom.labelSet.parentNode) { - this.body.dom.left.appendChild(this.dom.labelSet); - } + // reposition line + line.style.left = (start - this.props.line.width / 2) + 'px'; + + // reposition dot + dot.style.left = (start - this.props.dot.width / 2) + 'px'; }; /** - * Set selected items by their id. Replaces the current selection - * Unknown id's are silently ignored. - * @param {string[] | string} [ids] An array with zero or more id's of the items to be - * selected, or a single item id. If ids is undefined - * or an empty array, all items will be unselected. + * Reposition the item vertically + * @Override */ - ItemSet.prototype.setSelection = function(ids) { - var i, ii, id, item; + BoxItem.prototype.repositionY = function() { + var orientation = this.options.orientation; + var box = this.dom.box; + var line = this.dom.line; + var dot = this.dom.dot; - if (ids == undefined) ids = []; - if (!Array.isArray(ids)) ids = [ids]; + if (orientation == 'top') { + box.style.top = (this.top || 0) + 'px'; - // unselect currently selected items - for (i = 0, ii = this.selection.length; i < ii; i++) { - id = this.selection[i]; - item = this.items[id]; - if (item) item.unselect(); + line.style.top = '0'; + line.style.height = (this.parent.top + this.top + 1) + 'px'; + line.style.bottom = ''; } + else { // orientation 'bottom' + var itemSetHeight = this.parent.itemSet.props.height; // TODO: this is nasty + var lineHeight = itemSetHeight - this.parent.top - this.parent.height + this.top; - // select items - this.selection = []; - for (i = 0, ii = ids.length; i < ii; i++) { - id = ids[i]; - item = this.items[id]; - if (item) { - this.selection.push(id); - item.select(); - } + box.style.top = (this.parent.height - this.top - this.height || 0) + 'px'; + line.style.top = (itemSetHeight - lineHeight) + 'px'; + line.style.bottom = '0'; } - }; - /** - * Get the selected items by their id - * @return {Array} ids The ids of the selected items - */ - ItemSet.prototype.getSelection = function() { - return this.selection.concat([]); + dot.style.top = (-this.props.dot.height / 2) + 'px'; }; + module.exports = BoxItem; + + +/***/ }, +/* 34 */ +/***/ function(module, exports, __webpack_require__) { + + var Item = __webpack_require__(31); + /** - * Get the id's of the currently visible items. - * @returns {Array} The ids of the visible items + * @constructor PointItem + * @extends Item + * @param {Object} data Object containing parameters start + * content, className. + * @param {{toScreen: function, toTime: function}} conversion + * Conversion functions from time to screen and vice versa + * @param {Object} [options] Configuration options + * // TODO: describe available options */ - ItemSet.prototype.getVisibleItems = function() { - var range = this.body.range.getRange(); - var left = this.body.util.toScreen(range.start); - var right = this.body.util.toScreen(range.end); - - var ids = []; - for (var groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - var group = this.groups[groupId]; - var rawVisibleItems = group.visibleItems; + function PointItem (data, conversion, options) { + this.props = { + dot: { + top: 0, + width: 0, + height: 0 + }, + content: { + height: 0, + marginLeft: 0 + } + }; - // filter the "raw" set with visibleItems into a set which is really - // visible by pixels - for (var i = 0; i < rawVisibleItems.length; i++) { - var item = rawVisibleItems[i]; - // TODO: also check whether visible vertically - if ((item.left < right) && (item.left + item.width > left)) { - ids.push(item.id); - } - } + // validate data + if (data) { + if (data.start == undefined) { + throw new Error('Property "start" missing in item ' + data); } } - return ids; - }; + Item.call(this, data, conversion, options); + } + + PointItem.prototype = new Item (null, null, null); /** - * Deselect a selected item - * @param {String | Number} id - * @private + * Check whether this item is visible inside given range + * @returns {{start: Number, end: Number}} range with a timestamp for start and end + * @returns {boolean} True if visible */ - ItemSet.prototype._deselect = function(id) { - var selection = this.selection; - for (var i = 0, ii = selection.length; i < ii; i++) { - if (selection[i] == id) { // non-strict comparison! - selection.splice(i, 1); - break; - } - } + PointItem.prototype.isVisible = function(range) { + // determine visibility + // TODO: account for the real width of the item. Right now we just add 1/4 to the window + var interval = (range.end - range.start) / 4; + return (this.data.start > range.start - interval) && (this.data.start < range.end + interval); }; /** - * Repaint the component - * @return {boolean} Returns true if the component is resized + * Repaint the item */ - ItemSet.prototype.redraw = function() { - var margin = this.options.margin, - range = this.body.range, - asSize = util.option.asSize, - options = this.options, - orientation = options.orientation, - resized = false, - frame = this.dom.frame, - editable = options.editable.updateTime || options.editable.updateGroup; + PointItem.prototype.redraw = function() { + var dom = this.dom; + if (!dom) { + // create DOM + this.dom = {}; + dom = this.dom; - // recalculate absolute position (before redrawing groups) - this.props.top = this.body.domProps.top.height + this.body.domProps.border.top; - this.props.left = this.body.domProps.left.width + this.body.domProps.border.left; + // background box + dom.point = document.createElement('div'); + // className is updated in redraw() - // update class name - frame.className = 'itemset' + (editable ? ' editable' : ''); + // contents box, right from the dot + dom.content = document.createElement('div'); + dom.content.className = 'content'; + dom.point.appendChild(dom.content); - // reorder the groups (if needed) - resized = this._orderGroups() || resized; + // dot at start + dom.dot = document.createElement('div'); + dom.point.appendChild(dom.dot); - // check whether zoomed (in that case we need to re-stack everything) - // TODO: would be nicer to get this as a trigger from Range - var visibleInterval = range.end - range.start; - var zoomed = (visibleInterval != this.lastVisibleInterval) || (this.props.width != this.props.lastWidth); - if (zoomed) this.stackDirty = true; - this.lastVisibleInterval = visibleInterval; - this.props.lastWidth = this.props.width; + // attach this item as attribute + dom.point['timeline-item'] = this; - var restack = this.stackDirty; - var firstGroup = this._firstGroup(); - var firstMargin = { - item: margin.item, - axis: margin.axis - }; - var nonFirstMargin = { - item: margin.item, - axis: margin.item.vertical / 2 - }; - var height = 0; - var minHeight = margin.axis + margin.item.vertical; + this.dirty = true; + } - // redraw the background group - this.groups[BACKGROUND].redraw(range, nonFirstMargin, restack); + // append DOM to parent DOM + if (!this.parent) { + throw new Error('Cannot redraw item: no parent attached'); + } + if (!dom.point.parentNode) { + var foreground = this.parent.dom.foreground; + if (!foreground) { + throw new Error('Cannot redraw item: parent has no foreground container element'); + } + foreground.appendChild(dom.point); + } + this.displayed = true; - // redraw all regular groups - util.forEach(this.groups, function (group) { - var groupMargin = (group == firstGroup) ? firstMargin : nonFirstMargin; - var groupResized = group.redraw(range, groupMargin, restack); - resized = groupResized || resized; - height += group.height; - }); - height = Math.max(height, minHeight); - this.stackDirty = false; + // Update DOM when item is marked dirty. An item is marked dirty when: + // - the item is not yet rendered + // - the item's data is changed + // - the item is selected/deselected + if (this.dirty) { + this._updateContents(this.dom.content); + this._updateTitle(this.dom.point); + this._updateDataAttributes(this.dom.point); + this._updateStyle(this.dom.point); - // update frame height - frame.style.height = asSize(height); + // update class + var className = (this.data.className? ' ' + this.data.className : '') + + (this.selected ? ' selected' : ''); + dom.point.className = 'item point' + className; + dom.dot.className = 'item dot' + className; - // calculate actual size - this.props.width = frame.offsetWidth; - this.props.height = height; + // recalculate size + this.width = dom.point.offsetWidth; + this.height = dom.point.offsetHeight; + this.props.dot.width = dom.dot.offsetWidth; + this.props.dot.height = dom.dot.offsetHeight; + this.props.content.height = dom.content.offsetHeight; - // reposition axis - this.dom.axis.style.top = asSize((orientation == 'top') ? - (this.body.domProps.top.height + this.body.domProps.border.top) : - (this.body.domProps.top.height + this.body.domProps.centerContainer.height)); - this.dom.axis.style.left = '0'; + // resize contents + dom.content.style.marginLeft = 2 * this.props.dot.width + 'px'; + //dom.content.style.marginRight = ... + 'px'; // TODO: margin right - // check if this component is resized - resized = this._isResized() || resized; + dom.dot.style.top = ((this.height - this.props.dot.height) / 2) + 'px'; + dom.dot.style.left = (this.props.dot.width / 2) + 'px'; - return resized; + this.dirty = false; + } + + this._repaintDeleteButton(dom.point); }; /** - * Get the first group, aligned with the axis - * @return {Group | null} firstGroup - * @private + * Show the item in the DOM (when not already visible). The items DOM will + * be created when needed. */ - ItemSet.prototype._firstGroup = function() { - var firstGroupIndex = (this.options.orientation == 'top') ? 0 : (this.groupIds.length - 1); - var firstGroupId = this.groupIds[firstGroupIndex]; - var firstGroup = this.groups[firstGroupId] || this.groups[UNGROUPED]; - - return firstGroup || null; + PointItem.prototype.show = function() { + if (!this.displayed) { + this.redraw(); + } }; /** - * Create or delete the group holding all ungrouped items. This group is used when - * there are no groups specified. - * @protected + * Hide the item from the DOM (when visible) */ - ItemSet.prototype._updateUngrouped = function() { - var ungrouped = this.groups[UNGROUPED]; - var background = this.groups[BACKGROUND]; - var item, itemId; - - if (this.groupsData) { - // remove the group holding all ungrouped items - if (ungrouped) { - ungrouped.hide(); - delete this.groups[UNGROUPED]; - - for (itemId in this.items) { - if (this.items.hasOwnProperty(itemId)) { - item = this.items[itemId]; - item.parent && item.parent.remove(item); - var groupId = this._getGroupId(item.data); - var group = this.groups[groupId]; - group && group.add(item) || item.hide(); - } - } + PointItem.prototype.hide = function() { + if (this.displayed) { + if (this.dom.point.parentNode) { + this.dom.point.parentNode.removeChild(this.dom.point); } - } - else { - // create a group holding all (unfiltered) items - if (!ungrouped) { - var id = null; - var data = null; - ungrouped = new Group(id, data, this); - this.groups[UNGROUPED] = ungrouped; - for (itemId in this.items) { - if (this.items.hasOwnProperty(itemId)) { - item = this.items[itemId]; - ungrouped.add(item); - } - } + this.top = null; + this.left = null; - ungrouped.show(); - } + this.displayed = false; } }; /** - * Get the element for the labelset - * @return {HTMLElement} labelSet + * Reposition the item horizontally + * @Override */ - ItemSet.prototype.getLabelSet = function() { - return this.dom.labelSet; + PointItem.prototype.repositionX = function() { + var start = this.conversion.toScreen(this.data.start); + + this.left = start - this.props.dot.width; + + // reposition point + this.dom.point.style.left = this.left + 'px'; }; /** - * Set items - * @param {vis.DataSet | null} items + * Reposition the item vertically + * @Override */ - ItemSet.prototype.setItems = function(items) { - var me = this, - ids, - oldItemsData = this.itemsData; + PointItem.prototype.repositionY = function() { + var orientation = this.options.orientation, + point = this.dom.point; - // replace the dataset - if (!items) { - this.itemsData = null; - } - else if (items instanceof DataSet || items instanceof DataView) { - this.itemsData = items; + if (orientation == 'top') { + point.style.top = this.top + 'px'; } else { - throw new TypeError('Data must be an instance of DataSet or DataView'); + point.style.top = (this.parent.height - this.top - this.height) + 'px'; } + }; - if (oldItemsData) { - // unsubscribe from old dataset - util.forEach(this.itemListeners, function (callback, event) { - oldItemsData.off(event, callback); - }); + module.exports = PointItem; - // remove all drawn items - ids = oldItemsData.getIds(); - this._onRemove(ids); - } - if (this.itemsData) { - // subscribe to new dataset - var id = this.id; - util.forEach(this.itemListeners, function (callback, event) { - me.itemsData.on(event, callback, id); - }); +/***/ }, +/* 35 */ +/***/ function(module, exports, __webpack_require__) { - // add all new items - ids = this.itemsData.getIds(); - this._onAdd(ids); + var Hammer = __webpack_require__(45); + var Item = __webpack_require__(31); - // update the group holding all ungrouped items - this._updateUngrouped(); + /** + * @constructor RangeItem + * @extends Item + * @param {Object} data Object containing parameters start, end + * content, className. + * @param {{toScreen: function, toTime: function}} conversion + * Conversion functions from time to screen and vice versa + * @param {Object} [options] Configuration options + * // TODO: describe options + */ + function RangeItem (data, conversion, options) { + this.props = { + content: { + width: 0 + } + }; + this.overflow = false; // if contents can overflow (css styling), this flag is set to true + + // validate data + if (data) { + if (data.start == undefined) { + throw new Error('Property "start" missing in item ' + data.id); + } + if (data.end == undefined) { + throw new Error('Property "end" missing in item ' + data.id); + } } - }; + + Item.call(this, data, conversion, options); + } + + RangeItem.prototype = new Item (null, null, null); + + RangeItem.prototype.baseClassName = 'item range'; /** - * Get the current items - * @returns {vis.DataSet | null} + * Check whether this item is visible inside given range + * @returns {{start: Number, end: Number}} range with a timestamp for start and end + * @returns {boolean} True if visible */ - ItemSet.prototype.getItems = function() { - return this.itemsData; + RangeItem.prototype.isVisible = function(range) { + // determine visibility + return (this.data.start < range.end) && (this.data.end > range.start); }; /** - * Set groups - * @param {vis.DataSet} groups + * Repaint the item */ - ItemSet.prototype.setGroups = function(groups) { - var me = this, - ids; + RangeItem.prototype.redraw = function() { + var dom = this.dom; + if (!dom) { + // create DOM + this.dom = {}; + dom = this.dom; - // unsubscribe from current dataset - if (this.groupsData) { - util.forEach(this.groupListeners, function (callback, event) { - me.groupsData.unsubscribe(event, callback); - }); + // background box + dom.box = document.createElement('div'); + // className is updated in redraw() - // remove all drawn groups - ids = this.groupsData.getIds(); - this.groupsData = null; - this._onRemoveGroups(ids); // note: this will cause a redraw - } + // contents box + dom.content = document.createElement('div'); + dom.content.className = 'content'; + dom.box.appendChild(dom.content); - // replace the dataset - if (!groups) { - this.groupsData = null; + // attach this item as attribute + dom.box['timeline-item'] = this; + + this.dirty = true; } - else if (groups instanceof DataSet || groups instanceof DataView) { - this.groupsData = groups; + + // append DOM to parent DOM + if (!this.parent) { + throw new Error('Cannot redraw item: no parent attached'); } - else { - throw new TypeError('Data must be an instance of DataSet or DataView'); + if (!dom.box.parentNode) { + var foreground = this.parent.dom.foreground; + if (!foreground) { + throw new Error('Cannot redraw item: parent has no foreground container element'); + } + foreground.appendChild(dom.box); } + this.displayed = true; - if (this.groupsData) { - // subscribe to new dataset - var id = this.id; - util.forEach(this.groupListeners, function (callback, event) { - me.groupsData.on(event, callback, id); - }); + // Update DOM when item is marked dirty. An item is marked dirty when: + // - the item is not yet rendered + // - the item's data is changed + // - the item is selected/deselected + if (this.dirty) { + this._updateContents(this.dom.content); + this._updateTitle(this.dom.box); + this._updateDataAttributes(this.dom.box); + this._updateStyle(this.dom.box); - // draw all ms - ids = this.groupsData.getIds(); - this._onAddGroups(ids); - } + // update class + var className = (this.data.className ? (' ' + this.data.className) : '') + + (this.selected ? ' selected' : ''); + dom.box.className = this.baseClassName + className; - // update the group holding all ungrouped items - this._updateUngrouped(); + // determine from css whether this box has overflow + this.overflow = window.getComputedStyle(dom.content).overflow !== 'hidden'; + + // recalculate size + // turn off max-width to be able to calculate the real width + // this causes an extra browser repaint/reflow, but so be it + this.dom.content.style.maxWidth = 'none'; + this.props.content.width = this.dom.content.offsetWidth; + this.height = this.dom.box.offsetHeight; + this.dom.content.style.maxWidth = ''; - // update the order of all items in each group - this._order(); + this.dirty = false; + } - this.body.emitter.emit('change', {queue: true}); + this._repaintDeleteButton(dom.box); + this._repaintDragLeft(); + this._repaintDragRight(); }; /** - * Get the current groups - * @returns {vis.DataSet | null} groups + * Show the item in the DOM (when not already visible). The items DOM will + * be created when needed. */ - ItemSet.prototype.getGroups = function() { - return this.groupsData; + RangeItem.prototype.show = function() { + if (!this.displayed) { + this.redraw(); + } }; /** - * Remove an item by its id - * @param {String | Number} id + * Hide the item from the DOM (when visible) + * @return {Boolean} changed */ - ItemSet.prototype.removeItem = function(id) { - var item = this.itemsData.get(id), - dataset = this.itemsData.getDataSet(); + RangeItem.prototype.hide = function() { + if (this.displayed) { + var box = this.dom.box; - if (item) { - // confirm deletion - this.options.onRemove(item, function (item) { - if (item) { - // remove by id here, it is possible that an item has no id defined - // itself, so better not delete by the item itself - dataset.remove(id); - } - }); + if (box.parentNode) { + box.parentNode.removeChild(box); + } + + this.top = null; + this.left = null; + + this.displayed = false; } }; /** - * Get the time of an item based on it's data and options.type - * @param {Object} itemData - * @returns {string} Returns the type - * @private + * Reposition the item horizontally + * @Override */ - ItemSet.prototype._getType = function (itemData) { - return itemData.type || this.options.type || (itemData.end ? 'range' : 'box'); - }; + RangeItem.prototype.repositionX = function() { + var parentWidth = this.parent.width; + var start = this.conversion.toScreen(this.data.start); + var end = this.conversion.toScreen(this.data.end); + var contentLeft; + var contentWidth; + // limit the width of the this, as browsers cannot draw very wide divs + if (start < -parentWidth) { + start = -parentWidth; + } + if (end > 2 * parentWidth) { + end = 2 * parentWidth; + } + var boxWidth = Math.max(end - start, 1); - /** - * Get the group id for an item - * @param {Object} itemData - * @returns {string} Returns the groupId - * @private - */ - ItemSet.prototype._getGroupId = function (itemData) { - var type = this._getType(itemData); - if (type == 'background' && itemData.group == undefined) { - return BACKGROUND; + if (this.overflow) { + this.left = start; + this.width = boxWidth + this.props.content.width; + contentWidth = this.props.content.width; + + // Note: The calculation of width is an optimistic calculation, giving + // a width which will not change when moving the Timeline + // So no re-stacking needed, which is nicer for the eye; } else { - return this.groupsData ? itemData.group : UNGROUPED; + this.left = start; + this.width = boxWidth; + contentWidth = Math.min(end - start - 2 * this.options.padding, this.props.content.width); } - }; - /** - * Handle updated items - * @param {Number[]} ids - * @protected - */ - ItemSet.prototype._onUpdate = function(ids) { - var me = this; + this.dom.box.style.left = this.left + 'px'; + this.dom.box.style.width = boxWidth + 'px'; - ids.forEach(function (id) { - var itemData = me.itemsData.get(id, me.itemOptions); - var item = me.items[id]; - var type = me._getType(itemData); + switch (this.options.align) { + case 'left': + this.dom.content.style.left = '0'; + break; - var constructor = ItemSet.types[type]; + case 'right': + this.dom.content.style.left = Math.max((boxWidth - contentWidth - 2 * this.options.padding), 0) + 'px'; + break; - if (item) { - // update item - if (!constructor || !(item instanceof constructor)) { - // item type has changed, delete the item and recreate it - me._removeItem(item); - item = null; - } - else { - me._updateItem(item, itemData); - } - } + case 'center': + this.dom.content.style.left = Math.max((boxWidth - contentWidth - 2 * this.options.padding) / 2, 0) + 'px'; + break; - if (!item) { - // create item - if (constructor) { - item = new constructor(itemData, me.conversion, me.options); - item.id = id; // TODO: not so nice setting id afterwards - me._addItem(item); - } - else if (type == 'rangeoverflow') { - // TODO: deprecated since version 2.1.0 (or 3.0.0?). cleanup some day - throw new TypeError('Item type "rangeoverflow" is deprecated. Use css styling instead: ' + - '.vis.timeline .item.range .content {overflow: visible;}'); + default: // 'auto' + // when range exceeds left of the window, position the contents at the left of the visible area + if (this.overflow) { + if (end > 0) { + contentLeft = Math.max(-start, 0); + } + else { + contentLeft = -contentWidth; // ensure it's not visible anymore + } } else { - throw new TypeError('Unknown item type "' + type + '"'); + if (start < 0) { + contentLeft = Math.min(-start, + (end - start - contentWidth - 2 * this.options.padding)); + // TODO: remove the need for options.padding. it's terrible. + } + else { + contentLeft = 0; + } } - } - }); - - this._order(); - this.stackDirty = true; // force re-stacking of all items next redraw - this.body.emitter.emit('change', {queue: true}); + this.dom.content.style.left = contentLeft + 'px'; + } }; /** - * Handle added items - * @param {Number[]} ids - * @protected + * Reposition the item vertically + * @Override */ - ItemSet.prototype._onAdd = ItemSet.prototype._onUpdate; + RangeItem.prototype.repositionY = function() { + var orientation = this.options.orientation, + box = this.dom.box; + + if (orientation == 'top') { + box.style.top = this.top + 'px'; + } + else { + box.style.top = (this.parent.height - this.top - this.height) + 'px'; + } + }; /** - * Handle removed items - * @param {Number[]} ids + * Repaint a drag area on the left side of the range when the range is selected * @protected */ - ItemSet.prototype._onRemove = function(ids) { - var count = 0; - var me = this; - ids.forEach(function (id) { - var item = me.items[id]; - if (item) { - count++; - me._removeItem(item); - } - }); + RangeItem.prototype._repaintDragLeft = function () { + if (this.selected && this.options.editable.updateTime && !this.dom.dragLeft) { + // create and show drag area + var dragLeft = document.createElement('div'); + dragLeft.className = 'drag-left'; + dragLeft.dragLeftItem = this; - if (count) { - // update order - this._order(); - this.stackDirty = true; // force re-stacking of all items next redraw - this.body.emitter.emit('change', {queue: true}); + // TODO: this should be redundant? + Hammer(dragLeft, { + preventDefault: true + }).on('drag', function () { + //console.log('drag left') + }); + + this.dom.box.appendChild(dragLeft); + this.dom.dragLeft = dragLeft; + } + else if (!this.selected && this.dom.dragLeft) { + // delete drag area + if (this.dom.dragLeft.parentNode) { + this.dom.dragLeft.parentNode.removeChild(this.dom.dragLeft); + } + this.dom.dragLeft = null; } }; /** - * Update the order of item in all groups - * @private + * Repaint a drag area on the right side of the range when the range is selected + * @protected */ - ItemSet.prototype._order = function() { - // reorder the items in all groups - // TODO: optimization: only reorder groups affected by the changed items - util.forEach(this.groups, function (group) { - group.order(); - }); - }; + RangeItem.prototype._repaintDragRight = function () { + if (this.selected && this.options.editable.updateTime && !this.dom.dragRight) { + // create and show drag area + var dragRight = document.createElement('div'); + dragRight.className = 'drag-right'; + dragRight.dragRightItem = this; - /** - * Handle updated groups - * @param {Number[]} ids - * @private - */ - ItemSet.prototype._onUpdateGroups = function(ids) { - this._onAddGroups(ids); + // TODO: this should be redundant? + Hammer(dragRight, { + preventDefault: true + }).on('drag', function () { + //console.log('drag right') + }); + + this.dom.box.appendChild(dragRight); + this.dom.dragRight = dragRight; + } + else if (!this.selected && this.dom.dragRight) { + // delete drag area + if (this.dom.dragRight.parentNode) { + this.dom.dragRight.parentNode.removeChild(this.dom.dragRight); + } + this.dom.dragRight = null; + } }; + module.exports = RangeItem; + + +/***/ }, +/* 36 */ +/***/ function(module, exports, __webpack_require__) { + + var Emitter = __webpack_require__(56); + var Hammer = __webpack_require__(45); + var keycharm = __webpack_require__(59); + var util = __webpack_require__(1); + var hammerUtil = __webpack_require__(47); + var DataSet = __webpack_require__(3); + var DataView = __webpack_require__(4); + var dotparser = __webpack_require__(42); + var gephiParser = __webpack_require__(43); + var Groups = __webpack_require__(38); + var Images = __webpack_require__(39); + var Node = __webpack_require__(40); + var Edge = __webpack_require__(37); + var Popup = __webpack_require__(41); + var MixinLoader = __webpack_require__(54); + var Activator = __webpack_require__(55); + var locales = __webpack_require__(52); + + // Load custom shapes into CanvasRenderingContext2D + __webpack_require__(53); + /** - * Handle changed groups (added or updated) - * @param {Number[]} ids - * @private + * @constructor Network + * Create a network visualization, displaying nodes and edges. + * + * @param {Element} container The DOM element in which the Network will + * be created. Normally a div element. + * @param {Object} data An object containing parameters + * {Array} nodes + * {Array} edges + * @param {Object} options Options */ - ItemSet.prototype._onAddGroups = function(ids) { - var me = this; + function Network (container, data, options) { + if (!(this instanceof Network)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } - ids.forEach(function (id) { - var groupData = me.groupsData.get(id); - var group = me.groups[id]; + this._determineBrowserMethod(); + this._initializeMixinLoaders(); - if (!group) { - // check for reserved ids - if (id == UNGROUPED || id == BACKGROUND) { - throw new Error('Illegal group id. ' + id + ' is a reserved id.'); - } + // create variables and set default values + this.containerElement = container; - var groupOptions = Object.create(me.options); - util.extend(groupOptions, { - height: null - }); + // render and calculation settings + this.renderRefreshRate = 60; // hz (fps) + this.renderTimestep = 1000 / this.renderRefreshRate; // ms -- saves calculation later on + this.renderTime = 0; // measured time it takes to render a frame + this.physicsTime = 0; // measured time it takes to render a frame + this.runDoubleSpeed = false; + this.physicsDiscreteStepsize = 0.50; // discrete stepsize of the simulation - group = new Group(id, groupData, me); - me.groups[id] = group; + this.initializing = true; - // add items with this groupId to the new group - for (var itemId in me.items) { - if (me.items.hasOwnProperty(itemId)) { - var item = me.items[itemId]; - if (item.data.group == id) { - group.add(item); - } + this.triggerFunctions = {add:null,edit:null,editEdge:null,connect:null,del:null}; + + // set constant values + this.defaultOptions = { + nodes: { + mass: 1, + radiusMin: 10, + radiusMax: 30, + radius: 10, + shape: 'ellipse', + image: undefined, + widthMin: 16, // px + widthMax: 64, // px + fontColor: 'black', + fontSize: 14, // px + fontFace: 'verdana', + fontFill: undefined, + fontStrokeWidth: 0, // px + fontStrokeColor: 'white', + level: -1, + color: { + border: '#2B7CE9', + background: '#97C2FC', + highlight: { + border: '#2B7CE9', + background: '#D2E5FF' + }, + hover: { + border: '#2B7CE9', + background: '#D2E5FF' } + }, + group: undefined, + borderWidth: 1, + borderWidthSelected: undefined + }, + edges: { + widthMin: 1, // + widthMax: 15,// + width: 1, + widthSelectionMultiplier: 2, + hoverWidth: 1.5, + style: 'line', + color: { + color:'#848484', + highlight:'#848484', + hover: '#848484' + }, + fontColor: '#343434', + fontSize: 14, // px + fontFace: 'arial', + fontFill: 'white', + fontStrokeWidth: 0, // px + fontStrokeColor: 'white', + labelAlignment:'horizontal', + arrowScaleFactor: 1, + dash: { + length: 10, + gap: 5, + altLength: undefined + }, + inheritColor: "from" // to, from, false, true (== from) + }, + configurePhysics:false, + physics: { + barnesHut: { + enabled: true, + thetaInverted: 1 / 0.5, // inverted to save time during calculation + gravitationalConstant: -2000, + centralGravity: 0.3, + springLength: 95, + springConstant: 0.04, + damping: 0.09 + }, + repulsion: { + centralGravity: 0.0, + springLength: 200, + springConstant: 0.05, + nodeDistance: 100, + damping: 0.09 + }, + hierarchicalRepulsion: { + enabled: false, + centralGravity: 0.0, + springLength: 100, + springConstant: 0.01, + nodeDistance: 150, + damping: 0.09 + }, + damping: null, + centralGravity: null, + springLength: null, + springConstant: null + }, + clustering: { // Per Node in Cluster = PNiC + enabled: false, // (Boolean) | global on/off switch for clustering. + initialMaxNodes: 100, // (# nodes) | if the initial amount of nodes is larger than this, we cluster until the total number is less than this threshold. + clusterThreshold:500, // (# nodes) | during calculate forces, we check if the total number of nodes is larger than this. If it is, cluster until reduced to reduceToNodes + reduceToNodes:300, // (# nodes) | during calculate forces, we check if the total number of nodes is larger than clusterThreshold. If it is, cluster until reduced to this + chainThreshold: 0.4, // (% of all drawn nodes)| maximum percentage of allowed chainnodes (long strings of connected nodes) within all nodes. (lower means less chains). + clusterEdgeThreshold: 20, // (px) | edge length threshold. if smaller, this node is clustered. + sectorThreshold: 100, // (# nodes in cluster) | cluster size threshold. If larger, expanding in own sector. + screenSizeThreshold: 0.2, // (% of canvas) | relative size threshold. If the width or height of a clusternode takes up this much of the screen, decluster node. + fontSizeMultiplier: 4.0, // (px PNiC) | how much the cluster font size grows per node in cluster (in px). + maxFontSize: 1000, + forceAmplification: 0.1, // (multiplier PNiC) | factor of increase fo the repulsion force of a cluster (per node in cluster). + distanceAmplification: 0.1, // (multiplier PNiC) | factor how much the repulsion distance of a cluster increases (per node in cluster). + edgeGrowth: 20, // (px PNiC) | amount of clusterSize connected to the edge is multiplied with this and added to edgeLength. + nodeScaling: {width: 1, // (px PNiC) | growth of the width per node in cluster. + height: 1, // (px PNiC) | growth of the height per node in cluster. + radius: 1}, // (px PNiC) | growth of the radius per node in cluster. + maxNodeSizeIncrements: 600, // (# increments) | max growth of the width per node in cluster. + activeAreaBoxSize: 80, // (px) | box area around the curser where clusters are popped open. + clusterLevelDifference: 2 + }, + navigation: { + enabled: false + }, + keyboard: { + enabled: false, + speed: {x: 10, y: 10, zoom: 0.02} + }, + dataManipulation: { + enabled: false, + initiallyVisible: false + }, + hierarchicalLayout: { + enabled:false, + levelSeparation: 150, + nodeSpacing: 100, + direction: "UD", // UD, DU, LR, RL + layout: "hubsize" // hubsize, directed + }, + freezeForStabilization: false, + smoothCurves: { + enabled: true, + dynamic: true, + type: "continuous", + roundness: 0.5 + }, + maxVelocity: 30, + minVelocity: 0.1, // px/s + stabilize: true, // stabilize before displaying the network + stabilizationIterations: 1000, // maximum number of iteration to stabilize + zoomExtentOnStabilize: true, + locale: 'en', + locales: locales, + tooltip: { + delay: 300, + fontColor: 'black', + fontSize: 14, // px + fontFace: 'verdana', + color: { + border: '#666', + background: '#FFFFC6' } + }, + dragNetwork: true, + dragNodes: true, + zoomable: true, + hover: false, + hideEdgesOnDrag: false, + hideNodesOnDrag: false, + width : '100%', + height : '100%', + selectable: true + }; + this.constants = util.extend({}, this.defaultOptions); + this.pixelRatio = 1; + + + this.hoverObj = {nodes:{},edges:{}}; + this.controlNodesActive = false; + this.navigationHammers = {existing:[], _new: []}; - group.order(); - group.show(); - } - else { - // update group - group.setData(groupData); - } + // animation properties + this.animationSpeed = 1/this.renderRefreshRate; + this.animationEasingFunction = "easeInOutQuint"; + this.animating = false; + this.easingTime = 0; + this.sourceScale = 0; + this.targetScale = 0; + this.sourceTranslation = 0; + this.targetTranslation = 0; + this.lockedOnNodeId = null; + this.lockedOnNodeOffset = null; + this.touchTime = 0; + + // Node variables + var network = this; + this.groups = new Groups(); // object with groups + this.images = new Images(); // object with images + this.images.setOnloadCallback(function (status) { + network._redraw(); }); - this.body.emitter.emit('change', {queue: true}); - }; + // keyboard navigation variables + this.xIncrement = 0; + this.yIncrement = 0; + this.zoomIncrement = 0; - /** - * Handle removed groups - * @param {Number[]} ids - * @private - */ - ItemSet.prototype._onRemoveGroups = function(ids) { - var groups = this.groups; - ids.forEach(function (id) { - var group = groups[id]; + // loading all the mixins: + // load the force calculation functions, grouped under the physics system. + this._loadPhysicsSystem(); + // create a frame and canvas + this._create(); + // load the sector system. (mandatory, fully integrated with Network) + this._loadSectorSystem(); + // load the cluster system. (mandatory, even when not using the cluster system, there are function calls to it) + this._loadClusterSystem(); + // load the selection system. (mandatory, required by Network) + this._loadSelectionSystem(); + // load the selection system. (mandatory, required by Network) + this._loadHierarchySystem(); - if (group) { - group.hide(); - delete groups[id]; - } - }); - this.markDirty(); + // apply options + this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2); + this._setScale(1); + this.setOptions(options); - this.body.emitter.emit('change', {queue: true}); - }; + // other vars + this.freezeSimulation = false;// freeze the simulation + this.cachedFunctions = {}; + this.startedStabilization = false; + this.stabilized = false; + this.stabilizationIterations = null; + this.draggingNodes = false; - /** - * Reorder the groups if needed - * @return {boolean} changed - * @private - */ - ItemSet.prototype._orderGroups = function () { - if (this.groupsData) { - // reorder the groups - var groupIds = this.groupsData.getIds({ - order: this.options.groupOrder - }); + // containers for nodes and edges + this.calculationNodes = {}; + this.calculationNodeIndices = []; + this.nodeIndices = []; // array with all the indices of the nodes. Used to speed up forces calculation + this.nodes = {}; // object with Node objects + this.edges = {}; // object with Edge objects - var changed = !util.equalArray(groupIds, this.groupIds); - if (changed) { - // hide all groups, removes them from the DOM - var groups = this.groups; - groupIds.forEach(function (groupId) { - groups[groupId].hide(); - }); + // position and scale variables and objects + this.canvasTopLeft = {"x": 0,"y": 0}; // coordinates of the top left of the canvas. they will be set during _redraw. + this.canvasBottomRight = {"x": 0,"y": 0}; // coordinates of the bottom right of the canvas. they will be set during _redraw + this.pointerPosition = {"x": 0,"y": 0}; // coordinates of the bottom right of the canvas. they will be set during _redraw + this.areaCenter = {}; // object with x and y elements used for determining the center of the zoom action + this.scale = 1; // defining the global scale variable in the constructor + this.previousScale = this.scale; // this is used to check if the zoom operation is zooming in or out - // show the groups again, attach them to the DOM in correct order - groupIds.forEach(function (groupId) { - groups[groupId].show(); - }); + // datasets or dataviews + this.nodesData = null; // A DataSet or DataView + this.edgesData = null; // A DataSet or DataView - this.groupIds = groupIds; + // create event listeners used to subscribe on the DataSets of the nodes and edges + this.nodesListeners = { + 'add': function (event, params) { + network._addNodes(params.items); + network.start(); + }, + 'update': function (event, params) { + network._updateNodes(params.items, params.data); + network.start(); + }, + 'remove': function (event, params) { + network._removeNodes(params.items); + network.start(); + } + }; + this.edgesListeners = { + 'add': function (event, params) { + network._addEdges(params.items); + network.start(); + }, + 'update': function (event, params) { + network._updateEdges(params.items); + network.start(); + }, + 'remove': function (event, params) { + network._removeEdges(params.items); + network.start(); } + }; - return changed; + // properties for the animation + this.moving = true; + this.timer = undefined; // Scheduling function. Is definded in this.start(); + + // load data (the disable start variable will be the same as the enabled clustering) + this.setData(data,this.constants.clustering.enabled || this.constants.hierarchicalLayout.enabled); + + // hierarchical layout + this.initializing = false; + if (this.constants.hierarchicalLayout.enabled == true) { + this._setupHierarchicalLayout(); } else { - return false; + // zoom so all data will fit on the screen, if clustering is enabled, we do not want start to be called here. + if (this.constants.stabilize == false) { + this.zoomExtent(undefined, true,this.constants.clustering.enabled); + } } - }; - /** - * Add a new item - * @param {Item} item - * @private - */ - ItemSet.prototype._addItem = function(item) { - this.items[item.id] = item; + // if clustering is disabled, the simulation will have started in the setData function + if (this.constants.clustering.enabled) { + this.startWithClustering(); + } + } - // add to group - var groupId = this._getGroupId(item.data); - var group = this.groups[groupId]; - if (group) group.add(item); - }; + // Extend Network with an Emitter mixin + Emitter(Network.prototype); /** - * Update an existing item - * @param {Item} item - * @param {Object} itemData + * Determine if the browser requires a setTimeout or a requestAnimationFrame. This was required because + * some implementations (safari and IE9) did not support requestAnimationFrame * @private */ - ItemSet.prototype._updateItem = function(item, itemData) { - var oldGroupId = item.data.group; - - // update the items data (will redraw the item when displayed) - item.setData(itemData); - - // update group - if (oldGroupId != item.data.group) { - var oldGroup = this.groups[oldGroupId]; - if (oldGroup) oldGroup.remove(item); - - var groupId = this._getGroupId(item.data); - var group = this.groups[groupId]; - if (group) group.add(item); + Network.prototype._determineBrowserMethod = function() { + var browserType = navigator.userAgent.toLowerCase(); + this.requiresTimeout = false; + if (browserType.indexOf('msie 9.0') != -1) { // IE 9 + this.requiresTimeout = true; } - }; + else if (browserType.indexOf('safari') != -1) { // safari + if (browserType.indexOf('chrome') <= -1) { + this.requiresTimeout = true; + } + } + } + /** - * Delete an item from the ItemSet: remove it from the DOM, from the map - * with items, and from the map with visible items, and from the selection - * @param {Item} item + * Get the script path where the vis.js library is located + * + * @returns {string | null} path Path or null when not found. Path does not + * end with a slash. * @private */ - ItemSet.prototype._removeItem = function(item) { - // remove from DOM - item.hide(); - - // remove from items - delete this.items[item.id]; + Network.prototype._getScriptPath = function() { + var scripts = document.getElementsByTagName( 'script' ); - // remove from selection - var index = this.selection.indexOf(item.id); - if (index != -1) this.selection.splice(index, 1); + // find script named vis.js or vis.min.js + for (var i = 0; i < scripts.length; i++) { + var src = scripts[i].src; + var match = src && /\/?vis(.min)?\.js$/.exec(src); + if (match) { + // return path without the script name + return src.substring(0, src.length - match[0].length); + } + } - // remove from group - item.parent && item.parent.remove(item); + return null; }; + /** - * Create an array containing all items being a range (having an end date) - * @param array - * @returns {Array} + * Find the center position of the network * @private */ - ItemSet.prototype._constructByEndArray = function(array) { - var endArray = []; - - for (var i = 0; i < array.length; i++) { - if (array[i] instanceof RangeItem) { - endArray.push(array[i]); + Network.prototype._getRange = function() { + var minY = 1e9, maxY = -1e9, minX = 1e9, maxX = -1e9, node; + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + if (minX > (node.boundingBox.left)) {minX = node.boundingBox.left;} + if (maxX < (node.boundingBox.right)) {maxX = node.boundingBox.right;} + if (minY > (node.boundingBox.bottom)) {minY = node.boundingBox.top;} // top is negative, bottom is positive + if (maxY < (node.boundingBox.top)) {maxY = node.boundingBox.bottom;} // top is negative, bottom is positive } } - return endArray; + if (minX == 1e9 && maxX == -1e9 && minY == 1e9 && maxY == -1e9) { + minY = 0, maxY = 0, minX = 0, maxX = 0; + } + return {minX: minX, maxX: maxX, minY: minY, maxY: maxY}; }; + /** - * Register the clicked item on touch, before dragStart is initiated. - * - * dragStart is initiated from a mousemove event, which can have left the item - * already resulting in an item == null - * - * @param {Event} event + * @param {object} range = {minX: minX, maxX: maxX, minY: minY, maxY: maxY}; + * @returns {{x: number, y: number}} * @private */ - ItemSet.prototype._onTouch = function (event) { - // store the touched item, used in _onDragStart - this.touchParams.item = ItemSet.itemFromTarget(event); + Network.prototype._findCenter = function(range) { + return {x: (0.5 * (range.maxX + range.minX)), + y: (0.5 * (range.maxY + range.minY))}; }; + /** - * Start dragging the selected events - * @param {Event} event - * @private + * This function zooms out to fit all data on screen based on amount of nodes + * + * @param {Boolean} [initialZoom] | zoom based on fitted formula or range, true = fitted, default = false; + * @param {Boolean} [disableStart] | If true, start is not called. */ - ItemSet.prototype._onDragStart = function (event) { - if (!this.options.editable.updateTime && !this.options.editable.updateGroup) { - return; - } - - var item = this.touchParams.item || null; - var me = this; - var props; + Network.prototype.zoomExtent = function(animationOptions, initialZoom, disableStart) { + this._redraw(true); - if (item && item.selected) { - var dragLeftItem = event.target.dragLeftItem; - var dragRightItem = event.target.dragRightItem; + if (initialZoom === undefined) {initialZoom = false;} + if (disableStart === undefined) {disableStart = false;} + if (animationOptions === undefined) {animationOptions = false;} - if (dragLeftItem) { - props = { - item: dragLeftItem, - initialX: event.gesture.center.clientX - }; + var range = this._getRange(); + var zoomLevel; - if (me.options.editable.updateTime) { - props.start = item.data.start.valueOf(); + if (initialZoom == true) { + var numberOfNodes = this.nodeIndices.length; + if (this.constants.smoothCurves == true) { + if (this.constants.clustering.enabled == true && + numberOfNodes >= this.constants.clustering.initialMaxNodes) { + zoomLevel = 49.07548 / (numberOfNodes + 142.05338) + 9.1444e-04; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. } - if (me.options.editable.updateGroup) { - if ('group' in item.data) props.group = item.data.group; + else { + zoomLevel = 12.662 / (numberOfNodes + 7.4147) + 0.0964822; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. } - - this.touchParams.itemProps = [props]; } - else if (dragRightItem) { - props = { - item: dragRightItem, - initialX: event.gesture.center.clientX - }; - - if (me.options.editable.updateTime) { - props.end = item.data.end.valueOf(); + else { + if (this.constants.clustering.enabled == true && + numberOfNodes >= this.constants.clustering.initialMaxNodes) { + zoomLevel = 77.5271985 / (numberOfNodes + 187.266146) + 4.76710517e-05; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. } - if (me.options.editable.updateGroup) { - if ('group' in item.data) props.group = item.data.group; + else { + zoomLevel = 30.5062972 / (numberOfNodes + 19.93597763) + 0.08413486; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. } - - this.touchParams.itemProps = [props]; - } - else { - this.touchParams.itemProps = this.getSelection().map(function (id) { - var item = me.items[id]; - var props = { - item: item, - initialX: event.gesture.center.clientX - }; - - if (me.options.editable.updateTime) { - if ('start' in item.data) props.start = item.data.start.valueOf(); - if ('end' in item.data) props.end = item.data.end.valueOf(); - } - if (me.options.editable.updateGroup) { - if ('group' in item.data) props.group = item.data.group; - } - - return props; - }); } - event.stopPropagation(); + // correct for larger canvasses. + var factor = Math.min(this.frame.canvas.clientWidth / 600, this.frame.canvas.clientHeight / 600); + zoomLevel *= factor; } - }; - - /** - * Drag selected items - * @param {Event} event - * @private - */ - ItemSet.prototype._onDrag = function (event) { - event.preventDefault() - - if (this.touchParams.itemProps) { - var me = this; - var snap = this.body.util.snap || null; - var xOffset = this.body.dom.root.offsetLeft + this.body.domProps.left.width; - - // move - this.touchParams.itemProps.forEach(function (props) { - var newProps = {}; - var current = me.body.util.toTime(event.gesture.center.clientX - xOffset); - var initial = me.body.util.toTime(props.initialX - xOffset); - var offset = current - initial; - - if ('start' in props) { - var start = new Date(props.start + offset); - newProps.start = snap ? snap(start) : start; - } - - if ('end' in props) { - var end = new Date(props.end + offset); - newProps.end = snap ? snap(end) : end; - } - - if ('group' in props) { - // drag from one group to another - var group = ItemSet.groupFromTarget(event); - newProps.group = group && group.groupId; - } - - // confirm moving the item - var itemData = util.extend({}, props.item.data, newProps); - me.options.onMoving(itemData, function (itemData) { - if (itemData) { - me._updateItemProps(props.item, itemData); - } - }); - }); - - this.stackDirty = true; // force re-stacking of all items next redraw - this.body.emitter.emit('change'); + else { + var xDistance = Math.abs(range.maxX - range.minX) * 1.1; + var yDistance = Math.abs(range.maxY - range.minY) * 1.1; - event.stopPropagation(); + var xZoomLevel = this.frame.canvas.clientWidth / xDistance; + var yZoomLevel = this.frame.canvas.clientHeight / yDistance; + zoomLevel = (xZoomLevel <= yZoomLevel) ? xZoomLevel : yZoomLevel; } - }; - /** - * Update an items properties - * @param {Item} item - * @param {Object} props Can contain properties start, end, and group. - * @private - */ - ItemSet.prototype._updateItemProps = function(item, props) { - // TODO: copy all properties from props to item? (also new ones) - if ('start' in props) item.data.start = props.start; - if ('end' in props) item.data.end = props.end; - if ('group' in props && item.data.group != props.group) { - this._moveToGroup(item, props.group) + if (zoomLevel > 1.0) { + zoomLevel = 1.0; } - }; - /** - * Move an item to another group - * @param {Item} item - * @param {String | Number} groupId - * @private - */ - ItemSet.prototype._moveToGroup = function(item, groupId) { - var group = this.groups[groupId]; - if (group && group.groupId != item.data.group) { - var oldGroup = item.parent; - oldGroup.remove(item); - oldGroup.order(); - group.add(item); - group.order(); - item.data.group = group.groupId; + var center = this._findCenter(range); + if (disableStart == false) { + var options = {position: center, scale: zoomLevel, animation: animationOptions}; + this.moveTo(options); + this.moving = true; + this.start(); + } + else { + center.x *= zoomLevel; + center.y *= zoomLevel; + center.x -= 0.5 * this.frame.canvas.clientWidth; + center.y -= 0.5 * this.frame.canvas.clientHeight; + this._setScale(zoomLevel); + this._setTranslation(-center.x,-center.y); } }; + /** - * End of dragging selected items - * @param {Event} event + * Update the this.nodeIndices with the most recent node index list * @private */ - ItemSet.prototype._onDragEnd = function (event) { - event.preventDefault() - - if (this.touchParams.itemProps) { - // prepare a change set for the changed items - var changes = [], - me = this, - dataset = this.itemsData.getDataSet(); - - var itemProps = this.touchParams.itemProps ; - this.touchParams.itemProps = null; - itemProps.forEach(function (props) { - var id = props.item.id, - itemData = me.itemsData.get(id, me.itemOptions); - - var changed = false; - if ('start' in props.item.data) { - changed = (props.start != props.item.data.start.valueOf()); - itemData.start = util.convert(props.item.data.start, - dataset._options.type && dataset._options.type.start || 'Date'); - } - if ('end' in props.item.data) { - changed = changed || (props.end != props.item.data.end.valueOf()); - itemData.end = util.convert(props.item.data.end, - dataset._options.type && dataset._options.type.end || 'Date'); - } - if ('group' in props.item.data) { - changed = changed || (props.group != props.item.data.group); - itemData.group = props.item.data.group; - } - - // only apply changes when start or end is actually changed - if (changed) { - me.options.onMove(itemData, function (itemData) { - if (itemData) { - // apply changes - itemData[dataset._fieldId] = id; // ensure the item contains its id (can be undefined) - changes.push(itemData); - } - else { - // restore original values - me._updateItemProps(props.item, props); - - me.stackDirty = true; // force re-stacking of all items next redraw - me.body.emitter.emit('change'); - } - }); - } - }); - - // apply the changes to the data (if there are changes) - if (changes.length) { - dataset.update(changes); + Network.prototype._updateNodeIndexList = function() { + this._clearNodeIndexList(); + for (var idx in this.nodes) { + if (this.nodes.hasOwnProperty(idx)) { + this.nodeIndices.push(idx); } - - event.stopPropagation(); } }; + /** - * Handle selecting/deselecting an item when tapping it - * @param {Event} event - * @private + * Set nodes and edges, and optionally options as well. + * + * @param {Object} data Object containing parameters: + * {Array | DataSet | DataView} [nodes] Array with nodes + * {Array | DataSet | DataView} [edges] Array with edges + * {String} [dot] String containing data in DOT format + * {String} [gephi] String containing data in gephi JSON format + * {Options} [options] Object with options + * @param {Boolean} [disableStart] | optional: disable the calling of the start function. */ - ItemSet.prototype._onSelectItem = function (event) { - if (!this.options.selectable) return; - - var ctrlKey = event.gesture.srcEvent && event.gesture.srcEvent.ctrlKey; - var shiftKey = event.gesture.srcEvent && event.gesture.srcEvent.shiftKey; - if (ctrlKey || shiftKey) { - this._onMultiSelectItem(event); - return; + Network.prototype.setData = function(data, disableStart) { + if (disableStart === undefined) { + disableStart = false; } + // we set initializing to true to ensure that the hierarchical layout is not performed until both nodes and edges are added. + this.initializing = true; - var oldSelection = this.getSelection(); - - var item = ItemSet.itemFromTarget(event); - var selection = item ? [item.id] : []; - this.setSelection(selection); + if (data && data.dot && (data.nodes || data.edges)) { + throw new SyntaxError('Data must contain either parameter "dot" or ' + + ' parameter pair "nodes" and "edges", but not both.'); + } - var newSelection = this.getSelection(); + // clean up in case there is anyone in an active mode of the manipulation. This is the same option as bound to the escape button. + if (this.constants.dataManipulation.enabled == true) { + this._createManipulatorBar(); + } - // emit a select event, - // except when old selection is empty and new selection is still empty - if (newSelection.length > 0 || oldSelection.length > 0) { - this.body.emitter.emit('select', { - items: newSelection - }); + // set options + this.setOptions(data && data.options); + // set all data + if (data && data.dot) { + // parse DOT file + if(data && data.dot) { + var dotData = dotparser.DOTToGraph(data.dot); + this.setData(dotData); + return; + } + } + else if (data && data.gephi) { + // parse DOT file + if(data && data.gephi) { + var gephiData = gephiParser.parseGephi(data.gephi); + this.setData(gephiData); + return; + } + } + else { + this._setNodes(data && data.nodes); + this._setEdges(data && data.edges); + } + this._putDataInSector(); + if (disableStart == false) { + if (this.constants.hierarchicalLayout.enabled == true) { + this._resetLevels(); + this._setupHierarchicalLayout(); + } + else { + // find a stable position or start animating to a stable position + if (this.constants.stabilize) { + this._stabilize(); + } + } + this.start(); } + this.initializing = false; }; /** - * Handle creation and updates of an item on double tap - * @param event - * @private + * Set options + * @param {Object} options */ - ItemSet.prototype._onAddItem = function (event) { - if (!this.options.selectable) return; - if (!this.options.editable.add) return; - - var me = this, - snap = this.body.util.snap || null, - item = ItemSet.itemFromTarget(event); + Network.prototype.setOptions = function (options) { + if (options) { + var prop; + var fields = ['nodes','edges','smoothCurves','hierarchicalLayout','clustering','navigation', + 'keyboard','dataManipulation','onAdd','onEdit','onEditEdge','onConnect','onDelete','clickToUse' + ]; + // extend all but the values in fields + util.selectiveNotDeepExtend(fields,this.constants, options); + util.selectiveNotDeepExtend(['color'],this.constants.nodes, options.nodes); + util.selectiveNotDeepExtend(['color','length'],this.constants.edges, options.edges); - if (item) { - // update item + if (options.physics) { + util.mergeOptions(this.constants.physics, options.physics,'barnesHut'); + util.mergeOptions(this.constants.physics, options.physics,'repulsion'); - // execute async handler to update the item (or cancel it) - var itemData = me.itemsData.get(item.id); // get a clone of the data from the dataset - this.options.onUpdate(itemData, function (itemData) { - if (itemData) { - me.itemsData.getDataSet().update(itemData); + if (options.physics.hierarchicalRepulsion) { + this.constants.hierarchicalLayout.enabled = true; + this.constants.physics.hierarchicalRepulsion.enabled = true; + this.constants.physics.barnesHut.enabled = false; + for (prop in options.physics.hierarchicalRepulsion) { + if (options.physics.hierarchicalRepulsion.hasOwnProperty(prop)) { + this.constants.physics.hierarchicalRepulsion[prop] = options.physics.hierarchicalRepulsion[prop]; + } + } } - }); - } - else { - // add item - var xAbs = util.getAbsoluteLeft(this.dom.frame); - var x = event.gesture.center.pageX - xAbs; - var start = this.body.util.toTime(x); - var newItem = { - start: snap ? snap(start) : start, - content: 'new item' - }; - - // when default type is a range, add a default end date to the new item - if (this.options.type === 'range') { - var end = this.body.util.toTime(x + this.props.width / 5); - newItem.end = snap ? snap(end) : end; } - newItem[this.itemsData._fieldId] = util.randomUUID(); - - var group = ItemSet.groupFromTarget(event); - if (group) { - newItem.group = group.groupId; - } + if (options.onAdd) {this.triggerFunctions.add = options.onAdd;} + if (options.onEdit) {this.triggerFunctions.edit = options.onEdit;} + if (options.onEditEdge) {this.triggerFunctions.editEdge = options.onEditEdge;} + if (options.onConnect) {this.triggerFunctions.connect = options.onConnect;} + if (options.onDelete) {this.triggerFunctions.del = options.onDelete;} - // execute async handler to customize (or cancel) adding an item - this.options.onAdd(newItem, function (item) { - if (item) { - me.itemsData.getDataSet().add(item); - // TODO: need to trigger a redraw? - } - }); - } - }; + util.mergeOptions(this.constants, options,'smoothCurves'); + util.mergeOptions(this.constants, options,'hierarchicalLayout'); + util.mergeOptions(this.constants, options,'clustering'); + util.mergeOptions(this.constants, options,'navigation'); + util.mergeOptions(this.constants, options,'keyboard'); + util.mergeOptions(this.constants, options,'dataManipulation'); - /** - * Handle selecting/deselecting multiple items when holding an item - * @param {Event} event - * @private - */ - ItemSet.prototype._onMultiSelectItem = function (event) { - if (!this.options.selectable) return; - var selection, - item = ItemSet.itemFromTarget(event); + if (options.dataManipulation) { + this.editMode = this.constants.dataManipulation.initiallyVisible; + } - if (item) { - // multi select items - selection = this.getSelection(); // current selection - var shiftKey = event.gesture.touches[0] && event.gesture.touches[0].shiftKey || false; - if (shiftKey) { - // select all items between the old selection and the tapped item + // TODO: work out these options and document them + if (options.edges) { + if (options.edges.color !== undefined) { + if (util.isString(options.edges.color)) { + this.constants.edges.color = {}; + this.constants.edges.color.color = options.edges.color; + this.constants.edges.color.highlight = options.edges.color; + this.constants.edges.color.hover = options.edges.color; + } + else { + if (options.edges.color.color !== undefined) {this.constants.edges.color.color = options.edges.color.color;} + if (options.edges.color.highlight !== undefined) {this.constants.edges.color.highlight = options.edges.color.highlight;} + if (options.edges.color.hover !== undefined) {this.constants.edges.color.hover = options.edges.color.hover;} + } + this.constants.edges.inheritColor = false; + } - // determine the selection range - selection.push(item.id); - var range = ItemSet._getItemRange(this.itemsData.get(selection, this.itemOptions)); + if (!options.edges.fontColor) { + if (options.edges.color !== undefined) { + if (util.isString(options.edges.color)) {this.constants.edges.fontColor = options.edges.color;} + else if (options.edges.color.color !== undefined) {this.constants.edges.fontColor = options.edges.color.color;} + } + } + } - // select all items within the selection range - selection = []; - for (var id in this.items) { - if (this.items.hasOwnProperty(id)) { - var _item = this.items[id]; - var start = _item.data.start; - var end = (_item.data.end !== undefined) ? _item.data.end : start; + if (options.nodes) { + if (options.nodes.color) { + var newColorObj = util.parseColor(options.nodes.color); + this.constants.nodes.color.background = newColorObj.background; + this.constants.nodes.color.border = newColorObj.border; + this.constants.nodes.color.highlight.background = newColorObj.highlight.background; + this.constants.nodes.color.highlight.border = newColorObj.highlight.border; + this.constants.nodes.color.hover.background = newColorObj.hover.background; + this.constants.nodes.color.hover.border = newColorObj.hover.border; + } + } + if (options.groups) { + for (var groupname in options.groups) { + if (options.groups.hasOwnProperty(groupname)) { + var group = options.groups[groupname]; + this.groups.add(groupname, group); + } + } + } - if (start >= range.min && end <= range.max) { - selection.push(_item.id); // do not use id but item.id, id itself is stringified - } + if (options.tooltip) { + for (prop in options.tooltip) { + if (options.tooltip.hasOwnProperty(prop)) { + this.constants.tooltip[prop] = options.tooltip[prop]; } } + if (options.tooltip.color) { + this.constants.tooltip.color = util.parseColor(options.tooltip.color); + } } - else { - // add/remove this item from the current selection - var index = selection.indexOf(item.id); - if (index == -1) { - // item is not yet selected -> select it - selection.push(item.id); + + if ('clickToUse' in options) { + if (options.clickToUse) { + if (!this.activator) { + this.activator = new Activator(this.frame); + this.activator.on('change', this._createKeyBinds.bind(this)); + } } else { - // item is already selected -> deselect it - selection.splice(index, 1); + if (this.activator) { + this.activator.destroy(); + delete this.activator; + } } } - this.setSelection(selection); + if (options.labels) { + throw new Error('Option "labels" is deprecated. Use options "locale" and "locales" instead.'); + } - this.body.emitter.emit('select', { - items: this.getSelection() - }); + + // (Re)loading the mixins that can be enabled or disabled in the options. + // load the force calculation functions, grouped under the physics system. + this._loadPhysicsSystem(); + // load the navigation system. + this._loadNavigationControls(); + // load the data manipulation system + this._loadManipulationSystem(); + // configure the smooth curves + this._configureSmoothCurves(); + + + // bind keys. If disabled, this will not do anything; + this._createKeyBinds(); + + this.setSize(this.constants.width, this.constants.height); + this.moving = true; + this.start(); } }; + + /** - * Calculate the time range of a list of items - * @param {Array.} itemsData - * @return {{min: Date, max: Date}} Returns the range of the provided items + * Create the main frame for the Network. + * This function is executed once when a Network object is created. The frame + * contains a canvas, and this canvas contains all objects like the axis and + * nodes. * @private */ - ItemSet._getItemRange = function(itemsData) { - var max = null; - var min = null; + Network.prototype._create = function () { + // remove all elements from the container element. + while (this.containerElement.hasChildNodes()) { + this.containerElement.removeChild(this.containerElement.firstChild); + } - itemsData.forEach(function (data) { - if (min == null || data.start < min) { - min = data.start; - } + this.frame = document.createElement('div'); + this.frame.className = 'vis network-frame'; + this.frame.style.position = 'relative'; + this.frame.style.overflow = 'hidden'; - if (data.end != undefined) { - if (max == null || data.end > max) { - max = data.end; - } - } - else { - if (max == null || data.start > max) { - max = data.start; - } - } - }); - return { - min: min, - max: max + ////////////////////////////////////////////////////////////////// + + this.frame.canvas = document.createElement("canvas"); + this.frame.canvas.style.position = 'relative'; + this.frame.appendChild(this.frame.canvas); + + if (!this.frame.canvas.getContext) { + var noCanvas = document.createElement( 'DIV' ); + noCanvas.style.color = 'red'; + noCanvas.style.fontWeight = 'bold' ; + noCanvas.style.padding = '10px'; + noCanvas.innerHTML = 'Error: your browser does not support HTML canvas'; + this.frame.canvas.appendChild(noCanvas); } - }; + else { + var ctx = this.frame.canvas.getContext("2d"); + this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || + ctx.mozBackingStorePixelRatio || + ctx.msBackingStorePixelRatio || + ctx.oBackingStorePixelRatio || + ctx.backingStorePixelRatio || 1); - /** - * Find an item from an event target: - * searches for the attribute 'timeline-item' in the event target's element tree - * @param {Event} event - * @return {Item | null} item - */ - ItemSet.itemFromTarget = function(event) { - var target = event.target; - while (target) { - if (target.hasOwnProperty('timeline-item')) { - return target['timeline-item']; - } - target = target.parentNode; + this.frame.canvas.getContext("2d").setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); } - return null; - }; + ////////////////////////////////////////////////////////////////// - /** - * Find the Group from an event target: - * searches for the attribute 'timeline-group' in the event target's element tree - * @param {Event} event - * @return {Group | null} group - */ - ItemSet.groupFromTarget = function(event) { - var target = event.target; - while (target) { - if (target.hasOwnProperty('timeline-group')) { - return target['timeline-group']; - } - target = target.parentNode; - } - return null; + var me = this; + this.drag = {}; + this.pinch = {}; + this.hammer = Hammer(this.frame.canvas, { + prevent_default: true + }); + this.hammer.on('tap', me._onTap.bind(me) ); + this.hammer.on('doubletap', me._onDoubleTap.bind(me) ); + this.hammer.on('hold', me._onHold.bind(me) ); + this.hammer.on('pinch', me._onPinch.bind(me) ); + this.hammer.on('touch', me._onTouch.bind(me) ); + this.hammer.on('dragstart', me._onDragStart.bind(me) ); + this.hammer.on('drag', me._onDrag.bind(me) ); + this.hammer.on('dragend', me._onDragEnd.bind(me) ); + this.hammer.on('mousewheel',me._onMouseWheel.bind(me) ); + this.hammer.on('DOMMouseScroll',me._onMouseWheel.bind(me) ); // for FF + this.hammer.on('mousemove', me._onMouseMoveTitle.bind(me) ); + + this.hammerFrame = Hammer(this.frame, { + prevent_default: true + }); + this.hammerFrame.on('release', me._onRelease.bind(me) ); + + // add the frame to the container element + this.containerElement.appendChild(this.frame); + }; + /** - * Find the ItemSet from an event target: - * searches for the attribute 'timeline-itemset' in the event target's element tree - * @param {Event} event - * @return {ItemSet | null} item + * Binding the keys for keyboard navigation. These functions are defined in the NavigationMixin + * @private */ - ItemSet.itemSetFromTarget = function(event) { - var target = event.target; - while (target) { - if (target.hasOwnProperty('timeline-itemset')) { - return target['timeline-itemset']; - } - target = target.parentNode; + Network.prototype._createKeyBinds = function() { + var me = this; + if (this.keycharm !== undefined) { + this.keycharm.destroy(); } + this.keycharm = keycharm(); - return null; - }; - - module.exports = ItemSet; - + this.keycharm.reset(); -/***/ }, -/* 27 */ -/***/ function(module, exports, __webpack_require__) { + if (this.constants.keyboard.enabled && this.isActive()) { + this.keycharm.bind("up", this._moveUp.bind(me) , "keydown"); + this.keycharm.bind("up", this._yStopMoving.bind(me), "keyup"); + this.keycharm.bind("down", this._moveDown.bind(me) , "keydown"); + this.keycharm.bind("down", this._yStopMoving.bind(me), "keyup"); + this.keycharm.bind("left", this._moveLeft.bind(me) , "keydown"); + this.keycharm.bind("left", this._xStopMoving.bind(me), "keyup"); + this.keycharm.bind("right",this._moveRight.bind(me), "keydown"); + this.keycharm.bind("right",this._xStopMoving.bind(me), "keyup"); + this.keycharm.bind("=", this._zoomIn.bind(me), "keydown"); + this.keycharm.bind("=", this._stopZoom.bind(me), "keyup"); + this.keycharm.bind("num+", this._zoomIn.bind(me), "keydown"); + this.keycharm.bind("num+", this._stopZoom.bind(me), "keyup"); + this.keycharm.bind("num-", this._zoomOut.bind(me), "keydown"); + this.keycharm.bind("num-", this._stopZoom.bind(me), "keyup"); + this.keycharm.bind("-", this._zoomOut.bind(me), "keydown"); + this.keycharm.bind("-", this._stopZoom.bind(me), "keyup"); + this.keycharm.bind("[", this._zoomIn.bind(me), "keydown"); + this.keycharm.bind("[", this._stopZoom.bind(me), "keyup"); + this.keycharm.bind("]", this._zoomOut.bind(me), "keydown"); + this.keycharm.bind("]", this._stopZoom.bind(me), "keyup"); + this.keycharm.bind("pageup",this._zoomIn.bind(me), "keydown"); + this.keycharm.bind("pageup",this._stopZoom.bind(me), "keyup"); + this.keycharm.bind("pagedown",this._zoomOut.bind(me),"keydown"); + this.keycharm.bind("pagedown",this._stopZoom.bind(me), "keyup"); + } - var util = __webpack_require__(1); - var stack = __webpack_require__(28); - var RangeItem = __webpack_require__(29); + if (this.constants.dataManipulation.enabled == true) { + this.keycharm.bind("esc",this._createManipulatorBar.bind(me)); + this.keycharm.bind("delete",this._deleteSelected.bind(me)); + } + }; /** - * @constructor Group - * @param {Number | String} groupId - * @param {Object} data - * @param {ItemSet} itemSet + * Cleans up all bindings of the network, removing it fully from the memory IF the variable is set to null after calling this function. + * var network = new vis.Network(..); + * network.destroy(); + * network = null; */ - function Group (groupId, data, itemSet) { - this.groupId = groupId; - this.subgroups = {}; - this.subgroupIndex = 0; - this.subgroupOrderer = data && data.subgroupOrder; - this.itemSet = itemSet; - - this.dom = {}; - this.props = { - label: { - width: 0, - height: 0 - } - }; - this.className = null; + Network.prototype.destroy = function() { + this.start = function () {}; + this.redraw = function () {}; + this.timer = false; - this.items = {}; // items filtered by groupId of this group - this.visibleItems = []; // items currently visible in window - this.orderedItems = { - byStart: [], - byEnd: [] - }; - this.checkRangedItems = false; // needed to refresh the ranged items if the window is programatically changed with NO overlap. - var me = this; - this.itemSet.body.emitter.on("checkRangedItems", function () { - me.checkRangedItems = true; - }) + // cleanup physicsConfiguration if it exists + this._cleanupPhysicsConfiguration(); - this._create(); + // remove keybindings + this.keycharm.reset(); - this.setData(data); + // clear hammer bindings + this.hammer.dispose(); + + // clear events + this.off(); + + this._recursiveDOMDelete(this.containerElement); + } + + Network.prototype._recursiveDOMDelete = function(DOMobject) { + while (DOMobject.hasChildNodes() == true) { + this._recursiveDOMDelete(DOMobject.firstChild); + DOMobject.removeChild(DOMobject.firstChild); + } } /** - * Create DOM elements for the group + * Get the pointer location from a touch location + * @param {{pageX: Number, pageY: Number}} touch + * @return {{x: Number, y: Number}} pointer * @private */ - Group.prototype._create = function() { - var label = document.createElement('div'); - label.className = 'vlabel'; - this.dom.label = label; - - var inner = document.createElement('div'); - inner.className = 'inner'; - label.appendChild(inner); - this.dom.inner = inner; - - var foreground = document.createElement('div'); - foreground.className = 'group'; - foreground['timeline-group'] = this; - this.dom.foreground = foreground; - - this.dom.background = document.createElement('div'); - this.dom.background.className = 'group'; - - this.dom.axis = document.createElement('div'); - this.dom.axis.className = 'group'; - - // create a hidden marker to detect when the Timelines container is attached - // to the DOM, or the style of a parent of the Timeline is changed from - // display:none is changed to visible. - this.dom.marker = document.createElement('div'); - this.dom.marker.style.visibility = 'hidden'; // TODO: ask jos why this is not none? - this.dom.marker.innerHTML = '?'; - this.dom.background.appendChild(this.dom.marker); + Network.prototype._getPointer = function (touch) { + return { + x: touch.pageX - util.getAbsoluteLeft(this.frame.canvas), + y: touch.pageY - util.getAbsoluteTop(this.frame.canvas) + }; }; /** - * Set the group data for this group - * @param {Object} data Group data, can contain properties content and className + * On start of a touch gesture, store the pointer + * @param event + * @private */ - Group.prototype.setData = function(data) { - // update contents - var content = data && data.content; - if (content instanceof Element) { - this.dom.inner.appendChild(content); - } - else if (content !== undefined && content !== null) { - this.dom.inner.innerHTML = content; - } - else { - this.dom.inner.innerHTML = this.groupId || ''; // groupId can be null - } - - // update title - this.dom.label.title = data && data.title || ''; - - if (!this.dom.inner.firstChild) { - util.addClassName(this.dom.inner, 'hidden'); - } - else { - util.removeClassName(this.dom.inner, 'hidden'); - } + Network.prototype._onTouch = function (event) { + if (new Date().valueOf() - this.touchTime > 100) { + this.drag.pointer = this._getPointer(event.gesture.center); + this.drag.pinched = false; + this.pinch.scale = this._getScale(); - // update className - var className = data && data.className || null; - if (className != this.className) { - if (this.className) { - util.removeClassName(this.dom.label, this.className); - util.removeClassName(this.dom.foreground, this.className); - util.removeClassName(this.dom.background, this.className); - util.removeClassName(this.dom.axis, this.className); - } - util.addClassName(this.dom.label, className); - util.addClassName(this.dom.foreground, className); - util.addClassName(this.dom.background, className); - util.addClassName(this.dom.axis, className); - this.className = className; - } + // to avoid double fireing of this event because we have two hammer instances. (on canvas and on frame) + this.touchTime = new Date().valueOf(); - // update style - if (this.style) { - util.removeCssText(this.dom.label, this.style); - this.style = null; - } - if (data && data.style) { - util.addCssText(this.dom.label, data.style); - this.style = data.style; + this._handleTouch(this.drag.pointer); } }; /** - * Get the width of the group label - * @return {number} width + * handle drag start event + * @private */ - Group.prototype.getLabelWidth = function() { - return this.props.label.width; + Network.prototype._onDragStart = function (event) { + this._handleDragStart(event); }; /** - * Repaint this group - * @param {{start: number, end: number}} range - * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin - * @param {boolean} [restack=false] Force restacking of all items - * @return {boolean} Returns true if the group is resized + * This function is called by _onDragStart. + * It is separated out because we can then overload it for the datamanipulation system. + * + * @private */ - Group.prototype.redraw = function(range, margin, restack) { - var resized = false; - - this.visibleItems = this._updateVisibleItems(this.orderedItems, this.visibleItems, range); - - // force recalculation of the height of the items when the marker height changed - // (due to the Timeline being attached to the DOM or changed from display:none to visible) - var markerHeight = this.dom.marker.clientHeight; - if (markerHeight != this.lastMarkerHeight) { - this.lastMarkerHeight = markerHeight; + Network.prototype._handleDragStart = function(event) { + // in case the touch event was triggered on an external div, do the initial touch now. + if (this.drag.pointer === undefined) { + this._onTouch(event); + } - util.forEach(this.items, function (item) { - item.dirty = true; - if (item.displayed) item.redraw(); - }); + var node = this._getNodeAt(this.drag.pointer); + // note: drag.pointer is set in _onTouch to get the initial touch location - restack = true; - } + this.drag.dragging = true; + this.drag.selection = []; + this.drag.translation = this._getTranslation(); + this.drag.nodeId = null; + this.draggingNodes = false; - // reposition visible items vertically - if (this.itemSet.options.stack) { // TODO: ugly way to access options... - stack.stack(this.visibleItems, margin, restack); - } - else { // no stacking - stack.nostack(this.visibleItems, margin, this.subgroups); - } + if (node != null && this.constants.dragNodes == true) { + this.draggingNodes = true; + this.drag.nodeId = node.id; + // select the clicked node if not yet selected + if (!node.isSelected()) { + this._selectObject(node,false); + } - // recalculate the height of the group - var height = this._calculateHeight(margin); + this.emit("dragStart",{nodeIds:this.getSelection().nodes}); - // calculate actual size and position - var foreground = this.dom.foreground; - this.top = foreground.offsetTop; - this.left = foreground.offsetLeft; - this.width = foreground.offsetWidth; - resized = util.updateProperty(this, 'height', height) || resized; + // create an array with the selected nodes and their original location and status + for (var objectId in this.selectionObj.nodes) { + if (this.selectionObj.nodes.hasOwnProperty(objectId)) { + var object = this.selectionObj.nodes[objectId]; + var s = { + id: object.id, + node: object, - // recalculate size of label - resized = util.updateProperty(this.props.label, 'width', this.dom.inner.clientWidth) || resized; - resized = util.updateProperty(this.props.label, 'height', this.dom.inner.clientHeight) || resized; + // store original x, y, xFixed and yFixed, make the node temporarily Fixed + x: object.x, + y: object.y, + xFixed: object.xFixed, + yFixed: object.yFixed + }; - // apply new height - this.dom.background.style.height = height + 'px'; - this.dom.foreground.style.height = height + 'px'; - this.dom.label.style.height = height + 'px'; + object.xFixed = true; + object.yFixed = true; - // update vertical position of items after they are re-stacked and the height of the group is calculated - for (var i = 0, ii = this.visibleItems.length; i < ii; i++) { - var item = this.visibleItems[i]; - item.repositionY(margin); + this.drag.selection.push(s); + } + } } + }; - return resized; + + /** + * handle drag event + * @private + */ + Network.prototype._onDrag = function (event) { + this._handleOnDrag(event) }; + /** - * recalculate the height of the group - * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin - * @returns {number} Returns the height + * This function is called by _onDrag. + * It is separated out because we can then overload it for the datamanipulation system. + * * @private */ - Group.prototype._calculateHeight = function (margin) { - // recalculate the height of the group - var height; - var visibleItems = this.visibleItems; - //var visibleSubgroups = []; - //this.visibleSubgroups = 0; - this.resetSubgroups(); + Network.prototype._handleOnDrag = function(event) { + if (this.drag.pinched) { + return; + } + + // remove the focus on node if it is focussed on by the focusOnNode + this.releaseNode(); + + var pointer = this._getPointer(event.gesture.center); var me = this; - if (visibleItems.length) { - var min = visibleItems[0].top; - var max = visibleItems[0].top + visibleItems[0].height; - util.forEach(visibleItems, function (item) { - min = Math.min(min, item.top); - max = Math.max(max, (item.top + item.height)); - if (item.data.subgroup !== undefined) { - me.subgroups[item.data.subgroup].height = Math.max(me.subgroups[item.data.subgroup].height,item.height); - me.subgroups[item.data.subgroup].visible = true; - //if (visibleSubgroups.indexOf(item.data.subgroup) == -1){ - // visibleSubgroups.push(item.data.subgroup); - // me.visibleSubgroups += 1; - //} + var drag = this.drag; + var selection = drag.selection; + if (selection && selection.length && this.constants.dragNodes == true) { + // calculate delta's and new location + var deltaX = pointer.x - drag.pointer.x; + var deltaY = pointer.y - drag.pointer.y; + + // update position of all selected nodes + selection.forEach(function (s) { + var node = s.node; + + if (!s.xFixed) { + node.x = me._XconvertDOMtoCanvas(me._XconvertCanvasToDOM(s.x) + deltaX); + } + + if (!s.yFixed) { + node.y = me._YconvertDOMtoCanvas(me._YconvertCanvasToDOM(s.y) + deltaY); } }); - if (min > margin.axis) { - // there is an empty gap between the lowest item and the axis - var offset = min - margin.axis; - max -= offset; - util.forEach(visibleItems, function (item) { - item.top -= offset; - }); + + + // start _animationStep if not yet running + if (!this.moving) { + this.moving = true; + this.start(); } - height = max + margin.item.vertical / 2; } else { - height = margin.axis + margin.item.vertical; - } - height = Math.max(height, this.props.label.height); + // move the network + if (this.constants.dragNetwork == true) { + // if the drag was not started properly because the click started outside the network div, start it now. + if (this.drag.pointer === undefined) { + this._handleDragStart(event); + return; + } + var diffX = pointer.x - this.drag.pointer.x; + var diffY = pointer.y - this.drag.pointer.y; - return height; + this._setTranslation( + this.drag.translation.x + diffX, + this.drag.translation.y + diffY + ); + this._redraw(); + } + } }; /** - * Show this group: attach to the DOM + * handle drag start event + * @private */ - Group.prototype.show = function() { - if (!this.dom.label.parentNode) { - this.itemSet.dom.labelSet.appendChild(this.dom.label); - } + Network.prototype._onDragEnd = function (event) { + this._handleDragEnd(event); + }; - if (!this.dom.foreground.parentNode) { - this.itemSet.dom.foreground.appendChild(this.dom.foreground); - } - if (!this.dom.background.parentNode) { - this.itemSet.dom.background.appendChild(this.dom.background); + Network.prototype._handleDragEnd = function(event) { + this.drag.dragging = false; + var selection = this.drag.selection; + if (selection && selection.length) { + selection.forEach(function (s) { + // restore original xFixed and yFixed + s.node.xFixed = s.xFixed; + s.node.yFixed = s.yFixed; + }); + this.moving = true; + this.start(); } - - if (!this.dom.axis.parentNode) { - this.itemSet.dom.axis.appendChild(this.dom.axis); + else { + this._redraw(); + } + if (this.draggingNodes == false) { + this.emit("dragEnd",{nodeIds:[]}); } + else { + this.emit("dragEnd",{nodeIds:this.getSelection().nodes}); + } + + } + /** + * handle tap/click event: select/unselect a node + * @private + */ + Network.prototype._onTap = function (event) { + var pointer = this._getPointer(event.gesture.center); + this.pointerPosition = pointer; + this._handleTap(pointer); + }; + /** - * Hide this group: remove from the DOM + * handle doubletap event + * @private */ - Group.prototype.hide = function() { - var label = this.dom.label; - if (label.parentNode) { - label.parentNode.removeChild(label); - } + Network.prototype._onDoubleTap = function (event) { + var pointer = this._getPointer(event.gesture.center); + this._handleDoubleTap(pointer); + }; - var foreground = this.dom.foreground; - if (foreground.parentNode) { - foreground.parentNode.removeChild(foreground); - } - var background = this.dom.background; - if (background.parentNode) { - background.parentNode.removeChild(background); - } + /** + * handle long tap event: multi select nodes + * @private + */ + Network.prototype._onHold = function (event) { + var pointer = this._getPointer(event.gesture.center); + this.pointerPosition = pointer; + this._handleOnHold(pointer); + }; - var axis = this.dom.axis; - if (axis.parentNode) { - axis.parentNode.removeChild(axis); - } + /** + * handle the release of the screen + * + * @private + */ + Network.prototype._onRelease = function (event) { + var pointer = this._getPointer(event.gesture.center); + this._handleOnRelease(pointer); }; /** - * Add an item to the group - * @param {Item} item + * Handle pinch event + * @param event + * @private */ - Group.prototype.add = function(item) { - this.items[item.id] = item; - item.setParent(this); + Network.prototype._onPinch = function (event) { + var pointer = this._getPointer(event.gesture.center); - // add to - if (item.data.subgroup !== undefined) { - if (this.subgroups[item.data.subgroup] === undefined) { - this.subgroups[item.data.subgroup] = {height:0, visible: false, index:this.subgroupIndex, items: []}; - this.subgroupIndex++; - } - this.subgroups[item.data.subgroup].items.push(item); + this.drag.pinched = true; + if (!('scale' in this.pinch)) { + this.pinch.scale = 1; } - this.orderSubgroups(); - if (this.visibleItems.indexOf(item) == -1) { - var range = this.itemSet.body.range; // TODO: not nice accessing the range like this - this._checkIfVisible(item, this.visibleItems, range); - } + // TODO: enabled moving while pinching? + var scale = this.pinch.scale * event.gesture.scale; + this._zoom(scale, pointer) }; - Group.prototype.orderSubgroups = function() { - if (this.subgroupOrderer !== undefined) { - var sortArray = []; - if (typeof this.subgroupOrderer == 'string') { - for (var subgroup in this.subgroups) { - sortArray.push({subgroup: subgroup, sortField: this.subgroups[subgroup].items[0].data[this.subgroupOrderer]}) - } - sortArray.sort(function (a, b) { - return a.sortField - b.sortField; - }) + /** + * Zoom the network in or out + * @param {Number} scale a number around 1, and between 0.01 and 10 + * @param {{x: Number, y: Number}} pointer Position on screen + * @return {Number} appliedScale scale is limited within the boundaries + * @private + */ + Network.prototype._zoom = function(scale, pointer) { + if (this.constants.zoomable == true) { + var scaleOld = this._getScale(); + if (scale < 0.00001) { + scale = 0.00001; } - else if (typeof this.subgroupOrderer == 'function') { - for (var subgroup in this.subgroups) { - sortArray.push(this.subgroups[subgroup].items[0].data); - } - sortArray.sort(this.subgroupOrderer); + if (scale > 10) { + scale = 10; } - if (sortArray.length > 0) { - for (var i = 0; i < sortArray.length; i++) { - this.subgroups[sortArray[i].subgroup].index = i; + var preScaleDragPointer = null; + if (this.drag !== undefined) { + if (this.drag.dragging == true) { + preScaleDragPointer = this.DOMtoCanvas(this.drag.pointer); } } - } - }; + // + this.frame.canvas.clientHeight / 2 + var translation = this._getTranslation(); - Group.prototype.resetSubgroups = function() { - for (var subgroup in this.subgroups) { - if (this.subgroups.hasOwnProperty(subgroup)) { - this.subgroups[subgroup].visible = false; - } - } - }; + var scaleFrac = scale / scaleOld; + var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac; + var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac; - /** - * Remove an item from the group - * @param {Item} item - */ - Group.prototype.remove = function(item) { - delete this.items[item.id]; - item.setParent(null); + this.areaCenter = {"x" : this._XconvertDOMtoCanvas(pointer.x), + "y" : this._YconvertDOMtoCanvas(pointer.y)}; - // remove from visible items - var index = this.visibleItems.indexOf(item); - if (index != -1) this.visibleItems.splice(index, 1); + this._setScale(scale); + this._setTranslation(tx, ty); + this.updateClustersDefault(); - // TODO: also remove from ordered items? - }; + if (preScaleDragPointer != null) { + var postScaleDragPointer = this.canvasToDOM(preScaleDragPointer); + this.drag.pointer.x = postScaleDragPointer.x; + this.drag.pointer.y = postScaleDragPointer.y; + } + this._redraw(); - /** - * Remove an item from the corresponding DataSet - * @param {Item} item - */ - Group.prototype.removeFromDataSet = function(item) { - this.itemSet.removeItem(item.id); + if (scaleOld < scale) { + this.emit("zoom", {direction:"+"}); + } + else { + this.emit("zoom", {direction:"-"}); + } + + return scale; + } }; /** - * Reorder the items + * Event handler for mouse wheel event, used to zoom the timeline + * See http://adomas.org/javascript-mouse-wheel/ + * https://github.com/EightMedia/hammer.js/issues/256 + * @param {MouseEvent} event + * @private */ - Group.prototype.order = function() { - var array = util.toArray(this.items); - var startArray = []; - var endArray = []; + Network.prototype._onMouseWheel = function(event) { + // retrieve delta + var delta = 0; + if (event.wheelDelta) { /* IE/Opera. */ + delta = event.wheelDelta/120; + } else if (event.detail) { /* Mozilla case. */ + // In Mozilla, sign of delta is different than in IE. + // Also, delta is multiple of 3. + delta = -event.detail/3; + } - for (var i = 0; i < array.length; i++) { - if (array[i].data.end !== undefined) { - endArray.push(array[i]); + // If delta is nonzero, handle it. + // Basically, delta is now positive if wheel was scrolled up, + // and negative, if wheel was scrolled down. + if (delta) { + + // calculate the new scale + var scale = this._getScale(); + var zoom = delta / 10; + if (delta < 0) { + zoom = zoom / (1 - zoom); } - startArray.push(array[i]); + scale *= (1 + zoom); + + // calculate the pointer location + var gesture = hammerUtil.fakeGesture(this, event); + var pointer = this._getPointer(gesture.center); + + // apply the new scale + this._zoom(scale, pointer); } - this.orderedItems = { - byStart: startArray, - byEnd: endArray - }; - stack.orderByStart(this.orderedItems.byStart); - stack.orderByEnd(this.orderedItems.byEnd); + // Prevent default actions caused by mouse wheel. + event.preventDefault(); }; /** - * Update the visible items - * @param {{byStart: Item[], byEnd: Item[]}} orderedItems All items ordered by start date and by end date - * @param {Item[]} visibleItems The previously visible items. - * @param {{start: number, end: number}} range Visible range - * @return {Item[]} visibleItems The new visible items. + * Mouse move handler for checking whether the title moves over a node with a title. + * @param {Event} event * @private */ - Group.prototype._updateVisibleItems = function(orderedItems, oldVisibleItems, range) { - var visibleItems = []; - var visibleItemsLookup = {}; // we keep this to quickly look up if an item already exists in the list without using indexOf on visibleItems - var interval = (range.end - range.start) / 4; - var lowerBound = range.start - interval; - var upperBound = range.end + interval; - var item, i; + Network.prototype._onMouseMoveTitle = function (event) { + var gesture = hammerUtil.fakeGesture(this, event); + var pointer = this._getPointer(gesture.center); - // this function is used to do the binary search. - var searchFunction = function (value) { - if (value < lowerBound) {return -1;} - else if (value <= upperBound) {return 0;} - else {return 1;} + // check if the previously selected node is still selected + if (this.popupObj) { + this._checkHidePopup(pointer); } - // first check if the items that were in view previously are still in view. - // IMPORTANT: this handles the case for the items with startdate before the window and enddate after the window! - // also cleans up invisible items. - if (oldVisibleItems.length > 0) { - for (i = 0; i < oldVisibleItems.length; i++) { - this._checkIfVisibleWithReference(oldVisibleItems[i], visibleItems, visibleItemsLookup, range); - } + // start a timeout that will check if the mouse is positioned above + // an element + var me = this; + var checkShow = function() { + me._checkShowPopup(pointer); + }; + if (this.popupTimer) { + clearInterval(this.popupTimer); // stop any running calculationTimer + } + if (!this.drag.dragging) { + this.popupTimer = setTimeout(checkShow, this.constants.tooltip.delay); } - // we do a binary search for the items that have only start values. - var initialPosByStart = util.binarySearchCustom(orderedItems.byStart, searchFunction, 'data','start'); - - // trace the visible items from the inital start pos both ways until an invisible item is found, we only look at the start values. - this._traceVisible(initialPosByStart, orderedItems.byStart, visibleItems, visibleItemsLookup, function (item) { - return (item.data.start < lowerBound || item.data.start > upperBound); - }); - // if the window has changed programmatically without overlapping the old window, the ranged items with start < lowerBound and end > upperbound are not shown. - // We therefore have to brute force check all items in the byEnd list - if (this.checkRangedItems == true) { - this.checkRangedItems = false; - for (i = 0; i < orderedItems.byEnd.length; i++) { - this._checkIfVisibleWithReference(orderedItems.byEnd[i], visibleItems, visibleItemsLookup, range); + /** + * Adding hover highlights + */ + if (this.constants.hover == true) { + // removing all hover highlights + for (var edgeId in this.hoverObj.edges) { + if (this.hoverObj.edges.hasOwnProperty(edgeId)) { + this.hoverObj.edges[edgeId].hover = false; + delete this.hoverObj.edges[edgeId]; + } } - } - else { - // we do a binary search for the items that have defined end times. - var initialPosByEnd = util.binarySearchCustom(orderedItems.byEnd, searchFunction, 'data','end'); - - // trace the visible items from the inital start pos both ways until an invisible item is found, we only look at the end values. - this._traceVisible(initialPosByEnd, orderedItems.byEnd, visibleItems, visibleItemsLookup, function (item) { - return (item.data.end < lowerBound || item.data.end > upperBound); - }); - } + // adding hover highlights + var obj = this._getNodeAt(pointer); + if (obj == null) { + obj = this._getEdgeAt(pointer); + } + if (obj != null) { + this._hoverObject(obj); + } - // finally, we reposition all the visible items. - for (i = 0; i < visibleItems.length; i++) { - item = visibleItems[i]; - if (!item.displayed) item.show(); - // reposition item horizontally - item.repositionX(); + // removing all node hover highlights except for the selected one. + for (var nodeId in this.hoverObj.nodes) { + if (this.hoverObj.nodes.hasOwnProperty(nodeId)) { + if (obj instanceof Node && obj.id != nodeId || obj instanceof Edge || obj == null) { + this._blurObject(this.hoverObj.nodes[nodeId]); + delete this.hoverObj.nodes[nodeId]; + } + } + } + this.redraw(); } - - // debug - //console.log("new line") - //if (this.groupId == null) { - // for (i = 0; i < orderedItems.byStart.length; i++) { - // item = orderedItems.byStart[i].data; - // console.log('start',i,initialPosByStart, item.start.valueOf(), item.content, item.start >= lowerBound && item.start <= upperBound,i == initialPosByStart ? "<------------------- HEREEEE" : "") - // } - // for (i = 0; i < orderedItems.byEnd.length; i++) { - // item = orderedItems.byEnd[i].data; - // console.log('rangeEnd',i,initialPosByEnd, item.end.valueOf(), item.content, item.end >= range.start && item.end <= range.end,i == initialPosByEnd ? "<------------------- HEREEEE" : "") - // } - //} - - return visibleItems; }; - Group.prototype._traceVisible = function (initialPos, items, visibleItems, visibleItemsLookup, breakCondition) { - var item; - var i; + /** + * Check if there is an element on the given position in the network + * (a node or edge). If so, and if this element has a title, + * show a popup window with its title. + * + * @param {{x:Number, y:Number}} pointer + * @private + */ + Network.prototype._checkShowPopup = function (pointer) { + var obj = { + left: this._XconvertDOMtoCanvas(pointer.x), + top: this._YconvertDOMtoCanvas(pointer.y), + right: this._XconvertDOMtoCanvas(pointer.x), + bottom: this._YconvertDOMtoCanvas(pointer.y) + }; - if (initialPos != -1) { - for (i = initialPos; i >= 0; i--) { - item = items[i]; - if (breakCondition(item)) { - break; - } - else { - if (visibleItemsLookup[item.id] === undefined) { - visibleItemsLookup[item.id] = true; - visibleItems.push(item); + var id; + var lastPopupNode = this.popupObj; + var nodeUnderCursor = false; + + if (this.popupObj == undefined) { + // search the nodes for overlap, select the top one in case of multiple nodes + var nodes = this.nodes; + var overlappingNodes = []; + for (id in nodes) { + if (nodes.hasOwnProperty(id)) { + var node = nodes[id]; + if (node.isOverlappingWith(obj)) { + if (node.getTitle() !== undefined) { + overlappingNodes.push(id); + } } } } - for (i = initialPos + 1; i < items.length; i++) { - item = items[i]; - if (breakCondition(item)) { - break; - } - else { - if (visibleItemsLookup[item.id] === undefined) { - visibleItemsLookup[item.id] = true; - visibleItems.push(item); + if (overlappingNodes.length > 0) { + // if there are overlapping nodes, select the last one, this is the + // one which is drawn on top of the others + this.popupObj = this.nodes[overlappingNodes[overlappingNodes.length - 1]]; + // if you hover over a node, the title of the edge is not supposed to be shown. + nodeUnderCursor = true; + } + } + + if (this.popupObj === undefined && nodeUnderCursor == false) { + // search the edges for overlap + var edges = this.edges; + var overlappingEdges = []; + for (id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + if (edge.connected && (edge.getTitle() !== undefined) && + edge.isOverlappingWith(obj)) { + overlappingEdges.push(id); } } } + + if (overlappingEdges.length > 0) { + this.popupObj = this.edges[overlappingEdges[overlappingEdges.length - 1]]; + } } - } + if (this.popupObj) { + // show popup message window + if (this.popupObj != lastPopupNode) { + var me = this; + if (!me.popup) { + me.popup = new Popup(me.frame, me.constants.tooltip); + } - /** - * this function is very similar to the _checkIfInvisible() but it does not - * return booleans, hides the item if it should not be seen and always adds to - * the visibleItems. - * this one is for brute forcing and hiding. - * - * @param {Item} item - * @param {Array} visibleItems - * @param {{start:number, end:number}} range - * @private - */ - Group.prototype._checkIfVisible = function(item, visibleItems, range) { - if (item.isVisible(range)) { - if (!item.displayed) item.show(); - // reposition item horizontally - item.repositionX(); - visibleItems.push(item); + // adjust a small offset such that the mouse cursor is located in the + // bottom left location of the popup, and you can easily move over the + // popup area + me.popup.setPosition(pointer.x - 3, pointer.y - 3); + me.popup.setText(me.popupObj.getTitle()); + me.popup.show(); } - else { - if (item.displayed) item.hide(); + } + else { + if (this.popup) { + this.popup.hide(); } + } }; /** - * this function is very similar to the _checkIfInvisible() but it does not - * return booleans, hides the item if it should not be seen and always adds to - * the visibleItems. - * this one is for brute forcing and hiding. - * - * @param {Item} item - * @param {Array} visibleItems - * @param {{start:number, end:number}} range + * Check if the popup must be hided, which is the case when the mouse is no + * longer hovering on the object + * @param {{x:Number, y:Number}} pointer * @private */ - Group.prototype._checkIfVisibleWithReference = function(item, visibleItems, visibleItemsLookup, range) { - if (item.isVisible(range)) { - if (visibleItemsLookup[item.id] === undefined) { - visibleItemsLookup[item.id] = true; - visibleItems.push(item); + Network.prototype._checkHidePopup = function (pointer) { + if (!this.popupObj || !this._getNodeAt(pointer) ) { + this.popupObj = undefined; + if (this.popup) { + this.popup.hide(); } } - else { - if (item.displayed) item.hide(); - } }; + /** + * Set a new size for the network + * @param {string} width Width in pixels or percentage (for example '800px' + * or '50%') + * @param {string} height Height in pixels or percentage (for example '400px' + * or '30%') + */ + Network.prototype.setSize = function(width, height) { + var emitEvent = false; + var oldWidth = this.frame.canvas.width; + var oldHeight = this.frame.canvas.height; + if (width != this.constants.width || height != this.constants.height || this.frame.style.width != width || this.frame.style.height != height) { + this.frame.style.width = width; + this.frame.style.height = height; - module.exports = Group; - + this.frame.canvas.style.width = '100%'; + this.frame.canvas.style.height = '100%'; -/***/ }, -/* 28 */ -/***/ function(module, exports, __webpack_require__) { + this.frame.canvas.width = this.frame.canvas.clientWidth * this.pixelRatio; + this.frame.canvas.height = this.frame.canvas.clientHeight * this.pixelRatio; - // Utility functions for ordering and stacking of items - var EPSILON = 0.001; // used when checking collisions, to prevent round-off errors + this.constants.width = width; + this.constants.height = height; - /** - * Order items by their start data - * @param {Item[]} items - */ - exports.orderByStart = function(items) { - items.sort(function (a, b) { - return a.data.start - b.data.start; - }); - }; + emitEvent = true; + } + else { + // this would adapt the width of the canvas to the width from 100% if and only if + // there is a change. - /** - * Order items by their end date. If they have no end date, their start date - * is used. - * @param {Item[]} items - */ - exports.orderByEnd = function(items) { - items.sort(function (a, b) { - var aTime = ('end' in a.data) ? a.data.end : a.data.start, - bTime = ('end' in b.data) ? b.data.end : b.data.start; + if (this.frame.canvas.width != this.frame.canvas.clientWidth * this.pixelRatio) { + this.frame.canvas.width = this.frame.canvas.clientWidth * this.pixelRatio; + emitEvent = true; + } + if (this.frame.canvas.height != this.frame.canvas.clientHeight * this.pixelRatio) { + this.frame.canvas.height = this.frame.canvas.clientHeight * this.pixelRatio; + emitEvent = true; + } + } - return aTime - bTime; - }); + if (emitEvent == true) { + this.emit('resize', {width:this.frame.canvas.width * this.pixelRatio,height:this.frame.canvas.height * this.pixelRatio, oldWidth: oldWidth * this.pixelRatio, oldHeight: oldHeight * this.pixelRatio}); + } }; /** - * Adjust vertical positions of the items such that they don't overlap each - * other. - * @param {Item[]} items - * All visible items - * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin - * Margins between items and between items and the axis. - * @param {boolean} [force=false] - * If true, all items will be repositioned. If false (default), only - * items having a top===null will be re-stacked + * Set a data set with nodes for the network + * @param {Array | DataSet | DataView} nodes The data containing the nodes. + * @private */ - exports.stack = function(items, margin, force) { - var i, iMax; + Network.prototype._setNodes = function(nodes) { + var oldNodesData = this.nodesData; - if (force) { - // reset top position of all items - for (i = 0, iMax = items.length; i < iMax; i++) { - items[i].top = null; - } + if (nodes instanceof DataSet || nodes instanceof DataView) { + this.nodesData = nodes; + } + else if (Array.isArray(nodes)) { + this.nodesData = new DataSet(); + this.nodesData.add(nodes); + } + else if (!nodes) { + this.nodesData = new DataSet(); + } + else { + throw new TypeError('Array or DataSet expected'); } - // calculate new, non-overlapping positions - for (i = 0, iMax = items.length; i < iMax; i++) { - var item = items[i]; - if (item.stack && item.top === null) { - // initialize top position - item.top = margin.axis; - - do { - // TODO: optimize checking for overlap. when there is a gap without items, - // you only need to check for items from the next item on, not from zero - var collidingItem = null; - for (var j = 0, jj = items.length; j < jj; j++) { - var other = items[j]; - if (other.top !== null && other !== item && other.stack && exports.collision(item, other, margin.item)) { - collidingItem = other; - break; - } - } - - if (collidingItem != null) { - // There is a collision. Reposition the items above the colliding element - item.top = collidingItem.top + collidingItem.height + margin.item.vertical; - } - } while (collidingItem); - } + if (oldNodesData) { + // unsubscribe from old dataset + util.forEach(this.nodesListeners, function (callback, event) { + oldNodesData.off(event, callback); + }); } - }; + // remove drawn nodes + this.nodes = {}; - /** - * Adjust vertical positions of the items without stacking them - * @param {Item[]} items - * All visible items - * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin - * Margins between items and between items and the axis. - */ - exports.nostack = function(items, margin, subgroups) { - var i, iMax, newTop; + if (this.nodesData) { + // subscribe to new dataset + var me = this; + util.forEach(this.nodesListeners, function (callback, event) { + me.nodesData.on(event, callback); + }); - // reset top position of all items - for (i = 0, iMax = items.length; i < iMax; i++) { - if (items[i].data.subgroup !== undefined) { - newTop = margin.axis; - for (var subgroup in subgroups) { - if (subgroups.hasOwnProperty(subgroup)) { - if (subgroups[subgroup].visible == true && subgroups[subgroup].index < subgroups[items[i].data.subgroup].index) { - newTop += subgroups[subgroup].height + margin.item.vertical; - } - } - } - items[i].top = newTop; - } - else { - items[i].top = margin.axis; - } + // draw all new nodes + var ids = this.nodesData.getIds(); + this._addNodes(ids); } + this._updateSelection(); }; /** - * Test if the two provided items collide - * The items must have parameters left, width, top, and height. - * @param {Item} a The first item - * @param {Item} b The second item - * @param {{horizontal: number, vertical: number}} margin - * An object containing a horizontal and vertical - * minimum required margin. - * @return {boolean} true if a and b collide, else false + * Add nodes + * @param {Number[] | String[]} ids + * @private */ - exports.collision = function(a, b, margin) { - return ((a.left - margin.horizontal + EPSILON) < (b.left + b.width) && - (a.left + a.width + margin.horizontal - EPSILON) > b.left && - (a.top - margin.vertical + EPSILON) < (b.top + b.height) && - (a.top + a.height + margin.vertical - EPSILON) > b.top); - }; - - -/***/ }, -/* 29 */ -/***/ function(module, exports, __webpack_require__) { + Network.prototype._addNodes = function(ids) { + var id; + for (var i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + var data = this.nodesData.get(id); + var node = new Node(data, this.images, this.groups, this.constants); + this.nodes[id] = node; // note: this may replace an existing node + if ((node.xFixed == false || node.yFixed == false) && (node.x === null || node.y === null)) { + var radius = 10 * 0.1*ids.length + 10; + var angle = 2 * Math.PI * Math.random(); + if (node.xFixed == false) {node.x = radius * Math.cos(angle);} + if (node.yFixed == false) {node.y = radius * Math.sin(angle);} + } + this.moving = true; + } - var Hammer = __webpack_require__(19); - var Item = __webpack_require__(30); + this._updateNodeIndexList(); + if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { + this._resetLevels(); + this._setupHierarchicalLayout(); + } + this._updateCalculationNodes(); + this._reconnectEdges(); + this._updateValueRange(this.nodes); + this.updateLabels(); + }; /** - * @constructor RangeItem - * @extends Item - * @param {Object} data Object containing parameters start, end - * content, className. - * @param {{toScreen: function, toTime: function}} conversion - * Conversion functions from time to screen and vice versa - * @param {Object} [options] Configuration options - * // TODO: describe options + * Update existing nodes, or create them when not yet existing + * @param {Number[] | String[]} ids + * @private */ - function RangeItem (data, conversion, options) { - this.props = { - content: { - width: 0 - } - }; - this.overflow = false; // if contents can overflow (css styling), this flag is set to true - - // validate data - if (data) { - if (data.start == undefined) { - throw new Error('Property "start" missing in item ' + data.id); + Network.prototype._updateNodes = function(ids,changedData) { + var nodes = this.nodes; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + var node = nodes[id]; + var data = changedData[i]; + if (node) { + // update node + node.setProperties(data, this.constants); } - if (data.end == undefined) { - throw new Error('Property "end" missing in item ' + data.id); + else { + // create node + node = new Node(properties, this.images, this.groups, this.constants); + nodes[id] = node; } } - - Item.call(this, data, conversion, options); - } - - RangeItem.prototype = new Item (null, null, null); - - RangeItem.prototype.baseClassName = 'item range'; + this.moving = true; + if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { + this._resetLevels(); + this._setupHierarchicalLayout(); + } + this._updateNodeIndexList(); + this._updateValueRange(nodes); + }; /** - * Check whether this item is visible inside given range - * @returns {{start: Number, end: Number}} range with a timestamp for start and end - * @returns {boolean} True if visible + * Remove existing nodes. If nodes do not exist, the method will just ignore it. + * @param {Number[] | String[]} ids + * @private */ - RangeItem.prototype.isVisible = function(range) { - // determine visibility - return (this.data.start < range.end) && (this.data.end > range.start); + Network.prototype._removeNodes = function(ids) { + var nodes = this.nodes; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + delete nodes[id]; + } + this._updateNodeIndexList(); + if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { + this._resetLevels(); + this._setupHierarchicalLayout(); + } + this._updateCalculationNodes(); + this._reconnectEdges(); + this._updateSelection(); + this._updateValueRange(nodes); }; /** - * Repaint the item + * Load edges by reading the data table + * @param {Array | DataSet | DataView} edges The data containing the edges. + * @private + * @private */ - RangeItem.prototype.redraw = function() { - var dom = this.dom; - if (!dom) { - // create DOM - this.dom = {}; - dom = this.dom; - - // background box - dom.box = document.createElement('div'); - // className is updated in redraw() - - // contents box - dom.content = document.createElement('div'); - dom.content.className = 'content'; - dom.box.appendChild(dom.content); - - // attach this item as attribute - dom.box['timeline-item'] = this; + Network.prototype._setEdges = function(edges) { + var oldEdgesData = this.edgesData; - this.dirty = true; + if (edges instanceof DataSet || edges instanceof DataView) { + this.edgesData = edges; } - - // append DOM to parent DOM - if (!this.parent) { - throw new Error('Cannot redraw item: no parent attached'); + else if (Array.isArray(edges)) { + this.edgesData = new DataSet(); + this.edgesData.add(edges); } - if (!dom.box.parentNode) { - var foreground = this.parent.dom.foreground; - if (!foreground) { - throw new Error('Cannot redraw item: parent has no foreground container element'); - } - foreground.appendChild(dom.box); + else if (!edges) { + this.edgesData = new DataSet(); + } + else { + throw new TypeError('Array or DataSet expected'); } - this.displayed = true; - - // Update DOM when item is marked dirty. An item is marked dirty when: - // - the item is not yet rendered - // - the item's data is changed - // - the item is selected/deselected - if (this.dirty) { - this._updateContents(this.dom.content); - this._updateTitle(this.dom.box); - this._updateDataAttributes(this.dom.box); - this._updateStyle(this.dom.box); - // update class - var className = (this.data.className ? (' ' + this.data.className) : '') + - (this.selected ? ' selected' : ''); - dom.box.className = this.baseClassName + className; + if (oldEdgesData) { + // unsubscribe from old dataset + util.forEach(this.edgesListeners, function (callback, event) { + oldEdgesData.off(event, callback); + }); + } - // determine from css whether this box has overflow - this.overflow = window.getComputedStyle(dom.content).overflow !== 'hidden'; + // remove drawn edges + this.edges = {}; - // recalculate size - // turn off max-width to be able to calculate the real width - // this causes an extra browser repaint/reflow, but so be it - this.dom.content.style.maxWidth = 'none'; - this.props.content.width = this.dom.content.offsetWidth; - this.height = this.dom.box.offsetHeight; - this.dom.content.style.maxWidth = ''; + if (this.edgesData) { + // subscribe to new dataset + var me = this; + util.forEach(this.edgesListeners, function (callback, event) { + me.edgesData.on(event, callback); + }); - this.dirty = false; + // draw all new nodes + var ids = this.edgesData.getIds(); + this._addEdges(ids); } - this._repaintDeleteButton(dom.box); - this._repaintDragLeft(); - this._repaintDragRight(); + this._reconnectEdges(); }; /** - * Show the item in the DOM (when not already visible). The items DOM will - * be created when needed. + * Add edges + * @param {Number[] | String[]} ids + * @private */ - RangeItem.prototype.show = function() { - if (!this.displayed) { - this.redraw(); - } - }; + Network.prototype._addEdges = function (ids) { + var edges = this.edges, + edgesData = this.edgesData; - /** - * Hide the item from the DOM (when visible) - * @return {Boolean} changed - */ - RangeItem.prototype.hide = function() { - if (this.displayed) { - var box = this.dom.box; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; - if (box.parentNode) { - box.parentNode.removeChild(box); + var oldEdge = edges[id]; + if (oldEdge) { + oldEdge.disconnect(); } - this.top = null; - this.left = null; - - this.displayed = false; + var data = edgesData.get(id, {"showInternalIds" : true}); + edges[id] = new Edge(data, this, this.constants); + } + this.moving = true; + this._updateValueRange(edges); + this._createBezierNodes(); + this._updateCalculationNodes(); + if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { + this._resetLevels(); + this._setupHierarchicalLayout(); } }; /** - * Reposition the item horizontally - * @Override + * Update existing edges, or create them when not yet existing + * @param {Number[] | String[]} ids + * @private */ - RangeItem.prototype.repositionX = function() { - var parentWidth = this.parent.width; - var start = this.conversion.toScreen(this.data.start); - var end = this.conversion.toScreen(this.data.end); - var contentLeft; - var contentWidth; - - // limit the width of the this, as browsers cannot draw very wide divs - if (start < -parentWidth) { - start = -parentWidth; - } - if (end > 2 * parentWidth) { - end = 2 * parentWidth; - } - var boxWidth = Math.max(end - start, 1); - - if (this.overflow) { - this.left = start; - this.width = boxWidth + this.props.content.width; - contentWidth = this.props.content.width; + Network.prototype._updateEdges = function (ids) { + var edges = this.edges, + edgesData = this.edgesData; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; - // Note: The calculation of width is an optimistic calculation, giving - // a width which will not change when moving the Timeline - // So no re-stacking needed, which is nicer for the eye; - } - else { - this.left = start; - this.width = boxWidth; - contentWidth = Math.min(end - start - 2 * this.options.padding, this.props.content.width); + var data = edgesData.get(id); + var edge = edges[id]; + if (edge) { + // update edge + edge.disconnect(); + edge.setProperties(data, this.constants); + edge.connect(); + } + else { + // create edge + edge = new Edge(data, this, this.constants); + this.edges[id] = edge; + } } - this.dom.box.style.left = this.left + 'px'; - this.dom.box.style.width = boxWidth + 'px'; - - switch (this.options.align) { - case 'left': - this.dom.content.style.left = '0'; - break; - - case 'right': - this.dom.content.style.left = Math.max((boxWidth - contentWidth - 2 * this.options.padding), 0) + 'px'; - break; - - case 'center': - this.dom.content.style.left = Math.max((boxWidth - contentWidth - 2 * this.options.padding) / 2, 0) + 'px'; - break; - - default: // 'auto' - // when range exceeds left of the window, position the contents at the left of the visible area - if (this.overflow) { - if (end > 0) { - contentLeft = Math.max(-start, 0); - } - else { - contentLeft = -contentWidth; // ensure it's not visible anymore - } - } - else { - if (start < 0) { - contentLeft = Math.min(-start, - (end - start - contentWidth - 2 * this.options.padding)); - // TODO: remove the need for options.padding. it's terrible. - } - else { - contentLeft = 0; - } - } - this.dom.content.style.left = contentLeft + 'px'; + this._createBezierNodes(); + if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { + this._resetLevels(); + this._setupHierarchicalLayout(); } + this.moving = true; + this._updateValueRange(edges); }; /** - * Reposition the item vertically - * @Override + * Remove existing edges. Non existing ids will be ignored + * @param {Number[] | String[]} ids + * @private */ - RangeItem.prototype.repositionY = function() { - var orientation = this.options.orientation, - box = this.dom.box; - - if (orientation == 'top') { - box.style.top = this.top + 'px'; + Network.prototype._removeEdges = function (ids) { + var edges = this.edges; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + var edge = edges[id]; + if (edge) { + if (edge.via != null) { + delete this.sectors['support']['nodes'][edge.via.id]; + } + edge.disconnect(); + delete edges[id]; + } } - else { - box.style.top = (this.parent.height - this.top - this.height) + 'px'; + + this.moving = true; + this._updateValueRange(edges); + if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { + this._resetLevels(); + this._setupHierarchicalLayout(); } + this._updateCalculationNodes(); }; /** - * Repaint a drag area on the left side of the range when the range is selected - * @protected + * Reconnect all edges + * @private */ - RangeItem.prototype._repaintDragLeft = function () { - if (this.selected && this.options.editable.updateTime && !this.dom.dragLeft) { - // create and show drag area - var dragLeft = document.createElement('div'); - dragLeft.className = 'drag-left'; - dragLeft.dragLeftItem = this; - - // TODO: this should be redundant? - Hammer(dragLeft, { - preventDefault: true - }).on('drag', function () { - //console.log('drag left') - }); - - this.dom.box.appendChild(dragLeft); - this.dom.dragLeft = dragLeft; + Network.prototype._reconnectEdges = function() { + var id, + nodes = this.nodes, + edges = this.edges; + for (id in nodes) { + if (nodes.hasOwnProperty(id)) { + nodes[id].edges = []; + nodes[id].dynamicEdges = []; + } } - else if (!this.selected && this.dom.dragLeft) { - // delete drag area - if (this.dom.dragLeft.parentNode) { - this.dom.dragLeft.parentNode.removeChild(this.dom.dragLeft); + + for (id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + edge.from = null; + edge.to = null; + edge.connect(); } - this.dom.dragLeft = null; } }; /** - * Repaint a drag area on the right side of the range when the range is selected - * @protected + * Update the values of all object in the given array according to the current + * value range of the objects in the array. + * @param {Object} obj An object containing a set of Edges or Nodes + * The objects must have a method getValue() and + * setValueRange(min, max). + * @private */ - RangeItem.prototype._repaintDragRight = function () { - if (this.selected && this.options.editable.updateTime && !this.dom.dragRight) { - // create and show drag area - var dragRight = document.createElement('div'); - dragRight.className = 'drag-right'; - dragRight.dragRightItem = this; - - // TODO: this should be redundant? - Hammer(dragRight, { - preventDefault: true - }).on('drag', function () { - //console.log('drag right') - }); + Network.prototype._updateValueRange = function(obj) { + var id; - this.dom.box.appendChild(dragRight); - this.dom.dragRight = dragRight; + // determine the range of the objects + var valueMin = undefined; + var valueMax = undefined; + for (id in obj) { + if (obj.hasOwnProperty(id)) { + var value = obj[id].getValue(); + if (value !== undefined) { + valueMin = (valueMin === undefined) ? value : Math.min(value, valueMin); + valueMax = (valueMax === undefined) ? value : Math.max(value, valueMax); + } + } } - else if (!this.selected && this.dom.dragRight) { - // delete drag area - if (this.dom.dragRight.parentNode) { - this.dom.dragRight.parentNode.removeChild(this.dom.dragRight); + + // adjust the range of all objects + if (valueMin !== undefined && valueMax !== undefined) { + for (id in obj) { + if (obj.hasOwnProperty(id)) { + obj[id].setValueRange(valueMin, valueMax); + } } - this.dom.dragRight = null; } }; - module.exports = RangeItem; + /** + * Redraw the network with the current data + * chart will be resized too. + */ + Network.prototype.redraw = function() { + this.setSize(this.constants.width, this.constants.height); + this._redraw(); + }; + /** + * Redraw the network with the current data + * @param hidden | used to get the first estimate of the node sizes. only the nodes are drawn after which they are quickly drawn over. + * @private + */ + Network.prototype._redraw = function(hidden) { + var ctx = this.frame.canvas.getContext('2d'); -/***/ }, -/* 30 */ -/***/ function(module, exports, __webpack_require__) { + ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); - var Hammer = __webpack_require__(19); - var util = __webpack_require__(1); + // clear the canvas + var w = this.frame.canvas.width * this.pixelRatio; + var h = this.frame.canvas.height * this.pixelRatio; + ctx.clearRect(0, 0, w, h); - /** - * @constructor Item - * @param {Object} data Object containing (optional) parameters type, - * start, end, content, group, className. - * @param {{toScreen: function, toTime: function}} conversion - * Conversion functions from time to screen and vice versa - * @param {Object} options Configuration options - * // TODO: describe available options - */ - function Item (data, conversion, options) { - this.id = null; - this.parent = null; - this.data = data; - this.dom = null; - this.conversion = conversion || {}; - this.options = options || {}; + // set scaling and translation + ctx.save(); + ctx.translate(this.translation.x, this.translation.y); + ctx.scale(this.scale, this.scale); - this.selected = false; - this.displayed = false; - this.dirty = true; + this.canvasTopLeft = { + "x": this._XconvertDOMtoCanvas(0), + "y": this._YconvertDOMtoCanvas(0) + }; + this.canvasBottomRight = { + "x": this._XconvertDOMtoCanvas(this.frame.canvas.clientWidth * this.pixelRatio), + "y": this._YconvertDOMtoCanvas(this.frame.canvas.clientHeight * this.pixelRatio) + }; - this.top = null; - this.left = null; - this.width = null; - this.height = null; - } + if (!(hidden == true)) { + this._doInAllSectors("_drawAllSectorNodes", ctx); + if (this.drag.dragging == false || this.drag.dragging === undefined || this.constants.hideEdgesOnDrag == false) { + this._doInAllSectors("_drawEdges", ctx); + } + } - Item.prototype.stack = true; + if (this.drag.dragging == false || this.drag.dragging === undefined || this.constants.hideNodesOnDrag == false) { + this._doInAllSectors("_drawNodes",ctx,false); + } - /** - * Select current item - */ - Item.prototype.select = function() { - this.selected = true; - this.dirty = true; - if (this.displayed) this.redraw(); + if (!(hidden == true)) { + if (this.controlNodesActive == true) { + this._doInAllSectors("_drawControlNodes", ctx); + } + } + + // this._doInSupportSector("_drawNodes",ctx,true); + // this._drawTree(ctx,"#F00F0F"); + + // restore original scaling and translation + ctx.restore(); + + if (hidden == true) { + ctx.clearRect(0, 0, w, h); + } }; /** - * Unselect current item + * Set the translation of the network + * @param {Number} offsetX Horizontal offset + * @param {Number} offsetY Vertical offset + * @private */ - Item.prototype.unselect = function() { - this.selected = false; - this.dirty = true; - if (this.displayed) this.redraw(); + Network.prototype._setTranslation = function(offsetX, offsetY) { + if (this.translation === undefined) { + this.translation = { + x: 0, + y: 0 + }; + } + + if (offsetX !== undefined) { + this.translation.x = offsetX; + } + if (offsetY !== undefined) { + this.translation.y = offsetY; + } + + this.emit('viewChanged'); }; /** - * Set data for the item. Existing data will be updated. The id should not - * be changed. When the item is displayed, it will be redrawn immediately. - * @param {Object} data + * Get the translation of the network + * @return {Object} translation An object with parameters x and y, both a number + * @private */ - Item.prototype.setData = function(data) { - this.data = data; - this.dirty = true; - if (this.displayed) this.redraw(); + Network.prototype._getTranslation = function() { + return { + x: this.translation.x, + y: this.translation.y + }; }; /** - * Set a parent for the item - * @param {ItemSet | Group} parent + * Scale the network + * @param {Number} scale Scaling factor 1.0 is unscaled + * @private */ - Item.prototype.setParent = function(parent) { - if (this.displayed) { - this.hide(); - this.parent = parent; - if (this.parent) { - this.show(); - } - } - else { - this.parent = parent; - } + Network.prototype._setScale = function(scale) { + this.scale = scale; }; /** - * Check whether this item is visible inside given range - * @returns {{start: Number, end: Number}} range with a timestamp for start and end - * @returns {boolean} True if visible + * Get the current scale of the network + * @return {Number} scale Scaling factor 1.0 is unscaled + * @private */ - Item.prototype.isVisible = function(range) { - // Should be implemented by Item implementations - return false; + Network.prototype._getScale = function() { + return this.scale; }; /** - * Show the Item in the DOM (when not already visible) - * @return {Boolean} changed + * Convert the X coordinate in DOM-space (coordinate point in browser relative to the container div) to + * the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon) + * @param {number} x + * @returns {number} + * @private */ - Item.prototype.show = function() { - return false; + Network.prototype._XconvertDOMtoCanvas = function(x) { + return (x - this.translation.x) / this.scale; }; /** - * Hide the Item from the DOM (when visible) - * @return {Boolean} changed + * Convert the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to + * the X coordinate in DOM-space (coordinate point in browser relative to the container div) + * @param {number} x + * @returns {number} + * @private */ - Item.prototype.hide = function() { - return false; + Network.prototype._XconvertCanvasToDOM = function(x) { + return x * this.scale + this.translation.x; }; /** - * Repaint the item + * Convert the Y coordinate in DOM-space (coordinate point in browser relative to the container div) to + * the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon) + * @param {number} y + * @returns {number} + * @private */ - Item.prototype.redraw = function() { - // should be implemented by the item + Network.prototype._YconvertDOMtoCanvas = function(y) { + return (y - this.translation.y) / this.scale; }; /** - * Reposition the Item horizontally + * Convert the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to + * the Y coordinate in DOM-space (coordinate point in browser relative to the container div) + * @param {number} y + * @returns {number} + * @private */ - Item.prototype.repositionX = function() { - // should be implemented by the item + Network.prototype._YconvertCanvasToDOM = function(y) { + return y * this.scale + this.translation.y ; }; + /** - * Reposition the Item vertically + * + * @param {object} pos = {x: number, y: number} + * @returns {{x: number, y: number}} + * @constructor */ - Item.prototype.repositionY = function() { - // should be implemented by the item + Network.prototype.canvasToDOM = function (pos) { + return {x: this._XconvertCanvasToDOM(pos.x), y: this._YconvertCanvasToDOM(pos.y)}; }; /** - * Repaint a delete button on the top right of the item when the item is selected - * @param {HTMLElement} anchor - * @protected + * + * @param {object} pos = {x: number, y: number} + * @returns {{x: number, y: number}} + * @constructor */ - Item.prototype._repaintDeleteButton = function (anchor) { - if (this.selected && this.options.editable.remove && !this.dom.deleteButton) { - // create and show button - var me = this; - - var deleteButton = document.createElement('div'); - deleteButton.className = 'delete'; - deleteButton.title = 'Delete this item'; - - Hammer(deleteButton, { - preventDefault: true - }).on('tap', function (event) { - me.parent.removeFromDataSet(me); - event.stopPropagation(); - }); - - anchor.appendChild(deleteButton); - this.dom.deleteButton = deleteButton; - } - else if (!this.selected && this.dom.deleteButton) { - // remove button - if (this.dom.deleteButton.parentNode) { - this.dom.deleteButton.parentNode.removeChild(this.dom.deleteButton); - } - this.dom.deleteButton = null; - } + Network.prototype.DOMtoCanvas = function (pos) { + return {x: this._XconvertDOMtoCanvas(pos.x), y: this._YconvertDOMtoCanvas(pos.y)}; }; /** - * Set HTML contents for the item - * @param {Element} element HTML element to fill with the contents + * Redraw all nodes + * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); + * @param {CanvasRenderingContext2D} ctx + * @param {Boolean} [alwaysShow] * @private */ - Item.prototype._updateContents = function (element) { - var content; - if (this.options.template) { - var itemData = this.parent.itemSet.itemsData.get(this.id); // get a clone of the data from the dataset - content = this.options.template(itemData); - } - else { - content = this.data.content; + Network.prototype._drawNodes = function(ctx,alwaysShow) { + if (alwaysShow === undefined) { + alwaysShow = false; } - if(content !== this.content) { - // only replace the content when changed - if (content instanceof Element) { - element.innerHTML = ''; - element.appendChild(content); - } - else if (content != undefined) { - element.innerHTML = content; - } - else { - if (!(this.data.type == 'background' && this.data.content === undefined)) { - throw new Error('Property "content" missing in item ' + this.id); + // first draw the unselected nodes + var nodes = this.nodes; + var selected = []; + + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + nodes[id].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight); + if (nodes[id].isSelected()) { + selected.push(id); + } + else { + if (nodes[id].inArea() || alwaysShow) { + nodes[id].draw(ctx); + } } } + } - this.content = content; + // draw the selected nodes on top + for (var s = 0, sMax = selected.length; s < sMax; s++) { + if (nodes[selected[s]].inArea() || alwaysShow) { + nodes[selected[s]].draw(ctx); + } } }; /** - * Set HTML contents for the item - * @param {Element} element HTML element to fill with the contents + * Redraw all edges + * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); + * @param {CanvasRenderingContext2D} ctx * @private */ - Item.prototype._updateTitle = function (element) { - if (this.data.title != null) { - element.title = this.data.title || ''; - } - else { - element.removeAttribute('title'); + Network.prototype._drawEdges = function(ctx) { + var edges = this.edges; + for (var id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + edge.setScale(this.scale); + if (edge.connected) { + edges[id].draw(ctx); + } + } } }; /** - * Process dataAttributes timeline option and set as data- attributes on dom.content - * @param {Element} element HTML element to which the attributes will be attached + * Redraw all edges + * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); + * @param {CanvasRenderingContext2D} ctx * @private */ - Item.prototype._updateDataAttributes = function(element) { - if (this.options.dataAttributes && this.options.dataAttributes.length > 0) { - var attributes = []; - - if (Array.isArray(this.options.dataAttributes)) { - attributes = this.options.dataAttributes; - } - else if (this.options.dataAttributes == 'all') { - attributes = Object.keys(this.data); - } - else { - return; - } - - for (var i = 0; i < attributes.length; i++) { - var name = attributes[i]; - var value = this.data[name]; - - if (value != null) { - element.setAttribute('data-' + name, value); - } - else { - element.removeAttribute('data-' + name); - } + Network.prototype._drawControlNodes = function(ctx) { + var edges = this.edges; + for (var id in edges) { + if (edges.hasOwnProperty(id)) { + edges[id]._drawControlNodes(ctx); } } }; /** - * Update custom styles of the element - * @param element + * Find a stable position for all nodes * @private */ - Item.prototype._updateStyle = function(element) { - // remove old styles - if (this.style) { - util.removeCssText(element, this.style); - this.style = null; + Network.prototype._stabilize = function() { + if (this.constants.freezeForStabilization == true) { + this._freezeDefinedNodes(); } - // append new styles - if (this.data.style) { - util.addCssText(element, this.data.style); - this.style = this.data.style; + // find stable position + var count = 0; + while (this.moving && count < this.constants.stabilizationIterations) { + this._physicsTick(); + count++; } - }; - - module.exports = Item; - - -/***/ }, -/* 31 */ -/***/ function(module, exports, __webpack_require__) { - - var util = __webpack_require__(1); - var Group = __webpack_require__(27); - - /** - * @constructor BackgroundGroup - * @param {Number | String} groupId - * @param {Object} data - * @param {ItemSet} itemSet - */ - function BackgroundGroup (groupId, data, itemSet) { - Group.call(this, groupId, data, itemSet); - - this.width = 0; - this.height = 0; - this.top = 0; - this.left = 0; - } - - BackgroundGroup.prototype = Object.create(Group.prototype); - - /** - * Repaint this group - * @param {{start: number, end: number}} range - * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin - * @param {boolean} [restack=false] Force restacking of all items - * @return {boolean} Returns true if the group is resized - */ - BackgroundGroup.prototype.redraw = function(range, margin, restack) { - var resized = false; - - this.visibleItems = this._updateVisibleItems(this.orderedItems, this.visibleItems, range); - // calculate actual size - this.width = this.dom.background.offsetWidth; - - // apply new height (just always zero for BackgroundGroup - this.dom.background.style.height = '0'; - - // update vertical position of items after they are re-stacked and the height of the group is calculated - for (var i = 0, ii = this.visibleItems.length; i < ii; i++) { - var item = this.visibleItems[i]; - item.repositionY(margin); + if (this.constants.zoomExtentOnStabilize == true) { + this.zoomExtent(undefined, false, true); } - return resized; + if (this.constants.freezeForStabilization == true) { + this._restoreFrozenNodes(); + } }; /** - * Show this group: attach to the DOM + * When initializing and stabilizing, we can freeze nodes with a predefined position. This greatly speeds up stabilization + * because only the supportnodes for the smoothCurves have to settle. + * + * @private */ - BackgroundGroup.prototype.show = function() { - if (!this.dom.background.parentNode) { - this.itemSet.dom.background.appendChild(this.dom.background); + Network.prototype._freezeDefinedNodes = function() { + var nodes = this.nodes; + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + if (nodes[id].x != null && nodes[id].y != null) { + nodes[id].fixedData.x = nodes[id].xFixed; + nodes[id].fixedData.y = nodes[id].yFixed; + nodes[id].xFixed = true; + nodes[id].yFixed = true; + } + } } }; - module.exports = BackgroundGroup; - - -/***/ }, -/* 32 */ -/***/ function(module, exports, __webpack_require__) { - - var Item = __webpack_require__(30); - var util = __webpack_require__(1); - /** - * @constructor BoxItem - * @extends Item - * @param {Object} data Object containing parameters start - * content, className. - * @param {{toScreen: function, toTime: function}} conversion - * Conversion functions from time to screen and vice versa - * @param {Object} [options] Configuration options - * // TODO: describe available options + * Unfreezes the nodes that have been frozen by _freezeDefinedNodes. + * + * @private */ - function BoxItem (data, conversion, options) { - this.props = { - dot: { - width: 0, - height: 0 - }, - line: { - width: 0, - height: 0 - } - }; - - // validate data - if (data) { - if (data.start == undefined) { - throw new Error('Property "start" missing in item ' + data); + Network.prototype._restoreFrozenNodes = function() { + var nodes = this.nodes; + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + if (nodes[id].fixedData.x != null) { + nodes[id].xFixed = nodes[id].fixedData.x; + nodes[id].yFixed = nodes[id].fixedData.y; + } } } - - Item.call(this, data, conversion, options); - } - - BoxItem.prototype = new Item (null, null, null); - - /** - * Check whether this item is visible inside given range - * @returns {{start: Number, end: Number}} range with a timestamp for start and end - * @returns {boolean} True if visible - */ - BoxItem.prototype.isVisible = function(range) { - // determine visibility - // TODO: account for the real width of the item. Right now we just add 1/4 to the window - var interval = (range.end - range.start) / 4; - return (this.data.start > range.start - interval) && (this.data.start < range.end + interval); }; + /** - * Repaint the item + * Check if any of the nodes is still moving + * @param {number} vmin the minimum velocity considered as 'moving' + * @return {boolean} true if moving, false if non of the nodes is moving + * @private */ - BoxItem.prototype.redraw = function() { - var dom = this.dom; - if (!dom) { - // create DOM - this.dom = {}; - dom = this.dom; - - // create main box - dom.box = document.createElement('DIV'); - - // contents box (inside the background box). used for making margins - dom.content = document.createElement('DIV'); - dom.content.className = 'content'; - dom.box.appendChild(dom.content); - - // line to axis - dom.line = document.createElement('DIV'); - dom.line.className = 'line'; - - // dot on axis - dom.dot = document.createElement('DIV'); - dom.dot.className = 'dot'; - - // attach this item as attribute - dom.box['timeline-item'] = this; - - this.dirty = true; - } - - // append DOM to parent DOM - if (!this.parent) { - throw new Error('Cannot redraw item: no parent attached'); - } - if (!dom.box.parentNode) { - var foreground = this.parent.dom.foreground; - if (!foreground) throw new Error('Cannot redraw item: parent has no foreground container element'); - foreground.appendChild(dom.box); - } - if (!dom.line.parentNode) { - var background = this.parent.dom.background; - if (!background) throw new Error('Cannot redraw item: parent has no background container element'); - background.appendChild(dom.line); - } - if (!dom.dot.parentNode) { - var axis = this.parent.dom.axis; - if (!background) throw new Error('Cannot redraw item: parent has no axis container element'); - axis.appendChild(dom.dot); - } - this.displayed = true; - - // Update DOM when item is marked dirty. An item is marked dirty when: - // - the item is not yet rendered - // - the item's data is changed - // - the item is selected/deselected - if (this.dirty) { - this._updateContents(this.dom.content); - this._updateTitle(this.dom.box); - this._updateDataAttributes(this.dom.box); - this._updateStyle(this.dom.box); - - // update class - var className = (this.data.className? ' ' + this.data.className : '') + - (this.selected ? ' selected' : ''); - dom.box.className = 'item box' + className; - dom.line.className = 'item line' + className; - dom.dot.className = 'item dot' + className; - - // recalculate size - this.props.dot.height = dom.dot.offsetHeight; - this.props.dot.width = dom.dot.offsetWidth; - this.props.line.width = dom.line.offsetWidth; - this.width = dom.box.offsetWidth; - this.height = dom.box.offsetHeight; - - this.dirty = false; + Network.prototype._isMoving = function(vmin) { + var nodes = this.nodes; + for (var id in nodes) { + if (nodes.hasOwnProperty(id) && nodes[id].isMoving(vmin)) { + return true; + } } - - this._repaintDeleteButton(dom.box); + return false; }; + /** - * Show the item in the DOM (when not already displayed). The items DOM will - * be created when needed. + * /** + * Perform one discrete step for all nodes + * + * @private */ - BoxItem.prototype.show = function() { - if (!this.displayed) { - this.redraw(); + Network.prototype._discreteStepNodes = function() { + var interval = this.physicsDiscreteStepsize; + var nodes = this.nodes; + var nodeId; + var nodesPresent = false; + + if (this.constants.maxVelocity > 0) { + for (nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + nodes[nodeId].discreteStepLimited(interval, this.constants.maxVelocity); + nodesPresent = true; + } + } + } + else { + for (nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + nodes[nodeId].discreteStep(interval); + nodesPresent = true; + } + } } - }; - /** - * Hide the item from the DOM (when visible) - */ - BoxItem.prototype.hide = function() { - if (this.displayed) { - var dom = this.dom; + if (nodesPresent == true) { + var vminCorrected = this.constants.minVelocity / Math.max(this.scale,0.05); + if (vminCorrected > 0.5*this.constants.maxVelocity) { + return true; + } + else { + return this._isMoving(vminCorrected); + } + } + return false; + }; - if (dom.box.parentNode) dom.box.parentNode.removeChild(dom.box); - if (dom.line.parentNode) dom.line.parentNode.removeChild(dom.line); - if (dom.dot.parentNode) dom.dot.parentNode.removeChild(dom.dot); - this.top = null; - this.left = null; + Network.prototype._revertPhysicsState = function() { + var nodes = this.nodes; + for (var nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + nodes[nodeId].revertPosition(); + } + } + } - this.displayed = false; + Network.prototype._revertPhysicsTick = function() { + this._doInAllActiveSectors("_revertPhysicsState"); + if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { + this._doInSupportSector("_revertPhysicsState"); } - }; + } /** - * Reposition the item horizontally - * @Override + * A single simulation step (or "tick") in the physics simulation + * + * @private */ - BoxItem.prototype.repositionX = function() { - var start = this.conversion.toScreen(this.data.start); - var align = this.options.align; - var left; - var box = this.dom.box; - var line = this.dom.line; - var dot = this.dom.dot; + Network.prototype._physicsTick = function() { + if (!this.freezeSimulation) { + if (this.moving == true) { + var mainMovingStatus = false; + var supportMovingStatus = false; - // calculate left position of the box - if (align == 'right') { - this.left = start - this.width; - } - else if (align == 'left') { - this.left = start; - } - else { - // default or 'center' - this.left = start - this.width / 2; - } + this._doInAllActiveSectors("_initializeForceCalculation"); + var mainMoving = this._doInAllActiveSectors("_discreteStepNodes"); + if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { + supportMovingStatus = this._doInSupportSector("_discreteStepNodes"); + } - // reposition box - box.style.left = this.left + 'px'; + // gather movement data from all sectors, if one moves, we are NOT stabilzied + for (var i = 0; i < mainMoving.length; i++) {mainMovingStatus = mainMoving[0] || mainMovingStatus;} - // reposition line - line.style.left = (start - this.props.line.width / 2) + 'px'; + // determine if the network has stabilzied + this.moving = mainMovingStatus || supportMovingStatus; - // reposition dot - dot.style.left = (start - this.props.dot.width / 2) + 'px'; + if (this.moving == false) { + this._revertPhysicsTick(); + } + else { + // this is here to ensure that there is no start event when the network is already stable. + if (this.startedStabilization == false) { + this.emit("startStabilization"); + this.startedStabilization = true; + } + } + + this.stabilizationIterations++; + } + } }; + /** - * Reposition the item vertically - * @Override + * This function runs one step of the animation. It calls an x amount of physics ticks and one render tick. + * It reschedules itself at the beginning of the function + * + * @private */ - BoxItem.prototype.repositionY = function() { - var orientation = this.options.orientation; - var box = this.dom.box; - var line = this.dom.line; - var dot = this.dom.dot; - - if (orientation == 'top') { - box.style.top = (this.top || 0) + 'px'; + Network.prototype._animationStep = function() { + // reset the timer so a new scheduled animation step can be set + this.timer = undefined; - line.style.top = '0'; - line.style.height = (this.parent.top + this.top + 1) + 'px'; - line.style.bottom = ''; - } - else { // orientation 'bottom' - var itemSetHeight = this.parent.itemSet.props.height; // TODO: this is nasty - var lineHeight = itemSetHeight - this.parent.top - this.parent.height + this.top; + // handle the keyboad movement + this._handleNavigation(); - box.style.top = (this.parent.height - this.top - this.height || 0) + 'px'; - line.style.top = (itemSetHeight - lineHeight) + 'px'; - line.style.bottom = '0'; - } + // check if the physics have settled + if (this.moving == true) { + var startTime = Date.now(); + this._physicsTick(); + var physicsTime = Date.now() - startTime; - dot.style.top = (-this.props.dot.height / 2) + 'px'; - }; + // run double speed if it is a little graph + if ((this.renderTimestep - this.renderTime > 2 * physicsTime || this.runDoubleSpeed == true) && this.moving == true) { + this._physicsTick(); - module.exports = BoxItem; + // this makes sure there is no jitter. The decision is taken once to run it at double speed. + if (this.renderTime != 0) { + this.runDoubleSpeed = true + } + } + } + var renderStartTime = Date.now(); + this._redraw(); + this.renderTime = Date.now() - renderStartTime; -/***/ }, -/* 33 */ -/***/ function(module, exports, __webpack_require__) { + // this schedules a new animation step + this.start(); + }; - var Item = __webpack_require__(30); + if (typeof window !== 'undefined') { + window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || + window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; + } /** - * @constructor PointItem - * @extends Item - * @param {Object} data Object containing parameters start - * content, className. - * @param {{toScreen: function, toTime: function}} conversion - * Conversion functions from time to screen and vice versa - * @param {Object} [options] Configuration options - * // TODO: describe available options + * Schedule a animation step with the refreshrate interval. */ - function PointItem (data, conversion, options) { - this.props = { - dot: { - top: 0, - width: 0, - height: 0 - }, - content: { - height: 0, - marginLeft: 0 + Network.prototype.start = function() { + if (this.moving == true || this.xIncrement != 0 || this.yIncrement != 0 || this.zoomIncrement != 0 || this.animating == true) { + if (!this.timer) { + if (this.requiresTimeout == true) { + this.timer = window.setTimeout(this._animationStep.bind(this), this.renderTimestep); // wait this.renderTimeStep milliseconds and perform the animation step function + } + else { + this.timer = window.requestAnimationFrame(this._animationStep.bind(this)); // wait this.renderTimeStep milliseconds and perform the animation step function + } } - }; - - // validate data - if (data) { - if (data.start == undefined) { - throw new Error('Property "start" missing in item ' + data); + } + else { + this._redraw(); + // this check is to ensure that the network does not emit these events if it was already stabilized and setOptions is called (setting moving to true and calling start()) + if (this.stabilizationIterations > 1) { + // trigger the "stabilized" event. + // The event is triggered on the next tick, to prevent the case that + // it is fired while initializing the Network, in which case you would not + // be able to catch it + var me = this; + var params = { + iterations: me.stabilizationIterations + }; + this.stabilizationIterations = 0; + this.startedStabilization = false; + setTimeout(function () { + me.emit("stabilized", params); + }, 0); + } + else { + this.stabilizationIterations = 0; } } + }; - Item.call(this, data, conversion, options); - } - - PointItem.prototype = new Item (null, null, null); /** - * Check whether this item is visible inside given range - * @returns {{start: Number, end: Number}} range with a timestamp for start and end - * @returns {boolean} True if visible + * Move the network according to the keyboard presses. + * + * @private */ - PointItem.prototype.isVisible = function(range) { - // determine visibility - // TODO: account for the real width of the item. Right now we just add 1/4 to the window - var interval = (range.end - range.start) / 4; - return (this.data.start > range.start - interval) && (this.data.start < range.end + interval); + Network.prototype._handleNavigation = function() { + if (this.xIncrement != 0 || this.yIncrement != 0) { + var translation = this._getTranslation(); + this._setTranslation(translation.x+this.xIncrement, translation.y+this.yIncrement); + } + if (this.zoomIncrement != 0) { + var center = { + x: this.frame.canvas.clientWidth / 2, + y: this.frame.canvas.clientHeight / 2 + }; + this._zoom(this.scale*(1 + this.zoomIncrement), center); + } }; + /** - * Repaint the item + * Freeze the _animationStep */ - PointItem.prototype.redraw = function() { - var dom = this.dom; - if (!dom) { - // create DOM - this.dom = {}; - dom = this.dom; - - // background box - dom.point = document.createElement('div'); - // className is updated in redraw() - - // contents box, right from the dot - dom.content = document.createElement('div'); - dom.content.className = 'content'; - dom.point.appendChild(dom.content); - - // dot at start - dom.dot = document.createElement('div'); - dom.point.appendChild(dom.dot); + Network.prototype.toggleFreeze = function() { + if (this.freezeSimulation == false) { + this.freezeSimulation = true; + } + else { + this.freezeSimulation = false; + this.start(); + } + }; - // attach this item as attribute - dom.point['timeline-item'] = this; - this.dirty = true; + /** + * This function cleans the support nodes if they are not needed and adds them when they are. + * + * @param {boolean} [disableStart] + * @private + */ + Network.prototype._configureSmoothCurves = function(disableStart) { + if (disableStart === undefined) { + disableStart = true; } - - // append DOM to parent DOM - if (!this.parent) { - throw new Error('Cannot redraw item: no parent attached'); + if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { + this._createBezierNodes(); + // cleanup unused support nodes + for (var nodeId in this.sectors['support']['nodes']) { + if (this.sectors['support']['nodes'].hasOwnProperty(nodeId)) { + if (this.edges[this.sectors['support']['nodes'][nodeId].parentEdgeId] === undefined) { + delete this.sectors['support']['nodes'][nodeId]; + } + } + } } - if (!dom.point.parentNode) { - var foreground = this.parent.dom.foreground; - if (!foreground) { - throw new Error('Cannot redraw item: parent has no foreground container element'); + else { + // delete the support nodes + this.sectors['support']['nodes'] = {}; + for (var edgeId in this.edges) { + if (this.edges.hasOwnProperty(edgeId)) { + this.edges[edgeId].via = null; + } } - foreground.appendChild(dom.point); } - this.displayed = true; - - // Update DOM when item is marked dirty. An item is marked dirty when: - // - the item is not yet rendered - // - the item's data is changed - // - the item is selected/deselected - if (this.dirty) { - this._updateContents(this.dom.content); - this._updateTitle(this.dom.point); - this._updateDataAttributes(this.dom.point); - this._updateStyle(this.dom.point); - // update class - var className = (this.data.className? ' ' + this.data.className : '') + - (this.selected ? ' selected' : ''); - dom.point.className = 'item point' + className; - dom.dot.className = 'item dot' + className; - // recalculate size - this.width = dom.point.offsetWidth; - this.height = dom.point.offsetHeight; - this.props.dot.width = dom.dot.offsetWidth; - this.props.dot.height = dom.dot.offsetHeight; - this.props.content.height = dom.content.offsetHeight; + this._updateCalculationNodes(); + if (!disableStart) { + this.moving = true; + this.start(); + } + }; - // resize contents - dom.content.style.marginLeft = 2 * this.props.dot.width + 'px'; - //dom.content.style.marginRight = ... + 'px'; // TODO: margin right - dom.dot.style.top = ((this.height - this.props.dot.height) / 2) + 'px'; - dom.dot.style.left = (this.props.dot.width / 2) + 'px'; + /** + * Bezier curves require an anchor point to calculate the smooth flow. These points are nodes. These nodes are invisible but + * are used for the force calculation. + * + * @private + */ + Network.prototype._createBezierNodes = function() { + if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { + for (var edgeId in this.edges) { + if (this.edges.hasOwnProperty(edgeId)) { + var edge = this.edges[edgeId]; + if (edge.via == null) { + var nodeId = "edgeId:".concat(edge.id); + this.sectors['support']['nodes'][nodeId] = new Node( + {id:nodeId, + mass:1, + shape:'circle', + image:"", + internalMultiplier:1 + },{},{},this.constants); + edge.via = this.sectors['support']['nodes'][nodeId]; + edge.via.parentEdgeId = edge.id; + edge.positionBezierNode(); + } + } + } + } + }; - this.dirty = false; + /** + * load the functions that load the mixins into the prototype. + * + * @private + */ + Network.prototype._initializeMixinLoaders = function () { + for (var mixin in MixinLoader) { + if (MixinLoader.hasOwnProperty(mixin)) { + Network.prototype[mixin] = MixinLoader[mixin]; + } } + }; - this._repaintDeleteButton(dom.point); + /** + * Load the XY positions of the nodes into the dataset. + */ + Network.prototype.storePosition = function() { + console.log("storePosition is depricated: use .storePositions() from now on.") + this.storePositions(); }; /** - * Show the item in the DOM (when not already visible). The items DOM will - * be created when needed. + * Load the XY positions of the nodes into the dataset. */ - PointItem.prototype.show = function() { - if (!this.displayed) { - this.redraw(); + Network.prototype.storePositions = function() { + var dataArray = []; + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + var node = this.nodes[nodeId]; + var allowedToMoveX = !this.nodes.xFixed; + var allowedToMoveY = !this.nodes.yFixed; + if (this.nodesData._data[nodeId].x != Math.round(node.x) || this.nodesData._data[nodeId].y != Math.round(node.y)) { + dataArray.push({id:nodeId,x:Math.round(node.x),y:Math.round(node.y),allowedToMoveX:allowedToMoveX,allowedToMoveY:allowedToMoveY}); + } + } } + this.nodesData.update(dataArray); }; /** - * Hide the item from the DOM (when visible) + * Return the positions of the nodes. */ - PointItem.prototype.hide = function() { - if (this.displayed) { - if (this.dom.point.parentNode) { - this.dom.point.parentNode.removeChild(this.dom.point); + Network.prototype.getPositions = function(ids) { + var dataArray = {}; + if (ids !== undefined) { + if (Array.isArray(ids) == true) { + for (var i = 0; i < ids.length; i++) { + if (this.nodes[ids[i]] !== undefined) { + var node = this.nodes[ids[i]]; + dataArray[ids[i]] = {x: Math.round(node.x), y: Math.round(node.y)}; + } + } + } + else { + if (this.nodes[ids] !== undefined) { + var node = this.nodes[ids]; + dataArray[ids] = {x: Math.round(node.x), y: Math.round(node.y)}; + } + } + } + else { + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + var node = this.nodes[nodeId]; + dataArray[nodeId] = {x: Math.round(node.x), y: Math.round(node.y)}; + } } - - this.top = null; - this.left = null; - - this.displayed = false; } + return dataArray; }; + + /** - * Reposition the item horizontally - * @Override + * Center a node in view. + * + * @param {Number} nodeId + * @param {Number} [options] */ - PointItem.prototype.repositionX = function() { - var start = this.conversion.toScreen(this.data.start); + Network.prototype.focusOnNode = function (nodeId, options) { + if (this.nodes.hasOwnProperty(nodeId)) { + if (options === undefined) { + options = {}; + } + var nodePosition = {x: this.nodes[nodeId].x, y: this.nodes[nodeId].y}; + options.position = nodePosition; + options.lockedOnNode = nodeId; - this.left = start - this.props.dot.width; + this.moveTo(options) + } + else { + console.log("This nodeId cannot be found."); + } + }; - // reposition point - this.dom.point.style.left = this.left + 'px'; + /** + * + * @param {Object} options | options.offset = {x:Number, y:Number} // offset from the center in DOM pixels + * | options.scale = Number // scale to move to + * | options.position = {x:Number, y:Number} // position to move to + * | options.animation = {duration:Number, easingFunction:String} || Boolean // position to move to + */ + Network.prototype.moveTo = function (options) { + if (options === undefined) { + options = {}; + return; + } + if (options.offset === undefined) {options.offset = {x: 0, y: 0}; } + if (options.offset.x === undefined) {options.offset.x = 0; } + if (options.offset.y === undefined) {options.offset.y = 0; } + if (options.scale === undefined) {options.scale = this._getScale(); } + if (options.position === undefined) {options.position = this._getTranslation();} + if (options.animation === undefined) {options.animation = {duration:0}; } + if (options.animation === false ) {options.animation = {duration:0}; } + if (options.animation === true ) {options.animation = {}; } + if (options.animation.duration === undefined) {options.animation.duration = 1000; } // default duration + if (options.animation.easingFunction === undefined) {options.animation.easingFunction = "easeInOutQuad"; } // default easing function + + this.animateView(options); }; /** - * Reposition the item vertically - * @Override + * + * @param {Object} options | options.offset = {x:Number, y:Number} // offset from the center in DOM pixels + * | options.time = Number // animation time in milliseconds + * | options.scale = Number // scale to animate to + * | options.position = {x:Number, y:Number} // position to animate to + * | options.easingFunction = String // linear, easeInQuad, easeOutQuad, easeInOutQuad, + * // easeInCubic, easeOutCubic, easeInOutCubic, + * // easeInQuart, easeOutQuart, easeInOutQuart, + * // easeInQuint, easeOutQuint, easeInOutQuint */ - PointItem.prototype.repositionY = function() { - var orientation = this.options.orientation, - point = this.dom.point; - - if (orientation == 'top') { - point.style.top = this.top + 'px'; - } - else { - point.style.top = (this.parent.height - this.top - this.height) + 'px'; + Network.prototype.animateView = function (options) { + if (options === undefined) { + options = {}; + return; } - }; - - module.exports = PointItem; + // release if something focussed on the node + this.releaseNode(); + if (options.locked == true) { + this.lockedOnNodeId = options.lockedOnNode; + this.lockedOnNodeOffset = options.offset; + } -/***/ }, -/* 34 */ -/***/ function(module, exports, __webpack_require__) { + // forcefully complete the old animation if it was still running + if (this.easingTime != 0) { + this._transitionRedraw(1); // by setting easingtime to 1, we finish the animation. + } - var Hammer = __webpack_require__(19); - var Item = __webpack_require__(30); - var BackgroundGroup = __webpack_require__(31); - var RangeItem = __webpack_require__(29); + this.sourceScale = this._getScale(); + this.sourceTranslation = this._getTranslation(); + this.targetScale = options.scale; - /** - * @constructor BackgroundItem - * @extends Item - * @param {Object} data Object containing parameters start, end - * content, className. - * @param {{toScreen: function, toTime: function}} conversion - * Conversion functions from time to screen and vice versa - * @param {Object} [options] Configuration options - * // TODO: describe options - */ - // TODO: implement support for the BackgroundItem just having a start, then being displayed as a sort of an annotation - function BackgroundItem (data, conversion, options) { - this.props = { - content: { - width: 0 - } + // set the scale so the viewCenter is based on the correct zoom level. This is overridden in the transitionRedraw + // but at least then we'll have the target transition + this._setScale(this.targetScale); + var viewCenter = this.DOMtoCanvas({x: 0.5 * this.frame.canvas.clientWidth, y: 0.5 * this.frame.canvas.clientHeight}); + var distanceFromCenter = { // offset from view, distance view has to change by these x and y to center the node + x: viewCenter.x - options.position.x, + y: viewCenter.y - options.position.y + }; + this.targetTranslation = { + x: this.sourceTranslation.x + distanceFromCenter.x * this.targetScale + options.offset.x, + y: this.sourceTranslation.y + distanceFromCenter.y * this.targetScale + options.offset.y }; - this.overflow = false; // if contents can overflow (css styling), this flag is set to true - // validate data - if (data) { - if (data.start == undefined) { - throw new Error('Property "start" missing in item ' + data.id); + // if the time is set to 0, don't do an animation + if (options.animation.duration == 0) { + if (this.lockedOnNodeId != null) { + this._classicRedraw = this._redraw; + this._redraw = this._lockedRedraw; } - if (data.end == undefined) { - throw new Error('Property "end" missing in item ' + data.id); + else { + this._setScale(this.targetScale); + this._setTranslation(this.targetTranslation.x, this.targetTranslation.y); + this._redraw(); } } + else { + this.animating = true; + this.animationSpeed = 1 / (this.renderRefreshRate * options.animation.duration * 0.001) || 1 / this.renderRefreshRate; + this.animationEasingFunction = options.animation.easingFunction; + this._classicRedraw = this._redraw; + this._redraw = this._transitionRedraw; + this._redraw(); + this.start(); + } + }; - Item.call(this, data, conversion, options); + /** + * used to animate smoothly by hijacking the redraw function. + * @private + */ + Network.prototype._lockedRedraw = function () { + var nodePosition = {x: this.nodes[this.lockedOnNodeId].x, y: this.nodes[this.lockedOnNodeId].y}; + var viewCenter = this.DOMtoCanvas({x: 0.5 * this.frame.canvas.clientWidth, y: 0.5 * this.frame.canvas.clientHeight}); + var distanceFromCenter = { // offset from view, distance view has to change by these x and y to center the node + x: viewCenter.x - nodePosition.x, + y: viewCenter.y - nodePosition.y + }; + var sourceTranslation = this._getTranslation(); + var targetTranslation = { + x: sourceTranslation.x + distanceFromCenter.x * this.scale + this.lockedOnNodeOffset.x, + y: sourceTranslation.y + distanceFromCenter.y * this.scale + this.lockedOnNodeOffset.y + }; - this.emptyContent = false; + this._setTranslation(targetTranslation.x,targetTranslation.y); + this._classicRedraw(); } - BackgroundItem.prototype = new Item (null, null, null); - - BackgroundItem.prototype.baseClassName = 'item background'; - BackgroundItem.prototype.stack = false; - - /** - * Check whether this item is visible inside given range - * @returns {{start: Number, end: Number}} range with a timestamp for start and end - * @returns {boolean} True if visible - */ - BackgroundItem.prototype.isVisible = function(range) { - // determine visibility - return (this.data.start < range.end) && (this.data.end > range.start); - }; + Network.prototype.releaseNode = function () { + if (this.lockedOnNodeId != null) { + this._redraw = this._classicRedraw; + this.lockedOnNodeId = null; + this.lockedOnNodeOffset = null; + } + } /** - * Repaint the item + * + * @param easingTime + * @private */ - BackgroundItem.prototype.redraw = function() { - var dom = this.dom; - if (!dom) { - // create DOM - this.dom = {}; - dom = this.dom; - - // background box - dom.box = document.createElement('div'); - // className is updated in redraw() + Network.prototype._transitionRedraw = function (easingTime) { + this.easingTime = easingTime || this.easingTime + this.animationSpeed; + this.easingTime += this.animationSpeed; - // contents box - dom.content = document.createElement('div'); - dom.content.className = 'content'; - dom.box.appendChild(dom.content); + var progress = util.easingFunctions[this.animationEasingFunction](this.easingTime); - // Note: we do NOT attach this item as attribute to the DOM, - // such that background items cannot be selected - //dom.box['timeline-item'] = this; + this._setScale(this.sourceScale + (this.targetScale - this.sourceScale) * progress); + this._setTranslation( + this.sourceTranslation.x + (this.targetTranslation.x - this.sourceTranslation.x) * progress, + this.sourceTranslation.y + (this.targetTranslation.y - this.sourceTranslation.y) * progress + ); - this.dirty = true; - } + this._classicRedraw(); - // append DOM to parent DOM - if (!this.parent) { - throw new Error('Cannot redraw item: no parent attached'); - } - if (!dom.box.parentNode) { - var background = this.parent.dom.background; - if (!background) { - throw new Error('Cannot redraw item: parent has no background container element'); + // cleanup + if (this.easingTime >= 1.0) { + this.animating = false; + this.easingTime = 0; + if (this.lockedOnNodeId != null) { + this._redraw = this._lockedRedraw; } - background.appendChild(dom.box); + else { + this._redraw = this._classicRedraw; + } + this.emit("animationFinished"); } - this.displayed = true; - - // Update DOM when item is marked dirty. An item is marked dirty when: - // - the item is not yet rendered - // - the item's data is changed - // - the item is selected/deselected - if (this.dirty) { - this._updateContents(this.dom.content); - this._updateTitle(this.dom.content); - this._updateDataAttributes(this.dom.content); - this._updateStyle(this.dom.box); - - // update class - var className = (this.data.className ? (' ' + this.data.className) : '') + - (this.selected ? ' selected' : ''); - dom.box.className = this.baseClassName + className; - - // determine from css whether this box has overflow - this.overflow = window.getComputedStyle(dom.content).overflow !== 'hidden'; - - // recalculate size - this.props.content.width = this.dom.content.offsetWidth; - this.height = 0; // set height zero, so this item will be ignored when stacking items + }; - this.dirty = false; - } + Network.prototype._classicRedraw = function () { + // placeholder function to be overloaded by animations; }; /** - * Show the item in the DOM (when not already visible). The items DOM will - * be created when needed. + * Returns true when the Network is active. + * @returns {boolean} */ - BackgroundItem.prototype.show = RangeItem.prototype.show; + Network.prototype.isActive = function () { + return !this.activator || this.activator.active; + }; + /** - * Hide the item from the DOM (when visible) - * @return {Boolean} changed + * Sets the scale + * @returns {Number} */ - BackgroundItem.prototype.hide = RangeItem.prototype.hide; + Network.prototype.setScale = function () { + return this._setScale(); + }; + /** - * Reposition the item horizontally - * @Override + * Returns the scale + * @returns {Number} */ - BackgroundItem.prototype.repositionX = RangeItem.prototype.repositionX; + Network.prototype.getScale = function () { + return this._getScale(); + }; + /** - * Reposition the item vertically - * @Override + * Returns the scale + * @returns {Number} */ - BackgroundItem.prototype.repositionY = function(margin) { - var onTop = this.options.orientation === 'top'; - this.dom.content.style.top = onTop ? '' : '0'; - this.dom.content.style.bottom = onTop ? '0' : ''; - var height; + Network.prototype.getCenterCoordinates = function () { + return this.DOMtoCanvas({x: 0.5 * this.frame.canvas.clientWidth, y: 0.5 * this.frame.canvas.clientHeight}); + }; - // special positioning for subgroups - if (this.data.subgroup !== undefined) { - var itemSubgroup = this.data.subgroup; - var subgroups = this.parent.subgroups; - var subgroupIndex = subgroups[itemSubgroup].index; - // if the orientation is top, we need to take the difference in height into account. - if (onTop == true) { - // the first subgroup will have to account for the distance from the top to the first item. - height = this.parent.subgroups[itemSubgroup].height + margin.item.vertical; - height += subgroupIndex == 0 ? margin.axis - 0.5*margin.item.vertical : 0; - var newTop = this.parent.top; - for (var subgroup in subgroups) { - if (subgroups.hasOwnProperty(subgroup)) { - if (subgroups[subgroup].visible == true && subgroups[subgroup].index < subgroupIndex) { - newTop += subgroups[subgroup].height + margin.item.vertical; - } - } - } - // the others will have to be offset downwards with this same distance. - newTop += subgroupIndex != 0 ? margin.axis - 0.5 * margin.item.vertical : 0; - this.dom.box.style.top = newTop + 'px'; - this.dom.box.style.bottom = ''; - } - // and when the orientation is bottom: - else { - var newTop = this.parent.top; - for (var subgroup in subgroups) { - if (subgroups.hasOwnProperty(subgroup)) { - if (subgroups[subgroup].visible == true && subgroups[subgroup].index > subgroupIndex) { - newTop += subgroups[subgroup].height + margin.item.vertical; - } - } - } - height = this.parent.subgroups[itemSubgroup].height + margin.item.vertical; - this.dom.box.style.top = newTop + 'px'; - this.dom.box.style.bottom = ''; - } - } - // and in the case of no subgroups: - else { - // we want backgrounds with groups to only show in groups. - if (this.parent instanceof BackgroundGroup) { - // if the item is not in a group: - height = Math.max(this.parent.height, - this.parent.itemSet.body.domProps.center.height, - this.parent.itemSet.body.domProps.centerContainer.height); - this.dom.box.style.top = onTop ? '0' : ''; - this.dom.box.style.bottom = onTop ? '' : '0'; - } - else { - height = this.parent.height; - // same alignment for items when orientation is top or bottom - this.dom.box.style.top = this.parent.top + 'px'; - this.dom.box.style.bottom = ''; - } + Network.prototype.getBoundingBox = function(nodeId) { + if (this.nodes[nodeId] !== undefined) { + return this.nodes[nodeId].boundingBox; } - this.dom.box.style.height = height + 'px'; - }; + } - module.exports = BackgroundItem; + module.exports = Network; /***/ }, -/* 35 */ +/* 37 */ /***/ function(module, exports, __webpack_require__) { - var keycharm = __webpack_require__(36); - var Emitter = __webpack_require__(11); - var Hammer = __webpack_require__(19); var util = __webpack_require__(1); + var Node = __webpack_require__(40); /** - * Turn an element into an clickToUse element. - * When not active, the element has a transparent overlay. When the overlay is - * clicked, the mode is changed to active. - * When active, the element is displayed with a blue border around it, and - * the interactive contents of the element can be used. When clicked outside - * the element, the elements mode is changed to inactive. - * @param {Element} container - * @constructor + * @class Edge + * + * A edge connects two nodes + * @param {Object} properties Object with properties. Must contain + * At least properties from and to. + * Available properties: from (number), + * to (number), label (string, color (string), + * width (number), style (string), + * length (number), title (string) + * @param {Network} network A Network object, used to find and edge to + * nodes. + * @param {Object} constants An object with default values for + * example for the color */ - function Activator(container) { - this.active = false; + function Edge (properties, network, networkConstants) { + if (!network) { + throw "No network provided"; + } + var fields = ['edges','physics']; + var constants = util.selectiveBridgeObject(fields,networkConstants); + this.options = constants.edges; + this.physics = constants.physics; + this.options['smoothCurves'] = networkConstants['smoothCurves']; - this.dom = { - container: container - }; - this.dom.overlay = document.createElement('div'); - this.dom.overlay.className = 'overlay'; + this.network = network; - this.dom.container.appendChild(this.dom.overlay); + // initialize variables + this.id = undefined; + this.fromId = undefined; + this.toId = undefined; + this.title = undefined; + this.widthSelected = this.options.width * this.options.widthSelectionMultiplier; + this.value = undefined; + this.selected = false; + this.hover = false; + this.labelDimensions = {top:0,left:0,width:0,height:0,yLine:0}; // could be cached + this.dirtyLabel = true; - this.hammer = Hammer(this.dom.overlay, {prevent_default: false}); - this.hammer.on('tap', this._onTapOverlay.bind(this)); + this.from = null; // a node + this.to = null; // a node + this.via = null; // a temp node - // block all touch events (except tap) - var me = this; - var events = [ - 'touch', 'pinch', - 'doubletap', 'hold', - 'dragstart', 'drag', 'dragend', - 'mousewheel', 'DOMMouseScroll' // DOMMouseScroll is needed for Firefox + this.fromBackup = null; // used to clean up after reconnect + this.toBackup = null;; // used to clean up after reconnect + + // we use this to be able to reconnect the edge to a cluster if its node is put into a cluster + // by storing the original information we can revert to the original connection when the cluser is opened. + this.originalFromId = []; + this.originalToId = []; + + this.connected = false; + + this.widthFixed = false; + this.lengthFixed = false; + + this.setProperties(properties); + + this.controlNodesEnabled = false; + this.controlNodes = {from:null, to:null, positions:{}}; + this.connectedNode = null; + } + + /** + * Set or overwrite properties for the edge + * @param {Object} properties an object with properties + * @param {Object} constants and object with default, global properties + */ + Edge.prototype.setProperties = function(properties) { + if (!properties) { + return; + } + + var fields = ['style','fontSize','fontFace','fontColor','fontFill','fontStrokeWidth','fontStrokeColor','width', + 'widthSelectionMultiplier','hoverWidth','arrowScaleFactor','dash','inheritColor','labelAlignment' ]; - events.forEach(function (event) { - me.hammer.on(event, function (event) { - event.stopPropagation(); - }); - }); + util.selectiveDeepExtend(fields, this.options, properties); - // attach a tap event to the window, in order to deactivate when clicking outside the timeline - this.windowHammer = Hammer(window, {prevent_default: false}); - this.windowHammer.on('tap', function (event) { - // deactivate when clicked outside the container - if (!_hasParent(event.target, container)) { - me.deactivate(); - } - }); + if (properties.from !== undefined) {this.fromId = properties.from;} + if (properties.to !== undefined) {this.toId = properties.to;} - if (this.keycharm !== undefined) { - this.keycharm.destroy(); + if (properties.id !== undefined) {this.id = properties.id;} + if (properties.label !== undefined) {this.label = properties.label; this.dirtyLabel = true;} + + if (properties.title !== undefined) {this.title = properties.title;} + if (properties.value !== undefined) {this.value = properties.value;} + if (properties.length !== undefined) {this.physics.springLength = properties.length;} + + if (properties.color !== undefined) { + this.options.inheritColor = false; + if (util.isString(properties.color)) { + this.options.color.color = properties.color; + this.options.color.highlight = properties.color; + } + else { + if (properties.color.color !== undefined) {this.options.color.color = properties.color.color;} + if (properties.color.highlight !== undefined) {this.options.color.highlight = properties.color.highlight;} + if (properties.color.hover !== undefined) {this.options.color.hover = properties.color.hover;} + } } - this.keycharm = keycharm(); - // keycharm listener only bounded when active) - this.escListener = this.deactivate.bind(this); - } + // A node is connected when it has a from and to node. + this.connect(); - // turn into an event emitter - Emitter(Activator.prototype); + this.widthFixed = this.widthFixed || (properties.width !== undefined); + this.lengthFixed = this.lengthFixed || (properties.length !== undefined); - // The currently active activator - Activator.current = null; + this.widthSelected = this.options.width* this.options.widthSelectionMultiplier; + + // set draw method based on style + switch (this.options.style) { + case 'line': this.draw = this._drawLine; break; + case 'arrow': this.draw = this._drawArrow; break; + case 'arrow-center': this.draw = this._drawArrowCenter; break; + case 'dash-line': this.draw = this._drawDashLine; break; + default: this.draw = this._drawLine; break; + } + + }; /** - * Destroy the activator. Cleans up all created DOM and event listeners + * Connect an edge to its nodes */ - Activator.prototype.destroy = function () { - this.deactivate(); + Edge.prototype.connect = function () { + this.disconnect(); - // remove dom - this.dom.overlay.parentNode.removeChild(this.dom.overlay); + this.from = this.network.nodes[this.fromId] || null; + this.to = this.network.nodes[this.toId] || null; + this.connected = (this.from && this.to); - // cleanup hammer instances - this.hammer = null; - this.windowHammer = null; - // FIXME: cleaning up hammer instances doesn't work (Timeline not removed from memory) + if (this.connected) { + this.from.attachEdge(this); + this.to.attachEdge(this); + } + else { + if (this.from) { + this.from.detachEdge(this); + } + if (this.to) { + this.to.detachEdge(this); + } + } }; /** - * Activate the element - * Overlay is hidden, element is decorated with a blue shadow border + * Disconnect an edge from its nodes */ - Activator.prototype.activate = function () { - // we allow only one active activator at a time - if (Activator.current) { - Activator.current.deactivate(); + Edge.prototype.disconnect = function () { + if (this.from) { + this.from.detachEdge(this); + this.from = null; + } + if (this.to) { + this.to.detachEdge(this); + this.to = null; } - Activator.current = this; - - this.active = true; - this.dom.overlay.style.display = 'none'; - util.addClassName(this.dom.container, 'vis-active'); - - this.emit('change'); - this.emit('activate'); - // ugly hack: bind ESC after emitting the events, as the Network rebinds all - // keyboard events on a 'change' event - this.keycharm.bind('esc', this.escListener); + this.connected = false; }; /** - * Deactivate the element - * Overlay is displayed on top of the element + * get the title of this edge. + * @return {string} title The title of the edge, or undefined when no title + * has been set. */ - Activator.prototype.deactivate = function () { - this.active = false; - this.dom.overlay.style.display = ''; - util.removeClassName(this.dom.container, 'vis-active'); - this.keycharm.unbind('esc', this.escListener); - - this.emit('change'); - this.emit('deactivate'); + Edge.prototype.getTitle = function() { + return typeof this.title === "function" ? this.title() : this.title; }; + /** - * Handle a tap event: activate the container - * @param event - * @private + * Retrieve the value of the edge. Can be undefined + * @return {Number} value */ - Activator.prototype._onTapOverlay = function (event) { - // activate the container - this.activate(); - event.stopPropagation(); + Edge.prototype.getValue = function() { + return this.value; }; /** - * Test whether the element has the requested parent element somewhere in - * its chain of parent nodes. - * @param {HTMLElement} element - * @param {HTMLElement} parent - * @returns {boolean} Returns true when the parent is found somewhere in the - * chain of parent nodes. - * @private + * Adjust the value range of the edge. The edge will adjust it's width + * based on its value. + * @param {Number} min + * @param {Number} max */ - function _hasParent(element, parent) { - while (element) { - if (element === parent) { - return true - } - element = element.parentNode; + Edge.prototype.setValueRange = function(min, max) { + if (!this.widthFixed && this.value !== undefined) { + var scale = (this.options.widthMax - this.options.widthMin) / (max - min); + this.options.width= (this.value - min) * scale + this.options.widthMin; + this.widthSelected = this.options.width* this.options.widthSelectionMultiplier; } - return false; - } - - module.exports = Activator; - + }; -/***/ }, -/* 36 */ -/***/ function(module, exports, __webpack_require__) { + /** + * Redraw a edge + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + */ + Edge.prototype.draw = function(ctx) { + throw "Method draw not initialized in edge"; + }; - var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;"use strict"; /** - * Created by Alex on 11/6/2014. + * Check if this object is overlapping with the provided object + * @param {Object} obj an object with parameters left, top + * @return {boolean} True if location is located on the edge */ + Edge.prototype.isOverlappingWith = function(obj) { + if (this.connected) { + var distMax = 10; + var xFrom = this.from.x; + var yFrom = this.from.y; + var xTo = this.to.x; + var yTo = this.to.y; + var xObj = obj.left; + var yObj = obj.top; - // https://github.com/umdjs/umd/blob/master/returnExports.js#L40-L60 - // if the module has no dependencies, the above pattern can be simplified to - (function (root, factory) { - if (true) { - // AMD. Register as an anonymous module. - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - } else if (typeof exports === 'object') { - // Node. Does not work with strict CommonJS, but - // only CommonJS-like environments that support module.exports, - // like Node. - module.exports = factory(); - } else { - // Browser globals (root is window) - root.keycharm = factory(); + var dist = this._getDistanceToEdge(xFrom, yFrom, xTo, yTo, xObj, yObj); + + return (dist < distMax); } - }(this, function () { + else { + return false + } + }; - function keycharm(options) { - var preventDefault = options && options.preventDefault || false; + Edge.prototype._getColor = function() { + var colorObj = this.options.color; + if (this.options.inheritColor == "to") { + colorObj = { + highlight: this.to.options.color.highlight.border, + hover: this.to.options.color.hover.border, + color: this.to.options.color.border + }; + } + else if (this.options.inheritColor == "from" || this.options.inheritColor == true) { + colorObj = { + highlight: this.from.options.color.highlight.border, + hover: this.from.options.color.hover.border, + color: this.from.options.color.border + }; + } - var container = options && options.container || window; + if (this.selected == true) {return colorObj.highlight;} + else if (this.hover == true) {return colorObj.hover;} + else {return colorObj.color;} + }; - var _exportFunctions = {}; - var _bound = {keydown:{}, keyup:{}}; - var _keys = {}; - var i; - // a - z - for (i = 97; i <= 122; i++) {_keys[String.fromCharCode(i)] = {code:65 + (i - 97), shift: false};} - // A - Z - for (i = 65; i <= 90; i++) {_keys[String.fromCharCode(i)] = {code:i, shift: true};} - // 0 - 9 - for (i = 0; i <= 9; i++) {_keys['' + i] = {code:48 + i, shift: false};} - // F1 - F12 - for (i = 1; i <= 12; i++) {_keys['F' + i] = {code:111 + i, shift: false};} - // num0 - num9 - for (i = 0; i <= 9; i++) {_keys['num' + i] = {code:96 + i, shift: false};} + /** + * Redraw a edge as a line + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private + */ + Edge.prototype._drawLine = function(ctx) { + // set style + ctx.strokeStyle = this._getColor(); + ctx.lineWidth = this._getLineWidth(); - // numpad misc - _keys['num*'] = {code:106, shift: false}; - _keys['num+'] = {code:107, shift: false}; - _keys['num-'] = {code:109, shift: false}; - _keys['num/'] = {code:111, shift: false}; - _keys['num.'] = {code:110, shift: false}; - // arrows - _keys['left'] = {code:37, shift: false}; - _keys['up'] = {code:38, shift: false}; - _keys['right'] = {code:39, shift: false}; - _keys['down'] = {code:40, shift: false}; - // extra keys - _keys['space'] = {code:32, shift: false}; - _keys['enter'] = {code:13, shift: false}; - _keys['shift'] = {code:16, shift: undefined}; - _keys['esc'] = {code:27, shift: false}; - _keys['backspace'] = {code:8, shift: false}; - _keys['tab'] = {code:9, shift: false}; - _keys['ctrl'] = {code:17, shift: false}; - _keys['alt'] = {code:18, shift: false}; - _keys['delete'] = {code:46, shift: false}; - _keys['pageup'] = {code:33, shift: false}; - _keys['pagedown'] = {code:34, shift: false}; - // symbols - _keys['='] = {code:187, shift: false}; - _keys['-'] = {code:189, shift: false}; - _keys[']'] = {code:221, shift: false}; - _keys['['] = {code:219, shift: false}; + if (this.from != this.to) { + // draw line + var via = this._line(ctx); + // draw label + var point; + if (this.label) { + if (this.options.smoothCurves.enabled == true && via != null) { + var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); + var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); + point = {x:midpointX, y:midpointY}; + } + else { + point = this._pointOnLine(0.5); + } + this._label(ctx, this.label, point.x, point.y); + } + } + else { + var x, y; + var radius = this.physics.springLength / 4; + var node = this.from; + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width / 2; + y = node.y - radius; + } + else { + x = node.x + radius; + y = node.y - node.height / 2; + } + this._circle(ctx, x, y, radius); + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); + } + }; + /** + * Get the line width of the edge. Depends on width and whether one of the + * connected nodes is selected. + * @return {Number} width + * @private + */ + Edge.prototype._getLineWidth = function() { + if (this.selected == true) { + return Math.max(Math.min(this.widthSelected, this.options.widthMax), 0.3*this.networkScaleInv); + } + else { + if (this.hover == true) { + return Math.max(Math.min(this.options.hoverWidth, this.options.widthMax), 0.3*this.networkScaleInv); + } + else { + return Math.max(this.options.width, 0.3*this.networkScaleInv); + } + } + }; - var down = function(event) {handleEvent(event,'keydown');}; - var up = function(event) {handleEvent(event,'keyup');}; + Edge.prototype._getViaCoordinates = function () { + if (this.options.smoothCurves.dynamic == true && this.options.smoothCurves.enabled == true ) { + return this.via; + } + else if (this.options.smoothCurves.enabled == false) { + return {x:0,y:0}; + } + else { + var xVia = null; + var yVia = null; + var factor = this.options.smoothCurves.roundness; + var type = this.options.smoothCurves.type; - // handle the actualy bound key with the event - var handleEvent = function(event,type) { - if (_bound[type][event.keyCode] !== undefined) { - var bound = _bound[type][event.keyCode]; - for (var i = 0; i < bound.length; i++) { - if (bound[i].shift === undefined) { - bound[i].fn(event); + var dx = Math.abs(this.from.x - this.to.x); + var dy = Math.abs(this.from.y - this.to.y); + if (type == 'discrete' || type == 'diagonalCross') { + if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { + if (this.from.y > this.to.y) { + if (this.from.x < this.to.x) { + xVia = this.from.x + factor * dy; + yVia = this.from.y - factor * dy; } - else if (bound[i].shift == true && event.shiftKey == true) { - bound[i].fn(event); + else if (this.from.x > this.to.x) { + xVia = this.from.x - factor * dy; + yVia = this.from.y - factor * dy; } - else if (bound[i].shift == false && event.shiftKey == false) { - bound[i].fn(event); + } + else if (this.from.y < this.to.y) { + if (this.from.x < this.to.x) { + xVia = this.from.x + factor * dy; + yVia = this.from.y + factor * dy; + } + else if (this.from.x > this.to.x) { + xVia = this.from.x - factor * dy; + yVia = this.from.y + factor * dy; } } - - if (preventDefault == true) { - event.preventDefault(); + if (type == "discrete") { + xVia = dx < factor * dy ? this.from.x : xVia; } } - }; - - // bind a key to a callback - _exportFunctions.bind = function(key, callback, type) { - if (type === undefined) { - type = 'keydown'; + else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { + if (this.from.y > this.to.y) { + if (this.from.x < this.to.x) { + xVia = this.from.x + factor * dx; + yVia = this.from.y - factor * dx; + } + else if (this.from.x > this.to.x) { + xVia = this.from.x - factor * dx; + yVia = this.from.y - factor * dx; + } + } + else if (this.from.y < this.to.y) { + if (this.from.x < this.to.x) { + xVia = this.from.x + factor * dx; + yVia = this.from.y + factor * dx; + } + else if (this.from.x > this.to.x) { + xVia = this.from.x - factor * dx; + yVia = this.from.y + factor * dx; + } + } + if (type == "discrete") { + yVia = dy < factor * dx ? this.from.y : yVia; + } } - if (_keys[key] === undefined) { - throw new Error("unsupported key: " + key); + } + else if (type == "straightCross") { + if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { // up - down + xVia = this.from.x; + if (this.from.y < this.to.y) { + yVia = this.to.y - (1 - factor) * dy; + } + else { + yVia = this.to.y + (1 - factor) * dy; + } } - if (_bound[type][_keys[key].code] === undefined) { - _bound[type][_keys[key].code] = []; + else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { // left - right + if (this.from.x < this.to.x) { + xVia = this.to.x - (1 - factor) * dx; + } + else { + xVia = this.to.x + (1 - factor) * dx; + } + yVia = this.from.y; } - _bound[type][_keys[key].code].push({fn:callback, shift:_keys[key].shift}); - }; - - - // bind all keys to a call back (demo purposes) - _exportFunctions.bindAll = function(callback, type) { - if (type === undefined) { - type = 'keydown'; + } + else if (type == 'horizontal') { + if (this.from.x < this.to.x) { + xVia = this.to.x - (1 - factor) * dx; } - for (var key in _keys) { - if (_keys.hasOwnProperty(key)) { - _exportFunctions.bind(key,callback,type); - } + else { + xVia = this.to.x + (1 - factor) * dx; } - }; - - // get the key label from an event - _exportFunctions.getKey = function(event) { - for (var key in _keys) { - if (_keys.hasOwnProperty(key)) { - if (event.shiftKey == true && _keys[key].shift == true && event.keyCode == _keys[key].code) { - return key; + yVia = this.from.y; + } + else if (type == 'vertical') { + xVia = this.from.x; + if (this.from.y < this.to.y) { + yVia = this.to.y - (1 - factor) * dy; + } + else { + yVia = this.to.y + (1 - factor) * dy; + } + } + else { // continuous + if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { + if (this.from.y > this.to.y) { + if (this.from.x < this.to.x) { + // console.log(1) + xVia = this.from.x + factor * dy; + yVia = this.from.y - factor * dy; + xVia = this.to.x < xVia ? this.to.x : xVia; } - else if (event.shiftKey == false && _keys[key].shift == false && event.keyCode == _keys[key].code) { - return key; + else if (this.from.x > this.to.x) { + // console.log(2) + xVia = this.from.x - factor * dy; + yVia = this.from.y - factor * dy; + xVia = this.to.x > xVia ? this.to.x : xVia; } - else if (event.keyCode == _keys[key].code && key == 'shift') { - return key; + } + else if (this.from.y < this.to.y) { + if (this.from.x < this.to.x) { + // console.log(3) + xVia = this.from.x + factor * dy; + yVia = this.from.y + factor * dy; + xVia = this.to.x < xVia ? this.to.x : xVia; + } + else if (this.from.x > this.to.x) { + // console.log(4, this.from.x, this.to.x) + xVia = this.from.x - factor * dy; + yVia = this.from.y + factor * dy; + xVia = this.to.x > xVia ? this.to.x : xVia; } } } - return "unknown key, currently not supported"; - }; - - // unbind either a specific callback from a key or all of them (by leaving callback undefined) - _exportFunctions.unbind = function(key, callback, type) { - if (type === undefined) { - type = 'keydown'; - } - if (_keys[key] === undefined) { - throw new Error("unsupported key: " + key); - } - if (callback !== undefined) { - var newBindings = []; - var bound = _bound[type][_keys[key].code]; - if (bound !== undefined) { - for (var i = 0; i < bound.length; i++) { - if (!(bound[i].fn == callback && bound[i].shift == _keys[key].shift)) { - newBindings.push(_bound[type][_keys[key].code][i]); - } + else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { + if (this.from.y > this.to.y) { + if (this.from.x < this.to.x) { + // console.log(5) + xVia = this.from.x + factor * dx; + yVia = this.from.y - factor * dx; + yVia = this.to.y > yVia ? this.to.y : yVia; + } + else if (this.from.x > this.to.x) { + // console.log(6) + xVia = this.from.x - factor * dx; + yVia = this.from.y - factor * dx; + yVia = this.to.y > yVia ? this.to.y : yVia; } } - _bound[type][_keys[key].code] = newBindings; - } - else { - _bound[type][_keys[key].code] = []; - } - }; - - // reset all bound variables. - _exportFunctions.reset = function() { - _bound = {keydown:{}, keyup:{}}; - }; - - // unbind all listeners and reset all variables. - _exportFunctions.destroy = function() { - _bound = {keydown:{}, keyup:{}}; - container.removeEventListener('keydown', down, true); - container.removeEventListener('keyup', up, true); - }; - - // create listeners. - container.addEventListener('keydown',down,true); - container.addEventListener('keyup',up,true); - - // return the public functions. - return _exportFunctions; - } - - return keycharm; - })); - - - - -/***/ }, -/* 37 */ -/***/ function(module, exports, __webpack_require__) { - - var util = __webpack_require__(1); - var Component = __webpack_require__(23); - var TimeStep = __webpack_require__(38); - var DateUtil = __webpack_require__(24); - var moment = __webpack_require__(2); - - /** - * A horizontal time axis - * @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} body - * @param {Object} [options] See TimeAxis.setOptions for the available - * options. - * @constructor TimeAxis - * @extends Component - */ - function TimeAxis (body, options) { - this.dom = { - foreground: null, - lines: [], - majorTexts: [], - minorTexts: [], - redundant: { - lines: [], - majorTexts: [], - minorTexts: [] + else if (this.from.y < this.to.y) { + if (this.from.x < this.to.x) { + // console.log(7) + xVia = this.from.x + factor * dx; + yVia = this.from.y + factor * dx; + yVia = this.to.y < yVia ? this.to.y : yVia; + } + else if (this.from.x > this.to.x) { + // console.log(8) + xVia = this.from.x - factor * dx; + yVia = this.from.y + factor * dx; + yVia = this.to.y < yVia ? this.to.y : yVia; + } + } + } } - }; - this.props = { - range: { - start: 0, - end: 0, - minimumStep: 0 - }, - lineTop: 0 - }; - - this.defaultOptions = { - orientation: 'bottom', // supported: 'top', 'bottom' - // TODO: implement timeaxis orientations 'left' and 'right' - showMinorLabels: true, - showMajorLabels: true, - format: null - }; - this.options = util.extend({}, this.defaultOptions); - - this.body = body; - - // create the HTML DOM - this._create(); - this.setOptions(options); - } - TimeAxis.prototype = new Component(); + return {x: xVia, y: yVia}; + } + }; /** - * Set options for the TimeAxis. - * Parameters will be merged in current options. - * @param {Object} options Available options: - * {string} [orientation] - * {boolean} [showMinorLabels] - * {boolean} [showMajorLabels] + * Draw a line between two nodes + * @param {CanvasRenderingContext2D} ctx + * @private */ - TimeAxis.prototype.setOptions = function(options) { - if (options) { - // copy all options that we know - util.selectiveExtend([ - 'orientation', - 'showMinorLabels', - 'showMajorLabels', - 'hiddenDates', - 'format' - ], 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); + Edge.prototype._line = function (ctx) { + // draw a straight line + ctx.beginPath(); + ctx.moveTo(this.from.x, this.from.y); + if (this.options.smoothCurves.enabled == true) { + if (this.options.smoothCurves.dynamic == false) { + var via = this._getViaCoordinates(); + if (via.x == null) { + ctx.lineTo(this.to.x, this.to.y); + ctx.stroke(); + return null; } else { - moment.lang(options.locale); + // this.via.x = via.x; + // this.via.y = via.y; + ctx.quadraticCurveTo(via.x,via.y,this.to.x, this.to.y); + ctx.stroke(); + return via; } } + else { + ctx.quadraticCurveTo(this.via.x,this.via.y,this.to.x, this.to.y); + ctx.stroke(); + return this.via; + } + } + else { + ctx.lineTo(this.to.x, this.to.y); + ctx.stroke(); + return null; } }; /** - * Create the HTML DOM for the TimeAxis - */ - TimeAxis.prototype._create = function() { - this.dom.foreground = document.createElement('div'); - this.dom.background = document.createElement('div'); - - this.dom.foreground.className = 'timeaxis foreground'; - this.dom.background.className = 'timeaxis background'; - }; - - /** - * Destroy the TimeAxis + * Draw a line from a node to itself, a circle + * @param {CanvasRenderingContext2D} ctx + * @param {Number} x + * @param {Number} y + * @param {Number} radius + * @private */ - TimeAxis.prototype.destroy = function() { - // remove from DOM - if (this.dom.foreground.parentNode) { - this.dom.foreground.parentNode.removeChild(this.dom.foreground); - } - if (this.dom.background.parentNode) { - this.dom.background.parentNode.removeChild(this.dom.background); - } - - this.body = null; + Edge.prototype._circle = function (ctx, x, y, radius) { + // draw a circle + ctx.beginPath(); + ctx.arc(x, y, radius, 0, 2 * Math.PI, false); + ctx.stroke(); }; /** - * Repaint the component - * @return {boolean} Returns true if the component is resized + * Draw label with white background and with the middle at (x, y) + * @param {CanvasRenderingContext2D} ctx + * @param {String} text + * @param {Number} x + * @param {Number} y + * @private */ - TimeAxis.prototype.redraw = function () { - var options = this.options; - var props = this.props; - var foreground = this.dom.foreground; - var background = this.dom.background; - - // determine the correct parent DOM element (depending on option orientation) - var parent = (options.orientation == 'top') ? this.body.dom.top : this.body.dom.bottom; - var parentChanged = (foreground.parentNode !== parent); - - // calculate character width and height - this._calculateCharSize(); - - // TODO: recalculate sizes only needed when parent is resized or options is changed - var orientation = this.options.orientation, - showMinorLabels = this.options.showMinorLabels, - showMajorLabels = this.options.showMajorLabels; - - // determine the width and height of the elemens for the axis - props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; - props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; - props.height = props.minorLabelHeight + props.majorLabelHeight; - props.width = foreground.offsetWidth; + Edge.prototype._label = function (ctx, text, x, y) { + if (text) { + ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") + + this.options.fontSize + "px " + this.options.fontFace; + var yLine; - props.minorLineHeight = this.body.domProps.root.height - props.majorLabelHeight - - (options.orientation == 'top' ? this.body.domProps.bottom.height : this.body.domProps.top.height); - props.minorLineWidth = 1; // TODO: really calculate width - props.majorLineHeight = props.minorLineHeight + props.majorLabelHeight; - props.majorLineWidth = 1; // TODO: really calculate width + if (this.dirtyLabel == true) { + var lines = String(text).split('\n'); + var lineCount = lines.length; + var fontSize = Number(this.options.fontSize); + yLine = y + (1 - lineCount) / 2 * fontSize; - // take foreground and background offline while updating (is almost twice as fast) - var foregroundNextSibling = foreground.nextSibling; - var backgroundNextSibling = background.nextSibling; - foreground.parentNode && foreground.parentNode.removeChild(foreground); - background.parentNode && background.parentNode.removeChild(background); + var width = ctx.measureText(lines[0]).width; + for (var i = 1; i < lineCount; i++) { + var lineWidth = ctx.measureText(lines[i]).width; + width = lineWidth > width ? lineWidth : width; + } + var height = this.options.fontSize * lineCount; + var left = x - width / 2; + var top = y - height / 2; - foreground.style.height = this.props.height + 'px'; + // cache + this.labelDimensions = {top:top,left:left,width:width,height:height,yLine:yLine}; + } - this._repaintLabels(); + var yLine = this.labelDimensions.yLine; + + ctx.save(); + + if (this.options.labelAlignment != "horizontal"){ + ctx.translate(x, yLine); + this._rotateForLabelAlignment(ctx); + x = 0; + yLine = 0; + } - // put DOM online again (at the same place) - if (foregroundNextSibling) { - parent.insertBefore(foreground, foregroundNextSibling); - } - else { - parent.appendChild(foreground) - } - if (backgroundNextSibling) { - this.body.dom.backgroundVertical.insertBefore(background, backgroundNextSibling); - } - else { - this.body.dom.backgroundVertical.appendChild(background) + + this._drawLabelRect(ctx); + this._drawLabelText(ctx,x,yLine, lines, lineCount, fontSize); + + ctx.restore(); } - - return this._isResized() || parentChanged; }; /** - * Repaint major and minor text labels and vertical grid lines + * Rotates the canvas so the text is most readable + * @param {CanvasRenderingContext2D} ctx * @private */ - TimeAxis.prototype._repaintLabels = function () { - var orientation = this.options.orientation; - - // calculate range and step (step such that we have space for 7 characters per label) - var start = util.convert(this.body.range.start, 'Number'); - var end = util.convert(this.body.range.end, 'Number'); - var timeLabelsize = this.body.util.toTime((this.props.minorCharWidth || 10) * 7).valueOf(); - var minimumStep = timeLabelsize - DateUtil.getHiddenDurationBefore(this.body.hiddenDates, this.body.range, timeLabelsize); - minimumStep -= this.body.util.toTime(0).valueOf(); - - var step = new TimeStep(new Date(start), new Date(end), minimumStep, this.body.hiddenDates); - if (this.options.format) { - step.setFormat(this.options.format); - } - this.step = step; - - // Move all DOM elements to a "redundant" list, where they - // can be picked for re-use, and clear the lists with lines and texts. - // At the end of the function _repaintLabels, left over elements will be cleaned up - var dom = this.dom; - dom.redundant.lines = dom.lines; - dom.redundant.majorTexts = dom.majorTexts; - dom.redundant.minorTexts = dom.minorTexts; - dom.lines = []; - dom.majorTexts = []; - dom.minorTexts = []; - - var cur; - var x = 0; - var isMajor; - var xPrev = 0; - var width = 0; - var prevLine; - var xFirstMajorLabel = undefined; - var max = 0; - var className; + Edge.prototype._rotateForLabelAlignment = function(ctx) { + var dy = this.from.y - this.to.y; + var dx = this.from.x - this.to.x; + var angleInDegrees = Math.atan2(dy, dx); - step.first(); - while (step.hasNext() && max < 1000) { - max++; + // rotate so label it is readable + if((angleInDegrees < -1 && dx < 0) || (angleInDegrees > 0 && dx < 0)){ + angleInDegrees = angleInDegrees + Math.PI; + } + + ctx.rotate(angleInDegrees); + }; - cur = step.getCurrent(); - isMajor = step.isMajor(); - className = step.getClassName(); + /** + * Draws the label rectangle + * @param {CanvasRenderingContext2D} ctx + * @param {String} labelAlignment + * @private + */ + Edge.prototype._drawLabelRect = function(ctx) { + if (this.options.fontFill !== undefined && this.options.fontFill !== null && this.options.fontFill !== "none") { + ctx.fillStyle = this.options.fontFill; + + var lineMargin = 2; - xPrev = x; - x = this.body.util.toScreen(cur); - width = x - xPrev; - if (prevLine) { - prevLine.style.width = width + 'px'; + if (this.options.labelAlignment == 'line-center') { + ctx.fillRect(-this.labelDimensions.width * 0.5, -this.labelDimensions.height * 0.5, this.labelDimensions.width, this.labelDimensions.height); } - - if (this.options.showMinorLabels) { - this._repaintMinorText(x, step.getLabelMinor(), orientation, className); + else if (this.options.labelAlignment == 'line-above') { + ctx.fillRect(-this.labelDimensions.width * 0.5, -(this.labelDimensions.height + lineMargin), this.labelDimensions.width, this.labelDimensions.height); } - - if (isMajor && this.options.showMajorLabels) { - if (x > 0) { - if (xFirstMajorLabel == undefined) { - xFirstMajorLabel = x; - } - this._repaintMajorText(x, step.getLabelMajor(), orientation, className); - } - prevLine = this._repaintMajorLine(x, orientation, className); + else if (this.options.labelAlignment == 'line-below') { + ctx.fillRect(-this.labelDimensions.width * 0.5, lineMargin, this.labelDimensions.width, this.labelDimensions.height); } else { - prevLine = this._repaintMinorLine(x, orientation, className); - } - - step.next(); - } - - // create a major label on the left when needed - if (this.options.showMajorLabels) { - var leftTime = this.body.util.toTime(0), - leftText = step.getLabelMajor(leftTime), - widthText = leftText.length * (this.props.majorCharWidth || 10) + 10; // upper bound estimation - - if (xFirstMajorLabel == undefined || widthText < xFirstMajorLabel) { - this._repaintMajorText(0, leftText, orientation, className); + ctx.fillRect(this.labelDimensions.left, this.labelDimensions.top, this.labelDimensions.width, this.labelDimensions.height); } } - - // Cleanup leftover DOM elements from the redundant list - util.forEach(this.dom.redundant, function (arr) { - while (arr.length) { - var elem = arr.pop(); - if (elem && elem.parentNode) { - elem.parentNode.removeChild(elem); - } - } - }); }; /** - * Create a minor label for the axis at position x + * Draws the label text + * @param {CanvasRenderingContext2D} ctx * @param {Number} x - * @param {String} text - * @param {String} orientation "top" or "bottom" (default) - * @param {String} className + * @param {Number} yLine + * @param {Array} lines + * @param {Number} lineCount + * @param {Number} fontSize * @private */ - TimeAxis.prototype._repaintMinorText = function (x, text, orientation, className) { - // reuse redundant label - var label = this.dom.redundant.minorTexts.shift(); + Edge.prototype._drawLabelText = function(ctx, x, yLine, lines, lineCount, fontSize) { + // draw text + ctx.fillStyle = this.options.fontColor || "black"; + ctx.textAlign = "center"; - if (!label) { - // create new label - var content = document.createTextNode(''); - label = document.createElement('div'); - label.appendChild(content); - this.dom.foreground.appendChild(label); + // check for label alignment + if (this.options.labelAlignment != 'horizontal') { + var lineMargin = 2; + if (this.options.labelAlignment == 'line-above') { + ctx.textBaseline = "alphabetic"; + yLine -= 2 * lineMargin; // distance from edge, required because we use alphabetic. Alphabetic has less difference between browsers + } + else if (this.options.labelAlignment == 'line-below') { + ctx.textBaseline = "hanging"; + yLine += 2 * lineMargin;// distance from edge, required because we use hanging. Hanging has less difference between browsers + } + else { + ctx.textBaseline = "middle"; + } + } + else { + ctx.textBaseline = "middle"; } - this.dom.minorTexts.push(label); - - label.childNodes[0].nodeValue = text; - label.style.top = (orientation == 'top') ? (this.props.majorLabelHeight + 'px') : '0'; - label.style.left = x + 'px'; - label.className = 'text minor ' + className; - //label.title = title; // TODO: this is a heavy operation + // check for strokeWidth + if (this.options.fontStrokeWidth > 0){ + ctx.lineWidth = this.options.fontStrokeWidth; + ctx.strokeStyle = this.options.fontStrokeColor; + ctx.lineJoin = 'round'; + } + for (var i = 0; i < lineCount; i++) { + if(this.options.fontStrokeWidth > 0){ + ctx.strokeText(lines[i], x, yLine); + } + ctx.fillText(lines[i], x, yLine); + yLine += fontSize; + } }; /** - * Create a Major label for the axis at position x - * @param {Number} x - * @param {String} text - * @param {String} orientation "top" or "bottom" (default) - * @param {String} className + * Redraw a edge as a dashed line + * Draw this edge in the given canvas + * @author David Jordan + * @date 2012-08-08 + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx * @private */ - TimeAxis.prototype._repaintMajorText = function (x, text, orientation, className) { - // reuse redundant label - var label = this.dom.redundant.majorTexts.shift(); + Edge.prototype._drawDashLine = function(ctx) { + // set style + ctx.strokeStyle = this._getColor(); + ctx.lineWidth = this._getLineWidth(); - if (!label) { - // create label - var content = document.createTextNode(text); - label = document.createElement('div'); - label.appendChild(content); - this.dom.foreground.appendChild(label); - } - this.dom.majorTexts.push(label); + var via = null; + // only firefox and chrome support this method, else we use the legacy one. + if (ctx.setLineDash !== undefined) { + ctx.save(); + // configure the dash pattern + var pattern = [0]; + if (this.options.dash.length !== undefined && this.options.dash.gap !== undefined) { + pattern = [this.options.dash.length,this.options.dash.gap]; + } + else { + pattern = [5,5]; + } - label.childNodes[0].nodeValue = text; - label.className = 'text major ' + className; - //label.title = title; // TODO: this is a heavy operation + // set dash settings for chrome or firefox + ctx.setLineDash(pattern); + ctx.lineDashOffset = 0; - label.style.top = (orientation == 'top') ? '0' : (this.props.minorLabelHeight + 'px'); - label.style.left = x + 'px'; + // draw the line + via = this._line(ctx); + + // restore the dash settings. + ctx.setLineDash([0]); + ctx.lineDashOffset = 0; + ctx.restore(); + } + else { // unsupporting smooth lines + // draw dashed line + ctx.beginPath(); + ctx.lineCap = 'round'; + if (this.options.dash.altLength !== undefined) //If an alt dash value has been set add to the array this value + { + ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, + [this.options.dash.length,this.options.dash.gap,this.options.dash.altLength,this.options.dash.gap]); + } + else if (this.options.dash.length !== undefined && this.options.dash.gap !== undefined) //If a dash and gap value has been set add to the array this value + { + ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, + [this.options.dash.length,this.options.dash.gap]); + } + else //If all else fails draw a line + { + ctx.moveTo(this.from.x, this.from.y); + ctx.lineTo(this.to.x, this.to.y); + } + ctx.stroke(); + } + + // draw label + if (this.label) { + var point; + if (this.options.smoothCurves.enabled == true && via != null) { + var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); + var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); + point = {x:midpointX, y:midpointY}; + } + else { + point = this._pointOnLine(0.5); + } + this._label(ctx, this.label, point.x, point.y); + } }; /** - * Create a minor line for the axis at position x - * @param {Number} x - * @param {String} orientation "top" or "bottom" (default) - * @param {String} className - * @return {Element} Returns the created line + * Get a point on a line + * @param {Number} percentage. Value between 0 (line start) and 1 (line end) + * @return {Object} point * @private */ - TimeAxis.prototype._repaintMinorLine = function (x, orientation, className) { - // reuse redundant line - var line = this.dom.redundant.lines.shift(); - if (!line) { - // create vertical line - line = document.createElement('div'); - this.dom.background.appendChild(line); - } - this.dom.lines.push(line); - - var props = this.props; - if (orientation == 'top') { - line.style.top = props.majorLabelHeight + 'px'; - } - else { - line.style.top = this.body.domProps.top.height + 'px'; + Edge.prototype._pointOnLine = function (percentage) { + return { + x: (1 - percentage) * this.from.x + percentage * this.to.x, + y: (1 - percentage) * this.from.y + percentage * this.to.y } - line.style.height = props.minorLineHeight + 'px'; - line.style.left = (x - props.minorLineWidth / 2) + 'px'; - - line.className = 'grid vertical minor ' + className; - - return line; }; /** - * Create a Major line for the axis at position x + * Get a point on a circle * @param {Number} x - * @param {String} orientation "top" or "bottom" (default) - * @param {String} className - * @return {Element} Returns the created line + * @param {Number} y + * @param {Number} radius + * @param {Number} percentage. Value between 0 (line start) and 1 (line end) + * @return {Object} point * @private */ - TimeAxis.prototype._repaintMajorLine = function (x, orientation, className) { - // reuse redundant line - var line = this.dom.redundant.lines.shift(); - if (!line) { - // create vertical line - line = document.createElement('div'); - this.dom.background.appendChild(line); - } - this.dom.lines.push(line); - - var props = this.props; - if (orientation == 'top') { - line.style.top = '0'; - } - else { - line.style.top = this.body.domProps.top.height + 'px'; + Edge.prototype._pointOnCircle = function (x, y, radius, percentage) { + var angle = (percentage - 3/8) * 2 * Math.PI; + return { + x: x + radius * Math.cos(angle), + y: y - radius * Math.sin(angle) } - line.style.left = (x - props.majorLineWidth / 2) + 'px'; - line.style.height = props.majorLineHeight + 'px'; - - line.className = 'grid vertical major ' + className; - - return line; }; /** - * Determine the size of text on the axis (both major and minor axis). - * The size is calculated only once and then cached in this.props. + * Redraw a edge as a line with an arrow halfway the line + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx * @private */ - TimeAxis.prototype._calculateCharSize = function () { - // Note: We calculate char size with every redraw. Size may change, for - // example when any of the timelines parents had display:none for example. + Edge.prototype._drawArrowCenter = function(ctx) { + var point; + // set style + ctx.strokeStyle = this._getColor(); + ctx.fillStyle = ctx.strokeStyle; + ctx.lineWidth = this._getLineWidth(); - // determine the char width and height on the minor axis - if (!this.dom.measureCharMinor) { - this.dom.measureCharMinor = document.createElement('DIV'); - this.dom.measureCharMinor.className = 'text minor measure'; - this.dom.measureCharMinor.style.position = 'absolute'; + if (this.from != this.to) { + // draw line + var via = this._line(ctx); - this.dom.measureCharMinor.appendChild(document.createTextNode('0')); - this.dom.foreground.appendChild(this.dom.measureCharMinor); - } - this.props.minorCharHeight = this.dom.measureCharMinor.clientHeight; - this.props.minorCharWidth = this.dom.measureCharMinor.clientWidth; + var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; + // draw an arrow halfway the line + if (this.options.smoothCurves.enabled == true && via != null) { + var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); + var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); + point = {x:midpointX, y:midpointY}; + } + else { + point = this._pointOnLine(0.5); + } - // determine the char width and height on the major axis - if (!this.dom.measureCharMajor) { - this.dom.measureCharMajor = document.createElement('DIV'); - this.dom.measureCharMajor.className = 'text major measure'; - this.dom.measureCharMajor.style.position = 'absolute'; + ctx.arrow(point.x, point.y, angle, length); + ctx.fill(); + ctx.stroke(); - this.dom.measureCharMajor.appendChild(document.createTextNode('0')); - this.dom.foreground.appendChild(this.dom.measureCharMajor); + // draw label + if (this.label) { + this._label(ctx, this.label, point.x, point.y); + } } - this.props.majorCharHeight = this.dom.measureCharMajor.clientHeight; - this.props.majorCharWidth = this.dom.measureCharMajor.clientWidth; - }; + else { + // draw circle + var x, y; + var radius = 0.25 * Math.max(100,this.physics.springLength); + var node = this.from; + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width * 0.5; + y = node.y - radius; + } + else { + x = node.x + radius; + y = node.y - node.height * 0.5; + } + this._circle(ctx, x, y, radius); - /** - * 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 - */ - TimeAxis.prototype.snap = function(date) { - return this.step.snap(date); - }; + // draw all arrows + var angle = 0.2 * Math.PI; + var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; + point = this._pointOnCircle(x, y, radius, 0.5); + ctx.arrow(point.x, point.y, angle, length); + ctx.fill(); + ctx.stroke(); - module.exports = TimeAxis; + // draw label + if (this.label) { + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); + } + } + }; + Edge.prototype._pointOnBezier = function(t) { + var via = this._getViaCoordinates(); -/***/ }, -/* 38 */ -/***/ function(module, exports, __webpack_require__) { + var x = Math.pow(1-t,2)*this.from.x + (2*t*(1 - t))*via.x + Math.pow(t,2)*this.to.x; + var y = Math.pow(1-t,2)*this.from.y + (2*t*(1 - t))*via.y + Math.pow(t,2)*this.to.y; - var moment = __webpack_require__(2); - var DateUtil = __webpack_require__(24); - var util = __webpack_require__(1); + return {x:x,y:y}; + } /** - * @constructor TimeStep - * The class TimeStep is an iterator for dates. You provide a start date and an - * end date. The class itself determines the best scale (step size) based on the - * provided start Date, end Date, and minimumStep. - * - * If minimumStep is provided, the step size is chosen as close as possible - * to the minimumStep but larger than minimumStep. If minimumStep is not - * provided, the scale is set to 1 DAY. - * The minimumStep should correspond with the onscreen size of about 6 characters - * - * Alternatively, you can set a scale by hand. - * After creation, you can initialize the class by executing first(). Then you - * can iterate from the start date to the end date via next(). You can check if - * the end date is reached with the function hasNext(). After each step, you can - * retrieve the current date via getCurrent(). - * The TimeStep has scales ranging from milliseconds, seconds, minutes, hours, - * days, to years. - * - * Version: 1.2 + * This function uses binary search to look for the point where the bezier curve crosses the border of the node. * - * @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 + * @param from + * @param ctx + * @returns {*} + * @private */ - function TimeStep(start, end, minimumStep, hiddenDates) { - // variables - this.current = new Date(); - this._start = new Date(); - this._end = new Date(); + Edge.prototype._findBorderPosition = function(from,ctx) { + var maxIterations = 10; + var iteration = 0; + var low = 0; + var high = 1; + var pos,angle,distanceToBorder, distanceToNodes, difference; + var threshold = 0.2; + var node = this.to; + if (from == true) { + node = this.from; + } - this.autoScale = true; - this.scale = 'day'; - this.step = 1; + while (low <= high && iteration < maxIterations) { + var middle = (low + high) * 0.5; - // initialize the range - this.setRange(start, end, minimumStep); + pos = this._pointOnBezier(middle); + angle = Math.atan2((node.y - pos.y), (node.x - pos.x)); + distanceToBorder = node.distanceToBorder(ctx,angle); + distanceToNodes = Math.sqrt(Math.pow(pos.x-node.x,2) + Math.pow(pos.y-node.y,2)); + difference = distanceToBorder - distanceToNodes; + if (Math.abs(difference) < threshold) { + break; // found + } + else if (difference < 0) { // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node. + if (from == false) { + low = middle; + } + else { + high = middle; + } + } + else { + if (from == false) { + high = middle; + } + else { + low = middle; + } + } - // hidden Dates options - this.switchedDay = false; - this.switchedMonth = false; - this.switchedYear = false; - this.hiddenDates = hiddenDates; - if (hiddenDates === undefined) { - this.hiddenDates = []; + iteration++; } + pos.t = middle; - this.format = TimeStep.FORMAT; // default formatting - } - - // Time formatting - TimeStep.FORMAT = { - minorLabels: { - millisecond:'SSS', - second: 's', - minute: 'HH:mm', - hour: 'HH:mm', - weekday: 'ddd D', - day: 'D', - month: 'MMM', - year: 'YYYY' - }, - majorLabels: { - millisecond:'HH:mm:ss', - second: 'D MMMM HH:mm', - minute: 'ddd D MMMM', - hour: 'ddd D MMMM', - weekday: 'MMMM YYYY', - day: 'MMMM YYYY', - month: 'YYYY', - year: '' - } + return pos; }; /** - * Set custom formatting for the minor an major labels of the TimeStep. - * Both `minorLabels` and `majorLabels` are an Object with properties: - * 'millisecond, 'second, 'minute', 'hour', 'weekday, 'day, 'month, 'year'. - * @param {{minorLabels: Object, majorLabels: Object}} format + * Redraw a edge as a line with an arrow + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private */ - TimeStep.prototype.setFormat = function (format) { - var defaultFormat = util.deepExtend({}, TimeStep.FORMAT); - this.format = util.deepExtend(defaultFormat, format); - }; + Edge.prototype._drawArrow = function(ctx) { + // set style + ctx.strokeStyle = this._getColor(); + ctx.fillStyle = ctx.strokeStyle; + ctx.lineWidth = this._getLineWidth(); - /** - * Set a new range - * If minimumStep is provided, the step size is chosen as close as possible - * to the minimumStep but larger than minimumStep. If minimumStep is not - * provided, the scale is set to 1 DAY. - * The minimumStep should correspond with the onscreen size of about 6 characters - * @param {Date} [start] The start date and time. - * @param {Date} [end] The end date and time. - * @param {int} [minimumStep] Optional. Minimum step size in milliseconds - */ - TimeStep.prototype.setRange = function(start, end, minimumStep) { - if (!(start instanceof Date) || !(end instanceof Date)) { - throw "No legal start or end date in method setRange"; - } + // set vars + var angle, length, arrowPos; - this._start = (start != undefined) ? new Date(start.valueOf()) : new Date(); - this._end = (end != undefined) ? new Date(end.valueOf()) : new Date(); + // if not connected to itself + if (this.from != this.to) { + // draw line + this._line(ctx); - if (this.autoScale) { - this.setMinimumStep(minimumStep); - } - }; + // draw arrow head + if (this.options.smoothCurves.enabled == true) { + var via = this._getViaCoordinates(); + arrowPos = this._findBorderPosition(false, ctx); + var guidePos = this._pointOnBezier(Math.max(0.0, arrowPos.t - 0.1)) + angle = Math.atan2((arrowPos.y - guidePos.y), (arrowPos.x - guidePos.x)); + } + else { + angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var dx = (this.to.x - this.from.x); + var dy = (this.to.y - this.from.y); + var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); + var toBorderDist = this.to.distanceToBorder(ctx, angle); + var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; - /** - * Set the range iterator to the start date. - */ - TimeStep.prototype.first = function() { - this.current = new Date(this._start.valueOf()); - this.roundToMinor(); - }; + arrowPos = {}; + arrowPos.x = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x; + arrowPos.y = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y; + } - /** - * Round the current date to the first minor date value - * This must be executed once when the current date is set to start Date - */ - TimeStep.prototype.roundToMinor = function() { - // round to floor - // IMPORTANT: we have no breaks in this switch! (this is no bug) - // noinspection FallThroughInSwitchStatementJS - switch (this.scale) { - case 'year': - this.current.setFullYear(this.step * Math.floor(this.current.getFullYear() / this.step)); - this.current.setMonth(0); - case 'month': this.current.setDate(1); - case 'day': // intentional fall through - case 'weekday': this.current.setHours(0); - case 'hour': this.current.setMinutes(0); - case 'minute': this.current.setSeconds(0); - case 'second': this.current.setMilliseconds(0); - //case 'millisecond': // nothing to do for milliseconds - } + // draw arrow at the end of the line + length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; + ctx.arrow(arrowPos.x,arrowPos.y, angle, length); + ctx.fill(); + ctx.stroke(); - if (this.step != 1) { - // round down to the first minor value that is a multiple of the current step size - switch (this.scale) { - case 'millisecond': this.current.setMilliseconds(this.current.getMilliseconds() - this.current.getMilliseconds() % this.step); break; - case 'second': this.current.setSeconds(this.current.getSeconds() - this.current.getSeconds() % this.step); break; - case 'minute': this.current.setMinutes(this.current.getMinutes() - this.current.getMinutes() % this.step); break; - case 'hour': this.current.setHours(this.current.getHours() - this.current.getHours() % this.step); break; - case 'weekday': // intentional fall through - case 'day': this.current.setDate((this.current.getDate()-1) - (this.current.getDate()-1) % this.step + 1); break; - case 'month': this.current.setMonth(this.current.getMonth() - this.current.getMonth() % this.step); break; - case 'year': this.current.setFullYear(this.current.getFullYear() - this.current.getFullYear() % this.step); break; - default: break; + // draw label + if (this.label) { + var point; + if (this.options.smoothCurves.enabled == true && via != null) { + point = this._pointOnBezier(0.5); + } + else { + point = this._pointOnLine(0.5); + } + this._label(ctx, this.label, point.x, point.y); } } - }; + else { + // draw circle + var node = this.from; + var x, y, arrow; + var radius = 0.25 * Math.max(100,this.physics.springLength); + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width * 0.5; + y = node.y - radius; + arrow = { + x: x, + y: node.y, + angle: 0.9 * Math.PI + }; + } + else { + x = node.x + radius; + y = node.y - node.height * 0.5; + arrow = { + x: node.x, + y: y, + angle: 0.6 * Math.PI + }; + } + ctx.beginPath(); + // TODO: similarly, for a line without arrows, draw to the border of the nodes instead of the center + ctx.arc(x, y, radius, 0, 2 * Math.PI, false); + ctx.stroke(); - /** - * Check if the there is a next step - * @return {boolean} true if the current date has not passed the end date - */ - TimeStep.prototype.hasNext = function () { - return (this.current.valueOf() <= this._end.valueOf()); + // draw all arrows + var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; + ctx.arrow(arrow.x, arrow.y, arrow.angle, length); + ctx.fill(); + ctx.stroke(); + + // draw label + if (this.label) { + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); + } + } }; /** - * Do the next step + * Calculate the distance between a point (x3,y3) and a line segment from + * (x1,y1) to (x2,y2). + * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment + * @param {number} x1 + * @param {number} y1 + * @param {number} x2 + * @param {number} y2 + * @param {number} x3 + * @param {number} y3 + * @private */ - TimeStep.prototype.next = function() { - var prev = this.current.valueOf(); - - // Two cases, needed to prevent issues with switching daylight savings - // (end of March and end of October) - if (this.current.getMonth() < 6) { - switch (this.scale) { - case 'millisecond': - - this.current = new Date(this.current.valueOf() + this.step); break; - case 'second': this.current = new Date(this.current.valueOf() + this.step * 1000); break; - case 'minute': this.current = new Date(this.current.valueOf() + this.step * 1000 * 60); break; - case 'hour': - this.current = new Date(this.current.valueOf() + this.step * 1000 * 60 * 60); - // in case of skipping an hour for daylight savings, adjust the hour again (else you get: 0h 5h 9h ... instead of 0h 4h 8h ...) - var h = this.current.getHours(); - this.current.setHours(h - (h % this.step)); - break; - case 'weekday': // intentional fall through - case 'day': this.current.setDate(this.current.getDate() + this.step); break; - case 'month': this.current.setMonth(this.current.getMonth() + this.step); break; - case 'year': this.current.setFullYear(this.current.getFullYear() + this.step); break; - default: break; + Edge.prototype._getDistanceToEdge = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point + var returnValue = 0; + if (this.from != this.to) { + if (this.options.smoothCurves.enabled == true) { + var xVia, yVia; + if (this.options.smoothCurves.enabled == true && this.options.smoothCurves.dynamic == true) { + xVia = this.via.x; + yVia = this.via.y; + } + else { + var via = this._getViaCoordinates(); + xVia = via.x; + yVia = via.y; + } + var minDistance = 1e9; + var distance; + var i,t,x,y, lastX, lastY; + for (i = 0; i < 10; i++) { + t = 0.1*i; + x = Math.pow(1-t,2)*x1 + (2*t*(1 - t))*xVia + Math.pow(t,2)*x2; + y = Math.pow(1-t,2)*y1 + (2*t*(1 - t))*yVia + Math.pow(t,2)*y2; + if (i > 0) { + distance = this._getDistanceToLine(lastX,lastY,x,y, x3,y3); + minDistance = distance < minDistance ? distance : minDistance; + } + lastX = x; lastY = y; + } + returnValue = minDistance; + } + else { + returnValue = this._getDistanceToLine(x1,y1,x2,y2,x3,y3); } } else { - switch (this.scale) { - case 'millisecond': this.current = new Date(this.current.valueOf() + this.step); break; - case 'second': this.current.setSeconds(this.current.getSeconds() + this.step); break; - case 'minute': this.current.setMinutes(this.current.getMinutes() + this.step); break; - case 'hour': this.current.setHours(this.current.getHours() + this.step); break; - case 'weekday': // intentional fall through - case 'day': this.current.setDate(this.current.getDate() + this.step); break; - case 'month': this.current.setMonth(this.current.getMonth() + this.step); break; - case 'year': this.current.setFullYear(this.current.getFullYear() + this.step); break; - default: break; + var x, y, dx, dy; + var radius = 0.25 * this.physics.springLength; + var node = this.from; + if (node.width > node.height) { + x = node.x + 0.5 * node.width; + y = node.y - radius; + } + else { + x = node.x + radius; + y = node.y - 0.5 * node.height; } + dx = x - x3; + dy = y - y3; + returnValue = Math.abs(Math.sqrt(dx*dx + dy*dy) - radius); } - if (this.step != 1) { - // round down to the correct major value - switch (this.scale) { - case 'millisecond': if(this.current.getMilliseconds() < this.step) this.current.setMilliseconds(0); break; - case 'second': if(this.current.getSeconds() < this.step) this.current.setSeconds(0); break; - case 'minute': if(this.current.getMinutes() < this.step) this.current.setMinutes(0); break; - case 'hour': if(this.current.getHours() < this.step) this.current.setHours(0); break; - case 'weekday': // intentional fall through - case 'day': if(this.current.getDate() < this.step+1) this.current.setDate(1); break; - case 'month': if(this.current.getMonth() < this.step) this.current.setMonth(0); break; - case 'year': break; // nothing to do for year - default: break; - } + if (this.labelDimensions.left < x3 && + this.labelDimensions.left + this.labelDimensions.width > x3 && + this.labelDimensions.top < y3 && + this.labelDimensions.top + this.labelDimensions.height > y3) { + return 0; + } + else { + return returnValue; } + }; - // safety mechanism: if current time is still unchanged, move to the end - if (this.current.valueOf() == prev) { - this.current = new Date(this._end.valueOf()); + Edge.prototype._getDistanceToLine = function(x1,y1,x2,y2,x3,y3) { + var px = x2-x1, + py = y2-y1, + something = px*px + py*py, + u = ((x3 - x1) * px + (y3 - y1) * py) / something; + + if (u > 1) { + u = 1; + } + else if (u < 0) { + u = 0; } - DateUtil.stepOverHiddenDates(this, prev); - }; + var x = x1 + u * px, + y = y1 + u * py, + dx = x - x3, + dy = y - y3; + //# Note: If the actual distance does not matter, + //# if you only want to compare what this function + //# returns to other results of this function, you + //# can just return the squared distance instead + //# (i.e. remove the sqrt) to gain a little performance - /** - * Get the current datetime - * @return {Date} current The current date - */ - TimeStep.prototype.getCurrent = function() { - return this.current; + return Math.sqrt(dx*dx + dy*dy); }; /** - * Set a custom scale. Autoscaling will be disabled. - * For example setScale(SCALE.MINUTES, 5) will result - * in minor steps of 5 minutes, and major steps of an hour. + * This allows the zoom level of the network to influence the rendering * - * @param {string} newScale - * A scale. Choose from 'millisecond, 'second, - * 'minute', 'hour', 'weekday, 'day, 'month, 'year'. - * @param {Number} newStep A step size, by default 1. Choose for - * example 1, 2, 5, or 10. + * @param scale */ - TimeStep.prototype.setScale = function(newScale, newStep) { - this.scale = newScale; + Edge.prototype.setScale = function(scale) { + this.networkScaleInv = 1.0/scale; + }; - if (newStep > 0) { - this.step = newStep; - } - this.autoScale = false; + Edge.prototype.select = function() { + this.selected = true; }; - /** - * Enable or disable autoscaling - * @param {boolean} enable If true, autoascaling is set true - */ - TimeStep.prototype.setAutoScale = function (enable) { - this.autoScale = enable; + Edge.prototype.unselect = function() { + this.selected = false; }; - - /** - * Automatically determine the scale that bests fits the provided minimum step - * @param {Number} [minimumStep] The minimum step size in milliseconds - */ - TimeStep.prototype.setMinimumStep = function(minimumStep) { - if (minimumStep == undefined) { - return; + Edge.prototype.positionBezierNode = function() { + if (this.via !== null && this.from !== null && this.to !== null) { + this.via.x = 0.5 * (this.from.x + this.to.x); + this.via.y = 0.5 * (this.from.y + this.to.y); + } + else if (this.via !== null) { + this.via.x = 0; + this.via.y = 0; } - - //var b = asc + ds; - - var stepYear = (1000 * 60 * 60 * 24 * 30 * 12); - var stepMonth = (1000 * 60 * 60 * 24 * 30); - var stepDay = (1000 * 60 * 60 * 24); - var stepHour = (1000 * 60 * 60); - var stepMinute = (1000 * 60); - var stepSecond = (1000); - var stepMillisecond= (1); - - // find the smallest step that is larger than the provided minimumStep - if (stepYear*1000 > minimumStep) {this.scale = 'year'; this.step = 1000;} - if (stepYear*500 > minimumStep) {this.scale = 'year'; this.step = 500;} - if (stepYear*100 > minimumStep) {this.scale = 'year'; this.step = 100;} - if (stepYear*50 > minimumStep) {this.scale = 'year'; this.step = 50;} - if (stepYear*10 > minimumStep) {this.scale = 'year'; this.step = 10;} - if (stepYear*5 > minimumStep) {this.scale = 'year'; this.step = 5;} - if (stepYear > minimumStep) {this.scale = 'year'; this.step = 1;} - if (stepMonth*3 > minimumStep) {this.scale = 'month'; this.step = 3;} - if (stepMonth > minimumStep) {this.scale = 'month'; this.step = 1;} - if (stepDay*5 > minimumStep) {this.scale = 'day'; this.step = 5;} - if (stepDay*2 > minimumStep) {this.scale = 'day'; this.step = 2;} - if (stepDay > minimumStep) {this.scale = 'day'; this.step = 1;} - if (stepDay/2 > minimumStep) {this.scale = 'weekday'; this.step = 1;} - if (stepHour*4 > minimumStep) {this.scale = 'hour'; this.step = 4;} - if (stepHour > minimumStep) {this.scale = 'hour'; this.step = 1;} - if (stepMinute*15 > minimumStep) {this.scale = 'minute'; this.step = 15;} - if (stepMinute*10 > minimumStep) {this.scale = 'minute'; this.step = 10;} - if (stepMinute*5 > minimumStep) {this.scale = 'minute'; this.step = 5;} - if (stepMinute > minimumStep) {this.scale = 'minute'; this.step = 1;} - if (stepSecond*15 > minimumStep) {this.scale = 'second'; this.step = 15;} - if (stepSecond*10 > minimumStep) {this.scale = 'second'; this.step = 10;} - if (stepSecond*5 > minimumStep) {this.scale = 'second'; this.step = 5;} - if (stepSecond > minimumStep) {this.scale = 'second'; this.step = 1;} - if (stepMillisecond*200 > minimumStep) {this.scale = 'millisecond'; this.step = 200;} - if (stepMillisecond*100 > minimumStep) {this.scale = 'millisecond'; this.step = 100;} - if (stepMillisecond*50 > minimumStep) {this.scale = 'millisecond'; this.step = 50;} - if (stepMillisecond*10 > minimumStep) {this.scale = 'millisecond'; this.step = 10;} - if (stepMillisecond*5 > minimumStep) {this.scale = 'millisecond'; this.step = 5;} - if (stepMillisecond > minimumStep) {this.scale = 'millisecond'; this.step = 1;} }; /** - * 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 + * This function draws the control nodes for the manipulator. + * In order to enable this, only set the this.controlNodesEnabled to true. + * @param ctx */ - TimeStep.prototype.snap = function(date) { - var clone = new Date(date.valueOf()); - - if (this.scale == 'year') { - var year = clone.getFullYear() + Math.round(clone.getMonth() / 12); - clone.setFullYear(Math.round(year / this.step) * this.step); - clone.setMonth(0); - clone.setDate(0); - clone.setHours(0); - clone.setMinutes(0); - clone.setSeconds(0); - clone.setMilliseconds(0); - } - else if (this.scale == 'month') { - if (clone.getDate() > 15) { - clone.setDate(1); - clone.setMonth(clone.getMonth() + 1); - // important: first set Date to 1, after that change the month. - } - else { - clone.setDate(1); + Edge.prototype._drawControlNodes = function(ctx) { + if (this.controlNodesEnabled == true) { + if (this.controlNodes.from === null && this.controlNodes.to === null) { + var nodeIdFrom = "edgeIdFrom:".concat(this.id); + var nodeIdTo = "edgeIdTo:".concat(this.id); + var constants = { + nodes:{group:'', radius:7, borderWidth:2, borderWidthSelected: 2}, + physics:{damping:0}, + clustering: {maxNodeSizeIncrements: 0 ,nodeScaling: {width:0, height: 0, radius:0}} + }; + this.controlNodes.from = new Node( + {id:nodeIdFrom, + shape:'dot', + color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}} + },{},{},constants); + this.controlNodes.to = new Node( + {id:nodeIdTo, + shape:'dot', + color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}} + },{},{},constants); } - clone.setHours(0); - clone.setMinutes(0); - clone.setSeconds(0); - clone.setMilliseconds(0); - } - else if (this.scale == 'day') { - //noinspection FallthroughInSwitchStatementJS - switch (this.step) { - case 5: - case 2: - clone.setHours(Math.round(clone.getHours() / 24) * 24); break; - default: - clone.setHours(Math.round(clone.getHours() / 12) * 12); break; - } - clone.setMinutes(0); - clone.setSeconds(0); - clone.setMilliseconds(0); - } - else if (this.scale == 'weekday') { - //noinspection FallthroughInSwitchStatementJS - switch (this.step) { - case 5: - case 2: - clone.setHours(Math.round(clone.getHours() / 12) * 12); break; - default: - clone.setHours(Math.round(clone.getHours() / 6) * 6); break; - } - clone.setMinutes(0); - clone.setSeconds(0); - clone.setMilliseconds(0); - } - else if (this.scale == 'hour') { - switch (this.step) { - case 4: - clone.setMinutes(Math.round(clone.getMinutes() / 60) * 60); break; - default: - clone.setMinutes(Math.round(clone.getMinutes() / 30) * 30); break; - } - clone.setSeconds(0); - clone.setMilliseconds(0); - } else if (this.scale == 'minute') { - //noinspection FallthroughInSwitchStatementJS - switch (this.step) { - case 15: - case 10: - clone.setMinutes(Math.round(clone.getMinutes() / 5) * 5); - clone.setSeconds(0); - break; - case 5: - clone.setSeconds(Math.round(clone.getSeconds() / 60) * 60); break; - default: - clone.setSeconds(Math.round(clone.getSeconds() / 30) * 30); break; + this.controlNodes.positions = {}; + if (this.controlNodes.from.selected == false) { + this.controlNodes.positions.from = this.getControlNodeFromPosition(ctx); + this.controlNodes.from.x = this.controlNodes.positions.from.x; + this.controlNodes.from.y = this.controlNodes.positions.from.y; } - clone.setMilliseconds(0); - } - else if (this.scale == 'second') { - //noinspection FallthroughInSwitchStatementJS - switch (this.step) { - case 15: - case 10: - clone.setSeconds(Math.round(clone.getSeconds() / 5) * 5); - clone.setMilliseconds(0); - break; - case 5: - clone.setMilliseconds(Math.round(clone.getMilliseconds() / 1000) * 1000); break; - default: - clone.setMilliseconds(Math.round(clone.getMilliseconds() / 500) * 500); break; + if (this.controlNodes.to.selected == false) { + this.controlNodes.positions.to = this.getControlNodeToPosition(ctx); + this.controlNodes.to.x = this.controlNodes.positions.to.x; + this.controlNodes.to.y = this.controlNodes.positions.to.y; } + + this.controlNodes.from.draw(ctx); + this.controlNodes.to.draw(ctx); } - else if (this.scale == 'millisecond') { - var step = this.step > 5 ? this.step / 2 : 1; - clone.setMilliseconds(Math.round(clone.getMilliseconds() / step) * step); + else { + this.controlNodes = {from:null, to:null, positions:{}}; } - - return clone; }; /** - * 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. + * Enable control nodes. + * @private */ - TimeStep.prototype.isMajor = function() { - if (this.switchedYear == true) { - this.switchedYear = false; - switch (this.scale) { - case 'year': - case 'month': - case 'weekday': - case 'day': - case 'hour': - case 'minute': - case 'second': - case 'millisecond': - return true; - default: - return false; - } - } - else if (this.switchedMonth == true) { - this.switchedMonth = false; - switch (this.scale) { - case 'weekday': - case 'day': - case 'hour': - case 'minute': - case 'second': - case 'millisecond': - return true; - default: - return false; - } - } - else if (this.switchedDay == true) { - this.switchedDay = false; - switch (this.scale) { - case 'millisecond': - case 'second': - case 'minute': - case 'hour': - return true; - default: - return false; - } - } - - switch (this.scale) { - case 'millisecond': - return (this.current.getMilliseconds() == 0); - case 'second': - return (this.current.getSeconds() == 0); - case 'minute': - return (this.current.getHours() == 0) && (this.current.getMinutes() == 0); - case 'hour': - return (this.current.getHours() == 0); - case 'weekday': // intentional fall through - case 'day': - return (this.current.getDate() == 1); - case 'month': - return (this.current.getMonth() == 0); - case 'year': - return false; - default: - return false; - } + Edge.prototype._enableControlNodes = function() { + this.fromBackup = this.from; + this.toBackup = this.to; + this.controlNodesEnabled = true; }; - /** - * Returns formatted text for the minor axislabel, depending on the current - * date and the scale. For example when scale is MINUTE, the current time is - * formatted as "hh:mm". - * @param {Date} [date] custom date. if not provided, current date is taken + * disable control nodes and remove from dynamicEdges from old node + * @private */ - TimeStep.prototype.getLabelMinor = function(date) { - if (date == undefined) { - date = this.current; + Edge.prototype._disableControlNodes = function() { + this.fromId = this.from.id; + this.toId = this.to.id; + if (this.fromId != this.fromBackup.id) { // from was changed, remove edge from old 'from' node dynamic edges + this.fromBackup.detachEdge(this); + } + else if (this.toId != this.toBackup.id) { // to was changed, remove edge from old 'to' node dynamic edges + this.toBackup.detachEdge(this); } - var format = this.format.minorLabels[this.scale]; - return (format && format.length > 0) ? moment(date).format(format) : ''; + this.fromBackup = null; + this.toBackup = null; + this.controlNodesEnabled = false; }; + /** - * Returns formatted text for the major axis label, depending on the current - * date and the scale. For example when scale is MINUTE, the major scale is - * hours, and the hour will be formatted as "hh". - * @param {Date} [date] custom date. if not provided, current date is taken + * This checks if one of the control nodes is selected and if so, returns the control node object. Else it returns null. + * @param x + * @param y + * @returns {null} + * @private */ - TimeStep.prototype.getLabelMajor = function(date) { - if (date == undefined) { - date = this.current; - } + Edge.prototype._getSelectedControlNode = function(x,y) { + var positions = this.controlNodes.positions; + var fromDistance = Math.sqrt(Math.pow(x - positions.from.x,2) + Math.pow(y - positions.from.y,2)); + var toDistance = Math.sqrt(Math.pow(x - positions.to.x ,2) + Math.pow(y - positions.to.y ,2)); - var format = this.format.majorLabels[this.scale]; - return (format && format.length > 0) ? moment(date).format(format) : ''; + if (fromDistance < 15) { + this.connectedNode = this.from; + this.from = this.controlNodes.from; + return this.controlNodes.from; + } + else if (toDistance < 15) { + this.connectedNode = this.to; + this.to = this.controlNodes.to; + return this.controlNodes.to; + } + else { + return null; + } }; - TimeStep.prototype.getClassName = function() { - var m = moment(this.current); - var date = m.locale ? m.locale('en') : m.lang('en'); // old versions of moment have .lang() function - var step = this.step; - - function even(value) { - return (value / step % 2 == 0) ? ' even' : ' odd'; - } - function today(date) { - if (date.isSame(new Date(), 'day')) { - return ' today'; - } - if (date.isSame(moment().add(1, 'day'), 'day')) { - return ' tomorrow'; - } - if (date.isSame(moment().add(-1, 'day'), 'day')) { - return ' yesterday'; - } - return ''; + /** + * this resets the control nodes to their original position. + * @private + */ + Edge.prototype._restoreControlNodes = function() { + if (this.controlNodes.from.selected == true) { + this.from = this.connectedNode; + this.connectedNode = null; + this.controlNodes.from.unselect(); } - - function currentWeek(date) { - return date.isSame(new Date(), 'week') ? ' current-week' : ''; + else if (this.controlNodes.to.selected == true) { + this.to = this.connectedNode; + this.connectedNode = null; + this.controlNodes.to.unselect(); } + }; - function currentMonth(date) { - return date.isSame(new Date(), 'month') ? ' current-month' : ''; + /** + * this calculates the position of the control nodes on the edges of the parent nodes. + * + * @param ctx + * @returns {x: *, y: *} + */ + Edge.prototype.getControlNodeFromPosition = function(ctx) { + // draw arrow head + var controlnodeFromPos; + if (this.options.smoothCurves.enabled == true) { + controlnodeFromPos = this._findBorderPosition(true, ctx); } + else { + var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var dx = (this.to.x - this.from.x); + var dy = (this.to.y - this.from.y); + var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); - function currentYear(date) { - return date.isSame(new Date(), 'year') ? ' current-year' : ''; + var fromBorderDist = this.from.distanceToBorder(ctx, angle + Math.PI); + var fromBorderPoint = (edgeSegmentLength - fromBorderDist) / edgeSegmentLength; + controlnodeFromPos = {}; + controlnodeFromPos.x = (fromBorderPoint) * this.from.x + (1 - fromBorderPoint) * this.to.x; + controlnodeFromPos.y = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y; } - switch (this.scale) { - case 'millisecond': - return even(date.milliseconds()).trim(); - - case 'second': - return even(date.seconds()).trim(); - - case 'minute': - return even(date.minutes()).trim(); - - case 'hour': - var hours = date.hours(); - if (this.step == 4) { - hours = hours + '-' + (hours + 4); - } - return hours + 'h' + today(date) + even(date.hours()); - - case 'weekday': - return date.format('dddd').toLowerCase() + - today(date) + currentWeek(date) + even(date.date()); - - case 'day': - var day = date.date(); - var month = date.format('MMMM').toLowerCase(); - return 'day' + day + ' ' + month + currentMonth(date) + even(day - 1); - - case 'month': - return date.format('MMMM').toLowerCase() + - currentMonth(date) + even(date.month()); + return controlnodeFromPos; + }; - case 'year': - var year = date.year(); - return 'year' + year + currentYear(date)+ even(year); + /** + * this calculates the position of the control nodes on the edges of the parent nodes. + * + * @param ctx + * @returns {{from: {x: number, y: number}, to: {x: *, y: *}}} + */ + Edge.prototype.getControlNodeToPosition = function(ctx) { + // draw arrow head + var controlnodeFromPos,controlnodeToPos; + if (this.options.smoothCurves.enabled == true) { + controlnodeToPos = this._findBorderPosition(false, ctx); + } + else { + var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var dx = (this.to.x - this.from.x); + var dy = (this.to.y - this.from.y); + var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); + var toBorderDist = this.to.distanceToBorder(ctx, angle); + var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; - default: - return ''; + controlnodeToPos = {}; + controlnodeToPos.x = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x; + controlnodeToPos.y = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y; } - }; - module.exports = TimeStep; + return controlnodeToPos; + }; + module.exports = Edge; /***/ }, -/* 39 */ +/* 38 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); - var Component = __webpack_require__(23); - var moment = __webpack_require__(2); - var locales = __webpack_require__(40); /** - * A current time bar - * @param {{range: Range, dom: Object, domProps: Object}} body - * @param {Object} [options] Available parameters: - * {Boolean} [showCurrentTime] - * @constructor CurrentTime - * @extends Component + * @class Groups + * This class can store groups and properties specific for groups. */ - function CurrentTime (body, options) { - this.body = body; - - // default options - this.defaultOptions = { - showCurrentTime: true, - - locales: locales, - locale: 'en' - }; - this.options = util.extend({}, this.defaultOptions); - this.offset = 0; - - this._create(); - - this.setOptions(options); + function Groups() { + this.clear(); + this.defaultIndex = 0; } - CurrentTime.prototype = new Component(); - - /** - * Create the HTML DOM for the current time bar - * @private - */ - CurrentTime.prototype._create = function() { - var bar = document.createElement('div'); - bar.className = 'currenttime'; - bar.style.position = 'absolute'; - bar.style.top = '0px'; - bar.style.height = '100%'; - - this.bar = bar; - }; /** - * Destroy the CurrentTime bar + * default constants for group colors */ - CurrentTime.prototype.destroy = function () { - this.options.showCurrentTime = false; - this.redraw(); // will remove the bar from the DOM and stop refreshing + Groups.DEFAULT = [ + {border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}, hover: {border: "#2B7CE9", background: "#D2E5FF"}}, // blue + {border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}, hover: {border: "#FFA500", background: "#FFFFA3"}}, // yellow + {border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}, hover: {border: "#FA0A10", background: "#FFAFB1"}}, // red + {border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}, hover: {border: "#41A906", background: "#A1EC76"}}, // green + {border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}, hover: {border: "#E129F0", background: "#F0B3F5"}}, // magenta + {border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}, hover: {border: "#7C29F0", background: "#D3BDF0"}}, // purple + {border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}, hover: {border: "#C37F00", background: "#FFCA66"}}, // orange + {border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}, hover: {border: "#4220FB", background: "#9B9BFD"}}, // darkblue + {border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}, hover: {border: "#FD5A77", background: "#FFD1D9"}}, // pink + {border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}, hover: {border: "#4AD63A", background: "#E6FFE3"}} // mint + ]; - this.body = null; - }; /** - * Set options for the component. Options will be merged in current options. - * @param {Object} options Available parameters: - * {boolean} [showCurrentTime] + * Clear all groups */ - CurrentTime.prototype.setOptions = function(options) { - if (options) { - // copy all options that we know - util.selectiveExtend(['showCurrentTime', 'locale', 'locales'], this.options, options); + Groups.prototype.clear = function () { + this.groups = {}; + this.groups.length = function() + { + var i = 0; + for ( var p in this ) { + if (this.hasOwnProperty(p)) { + i++; + } + } + return i; } }; + /** - * Repaint the component - * @return {boolean} Returns true if the component is resized + * get group properties of a groupname. If groupname is not found, a new group + * is added. + * @param {*} groupname Can be a number, string, Date, etc. + * @return {Object} group The created group, containing all group properties */ - CurrentTime.prototype.redraw = function() { - if (this.options.showCurrentTime) { - var parent = this.body.dom.backgroundVertical; - if (this.bar.parentNode != parent) { - // attach to the dom - if (this.bar.parentNode) { - this.bar.parentNode.removeChild(this.bar); - } - parent.appendChild(this.bar); - - this.start(); - } - - var now = new Date(new Date().valueOf() + this.offset); - 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 = title; - } - else { - // remove the line from the DOM - if (this.bar.parentNode) { - this.bar.parentNode.removeChild(this.bar); - } - this.stop(); + Groups.prototype.get = function (groupname) { + var group = this.groups[groupname]; + if (group == undefined) { + // create new group + var index = this.defaultIndex % Groups.DEFAULT.length; + this.defaultIndex++; + group = {}; + group.color = Groups.DEFAULT[index]; + this.groups[groupname] = group; } - return false; + return group; }; /** - * Start auto refreshing the current time bar + * Add a custom group style + * @param {String} groupname + * @param {Object} style An object containing borderColor, + * backgroundColor, etc. + * @return {Object} group The created group object */ - CurrentTime.prototype.start = function() { - var me = this; - - function update () { - me.stop(); - - // determine interval to refresh - var scale = me.body.range.conversion(me.body.domProps.center.width).scale; - var interval = 1 / scale / 10; - if (interval < 30) interval = 30; - if (interval > 1000) interval = 1000; + Groups.prototype.add = function (groupname, style) { + this.groups[groupname] = style; + return style; + }; - me.redraw(); + module.exports = Groups; - // start a timer to adjust for the new time - me.currentTimeTimer = setTimeout(update, interval); - } - update(); - }; +/***/ }, +/* 39 */ +/***/ function(module, exports, __webpack_require__) { /** - * Stop auto refreshing the current time bar + * @class Images + * This class loads images and keeps them stored. */ - CurrentTime.prototype.stop = function() { - if (this.currentTimeTimer !== undefined) { - clearTimeout(this.currentTimeTimer); - delete this.currentTimeTimer; - } - }; + function Images() { + this.images = {}; + this.imageBroken = {}; + this.callback = undefined; + } /** - * Set a current time. This can be used for example to ensure that a client's - * time is synchronized with a shared server time. - * @param {Date | String | Number} time A Date, unix timestamp, or - * ISO date string. + * Set an onload callback function. This will be called each time an image + * is loaded + * @param {function} callback */ - CurrentTime.prototype.setCurrentTime = function(time) { - var t = util.convert(time, 'Date').valueOf(); - var now = new Date().valueOf(); - this.offset = t - now; - this.redraw(); + Images.prototype.setOnloadCallback = function(callback) { + this.callback = callback; }; /** - * Get the current time. - * @return {Date} Returns the current time. + * + * @param {string} url Url of the image + * @param {string} url Url of an image to use if the url image is not found + * @return {Image} img The image object */ - CurrentTime.prototype.getCurrentTime = function() { - return new Date(new Date().valueOf() + this.offset); - }; + Images.prototype.load = function(url, brokenUrl) { + var img = this.images[url]; // make a pointer + if (img === undefined) { + // create the image + var me = this; + img = new Image(); + img.onload = function () { + // IE11 fix -- thanks dponch! + if (this.width == 0) { + document.body.appendChild(this); + this.width = this.offsetWidth; + this.height = this.offsetHeight; + document.body.removeChild(this); + } - module.exports = CurrentTime; + if (me.callback) { + me.images[url] = img; + me.callback(this); + } + }; + img.onerror = function () { + if (brokenUrl === undefined) { + console.error("Could not load image:", url); + delete this.src; + if (me.callback) { + me.callback(this); + } + } + else if (me.imageBroken[url] === true) { + console.error("Could not load brokenImage:", brokenUrl); + delete this.src; + if (me.callback) { + me.callback(this); + } + } + else { + this.src = brokenUrl; + me.imageBroken[url] = true; + } + }; -/***/ }, -/* 40 */ -/***/ function(module, exports, __webpack_require__) { + img.src = url; + } - // English - exports['en'] = { - current: 'current', - time: 'time' + return img; }; - 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']; + module.exports = Images; /***/ }, -/* 41 */ +/* 40 */ /***/ function(module, exports, __webpack_require__) { - var Hammer = __webpack_require__(19); var util = __webpack_require__(1); - var Component = __webpack_require__(23); - var moment = __webpack_require__(2); - var locales = __webpack_require__(40); - - /** - * A custom time bar - * @param {{range: Range, dom: Object}} body - * @param {Object} [options] Available parameters: - * {Boolean} [showCustomTime] - * @constructor CustomTime - * @extends Component - */ - - function CustomTime (body, options) { - this.body = body; - - // default options - this.defaultOptions = { - showCustomTime: false, - locales: locales, - locale: 'en' - }; - this.options = util.extend({}, this.defaultOptions); - - this.customTime = new Date(); - this.eventParams = {}; // stores state parameters while dragging the bar - - // create the DOM - this._create(); - - this.setOptions(options); - } - - CustomTime.prototype = new Component(); /** - * Set options for the component. Options will be merged in current options. - * @param {Object} options Available parameters: - * {boolean} [showCustomTime] - */ - CustomTime.prototype.setOptions = function(options) { - if (options) { - // copy all options that we know - util.selectiveExtend(['showCustomTime', 'locale', 'locales'], this.options, options); - } - }; - - /** - * Create the DOM for the custom time - * @private + * @class Node + * A node. A node can be connected to other nodes via one or multiple edges. + * @param {object} properties An object containing properties for the node. All + * properties are optional, except for the id. + * {number} id Id of the node. Required + * {string} label Text label for the node + * {number} x Horizontal position of the node + * {number} y Vertical position of the node + * {string} shape Node shape, available: + * "database", "circle", "ellipse", + * "box", "image", "text", "dot", + * "star", "triangle", "triangleDown", + * "square" + * {string} image An image url + * {string} title An title text, can be HTML + * {anytype} group A group name or number + * @param {Network.Images} imagelist A list with images. Only needed + * when the node has an image + * @param {Network.Groups} grouplist A list with groups. Needed for + * retrieving group properties + * @param {Object} constants An object with default values for + * example for the color + * */ - CustomTime.prototype._create = function() { - var bar = document.createElement('div'); - bar.className = 'customtime'; - bar.style.position = 'absolute'; - bar.style.top = '0px'; - bar.style.height = '100%'; - this.bar = bar; + function Node(properties, imagelist, grouplist, networkConstants) { + var constants = util.selectiveBridgeObject(['nodes'],networkConstants); + this.options = constants.nodes; - var drag = document.createElement('div'); - drag.style.position = 'relative'; - drag.style.top = '0px'; - drag.style.left = '-10px'; - drag.style.height = '100%'; - drag.style.width = '20px'; - bar.appendChild(drag); + this.selected = false; + this.hover = false; - // attach event listeners - this.hammer = Hammer(bar, { - prevent_default: true - }); - this.hammer.on('dragstart', this._onDragStart.bind(this)); - this.hammer.on('drag', this._onDrag.bind(this)); - this.hammer.on('dragend', this._onDragEnd.bind(this)); - }; + this.edges = []; // all edges connected to this node + this.dynamicEdges = []; + this.reroutedEdges = {}; - /** - * Destroy the CustomTime bar - */ - CustomTime.prototype.destroy = function () { - this.options.showCustomTime = false; - this.redraw(); // will remove the bar from the DOM + this.fontDrawThreshold = 3; - this.hammer.enable(false); - this.hammer = null; + // set defaults for the properties + this.id = undefined; + this.allowedToMoveX = false; + this.allowedToMoveY = false; + this.xFixed = false; + this.yFixed = false; + this.horizontalAlignLeft = true; // these are for the navigation controls + this.verticalAlignTop = true; // these are for the navigation controls + this.baseRadiusValue = networkConstants.nodes.radius; + this.radiusFixed = false; + this.level = -1; + this.preassignedLevel = false; + this.hierarchyEnumerated = false; + this.labelDimensions = {top:0, left:0, width:0, height:0, yLine:0}; // could be cached + this.boundingBox = {top:0, left:0, right:0, bottom:0}; - this.body = null; - }; + this.imagelist = imagelist; + this.grouplist = grouplist; - /** - * Repaint the component - * @return {boolean} Returns true if the component is resized - */ - CustomTime.prototype.redraw = function () { - if (this.options.showCustomTime) { - var parent = this.body.dom.backgroundVertical; - if (this.bar.parentNode != parent) { - // attach to the dom - if (this.bar.parentNode) { - this.bar.parentNode.removeChild(this.bar); - } - parent.appendChild(this.bar); - } + // physics properties + this.fx = 0.0; // external force x + this.fy = 0.0; // external force y + this.vx = 0.0; // velocity x + this.vy = 0.0; // velocity y + this.x = null; + this.y = null; - var x = this.body.util.toScreen(this.customTime); + // used for reverting to previous position on stabilization + this.previousState = {vx:0,vy:0,x:0,y:0}; - 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.damping = networkConstants.physics.damping; // written every time gravity is calculated + this.fixedData = {x:null,y:null}; - this.bar.style.left = x + 'px'; - this.bar.title = title; - } - else { - // remove the line from the DOM - if (this.bar.parentNode) { - this.bar.parentNode.removeChild(this.bar); - } - } + this.setProperties(properties, constants); - return false; - }; + // creating the variables for clustering + this.resetCluster(); + this.dynamicEdgesLength = 0; + this.clusterSession = 0; + this.clusterSizeWidthFactor = networkConstants.clustering.nodeScaling.width; + this.clusterSizeHeightFactor = networkConstants.clustering.nodeScaling.height; + this.clusterSizeRadiusFactor = networkConstants.clustering.nodeScaling.radius; + this.maxNodeSizeIncrements = networkConstants.clustering.maxNodeSizeIncrements; + this.growthIndicator = 0; - /** - * Set custom time. - * @param {Date | number | string} time - */ - CustomTime.prototype.setCustomTime = function(time) { - this.customTime = util.convert(time, 'Date'); - this.redraw(); - }; + // variables to tell the node about the network. + this.networkScaleInv = 1; + this.networkScale = 1; + this.canvasTopLeft = {"x": -300, "y": -300}; + this.canvasBottomRight = {"x": 300, "y": 300}; + this.parentEdgeId = null; + } - /** - * Retrieve the current custom time. - * @return {Date} customTime - */ - CustomTime.prototype.getCustomTime = function() { - return new Date(this.customTime.valueOf()); - }; /** - * Start moving horizontally - * @param {Event} event - * @private + * Revert the position and velocity of the previous step. */ - CustomTime.prototype._onDragStart = function(event) { - this.eventParams.dragging = true; - this.eventParams.customTime = this.customTime; + Node.prototype.revertPosition = function() { + this.x = this.previousState.x; + this.y = this.previousState.y; + this.vx = this.previousState.vx; + this.vy = this.previousState.vy; + } - event.stopPropagation(); - event.preventDefault(); - }; /** - * Perform moving operating. - * @param {Event} event - * @private + * (re)setting the clustering variables and objects */ - CustomTime.prototype._onDrag = function (event) { - if (!this.eventParams.dragging) return; - - var deltaX = event.gesture.deltaX, - x = this.body.util.toScreen(this.eventParams.customTime) + deltaX, - time = this.body.util.toTime(x); - - this.setCustomTime(time); - - // fire a timechange event - this.body.emitter.emit('timechange', { - time: new Date(this.customTime.valueOf()) - }); - - event.stopPropagation(); - event.preventDefault(); + Node.prototype.resetCluster = function() { + // clustering variables + this.formationScale = undefined; // this is used to determine when to open the cluster + this.clusterSize = 1; // this signifies the total amount of nodes in this cluster + this.containedNodes = {}; + this.containedEdges = {}; + this.clusterSessions = []; }; /** - * Stop moving operating. - * @param {event} event - * @private + * Attach a edge to the node + * @param {Edge} edge */ - CustomTime.prototype._onDragEnd = function (event) { - if (!this.eventParams.dragging) return; - - // fire a timechanged event - this.body.emitter.emit('timechanged', { - time: new Date(this.customTime.valueOf()) - }); - - event.stopPropagation(); - event.preventDefault(); + Node.prototype.attachEdge = function(edge) { + if (this.edges.indexOf(edge) == -1) { + this.edges.push(edge); + } + if (this.dynamicEdges.indexOf(edge) == -1) { + this.dynamicEdges.push(edge); + } + this.dynamicEdgesLength = this.dynamicEdges.length; }; - module.exports = CustomTime; - - -/***/ }, -/* 42 */ -/***/ function(module, exports, __webpack_require__) { - - var Emitter = __webpack_require__(11); - var Hammer = __webpack_require__(19); - var util = __webpack_require__(1); - var DataSet = __webpack_require__(7); - var DataView = __webpack_require__(9); - var Range = __webpack_require__(21); - var Core = __webpack_require__(25); - var TimeAxis = __webpack_require__(37); - var CurrentTime = __webpack_require__(39); - var CustomTime = __webpack_require__(41); - var LineGraph = __webpack_require__(43); - /** - * Create a timeline visualization - * @param {HTMLElement} container - * @param {vis.DataSet | Array | google.visualization.DataTable} [items] - * @param {Object} [options] See Graph2d.setOptions for the available options. - * @constructor - * @extends Core + * Detach a edge from the node + * @param {Edge} edge */ - function Graph2d (container, items, groups, options) { - // if the third element is options, the forth is groups (optionally); - if (!(Array.isArray(groups) || groups instanceof DataSet) && groups instanceof Object) { - var forthArgument = options; - options = groups; - groups = forthArgument; + Node.prototype.detachEdge = function(edge) { + var index = this.edges.indexOf(edge); + if (index != -1) { + this.edges.splice(index, 1); } + index = this.dynamicEdges.indexOf(edge); + if (index != -1) { + this.dynamicEdges.splice(index, 1); + } + this.dynamicEdgesLength = this.dynamicEdges.length; + }; - var me = this; - this.defaultOptions = { - start: null, - end: null, - - autoResize: true, - - orientation: 'bottom', - width: null, - height: null, - maxHeight: null, - minHeight: null - }; - this.options = util.deepExtend({}, this.defaultOptions); - - // Create the DOM, props, and emitter - this._create(container); - - // all components listed here will be repainted automatically - this.components = []; - - this.body = { - dom: this.dom, - domProps: this.props, - emitter: { - on: this.on.bind(this), - off: this.off.bind(this), - emit: this.emit.bind(this) - }, - hiddenDates: [], - util: { - snap: null, // will be specified after TimeAxis is created - toScreen: me._toScreen.bind(me), - toGlobalScreen: me._toGlobalScreen.bind(me), // this refers to the root.width - toTime: me._toTime.bind(me), - toGlobalTime : me._toGlobalTime.bind(me) - } - }; - - // range - this.range = new Range(this.body); - this.components.push(this.range); - this.body.range = this.range; - // time axis - this.timeAxis = new TimeAxis(this.body); - this.components.push(this.timeAxis); - this.body.util.snap = this.timeAxis.snap.bind(this.timeAxis); + /** + * Set or overwrite properties for the node + * @param {Object} properties an object with properties + * @param {Object} constants and object with default, global properties + */ + Node.prototype.setProperties = function(properties, constants) { + if (!properties) { + return; + } - // current time bar - this.currentTime = new CurrentTime(this.body); - this.components.push(this.currentTime); + var fields = ['borderWidth','borderWidthSelected','shape','image','brokenImage','radius','fontColor', + 'fontSize','fontFace','fontFill','fontStrokeWidth','fontStrokeColor','group','mass' + ]; + util.selectiveDeepExtend(fields, this.options, properties); - // custom time bar - // Note: time bar will be attached in this.setOptions when selected - this.customTime = new CustomTime(this.body); - this.components.push(this.customTime); + // basic properties + if (properties.id !== undefined) {this.id = properties.id;} + if (properties.label !== undefined) {this.label = properties.label; this.originalLabel = properties.label;} + if (properties.title !== undefined) {this.title = properties.title;} + if (properties.x !== undefined) {this.x = properties.x;} + if (properties.y !== undefined) {this.y = properties.y;} + if (properties.value !== undefined) {this.value = properties.value;} + if (properties.level !== undefined) {this.level = properties.level; this.preassignedLevel = true;} - // item set - this.linegraph = new LineGraph(this.body); - this.components.push(this.linegraph); + // navigation controls properties + if (properties.horizontalAlignLeft !== undefined) {this.horizontalAlignLeft = properties.horizontalAlignLeft;} + if (properties.verticalAlignTop !== undefined) {this.verticalAlignTop = properties.verticalAlignTop;} + if (properties.triggerFunction !== undefined) {this.triggerFunction = properties.triggerFunction;} - this.itemsData = null; // DataSet - this.groupsData = null; // DataSet + if (this.id === undefined) { + throw "Node must have an id"; + } - // apply options - if (options) { - this.setOptions(options); + // copy group properties + if (typeof properties.group === 'number' || (typeof properties.group === 'string' && properties.group != '')) { + var groupObj = this.grouplist.get(properties.group); + util.deepExtend(this.options, groupObj); + // the color object needs to be completely defined. Since groups can partially overwrite the colors, we parse it again, just in case. + this.options.color = util.parseColor(this.options.color); } + // individual shape properties + if (properties.radius !== undefined) {this.baseRadiusValue = this.options.radius;} + if (properties.color !== undefined) {this.options.color = util.parseColor(properties.color);} - // IMPORTANT: THIS HAPPENS BEFORE SET ITEMS! - if (groups) { - this.setGroups(groups); + if (this.options.image !== undefined && this.options.image!= "") { + if (this.imagelist) { + this.imageObj = this.imagelist.load(this.options.image, this.options.brokenImage); + } + else { + throw "No imagelist provided"; + } } - // create itemset - if (items) { - this.setItems(items); + if (properties.allowedToMoveX !== undefined) { + this.xFixed = !properties.allowedToMoveX; + this.allowedToMoveX = properties.allowedToMoveX; } - else { - this.redraw(); + else if (properties.x !== undefined && this.allowedToMoveX == false) { + this.xFixed = true; } - } - - // Extend the functionality from Core - Graph2d.prototype = new Core(); - /** - * Set items - * @param {vis.DataSet | Array | google.visualization.DataTable | null} items - */ - Graph2d.prototype.setItems = function(items) { - var initialLoad = (this.itemsData == null); - // convert to type DataSet when needed - var newDataSet; - if (!items) { - newDataSet = null; - } - else if (items instanceof DataSet || items instanceof DataView) { - newDataSet = items; + if (properties.allowedToMoveY !== undefined) { + this.yFixed = !properties.allowedToMoveY; + this.allowedToMoveY = properties.allowedToMoveY; } - else { - // turn an array into a dataset - newDataSet = new DataSet(items, { - type: { - start: 'Date', - end: 'Date' - } - }); + else if (properties.y !== undefined && this.allowedToMoveY == false) { + this.yFixed = true; } - // set items - this.itemsData = newDataSet; - this.linegraph && this.linegraph.setItems(newDataSet); + this.radiusFixed = this.radiusFixed || (properties.radius !== undefined); - if (initialLoad) { - if (this.options.start != undefined || this.options.end != undefined) { - var start = this.options.start != undefined ? this.options.start : null; - var end = this.options.end != undefined ? this.options.end : null; + if (this.options.shape === 'image' || this.options.shape === 'circularImage') { + this.options.radiusMin = constants.nodes.widthMin; + this.options.radiusMax = constants.nodes.widthMax; + } - this.setWindow(start, end, {animate: false}); - } - else { - this.fit({animate: false}); - } + // choose draw method depending on the shape + switch (this.options.shape) { + case 'database': this.draw = this._drawDatabase; this.resize = this._resizeDatabase; break; + case 'box': this.draw = this._drawBox; this.resize = this._resizeBox; break; + case 'circle': this.draw = this._drawCircle; this.resize = this._resizeCircle; break; + case 'ellipse': this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break; + // TODO: add diamond shape + case 'image': this.draw = this._drawImage; this.resize = this._resizeImage; break; + case 'circularImage': this.draw = this._drawCircularImage; this.resize = this._resizeCircularImage; break; + case 'text': this.draw = this._drawText; this.resize = this._resizeText; break; + case 'dot': this.draw = this._drawDot; this.resize = this._resizeShape; break; + case 'square': this.draw = this._drawSquare; this.resize = this._resizeShape; break; + case 'triangle': this.draw = this._drawTriangle; this.resize = this._resizeShape; break; + case 'triangleDown': this.draw = this._drawTriangleDown; this.resize = this._resizeShape; break; + case 'star': this.draw = this._drawStar; this.resize = this._resizeShape; break; + default: this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break; } + // reset the size of the node, this can be changed + this._reset(); + }; /** - * Set groups - * @param {vis.DataSet | Array | google.visualization.DataTable} groups + * select this node */ - Graph2d.prototype.setGroups = function(groups) { - // convert to type DataSet when needed - var newDataSet; - if (!groups) { - newDataSet = null; - } - else if (groups instanceof DataSet || groups instanceof DataView) { - newDataSet = groups; - } - else { - // turn an array into a dataset - newDataSet = new DataSet(groups); - } + Node.prototype.select = function() { + this.selected = true; + this._reset(); + }; - this.groupsData = newDataSet; - this.linegraph.setGroups(newDataSet); + /** + * unselect this node + */ + Node.prototype.unselect = function() { + this.selected = false; + this._reset(); }; + /** - * Returns an object containing an SVG element with the icon of the group (size determined by iconWidth and iconHeight), the label of the group (content) and the yAxisOrientation of the group (left or right). - * @param groupId - * @param width - * @param height + * Reset the calculated size of the node, forces it to recalculate its size */ - Graph2d.prototype.getLegend = function(groupId, width, height) { - if (width === undefined) {width = 15;} - if (height === undefined) {height = 15;} - if (this.linegraph.groups[groupId] !== undefined) { - return this.linegraph.groups[groupId].getLegend(width,height); - } - else { - return "cannot find group:" + groupId; - } - } + Node.prototype.clearSizeCache = function() { + this._reset(); + }; /** - * This checks if the visible option of the supplied group (by ID) is true or false. - * @param groupId - * @returns {*} + * Reset the calculated size of the node, forces it to recalculate its size + * @private */ - Graph2d.prototype.isGroupVisible = function(groupId) { - if (this.linegraph.groups[groupId] !== undefined) { - return (this.linegraph.groups[groupId].visible && (this.linegraph.options.groups.visibility[groupId] === undefined || this.linegraph.options.groups.visibility[groupId] == true)); - } - else { - return false; - } - } + Node.prototype._reset = function() { + this.width = undefined; + this.height = undefined; + }; + /** + * get the title of this node. + * @return {string} title The title of the node, or undefined when no title + * has been set. + */ + Node.prototype.getTitle = function() { + return typeof this.title === "function" ? this.title() : this.title; + }; /** - * Get the data range of the item set. - * @returns {{min: Date, max: Date}} range A range with a start and end Date. - * When no minimum is found, min==null - * When no maximum is found, max==null + * Calculate the distance to the border of the Node + * @param {CanvasRenderingContext2D} ctx + * @param {Number} angle Angle in radians + * @returns {number} distance Distance to the border in pixels */ - Graph2d.prototype.getItemRange = function() { - var min = null; - var max = null; + Node.prototype.distanceToBorder = function (ctx, angle) { + var borderWidth = 1; - // calculate min from start filed - for (var groupId in this.linegraph.groups) { - if (this.linegraph.groups.hasOwnProperty(groupId)) { - if (this.linegraph.groups[groupId].visible == true) { - for (var i = 0; i < this.linegraph.groups[groupId].itemsData.length; i++) { - var item = this.linegraph.groups[groupId].itemsData[i]; - var value = util.convert(item.x, 'Date').valueOf(); - min = min == null ? value : min > value ? value : min; - max = max == null ? value : max < value ? value : max; - } - } - } + if (!this.width) { + this.resize(ctx); } - return { - min: (min != null) ? new Date(min) : null, - max: (max != null) ? new Date(max) : null - }; - }; - - + switch (this.options.shape) { + case 'circle': + case 'dot': + return this.options.radius+ borderWidth; - module.exports = Graph2d; + case 'ellipse': + var a = this.width / 2; + var b = this.height / 2; + var w = (Math.sin(angle) * a); + var h = (Math.cos(angle) * b); + return a * b / Math.sqrt(w * w + h * h); + // TODO: implement distanceToBorder for database + // TODO: implement distanceToBorder for triangle + // TODO: implement distanceToBorder for triangleDown -/***/ }, -/* 43 */ -/***/ function(module, exports, __webpack_require__) { + case 'box': + case 'image': + case 'text': + default: + if (this.width) { + return Math.min( + Math.abs(this.width / 2 / Math.cos(angle)), + Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth; + // TODO: reckon with border radius too in case of box + } + else { + return 0; + } - var util = __webpack_require__(1); - var DOMutil = __webpack_require__(6); - var DataSet = __webpack_require__(7); - var DataView = __webpack_require__(9); - var Component = __webpack_require__(23); - var DataAxis = __webpack_require__(44); - var GraphGroup = __webpack_require__(46); - var Legend = __webpack_require__(50); - var BarGraphFunctions = __webpack_require__(49); + } + // TODO: implement calculation of distance to border for all shapes + }; - var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items + /** + * Set forces acting on the node + * @param {number} fx Force in horizontal direction + * @param {number} fy Force in vertical direction + */ + Node.prototype._setForce = function(fx, fy) { + this.fx = fx; + this.fy = fy; + }; /** - * This is the constructor of the LineGraph. It requires a Timeline body and options. - * - * @param body - * @param options - * @constructor + * Add forces acting on the node + * @param {number} fx Force in horizontal direction + * @param {number} fy Force in vertical direction + * @private */ - function LineGraph(body, options) { - this.id = util.randomUUID(); - this.body = body; + Node.prototype._addForce = function(fx, fy) { + this.fx += fx; + this.fy += fy; + }; - this.defaultOptions = { - yAxisOrientation: 'left', - defaultGroup: 'default', - sort: true, - sampling: true, - graphHeight: '400px', - shaded: { - enabled: false, - orientation: 'bottom' // top, bottom - }, - style: 'line', // line, bar - barChart: { - width: 50, - handleOverlap: 'overlap', - align: 'center' // left, center, right - }, - catmullRom: { - enabled: true, - parametrization: 'centripetal', // uniform (alpha = 0.0), chordal (alpha = 1.0), centripetal (alpha = 0.5) - alpha: 0.5 - }, - drawPoints: { - enabled: true, - size: 6, - style: 'square' // square, circle - }, - dataAxis: { - showMinorLabels: true, - showMajorLabels: true, - icons: false, - width: '40px', - visible: true, - alignZeros: true, - customRange: { - left: {min:undefined, max:undefined}, - right: {min:undefined, max:undefined} - } - //, these options are not set by default, but this shows the format they will be in - //format: { - // left: {decimals: 2}, - // right: {decimals: 2} - //}, - //title: { - // left: { - // text: 'left', - // style: 'color:black;' - // }, - // right: { - // text: 'right', - // style: 'color:black;' - // } - //} - }, - legend: { - enabled: false, - icons: true, - left: { - visible: true, - position: 'top-left' // top/bottom - left,right - }, - right: { - visible: true, - position: 'top-right' // top/bottom - left,right - } - }, - groups: { - visibility: {} - } - }; + /** + * Store the state before the next step + */ + Node.prototype.storeState = function() { + this.previousState.x = this.x; + this.previousState.y = this.y; + this.previousState.vx = this.vx; + this.previousState.vy = this.vy; + } - // options is shared by this ItemSet and all its items - this.options = util.extend({}, this.defaultOptions); - this.dom = {}; - this.props = {}; - this.hammer = null; - this.groups = {}; - this.abortedGraphUpdate = false; - this.updateSVGheight = false; - this.updateSVGheightOnResize = false; + /** + * Perform one discrete step for the node + * @param {number} interval Time interval in seconds + */ + Node.prototype.discreteStep = function(interval) { + this.storeState(); + if (!this.xFixed) { + var dx = this.damping * this.vx; // damping force + var ax = (this.fx - dx) / this.options.mass; // acceleration + this.vx += ax * interval; // velocity + this.x += this.vx * interval; // position + } + else { + this.fx = 0; + this.vx = 0; + } - var me = this; - this.itemsData = null; // DataSet - this.groupsData = null; // DataSet + if (!this.yFixed) { + var dy = this.damping * this.vy; // damping force + var ay = (this.fy - dy) / this.options.mass; // acceleration + this.vy += ay * interval; // velocity + this.y += this.vy * interval; // position + } + else { + this.fy = 0; + this.vy = 0; + } + }; - // listeners for the DataSet of the items - this.itemListeners = { - 'add': function (event, params, senderId) { - me._onAdd(params.items); - }, - 'update': function (event, params, senderId) { - me._onUpdate(params.items); - }, - 'remove': function (event, params, senderId) { - me._onRemove(params.items); - } - }; - // listeners for the DataSet of the groups - this.groupListeners = { - 'add': function (event, params, senderId) { - me._onAddGroups(params.items); - }, - 'update': function (event, params, senderId) { - me._onUpdateGroups(params.items); - }, - 'remove': function (event, params, senderId) { - me._onRemoveGroups(params.items); - } - }; - this.items = {}; // object with an Item for every data item - this.selection = []; // list with the ids of all selected nodes - this.lastStart = this.body.range.start; - this.touchParams = {}; // stores properties while dragging + /** + * Perform one discrete step for the node + * @param {number} interval Time interval in seconds + * @param {number} maxVelocity The speed limit imposed on the velocity + */ + Node.prototype.discreteStepLimited = function(interval, maxVelocity) { + this.storeState(); + if (!this.xFixed) { + var dx = this.damping * this.vx; // damping force + var ax = (this.fx - dx) / this.options.mass; // acceleration + this.vx += ax * interval; // velocity + this.vx = (Math.abs(this.vx) > maxVelocity) ? ((this.vx > 0) ? maxVelocity : -maxVelocity) : this.vx; + this.x += this.vx * interval; // position + } + else { + this.fx = 0; + this.vx = 0; + } - this.svgElements = {}; - this.setOptions(options); - this.groupsUsingDefaultStyles = [0]; - this.COUNTER = 0; - this.body.emitter.on('rangechanged', function() { - me.lastStart = me.body.range.start; - me.svg.style.left = util.option.asSize(-me.props.width); - me.redraw.call(me,true); - }); + if (!this.yFixed) { + var dy = this.damping * this.vy; // damping force + var ay = (this.fy - dy) / this.options.mass; // acceleration + this.vy += ay * interval; // velocity + this.vy = (Math.abs(this.vy) > maxVelocity) ? ((this.vy > 0) ? maxVelocity : -maxVelocity) : this.vy; + this.y += this.vy * interval; // position + } + else { + this.fy = 0; + this.vy = 0; + } + }; - // create the HTML DOM - this._create(); - this.framework = {svg: this.svg, svgElements: this.svgElements, options: this.options, groups: this.groups}; - this.body.emitter.emit('change'); + /** + * Check if this node has a fixed x and y position + * @return {boolean} true if fixed, false if not + */ + Node.prototype.isFixed = function() { + return (this.xFixed && this.yFixed); + }; - } + /** + * Check if this node is moving + * @param {number} vmin the minimum velocity considered as "moving" + * @return {boolean} true if moving, false if it has no velocity + */ + Node.prototype.isMoving = function(vmin) { + var velocity = Math.sqrt(Math.pow(this.vx,2) + Math.pow(this.vy,2)); + // this.velocity = Math.sqrt(Math.pow(this.vx,2) + Math.pow(this.vy,2)) + return (velocity > vmin); + }; - LineGraph.prototype = new Component(); + /** + * check if this node is selecte + * @return {boolean} selected True if node is selected, else false + */ + Node.prototype.isSelected = function() { + return this.selected; + }; /** - * Create the HTML DOM for the ItemSet + * Retrieve the value of the node. Can be undefined + * @return {Number} value */ - LineGraph.prototype._create = function(){ - var frame = document.createElement('div'); - frame.className = 'LineGraph'; - this.dom.frame = frame; + Node.prototype.getValue = function() { + return this.value; + }; - // create svg element for graph drawing. - this.svg = document.createElementNS('http://www.w3.org/2000/svg','svg'); - this.svg.style.position = 'relative'; - this.svg.style.height = ('' + this.options.graphHeight).replace('px','') + 'px'; - this.svg.style.display = 'block'; - frame.appendChild(this.svg); + /** + * Calculate the distance from the nodes location to the given location (x,y) + * @param {Number} x + * @param {Number} y + * @return {Number} value + */ + Node.prototype.getDistance = function(x, y) { + var dx = this.x - x, + dy = this.y - y; + return Math.sqrt(dx * dx + dy * dy); + }; - // data axis - this.options.dataAxis.orientation = 'left'; - this.yAxisLeft = new DataAxis(this.body, this.options.dataAxis, this.svg, this.options.groups); - this.options.dataAxis.orientation = 'right'; - this.yAxisRight = new DataAxis(this.body, this.options.dataAxis, this.svg, this.options.groups); - delete this.options.dataAxis.orientation; + /** + * Adjust the value range of the node. The node will adjust it's radius + * based on its value. + * @param {Number} min + * @param {Number} max + */ + Node.prototype.setValueRange = function(min, max) { + if (!this.radiusFixed && this.value !== undefined) { + if (max == min) { + this.options.radius= (this.options.radiusMin + this.options.radiusMax) / 2; + } + else { + var scale = (this.options.radiusMax - this.options.radiusMin) / (max - min); + this.options.radius= (this.value - min) * scale + this.options.radiusMin; + } + } + this.baseRadiusValue = this.options.radius; + }; - // legends - this.legendLeft = new Legend(this.body, this.options.legend, 'left', this.options.groups); - this.legendRight = new Legend(this.body, this.options.legend, 'right', this.options.groups); + /** + * Draw this node in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + */ + Node.prototype.draw = function(ctx) { + throw "Draw method not initialized for node"; + }; - this.show(); + /** + * Recalculate the size of this node in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + */ + Node.prototype.resize = function(ctx) { + throw "Resize method not initialized for node"; }; /** - * set the options of the LineGraph. the mergeOptions is used for subObjects that have an enabled element. - * @param {object} options + * Check if this object is overlapping with the provided object + * @param {Object} obj an object with parameters left, top, right, bottom + * @return {boolean} True if location is located on node */ - LineGraph.prototype.setOptions = function(options) { - if (options) { - var fields = ['sampling','defaultGroup','height','graphHeight','yAxisOrientation','style','barChart','dataAxis','sort','groups']; - if (options.graphHeight === undefined && options.height !== undefined && this.body.domProps.centerContainer.height !== undefined) { - this.updateSVGheight = true; - this.updateSVGheightOnResize = true; - } - else if (this.body.domProps.centerContainer.height !== undefined && options.graphHeight !== undefined) { - if (parseInt((options.graphHeight + '').replace("px",'')) < this.body.domProps.centerContainer.height) { - this.updateSVGheight = true; - } - } - util.selectiveDeepExtend(fields, this.options, options); - util.mergeOptions(this.options, options,'catmullRom'); - util.mergeOptions(this.options, options,'drawPoints'); - util.mergeOptions(this.options, options,'shaded'); - util.mergeOptions(this.options, options,'legend'); + Node.prototype.isOverlappingWith = function(obj) { + return (this.left < obj.right && + this.left + this.width > obj.left && + this.top < obj.bottom && + this.top + this.height > obj.top); + }; - if (options.catmullRom) { - if (typeof options.catmullRom == 'object') { - if (options.catmullRom.parametrization) { - if (options.catmullRom.parametrization == 'uniform') { - this.options.catmullRom.alpha = 0; - } - else if (options.catmullRom.parametrization == 'chordal') { - this.options.catmullRom.alpha = 1.0; - } - else { - this.options.catmullRom.parametrization = 'centripetal'; - this.options.catmullRom.alpha = 0.5; - } - } - } - } + Node.prototype._resizeImage = function (ctx) { + // TODO: pre calculate the image size - if (this.yAxisLeft) { - if (options.dataAxis !== undefined) { - this.yAxisLeft.setOptions(this.options.dataAxis); - this.yAxisRight.setOptions(this.options.dataAxis); + if (!this.width || !this.height) { // undefined or 0 + var width, height; + if (this.value) { + this.options.radius= this.baseRadiusValue; + var scale = this.imageObj.height / this.imageObj.width; + if (scale !== undefined) { + width = this.options.radius|| this.imageObj.width; + height = this.options.radius* scale || this.imageObj.height; } - } - - if (this.legendLeft) { - if (options.legend !== undefined) { - this.legendLeft.setOptions(this.options.legend); - this.legendRight.setOptions(this.options.legend); + else { + width = 0; + height = 0; } } + else { + width = this.imageObj.width; + height = this.imageObj.height; + } + this.width = width; + this.height = height; - if (this.groups.hasOwnProperty(UNGROUPED)) { - this.groups[UNGROUPED].setOptions(options); + this.growthIndicator = 0; + if (this.width > 0 && this.height > 0) { + this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; + this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; + this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor; + this.growthIndicator = this.width - width; } } + }; - // this is used to redraw the graph if the visibility of the groups is changed. - if (this.dom.frame) { - this.redraw(true); + Node.prototype._drawImageAtPosition = function (ctx) { + if (this.imageObj.width != 0 ) { + // draw the shade + if (this.clusterSize > 1) { + var lineWidth = ((this.clusterSize > 1) ? 10 : 0.0); + lineWidth *= this.networkScaleInv; + lineWidth = Math.min(0.2 * this.width,lineWidth); + + ctx.globalAlpha = 0.5; + ctx.drawImage(this.imageObj, this.left - lineWidth, this.top - lineWidth, this.width + 2*lineWidth, this.height + 2*lineWidth); + } + + // draw the image + ctx.globalAlpha = 1.0; + ctx.drawImage(this.imageObj, this.left, this.top, this.width, this.height); } }; - /** - * Hide the component from the DOM - */ - LineGraph.prototype.hide = function() { - // remove the frame containing the items - if (this.dom.frame.parentNode) { - this.dom.frame.parentNode.removeChild(this.dom.frame); + Node.prototype._drawImageLabel = function (ctx) { + var yLabel; + var offset = 0; + + if (this.height){ + offset = this.height / 2; + var labelDimensions = this.getTextSize(ctx); + + if (labelDimensions.lineCount >= 1){ + offset += labelDimensions.height / 2; + offset += 3; + } } + + yLabel = this.y + offset; + + this._label(ctx, this.label, this.x, yLabel, undefined); }; + Node.prototype._drawImage = function (ctx) { + this._resizeImage(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; - /** - * Show the component in the DOM (when not already visible). - * @return {Boolean} changed - */ - LineGraph.prototype.show = function() { - // show frame containing the items - if (!this.dom.frame.parentNode) { - this.body.dom.center.appendChild(this.dom.frame); - } - }; + this._drawImageAtPosition(ctx); + + this.boundingBox.top = this.top; + this.boundingBox.left = this.left; + this.boundingBox.right = this.left + this.width; + this.boundingBox.bottom = this.top + this.height; + this._drawImageLabel(ctx); + this.boundingBox.left = Math.min(this.boundingBox.left, this.labelDimensions.left); + this.boundingBox.right = Math.max(this.boundingBox.right, this.labelDimensions.left + this.labelDimensions.width); + this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelDimensions.height); + }; - /** - * Set items - * @param {vis.DataSet | null} items - */ - LineGraph.prototype.setItems = function(items) { - var me = this, - ids, - oldItemsData = this.itemsData; + Node.prototype._resizeCircularImage = function (ctx) { + if(!this.imageObj.src || !this.imageObj.width || !this.imageObj.height){ + if (!this.width) { + var diameter = this.options.radius * 2; + this.width = diameter; + this.height = diameter; - // replace the dataset - if (!items) { - this.itemsData = null; - } - else if (items instanceof DataSet || items instanceof DataView) { - this.itemsData = items; + // scaling used for clustering + //this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor; + //this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor; + this.options.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor; + this.growthIndicator = this.options.radius- 0.5*diameter; + this._swapToImageResizeWhenImageLoaded = true; + } } else { - throw new TypeError('Data must be an instance of DataSet or DataView'); + if (this._swapToImageResizeWhenImageLoaded) { + this.width = 0; + this.height = 0; + delete this._swapToImageResizeWhenImageLoaded; + } + this._resizeImage(ctx); } - if (oldItemsData) { - // unsubscribe from old dataset - util.forEach(this.itemListeners, function (callback, event) { - oldItemsData.off(event, callback); - }); + }; - // remove all drawn items - ids = oldItemsData.getIds(); - this._onRemove(ids); - } + Node.prototype._drawCircularImage = function (ctx) { + this._resizeCircularImage(ctx); - if (this.itemsData) { - // subscribe to new dataset - var id = this.id; - util.forEach(this.itemListeners, function (callback, event) { - me.itemsData.on(event, callback, id); - }); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + var centerX = this.left + (this.width / 2); + var centerY = this.top + (this.height / 2); + var radius = Math.abs(this.height / 2); + + this._drawRawCircle(ctx, centerX, centerY, radius); + + ctx.save(); + ctx.circle(this.x, this.y, radius); + ctx.stroke(); + ctx.clip(); + + this._drawImageAtPosition(ctx); + + ctx.restore(); + + this.boundingBox.top = this.y - this.options.radius; + this.boundingBox.left = this.x - this.options.radius; + this.boundingBox.right = this.x + this.options.radius; + this.boundingBox.bottom = this.y + this.options.radius; + + this._drawImageLabel(ctx); + + this.boundingBox.left = Math.min(this.boundingBox.left, this.labelDimensions.left); + this.boundingBox.right = Math.max(this.boundingBox.right, this.labelDimensions.left + this.labelDimensions.width); + this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelDimensions.height); + }; + + Node.prototype._resizeBox = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + this.width = textSize.width + 2 * margin; + this.height = textSize.height + 2 * margin; + + this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor; + this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor; + this.growthIndicator = this.width - (textSize.width + 2 * margin); + // this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor; - // add all new items - ids = this.itemsData.getIds(); - this._onAdd(ids); } - this._updateUngrouped(); - //this._updateGraph(); - this.redraw(true); }; + Node.prototype._drawBox = function (ctx) { + this._resizeBox(ctx); - /** - * Set groups - * @param {vis.DataSet} groups - */ - LineGraph.prototype.setGroups = function(groups) { - var me = this; - var ids; + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; - // unsubscribe from current dataset - if (this.groupsData) { - util.forEach(this.groupListeners, function (callback, event) { - me.groupsData.unsubscribe(event, callback); - }); + var clusterLineWidth = 2.5; + var borderWidth = this.options.borderWidth; + var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; - // remove all drawn groups - ids = this.groupsData.getIds(); - this.groupsData = null; - this._onRemoveGroups(ids); // note: this will cause a redraw - } + ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; - // replace the dataset - if (!groups) { - this.groupsData = null; - } - else if (groups instanceof DataSet || groups instanceof DataView) { - this.groupsData = groups; + // draw the outer border + if (this.clusterSize > 1) { + ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.networkScaleInv; + ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + + ctx.roundRect(this.left-2*ctx.lineWidth, this.top-2*ctx.lineWidth, this.width+4*ctx.lineWidth, this.height+4*ctx.lineWidth, this.options.radius); + ctx.stroke(); } - else { - throw new TypeError('Data must be an instance of DataSet or DataView'); + ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.networkScaleInv; + ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + + ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; + + ctx.roundRect(this.left, this.top, this.width, this.height, this.options.radius); + ctx.fill(); + ctx.stroke(); + + this.boundingBox.top = this.top; + this.boundingBox.left = this.left; + this.boundingBox.right = this.left + this.width; + this.boundingBox.bottom = this.top + this.height; + + this._label(ctx, this.label, this.x, this.y); + }; + + + Node.prototype._resizeDatabase = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + var size = textSize.width + 2 * margin; + this.width = size; + this.height = size; + + // scaling used for clustering + this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; + this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; + this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor; + this.growthIndicator = this.width - size; } + }; + + Node.prototype._drawDatabase = function (ctx) { + this._resizeDatabase(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + var clusterLineWidth = 2.5; + var borderWidth = this.options.borderWidth; + var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; + + ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; - if (this.groupsData) { - // subscribe to new dataset - var id = this.id; - util.forEach(this.groupListeners, function (callback, event) { - me.groupsData.on(event, callback, id); - }); + // draw the outer border + if (this.clusterSize > 1) { + ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.networkScaleInv; + ctx.lineWidth = Math.min(this.width,ctx.lineWidth); - // draw all ms - ids = this.groupsData.getIds(); - this._onAddGroups(ids); + ctx.database(this.x - this.width/2 - 2*ctx.lineWidth, this.y - this.height*0.5 - 2*ctx.lineWidth, this.width + 4*ctx.lineWidth, this.height + 4*ctx.lineWidth); + ctx.stroke(); } - this._onUpdate(); - }; + ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.networkScaleInv; + ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; + ctx.database(this.x - this.width/2, this.y - this.height*0.5, this.width, this.height); + ctx.fill(); + ctx.stroke(); - /** - * Update the data - * @param [ids] - * @private - */ - LineGraph.prototype._onUpdate = function(ids) { - this._updateUngrouped(); - this._updateAllGroupData(); - //this._updateGraph(); - this.redraw(true); - }; - LineGraph.prototype._onAdd = function (ids) {this._onUpdate(ids);}; - LineGraph.prototype._onRemove = function (ids) {this._onUpdate(ids);}; - LineGraph.prototype._onUpdateGroups = function (groupIds) { - for (var i = 0; i < groupIds.length; i++) { - var group = this.groupsData.get(groupIds[i]); - this._updateGroup(group, groupIds[i]); - } + this.boundingBox.top = this.top; + this.boundingBox.left = this.left; + this.boundingBox.right = this.left + this.width; + this.boundingBox.bottom = this.top + this.height; - //this._updateGraph(); - this.redraw(true); + this._label(ctx, this.label, this.x, this.y); }; - LineGraph.prototype._onAddGroups = function (groupIds) {this._onUpdateGroups(groupIds);}; - /** - * this cleans the group out off the legends and the dataaxis, updates the ungrouped and updates the graph - * @param {Array} groupIds - * @private - */ - LineGraph.prototype._onRemoveGroups = function (groupIds) { - for (var i = 0; i < groupIds.length; i++) { - if (this.groups.hasOwnProperty(groupIds[i])) { - if (this.groups[groupIds[i]].options.yAxisOrientation == 'right') { - this.yAxisRight.removeGroup(groupIds[i]); - this.legendRight.removeGroup(groupIds[i]); - this.legendRight.redraw(); - } - else { - this.yAxisLeft.removeGroup(groupIds[i]); - this.legendLeft.removeGroup(groupIds[i]); - this.legendLeft.redraw(); - } - delete this.groups[groupIds[i]]; - } + Node.prototype._resizeCircle = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + var diameter = Math.max(textSize.width, textSize.height) + 2 * margin; + this.options.radius = diameter / 2; + + this.width = diameter; + this.height = diameter; + + // scaling used for clustering + // this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor; + // this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor; + this.options.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor; + this.growthIndicator = this.options.radius- 0.5*diameter; } - this._updateUngrouped(); - //this._updateGraph(); - this.redraw(true); }; + Node.prototype._drawRawCircle = function (ctx, x, y, radius) { + var clusterLineWidth = 2.5; + var borderWidth = this.options.borderWidth; + var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; + + ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; - /** - * update a group object with the group dataset entree - * - * @param group - * @param groupId - * @private - */ - LineGraph.prototype._updateGroup = function (group, groupId) { - if (!this.groups.hasOwnProperty(groupId)) { - this.groups[groupId] = new GraphGroup(group, groupId, this.options, this.groupsUsingDefaultStyles); - if (this.groups[groupId].options.yAxisOrientation == 'right') { - this.yAxisRight.addGroup(groupId, this.groups[groupId]); - this.legendRight.addGroup(groupId, this.groups[groupId]); - } - else { - this.yAxisLeft.addGroup(groupId, this.groups[groupId]); - this.legendLeft.addGroup(groupId, this.groups[groupId]); - } - } - else { - this.groups[groupId].update(group); - if (this.groups[groupId].options.yAxisOrientation == 'right') { - this.yAxisRight.updateGroup(groupId, this.groups[groupId]); - this.legendRight.updateGroup(groupId, this.groups[groupId]); - } - else { - this.yAxisLeft.updateGroup(groupId, this.groups[groupId]); - this.legendLeft.updateGroup(groupId, this.groups[groupId]); - } + // draw the outer border + if (this.clusterSize > 1) { + ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.networkScaleInv; + ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + + ctx.circle(x, y, radius+2*ctx.lineWidth); + ctx.stroke(); } - this.legendLeft.redraw(); - this.legendRight.redraw(); + ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.networkScaleInv; + ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + + ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; + ctx.circle(this.x, this.y, radius); + ctx.fill(); + ctx.stroke(); }; + Node.prototype._drawCircle = function (ctx) { + this._resizeCircle(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; - /** - * this updates all groups, it is used when there is an update the the itemset. - * - * @private - */ - LineGraph.prototype._updateAllGroupData = function () { - if (this.itemsData != null) { - var groupsContent = {}; - var groupId; - for (groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - groupsContent[groupId] = []; - } - } - for (var itemId in this.itemsData._data) { - if (this.itemsData._data.hasOwnProperty(itemId)) { - var item = this.itemsData._data[itemId]; - if (groupsContent[item.group] === undefined) { - throw new Error('Cannot find referenced group. Possible reason: items added before groups? Groups need to be added before items, as items refer to groups.') - } - item.x = util.convert(item.x,'Date'); - groupsContent[item.group].push(item); - } - } - for (groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - this.groups[groupId].setItems(groupsContent[groupId]); - } - } - } + this._drawRawCircle(ctx, this.x, this.y, this.options.radius); + + this.boundingBox.top = this.y - this.options.radius; + this.boundingBox.left = this.x - this.options.radius; + this.boundingBox.right = this.x + this.options.radius; + this.boundingBox.bottom = this.y + this.options.radius; + + this._label(ctx, this.label, this.x, this.y); }; + Node.prototype._resizeEllipse = function (ctx) { + if (!this.width) { + var textSize = this.getTextSize(ctx); - /** - * Create or delete the group holding all ungrouped items. This group is used when - * there are no groups specified. This anonymous group is called 'graph'. - * @protected - */ - LineGraph.prototype._updateUngrouped = function() { - if (this.itemsData && this.itemsData != null) { - var ungroupedCounter = 0; - for (var itemId in this.itemsData._data) { - if (this.itemsData._data.hasOwnProperty(itemId)) { - var item = this.itemsData._data[itemId]; - if (item != undefined) { - if (item.hasOwnProperty('group')) { - if (item.group === undefined) { - item.group = UNGROUPED; - } - } - else { - item.group = UNGROUPED; - } - ungroupedCounter = item.group == UNGROUPED ? ungroupedCounter + 1 : ungroupedCounter; - } - } + this.width = textSize.width * 1.5; + this.height = textSize.height * 2; + if (this.width < this.height) { + this.width = this.height; } + var defaultSize = this.width; - if (ungroupedCounter == 0) { - delete this.groups[UNGROUPED]; - this.legendLeft.removeGroup(UNGROUPED); - this.legendRight.removeGroup(UNGROUPED); - this.yAxisLeft.removeGroup(UNGROUPED); - this.yAxisRight.removeGroup(UNGROUPED); - } - else { - var group = {id: UNGROUPED, content: this.options.defaultGroup}; - this._updateGroup(group, UNGROUPED); - } - } - else { - delete this.groups[UNGROUPED]; - this.legendLeft.removeGroup(UNGROUPED); - this.legendRight.removeGroup(UNGROUPED); - this.yAxisLeft.removeGroup(UNGROUPED); - this.yAxisRight.removeGroup(UNGROUPED); + // scaling used for clustering + this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; + this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; + this.options.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor; + this.growthIndicator = this.width - defaultSize; } - - this.legendLeft.redraw(); - this.legendRight.redraw(); }; + Node.prototype._drawEllipse = function (ctx) { + this._resizeEllipse(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; - /** - * Redraw the component, mandatory function - * @return {boolean} Returns true if the component is resized - */ - LineGraph.prototype.redraw = function(forceGraphUpdate) { - var resized = false; + var clusterLineWidth = 2.5; + var borderWidth = this.options.borderWidth; + var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; - // calculate actual size and position - this.props.width = this.dom.frame.offsetWidth; - this.props.height = this.body.domProps.centerContainer.height; + ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; - // update the graph if there is no lastWidth or with, used for the initial draw - if (this.lastWidth === undefined && this.props.width) { - forceGraphUpdate = true; + // draw the outer border + if (this.clusterSize > 1) { + ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.networkScaleInv; + ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + + ctx.ellipse(this.left-2*ctx.lineWidth, this.top-2*ctx.lineWidth, this.width+4*ctx.lineWidth, this.height+4*ctx.lineWidth); + ctx.stroke(); } + ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.networkScaleInv; + ctx.lineWidth = Math.min(this.width,ctx.lineWidth); - // check if this component is resized - resized = this._isResized() || resized; + ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; - // check whether zoomed (in that case we need to re-stack everything) - var visibleInterval = this.body.range.end - this.body.range.start; - var zoomed = (visibleInterval != this.lastVisibleInterval); - this.lastVisibleInterval = visibleInterval; + ctx.ellipse(this.left, this.top, this.width, this.height); + ctx.fill(); + ctx.stroke(); + this.boundingBox.top = this.top; + this.boundingBox.left = this.left; + this.boundingBox.right = this.left + this.width; + this.boundingBox.bottom = this.top + this.height; - // the svg element is three times as big as the width, this allows for fully dragging left and right - // without reloading the graph. the controls for this are bound to events in the constructor - if (resized == true) { - this.svg.style.width = util.option.asSize(3*this.props.width); - this.svg.style.left = util.option.asSize(-this.props.width); + this._label(ctx, this.label, this.x, this.y); + }; - // if the height of the graph is set as proportional, change the height of the svg - if ((this.options.height + '').indexOf("%") != -1 || this.updateSVGheightOnResize == true) { - this.updateSVGheight = true; - } - } + Node.prototype._drawDot = function (ctx) { + this._drawShape(ctx, 'circle'); + }; - // update the height of the graph on each redraw of the graph. - if (this.updateSVGheight == true) { - if (this.options.graphHeight != this.body.domProps.centerContainer.height + 'px') { - this.options.graphHeight = this.body.domProps.centerContainer.height + 'px'; - this.svg.style.height = this.body.domProps.centerContainer.height + 'px'; - } - this.updateSVGheight = false; - } - else { - this.svg.style.height = ('' + this.options.graphHeight).replace('px','') + 'px'; - } + Node.prototype._drawTriangle = function (ctx) { + this._drawShape(ctx, 'triangle'); + }; - // zoomed is here to ensure that animations are shown correctly. - if (resized == true || zoomed == true || this.abortedGraphUpdate == true || forceGraphUpdate == true) { - resized = this._updateGraph() || resized; - } - else { - // move the whole svg while dragging - if (this.lastStart != 0) { - var offset = this.body.range.start - this.lastStart; - var range = this.body.range.end - this.body.range.start; - if (this.props.width != 0) { - var rangePerPixelInv = this.props.width/range; - var xOffset = offset * rangePerPixelInv; - this.svg.style.left = (-this.props.width - xOffset) + 'px'; - } - } - } + Node.prototype._drawTriangleDown = function (ctx) { + this._drawShape(ctx, 'triangleDown'); + }; - this.legendLeft.redraw(); - this.legendRight.redraw(); - return resized; + Node.prototype._drawSquare = function (ctx) { + this._drawShape(ctx, 'square'); }; + Node.prototype._drawStar = function (ctx) { + this._drawShape(ctx, 'star'); + }; - /** - * Update and redraw the graph. - * - */ - LineGraph.prototype._updateGraph = function () { - // reset the svg elements - DOMutil.prepareElements(this.svgElements); - if (this.props.width != 0 && this.itemsData != null) { - var group, i; - var preprocessedGroupData = {}; - var processedGroupData = {}; - var groupRanges = {}; - var changeCalled = false; + Node.prototype._resizeShape = function (ctx) { + if (!this.width) { + this.options.radius= this.baseRadiusValue; + var size = 2 * this.options.radius; + this.width = size; + this.height = size; - // getting group Ids - var groupIds = []; - for (var groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - group = this.groups[groupId]; - if (group.visible == true && (this.options.groups.visibility[groupId] === undefined || this.options.groups.visibility[groupId] == true)) { - groupIds.push(groupId); - } - } - } - if (groupIds.length > 0) { - // this is the range of the SVG canvas - var minDate = this.body.util.toGlobalTime(-this.body.domProps.root.width); - var maxDate = this.body.util.toGlobalTime(2 * this.body.domProps.root.width); - var groupsData = {}; - // fill groups data, this only loads the data we require based on the timewindow - this._getRelevantData(groupIds, groupsData, minDate, maxDate); + // scaling used for clustering + this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; + this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; + this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor; + this.growthIndicator = this.width - size; + } + }; - // apply sampling, if disabled, it will pass through this function. - this._applySampling(groupIds, groupsData); + Node.prototype._drawShape = function (ctx, shape) { + this._resizeShape(ctx); - // we transform the X coordinates to detect collisions - for (i = 0; i < groupIds.length; i++) { - preprocessedGroupData[groupIds[i]] = this._convertXcoordinates(groupsData[groupIds[i]]); - } + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; - // now all needed data has been collected we start the processing. - this._getYRanges(groupIds, preprocessedGroupData, groupRanges); + var clusterLineWidth = 2.5; + var borderWidth = this.options.borderWidth; + var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; + var radiusMultiplier = 2; - // update the Y axis first, we use this data to draw at the correct Y points - // changeCalled is required to clean the SVG on a change emit. - changeCalled = this._updateYAxis(groupIds, groupRanges); - var MAX_CYCLES = 5; - if (changeCalled == true && this.COUNTER < MAX_CYCLES) { - DOMutil.cleanupElements(this.svgElements); - this.abortedGraphUpdate = true; - this.COUNTER++; - this.body.emitter.emit('change'); - return true; - } - else { - if (this.COUNTER > MAX_CYCLES) { - console.log("WARNING: there may be an infinite loop in the _updateGraph emitter cycle.") - } - this.COUNTER = 0; - this.abortedGraphUpdate = false; + // choose draw method depending on the shape + switch (shape) { + case 'dot': radiusMultiplier = 2; break; + case 'square': radiusMultiplier = 2; break; + case 'triangle': radiusMultiplier = 3; break; + case 'triangleDown': radiusMultiplier = 3; break; + case 'star': radiusMultiplier = 4; break; + } - // With the yAxis scaled correctly, use this to get the Y values of the points. - for (i = 0; i < groupIds.length; i++) { - group = this.groups[groupIds[i]]; - processedGroupData[groupIds[i]] = this._convertYcoordinates(groupsData[groupIds[i]], group); - } + ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; + // draw the outer border + if (this.clusterSize > 1) { + ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.networkScaleInv; + ctx.lineWidth = Math.min(this.width,ctx.lineWidth); - // draw the groups - for (i = 0; i < groupIds.length; i++) { - group = this.groups[groupIds[i]]; - if (group.options.style != 'bar') { // bar needs to be drawn enmasse - group.draw(processedGroupData[groupIds[i]], group, this.framework); - } - } - BarGraphFunctions.draw(groupIds, processedGroupData, this.framework); - } - } + ctx[shape](this.x, this.y, this.options.radius+ radiusMultiplier * ctx.lineWidth); + ctx.stroke(); } + ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); + ctx.lineWidth *= this.networkScaleInv; + ctx.lineWidth = Math.min(this.width,ctx.lineWidth); - // cleanup unused svg elements - DOMutil.cleanupElements(this.svgElements); - return false; - }; + ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; + ctx[shape](this.x, this.y, this.options.radius); + ctx.fill(); + ctx.stroke(); + this.boundingBox.top = this.y - this.options.radius; + this.boundingBox.left = this.x - this.options.radius; + this.boundingBox.right = this.x + this.options.radius; + this.boundingBox.bottom = this.y + this.options.radius; - /** - * first select and preprocess the data from the datasets. - * the groups have their preselection of data, we now loop over this data to see - * what data we need to draw. Sorted data is much faster. - * more optimization is possible by doing the sampling before and using the binary search - * to find the end date to determine the increment. - * - * @param {array} groupIds - * @param {object} groupsData - * @param {date} minDate - * @param {date} maxDate - * @private - */ - LineGraph.prototype._getRelevantData = function (groupIds, groupsData, minDate, maxDate) { - var group, i, j, item; - if (groupIds.length > 0) { - for (i = 0; i < groupIds.length; i++) { - group = this.groups[groupIds[i]]; - groupsData[groupIds[i]] = []; - var dataContainer = groupsData[groupIds[i]]; - // optimization for sorted data - if (group.options.sort == true) { - var guess = Math.max(0, util.binarySearchValue(group.itemsData, minDate, 'x', 'before')); - for (j = guess; j < group.itemsData.length; j++) { - item = group.itemsData[j]; - if (item !== undefined) { - if (item.x > maxDate) { - dataContainer.push(item); - break; - } - else { - dataContainer.push(item); - } - } - } - } - else { - for (j = 0; j < group.itemsData.length; j++) { - item = group.itemsData[j]; - if (item !== undefined) { - if (item.x > minDate && item.x < maxDate) { - dataContainer.push(item); - } - } - } - } - } + if (this.label) { + this._label(ctx, this.label, this.x, this.y + this.height / 2, undefined, 'hanging',true); + this.boundingBox.left = Math.min(this.boundingBox.left, this.labelDimensions.left); + this.boundingBox.right = Math.max(this.boundingBox.right, this.labelDimensions.left + this.labelDimensions.width); + this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelDimensions.height); } }; + Node.prototype._resizeText = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + this.width = textSize.width + 2 * margin; + this.height = textSize.height + 2 * margin; - /** - * - * @param groupIds - * @param groupsData - * @private - */ - LineGraph.prototype._applySampling = function (groupIds, groupsData) { - var group; - if (groupIds.length > 0) { - for (var i = 0; i < groupIds.length; i++) { - group = this.groups[groupIds[i]]; - if (group.options.sampling == true) { - var dataContainer = groupsData[groupIds[i]]; - if (dataContainer.length > 0) { - var increment = 1; - var amountOfPoints = dataContainer.length; - - // the global screen is used because changing the width of the yAxis may affect the increment, resulting in an endless loop - // of width changing of the yAxis. - var xDistance = this.body.util.toGlobalScreen(dataContainer[dataContainer.length - 1].x) - this.body.util.toGlobalScreen(dataContainer[0].x); - var pointsPerPixel = amountOfPoints / xDistance; - increment = Math.min(Math.ceil(0.2 * amountOfPoints), Math.max(1, Math.round(pointsPerPixel))); - - var sampledData = []; - for (var j = 0; j < amountOfPoints; j += increment) { - sampledData.push(dataContainer[j]); - - } - groupsData[groupIds[i]] = sampledData; - } - } - } + // scaling used for clustering + this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; + this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; + this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor; + this.growthIndicator = this.width - (textSize.width + 2 * margin); } }; + Node.prototype._drawText = function (ctx) { + this._resizeText(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; - /** - * - * - * @param {array} groupIds - * @param {object} groupsData - * @param {object} groupRanges | this is being filled here - * @private - */ - LineGraph.prototype._getYRanges = function (groupIds, groupsData, groupRanges) { - var groupData, group, i; - var barCombinedDataLeft = []; - var barCombinedDataRight = []; - var options; - if (groupIds.length > 0) { - for (i = 0; i < groupIds.length; i++) { - groupData = groupsData[groupIds[i]]; - options = this.groups[groupIds[i]].options; - if (groupData.length > 0) { - group = this.groups[groupIds[i]]; - // if bar graphs are stacked, their range need to be handled differently and accumulated over all groups. - if (options.barChart.handleOverlap == 'stack' && options.style == 'bar') { - if (options.yAxisOrientation == 'left') {barCombinedDataLeft = barCombinedDataLeft.concat(group.getYRange(groupData)) ;} - else {barCombinedDataRight = barCombinedDataRight.concat(group.getYRange(groupData));} - } - else { - groupRanges[groupIds[i]] = group.getYRange(groupData,groupIds[i]); - } - } - } + this._label(ctx, this.label, this.x, this.y); - // if bar graphs are stacked, their range need to be handled differently and accumulated over all groups. - BarGraphFunctions.getStackedBarYRange(barCombinedDataLeft , groupRanges, groupIds, '__barchartLeft' , 'left' ); - BarGraphFunctions.getStackedBarYRange(barCombinedDataRight, groupRanges, groupIds, '__barchartRight', 'right'); - } + this.boundingBox.top = this.top; + this.boundingBox.left = this.left; + this.boundingBox.right = this.left + this.width; + this.boundingBox.bottom = this.top + this.height; }; - /** - * this sets the Y ranges for the Y axis. It also determines which of the axis should be shown or hidden. - * @param {Array} groupIds - * @param {Object} groupRanges - * @private - */ - LineGraph.prototype._updateYAxis = function (groupIds, groupRanges) { - var resized = false; - var yAxisLeftUsed = false; - var yAxisRightUsed = false; - var minLeft = 1e9, minRight = 1e9, maxLeft = -1e9, maxRight = -1e9, minVal, maxVal; - // if groups are present - if (groupIds.length > 0) { - // this is here to make sure that if there are no items in the axis but there are groups, that there is no infinite draw/redraw loop. - for (var i = 0; i < groupIds.length; i++) { - var group = this.groups[groupIds[i]]; - if (group && group.options.yAxisOrientation != 'right') { - yAxisLeftUsed = true; - minLeft = 0; - maxLeft = 0; - } - else if (group && group.options.yAxisOrientation) { - yAxisRightUsed = true; - minRight = 0; - maxRight = 0; - } + Node.prototype._label = function (ctx, text, x, y, align, baseline, labelUnderNode) { + if (text && Number(this.options.fontSize) * this.networkScale > this.fontDrawThreshold) { + ctx.font = (this.selected ? "bold " : "") + this.options.fontSize + "px " + this.options.fontFace; + + var lines = text.split('\n'); + var lineCount = lines.length; + var fontSize = Number(this.options.fontSize); + var yLine = y + (1 - lineCount) / 2 * fontSize; + if (labelUnderNode == true) { + yLine = y + (1 - lineCount) / (2 * fontSize); } - // if there are items: - for (var i = 0; i < groupIds.length; i++) { - if (groupRanges.hasOwnProperty(groupIds[i])) { - if (groupRanges[groupIds[i]].ignore !== true) { - minVal = groupRanges[groupIds[i]].min; - maxVal = groupRanges[groupIds[i]].max; + // font fill from edges now for nodes! + var width = ctx.measureText(lines[0]).width; + for (var i = 1; i < lineCount; i++) { + var lineWidth = ctx.measureText(lines[i]).width; + width = lineWidth > width ? lineWidth : width; + } + var height = this.options.fontSize * lineCount; + var left = x - width / 2; + var top = y - height / 2; + if (baseline == "hanging") { + top += 0.5 * fontSize; + top += 4; // distance from node, required because we use hanging. Hanging has less difference between browsers + yLine += 4; // distance from node + } + this.labelDimensions = {top:top,left:left,width:width,height:height,yLine:yLine}; - if (groupRanges[groupIds[i]].yAxisOrientation != 'right') { - yAxisLeftUsed = true; - minLeft = minLeft > minVal ? minVal : minLeft; - maxLeft = maxLeft < maxVal ? maxVal : maxLeft; - } - else { - yAxisRightUsed = true; - minRight = minRight > minVal ? minVal : minRight; - maxRight = maxRight < maxVal ? maxVal : maxRight; - } - } - } + // create the fontfill background + if (this.options.fontFill !== undefined && this.options.fontFill !== null && this.options.fontFill !== "none") { + ctx.fillStyle = this.options.fontFill; + ctx.fillRect(left, top, width, height); } - if (yAxisLeftUsed == true) { - this.yAxisLeft.setRange(minLeft, maxLeft); + // draw text + ctx.fillStyle = this.options.fontColor || "black"; + ctx.textAlign = align || "center"; + ctx.textBaseline = baseline || "middle"; + if (this.options.fontStrokeWidth > 0){ + ctx.lineWidth = this.options.fontStrokeWidth; + ctx.strokeStyle = this.options.fontStrokeColor; + ctx.lineJoin = 'round'; } - if (yAxisRightUsed == true) { - this.yAxisRight.setRange(minRight, maxRight); + for (var i = 0; i < lineCount; i++) { + if(this.options.fontStrokeWidth){ + ctx.strokeText(lines[i], x, yLine); + } + ctx.fillText(lines[i], x, yLine); + yLine += fontSize; } } - resized = this._toggleAxisVisiblity(yAxisLeftUsed , this.yAxisLeft) || resized; - resized = this._toggleAxisVisiblity(yAxisRightUsed, this.yAxisRight) || resized; + }; - if (yAxisRightUsed == true && yAxisLeftUsed == true) { - this.yAxisLeft.drawIcons = true; - this.yAxisRight.drawIcons = true; - } - else { - this.yAxisLeft.drawIcons = false; - this.yAxisRight.drawIcons = false; - } - this.yAxisRight.master = !yAxisLeftUsed; - if (this.yAxisRight.master == false) { - if (yAxisRightUsed == true) {this.yAxisLeft.lineOffset = this.yAxisRight.width;} - else {this.yAxisLeft.lineOffset = 0;} - resized = this.yAxisLeft.redraw() || resized; - this.yAxisRight.stepPixelsForced = this.yAxisLeft.stepPixels; - this.yAxisRight.zeroCrossing = this.yAxisLeft.zeroCrossing; - resized = this.yAxisRight.redraw() || resized; - } - else { - resized = this.yAxisRight.redraw() || resized; - } + Node.prototype.getTextSize = function(ctx) { + if (this.label !== undefined) { + ctx.font = (this.selected ? "bold " : "") + this.options.fontSize + "px " + this.options.fontFace; - // clean the accumulated lists - if (groupIds.indexOf('__barchartLeft') != -1) { - groupIds.splice(groupIds.indexOf('__barchartLeft'),1); + var lines = this.label.split('\n'), + height = (Number(this.options.fontSize) + 4) * lines.length, + width = 0; + + for (var i = 0, iMax = lines.length; i < iMax; i++) { + width = Math.max(width, ctx.measureText(lines[i]).width); + } + + return {"width": width, "height": height, lineCount: lines.length}; } - if (groupIds.indexOf('__barchartRight') != -1) { - groupIds.splice(groupIds.indexOf('__barchartRight'),1); + else { + return {"width": 0, "height": 0, lineCount: 0}; } - - return resized; }; - /** - * This shows or hides the Y axis if needed. If there is a change, the changed event is emitted by the updateYAxis function + * this is used to determine if a node is visible at all. this is used to determine when it needs to be drawn. + * there is a safety margin of 0.3 * width; * - * @param {boolean} axisUsed * @returns {boolean} - * @private - * @param axis */ - LineGraph.prototype._toggleAxisVisiblity = function (axisUsed, axis) { - var changed = false; - if (axisUsed == false) { - if (axis.dom.frame.parentNode && axis.hidden == false) { - axis.hide() - changed = true; - } + Node.prototype.inArea = function() { + if (this.width !== undefined) { + return (this.x + this.width *this.networkScaleInv >= this.canvasTopLeft.x && + this.x - this.width *this.networkScaleInv < this.canvasBottomRight.x && + this.y + this.height*this.networkScaleInv >= this.canvasTopLeft.y && + this.y - this.height*this.networkScaleInv < this.canvasBottomRight.y); } else { - if (!axis.dom.frame.parentNode && axis.hidden == true) { - axis.show(); - changed = true; - } + return true; } - return changed; }; + /** + * checks if the core of the node is in the display area, this is used for opening clusters around zoom + * @returns {boolean} + */ + Node.prototype.inView = function() { + return (this.x >= this.canvasTopLeft.x && + this.x < this.canvasBottomRight.x && + this.y >= this.canvasTopLeft.y && + this.y < this.canvasBottomRight.y); + }; /** - * This uses the DataAxis object to generate the correct X coordinate on the SVG window. It uses the - * util function toScreen to get the x coordinate from the timestamp. It also pre-filters the data and get the minMax ranges for - * the yAxis. + * This allows the zoom level of the network to influence the rendering + * We store the inverted scale and the coordinates of the top left, and bottom right points of the canvas * - * @param datapoints - * @returns {Array} - * @private + * @param scale + * @param canvasTopLeft + * @param canvasBottomRight */ - LineGraph.prototype._convertXcoordinates = function (datapoints) { - var extractedData = []; - var xValue, yValue; - var toScreen = this.body.util.toScreen; - - for (var i = 0; i < datapoints.length; i++) { - xValue = toScreen(datapoints[i].x) + this.props.width; - yValue = datapoints[i].y; - extractedData.push({x: xValue, y: yValue}); - } - - return extractedData; + Node.prototype.setScaleAndPos = function(scale,canvasTopLeft,canvasBottomRight) { + this.networkScaleInv = 1.0/scale; + this.networkScale = scale; + this.canvasTopLeft = canvasTopLeft; + this.canvasBottomRight = canvasBottomRight; }; /** - * This uses the DataAxis object to generate the correct X coordinate on the SVG window. It uses the - * util function toScreen to get the x coordinate from the timestamp. It also pre-filters the data and get the minMax ranges for - * the yAxis. + * This allows the zoom level of the network to influence the rendering * - * @param datapoints - * @param group - * @returns {Array} - * @private + * @param scale */ - LineGraph.prototype._convertYcoordinates = function (datapoints, group) { - var extractedData = []; - var xValue, yValue; - var toScreen = this.body.util.toScreen; - var axis = this.yAxisLeft; - var svgHeight = Number(this.svg.style.height.replace('px','')); - if (group.options.yAxisOrientation == 'right') { - axis = this.yAxisRight; - } + Node.prototype.setScale = function(scale) { + this.networkScaleInv = 1.0/scale; + this.networkScale = scale; + }; - for (var i = 0; i < datapoints.length; i++) { - xValue = toScreen(datapoints[i].x) + this.props.width; - yValue = Math.round(axis.convertValue(datapoints[i].y)); - extractedData.push({x: xValue, y: yValue}); - } - group.setZeroPosition(Math.min(svgHeight, axis.convertValue(0))); - return extractedData; + /** + * set the velocity at 0. Is called when this node is contained in another during clustering + */ + Node.prototype.clearVelocity = function() { + this.vx = 0; + this.vy = 0; }; - module.exports = LineGraph; + /** + * Basic preservation of (kinectic) energy + * + * @param massBeforeClustering + */ + Node.prototype.updateVelocity = function(massBeforeClustering) { + var energyBefore = this.vx * this.vx * massBeforeClustering; + //this.vx = (this.vx < 0) ? -Math.sqrt(energyBefore/this.options.mass) : Math.sqrt(energyBefore/this.options.mass); + this.vx = Math.sqrt(energyBefore/this.options.mass); + energyBefore = this.vy * this.vy * massBeforeClustering; + //this.vy = (this.vy < 0) ? -Math.sqrt(energyBefore/this.options.mass) : Math.sqrt(energyBefore/this.options.mass); + this.vy = Math.sqrt(energyBefore/this.options.mass); + }; + + module.exports = Node; /***/ }, -/* 44 */ +/* 41 */ /***/ function(module, exports, __webpack_require__) { - var util = __webpack_require__(1); - var DOMutil = __webpack_require__(6); - var Component = __webpack_require__(23); - var DataStep = __webpack_require__(45); - /** - * A horizontal time axis - * @param {Object} [options] See DataAxis.setOptions for the available - * options. - * @constructor DataAxis - * @extends Component - * @param body + * Popup is a class to create a popup window with some text + * @param {Element} container The container object. + * @param {Number} [x] + * @param {Number} [y] + * @param {String} [text] + * @param {Object} [style] An object containing borderColor, + * backgroundColor, etc. */ - function DataAxis (body, options, svg, linegraphOptions) { - this.id = util.randomUUID(); - this.body = body; + function Popup(container, x, y, text, style) { + if (container) { + this.container = container; + } + else { + this.container = document.body; + } - this.defaultOptions = { - orientation: 'left', // supported: 'left', 'right' - showMinorLabels: true, - showMajorLabels: true, - icons: true, - majorLinesOffset: 7, - minorLinesOffset: 4, - labelOffsetX: 10, - labelOffsetY: 2, - iconWidth: 20, - width: '40px', - visible: true, - alignZeros: true, - customRange: { - left: {min:undefined, max:undefined}, - right: {min:undefined, max:undefined} - }, - title: { - left: {text:undefined}, - right: {text:undefined} - }, - format: { - left: {decimals: undefined}, - right: {decimals: undefined} + // x, y and text are optional, see if a style object was passed in their place + if (style === undefined) { + if (typeof x === "object") { + style = x; + x = undefined; + } else if (typeof text === "object") { + style = text; + text = undefined; + } else { + // for backwards compatibility, in case clients other than Network are creating Popup directly + style = { + fontColor: 'black', + fontSize: 14, // px + fontFace: 'verdana', + color: { + border: '#666', + background: '#FFFFC6' + } + } } - }; - - this.linegraphOptions = linegraphOptions; - this.linegraphSVG = svg; - this.props = {}; - this.DOMelements = { // dynamic elements - lines: {}, - labels: {}, - title: {} - }; - - this.dom = {}; - - this.range = {start:0, end:0}; - - this.options = util.extend({}, this.defaultOptions); - this.conversionFactor = 1; + } - this.setOptions(options); - this.width = Number(('' + this.options.width).replace("px","")); - this.minWidth = this.width; - this.height = this.linegraphSVG.offsetHeight; - this.hidden = false; + this.x = 0; + this.y = 0; + this.padding = 5; - this.stepPixels = 25; - this.stepPixelsForced = 25; - this.zeroCrossing = -1; + if (x !== undefined && y !== undefined ) { + this.setPosition(x, y); + } + if (text !== undefined) { + this.setText(text); + } - this.lineOffset = 0; - this.master = true; - this.svgElements = {}; - this.iconsRemoved = false; + // create the frame + this.frame = document.createElement("div"); + var styleAttr = this.frame.style; + styleAttr.position = "absolute"; + styleAttr.visibility = "hidden"; + styleAttr.border = "1px solid " + style.color.border; + styleAttr.color = style.fontColor; + styleAttr.fontSize = style.fontSize + "px"; + styleAttr.fontFamily = style.fontFace; + styleAttr.padding = this.padding + "px"; + styleAttr.backgroundColor = style.color.background; + styleAttr.borderRadius = "3px"; + styleAttr.MozBorderRadius = "3px"; + styleAttr.WebkitBorderRadius = "3px"; + styleAttr.boxShadow = "3px 3px 10px rgba(128, 128, 128, 0.5)"; + styleAttr.whiteSpace = "nowrap"; + this.container.appendChild(this.frame); + } + /** + * @param {number} x Horizontal position of the popup window + * @param {number} y Vertical position of the popup window + */ + Popup.prototype.setPosition = function(x, y) { + this.x = parseInt(x); + this.y = parseInt(y); + }; - this.groups = {}; - this.amountOfGroups = 0; + /** + * Set the content for the popup window. This can be HTML code or text. + * @param {string | Element} content + */ + Popup.prototype.setText = function(content) { + if (content instanceof Element) { + this.frame.innerHTML = ''; + this.frame.appendChild(content); + } + else { + this.frame.innerHTML = content; // string containing text or HTML + } + }; - // create the HTML DOM - this._create(); + /** + * Show the popup window + * @param {boolean} show Optional. Show or hide the window + */ + Popup.prototype.show = function (show) { + if (show === undefined) { + show = true; + } - var me = this; - this.body.emitter.on("verticalDrag", function() { - me.dom.lineContainer.style.top = me.body.domProps.scrollTop + 'px'; - }); - } + if (show) { + var height = this.frame.clientHeight; + var width = this.frame.clientWidth; + var maxHeight = this.frame.parentNode.clientHeight; + var maxWidth = this.frame.parentNode.clientWidth; - DataAxis.prototype = new Component(); + var top = (this.y - height); + if (top + height + this.padding > maxHeight) { + top = maxHeight - height - this.padding; + } + if (top < this.padding) { + top = this.padding; + } + var left = this.x; + if (left + width + this.padding > maxWidth) { + left = maxWidth - width - this.padding; + } + if (left < this.padding) { + left = this.padding; + } - DataAxis.prototype.addGroup = function(label, graphOptions) { - if (!this.groups.hasOwnProperty(label)) { - this.groups[label] = graphOptions; + this.frame.style.left = left + "px"; + this.frame.style.top = top + "px"; + this.frame.style.visibility = "visible"; + } + else { + this.hide(); } - this.amountOfGroups += 1; }; - DataAxis.prototype.updateGroup = function(label, graphOptions) { - this.groups[label] = graphOptions; + /** + * Hide the popup window + */ + Popup.prototype.hide = function () { + this.frame.style.visibility = "hidden"; }; - DataAxis.prototype.removeGroup = function(label) { - if (this.groups.hasOwnProperty(label)) { - delete this.groups[label]; - this.amountOfGroups -= 1; - } - }; + module.exports = Popup; - DataAxis.prototype.setOptions = function (options) { - if (options) { - var redraw = false; - if (this.options.orientation != options.orientation && options.orientation !== undefined) { - redraw = true; - } - var fields = [ - 'orientation', - 'showMinorLabels', - 'showMajorLabels', - 'icons', - 'majorLinesOffset', - 'minorLinesOffset', - 'labelOffsetX', - 'labelOffsetY', - 'iconWidth', - 'width', - 'visible', - 'customRange', - 'title', - 'format', - 'alignZeros' - ]; - util.selectiveExtend(fields, this.options, options); +/***/ }, +/* 42 */ +/***/ function(module, exports, __webpack_require__) { - this.minWidth = Number(('' + this.options.width).replace("px","")); + /** + * Parse a text source containing data in DOT language into a JSON object. + * The object contains two lists: one with nodes and one with edges. + * + * DOT language reference: http://www.graphviz.org/doc/info/lang.html + * + * @param {String} data Text containing a graph in DOT-notation + * @return {Object} graph An object containing two parameters: + * {Object[]} nodes + * {Object[]} edges + */ + function parseDOT (data) { + dot = data; + return parseGraph(); + } - if (redraw == true && this.dom.frame) { - this.hide(); - this.show(); - } - } + // token types enumeration + var TOKENTYPE = { + NULL : 0, + DELIMITER : 1, + IDENTIFIER: 2, + UNKNOWN : 3 + }; + + // map with all delimiters + var DELIMITERS = { + '{': true, + '}': true, + '[': true, + ']': true, + ';': true, + '=': true, + ',': true, + + '->': true, + '--': true }; + var dot = ''; // current dot file + var index = 0; // current index in dot file + var c = ''; // current token character in expr + var token = ''; // current token + var tokenType = TOKENTYPE.NULL; // type of the token /** - * Create the HTML DOM for the DataAxis + * Get the first character from the dot file. + * The character is stored into the char c. If the end of the dot file is + * reached, the function puts an empty string in c. */ - DataAxis.prototype._create = function() { - this.dom.frame = document.createElement('div'); - this.dom.frame.style.width = this.options.width; - this.dom.frame.style.height = this.height; - - this.dom.lineContainer = document.createElement('div'); - this.dom.lineContainer.style.width = '100%'; - this.dom.lineContainer.style.height = this.height; - this.dom.lineContainer.style.position = 'relative'; + function first() { + index = 0; + c = dot.charAt(0); + } - // create svg element for graph drawing. - this.svg = document.createElementNS('http://www.w3.org/2000/svg',"svg"); - this.svg.style.position = "absolute"; - this.svg.style.top = '0px'; - this.svg.style.height = '100%'; - this.svg.style.width = '100%'; - this.svg.style.display = "block"; - this.dom.frame.appendChild(this.svg); - }; + /** + * Get the next character from the dot file. + * The character is stored into the char c. If the end of the dot file is + * reached, the function puts an empty string in c. + */ + function next() { + index++; + c = dot.charAt(index); + } - DataAxis.prototype._redrawGroupIcons = function () { - DOMutil.prepareElements(this.svgElements); + /** + * Preview the next character from the dot file. + * @return {String} cNext + */ + function nextPreview() { + return dot.charAt(index + 1); + } - var x; - var iconWidth = this.options.iconWidth; - var iconHeight = 15; - var iconOffset = 4; - var y = iconOffset + 0.5 * iconHeight; + /** + * Test whether given character is alphabetic or numeric + * @param {String} c + * @return {Boolean} isAlphaNumeric + */ + var regexAlphaNumeric = /[a-zA-Z_0-9.:#]/; + function isAlphaNumeric(c) { + return regexAlphaNumeric.test(c); + } - if (this.options.orientation == 'left') { - x = iconOffset; - } - else { - x = this.width - iconWidth - iconOffset; + /** + * Merge all properties of object b into object b + * @param {Object} a + * @param {Object} b + * @return {Object} a + */ + function merge (a, b) { + if (!a) { + a = {}; } - for (var groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) { - this.groups[groupId].drawIcon(x, y, this.svgElements, this.svg, iconWidth, iconHeight); - y += iconHeight + iconOffset; + if (b) { + for (var name in b) { + if (b.hasOwnProperty(name)) { + a[name] = b[name]; } } } + return a; + } - DOMutil.cleanupElements(this.svgElements); - this.iconsRemoved = false; - }; - - DataAxis.prototype._cleanupIcons = function() { - if (this.iconsRemoved == false) { - DOMutil.prepareElements(this.svgElements); - DOMutil.cleanupElements(this.svgElements); - this.iconsRemoved = true; + /** + * Set a value in an object, where the provided parameter name can be a + * path with nested parameters. For example: + * + * var obj = {a: 2}; + * setValue(obj, 'b.c', 3); // obj = {a: 2, b: {c: 3}} + * + * @param {Object} obj + * @param {String} path A parameter name or dot-separated parameter path, + * like "color.highlight.border". + * @param {*} value + */ + function setValue(obj, path, value) { + var keys = path.split('.'); + var o = obj; + while (keys.length) { + var key = keys.shift(); + if (keys.length) { + // this isn't the end point + if (!o[key]) { + o[key] = {}; + } + o = o[key]; + } + else { + // this is the end point + o[key] = value; + } } } /** - * Create the HTML DOM for the DataAxis + * Add a node to a graph object. If there is already a node with + * the same id, their attributes will be merged. + * @param {Object} graph + * @param {Object} node */ - DataAxis.prototype.show = function() { - this.hidden = false; - if (!this.dom.frame.parentNode) { - if (this.options.orientation == 'left') { - this.body.dom.left.appendChild(this.dom.frame); + function addNode(graph, node) { + var i, len; + var current = null; + + // find root graph (in case of subgraph) + var graphs = [graph]; // list with all graphs from current graph to root graph + var root = graph; + while (root.parent) { + graphs.push(root.parent); + root = root.parent; + } + + // find existing node (at root level) by its id + if (root.nodes) { + for (i = 0, len = root.nodes.length; i < len; i++) { + if (node.id === root.nodes[i].id) { + current = root.nodes[i]; + break; + } } - else { - this.body.dom.right.appendChild(this.dom.frame); + } + + if (!current) { + // this is a new node + current = { + id: node.id + }; + if (graph.node) { + // clone default attributes + current.attr = merge(current.attr, graph.node); } } - if (!this.dom.lineContainer.parentNode) { - this.body.dom.backgroundHorizontal.appendChild(this.dom.lineContainer); + // add node to this (sub)graph and all its parent graphs + for (i = graphs.length - 1; i >= 0; i--) { + var g = graphs[i]; + + if (!g.nodes) { + g.nodes = []; + } + if (g.nodes.indexOf(current) == -1) { + g.nodes.push(current); + } } - }; + + // merge attributes + if (node.attr) { + current.attr = merge(current.attr, node.attr); + } + } /** - * Create the HTML DOM for the DataAxis + * Add an edge to a graph object + * @param {Object} graph + * @param {Object} edge */ - DataAxis.prototype.hide = function() { - this.hidden = true; - if (this.dom.frame.parentNode) { - this.dom.frame.parentNode.removeChild(this.dom.frame); + function addEdge(graph, edge) { + if (!graph.edges) { + graph.edges = []; } - - if (this.dom.lineContainer.parentNode) { - this.dom.lineContainer.parentNode.removeChild(this.dom.lineContainer); + graph.edges.push(edge); + if (graph.edge) { + var attr = merge({}, graph.edge); // clone default attributes + edge.attr = merge(attr, edge.attr); // merge attributes } - }; + } /** - * Set a range (start and end) - * @param end - * @param start - * @param end + * Create an edge to a graph object + * @param {Object} graph + * @param {String | Number | Object} from + * @param {String | Number | Object} to + * @param {String} type + * @param {Object | null} attr + * @return {Object} edge */ - DataAxis.prototype.setRange = function (start, end) { - if (this.master == false && this.options.alignZeros == true && this.zeroCrossing != -1) { - if (start > 0) { - start = 0; - } + function createEdge(graph, from, to, type, attr) { + var edge = { + from: from, + to: to, + type: type + }; + + if (graph.edge) { + edge.attr = merge({}, graph.edge); // clone default attributes } - this.range.start = start; - this.range.end = end; - }; + edge.attr = merge(edge.attr || {}, attr); // merge attributes + + return edge; + } /** - * Repaint the component - * @return {boolean} Returns true if the component is resized + * Get next token in the current dot file. + * The token and token type are available as token and tokenType */ - DataAxis.prototype.redraw = function () { - var resized = false; - var activeGroups = 0; - - // Make sure the line container adheres to the vertical scrolling. - this.dom.lineContainer.style.top = this.body.domProps.scrollTop + 'px'; + function getToken() { + tokenType = TOKENTYPE.NULL; + token = ''; - for (var groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) { - activeGroups++; - } - } - } - if (this.amountOfGroups == 0 || activeGroups == 0) { - this.hide(); + // skip over whitespaces + while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter + next(); } - else { - this.show(); - this.height = Number(this.linegraphSVG.style.height.replace("px","")); - // svg offsetheight did not work in firefox and explorer... - this.dom.lineContainer.style.height = this.height + 'px'; - this.width = this.options.visible == true ? Number(('' + this.options.width).replace("px","")) : 0; + do { + var isComment = false; - var props = this.props; - var frame = this.dom.frame; + // skip comment + if (c == '#') { + // find the previous non-space character + var i = index - 1; + while (dot.charAt(i) == ' ' || dot.charAt(i) == '\t') { + i--; + } + if (dot.charAt(i) == '\n' || dot.charAt(i) == '') { + // the # is at the start of a line, this is indeed a line comment + while (c != '' && c != '\n') { + next(); + } + isComment = true; + } + } + if (c == '/' && nextPreview() == '/') { + // skip line comment + while (c != '' && c != '\n') { + next(); + } + isComment = true; + } + if (c == '/' && nextPreview() == '*') { + // skip block comment + while (c != '') { + if (c == '*' && nextPreview() == '/') { + // end of block comment found. skip these last two characters + next(); + next(); + break; + } + else { + next(); + } + } + isComment = true; + } - // update classname - frame.className = 'dataaxis'; + // skip over whitespaces + while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter + next(); + } + } + while (isComment); - // calculate character width and height - this._calculateCharSize(); + // check for end of dot file + if (c == '') { + // token is still empty + tokenType = TOKENTYPE.DELIMITER; + return; + } - var orientation = this.options.orientation; - var showMinorLabels = this.options.showMinorLabels; - var showMajorLabels = this.options.showMajorLabels; + // check for delimiters consisting of 2 characters + var c2 = c + nextPreview(); + if (DELIMITERS[c2]) { + tokenType = TOKENTYPE.DELIMITER; + token = c2; + next(); + next(); + return; + } - // determine the width and height of the elements for the axis - props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; - props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; + // check for delimiters consisting of 1 character + if (DELIMITERS[c]) { + tokenType = TOKENTYPE.DELIMITER; + token = c; + next(); + return; + } - props.minorLineWidth = this.body.dom.backgroundHorizontal.offsetWidth - this.lineOffset - this.width + 2 * this.options.minorLinesOffset; - props.minorLineHeight = 1; - props.majorLineWidth = this.body.dom.backgroundHorizontal.offsetWidth - this.lineOffset - this.width + 2 * this.options.majorLinesOffset; - props.majorLineHeight = 1; + // check for an identifier (number or string) + // TODO: more precise parsing of numbers/strings (and the port separator ':') + if (isAlphaNumeric(c) || c == '-') { + token += c; + next(); - // take frame offline while updating (is almost twice as fast) - if (orientation == 'left') { - frame.style.top = '0'; - frame.style.left = '0'; - frame.style.bottom = ''; - frame.style.width = this.width + 'px'; - frame.style.height = this.height + "px"; - this.props.width = this.body.domProps.left.width; - this.props.height = this.body.domProps.left.height; + while (isAlphaNumeric(c)) { + token += c; + next(); } - else { // right - frame.style.top = ''; - frame.style.bottom = '0'; - frame.style.left = '0'; - frame.style.width = this.width + 'px'; - frame.style.height = this.height + "px"; - this.props.width = this.body.domProps.right.width; - this.props.height = this.body.domProps.right.height; + if (token == 'false') { + token = false; // convert to boolean } + else if (token == 'true') { + token = true; // convert to boolean + } + else if (!isNaN(Number(token))) { + token = Number(token); // convert to number + } + tokenType = TOKENTYPE.IDENTIFIER; + return; + } - resized = this._redrawLabels(); - resized = this._isResized() || resized; - - if (this.options.icons == true) { - this._redrawGroupIcons(); + // check for a string enclosed by double quotes + if (c == '"') { + next(); + while (c != '' && (c != '"' || (c == '"' && nextPreview() == '"'))) { + token += c; + if (c == '"') { // skip the escape character + next(); + } + next(); } - else { - this._cleanupIcons(); + if (c != '"') { + throw newSyntaxError('End of string " expected'); } + next(); + tokenType = TOKENTYPE.IDENTIFIER; + return; + } - this._redrawTitle(orientation); + // something unknown is found, wrong characters, a syntax error + tokenType = TOKENTYPE.UNKNOWN; + while (c != '') { + token += c; + next(); } - return resized; - }; + throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"'); + } /** - * Repaint major and minor text labels and vertical grid lines - * @private + * Parse a graph. + * @returns {Object} graph */ - DataAxis.prototype._redrawLabels = function () { - var resized = false; - DOMutil.prepareElements(this.DOMelements.lines); - DOMutil.prepareElements(this.DOMelements.labels); - - var orientation = this.options['orientation']; - - // calculate range and step (step such that we have space for 7 characters per label) - var minimumStep = this.master ? this.props.majorCharHeight || 10 : this.stepPixelsForced; - - var step = new DataStep( - this.range.start, - this.range.end, - minimumStep, - this.dom.frame.offsetHeight, - this.options.customRange[this.options.orientation], - this.master == false && this.options.alignZeros // doess the step have to align zeros? only if not master and the options is on - ); - - this.step = step; - // get the distance in pixels for a step - // dead space is space that is "left over" after a step - var stepPixels = (this.dom.frame.offsetHeight - (step.deadSpace * (this.dom.frame.offsetHeight / step.marginRange))) / (((step.marginRange - step.deadSpace) / step.step)); - - this.stepPixels = stepPixels; + function parseGraph() { + var graph = {}; - var amountOfSteps = this.height / stepPixels; - var stepDifference = 0; + first(); + getToken(); - // the slave axis needs to use the same horizontal lines as the master axis. - if (this.master == false) { - stepPixels = this.stepPixelsForced; - stepDifference = Math.round((this.dom.frame.offsetHeight / stepPixels) - amountOfSteps); - for (var i = 0; i < 0.5 * stepDifference; i++) { - step.previous(); - } - amountOfSteps = this.height / stepPixels; + // optional strict keyword + if (token == 'strict') { + graph.strict = true; + getToken(); + } - if (this.zeroCrossing != -1 && this.options.alignZeros == true) { - var zeroStepDifference = (step.marginEnd / step.step) - this.zeroCrossing; - if (zeroStepDifference > 0) { - for (var i = 0; i < zeroStepDifference; i++) {step.next();} - } - else if (zeroStepDifference < 0) { - for (var i = 0; i < -zeroStepDifference; i++) {step.previous();} - } - } + // graph or digraph keyword + if (token == 'graph' || token == 'digraph') { + graph.type = token; + getToken(); } - else { - amountOfSteps += 0.25; + + // optional graph id + if (tokenType == TOKENTYPE.IDENTIFIER) { + graph.id = token; + getToken(); } + // open angle bracket + if (token != '{') { + throw newSyntaxError('Angle bracket { expected'); + } + getToken(); - this.valueAtZero = step.marginEnd; - var marginStartPos = 0; + // statements + parseStatements(graph); - // do not draw the first label - var max = 1; + // close angle bracket + if (token != '}') { + throw newSyntaxError('Angle bracket } expected'); + } + getToken(); - // Get the number of decimal places - var decimals; - if(this.options.format[orientation] !== undefined) { - decimals = this.options.format[orientation].decimals; + // end of file + if (token !== '') { + throw newSyntaxError('End of file expected'); } + getToken(); - this.maxLabelSize = 0; - var y = 0; - while (max < Math.round(amountOfSteps)) { - step.next(); - y = Math.round(max * stepPixels); - marginStartPos = max * stepPixels; - var isMajor = step.isMajor(); + // remove temporary default properties + delete graph.node; + delete graph.edge; + delete graph.graph; - if (this.options['showMinorLabels'] && isMajor == false || this.master == false && this.options['showMinorLabels'] == true) { - this._redrawLabel(y - 2, step.getCurrent(decimals), orientation, 'yAxis minor', this.props.minorCharHeight); - } + return graph; + } - if (isMajor && this.options['showMajorLabels'] && this.master == true || - this.options['showMinorLabels'] == false && this.master == false && isMajor == true) { - if (y >= 0) { - this._redrawLabel(y - 2, step.getCurrent(decimals), orientation, 'yAxis major', this.props.majorCharHeight); - } - this._redrawLine(y, orientation, 'grid horizontal major', this.options.majorLinesOffset, this.props.majorLineWidth); - } - else { - this._redrawLine(y, orientation, 'grid horizontal minor', this.options.minorLinesOffset, this.props.minorLineWidth); + /** + * Parse a list with statements. + * @param {Object} graph + */ + function parseStatements (graph) { + while (token !== '' && token != '}') { + parseStatement(graph); + if (token == ';') { + getToken(); } + } + } - if (this.master == true && step.current == 0) { - this.zeroCrossing = max; - } + /** + * Parse a single statement. Can be a an attribute statement, node + * statement, a series of node statements and edge statements, or a + * parameter. + * @param {Object} graph + */ + function parseStatement(graph) { + // parse subgraph + var subgraph = parseSubgraph(graph); + if (subgraph) { + // edge statements + parseEdge(graph, subgraph); - max++; + return; } - if (this.master == false) { - this.conversionFactor = y / (this.valueAtZero - step.current); - } - else { - this.conversionFactor = this.dom.frame.offsetHeight / step.marginRange; + // parse an attribute statement + var attr = parseAttributeStatement(graph); + if (attr) { + return; } - // Note that title is rotated, so we're using the height, not width! - var titleWidth = 0; - if (this.options.title[orientation] !== undefined && this.options.title[orientation].text !== undefined) { - titleWidth = this.props.titleCharHeight; + // parse node + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier expected'); } - var offset = this.options.icons == true ? Math.max(this.options.iconWidth, titleWidth) + this.options.labelOffsetX + 15 : titleWidth + this.options.labelOffsetX + 15; + var id = token; // id can be a string or a number + getToken(); - // this will resize the yAxis to accommodate the labels. - if (this.maxLabelSize > (this.width - offset) && this.options.visible == true) { - this.width = this.maxLabelSize + offset; - this.options.width = this.width + "px"; - DOMutil.cleanupElements(this.DOMelements.lines); - DOMutil.cleanupElements(this.DOMelements.labels); - this.redraw(); - resized = true; - } - // this will resize the yAxis if it is too big for the labels. - else if (this.maxLabelSize < (this.width - offset) && this.options.visible == true && this.width > this.minWidth) { - this.width = Math.max(this.minWidth,this.maxLabelSize + offset); - this.options.width = this.width + "px"; - DOMutil.cleanupElements(this.DOMelements.lines); - DOMutil.cleanupElements(this.DOMelements.labels); - this.redraw(); - resized = true; + if (token == '=') { + // id statement + getToken(); + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier expected'); + } + graph[id] = token; + getToken(); + // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] " } else { - DOMutil.cleanupElements(this.DOMelements.lines); - DOMutil.cleanupElements(this.DOMelements.labels); - resized = false; + parseNodeStatement(graph, id); } - - return resized; - }; - - DataAxis.prototype.convertValue = function (value) { - var invertedValue = this.valueAtZero - value; - var convertedValue = invertedValue * this.conversionFactor; - return convertedValue; - }; + } /** - * Create a label for the axis at position x - * @private - * @param y - * @param text - * @param orientation - * @param className - * @param characterHeight + * Parse a subgraph + * @param {Object} graph parent graph object + * @return {Object | null} subgraph */ - DataAxis.prototype._redrawLabel = function (y, text, orientation, className, characterHeight) { - // reuse redundant label - var label = DOMutil.getDOMElement('div',this.DOMelements.labels, this.dom.frame); //this.dom.redundant.labels.shift(); - label.className = className; - label.innerHTML = text; - if (orientation == 'left') { - label.style.left = '-' + this.options.labelOffsetX + 'px'; - label.style.textAlign = "right"; - } - else { - label.style.right = '-' + this.options.labelOffsetX + 'px'; - label.style.textAlign = "left"; + function parseSubgraph (graph) { + var subgraph = null; + + // optional subgraph keyword + if (token == 'subgraph') { + subgraph = {}; + subgraph.type = 'subgraph'; + getToken(); + + // optional graph id + if (tokenType == TOKENTYPE.IDENTIFIER) { + subgraph.id = token; + getToken(); + } } - label.style.top = y - 0.5 * characterHeight + this.options.labelOffsetY + 'px'; + // open angle bracket + if (token == '{') { + getToken(); - text += ''; + if (!subgraph) { + subgraph = {}; + } + subgraph.parent = graph; + subgraph.node = graph.node; + subgraph.edge = graph.edge; + subgraph.graph = graph.graph; - var largestWidth = Math.max(this.props.majorCharWidth,this.props.minorCharWidth); - if (this.maxLabelSize < text.length * largestWidth) { - this.maxLabelSize = text.length * largestWidth; + // statements + parseStatements(subgraph); + + // close angle bracket + if (token != '}') { + throw newSyntaxError('Angle bracket } expected'); + } + getToken(); + + // remove temporary default properties + delete subgraph.node; + delete subgraph.edge; + delete subgraph.graph; + delete subgraph.parent; + + // register at the parent graph + if (!graph.subgraphs) { + graph.subgraphs = []; + } + graph.subgraphs.push(subgraph); } - }; + + return subgraph; + } /** - * Create a minor line for the axis at position y - * @param y - * @param orientation - * @param className - * @param offset - * @param width + * parse an attribute statement like "node [shape=circle fontSize=16]". + * Available keywords are 'node', 'edge', 'graph'. + * The previous list with default attributes will be replaced + * @param {Object} graph + * @returns {String | null} keyword Returns the name of the parsed attribute + * (node, edge, graph), or null if nothing + * is parsed. */ - DataAxis.prototype._redrawLine = function (y, orientation, className, offset, width) { - if (this.master == true) { - var line = DOMutil.getDOMElement('div',this.DOMelements.lines, this.dom.lineContainer);//this.dom.redundant.lines.shift(); - line.className = className; - line.innerHTML = ''; + function parseAttributeStatement (graph) { + // attribute statements + if (token == 'node') { + getToken(); - if (orientation == 'left') { - line.style.left = (this.width - offset) + 'px'; - } - else { - line.style.right = (this.width - offset) + 'px'; - } + // node attributes + graph.node = parseAttributeList(); + return 'node'; + } + else if (token == 'edge') { + getToken(); - line.style.width = width + 'px'; - line.style.top = y + 'px'; + // edge attributes + graph.edge = parseAttributeList(); + return 'edge'; } - }; + else if (token == 'graph') { + getToken(); + + // graph attributes + graph.graph = parseAttributeList(); + return 'graph'; + } + + return null; + } /** - * Create a title for the axis - * @private - * @param orientation + * parse a node statement + * @param {Object} graph + * @param {String | Number} id */ - DataAxis.prototype._redrawTitle = function (orientation) { - DOMutil.prepareElements(this.DOMelements.title); + function parseNodeStatement(graph, id) { + // node statement + var node = { + id: id + }; + var attr = parseAttributeList(); + if (attr) { + node.attr = attr; + } + addNode(graph, node); - // Check if the title is defined for this axes - if (this.options.title[orientation] !== undefined && this.options.title[orientation].text !== undefined) { - var title = DOMutil.getDOMElement('div', this.DOMelements.title, this.dom.frame); - title.className = 'yAxis title ' + orientation; - title.innerHTML = this.options.title[orientation].text; + // edge statements + parseEdge(graph, id); + } - // Add style - if provided - if (this.options.title[orientation].style !== undefined) { - util.addCssText(title, this.options.title[orientation].style); - } + /** + * Parse an edge or a series of edges + * @param {Object} graph + * @param {String | Number} from Id of the from node + */ + function parseEdge(graph, from) { + while (token == '->' || token == '--') { + var to; + var type = token; + getToken(); - if (orientation == 'left') { - title.style.left = this.props.titleCharHeight + 'px'; + var subgraph = parseSubgraph(graph); + if (subgraph) { + to = subgraph; } else { - title.style.right = this.props.titleCharHeight + 'px'; + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier or subgraph expected'); + } + to = token; + addNode(graph, { + id: to + }); + getToken(); } - title.style.width = this.height + 'px'; - } - - // we need to clean up in case we did not use all elements. - DOMutil.cleanupElements(this.DOMelements.title); - }; - + // parse edge attributes + var attr = parseAttributeList(); + // create edge + var edge = createEdge(graph, from, to, type, attr); + addEdge(graph, edge); + from = to; + } + } /** - * Determine the size of text on the axis (both major and minor axis). - * The size is calculated only once and then cached in this.props. - * @private + * Parse a set with attributes, + * for example [label="1.000", shape=solid] + * @return {Object | null} attr */ - DataAxis.prototype._calculateCharSize = function () { - // determine the char width and height on the minor axis - if (!('minorCharHeight' in this.props)) { - var textMinor = document.createTextNode('0'); - var measureCharMinor = document.createElement('div'); - measureCharMinor.className = 'yAxis minor measure'; - measureCharMinor.appendChild(textMinor); - this.dom.frame.appendChild(measureCharMinor); + function parseAttributeList() { + var attr = null; - this.props.minorCharHeight = measureCharMinor.clientHeight; - this.props.minorCharWidth = measureCharMinor.clientWidth; + while (token == '[') { + getToken(); + attr = {}; + while (token !== '' && token != ']') { + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Attribute name expected'); + } + var name = token; - this.dom.frame.removeChild(measureCharMinor); - } + getToken(); + if (token != '=') { + throw newSyntaxError('Equal sign = expected'); + } + getToken(); - if (!('majorCharHeight' in this.props)) { - var textMajor = document.createTextNode('0'); - var measureCharMajor = document.createElement('div'); - measureCharMajor.className = 'yAxis major measure'; - measureCharMajor.appendChild(textMajor); - this.dom.frame.appendChild(measureCharMajor); + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Attribute value expected'); + } + var value = token; + setValue(attr, name, value); // name can be a path - this.props.majorCharHeight = measureCharMajor.clientHeight; - this.props.majorCharWidth = measureCharMajor.clientWidth; + getToken(); + if (token ==',') { + getToken(); + } + } - this.dom.frame.removeChild(measureCharMajor); + if (token != ']') { + throw newSyntaxError('Bracket ] expected'); + } + getToken(); } - if (!('titleCharHeight' in this.props)) { - var textTitle = document.createTextNode('0'); - var measureCharTitle = document.createElement('div'); - measureCharTitle.className = 'yAxis title measure'; - measureCharTitle.appendChild(textTitle); - this.dom.frame.appendChild(measureCharTitle); + return attr; + } - this.props.titleCharHeight = measureCharTitle.clientHeight; - this.props.titleCharWidth = measureCharTitle.clientWidth; + /** + * Create a syntax error with extra information on current token and index. + * @param {String} message + * @returns {SyntaxError} err + */ + function newSyntaxError(message) { + return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ')'); + } - this.dom.frame.removeChild(measureCharTitle); + /** + * Chop off text after a maximum length + * @param {String} text + * @param {Number} maxLength + * @returns {String} + */ + function chop (text, maxLength) { + return (text.length <= maxLength) ? text : (text.substr(0, 27) + '...'); + } + + /** + * Execute a function fn for each pair of elements in two arrays + * @param {Array | *} array1 + * @param {Array | *} array2 + * @param {function} fn + */ + function forEach2(array1, array2, fn) { + if (Array.isArray(array1)) { + array1.forEach(function (elem1) { + if (Array.isArray(array2)) { + array2.forEach(function (elem2) { + fn(elem1, elem2); + }); + } + else { + fn(elem1, array2); + } + }); } - }; + else { + if (Array.isArray(array2)) { + array2.forEach(function (elem2) { + fn(array1, elem2); + }); + } + else { + fn(array1, array2); + } + } + } /** - * 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 + * Convert a string containing a graph in DOT language into a map containing + * with nodes and edges in the format of graph. + * @param {String} data Text containing a graph in DOT-notation + * @return {Object} graphData */ - DataAxis.prototype.snap = function(date) { - return this.step.snap(date); - }; + function DOTToGraph (data) { + // parse the DOT file + var dotData = parseDOT(data); + var graphData = { + nodes: [], + edges: [], + options: {} + }; - module.exports = DataAxis; + // copy the nodes + if (dotData.nodes) { + dotData.nodes.forEach(function (dotNode) { + var graphNode = { + id: dotNode.id, + label: String(dotNode.label || dotNode.id) + }; + merge(graphNode, dotNode.attr); + if (graphNode.image) { + graphNode.shape = 'image'; + } + graphData.nodes.push(graphNode); + }); + } + // copy the edges + if (dotData.edges) { + /** + * Convert an edge in DOT format to an edge with VisGraph format + * @param {Object} dotEdge + * @returns {Object} graphEdge + */ + var convertEdge = function (dotEdge) { + var graphEdge = { + from: dotEdge.from, + to: dotEdge.to + }; + merge(graphEdge, dotEdge.attr); + graphEdge.style = (dotEdge.type == '->') ? 'arrow' : 'line'; + return graphEdge; + } -/***/ }, -/* 45 */ -/***/ function(module, exports, __webpack_require__) { + dotData.edges.forEach(function (dotEdge) { + var from, to; + if (dotEdge.from instanceof Object) { + from = dotEdge.from.nodes; + } + else { + from = { + id: dotEdge.from + } + } - /** - * @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, alignZeros) { - // variables - this.current = 0; + if (dotEdge.to instanceof Object) { + to = dotEdge.to.nodes; + } + else { + to = { + id: dotEdge.to + } + } - this.autoScale = true; - this.stepIndex = 0; - this.step = 1; - this.scale = 1; + if (dotEdge.from instanceof Object && dotEdge.from.edges) { + dotEdge.from.edges.forEach(function (subEdge) { + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); + } - this.marginStart; - this.marginEnd; - this.deadSpace = 0; + forEach2(from, to, function (from, to) { + var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr); + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); - this.majorSteps = [1, 2, 5, 10]; - this.minorSteps = [0.25, 0.5, 1, 2]; + if (dotEdge.to instanceof Object && dotEdge.to.edges) { + dotEdge.to.edges.forEach(function (subEdge) { + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); + } + }); + } - this.alignZeros = alignZeros; + // copy the options + if (dotData.attr) { + graphData.options = dotData.attr; + } - this.setRange(start, end, minimumStep, containerHeight, customRange); + return graphData; } + // exports + exports.parseDOT = parseDOT; + exports.DOTToGraph = DOTToGraph; - /** - * 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; +/***/ }, +/* 43 */ +/***/ function(module, exports, __webpack_require__) { - if (this._start == this._end) { - this._start -= 0.75; - this._end += 1; - } + + function parseGephi(gephiJSON, options) { + var edges = []; + var nodes = []; + this.options = { + edges: { + inheritColor: true + }, + nodes: { + allowedToMove: false, + parseColor: false + } + }; - if (this.autoScale == true) { - this.setMinimumStep(minimumStep, containerHeight); + if (options !== undefined) { + this.options.nodes['allowedToMove'] = options.allowedToMove | false; + this.options.nodes['parseColor'] = options.parseColor | false; + this.options.edges['inheritColor'] = options.inheritColor | true; } - 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 gEdges = gephiJSON.edges; + var gNodes = gephiJSON.nodes; + for (var i = 0; i < gEdges.length; i++) { + var edge = {}; + var gEdge = gEdges[i]; + edge['id'] = gEdge.id; + edge['from'] = gEdge.source; + edge['to'] = gEdge.target; + edge['attributes'] = gEdge.attributes; + // edge['value'] = gEdge.attributes !== undefined ? gEdge.attributes.Weight : undefined; + // edge['width'] = edge['value'] !== undefined ? undefined : edgegEdge.size; + edge['color'] = gEdge.color; + edge['inheritColor'] = edge['color'] !== undefined ? false : this.options.inheritColor; + edges.push(edge); } - 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; - } + for (var i = 0; i < gNodes.length; i++) { + var node = {}; + var gNode = gNodes[i]; + node['id'] = gNode.id; + node['attributes'] = gNode.attributes; + node['x'] = gNode.x; + node['y'] = gNode.y; + node['label'] = gNode.label; + if (this.options.nodes.parseColor == true) { + node['color'] = gNode.color; } - if (solutionFound == true) { - break; + else { + node['color'] = gNode.color !== undefined ? {background:gNode.color, border:gNode.color} : undefined; } - } - 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 = {}; + node['radius'] = gNode.size; + node['allowedToMoveX'] = this.options.nodes.allowedToMove; + node['allowedToMoveY'] = this.options.nodes.allowedToMove; + nodes.push(node); } - 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; + return {nodes:nodes, edges:edges}; + } - this.marginEnd = customRange.max === undefined ? this.roundToMinor(niceEnd) : customRange.max; - this.marginStart = customRange.min === undefined ? this.roundToMinor(niceStart) : customRange.min; + exports.parseGephi = parseGephi; - // if we need to align the zero's we need to make sure that there is a zero to use. - if (this.alignZeros == true && (this.marginEnd - this.marginStart) % this.step != 0) { - this.marginEnd += this.marginEnd % this.step; - } +/***/ }, +/* 44 */ +/***/ function(module, exports, __webpack_require__) { - this.deadSpace = this.roundToMinor(niceEnd) - niceEnd + this.roundToMinor(niceStart) - niceStart; - this.marginRange = this.marginEnd - this.marginStart; + // first check if moment.js is already loaded in the browser window, if so, + // use this instance. Else, load via commonjs. + module.exports = (typeof window !== 'undefined') && window['moment'] || __webpack_require__(57); - this.current = this.marginEnd; - }; +/***/ }, +/* 45 */ +/***/ function(module, exports, __webpack_require__) { - 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; + // Only load hammer.js when in a browser environment + // (loading hammer.js in a node.js environment gives errors) + if (typeof window !== 'undefined') { + module.exports = window['Hammer'] || __webpack_require__(58); + } + else { + module.exports = function () { + throw Error('hammer.js is only available in a browser, not in node.js.'); } } - /** - * 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); - }; +/***/ }, +/* 46 */ +/***/ function(module, exports, __webpack_require__) { + + var Emitter = __webpack_require__(56); + var Hammer = __webpack_require__(45); + var util = __webpack_require__(1); + var DataSet = __webpack_require__(3); + var DataView = __webpack_require__(4); + var Range = __webpack_require__(17); + var ItemSet = __webpack_require__(27); + var Activator = __webpack_require__(55); + var DateUtil = __webpack_require__(15); /** - * Do the next step + * Create a timeline visualization + * @param {HTMLElement} container + * @param {vis.DataSet | Array | google.visualization.DataTable} [items] + * @param {Object} [options] See Core.setOptions for the available options. + * @constructor */ - DataStep.prototype.next = function() { - var prev = this.current; - this.current -= this.step; + function Core () {} - // safety mechanism: if current time is still unchanged, move to the end - if (this.current == prev) { - this.current = this._end; - } - }; + // turn Core into an event emitter + Emitter(Core.prototype); /** - * Do the next step + * Create the main DOM for the Core: a root panel containing left, right, + * top, bottom, content, and background panel. + * @param {Element} container The container element where the Core will + * be attached. + * @private */ - DataStep.prototype.previous = function() { - this.current += this.step; - this.marginEnd += this.step; - this.marginRange = this.marginEnd - this.marginStart; - }; + Core.prototype._create = function (container) { + this.dom = {}; + this.dom.root = document.createElement('div'); + this.dom.background = document.createElement('div'); + this.dom.backgroundVertical = document.createElement('div'); + this.dom.backgroundHorizontal = document.createElement('div'); + this.dom.centerContainer = document.createElement('div'); + this.dom.leftContainer = document.createElement('div'); + this.dom.rightContainer = document.createElement('div'); + this.dom.center = document.createElement('div'); + this.dom.left = document.createElement('div'); + this.dom.right = document.createElement('div'); + this.dom.top = document.createElement('div'); + this.dom.bottom = document.createElement('div'); + this.dom.shadowTop = document.createElement('div'); + this.dom.shadowBottom = document.createElement('div'); + this.dom.shadowTopLeft = document.createElement('div'); + this.dom.shadowBottomLeft = document.createElement('div'); + this.dom.shadowTopRight = document.createElement('div'); + this.dom.shadowBottomRight = document.createElement('div'); + this.dom.root.className = 'vis timeline root'; + this.dom.background.className = 'vispanel background'; + this.dom.backgroundVertical.className = 'vispanel background vertical'; + this.dom.backgroundHorizontal.className = 'vispanel background horizontal'; + this.dom.centerContainer.className = 'vispanel center'; + this.dom.leftContainer.className = 'vispanel left'; + this.dom.rightContainer.className = 'vispanel right'; + this.dom.top.className = 'vispanel top'; + this.dom.bottom.className = 'vispanel bottom'; + this.dom.left.className = 'content'; + this.dom.center.className = 'content'; + this.dom.right.className = 'content'; + this.dom.shadowTop.className = 'shadow top'; + this.dom.shadowBottom.className = 'shadow bottom'; + this.dom.shadowTopLeft.className = 'shadow top'; + this.dom.shadowBottomLeft.className = 'shadow bottom'; + this.dom.shadowTopRight.className = 'shadow top'; + this.dom.shadowBottomRight.className = 'shadow bottom'; - /** - * Get the current datetime - * @return {String} current The current date - */ - DataStep.prototype.getCurrent = function(decimals) { - // prevent round-off errors when close to zero - var current = (Math.abs(this.current) < this.step / 2) ? 0 : this.current; - var toPrecision = '' + Number(current).toPrecision(5); + this.dom.root.appendChild(this.dom.background); + this.dom.root.appendChild(this.dom.backgroundVertical); + this.dom.root.appendChild(this.dom.backgroundHorizontal); + this.dom.root.appendChild(this.dom.centerContainer); + this.dom.root.appendChild(this.dom.leftContainer); + this.dom.root.appendChild(this.dom.rightContainer); + this.dom.root.appendChild(this.dom.top); + this.dom.root.appendChild(this.dom.bottom); - // If decimals is specified, then limit or extend the string as required - if(decimals !== undefined && !isNaN(Number(decimals))) { - // If string includes exponent, then we need to add it to the end - var exp = ""; - var index = toPrecision.indexOf("e"); - if(index != -1) { - // Get the exponent - exp = toPrecision.slice(index); - // Remove the exponent in case we need to zero-extend - toPrecision = toPrecision.slice(0, index); - } - index = Math.max(toPrecision.indexOf(","), toPrecision.indexOf(".")); - if(index === -1) { - // No decimal found - if we want decimals, then we need to add it - if(decimals !== 0) { - toPrecision += '.'; - } - // Calculate how long the string should be - index = toPrecision.length + decimals; - } - else if(decimals !== 0) { - // Calculate how long the string should be - accounting for the decimal place - index += decimals + 1; - } - if(index > toPrecision.length) { - // We need to add zeros! - for(var cnt = index - toPrecision.length; cnt > 0; cnt--) { - toPrecision += '0'; + this.dom.centerContainer.appendChild(this.dom.center); + this.dom.leftContainer.appendChild(this.dom.left); + this.dom.rightContainer.appendChild(this.dom.right); + + this.dom.centerContainer.appendChild(this.dom.shadowTop); + this.dom.centerContainer.appendChild(this.dom.shadowBottom); + this.dom.leftContainer.appendChild(this.dom.shadowTopLeft); + this.dom.leftContainer.appendChild(this.dom.shadowBottomLeft); + this.dom.rightContainer.appendChild(this.dom.shadowTopRight); + this.dom.rightContainer.appendChild(this.dom.shadowBottomRight); + + this.on('rangechange', this.redraw.bind(this)); + this.on('touch', this._onTouch.bind(this)); + this.on('pinch', this._onPinch.bind(this)); + this.on('dragstart', this._onDragStart.bind(this)); + this.on('drag', this._onDrag.bind(this)); + + var me = this; + this.on('change', function (properties) { + if (properties && properties.queue == true) { + // redraw once on next tick + if (!me._redrawTimer) { + me._redrawTimer = setTimeout(function () { + me._redrawTimer = null; + me.redraw(); + }, 0) } } else { - // we need to remove characters - toPrecision = toPrecision.slice(0, index); - } - // Add the exponent if there is one - toPrecision += exp; - } - else { - if (toPrecision.indexOf(",") != -1 || toPrecision.indexOf(".") != -1) { - // If no decimal is specified, and there are decimal places, remove trailing zeros - 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; - } - } + // redraw immediately + me.redraw(); } - } + }); - return toPrecision; - }; + // create event listeners for all interesting events, these events will be + // emitted via emitter + this.hammer = Hammer(this.dom.root, { + preventDefault: true + }); + this.listeners = {}; + var events = [ + 'touch', 'pinch', + 'tap', 'doubletap', 'hold', + 'dragstart', 'drag', 'dragend', + 'mousewheel', 'DOMMouseScroll' // DOMMouseScroll is needed for Firefox + ]; + events.forEach(function (event) { + var listener = function () { + var args = [event].concat(Array.prototype.slice.call(arguments, 0)); + if (me.isActive()) { + me.emit.apply(me, args); + } + }; + me.hammer.on(event, listener); + me.listeners[event] = listener; + }); + // size properties of each of the panels + this.props = { + root: {}, + background: {}, + centerContainer: {}, + leftContainer: {}, + rightContainer: {}, + center: {}, + left: {}, + right: {}, + top: {}, + bottom: {}, + border: {}, + scrollTop: 0, + scrollTopMin: 0 + }; + this.touch = {}; // store state information needed for touch events - /** - * 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) { + this.redrawCount = 0; + // attach the root panel to the provided container + if (!container) throw new Error('No container provided'); + container.appendChild(this.dom.root); }; /** - * 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. + * Set options. Options will be passed to all components loaded in the Timeline. + * @param {Object} [options] + * {String} orientation + * Vertical orientation for the Timeline, + * can be 'bottom' (default) or 'top'. + * {String | Number} width + * Width for the timeline, a number in pixels or + * a css string like '1000px' or '75%'. '100%' by default. + * {String | Number} height + * Fixed height for the Timeline, a number in pixels or + * a css string like '400px' or '75%'. If undefined, + * The Timeline will automatically size such that + * its contents fit. + * {String | Number} minHeight + * Minimum height for the Timeline, a number in pixels or + * a css string like '400px' or '75%'. + * {String | Number} maxHeight + * Maximum height for the Timeline, a number in pixels or + * a css string like '400px' or '75%'. + * {Number | Date | String} start + * Start date for the visible window + * {Number | Date | String} end + * End date for the visible window */ - DataStep.prototype.isMajor = function() { - return (this.current % (this.scale * this.majorSteps[this.stepIndex]) == 0); - }; - - module.exports = DataStep; - + Core.prototype.setOptions = function (options) { + if (options) { + // copy the known options + var fields = ['width', 'height', 'minHeight', 'maxHeight', 'autoResize', 'start', 'end', 'orientation', 'clickToUse', 'dataAttributes', 'hiddenDates']; + util.selectiveExtend(fields, this.options, options); -/***/ }, -/* 46 */ -/***/ function(module, exports, __webpack_require__) { + if ('hiddenDates' in this.options) { + DateUtil.convertHiddenOptions(this.body, this.options.hiddenDates); + } - var util = __webpack_require__(1); - var DOMutil = __webpack_require__(6); - var Line = __webpack_require__(47); - var Bar = __webpack_require__(49); - var Points = __webpack_require__(48); + if ('clickToUse' in options) { + if (options.clickToUse) { + if (!this.activator) { + this.activator = new Activator(this.dom.root); + } + } + else { + if (this.activator) { + this.activator.destroy(); + delete this.activator; + } + } + } - /** - * /** - * @param {object} group | the object of the group from the dataset - * @param {string} groupId | ID of the group - * @param {object} options | the default options - * @param {array} groupsUsingDefaultStyles | this array has one entree. - * It is passed as an array so it is passed by reference. - * It enumerates through the default styles - * @constructor - */ - function GraphGroup (group, groupId, options, groupsUsingDefaultStyles) { - this.id = groupId; - var fields = ['sampling','style','sort','yAxisOrientation','barChart','drawPoints','shaded','catmullRom'] - this.options = util.selectiveBridgeObject(fields,options); - this.usingDefaultStyle = group.className === undefined; - this.groupsUsingDefaultStyles = groupsUsingDefaultStyles; - this.zeroPosition = 0; - this.update(group); - if (this.usingDefaultStyle == true) { - this.groupsUsingDefaultStyles[0] += 1; + // enable/disable autoResize + this._initAutoResize(); } - this.itemsData = []; - this.visible = group.visible === undefined ? true : group.visible; - } + // propagate options to all components + this.components.forEach(function (component) { + component.setOptions(options); + }); - /** - * this loads a reference to all items in this group into this group. - * @param {array} items - */ - GraphGroup.prototype.setItems = function(items) { - if (items != null) { - this.itemsData = items; - if (this.options.sort == true) { - this.itemsData.sort(function (a,b) {return a.x - b.x;}) - } - } - else { - this.itemsData = []; + // TODO: remove deprecation error one day (deprecated since version 0.8.0) + if (options && options.order) { + throw new Error('Option order is deprecated. There is no replacement for this feature.'); } - }; + // redraw everything + this.redraw(); + }; /** - * this is used for plotting barcharts, this way, we only have to calculate it once. - * @param pos + * Returns true when the Timeline is active. + * @returns {boolean} */ - GraphGroup.prototype.setZeroPosition = function(pos) { - this.zeroPosition = pos; + Core.prototype.isActive = function () { + return !this.activator || this.activator.active; }; - /** - * set the options of the graph group over the default options. - * @param options + * Destroy the Core, clean up all DOM elements and event listeners. */ - GraphGroup.prototype.setOptions = function(options) { - if (options !== undefined) { - var fields = ['sampling','style','sort','yAxisOrientation','barChart']; - util.selectiveDeepExtend(fields, this.options, options); + Core.prototype.destroy = function () { + // unbind datasets + this.clear(); - util.mergeOptions(this.options, options,'catmullRom'); - util.mergeOptions(this.options, options,'drawPoints'); - util.mergeOptions(this.options, options,'shaded'); + // remove all event listeners + this.off(); - if (options.catmullRom) { - if (typeof options.catmullRom == 'object') { - if (options.catmullRom.parametrization) { - if (options.catmullRom.parametrization == 'uniform') { - this.options.catmullRom.alpha = 0; - } - else if (options.catmullRom.parametrization == 'chordal') { - this.options.catmullRom.alpha = 1.0; - } - else { - this.options.catmullRom.parametrization = 'centripetal'; - this.options.catmullRom.alpha = 0.5; - } - } - } - } - } + // stop checking for changed size + this._stopAutoResize(); - if (this.options.style == 'line') { - this.type = new Line(this.id, this.options); + // remove from DOM + if (this.dom.root.parentNode) { + this.dom.root.parentNode.removeChild(this.dom.root); } - else if (this.options.style == 'bar') { - this.type = new Bar(this.id, this.options); + this.dom = null; + + // remove Activator + if (this.activator) { + this.activator.destroy(); + delete this.activator; } - else if (this.options.style == 'points') { - this.type = new Points(this.id, this.options); + + // cleanup hammer touch events + for (var event in this.listeners) { + if (this.listeners.hasOwnProperty(event)) { + delete this.listeners[event]; + } } - }; + this.listeners = null; + this.hammer = null; + // give all components the opportunity to cleanup + this.components.forEach(function (component) { + component.destroy(); + }); - /** - * this updates the current group class with the latest group dataset entree, used in _updateGroup in linegraph - * @param group - */ - GraphGroup.prototype.update = function(group) { - this.group = group; - this.content = group.content || 'graph'; - this.className = group.className || this.className || "graphGroup" + this.groupsUsingDefaultStyles[0] % 10; - this.visible = group.visible === undefined ? true : group.visible; - this.style = group.style; - this.setOptions(group.options); + this.body = null; }; /** - * draw the icon for the legend. - * - * @param x - * @param y - * @param JSONcontainer - * @param SVGcontainer - * @param iconWidth - * @param iconHeight + * Set a custom time bar + * @param {Date} time */ - GraphGroup.prototype.drawIcon = function(x, y, JSONcontainer, SVGcontainer, iconWidth, iconHeight) { - var fillHeight = iconHeight * 0.5; - var path, fillPath; - - var outline = DOMutil.getSVGElement("rect", JSONcontainer, SVGcontainer); - outline.setAttributeNS(null, "x", x); - outline.setAttributeNS(null, "y", y - fillHeight); - outline.setAttributeNS(null, "width", iconWidth); - outline.setAttributeNS(null, "height", 2*fillHeight); - outline.setAttributeNS(null, "class", "outline"); - - if (this.options.style == 'line') { - path = DOMutil.getSVGElement("path", JSONcontainer, SVGcontainer); - path.setAttributeNS(null, "class", this.className); - if(this.style !== undefined) { - path.setAttributeNS(null, "style", this.style); - } - - path.setAttributeNS(null, "d", "M" + x + ","+y+" L" + (x + iconWidth) + ","+y+""); - if (this.options.shaded.enabled == true) { - fillPath = DOMutil.getSVGElement("path", JSONcontainer, SVGcontainer); - if (this.options.shaded.orientation == 'top') { - fillPath.setAttributeNS(null, "d", "M"+x+", " + (y - fillHeight) + - "L"+x+","+y+" L"+ (x + iconWidth) + ","+y+" L"+ (x + iconWidth) + "," + (y - fillHeight)); - } - else { - fillPath.setAttributeNS(null, "d", "M"+x+","+y+" " + - "L"+x+"," + (y + fillHeight) + " " + - "L"+ (x + iconWidth) + "," + (y + fillHeight) + - "L"+ (x + iconWidth) + ","+y); - } - fillPath.setAttributeNS(null, "class", this.className + " iconFill"); - } - - if (this.options.drawPoints.enabled == true) { - DOMutil.drawPoint(x + 0.5 * iconWidth,y, this, JSONcontainer, SVGcontainer); - } + Core.prototype.setCustomTime = function (time) { + if (!this.customTime) { + throw new Error('Cannot get custom time: Custom time bar is not enabled'); } - else { - var barWidth = Math.round(0.3 * iconWidth); - var bar1Height = Math.round(0.4 * iconHeight); - var bar2Height = Math.round(0.75 * iconHeight); - var offset = Math.round((iconWidth - (2 * barWidth))/3); - - DOMutil.drawBar(x + 0.5*barWidth + offset , y + fillHeight - bar1Height - 1, barWidth, bar1Height, this.className + ' bar', JSONcontainer, SVGcontainer); - DOMutil.drawBar(x + 1.5*barWidth + offset + 2, y + fillHeight - bar2Height - 1, barWidth, bar2Height, this.className + ' bar', JSONcontainer, SVGcontainer); - } + this.customTime.setCustomTime(time); }; - /** - * return the legend entree for this group. - * - * @param iconWidth - * @param iconHeight - * @returns {{icon: HTMLElement, label: (group.content|*|string), orientation: (.options.yAxisOrientation|*)}} + * Retrieve the current custom time. + * @return {Date} customTime */ - GraphGroup.prototype.getLegend = function(iconWidth, iconHeight) { - var svg = document.createElementNS('http://www.w3.org/2000/svg',"svg"); - this.drawIcon(0,0.5*iconHeight,[],svg,iconWidth,iconHeight); - return {icon: svg, label: this.content, orientation:this.options.yAxisOrientation}; - } - - GraphGroup.prototype.getYRange = function(groupData) { - return this.type.getYRange(groupData); - } - - GraphGroup.prototype.draw = function(dataset, group, framework) { - this.type.draw(dataset, group, framework); - } - - - module.exports = GraphGroup; + Core.prototype.getCustomTime = function() { + if (!this.customTime) { + throw new Error('Cannot get custom time: Custom time bar is not enabled'); + } + return this.customTime.getCustomTime(); + }; -/***/ }, -/* 47 */ -/***/ function(module, exports, __webpack_require__) { /** - * Created by Alex on 11/11/2014. + * Get the id's of the currently visible items. + * @returns {Array} The ids of the visible items */ - var DOMutil = __webpack_require__(6); - var Points = __webpack_require__(48); - - function Line(groupId, options) { - this.groupId = groupId; - this.options = options; - } - - Line.prototype.getYRange = function(groupData) { - var yMin = groupData[0].y; - var yMax = groupData[0].y; - for (var j = 0; j < groupData.length; j++) { - yMin = yMin > groupData[j].y ? groupData[j].y : yMin; - yMax = yMax < groupData[j].y ? groupData[j].y : yMax; - } - return {min: yMin, max: yMax, yAxisOrientation: this.options.yAxisOrientation}; + Core.prototype.getVisibleItems = function() { + return this.itemSet && this.itemSet.getVisibleItems() || []; }; + /** - * draw a line graph + * Clear the Core. By Default, items, groups and options are cleared. + * Example usage: * - * @param dataset - * @param group + * timeline.clear(); // clear items, groups, and options + * timeline.clear({options: true}); // clear options only + * + * @param {Object} [what] Optionally specify what to clear. By default: + * {items: true, groups: true, options: true} */ - Line.prototype.draw = function (dataset, group, framework) { - if (dataset != null) { - if (dataset.length > 0) { - var path, d; - var svgHeight = Number(framework.svg.style.height.replace('px','')); - path = DOMutil.getSVGElement('path', framework.svgElements, framework.svg); - path.setAttributeNS(null, "class", group.className); - if(group.style !== undefined) { - path.setAttributeNS(null, "style", group.style); - } + Core.prototype.clear = function(what) { + // clear items + if (!what || what.items) { + this.setItems(null); + } - // construct path from dataset - if (group.options.catmullRom.enabled == true) { - d = Line._catmullRom(dataset, group); - } - else { - d = Line._linear(dataset); - } + // clear groups + if (!what || what.groups) { + this.setGroups(null); + } - // append with points for fill and finalize the path - if (group.options.shaded.enabled == true) { - var fillPath = DOMutil.getSVGElement('path', framework.svgElements, framework.svg); - var dFill; - if (group.options.shaded.orientation == 'top') { - dFill = 'M' + dataset[0].x + ',' + 0 + ' ' + d + 'L' + dataset[dataset.length - 1].x + ',' + 0; - } - else { - dFill = 'M' + dataset[0].x + ',' + svgHeight + ' ' + d + 'L' + dataset[dataset.length - 1].x + ',' + svgHeight; - } - fillPath.setAttributeNS(null, "class", group.className + " fill"); - if(group.options.shaded.style !== undefined) { - fillPath.setAttributeNS(null, "style", group.options.shaded.style); - } - fillPath.setAttributeNS(null, "d", dFill); - } - // copy properties to path for drawing. - path.setAttributeNS(null, 'd', 'M' + d); + // clear options of timeline and of each of the components + if (!what || what.options) { + this.components.forEach(function (component) { + component.setOptions(component.defaultOptions); + }); - // draw points - if (group.options.drawPoints.enabled == true) { - Points.draw(dataset, group, framework); - } - } + this.setOptions(this.defaultOptions); // this will also do a redraw } }; - - /** - * This uses an uniform parametrization of the CatmullRom algorithm: - * 'On the Parameterization of Catmull-Rom Curves' by Cem Yuksel et al. - * @param data - * @returns {string} - * @private + * Set Core window such that it fits all items + * @param {Object} [options] Available options: + * `animate: boolean | number` + * If true (default), the range is animated + * smoothly to the new window. + * If a number, the number is taken as duration + * for the animation. Default duration is 500 ms. */ - Line._catmullRomUniform = function(data) { - // catmull rom - var p0, p1, p2, p3, bp1, bp2; - var d = Math.round(data[0].x) + ',' + Math.round(data[0].y) + ' '; - var normalization = 1/6; - var length = data.length; - for (var i = 0; i < length - 1; i++) { - - p0 = (i == 0) ? data[0] : data[i-1]; - p1 = data[i]; - p2 = data[i+1]; - p3 = (i + 2 < length) ? data[i+2] : p2; - - - // Catmull-Rom to Cubic Bezier conversion matrix - // 0 1 0 0 - // -1/6 1 1/6 0 - // 0 1/6 1 -1/6 - // 0 0 1 0 - - // bp0 = { x: p1.x, y: p1.y }; - bp1 = { x: ((-p0.x + 6*p1.x + p2.x) *normalization), y: ((-p0.y + 6*p1.y + p2.y) *normalization)}; - bp2 = { x: (( p1.x + 6*p2.x - p3.x) *normalization), y: (( p1.y + 6*p2.y - p3.y) *normalization)}; - // bp0 = { x: p2.x, y: p2.y }; + Core.prototype.fit = function(options) { + var range = this._getDataRange(); - d += 'C' + - bp1.x + ',' + - bp1.y + ' ' + - bp2.x + ',' + - bp2.y + ' ' + - p2.x + ',' + - p2.y + ' '; + // skip range set if there is no start and end date + if (range.start === null && range.end === null) { + return; } - return d; + var animate = (options && options.animate !== undefined) ? options.animate : true; + this.range.setRange(range.start, range.end, animate); }; /** - * This uses either the chordal or centripetal parameterization of the catmull-rom algorithm. - * By default, the centripetal parameterization is used because this gives the nicest results. - * These parameterizations are relatively heavy because the distance between 4 points have to be calculated. - * - * One optimization can be used to reuse distances since this is a sliding window approach. - * @param data - * @param group - * @returns {string} - * @private + * Calculate the data range of the items and applies a 5% window around it. + * @returns {{start: Date | null, end: Date | null}} + * @protected */ - Line._catmullRom = function(data, group) { - var alpha = group.options.catmullRom.alpha; - if (alpha == 0 || alpha === undefined) { - return this._catmullRomUniform(data); - } - else { - var p0, p1, p2, p3, bp1, bp2, d1,d2,d3, A, B, N, M; - var d3powA, d2powA, d3pow2A, d2pow2A, d1pow2A, d1powA; - var d = Math.round(data[0].x) + ',' + Math.round(data[0].y) + ' '; - var length = data.length; - for (var i = 0; i < length - 1; i++) { - - p0 = (i == 0) ? data[0] : data[i-1]; - p1 = data[i]; - p2 = data[i+1]; - p3 = (i + 2 < length) ? data[i+2] : p2; - - d1 = Math.sqrt(Math.pow(p0.x - p1.x,2) + Math.pow(p0.y - p1.y,2)); - d2 = Math.sqrt(Math.pow(p1.x - p2.x,2) + Math.pow(p1.y - p2.y,2)); - d3 = Math.sqrt(Math.pow(p2.x - p3.x,2) + Math.pow(p2.y - p3.y,2)); - - // Catmull-Rom to Cubic Bezier conversion matrix - - // A = 2d1^2a + 3d1^a * d2^a + d3^2a - // B = 2d3^2a + 3d3^a * d2^a + d2^2a - - // [ 0 1 0 0 ] - // [ -d2^2a /N A/N d1^2a /N 0 ] - // [ 0 d3^2a /M B/M -d2^2a /M ] - // [ 0 0 1 0 ] - - d3powA = Math.pow(d3, alpha); - d3pow2A = Math.pow(d3,2*alpha); - d2powA = Math.pow(d2, alpha); - d2pow2A = Math.pow(d2,2*alpha); - d1powA = Math.pow(d1, alpha); - d1pow2A = Math.pow(d1,2*alpha); - - A = 2*d1pow2A + 3*d1powA * d2powA + d2pow2A; - B = 2*d3pow2A + 3*d3powA * d2powA + d2pow2A; - N = 3*d1powA * (d1powA + d2powA); - if (N > 0) {N = 1 / N;} - M = 3*d3powA * (d3powA + d2powA); - if (M > 0) {M = 1 / M;} - - bp1 = { x: ((-d2pow2A * p0.x + A*p1.x + d1pow2A * p2.x) * N), - y: ((-d2pow2A * p0.y + A*p1.y + d1pow2A * p2.y) * N)}; - - bp2 = { x: (( d3pow2A * p1.x + B*p2.x - d2pow2A * p3.x) * M), - y: (( d3pow2A * p1.y + B*p2.y - d2pow2A * p3.y) * M)}; - - if (bp1.x == 0 && bp1.y == 0) {bp1 = p1;} - if (bp2.x == 0 && bp2.y == 0) {bp2 = p2;} - d += 'C' + - bp1.x + ',' + - bp1.y + ' ' + - bp2.x + ',' + - bp2.y + ' ' + - p2.x + ',' + - p2.y + ' '; + Core.prototype._getDataRange = function() { + // apply the data range as range + var dataRange = this.getItemRange(); + + // add 5% space on both sides + var start = dataRange.min; + var end = dataRange.max; + if (start != null && end != null) { + var interval = (end.valueOf() - start.valueOf()); + if (interval <= 0) { + // prevent an empty interval + interval = 24 * 60 * 60 * 1000; // 1 day } + start = new Date(start.valueOf() - interval * 0.05); + end = new Date(end.valueOf() + interval * 0.05); + } - return d; + return { + start: start, + end: end } }; /** - * this generates the SVG path for a linear drawing between datapoints. - * @param data - * @returns {string} - * @private + * Set the visible window. Both parameters are optional, you can change only + * start or only end. Syntax: + * + * TimeLine.setWindow(start, end) + * TimeLine.setWindow(range) + * + * Where start and end can be a Date, number, or string, and range is an + * object with properties start and end. + * + * @param {Date | Number | String | Object} [start] Start date of visible window + * @param {Date | Number | String} [end] End date of visible window + * @param {Object} [options] Available options: + * `animate: boolean | number` + * If true (default), the range is animated + * smoothly to the new window. + * If a number, the number is taken as duration + * for the animation. Default duration is 500 ms. */ - Line._linear = function(data) { - // linear - var d = ''; - for (var i = 0; i < data.length; i++) { - if (i == 0) { - d += data[i].x + ',' + data[i].y; - } - else { - d += ' ' + data[i].x + ',' + data[i].y; - } + Core.prototype.setWindow = function(start, end, options) { + var animate = (options && options.animate !== undefined) ? options.animate : true; + if (arguments.length == 1) { + var range = arguments[0]; + this.range.setRange(range.start, range.end, animate); + } + else { + this.range.setRange(start, end, animate); } - return d; }; - module.exports = Line; - - -/***/ }, -/* 48 */ -/***/ function(module, exports, __webpack_require__) { - /** - * Created by Alex on 11/11/2014. + * Move the window such that given time is centered on screen. + * @param {Date | Number | String} time + * @param {Object} [options] Available options: + * `animate: boolean | number` + * If true (default), the range is animated + * smoothly to the new window. + * If a number, the number is taken as duration + * for the animation. Default duration is 500 ms. */ - var DOMutil = __webpack_require__(6); - - function Points(groupId, options) { - this.groupId = groupId; - this.options = options; - } + Core.prototype.moveTo = function(time, options) { + var interval = this.range.end - this.range.start; + var t = util.convert(time, 'Date').valueOf(); + var start = t - interval / 2; + var end = t + interval / 2; + var animate = (options && options.animate !== undefined) ? options.animate : true; - Points.prototype.getYRange = function(groupData) { - var yMin = groupData[0].y; - var yMax = groupData[0].y; - for (var j = 0; j < groupData.length; j++) { - yMin = yMin > groupData[j].y ? groupData[j].y : yMin; - yMax = yMax < groupData[j].y ? groupData[j].y : yMax; - } - return {min: yMin, max: yMax, yAxisOrientation: this.options.yAxisOrientation}; + this.range.setRange(start, end, animate); }; - Points.prototype.draw = function(dataset, group, framework, offset) { - Points.draw(dataset, group, framework, offset); - } - /** - * draw the data points - * - * @param {Array} dataset - * @param {Object} JSONcontainer - * @param {Object} svg | SVG DOM element - * @param {GraphGroup} group - * @param {Number} [offset] + * Get the visible window + * @return {{start: Date, end: Date}} Visible range */ - Points.draw = function (dataset, group, framework, offset) { - if (offset === undefined) {offset = 0;} - for (var i = 0; i < dataset.length; i++) { - DOMutil.drawPoint(dataset[i].x + offset, dataset[i].y, group, framework.svgElements, framework.svg); - } + Core.prototype.getWindow = function() { + var range = this.range.getRange(); + return { + start: new Date(range.start), + end: new Date(range.end) + }; }; - - module.exports = Points; - -/***/ }, -/* 49 */ -/***/ function(module, exports, __webpack_require__) { - /** - * Created by Alex on 11/11/2014. + * Force a redraw of the Core. Can be useful to manually redraw when + * option autoResize=false */ - var DOMutil = __webpack_require__(6); - var Points = __webpack_require__(48); + Core.prototype.redraw = function() { + var resized = false; + var options = this.options; + var props = this.props; + var dom = this.dom; - function Bargraph(groupId, options) { - this.groupId = groupId; - this.options = options; - } + if (!dom) return; // when destroyed - Bargraph.prototype.getYRange = function(groupData) { - if (this.options.barChart.handleOverlap != 'stack') { - var yMin = groupData[0].y; - var yMax = groupData[0].y; - for (var j = 0; j < groupData.length; j++) { - yMin = yMin > groupData[j].y ? groupData[j].y : yMin; - yMax = yMax < groupData[j].y ? groupData[j].y : yMax; - } - return {min: yMin, max: yMax, yAxisOrientation: this.options.yAxisOrientation}; + DateUtil.updateHiddenDates(this.body, this.options.hiddenDates); + + // update class names + if (options.orientation == 'top') { + util.addClassName(dom.root, 'top'); + util.removeClassName(dom.root, 'bottom'); } else { - var barCombinedData = []; - for (var j = 0; j < groupData.length; j++) { - barCombinedData.push({ - x: groupData[j].x, - y: groupData[j].y, - groupId: this.groupId - }); - } - return barCombinedData; + util.removeClassName(dom.root, 'top'); + util.addClassName(dom.root, 'bottom'); } - }; - + // update root width and height options + dom.root.style.maxHeight = util.option.asSize(options.maxHeight, ''); + dom.root.style.minHeight = util.option.asSize(options.minHeight, ''); + dom.root.style.width = util.option.asSize(options.width, ''); - /** - * draw a bar graph - * - * @param groupIds - * @param processedGroupData - */ - Bargraph.draw = function (groupIds, processedGroupData, framework) { - var combinedData = []; - var intersections = {}; - var coreDistance; - var key, drawData; - var group; - var i,j; - var barPoints = 0; + // calculate border widths + props.border.left = (dom.centerContainer.offsetWidth - dom.centerContainer.clientWidth) / 2; + props.border.right = props.border.left; + props.border.top = (dom.centerContainer.offsetHeight - dom.centerContainer.clientHeight) / 2; + props.border.bottom = props.border.top; + var borderRootHeight= dom.root.offsetHeight - dom.root.clientHeight; + var borderRootWidth = dom.root.offsetWidth - dom.root.clientWidth; - // combine all barchart data - for (i = 0; i < groupIds.length; i++) { - group = framework.groups[groupIds[i]]; - if (group.options.style == 'bar') { - if (group.visible == true && (framework.options.groups.visibility[groupIds[i]] === undefined || framework.options.groups.visibility[groupIds[i]] == true)) { - for (j = 0; j < processedGroupData[groupIds[i]].length; j++) { - combinedData.push({ - x: processedGroupData[groupIds[i]][j].x, - y: processedGroupData[groupIds[i]][j].y, - groupId: groupIds[i] - }); - barPoints += 1; - } - } - } + // workaround for a bug in IE: the clientWidth of an element with + // a height:0px and overflow:hidden is not calculated and always has value 0 + if (dom.centerContainer.clientHeight === 0) { + props.border.left = props.border.top; + props.border.right = props.border.left; + } + if (dom.root.clientHeight === 0) { + borderRootWidth = borderRootHeight; } - if (barPoints == 0) {return;} - - // sort by time and by group - combinedData.sort(function (a, b) { - if (a.x == b.x) { - return a.groupId - b.groupId; - } else { - return a.x - b.x; - } - }); + // calculate the heights. If any of the side panels is empty, we set the height to + // minus the border width, such that the border will be invisible + props.center.height = dom.center.offsetHeight; + props.left.height = dom.left.offsetHeight; + props.right.height = dom.right.offsetHeight; + props.top.height = dom.top.clientHeight || -props.border.top; + props.bottom.height = dom.bottom.clientHeight || -props.border.bottom; - // get intersections - Bargraph._getDataIntersections(intersections, combinedData); + // TODO: compensate borders when any of the panels is empty. - // plot barchart - for (i = 0; i < combinedData.length; i++) { - group = framework.groups[combinedData[i].groupId]; - var minWidth = 0.1 * group.options.barChart.width; + // apply auto height + // TODO: only calculate autoHeight when needed (else we cause an extra reflow/repaint of the DOM) + var contentHeight = Math.max(props.left.height, props.center.height, props.right.height); + var autoHeight = props.top.height + contentHeight + props.bottom.height + + borderRootHeight + props.border.top + props.border.bottom; + dom.root.style.height = util.option.asSize(options.height, autoHeight + 'px'); - key = combinedData[i].x; - var heightOffset = 0; - if (intersections[key] === undefined) { - if (i+1 < combinedData.length) {coreDistance = Math.abs(combinedData[i+1].x - key);} - if (i > 0) {coreDistance = Math.min(coreDistance,Math.abs(combinedData[i-1].x - key));} - drawData = Bargraph._getSafeDrawData(coreDistance, group, minWidth); - } - else { - var nextKey = i + (intersections[key].amount - intersections[key].resolved); - var prevKey = i - (intersections[key].resolved + 1); - if (nextKey < combinedData.length) {coreDistance = Math.abs(combinedData[nextKey].x - key);} - if (prevKey > 0) {coreDistance = Math.min(coreDistance,Math.abs(combinedData[prevKey].x - key));} - drawData = Bargraph._getSafeDrawData(coreDistance, group, minWidth); - intersections[key].resolved += 1; + // calculate heights of the content panels + props.root.height = dom.root.offsetHeight; + props.background.height = props.root.height - borderRootHeight; + var containerHeight = props.root.height - props.top.height - props.bottom.height - + borderRootHeight; + props.centerContainer.height = containerHeight; + props.leftContainer.height = containerHeight; + props.rightContainer.height = props.leftContainer.height; - if (group.options.barChart.handleOverlap == 'stack') { - heightOffset = intersections[key].accumulated; - intersections[key].accumulated += group.zeroPosition - combinedData[i].y; - } - else if (group.options.barChart.handleOverlap == 'sideBySide') { - drawData.width = drawData.width / intersections[key].amount; - drawData.offset += (intersections[key].resolved) * drawData.width - (0.5*drawData.width * (intersections[key].amount+1)); - if (group.options.barChart.align == 'left') {drawData.offset -= 0.5*drawData.width;} - else if (group.options.barChart.align == 'right') {drawData.offset += 0.5*drawData.width;} - } - } - DOMutil.drawBar(combinedData[i].x + drawData.offset, combinedData[i].y - heightOffset, drawData.width, group.zeroPosition - combinedData[i].y, group.className + ' bar', framework.svgElements, framework.svg); - // draw points - if (group.options.drawPoints.enabled == true) { - DOMutil.drawPoint(combinedData[i].x + drawData.offset, combinedData[i].y, group, framework.svgElements, framework.svg); - } - } - }; + // calculate the widths of the panels + props.root.width = dom.root.offsetWidth; + props.background.width = props.root.width - borderRootWidth; + props.left.width = dom.leftContainer.clientWidth || -props.border.left; + props.leftContainer.width = props.left.width; + props.right.width = dom.rightContainer.clientWidth || -props.border.right; + props.rightContainer.width = props.right.width; + var centerWidth = props.root.width - props.left.width - props.right.width - borderRootWidth; + props.center.width = centerWidth; + props.centerContainer.width = centerWidth; + props.top.width = centerWidth; + props.bottom.width = centerWidth; + // resize the panels + dom.background.style.height = props.background.height + 'px'; + dom.backgroundVertical.style.height = props.background.height + 'px'; + dom.backgroundHorizontal.style.height = props.centerContainer.height + 'px'; + dom.centerContainer.style.height = props.centerContainer.height + 'px'; + dom.leftContainer.style.height = props.leftContainer.height + 'px'; + dom.rightContainer.style.height = props.rightContainer.height + 'px'; - /** - * Fill the intersections object with counters of how many datapoints share the same x coordinates - * @param intersections - * @param combinedData - * @private - */ - Bargraph._getDataIntersections = function (intersections, combinedData) { - // get intersections - var coreDistance; - for (var i = 0; i < combinedData.length; i++) { - if (i + 1 < combinedData.length) { - coreDistance = Math.abs(combinedData[i + 1].x - combinedData[i].x); - } - if (i > 0) { - coreDistance = Math.min(coreDistance, Math.abs(combinedData[i - 1].x - combinedData[i].x)); - } - if (coreDistance == 0) { - if (intersections[combinedData[i].x] === undefined) { - intersections[combinedData[i].x] = {amount: 0, resolved: 0, accumulated: 0}; - } - intersections[combinedData[i].x].amount += 1; - } - } - }; + dom.background.style.width = props.background.width + 'px'; + dom.backgroundVertical.style.width = props.centerContainer.width + 'px'; + dom.backgroundHorizontal.style.width = props.background.width + 'px'; + dom.centerContainer.style.width = props.center.width + 'px'; + dom.top.style.width = props.top.width + 'px'; + dom.bottom.style.width = props.bottom.width + 'px'; + // reposition the panels + dom.background.style.left = '0'; + dom.background.style.top = '0'; + dom.backgroundVertical.style.left = (props.left.width + props.border.left) + 'px'; + dom.backgroundVertical.style.top = '0'; + dom.backgroundHorizontal.style.left = '0'; + dom.backgroundHorizontal.style.top = props.top.height + 'px'; + dom.centerContainer.style.left = props.left.width + 'px'; + dom.centerContainer.style.top = props.top.height + 'px'; + dom.leftContainer.style.left = '0'; + dom.leftContainer.style.top = props.top.height + 'px'; + dom.rightContainer.style.left = (props.left.width + props.center.width) + 'px'; + dom.rightContainer.style.top = props.top.height + 'px'; + dom.top.style.left = props.left.width + 'px'; + dom.top.style.top = '0'; + dom.bottom.style.left = props.left.width + 'px'; + dom.bottom.style.top = (props.top.height + props.centerContainer.height) + 'px'; - /** - * Get the width and offset for bargraphs based on the coredistance between datapoints - * - * @param coreDistance - * @param group - * @param minWidth - * @returns {{width: Number, offset: Number}} - * @private - */ - Bargraph._getSafeDrawData = function (coreDistance, group, minWidth) { - var width, offset; - if (coreDistance < group.options.barChart.width && coreDistance > 0) { - width = coreDistance < minWidth ? minWidth : coreDistance; + // update the scrollTop, feasible range for the offset can be changed + // when the height of the Core or of the contents of the center changed + this._updateScrollTop(); - offset = 0; // recalculate offset with the new width; - if (group.options.barChart.align == 'left') { - offset -= 0.5 * coreDistance; - } - else if (group.options.barChart.align == 'right') { - offset += 0.5 * coreDistance; - } - } - else { - // default settings - width = group.options.barChart.width; - offset = 0; - if (group.options.barChart.align == 'left') { - offset -= 0.5 * group.options.barChart.width; - } - else if (group.options.barChart.align == 'right') { - offset += 0.5 * group.options.barChart.width; - } + // reposition the scrollable contents + var offset = this.props.scrollTop; + if (options.orientation == 'bottom') { + offset += Math.max(this.props.centerContainer.height - this.props.center.height - + this.props.border.top - this.props.border.bottom, 0); } + dom.center.style.left = '0'; + dom.center.style.top = offset + 'px'; + dom.left.style.left = '0'; + dom.left.style.top = offset + 'px'; + dom.right.style.left = '0'; + dom.right.style.top = offset + 'px'; - return {width: width, offset: offset}; - }; - - Bargraph.getStackedBarYRange = function(barCombinedData, groupRanges, groupIds, groupLabel, orientation) { - if (barCombinedData.length > 0) { - // sort by time and by group - barCombinedData.sort(function (a, b) { - if (a.x == b.x) { - return a.groupId - b.groupId; - } else { - return a.x - b.x; - } - }); - var intersections = {}; - - Bargraph._getDataIntersections(intersections, barCombinedData); - groupRanges[groupLabel] = Bargraph._getStackedBarYRange(intersections, barCombinedData); - groupRanges[groupLabel].yAxisOrientation = orientation; - groupIds.push(groupLabel); - } - } + // show shadows when vertical scrolling is available + var visibilityTop = this.props.scrollTop == 0 ? 'hidden' : ''; + var visibilityBottom = this.props.scrollTop == this.props.scrollTopMin ? 'hidden' : ''; + dom.shadowTop.style.visibility = visibilityTop; + dom.shadowBottom.style.visibility = visibilityBottom; + dom.shadowTopLeft.style.visibility = visibilityTop; + dom.shadowBottomLeft.style.visibility = visibilityBottom; + dom.shadowTopRight.style.visibility = visibilityTop; + dom.shadowBottomRight.style.visibility = visibilityBottom; - Bargraph._getStackedBarYRange = function (intersections, combinedData) { - var key; - var yMin = combinedData[0].y; - var yMax = combinedData[0].y; - for (var i = 0; i < combinedData.length; i++) { - key = combinedData[i].x; - if (intersections[key] === undefined) { - yMin = yMin > combinedData[i].y ? combinedData[i].y : yMin; - yMax = yMax < combinedData[i].y ? combinedData[i].y : yMax; + // redraw all components + this.components.forEach(function (component) { + resized = component.redraw() || resized; + }); + if (resized) { + // keep repainting until all sizes are settled + var MAX_REDRAWS = 3; // maximum number of consecutive redraws + if (this.redrawCount < MAX_REDRAWS) { + this.redrawCount++; + this.redraw(); } else { - intersections[key].accumulated += combinedData[i].y; - } - } - for (var xpos in intersections) { - if (intersections.hasOwnProperty(xpos)) { - yMin = yMin > intersections[xpos].accumulated ? intersections[xpos].accumulated : yMin; - yMax = yMax < intersections[xpos].accumulated ? intersections[xpos].accumulated : yMax; + console.log('WARNING: infinite loop in redraw?'); } + this.redrawCount = 0; } - return {min: yMin, max: yMax}; + this.emit("finishedRedraw"); }; - module.exports = Bargraph; - -/***/ }, -/* 50 */ -/***/ function(module, exports, __webpack_require__) { - - var util = __webpack_require__(1); - var DOMutil = __webpack_require__(6); - var Component = __webpack_require__(23); + // TODO: deprecated since version 1.1.0, remove some day + Core.prototype.repaint = function () { + throw new Error('Function repaint is deprecated. Use redraw instead.'); + }; /** - * Legend for Graph2d + * Set a current time. This can be used for example to ensure that a client's + * time is synchronized with a shared server time. + * Only applicable when option `showCurrentTime` is true. + * @param {Date | String | Number} time A Date, unix timestamp, or + * ISO date string. */ - function Legend(body, options, side, linegraphOptions) { - this.body = body; - this.defaultOptions = { - enabled: true, - icons: true, - iconSize: 20, - iconSpacing: 6, - left: { - visible: true, - position: 'top-left' // top/bottom - left,center,right - }, - right: { - visible: true, - position: 'top-left' // top/bottom - left,center,right - } - } - this.side = side; - this.options = util.extend({},this.defaultOptions); - this.linegraphOptions = linegraphOptions; - - this.svgElements = {}; - this.dom = {}; - this.groups = {}; - this.amountOfGroups = 0; - this._create(); - - this.setOptions(options); - } - - Legend.prototype = new Component(); - - Legend.prototype.clear = function() { - this.groups = {}; - this.amountOfGroups = 0; - } - - Legend.prototype.addGroup = function(label, graphOptions) { - - if (!this.groups.hasOwnProperty(label)) { - this.groups[label] = graphOptions; + Core.prototype.setCurrentTime = function(time) { + if (!this.currentTime) { + throw new Error('Option showCurrentTime must be true'); } - this.amountOfGroups += 1; - }; - Legend.prototype.updateGroup = function(label, graphOptions) { - this.groups[label] = graphOptions; + this.currentTime.setCurrentTime(time); }; - Legend.prototype.removeGroup = function(label) { - if (this.groups.hasOwnProperty(label)) { - delete this.groups[label]; - this.amountOfGroups -= 1; + /** + * Get the current time. + * Only applicable when option `showCurrentTime` is true. + * @return {Date} Returns the current time. + */ + Core.prototype.getCurrentTime = function() { + if (!this.currentTime) { + throw new Error('Option showCurrentTime must be true'); } - }; - - Legend.prototype._create = function() { - this.dom.frame = document.createElement('div'); - this.dom.frame.className = 'legend'; - this.dom.frame.style.position = "absolute"; - this.dom.frame.style.top = "10px"; - this.dom.frame.style.display = "block"; - - this.dom.textArea = document.createElement('div'); - this.dom.textArea.className = 'legendText'; - this.dom.textArea.style.position = "relative"; - this.dom.textArea.style.top = "0px"; - this.svg = document.createElementNS('http://www.w3.org/2000/svg',"svg"); - this.svg.style.position = 'absolute'; - this.svg.style.top = 0 +'px'; - this.svg.style.width = this.options.iconSize + 5 + 'px'; - this.svg.style.height = '100%'; + return this.currentTime.getCurrentTime(); + }; - this.dom.frame.appendChild(this.svg); - this.dom.frame.appendChild(this.dom.textArea); + /** + * Convert a position on screen (pixels) to a datetime + * @param {int} x Position on the screen in pixels + * @return {Date} time The datetime the corresponds with given position x + * @private + */ + // TODO: move this function to Range + Core.prototype._toTime = function(x) { + return DateUtil.toTime(this, x, this.props.center.width); }; /** - * Hide the component from the DOM + * Convert a position on the global screen (pixels) to a datetime + * @param {int} x Position on the screen in pixels + * @return {Date} time The datetime the corresponds with given position x + * @private */ - Legend.prototype.hide = function() { - // remove the frame containing the items - if (this.dom.frame.parentNode) { - this.dom.frame.parentNode.removeChild(this.dom.frame); - } + // TODO: move this function to Range + Core.prototype._toGlobalTime = function(x) { + return DateUtil.toTime(this, x, this.props.root.width); + //var conversion = this.range.conversion(this.props.root.width); + //return new Date(x / conversion.scale + conversion.offset); }; /** - * Show the component in the DOM (when not already visible). - * @return {Boolean} changed + * Convert a datetime (Date object) into a position on the screen + * @param {Date} time A date + * @return {int} x The position on the screen in pixels which corresponds + * with the given date. + * @private */ - Legend.prototype.show = function() { - // show frame containing the items - if (!this.dom.frame.parentNode) { - this.body.dom.center.appendChild(this.dom.frame); - } + // TODO: move this function to Range + Core.prototype._toScreen = function(time) { + return DateUtil.toScreen(this, time, this.props.center.width); }; - Legend.prototype.setOptions = function(options) { - var fields = ['enabled','orientation','icons','left','right']; - util.selectiveDeepExtend(fields, this.options, options); + + + /** + * Convert a datetime (Date object) into a position on the root + * This is used to get the pixel density estimate for the screen, not the center panel + * @param {Date} time A date + * @return {int} x The position on root in pixels which corresponds + * with the given date. + * @private + */ + // TODO: move this function to Range + Core.prototype._toGlobalScreen = function(time) { + return DateUtil.toScreen(this, time, this.props.root.width); + //var conversion = this.range.conversion(this.props.root.width); + //return (time.valueOf() - conversion.offset) * conversion.scale; }; - Legend.prototype.redraw = function() { - var activeGroups = 0; - for (var groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) { - activeGroups++; - } - } - } - if (this.options[this.side].visible == false || this.amountOfGroups == 0 || this.options.enabled == false || activeGroups == 0) { - this.hide(); + /** + * Initialize watching when option autoResize is true + * @private + */ + Core.prototype._initAutoResize = function () { + if (this.options.autoResize == true) { + this._startAutoResize(); } else { - this.show(); - if (this.options[this.side].position == 'top-left' || this.options[this.side].position == 'bottom-left') { - this.dom.frame.style.left = '4px'; - this.dom.frame.style.textAlign = "left"; - this.dom.textArea.style.textAlign = "left"; - this.dom.textArea.style.left = (this.options.iconSize + 15) + 'px'; - this.dom.textArea.style.right = ''; - this.svg.style.left = 0 +'px'; - this.svg.style.right = ''; - } - else { - this.dom.frame.style.right = '4px'; - this.dom.frame.style.textAlign = "right"; - this.dom.textArea.style.textAlign = "right"; - this.dom.textArea.style.right = (this.options.iconSize + 15) + 'px'; - this.dom.textArea.style.left = ''; - this.svg.style.right = 0 +'px'; - this.svg.style.left = ''; - } + this._stopAutoResize(); + } + }; - if (this.options[this.side].position == 'top-left' || this.options[this.side].position == 'top-right') { - this.dom.frame.style.top = 4 - Number(this.body.dom.center.style.top.replace("px","")) + 'px'; - this.dom.frame.style.bottom = ''; - } - else { - var scrollableHeight = this.body.domProps.center.height - this.body.domProps.centerContainer.height; - this.dom.frame.style.bottom = 4 + scrollableHeight + Number(this.body.dom.center.style.top.replace("px","")) + 'px'; - this.dom.frame.style.top = ''; - } + /** + * Watch for changes in the size of the container. On resize, the Panel will + * automatically redraw itself. + * @private + */ + Core.prototype._startAutoResize = function () { + var me = this; - if (this.options.icons == false) { - this.dom.frame.style.width = this.dom.textArea.offsetWidth + 10 + 'px'; - this.dom.textArea.style.right = ''; - this.dom.textArea.style.left = ''; - this.svg.style.width = '0px'; - } - else { - this.dom.frame.style.width = this.options.iconSize + 15 + this.dom.textArea.offsetWidth + 10 + 'px' - this.drawLegendIcons(); + this._stopAutoResize(); + + this._onResize = function() { + if (me.options.autoResize != true) { + // stop watching when the option autoResize is changed to false + me._stopAutoResize(); + return; } - var content = ''; - for (var groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) { - content += this.groups[groupId].content + '
'; - } + if (me.dom.root) { + // check whether the frame is resized + // Note: we compare offsetWidth here, not clientWidth. For some reason, + // IE does not restore the clientWidth from 0 to the actual width after + // changing the timeline's container display style from none to visible + if ((me.dom.root.offsetWidth != me.props.lastWidth) || + (me.dom.root.offsetHeight != me.props.lastHeight)) { + me.props.lastWidth = me.dom.root.offsetWidth; + me.props.lastHeight = me.dom.root.offsetHeight; + + me.emit('change'); } } - this.dom.textArea.innerHTML = content; - this.dom.textArea.style.lineHeight = ((0.75 * this.options.iconSize) + this.options.iconSpacing) + 'px'; - } + }; + + // add event listener to window resize + util.addEventListener(window, 'resize', this._onResize); + + this.watchTimer = setInterval(this._onResize, 1000); }; - Legend.prototype.drawLegendIcons = function() { - if (this.dom.frame.parentNode) { - DOMutil.prepareElements(this.svgElements); - var padding = window.getComputedStyle(this.dom.frame).paddingTop; - var iconOffset = Number(padding.replace('px','')); - var x = iconOffset; - var iconWidth = this.options.iconSize; - var iconHeight = 0.75 * this.options.iconSize; - var y = iconOffset + 0.5 * iconHeight + 3; + /** + * Stop watching for a resize of the frame. + * @private + */ + Core.prototype._stopAutoResize = function () { + if (this.watchTimer) { + clearInterval(this.watchTimer); + this.watchTimer = undefined; + } - this.svg.style.width = iconWidth + 5 + iconOffset + 'px'; + // remove event listener on window.resize + util.removeEventListener(window, 'resize', this._onResize); + this._onResize = null; + }; - for (var groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) { - this.groups[groupId].drawIcon(x, y, this.svgElements, this.svg, iconWidth, iconHeight); - y += iconHeight + this.options.iconSpacing; - } - } - } + /** + * Start moving the timeline vertically + * @param {Event} event + * @private + */ + Core.prototype._onTouch = function (event) { + this.touch.allowDragging = true; + }; - DOMutil.cleanupElements(this.svgElements); - } + /** + * Start moving the timeline vertically + * @param {Event} event + * @private + */ + Core.prototype._onPinch = function (event) { + this.touch.allowDragging = false; }; - module.exports = Legend; + /** + * Start moving the timeline vertically + * @param {Event} event + * @private + */ + Core.prototype._onDragStart = function (event) { + this.touch.initialScrollTop = this.props.scrollTop; + }; + + /** + * Move the timeline vertically + * @param {Event} event + * @private + */ + Core.prototype._onDrag = function (event) { + // refuse to drag when we where pinching to prevent the timeline make a jump + // when releasing the fingers in opposite order from the touch screen + if (!this.touch.allowDragging) return; + var delta = event.gesture.deltaY; -/***/ }, -/* 51 */ -/***/ function(module, exports, __webpack_require__) { + var oldScrollTop = this._getScrollTop(); + var newScrollTop = this._setScrollTop(this.touch.initialScrollTop + delta); - var Emitter = __webpack_require__(11); - var Hammer = __webpack_require__(19); - var keycharm = __webpack_require__(36); - var util = __webpack_require__(1); - var hammerUtil = __webpack_require__(22); - var DataSet = __webpack_require__(7); - var DataView = __webpack_require__(9); - var dotparser = __webpack_require__(52); - var gephiParser = __webpack_require__(53); - var Groups = __webpack_require__(54); - var Images = __webpack_require__(55); - var Node = __webpack_require__(56); - var Edge = __webpack_require__(57); - var Popup = __webpack_require__(58); - var MixinLoader = __webpack_require__(59); - var Activator = __webpack_require__(35); - var locales = __webpack_require__(70); - // Load custom shapes into CanvasRenderingContext2D - __webpack_require__(71); + if (newScrollTop != oldScrollTop) { + this.redraw(); // TODO: this causes two redraws when dragging, the other is triggered by rangechange already + this.emit("verticalDrag"); + } + }; /** - * @constructor Network - * Create a network visualization, displaying nodes and edges. - * - * @param {Element} container The DOM element in which the Network will - * be created. Normally a div element. - * @param {Object} data An object containing parameters - * {Array} nodes - * {Array} edges - * @param {Object} options Options + * Apply a scrollTop + * @param {Number} scrollTop + * @returns {Number} scrollTop Returns the applied scrollTop + * @private */ - function Network (container, data, options) { - if (!(this instanceof Network)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } + Core.prototype._setScrollTop = function (scrollTop) { + this.props.scrollTop = scrollTop; + this._updateScrollTop(); + return this.props.scrollTop; + }; - this._determineBrowserMethod(); - this._initializeMixinLoaders(); + /** + * Update the current scrollTop when the height of the containers has been changed + * @returns {Number} scrollTop Returns the applied scrollTop + * @private + */ + Core.prototype._updateScrollTop = function () { + // recalculate the scrollTopMin + var scrollTopMin = Math.min(this.props.centerContainer.height - this.props.center.height, 0); // is negative or zero + if (scrollTopMin != this.props.scrollTopMin) { + // in case of bottom orientation, change the scrollTop such that the contents + // do not move relative to the time axis at the bottom + if (this.options.orientation == 'bottom') { + this.props.scrollTop += (scrollTopMin - this.props.scrollTopMin); + } + this.props.scrollTopMin = scrollTopMin; + } - // create variables and set default values - this.containerElement = container; + // limit the scrollTop to the feasible scroll range + if (this.props.scrollTop > 0) this.props.scrollTop = 0; + if (this.props.scrollTop < scrollTopMin) this.props.scrollTop = scrollTopMin; - // render and calculation settings - this.renderRefreshRate = 60; // hz (fps) - this.renderTimestep = 1000 / this.renderRefreshRate; // ms -- saves calculation later on - this.renderTime = 0; // measured time it takes to render a frame - this.physicsTime = 0; // measured time it takes to render a frame - this.runDoubleSpeed = false; - this.physicsDiscreteStepsize = 0.50; // discrete stepsize of the simulation + return this.props.scrollTop; + }; - this.initializing = true; + /** + * Get the current scrollTop + * @returns {number} scrollTop + * @private + */ + Core.prototype._getScrollTop = function () { + return this.props.scrollTop; + }; - this.triggerFunctions = {add:null,edit:null,editEdge:null,connect:null,del:null}; + module.exports = Core; - // set constant values - this.defaultOptions = { - nodes: { - mass: 1, - radiusMin: 10, - radiusMax: 30, - radius: 10, - shape: 'ellipse', - image: undefined, - widthMin: 16, // px - widthMax: 64, // px - fontColor: 'black', - fontSize: 14, // px - fontFace: 'verdana', - fontFill: undefined, - fontStrokeWidth: 0, // px - fontStrokeColor: 'white', - level: -1, - color: { - border: '#2B7CE9', - background: '#97C2FC', - highlight: { - border: '#2B7CE9', - background: '#D2E5FF' - }, - hover: { - border: '#2B7CE9', - background: '#D2E5FF' - } - }, - group: undefined, - borderWidth: 1, - borderWidthSelected: undefined - }, - edges: { - widthMin: 1, // - widthMax: 15,// - width: 1, - widthSelectionMultiplier: 2, - hoverWidth: 1.5, - style: 'line', - color: { - color:'#848484', - highlight:'#848484', - hover: '#848484' - }, - fontColor: '#343434', - fontSize: 14, // px - fontFace: 'arial', - fontFill: 'white', - fontStrokeWidth: 0, // px - fontStrokeColor: 'white', - labelAlignment:'horizontal', - arrowScaleFactor: 1, - dash: { - length: 10, - gap: 5, - altLength: undefined - }, - inheritColor: "from" // to, from, false, true (== from) - }, - configurePhysics:false, - physics: { - barnesHut: { - enabled: true, - thetaInverted: 1 / 0.5, // inverted to save time during calculation - gravitationalConstant: -2000, - centralGravity: 0.3, - springLength: 95, - springConstant: 0.04, - damping: 0.09 - }, - repulsion: { - centralGravity: 0.0, - springLength: 200, - springConstant: 0.05, - nodeDistance: 100, - damping: 0.09 - }, - hierarchicalRepulsion: { - enabled: false, - centralGravity: 0.0, - springLength: 100, - springConstant: 0.01, - nodeDistance: 150, - damping: 0.09 - }, - damping: null, - centralGravity: null, - springLength: null, - springConstant: null - }, - clustering: { // Per Node in Cluster = PNiC - enabled: false, // (Boolean) | global on/off switch for clustering. - initialMaxNodes: 100, // (# nodes) | if the initial amount of nodes is larger than this, we cluster until the total number is less than this threshold. - clusterThreshold:500, // (# nodes) | during calculate forces, we check if the total number of nodes is larger than this. If it is, cluster until reduced to reduceToNodes - reduceToNodes:300, // (# nodes) | during calculate forces, we check if the total number of nodes is larger than clusterThreshold. If it is, cluster until reduced to this - chainThreshold: 0.4, // (% of all drawn nodes)| maximum percentage of allowed chainnodes (long strings of connected nodes) within all nodes. (lower means less chains). - clusterEdgeThreshold: 20, // (px) | edge length threshold. if smaller, this node is clustered. - sectorThreshold: 100, // (# nodes in cluster) | cluster size threshold. If larger, expanding in own sector. - screenSizeThreshold: 0.2, // (% of canvas) | relative size threshold. If the width or height of a clusternode takes up this much of the screen, decluster node. - fontSizeMultiplier: 4.0, // (px PNiC) | how much the cluster font size grows per node in cluster (in px). - maxFontSize: 1000, - forceAmplification: 0.1, // (multiplier PNiC) | factor of increase fo the repulsion force of a cluster (per node in cluster). - distanceAmplification: 0.1, // (multiplier PNiC) | factor how much the repulsion distance of a cluster increases (per node in cluster). - edgeGrowth: 20, // (px PNiC) | amount of clusterSize connected to the edge is multiplied with this and added to edgeLength. - nodeScaling: {width: 1, // (px PNiC) | growth of the width per node in cluster. - height: 1, // (px PNiC) | growth of the height per node in cluster. - radius: 1}, // (px PNiC) | growth of the radius per node in cluster. - maxNodeSizeIncrements: 600, // (# increments) | max growth of the width per node in cluster. - activeAreaBoxSize: 80, // (px) | box area around the curser where clusters are popped open. - clusterLevelDifference: 2 - }, - navigation: { - enabled: false - }, - keyboard: { - enabled: false, - speed: {x: 10, y: 10, zoom: 0.02} - }, - dataManipulation: { - enabled: false, - initiallyVisible: false - }, - hierarchicalLayout: { - enabled:false, - levelSeparation: 150, - nodeSpacing: 100, - direction: "UD", // UD, DU, LR, RL - layout: "hubsize" // hubsize, directed - }, - freezeForStabilization: false, - smoothCurves: { - enabled: true, - dynamic: true, - type: "continuous", - roundness: 0.5 - }, - maxVelocity: 30, - minVelocity: 0.1, // px/s - stabilize: true, // stabilize before displaying the network - stabilizationIterations: 1000, // maximum number of iteration to stabilize - zoomExtentOnStabilize: true, - locale: 'en', - locales: locales, - tooltip: { - delay: 300, - fontColor: 'black', - fontSize: 14, // px - fontFace: 'verdana', - color: { - border: '#666', - background: '#FFFFC6' - } - }, - dragNetwork: true, - dragNodes: true, - zoomable: true, - hover: false, - hideEdgesOnDrag: false, - hideNodesOnDrag: false, - width : '100%', - height : '100%', - selectable: true - }; - this.constants = util.extend({}, this.defaultOptions); - this.pixelRatio = 1; - - - this.hoverObj = {nodes:{},edges:{}}; - this.controlNodesActive = false; - this.navigationHammers = {existing:[], _new: []}; - // animation properties - this.animationSpeed = 1/this.renderRefreshRate; - this.animationEasingFunction = "easeInOutQuint"; - this.easingTime = 0; - this.sourceScale = 0; - this.targetScale = 0; - this.sourceTranslation = 0; - this.targetTranslation = 0; - this.lockedOnNodeId = null; - this.lockedOnNodeOffset = null; - this.touchTime = 0; +/***/ }, +/* 47 */ +/***/ function(module, exports, __webpack_require__) { - // Node variables - var network = this; - this.groups = new Groups(); // object with groups - this.images = new Images(); // object with images - this.images.setOnloadCallback(function (status) { - network._redraw(); - }); + var Hammer = __webpack_require__(45); - // keyboard navigation variables - this.xIncrement = 0; - this.yIncrement = 0; - this.zoomIncrement = 0; + /** + * Fake a hammer.js gesture. Event can be a ScrollEvent or MouseMoveEvent + * @param {Element} element + * @param {Event} event + */ + exports.fakeGesture = function(element, event) { + var eventType = null; - // loading all the mixins: - // load the force calculation functions, grouped under the physics system. - this._loadPhysicsSystem(); - // create a frame and canvas - this._create(); - // load the sector system. (mandatory, fully integrated with Network) - this._loadSectorSystem(); - // load the cluster system. (mandatory, even when not using the cluster system, there are function calls to it) - this._loadClusterSystem(); - // load the selection system. (mandatory, required by Network) - this._loadSelectionSystem(); - // load the selection system. (mandatory, required by Network) - this._loadHierarchySystem(); + // for hammer.js 1.0.5 + // var gesture = Hammer.event.collectEventData(this, eventType, event); + // for hammer.js 1.0.6+ + var touches = Hammer.event.getTouchList(event, eventType); + var gesture = Hammer.event.collectEventData(this, eventType, touches, event); - // apply options - this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2); - this._setScale(1); - this.setOptions(options); + // on IE in standards mode, no touches are recognized by hammer.js, + // resulting in NaN values for center.pageX and center.pageY + if (isNaN(gesture.center.pageX)) { + gesture.center.pageX = event.pageX; + } + if (isNaN(gesture.center.pageY)) { + gesture.center.pageY = event.pageY; + } - // other vars - this.freezeSimulation = false;// freeze the simulation - this.cachedFunctions = {}; - this.startedStabilization = false; - this.stabilized = false; - this.stabilizationIterations = null; - this.draggingNodes = false; + return gesture; + }; - // containers for nodes and edges - this.calculationNodes = {}; - this.calculationNodeIndices = []; - this.nodeIndices = []; // array with all the indices of the nodes. Used to speed up forces calculation - this.nodes = {}; // object with Node objects - this.edges = {}; // object with Edge objects - // position and scale variables and objects - this.canvasTopLeft = {"x": 0,"y": 0}; // coordinates of the top left of the canvas. they will be set during _redraw. - this.canvasBottomRight = {"x": 0,"y": 0}; // coordinates of the bottom right of the canvas. they will be set during _redraw - this.pointerPosition = {"x": 0,"y": 0}; // coordinates of the bottom right of the canvas. they will be set during _redraw - this.areaCenter = {}; // object with x and y elements used for determining the center of the zoom action - this.scale = 1; // defining the global scale variable in the constructor - this.previousScale = this.scale; // this is used to check if the zoom operation is zooming in or out +/***/ }, +/* 48 */ +/***/ function(module, exports, __webpack_require__) { - // datasets or dataviews - this.nodesData = null; // A DataSet or DataView - this.edgesData = null; // A DataSet or DataView + // English + exports['en'] = { + current: 'current', + time: 'time' + }; + exports['en_EN'] = exports['en']; + exports['en_US'] = exports['en']; - // create event listeners used to subscribe on the DataSets of the nodes and edges - this.nodesListeners = { - 'add': function (event, params) { - network._addNodes(params.items); - network.start(); - }, - 'update': function (event, params) { - network._updateNodes(params.items, params.data); - network.start(); - }, - 'remove': function (event, params) { - network._removeNodes(params.items); - network.start(); - } - }; - this.edgesListeners = { - 'add': function (event, params) { - network._addEdges(params.items); - network.start(); - }, - 'update': function (event, params) { - network._updateEdges(params.items); - network.start(); - }, - 'remove': function (event, params) { - network._removeEdges(params.items); - network.start(); - } - }; + // Dutch + exports['nl'] = { + custom: 'aangepaste', + time: 'tijd' + }; + exports['nl_NL'] = exports['nl']; + exports['nl_BE'] = exports['nl']; - // properties for the animation - this.moving = true; - this.timer = undefined; // Scheduling function. Is definded in this.start(); - // load data (the disable start variable will be the same as the enabled clustering) - this.setData(data,this.constants.clustering.enabled || this.constants.hierarchicalLayout.enabled); +/***/ }, +/* 49 */ +/***/ function(module, exports, __webpack_require__) { - // hierarchical layout - this.initializing = false; - if (this.constants.hierarchicalLayout.enabled == true) { - this._setupHierarchicalLayout(); + /** + * Created by Alex on 11/11/2014. + */ + var DOMutil = __webpack_require__(2); + var Points = __webpack_require__(51); + + function Line(groupId, options) { + this.groupId = groupId; + this.options = options; + } + + Line.prototype.getYRange = function(groupData) { + var yMin = groupData[0].y; + var yMax = groupData[0].y; + for (var j = 0; j < groupData.length; j++) { + yMin = yMin > groupData[j].y ? groupData[j].y : yMin; + yMax = yMax < groupData[j].y ? groupData[j].y : yMax; } - else { - // zoom so all data will fit on the screen, if clustering is enabled, we do not want start to be called here. - if (this.constants.stabilize == false) { - this.zoomExtent(undefined, true,this.constants.clustering.enabled); + return {min: yMin, max: yMax, yAxisOrientation: this.options.yAxisOrientation}; + }; + + + /** + * draw a line graph + * + * @param dataset + * @param group + */ + Line.prototype.draw = function (dataset, group, framework) { + if (dataset != null) { + if (dataset.length > 0) { + var path, d; + var svgHeight = Number(framework.svg.style.height.replace('px','')); + path = DOMutil.getSVGElement('path', framework.svgElements, framework.svg); + path.setAttributeNS(null, "class", group.className); + if(group.style !== undefined) { + path.setAttributeNS(null, "style", group.style); + } + + // construct path from dataset + if (group.options.catmullRom.enabled == true) { + d = Line._catmullRom(dataset, group); + } + else { + d = Line._linear(dataset); + } + + // append with points for fill and finalize the path + if (group.options.shaded.enabled == true) { + var fillPath = DOMutil.getSVGElement('path', framework.svgElements, framework.svg); + var dFill; + if (group.options.shaded.orientation == 'top') { + dFill = 'M' + dataset[0].x + ',' + 0 + ' ' + d + 'L' + dataset[dataset.length - 1].x + ',' + 0; + } + else { + dFill = 'M' + dataset[0].x + ',' + svgHeight + ' ' + d + 'L' + dataset[dataset.length - 1].x + ',' + svgHeight; + } + fillPath.setAttributeNS(null, "class", group.className + " fill"); + if(group.options.shaded.style !== undefined) { + fillPath.setAttributeNS(null, "style", group.options.shaded.style); + } + fillPath.setAttributeNS(null, "d", dFill); + } + // copy properties to path for drawing. + path.setAttributeNS(null, 'd', 'M' + d); + + // draw points + if (group.options.drawPoints.enabled == true) { + Points.draw(dataset, group, framework); + } } } + }; - // if clustering is disabled, the simulation will have started in the setData function - if (this.constants.clustering.enabled) { - this.startWithClustering(); - } - } - // Extend Network with an Emitter mixin - Emitter(Network.prototype); /** - * Determine if the browser requires a setTimeout or a requestAnimationFrame. This was required because - * some implementations (safari and IE9) did not support requestAnimationFrame + * This uses an uniform parametrization of the CatmullRom algorithm: + * 'On the Parameterization of Catmull-Rom Curves' by Cem Yuksel et al. + * @param data + * @returns {string} * @private */ - Network.prototype._determineBrowserMethod = function() { - var browserType = navigator.userAgent.toLowerCase(); - this.requiresTimeout = false; - if (browserType.indexOf('msie 9.0') != -1) { // IE 9 - this.requiresTimeout = true; - } - else if (browserType.indexOf('safari') != -1) { // safari - if (browserType.indexOf('chrome') <= -1) { - this.requiresTimeout = true; - } + Line._catmullRomUniform = function(data) { + // catmull rom + var p0, p1, p2, p3, bp1, bp2; + var d = Math.round(data[0].x) + ',' + Math.round(data[0].y) + ' '; + var normalization = 1/6; + var length = data.length; + for (var i = 0; i < length - 1; i++) { + + p0 = (i == 0) ? data[0] : data[i-1]; + p1 = data[i]; + p2 = data[i+1]; + p3 = (i + 2 < length) ? data[i+2] : p2; + + + // Catmull-Rom to Cubic Bezier conversion matrix + // 0 1 0 0 + // -1/6 1 1/6 0 + // 0 1/6 1 -1/6 + // 0 0 1 0 + + // bp0 = { x: p1.x, y: p1.y }; + bp1 = { x: ((-p0.x + 6*p1.x + p2.x) *normalization), y: ((-p0.y + 6*p1.y + p2.y) *normalization)}; + bp2 = { x: (( p1.x + 6*p2.x - p3.x) *normalization), y: (( p1.y + 6*p2.y - p3.y) *normalization)}; + // bp0 = { x: p2.x, y: p2.y }; + + d += 'C' + + bp1.x + ',' + + bp1.y + ' ' + + bp2.x + ',' + + bp2.y + ' ' + + p2.x + ',' + + p2.y + ' '; } - } + return d; + }; /** - * Get the script path where the vis.js library is located + * This uses either the chordal or centripetal parameterization of the catmull-rom algorithm. + * By default, the centripetal parameterization is used because this gives the nicest results. + * These parameterizations are relatively heavy because the distance between 4 points have to be calculated. * - * @returns {string | null} path Path or null when not found. Path does not - * end with a slash. + * One optimization can be used to reuse distances since this is a sliding window approach. + * @param data + * @param group + * @returns {string} * @private */ - Network.prototype._getScriptPath = function() { - var scripts = document.getElementsByTagName( 'script' ); + Line._catmullRom = function(data, group) { + var alpha = group.options.catmullRom.alpha; + if (alpha == 0 || alpha === undefined) { + return this._catmullRomUniform(data); + } + else { + var p0, p1, p2, p3, bp1, bp2, d1,d2,d3, A, B, N, M; + var d3powA, d2powA, d3pow2A, d2pow2A, d1pow2A, d1powA; + var d = Math.round(data[0].x) + ',' + Math.round(data[0].y) + ' '; + var length = data.length; + for (var i = 0; i < length - 1; i++) { - // find script named vis.js or vis.min.js - for (var i = 0; i < scripts.length; i++) { - var src = scripts[i].src; - var match = src && /\/?vis(.min)?\.js$/.exec(src); - if (match) { - // return path without the script name - return src.substring(0, src.length - match[0].length); + p0 = (i == 0) ? data[0] : data[i-1]; + p1 = data[i]; + p2 = data[i+1]; + p3 = (i + 2 < length) ? data[i+2] : p2; + + d1 = Math.sqrt(Math.pow(p0.x - p1.x,2) + Math.pow(p0.y - p1.y,2)); + d2 = Math.sqrt(Math.pow(p1.x - p2.x,2) + Math.pow(p1.y - p2.y,2)); + d3 = Math.sqrt(Math.pow(p2.x - p3.x,2) + Math.pow(p2.y - p3.y,2)); + + // Catmull-Rom to Cubic Bezier conversion matrix + + // A = 2d1^2a + 3d1^a * d2^a + d3^2a + // B = 2d3^2a + 3d3^a * d2^a + d2^2a + + // [ 0 1 0 0 ] + // [ -d2^2a /N A/N d1^2a /N 0 ] + // [ 0 d3^2a /M B/M -d2^2a /M ] + // [ 0 0 1 0 ] + + d3powA = Math.pow(d3, alpha); + d3pow2A = Math.pow(d3,2*alpha); + d2powA = Math.pow(d2, alpha); + d2pow2A = Math.pow(d2,2*alpha); + d1powA = Math.pow(d1, alpha); + d1pow2A = Math.pow(d1,2*alpha); + + A = 2*d1pow2A + 3*d1powA * d2powA + d2pow2A; + B = 2*d3pow2A + 3*d3powA * d2powA + d2pow2A; + N = 3*d1powA * (d1powA + d2powA); + if (N > 0) {N = 1 / N;} + M = 3*d3powA * (d3powA + d2powA); + if (M > 0) {M = 1 / M;} + + bp1 = { x: ((-d2pow2A * p0.x + A*p1.x + d1pow2A * p2.x) * N), + y: ((-d2pow2A * p0.y + A*p1.y + d1pow2A * p2.y) * N)}; + + bp2 = { x: (( d3pow2A * p1.x + B*p2.x - d2pow2A * p3.x) * M), + y: (( d3pow2A * p1.y + B*p2.y - d2pow2A * p3.y) * M)}; + + if (bp1.x == 0 && bp1.y == 0) {bp1 = p1;} + if (bp2.x == 0 && bp2.y == 0) {bp2 = p2;} + d += 'C' + + bp1.x + ',' + + bp1.y + ' ' + + bp2.x + ',' + + bp2.y + ' ' + + p2.x + ',' + + p2.y + ' '; } + + return d; } + }; - return null; + /** + * this generates the SVG path for a linear drawing between datapoints. + * @param data + * @returns {string} + * @private + */ + Line._linear = function(data) { + // linear + var d = ''; + for (var i = 0; i < data.length; i++) { + if (i == 0) { + d += data[i].x + ',' + data[i].y; + } + else { + d += ' ' + data[i].x + ',' + data[i].y; + } + } + return d; }; + module.exports = Line; + + +/***/ }, +/* 50 */ +/***/ function(module, exports, __webpack_require__) { /** - * Find the center position of the network - * @private + * Created by Alex on 11/11/2014. */ - Network.prototype._getRange = function() { - var minY = 1e9, maxY = -1e9, minX = 1e9, maxX = -1e9, node; - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - if (minX > (node.boundingBox.left)) {minX = node.boundingBox.left;} - if (maxX < (node.boundingBox.right)) {maxX = node.boundingBox.right;} - if (minY > (node.boundingBox.bottom)) {minY = node.boundingBox.top;} // top is negative, bottom is positive - if (maxY < (node.boundingBox.top)) {maxY = node.boundingBox.bottom;} // top is negative, bottom is positive + var DOMutil = __webpack_require__(2); + var Points = __webpack_require__(51); + + function Bargraph(groupId, options) { + this.groupId = groupId; + this.options = options; + } + + Bargraph.prototype.getYRange = function(groupData) { + if (this.options.barChart.handleOverlap != 'stack') { + var yMin = groupData[0].y; + var yMax = groupData[0].y; + for (var j = 0; j < groupData.length; j++) { + yMin = yMin > groupData[j].y ? groupData[j].y : yMin; + yMax = yMax < groupData[j].y ? groupData[j].y : yMax; } + return {min: yMin, max: yMax, yAxisOrientation: this.options.yAxisOrientation}; } - if (minX == 1e9 && maxX == -1e9 && minY == 1e9 && maxY == -1e9) { - minY = 0, maxY = 0, minX = 0, maxX = 0; + else { + var barCombinedData = []; + for (var j = 0; j < groupData.length; j++) { + barCombinedData.push({ + x: groupData[j].x, + y: groupData[j].y, + groupId: this.groupId + }); + } + return barCombinedData; } - return {minX: minX, maxX: maxX, minY: minY, maxY: maxY}; }; + /** - * @param {object} range = {minX: minX, maxX: maxX, minY: minY, maxY: maxY}; - * @returns {{x: number, y: number}} + * draw a bar graph + * + * @param groupIds + * @param processedGroupData + */ + Bargraph.draw = function (groupIds, processedGroupData, framework) { + var combinedData = []; + var intersections = {}; + var coreDistance; + var key, drawData; + var group; + var i,j; + var barPoints = 0; + + // combine all barchart data + for (i = 0; i < groupIds.length; i++) { + group = framework.groups[groupIds[i]]; + if (group.options.style == 'bar') { + if (group.visible == true && (framework.options.groups.visibility[groupIds[i]] === undefined || framework.options.groups.visibility[groupIds[i]] == true)) { + for (j = 0; j < processedGroupData[groupIds[i]].length; j++) { + combinedData.push({ + x: processedGroupData[groupIds[i]][j].x, + y: processedGroupData[groupIds[i]][j].y, + groupId: groupIds[i] + }); + barPoints += 1; + } + } + } + } + + if (barPoints == 0) {return;} + + // sort by time and by group + combinedData.sort(function (a, b) { + if (a.x == b.x) { + return a.groupId - b.groupId; + } else { + return a.x - b.x; + } + }); + + // get intersections + Bargraph._getDataIntersections(intersections, combinedData); + + // plot barchart + for (i = 0; i < combinedData.length; i++) { + group = framework.groups[combinedData[i].groupId]; + var minWidth = 0.1 * group.options.barChart.width; + + key = combinedData[i].x; + var heightOffset = 0; + if (intersections[key] === undefined) { + if (i+1 < combinedData.length) {coreDistance = Math.abs(combinedData[i+1].x - key);} + if (i > 0) {coreDistance = Math.min(coreDistance,Math.abs(combinedData[i-1].x - key));} + drawData = Bargraph._getSafeDrawData(coreDistance, group, minWidth); + } + else { + var nextKey = i + (intersections[key].amount - intersections[key].resolved); + var prevKey = i - (intersections[key].resolved + 1); + if (nextKey < combinedData.length) {coreDistance = Math.abs(combinedData[nextKey].x - key);} + if (prevKey > 0) {coreDistance = Math.min(coreDistance,Math.abs(combinedData[prevKey].x - key));} + drawData = Bargraph._getSafeDrawData(coreDistance, group, minWidth); + intersections[key].resolved += 1; + + if (group.options.barChart.handleOverlap == 'stack') { + heightOffset = intersections[key].accumulated; + intersections[key].accumulated += group.zeroPosition - combinedData[i].y; + } + else if (group.options.barChart.handleOverlap == 'sideBySide') { + drawData.width = drawData.width / intersections[key].amount; + drawData.offset += (intersections[key].resolved) * drawData.width - (0.5*drawData.width * (intersections[key].amount+1)); + if (group.options.barChart.align == 'left') {drawData.offset -= 0.5*drawData.width;} + else if (group.options.barChart.align == 'right') {drawData.offset += 0.5*drawData.width;} + } + } + DOMutil.drawBar(combinedData[i].x + drawData.offset, combinedData[i].y - heightOffset, drawData.width, group.zeroPosition - combinedData[i].y, group.className + ' bar', framework.svgElements, framework.svg); + // draw points + if (group.options.drawPoints.enabled == true) { + DOMutil.drawPoint(combinedData[i].x + drawData.offset, combinedData[i].y, group, framework.svgElements, framework.svg); + } + } + }; + + + /** + * Fill the intersections object with counters of how many datapoints share the same x coordinates + * @param intersections + * @param combinedData * @private */ - Network.prototype._findCenter = function(range) { - return {x: (0.5 * (range.maxX + range.minX)), - y: (0.5 * (range.maxY + range.minY))}; + Bargraph._getDataIntersections = function (intersections, combinedData) { + // get intersections + var coreDistance; + for (var i = 0; i < combinedData.length; i++) { + if (i + 1 < combinedData.length) { + coreDistance = Math.abs(combinedData[i + 1].x - combinedData[i].x); + } + if (i > 0) { + coreDistance = Math.min(coreDistance, Math.abs(combinedData[i - 1].x - combinedData[i].x)); + } + if (coreDistance == 0) { + if (intersections[combinedData[i].x] === undefined) { + intersections[combinedData[i].x] = {amount: 0, resolved: 0, accumulated: 0}; + } + intersections[combinedData[i].x].amount += 1; + } + } }; /** - * This function zooms out to fit all data on screen based on amount of nodes + * Get the width and offset for bargraphs based on the coredistance between datapoints * - * @param {Boolean} [initialZoom] | zoom based on fitted formula or range, true = fitted, default = false; - * @param {Boolean} [disableStart] | If true, start is not called. + * @param coreDistance + * @param group + * @param minWidth + * @returns {{width: Number, offset: Number}} + * @private */ - Network.prototype.zoomExtent = function(animationOptions, initialZoom, disableStart) { - this._redraw(true); - - if (initialZoom === undefined) {initialZoom = false;} - if (disableStart === undefined) {disableStart = false;} - if (animationOptions === undefined) {animationOptions = false;} - - var range = this._getRange(); - var zoomLevel; + Bargraph._getSafeDrawData = function (coreDistance, group, minWidth) { + var width, offset; + if (coreDistance < group.options.barChart.width && coreDistance > 0) { + width = coreDistance < minWidth ? minWidth : coreDistance; - if (initialZoom == true) { - var numberOfNodes = this.nodeIndices.length; - if (this.constants.smoothCurves == true) { - if (this.constants.clustering.enabled == true && - numberOfNodes >= this.constants.clustering.initialMaxNodes) { - zoomLevel = 49.07548 / (numberOfNodes + 142.05338) + 9.1444e-04; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. - } - else { - zoomLevel = 12.662 / (numberOfNodes + 7.4147) + 0.0964822; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. - } + offset = 0; // recalculate offset with the new width; + if (group.options.barChart.align == 'left') { + offset -= 0.5 * coreDistance; } - else { - if (this.constants.clustering.enabled == true && - numberOfNodes >= this.constants.clustering.initialMaxNodes) { - zoomLevel = 77.5271985 / (numberOfNodes + 187.266146) + 4.76710517e-05; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. - } - else { - zoomLevel = 30.5062972 / (numberOfNodes + 19.93597763) + 0.08413486; // this is obtained from fitting a dataset from 5 points with scale levels that looked good. - } + else if (group.options.barChart.align == 'right') { + offset += 0.5 * coreDistance; } - - // correct for larger canvasses. - var factor = Math.min(this.frame.canvas.clientWidth / 600, this.frame.canvas.clientHeight / 600); - zoomLevel *= factor; } else { - var xDistance = Math.abs(range.maxX - range.minX) * 1.1; - var yDistance = Math.abs(range.maxY - range.minY) * 1.1; - - var xZoomLevel = this.frame.canvas.clientWidth / xDistance; - var yZoomLevel = this.frame.canvas.clientHeight / yDistance; - zoomLevel = (xZoomLevel <= yZoomLevel) ? xZoomLevel : yZoomLevel; + // default settings + width = group.options.barChart.width; + offset = 0; + if (group.options.barChart.align == 'left') { + offset -= 0.5 * group.options.barChart.width; + } + else if (group.options.barChart.align == 'right') { + offset += 0.5 * group.options.barChart.width; + } } - if (zoomLevel > 1.0) { - zoomLevel = 1.0; - } + return {width: width, offset: offset}; + }; + Bargraph.getStackedBarYRange = function(barCombinedData, groupRanges, groupIds, groupLabel, orientation) { + if (barCombinedData.length > 0) { + // sort by time and by group + barCombinedData.sort(function (a, b) { + if (a.x == b.x) { + return a.groupId - b.groupId; + } else { + return a.x - b.x; + } + }); + var intersections = {}; - var center = this._findCenter(range); - if (disableStart == false) { - var options = {position: center, scale: zoomLevel, animation: animationOptions}; - this.moveTo(options); - this.moving = true; - this.start(); + Bargraph._getDataIntersections(intersections, barCombinedData); + groupRanges[groupLabel] = Bargraph._getStackedBarYRange(intersections, barCombinedData); + groupRanges[groupLabel].yAxisOrientation = orientation; + groupIds.push(groupLabel); } - else { - center.x *= zoomLevel; - center.y *= zoomLevel; - center.x -= 0.5 * this.frame.canvas.clientWidth; - center.y -= 0.5 * this.frame.canvas.clientHeight; - this._setScale(zoomLevel); - this._setTranslation(-center.x,-center.y); + } + + Bargraph._getStackedBarYRange = function (intersections, combinedData) { + var key; + var yMin = combinedData[0].y; + var yMax = combinedData[0].y; + for (var i = 0; i < combinedData.length; i++) { + key = combinedData[i].x; + if (intersections[key] === undefined) { + yMin = yMin > combinedData[i].y ? combinedData[i].y : yMin; + yMax = yMax < combinedData[i].y ? combinedData[i].y : yMax; + } + else { + intersections[key].accumulated += combinedData[i].y; + } + } + for (var xpos in intersections) { + if (intersections.hasOwnProperty(xpos)) { + yMin = yMin > intersections[xpos].accumulated ? intersections[xpos].accumulated : yMin; + yMax = yMax < intersections[xpos].accumulated ? intersections[xpos].accumulated : yMax; + } } + + return {min: yMin, max: yMax}; }; + module.exports = Bargraph; + +/***/ }, +/* 51 */ +/***/ function(module, exports, __webpack_require__) { /** - * Update the this.nodeIndices with the most recent node index list - * @private + * Created by Alex on 11/11/2014. */ - Network.prototype._updateNodeIndexList = function() { - this._clearNodeIndexList(); - for (var idx in this.nodes) { - if (this.nodes.hasOwnProperty(idx)) { - this.nodeIndices.push(idx); - } + var DOMutil = __webpack_require__(2); + + function Points(groupId, options) { + this.groupId = groupId; + this.options = options; + } + + + Points.prototype.getYRange = function(groupData) { + var yMin = groupData[0].y; + var yMax = groupData[0].y; + for (var j = 0; j < groupData.length; j++) { + yMin = yMin > groupData[j].y ? groupData[j].y : yMin; + yMax = yMax < groupData[j].y ? groupData[j].y : yMax; } + return {min: yMin, max: yMax, yAxisOrientation: this.options.yAxisOrientation}; }; + Points.prototype.draw = function(dataset, group, framework, offset) { + Points.draw(dataset, group, framework, offset); + } /** - * Set nodes and edges, and optionally options as well. + * draw the data points * - * @param {Object} data Object containing parameters: - * {Array | DataSet | DataView} [nodes] Array with nodes - * {Array | DataSet | DataView} [edges] Array with edges - * {String} [dot] String containing data in DOT format - * {String} [gephi] String containing data in gephi JSON format - * {Options} [options] Object with options - * @param {Boolean} [disableStart] | optional: disable the calling of the start function. + * @param {Array} dataset + * @param {Object} JSONcontainer + * @param {Object} svg | SVG DOM element + * @param {GraphGroup} group + * @param {Number} [offset] */ - Network.prototype.setData = function(data, disableStart) { - if (disableStart === undefined) { - disableStart = false; + Points.draw = function (dataset, group, framework, offset) { + if (offset === undefined) {offset = 0;} + for (var i = 0; i < dataset.length; i++) { + DOMutil.drawPoint(dataset[i].x + offset, dataset[i].y, group, framework.svgElements, framework.svg); } - // we set initializing to true to ensure that the hierarchical layout is not performed until both nodes and edges are added. - this.initializing = true; + }; - if (data && data.dot && (data.nodes || data.edges)) { - throw new SyntaxError('Data must contain either parameter "dot" or ' + - ' parameter pair "nodes" and "edges", but not both.'); - } - // clean up in case there is anyone in an active mode of the manipulation. This is the same option as bound to the escape button. - if (this.constants.dataManipulation.enabled == true) { - this._createManipulatorBar(); - } + module.exports = Points; - // set options - this.setOptions(data && data.options); - // set all data - if (data && data.dot) { - // parse DOT file - if(data && data.dot) { - var dotData = dotparser.DOTToGraph(data.dot); - this.setData(dotData); - return; - } - } - else if (data && data.gephi) { - // parse DOT file - if(data && data.gephi) { - var gephiData = gephiParser.parseGephi(data.gephi); - this.setData(gephiData); - return; - } - } - else { - this._setNodes(data && data.nodes); - this._setEdges(data && data.edges); - } - this._putDataInSector(); - if (disableStart == false) { - if (this.constants.hierarchicalLayout.enabled == true) { - this._resetLevels(); - this._setupHierarchicalLayout(); - } - else { - // find a stable position or start animating to a stable position - if (this.constants.stabilize) { - this._stabilize(); - } - } - this.start(); - } - this.initializing = false; +/***/ }, +/* 52 */ +/***/ function(module, exports, __webpack_require__) { + + // English + exports['en'] = { + edit: 'Edit', + del: 'Delete selected', + back: 'Back', + addNode: 'Add Node', + addEdge: 'Add Edge', + editNode: 'Edit Node', + editEdge: 'Edit Edge', + addDescription: 'Click in an empty space to place a new node.', + edgeDescription: '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'] = { + edit: 'Wijzigen', + del: 'Selectie verwijderen', + back: 'Terug', + addNode: 'Node toevoegen', + addEdge: 'Link toevoegen', + editNode: 'Node wijzigen', + editEdge: 'Link wijzigen', + addDescription: 'Klik op een leeg gebied om een nieuwe node te maken.', + edgeDescription: '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']; + + +/***/ }, +/* 53 */ +/***/ function(module, exports, __webpack_require__) { /** - * Set options - * @param {Object} options + * Canvas shapes used by Network */ - Network.prototype.setOptions = function (options) { - if (options) { - var prop; - var fields = ['nodes','edges','smoothCurves','hierarchicalLayout','clustering','navigation', - 'keyboard','dataManipulation','onAdd','onEdit','onEditEdge','onConnect','onDelete','clickToUse' - ]; - // extend all but the values in fields - util.selectiveNotDeepExtend(fields,this.constants, options); - util.selectiveNotDeepExtend(['color'],this.constants.nodes, options.nodes); - util.selectiveNotDeepExtend(['color','length'],this.constants.edges, options.edges); + if (typeof CanvasRenderingContext2D !== 'undefined') { - if (options.physics) { - util.mergeOptions(this.constants.physics, options.physics,'barnesHut'); - util.mergeOptions(this.constants.physics, options.physics,'repulsion'); + /** + * Draw a circle shape + */ + CanvasRenderingContext2D.prototype.circle = function(x, y, r) { + this.beginPath(); + this.arc(x, y, r, 0, 2*Math.PI, false); + }; - if (options.physics.hierarchicalRepulsion) { - this.constants.hierarchicalLayout.enabled = true; - this.constants.physics.hierarchicalRepulsion.enabled = true; - this.constants.physics.barnesHut.enabled = false; - for (prop in options.physics.hierarchicalRepulsion) { - if (options.physics.hierarchicalRepulsion.hasOwnProperty(prop)) { - this.constants.physics.hierarchicalRepulsion[prop] = options.physics.hierarchicalRepulsion[prop]; - } - } - } - } + /** + * Draw a square shape + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r size, width and height of the square + */ + CanvasRenderingContext2D.prototype.square = function(x, y, r) { + this.beginPath(); + this.rect(x - r, y - r, r * 2, r * 2); + }; - if (options.onAdd) {this.triggerFunctions.add = options.onAdd;} - if (options.onEdit) {this.triggerFunctions.edit = options.onEdit;} - if (options.onEditEdge) {this.triggerFunctions.editEdge = options.onEditEdge;} - if (options.onConnect) {this.triggerFunctions.connect = options.onConnect;} - if (options.onDelete) {this.triggerFunctions.del = options.onDelete;} + /** + * Draw a triangle shape + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r radius, half the length of the sides of the triangle + */ + CanvasRenderingContext2D.prototype.triangle = function(x, y, r) { + // http://en.wikipedia.org/wiki/Equilateral_triangle + this.beginPath(); - util.mergeOptions(this.constants, options,'smoothCurves'); - util.mergeOptions(this.constants, options,'hierarchicalLayout'); - util.mergeOptions(this.constants, options,'clustering'); - util.mergeOptions(this.constants, options,'navigation'); - util.mergeOptions(this.constants, options,'keyboard'); - util.mergeOptions(this.constants, options,'dataManipulation'); + var s = r * 2; + var s2 = s / 2; + var ir = Math.sqrt(3) / 6 * s; // radius of inner circle + var h = Math.sqrt(s * s - s2 * s2); // height + this.moveTo(x, y - (h - ir)); + this.lineTo(x + s2, y + ir); + this.lineTo(x - s2, y + ir); + this.lineTo(x, y - (h - ir)); + this.closePath(); + }; - if (options.dataManipulation) { - this.editMode = this.constants.dataManipulation.initiallyVisible; - } + /** + * Draw a triangle shape in downward orientation + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r radius + */ + CanvasRenderingContext2D.prototype.triangleDown = function(x, y, r) { + // http://en.wikipedia.org/wiki/Equilateral_triangle + this.beginPath(); + var s = r * 2; + var s2 = s / 2; + var ir = Math.sqrt(3) / 6 * s; // radius of inner circle + var h = Math.sqrt(s * s - s2 * s2); // height - // TODO: work out these options and document them - if (options.edges) { - if (options.edges.color !== undefined) { - if (util.isString(options.edges.color)) { - this.constants.edges.color = {}; - this.constants.edges.color.color = options.edges.color; - this.constants.edges.color.highlight = options.edges.color; - this.constants.edges.color.hover = options.edges.color; - } - else { - if (options.edges.color.color !== undefined) {this.constants.edges.color.color = options.edges.color.color;} - if (options.edges.color.highlight !== undefined) {this.constants.edges.color.highlight = options.edges.color.highlight;} - if (options.edges.color.hover !== undefined) {this.constants.edges.color.hover = options.edges.color.hover;} - } - this.constants.edges.inheritColor = false; - } + this.moveTo(x, y + (h - ir)); + this.lineTo(x + s2, y - ir); + this.lineTo(x - s2, y - ir); + this.lineTo(x, y + (h - ir)); + this.closePath(); + }; - if (!options.edges.fontColor) { - if (options.edges.color !== undefined) { - if (util.isString(options.edges.color)) {this.constants.edges.fontColor = options.edges.color;} - else if (options.edges.color.color !== undefined) {this.constants.edges.fontColor = options.edges.color.color;} - } - } - } + /** + * Draw a star shape, a star with 5 points + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r radius, half the length of the sides of the triangle + */ + CanvasRenderingContext2D.prototype.star = function(x, y, r) { + // http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/ + this.beginPath(); - if (options.nodes) { - if (options.nodes.color) { - var newColorObj = util.parseColor(options.nodes.color); - this.constants.nodes.color.background = newColorObj.background; - this.constants.nodes.color.border = newColorObj.border; - this.constants.nodes.color.highlight.background = newColorObj.highlight.background; - this.constants.nodes.color.highlight.border = newColorObj.highlight.border; - this.constants.nodes.color.hover.background = newColorObj.hover.background; - this.constants.nodes.color.hover.border = newColorObj.hover.border; - } - } - if (options.groups) { - for (var groupname in options.groups) { - if (options.groups.hasOwnProperty(groupname)) { - var group = options.groups[groupname]; - this.groups.add(groupname, group); - } - } + for (var n = 0; n < 10; n++) { + var radius = (n % 2 === 0) ? r * 1.3 : r * 0.5; + this.lineTo( + x + radius * Math.sin(n * 2 * Math.PI / 10), + y - radius * Math.cos(n * 2 * Math.PI / 10) + ); } - if (options.tooltip) { - for (prop in options.tooltip) { - if (options.tooltip.hasOwnProperty(prop)) { - this.constants.tooltip[prop] = options.tooltip[prop]; - } - } - if (options.tooltip.color) { - this.constants.tooltip.color = util.parseColor(options.tooltip.color); - } - } + this.closePath(); + }; - if ('clickToUse' in options) { - if (options.clickToUse) { - if (!this.activator) { - this.activator = new Activator(this.frame); - this.activator.on('change', this._createKeyBinds.bind(this)); - } - } - else { - if (this.activator) { - this.activator.destroy(); - delete this.activator; - } - } - } + /** + * http://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas + */ + CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) { + var r2d = Math.PI/180; + if( w - ( 2 * r ) < 0 ) { r = ( w / 2 ); } //ensure that the radius isn't too large for x + if( h - ( 2 * r ) < 0 ) { r = ( h / 2 ); } //ensure that the radius isn't too large for y + this.beginPath(); + this.moveTo(x+r,y); + this.lineTo(x+w-r,y); + this.arc(x+w-r,y+r,r,r2d*270,r2d*360,false); + this.lineTo(x+w,y+h-r); + this.arc(x+w-r,y+h-r,r,0,r2d*90,false); + this.lineTo(x+r,y+h); + this.arc(x+r,y+h-r,r,r2d*90,r2d*180,false); + this.lineTo(x,y+r); + this.arc(x+r,y+r,r,r2d*180,r2d*270,false); + }; - if (options.labels) { - throw new Error('Option "labels" is deprecated. Use options "locale" and "locales" instead.'); - } + /** + * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + */ + CanvasRenderingContext2D.prototype.ellipse = function(x, y, w, h) { + var kappa = .5522848, + ox = (w / 2) * kappa, // control point offset horizontal + oy = (h / 2) * kappa, // control point offset vertical + xe = x + w, // x-end + ye = y + h, // y-end + xm = x + w / 2, // x-middle + ym = y + h / 2; // y-middle + this.beginPath(); + this.moveTo(x, ym); + this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + }; + + + + /** + * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + */ + CanvasRenderingContext2D.prototype.database = function(x, y, w, h) { + var f = 1/3; + var wEllipse = w; + var hEllipse = h * f; - // (Re)loading the mixins that can be enabled or disabled in the options. - // load the force calculation functions, grouped under the physics system. - this._loadPhysicsSystem(); - // load the navigation system. - this._loadNavigationControls(); - // load the data manipulation system - this._loadManipulationSystem(); - // configure the smooth curves - this._configureSmoothCurves(); + var kappa = .5522848, + ox = (wEllipse / 2) * kappa, // control point offset horizontal + oy = (hEllipse / 2) * kappa, // control point offset vertical + xe = x + wEllipse, // x-end + ye = y + hEllipse, // y-end + xm = x + wEllipse / 2, // x-middle + ym = y + hEllipse / 2, // y-middle + ymb = y + (h - hEllipse/2), // y-midlle, bottom ellipse + yeb = y + h; // y-end, bottom ellipse + this.beginPath(); + this.moveTo(xe, ym); - // bind keys. If disabled, this will not do anything; - this._createKeyBinds(); + this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - this.setSize(this.constants.width, this.constants.height); - this.moving = true; - this.start(); - } - }; + this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + this.lineTo(xe, ymb); + this.bezierCurveTo(xe, ymb + oy, xm + ox, yeb, xm, yeb); + this.bezierCurveTo(xm - ox, yeb, x, ymb + oy, x, ymb); - /** - * Create the main frame for the Network. - * This function is executed once when a Network object is created. The frame - * contains a canvas, and this canvas contains all objects like the axis and - * nodes. - * @private - */ - Network.prototype._create = function () { - // remove all elements from the container element. - while (this.containerElement.hasChildNodes()) { - this.containerElement.removeChild(this.containerElement.firstChild); - } + this.lineTo(x, ym); + }; - this.frame = document.createElement('div'); - this.frame.className = 'vis network-frame'; - this.frame.style.position = 'relative'; - this.frame.style.overflow = 'hidden'; + /** + * Draw an arrow point (no line) + */ + CanvasRenderingContext2D.prototype.arrow = function(x, y, angle, length) { + // tail + var xt = x - length * Math.cos(angle); + var yt = y - length * Math.sin(angle); - ////////////////////////////////////////////////////////////////// + // inner tail + // TODO: allow to customize different shapes + var xi = x - length * 0.9 * Math.cos(angle); + var yi = y - length * 0.9 * Math.sin(angle); - this.frame.canvas = document.createElement("canvas"); - this.frame.canvas.style.position = 'relative'; - this.frame.appendChild(this.frame.canvas); + // left + var xl = xt + length / 3 * Math.cos(angle + 0.5 * Math.PI); + var yl = yt + length / 3 * Math.sin(angle + 0.5 * Math.PI); - if (!this.frame.canvas.getContext) { - var noCanvas = document.createElement( 'DIV' ); - noCanvas.style.color = 'red'; - noCanvas.style.fontWeight = 'bold' ; - noCanvas.style.padding = '10px'; - noCanvas.innerHTML = 'Error: your browser does not support HTML canvas'; - this.frame.canvas.appendChild(noCanvas); - } - else { - var ctx = this.frame.canvas.getContext("2d"); - this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || - ctx.mozBackingStorePixelRatio || - ctx.msBackingStorePixelRatio || - ctx.oBackingStorePixelRatio || - ctx.backingStorePixelRatio || 1); + // right + var xr = xt + length / 3 * Math.cos(angle - 0.5 * Math.PI); + var yr = yt + length / 3 * Math.sin(angle - 0.5 * Math.PI); - this.frame.canvas.getContext("2d").setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); - } + this.beginPath(); + this.moveTo(x, y); + this.lineTo(xl, yl); + this.lineTo(xi, yi); + this.lineTo(xr, yr); + this.closePath(); + }; - ////////////////////////////////////////////////////////////////// + /** + * Sets up the dashedLine functionality for drawing + * Original code came from http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas + * @author David Jordan + * @date 2012-08-08 + */ + CanvasRenderingContext2D.prototype.dashedLine = function(x,y,x2,y2,dashArray){ + if (!dashArray) dashArray=[10,5]; + if (dashLength==0) dashLength = 0.001; // Hack for Safari + var dashCount = dashArray.length; + this.moveTo(x, y); + var dx = (x2-x), dy = (y2-y); + var slope = dy/dx; + var distRemaining = Math.sqrt( dx*dx + dy*dy ); + var dashIndex=0, draw=true; + while (distRemaining>=0.1){ + var dashLength = dashArray[dashIndex++%dashCount]; + if (dashLength > distRemaining) dashLength = distRemaining; + var xStep = Math.sqrt( dashLength*dashLength / (1 + slope*slope) ); + if (dx<0) xStep = -xStep; + x += xStep; + y += slope*xStep; + this[draw ? 'lineTo' : 'moveTo'](x,y); + distRemaining -= dashLength; + draw = !draw; + } + }; + // TODO: add diamond shape + } - var me = this; - this.drag = {}; - this.pinch = {}; - this.hammer = Hammer(this.frame.canvas, { - prevent_default: true - }); - this.hammer.on('tap', me._onTap.bind(me) ); - this.hammer.on('doubletap', me._onDoubleTap.bind(me) ); - this.hammer.on('hold', me._onHold.bind(me) ); - this.hammer.on('pinch', me._onPinch.bind(me) ); - this.hammer.on('touch', me._onTouch.bind(me) ); - this.hammer.on('dragstart', me._onDragStart.bind(me) ); - this.hammer.on('drag', me._onDrag.bind(me) ); - this.hammer.on('dragend', me._onDragEnd.bind(me) ); - this.hammer.on('mousewheel',me._onMouseWheel.bind(me) ); - this.hammer.on('DOMMouseScroll',me._onMouseWheel.bind(me) ); // for FF - this.hammer.on('mousemove', me._onMouseMoveTitle.bind(me) ); - this.hammerFrame = Hammer(this.frame, { - prevent_default: true - }); - this.hammerFrame.on('release', me._onRelease.bind(me) ); +/***/ }, +/* 54 */ +/***/ function(module, exports, __webpack_require__) { - // add the frame to the container element - this.containerElement.appendChild(this.frame); + var PhysicsMixin = __webpack_require__(66); + var ClusterMixin = __webpack_require__(60); + var SectorsMixin = __webpack_require__(61); + var SelectionMixin = __webpack_require__(62); + var ManipulationMixin = __webpack_require__(63); + var NavigationMixin = __webpack_require__(64); + var HierarchicalLayoutMixin = __webpack_require__(65); + /** + * Load a mixin into the network object + * + * @param {Object} sourceVariable | this object has to contain functions. + * @private + */ + exports._loadMixin = function (sourceVariable) { + for (var mixinFunction in sourceVariable) { + if (sourceVariable.hasOwnProperty(mixinFunction)) { + this[mixinFunction] = sourceVariable[mixinFunction]; + } + } }; /** - * Binding the keys for keyboard navigation. These functions are defined in the NavigationMixin + * removes a mixin from the network object. + * + * @param {Object} sourceVariable | this object has to contain functions. * @private */ - Network.prototype._createKeyBinds = function() { - var me = this; - if (this.keycharm !== undefined) { - this.keycharm.destroy(); + exports._clearMixin = function (sourceVariable) { + for (var mixinFunction in sourceVariable) { + if (sourceVariable.hasOwnProperty(mixinFunction)) { + this[mixinFunction] = undefined; + } } - this.keycharm = keycharm(); + }; - this.keycharm.reset(); - if (this.constants.keyboard.enabled && this.isActive()) { - this.keycharm.bind("up", this._moveUp.bind(me) , "keydown"); - this.keycharm.bind("up", this._yStopMoving.bind(me), "keyup"); - this.keycharm.bind("down", this._moveDown.bind(me) , "keydown"); - this.keycharm.bind("down", this._yStopMoving.bind(me), "keyup"); - this.keycharm.bind("left", this._moveLeft.bind(me) , "keydown"); - this.keycharm.bind("left", this._xStopMoving.bind(me), "keyup"); - this.keycharm.bind("right",this._moveRight.bind(me), "keydown"); - this.keycharm.bind("right",this._xStopMoving.bind(me), "keyup"); - this.keycharm.bind("=", this._zoomIn.bind(me), "keydown"); - this.keycharm.bind("=", this._stopZoom.bind(me), "keyup"); - this.keycharm.bind("num+", this._zoomIn.bind(me), "keydown"); - this.keycharm.bind("num+", this._stopZoom.bind(me), "keyup"); - this.keycharm.bind("num-", this._zoomOut.bind(me), "keydown"); - this.keycharm.bind("num-", this._stopZoom.bind(me), "keyup"); - this.keycharm.bind("-", this._zoomOut.bind(me), "keydown"); - this.keycharm.bind("-", this._stopZoom.bind(me), "keyup"); - this.keycharm.bind("[", this._zoomIn.bind(me), "keydown"); - this.keycharm.bind("[", this._stopZoom.bind(me), "keyup"); - this.keycharm.bind("]", this._zoomOut.bind(me), "keydown"); - this.keycharm.bind("]", this._stopZoom.bind(me), "keyup"); - this.keycharm.bind("pageup",this._zoomIn.bind(me), "keydown"); - this.keycharm.bind("pageup",this._stopZoom.bind(me), "keyup"); - this.keycharm.bind("pagedown",this._zoomOut.bind(me),"keydown"); - this.keycharm.bind("pagedown",this._stopZoom.bind(me), "keyup"); + /** + * Mixin the physics system and initialize the parameters required. + * + * @private + */ + exports._loadPhysicsSystem = function () { + this._loadMixin(PhysicsMixin); + this._loadSelectedForceSolver(); + if (this.constants.configurePhysics == true) { + this._loadPhysicsConfiguration(); } - - if (this.constants.dataManipulation.enabled == true) { - this.keycharm.bind("esc",this._createManipulatorBar.bind(me)); - this.keycharm.bind("delete",this._deleteSelected.bind(me)); + else { + this._cleanupPhysicsConfiguration(); } }; + /** - * Cleans up all bindings of the network, removing it fully from the memory IF the variable is set to null after calling this function. - * var network = new vis.Network(..); - * network.destroy(); - * network = null; + * Mixin the cluster system and initialize the parameters required. + * + * @private */ - Network.prototype.destroy = function() { - this.start = function () {}; - this.redraw = function () {}; - this.timer = false; - - // cleanup physicsConfiguration if it exists - this._cleanupPhysicsConfiguration(); + exports._loadClusterSystem = function () { + this.clusterSession = 0; + this.hubThreshold = 5; + this._loadMixin(ClusterMixin); + }; - // remove keybindings - this.keycharm.reset(); - // clear hammer bindings - this.hammer.dispose(); + /** + * Mixin the sector system and initialize the parameters required + * + * @private + */ + exports._loadSectorSystem = function () { + this.sectors = {}; + this.activeSector = ["default"]; + this.sectors["active"] = {}; + this.sectors["active"]["default"] = {"nodes": {}, + "edges": {}, + "nodeIndices": [], + "formationScale": 1.0, + "drawingNode": undefined }; + this.sectors["frozen"] = {}; + this.sectors["support"] = {"nodes": {}, + "edges": {}, + "nodeIndices": [], + "formationScale": 1.0, + "drawingNode": undefined }; - // clear events - this.off(); + this.nodeIndices = this.sectors["active"]["default"]["nodeIndices"]; // the node indices list is used to speed up the computation of the repulsion fields - this._recursiveDOMDelete(this.containerElement); - } + this._loadMixin(SectorsMixin); + }; - Network.prototype._recursiveDOMDelete = function(DOMobject) { - while (DOMobject.hasChildNodes() == true) { - this._recursiveDOMDelete(DOMobject.firstChild); - DOMobject.removeChild(DOMobject.firstChild); - } - } /** - * Get the pointer location from a touch location - * @param {{pageX: Number, pageY: Number}} touch - * @return {{x: Number, y: Number}} pointer + * Mixin the selection system and initialize the parameters required + * * @private */ - Network.prototype._getPointer = function (touch) { - return { - x: touch.pageX - util.getAbsoluteLeft(this.frame.canvas), - y: touch.pageY - util.getAbsoluteTop(this.frame.canvas) - }; + exports._loadSelectionSystem = function () { + this.selectionObj = {nodes: {}, edges: {}}; + + this._loadMixin(SelectionMixin); }; + /** - * On start of a touch gesture, store the pointer - * @param event + * Mixin the navigationUI (User Interface) system and initialize the parameters required + * * @private */ - Network.prototype._onTouch = function (event) { - if (new Date().valueOf() - this.touchTime > 100) { - this.drag.pointer = this._getPointer(event.gesture.center); - this.drag.pinched = false; - this.pinch.scale = this._getScale(); + exports._loadManipulationSystem = function () { + // reset global variables -- these are used by the selection of nodes and edges. + this.blockConnectingEdgeSelection = false; + this.forceAppendSelection = false; - // to avoid double fireing of this event because we have two hammer instances. (on canvas and on frame) - this.touchTime = new Date().valueOf(); + if (this.constants.dataManipulation.enabled == true) { + // load the manipulator HTML elements. All styling done in css. + if (this.manipulationDiv === undefined) { + this.manipulationDiv = document.createElement('div'); + this.manipulationDiv.className = 'network-manipulationDiv'; + if (this.editMode == true) { + this.manipulationDiv.style.display = "block"; + } + else { + this.manipulationDiv.style.display = "none"; + } + this.frame.appendChild(this.manipulationDiv); + } - this._handleTouch(this.drag.pointer); + if (this.editModeDiv === undefined) { + this.editModeDiv = document.createElement('div'); + this.editModeDiv.className = 'network-manipulation-editMode'; + if (this.editMode == true) { + this.editModeDiv.style.display = "none"; + } + else { + this.editModeDiv.style.display = "block"; + } + this.frame.appendChild(this.editModeDiv); + } + + if (this.closeDiv === undefined) { + this.closeDiv = document.createElement('div'); + this.closeDiv.className = 'network-manipulation-closeDiv'; + this.closeDiv.style.display = this.manipulationDiv.style.display; + this.frame.appendChild(this.closeDiv); + } + + // load the manipulation functions + this._loadMixin(ManipulationMixin); + + // create the manipulator toolbar + this._createManipulatorBar(); + } + else { + if (this.manipulationDiv !== undefined) { + // removes all the bindings and overloads + this._createManipulatorBar(); + + // remove the manipulation divs + this.frame.removeChild(this.manipulationDiv); + this.frame.removeChild(this.editModeDiv); + this.frame.removeChild(this.closeDiv); + + this.manipulationDiv = undefined; + this.editModeDiv = undefined; + this.closeDiv = undefined; + // remove the mixin functions + this._clearMixin(ManipulationMixin); + } } }; + /** - * handle drag start event + * Mixin the navigation (User Interface) system and initialize the parameters required + * * @private */ - Network.prototype._onDragStart = function (event) { - this._handleDragStart(event); + exports._loadNavigationControls = function () { + this._loadMixin(NavigationMixin); + // the clean function removes the button divs, this is done to remove the bindings. + this._cleanNavigation(); + if (this.constants.navigation.enabled == true) { + this._loadNavigationElements(); + } }; /** - * This function is called by _onDragStart. - * It is separated out because we can then overload it for the datamanipulation system. + * Mixin the hierarchical layout system. * * @private */ - Network.prototype._handleDragStart = function(event) { - // in case the touch event was triggered on an external div, do the initial touch now. - if (this.drag.pointer === undefined) { - this._onTouch(event); - } + exports._loadHierarchySystem = function () { + this._loadMixin(HierarchicalLayoutMixin); + }; - var node = this._getNodeAt(this.drag.pointer); - // note: drag.pointer is set in _onTouch to get the initial touch location - this.drag.dragging = true; - this.drag.selection = []; - this.drag.translation = this._getTranslation(); - this.drag.nodeId = null; - this.draggingNodes = false; +/***/ }, +/* 55 */ +/***/ function(module, exports, __webpack_require__) { - if (node != null && this.constants.dragNodes == true) { - this.draggingNodes = true; - this.drag.nodeId = node.id; - // select the clicked node if not yet selected - if (!node.isSelected()) { - this._selectObject(node,false); + var keycharm = __webpack_require__(59); + var Emitter = __webpack_require__(56); + var Hammer = __webpack_require__(45); + var util = __webpack_require__(1); + + /** + * Turn an element into an clickToUse element. + * When not active, the element has a transparent overlay. When the overlay is + * clicked, the mode is changed to active. + * When active, the element is displayed with a blue border around it, and + * the interactive contents of the element can be used. When clicked outside + * the element, the elements mode is changed to inactive. + * @param {Element} container + * @constructor + */ + function Activator(container) { + this.active = false; + + this.dom = { + container: container + }; + + this.dom.overlay = document.createElement('div'); + this.dom.overlay.className = 'overlay'; + + this.dom.container.appendChild(this.dom.overlay); + + this.hammer = Hammer(this.dom.overlay, {prevent_default: false}); + this.hammer.on('tap', this._onTapOverlay.bind(this)); + + // block all touch events (except tap) + var me = this; + var events = [ + 'touch', 'pinch', + 'doubletap', 'hold', + 'dragstart', 'drag', 'dragend', + 'mousewheel', 'DOMMouseScroll' // DOMMouseScroll is needed for Firefox + ]; + events.forEach(function (event) { + me.hammer.on(event, function (event) { + event.stopPropagation(); + }); + }); + + // attach a tap event to the window, in order to deactivate when clicking outside the timeline + this.windowHammer = Hammer(window, {prevent_default: false}); + this.windowHammer.on('tap', function (event) { + // deactivate when clicked outside the container + if (!_hasParent(event.target, container)) { + me.deactivate(); } + }); - this.emit("dragStart",{nodeIds:this.getSelection().nodes}); + if (this.keycharm !== undefined) { + this.keycharm.destroy(); + } + this.keycharm = keycharm(); - // create an array with the selected nodes and their original location and status - for (var objectId in this.selectionObj.nodes) { - if (this.selectionObj.nodes.hasOwnProperty(objectId)) { - var object = this.selectionObj.nodes[objectId]; - var s = { - id: object.id, - node: object, + // keycharm listener only bounded when active) + this.escListener = this.deactivate.bind(this); + } - // store original x, y, xFixed and yFixed, make the node temporarily Fixed - x: object.x, - y: object.y, - xFixed: object.xFixed, - yFixed: object.yFixed - }; + // turn into an event emitter + Emitter(Activator.prototype); - object.xFixed = true; - object.yFixed = true; + // The currently active activator + Activator.current = null; + + /** + * Destroy the activator. Cleans up all created DOM and event listeners + */ + Activator.prototype.destroy = function () { + this.deactivate(); + + // remove dom + this.dom.overlay.parentNode.removeChild(this.dom.overlay); + + // cleanup hammer instances + this.hammer = null; + this.windowHammer = null; + // FIXME: cleaning up hammer instances doesn't work (Timeline not removed from memory) + }; + + /** + * Activate the element + * Overlay is hidden, element is decorated with a blue shadow border + */ + Activator.prototype.activate = function () { + // we allow only one active activator at a time + if (Activator.current) { + Activator.current.deactivate(); + } + Activator.current = this; + + this.active = true; + this.dom.overlay.style.display = 'none'; + util.addClassName(this.dom.container, 'vis-active'); + + this.emit('change'); + this.emit('activate'); - this.drag.selection.push(s); - } - } - } + // ugly hack: bind ESC after emitting the events, as the Network rebinds all + // keyboard events on a 'change' event + this.keycharm.bind('esc', this.escListener); }; + /** + * Deactivate the element + * Overlay is displayed on top of the element + */ + Activator.prototype.deactivate = function () { + this.active = false; + this.dom.overlay.style.display = ''; + util.removeClassName(this.dom.container, 'vis-active'); + this.keycharm.unbind('esc', this.escListener); + + this.emit('change'); + this.emit('deactivate'); + }; /** - * handle drag event + * Handle a tap event: activate the container + * @param event * @private */ - Network.prototype._onDrag = function (event) { - this._handleOnDrag(event) + Activator.prototype._onTapOverlay = function (event) { + // activate the container + this.activate(); + event.stopPropagation(); }; - /** - * This function is called by _onDrag. - * It is separated out because we can then overload it for the datamanipulation system. - * + * Test whether the element has the requested parent element somewhere in + * its chain of parent nodes. + * @param {HTMLElement} element + * @param {HTMLElement} parent + * @returns {boolean} Returns true when the parent is found somewhere in the + * chain of parent nodes. * @private */ - Network.prototype._handleOnDrag = function(event) { - if (this.drag.pinched) { - return; + function _hasParent(element, parent) { + while (element) { + if (element === parent) { + return true + } + element = element.parentNode; } + return false; + } - // remove the focus on node if it is focussed on by the focusOnNode - this.releaseNode(); - - var pointer = this._getPointer(event.gesture.center); - var me = this; - var drag = this.drag; - var selection = drag.selection; - if (selection && selection.length && this.constants.dragNodes == true) { - // calculate delta's and new location - var deltaX = pointer.x - drag.pointer.x; - var deltaY = pointer.y - drag.pointer.y; - - // update position of all selected nodes - selection.forEach(function (s) { - var node = s.node; - - if (!s.xFixed) { - node.x = me._XconvertDOMtoCanvas(me._XconvertCanvasToDOM(s.x) + deltaX); - } - - if (!s.yFixed) { - node.y = me._YconvertDOMtoCanvas(me._YconvertCanvasToDOM(s.y) + deltaY); - } - }); - + module.exports = Activator; - // start _animationStep if not yet running - if (!this.moving) { - this.moving = true; - this.start(); - } - } - else { - // move the network - if (this.constants.dragNetwork == true) { - // if the drag was not started properly because the click started outside the network div, start it now. - if (this.drag.pointer === undefined) { - this._handleDragStart(event); - return; - } - var diffX = pointer.x - this.drag.pointer.x; - var diffY = pointer.y - this.drag.pointer.y; - this._setTranslation( - this.drag.translation.x + diffX, - this.drag.translation.y + diffY - ); - this._redraw(); - } - } - }; +/***/ }, +/* 56 */ +/***/ function(module, exports, __webpack_require__) { + /** - * handle drag start event - * @private + * Expose `Emitter`. */ - Network.prototype._onDragEnd = function (event) { - this._handleDragEnd(event); - }; - - Network.prototype._handleDragEnd = function(event) { - this.drag.dragging = false; - var selection = this.drag.selection; - if (selection && selection.length) { - selection.forEach(function (s) { - // restore original xFixed and yFixed - s.node.xFixed = s.xFixed; - s.node.yFixed = s.yFixed; - }); - this.moving = true; - this.start(); - } - else { - this._redraw(); - } - if (this.draggingNodes == false) { - this.emit("dragEnd",{nodeIds:[]}); - } - else { - this.emit("dragEnd",{nodeIds:this.getSelection().nodes}); - } + module.exports = Emitter; - } /** - * handle tap/click event: select/unselect a node - * @private + * Initialize a new `Emitter`. + * + * @api public */ - Network.prototype._onTap = function (event) { - var pointer = this._getPointer(event.gesture.center); - this.pointerPosition = pointer; - this._handleTap(pointer); + function Emitter(obj) { + if (obj) return mixin(obj); }; - /** - * handle doubletap event - * @private + * Mixin the emitter properties. + * + * @param {Object} obj + * @return {Object} + * @api private */ - Network.prototype._onDoubleTap = function (event) { - var pointer = this._getPointer(event.gesture.center); - this._handleDoubleTap(pointer); - }; + function mixin(obj) { + for (var key in Emitter.prototype) { + obj[key] = Emitter.prototype[key]; + } + return obj; + } /** - * handle long tap event: multi select nodes - * @private + * Listen on the given `event` with `fn`. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public */ - Network.prototype._onHold = function (event) { - var pointer = this._getPointer(event.gesture.center); - this.pointerPosition = pointer; - this._handleOnHold(pointer); + + Emitter.prototype.on = + Emitter.prototype.addEventListener = function(event, fn){ + this._callbacks = this._callbacks || {}; + (this._callbacks[event] = this._callbacks[event] || []) + .push(fn); + return this; }; /** - * handle the release of the screen + * Adds an `event` listener that will be invoked a single + * time then automatically removed. * - * @private + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public */ - Network.prototype._onRelease = function (event) { - var pointer = this._getPointer(event.gesture.center); - this._handleOnRelease(pointer); - }; - /** - * Handle pinch event - * @param event - * @private - */ - Network.prototype._onPinch = function (event) { - var pointer = this._getPointer(event.gesture.center); + Emitter.prototype.once = function(event, fn){ + var self = this; + this._callbacks = this._callbacks || {}; - this.drag.pinched = true; - if (!('scale' in this.pinch)) { - this.pinch.scale = 1; + function on() { + self.off(event, on); + fn.apply(this, arguments); } - // TODO: enabled moving while pinching? - var scale = this.pinch.scale * event.gesture.scale; - this._zoom(scale, pointer) + on.fn = fn; + this.on(event, on); + return this; }; /** - * Zoom the network in or out - * @param {Number} scale a number around 1, and between 0.01 and 10 - * @param {{x: Number, y: Number}} pointer Position on screen - * @return {Number} appliedScale scale is limited within the boundaries - * @private + * Remove the given callback for `event` or all + * registered callbacks. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public */ - Network.prototype._zoom = function(scale, pointer) { - if (this.constants.zoomable == true) { - var scaleOld = this._getScale(); - if (scale < 0.00001) { - scale = 0.00001; - } - if (scale > 10) { - scale = 10; - } - - var preScaleDragPointer = null; - if (this.drag !== undefined) { - if (this.drag.dragging == true) { - preScaleDragPointer = this.DOMtoCanvas(this.drag.pointer); - } - } - // + this.frame.canvas.clientHeight / 2 - var translation = this._getTranslation(); - - var scaleFrac = scale / scaleOld; - var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac; - var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac; - this.areaCenter = {"x" : this._XconvertDOMtoCanvas(pointer.x), - "y" : this._YconvertDOMtoCanvas(pointer.y)}; + Emitter.prototype.off = + Emitter.prototype.removeListener = + Emitter.prototype.removeAllListeners = + Emitter.prototype.removeEventListener = function(event, fn){ + this._callbacks = this._callbacks || {}; - this._setScale(scale); - this._setTranslation(tx, ty); - this.updateClustersDefault(); + // all + if (0 == arguments.length) { + this._callbacks = {}; + return this; + } - if (preScaleDragPointer != null) { - var postScaleDragPointer = this.canvasToDOM(preScaleDragPointer); - this.drag.pointer.x = postScaleDragPointer.x; - this.drag.pointer.y = postScaleDragPointer.y; - } + // specific event + var callbacks = this._callbacks[event]; + if (!callbacks) return this; - this._redraw(); + // remove all handlers + if (1 == arguments.length) { + delete this._callbacks[event]; + return this; + } - if (scaleOld < scale) { - this.emit("zoom", {direction:"+"}); - } - else { - this.emit("zoom", {direction:"-"}); + // remove specific handler + var cb; + for (var i = 0; i < callbacks.length; i++) { + cb = callbacks[i]; + if (cb === fn || cb.fn === fn) { + callbacks.splice(i, 1); + break; } - - return scale; } + return this; }; - /** - * Event handler for mouse wheel event, used to zoom the timeline - * See http://adomas.org/javascript-mouse-wheel/ - * https://github.com/EightMedia/hammer.js/issues/256 - * @param {MouseEvent} event - * @private + * Emit `event` with the given args. + * + * @param {String} event + * @param {Mixed} ... + * @return {Emitter} */ - Network.prototype._onMouseWheel = function(event) { - // retrieve delta - var delta = 0; - if (event.wheelDelta) { /* IE/Opera. */ - delta = event.wheelDelta/120; - } else if (event.detail) { /* Mozilla case. */ - // In Mozilla, sign of delta is different than in IE. - // Also, delta is multiple of 3. - delta = -event.detail/3; - } - // If delta is nonzero, handle it. - // Basically, delta is now positive if wheel was scrolled up, - // and negative, if wheel was scrolled down. - if (delta) { + Emitter.prototype.emit = function(event){ + this._callbacks = this._callbacks || {}; + var args = [].slice.call(arguments, 1) + , callbacks = this._callbacks[event]; - // calculate the new scale - var scale = this._getScale(); - var zoom = delta / 10; - if (delta < 0) { - zoom = zoom / (1 - zoom); + if (callbacks) { + callbacks = callbacks.slice(0); + for (var i = 0, len = callbacks.length; i < len; ++i) { + callbacks[i].apply(this, args); } - scale *= (1 + zoom); - - // calculate the pointer location - var gesture = hammerUtil.fakeGesture(this, event); - var pointer = this._getPointer(gesture.center); - - // apply the new scale - this._zoom(scale, pointer); } - // Prevent default actions caused by mouse wheel. - event.preventDefault(); + return this; }; + /** + * Return array of callbacks for `event`. + * + * @param {String} event + * @return {Array} + * @api public + */ + + Emitter.prototype.listeners = function(event){ + this._callbacks = this._callbacks || {}; + return this._callbacks[event] || []; + }; /** - * Mouse move handler for checking whether the title moves over a node with a title. - * @param {Event} event - * @private + * Check if this emitter has `event` handlers. + * + * @param {String} event + * @return {Boolean} + * @api public */ - Network.prototype._onMouseMoveTitle = function (event) { - var gesture = hammerUtil.fakeGesture(this, event); - var pointer = this._getPointer(gesture.center); - // check if the previously selected node is still selected - if (this.popupObj) { - this._checkHidePopup(pointer); - } + Emitter.prototype.hasListeners = function(event){ + return !! this.listeners(event).length; + }; - // start a timeout that will check if the mouse is positioned above - // an element - var me = this; - var checkShow = function() { - me._checkShowPopup(pointer); - }; - if (this.popupTimer) { - clearInterval(this.popupTimer); // stop any running calculationTimer - } - if (!this.drag.dragging) { - this.popupTimer = setTimeout(checkShow, this.constants.tooltip.delay); - } +/***/ }, +/* 57 */ +/***/ function(module, exports, __webpack_require__) { - /** - * Adding hover highlights - */ - if (this.constants.hover == true) { - // removing all hover highlights - for (var edgeId in this.hoverObj.edges) { - if (this.hoverObj.edges.hasOwnProperty(edgeId)) { - this.hoverObj.edges[edgeId].hover = false; - delete this.hoverObj.edges[edgeId]; - } - } + var __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(global, module) {//! moment.js + //! version : 2.9.0 + //! authors : Tim Wood, Iskren Chernev, Moment.js contributors + //! license : MIT + //! momentjs.com - // adding hover highlights - var obj = this._getNodeAt(pointer); - if (obj == null) { - obj = this._getEdgeAt(pointer); - } - if (obj != null) { - this._hoverObject(obj); - } + (function (undefined) { + /************************************ + Constants + ************************************/ - // removing all node hover highlights except for the selected one. - for (var nodeId in this.hoverObj.nodes) { - if (this.hoverObj.nodes.hasOwnProperty(nodeId)) { - if (obj instanceof Node && obj.id != nodeId || obj instanceof Edge || obj == null) { - this._blurObject(this.hoverObj.nodes[nodeId]); - delete this.hoverObj.nodes[nodeId]; - } - } - } - this.redraw(); - } - }; + var moment, + VERSION = '2.9.0', + // the global-scope this is NOT the global object in Node.js + globalScope = (typeof global !== 'undefined' && (typeof window === 'undefined' || window === global.window)) ? global : this, + oldGlobalMoment, + round = Math.round, + hasOwnProperty = Object.prototype.hasOwnProperty, + i, - /** - * Check if there is an element on the given position in the network - * (a node or edge). If so, and if this element has a title, - * show a popup window with its title. - * - * @param {{x:Number, y:Number}} pointer - * @private - */ - Network.prototype._checkShowPopup = function (pointer) { - var obj = { - left: this._XconvertDOMtoCanvas(pointer.x), - top: this._YconvertDOMtoCanvas(pointer.y), - right: this._XconvertDOMtoCanvas(pointer.x), - bottom: this._YconvertDOMtoCanvas(pointer.y) - }; + YEAR = 0, + MONTH = 1, + DATE = 2, + HOUR = 3, + MINUTE = 4, + SECOND = 5, + MILLISECOND = 6, - var id; - var lastPopupNode = this.popupObj; - var nodeUnderCursor = false; + // internal storage for locale config files + locales = {}, - if (this.popupObj == undefined) { - // search the nodes for overlap, select the top one in case of multiple nodes - var nodes = this.nodes; - var overlappingNodes = []; - for (id in nodes) { - if (nodes.hasOwnProperty(id)) { - var node = nodes[id]; - if (node.isOverlappingWith(obj)) { - if (node.getTitle() !== undefined) { - overlappingNodes.push(id); - } - } - } - } + // extra moment internal properties (plugins register props here) + momentProperties = [], - if (overlappingNodes.length > 0) { - // if there are overlapping nodes, select the last one, this is the - // one which is drawn on top of the others - this.popupObj = this.nodes[overlappingNodes[overlappingNodes.length - 1]]; - // if you hover over a node, the title of the edge is not supposed to be shown. - nodeUnderCursor = true; - } - } + // check for nodeJS + hasModule = (typeof module !== 'undefined' && module && module.exports), - if (this.popupObj === undefined && nodeUnderCursor == false) { - // search the edges for overlap - var edges = this.edges; - var overlappingEdges = []; - for (id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - if (edge.connected && (edge.getTitle() !== undefined) && - edge.isOverlappingWith(obj)) { - overlappingEdges.push(id); - } - } - } + // ASP.NET json date format regex + aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, + aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/, + + // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html + // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere + isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/, + + // format tokens + formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|x|X|zz?|ZZ?|.)/g, + localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, - if (overlappingEdges.length > 0) { - this.popupObj = this.edges[overlappingEdges[overlappingEdges.length - 1]]; - } - } + // parsing token regexes + parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 + parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 + parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999 + parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 + parseTokenDigits = /\d+/, // nonzero number of digits + parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic. + parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z + parseTokenT = /T/i, // T (ISO separator) + parseTokenOffsetMs = /[\+\-]?\d+/, // 1234567890123 + parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 - if (this.popupObj) { - // show popup message window - if (this.popupObj != lastPopupNode) { - var me = this; - if (!me.popup) { - me.popup = new Popup(me.frame, me.constants.tooltip); - } + //strict parsing regexes + parseTokenOneDigit = /\d/, // 0 - 9 + parseTokenTwoDigits = /\d\d/, // 00 - 99 + parseTokenThreeDigits = /\d{3}/, // 000 - 999 + parseTokenFourDigits = /\d{4}/, // 0000 - 9999 + parseTokenSixDigits = /[+-]?\d{6}/, // -999,999 - 999,999 + parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf - // adjust a small offset such that the mouse cursor is located in the - // bottom left location of the popup, and you can easily move over the - // popup area - me.popup.setPosition(pointer.x - 3, pointer.y - 3); - me.popup.setText(me.popupObj.getTitle()); - me.popup.show(); - } - } - else { - if (this.popup) { - this.popup.hide(); - } - } - }; + // iso 8601 regex + // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) + isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/, + isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', - /** - * Check if the popup must be hided, which is the case when the mouse is no - * longer hovering on the object - * @param {{x:Number, y:Number}} pointer - * @private - */ - Network.prototype._checkHidePopup = function (pointer) { - if (!this.popupObj || !this._getNodeAt(pointer) ) { - this.popupObj = undefined; - if (this.popup) { - this.popup.hide(); - } - } - }; + isoDates = [ + ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/], + ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/], + ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/], + ['GGGG-[W]WW', /\d{4}-W\d{2}/], + ['YYYY-DDD', /\d{4}-\d{3}/] + ], + // iso time formats and regexes + isoTimes = [ + ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d+/], + ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], + ['HH:mm', /(T| )\d\d:\d\d/], + ['HH', /(T| )\d\d/] + ], - /** - * Set a new size for the network - * @param {string} width Width in pixels or percentage (for example '800px' - * or '50%') - * @param {string} height Height in pixels or percentage (for example '400px' - * or '30%') - */ - Network.prototype.setSize = function(width, height) { - var emitEvent = false; - var oldWidth = this.frame.canvas.width; - var oldHeight = this.frame.canvas.height; - if (width != this.constants.width || height != this.constants.height || this.frame.style.width != width || this.frame.style.height != height) { - this.frame.style.width = width; - this.frame.style.height = height; + // timezone chunker '+10:00' > ['10', '00'] or '-1530' > ['-', '15', '30'] + parseTimezoneChunker = /([\+\-]|\d\d)/gi, - this.frame.canvas.style.width = '100%'; - this.frame.canvas.style.height = '100%'; + // getter and setter names + proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), + unitMillisecondFactors = { + 'Milliseconds' : 1, + 'Seconds' : 1e3, + 'Minutes' : 6e4, + 'Hours' : 36e5, + 'Days' : 864e5, + 'Months' : 2592e6, + 'Years' : 31536e6 + }, - this.frame.canvas.width = this.frame.canvas.clientWidth * this.pixelRatio; - this.frame.canvas.height = this.frame.canvas.clientHeight * this.pixelRatio; + unitAliases = { + ms : 'millisecond', + s : 'second', + m : 'minute', + h : 'hour', + d : 'day', + D : 'date', + w : 'week', + W : 'isoWeek', + M : 'month', + Q : 'quarter', + y : 'year', + DDD : 'dayOfYear', + e : 'weekday', + E : 'isoWeekday', + gg: 'weekYear', + GG: 'isoWeekYear' + }, - this.constants.width = width; - this.constants.height = height; + camelFunctions = { + dayofyear : 'dayOfYear', + isoweekday : 'isoWeekday', + isoweek : 'isoWeek', + weekyear : 'weekYear', + isoweekyear : 'isoWeekYear' + }, - emitEvent = true; - } - else { - // this would adapt the width of the canvas to the width from 100% if and only if - // there is a change. + // format function strings + formatFunctions = {}, - if (this.frame.canvas.width != this.frame.canvas.clientWidth * this.pixelRatio) { - this.frame.canvas.width = this.frame.canvas.clientWidth * this.pixelRatio; - emitEvent = true; - } - if (this.frame.canvas.height != this.frame.canvas.clientHeight * this.pixelRatio) { - this.frame.canvas.height = this.frame.canvas.clientHeight * this.pixelRatio; - emitEvent = true; - } - } + // default relative time thresholds + relativeTimeThresholds = { + 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 + }, - if (emitEvent == true) { - this.emit('resize', {width:this.frame.canvas.width * this.pixelRatio,height:this.frame.canvas.height * this.pixelRatio, oldWidth: oldWidth * this.pixelRatio, oldHeight: oldHeight * this.pixelRatio}); - } - }; + // tokens to ordinalize and pad + ordinalizeTokens = 'DDD w W M D d'.split(' '), + paddedTokens = 'M D H h m s w W'.split(' '), - /** - * Set a data set with nodes for the network - * @param {Array | DataSet | DataView} nodes The data containing the nodes. - * @private - */ - Network.prototype._setNodes = function(nodes) { - var oldNodesData = this.nodesData; + formatTokenFunctions = { + M : function () { + return this.month() + 1; + }, + MMM : function (format) { + return this.localeData().monthsShort(this, format); + }, + MMMM : function (format) { + return this.localeData().months(this, format); + }, + D : function () { + return this.date(); + }, + DDD : function () { + return this.dayOfYear(); + }, + d : function () { + return this.day(); + }, + dd : function (format) { + return this.localeData().weekdaysMin(this, format); + }, + ddd : function (format) { + return this.localeData().weekdaysShort(this, format); + }, + dddd : function (format) { + return this.localeData().weekdays(this, format); + }, + w : function () { + return this.week(); + }, + W : function () { + return this.isoWeek(); + }, + YY : function () { + return leftZeroFill(this.year() % 100, 2); + }, + YYYY : function () { + return leftZeroFill(this.year(), 4); + }, + YYYYY : function () { + return leftZeroFill(this.year(), 5); + }, + YYYYYY : function () { + var y = this.year(), sign = y >= 0 ? '+' : '-'; + return sign + leftZeroFill(Math.abs(y), 6); + }, + gg : function () { + return leftZeroFill(this.weekYear() % 100, 2); + }, + gggg : function () { + return leftZeroFill(this.weekYear(), 4); + }, + ggggg : function () { + return leftZeroFill(this.weekYear(), 5); + }, + GG : function () { + return leftZeroFill(this.isoWeekYear() % 100, 2); + }, + GGGG : function () { + return leftZeroFill(this.isoWeekYear(), 4); + }, + GGGGG : function () { + return leftZeroFill(this.isoWeekYear(), 5); + }, + e : function () { + return this.weekday(); + }, + E : function () { + return this.isoWeekday(); + }, + a : function () { + return this.localeData().meridiem(this.hours(), this.minutes(), true); + }, + A : function () { + return this.localeData().meridiem(this.hours(), this.minutes(), false); + }, + H : function () { + return this.hours(); + }, + h : function () { + return this.hours() % 12 || 12; + }, + m : function () { + return this.minutes(); + }, + s : function () { + return this.seconds(); + }, + S : function () { + return toInt(this.milliseconds() / 100); + }, + SS : function () { + return leftZeroFill(toInt(this.milliseconds() / 10), 2); + }, + SSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + SSSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + Z : function () { + var a = this.utcOffset(), + b = '+'; + if (a < 0) { + a = -a; + b = '-'; + } + return b + leftZeroFill(toInt(a / 60), 2) + ':' + leftZeroFill(toInt(a) % 60, 2); + }, + ZZ : function () { + var a = this.utcOffset(), + b = '+'; + if (a < 0) { + a = -a; + b = '-'; + } + return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2); + }, + z : function () { + return this.zoneAbbr(); + }, + zz : function () { + return this.zoneName(); + }, + x : function () { + return this.valueOf(); + }, + X : function () { + return this.unix(); + }, + Q : function () { + return this.quarter(); + } + }, - if (nodes instanceof DataSet || nodes instanceof DataView) { - this.nodesData = nodes; - } - else if (Array.isArray(nodes)) { - this.nodesData = new DataSet(); - this.nodesData.add(nodes); - } - else if (!nodes) { - this.nodesData = new DataSet(); - } - else { - throw new TypeError('Array or DataSet expected'); - } + deprecations = {}, - if (oldNodesData) { - // unsubscribe from old dataset - util.forEach(this.nodesListeners, function (callback, event) { - oldNodesData.off(event, callback); - }); - } + lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin'], - // remove drawn nodes - this.nodes = {}; + updateInProgress = false; - if (this.nodesData) { - // subscribe to new dataset - var me = this; - util.forEach(this.nodesListeners, function (callback, event) { - me.nodesData.on(event, callback); - }); + // Pick the first defined of two or three arguments. dfl comes from + // default. + function dfl(a, b, c) { + 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'); + } + } - // draw all new nodes - var ids = this.nodesData.getIds(); - this._addNodes(ids); - } - this._updateSelection(); - }; + function hasOwnProp(a, b) { + return hasOwnProperty.call(a, b); + } - /** - * Add nodes - * @param {Number[] | String[]} ids - * @private - */ - Network.prototype._addNodes = function(ids) { - var id; - for (var i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - var data = this.nodesData.get(id); - var node = new Node(data, this.images, this.groups, this.constants); - this.nodes[id] = node; // note: this may replace an existing node - if ((node.xFixed == false || node.yFixed == false) && (node.x === null || node.y === null)) { - var radius = 10 * 0.1*ids.length + 10; - var angle = 2 * Math.PI * Math.random(); - if (node.xFixed == false) {node.x = radius * Math.cos(angle);} - if (node.yFixed == false) {node.y = radius * Math.sin(angle);} + function defaultParsingFlags() { + // We need to deep clone this object, and es5 standard is not very + // helpful. + return { + empty : false, + unusedTokens : [], + unusedInput : [], + overflow : -2, + charsLeftOver : 0, + nullInput : false, + invalidMonth : null, + invalidFormat : false, + userInvalidated : false, + iso: false + }; } - this.moving = true; - } - this._updateNodeIndexList(); - if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { - this._resetLevels(); - this._setupHierarchicalLayout(); - } - this._updateCalculationNodes(); - this._reconnectEdges(); - this._updateValueRange(this.nodes); - this.updateLabels(); - }; + function printMsg(msg) { + if (moment.suppressDeprecationWarnings === false && + typeof console !== 'undefined' && console.warn) { + console.warn('Deprecation warning: ' + msg); + } + } - /** - * Update existing nodes, or create them when not yet existing - * @param {Number[] | String[]} ids - * @private - */ - Network.prototype._updateNodes = function(ids,changedData) { - var nodes = this.nodes; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - var node = nodes[id]; - var data = changedData[i]; - if (node) { - // update node - node.setProperties(data, this.constants); + function deprecate(msg, fn) { + var firstTime = true; + return extend(function () { + if (firstTime) { + printMsg(msg); + firstTime = false; + } + return fn.apply(this, arguments); + }, fn); } - else { - // create node - node = new Node(properties, this.images, this.groups, this.constants); - nodes[id] = node; + + function deprecateSimple(name, msg) { + if (!deprecations[name]) { + printMsg(msg); + deprecations[name] = true; + } } - } - this.moving = true; - if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { - this._resetLevels(); - this._setupHierarchicalLayout(); - } - this._updateNodeIndexList(); - this._updateValueRange(nodes); - }; - /** - * Remove existing nodes. If nodes do not exist, the method will just ignore it. - * @param {Number[] | String[]} ids - * @private - */ - Network.prototype._removeNodes = function(ids) { - var nodes = this.nodes; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - delete nodes[id]; - } - this._updateNodeIndexList(); - if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { - this._resetLevels(); - this._setupHierarchicalLayout(); - } - this._updateCalculationNodes(); - this._reconnectEdges(); - this._updateSelection(); - this._updateValueRange(nodes); - }; + function padToken(func, count) { + return function (a) { + return leftZeroFill(func.call(this, a), count); + }; + } + function ordinalizeToken(func, period) { + return function (a) { + return this.localeData().ordinal(func.call(this, a), period); + }; + } - /** - * Load edges by reading the data table - * @param {Array | DataSet | DataView} edges The data containing the edges. - * @private - * @private - */ - Network.prototype._setEdges = function(edges) { - var oldEdgesData = this.edgesData; + function monthDiff(a, b) { + // difference in months + var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()), + // b is in (anchor - 1 month, anchor + 1 month) + anchor = a.clone().add(wholeMonthDiff, 'months'), + anchor2, adjust; - if (edges instanceof DataSet || edges instanceof DataView) { - this.edgesData = edges; - } - else if (Array.isArray(edges)) { - this.edgesData = new DataSet(); - this.edgesData.add(edges); - } - else if (!edges) { - this.edgesData = new DataSet(); - } - else { - throw new TypeError('Array or DataSet expected'); - } + if (b - anchor < 0) { + anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor - anchor2); + } else { + anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor2 - anchor); + } - if (oldEdgesData) { - // unsubscribe from old dataset - util.forEach(this.edgesListeners, function (callback, event) { - oldEdgesData.off(event, callback); - }); - } + return -(wholeMonthDiff + adjust); + } - // remove drawn edges - this.edges = {}; + while (ordinalizeTokens.length) { + i = ordinalizeTokens.pop(); + formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i); + } + while (paddedTokens.length) { + i = paddedTokens.pop(); + formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); + } + formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); - if (this.edgesData) { - // subscribe to new dataset - var me = this; - util.forEach(this.edgesListeners, function (callback, event) { - me.edgesData.on(event, callback); - }); - // draw all new nodes - var ids = this.edgesData.getIds(); - this._addEdges(ids); - } + function meridiemFixWrap(locale, hour, meridiem) { + var isPm; - this._reconnectEdges(); - }; + if (meridiem == null) { + // nothing to do + return hour; + } + if (locale.meridiemHour != null) { + return locale.meridiemHour(hour, meridiem); + } else if (locale.isPM != null) { + // Fallback + isPm = locale.isPM(meridiem); + if (isPm && hour < 12) { + hour += 12; + } + if (!isPm && hour === 12) { + hour = 0; + } + return hour; + } else { + // thie is not supposed to happen + return hour; + } + } - /** - * Add edges - * @param {Number[] | String[]} ids - * @private - */ - Network.prototype._addEdges = function (ids) { - var edges = this.edges, - edgesData = this.edgesData; + /************************************ + Constructors + ************************************/ - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; + function Locale() { + } - var oldEdge = edges[id]; - if (oldEdge) { - oldEdge.disconnect(); + // Moment prototype object + function Moment(config, skipOverflow) { + if (skipOverflow !== false) { + checkOverflow(config); + } + copyConfig(this, config); + this._d = new Date(+config._d); + // Prevent infinite loop in case updateOffset creates new moment + // objects. + if (updateInProgress === false) { + updateInProgress = true; + moment.updateOffset(this); + updateInProgress = false; + } } - var data = edgesData.get(id, {"showInternalIds" : true}); - edges[id] = new Edge(data, this, this.constants); - } - this.moving = true; - this._updateValueRange(edges); - this._createBezierNodes(); - this._updateCalculationNodes(); - if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { - this._resetLevels(); - this._setupHierarchicalLayout(); - } - }; + // Duration Constructor + function Duration(duration) { + var normalizedInput = normalizeObjectUnits(duration), + years = normalizedInput.year || 0, + quarters = normalizedInput.quarter || 0, + months = normalizedInput.month || 0, + weeks = normalizedInput.week || 0, + days = normalizedInput.day || 0, + hours = normalizedInput.hour || 0, + minutes = normalizedInput.minute || 0, + seconds = normalizedInput.second || 0, + milliseconds = normalizedInput.millisecond || 0; - /** - * Update existing edges, or create them when not yet existing - * @param {Number[] | String[]} ids - * @private - */ - Network.prototype._updateEdges = function (ids) { - var edges = this.edges, - edgesData = this.edgesData; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; + // representation for dateAddRemove + this._milliseconds = +milliseconds + + seconds * 1e3 + // 1000 + minutes * 6e4 + // 1000 * 60 + hours * 36e5; // 1000 * 60 * 60 + // Because of dateAddRemove treats 24 hours as different from a + // day when working around DST, we need to store them separately + this._days = +days + + weeks * 7; + // It is impossible translate months into days without knowing + // which months you are are talking about, so we have to store + // it separately. + this._months = +months + + quarters * 3 + + years * 12; - var data = edgesData.get(id); - var edge = edges[id]; - if (edge) { - // update edge - edge.disconnect(); - edge.setProperties(data, this.constants); - edge.connect(); - } - else { - // create edge - edge = new Edge(data, this, this.constants); - this.edges[id] = edge; - } - } + this._data = {}; - this._createBezierNodes(); - if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { - this._resetLevels(); - this._setupHierarchicalLayout(); - } - this.moving = true; - this._updateValueRange(edges); - }; + this._locale = moment.localeData(); - /** - * Remove existing edges. Non existing ids will be ignored - * @param {Number[] | String[]} ids - * @private - */ - Network.prototype._removeEdges = function (ids) { - var edges = this.edges; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - var edge = edges[id]; - if (edge) { - if (edge.via != null) { - delete this.sectors['support']['nodes'][edge.via.id]; - } - edge.disconnect(); - delete edges[id]; + this._bubble(); } - } - this.moving = true; - this._updateValueRange(edges); - if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { - this._resetLevels(); - this._setupHierarchicalLayout(); - } - this._updateCalculationNodes(); - }; + /************************************ + Helpers + ************************************/ - /** - * Reconnect all edges - * @private - */ - Network.prototype._reconnectEdges = function() { - var id, - nodes = this.nodes, - edges = this.edges; - for (id in nodes) { - if (nodes.hasOwnProperty(id)) { - nodes[id].edges = []; - nodes[id].dynamicEdges = []; - } - } - for (id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - edge.from = null; - edge.to = null; - edge.connect(); - } - } - }; + function extend(a, b) { + for (var i in b) { + if (hasOwnProp(b, i)) { + a[i] = b[i]; + } + } - /** - * Update the values of all object in the given array according to the current - * value range of the objects in the array. - * @param {Object} obj An object containing a set of Edges or Nodes - * The objects must have a method getValue() and - * setValueRange(min, max). - * @private - */ - Network.prototype._updateValueRange = function(obj) { - var id; + if (hasOwnProp(b, 'toString')) { + a.toString = b.toString; + } - // determine the range of the objects - var valueMin = undefined; - var valueMax = undefined; - for (id in obj) { - if (obj.hasOwnProperty(id)) { - var value = obj[id].getValue(); - if (value !== undefined) { - valueMin = (valueMin === undefined) ? value : Math.min(value, valueMin); - valueMax = (valueMax === undefined) ? value : Math.max(value, valueMax); - } - } - } + if (hasOwnProp(b, 'valueOf')) { + a.valueOf = b.valueOf; + } - // adjust the range of all objects - if (valueMin !== undefined && valueMax !== undefined) { - for (id in obj) { - if (obj.hasOwnProperty(id)) { - obj[id].setValueRange(valueMin, valueMax); - } + return a; } - } - }; - /** - * Redraw the network with the current data - * chart will be resized too. - */ - Network.prototype.redraw = function() { - this.setSize(this.constants.width, this.constants.height); - this._redraw(); - }; + function copyConfig(to, from) { + var i, prop, val; - /** - * Redraw the network with the current data - * @param hidden | used to get the first estimate of the node sizes. only the nodes are drawn after which they are quickly drawn over. - * @private - */ - Network.prototype._redraw = function(hidden) { - var ctx = this.frame.canvas.getContext('2d'); + 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; + } - ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); + if (momentProperties.length > 0) { + for (i in momentProperties) { + prop = momentProperties[i]; + val = from[prop]; + if (typeof val !== 'undefined') { + to[prop] = val; + } + } + } - // clear the canvas - var w = this.frame.canvas.width * this.pixelRatio; - var h = this.frame.canvas.height * this.pixelRatio; - ctx.clearRect(0, 0, w, h); + return to; + } - // set scaling and translation - ctx.save(); - ctx.translate(this.translation.x, this.translation.y); - ctx.scale(this.scale, this.scale); + function absRound(number) { + if (number < 0) { + return Math.ceil(number); + } else { + return Math.floor(number); + } + } - this.canvasTopLeft = { - "x": this._XconvertDOMtoCanvas(0), - "y": this._YconvertDOMtoCanvas(0) - }; - this.canvasBottomRight = { - "x": this._XconvertDOMtoCanvas(this.frame.canvas.clientWidth * this.pixelRatio), - "y": this._YconvertDOMtoCanvas(this.frame.canvas.clientHeight * this.pixelRatio) - }; + // left zero fill a number + // see http://jsperf.com/left-zero-filling for performance comparison + function leftZeroFill(number, targetLength, forceSign) { + var output = '' + Math.abs(number), + sign = number >= 0; - if (!(hidden == true)) { - this._doInAllSectors("_drawAllSectorNodes", ctx); - if (this.drag.dragging == false || this.drag.dragging === undefined || this.constants.hideEdgesOnDrag == false) { - this._doInAllSectors("_drawEdges", ctx); + while (output.length < targetLength) { + output = '0' + output; + } + return (sign ? (forceSign ? '+' : '') : '-') + output; } - } - if (this.drag.dragging == false || this.drag.dragging === undefined || this.constants.hideNodesOnDrag == false) { - this._doInAllSectors("_drawNodes",ctx,false); - } + function positiveMomentsDifference(base, other) { + var res = {milliseconds: 0, months: 0}; - if (!(hidden == true)) { - if (this.controlNodesActive == true) { - this._doInAllSectors("_drawControlNodes", ctx); + 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; } - } - // this._doInSupportSector("_drawNodes",ctx,true); - // this._drawTree(ctx,"#F00F0F"); + 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; + } - // restore original scaling and translation - ctx.restore(); + return res; + } - if (hidden == true) { - ctx.clearRect(0, 0, w, h); - } - }; + // 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; + } - /** - * Set the translation of the network - * @param {Number} offsetX Horizontal offset - * @param {Number} offsetY Vertical offset - * @private - */ - Network.prototype._setTranslation = function(offsetX, offsetY) { - if (this.translation === undefined) { - this.translation = { - x: 0, - y: 0 - }; - } + val = typeof val === 'string' ? +val : val; + dur = moment.duration(val, period); + addOrSubtractDurationFromMoment(this, dur, direction); + return this; + }; + } - if (offsetX !== undefined) { - this.translation.x = offsetX; - } - if (offsetY !== undefined) { - this.translation.y = offsetY; - } + function addOrSubtractDurationFromMoment(mom, duration, isAdding, updateOffset) { + var milliseconds = duration._milliseconds, + days = duration._days, + months = duration._months; + updateOffset = updateOffset == null ? true : updateOffset; - this.emit('viewChanged'); - }; + if (milliseconds) { + mom._d.setTime(+mom._d + milliseconds * isAdding); + } + if (days) { + rawSetter(mom, 'Date', rawGetter(mom, 'Date') + days * isAdding); + } + if (months) { + rawMonthSetter(mom, rawGetter(mom, 'Month') + months * isAdding); + } + if (updateOffset) { + moment.updateOffset(mom, days || months); + } + } - /** - * Get the translation of the network - * @return {Object} translation An object with parameters x and y, both a number - * @private - */ - Network.prototype._getTranslation = function() { - return { - x: this.translation.x, - y: this.translation.y - }; - }; + // check if is an array + function isArray(input) { + return Object.prototype.toString.call(input) === '[object Array]'; + } - /** - * Scale the network - * @param {Number} scale Scaling factor 1.0 is unscaled - * @private - */ - Network.prototype._setScale = function(scale) { - this.scale = scale; - }; + function isDate(input) { + return Object.prototype.toString.call(input) === '[object Date]' || + input instanceof Date; + } - /** - * Get the current scale of the network - * @return {Number} scale Scaling factor 1.0 is unscaled - * @private - */ - Network.prototype._getScale = function() { - return this.scale; - }; + // compare two arrays, return the number of differences + function compareArrays(array1, array2, dontConvert) { + var len = Math.min(array1.length, array2.length), + lengthDiff = Math.abs(array1.length - array2.length), + diffs = 0, + i; + for (i = 0; i < len; i++) { + if ((dontConvert && array1[i] !== array2[i]) || + (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { + diffs++; + } + } + return diffs + lengthDiff; + } - /** - * Convert the X coordinate in DOM-space (coordinate point in browser relative to the container div) to - * the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon) - * @param {number} x - * @returns {number} - * @private - */ - Network.prototype._XconvertDOMtoCanvas = function(x) { - return (x - this.translation.x) / this.scale; - }; + function normalizeUnits(units) { + if (units) { + var lowered = units.toLowerCase().replace(/(.)s$/, '$1'); + units = unitAliases[units] || camelFunctions[lowered] || lowered; + } + return units; + } + + function normalizeObjectUnits(inputObject) { + var normalizedInput = {}, + normalizedProp, + prop; - /** - * Convert the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to - * the X coordinate in DOM-space (coordinate point in browser relative to the container div) - * @param {number} x - * @returns {number} - * @private - */ - Network.prototype._XconvertCanvasToDOM = function(x) { - return x * this.scale + this.translation.x; - }; + for (prop in inputObject) { + if (hasOwnProp(inputObject, prop)) { + normalizedProp = normalizeUnits(prop); + if (normalizedProp) { + normalizedInput[normalizedProp] = inputObject[prop]; + } + } + } - /** - * Convert the Y coordinate in DOM-space (coordinate point in browser relative to the container div) to - * the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon) - * @param {number} y - * @returns {number} - * @private - */ - Network.prototype._YconvertDOMtoCanvas = function(y) { - return (y - this.translation.y) / this.scale; - }; + return normalizedInput; + } - /** - * Convert the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to - * the Y coordinate in DOM-space (coordinate point in browser relative to the container div) - * @param {number} y - * @returns {number} - * @private - */ - Network.prototype._YconvertCanvasToDOM = function(y) { - return y * this.scale + this.translation.y ; - }; + function makeList(field) { + var count, setter; + if (field.indexOf('week') === 0) { + count = 7; + setter = 'day'; + } + else if (field.indexOf('month') === 0) { + count = 12; + setter = 'month'; + } + else { + return; + } - /** - * - * @param {object} pos = {x: number, y: number} - * @returns {{x: number, y: number}} - * @constructor - */ - Network.prototype.canvasToDOM = function (pos) { - return {x: this._XconvertCanvasToDOM(pos.x), y: this._YconvertCanvasToDOM(pos.y)}; - }; + moment[field] = function (format, index) { + var i, getter, + method = moment._locale[field], + results = []; - /** - * - * @param {object} pos = {x: number, y: number} - * @returns {{x: number, y: number}} - * @constructor - */ - Network.prototype.DOMtoCanvas = function (pos) { - return {x: this._XconvertDOMtoCanvas(pos.x), y: this._YconvertDOMtoCanvas(pos.y)}; - }; + if (typeof format === 'number') { + index = format; + format = undefined; + } - /** - * Redraw all nodes - * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); - * @param {CanvasRenderingContext2D} ctx - * @param {Boolean} [alwaysShow] - * @private - */ - Network.prototype._drawNodes = function(ctx,alwaysShow) { - if (alwaysShow === undefined) { - alwaysShow = false; - } + getter = function (i) { + var m = moment().utc().set(setter, i); + return method.call(moment._locale, m, format || ''); + }; - // first draw the unselected nodes - var nodes = this.nodes; - var selected = []; + if (index != null) { + return getter(index); + } + else { + for (i = 0; i < count; i++) { + results.push(getter(i)); + } + return results; + } + }; + } - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - nodes[id].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight); - if (nodes[id].isSelected()) { - selected.push(id); - } - else { - if (nodes[id].inArea() || alwaysShow) { - nodes[id].draw(ctx); + function toInt(argumentForCoercion) { + var coercedNumber = +argumentForCoercion, + value = 0; + + if (coercedNumber !== 0 && isFinite(coercedNumber)) { + if (coercedNumber >= 0) { + value = Math.floor(coercedNumber); + } else { + value = Math.ceil(coercedNumber); + } } - } - } - } - // draw the selected nodes on top - for (var s = 0, sMax = selected.length; s < sMax; s++) { - if (nodes[selected[s]].inArea() || alwaysShow) { - nodes[selected[s]].draw(ctx); + return value; } - } - }; - /** - * Redraw all edges - * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); - * @param {CanvasRenderingContext2D} ctx - * @private - */ - Network.prototype._drawEdges = function(ctx) { - var edges = this.edges; - for (var id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - edge.setScale(this.scale); - if (edge.connected) { - edges[id].draw(ctx); - } + function daysInMonth(year, month) { + return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); } - } - }; - /** - * Redraw all edges - * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); - * @param {CanvasRenderingContext2D} ctx - * @private - */ - Network.prototype._drawControlNodes = function(ctx) { - var edges = this.edges; - for (var id in edges) { - if (edges.hasOwnProperty(id)) { - edges[id]._drawControlNodes(ctx); + function weeksInYear(year, dow, doy) { + return weekOfYear(moment([year, 11, 31 + dow - doy]), dow, doy).week; } - } - }; - - /** - * Find a stable position for all nodes - * @private - */ - Network.prototype._stabilize = function() { - if (this.constants.freezeForStabilization == true) { - this._freezeDefinedNodes(); - } - // find stable position - var count = 0; - while (this.moving && count < this.constants.stabilizationIterations) { - this._physicsTick(); - count++; - } + function daysInYear(year) { + return isLeapYear(year) ? 366 : 365; + } - if (this.constants.zoomExtentOnStabilize == true) { - this.zoomExtent(undefined, false, true); - } + function isLeapYear(year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; + } - if (this.constants.freezeForStabilization == true) { - this._restoreFrozenNodes(); - } - }; + function checkOverflow(m) { + var overflow; + if (m._a && m._pf.overflow === -2) { + overflow = + m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH : + m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE : + m._a[HOUR] < 0 || m._a[HOUR] > 24 || + (m._a[HOUR] === 24 && (m._a[MINUTE] !== 0 || + m._a[SECOND] !== 0 || + m._a[MILLISECOND] !== 0)) ? HOUR : + m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE : + m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND : + m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND : + -1; - /** - * When initializing and stabilizing, we can freeze nodes with a predefined position. This greatly speeds up stabilization - * because only the supportnodes for the smoothCurves have to settle. - * - * @private - */ - Network.prototype._freezeDefinedNodes = function() { - var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - if (nodes[id].x != null && nodes[id].y != null) { - nodes[id].fixedData.x = nodes[id].xFixed; - nodes[id].fixedData.y = nodes[id].yFixed; - nodes[id].xFixed = true; - nodes[id].yFixed = true; - } - } - } - }; + if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { + overflow = DATE; + } - /** - * Unfreezes the nodes that have been frozen by _freezeDefinedNodes. - * - * @private - */ - Network.prototype._restoreFrozenNodes = function() { - var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - if (nodes[id].fixedData.x != null) { - nodes[id].xFixed = nodes[id].fixedData.x; - nodes[id].yFixed = nodes[id].fixedData.y; - } + m._pf.overflow = overflow; + } } - } - }; + function isValid(m) { + if (m._isValid == null) { + m._isValid = !isNaN(m._d.getTime()) && + m._pf.overflow < 0 && + !m._pf.empty && + !m._pf.invalidMonth && + !m._pf.nullInput && + !m._pf.invalidFormat && + !m._pf.userInvalidated; - /** - * Check if any of the nodes is still moving - * @param {number} vmin the minimum velocity considered as 'moving' - * @return {boolean} true if moving, false if non of the nodes is moving - * @private - */ - Network.prototype._isMoving = function(vmin) { - var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id) && nodes[id].isMoving(vmin)) { - return true; + if (m._strict) { + m._isValid = m._isValid && + m._pf.charsLeftOver === 0 && + m._pf.unusedTokens.length === 0 && + m._pf.bigHour === undefined; + } + } + return m._isValid; } - } - return false; - }; + function normalizeLocale(key) { + return key ? key.toLowerCase().replace('_', '-') : key; + } - /** - * /** - * Perform one discrete step for all nodes - * - * @private - */ - Network.prototype._discreteStepNodes = function() { - var interval = this.physicsDiscreteStepsize; - var nodes = this.nodes; - var nodeId; - var nodesPresent = false; + // 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; - if (this.constants.maxVelocity > 0) { - for (nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - nodes[nodeId].discreteStepLimited(interval, this.constants.maxVelocity); - nodesPresent = true; - } - } - } - else { - for (nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - nodes[nodeId].discreteStep(interval); - nodesPresent = true; - } + 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; } - } - if (nodesPresent == true) { - var vminCorrected = this.constants.minVelocity / Math.max(this.scale,0.05); - if (vminCorrected > 0.5*this.constants.maxVelocity) { - return true; + 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]; } - else { - return this._isMoving(vminCorrected); + + // Return a moment from input, that is local/utc/utcOffset equivalent to + // model. + function makeAs(input, model) { + var res, diff; + if (model._isUTC) { + res = model.clone(); + diff = (moment.isMoment(input) || isDate(input) ? + +input : +moment(input)) - (+res); + // Use low-level api, because this fn is low-level api. + res._d.setTime(+res._d + diff); + moment.updateOffset(res, false); + return res; + } else { + return moment(input).local(); + } } - } - return false; - }; + /************************************ + Locale + ************************************/ - Network.prototype._revertPhysicsState = function() { - var nodes = this.nodes; - for (var nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - nodes[nodeId].revertPosition(); - } - } - } - Network.prototype._revertPhysicsTick = function() { - this._doInAllActiveSectors("_revertPhysicsState"); - if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { - this._doInSupportSector("_revertPhysicsState"); - } - } + extend(Locale.prototype, { - /** - * A single simulation step (or "tick") in the physics simulation - * - * @private - */ - Network.prototype._physicsTick = function() { - if (!this.freezeSimulation) { - if (this.moving == true) { - var mainMovingStatus = false; - var supportMovingStatus = false; + set : function (config) { + var prop, i; + for (i in config) { + prop = config[i]; + if (typeof prop === 'function') { + this[i] = prop; + } else { + this['_' + i] = prop; + } + } + // Lenient ordinal parsing accepts just a number in addition to + // number + (possibly) stuff coming from _ordinalParseLenient. + this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + /\d{1,2}/.source); + }, - this._doInAllActiveSectors("_initializeForceCalculation"); - var mainMoving = this._doInAllActiveSectors("_discreteStepNodes"); - if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { - supportMovingStatus = this._doInSupportSector("_discreteStepNodes"); - } + _months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), + months : function (m) { + return this._months[m.month()]; + }, - // gather movement data from all sectors, if one moves, we are NOT stabilzied - for (var i = 0; i < mainMoving.length; i++) {mainMovingStatus = mainMoving[0] || mainMovingStatus;} + _monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), + monthsShort : function (m) { + return this._monthsShort[m.month()]; + }, - // determine if the network has stabilzied - this.moving = mainMovingStatus || supportMovingStatus; + monthsParse : function (monthName, format, strict) { + var i, mom, regex; - if (this.moving == false) { - this._revertPhysicsTick(); - } - else { - // this is here to ensure that there is no start event when the network is already stable. - if (this.startedStabilization == false) { - this.emit("startStabilization"); - this.startedStabilization = true; - } - } + if (!this._monthsParse) { + this._monthsParse = []; + this._longMonthsParse = []; + this._shortMonthsParse = []; + } - this.stabilizationIterations++; - } - } - }; + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + mom = moment.utc([2000, i]); + if (strict && !this._longMonthsParse[i]) { + this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i'); + this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i'); + } + if (!strict && !this._monthsParse[i]) { + regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); + this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) { + return i; + } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) { + return i; + } else if (!strict && this._monthsParse[i].test(monthName)) { + return i; + } + } + }, + + _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 : function (m) { + return this._weekdaysShort[m.day()]; + }, + + _weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), + weekdaysMin : function (m) { + return this._weekdaysMin[m.day()]; + }, + + weekdaysParse : function (weekdayName) { + var i, mom, regex; + + if (!this._weekdaysParse) { + this._weekdaysParse = []; + } + + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + if (!this._weekdaysParse[i]) { + mom = moment([2000, 1]).day(i); + regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); + this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (this._weekdaysParse[i].test(weekdayName)) { + return i; + } + } + }, + _longDateFormat : { + LTS : 'h:mm:ss A', + 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]; + if (!output && this._longDateFormat[key.toUpperCase()]) { + output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { + return val.slice(1); + }); + this._longDateFormat[key] = output; + } + return output; + }, - /** - * This function runs one step of the animation. It calls an x amount of physics ticks and one render tick. - * It reschedules itself at the beginning of the function - * - * @private - */ - Network.prototype._animationStep = function() { - // reset the timer so a new scheduled animation step can be set - this.timer = undefined; + isPM : function (input) { + // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays + // Using charAt should be more compatible. + return ((input + '').toLowerCase().charAt(0) === 'p'); + }, - // handle the keyboad movement - this._handleNavigation(); + _meridiemParse : /[ap]\.?m?\.?/i, + meridiem : function (hours, minutes, isLower) { + if (hours > 11) { + return isLower ? 'pm' : 'PM'; + } else { + return isLower ? 'am' : 'AM'; + } + }, - var startTime = Date.now(); - this._physicsTick(); - var physicsTime = Date.now() - startTime; - // run double speed if it is a little graph - if ((this.renderTimestep - this.renderTime > 2 * physicsTime || this.runDoubleSpeed == true) && this.moving == true) { - this._physicsTick(); + _calendar : { + sameDay : '[Today at] LT', + nextDay : '[Tomorrow at] LT', + nextWeek : 'dddd [at] LT', + lastDay : '[Yesterday at] LT', + lastWeek : '[Last] dddd [at] LT', + sameElse : 'L' + }, + calendar : function (key, mom, now) { + var output = this._calendar[key]; + return typeof output === 'function' ? output.apply(mom, [now]) : output; + }, - // this makes sure there is no jitter. The decision is taken once to run it at double speed. - if (this.renderTime != 0) { - this.runDoubleSpeed = true - } - } + _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' + }, - var renderStartTime = Date.now(); - this._redraw(); - this.renderTime = Date.now() - renderStartTime; + 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); + }, - // this schedules a new animation step - this.start(); - }; + pastFuture : function (diff, output) { + var format = this._relativeTime[diff > 0 ? 'future' : 'past']; + return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); + }, - if (typeof window !== 'undefined') { - window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || - window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; - } + ordinal : function (number) { + return this._ordinal.replace('%d', number); + }, + _ordinal : '%d', + _ordinalParse : /\d{1,2}/, - /** - * Schedule a animation step with the refreshrate interval. - */ - Network.prototype.start = function() { - if (this.moving == true || this.xIncrement != 0 || this.yIncrement != 0 || this.zoomIncrement != 0) { - if (!this.timer) { - if (this.requiresTimeout == true) { - this.timer = window.setTimeout(this._animationStep.bind(this), this.renderTimestep); // wait this.renderTimeStep milliseconds and perform the animation step function - } - else { - this.timer = window.requestAnimationFrame(this._animationStep.bind(this)); // wait this.renderTimeStep milliseconds and perform the animation step function - } - } - } - else { - this._redraw(); - // this check is to ensure that the network does not emit these events if it was already stabilized and setOptions is called (setting moving to true and calling start()) - if (this.stabilizationIterations > 1) { - // trigger the "stabilized" event. - // The event is triggered on the next tick, to prevent the case that - // it is fired while initializing the Network, in which case you would not - // be able to catch it - var me = this; - var params = { - iterations: me.stabilizationIterations - }; - this.stabilizationIterations = 0; - this.startedStabilization = false; - setTimeout(function () { - me.emit("stabilized", params); - }, 0); - } - else { - this.stabilizationIterations = 0; - } - } - }; + preparse : function (string) { + return string; + }, + postformat : function (string) { + return string; + }, - /** - * Move the network according to the keyboard presses. - * - * @private - */ - Network.prototype._handleNavigation = function() { - if (this.xIncrement != 0 || this.yIncrement != 0) { - var translation = this._getTranslation(); - this._setTranslation(translation.x+this.xIncrement, translation.y+this.yIncrement); - } - if (this.zoomIncrement != 0) { - var center = { - x: this.frame.canvas.clientWidth / 2, - y: this.frame.canvas.clientHeight / 2 - }; - this._zoom(this.scale*(1 + this.zoomIncrement), center); - } - }; + week : function (mom) { + return weekOfYear(mom, this._week.dow, this._week.doy).week; + }, + _week : { + dow : 0, // Sunday is the first day of the week. + doy : 6 // The week that contains Jan 1st is the first week of the year. + }, - /** - * Freeze the _animationStep - */ - Network.prototype.toggleFreeze = function() { - if (this.freezeSimulation == false) { - this.freezeSimulation = true; - } - else { - this.freezeSimulation = false; - this.start(); - } - }; + firstDayOfWeek : function () { + return this._week.dow; + }, + firstDayOfYear : function () { + return this._week.doy; + }, - /** - * This function cleans the support nodes if they are not needed and adds them when they are. - * - * @param {boolean} [disableStart] - * @private - */ - Network.prototype._configureSmoothCurves = function(disableStart) { - if (disableStart === undefined) { - disableStart = true; - } - if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { - this._createBezierNodes(); - // cleanup unused support nodes - for (var nodeId in this.sectors['support']['nodes']) { - if (this.sectors['support']['nodes'].hasOwnProperty(nodeId)) { - if (this.edges[this.sectors['support']['nodes'][nodeId].parentEdgeId] === undefined) { - delete this.sectors['support']['nodes'][nodeId]; + _invalidDate: 'Invalid date', + invalidDate: function () { + return this._invalidDate; } - } - } - } - else { - // delete the support nodes - this.sectors['support']['nodes'] = {}; - for (var edgeId in this.edges) { - if (this.edges.hasOwnProperty(edgeId)) { - this.edges[edgeId].via = null; - } - } - } - + }); - this._updateCalculationNodes(); - if (!disableStart) { - this.moving = true; - this.start(); - } - }; + /************************************ + Formatting + ************************************/ - /** - * Bezier curves require an anchor point to calculate the smooth flow. These points are nodes. These nodes are invisible but - * are used for the force calculation. - * - * @private - */ - Network.prototype._createBezierNodes = function() { - if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { - for (var edgeId in this.edges) { - if (this.edges.hasOwnProperty(edgeId)) { - var edge = this.edges[edgeId]; - if (edge.via == null) { - var nodeId = "edgeId:".concat(edge.id); - this.sectors['support']['nodes'][nodeId] = new Node( - {id:nodeId, - mass:1, - shape:'circle', - image:"", - internalMultiplier:1 - },{},{},this.constants); - edge.via = this.sectors['support']['nodes'][nodeId]; - edge.via.parentEdgeId = edge.id; - edge.positionBezierNode(); + function removeFormattingTokens(input) { + if (input.match(/\[[\s\S]/)) { + return input.replace(/^\[|\]$/g, ''); } - } + return input.replace(/\\/g, ''); } - } - }; - /** - * load the functions that load the mixins into the prototype. - * - * @private - */ - Network.prototype._initializeMixinLoaders = function () { - for (var mixin in MixinLoader) { - if (MixinLoader.hasOwnProperty(mixin)) { - Network.prototype[mixin] = MixinLoader[mixin]; - } - } - }; + function makeFormatFunction(format) { + var array = format.match(formattingTokens), i, length; - /** - * Load the XY positions of the nodes into the dataset. - */ - Network.prototype.storePosition = function() { - console.log("storePosition is depricated: use .storePositions() from now on.") - this.storePositions(); - }; + for (i = 0, length = array.length; i < length; i++) { + if (formatTokenFunctions[array[i]]) { + array[i] = formatTokenFunctions[array[i]]; + } else { + array[i] = removeFormattingTokens(array[i]); + } + } - /** - * Load the XY positions of the nodes into the dataset. - */ - Network.prototype.storePositions = function() { - var dataArray = []; - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - var node = this.nodes[nodeId]; - var allowedToMoveX = !this.nodes.xFixed; - var allowedToMoveY = !this.nodes.yFixed; - if (this.nodesData._data[nodeId].x != Math.round(node.x) || this.nodesData._data[nodeId].y != Math.round(node.y)) { - dataArray.push({id:nodeId,x:Math.round(node.x),y:Math.round(node.y),allowedToMoveX:allowedToMoveX,allowedToMoveY:allowedToMoveY}); - } + return function (mom) { + var output = ''; + for (i = 0; i < length; i++) { + output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; + } + return output; + }; } - } - this.nodesData.update(dataArray); - }; - /** - * Return the positions of the nodes. - */ - Network.prototype.getPositions = function(ids) { - var dataArray = {}; - if (ids !== undefined) { - if (Array.isArray(ids) == true) { - for (var i = 0; i < ids.length; i++) { - if (this.nodes[ids[i]] !== undefined) { - var node = this.nodes[ids[i]]; - dataArray[ids[i]] = {x: Math.round(node.x), y: Math.round(node.y)}; + // format date using native date object + function formatMoment(m, format) { + if (!m.isValid()) { + return m.localeData().invalidDate(); } - } - } - else { - if (this.nodes[ids] !== undefined) { - var node = this.nodes[ids]; - dataArray[ids] = {x: Math.round(node.x), y: Math.round(node.y)}; - } - } - } - else { - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - var node = this.nodes[nodeId]; - dataArray[nodeId] = {x: Math.round(node.x), y: Math.round(node.y)}; - } - } - } - return dataArray; - }; + format = expandFormat(format, m.localeData()); + if (!formatFunctions[format]) { + formatFunctions[format] = makeFormatFunction(format); + } - /** - * Center a node in view. - * - * @param {Number} nodeId - * @param {Number} [options] - */ - Network.prototype.focusOnNode = function (nodeId, options) { - if (this.nodes.hasOwnProperty(nodeId)) { - if (options === undefined) { - options = {}; + return formatFunctions[format](m); } - var nodePosition = {x: this.nodes[nodeId].x, y: this.nodes[nodeId].y}; - options.position = nodePosition; - options.lockedOnNode = nodeId; - - this.moveTo(options) - } - else { - console.log("This nodeId cannot be found."); - } - }; - - /** - * - * @param {Object} options | options.offset = {x:Number, y:Number} // offset from the center in DOM pixels - * | options.scale = Number // scale to move to - * | options.position = {x:Number, y:Number} // position to move to - * | options.animation = {duration:Number, easingFunction:String} || Boolean // position to move to - */ - Network.prototype.moveTo = function (options) { - if (options === undefined) { - options = {}; - return; - } - if (options.offset === undefined) {options.offset = {x: 0, y: 0}; } - if (options.offset.x === undefined) {options.offset.x = 0; } - if (options.offset.y === undefined) {options.offset.y = 0; } - if (options.scale === undefined) {options.scale = this._getScale(); } - if (options.position === undefined) {options.position = this._getTranslation();} - if (options.animation === undefined) {options.animation = {duration:0}; } - if (options.animation === false ) {options.animation = {duration:0}; } - if (options.animation === true ) {options.animation = {}; } - if (options.animation.duration === undefined) {options.animation.duration = 1000; } // default duration - if (options.animation.easingFunction === undefined) {options.animation.easingFunction = "easeInOutQuad"; } // default easing function - - this.animateView(options); - }; - - /** - * - * @param {Object} options | options.offset = {x:Number, y:Number} // offset from the center in DOM pixels - * | options.time = Number // animation time in milliseconds - * | options.scale = Number // scale to animate to - * | options.position = {x:Number, y:Number} // position to animate to - * | options.easingFunction = String // linear, easeInQuad, easeOutQuad, easeInOutQuad, - * // easeInCubic, easeOutCubic, easeInOutCubic, - * // easeInQuart, easeOutQuart, easeInOutQuart, - * // easeInQuint, easeOutQuint, easeInOutQuint - */ - Network.prototype.animateView = function (options) { - if (options === undefined) { - options = {}; - return; - } - - // release if something focussed on the node - this.releaseNode(); - if (options.locked == true) { - this.lockedOnNodeId = options.lockedOnNode; - this.lockedOnNodeOffset = options.offset; - } - // forcefully complete the old animation if it was still running - if (this.easingTime != 0) { - this._transitionRedraw(1); // by setting easingtime to 1, we finish the animation. - } + function expandFormat(format, locale) { + var i = 5; - this.sourceScale = this._getScale(); - this.sourceTranslation = this._getTranslation(); - this.targetScale = options.scale; + function replaceLongDateFormatTokens(input) { + return locale.longDateFormat(input) || input; + } - // set the scale so the viewCenter is based on the correct zoom level. This is overridden in the transitionRedraw - // but at least then we'll have the target transition - this._setScale(this.targetScale); - var viewCenter = this.DOMtoCanvas({x: 0.5 * this.frame.canvas.clientWidth, y: 0.5 * this.frame.canvas.clientHeight}); - var distanceFromCenter = { // offset from view, distance view has to change by these x and y to center the node - x: viewCenter.x - options.position.x, - y: viewCenter.y - options.position.y - }; - this.targetTranslation = { - x: this.sourceTranslation.x + distanceFromCenter.x * this.targetScale + options.offset.x, - y: this.sourceTranslation.y + distanceFromCenter.y * this.targetScale + options.offset.y - }; + localFormattingTokens.lastIndex = 0; + while (i >= 0 && localFormattingTokens.test(format)) { + format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); + localFormattingTokens.lastIndex = 0; + i -= 1; + } - // if the time is set to 0, don't do an animation - if (options.animation.duration == 0) { - if (this.lockedOnNodeId != null) { - this._classicRedraw = this._redraw; - this._redraw = this._lockedRedraw; - } - else { - this._setScale(this.targetScale); - this._setTranslation(this.targetTranslation.x, this.targetTranslation.y); - this._redraw(); + return format; } - } - else { - this.animationSpeed = 1 / (this.renderRefreshRate * options.animation.duration * 0.001) || 1 / this.renderRefreshRate; - this.animationEasingFunction = options.animation.easingFunction; - this._classicRedraw = this._redraw; - this._redraw = this._transitionRedraw; - this._redraw(); - this.moving = true; - this.start(); - } - }; - - /** - * used to animate smoothly by hijacking the redraw function. - * @private - */ - Network.prototype._lockedRedraw = function () { - var nodePosition = {x: this.nodes[this.lockedOnNodeId].x, y: this.nodes[this.lockedOnNodeId].y}; - var viewCenter = this.DOMtoCanvas({x: 0.5 * this.frame.canvas.clientWidth, y: 0.5 * this.frame.canvas.clientHeight}); - var distanceFromCenter = { // offset from view, distance view has to change by these x and y to center the node - x: viewCenter.x - nodePosition.x, - y: viewCenter.y - nodePosition.y - }; - var sourceTranslation = this._getTranslation(); - var targetTranslation = { - x: sourceTranslation.x + distanceFromCenter.x * this.scale + this.lockedOnNodeOffset.x, - y: sourceTranslation.y + distanceFromCenter.y * this.scale + this.lockedOnNodeOffset.y - }; - - this._setTranslation(targetTranslation.x,targetTranslation.y); - this._classicRedraw(); - } - - Network.prototype.releaseNode = function () { - if (this.lockedOnNodeId != null) { - this._redraw = this._classicRedraw; - this.lockedOnNodeId = null; - this.lockedOnNodeOffset = null; - } - } - - /** - * - * @param easingTime - * @private - */ - Network.prototype._transitionRedraw = function (easingTime) { - this.easingTime = easingTime || this.easingTime + this.animationSpeed; - this.easingTime += this.animationSpeed; - var progress = util.easingFunctions[this.animationEasingFunction](this.easingTime); - this._setScale(this.sourceScale + (this.targetScale - this.sourceScale) * progress); - this._setTranslation( - this.sourceTranslation.x + (this.targetTranslation.x - this.sourceTranslation.x) * progress, - this.sourceTranslation.y + (this.targetTranslation.y - this.sourceTranslation.y) * progress - ); + /************************************ + Parsing + ************************************/ - this._classicRedraw(); - this.moving = true; - // cleanup - if (this.easingTime >= 1.0) { - this.easingTime = 0; - if (this.lockedOnNodeId != null) { - this._redraw = this._lockedRedraw; - } - else { - this._redraw = this._classicRedraw; + // get the regex to find the next token + function getParseRegexForToken(token, config) { + var a, strict = config._strict; + switch (token) { + case 'Q': + return parseTokenOneDigit; + case 'DDDD': + return parseTokenThreeDigits; + case 'YYYY': + case 'GGGG': + case 'gggg': + return strict ? parseTokenFourDigits : parseTokenOneToFourDigits; + case 'Y': + case 'G': + case 'g': + return parseTokenSignedNumber; + case 'YYYYYY': + case 'YYYYY': + case 'GGGGG': + case 'ggggg': + return strict ? parseTokenSixDigits : parseTokenOneToSixDigits; + case 'S': + if (strict) { + return parseTokenOneDigit; + } + /* falls through */ + case 'SS': + if (strict) { + return parseTokenTwoDigits; + } + /* falls through */ + case 'SSS': + if (strict) { + return parseTokenThreeDigits; + } + /* falls through */ + case 'DDD': + return parseTokenOneToThreeDigits; + case 'MMM': + case 'MMMM': + case 'dd': + case 'ddd': + case 'dddd': + return parseTokenWord; + case 'a': + case 'A': + return config._locale._meridiemParse; + case 'x': + return parseTokenOffsetMs; + case 'X': + return parseTokenTimestampMs; + case 'Z': + case 'ZZ': + return parseTokenTimezone; + case 'T': + return parseTokenT; + case 'SSSS': + return parseTokenDigits; + case 'MM': + case 'DD': + case 'YY': + case 'GG': + case 'gg': + case 'HH': + case 'hh': + case 'mm': + case 'ss': + case 'ww': + case 'WW': + return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits; + case 'M': + case 'D': + case 'd': + case 'H': + case 'h': + case 'm': + case 's': + case 'w': + case 'W': + case 'e': + case 'E': + return parseTokenOneOrTwoDigits; + case 'Do': + return strict ? config._locale._ordinalParse : config._locale._ordinalParseLenient; + default : + a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), 'i')); + return a; + } } - this.emit("animationFinished"); - } - }; - Network.prototype._classicRedraw = function () { - // placeholder function to be overloaded by animations; - }; - - /** - * Returns true when the Network is active. - * @returns {boolean} - */ - Network.prototype.isActive = function () { - return !this.activator || this.activator.active; - }; + function utcOffsetFromString(string) { + string = string || ''; + var possibleTzMatches = (string.match(parseTokenTimezone) || []), + tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [], + parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0], + minutes = +(parts[1] * 60) + toInt(parts[2]); + return parts[0] === '+' ? minutes : -minutes; + } - /** - * Sets the scale - * @returns {Number} - */ - Network.prototype.setScale = function () { - return this._setScale(); - }; + // function to convert string input to date + function addTimeToArrayFromToken(token, input, config) { + var a, datePartArray = config._a; + switch (token) { + // QUARTER + case 'Q': + if (input != null) { + datePartArray[MONTH] = (toInt(input) - 1) * 3; + } + break; + // MONTH + case 'M' : // fall through to MM + case 'MM' : + if (input != null) { + datePartArray[MONTH] = toInt(input) - 1; + } + break; + case 'MMM' : // fall through to MMMM + case 'MMMM' : + a = config._locale.monthsParse(input, token, config._strict); + // if we didn't find a month name, mark the date as invalid. + if (a != null) { + datePartArray[MONTH] = a; + } else { + config._pf.invalidMonth = input; + } + break; + // DAY OF MONTH + case 'D' : // fall through to DD + case 'DD' : + if (input != null) { + datePartArray[DATE] = toInt(input); + } + break; + case 'Do' : + if (input != null) { + datePartArray[DATE] = toInt(parseInt( + input.match(/\d{1,2}/)[0], 10)); + } + break; + // DAY OF YEAR + case 'DDD' : // fall through to DDDD + case 'DDDD' : + if (input != null) { + config._dayOfYear = toInt(input); + } - /** - * Returns the scale - * @returns {Number} - */ - Network.prototype.getScale = function () { - return this._getScale(); - }; + break; + // YEAR + case 'YY' : + datePartArray[YEAR] = moment.parseTwoDigitYear(input); + break; + case 'YYYY' : + case 'YYYYY' : + case 'YYYYYY' : + datePartArray[YEAR] = toInt(input); + break; + // AM / PM + case 'a' : // fall through to A + case 'A' : + config._meridiem = input; + // config._isPm = config._locale.isPM(input); + break; + // HOUR + case 'h' : // fall through to hh + case 'hh' : + config._pf.bigHour = true; + /* falls through */ + case 'H' : // fall through to HH + case 'HH' : + datePartArray[HOUR] = toInt(input); + break; + // MINUTE + case 'm' : // fall through to mm + case 'mm' : + datePartArray[MINUTE] = toInt(input); + break; + // SECOND + case 's' : // fall through to ss + case 'ss' : + datePartArray[SECOND] = toInt(input); + break; + // MILLISECOND + case 'S' : + case 'SS' : + case 'SSS' : + case 'SSSS' : + datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000); + break; + // UNIX OFFSET (MILLISECONDS) + case 'x': + config._d = new Date(toInt(input)); + break; + // UNIX TIMESTAMP WITH MS + case 'X': + config._d = new Date(parseFloat(input) * 1000); + break; + // TIMEZONE + case 'Z' : // fall through to ZZ + case 'ZZ' : + config._useUTC = true; + config._tzm = utcOffsetFromString(input); + break; + // WEEKDAY - human + case 'dd': + case 'ddd': + case 'dddd': + 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 || {}; + config._w['d'] = a; + } else { + config._pf.invalidWeekday = input; + } + break; + // WEEK, WEEK DAY - numeric + case 'w': + case 'ww': + case 'W': + case 'WW': + case 'd': + case 'e': + case 'E': + token = token.substr(0, 1); + /* falls through */ + case 'gggg': + case 'GGGG': + case 'GGGGG': + token = token.substr(0, 2); + if (input) { + config._w = config._w || {}; + config._w[token] = toInt(input); + } + break; + case 'gg': + case 'GG': + config._w = config._w || {}; + config._w[token] = moment.parseTwoDigitYear(input); + } + } + function dayOfYearFromWeekInfo(config) { + var w, weekYear, week, weekday, dow, doy, temp; - /** - * Returns the scale - * @returns {Number} - */ - Network.prototype.getCenterCoordinates = function () { - return this.DOMtoCanvas({x: 0.5 * this.frame.canvas.clientWidth, y: 0.5 * this.frame.canvas.clientHeight}); - }; + w = config._w; + if (w.GG != null || w.W != null || w.E != null) { + dow = 1; + doy = 4; + // TODO: We need to take the current isoWeekYear, but that depends on + // how we interpret now (local, utc, fixed offset). So create + // a now version of current config (take local/utc/offset flags, and + // create now). + weekYear = dfl(w.GG, config._a[YEAR], weekOfYear(moment(), 1, 4).year); + week = dfl(w.W, 1); + weekday = dfl(w.E, 1); + } else { + dow = config._locale._week.dow; + doy = config._locale._week.doy; - Network.prototype.getBoundingBox = function(nodeId) { - if (this.nodes[nodeId] !== undefined) { - return this.nodes[nodeId].boundingBox; - } - } + weekYear = dfl(w.gg, config._a[YEAR], weekOfYear(moment(), dow, doy).year); + week = dfl(w.w, 1); - module.exports = Network; + if (w.d != null) { + // weekday -- low day numbers are considered next week + weekday = w.d; + if (weekday < dow) { + ++week; + } + } else if (w.e != null) { + // local weekday -- counting starts from begining of week + weekday = w.e + dow; + } else { + // default to begining of week + weekday = dow; + } + } + temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow); + config._a[YEAR] = temp.year; + config._dayOfYear = temp.dayOfYear; + } -/***/ }, -/* 52 */ -/***/ function(module, exports, __webpack_require__) { + // convert an array to a date. + // the array should mirror the parameters below + // note: all values past the year are optional and will default to the lowest possible value. + // [year, month, day , hour, minute, second, millisecond] + function dateFromConfig(config) { + var i, date, input = [], currentDate, yearToUse; - /** - * Parse a text source containing data in DOT language into a JSON object. - * The object contains two lists: one with nodes and one with edges. - * - * DOT language reference: http://www.graphviz.org/doc/info/lang.html - * - * @param {String} data Text containing a graph in DOT-notation - * @return {Object} graph An object containing two parameters: - * {Object[]} nodes - * {Object[]} edges - */ - function parseDOT (data) { - dot = data; - return parseGraph(); - } + if (config._d) { + return; + } - // token types enumeration - var TOKENTYPE = { - NULL : 0, - DELIMITER : 1, - IDENTIFIER: 2, - UNKNOWN : 3 - }; + currentDate = currentDateArray(config); - // map with all delimiters - var DELIMITERS = { - '{': true, - '}': true, - '[': true, - ']': true, - ';': true, - '=': true, - ',': true, + //compute day of the year from weeks and weekdays + if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { + dayOfYearFromWeekInfo(config); + } - '->': true, - '--': true - }; + //if the day of the year is set, figure out what it is + if (config._dayOfYear) { + yearToUse = dfl(config._a[YEAR], currentDate[YEAR]); - var dot = ''; // current dot file - var index = 0; // current index in dot file - var c = ''; // current token character in expr - var token = ''; // current token - var tokenType = TOKENTYPE.NULL; // type of the token + if (config._dayOfYear > daysInYear(yearToUse)) { + config._pf._overflowDayOfYear = true; + } - /** - * Get the first character from the dot file. - * The character is stored into the char c. If the end of the dot file is - * reached, the function puts an empty string in c. - */ - function first() { - index = 0; - c = dot.charAt(0); - } + date = makeUTCDate(yearToUse, 0, config._dayOfYear); + config._a[MONTH] = date.getUTCMonth(); + config._a[DATE] = date.getUTCDate(); + } - /** - * Get the next character from the dot file. - * The character is stored into the char c. If the end of the dot file is - * reached, the function puts an empty string in c. - */ - function next() { - index++; - c = dot.charAt(index); - } + // Default to current date. + // * if no year, month, day of month are given, default to today + // * if day of month is given, default month and year + // * if month is given, default only year + // * if year is given, don't default anything + for (i = 0; i < 3 && config._a[i] == null; ++i) { + config._a[i] = input[i] = currentDate[i]; + } - /** - * Preview the next character from the dot file. - * @return {String} cNext - */ - function nextPreview() { - return dot.charAt(index + 1); - } + // Zero out whatever was not defaulted, including time + for (; i < 7; i++) { + config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; + } - /** - * Test whether given character is alphabetic or numeric - * @param {String} c - * @return {Boolean} isAlphaNumeric - */ - var regexAlphaNumeric = /[a-zA-Z_0-9.:#]/; - function isAlphaNumeric(c) { - return regexAlphaNumeric.test(c); - } + // Check for 24:00:00.000 + if (config._a[HOUR] === 24 && + config._a[MINUTE] === 0 && + config._a[SECOND] === 0 && + config._a[MILLISECOND] === 0) { + config._nextDay = true; + config._a[HOUR] = 0; + } - /** - * Merge all properties of object b into object b - * @param {Object} a - * @param {Object} b - * @return {Object} a - */ - function merge (a, b) { - if (!a) { - a = {}; - } + config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input); + // Apply timezone offset from input. The actual utcOffset can be changed + // with parseZone. + if (config._tzm != null) { + config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); + } - if (b) { - for (var name in b) { - if (b.hasOwnProperty(name)) { - a[name] = b[name]; - } + if (config._nextDay) { + config._a[HOUR] = 24; + } } - } - return a; - } - /** - * Set a value in an object, where the provided parameter name can be a - * path with nested parameters. For example: - * - * var obj = {a: 2}; - * setValue(obj, 'b.c', 3); // obj = {a: 2, b: {c: 3}} - * - * @param {Object} obj - * @param {String} path A parameter name or dot-separated parameter path, - * like "color.highlight.border". - * @param {*} value - */ - function setValue(obj, path, value) { - var keys = path.split('.'); - var o = obj; - while (keys.length) { - var key = keys.shift(); - if (keys.length) { - // this isn't the end point - if (!o[key]) { - o[key] = {}; - } - o = o[key]; + function dateFromObject(config) { + var normalizedInput; + + if (config._d) { + return; + } + + normalizedInput = normalizeObjectUnits(config._i); + config._a = [ + normalizedInput.year, + normalizedInput.month, + normalizedInput.day || normalizedInput.date, + normalizedInput.hour, + normalizedInput.minute, + normalizedInput.second, + normalizedInput.millisecond + ]; + + dateFromConfig(config); } - else { - // this is the end point - o[key] = value; + + function currentDateArray(config) { + var now = new Date(); + if (config._useUTC) { + return [ + now.getUTCFullYear(), + now.getUTCMonth(), + now.getUTCDate() + ]; + } else { + return [now.getFullYear(), now.getMonth(), now.getDate()]; + } } - } - } - /** - * Add a node to a graph object. If there is already a node with - * the same id, their attributes will be merged. - * @param {Object} graph - * @param {Object} node - */ - function addNode(graph, node) { - var i, len; - var current = null; + // date from string and format string + function makeDateFromStringAndFormat(config) { + if (config._f === moment.ISO_8601) { + parseISO(config); + return; + } - // find root graph (in case of subgraph) - var graphs = [graph]; // list with all graphs from current graph to root graph - var root = graph; - while (root.parent) { - graphs.push(root.parent); - root = root.parent; - } + config._a = []; + config._pf.empty = true; - // find existing node (at root level) by its id - if (root.nodes) { - for (i = 0, len = root.nodes.length; i < len; i++) { - if (node.id === root.nodes[i].id) { - current = root.nodes[i]; - break; - } - } - } + // This array is used to make a Date, either with `new Date` or `Date.UTC` + var string = '' + config._i, + i, parsedInput, tokens, token, skipped, + stringLength = string.length, + totalParsedInputLength = 0; - if (!current) { - // this is a new node - current = { - id: node.id - }; - if (graph.node) { - // clone default attributes - current.attr = merge(current.attr, graph.node); - } - } + tokens = expandFormat(config._f, config._locale).match(formattingTokens) || []; - // add node to this (sub)graph and all its parent graphs - for (i = graphs.length - 1; i >= 0; i--) { - var g = graphs[i]; + for (i = 0; i < tokens.length; i++) { + token = tokens[i]; + parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; + if (parsedInput) { + skipped = string.substr(0, string.indexOf(parsedInput)); + if (skipped.length > 0) { + config._pf.unusedInput.push(skipped); + } + string = string.slice(string.indexOf(parsedInput) + parsedInput.length); + totalParsedInputLength += parsedInput.length; + } + // don't parse if it's not a known token + if (formatTokenFunctions[token]) { + if (parsedInput) { + config._pf.empty = false; + } + else { + config._pf.unusedTokens.push(token); + } + addTimeToArrayFromToken(token, parsedInput, config); + } + else if (config._strict && !parsedInput) { + config._pf.unusedTokens.push(token); + } + } - if (!g.nodes) { - g.nodes = []; + // add remaining unparsed input length to the string + config._pf.charsLeftOver = stringLength - totalParsedInputLength; + if (string.length > 0) { + config._pf.unusedInput.push(string); + } + + // clear _12h flag if hour is <= 12 + if (config._pf.bigHour === true && config._a[HOUR] <= 12) { + config._pf.bigHour = undefined; + } + // handle meridiem + config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], + config._meridiem); + dateFromConfig(config); + checkOverflow(config); } - if (g.nodes.indexOf(current) == -1) { - g.nodes.push(current); + + function unescapeFormat(s) { + return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { + return p1 || p2 || p3 || p4; + }); } - } - // merge attributes - if (node.attr) { - current.attr = merge(current.attr, node.attr); - } - } + // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript + function regexpEscape(s) { + return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } - /** - * Add an edge to a graph object - * @param {Object} graph - * @param {Object} edge - */ - function addEdge(graph, edge) { - if (!graph.edges) { - graph.edges = []; - } - graph.edges.push(edge); - if (graph.edge) { - var attr = merge({}, graph.edge); // clone default attributes - edge.attr = merge(attr, edge.attr); // merge attributes - } - } + // date from string and array of format strings + function makeDateFromStringAndArray(config) { + var tempConfig, + bestMoment, - /** - * Create an edge to a graph object - * @param {Object} graph - * @param {String | Number | Object} from - * @param {String | Number | Object} to - * @param {String} type - * @param {Object | null} attr - * @return {Object} edge - */ - function createEdge(graph, from, to, type, attr) { - var edge = { - from: from, - to: to, - type: type - }; + scoreToBeat, + i, + currentScore; - if (graph.edge) { - edge.attr = merge({}, graph.edge); // clone default attributes - } - edge.attr = merge(edge.attr || {}, attr); // merge attributes + if (config._f.length === 0) { + config._pf.invalidFormat = true; + config._d = new Date(NaN); + return; + } - return edge; - } + for (i = 0; i < config._f.length; i++) { + currentScore = 0; + tempConfig = copyConfig({}, config); + if (config._useUTC != null) { + tempConfig._useUTC = config._useUTC; + } + tempConfig._pf = defaultParsingFlags(); + tempConfig._f = config._f[i]; + makeDateFromStringAndFormat(tempConfig); - /** - * Get next token in the current dot file. - * The token and token type are available as token and tokenType - */ - function getToken() { - tokenType = TOKENTYPE.NULL; - token = ''; + if (!isValid(tempConfig)) { + continue; + } - // skip over whitespaces - while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter - next(); - } + // if there is any input that was not parsed add a penalty for that format + currentScore += tempConfig._pf.charsLeftOver; - do { - var isComment = false; + //or tokens + currentScore += tempConfig._pf.unusedTokens.length * 10; - // skip comment - if (c == '#') { - // find the previous non-space character - var i = index - 1; - while (dot.charAt(i) == ' ' || dot.charAt(i) == '\t') { - i--; - } - if (dot.charAt(i) == '\n' || dot.charAt(i) == '') { - // the # is at the start of a line, this is indeed a line comment - while (c != '' && c != '\n') { - next(); + tempConfig._pf.score = currentScore; + + if (scoreToBeat == null || currentScore < scoreToBeat) { + scoreToBeat = currentScore; + bestMoment = tempConfig; + } } - isComment = true; - } - } - if (c == '/' && nextPreview() == '/') { - // skip line comment - while (c != '' && c != '\n') { - next(); - } - isComment = true; + + extend(config, bestMoment || tempConfig); } - if (c == '/' && nextPreview() == '*') { - // skip block comment - while (c != '') { - if (c == '*' && nextPreview() == '/') { - // end of block comment found. skip these last two characters - next(); - next(); - break; - } - else { - next(); + + // date from iso format + function parseISO(config) { + var i, l, + string = config._i, + match = isoRegex.exec(string); + + if (match) { + config._pf.iso = true; + for (i = 0, l = isoDates.length; i < l; i++) { + if (isoDates[i][1].exec(string)) { + // match[5] should be 'T' or undefined + config._f = isoDates[i][0] + (match[6] || ' '); + break; + } + } + for (i = 0, l = isoTimes.length; i < l; i++) { + if (isoTimes[i][1].exec(string)) { + config._f += isoTimes[i][0]; + break; + } + } + if (string.match(parseTokenTimezone)) { + config._f += 'Z'; + } + makeDateFromStringAndFormat(config); + } else { + config._isValid = false; } - } - isComment = true; } - // skip over whitespaces - while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter - next(); + // date from iso format or fallback + function makeDateFromString(config) { + parseISO(config); + if (config._isValid === false) { + delete config._isValid; + moment.createFromInputFallback(config); + } } - } - while (isComment); - - // check for end of dot file - if (c == '') { - // token is still empty - tokenType = TOKENTYPE.DELIMITER; - return; - } - // check for delimiters consisting of 2 characters - var c2 = c + nextPreview(); - if (DELIMITERS[c2]) { - tokenType = TOKENTYPE.DELIMITER; - token = c2; - next(); - next(); - return; - } + function map(arr, fn) { + var res = [], i; + for (i = 0; i < arr.length; ++i) { + res.push(fn(arr[i], i)); + } + return res; + } - // check for delimiters consisting of 1 character - if (DELIMITERS[c]) { - tokenType = TOKENTYPE.DELIMITER; - token = c; - next(); - return; - } + function makeDateFromInput(config) { + var input = config._i, matched; + if (input === undefined) { + config._d = new Date(); + } 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 = map(input.slice(0), function (obj) { + return parseInt(obj, 10); + }); + dateFromConfig(config); + } else if (typeof(input) === 'object') { + dateFromObject(config); + } else if (typeof(input) === 'number') { + // from milliseconds + config._d = new Date(input); + } else { + moment.createFromInputFallback(config); + } + } - // check for an identifier (number or string) - // TODO: more precise parsing of numbers/strings (and the port separator ':') - if (isAlphaNumeric(c) || c == '-') { - token += c; - next(); + function makeDate(y, m, d, h, M, s, ms) { + //can't just apply() to create a date: + //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply + var date = new Date(y, m, d, h, M, s, ms); - while (isAlphaNumeric(c)) { - token += c; - next(); - } - if (token == 'false') { - token = false; // convert to boolean - } - else if (token == 'true') { - token = true; // convert to boolean + //the date constructor doesn't accept years < 1970 + if (y < 1970) { + date.setFullYear(y); + } + return date; } - else if (!isNaN(Number(token))) { - token = Number(token); // convert to number + + function makeUTCDate(y) { + var date = new Date(Date.UTC.apply(null, arguments)); + if (y < 1970) { + date.setUTCFullYear(y); + } + return date; } - tokenType = TOKENTYPE.IDENTIFIER; - return; - } - // check for a string enclosed by double quotes - if (c == '"') { - next(); - while (c != '' && (c != '"' || (c == '"' && nextPreview() == '"'))) { - token += c; - if (c == '"') { // skip the escape character - next(); - } - next(); + function parseWeekday(input, locale) { + if (typeof input === 'string') { + if (!isNaN(input)) { + input = parseInt(input, 10); + } + else { + input = locale.weekdaysParse(input); + if (typeof input !== 'number') { + return null; + } + } + } + return input; } - if (c != '"') { - throw newSyntaxError('End of string " expected'); + + /************************************ + Relative Time + ************************************/ + + + // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize + function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { + return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); } - next(); - tokenType = TOKENTYPE.IDENTIFIER; - return; - } - // something unknown is found, wrong characters, a syntax error - tokenType = TOKENTYPE.UNKNOWN; - while (c != '') { - token += c; - next(); - } - throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"'); - } + 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')), - /** - * Parse a graph. - * @returns {Object} graph - */ - function parseGraph() { - var graph = {}; + 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.d && ['dd', days] || + months === 1 && ['M'] || + months < relativeTimeThresholds.M && ['MM', months] || + years === 1 && ['y'] || ['yy', years]; - first(); - getToken(); + args[2] = withoutSuffix; + args[3] = +posNegDuration > 0; + args[4] = locale; + return substituteTimeAgo.apply({}, args); + } - // optional strict keyword - if (token == 'strict') { - graph.strict = true; - getToken(); - } - // graph or digraph keyword - if (token == 'graph' || token == 'digraph') { - graph.type = token; - getToken(); - } + /************************************ + Week of Year + ************************************/ - // optional graph id - if (tokenType == TOKENTYPE.IDENTIFIER) { - graph.id = token; - getToken(); - } - // open angle bracket - if (token != '{') { - throw newSyntaxError('Angle bracket { expected'); - } - getToken(); + // firstDayOfWeek 0 = sun, 6 = sat + // the day of the week that starts the week + // (usually sunday or monday) + // firstDayOfWeekOfYear 0 = sun, 6 = sat + // the first week is the week that contains the first + // of this day of the week + // (eg. ISO weeks use thursday (4)) + function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { + var end = firstDayOfWeekOfYear - firstDayOfWeek, + daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), + adjustedMoment; - // statements - parseStatements(graph); - // close angle bracket - if (token != '}') { - throw newSyntaxError('Angle bracket } expected'); - } - getToken(); + if (daysToDayOfWeek > end) { + daysToDayOfWeek -= 7; + } - // end of file - if (token !== '') { - throw newSyntaxError('End of file expected'); - } - getToken(); + if (daysToDayOfWeek < end - 7) { + daysToDayOfWeek += 7; + } + + adjustedMoment = moment(mom).add(daysToDayOfWeek, 'd'); + return { + week: Math.ceil(adjustedMoment.dayOfYear() / 7), + year: adjustedMoment.year() + }; + } - // remove temporary default properties - delete graph.node; - delete graph.edge; - delete graph.graph; + //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday + function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { + var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear; - return graph; - } + d = d === 0 ? 7 : d; + weekday = weekday != null ? weekday : firstDayOfWeek; + daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0); + dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; - /** - * Parse a list with statements. - * @param {Object} graph - */ - function parseStatements (graph) { - while (token !== '' && token != '}') { - parseStatement(graph); - if (token == ';') { - getToken(); + return { + year: dayOfYear > 0 ? year : year - 1, + dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear + }; } - } - } - /** - * Parse a single statement. Can be a an attribute statement, node - * statement, a series of node statements and edge statements, or a - * parameter. - * @param {Object} graph - */ - function parseStatement(graph) { - // parse subgraph - var subgraph = parseSubgraph(graph); - if (subgraph) { - // edge statements - parseEdge(graph, subgraph); + /************************************ + Top Level Functions + ************************************/ - return; - } + function makeMoment(config) { + var input = config._i, + format = config._f, + res; - // parse an attribute statement - var attr = parseAttributeStatement(graph); - if (attr) { - return; - } + config._locale = config._locale || moment.localeData(config._l); - // parse node - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier expected'); - } - var id = token; // id can be a string or a number - getToken(); + if (input === null || (format === undefined && input === '')) { + return moment.invalid({nullInput: true}); + } - if (token == '=') { - // id statement - getToken(); - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier expected'); - } - graph[id] = token; - getToken(); - // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] " - } - else { - parseNodeStatement(graph, id); - } - } + if (typeof input === 'string') { + config._i = input = config._locale.preparse(input); + } - /** - * Parse a subgraph - * @param {Object} graph parent graph object - * @return {Object | null} subgraph - */ - function parseSubgraph (graph) { - var subgraph = null; + if (moment.isMoment(input)) { + return new Moment(input, true); + } else if (format) { + if (isArray(format)) { + makeDateFromStringAndArray(config); + } else { + makeDateFromStringAndFormat(config); + } + } else { + makeDateFromInput(config); + } - // optional subgraph keyword - if (token == 'subgraph') { - subgraph = {}; - subgraph.type = 'subgraph'; - getToken(); + res = new Moment(config); + if (res._nextDay) { + // Adding is smart enough around DST + res.add(1, 'd'); + res._nextDay = undefined; + } - // optional graph id - if (tokenType == TOKENTYPE.IDENTIFIER) { - subgraph.id = token; - getToken(); + return res; } - } - // open angle bracket - if (token == '{') { - getToken(); + moment = function (input, format, locale, strict) { + var c; - if (!subgraph) { - subgraph = {}; - } - subgraph.parent = graph; - subgraph.node = graph.node; - subgraph.edge = graph.edge; - subgraph.graph = graph.graph; + if (typeof(locale) === 'boolean') { + strict = locale; + locale = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c = {}; + c._isAMomentObject = true; + c._i = input; + c._f = format; + c._l = locale; + c._strict = strict; + c._isUTC = false; + c._pf = defaultParsingFlags(); - // statements - parseStatements(subgraph); + return makeMoment(c); + }; - // close angle bracket - if (token != '}') { - throw newSyntaxError('Angle bracket } expected'); - } - getToken(); + moment.suppressDeprecationWarnings = false; - // remove temporary default properties - delete subgraph.node; - delete subgraph.edge; - delete subgraph.graph; - delete subgraph.parent; + 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 + (config._useUTC ? ' UTC' : '')); + } + ); - // register at the parent graph - if (!graph.subgraphs) { - graph.subgraphs = []; + // 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. + // + // moments should either be an array of moment objects or an array, whose + // first element is an array of moment objects. + function pickBy(fn, moments) { + var res, i; + if (moments.length === 1 && isArray(moments[0])) { + moments = moments[0]; + } + if (!moments.length) { + return moment(); + } + res = moments[0]; + for (i = 1; i < moments.length; ++i) { + if (moments[i][fn](res)) { + res = moments[i]; + } + } + return res; } - graph.subgraphs.push(subgraph); - } - return subgraph; - } + moment.min = function () { + var args = [].slice.call(arguments, 0); - /** - * parse an attribute statement like "node [shape=circle fontSize=16]". - * Available keywords are 'node', 'edge', 'graph'. - * The previous list with default attributes will be replaced - * @param {Object} graph - * @returns {String | null} keyword Returns the name of the parsed attribute - * (node, edge, graph), or null if nothing - * is parsed. - */ - function parseAttributeStatement (graph) { - // attribute statements - if (token == 'node') { - getToken(); + return pickBy('isBefore', args); + }; - // node attributes - graph.node = parseAttributeList(); - return 'node'; - } - else if (token == 'edge') { - getToken(); + moment.max = function () { + var args = [].slice.call(arguments, 0); - // edge attributes - graph.edge = parseAttributeList(); - return 'edge'; - } - else if (token == 'graph') { - getToken(); + return pickBy('isAfter', args); + }; - // graph attributes - graph.graph = parseAttributeList(); - return 'graph'; - } + // creating with utc + moment.utc = function (input, format, locale, strict) { + var c; - return null; - } + if (typeof(locale) === 'boolean') { + strict = locale; + locale = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c = {}; + c._isAMomentObject = true; + c._useUTC = true; + c._isUTC = true; + c._l = locale; + c._i = input; + c._f = format; + c._strict = strict; + c._pf = defaultParsingFlags(); - /** - * parse a node statement - * @param {Object} graph - * @param {String | Number} id - */ - function parseNodeStatement(graph, id) { - // node statement - var node = { - id: id - }; - var attr = parseAttributeList(); - if (attr) { - node.attr = attr; - } - addNode(graph, node); + return makeMoment(c).utc(); + }; - // edge statements - parseEdge(graph, id); - } + // creating with unix timestamp (in seconds) + moment.unix = function (input) { + return moment(input * 1000); + }; - /** - * Parse an edge or a series of edges - * @param {Object} graph - * @param {String | Number} from Id of the from node - */ - function parseEdge(graph, from) { - while (token == '->' || token == '--') { - var to; - var type = token; - getToken(); + // duration + moment.duration = function (input, key) { + var duration = input, + // matching against regexp is expensive, do it on demand + match = null, + sign, + ret, + parseIso, + diffRes; - var subgraph = parseSubgraph(graph); - if (subgraph) { - to = subgraph; - } - else { - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier or subgraph expected'); - } - to = token; - addNode(graph, { - id: to - }); - getToken(); - } + if (moment.isDuration(input)) { + duration = { + ms: input._milliseconds, + d: input._days, + M: input._months + }; + } else if (typeof input === 'number') { + duration = {}; + if (key) { + duration[key] = input; + } else { + duration.milliseconds = input; + } + } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) { + sign = (match[1] === '-') ? -1 : 1; + duration = { + y: 0, + d: toInt(match[DATE]) * sign, + h: toInt(match[HOUR]) * sign, + m: toInt(match[MINUTE]) * sign, + s: toInt(match[SECOND]) * sign, + ms: toInt(match[MILLISECOND]) * sign + }; + } else if (!!(match = isoDurationRegex.exec(input))) { + sign = (match[1] === '-') ? -1 : 1; + parseIso = function (inp) { + // We'd normally use ~~inp for this, but unfortunately it also + // converts floats to ints. + // inp may be undefined, so careful calling replace on it. + var res = inp && parseFloat(inp.replace(',', '.')); + // apply sign while we're at it + return (isNaN(res) ? 0 : res) * sign; + }; + duration = { + y: parseIso(match[2]), + M: parseIso(match[3]), + d: parseIso(match[4]), + h: parseIso(match[5]), + m: parseIso(match[6]), + s: parseIso(match[7]), + w: parseIso(match[8]) + }; + } else if (duration == null) {// checks for null or undefined + duration = {}; + } else if (typeof duration === 'object' && + ('from' in duration || 'to' in duration)) { + diffRes = momentsDifference(moment(duration.from), moment(duration.to)); - // parse edge attributes - var attr = parseAttributeList(); + duration = {}; + duration.ms = diffRes.milliseconds; + duration.M = diffRes.months; + } - // create edge - var edge = createEdge(graph, from, to, type, attr); - addEdge(graph, edge); + ret = new Duration(duration); - from = to; - } - } + if (moment.isDuration(input) && hasOwnProp(input, '_locale')) { + ret._locale = input._locale; + } - /** - * Parse a set with attributes, - * for example [label="1.000", shape=solid] - * @return {Object | null} attr - */ - function parseAttributeList() { - var attr = null; + return ret; + }; - while (token == '[') { - getToken(); - attr = {}; - while (token !== '' && token != ']') { - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Attribute name expected'); - } - var name = token; + // version number + moment.version = VERSION; - getToken(); - if (token != '=') { - throw newSyntaxError('Equal sign = expected'); - } - getToken(); + // default format + moment.defaultFormat = isoFormat; - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Attribute value expected'); - } - var value = token; - setValue(attr, name, value); // name can be a path + // constant that refers to the ISO standard + moment.ISO_8601 = function () {}; - getToken(); - if (token ==',') { - getToken(); - } - } + // Plugins that add properties should also add the key here (null value), + // so we can properly clone ourselves. + moment.momentProperties = momentProperties; - if (token != ']') { - throw newSyntaxError('Bracket ] expected'); - } - getToken(); - } + // This function will be called whenever a moment is mutated. + // It is intended to keep the offset in sync with the timezone. + moment.updateOffset = function () {}; - return attr; - } + // This function allows you to set a threshold for relative time strings + moment.relativeTimeThreshold = function (threshold, limit) { + if (relativeTimeThresholds[threshold] === undefined) { + return false; + } + if (limit === undefined) { + return relativeTimeThresholds[threshold]; + } + relativeTimeThresholds[threshold] = limit; + return true; + }; - /** - * Create a syntax error with extra information on current token and index. - * @param {String} message - * @returns {SyntaxError} err - */ - function newSyntaxError(message) { - return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ')'); - } + moment.lang = deprecate( + 'moment.lang is deprecated. Use moment.locale instead.', + function (key, value) { + return moment.locale(key, value); + } + ); - /** - * Chop off text after a maximum length - * @param {String} text - * @param {Number} maxLength - * @returns {String} - */ - function chop (text, maxLength) { - return (text.length <= maxLength) ? text : (text.substr(0, 27) + '...'); - } + // This function will load locale and then set the global locale. If + // no arguments are passed in, it will simply return the current global + // 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); + } - /** - * Execute a function fn for each pair of elements in two arrays - * @param {Array | *} array1 - * @param {Array | *} array2 - * @param {function} fn - */ - function forEach2(array1, array2, fn) { - if (Array.isArray(array1)) { - array1.forEach(function (elem1) { - if (Array.isArray(array2)) { - array2.forEach(function (elem2) { - fn(elem1, elem2); - }); - } - else { - fn(elem1, array2); - } - }); - } - else { - if (Array.isArray(array2)) { - array2.forEach(function (elem2) { - fn(array1, elem2); - }); - } - else { - fn(array1, array2); - } - } - } + 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); - /** - * Convert a string containing a graph in DOT language into a map containing - * with nodes and edges in the format of graph. - * @param {String} data Text containing a graph in DOT-notation - * @return {Object} graphData - */ - function DOTToGraph (data) { - // parse the DOT file - var dotData = parseDOT(data); - var graphData = { - nodes: [], - edges: [], - options: {} - }; + // backwards compat for now: also set the locale + moment.locale(name); - // copy the nodes - if (dotData.nodes) { - dotData.nodes.forEach(function (dotNode) { - var graphNode = { - id: dotNode.id, - label: String(dotNode.label || dotNode.id) - }; - merge(graphNode, dotNode.attr); - if (graphNode.image) { - graphNode.shape = 'image'; - } - graphData.nodes.push(graphNode); - }); - } + return locales[name]; + } else { + // useful for testing + delete locales[name]; + return null; + } + }; - // copy the edges - if (dotData.edges) { - /** - * Convert an edge in DOT format to an edge with VisGraph format - * @param {Object} dotEdge - * @returns {Object} graphEdge - */ - var convertEdge = function (dotEdge) { - var graphEdge = { - from: dotEdge.from, - to: dotEdge.to - }; - merge(graphEdge, dotEdge.attr); - graphEdge.style = (dotEdge.type == '->') ? 'arrow' : 'line'; - return graphEdge; - } + moment.langData = deprecate( + 'moment.langData is deprecated. Use moment.localeData instead.', + function (key) { + return moment.localeData(key); + } + ); - dotData.edges.forEach(function (dotEdge) { - var from, to; - if (dotEdge.from instanceof Object) { - from = dotEdge.from.nodes; - } - else { - from = { - id: dotEdge.from + // returns locale data + moment.localeData = function (key) { + var locale; + + if (key && key._locale && key._locale._abbr) { + key = key._locale._abbr; } - } - if (dotEdge.to instanceof Object) { - to = dotEdge.to.nodes; - } - else { - to = { - id: dotEdge.to + if (!key) { + return moment._locale; } - } - if (dotEdge.from instanceof Object && dotEdge.from.edges) { - dotEdge.from.edges.forEach(function (subEdge) { - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - } + if (!isArray(key)) { + //short-circuit everything else + locale = loadLocale(key); + if (locale) { + return locale; + } + key = [key]; + } - forEach2(from, to, function (from, to) { - var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr); - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); + return chooseLocale(key); + }; - if (dotEdge.to instanceof Object && dotEdge.to.edges) { - dotEdge.to.edges.forEach(function (subEdge) { - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - } - }); - } + // compare moment object + moment.isMoment = function (obj) { + return obj instanceof Moment || + (obj != null && hasOwnProp(obj, '_isAMomentObject')); + }; - // copy the options - if (dotData.attr) { - graphData.options = dotData.attr; - } + // for typechecking Duration objects + moment.isDuration = function (obj) { + return obj instanceof Duration; + }; - return graphData; - } + for (i = lists.length - 1; i >= 0; --i) { + makeList(lists[i]); + } - // exports - exports.parseDOT = parseDOT; - exports.DOTToGraph = DOTToGraph; + moment.normalizeUnits = function (units) { + return normalizeUnits(units); + }; + moment.invalid = function (flags) { + var m = moment.utc(NaN); + if (flags != null) { + extend(m._pf, flags); + } + else { + m._pf.userInvalidated = true; + } -/***/ }, -/* 53 */ -/***/ function(module, exports, __webpack_require__) { + return m; + }; - - function parseGephi(gephiJSON, options) { - var edges = []; - var nodes = []; - this.options = { - edges: { - inheritColor: true - }, - nodes: { - allowedToMove: false, - parseColor: false - } - }; + moment.parseZone = function () { + return moment.apply(null, arguments).parseZone(); + }; - if (options !== undefined) { - this.options.nodes['allowedToMove'] = options.allowedToMove | false; - this.options.nodes['parseColor'] = options.parseColor | false; - this.options.edges['inheritColor'] = options.inheritColor | true; - } + moment.parseTwoDigitYear = function (input) { + return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); + }; - var gEdges = gephiJSON.edges; - var gNodes = gephiJSON.nodes; - for (var i = 0; i < gEdges.length; i++) { - var edge = {}; - var gEdge = gEdges[i]; - edge['id'] = gEdge.id; - edge['from'] = gEdge.source; - edge['to'] = gEdge.target; - edge['attributes'] = gEdge.attributes; - // edge['value'] = gEdge.attributes !== undefined ? gEdge.attributes.Weight : undefined; - // edge['width'] = edge['value'] !== undefined ? undefined : edgegEdge.size; - edge['color'] = gEdge.color; - edge['inheritColor'] = edge['color'] !== undefined ? false : this.options.inheritColor; - edges.push(edge); - } + moment.isDate = isDate; - for (var i = 0; i < gNodes.length; i++) { - var node = {}; - var gNode = gNodes[i]; - node['id'] = gNode.id; - node['attributes'] = gNode.attributes; - node['x'] = gNode.x; - node['y'] = gNode.y; - node['label'] = gNode.label; - if (this.options.nodes.parseColor == true) { - node['color'] = gNode.color; - } - else { - node['color'] = gNode.color !== undefined ? {background:gNode.color, border:gNode.color} : undefined; - } - node['radius'] = gNode.size; - node['allowedToMoveX'] = this.options.nodes.allowedToMove; - node['allowedToMoveY'] = this.options.nodes.allowedToMove; - nodes.push(node); - } + /************************************ + Moment Prototype + ************************************/ - return {nodes:nodes, edges:edges}; - } - exports.parseGephi = parseGephi; + extend(moment.fn = Moment.prototype, { -/***/ }, -/* 54 */ -/***/ function(module, exports, __webpack_require__) { + clone : function () { + return moment(this); + }, - var util = __webpack_require__(1); + valueOf : function () { + return +this._d - ((this._offset || 0) * 60000); + }, - /** - * @class Groups - * This class can store groups and properties specific for groups. - */ - function Groups() { - this.clear(); - this.defaultIndex = 0; - } + unix : function () { + return Math.floor(+this / 1000); + }, + toString : function () { + return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); + }, - /** - * default constants for group colors - */ - Groups.DEFAULT = [ - {border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}, hover: {border: "#2B7CE9", background: "#D2E5FF"}}, // blue - {border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}, hover: {border: "#FFA500", background: "#FFFFA3"}}, // yellow - {border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}, hover: {border: "#FA0A10", background: "#FFAFB1"}}, // red - {border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}, hover: {border: "#41A906", background: "#A1EC76"}}, // green - {border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}, hover: {border: "#E129F0", background: "#F0B3F5"}}, // magenta - {border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}, hover: {border: "#7C29F0", background: "#D3BDF0"}}, // purple - {border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}, hover: {border: "#C37F00", background: "#FFCA66"}}, // orange - {border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}, hover: {border: "#4220FB", background: "#9B9BFD"}}, // darkblue - {border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}, hover: {border: "#FD5A77", background: "#FFD1D9"}}, // pink - {border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}, hover: {border: "#4AD63A", background: "#E6FFE3"}} // mint - ]; + toDate : function () { + return this._offset ? new Date(+this) : this._d; + }, + toISOString : function () { + var m = moment(this).utc(); + if (0 < m.year() && m.year() <= 9999) { + if ('function' === typeof Date.prototype.toISOString) { + // native implementation is ~50x faster, use it when we can + return this.toDate().toISOString(); + } else { + return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } + } else { + return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } + }, - /** - * Clear all groups - */ - Groups.prototype.clear = function () { - this.groups = {}; - this.groups.length = function() - { - var i = 0; - for ( var p in this ) { - if (this.hasOwnProperty(p)) { - i++; - } - } - return i; - } - }; + toArray : function () { + var m = this; + return [ + m.year(), + m.month(), + m.date(), + m.hours(), + m.minutes(), + m.seconds(), + m.milliseconds() + ]; + }, + isValid : function () { + return isValid(this); + }, - /** - * get group properties of a groupname. If groupname is not found, a new group - * is added. - * @param {*} groupname Can be a number, string, Date, etc. - * @return {Object} group The created group, containing all group properties - */ - Groups.prototype.get = function (groupname) { - var group = this.groups[groupname]; - if (group == undefined) { - // create new group - var index = this.defaultIndex % Groups.DEFAULT.length; - this.defaultIndex++; - group = {}; - group.color = Groups.DEFAULT[index]; - this.groups[groupname] = group; - } + isDSTShifted : function () { + if (this._a) { + return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0; + } - return group; - }; + return false; + }, - /** - * Add a custom group style - * @param {String} groupname - * @param {Object} style An object containing borderColor, - * backgroundColor, etc. - * @return {Object} group The created group object - */ - Groups.prototype.add = function (groupname, style) { - this.groups[groupname] = style; - return style; - }; + parsingFlags : function () { + return extend({}, this._pf); + }, - module.exports = Groups; + invalidAt: function () { + return this._pf.overflow; + }, + utc : function (keepLocalTime) { + return this.utcOffset(0, keepLocalTime); + }, -/***/ }, -/* 55 */ -/***/ function(module, exports, __webpack_require__) { + local : function (keepLocalTime) { + if (this._isUTC) { + this.utcOffset(0, keepLocalTime); + this._isUTC = false; - /** - * @class Images - * This class loads images and keeps them stored. - */ - function Images() { - this.images = {}; - this.imageBroken = {}; - this.callback = undefined; - } + if (keepLocalTime) { + this.subtract(this._dateUtcOffset(), 'm'); + } + } + return this; + }, - /** - * Set an onload callback function. This will be called each time an image - * is loaded - * @param {function} callback - */ - Images.prototype.setOnloadCallback = function(callback) { - this.callback = callback; - }; + format : function (inputString) { + var output = formatMoment(this, inputString || moment.defaultFormat); + return this.localeData().postformat(output); + }, - /** - * - * @param {string} url Url of the image - * @param {string} url Url of an image to use if the url image is not found - * @return {Image} img The image object - */ - Images.prototype.load = function(url, brokenUrl) { - var img = this.images[url]; // make a pointer - if (img === undefined) { - // create the image - var me = this; - img = new Image(); - img.onload = function () { - // IE11 fix -- thanks dponch! - if (this.width == 0) { - document.body.appendChild(this); - this.width = this.offsetWidth; - this.height = this.offsetHeight; - document.body.removeChild(this); - } + add : createAdder(1, 'add'), - if (me.callback) { - me.images[url] = img; - me.callback(this); - } - }; + subtract : createAdder(-1, 'subtract'), - img.onerror = function () { - if (brokenUrl === undefined) { - console.error("Could not load image:", url); - delete this.src; - if (me.callback) { - me.callback(this); - } - } - else if (me.imageBroken[url] === true) { - console.error("Could not load brokenImage:", brokenUrl); - delete this.src; - if (me.callback) { - me.callback(this); - } - } - else { - this.src = brokenUrl; - me.imageBroken[url] = true; - } - }; + diff : function (input, units, asFloat) { + var that = makeAs(input, this), + zoneDiff = (that.utcOffset() - this.utcOffset()) * 6e4, + anchor, diff, output, daysAdjust; - img.src = url; - } + units = normalizeUnits(units); - return img; - }; + if (units === 'year' || units === 'month' || units === 'quarter') { + output = monthDiff(this, that); + if (units === 'quarter') { + output = output / 3; + } else if (units === 'year') { + output = output / 12; + } + } else { + diff = this - that; + output = units === 'second' ? diff / 1e3 : // 1000 + units === 'minute' ? diff / 6e4 : // 1000 * 60 + units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 + units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst + units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst + diff; + } + return asFloat ? output : absRound(output); + }, - module.exports = Images; + from : function (time, withoutSuffix) { + return moment.duration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix); + }, + fromNow : function (withoutSuffix) { + return this.from(moment(), withoutSuffix); + }, -/***/ }, -/* 56 */ -/***/ function(module, exports, __webpack_require__) { + calendar : function (time) { + // We want to compare the start of today, vs this. + // Getting start-of-today depends on whether we're locat/utc/offset + // or not. + var now = time || moment(), + sod = makeAs(now, this).startOf('day'), + diff = this.diff(sod, 'days', true), + format = diff < -6 ? 'sameElse' : + diff < -1 ? 'lastWeek' : + diff < 0 ? 'lastDay' : + diff < 1 ? 'sameDay' : + diff < 2 ? 'nextDay' : + diff < 7 ? 'nextWeek' : 'sameElse'; + return this.format(this.localeData().calendar(format, this, moment(now))); + }, - var util = __webpack_require__(1); + isLeapYear : function () { + return isLeapYear(this.year()); + }, - /** - * @class Node - * A node. A node can be connected to other nodes via one or multiple edges. - * @param {object} properties An object containing properties for the node. All - * properties are optional, except for the id. - * {number} id Id of the node. Required - * {string} label Text label for the node - * {number} x Horizontal position of the node - * {number} y Vertical position of the node - * {string} shape Node shape, available: - * "database", "circle", "ellipse", - * "box", "image", "text", "dot", - * "star", "triangle", "triangleDown", - * "square" - * {string} image An image url - * {string} title An title text, can be HTML - * {anytype} group A group name or number - * @param {Network.Images} imagelist A list with images. Only needed - * when the node has an image - * @param {Network.Groups} grouplist A list with groups. Needed for - * retrieving group properties - * @param {Object} constants An object with default values for - * example for the color - * - */ - function Node(properties, imagelist, grouplist, networkConstants) { - var constants = util.selectiveBridgeObject(['nodes'],networkConstants); - this.options = constants.nodes; + isDST : function () { + return (this.utcOffset() > this.clone().month(0).utcOffset() || + this.utcOffset() > this.clone().month(5).utcOffset()); + }, - this.selected = false; - this.hover = false; + day : function (input) { + var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); + if (input != null) { + input = parseWeekday(input, this.localeData()); + return this.add(input - day, 'd'); + } else { + return day; + } + }, - this.edges = []; // all edges connected to this node - this.dynamicEdges = []; - this.reroutedEdges = {}; + month : makeAccessor('Month', true), - this.fontDrawThreshold = 3; + startOf : function (units) { + units = normalizeUnits(units); + // the following switch intentionally omits break keywords + // to utilize falling through the cases. + switch (units) { + case 'year': + this.month(0); + /* falls through */ + case 'quarter': + case 'month': + this.date(1); + /* falls through */ + case 'week': + case 'isoWeek': + case 'day': + this.hours(0); + /* falls through */ + case 'hour': + this.minutes(0); + /* falls through */ + case 'minute': + this.seconds(0); + /* falls through */ + case 'second': + this.milliseconds(0); + /* falls through */ + } - // set defaults for the properties - this.id = undefined; - this.allowedToMoveX = false; - this.allowedToMoveY = false; - this.xFixed = false; - this.yFixed = false; - this.horizontalAlignLeft = true; // these are for the navigation controls - this.verticalAlignTop = true; // these are for the navigation controls - this.baseRadiusValue = networkConstants.nodes.radius; - this.radiusFixed = false; - this.level = -1; - this.preassignedLevel = false; - this.hierarchyEnumerated = false; - this.labelDimensions = {top:0, left:0, width:0, height:0, yLine:0}; // could be cached - this.boundingBox = {top:0, left:0, right:0, bottom:0}; + // weeks are a special case + if (units === 'week') { + this.weekday(0); + } else if (units === 'isoWeek') { + this.isoWeekday(1); + } - this.imagelist = imagelist; - this.grouplist = grouplist; + // quarters are also special + if (units === 'quarter') { + this.month(Math.floor(this.month() / 3) * 3); + } - // physics properties - this.fx = 0.0; // external force x - this.fy = 0.0; // external force y - this.vx = 0.0; // velocity x - this.vy = 0.0; // velocity y - this.x = null; - this.y = null; + return this; + }, - // used for reverting to previous position on stabilization - this.previousState = {vx:0,vy:0,x:0,y:0}; + endOf: function (units) { + units = normalizeUnits(units); + if (units === undefined || units === 'millisecond') { + return this; + } + return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms'); + }, - this.damping = networkConstants.physics.damping; // written every time gravity is calculated - this.fixedData = {x:null,y:null}; + isAfter: function (input, units) { + var inputMs; + units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); + if (units === 'millisecond') { + input = moment.isMoment(input) ? input : moment(input); + return +this > +input; + } else { + inputMs = moment.isMoment(input) ? +input : +moment(input); + return inputMs < +this.clone().startOf(units); + } + }, - this.setProperties(properties, constants); + isBefore: function (input, units) { + var inputMs; + units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); + if (units === 'millisecond') { + input = moment.isMoment(input) ? input : moment(input); + return +this < +input; + } else { + inputMs = moment.isMoment(input) ? +input : +moment(input); + return +this.clone().endOf(units) < inputMs; + } + }, - // creating the variables for clustering - this.resetCluster(); - this.dynamicEdgesLength = 0; - this.clusterSession = 0; - this.clusterSizeWidthFactor = networkConstants.clustering.nodeScaling.width; - this.clusterSizeHeightFactor = networkConstants.clustering.nodeScaling.height; - this.clusterSizeRadiusFactor = networkConstants.clustering.nodeScaling.radius; - this.maxNodeSizeIncrements = networkConstants.clustering.maxNodeSizeIncrements; - this.growthIndicator = 0; + isBetween: function (from, to, units) { + return this.isAfter(from, units) && this.isBefore(to, units); + }, - // variables to tell the node about the network. - this.networkScaleInv = 1; - this.networkScale = 1; - this.canvasTopLeft = {"x": -300, "y": -300}; - this.canvasBottomRight = {"x": 300, "y": 300}; - this.parentEdgeId = null; - } + isSame: function (input, units) { + var inputMs; + units = normalizeUnits(units || 'millisecond'); + if (units === 'millisecond') { + input = moment.isMoment(input) ? input : moment(input); + return +this === +input; + } else { + inputMs = +moment(input); + return +(this.clone().startOf(units)) <= inputMs && inputMs <= +(this.clone().endOf(units)); + } + }, + min: deprecate( + '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; + } + ), - /** - * Revert the position and velocity of the previous step. - */ - Node.prototype.revertPosition = function() { - this.x = this.previousState.x; - this.y = this.previousState.y; - this.vx = this.previousState.vx; - this.vy = this.previousState.vy; - } + max: deprecate( + '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; + } + ), + zone : deprecate( + 'moment().zone is deprecated, use moment().utcOffset instead. ' + + 'https://github.com/moment/moment/issues/1779', + function (input, keepLocalTime) { + if (input != null) { + if (typeof input !== 'string') { + input = -input; + } - /** - * (re)setting the clustering variables and objects - */ - Node.prototype.resetCluster = function() { - // clustering variables - this.formationScale = undefined; // this is used to determine when to open the cluster - this.clusterSize = 1; // this signifies the total amount of nodes in this cluster - this.containedNodes = {}; - this.containedEdges = {}; - this.clusterSessions = []; - }; + this.utcOffset(input, keepLocalTime); - /** - * Attach a edge to the node - * @param {Edge} edge - */ - Node.prototype.attachEdge = function(edge) { - if (this.edges.indexOf(edge) == -1) { - this.edges.push(edge); - } - if (this.dynamicEdges.indexOf(edge) == -1) { - this.dynamicEdges.push(edge); - } - this.dynamicEdgesLength = this.dynamicEdges.length; - }; + return this; + } else { + return -this.utcOffset(); + } + } + ), - /** - * Detach a edge from the node - * @param {Edge} edge - */ - Node.prototype.detachEdge = function(edge) { - var index = this.edges.indexOf(edge); - if (index != -1) { - this.edges.splice(index, 1); - } - index = this.dynamicEdges.indexOf(edge); - if (index != -1) { - this.dynamicEdges.splice(index, 1); - } - this.dynamicEdgesLength = this.dynamicEdges.length; - }; + // keepLocalTime = true means only change the timezone, without + // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]--> + // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset + // +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. + utcOffset : function (input, keepLocalTime) { + var offset = this._offset || 0, + localAdjust; + if (input != null) { + if (typeof input === 'string') { + input = utcOffsetFromString(input); + } + if (Math.abs(input) < 16) { + input = input * 60; + } + if (!this._isUTC && keepLocalTime) { + localAdjust = this._dateUtcOffset(); + } + this._offset = input; + this._isUTC = true; + if (localAdjust != null) { + this.add(localAdjust, 'm'); + } + if (offset !== input) { + if (!keepLocalTime || this._changeInProgress) { + addOrSubtractDurationFromMoment(this, + moment.duration(input - offset, 'm'), 1, false); + } else if (!this._changeInProgress) { + this._changeInProgress = true; + moment.updateOffset(this, true); + this._changeInProgress = null; + } + } + return this; + } else { + return this._isUTC ? offset : this._dateUtcOffset(); + } + }, - /** - * Set or overwrite properties for the node - * @param {Object} properties an object with properties - * @param {Object} constants and object with default, global properties - */ - Node.prototype.setProperties = function(properties, constants) { - if (!properties) { - return; - } + isLocal : function () { + return !this._isUTC; + }, - var fields = ['borderWidth','borderWidthSelected','shape','image','brokenImage','radius','fontColor', - 'fontSize','fontFace','fontFill','fontStrokeWidth','fontStrokeColor','group','mass' - ]; - util.selectiveDeepExtend(fields, this.options, properties); + isUtcOffset : function () { + return this._isUTC; + }, - // basic properties - if (properties.id !== undefined) {this.id = properties.id;} - if (properties.label !== undefined) {this.label = properties.label; this.originalLabel = properties.label;} - if (properties.title !== undefined) {this.title = properties.title;} - if (properties.x !== undefined) {this.x = properties.x;} - if (properties.y !== undefined) {this.y = properties.y;} - if (properties.value !== undefined) {this.value = properties.value;} - if (properties.level !== undefined) {this.level = properties.level; this.preassignedLevel = true;} + isUtc : function () { + return this._isUTC && this._offset === 0; + }, - // navigation controls properties - if (properties.horizontalAlignLeft !== undefined) {this.horizontalAlignLeft = properties.horizontalAlignLeft;} - if (properties.verticalAlignTop !== undefined) {this.verticalAlignTop = properties.verticalAlignTop;} - if (properties.triggerFunction !== undefined) {this.triggerFunction = properties.triggerFunction;} + zoneAbbr : function () { + return this._isUTC ? 'UTC' : ''; + }, - if (this.id === undefined) { - throw "Node must have an id"; - } + zoneName : function () { + return this._isUTC ? 'Coordinated Universal Time' : ''; + }, - // copy group properties - if (typeof properties.group === 'number' || (typeof properties.group === 'string' && properties.group != '')) { - var groupObj = this.grouplist.get(properties.group); - util.deepExtend(this.options, groupObj); - // the color object needs to be completely defined. Since groups can partially overwrite the colors, we parse it again, just in case. - this.options.color = util.parseColor(this.options.color); - } - // individual shape properties - if (properties.radius !== undefined) {this.baseRadiusValue = this.options.radius;} - if (properties.color !== undefined) {this.options.color = util.parseColor(properties.color);} + parseZone : function () { + if (this._tzm) { + this.utcOffset(this._tzm); + } else if (typeof this._i === 'string') { + this.utcOffset(utcOffsetFromString(this._i)); + } + return this; + }, - if (this.options.image !== undefined && this.options.image!= "") { - if (this.imagelist) { - this.imageObj = this.imagelist.load(this.options.image, this.options.brokenImage); - } - else { - throw "No imagelist provided"; - } - } + hasAlignedHourOffset : function (input) { + if (!input) { + input = 0; + } + else { + input = moment(input).utcOffset(); + } - if (properties.allowedToMoveX !== undefined) { - this.xFixed = !properties.allowedToMoveX; - this.allowedToMoveX = properties.allowedToMoveX; - } - else if (properties.x !== undefined && this.allowedToMoveX == false) { - this.xFixed = true; - } + return (this.utcOffset() - input) % 60 === 0; + }, + daysInMonth : function () { + return daysInMonth(this.year(), this.month()); + }, - if (properties.allowedToMoveY !== undefined) { - this.yFixed = !properties.allowedToMoveY; - this.allowedToMoveY = properties.allowedToMoveY; - } - else if (properties.y !== undefined && this.allowedToMoveY == false) { - this.yFixed = true; - } + dayOfYear : function (input) { + var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; + return input == null ? dayOfYear : this.add((input - dayOfYear), 'd'); + }, - this.radiusFixed = this.radiusFixed || (properties.radius !== undefined); + quarter : function (input) { + return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3); + }, - if (this.options.shape === 'image' || this.options.shape === 'circularImage') { - this.options.radiusMin = constants.nodes.widthMin; - this.options.radiusMax = constants.nodes.widthMax; - } + weekYear : function (input) { + var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year; + return input == null ? year : this.add((input - year), 'y'); + }, - // choose draw method depending on the shape - switch (this.options.shape) { - case 'database': this.draw = this._drawDatabase; this.resize = this._resizeDatabase; break; - case 'box': this.draw = this._drawBox; this.resize = this._resizeBox; break; - case 'circle': this.draw = this._drawCircle; this.resize = this._resizeCircle; break; - case 'ellipse': this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break; - // TODO: add diamond shape - case 'image': this.draw = this._drawImage; this.resize = this._resizeImage; break; - case 'circularImage': this.draw = this._drawCircularImage; this.resize = this._resizeCircularImage; break; - case 'text': this.draw = this._drawText; this.resize = this._resizeText; break; - case 'dot': this.draw = this._drawDot; this.resize = this._resizeShape; break; - case 'square': this.draw = this._drawSquare; this.resize = this._resizeShape; break; - case 'triangle': this.draw = this._drawTriangle; this.resize = this._resizeShape; break; - case 'triangleDown': this.draw = this._drawTriangleDown; this.resize = this._resizeShape; break; - case 'star': this.draw = this._drawStar; this.resize = this._resizeShape; break; - default: this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break; - } - // reset the size of the node, this can be changed - this._reset(); + isoWeekYear : function (input) { + var year = weekOfYear(this, 1, 4).year; + return input == null ? year : this.add((input - year), 'y'); + }, - }; + week : function (input) { + var week = this.localeData().week(this); + return input == null ? week : this.add((input - week) * 7, 'd'); + }, - /** - * select this node - */ - Node.prototype.select = function() { - this.selected = true; - this._reset(); - }; + isoWeek : function (input) { + var week = weekOfYear(this, 1, 4).week; + return input == null ? week : this.add((input - week) * 7, 'd'); + }, - /** - * unselect this node - */ - Node.prototype.unselect = function() { - this.selected = false; - this._reset(); - }; + weekday : function (input) { + var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; + return input == null ? weekday : this.add(input - weekday, 'd'); + }, + isoWeekday : function (input) { + // behaves the same as moment#day except + // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) + // as a setter, sunday should belong to the previous week. + return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); + }, - /** - * Reset the calculated size of the node, forces it to recalculate its size - */ - Node.prototype.clearSizeCache = function() { - this._reset(); - }; + isoWeeksInYear : function () { + return weeksInYear(this.year(), 1, 4); + }, - /** - * Reset the calculated size of the node, forces it to recalculate its size - * @private - */ - Node.prototype._reset = function() { - this.width = undefined; - this.height = undefined; - }; + weeksInYear : function () { + var weekInfo = this.localeData()._week; + return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); + }, - /** - * get the title of this node. - * @return {string} title The title of the node, or undefined when no title - * has been set. - */ - Node.prototype.getTitle = function() { - return typeof this.title === "function" ? this.title() : this.title; - }; + get : function (units) { + units = normalizeUnits(units); + return this[units](); + }, - /** - * Calculate the distance to the border of the Node - * @param {CanvasRenderingContext2D} ctx - * @param {Number} angle Angle in radians - * @returns {number} distance Distance to the border in pixels - */ - Node.prototype.distanceToBorder = function (ctx, angle) { - var borderWidth = 1; + set : function (units, value) { + var unit; + if (typeof units === 'object') { + for (unit in units) { + this.set(unit, units[unit]); + } + } + else { + units = normalizeUnits(units); + if (typeof this[units] === 'function') { + this[units](value); + } + } + return this; + }, - if (!this.width) { - this.resize(ctx); - } + // If passed a locale key, it will set the locale for this + // instance. Otherwise, it will return the locale configuration + // variables for this instance. + locale : function (key) { + var newLocaleData; + + if (key === undefined) { + return this._locale._abbr; + } else { + newLocaleData = moment.localeData(key); + if (newLocaleData != null) { + this._locale = newLocaleData; + } + return this; + } + }, + + lang : deprecate( + 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', + function (key) { + if (key === undefined) { + return this.localeData(); + } else { + return this.locale(key); + } + } + ), - switch (this.options.shape) { - case 'circle': - case 'dot': - return this.options.radius+ borderWidth; + localeData : function () { + return this._locale; + }, - case 'ellipse': - var a = this.width / 2; - var b = this.height / 2; - var w = (Math.sin(angle) * a); - var h = (Math.cos(angle) * b); - return a * b / Math.sqrt(w * w + h * h); + _dateUtcOffset : function () { + // On Firefox.24 Date#getTimezoneOffset returns a floating point. + // https://github.com/moment/moment/pull/1871 + return -Math.round(this._d.getTimezoneOffset() / 15) * 15; + } - // TODO: implement distanceToBorder for database - // TODO: implement distanceToBorder for triangle - // TODO: implement distanceToBorder for triangleDown + }); - case 'box': - case 'image': - case 'text': - default: - if (this.width) { - return Math.min( - Math.abs(this.width / 2 / Math.cos(angle)), - Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth; - // TODO: reckon with border radius too in case of box - } - else { - return 0; - } + function rawMonthSetter(mom, value) { + var dayOfMonth; - } - // TODO: implement calculation of distance to border for all shapes - }; + // TODO: Move this out of here! + if (typeof value === 'string') { + value = mom.localeData().monthsParse(value); + // TODO: Another silent failure? + if (typeof value !== 'number') { + return mom; + } + } - /** - * Set forces acting on the node - * @param {number} fx Force in horizontal direction - * @param {number} fy Force in vertical direction - */ - Node.prototype._setForce = function(fx, fy) { - this.fx = fx; - this.fy = fy; - }; + dayOfMonth = Math.min(mom.date(), + daysInMonth(mom.year(), value)); + mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); + return mom; + } - /** - * Add forces acting on the node - * @param {number} fx Force in horizontal direction - * @param {number} fy Force in vertical direction - * @private - */ - Node.prototype._addForce = function(fx, fy) { - this.fx += fx; - this.fy += fy; - }; + function rawGetter(mom, unit) { + return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit](); + } - /** - * Store the state before the next step - */ - Node.prototype.storeState = function() { - this.previousState.x = this.x; - this.previousState.y = this.y; - this.previousState.vx = this.vx; - this.previousState.vy = this.vy; - } + function rawSetter(mom, unit, value) { + if (unit === 'Month') { + return rawMonthSetter(mom, value); + } else { + return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); + } + } - /** - * Perform one discrete step for the node - * @param {number} interval Time interval in seconds - */ - Node.prototype.discreteStep = function(interval) { - this.storeState(); - if (!this.xFixed) { - var dx = this.damping * this.vx; // damping force - var ax = (this.fx - dx) / this.options.mass; // acceleration - this.vx += ax * interval; // velocity - this.x += this.vx * interval; // position - } - else { - this.fx = 0; - this.vx = 0; - } + function makeAccessor(unit, keepTime) { + return function (value) { + if (value != null) { + rawSetter(this, unit, value); + moment.updateOffset(this, keepTime); + return this; + } else { + return rawGetter(this, unit); + } + }; + } - if (!this.yFixed) { - var dy = this.damping * this.vy; // damping force - var ay = (this.fy - dy) / this.options.mass; // acceleration - this.vy += ay * interval; // velocity - this.y += this.vy * interval; // position - } - else { - this.fy = 0; - this.vy = 0; - } - }; + moment.fn.millisecond = moment.fn.milliseconds = makeAccessor('Milliseconds', false); + moment.fn.second = moment.fn.seconds = makeAccessor('Seconds', false); + moment.fn.minute = moment.fn.minutes = makeAccessor('Minutes', false); + // Setting the hour should keep the time, because the user explicitly + // specified which hour he wants. So trying to maintain the same hour (in + // a new timezone) makes sense. Adding/subtracting hours does not follow + // this rule. + 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.year = 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; + moment.fn.months = moment.fn.month; + moment.fn.weeks = moment.fn.week; + moment.fn.isoWeeks = moment.fn.isoWeek; + moment.fn.quarters = moment.fn.quarter; + // add aliased format methods + moment.fn.toJSON = moment.fn.toISOString; - /** - * Perform one discrete step for the node - * @param {number} interval Time interval in seconds - * @param {number} maxVelocity The speed limit imposed on the velocity - */ - Node.prototype.discreteStepLimited = function(interval, maxVelocity) { - this.storeState(); - if (!this.xFixed) { - var dx = this.damping * this.vx; // damping force - var ax = (this.fx - dx) / this.options.mass; // acceleration - this.vx += ax * interval; // velocity - this.vx = (Math.abs(this.vx) > maxVelocity) ? ((this.vx > 0) ? maxVelocity : -maxVelocity) : this.vx; - this.x += this.vx * interval; // position - } - else { - this.fx = 0; - this.vx = 0; - } + // alias isUtc for dev-friendliness + moment.fn.isUTC = moment.fn.isUtc; - if (!this.yFixed) { - var dy = this.damping * this.vy; // damping force - var ay = (this.fy - dy) / this.options.mass; // acceleration - this.vy += ay * interval; // velocity - this.vy = (Math.abs(this.vy) > maxVelocity) ? ((this.vy > 0) ? maxVelocity : -maxVelocity) : this.vy; - this.y += this.vy * interval; // position - } - else { - this.fy = 0; - this.vy = 0; - } - }; + /************************************ + Duration Prototype + ************************************/ - /** - * Check if this node has a fixed x and y position - * @return {boolean} true if fixed, false if not - */ - Node.prototype.isFixed = function() { - return (this.xFixed && this.yFixed); - }; - /** - * Check if this node is moving - * @param {number} vmin the minimum velocity considered as "moving" - * @return {boolean} true if moving, false if it has no velocity - */ - Node.prototype.isMoving = function(vmin) { - var velocity = Math.sqrt(Math.pow(this.vx,2) + Math.pow(this.vy,2)); - // this.velocity = Math.sqrt(Math.pow(this.vx,2) + Math.pow(this.vy,2)) - return (velocity > vmin); - }; + function daysToYears (days) { + // 400 years have 146097 days (taking into account leap year rules) + return days * 400 / 146097; + } - /** - * check if this node is selecte - * @return {boolean} selected True if node is selected, else false - */ - Node.prototype.isSelected = function() { - return this.selected; - }; + function yearsToDays (years) { + // years * 365 + absRound(years / 4) - + // absRound(years / 100) + absRound(years / 400); + return years * 146097 / 400; + } - /** - * Retrieve the value of the node. Can be undefined - * @return {Number} value - */ - Node.prototype.getValue = function() { - return this.value; - }; + extend(moment.duration.fn = Duration.prototype, { - /** - * Calculate the distance from the nodes location to the given location (x,y) - * @param {Number} x - * @param {Number} y - * @return {Number} value - */ - Node.prototype.getDistance = function(x, y) { - var dx = this.x - x, - dy = this.y - y; - return Math.sqrt(dx * dx + dy * dy); - }; + _bubble : function () { + var milliseconds = this._milliseconds, + days = this._days, + months = this._months, + data = this._data, + seconds, minutes, hours, years = 0; + // The following code bubbles up values, see the tests for + // examples of what that means. + data.milliseconds = milliseconds % 1000; - /** - * Adjust the value range of the node. The node will adjust it's radius - * based on its value. - * @param {Number} min - * @param {Number} max - */ - Node.prototype.setValueRange = function(min, max) { - if (!this.radiusFixed && this.value !== undefined) { - if (max == min) { - this.options.radius= (this.options.radiusMin + this.options.radiusMax) / 2; - } - else { - var scale = (this.options.radiusMax - this.options.radiusMin) / (max - min); - this.options.radius= (this.value - min) * scale + this.options.radiusMin; - } - } - this.baseRadiusValue = this.options.radius; - }; + seconds = absRound(milliseconds / 1000); + data.seconds = seconds % 60; - /** - * Draw this node in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - */ - Node.prototype.draw = function(ctx) { - throw "Draw method not initialized for node"; - }; + minutes = absRound(seconds / 60); + data.minutes = minutes % 60; - /** - * Recalculate the size of this node in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - */ - Node.prototype.resize = function(ctx) { - throw "Resize method not initialized for node"; - }; + hours = absRound(minutes / 60); + data.hours = hours % 24; - /** - * Check if this object is overlapping with the provided object - * @param {Object} obj an object with parameters left, top, right, bottom - * @return {boolean} True if location is located on node - */ - Node.prototype.isOverlappingWith = function(obj) { - return (this.left < obj.right && - this.left + this.width > obj.left && - this.top < obj.bottom && - this.top + this.height > obj.top); - }; + days += absRound(hours / 24); - Node.prototype._resizeImage = function (ctx) { - // TODO: pre calculate the image size + // Accurately convert days to years, assume start from year 0. + years = absRound(daysToYears(days)); + days -= absRound(yearsToDays(years)); - if (!this.width || !this.height) { // undefined or 0 - var width, height; - if (this.value) { - this.options.radius= this.baseRadiusValue; - var scale = this.imageObj.height / this.imageObj.width; - if (scale !== undefined) { - width = this.options.radius|| this.imageObj.width; - height = this.options.radius* scale || this.imageObj.height; - } - else { - width = 0; - height = 0; - } - } - else { - width = this.imageObj.width; - height = this.imageObj.height; - } - this.width = width; - this.height = height; + // 30 days to a month + // TODO (iskren): Use anchor date (like 1st Jan) to compute this. + months += absRound(days / 30); + days %= 30; - this.growthIndicator = 0; - if (this.width > 0 && this.height > 0) { - this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; - this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; - this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor; - this.growthIndicator = this.width - width; - } - } - }; + // 12 months -> 1 year + years += absRound(months / 12); + months %= 12; - Node.prototype._drawImageAtPosition = function (ctx) { - if (this.imageObj.width != 0 ) { - // draw the shade - if (this.clusterSize > 1) { - var lineWidth = ((this.clusterSize > 1) ? 10 : 0.0); - lineWidth *= this.networkScaleInv; - lineWidth = Math.min(0.2 * this.width,lineWidth); + data.days = days; + data.months = months; + data.years = years; + }, - ctx.globalAlpha = 0.5; - ctx.drawImage(this.imageObj, this.left - lineWidth, this.top - lineWidth, this.width + 2*lineWidth, this.height + 2*lineWidth); - } + abs : function () { + this._milliseconds = Math.abs(this._milliseconds); + this._days = Math.abs(this._days); + this._months = Math.abs(this._months); - // draw the image - ctx.globalAlpha = 1.0; - ctx.drawImage(this.imageObj, this.left, this.top, this.width, this.height); - } - }; + 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); - Node.prototype._drawImageLabel = function (ctx) { - var yLabel; - var offset = 0; - - if (this.height){ - offset = this.height / 2; - var labelDimensions = this.getTextSize(ctx); - - if (labelDimensions.lineCount >= 1){ - offset += labelDimensions.height / 2; - offset += 3; - } - } - - yLabel = this.y + offset; + return this; + }, - this._label(ctx, this.label, this.x, yLabel, undefined); - }; + weeks : function () { + return absRound(this.days() / 7); + }, - Node.prototype._drawImage = function (ctx) { - this._resizeImage(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; + valueOf : function () { + return this._milliseconds + + this._days * 864e5 + + (this._months % 12) * 2592e6 + + toInt(this._months / 12) * 31536e6; + }, - this._drawImageAtPosition(ctx); + humanize : function (withSuffix) { + var output = relativeTime(this, !withSuffix, this.localeData()); - this.boundingBox.top = this.top; - this.boundingBox.left = this.left; - this.boundingBox.right = this.left + this.width; - this.boundingBox.bottom = this.top + this.height; + if (withSuffix) { + output = this.localeData().pastFuture(+this, output); + } - this._drawImageLabel(ctx); - this.boundingBox.left = Math.min(this.boundingBox.left, this.labelDimensions.left); - this.boundingBox.right = Math.max(this.boundingBox.right, this.labelDimensions.left + this.labelDimensions.width); - this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelDimensions.height); - }; + return this.localeData().postformat(output); + }, - Node.prototype._resizeCircularImage = function (ctx) { - if(!this.imageObj.src || !this.imageObj.width || !this.imageObj.height){ - if (!this.width) { - var diameter = this.options.radius * 2; - this.width = diameter; - this.height = diameter; + add : function (input, val) { + // supports only 2.0-style add(1, 's') or add(moment) + var dur = moment.duration(input, val); - // scaling used for clustering - //this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor; - //this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor; - this.options.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor; - this.growthIndicator = this.options.radius- 0.5*diameter; - this._swapToImageResizeWhenImageLoaded = true; - } - } - else { - if (this._swapToImageResizeWhenImageLoaded) { - this.width = 0; - this.height = 0; - delete this._swapToImageResizeWhenImageLoaded; - } - this._resizeImage(ctx); - } + this._milliseconds += dur._milliseconds; + this._days += dur._days; + this._months += dur._months; - }; + this._bubble(); - Node.prototype._drawCircularImage = function (ctx) { - this._resizeCircularImage(ctx); + return this; + }, - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - var centerX = this.left + (this.width / 2); - var centerY = this.top + (this.height / 2); - var radius = Math.abs(this.height / 2); + subtract : function (input, val) { + var dur = moment.duration(input, val); - this._drawRawCircle(ctx, centerX, centerY, radius); + this._milliseconds -= dur._milliseconds; + this._days -= dur._days; + this._months -= dur._months; - ctx.save(); - ctx.circle(this.x, this.y, radius); - ctx.stroke(); - ctx.clip(); + this._bubble(); - this._drawImageAtPosition(ctx); + return this; + }, - ctx.restore(); + get : function (units) { + units = normalizeUnits(units); + return this[units.toLowerCase() + 's'](); + }, - this.boundingBox.top = this.y - this.options.radius; - this.boundingBox.left = this.x - this.options.radius; - this.boundingBox.right = this.x + this.options.radius; - this.boundingBox.bottom = this.y + this.options.radius; + as : function (units) { + var days, months; + units = normalizeUnits(units); - this._drawImageLabel(ctx); - - this.boundingBox.left = Math.min(this.boundingBox.left, this.labelDimensions.left); - this.boundingBox.right = Math.max(this.boundingBox.right, this.labelDimensions.left + this.labelDimensions.width); - this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelDimensions.height); - }; + if (units === 'month' || units === 'year') { + days = this._days + this._milliseconds / 864e5; + months = this._months + daysToYears(days) * 12; + return units === 'month' ? months : months / 12; + } else { + // handle milliseconds separately because of floating point math errors (issue #1867) + days = this._days + Math.round(yearsToDays(this._months / 12)); + switch (units) { + case 'week': return days / 7 + this._milliseconds / 6048e5; + case 'day': return days + this._milliseconds / 864e5; + case 'hour': return days * 24 + this._milliseconds / 36e5; + case 'minute': return days * 24 * 60 + this._milliseconds / 6e4; + case 'second': return days * 24 * 60 * 60 + this._milliseconds / 1000; + // Math.floor prevents floating point math errors here + case 'millisecond': return Math.floor(days * 24 * 60 * 60 * 1000) + this._milliseconds; + default: throw new Error('Unknown unit ' + units); + } + } + }, - Node.prototype._resizeBox = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - this.width = textSize.width + 2 * margin; - this.height = textSize.height + 2 * margin; + lang : moment.fn.lang, + locale : moment.fn.locale, - this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor; - this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor; - this.growthIndicator = this.width - (textSize.width + 2 * margin); - // this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor; + toIsoString : deprecate( + 'toIsoString() is deprecated. Please use toISOString() instead ' + + '(notice the capitals)', + function () { + return this.toISOString(); + } + ), - } - }; + 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()), + days = Math.abs(this.days()), + hours = Math.abs(this.hours()), + minutes = Math.abs(this.minutes()), + seconds = Math.abs(this.seconds() + this.milliseconds() / 1000); - Node.prototype._drawBox = function (ctx) { - this._resizeBox(ctx); + if (!this.asSeconds()) { + // this is the same as C#'s (Noda) and python (isodate)... + // but not other JS (goog.date) + return 'P0D'; + } - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; + return (this.asSeconds() < 0 ? '-' : '') + + 'P' + + (years ? years + 'Y' : '') + + (months ? months + 'M' : '') + + (days ? days + 'D' : '') + + ((hours || minutes || seconds) ? 'T' : '') + + (hours ? hours + 'H' : '') + + (minutes ? minutes + 'M' : '') + + (seconds ? seconds + 'S' : ''); + }, - var clusterLineWidth = 2.5; - var borderWidth = this.options.borderWidth; - var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; + localeData : function () { + return this._locale; + }, - ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; + toJSON : function () { + return this.toISOString(); + } + }); - // draw the outer border - if (this.clusterSize > 1) { - ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.networkScaleInv; - ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + moment.duration.fn.toString = moment.duration.fn.toISOString; - ctx.roundRect(this.left-2*ctx.lineWidth, this.top-2*ctx.lineWidth, this.width+4*ctx.lineWidth, this.height+4*ctx.lineWidth, this.options.radius); - ctx.stroke(); - } - ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.networkScaleInv; - ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + function makeDurationGetter(name) { + moment.duration.fn[name] = function () { + return this._data[name]; + }; + } - ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; + for (i in unitMillisecondFactors) { + if (hasOwnProp(unitMillisecondFactors, i)) { + makeDurationGetter(i.toLowerCase()); + } + } - ctx.roundRect(this.left, this.top, this.width, this.height, this.options.radius); - ctx.fill(); - ctx.stroke(); + 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.as('M'); + }; + moment.duration.fn.asYears = function () { + return this.as('y'); + }; - this.boundingBox.top = this.top; - this.boundingBox.left = this.left; - this.boundingBox.right = this.left + this.width; - this.boundingBox.bottom = this.top + this.height; + /************************************ + Default Locale + ************************************/ - this._label(ctx, this.label, this.x, this.y); - }; + // Set default locale, other locale will inherit from English. + moment.locale('en', { + ordinalParse: /\d{1,2}(th|st|nd|rd)/, + ordinal : function (number) { + var b = number % 10, + output = (toInt(number % 100 / 10) === 1) ? 'th' : + (b === 1) ? 'st' : + (b === 2) ? 'nd' : + (b === 3) ? 'rd' : 'th'; + return number + output; + } + }); - Node.prototype._resizeDatabase = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - var size = textSize.width + 2 * margin; - this.width = size; - this.height = size; + /* EMBED_LOCALES */ - // scaling used for clustering - this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; - this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; - this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor; - this.growthIndicator = this.width - size; - } - }; + /************************************ + Exposing Moment + ************************************/ - Node.prototype._drawDatabase = function (ctx) { - this._resizeDatabase(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; + function makeGlobal(shouldDeprecate) { + /*global ender:false */ + if (typeof ender !== 'undefined') { + return; + } + oldGlobalMoment = globalScope.moment; + if (shouldDeprecate) { + globalScope.moment = deprecate( + 'Accessing Moment through the global scope is ' + + 'deprecated, and will be removed in an upcoming ' + + 'release.', + moment); + } else { + globalScope.moment = moment; + } + } - var clusterLineWidth = 2.5; - var borderWidth = this.options.borderWidth; - var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; + // CommonJS module is defined + if (hasModule) { + module.exports = moment; + } else if (true) { + !(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) { + if (module.config && module.config() && module.config().noGlobal === true) { + // release the global variable + globalScope.moment = oldGlobalMoment; + } - ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; + return moment; + }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + makeGlobal(true); + } else { + makeGlobal(); + } + }).call(this); + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()), __webpack_require__(71)(module))) - // draw the outer border - if (this.clusterSize > 1) { - ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.networkScaleInv; - ctx.lineWidth = Math.min(this.width,ctx.lineWidth); +/***/ }, +/* 58 */ +/***/ function(module, exports, __webpack_require__) { - ctx.database(this.x - this.width/2 - 2*ctx.lineWidth, this.y - this.height*0.5 - 2*ctx.lineWidth, this.width + 4*ctx.lineWidth, this.height + 4*ctx.lineWidth); - ctx.stroke(); - } - ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.networkScaleInv; - ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + var __WEBPACK_AMD_DEFINE_RESULT__;/*! Hammer.JS - v1.1.3 - 2014-05-20 + * http://eightmedia.github.io/hammer.js + * + * Copyright (c) 2014 Jorik Tangelder ; + * Licensed under the MIT license */ - ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; - ctx.database(this.x - this.width/2, this.y - this.height*0.5, this.width, this.height); - ctx.fill(); - ctx.stroke(); + (function(window, undefined) { + 'use strict'; - this.boundingBox.top = this.top; - this.boundingBox.left = this.left; - this.boundingBox.right = this.left + this.width; - this.boundingBox.bottom = this.top + this.height; + /** + * @main + * @module hammer + * + * @class Hammer + * @static + */ - this._label(ctx, this.label, this.x, this.y); + /** + * Hammer, use this to create instances + * ```` + * var hammertime = new Hammer(myElement); + * ```` + * + * @method Hammer + * @param {HTMLElement} element + * @param {Object} [options={}] + * @return {Hammer.Instance} + */ + var Hammer = function Hammer(element, options) { + return new Hammer.Instance(element, options || {}); }; + /** + * version, as defined in package.json + * the value will be set at each build + * @property VERSION + * @final + * @type {String} + */ + Hammer.VERSION = '1.1.3'; - Node.prototype._resizeCircle = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - var diameter = Math.max(textSize.width, textSize.height) + 2 * margin; - this.options.radius = diameter / 2; - - this.width = diameter; - this.height = diameter; + /** + * default settings. + * more settings are defined per gesture at `/gestures`. Each gesture can be disabled/enabled + * by setting it's name (like `swipe`) to false. + * You can set the defaults for all instances by changing this object before creating an instance. + * @example + * ```` + * Hammer.defaults.drag = false; + * Hammer.defaults.behavior.touchAction = 'pan-y'; + * delete Hammer.defaults.behavior.userSelect; + * ```` + * @property defaults + * @type {Object} + */ + Hammer.defaults = { + /** + * this setting object adds styles and attributes to the element to prevent the browser from doing + * its native behavior. The css properties are auto prefixed for the browsers when needed. + * @property defaults.behavior + * @type {Object} + */ + behavior: { + /** + * Disables text selection to improve the dragging gesture. When the value is `none` it also sets + * `onselectstart=false` for IE on the element. Mainly for desktop browsers. + * @property defaults.behavior.userSelect + * @type {String} + * @default 'none' + */ + userSelect: 'none', - // scaling used for clustering - // this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor; - // this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor; - this.options.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor; - this.growthIndicator = this.options.radius- 0.5*diameter; - } - }; + /** + * Specifies whether and how a given region can be manipulated by the user (for instance, by panning or zooming). + * Used by Chrome 35> and IE10>. By default this makes the element blocking any touch event. + * @property defaults.behavior.touchAction + * @type {String} + * @default: 'pan-y' + */ + touchAction: 'pan-y', - Node.prototype._drawRawCircle = function (ctx, x, y, radius) { - var clusterLineWidth = 2.5; - var borderWidth = this.options.borderWidth; - var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; - - ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; + /** + * Disables the default callout shown when you touch and hold a touch target. + * On iOS, when you touch and hold a touch target such as a link, Safari displays + * a callout containing information about the link. This property allows you to disable that callout. + * @property defaults.behavior.touchCallout + * @type {String} + * @default 'none' + */ + touchCallout: 'none', - // draw the outer border - if (this.clusterSize > 1) { - ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.networkScaleInv; - ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + /** + * Specifies whether zooming is enabled. Used by IE10> + * @property defaults.behavior.contentZooming + * @type {String} + * @default 'none' + */ + contentZooming: 'none', - ctx.circle(x, y, radius+2*ctx.lineWidth); - ctx.stroke(); - } - ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.networkScaleInv; - ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + /** + * Specifies that an entire element should be draggable instead of its contents. + * Mainly for desktop browsers. + * @property defaults.behavior.userDrag + * @type {String} + * @default 'none' + */ + userDrag: 'none', - ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; - ctx.circle(this.x, this.y, radius); - ctx.fill(); - ctx.stroke(); + /** + * Overrides the highlight color shown when the user taps a link or a JavaScript + * clickable element in Safari on iPhone. This property obeys the alpha value, if specified. + * + * If you don't specify an alpha value, Safari on iPhone applies a default alpha value + * to the color. To disable tap highlighting, set the alpha value to 0 (invisible). + * If you set the alpha value to 1.0 (opaque), the element is not visible when tapped. + * @property defaults.behavior.tapHighlightColor + * @type {String} + * @default 'rgba(0,0,0,0)' + */ + tapHighlightColor: 'rgba(0,0,0,0)' + } }; - Node.prototype._drawCircle = function (ctx) { - this._resizeCircle(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - this._drawRawCircle(ctx, this.x, this.y, this.options.radius); + /** + * hammer document where the base events are added at + * @property DOCUMENT + * @type {HTMLElement} + * @default window.document + */ + Hammer.DOCUMENT = document; - this.boundingBox.top = this.y - this.options.radius; - this.boundingBox.left = this.x - this.options.radius; - this.boundingBox.right = this.x + this.options.radius; - this.boundingBox.bottom = this.y + this.options.radius; + /** + * detect support for pointer events + * @property HAS_POINTEREVENTS + * @type {Boolean} + */ + Hammer.HAS_POINTEREVENTS = navigator.pointerEnabled || navigator.msPointerEnabled; - this._label(ctx, this.label, this.x, this.y); - }; + /** + * detect support for touch events + * @property HAS_TOUCHEVENTS + * @type {Boolean} + */ + Hammer.HAS_TOUCHEVENTS = ('ontouchstart' in window); - Node.prototype._resizeEllipse = function (ctx) { - if (!this.width) { - var textSize = this.getTextSize(ctx); + /** + * detect mobile browsers + * @property IS_MOBILE + * @type {Boolean} + */ + Hammer.IS_MOBILE = /mobile|tablet|ip(ad|hone|od)|android|silk/i.test(navigator.userAgent); - this.width = textSize.width * 1.5; - this.height = textSize.height * 2; - if (this.width < this.height) { - this.width = this.height; - } - var defaultSize = this.width; + /** + * detect if we want to support mouseevents at all + * @property NO_MOUSEEVENTS + * @type {Boolean} + */ + Hammer.NO_MOUSEEVENTS = (Hammer.HAS_TOUCHEVENTS && Hammer.IS_MOBILE) || Hammer.HAS_POINTEREVENTS; - // scaling used for clustering - this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; - this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; - this.options.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor; - this.growthIndicator = this.width - defaultSize; - } - }; + /** + * interval in which Hammer recalculates current velocity/direction/angle in ms + * @property CALCULATE_INTERVAL + * @type {Number} + * @default 25 + */ + Hammer.CALCULATE_INTERVAL = 25; - Node.prototype._drawEllipse = function (ctx) { - this._resizeEllipse(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; + /** + * eventtypes per touchevent (start, move, end) are filled by `Event.determineEventTypes` on `setup` + * the object contains the DOM event names per type (`EVENT_START`, `EVENT_MOVE`, `EVENT_END`) + * @property EVENT_TYPES + * @private + * @writeOnce + * @type {Object} + */ + var EVENT_TYPES = {}; - var clusterLineWidth = 2.5; - var borderWidth = this.options.borderWidth; - var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; + /** + * direction strings, for safe comparisons + * @property DIRECTION_DOWN|LEFT|UP|RIGHT + * @final + * @type {String} + * @default 'down' 'left' 'up' 'right' + */ + var DIRECTION_DOWN = Hammer.DIRECTION_DOWN = 'down'; + var DIRECTION_LEFT = Hammer.DIRECTION_LEFT = 'left'; + var DIRECTION_UP = Hammer.DIRECTION_UP = 'up'; + var DIRECTION_RIGHT = Hammer.DIRECTION_RIGHT = 'right'; - ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; + /** + * pointertype strings, for safe comparisons + * @property POINTER_MOUSE|TOUCH|PEN + * @final + * @type {String} + * @default 'mouse' 'touch' 'pen' + */ + var POINTER_MOUSE = Hammer.POINTER_MOUSE = 'mouse'; + var POINTER_TOUCH = Hammer.POINTER_TOUCH = 'touch'; + var POINTER_PEN = Hammer.POINTER_PEN = 'pen'; - // draw the outer border - if (this.clusterSize > 1) { - ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.networkScaleInv; - ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + /** + * eventtypes + * @property EVENT_START|MOVE|END|RELEASE|TOUCH + * @final + * @type {String} + * @default 'start' 'change' 'move' 'end' 'release' 'touch' + */ + var EVENT_START = Hammer.EVENT_START = 'start'; + var EVENT_MOVE = Hammer.EVENT_MOVE = 'move'; + var EVENT_END = Hammer.EVENT_END = 'end'; + var EVENT_RELEASE = Hammer.EVENT_RELEASE = 'release'; + var EVENT_TOUCH = Hammer.EVENT_TOUCH = 'touch'; - ctx.ellipse(this.left-2*ctx.lineWidth, this.top-2*ctx.lineWidth, this.width+4*ctx.lineWidth, this.height+4*ctx.lineWidth); - ctx.stroke(); - } - ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.networkScaleInv; - ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + /** + * if the window events are set... + * @property READY + * @writeOnce + * @type {Boolean} + * @default false + */ + Hammer.READY = false; - ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; + /** + * plugins namespace + * @property plugins + * @type {Object} + */ + Hammer.plugins = Hammer.plugins || {}; - ctx.ellipse(this.left, this.top, this.width, this.height); - ctx.fill(); - ctx.stroke(); + /** + * gestures namespace + * see `/gestures` for the definitions + * @property gestures + * @type {Object} + */ + Hammer.gestures = Hammer.gestures || {}; - this.boundingBox.top = this.top; - this.boundingBox.left = this.left; - this.boundingBox.right = this.left + this.width; - this.boundingBox.bottom = this.top + this.height; + /** + * setup events to detect gestures on the document + * this function is called when creating an new instance + * @private + */ + function setup() { + if(Hammer.READY) { + return; + } - this._label(ctx, this.label, this.x, this.y); - }; + // find what eventtypes we add listeners to + Event.determineEventTypes(); - Node.prototype._drawDot = function (ctx) { - this._drawShape(ctx, 'circle'); - }; + // Register all gestures inside Hammer.gestures + Utils.each(Hammer.gestures, function(gesture) { + Detection.register(gesture); + }); - Node.prototype._drawTriangle = function (ctx) { - this._drawShape(ctx, 'triangle'); - }; + // Add touch events on the document + Event.onTouch(Hammer.DOCUMENT, EVENT_MOVE, Detection.detect); + Event.onTouch(Hammer.DOCUMENT, EVENT_END, Detection.detect); - Node.prototype._drawTriangleDown = function (ctx) { - this._drawShape(ctx, 'triangleDown'); - }; + // Hammer is ready...! + Hammer.READY = true; + } - Node.prototype._drawSquare = function (ctx) { - this._drawShape(ctx, 'square'); - }; + /** + * @module hammer + * + * @class Utils + * @static + */ + var Utils = Hammer.utils = { + /** + * extend method, could also be used for cloning when `dest` is an empty object. + * changes the dest object + * @method extend + * @param {Object} dest + * @param {Object} src + * @param {Boolean} [merge=false] do a merge + * @return {Object} dest + */ + extend: function extend(dest, src, merge) { + for(var key in src) { + if(!src.hasOwnProperty(key) || (dest[key] !== undefined && merge)) { + continue; + } + dest[key] = src[key]; + } + return dest; + }, - Node.prototype._drawStar = function (ctx) { - this._drawShape(ctx, 'star'); - }; + /** + * simple addEventListener wrapper + * @method on + * @param {HTMLElement} element + * @param {String} type + * @param {Function} handler + */ + on: function on(element, type, handler) { + element.addEventListener(type, handler, false); + }, - Node.prototype._resizeShape = function (ctx) { - if (!this.width) { - this.options.radius= this.baseRadiusValue; - var size = 2 * this.options.radius; - this.width = size; - this.height = size; + /** + * simple removeEventListener wrapper + * @method off + * @param {HTMLElement} element + * @param {String} type + * @param {Function} handler + */ + off: function off(element, type, handler) { + element.removeEventListener(type, handler, false); + }, - // scaling used for clustering - this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; - this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; - this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor; - this.growthIndicator = this.width - size; - } - }; + /** + * forEach over arrays and objects + * @method each + * @param {Object|Array} obj + * @param {Function} iterator + * @param {any} iterator.item + * @param {Number} iterator.index + * @param {Object|Array} iterator.obj the source object + * @param {Object} context value to use as `this` in the iterator + */ + each: function each(obj, iterator, context) { + var i, len; - Node.prototype._drawShape = function (ctx, shape) { - this._resizeShape(ctx); + // native forEach on arrays + if('forEach' in obj) { + obj.forEach(iterator, context); + // arrays + } else if(obj.length !== undefined) { + for(i = 0, len = obj.length; i < len; i++) { + if(iterator.call(context, obj[i], i, obj) === false) { + return; + } + } + // objects + } else { + for(i in obj) { + if(obj.hasOwnProperty(i) && + iterator.call(context, obj[i], i, obj) === false) { + return; + } + } + } + }, - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; + /** + * find if a string contains the string using indexOf + * @method inStr + * @param {String} src + * @param {String} find + * @return {Boolean} found + */ + inStr: function inStr(src, find) { + return src.indexOf(find) > -1; + }, - var clusterLineWidth = 2.5; - var borderWidth = this.options.borderWidth; - var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth; - var radiusMultiplier = 2; + /** + * find if a array contains the object using indexOf or a simple polyfill + * @method inArray + * @param {String} src + * @param {String} find + * @return {Boolean|Number} false when not found, or the index + */ + inArray: function inArray(src, find) { + if(src.indexOf) { + var index = src.indexOf(find); + return (index === -1) ? false : index; + } else { + for(var i = 0, len = src.length; i < len; i++) { + if(src[i] === find) { + return i; + } + } + return false; + } + }, - // choose draw method depending on the shape - switch (shape) { - case 'dot': radiusMultiplier = 2; break; - case 'square': radiusMultiplier = 2; break; - case 'triangle': radiusMultiplier = 3; break; - case 'triangleDown': radiusMultiplier = 3; break; - case 'star': radiusMultiplier = 4; break; - } + /** + * convert an array-like object (`arguments`, `touchlist`) to an array + * @method toArray + * @param {Object} obj + * @return {Array} + */ + toArray: function toArray(obj) { + return Array.prototype.slice.call(obj, 0); + }, - ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border; - // draw the outer border - if (this.clusterSize > 1) { - ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.networkScaleInv; - ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + /** + * find if a node is in the given parent + * @method hasParent + * @param {HTMLElement} node + * @param {HTMLElement} parent + * @return {Boolean} found + */ + hasParent: function hasParent(node, parent) { + while(node) { + if(node == parent) { + return true; + } + node = node.parentNode; + } + return false; + }, - ctx[shape](this.x, this.y, this.options.radius+ radiusMultiplier * ctx.lineWidth); - ctx.stroke(); - } - ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); - ctx.lineWidth *= this.networkScaleInv; - ctx.lineWidth = Math.min(this.width,ctx.lineWidth); + /** + * get the center of all the touches + * @method getCenter + * @param {Array} touches + * @return {Object} center contains `pageX`, `pageY`, `clientX` and `clientY` properties + */ + getCenter: function getCenter(touches) { + var pageX = [], + pageY = [], + clientX = [], + clientY = [], + min = Math.min, + max = Math.max; - ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background; - ctx[shape](this.x, this.y, this.options.radius); - ctx.fill(); - ctx.stroke(); + // no need to loop when only one touch + if(touches.length === 1) { + return { + pageX: touches[0].pageX, + pageY: touches[0].pageY, + clientX: touches[0].clientX, + clientY: touches[0].clientY + }; + } - this.boundingBox.top = this.y - this.options.radius; - this.boundingBox.left = this.x - this.options.radius; - this.boundingBox.right = this.x + this.options.radius; - this.boundingBox.bottom = this.y + this.options.radius; + Utils.each(touches, function(touch) { + pageX.push(touch.pageX); + pageY.push(touch.pageY); + clientX.push(touch.clientX); + clientY.push(touch.clientY); + }); - if (this.label) { - this._label(ctx, this.label, this.x, this.y + this.height / 2, undefined, 'hanging',true); - this.boundingBox.left = Math.min(this.boundingBox.left, this.labelDimensions.left); - this.boundingBox.right = Math.max(this.boundingBox.right, this.labelDimensions.left + this.labelDimensions.width); - this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelDimensions.height); - } - }; + return { + pageX: (min.apply(Math, pageX) + max.apply(Math, pageX)) / 2, + pageY: (min.apply(Math, pageY) + max.apply(Math, pageY)) / 2, + clientX: (min.apply(Math, clientX) + max.apply(Math, clientX)) / 2, + clientY: (min.apply(Math, clientY) + max.apply(Math, clientY)) / 2 + }; + }, - Node.prototype._resizeText = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - this.width = textSize.width + 2 * margin; - this.height = textSize.height + 2 * margin; + /** + * calculate the velocity between two points. unit is in px per ms. + * @method getVelocity + * @param {Number} deltaTime + * @param {Number} deltaX + * @param {Number} deltaY + * @return {Object} velocity `x` and `y` + */ + getVelocity: function getVelocity(deltaTime, deltaX, deltaY) { + return { + x: Math.abs(deltaX / deltaTime) || 0, + y: Math.abs(deltaY / deltaTime) || 0 + }; + }, - // scaling used for clustering - this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; - this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; - this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor; - this.growthIndicator = this.width - (textSize.width + 2 * margin); - } - }; + /** + * calculate the angle between two coordinates + * @method getAngle + * @param {Touch} touch1 + * @param {Touch} touch2 + * @return {Number} angle + */ + getAngle: function getAngle(touch1, touch2) { + var x = touch2.clientX - touch1.clientX, + y = touch2.clientY - touch1.clientY; - Node.prototype._drawText = function (ctx) { - this._resizeText(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; + return Math.atan2(y, x) * 180 / Math.PI; + }, - this._label(ctx, this.label, this.x, this.y); + /** + * do a small comparision to get the direction between two touches. + * @method getDirection + * @param {Touch} touch1 + * @param {Touch} touch2 + * @return {String} direction matches `DIRECTION_LEFT|RIGHT|UP|DOWN` + */ + getDirection: function getDirection(touch1, touch2) { + var x = Math.abs(touch1.clientX - touch2.clientX), + y = Math.abs(touch1.clientY - touch2.clientY); - this.boundingBox.top = this.top; - this.boundingBox.left = this.left; - this.boundingBox.right = this.left + this.width; - this.boundingBox.bottom = this.top + this.height; - }; + if(x >= y) { + return touch1.clientX - touch2.clientX > 0 ? DIRECTION_LEFT : DIRECTION_RIGHT; + } + return touch1.clientY - touch2.clientY > 0 ? DIRECTION_UP : DIRECTION_DOWN; + }, + /** + * calculate the distance between two touches + * @method getDistance + * @param {Touch}touch1 + * @param {Touch} touch2 + * @return {Number} distance + */ + getDistance: function getDistance(touch1, touch2) { + var x = touch2.clientX - touch1.clientX, + y = touch2.clientY - touch1.clientY; - Node.prototype._label = function (ctx, text, x, y, align, baseline, labelUnderNode) { - if (text && Number(this.options.fontSize) * this.networkScale > this.fontDrawThreshold) { - ctx.font = (this.selected ? "bold " : "") + this.options.fontSize + "px " + this.options.fontFace; + return Math.sqrt((x * x) + (y * y)); + }, - var lines = text.split('\n'); - var lineCount = lines.length; - var fontSize = Number(this.options.fontSize); - var yLine = y + (1 - lineCount) / 2 * fontSize; - if (labelUnderNode == true) { - yLine = y + (1 - lineCount) / (2 * fontSize); - } + /** + * calculate the scale factor between two touchLists + * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out + * @method getScale + * @param {Array} start array of touches + * @param {Array} end array of touches + * @return {Number} scale + */ + getScale: function getScale(start, end) { + // need two fingers... + if(start.length >= 2 && end.length >= 2) { + return this.getDistance(end[0], end[1]) / this.getDistance(start[0], start[1]); + } + return 1; + }, - // font fill from edges now for nodes! - var width = ctx.measureText(lines[0]).width; - for (var i = 1; i < lineCount; i++) { - var lineWidth = ctx.measureText(lines[i]).width; - width = lineWidth > width ? lineWidth : width; - } - var height = this.options.fontSize * lineCount; - var left = x - width / 2; - var top = y - height / 2; - if (baseline == "hanging") { - top += 0.5 * fontSize; - top += 4; // distance from node, required because we use hanging. Hanging has less difference between browsers - yLine += 4; // distance from node - } - this.labelDimensions = {top:top,left:left,width:width,height:height,yLine:yLine}; + /** + * calculate the rotation degrees between two touchLists + * @method getRotation + * @param {Array} start array of touches + * @param {Array} end array of touches + * @return {Number} rotation + */ + getRotation: function getRotation(start, end) { + // need two fingers + if(start.length >= 2 && end.length >= 2) { + return this.getAngle(end[1], end[0]) - this.getAngle(start[1], start[0]); + } + return 0; + }, - // create the fontfill background - if (this.options.fontFill !== undefined && this.options.fontFill !== null && this.options.fontFill !== "none") { - ctx.fillStyle = this.options.fontFill; - ctx.fillRect(left, top, width, height); - } + /** + * find out if the direction is vertical * + * @method isVertical + * @param {String} direction matches `DIRECTION_UP|DOWN` + * @return {Boolean} is_vertical + */ + isVertical: function isVertical(direction) { + return direction == DIRECTION_UP || direction == DIRECTION_DOWN; + }, - // draw text - ctx.fillStyle = this.options.fontColor || "black"; - ctx.textAlign = align || "center"; - ctx.textBaseline = baseline || "middle"; - if (this.options.fontStrokeWidth > 0){ - ctx.lineWidth = this.options.fontStrokeWidth; - ctx.strokeStyle = this.options.fontStrokeColor; - ctx.lineJoin = 'round'; - } - for (var i = 0; i < lineCount; i++) { - if(this.options.fontStrokeWidth){ - ctx.strokeText(lines[i], x, yLine); - } - ctx.fillText(lines[i], x, yLine); - yLine += fontSize; - } - } - }; + /** + * set css properties with their prefixes + * @param {HTMLElement} element + * @param {String} prop + * @param {String} value + * @param {Boolean} [toggle=true] + * @return {Boolean} + */ + setPrefixedCss: function setPrefixedCss(element, prop, value, toggle) { + var prefixes = ['', 'Webkit', 'Moz', 'O', 'ms']; + prop = Utils.toCamelCase(prop); + for(var i = 0; i < prefixes.length; i++) { + var p = prop; + // prefixes + if(prefixes[i]) { + p = prefixes[i] + p.slice(0, 1).toUpperCase() + p.slice(1); + } - Node.prototype.getTextSize = function(ctx) { - if (this.label !== undefined) { - ctx.font = (this.selected ? "bold " : "") + this.options.fontSize + "px " + this.options.fontFace; + // test the style + if(p in element.style) { + element.style[p] = (toggle == null || toggle) && value || ''; + break; + } + } + }, - var lines = this.label.split('\n'), - height = (Number(this.options.fontSize) + 4) * lines.length, - width = 0; + /** + * toggle browser default behavior by setting css properties. + * `userSelect='none'` also sets `element.onselectstart` to false + * `userDrag='none'` also sets `element.ondragstart` to false + * + * @method toggleBehavior + * @param {HtmlElement} element + * @param {Object} props + * @param {Boolean} [toggle=true] + */ + toggleBehavior: function toggleBehavior(element, props, toggle) { + if(!props || !element || !element.style) { + return; + } - for (var i = 0, iMax = lines.length; i < iMax; i++) { - width = Math.max(width, ctx.measureText(lines[i]).width); - } + // set the css properties + Utils.each(props, function(value, prop) { + Utils.setPrefixedCss(element, prop, value, toggle); + }); - return {"width": width, "height": height, lineCount: lines.length}; - } - else { - return {"width": 0, "height": 0, lineCount: 0}; - } - }; + var falseFn = toggle && function() { + return false; + }; - /** - * this is used to determine if a node is visible at all. this is used to determine when it needs to be drawn. - * there is a safety margin of 0.3 * width; - * - * @returns {boolean} - */ - Node.prototype.inArea = function() { - if (this.width !== undefined) { - return (this.x + this.width *this.networkScaleInv >= this.canvasTopLeft.x && - this.x - this.width *this.networkScaleInv < this.canvasBottomRight.x && - this.y + this.height*this.networkScaleInv >= this.canvasTopLeft.y && - this.y - this.height*this.networkScaleInv < this.canvasBottomRight.y); - } - else { - return true; - } + // also the disable onselectstart + if(props.userSelect == 'none') { + element.onselectstart = falseFn; + } + // and disable ondragstart + if(props.userDrag == 'none') { + element.ondragstart = falseFn; + } + }, + + /** + * convert a string with underscores to camelCase + * so prevent_default becomes preventDefault + * @param {String} str + * @return {String} camelCaseStr + */ + toCamelCase: function toCamelCase(str) { + return str.replace(/[_-]([a-z])/g, function(s) { + return s[1].toUpperCase(); + }); + } }; + /** - * checks if the core of the node is in the display area, this is used for opening clusters around zoom - * @returns {boolean} + * @module hammer */ - Node.prototype.inView = function() { - return (this.x >= this.canvasTopLeft.x && - this.x < this.canvasBottomRight.x && - this.y >= this.canvasTopLeft.y && - this.y < this.canvasBottomRight.y); - }; - /** - * This allows the zoom level of the network to influence the rendering - * We store the inverted scale and the coordinates of the top left, and bottom right points of the canvas - * - * @param scale - * @param canvasTopLeft - * @param canvasBottomRight + * @class Event + * @static */ - Node.prototype.setScaleAndPos = function(scale,canvasTopLeft,canvasBottomRight) { - this.networkScaleInv = 1.0/scale; - this.networkScale = scale; - this.canvasTopLeft = canvasTopLeft; - this.canvasBottomRight = canvasBottomRight; - }; + var Event = Hammer.event = { + /** + * when touch events have been fired, this is true + * this is used to stop mouse events + * @property prevent_mouseevents + * @private + * @type {Boolean} + */ + preventMouseEvents: false, + /** + * if EVENT_START has been fired + * @property started + * @private + * @type {Boolean} + */ + started: false, - /** - * This allows the zoom level of the network to influence the rendering - * - * @param scale - */ - Node.prototype.setScale = function(scale) { - this.networkScaleInv = 1.0/scale; - this.networkScale = scale; - }; + /** + * when the mouse is hold down, this is true + * @property should_detect + * @private + * @type {Boolean} + */ + shouldDetect: false, + /** + * simple event binder with a hook and support for multiple types + * @method on + * @param {HTMLElement} element + * @param {String} type + * @param {Function} handler + * @param {Function} [hook] + * @param {Object} hook.type + */ + on: function on(element, type, handler, hook) { + var types = type.split(' '); + Utils.each(types, function(type) { + Utils.on(element, type, handler); + hook && hook(type); + }); + }, + /** + * simple event unbinder with a hook and support for multiple types + * @method off + * @param {HTMLElement} element + * @param {String} type + * @param {Function} handler + * @param {Function} [hook] + * @param {Object} hook.type + */ + off: function off(element, type, handler, hook) { + var types = type.split(' '); + Utils.each(types, function(type) { + Utils.off(element, type, handler); + hook && hook(type); + }); + }, - /** - * set the velocity at 0. Is called when this node is contained in another during clustering - */ - Node.prototype.clearVelocity = function() { - this.vx = 0; - this.vy = 0; - }; + /** + * the core touch event handler. + * this finds out if we should to detect gestures + * @method onTouch + * @param {HTMLElement} element + * @param {String} eventType matches `EVENT_START|MOVE|END` + * @param {Function} handler + * @return onTouchHandler {Function} the core event handler + */ + onTouch: function onTouch(element, eventType, handler) { + var self = this; + var onTouchHandler = function onTouchHandler(ev) { + var srcType = ev.type.toLowerCase(), + isPointer = Hammer.HAS_POINTEREVENTS, + isMouse = Utils.inStr(srcType, 'mouse'), + triggerType; - /** - * Basic preservation of (kinectic) energy - * - * @param massBeforeClustering - */ - Node.prototype.updateVelocity = function(massBeforeClustering) { - var energyBefore = this.vx * this.vx * massBeforeClustering; - //this.vx = (this.vx < 0) ? -Math.sqrt(energyBefore/this.options.mass) : Math.sqrt(energyBefore/this.options.mass); - this.vx = Math.sqrt(energyBefore/this.options.mass); - energyBefore = this.vy * this.vy * massBeforeClustering; - //this.vy = (this.vy < 0) ? -Math.sqrt(energyBefore/this.options.mass) : Math.sqrt(energyBefore/this.options.mass); - this.vy = Math.sqrt(energyBefore/this.options.mass); - }; + // if we are in a mouseevent, but there has been a touchevent triggered in this session + // we want to do nothing. simply break out of the event. + if(isMouse && self.preventMouseEvents) { + return; - module.exports = Node; + // mousebutton must be down + } else if(isMouse && eventType == EVENT_START && ev.button === 0) { + self.preventMouseEvents = false; + self.shouldDetect = true; + } else if(isPointer && eventType == EVENT_START) { + self.shouldDetect = (ev.buttons === 1 || PointerEvent.matchType(POINTER_TOUCH, ev)); + // just a valid start event, but no mouse + } else if(!isMouse && eventType == EVENT_START) { + self.preventMouseEvents = true; + self.shouldDetect = true; + } + // update the pointer event before entering the detection + if(isPointer && eventType != EVENT_END) { + PointerEvent.updatePointer(eventType, ev); + } -/***/ }, -/* 57 */ -/***/ function(module, exports, __webpack_require__) { + // we are in a touch/down state, so allowed detection of gestures + if(self.shouldDetect) { + triggerType = self.doDetect.call(self, ev, eventType, element, handler); + } - var util = __webpack_require__(1); - var Node = __webpack_require__(56); + // ...and we are done with the detection + // so reset everything to start each detection totally fresh + if(triggerType == EVENT_END) { + self.preventMouseEvents = false; + self.shouldDetect = false; + PointerEvent.reset(); + // update the pointerevent object after the detection + } - /** - * @class Edge - * - * A edge connects two nodes - * @param {Object} properties Object with properties. Must contain - * At least properties from and to. - * Available properties: from (number), - * to (number), label (string, color (string), - * width (number), style (string), - * length (number), title (string) - * @param {Network} network A Network object, used to find and edge to - * nodes. - * @param {Object} constants An object with default values for - * example for the color - */ - function Edge (properties, network, networkConstants) { - if (!network) { - throw "No network provided"; - } - var fields = ['edges','physics']; - var constants = util.selectiveBridgeObject(fields,networkConstants); - this.options = constants.edges; - this.physics = constants.physics; - this.options['smoothCurves'] = networkConstants['smoothCurves']; + if(isPointer && eventType == EVENT_END) { + PointerEvent.updatePointer(eventType, ev); + } + }; + this.on(element, EVENT_TYPES[eventType], onTouchHandler); + return onTouchHandler; + }, - this.network = network; + /** + * the core detection method + * this finds out what hammer-touch-events to trigger + * @method doDetect + * @param {Object} ev + * @param {String} eventType matches `EVENT_START|MOVE|END` + * @param {HTMLElement} element + * @param {Function} handler + * @return {String} triggerType matches `EVENT_START|MOVE|END` + */ + doDetect: function doDetect(ev, eventType, element, handler) { + var touchList = this.getTouchList(ev, eventType); + var touchListLength = touchList.length; + var triggerType = eventType; + var triggerChange = touchList.trigger; // used by fakeMultitouch plugin + var changedLength = touchListLength; - // initialize variables - this.id = undefined; - this.fromId = undefined; - this.toId = undefined; - this.title = undefined; - this.widthSelected = this.options.width * this.options.widthSelectionMultiplier; - this.value = undefined; - this.selected = false; - this.hover = false; - this.labelDimensions = {top:0,left:0,width:0,height:0,yLine:0}; // could be cached - this.dirtyLabel = true; + // at each touchstart-like event we want also want to trigger a TOUCH event... + if(eventType == EVENT_START) { + triggerChange = EVENT_TOUCH; + // ...the same for a touchend-like event + } else if(eventType == EVENT_END) { + triggerChange = EVENT_RELEASE; - this.from = null; // a node - this.to = null; // a node - this.via = null; // a temp node + // keep track of how many touches have been removed + changedLength = touchList.length - ((ev.changedTouches) ? ev.changedTouches.length : 1); + } - this.fromBackup = null; // used to clean up after reconnect - this.toBackup = null;; // used to clean up after reconnect + // after there are still touches on the screen, + // we just want to trigger a MOVE event. so change the START or END to a MOVE + // but only after detection has been started, the first time we actualy want a START + if(changedLength > 0 && this.started) { + triggerType = EVENT_MOVE; + } - // we use this to be able to reconnect the edge to a cluster if its node is put into a cluster - // by storing the original information we can revert to the original connection when the cluser is opened. - this.originalFromId = []; - this.originalToId = []; + // detection has been started, we keep track of this, see above + this.started = true; - this.connected = false; + // generate some event data, some basic information + var evData = this.collectEventData(element, triggerType, touchList, ev); - this.widthFixed = false; - this.lengthFixed = false; + // trigger the triggerType event before the change (TOUCH, RELEASE) events + // but the END event should be at last + if(eventType != EVENT_END) { + handler.call(Detection, evData); + } - this.setProperties(properties); + // trigger a change (TOUCH, RELEASE) event, this means the length of the touches changed + if(triggerChange) { + evData.changedLength = changedLength; + evData.eventType = triggerChange; - this.controlNodesEnabled = false; - this.controlNodes = {from:null, to:null, positions:{}}; - this.connectedNode = null; - } + handler.call(Detection, evData); - /** - * Set or overwrite properties for the edge - * @param {Object} properties an object with properties - * @param {Object} constants and object with default, global properties - */ - Edge.prototype.setProperties = function(properties) { - if (!properties) { - return; - } + evData.eventType = triggerType; + delete evData.changedLength; + } - var fields = ['style','fontSize','fontFace','fontColor','fontFill','fontStrokeWidth','fontStrokeColor','width', - 'widthSelectionMultiplier','hoverWidth','arrowScaleFactor','dash','inheritColor','labelAlignment' - ]; - util.selectiveDeepExtend(fields, this.options, properties); + // trigger the END event + if(triggerType == EVENT_END) { + handler.call(Detection, evData); - if (properties.from !== undefined) {this.fromId = properties.from;} - if (properties.to !== undefined) {this.toId = properties.to;} + // ...and we are done with the detection + // so reset everything to start each detection totally fresh + this.started = false; + } - if (properties.id !== undefined) {this.id = properties.id;} - if (properties.label !== undefined) {this.label = properties.label; this.dirtyLabel = true;} + return triggerType; + }, - if (properties.title !== undefined) {this.title = properties.title;} - if (properties.value !== undefined) {this.value = properties.value;} - if (properties.length !== undefined) {this.physics.springLength = properties.length;} + /** + * we have different events for each device/browser + * determine what we need and set them in the EVENT_TYPES constant + * the `onTouch` method is bind to these properties. + * @method determineEventTypes + * @return {Object} events + */ + determineEventTypes: function determineEventTypes() { + var types; + if(Hammer.HAS_POINTEREVENTS) { + if(window.PointerEvent) { + types = [ + 'pointerdown', + 'pointermove', + 'pointerup pointercancel lostpointercapture' + ]; + } else { + types = [ + 'MSPointerDown', + 'MSPointerMove', + 'MSPointerUp MSPointerCancel MSLostPointerCapture' + ]; + } + } else if(Hammer.NO_MOUSEEVENTS) { + types = [ + 'touchstart', + 'touchmove', + 'touchend touchcancel' + ]; + } else { + types = [ + 'touchstart mousedown', + 'touchmove mousemove', + 'touchend touchcancel mouseup' + ]; + } - if (properties.color !== undefined) { - this.options.inheritColor = false; - if (util.isString(properties.color)) { - this.options.color.color = properties.color; - this.options.color.highlight = properties.color; - } - else { - if (properties.color.color !== undefined) {this.options.color.color = properties.color.color;} - if (properties.color.highlight !== undefined) {this.options.color.highlight = properties.color.highlight;} - if (properties.color.hover !== undefined) {this.options.color.hover = properties.color.hover;} - } - } + EVENT_TYPES[EVENT_START] = types[0]; + EVENT_TYPES[EVENT_MOVE] = types[1]; + EVENT_TYPES[EVENT_END] = types[2]; + return EVENT_TYPES; + }, - // A node is connected when it has a from and to node. - this.connect(); + /** + * create touchList depending on the event + * @method getTouchList + * @param {Object} ev + * @param {String} eventType + * @return {Array} touches + */ + getTouchList: function getTouchList(ev, eventType) { + // get the fake pointerEvent touchlist + if(Hammer.HAS_POINTEREVENTS) { + return PointerEvent.getTouchList(); + } - this.widthFixed = this.widthFixed || (properties.width !== undefined); - this.lengthFixed = this.lengthFixed || (properties.length !== undefined); + // get the touchlist + if(ev.touches) { + if(eventType == EVENT_MOVE) { + return ev.touches; + } - this.widthSelected = this.options.width* this.options.widthSelectionMultiplier; + var identifiers = []; + var concat = [].concat(Utils.toArray(ev.touches), Utils.toArray(ev.changedTouches)); + var touchList = []; - // set draw method based on style - switch (this.options.style) { - case 'line': this.draw = this._drawLine; break; - case 'arrow': this.draw = this._drawArrow; break; - case 'arrow-center': this.draw = this._drawArrowCenter; break; - case 'dash-line': this.draw = this._drawDashLine; break; - default: this.draw = this._drawLine; break; - } - - }; + Utils.each(concat, function(touch) { + if(Utils.inArray(identifiers, touch.identifier) === false) { + touchList.push(touch); + } + identifiers.push(touch.identifier); + }); - /** - * Connect an edge to its nodes - */ - Edge.prototype.connect = function () { - this.disconnect(); + return touchList; + } - this.from = this.network.nodes[this.fromId] || null; - this.to = this.network.nodes[this.toId] || null; - this.connected = (this.from && this.to); + // make fake touchList from mouse position + ev.identifier = 1; + return [ev]; + }, - if (this.connected) { - this.from.attachEdge(this); - this.to.attachEdge(this); - } - else { - if (this.from) { - this.from.detachEdge(this); - } - if (this.to) { - this.to.detachEdge(this); + /** + * collect basic event data + * @method collectEventData + * @param {HTMLElement} element + * @param {String} eventType matches `EVENT_START|MOVE|END` + * @param {Array} touches + * @param {Object} ev + * @return {Object} ev + */ + collectEventData: function collectEventData(element, eventType, touches, ev) { + // find out pointerType + var pointerType = POINTER_TOUCH; + if(Utils.inStr(ev.type, 'mouse') || PointerEvent.matchType(POINTER_MOUSE, ev)) { + pointerType = POINTER_MOUSE; + } else if(PointerEvent.matchType(POINTER_PEN, ev)) { + pointerType = POINTER_PEN; + } + + return { + center: Utils.getCenter(touches), + timeStamp: Date.now(), + target: ev.target, + touches: touches, + eventType: eventType, + pointerType: pointerType, + srcEvent: ev, + + /** + * prevent the browser default actions + * mostly used to disable scrolling of the browser + */ + preventDefault: function() { + var srcEvent = this.srcEvent; + srcEvent.preventManipulation && srcEvent.preventManipulation(); + srcEvent.preventDefault && srcEvent.preventDefault(); + }, + + /** + * stop bubbling the event up to its parents + */ + stopPropagation: function() { + this.srcEvent.stopPropagation(); + }, + + /** + * immediately stop gesture detection + * might be useful after a swipe was detected + * @return {*} + */ + stopDetect: function() { + return Detection.stopDetect(); + } + }; } - } }; + /** - * Disconnect an edge from its nodes + * @module hammer + * + * @class PointerEvent + * @static */ - Edge.prototype.disconnect = function () { - if (this.from) { - this.from.detachEdge(this); - this.from = null; - } - if (this.to) { - this.to.detachEdge(this); - this.to = null; - } + var PointerEvent = Hammer.PointerEvent = { + /** + * holds all pointers, by `identifier` + * @property pointers + * @type {Object} + */ + pointers: {}, + + /** + * get the pointers as an array + * @method getTouchList + * @return {Array} touchlist + */ + getTouchList: function getTouchList() { + var touchlist = []; + // we can use forEach since pointerEvents only is in IE10 + Utils.each(this.pointers, function(pointer) { + touchlist.push(pointer); + }); + return touchlist; + }, - this.connected = false; - }; + /** + * update the position of a pointer + * @method updatePointer + * @param {String} eventType matches `EVENT_START|MOVE|END` + * @param {Object} pointerEvent + */ + updatePointer: function updatePointer(eventType, pointerEvent) { + if(eventType == EVENT_END || (eventType != EVENT_END && pointerEvent.buttons !== 1)) { + delete this.pointers[pointerEvent.pointerId]; + } else { + pointerEvent.identifier = pointerEvent.pointerId; + this.pointers[pointerEvent.pointerId] = pointerEvent; + } + }, - /** - * get the title of this edge. - * @return {string} title The title of the edge, or undefined when no title - * has been set. - */ - Edge.prototype.getTitle = function() { - return typeof this.title === "function" ? this.title() : this.title; - }; + /** + * check if ev matches pointertype + * @method matchType + * @param {String} pointerType matches `POINTER_MOUSE|TOUCH|PEN` + * @param {PointerEvent} ev + */ + matchType: function matchType(pointerType, ev) { + if(!ev.pointerType) { + return false; + } + var pt = ev.pointerType, + types = {}; - /** - * Retrieve the value of the edge. Can be undefined - * @return {Number} value - */ - Edge.prototype.getValue = function() { - return this.value; - }; + types[POINTER_MOUSE] = (pt === (ev.MSPOINTER_TYPE_MOUSE || POINTER_MOUSE)); + types[POINTER_TOUCH] = (pt === (ev.MSPOINTER_TYPE_TOUCH || POINTER_TOUCH)); + types[POINTER_PEN] = (pt === (ev.MSPOINTER_TYPE_PEN || POINTER_PEN)); + return types[pointerType]; + }, - /** - * Adjust the value range of the edge. The edge will adjust it's width - * based on its value. - * @param {Number} min - * @param {Number} max - */ - Edge.prototype.setValueRange = function(min, max) { - if (!this.widthFixed && this.value !== undefined) { - var scale = (this.options.widthMax - this.options.widthMin) / (max - min); - this.options.width= (this.value - min) * scale + this.options.widthMin; - this.widthSelected = this.options.width* this.options.widthSelectionMultiplier; - } + /** + * reset the stored pointers + * @method reset + */ + reset: function resetList() { + this.pointers = {}; + } }; - /** - * Redraw a edge - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - */ - Edge.prototype.draw = function(ctx) { - throw "Method draw not initialized in edge"; - }; /** - * Check if this object is overlapping with the provided object - * @param {Object} obj an object with parameters left, top - * @return {boolean} True if location is located on the edge + * @module hammer + * + * @class Detection + * @static */ - Edge.prototype.isOverlappingWith = function(obj) { - if (this.connected) { - var distMax = 10; - var xFrom = this.from.x; - var yFrom = this.from.y; - var xTo = this.to.x; - var yTo = this.to.y; - var xObj = obj.left; - var yObj = obj.top; + var Detection = Hammer.detection = { + // contains all registred Hammer.gestures in the correct order + gestures: [], - var dist = this._getDistanceToEdge(xFrom, yFrom, xTo, yTo, xObj, yObj); + // data of the current Hammer.gesture detection session + current: null, - return (dist < distMax); - } - else { - return false - } - }; + // the previous Hammer.gesture session data + // is a full clone of the previous gesture.current object + previous: null, - Edge.prototype._getColor = function() { - var colorObj = this.options.color; - if (this.options.inheritColor == "to") { - colorObj = { - highlight: this.to.options.color.highlight.border, - hover: this.to.options.color.hover.border, - color: this.to.options.color.border - }; - } - else if (this.options.inheritColor == "from" || this.options.inheritColor == true) { - colorObj = { - highlight: this.from.options.color.highlight.border, - hover: this.from.options.color.hover.border, - color: this.from.options.color.border - }; - } + // when this becomes true, no gestures are fired + stopped: false, - if (this.selected == true) {return colorObj.highlight;} - else if (this.hover == true) {return colorObj.hover;} - else {return colorObj.color;} - }; + /** + * start Hammer.gesture detection + * @method startDetect + * @param {Hammer.Instance} inst + * @param {Object} eventData + */ + startDetect: function startDetect(inst, eventData) { + // already busy with a Hammer.gesture detection on an element + if(this.current) { + return; + } + this.stopped = false; - /** - * Redraw a edge as a line - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ - Edge.prototype._drawLine = function(ctx) { - // set style - ctx.strokeStyle = this._getColor(); - ctx.lineWidth = this._getLineWidth(); + // holds current session + this.current = { + inst: inst, // reference to HammerInstance we're working for + startEvent: Utils.extend({}, eventData), // start eventData for distances, timing etc + lastEvent: false, // last eventData + lastCalcEvent: false, // last eventData for calculations. + futureCalcEvent: false, // last eventData for calculations. + lastCalcData: {}, // last lastCalcData + name: '' // current gesture we're in/detected, can be 'tap', 'hold' etc + }; - if (this.from != this.to) { - // draw line - var via = this._line(ctx); + this.detect(eventData); + }, - // draw label - var point; - if (this.label) { - if (this.options.smoothCurves.enabled == true && via != null) { - var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); - var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); - point = {x:midpointX, y:midpointY}; - } - else { - point = this._pointOnLine(0.5); - } - this._label(ctx, this.label, point.x, point.y); - } - } - else { - var x, y; - var radius = this.physics.springLength / 4; - var node = this.from; - if (!node.width) { - node.resize(ctx); - } - if (node.width > node.height) { - x = node.x + node.width / 2; - y = node.y - radius; - } - else { - x = node.x + radius; - y = node.y - node.height / 2; - } - this._circle(ctx, x, y, radius); - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); - } - }; + /** + * Hammer.gesture detection + * @method detect + * @param {Object} eventData + * @return {any} + */ + detect: function detect(eventData) { + if(!this.current || this.stopped) { + return; + } - /** - * Get the line width of the edge. Depends on width and whether one of the - * connected nodes is selected. - * @return {Number} width - * @private - */ - Edge.prototype._getLineWidth = function() { - if (this.selected == true) { - return Math.max(Math.min(this.widthSelected, this.options.widthMax), 0.3*this.networkScaleInv); - } - else { - if (this.hover == true) { - return Math.max(Math.min(this.options.hoverWidth, this.options.widthMax), 0.3*this.networkScaleInv); - } - else { - return Math.max(this.options.width, 0.3*this.networkScaleInv); - } - } - }; + // extend event data with calculations about scale, distance etc + eventData = this.extendEventData(eventData); - Edge.prototype._getViaCoordinates = function () { - if (this.options.smoothCurves.dynamic == true && this.options.smoothCurves.enabled == true ) { - return this.via; - } - else if (this.options.smoothCurves.enabled == false) { - return {x:0,y:0}; - } - else { - var xVia = null; - var yVia = null; - var factor = this.options.smoothCurves.roundness; - var type = this.options.smoothCurves.type; + // hammer instance and instance options + var inst = this.current.inst, + instOptions = inst.options; - var dx = Math.abs(this.from.x - this.to.x); - var dy = Math.abs(this.from.y - this.to.y); - if (type == 'discrete' || type == 'diagonalCross') { - if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { - if (this.from.y > this.to.y) { - if (this.from.x < this.to.x) { - xVia = this.from.x + factor * dy; - yVia = this.from.y - factor * dy; - } - else if (this.from.x > this.to.x) { - xVia = this.from.x - factor * dy; - yVia = this.from.y - factor * dy; - } - } - else if (this.from.y < this.to.y) { - if (this.from.x < this.to.x) { - xVia = this.from.x + factor * dy; - yVia = this.from.y + factor * dy; - } - else if (this.from.x > this.to.x) { - xVia = this.from.x - factor * dy; - yVia = this.from.y + factor * dy; - } - } - if (type == "discrete") { - xVia = dx < factor * dy ? this.from.x : xVia; - } - } - else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { - if (this.from.y > this.to.y) { - if (this.from.x < this.to.x) { - xVia = this.from.x + factor * dx; - yVia = this.from.y - factor * dx; - } - else if (this.from.x > this.to.x) { - xVia = this.from.x - factor * dx; - yVia = this.from.y - factor * dx; - } - } - else if (this.from.y < this.to.y) { - if (this.from.x < this.to.x) { - xVia = this.from.x + factor * dx; - yVia = this.from.y + factor * dx; - } - else if (this.from.x > this.to.x) { - xVia = this.from.x - factor * dx; - yVia = this.from.y + factor * dx; - } - } - if (type == "discrete") { - yVia = dy < factor * dx ? this.from.y : yVia; - } - } - } - else if (type == "straightCross") { - if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { // up - down - xVia = this.from.x; - if (this.from.y < this.to.y) { - yVia = this.to.y - (1 - factor) * dy; - } - else { - yVia = this.to.y + (1 - factor) * dy; - } - } - else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { // left - right - if (this.from.x < this.to.x) { - xVia = this.to.x - (1 - factor) * dx; - } - else { - xVia = this.to.x + (1 - factor) * dx; - } - yVia = this.from.y; - } - } - else if (type == 'horizontal') { - if (this.from.x < this.to.x) { - xVia = this.to.x - (1 - factor) * dx; - } - else { - xVia = this.to.x + (1 - factor) * dx; - } - yVia = this.from.y; - } - else if (type == 'vertical') { - xVia = this.from.x; - if (this.from.y < this.to.y) { - yVia = this.to.y - (1 - factor) * dy; - } - else { - yVia = this.to.y + (1 - factor) * dy; - } - } - else { // continuous - if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { - if (this.from.y > this.to.y) { - if (this.from.x < this.to.x) { - // console.log(1) - xVia = this.from.x + factor * dy; - yVia = this.from.y - factor * dy; - xVia = this.to.x < xVia ? this.to.x : xVia; - } - else if (this.from.x > this.to.x) { - // console.log(2) - xVia = this.from.x - factor * dy; - yVia = this.from.y - factor * dy; - xVia = this.to.x > xVia ? this.to.x : xVia; - } - } - else if (this.from.y < this.to.y) { - if (this.from.x < this.to.x) { - // console.log(3) - xVia = this.from.x + factor * dy; - yVia = this.from.y + factor * dy; - xVia = this.to.x < xVia ? this.to.x : xVia; - } - else if (this.from.x > this.to.x) { - // console.log(4, this.from.x, this.to.x) - xVia = this.from.x - factor * dy; - yVia = this.from.y + factor * dy; - xVia = this.to.x > xVia ? this.to.x : xVia; - } - } - } - else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { - if (this.from.y > this.to.y) { - if (this.from.x < this.to.x) { - // console.log(5) - xVia = this.from.x + factor * dx; - yVia = this.from.y - factor * dx; - yVia = this.to.y > yVia ? this.to.y : yVia; - } - else if (this.from.x > this.to.x) { - // console.log(6) - xVia = this.from.x - factor * dx; - yVia = this.from.y - factor * dx; - yVia = this.to.y > yVia ? this.to.y : yVia; - } - } - else if (this.from.y < this.to.y) { - if (this.from.x < this.to.x) { - // console.log(7) - xVia = this.from.x + factor * dx; - yVia = this.from.y + factor * dx; - yVia = this.to.y < yVia ? this.to.y : yVia; - } - else if (this.from.x > this.to.x) { - // console.log(8) - xVia = this.from.x - factor * dx; - yVia = this.from.y + factor * dx; - yVia = this.to.y < yVia ? this.to.y : yVia; - } + // call Hammer.gesture handlers + Utils.each(this.gestures, function triggerGesture(gesture) { + // only when the instance options have enabled this gesture + if(!this.stopped && inst.enabled && instOptions[gesture.name]) { + gesture.handler.call(gesture, eventData, inst); + } + }, this); + + // store as previous event event + if(this.current) { + this.current.lastEvent = eventData; } - } - } + if(eventData.eventType == EVENT_END) { + this.stopDetect(); + } - return {x: xVia, y: yVia}; - } - }; + return eventData; + }, - /** - * Draw a line between two nodes - * @param {CanvasRenderingContext2D} ctx - * @private - */ - Edge.prototype._line = function (ctx) { - // draw a straight line - ctx.beginPath(); - ctx.moveTo(this.from.x, this.from.y); - if (this.options.smoothCurves.enabled == true) { - if (this.options.smoothCurves.dynamic == false) { - var via = this._getViaCoordinates(); - if (via.x == null) { - ctx.lineTo(this.to.x, this.to.y); - ctx.stroke(); - return null; - } - else { - // this.via.x = via.x; - // this.via.y = via.y; - ctx.quadraticCurveTo(via.x,via.y,this.to.x, this.to.y); - ctx.stroke(); - return via; - } - } - else { - ctx.quadraticCurveTo(this.via.x,this.via.y,this.to.x, this.to.y); - ctx.stroke(); - return this.via; - } - } - else { - ctx.lineTo(this.to.x, this.to.y); - ctx.stroke(); - return null; - } - }; + /** + * clear the Hammer.gesture vars + * this is called on endDetect, but can also be used when a final Hammer.gesture has been detected + * to stop other Hammer.gestures from being fired + * @method stopDetect + */ + stopDetect: function stopDetect() { + // clone current data to the store as the previous gesture + // used for the double tap gesture, since this is an other gesture detect session + this.previous = Utils.extend({}, this.current); - /** - * Draw a line from a node to itself, a circle - * @param {CanvasRenderingContext2D} ctx - * @param {Number} x - * @param {Number} y - * @param {Number} radius - * @private - */ - Edge.prototype._circle = function (ctx, x, y, radius) { - // draw a circle - ctx.beginPath(); - ctx.arc(x, y, radius, 0, 2 * Math.PI, false); - ctx.stroke(); - }; + // reset the current + this.current = null; + this.stopped = true; + }, - /** - * Draw label with white background and with the middle at (x, y) - * @param {CanvasRenderingContext2D} ctx - * @param {String} text - * @param {Number} x - * @param {Number} y - * @private - */ - Edge.prototype._label = function (ctx, text, x, y) { - if (text) { - ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") + - this.options.fontSize + "px " + this.options.fontFace; - var yLine; + /** + * calculate velocity, angle and direction + * @method getVelocityData + * @param {Object} ev + * @param {Object} center + * @param {Number} deltaTime + * @param {Number} deltaX + * @param {Number} deltaY + */ + getCalculatedData: function getCalculatedData(ev, center, deltaTime, deltaX, deltaY) { + var cur = this.current, + recalc = false, + calcEv = cur.lastCalcEvent, + calcData = cur.lastCalcData; - if (this.dirtyLabel == true) { - var lines = String(text).split('\n'); - var lineCount = lines.length; - var fontSize = Number(this.options.fontSize); - yLine = y + (1 - lineCount) / 2 * fontSize; + if(calcEv && ev.timeStamp - calcEv.timeStamp > Hammer.CALCULATE_INTERVAL) { + center = calcEv.center; + deltaTime = ev.timeStamp - calcEv.timeStamp; + deltaX = ev.center.clientX - calcEv.center.clientX; + deltaY = ev.center.clientY - calcEv.center.clientY; + recalc = true; + } - var width = ctx.measureText(lines[0]).width; - for (var i = 1; i < lineCount; i++) { - var lineWidth = ctx.measureText(lines[i]).width; - width = lineWidth > width ? lineWidth : width; - } - var height = this.options.fontSize * lineCount; - var left = x - width / 2; - var top = y - height / 2; + if(ev.eventType == EVENT_TOUCH || ev.eventType == EVENT_RELEASE) { + cur.futureCalcEvent = ev; + } - // cache - this.labelDimensions = {top:top,left:left,width:width,height:height,yLine:yLine}; - } + if(!cur.lastCalcEvent || recalc) { + calcData.velocity = Utils.getVelocity(deltaTime, deltaX, deltaY); + calcData.angle = Utils.getAngle(center, ev.center); + calcData.direction = Utils.getDirection(center, ev.center); - var yLine = this.labelDimensions.yLine; - - ctx.save(); - - if (this.options.labelAlignment != "horizontal"){ - ctx.translate(x, yLine); - this._rotateForLabelAlignment(ctx); - x = 0; - yLine = 0; - } + cur.lastCalcEvent = cur.futureCalcEvent || ev; + cur.futureCalcEvent = ev; + } - - this._drawLabelRect(ctx); - this._drawLabelText(ctx,x,yLine, lines, lineCount, fontSize); - - ctx.restore(); - } - }; + ev.velocityX = calcData.velocity.x; + ev.velocityY = calcData.velocity.y; + ev.interimAngle = calcData.angle; + ev.interimDirection = calcData.direction; + }, - /** - * Rotates the canvas so the text is most readable - * @param {CanvasRenderingContext2D} ctx - * @private - */ - Edge.prototype._rotateForLabelAlignment = function(ctx) { - var dy = this.from.y - this.to.y; - var dx = this.from.x - this.to.x; - var angleInDegrees = Math.atan2(dy, dx); + /** + * extend eventData for Hammer.gestures + * @method extendEventData + * @param {Object} ev + * @return {Object} ev + */ + extendEventData: function extendEventData(ev) { + var cur = this.current, + startEv = cur.startEvent, + lastEv = cur.lastEvent || startEv; - // rotate so label it is readable - if((angleInDegrees < -1 && dx < 0) || (angleInDegrees > 0 && dx < 0)){ - angleInDegrees = angleInDegrees + Math.PI; - } - - ctx.rotate(angleInDegrees); - }; + // update the start touchlist to calculate the scale/rotation + if(ev.eventType == EVENT_TOUCH || ev.eventType == EVENT_RELEASE) { + startEv.touches = []; + Utils.each(ev.touches, function(touch) { + startEv.touches.push({ + clientX: touch.clientX, + clientY: touch.clientY + }); + }); + } - /** - * Draws the label rectangle - * @param {CanvasRenderingContext2D} ctx - * @param {String} labelAlignment - * @private - */ - Edge.prototype._drawLabelRect = function(ctx) { - if (this.options.fontFill !== undefined && this.options.fontFill !== null && this.options.fontFill !== "none") { - ctx.fillStyle = this.options.fontFill; - - var lineMargin = 2; + var deltaTime = ev.timeStamp - startEv.timeStamp, + deltaX = ev.center.clientX - startEv.center.clientX, + deltaY = ev.center.clientY - startEv.center.clientY; - if (this.options.labelAlignment == 'line-center') { - ctx.fillRect(-this.labelDimensions.width * 0.5, -this.labelDimensions.height * 0.5, this.labelDimensions.width, this.labelDimensions.height); - } - else if (this.options.labelAlignment == 'line-above') { - ctx.fillRect(-this.labelDimensions.width * 0.5, -(this.labelDimensions.height + lineMargin), this.labelDimensions.width, this.labelDimensions.height); - } - else if (this.options.labelAlignment == 'line-below') { - ctx.fillRect(-this.labelDimensions.width * 0.5, lineMargin, this.labelDimensions.width, this.labelDimensions.height); - } - else { - ctx.fillRect(this.labelDimensions.left, this.labelDimensions.top, this.labelDimensions.width, this.labelDimensions.height); - } - } - }; + this.getCalculatedData(ev, lastEv.center, deltaTime, deltaX, deltaY); - /** - * Draws the label text - * @param {CanvasRenderingContext2D} ctx - * @param {Number} x - * @param {Number} yLine - * @param {Array} lines - * @param {Number} lineCount - * @param {Number} fontSize - * @private - */ - Edge.prototype._drawLabelText = function(ctx, x, yLine, lines, lineCount, fontSize) { - // draw text - ctx.fillStyle = this.options.fontColor || "black"; - ctx.textAlign = "center"; + Utils.extend(ev, { + startEvent: startEv, - // check for label alignment - if (this.options.labelAlignment != 'horizontal') { - var lineMargin = 2; - if (this.options.labelAlignment == 'line-above') { - ctx.textBaseline = "alphabetic"; - yLine -= 2 * lineMargin; // distance from edge, required because we use alphabetic. Alphabetic has less difference between browsers - } - else if (this.options.labelAlignment == 'line-below') { - ctx.textBaseline = "hanging"; - yLine += 2 * lineMargin;// distance from edge, required because we use hanging. Hanging has less difference between browsers - } - else { - ctx.textBaseline = "middle"; - } - } - else { - ctx.textBaseline = "middle"; - } + deltaTime: deltaTime, + deltaX: deltaX, + deltaY: deltaY, - // check for strokeWidth - if (this.options.fontStrokeWidth > 0){ - ctx.lineWidth = this.options.fontStrokeWidth; - ctx.strokeStyle = this.options.fontStrokeColor; - ctx.lineJoin = 'round'; - } - for (var i = 0; i < lineCount; i++) { - if(this.options.fontStrokeWidth > 0){ - ctx.strokeText(lines[i], x, yLine); - } - ctx.fillText(lines[i], x, yLine); - yLine += fontSize; - } - }; + distance: Utils.getDistance(startEv.center, ev.center), + angle: Utils.getAngle(startEv.center, ev.center), + direction: Utils.getDirection(startEv.center, ev.center), + scale: Utils.getScale(startEv.touches, ev.touches), + rotation: Utils.getRotation(startEv.touches, ev.touches) + }); - /** - * Redraw a edge as a dashed line - * Draw this edge in the given canvas - * @author David Jordan - * @date 2012-08-08 - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ - Edge.prototype._drawDashLine = function(ctx) { - // set style - ctx.strokeStyle = this._getColor(); - ctx.lineWidth = this._getLineWidth(); + return ev; + }, - var via = null; - // only firefox and chrome support this method, else we use the legacy one. - if (ctx.setLineDash !== undefined) { - ctx.save(); - // configure the dash pattern - var pattern = [0]; - if (this.options.dash.length !== undefined && this.options.dash.gap !== undefined) { - pattern = [this.options.dash.length,this.options.dash.gap]; - } - else { - pattern = [5,5]; - } + /** + * register new gesture + * @method register + * @param {Object} gesture object, see `gestures/` for documentation + * @return {Array} gestures + */ + register: function register(gesture) { + // add an enable gesture options if there is no given + var options = gesture.defaults || {}; + if(options[gesture.name] === undefined) { + options[gesture.name] = true; + } - // set dash settings for chrome or firefox - ctx.setLineDash(pattern); - ctx.lineDashOffset = 0; + // extend Hammer default options with the Hammer.gesture options + Utils.extend(Hammer.defaults, options, true); - // draw the line - via = this._line(ctx); + // set its index + gesture.index = gesture.index || 1000; - // restore the dash settings. - ctx.setLineDash([0]); - ctx.lineDashOffset = 0; - ctx.restore(); - } - else { // unsupporting smooth lines - // draw dashed line - ctx.beginPath(); - ctx.lineCap = 'round'; - if (this.options.dash.altLength !== undefined) //If an alt dash value has been set add to the array this value - { - ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, - [this.options.dash.length,this.options.dash.gap,this.options.dash.altLength,this.options.dash.gap]); - } - else if (this.options.dash.length !== undefined && this.options.dash.gap !== undefined) //If a dash and gap value has been set add to the array this value - { - ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, - [this.options.dash.length,this.options.dash.gap]); - } - else //If all else fails draw a line - { - ctx.moveTo(this.from.x, this.from.y); - ctx.lineTo(this.to.x, this.to.y); - } - ctx.stroke(); - } + // add Hammer.gesture to the list + this.gestures.push(gesture); - // draw label - if (this.label) { - var point; - if (this.options.smoothCurves.enabled == true && via != null) { - var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); - var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); - point = {x:midpointX, y:midpointY}; - } - else { - point = this._pointOnLine(0.5); + // sort the list by index + this.gestures.sort(function(a, b) { + if(a.index < b.index) { + return -1; + } + if(a.index > b.index) { + return 1; + } + return 0; + }); + + return this.gestures; } - this._label(ctx, this.label, point.x, point.y); - } }; - /** - * Get a point on a line - * @param {Number} percentage. Value between 0 (line start) and 1 (line end) - * @return {Object} point - * @private - */ - Edge.prototype._pointOnLine = function (percentage) { - return { - x: (1 - percentage) * this.from.x + percentage * this.to.x, - y: (1 - percentage) * this.from.y + percentage * this.to.y - } - }; /** - * Get a point on a circle - * @param {Number} x - * @param {Number} y - * @param {Number} radius - * @param {Number} percentage. Value between 0 (line start) and 1 (line end) - * @return {Object} point - * @private + * @module hammer */ - Edge.prototype._pointOnCircle = function (x, y, radius, percentage) { - var angle = (percentage - 3/8) * 2 * Math.PI; - return { - x: x + radius * Math.cos(angle), - y: y - radius * Math.sin(angle) - } - }; /** - * Redraw a edge as a line with an arrow halfway the line - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private + * create new hammer instance + * all methods should return the instance itself, so it is chainable. + * + * @class Instance + * @constructor + * @param {HTMLElement} element + * @param {Object} [options={}] options are merged with `Hammer.defaults` + * @return {Hammer.Instance} */ - Edge.prototype._drawArrowCenter = function(ctx) { - var point; - // set style - ctx.strokeStyle = this._getColor(); - ctx.fillStyle = ctx.strokeStyle; - ctx.lineWidth = this._getLineWidth(); + Hammer.Instance = function(element, options) { + var self = this; - if (this.from != this.to) { - // draw line - var via = this._line(ctx); + // setup HammerJS window events and register all gestures + // this also sets up the default options + setup(); - var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; - // draw an arrow halfway the line - if (this.options.smoothCurves.enabled == true && via != null) { - var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); - var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); - point = {x:midpointX, y:midpointY}; - } - else { - point = this._pointOnLine(0.5); - } + /** + * @property element + * @type {HTMLElement} + */ + this.element = element; - ctx.arrow(point.x, point.y, angle, length); - ctx.fill(); - ctx.stroke(); + /** + * @property enabled + * @type {Boolean} + * @protected + */ + this.enabled = true; - // draw label - if (this.label) { - this._label(ctx, this.label, point.x, point.y); - } - } - else { - // draw circle - var x, y; - var radius = 0.25 * Math.max(100,this.physics.springLength); - var node = this.from; - if (!node.width) { - node.resize(ctx); - } - if (node.width > node.height) { - x = node.x + node.width * 0.5; - y = node.y - radius; - } - else { - x = node.x + radius; - y = node.y - node.height * 0.5; - } - this._circle(ctx, x, y, radius); + /** + * options, merged with the defaults + * options with an _ are converted to camelCase + * @property options + * @type {Object} + */ + Utils.each(options, function(value, name) { + delete options[name]; + options[Utils.toCamelCase(name)] = value; + }); - // draw all arrows - var angle = 0.2 * Math.PI; - var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; - point = this._pointOnCircle(x, y, radius, 0.5); - ctx.arrow(point.x, point.y, angle, length); - ctx.fill(); - ctx.stroke(); + this.options = Utils.extend(Utils.extend({}, Hammer.defaults), options || {}); - // draw label - if (this.label) { - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); + // add some css to the element to prevent the browser from doing its native behavoir + if(this.options.behavior) { + Utils.toggleBehavior(this.element, this.options.behavior, true); } - } - }; - - Edge.prototype._pointOnBezier = function(t) { - var via = this._getViaCoordinates(); - var x = Math.pow(1-t,2)*this.from.x + (2*t*(1 - t))*via.x + Math.pow(t,2)*this.to.x; - var y = Math.pow(1-t,2)*this.from.y + (2*t*(1 - t))*via.y + Math.pow(t,2)*this.to.y; + /** + * event start handler on the element to start the detection + * @property eventStartHandler + * @type {Object} + */ + this.eventStartHandler = Event.onTouch(element, EVENT_START, function(ev) { + if(self.enabled && ev.eventType == EVENT_START) { + Detection.startDetect(self, ev); + } else if(ev.eventType == EVENT_TOUCH) { + Detection.detect(ev); + } + }); - return {x:x,y:y}; - } + /** + * keep a list of user event handlers which needs to be removed when calling 'dispose' + * @property eventHandlers + * @type {Array} + */ + this.eventHandlers = []; + }; - /** - * This function uses binary search to look for the point where the bezier curve crosses the border of the node. - * - * @param from - * @param ctx - * @returns {*} - * @private - */ - Edge.prototype._findBorderPosition = function(from,ctx) { - var maxIterations = 10; - var iteration = 0; - var low = 0; - var high = 1; - var pos,angle,distanceToBorder, distanceToNodes, difference; - var threshold = 0.2; - var node = this.to; - if (from == true) { - node = this.from; - } + Hammer.Instance.prototype = { + /** + * bind events to the instance + * @method on + * @chainable + * @param {String} gestures multiple gestures by splitting with a space + * @param {Function} handler + * @param {Object} handler.ev event object + */ + on: function onEvent(gestures, handler) { + var self = this; + Event.on(self.element, gestures, handler, function(type) { + self.eventHandlers.push({ gesture: type, handler: handler }); + }); + return self; + }, - while (low <= high && iteration < maxIterations) { - var middle = (low + high) * 0.5; + /** + * unbind events to the instance + * @method off + * @chainable + * @param {String} gestures + * @param {Function} handler + */ + off: function offEvent(gestures, handler) { + var self = this; - pos = this._pointOnBezier(middle); - angle = Math.atan2((node.y - pos.y), (node.x - pos.x)); - distanceToBorder = node.distanceToBorder(ctx,angle); - distanceToNodes = Math.sqrt(Math.pow(pos.x-node.x,2) + Math.pow(pos.y-node.y,2)); - difference = distanceToBorder - distanceToNodes; - if (Math.abs(difference) < threshold) { - break; // found - } - else if (difference < 0) { // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node. - if (from == false) { - low = middle; - } - else { - high = middle; - } - } - else { - if (from == false) { - high = middle; - } - else { - low = middle; - } - } + Event.off(self.element, gestures, handler, function(type) { + var index = Utils.inArray({ gesture: type, handler: handler }); + if(index !== false) { + self.eventHandlers.splice(index, 1); + } + }); + return self; + }, - iteration++; - } - pos.t = middle; + /** + * trigger gesture event + * @method trigger + * @chainable + * @param {String} gesture + * @param {Object} [eventData] + */ + trigger: function triggerEvent(gesture, eventData) { + // optional + if(!eventData) { + eventData = {}; + } - return pos; - }; + // create DOM event + var event = Hammer.DOCUMENT.createEvent('Event'); + event.initEvent(gesture, true, true); + event.gesture = eventData; - /** - * Redraw a edge as a line with an arrow - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ - Edge.prototype._drawArrow = function(ctx) { - // set style - ctx.strokeStyle = this._getColor(); - ctx.fillStyle = ctx.strokeStyle; - ctx.lineWidth = this._getLineWidth(); + // trigger on the target if it is in the instance element, + // this is for event delegation tricks + var element = this.element; + if(Utils.hasParent(eventData.target, element)) { + element = eventData.target; + } - // set vars - var angle, length, arrowPos; + element.dispatchEvent(event); + return this; + }, - // if not connected to itself - if (this.from != this.to) { - // draw line - this._line(ctx); + /** + * enable of disable hammer.js detection + * @method enable + * @chainable + * @param {Boolean} state + */ + enable: function enable(state) { + this.enabled = state; + return this; + }, - // draw arrow head - if (this.options.smoothCurves.enabled == true) { - var via = this._getViaCoordinates(); - arrowPos = this._findBorderPosition(false, ctx); - var guidePos = this._pointOnBezier(Math.max(0.0, arrowPos.t - 0.1)) - angle = Math.atan2((arrowPos.y - guidePos.y), (arrowPos.x - guidePos.x)); - } - else { - angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var dx = (this.to.x - this.from.x); - var dy = (this.to.y - this.from.y); - var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); - var toBorderDist = this.to.distanceToBorder(ctx, angle); - var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; + /** + * dispose this hammer instance + * @method dispose + * @return {Null} + */ + dispose: function dispose() { + var i, eh; - arrowPos = {}; - arrowPos.x = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x; - arrowPos.y = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y; - } + // undo all changes made by stop_browser_behavior + Utils.toggleBehavior(this.element, this.options.behavior, false); - // draw arrow at the end of the line - length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; - ctx.arrow(arrowPos.x,arrowPos.y, angle, length); - ctx.fill(); - ctx.stroke(); + // unbind all custom event handlers + for(i = -1; (eh = this.eventHandlers[++i]);) { + Utils.off(this.element, eh.gesture, eh.handler); + } - // draw label - if (this.label) { - var point; - if (this.options.smoothCurves.enabled == true && via != null) { - point = this._pointOnBezier(0.5); - } - else { - point = this._pointOnLine(0.5); - } - this._label(ctx, this.label, point.x, point.y); - } - } - else { - // draw circle - var node = this.from; - var x, y, arrow; - var radius = 0.25 * Math.max(100,this.physics.springLength); - if (!node.width) { - node.resize(ctx); - } - if (node.width > node.height) { - x = node.x + node.width * 0.5; - y = node.y - radius; - arrow = { - x: x, - y: node.y, - angle: 0.9 * Math.PI - }; - } - else { - x = node.x + radius; - y = node.y - node.height * 0.5; - arrow = { - x: node.x, - y: y, - angle: 0.6 * Math.PI - }; - } - ctx.beginPath(); - // TODO: similarly, for a line without arrows, draw to the border of the nodes instead of the center - ctx.arc(x, y, radius, 0, 2 * Math.PI, false); - ctx.stroke(); + this.eventHandlers = []; - // draw all arrows - var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor; - ctx.arrow(arrow.x, arrow.y, arrow.angle, length); - ctx.fill(); - ctx.stroke(); + // unbind the start event listener + Event.off(this.element, EVENT_TYPES[EVENT_START], this.eventStartHandler); - // draw label - if (this.label) { - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); + return null; } - } }; + /** - * Calculate the distance between a point (x3,y3) and a line segment from - * (x1,y1) to (x2,y2). - * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment - * @param {number} x1 - * @param {number} y1 - * @param {number} x2 - * @param {number} y2 - * @param {number} x3 - * @param {number} y3 - * @private + * @module gestures */ - Edge.prototype._getDistanceToEdge = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point - var returnValue = 0; - if (this.from != this.to) { - if (this.options.smoothCurves.enabled == true) { - var xVia, yVia; - if (this.options.smoothCurves.enabled == true && this.options.smoothCurves.dynamic == true) { - xVia = this.via.x; - yVia = this.via.y; - } - else { - var via = this._getViaCoordinates(); - xVia = via.x; - yVia = via.y; - } - var minDistance = 1e9; - var distance; - var i,t,x,y, lastX, lastY; - for (i = 0; i < 10; i++) { - t = 0.1*i; - x = Math.pow(1-t,2)*x1 + (2*t*(1 - t))*xVia + Math.pow(t,2)*x2; - y = Math.pow(1-t,2)*y1 + (2*t*(1 - t))*yVia + Math.pow(t,2)*y2; - if (i > 0) { - distance = this._getDistanceToLine(lastX,lastY,x,y, x3,y3); - minDistance = distance < minDistance ? distance : minDistance; + /** + * Move with x fingers (default 1) around on the page. + * Preventing the default browser behavior is a good way to improve feel and working. + * ```` + * hammertime.on("drag", function(ev) { + * console.log(ev); + * ev.gesture.preventDefault(); + * }); + * ```` + * + * @class Drag + * @static + */ + /** + * @event drag + * @param {Object} ev + */ + /** + * @event dragstart + * @param {Object} ev + */ + /** + * @event dragend + * @param {Object} ev + */ + /** + * @event drapleft + * @param {Object} ev + */ + /** + * @event dragright + * @param {Object} ev + */ + /** + * @event dragup + * @param {Object} ev + */ + /** + * @event dragdown + * @param {Object} ev + */ + + /** + * @param {String} name + */ + (function(name) { + var triggered = false; + + function dragGesture(ev, inst) { + var cur = Detection.current; + + // max touches + if(inst.options.dragMaxTouches > 0 && + ev.touches.length > inst.options.dragMaxTouches) { + return; } - lastX = x; lastY = y; - } - returnValue = minDistance; - } - else { - returnValue = this._getDistanceToLine(x1,y1,x2,y2,x3,y3); - } - } - else { - var x, y, dx, dy; - var radius = 0.25 * this.physics.springLength; - var node = this.from; - if (node.width > node.height) { - x = node.x + 0.5 * node.width; - y = node.y - radius; - } - else { - x = node.x + radius; - y = node.y - 0.5 * node.height; - } - dx = x - x3; - dy = y - y3; - returnValue = Math.abs(Math.sqrt(dx*dx + dy*dy) - radius); - } - if (this.labelDimensions.left < x3 && - this.labelDimensions.left + this.labelDimensions.width > x3 && - this.labelDimensions.top < y3 && - this.labelDimensions.top + this.labelDimensions.height > y3) { - return 0; - } - else { - return returnValue; - } - }; + switch(ev.eventType) { + case EVENT_START: + triggered = false; + break; - Edge.prototype._getDistanceToLine = function(x1,y1,x2,y2,x3,y3) { - var px = x2-x1, - py = y2-y1, - something = px*px + py*py, - u = ((x3 - x1) * px + (y3 - y1) * py) / something; + case EVENT_MOVE: + // when the distance we moved is too small we skip this gesture + // or we can be already in dragging + if(ev.distance < inst.options.dragMinDistance && + cur.name != name) { + return; + } - if (u > 1) { - u = 1; - } - else if (u < 0) { - u = 0; - } + var startCenter = cur.startEvent.center; - var x = x1 + u * px, - y = y1 + u * py, - dx = x - x3, - dy = y - y3; + // we are dragging! + if(cur.name != name) { + cur.name = name; + if(inst.options.dragDistanceCorrection && ev.distance > 0) { + // When a drag is triggered, set the event center to dragMinDistance pixels from the original event center. + // Without this correction, the dragged distance would jumpstart at dragMinDistance pixels instead of at 0. + // It might be useful to save the original start point somewhere + var factor = Math.abs(inst.options.dragMinDistance / ev.distance); + startCenter.pageX += ev.deltaX * factor; + startCenter.pageY += ev.deltaY * factor; + startCenter.clientX += ev.deltaX * factor; + startCenter.clientY += ev.deltaY * factor; - //# Note: If the actual distance does not matter, - //# if you only want to compare what this function - //# returns to other results of this function, you - //# can just return the squared distance instead - //# (i.e. remove the sqrt) to gain a little performance + // recalculate event data using new start point + ev = Detection.extendEventData(ev); + } + } - return Math.sqrt(dx*dx + dy*dy); - }; + // lock drag to axis? + if(cur.lastEvent.dragLockToAxis || + ( inst.options.dragLockToAxis && + inst.options.dragLockMinDistance <= ev.distance + )) { + ev.dragLockToAxis = true; + } - /** - * This allows the zoom level of the network to influence the rendering - * - * @param scale - */ - Edge.prototype.setScale = function(scale) { - this.networkScaleInv = 1.0/scale; - }; + // keep direction on the axis that the drag gesture started on + var lastDirection = cur.lastEvent.direction; + if(ev.dragLockToAxis && lastDirection !== ev.direction) { + if(Utils.isVertical(lastDirection)) { + ev.direction = (ev.deltaY < 0) ? DIRECTION_UP : DIRECTION_DOWN; + } else { + ev.direction = (ev.deltaX < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT; + } + } + // first time, trigger dragstart event + if(!triggered) { + inst.trigger(name + 'start', ev); + triggered = true; + } - Edge.prototype.select = function() { - this.selected = true; - }; + // trigger events + inst.trigger(name, ev); + inst.trigger(name + ev.direction, ev); - Edge.prototype.unselect = function() { - this.selected = false; - }; + var isVertical = Utils.isVertical(ev.direction); - Edge.prototype.positionBezierNode = function() { - if (this.via !== null && this.from !== null && this.to !== null) { - this.via.x = 0.5 * (this.from.x + this.to.x); - this.via.y = 0.5 * (this.from.y + this.to.y); - } - else if (this.via !== null) { - this.via.x = 0; - this.via.y = 0; - } - }; + // block the browser events + if((inst.options.dragBlockVertical && isVertical) || + (inst.options.dragBlockHorizontal && !isVertical)) { + ev.preventDefault(); + } + break; - /** - * This function draws the control nodes for the manipulator. - * In order to enable this, only set the this.controlNodesEnabled to true. - * @param ctx - */ - Edge.prototype._drawControlNodes = function(ctx) { - if (this.controlNodesEnabled == true) { - if (this.controlNodes.from === null && this.controlNodes.to === null) { - var nodeIdFrom = "edgeIdFrom:".concat(this.id); - var nodeIdTo = "edgeIdTo:".concat(this.id); - var constants = { - nodes:{group:'', radius:7, borderWidth:2, borderWidthSelected: 2}, - physics:{damping:0}, - clustering: {maxNodeSizeIncrements: 0 ,nodeScaling: {width:0, height: 0, radius:0}} - }; - this.controlNodes.from = new Node( - {id:nodeIdFrom, - shape:'dot', - color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}} - },{},{},constants); - this.controlNodes.to = new Node( - {id:nodeIdTo, - shape:'dot', - color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}} - },{},{},constants); - } + case EVENT_RELEASE: + if(triggered && ev.changedLength <= inst.options.dragMaxTouches) { + inst.trigger(name + 'end', ev); + triggered = false; + } + break; - this.controlNodes.positions = {}; - if (this.controlNodes.from.selected == false) { - this.controlNodes.positions.from = this.getControlNodeFromPosition(ctx); - this.controlNodes.from.x = this.controlNodes.positions.from.x; - this.controlNodes.from.y = this.controlNodes.positions.from.y; - } - if (this.controlNodes.to.selected == false) { - this.controlNodes.positions.to = this.getControlNodeToPosition(ctx); - this.controlNodes.to.x = this.controlNodes.positions.to.x; - this.controlNodes.to.y = this.controlNodes.positions.to.y; + case EVENT_END: + triggered = false; + break; + } } - this.controlNodes.from.draw(ctx); - this.controlNodes.to.draw(ctx); - } - else { - this.controlNodes = {from:null, to:null, positions:{}}; - } - }; + Hammer.gestures.Drag = { + name: name, + index: 50, + handler: dragGesture, + defaults: { + /** + * minimal movement that have to be made before the drag event gets triggered + * @property dragMinDistance + * @type {Number} + * @default 10 + */ + dragMinDistance: 10, - /** - * Enable control nodes. - * @private - */ - Edge.prototype._enableControlNodes = function() { - this.fromBackup = this.from; - this.toBackup = this.to; - this.controlNodesEnabled = true; - }; + /** + * Set dragDistanceCorrection to true to make the starting point of the drag + * be calculated from where the drag was triggered, not from where the touch started. + * Useful to avoid a jerk-starting drag, which can make fine-adjustments + * through dragging difficult, and be visually unappealing. + * @property dragDistanceCorrection + * @type {Boolean} + * @default true + */ + dragDistanceCorrection: true, + + /** + * set 0 for unlimited, but this can conflict with transform + * @property dragMaxTouches + * @type {Number} + * @default 1 + */ + dragMaxTouches: 1, + + /** + * prevent default browser behavior when dragging occurs + * be careful with it, it makes the element a blocking element + * when you are using the drag gesture, it is a good practice to set this true + * @property dragBlockHorizontal + * @type {Boolean} + * @default false + */ + dragBlockHorizontal: false, + + /** + * same as `dragBlockHorizontal`, but for vertical movement + * @property dragBlockVertical + * @type {Boolean} + * @default false + */ + dragBlockVertical: false, + + /** + * dragLockToAxis keeps the drag gesture on the axis that it started on, + * It disallows vertical directions if the initial direction was horizontal, and vice versa. + * @property dragLockToAxis + * @type {Boolean} + * @default false + */ + dragLockToAxis: false, + + /** + * drag lock only kicks in when distance > dragLockMinDistance + * This way, locking occurs only when the distance has become large enough to reliably determine the direction + * @property dragLockMinDistance + * @type {Number} + * @default 25 + */ + dragLockMinDistance: 25 + } + }; + })('drag'); /** - * disable control nodes and remove from dynamicEdges from old node - * @private + * @module gestures */ - Edge.prototype._disableControlNodes = function() { - this.fromId = this.from.id; - this.toId = this.to.id; - if (this.fromId != this.fromBackup.id) { // from was changed, remove edge from old 'from' node dynamic edges - this.fromBackup.detachEdge(this); - } - else if (this.toId != this.toBackup.id) { // to was changed, remove edge from old 'to' node dynamic edges - this.toBackup.detachEdge(this); - } - - this.fromBackup = null; - this.toBackup = null; - this.controlNodesEnabled = false; - }; - - /** - * This checks if one of the control nodes is selected and if so, returns the control node object. Else it returns null. - * @param x - * @param y - * @returns {null} - * @private + * trigger a simple gesture event, so you can do anything in your handler. + * only usable if you know what your doing... + * + * @class Gesture + * @static */ - Edge.prototype._getSelectedControlNode = function(x,y) { - var positions = this.controlNodes.positions; - var fromDistance = Math.sqrt(Math.pow(x - positions.from.x,2) + Math.pow(y - positions.from.y,2)); - var toDistance = Math.sqrt(Math.pow(x - positions.to.x ,2) + Math.pow(y - positions.to.y ,2)); - - if (fromDistance < 15) { - this.connectedNode = this.from; - this.from = this.controlNodes.from; - return this.controlNodes.from; - } - else if (toDistance < 15) { - this.connectedNode = this.to; - this.to = this.controlNodes.to; - return this.controlNodes.to; - } - else { - return null; - } - }; - - /** - * this resets the control nodes to their original position. - * @private + * @event gesture + * @param {Object} ev */ - Edge.prototype._restoreControlNodes = function() { - if (this.controlNodes.from.selected == true) { - this.from = this.connectedNode; - this.connectedNode = null; - this.controlNodes.from.unselect(); - } - else if (this.controlNodes.to.selected == true) { - this.to = this.connectedNode; - this.connectedNode = null; - this.controlNodes.to.unselect(); - } + Hammer.gestures.Gesture = { + name: 'gesture', + index: 1337, + handler: function releaseGesture(ev, inst) { + inst.trigger(this.name, ev); + } }; /** - * this calculates the position of the control nodes on the edges of the parent nodes. + * @module gestures + */ + /** + * Touch stays at the same place for x time * - * @param ctx - * @returns {x: *, y: *} + * @class Hold + * @static + */ + /** + * @event hold + * @param {Object} ev */ - Edge.prototype.getControlNodeFromPosition = function(ctx) { - // draw arrow head - var controlnodeFromPos; - if (this.options.smoothCurves.enabled == true) { - controlnodeFromPos = this._findBorderPosition(true, ctx); - } - else { - var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var dx = (this.to.x - this.from.x); - var dy = (this.to.y - this.from.y); - var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); - - var fromBorderDist = this.from.distanceToBorder(ctx, angle + Math.PI); - var fromBorderPoint = (edgeSegmentLength - fromBorderDist) / edgeSegmentLength; - controlnodeFromPos = {}; - controlnodeFromPos.x = (fromBorderPoint) * this.from.x + (1 - fromBorderPoint) * this.to.x; - controlnodeFromPos.y = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y; - } - - return controlnodeFromPos; - }; /** - * this calculates the position of the control nodes on the edges of the parent nodes. - * - * @param ctx - * @returns {{from: {x: number, y: number}, to: {x: *, y: *}}} + * @param {String} name */ - Edge.prototype.getControlNodeToPosition = function(ctx) { - // draw arrow head - var controlnodeFromPos,controlnodeToPos; - if (this.options.smoothCurves.enabled == true) { - controlnodeToPos = this._findBorderPosition(false, ctx); - } - else { - var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var dx = (this.to.x - this.from.x); - var dy = (this.to.y - this.from.y); - var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy); - var toBorderDist = this.to.distanceToBorder(ctx, angle); - var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; + (function(name) { + var timer; - controlnodeToPos = {}; - controlnodeToPos.x = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x; - controlnodeToPos.y = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y; - } + function holdGesture(ev, inst) { + var options = inst.options, + current = Detection.current; - return controlnodeToPos; - }; + switch(ev.eventType) { + case EVENT_START: + clearTimeout(timer); - module.exports = Edge; + // set the gesture so we can check in the timeout if it still is + current.name = name; -/***/ }, -/* 58 */ -/***/ function(module, exports, __webpack_require__) { + // set timer and if after the timeout it still is hold, + // we trigger the hold event + timer = setTimeout(function() { + if(current && current.name == name) { + inst.trigger(name, ev); + } + }, options.holdTimeout); + break; - /** - * Popup is a class to create a popup window with some text - * @param {Element} container The container object. - * @param {Number} [x] - * @param {Number} [y] - * @param {String} [text] - * @param {Object} [style] An object containing borderColor, - * backgroundColor, etc. - */ - function Popup(container, x, y, text, style) { - if (container) { - this.container = container; - } - else { - this.container = document.body; - } + case EVENT_MOVE: + if(ev.distance > options.holdThreshold) { + clearTimeout(timer); + } + break; - // x, y and text are optional, see if a style object was passed in their place - if (style === undefined) { - if (typeof x === "object") { - style = x; - x = undefined; - } else if (typeof text === "object") { - style = text; - text = undefined; - } else { - // for backwards compatibility, in case clients other than Network are creating Popup directly - style = { - fontColor: 'black', - fontSize: 14, // px - fontFace: 'verdana', - color: { - border: '#666', - background: '#FFFFC6' + case EVENT_RELEASE: + clearTimeout(timer); + break; } - } } - } - - this.x = 0; - this.y = 0; - this.padding = 5; - if (x !== undefined && y !== undefined ) { - this.setPosition(x, y); - } - if (text !== undefined) { - this.setText(text); - } + Hammer.gestures.Hold = { + name: name, + index: 10, + defaults: { + /** + * @property holdTimeout + * @type {Number} + * @default 500 + */ + holdTimeout: 500, - // create the frame - this.frame = document.createElement("div"); - var styleAttr = this.frame.style; - styleAttr.position = "absolute"; - styleAttr.visibility = "hidden"; - styleAttr.border = "1px solid " + style.color.border; - styleAttr.color = style.fontColor; - styleAttr.fontSize = style.fontSize + "px"; - styleAttr.fontFamily = style.fontFace; - styleAttr.padding = this.padding + "px"; - styleAttr.backgroundColor = style.color.background; - styleAttr.borderRadius = "3px"; - styleAttr.MozBorderRadius = "3px"; - styleAttr.WebkitBorderRadius = "3px"; - styleAttr.boxShadow = "3px 3px 10px rgba(128, 128, 128, 0.5)"; - styleAttr.whiteSpace = "nowrap"; - this.container.appendChild(this.frame); - } + /** + * movement allowed while holding + * @property holdThreshold + * @type {Number} + * @default 2 + */ + holdThreshold: 2 + }, + handler: holdGesture + }; + })('hold'); /** - * @param {number} x Horizontal position of the popup window - * @param {number} y Vertical position of the popup window + * @module gestures */ - Popup.prototype.setPosition = function(x, y) { - this.x = parseInt(x); - this.y = parseInt(y); - }; - /** - * Set the content for the popup window. This can be HTML code or text. - * @param {string | Element} content + * when a touch is being released from the page + * + * @class Release + * @static */ - Popup.prototype.setText = function(content) { - if (content instanceof Element) { - this.frame.innerHTML = ''; - this.frame.appendChild(content); - } - else { - this.frame.innerHTML = content; // string containing text or HTML - } - }; - /** - * Show the popup window - * @param {boolean} show Optional. Show or hide the window + * @event release + * @param {Object} ev */ - Popup.prototype.show = function (show) { - if (show === undefined) { - show = true; - } - - if (show) { - var height = this.frame.clientHeight; - var width = this.frame.clientWidth; - var maxHeight = this.frame.parentNode.clientHeight; - var maxWidth = this.frame.parentNode.clientWidth; - - var top = (this.y - height); - if (top + height + this.padding > maxHeight) { - top = maxHeight - height - this.padding; - } - if (top < this.padding) { - top = this.padding; - } - - var left = this.x; - if (left + width + this.padding > maxWidth) { - left = maxWidth - width - this.padding; - } - if (left < this.padding) { - left = this.padding; + Hammer.gestures.Release = { + name: 'release', + index: Infinity, + handler: function releaseGesture(ev, inst) { + if(ev.eventType == EVENT_RELEASE) { + inst.trigger(this.name, ev); + } } - - this.frame.style.left = left + "px"; - this.frame.style.top = top + "px"; - this.frame.style.visibility = "visible"; - } - else { - this.hide(); - } - }; - - /** - * Hide the popup window - */ - Popup.prototype.hide = function () { - this.frame.style.visibility = "hidden"; }; - module.exports = Popup; - - -/***/ }, -/* 59 */ -/***/ function(module, exports, __webpack_require__) { - - var PhysicsMixin = __webpack_require__(60); - var ClusterMixin = __webpack_require__(64); - var SectorsMixin = __webpack_require__(65); - var SelectionMixin = __webpack_require__(66); - var ManipulationMixin = __webpack_require__(67); - var NavigationMixin = __webpack_require__(68); - var HierarchicalLayoutMixin = __webpack_require__(69); - /** - * Load a mixin into the network object - * - * @param {Object} sourceVariable | this object has to contain functions. - * @private + * @module gestures */ - exports._loadMixin = function (sourceVariable) { - for (var mixinFunction in sourceVariable) { - if (sourceVariable.hasOwnProperty(mixinFunction)) { - this[mixinFunction] = sourceVariable[mixinFunction]; - } - } - }; - - /** - * removes a mixin from the network object. + * triggers swipe events when the end velocity is above the threshold + * for best usage, set `preventDefault` (on the drag gesture) to `true` + * ```` + * hammertime.on("dragleft swipeleft", function(ev) { + * console.log(ev); + * ev.gesture.preventDefault(); + * }); + * ```` * - * @param {Object} sourceVariable | this object has to contain functions. - * @private + * @class Swipe + * @static */ - exports._clearMixin = function (sourceVariable) { - for (var mixinFunction in sourceVariable) { - if (sourceVariable.hasOwnProperty(mixinFunction)) { - this[mixinFunction] = undefined; - } - } - }; - - /** - * Mixin the physics system and initialize the parameters required. - * - * @private + * @event swipe + * @param {Object} ev */ - exports._loadPhysicsSystem = function () { - this._loadMixin(PhysicsMixin); - this._loadSelectedForceSolver(); - if (this.constants.configurePhysics == true) { - this._loadPhysicsConfiguration(); - } - else { - this._cleanupPhysicsConfiguration(); - } - }; - - /** - * Mixin the cluster system and initialize the parameters required. - * - * @private + * @event swipeleft + * @param {Object} ev */ - exports._loadClusterSystem = function () { - this.clusterSession = 0; - this.hubThreshold = 5; - this._loadMixin(ClusterMixin); - }; - - /** - * Mixin the sector system and initialize the parameters required - * - * @private + * @event swiperight + * @param {Object} ev */ - exports._loadSectorSystem = function () { - this.sectors = {}; - this.activeSector = ["default"]; - this.sectors["active"] = {}; - this.sectors["active"]["default"] = {"nodes": {}, - "edges": {}, - "nodeIndices": [], - "formationScale": 1.0, - "drawingNode": undefined }; - this.sectors["frozen"] = {}; - this.sectors["support"] = {"nodes": {}, - "edges": {}, - "nodeIndices": [], - "formationScale": 1.0, - "drawingNode": undefined }; - - this.nodeIndices = this.sectors["active"]["default"]["nodeIndices"]; // the node indices list is used to speed up the computation of the repulsion fields - - this._loadMixin(SectorsMixin); - }; - - /** - * Mixin the selection system and initialize the parameters required - * - * @private + * @event swipeup + * @param {Object} ev */ - exports._loadSelectionSystem = function () { - this.selectionObj = {nodes: {}, edges: {}}; - - this._loadMixin(SelectionMixin); - }; - - /** - * Mixin the navigationUI (User Interface) system and initialize the parameters required - * - * @private + * @event swipedown + * @param {Object} ev */ - exports._loadManipulationSystem = function () { - // reset global variables -- these are used by the selection of nodes and edges. - this.blockConnectingEdgeSelection = false; - this.forceAppendSelection = false; - - if (this.constants.dataManipulation.enabled == true) { - // load the manipulator HTML elements. All styling done in css. - if (this.manipulationDiv === undefined) { - this.manipulationDiv = document.createElement('div'); - this.manipulationDiv.className = 'network-manipulationDiv'; - if (this.editMode == true) { - this.manipulationDiv.style.display = "block"; - } - else { - this.manipulationDiv.style.display = "none"; - } - this.frame.appendChild(this.manipulationDiv); - } - - if (this.editModeDiv === undefined) { - this.editModeDiv = document.createElement('div'); - this.editModeDiv.className = 'network-manipulation-editMode'; - if (this.editMode == true) { - this.editModeDiv.style.display = "none"; - } - else { - this.editModeDiv.style.display = "block"; - } - this.frame.appendChild(this.editModeDiv); - } + Hammer.gestures.Swipe = { + name: 'swipe', + index: 40, + defaults: { + /** + * @property swipeMinTouches + * @type {Number} + * @default 1 + */ + swipeMinTouches: 1, - if (this.closeDiv === undefined) { - this.closeDiv = document.createElement('div'); - this.closeDiv.className = 'network-manipulation-closeDiv'; - this.closeDiv.style.display = this.manipulationDiv.style.display; - this.frame.appendChild(this.closeDiv); - } + /** + * @property swipeMaxTouches + * @type {Number} + * @default 1 + */ + swipeMaxTouches: 1, - // load the manipulation functions - this._loadMixin(ManipulationMixin); + /** + * horizontal swipe velocity + * @property swipeVelocityX + * @type {Number} + * @default 0.6 + */ + swipeVelocityX: 0.6, - // create the manipulator toolbar - this._createManipulatorBar(); - } - else { - if (this.manipulationDiv !== undefined) { - // removes all the bindings and overloads - this._createManipulatorBar(); + /** + * vertical swipe velocity + * @property swipeVelocityY + * @type {Number} + * @default 0.6 + */ + swipeVelocityY: 0.6 + }, - // remove the manipulation divs - this.frame.removeChild(this.manipulationDiv); - this.frame.removeChild(this.editModeDiv); - this.frame.removeChild(this.closeDiv); + handler: function swipeGesture(ev, inst) { + if(ev.eventType == EVENT_RELEASE) { + var touches = ev.touches.length, + options = inst.options; - this.manipulationDiv = undefined; - this.editModeDiv = undefined; - this.closeDiv = undefined; - // remove the mixin functions - this._clearMixin(ManipulationMixin); + // max touches + if(touches < options.swipeMinTouches || + touches > options.swipeMaxTouches) { + return; + } + + // when the distance we moved is too small we skip this gesture + // or we can be already in dragging + if(ev.velocityX > options.swipeVelocityX || + ev.velocityY > options.swipeVelocityY) { + // trigger swipe events + inst.trigger(this.name, ev); + inst.trigger(this.name + ev.direction, ev); + } + } } - } }; - /** - * Mixin the navigation (User Interface) system and initialize the parameters required - * - * @private + * @module gestures */ - exports._loadNavigationControls = function () { - this._loadMixin(NavigationMixin); - // the clean function removes the button divs, this is done to remove the bindings. - this._cleanNavigation(); - if (this.constants.navigation.enabled == true) { - this._loadNavigationElements(); - } - }; - - /** - * Mixin the hierarchical layout system. + * Single tap and a double tap on a place * - * @private + * @class Tap + * @static */ - exports._loadHierarchySystem = function () { - this._loadMixin(HierarchicalLayoutMixin); - }; - - -/***/ }, -/* 60 */ -/***/ function(module, exports, __webpack_require__) { - - var util = __webpack_require__(1); - var RepulsionMixin = __webpack_require__(61); - var HierarchialRepulsionMixin = __webpack_require__(62); - var BarnesHutMixin = __webpack_require__(63); - /** - * Toggling barnes Hut calculation on and off. - * - * @private + * @event tap + * @param {Object} ev */ - exports._toggleBarnesHut = function () { - this.constants.physics.barnesHut.enabled = !this.constants.physics.barnesHut.enabled; - this._loadSelectedForceSolver(); - this.moving = true; - this.start(); - }; - - /** - * This loads the node force solver based on the barnes hut or repulsion algorithm - * - * @private + * @event doubletap + * @param {Object} ev */ - exports._loadSelectedForceSolver = function () { - // this overloads the this._calculateNodeForces - if (this.constants.physics.barnesHut.enabled == true) { - this._clearMixin(RepulsionMixin); - this._clearMixin(HierarchialRepulsionMixin); - this.constants.physics.centralGravity = this.constants.physics.barnesHut.centralGravity; - this.constants.physics.springLength = this.constants.physics.barnesHut.springLength; - this.constants.physics.springConstant = this.constants.physics.barnesHut.springConstant; - this.constants.physics.damping = this.constants.physics.barnesHut.damping; + /** + * @param {String} name + */ + (function(name) { + var hasMoved = false; - this._loadMixin(BarnesHutMixin); - } - else if (this.constants.physics.hierarchicalRepulsion.enabled == true) { - this._clearMixin(BarnesHutMixin); - this._clearMixin(RepulsionMixin); + function tapGesture(ev, inst) { + var options = inst.options, + current = Detection.current, + prev = Detection.previous, + sincePrev, + didDoubleTap; - this.constants.physics.centralGravity = this.constants.physics.hierarchicalRepulsion.centralGravity; - this.constants.physics.springLength = this.constants.physics.hierarchicalRepulsion.springLength; - this.constants.physics.springConstant = this.constants.physics.hierarchicalRepulsion.springConstant; - this.constants.physics.damping = this.constants.physics.hierarchicalRepulsion.damping; + switch(ev.eventType) { + case EVENT_START: + hasMoved = false; + break; - this._loadMixin(HierarchialRepulsionMixin); - } - else { - this._clearMixin(BarnesHutMixin); - this._clearMixin(HierarchialRepulsionMixin); - this.barnesHutTree = undefined; + case EVENT_MOVE: + hasMoved = hasMoved || (ev.distance > options.tapMaxDistance); + break; - this.constants.physics.centralGravity = this.constants.physics.repulsion.centralGravity; - this.constants.physics.springLength = this.constants.physics.repulsion.springLength; - this.constants.physics.springConstant = this.constants.physics.repulsion.springConstant; - this.constants.physics.damping = this.constants.physics.repulsion.damping; + case EVENT_END: + if(!Utils.inStr(ev.srcEvent.type, 'cancel') && ev.deltaTime < options.tapMaxTime && !hasMoved) { + // previous gesture, for the double tap since these are two different gesture detections + sincePrev = prev && prev.lastEvent && ev.timeStamp - prev.lastEvent.timeStamp; + didDoubleTap = false; - this._loadMixin(RepulsionMixin); - } - }; + // check if double tap + if(prev && prev.name == name && + (sincePrev && sincePrev < options.doubleTapInterval) && + ev.distance < options.doubleTapDistance) { + inst.trigger('doubletap', ev); + didDoubleTap = true; + } - /** - * Before calculating the forces, we check if we need to cluster to keep up performance and we check - * if there is more than one node. If it is just one node, we dont calculate anything. - * - * @private - */ - exports._initializeForceCalculation = function () { - // stop calculation if there is only one node - if (this.nodeIndices.length == 1) { - this.nodes[this.nodeIndices[0]]._setForce(0, 0); - } - else { - // if there are too many nodes on screen, we cluster without repositioning - if (this.nodeIndices.length > this.constants.clustering.clusterThreshold && this.constants.clustering.enabled == true) { - this.clusterToFit(this.constants.clustering.reduceToNodes, false); + // do a single tap + if(!didDoubleTap || options.tapAlways) { + current.name = name; + inst.trigger(current.name, ev); + } + } + break; + } } - // we now start the force calculation - this._calculateForces(); - } - }; - + Hammer.gestures.Tap = { + name: name, + index: 100, + handler: tapGesture, + defaults: { + /** + * max time of a tap, this is for the slow tappers + * @property tapMaxTime + * @type {Number} + * @default 250 + */ + tapMaxTime: 250, - /** - * Calculate the external forces acting on the nodes - * Forces are caused by: edges, repulsing forces between nodes, gravity - * @private - */ - exports._calculateForces = function () { - // Gravity is required to keep separated groups from floating off - // the forces are reset to zero in this loop by using _setForce instead - // of _addForce + /** + * max distance of movement of a tap, this is for the slow tappers + * @property tapMaxDistance + * @type {Number} + * @default 10 + */ + tapMaxDistance: 10, - this._calculateGravitationalForces(); - this._calculateNodeForces(); + /** + * always trigger the `tap` event, even while double-tapping + * @property tapAlways + * @type {Boolean} + * @default true + */ + tapAlways: true, - if (this.constants.physics.springConstant > 0) { - if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { - this._calculateSpringForcesWithSupport(); - } - else { - if (this.constants.physics.hierarchicalRepulsion.enabled == true) { - this._calculateHierarchicalSpringForces(); - } - else { - this._calculateSpringForces(); - } - } - } - }; + /** + * max distance between two taps + * @property doubleTapDistance + * @type {Number} + * @default 20 + */ + doubleTapDistance: 20, + /** + * max time between two taps + * @property doubleTapInterval + * @type {Number} + * @default 300 + */ + doubleTapInterval: 300 + } + }; + })('tap'); /** - * Smooth curves are created by adding invisible nodes in the center of the edges. These nodes are also - * handled in the calculateForces function. We then use a quadratic curve with the center node as control. - * This function joins the datanodes and invisible (called support) nodes into one object. - * We do this so we do not contaminate this.nodes with the support nodes. + * @module gestures + */ + /** + * when a touch is being touched at the page * - * @private + * @class Touch + * @static */ - exports._updateCalculationNodes = function () { - if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { - this.calculationNodes = {}; - this.calculationNodeIndices = []; + /** + * @event touch + * @param {Object} ev + */ + Hammer.gestures.Touch = { + name: 'touch', + index: -Infinity, + defaults: { + /** + * call preventDefault at touchstart, and makes the element blocking by disabling the scrolling of the page, + * but it improves gestures like transforming and dragging. + * be careful with using this, it can be very annoying for users to be stuck on the page + * @property preventDefault + * @type {Boolean} + * @default false + */ + preventDefault: false, - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - this.calculationNodes[nodeId] = this.nodes[nodeId]; - } - } - var supportNodes = this.sectors['support']['nodes']; - for (var supportNodeId in supportNodes) { - if (supportNodes.hasOwnProperty(supportNodeId)) { - if (this.edges.hasOwnProperty(supportNodes[supportNodeId].parentEdgeId)) { - this.calculationNodes[supportNodeId] = supportNodes[supportNodeId]; + /** + * disable mouse events, so only touch (or pen!) input triggers events + * @property preventMouse + * @type {Boolean} + * @default false + */ + preventMouse: false + }, + handler: function touchGesture(ev, inst) { + if(inst.options.preventMouse && ev.pointerType == POINTER_MOUSE) { + ev.stopDetect(); + return; } - else { - supportNodes[supportNodeId]._setForce(0, 0); + + if(inst.options.preventDefault) { + ev.preventDefault(); } - } - } - for (var idx in this.calculationNodes) { - if (this.calculationNodes.hasOwnProperty(idx)) { - this.calculationNodeIndices.push(idx); - } + if(ev.eventType == EVENT_TOUCH) { + inst.trigger('touch', ev); + } } - } - else { - this.calculationNodes = this.nodes; - this.calculationNodeIndices = this.nodeIndices; - } }; - /** - * this function applies the central gravity effect to keep groups from floating off - * - * @private + * @module gestures */ - exports._calculateGravitationalForces = function () { - var dx, dy, distance, node, i; - var nodes = this.calculationNodes; - var gravity = this.constants.physics.centralGravity; - var gravityForce = 0; - - for (i = 0; i < this.calculationNodeIndices.length; i++) { - node = nodes[this.calculationNodeIndices[i]]; - node.damping = this.constants.physics.damping; // possibly add function to alter damping properties of clusters. - // gravity does not apply when we are in a pocket sector - if (this._sector() == "default" && gravity != 0) { - dx = -node.x; - dy = -node.y; - distance = Math.sqrt(dx * dx + dy * dy); - - gravityForce = (distance == 0) ? 0 : (gravity / distance); - node.fx = dx * gravityForce; - node.fy = dy * gravityForce; - } - else { - node.fx = 0; - node.fy = 0; - } - } - }; - - - - /** - * this function calculates the effects of the springs in the case of unsmooth curves. + * User want to scale or rotate with 2 fingers + * Preventing the default browser behavior is a good way to improve feel and working. This can be done with the + * `preventDefault` option. * - * @private + * @class Transform + * @static + */ + /** + * @event transform + * @param {Object} ev + */ + /** + * @event transformstart + * @param {Object} ev + */ + /** + * @event transformend + * @param {Object} ev + */ + /** + * @event pinchin + * @param {Object} ev + */ + /** + * @event pinchout + * @param {Object} ev + */ + /** + * @event rotate + * @param {Object} ev */ - exports._calculateSpringForces = function () { - var edgeLength, edge, edgeId; - var dx, dy, fx, fy, springForce, distance; - var edges = this.edges; - - // forces caused by the edges, modelled as springs - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.connected) { - // only calculate forces if nodes are in the same sector - if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { - edgeLength = edge.physics.springLength; - // this implies that the edges between big clusters are longer - edgeLength += (edge.to.clusterSize + edge.from.clusterSize - 2) * this.constants.clustering.edgeGrowth; - - dx = (edge.from.x - edge.to.x); - dy = (edge.from.y - edge.to.y); - distance = Math.sqrt(dx * dx + dy * dy); - - if (distance == 0) { - distance = 0.01; - } - // the 1/distance is so the fx and fy can be calculated without sine or cosine. - springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance; + /** + * @param {String} name + */ + (function(name) { + var triggered = false; - fx = dx * springForce; - fy = dy * springForce; + function transformGesture(ev, inst) { + switch(ev.eventType) { + case EVENT_START: + triggered = false; + break; - edge.from.fx += fx; - edge.from.fy += fy; - edge.to.fx -= fx; - edge.to.fy -= fy; - } - } - } - } - }; + case EVENT_MOVE: + // at least multitouch + if(ev.touches.length < 2) { + return; + } + var scaleThreshold = Math.abs(1 - ev.scale); + var rotationThreshold = Math.abs(ev.rotation); + // when the distance we moved is too small we skip this gesture + // or we can be already in dragging + if(scaleThreshold < inst.options.transformMinScale && + rotationThreshold < inst.options.transformMinRotation) { + return; + } + // we are transforming! + Detection.current.name = name; - /** - * This function calculates the springforces on the nodes, accounting for the support nodes. - * - * @private - */ - exports._calculateSpringForcesWithSupport = function () { - var edgeLength, edge, edgeId, combinedClusterSize; - var edges = this.edges; + // first time, trigger dragstart event + if(!triggered) { + inst.trigger(name + 'start', ev); + triggered = true; + } - // forces caused by the edges, modelled as springs - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.connected) { - // only calculate forces if nodes are in the same sector - if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { - if (edge.via != null) { - var node1 = edge.to; - var node2 = edge.via; - var node3 = edge.from; + inst.trigger(name, ev); // basic transform event - edgeLength = edge.physics.springLength; + // trigger rotate event + if(rotationThreshold > inst.options.transformMinRotation) { + inst.trigger('rotate', ev); + } - combinedClusterSize = node1.clusterSize + node3.clusterSize - 2; + // trigger pinch event + if(scaleThreshold > inst.options.transformMinScale) { + inst.trigger('pinch', ev); + inst.trigger('pinch' + (ev.scale < 1 ? 'in' : 'out'), ev); + } + break; - // this implies that the edges between big clusters are longer - edgeLength += combinedClusterSize * this.constants.clustering.edgeGrowth; - this._calculateSpringForce(node1, node2, 0.5 * edgeLength); - this._calculateSpringForce(node2, node3, 0.5 * edgeLength); - } + case EVENT_RELEASE: + if(triggered && ev.changedLength < 2) { + inst.trigger(name + 'end', ev); + triggered = false; + } + break; } - } } - } - }; - - - /** - * This is the code actually performing the calculation for the function above. It is split out to avoid repetition. - * - * @param node1 - * @param node2 - * @param edgeLength - * @private - */ - exports._calculateSpringForce = function (node1, node2, edgeLength) { - var dx, dy, fx, fy, springForce, distance; - - dx = (node1.x - node2.x); - dy = (node1.y - node2.y); - distance = Math.sqrt(dx * dx + dy * dy); - if (distance == 0) { - distance = 0.01; - } + Hammer.gestures.Transform = { + name: name, + index: 45, + defaults: { + /** + * minimal scale factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1 + * @property transformMinScale + * @type {Number} + * @default 0.01 + */ + transformMinScale: 0.01, - // the 1/distance is so the fx and fy can be calculated without sine or cosine. - springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance; + /** + * rotation in degrees + * @property transformMinRotation + * @type {Number} + * @default 1 + */ + transformMinRotation: 1 + }, - fx = dx * springForce; - fy = dy * springForce; + handler: transformGesture + }; + })('transform'); - node1.fx += fx; - node1.fy += fy; - node2.fx -= fx; - node2.fy -= fy; - }; + /** + * @module hammer + */ + // AMD export + if(true) { + !(__WEBPACK_AMD_DEFINE_RESULT__ = function() { + return Hammer; + }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + // commonjs export + } else if(typeof module !== 'undefined' && module.exports) { + module.exports = Hammer; + // browser export + } else { + window.Hammer = Hammer; + } - exports._cleanupPhysicsConfiguration = function() { - if (this.physicsConfiguration !== undefined) { - while (this.physicsConfiguration.hasChildNodes()) { - this.physicsConfiguration.removeChild(this.physicsConfiguration.firstChild); - } + })(window); - this.physicsConfiguration.parentNode.removeChild(this.physicsConfiguration); - this.physicsConfiguration = undefined; - } - } +/***/ }, +/* 59 */ +/***/ function(module, exports, __webpack_require__) { + var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;"use strict"; /** - * Load the HTML for the physics config and bind it - * @private + * Created by Alex on 11/6/2014. */ - exports._loadPhysicsConfiguration = function () { - if (this.physicsConfiguration === undefined) { - this.backupConstants = {}; - util.deepExtend(this.backupConstants,this.constants); - - var hierarchicalLayoutDirections = ["LR", "RL", "UD", "DU"]; - this.physicsConfiguration = document.createElement('div'); - this.physicsConfiguration.className = "PhysicsConfiguration"; - this.physicsConfiguration.innerHTML = '' + - '' + - '' + - '' + - '' + - '' + - '' + - '
Simulation Mode:
Barnes HutRepulsionHierarchical
' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '
Options:
' - this.containerElement.parentElement.insertBefore(this.physicsConfiguration, this.containerElement); - this.optionsDiv = document.createElement("div"); - this.optionsDiv.style.fontSize = "14px"; - this.optionsDiv.style.fontFamily = "verdana"; - this.containerElement.parentElement.insertBefore(this.optionsDiv, this.containerElement); - - var rangeElement; - rangeElement = document.getElementById('graph_BH_gc'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_gc', -1, "physics_barnesHut_gravitationalConstant"); - rangeElement = document.getElementById('graph_BH_cg'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_cg', 1, "physics_centralGravity"); - rangeElement = document.getElementById('graph_BH_sc'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_sc', 1, "physics_springConstant"); - rangeElement = document.getElementById('graph_BH_sl'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_sl', 1, "physics_springLength"); - rangeElement = document.getElementById('graph_BH_damp'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_damp', 1, "physics_damping"); - rangeElement = document.getElementById('graph_R_nd'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_nd', 1, "physics_repulsion_nodeDistance"); - rangeElement = document.getElementById('graph_R_cg'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_cg', 1, "physics_centralGravity"); - rangeElement = document.getElementById('graph_R_sc'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_sc', 1, "physics_springConstant"); - rangeElement = document.getElementById('graph_R_sl'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_sl', 1, "physics_springLength"); - rangeElement = document.getElementById('graph_R_damp'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_damp', 1, "physics_damping"); + // https://github.com/umdjs/umd/blob/master/returnExports.js#L40-L60 + // if the module has no dependencies, the above pattern can be simplified to + (function (root, factory) { + if (true) { + // AMD. Register as an anonymous module. + !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + } else if (typeof exports === 'object') { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); + } else { + // Browser globals (root is window) + root.keycharm = factory(); + } + }(this, function () { - rangeElement = document.getElementById('graph_H_nd'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_nd', 1, "physics_hierarchicalRepulsion_nodeDistance"); - rangeElement = document.getElementById('graph_H_cg'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_cg', 1, "physics_centralGravity"); - rangeElement = document.getElementById('graph_H_sc'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_sc', 1, "physics_springConstant"); - rangeElement = document.getElementById('graph_H_sl'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_sl', 1, "physics_springLength"); - rangeElement = document.getElementById('graph_H_damp'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_damp', 1, "physics_damping"); - rangeElement = document.getElementById('graph_H_direction'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_direction', hierarchicalLayoutDirections, "hierarchicalLayout_direction"); - rangeElement = document.getElementById('graph_H_levsep'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_levsep', 1, "hierarchicalLayout_levelSeparation"); - rangeElement = document.getElementById('graph_H_nspac'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_nspac', 1, "hierarchicalLayout_nodeSpacing"); + function keycharm(options) { + var preventDefault = options && options.preventDefault || false; - var radioButton1 = document.getElementById("graph_physicsMethod1"); - var radioButton2 = document.getElementById("graph_physicsMethod2"); - var radioButton3 = document.getElementById("graph_physicsMethod3"); - radioButton2.checked = true; - if (this.constants.physics.barnesHut.enabled) { - radioButton1.checked = true; - } - if (this.constants.hierarchicalLayout.enabled) { - radioButton3.checked = true; - } + var container = options && options.container || window; - var graph_toggleSmooth = document.getElementById("graph_toggleSmooth"); - var graph_repositionNodes = document.getElementById("graph_repositionNodes"); - var graph_generateOptions = document.getElementById("graph_generateOptions"); + var _exportFunctions = {}; + var _bound = {keydown:{}, keyup:{}}; + var _keys = {}; + var i; - graph_toggleSmooth.onclick = graphToggleSmoothCurves.bind(this); - graph_repositionNodes.onclick = graphRepositionNodes.bind(this); - graph_generateOptions.onclick = graphGenerateOptions.bind(this); - if (this.constants.smoothCurves == true && this.constants.dynamicSmoothCurves == false) { - graph_toggleSmooth.style.background = "#A4FF56"; - } - else { - graph_toggleSmooth.style.background = "#FF8532"; - } + // a - z + for (i = 97; i <= 122; i++) {_keys[String.fromCharCode(i)] = {code:65 + (i - 97), shift: false};} + // A - Z + for (i = 65; i <= 90; i++) {_keys[String.fromCharCode(i)] = {code:i, shift: true};} + // 0 - 9 + for (i = 0; i <= 9; i++) {_keys['' + i] = {code:48 + i, shift: false};} + // F1 - F12 + for (i = 1; i <= 12; i++) {_keys['F' + i] = {code:111 + i, shift: false};} + // num0 - num9 + for (i = 0; i <= 9; i++) {_keys['num' + i] = {code:96 + i, shift: false};} + // numpad misc + _keys['num*'] = {code:106, shift: false}; + _keys['num+'] = {code:107, shift: false}; + _keys['num-'] = {code:109, shift: false}; + _keys['num/'] = {code:111, shift: false}; + _keys['num.'] = {code:110, shift: false}; + // arrows + _keys['left'] = {code:37, shift: false}; + _keys['up'] = {code:38, shift: false}; + _keys['right'] = {code:39, shift: false}; + _keys['down'] = {code:40, shift: false}; + // extra keys + _keys['space'] = {code:32, shift: false}; + _keys['enter'] = {code:13, shift: false}; + _keys['shift'] = {code:16, shift: undefined}; + _keys['esc'] = {code:27, shift: false}; + _keys['backspace'] = {code:8, shift: false}; + _keys['tab'] = {code:9, shift: false}; + _keys['ctrl'] = {code:17, shift: false}; + _keys['alt'] = {code:18, shift: false}; + _keys['delete'] = {code:46, shift: false}; + _keys['pageup'] = {code:33, shift: false}; + _keys['pagedown'] = {code:34, shift: false}; + // symbols + _keys['='] = {code:187, shift: false}; + _keys['-'] = {code:189, shift: false}; + _keys[']'] = {code:221, shift: false}; + _keys['['] = {code:219, shift: false}; - switchConfigurations.apply(this); - radioButton1.onchange = switchConfigurations.bind(this); - radioButton2.onchange = switchConfigurations.bind(this); - radioButton3.onchange = switchConfigurations.bind(this); - } - }; - /** - * This overwrites the this.constants. - * - * @param constantsVariableName - * @param value - * @private - */ - exports._overWriteGraphConstants = function (constantsVariableName, value) { - var nameArray = constantsVariableName.split("_"); - if (nameArray.length == 1) { - this.constants[nameArray[0]] = value; - } - else if (nameArray.length == 2) { - this.constants[nameArray[0]][nameArray[1]] = value; - } - else if (nameArray.length == 3) { - this.constants[nameArray[0]][nameArray[1]][nameArray[2]] = value; - } - }; + var down = function(event) {handleEvent(event,'keydown');}; + var up = function(event) {handleEvent(event,'keyup');}; + // handle the actualy bound key with the event + var handleEvent = function(event,type) { + if (_bound[type][event.keyCode] !== undefined) { + var bound = _bound[type][event.keyCode]; + for (var i = 0; i < bound.length; i++) { + if (bound[i].shift === undefined) { + bound[i].fn(event); + } + else if (bound[i].shift == true && event.shiftKey == true) { + bound[i].fn(event); + } + else if (bound[i].shift == false && event.shiftKey == false) { + bound[i].fn(event); + } + } - /** - * this function is bound to the toggle smooth curves button. That is also why it is not in the prototype. - */ - function graphToggleSmoothCurves () { - this.constants.smoothCurves.enabled = !this.constants.smoothCurves.enabled; - var graph_toggleSmooth = document.getElementById("graph_toggleSmooth"); - if (this.constants.smoothCurves.enabled == true) {graph_toggleSmooth.style.background = "#A4FF56";} - else {graph_toggleSmooth.style.background = "#FF8532";} + if (preventDefault == true) { + event.preventDefault(); + } + } + }; - this._configureSmoothCurves(false); - } + // bind a key to a callback + _exportFunctions.bind = function(key, callback, type) { + if (type === undefined) { + type = 'keydown'; + } + if (_keys[key] === undefined) { + throw new Error("unsupported key: " + key); + } + if (_bound[type][_keys[key].code] === undefined) { + _bound[type][_keys[key].code] = []; + } + _bound[type][_keys[key].code].push({fn:callback, shift:_keys[key].shift}); + }; - /** - * this function is used to scramble the nodes - * - */ - function graphRepositionNodes () { - for (var nodeId in this.calculationNodes) { - if (this.calculationNodes.hasOwnProperty(nodeId)) { - this.calculationNodes[nodeId].vx = 0; this.calculationNodes[nodeId].vy = 0; - this.calculationNodes[nodeId].fx = 0; this.calculationNodes[nodeId].fy = 0; - } - } - if (this.constants.hierarchicalLayout.enabled == true) { - this._setupHierarchicalLayout(); - showValueOfRange.call(this, 'graph_H_nd', 1, "physics_hierarchicalRepulsion_nodeDistance"); - showValueOfRange.call(this, 'graph_H_cg', 1, "physics_centralGravity"); - showValueOfRange.call(this, 'graph_H_sc', 1, "physics_springConstant"); - showValueOfRange.call(this, 'graph_H_sl', 1, "physics_springLength"); - showValueOfRange.call(this, 'graph_H_damp', 1, "physics_damping"); - } - else { - this.repositionNodes(); - } - this.moving = true; - this.start(); - } - /** - * this is used to generate an options file from the playing with physics system. - */ - function graphGenerateOptions () { - var options = "No options are required, default values used."; - var optionsSpecific = []; - var radioButton1 = document.getElementById("graph_physicsMethod1"); - var radioButton2 = document.getElementById("graph_physicsMethod2"); - if (radioButton1.checked == true) { - if (this.constants.physics.barnesHut.gravitationalConstant != this.backupConstants.physics.barnesHut.gravitationalConstant) {optionsSpecific.push("gravitationalConstant: " + this.constants.physics.barnesHut.gravitationalConstant);} - if (this.constants.physics.centralGravity != this.backupConstants.physics.barnesHut.centralGravity) {optionsSpecific.push("centralGravity: " + this.constants.physics.centralGravity);} - if (this.constants.physics.springLength != this.backupConstants.physics.barnesHut.springLength) {optionsSpecific.push("springLength: " + this.constants.physics.springLength);} - if (this.constants.physics.springConstant != this.backupConstants.physics.barnesHut.springConstant) {optionsSpecific.push("springConstant: " + this.constants.physics.springConstant);} - if (this.constants.physics.damping != this.backupConstants.physics.barnesHut.damping) {optionsSpecific.push("damping: " + this.constants.physics.damping);} - if (optionsSpecific.length != 0) { - options = "var options = {"; - options += "physics: {barnesHut: {"; - for (var i = 0; i < optionsSpecific.length; i++) { - options += optionsSpecific[i]; - if (i < optionsSpecific.length - 1) { - options += ", " - } + // bind all keys to a call back (demo purposes) + _exportFunctions.bindAll = function(callback, type) { + if (type === undefined) { + type = 'keydown'; } - options += '}}' - } - if (this.constants.smoothCurves.enabled != this.backupConstants.smoothCurves.enabled) { - if (optionsSpecific.length == 0) {options = "var options = {";} - else {options += ", "} - options += "smoothCurves: " + this.constants.smoothCurves.enabled; - } - if (options != "No options are required, default values used.") { - options += '};' - } - } - else if (radioButton2.checked == true) { - options = "var options = {"; - options += "physics: {barnesHut: {enabled: false}"; - if (this.constants.physics.repulsion.nodeDistance != this.backupConstants.physics.repulsion.nodeDistance) {optionsSpecific.push("nodeDistance: " + this.constants.physics.repulsion.nodeDistance);} - if (this.constants.physics.centralGravity != this.backupConstants.physics.repulsion.centralGravity) {optionsSpecific.push("centralGravity: " + this.constants.physics.centralGravity);} - if (this.constants.physics.springLength != this.backupConstants.physics.repulsion.springLength) {optionsSpecific.push("springLength: " + this.constants.physics.springLength);} - if (this.constants.physics.springConstant != this.backupConstants.physics.repulsion.springConstant) {optionsSpecific.push("springConstant: " + this.constants.physics.springConstant);} - if (this.constants.physics.damping != this.backupConstants.physics.repulsion.damping) {optionsSpecific.push("damping: " + this.constants.physics.damping);} - if (optionsSpecific.length != 0) { - options += ", repulsion: {"; - for (var i = 0; i < optionsSpecific.length; i++) { - options += optionsSpecific[i]; - if (i < optionsSpecific.length - 1) { - options += ", " + for (var key in _keys) { + if (_keys.hasOwnProperty(key)) { + _exportFunctions.bind(key,callback,type); } } - options += '}}' - } - if (optionsSpecific.length == 0) {options += "}"} - if (this.constants.smoothCurves != this.backupConstants.smoothCurves) { - options += ", smoothCurves: " + this.constants.smoothCurves; - } - options += '};' - } - else { - options = "var options = {"; - if (this.constants.physics.hierarchicalRepulsion.nodeDistance != this.backupConstants.physics.hierarchicalRepulsion.nodeDistance) {optionsSpecific.push("nodeDistance: " + this.constants.physics.hierarchicalRepulsion.nodeDistance);} - if (this.constants.physics.centralGravity != this.backupConstants.physics.hierarchicalRepulsion.centralGravity) {optionsSpecific.push("centralGravity: " + this.constants.physics.centralGravity);} - if (this.constants.physics.springLength != this.backupConstants.physics.hierarchicalRepulsion.springLength) {optionsSpecific.push("springLength: " + this.constants.physics.springLength);} - if (this.constants.physics.springConstant != this.backupConstants.physics.hierarchicalRepulsion.springConstant) {optionsSpecific.push("springConstant: " + this.constants.physics.springConstant);} - if (this.constants.physics.damping != this.backupConstants.physics.hierarchicalRepulsion.damping) {optionsSpecific.push("damping: " + this.constants.physics.damping);} - if (optionsSpecific.length != 0) { - options += "physics: {hierarchicalRepulsion: {"; - for (var i = 0; i < optionsSpecific.length; i++) { - options += optionsSpecific[i]; - if (i < optionsSpecific.length - 1) { - options += ", "; + }; + + // get the key label from an event + _exportFunctions.getKey = function(event) { + for (var key in _keys) { + if (_keys.hasOwnProperty(key)) { + if (event.shiftKey == true && _keys[key].shift == true && event.keyCode == _keys[key].code) { + return key; + } + else if (event.shiftKey == false && _keys[key].shift == false && event.keyCode == _keys[key].code) { + return key; + } + else if (event.keyCode == _keys[key].code && key == 'shift') { + return key; + } } } - options += '}},'; - } - options += 'hierarchicalLayout: {'; - optionsSpecific = []; - if (this.constants.hierarchicalLayout.direction != this.backupConstants.hierarchicalLayout.direction) {optionsSpecific.push("direction: " + this.constants.hierarchicalLayout.direction);} - if (Math.abs(this.constants.hierarchicalLayout.levelSeparation) != this.backupConstants.hierarchicalLayout.levelSeparation) {optionsSpecific.push("levelSeparation: " + this.constants.hierarchicalLayout.levelSeparation);} - if (this.constants.hierarchicalLayout.nodeSpacing != this.backupConstants.hierarchicalLayout.nodeSpacing) {optionsSpecific.push("nodeSpacing: " + this.constants.hierarchicalLayout.nodeSpacing);} - if (optionsSpecific.length != 0) { - for (var i = 0; i < optionsSpecific.length; i++) { - options += optionsSpecific[i]; - if (i < optionsSpecific.length - 1) { - options += ", " + return "unknown key, currently not supported"; + }; + + // unbind either a specific callback from a key or all of them (by leaving callback undefined) + _exportFunctions.unbind = function(key, callback, type) { + if (type === undefined) { + type = 'keydown'; + } + if (_keys[key] === undefined) { + throw new Error("unsupported key: " + key); + } + if (callback !== undefined) { + var newBindings = []; + var bound = _bound[type][_keys[key].code]; + if (bound !== undefined) { + for (var i = 0; i < bound.length; i++) { + if (!(bound[i].fn == callback && bound[i].shift == _keys[key].shift)) { + newBindings.push(_bound[type][_keys[key].code][i]); + } + } } + _bound[type][_keys[key].code] = newBindings; } - options += '}' - } - else { - options += "enabled:true}"; - } - options += '};' + else { + _bound[type][_keys[key].code] = []; + } + }; + + // reset all bound variables. + _exportFunctions.reset = function() { + _bound = {keydown:{}, keyup:{}}; + }; + + // unbind all listeners and reset all variables. + _exportFunctions.destroy = function() { + _bound = {keydown:{}, keyup:{}}; + container.removeEventListener('keydown', down, true); + container.removeEventListener('keyup', up, true); + }; + + // create listeners. + container.addEventListener('keydown',down,true); + container.addEventListener('keyup',up,true); + + // return the public functions. + return _exportFunctions; } + return keycharm; + })); - this.optionsDiv.innerHTML = options; - } + + + +/***/ }, +/* 60 */ +/***/ function(module, exports, __webpack_require__) { /** - * this is used to switch between barnesHut, repulsion and hierarchical. + * Creation of the ClusterMixin var. * + * This contains all the functions the Network object can use to employ clustering */ - function switchConfigurations () { - var ids = ["graph_BH_table", "graph_R_table", "graph_H_table"]; - var radioButton = document.querySelector('input[name="graph_physicsMethod"]:checked').value; - var tableId = "graph_" + radioButton + "_table"; - var table = document.getElementById(tableId); - table.style.display = "block"; - for (var i = 0; i < ids.length; i++) { - if (ids[i] != tableId) { - table = document.getElementById(ids[i]); - table.style.display = "none"; + + /** + * This is only called in the constructor of the network object + * + */ + exports.startWithClustering = function() { + // cluster if the data set is big + this.clusterToFit(this.constants.clustering.initialMaxNodes, true); + + // updates the lables after clustering + this.updateLabels(); + + // this is called here because if clusterin is disabled, the start and stabilize are called in + // the setData function. + if (this.stabilize) { + this._stabilize(); + } + this.start(); + }; + + /** + * This function clusters until the initialMaxNodes has been reached + * + * @param {Number} maxNumberOfNodes + * @param {Boolean} reposition + */ + exports.clusterToFit = function(maxNumberOfNodes, reposition) { + var numberOfNodes = this.nodeIndices.length; + + var maxLevels = 50; + var level = 0; + + // we first cluster the hubs, then we pull in the outliers, repeat + while (numberOfNodes > maxNumberOfNodes && level < maxLevels) { + if (level % 3 == 0) { + this.forceAggregateHubs(true); + this.normalizeClusterLevels(); } - } - this._restoreNodes(); - if (radioButton == "R") { - this.constants.hierarchicalLayout.enabled = false; - this.constants.physics.hierarchicalRepulsion.enabled = false; - this.constants.physics.barnesHut.enabled = false; - } - else if (radioButton == "H") { - if (this.constants.hierarchicalLayout.enabled == false) { - this.constants.hierarchicalLayout.enabled = true; - this.constants.physics.hierarchicalRepulsion.enabled = true; - this.constants.physics.barnesHut.enabled = false; - this.constants.smoothCurves.enabled = false; - this._setupHierarchicalLayout(); + else { + this.increaseClusterLevel(); // this also includes a cluster normalization } + + numberOfNodes = this.nodeIndices.length; + level += 1; } - else { - this.constants.hierarchicalLayout.enabled = false; - this.constants.physics.hierarchicalRepulsion.enabled = false; - this.constants.physics.barnesHut.enabled = true; - } - this._loadSelectedForceSolver(); - var graph_toggleSmooth = document.getElementById("graph_toggleSmooth"); - if (this.constants.smoothCurves.enabled == true) {graph_toggleSmooth.style.background = "#A4FF56";} - else {graph_toggleSmooth.style.background = "#FF8532";} - this.moving = true; - this.start(); - } + // after the clustering we reposition the nodes to reduce the initial chaos + if (level > 0 && reposition == true) { + this.repositionNodes(); + } + this._updateCalculationNodes(); + }; /** - * this generates the ranges depending on the iniital values. + * This function can be called to open up a specific cluster. It is only called by + * It will unpack the cluster back one level. * - * @param id - * @param map - * @param constantsVariableName + * @param node | Node object: cluster to open. */ - function showValueOfRange (id,map,constantsVariableName) { - var valueId = id + "_value"; - var rangeValue = document.getElementById(id).value; + exports.openCluster = function(node) { + var isMovingBeforeClustering = this.moving; + if (node.clusterSize > this.constants.clustering.sectorThreshold && this._nodeInActiveArea(node) && + !(this._sector() == "default" && this.nodeIndices.length == 1)) { + // this loads a new sector, loads the nodes and edges and nodeIndices of it. + this._addSector(node); + var level = 0; + + // we decluster until we reach a decent number of nodes + while ((this.nodeIndices.length < this.constants.clustering.initialMaxNodes) && (level < 10)) { + this.decreaseClusterLevel(); + level += 1; + } - if (Array.isArray(map)) { - document.getElementById(valueId).value = map[parseInt(rangeValue)]; - this._overWriteGraphConstants(constantsVariableName,map[parseInt(rangeValue)]); } else { - document.getElementById(valueId).value = parseInt(map) * parseFloat(rangeValue); - this._overWriteGraphConstants(constantsVariableName, parseInt(map) * parseFloat(rangeValue)); + this._expandClusterNode(node,false,true); + + // update the index list, dynamic edges and labels + this._updateNodeIndexList(); + this._updateDynamicEdges(); + this._updateCalculationNodes(); + this.updateLabels(); } - if (constantsVariableName == "hierarchicalLayout_direction" || - constantsVariableName == "hierarchicalLayout_levelSeparation" || - constantsVariableName == "hierarchicalLayout_nodeSpacing") { - this._setupHierarchicalLayout(); + // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded + if (this.moving != isMovingBeforeClustering) { + this.start(); } - this.moving = true; - this.start(); - } + }; + /** + * This calls the updateClustes with default arguments + */ + exports.updateClustersDefault = function() { + if (this.constants.clustering.enabled == true) { + this.updateClusters(0,false,false); + } + }; -/***/ }, -/* 61 */ -/***/ function(module, exports, __webpack_require__) { + /** + * This function can be called to increase the cluster level. This means that the nodes with only one edge connection will + * be clustered with their connected node. This can be repeated as many times as needed. + * This can be called externally (by a keybind for instance) to reduce the complexity of big datasets. + */ + exports.increaseClusterLevel = function() { + this.updateClusters(-1,false,true); + }; + /** - * Calculate the forces the nodes apply on each other based on a repulsion field. - * This field is linearly approximated. - * - * @private + * This function can be called to decrease the cluster level. This means that the nodes with only one edge connection will + * be unpacked if they are a cluster. This can be repeated as many times as needed. + * This can be called externally (by a key-bind for instance) to look into clusters without zooming. */ - exports._calculateNodeForces = function () { - var dx, dy, angle, distance, fx, fy, combinedClusterSize, - repulsingForce, node1, node2, i, j; + exports.decreaseClusterLevel = function() { + this.updateClusters(1,false,true); + }; - var nodes = this.calculationNodes; - var nodeIndices = this.calculationNodeIndices; - // approximation constants - var a_base = -2 / 3; - var b = 4 / 3; + /** + * This is the main clustering function. It clusters and declusters on zoom or forced + * This function clusters on zoom, it can be called with a predefined zoom direction + * If out, check if we can form clusters, if in, check if we can open clusters. + * This function is only called from _zoom() + * + * @param {Number} zoomDirection | -1 / 0 / +1 for zoomOut / determineByZoom / zoomIn + * @param {Boolean} recursive | enabled or disable recursive calling of the opening of clusters + * @param {Boolean} force | enabled or disable forcing + * @param {Boolean} doNotStart | if true do not call start + * + */ + exports.updateClusters = function(zoomDirection,recursive,force,doNotStart) { + var isMovingBeforeClustering = this.moving; + var amountOfNodes = this.nodeIndices.length; - // repulsing forces between nodes - var nodeDistance = this.constants.physics.repulsion.nodeDistance; - var minimumDistance = nodeDistance; + // on zoom out collapse the sector if the scale is at the level the sector was made + if (this.previousScale > this.scale && zoomDirection == 0) { + this._collapseSector(); + } - // we loop from i over all but the last entree in the array - // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j - for (i = 0; i < nodeIndices.length - 1; i++) { - node1 = nodes[nodeIndices[i]]; - for (j = i + 1; j < nodeIndices.length; j++) { - node2 = nodes[nodeIndices[j]]; - combinedClusterSize = node1.clusterSize + node2.clusterSize - 2; + // check if we zoom in or out + if (this.previousScale > this.scale || zoomDirection == -1) { // zoom out + // forming clusters when forced pulls outliers in. When not forced, the edge length of the + // outer nodes determines if it is being clustered + this._formClusters(force); + } + else if (this.previousScale < this.scale || zoomDirection == 1) { // zoom in + if (force == true) { + // _openClusters checks for each node if the formationScale of the cluster is smaller than + // the current scale and if so, declusters. When forced, all clusters are reduced by one step + this._openClusters(recursive,force); + } + else { + // if a cluster takes up a set percentage of the active window + this._openClustersBySize(); + } + } + this._updateNodeIndexList(); - dx = node2.x - node1.x; - dy = node2.y - node1.y; - distance = Math.sqrt(dx * dx + dy * dy); + // if a cluster was NOT formed and the user zoomed out, we try clustering by hubs + if (this.nodeIndices.length == amountOfNodes && (this.previousScale > this.scale || zoomDirection == -1)) { + this._aggregateHubs(force); + this._updateNodeIndexList(); + } - // same condition as BarnesHut, making sure nodes are never 100% overlapping. - if (distance == 0) { - distance = 0.1*Math.random(); - dx = distance; - } + // we now reduce chains. + if (this.previousScale > this.scale || zoomDirection == -1) { // zoom out + this.handleChains(); + this._updateNodeIndexList(); + } - minimumDistance = (combinedClusterSize == 0) ? nodeDistance : (nodeDistance * (1 + combinedClusterSize * this.constants.clustering.distanceAmplification)); - var a = a_base / minimumDistance; - if (distance < 2 * minimumDistance) { - if (distance < 0.5 * minimumDistance) { - repulsingForce = 1.0; - } - else { - repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)) - } + this.previousScale = this.scale; - // amplify the repulsion for clusters. - repulsingForce *= (combinedClusterSize == 0) ? 1 : 1 + combinedClusterSize * this.constants.clustering.forceAmplification; - repulsingForce = repulsingForce / Math.max(distance,0.01*minimumDistance); + // rest of the update the index list, dynamic edges and labels + this._updateDynamicEdges(); + this.updateLabels(); - fx = dx * repulsingForce; - fy = dy * repulsingForce; - node1.fx -= fx; - node1.fy -= fy; - node2.fx += fx; - node2.fy += fy; + // if a cluster was formed, we increase the clusterSession + if (this.nodeIndices.length < amountOfNodes) { // this means a clustering operation has taken place + this.clusterSession += 1; + // if clusters have been made, we normalize the cluster level + this.normalizeClusterLevels(); + } - } + if (doNotStart == false || doNotStart === undefined) { + // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded + if (this.moving != isMovingBeforeClustering) { + this.start(); } } + + this._updateCalculationNodes(); }; + /** + * This function handles the chains. It is called on every updateClusters(). + */ + exports.handleChains = function() { + // after clustering we check how many chains there are + var chainPercentage = this._getChainFraction(); + if (chainPercentage > this.constants.clustering.chainThreshold) { + this._reduceAmountOfChains(1 - this.constants.clustering.chainThreshold / chainPercentage) -/***/ }, -/* 62 */ -/***/ function(module, exports, __webpack_require__) { + } + }; /** - * Calculate the forces the nodes apply on eachother based on a repulsion field. - * This field is linearly approximated. + * this functions starts clustering by hubs + * The minimum hub threshold is set globally * * @private */ - exports._calculateNodeForces = function () { - var dx, dy, distance, fx, fy, - repulsingForce, node1, node2, i, j; + exports._aggregateHubs = function(force) { + this._getHubSize(); + this._formClustersByHub(force,false); + }; - var nodes = this.calculationNodes; - var nodeIndices = this.calculationNodeIndices; - // repulsing forces between nodes - var nodeDistance = this.constants.physics.hierarchicalRepulsion.nodeDistance; + /** + * This function is fired by keypress. It forces hubs to form. + * + */ + exports.forceAggregateHubs = function(doNotStart) { + var isMovingBeforeClustering = this.moving; + var amountOfNodes = this.nodeIndices.length; - // we loop from i over all but the last entree in the array - // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j - for (i = 0; i < nodeIndices.length - 1; i++) { - node1 = nodes[nodeIndices[i]]; - for (j = i + 1; j < nodeIndices.length; j++) { - node2 = nodes[nodeIndices[j]]; + this._aggregateHubs(true); - // nodes only affect nodes on their level - if (node1.level == node2.level) { + // update the index list, dynamic edges and labels + this._updateNodeIndexList(); + this._updateDynamicEdges(); + this.updateLabels(); - dx = node2.x - node1.x; - dy = node2.y - node1.y; - distance = Math.sqrt(dx * dx + dy * dy); + // if a cluster was formed, we increase the clusterSession + if (this.nodeIndices.length != amountOfNodes) { + this.clusterSession += 1; + } + if (doNotStart == false || doNotStart === undefined) { + // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded + if (this.moving != isMovingBeforeClustering) { + this.start(); + } + } + }; - var steepness = 0.05; - if (distance < nodeDistance) { - repulsingForce = -Math.pow(steepness*distance,2) + Math.pow(steepness*nodeDistance,2); - } - else { - repulsingForce = 0; + /** + * If a cluster takes up more than a set percentage of the screen, open the cluster + * + * @private + */ + exports._openClustersBySize = function() { + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + var node = this.nodes[nodeId]; + if (node.inView() == true) { + if ((node.width*this.scale > this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientWidth) || + (node.height*this.scale > this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientHeight)) { + this.openCluster(node); } - // normalize force with - if (distance == 0) { - distance = 0.01; - } - else { - repulsingForce = repulsingForce / distance; - } - fx = dx * repulsingForce; - fy = dy * repulsingForce; - - node1.fx -= fx; - node1.fy -= fy; - node2.fx += fx; - node2.fy += fy; } } } @@ -30158,191 +29823,217 @@ return /******/ (function(modules) { // webpackBootstrap /** - * this function calculates the effects of the springs in the case of unsmooth curves. + * This function loops over all nodes in the nodeIndices list. For each node it checks if it is a cluster and if it + * has to be opened based on the current zoom level. * * @private */ - exports._calculateHierarchicalSpringForces = function () { - var edgeLength, edge, edgeId; - var dx, dy, fx, fy, springForce, distance; - var edges = this.edges; + exports._openClusters = function(recursive,force) { + for (var i = 0; i < this.nodeIndices.length; i++) { + var node = this.nodes[this.nodeIndices[i]]; + this._expandClusterNode(node,recursive,force); + this._updateCalculationNodes(); + } + }; - var nodes = this.calculationNodes; - var nodeIndices = this.calculationNodeIndices; + /** + * This function checks if a node has to be opened. This is done by checking the zoom level. + * If the node contains child nodes, this function is recursively called on the child nodes as well. + * This recursive behaviour is optional and can be set by the recursive argument. + * + * @param {Node} parentNode | to check for cluster and expand + * @param {Boolean} recursive | enabled or disable recursive calling + * @param {Boolean} force | enabled or disable forcing + * @param {Boolean} [openAll] | This will recursively force all nodes in the parent to be released + * @private + */ + exports._expandClusterNode = function(parentNode, recursive, force, openAll) { + // first check if node is a cluster + if (parentNode.clusterSize > 1) { + // this means that on a double tap event or a zoom event, the cluster fully unpacks if it is smaller than 20 + if (parentNode.clusterSize < this.constants.clustering.sectorThreshold) { + openAll = true; + } + recursive = openAll ? true : recursive; + // if the last child has been added on a smaller scale than current scale decluster + if (parentNode.formationScale < this.scale || force == true) { + // we will check if any of the contained child nodes should be removed from the cluster + for (var containedNodeId in parentNode.containedNodes) { + if (parentNode.containedNodes.hasOwnProperty(containedNodeId)) { + var childNode = parentNode.containedNodes[containedNodeId]; - for (var i = 0; i < nodeIndices.length; i++) { - var node1 = nodes[nodeIndices[i]]; - node1.springFx = 0; - node1.springFy = 0; + // force expand will expand the largest cluster size clusters. Since we cluster from outside in, we assume that + // the largest cluster is the one that comes from outside + if (force == true) { + if (childNode.clusterSession == parentNode.clusterSessions[parentNode.clusterSessions.length-1] + || openAll) { + this._expelChildFromParent(parentNode,containedNodeId,recursive,force,openAll); + } + } + else { + if (this._nodeInActiveArea(parentNode)) { + this._expelChildFromParent(parentNode,containedNodeId,recursive,force,openAll); + } + } + } + } + } } + }; + /** + * ONLY CALLED FROM _expandClusterNode + * + * This function will expel a child_node from a parent_node. This is to de-cluster the node. This function will remove + * the child node from the parent contained_node object and put it back into the global nodes object. + * The same holds for the edge that was connected to the child node. It is moved back into the global edges object. + * + * @param {Node} parentNode | the parent node + * @param {String} containedNodeId | child_node id as it is contained in the containedNodes object of the parent node + * @param {Boolean} recursive | This will also check if the child needs to be expanded. + * With force and recursive both true, the entire cluster is unpacked + * @param {Boolean} force | This will disregard the zoom level and will expel this child from the parent + * @param {Boolean} openAll | This will recursively force all nodes in the parent to be released + * @private + */ + exports._expelChildFromParent = function(parentNode, containedNodeId, recursive, force, openAll) { + var childNode = parentNode.containedNodes[containedNodeId]; - // forces caused by the edges, modelled as springs - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.connected) { - // only calculate forces if nodes are in the same sector - if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { - edgeLength = edge.physics.springLength; - // this implies that the edges between big clusters are longer - edgeLength += (edge.to.clusterSize + edge.from.clusterSize - 2) * this.constants.clustering.edgeGrowth; - - dx = (edge.from.x - edge.to.x); - dy = (edge.from.y - edge.to.y); - distance = Math.sqrt(dx * dx + dy * dy); + // if child node has been added on smaller scale than current, kick out + if (childNode.formationScale < this.scale || force == true) { + // unselect all selected items + this._unselectAll(); - if (distance == 0) { - distance = 0.01; - } + // put the child node back in the global nodes object + this.nodes[containedNodeId] = childNode; - // the 1/distance is so the fx and fy can be calculated without sine or cosine. - springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance; + // release the contained edges from this childNode back into the global edges + this._releaseContainedEdges(parentNode,childNode); - fx = dx * springForce; - fy = dy * springForce; + // reconnect rerouted edges to the childNode + this._connectEdgeBackToChild(parentNode,childNode); + // validate all edges in dynamicEdges + this._validateEdges(parentNode); + // undo the changes from the clustering operation on the parent node + parentNode.options.mass -= childNode.options.mass; + parentNode.clusterSize -= childNode.clusterSize; + parentNode.options.fontSize = Math.min(this.constants.clustering.maxFontSize, this.constants.nodes.fontSize + this.constants.clustering.fontSizeMultiplier*(parentNode.clusterSize-1)); + parentNode.dynamicEdgesLength = parentNode.dynamicEdges.length; - if (edge.to.level != edge.from.level) { - edge.to.springFx -= fx; - edge.to.springFy -= fy; - edge.from.springFx += fx; - edge.from.springFy += fy; - } - else { - var factor = 0.5; - edge.to.fx -= factor*fx; - edge.to.fy -= factor*fy; - edge.from.fx += factor*fx; - edge.from.fy += factor*fy; - } + // place the child node near the parent, not at the exact same location to avoid chaos in the system + childNode.x = parentNode.x + parentNode.growthIndicator * (0.5 - Math.random()); + childNode.y = parentNode.y + parentNode.growthIndicator * (0.5 - Math.random()); + + // remove node from the list + delete parentNode.containedNodes[containedNodeId]; + + // check if there are other childs with this clusterSession in the parent. + var othersPresent = false; + for (var childNodeId in parentNode.containedNodes) { + if (parentNode.containedNodes.hasOwnProperty(childNodeId)) { + if (parentNode.containedNodes[childNodeId].clusterSession == childNode.clusterSession) { + othersPresent = true; + break; } } } - } + // if there are no others, remove the cluster session from the list + if (othersPresent == false) { + parentNode.clusterSessions.pop(); + } - // normalize spring forces - var springForce = 1; - var springFx, springFy; - for (i = 0; i < nodeIndices.length; i++) { - var node = nodes[nodeIndices[i]]; - springFx = Math.min(springForce,Math.max(-springForce,node.springFx)); - springFy = Math.min(springForce,Math.max(-springForce,node.springFy)); + this._repositionBezierNodes(childNode); + // this._repositionBezierNodes(parentNode); - node.fx += springFx; - node.fy += springFy; - } + // remove the clusterSession from the child node + childNode.clusterSession = 0; - // retain energy balance - var totalFx = 0; - var totalFy = 0; - for (i = 0; i < nodeIndices.length; i++) { - var node = nodes[nodeIndices[i]]; - totalFx += node.fx; - totalFy += node.fy; - } - var correctionFx = totalFx / nodeIndices.length; - var correctionFy = totalFy / nodeIndices.length; + // recalculate the size of the node on the next time the node is rendered + parentNode.clearSizeCache(); - for (i = 0; i < nodeIndices.length; i++) { - var node = nodes[nodeIndices[i]]; - node.fx -= correctionFx; - node.fy -= correctionFy; + // restart the simulation to reorganise all nodes + this.moving = true; } + // check if a further expansion step is possible if recursivity is enabled + if (recursive == true) { + this._expandClusterNode(childNode,recursive,force,openAll); + } }; -/***/ }, -/* 63 */ -/***/ function(module, exports, __webpack_require__) { /** - * This function calculates the forces the nodes apply on eachother based on a gravitational model. - * The Barnes Hut method is used to speed up this N-body simulation. + * position the bezier nodes at the center of the edges * + * @param node * @private */ - exports._calculateNodeForces = function() { - if (this.constants.physics.barnesHut.gravitationalConstant != 0) { - var node; - var nodes = this.calculationNodes; - var nodeIndices = this.calculationNodeIndices; - var nodeCount = nodeIndices.length; - - this._formBarnesHutTree(nodes,nodeIndices); + exports._repositionBezierNodes = function(node) { + for (var i = 0; i < node.dynamicEdges.length; i++) { + node.dynamicEdges[i].positionBezierNode(); + } + }; - var barnesHutTree = this.barnesHutTree; - // place the nodes one by one recursively - for (var i = 0; i < nodeCount; i++) { - node = nodes[nodeIndices[i]]; - if (node.options.mass > 0) { - // starting with root is irrelevant, it never passes the BarnesHut condition - this._getForceContribution(barnesHutTree.root.children.NW,node); - this._getForceContribution(barnesHutTree.root.children.NE,node); - this._getForceContribution(barnesHutTree.root.children.SW,node); - this._getForceContribution(barnesHutTree.root.children.SE,node); - } - } + /** + * This function checks if any nodes at the end of their trees have edges below a threshold length + * This function is called only from updateClusters() + * forceLevelCollapse ignores the length of the edge and collapses one level + * This means that a node with only one edge will be clustered with its connected node + * + * @private + * @param {Boolean} force + */ + exports._formClusters = function(force) { + if (force == false) { + this._formClustersByZoom(); + } + else { + this._forceClustersByZoom(); } }; /** - * This function traverses the barnesHutTree. It checks when it can approximate distant nodes with their center of mass. - * If a region contains a single node, we check if it is not itself, then we apply the force. + * This function handles the clustering by zooming out, this is based on a minimum edge distance * - * @param parentBranch - * @param node * @private */ - exports._getForceContribution = function(parentBranch,node) { - // we get no force contribution from an empty region - if (parentBranch.childrenCount > 0) { - var dx,dy,distance; + exports._formClustersByZoom = function() { + var dx,dy,length, + minLength = this.constants.clustering.clusterEdgeThreshold/this.scale; - // get the distance from the center of mass to the node. - dx = parentBranch.centerOfMass.x - node.x; - dy = parentBranch.centerOfMass.y - node.y; - distance = Math.sqrt(dx * dx + dy * dy); + // check if any edges are shorter than minLength and start the clustering + // the clustering favours the node with the larger mass + for (var edgeId in this.edges) { + if (this.edges.hasOwnProperty(edgeId)) { + var edge = this.edges[edgeId]; + if (edge.connected) { + if (edge.toId != edge.fromId) { + dx = (edge.to.x - edge.from.x); + dy = (edge.to.y - edge.from.y); + length = Math.sqrt(dx * dx + dy * dy); - // BarnesHut condition - // original condition : s/d < thetaInverted = passed === d/s > 1/theta = passed - // calcSize = 1/s --> d * 1/s > 1/theta = passed - if (distance * parentBranch.calcSize > this.constants.physics.barnesHut.thetaInverted) { - // duplicate code to reduce function calls to speed up program - if (distance == 0) { - distance = 0.1*Math.random(); - dx = distance; - } - var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.options.mass / (distance * distance * distance); - var fx = dx * gravityForce; - var fy = dy * gravityForce; - node.fx += fx; - node.fy += fy; - } - else { - // Did not pass the condition, go into children if available - if (parentBranch.childrenCount == 4) { - this._getForceContribution(parentBranch.children.NW,node); - this._getForceContribution(parentBranch.children.NE,node); - this._getForceContribution(parentBranch.children.SW,node); - this._getForceContribution(parentBranch.children.SE,node); - } - else { // parentBranch must have only one node, if it was empty we wouldnt be here - if (parentBranch.children.data.id != node.id) { // if it is not self - // duplicate code to reduce function calls to speed up program - if (distance == 0) { - distance = 0.5*Math.random(); - dx = distance; + + if (length < minLength) { + // first check which node is larger + var parentNode = edge.from; + var childNode = edge.to; + if (edge.to.options.mass > edge.from.options.mass) { + parentNode = edge.to; + childNode = edge.from; + } + + if (childNode.dynamicEdgesLength == 1) { + this._addToCluster(parentNode,childNode,false); + } + else if (parentNode.dynamicEdgesLength == 1) { + this._addToCluster(childNode,parentNode,false); + } } - var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.options.mass / (distance * distance * distance); - var fx = dx * gravityForce; - var fy = dy * gravityForce; - node.fx += fx; - node.fy += fy; } } } @@ -30350,3605 +30041,4015 @@ return /******/ (function(modules) { // webpackBootstrap }; /** - * This function constructs the barnesHut tree recursively. It creates the root, splits it and starts placing the nodes. + * This function forces the network to cluster all nodes with only one connecting edge to their + * connected node. * - * @param nodes - * @param nodeIndices * @private */ - exports._formBarnesHutTree = function(nodes,nodeIndices) { - var node; - var nodeCount = nodeIndices.length; + exports._forceClustersByZoom = function() { + for (var nodeId in this.nodes) { + // another node could have absorbed this child. + if (this.nodes.hasOwnProperty(nodeId)) { + var childNode = this.nodes[nodeId]; - var minX = Number.MAX_VALUE, - minY = Number.MAX_VALUE, - maxX =-Number.MAX_VALUE, - maxY =-Number.MAX_VALUE; + // the edges can be swallowed by another decrease + if (childNode.dynamicEdgesLength == 1 && childNode.dynamicEdges.length != 0) { + var edge = childNode.dynamicEdges[0]; + var parentNode = (edge.toId == childNode.id) ? this.nodes[edge.fromId] : this.nodes[edge.toId]; - // get the range of the nodes - for (var i = 0; i < nodeCount; i++) { - var x = nodes[nodeIndices[i]].x; - var y = nodes[nodeIndices[i]].y; - if (nodes[nodeIndices[i]].options.mass > 0) { - if (x < minX) { minX = x; } - if (x > maxX) { maxX = x; } - if (y < minY) { minY = y; } - if (y > maxY) { maxY = y; } + // group to the largest node + if (childNode.id != parentNode.id) { + if (parentNode.options.mass > childNode.options.mass) { + this._addToCluster(parentNode,childNode,true); + } + else { + this._addToCluster(childNode,parentNode,true); + } + } + } } } - // make the range a square - var sizeDiff = Math.abs(maxX - minX) - Math.abs(maxY - minY); // difference between X and Y - if (sizeDiff > 0) {minY -= 0.5 * sizeDiff; maxY += 0.5 * sizeDiff;} // xSize > ySize - else {minX += 0.5 * sizeDiff; maxX -= 0.5 * sizeDiff;} // xSize < ySize + }; - var minimumTreeSize = 1e-5; - var rootSize = Math.max(minimumTreeSize,Math.abs(maxX - minX)); - var halfRootSize = 0.5 * rootSize; - var centerX = 0.5 * (minX + maxX), centerY = 0.5 * (minY + maxY); + /** + * To keep the nodes of roughly equal size we normalize the cluster levels. + * This function clusters a node to its smallest connected neighbour. + * + * @param node + * @private + */ + exports._clusterToSmallestNeighbour = function(node) { + var smallestNeighbour = -1; + var smallestNeighbourNode = null; + for (var i = 0; i < node.dynamicEdges.length; i++) { + if (node.dynamicEdges[i] !== undefined) { + var neighbour = null; + if (node.dynamicEdges[i].fromId != node.id) { + neighbour = node.dynamicEdges[i].from; + } + else if (node.dynamicEdges[i].toId != node.id) { + neighbour = node.dynamicEdges[i].to; + } - // construct the barnesHutTree - var barnesHutTree = { - root:{ - centerOfMass: {x:0, y:0}, - mass:0, - range: { - minX: centerX-halfRootSize,maxX:centerX+halfRootSize, - minY: centerY-halfRootSize,maxY:centerY+halfRootSize - }, - size: rootSize, - calcSize: 1 / rootSize, - children: { data:null}, - maxWidth: 0, - level: 0, - childrenCount: 4 - } - }; - this._splitBranch(barnesHutTree.root); - // place the nodes one by one recursively - for (i = 0; i < nodeCount; i++) { - node = nodes[nodeIndices[i]]; - if (node.options.mass > 0) { - this._placeInTree(barnesHutTree.root,node); + if (neighbour != null && smallestNeighbour > neighbour.clusterSessions.length) { + smallestNeighbour = neighbour.clusterSessions.length; + smallestNeighbourNode = neighbour; + } } } - // make global - this.barnesHutTree = barnesHutTree + if (neighbour != null && this.nodes[neighbour.id] !== undefined) { + this._addToCluster(neighbour, node, true); + } }; /** - * this updates the mass of a branch. this is increased by adding a node. + * This function forms clusters from hubs, it loops over all nodes * - * @param parentBranch - * @param node + * @param {Boolean} force | Disregard zoom level + * @param {Boolean} onlyEqual | This only clusters a hub with a specific number of edges * @private */ - exports._updateBranchMass = function(parentBranch, node) { - var totalMass = parentBranch.mass + node.options.mass; - var totalMassInv = 1/totalMass; - - parentBranch.centerOfMass.x = parentBranch.centerOfMass.x * parentBranch.mass + node.x * node.options.mass; - parentBranch.centerOfMass.x *= totalMassInv; - - parentBranch.centerOfMass.y = parentBranch.centerOfMass.y * parentBranch.mass + node.y * node.options.mass; - parentBranch.centerOfMass.y *= totalMassInv; - - parentBranch.mass = totalMass; - var biggestSize = Math.max(Math.max(node.height,node.radius),node.width); - parentBranch.maxWidth = (parentBranch.maxWidth < biggestSize) ? biggestSize : parentBranch.maxWidth; - + exports._formClustersByHub = function(force, onlyEqual) { + // we loop over all nodes in the list + for (var nodeId in this.nodes) { + // we check if it is still available since it can be used by the clustering in this loop + if (this.nodes.hasOwnProperty(nodeId)) { + this._formClusterFromHub(this.nodes[nodeId],force,onlyEqual); + } + } }; - /** - * determine in which branch the node will be placed. + * This function forms a cluster from a specific preselected hub node * - * @param parentBranch - * @param node - * @param skipMassUpdate + * @param {Node} hubNode | the node we will cluster as a hub + * @param {Boolean} force | Disregard zoom level + * @param {Boolean} onlyEqual | This only clusters a hub with a specific number of edges + * @param {Number} [absorptionSizeOffset] | * @private */ - exports._placeInTree = function(parentBranch,node,skipMassUpdate) { - if (skipMassUpdate != true || skipMassUpdate === undefined) { - // update the mass of the branch. - this._updateBranchMass(parentBranch,node); + exports._formClusterFromHub = function(hubNode, force, onlyEqual, absorptionSizeOffset) { + if (absorptionSizeOffset === undefined) { + absorptionSizeOffset = 0; } + // we decide if the node is a hub + if ((hubNode.dynamicEdgesLength >= this.hubThreshold && onlyEqual == false) || + (hubNode.dynamicEdgesLength == this.hubThreshold && onlyEqual == true)) { + // initialize variables + var dx,dy,length; + var minLength = this.constants.clustering.clusterEdgeThreshold/this.scale; + var allowCluster = false; - if (parentBranch.children.NW.range.maxX > node.x) { // in NW or SW - if (parentBranch.children.NW.range.maxY > node.y) { // in NW - this._placeInRegion(parentBranch,node,"NW"); - } - else { // in SW - this._placeInRegion(parentBranch,node,"SW"); + // we create a list of edges because the dynamicEdges change over the course of this loop + var edgesIdarray = []; + var amountOfInitialEdges = hubNode.dynamicEdges.length; + for (var j = 0; j < amountOfInitialEdges; j++) { + edgesIdarray.push(hubNode.dynamicEdges[j].id); } - } - else { // in NE or SE - if (parentBranch.children.NW.range.maxY > node.y) { // in NE - this._placeInRegion(parentBranch,node,"NE"); + + // if the hub clustering is not forces, we check if one of the edges connected + // to a cluster is small enough based on the constants.clustering.clusterEdgeThreshold + if (force == false) { + allowCluster = false; + for (j = 0; j < amountOfInitialEdges; j++) { + var edge = this.edges[edgesIdarray[j]]; + if (edge !== undefined) { + if (edge.connected) { + if (edge.toId != edge.fromId) { + dx = (edge.to.x - edge.from.x); + dy = (edge.to.y - edge.from.y); + length = Math.sqrt(dx * dx + dy * dy); + + if (length < minLength) { + allowCluster = true; + break; + } + } + } + } + } } - else { // in SE - this._placeInRegion(parentBranch,node,"SE"); + + // start the clustering if allowed + if ((!force && allowCluster) || force) { + // we loop over all edges INITIALLY connected to this hub + for (j = 0; j < amountOfInitialEdges; j++) { + edge = this.edges[edgesIdarray[j]]; + // the edge can be clustered by this function in a previous loop + if (edge !== undefined) { + var childNode = this.nodes[(edge.fromId == hubNode.id) ? edge.toId : edge.fromId]; + // we do not want hubs to merge with other hubs nor do we want to cluster itself. + if ((childNode.dynamicEdges.length <= (this.hubThreshold + absorptionSizeOffset)) && + (childNode.id != hubNode.id)) { + this._addToCluster(hubNode,childNode,force); + } + } + } } } }; + /** - * actually place the node in a region (or branch) + * This function adds the child node to the parent node, creating a cluster if it is not already. * - * @param parentBranch - * @param node - * @param region + * @param {Node} parentNode | this is the node that will house the child node + * @param {Node} childNode | this node will be deleted from the global this.nodes and stored in the parent node + * @param {Boolean} force | true will only update the remainingEdges at the very end of the clustering, ensuring single level collapse * @private */ - exports._placeInRegion = function(parentBranch,node,region) { - switch (parentBranch.children[region].childrenCount) { - case 0: // place node here - parentBranch.children[region].children.data = node; - parentBranch.children[region].childrenCount = 1; - this._updateBranchMass(parentBranch.children[region],node); - break; - case 1: // convert into children - // if there are two nodes exactly overlapping (on init, on opening of cluster etc.) - // we move one node a pixel and we do not put it in the tree. - if (parentBranch.children[region].children.data.x == node.x && - parentBranch.children[region].children.data.y == node.y) { - node.x += Math.random(); - node.y += Math.random(); - } - else { - this._splitBranch(parentBranch.children[region]); - this._placeInTree(parentBranch.children[region],node); - } - break; - case 4: // place in branch - this._placeInTree(parentBranch.children[region],node); - break; + exports._addToCluster = function(parentNode, childNode, force) { + // join child node in the parent node + parentNode.containedNodes[childNode.id] = childNode; + + // manage all the edges connected to the child and parent nodes + for (var i = 0; i < childNode.dynamicEdges.length; i++) { + var edge = childNode.dynamicEdges[i]; + if (edge.toId == parentNode.id || edge.fromId == parentNode.id) { // edge connected to parentNode + this._addToContainedEdges(parentNode,childNode,edge); + } + else { + this._connectEdgeToCluster(parentNode,childNode,edge); + } + } + // a contained node has no dynamic edges. + childNode.dynamicEdges = []; + + // remove circular edges from clusters + this._containCircularEdgesFromNode(parentNode,childNode); + + + // remove the childNode from the global nodes object + delete this.nodes[childNode.id]; + + // update the properties of the child and parent + var massBefore = parentNode.options.mass; + childNode.clusterSession = this.clusterSession; + parentNode.options.mass += childNode.options.mass; + parentNode.clusterSize += childNode.clusterSize; + parentNode.options.fontSize = Math.min(this.constants.clustering.maxFontSize, this.constants.nodes.fontSize + this.constants.clustering.fontSizeMultiplier*parentNode.clusterSize); + + // keep track of the clustersessions so we can open the cluster up as it has been formed. + if (parentNode.clusterSessions[parentNode.clusterSessions.length - 1] != this.clusterSession) { + parentNode.clusterSessions.push(this.clusterSession); + } + + // forced clusters only open from screen size and double tap + if (force == true) { + // parentNode.formationScale = Math.pow(1 - (1.0/11.0),this.clusterSession+3); + parentNode.formationScale = 0; } + else { + parentNode.formationScale = this.scale; // The latest child has been added on this scale + } + + // recalculate the size of the node on the next time the node is rendered + parentNode.clearSizeCache(); + + // set the pop-out scale for the childnode + parentNode.containedNodes[childNode.id].formationScale = parentNode.formationScale; + + // nullify the movement velocity of the child, this is to avoid hectic behaviour + childNode.clearVelocity(); + + // the mass has altered, preservation of energy dictates the velocity to be updated + parentNode.updateVelocity(massBefore); + + // restart the simulation to reorganise all nodes + this.moving = true; }; /** - * this function splits a branch into 4 sub branches. If the branch contained a node, we place it in the subbranch - * after the split is complete. - * - * @param parentBranch + * This function will apply the changes made to the remainingEdges during the formation of the clusters. + * This is a seperate function to allow for level-wise collapsing of the node barnesHutTree. + * It has to be called if a level is collapsed. It is called by _formClusters(). * @private */ - exports._splitBranch = function(parentBranch) { - // if the branch is shaded with a node, replace the node in the new subset. - var containedNode = null; - if (parentBranch.childrenCount == 1) { - containedNode = parentBranch.children.data; - parentBranch.mass = 0; parentBranch.centerOfMass.x = 0; parentBranch.centerOfMass.y = 0; - } - parentBranch.childrenCount = 4; - parentBranch.children.data = null; - this._insertRegion(parentBranch,"NW"); - this._insertRegion(parentBranch,"NE"); - this._insertRegion(parentBranch,"SW"); - this._insertRegion(parentBranch,"SE"); + exports._updateDynamicEdges = function() { + for (var i = 0; i < this.nodeIndices.length; i++) { + var node = this.nodes[this.nodeIndices[i]]; + node.dynamicEdgesLength = node.dynamicEdges.length; - if (containedNode != null) { - this._placeInTree(parentBranch,containedNode); + // this corrects for multiple edges pointing at the same other node + var correction = 0; + if (node.dynamicEdgesLength > 1) { + for (var j = 0; j < node.dynamicEdgesLength - 1; j++) { + var edgeToId = node.dynamicEdges[j].toId; + var edgeFromId = node.dynamicEdges[j].fromId; + for (var k = j+1; k < node.dynamicEdgesLength; k++) { + if ((node.dynamicEdges[k].toId == edgeToId && node.dynamicEdges[k].fromId == edgeFromId) || + (node.dynamicEdges[k].fromId == edgeToId && node.dynamicEdges[k].toId == edgeFromId)) { + correction += 1; + } + } + } + } + node.dynamicEdgesLength -= correction; } }; /** - * This function subdivides the region into four new segments. - * Specifically, this inserts a single new segment. - * It fills the children section of the parentBranch + * This adds an edge from the childNode to the contained edges of the parent node * - * @param parentBranch - * @param region - * @param parentRange + * @param parentNode | Node object + * @param childNode | Node object + * @param edge | Edge object * @private */ - exports._insertRegion = function(parentBranch, region) { - var minX,maxX,minY,maxY; - var childSize = 0.5 * parentBranch.size; - switch (region) { - case "NW": - minX = parentBranch.range.minX; - maxX = parentBranch.range.minX + childSize; - minY = parentBranch.range.minY; - maxY = parentBranch.range.minY + childSize; - break; - case "NE": - minX = parentBranch.range.minX + childSize; - maxX = parentBranch.range.maxX; - minY = parentBranch.range.minY; - maxY = parentBranch.range.minY + childSize; - break; - case "SW": - minX = parentBranch.range.minX; - maxX = parentBranch.range.minX + childSize; - minY = parentBranch.range.minY + childSize; - maxY = parentBranch.range.maxY; - break; - case "SE": - minX = parentBranch.range.minX + childSize; - maxX = parentBranch.range.maxX; - minY = parentBranch.range.minY + childSize; - maxY = parentBranch.range.maxY; - break; + exports._addToContainedEdges = function(parentNode, childNode, edge) { + // create an array object if it does not yet exist for this childNode + if (!(parentNode.containedEdges.hasOwnProperty(childNode.id))) { + parentNode.containedEdges[childNode.id] = [] } + // add this edge to the list + parentNode.containedEdges[childNode.id].push(edge); + // remove the edge from the global edges object + delete this.edges[edge.id]; - parentBranch.children[region] = { - centerOfMass:{x:0,y:0}, - mass:0, - range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY}, - size: 0.5 * parentBranch.size, - calcSize: 2 * parentBranch.calcSize, - children: {data:null}, - maxWidth: 0, - level: parentBranch.level+1, - childrenCount: 0 - }; + // remove the edge from the parent object + for (var i = 0; i < parentNode.dynamicEdges.length; i++) { + if (parentNode.dynamicEdges[i].id == edge.id) { + parentNode.dynamicEdges.splice(i,1); + break; + } + } }; - /** - * This function is for debugging purposed, it draws the tree. + * This function connects an edge that was connected to a child node to the parent node. + * It keeps track of which nodes it has been connected to with the originalId array. * - * @param ctx - * @param color + * @param {Node} parentNode | Node object + * @param {Node} childNode | Node object + * @param {Edge} edge | Edge object * @private */ - exports._drawTree = function(ctx,color) { - if (this.barnesHutTree !== undefined) { + exports._connectEdgeToCluster = function(parentNode, childNode, edge) { + // handle circular edges + if (edge.toId == edge.fromId) { + this._addToContainedEdges(parentNode, childNode, edge); + } + else { + if (edge.toId == childNode.id) { // edge connected to other node on the "to" side + edge.originalToId.push(childNode.id); + edge.to = parentNode; + edge.toId = parentNode.id; + } + else { // edge connected to other node with the "from" side - ctx.lineWidth = 1; + edge.originalFromId.push(childNode.id); + edge.from = parentNode; + edge.fromId = parentNode.id; + } - this._drawBranch(this.barnesHutTree.root,ctx,color); + this._addToReroutedEdges(parentNode,childNode,edge); } }; /** - * This function is for debugging purposes. It draws the branches recursively. + * If a node is connected to itself, a circular edge is drawn. When clustering we want to contain + * these edges inside of the cluster. * - * @param branch - * @param ctx - * @param color + * @param parentNode + * @param childNode * @private */ - exports._drawBranch = function(branch,ctx,color) { - if (color === undefined) { - color = "#FF0000"; - } - - if (branch.childrenCount == 4) { - this._drawBranch(branch.children.NW,ctx); - this._drawBranch(branch.children.NE,ctx); - this._drawBranch(branch.children.SE,ctx); - this._drawBranch(branch.children.SW,ctx); + exports._containCircularEdgesFromNode = function(parentNode, childNode) { + // manage all the edges connected to the child and parent nodes + for (var i = 0; i < parentNode.dynamicEdges.length; i++) { + var edge = parentNode.dynamicEdges[i]; + // handle circular edges + if (edge.toId == edge.fromId) { + this._addToContainedEdges(parentNode, childNode, edge); + } } - ctx.strokeStyle = color; - ctx.beginPath(); - ctx.moveTo(branch.range.minX,branch.range.minY); - ctx.lineTo(branch.range.maxX,branch.range.minY); - ctx.stroke(); - - ctx.beginPath(); - ctx.moveTo(branch.range.maxX,branch.range.minY); - ctx.lineTo(branch.range.maxX,branch.range.maxY); - ctx.stroke(); - - ctx.beginPath(); - ctx.moveTo(branch.range.maxX,branch.range.maxY); - ctx.lineTo(branch.range.minX,branch.range.maxY); - ctx.stroke(); - - ctx.beginPath(); - ctx.moveTo(branch.range.minX,branch.range.maxY); - ctx.lineTo(branch.range.minX,branch.range.minY); - ctx.stroke(); - - /* - if (branch.mass > 0) { - ctx.circle(branch.centerOfMass.x, branch.centerOfMass.y, 3*branch.mass); - ctx.stroke(); - } - */ }; -/***/ }, -/* 64 */ -/***/ function(module, exports, __webpack_require__) { - /** - * Creation of the ClusterMixin var. + * This adds an edge from the childNode to the rerouted edges of the parent node * - * This contains all the functions the Network object can use to employ clustering + * @param parentNode | Node object + * @param childNode | Node object + * @param edge | Edge object + * @private */ + exports._addToReroutedEdges = function(parentNode, childNode, edge) { + // create an array object if it does not yet exist for this childNode + // we store the edge in the rerouted edges so we can restore it when the cluster pops open + if (!(parentNode.reroutedEdges.hasOwnProperty(childNode.id))) { + parentNode.reroutedEdges[childNode.id] = []; + } + parentNode.reroutedEdges[childNode.id].push(edge); - /** - * This is only called in the constructor of the network object - * - */ - exports.startWithClustering = function() { - // cluster if the data set is big - this.clusterToFit(this.constants.clustering.initialMaxNodes, true); + // this edge becomes part of the dynamicEdges of the cluster node + parentNode.dynamicEdges.push(edge); + }; - // updates the lables after clustering - this.updateLabels(); - // this is called here because if clusterin is disabled, the start and stabilize are called in - // the setData function. - if (this.stabilize) { - this._stabilize(); - } - this.start(); - }; /** - * This function clusters until the initialMaxNodes has been reached + * This function connects an edge that was connected to a cluster node back to the child node. * - * @param {Number} maxNumberOfNodes - * @param {Boolean} reposition + * @param parentNode | Node object + * @param childNode | Node object + * @private */ - exports.clusterToFit = function(maxNumberOfNodes, reposition) { - var numberOfNodes = this.nodeIndices.length; + exports._connectEdgeBackToChild = function(parentNode, childNode) { + if (parentNode.reroutedEdges.hasOwnProperty(childNode.id)) { + for (var i = 0; i < parentNode.reroutedEdges[childNode.id].length; i++) { + var edge = parentNode.reroutedEdges[childNode.id][i]; + if (edge.originalFromId[edge.originalFromId.length-1] == childNode.id) { + edge.originalFromId.pop(); + edge.fromId = childNode.id; + edge.from = childNode; + } + else { + edge.originalToId.pop(); + edge.toId = childNode.id; + edge.to = childNode; + } - var maxLevels = 50; - var level = 0; + // append this edge to the list of edges connecting to the childnode + childNode.dynamicEdges.push(edge); - // we first cluster the hubs, then we pull in the outliers, repeat - while (numberOfNodes > maxNumberOfNodes && level < maxLevels) { - if (level % 3 == 0) { - this.forceAggregateHubs(true); - this.normalizeClusterLevels(); - } - else { - this.increaseClusterLevel(); // this also includes a cluster normalization + // remove the edge from the parent object + for (var j = 0; j < parentNode.dynamicEdges.length; j++) { + if (parentNode.dynamicEdges[j].id == edge.id) { + parentNode.dynamicEdges.splice(j,1); + break; + } + } } - - numberOfNodes = this.nodeIndices.length; - level += 1; - } - - // after the clustering we reposition the nodes to reduce the initial chaos - if (level > 0 && reposition == true) { - this.repositionNodes(); + // remove the entry from the rerouted edges + delete parentNode.reroutedEdges[childNode.id]; } - this._updateCalculationNodes(); }; + /** - * This function can be called to open up a specific cluster. It is only called by - * It will unpack the cluster back one level. + * When loops are clustered, an edge can be both in the rerouted array and the contained array. + * This function is called last to verify that all edges in dynamicEdges are in fact connected to the + * parentNode * - * @param node | Node object: cluster to open. + * @param parentNode | Node object + * @private */ - exports.openCluster = function(node) { - var isMovingBeforeClustering = this.moving; - if (node.clusterSize > this.constants.clustering.sectorThreshold && this._nodeInActiveArea(node) && - !(this._sector() == "default" && this.nodeIndices.length == 1)) { - // this loads a new sector, loads the nodes and edges and nodeIndices of it. - this._addSector(node); - var level = 0; - - // we decluster until we reach a decent number of nodes - while ((this.nodeIndices.length < this.constants.clustering.initialMaxNodes) && (level < 10)) { - this.decreaseClusterLevel(); - level += 1; + exports._validateEdges = function(parentNode) { + for (var i = 0; i < parentNode.dynamicEdges.length; i++) { + var edge = parentNode.dynamicEdges[i]; + if (parentNode.id != edge.toId && parentNode.id != edge.fromId) { + parentNode.dynamicEdges.splice(i,1); } - - } - else { - this._expandClusterNode(node,false,true); - - // update the index list, dynamic edges and labels - this._updateNodeIndexList(); - this._updateDynamicEdges(); - this._updateCalculationNodes(); - this.updateLabels(); - } - - // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded - if (this.moving != isMovingBeforeClustering) { - this.start(); } }; /** - * This calls the updateClustes with default arguments + * This function released the contained edges back into the global domain and puts them back into the + * dynamic edges of both parent and child. + * + * @param {Node} parentNode | + * @param {Node} childNode | + * @private */ - exports.updateClustersDefault = function() { - if (this.constants.clustering.enabled == true) { - this.updateClusters(0,false,false); + exports._releaseContainedEdges = function(parentNode, childNode) { + for (var i = 0; i < parentNode.containedEdges[childNode.id].length; i++) { + var edge = parentNode.containedEdges[childNode.id][i]; + + // put the edge back in the global edges object + this.edges[edge.id] = edge; + + // put the edge back in the dynamic edges of the child and parent + childNode.dynamicEdges.push(edge); + parentNode.dynamicEdges.push(edge); } + // remove the entry from the contained edges + delete parentNode.containedEdges[childNode.id]; + }; - /** - * This function can be called to increase the cluster level. This means that the nodes with only one edge connection will - * be clustered with their connected node. This can be repeated as many times as needed. - * This can be called externally (by a keybind for instance) to reduce the complexity of big datasets. - */ - exports.increaseClusterLevel = function() { - this.updateClusters(-1,false,true); - }; - /** - * This function can be called to decrease the cluster level. This means that the nodes with only one edge connection will - * be unpacked if they are a cluster. This can be repeated as many times as needed. - * This can be called externally (by a key-bind for instance) to look into clusters without zooming. - */ - exports.decreaseClusterLevel = function() { - this.updateClusters(1,false,true); - }; + // ------------------- UTILITY FUNCTIONS ---------------------------- // /** - * This is the main clustering function. It clusters and declusters on zoom or forced - * This function clusters on zoom, it can be called with a predefined zoom direction - * If out, check if we can form clusters, if in, check if we can open clusters. - * This function is only called from _zoom() - * - * @param {Number} zoomDirection | -1 / 0 / +1 for zoomOut / determineByZoom / zoomIn - * @param {Boolean} recursive | enabled or disable recursive calling of the opening of clusters - * @param {Boolean} force | enabled or disable forcing - * @param {Boolean} doNotStart | if true do not call start - * + * This updates the node labels for all nodes (for debugging purposes) */ - exports.updateClusters = function(zoomDirection,recursive,force,doNotStart) { - var isMovingBeforeClustering = this.moving; - var amountOfNodes = this.nodeIndices.length; - - // on zoom out collapse the sector if the scale is at the level the sector was made - if (this.previousScale > this.scale && zoomDirection == 0) { - this._collapseSector(); + exports.updateLabels = function() { + var nodeId; + // update node labels + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + var node = this.nodes[nodeId]; + if (node.clusterSize > 1) { + node.label = "[".concat(String(node.clusterSize),"]"); + } + } } - // check if we zoom in or out - if (this.previousScale > this.scale || zoomDirection == -1) { // zoom out - // forming clusters when forced pulls outliers in. When not forced, the edge length of the - // outer nodes determines if it is being clustered - this._formClusters(force); - } - else if (this.previousScale < this.scale || zoomDirection == 1) { // zoom in - if (force == true) { - // _openClusters checks for each node if the formationScale of the cluster is smaller than - // the current scale and if so, declusters. When forced, all clusters are reduced by one step - this._openClusters(recursive,force); - } - else { - // if a cluster takes up a set percentage of the active window - this._openClustersBySize(); + // update node labels + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + if (node.clusterSize == 1) { + if (node.originalLabel !== undefined) { + node.label = node.originalLabel; + } + else { + node.label = String(node.id); + } + } } } - this._updateNodeIndexList(); - // if a cluster was NOT formed and the user zoomed out, we try clustering by hubs - if (this.nodeIndices.length == amountOfNodes && (this.previousScale > this.scale || zoomDirection == -1)) { - this._aggregateHubs(force); - this._updateNodeIndexList(); - } + // /* Debug Override */ + // for (nodeId in this.nodes) { + // if (this.nodes.hasOwnProperty(nodeId)) { + // node = this.nodes[nodeId]; + // node.label = String(node.level); + // } + // } - // we now reduce chains. - if (this.previousScale > this.scale || zoomDirection == -1) { // zoom out - this.handleChains(); - this._updateNodeIndexList(); - } + }; - this.previousScale = this.scale; - // rest of the update the index list, dynamic edges and labels - this._updateDynamicEdges(); - this.updateLabels(); + /** + * We want to keep the cluster level distribution rather small. This means we do not want unclustered nodes + * if the rest of the nodes are already a few cluster levels in. + * To fix this we use this function. It determines the min and max cluster level and sends nodes that have not + * clustered enough to the clusterToSmallestNeighbours function. + */ + exports.normalizeClusterLevels = function() { + var maxLevel = 0; + var minLevel = 1e9; + var clusterLevel = 0; + var nodeId; - // if a cluster was formed, we increase the clusterSession - if (this.nodeIndices.length < amountOfNodes) { // this means a clustering operation has taken place - this.clusterSession += 1; - // if clusters have been made, we normalize the cluster level - this.normalizeClusterLevels(); + // we loop over all nodes in the list + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + clusterLevel = this.nodes[nodeId].clusterSessions.length; + if (maxLevel < clusterLevel) {maxLevel = clusterLevel;} + if (minLevel > clusterLevel) {minLevel = clusterLevel;} + } } - if (doNotStart == false || doNotStart === undefined) { - // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded - if (this.moving != isMovingBeforeClustering) { - this.start(); + if (maxLevel - minLevel > this.constants.clustering.clusterLevelDifference) { + var amountOfNodes = this.nodeIndices.length; + var targetLevel = maxLevel - this.constants.clustering.clusterLevelDifference; + // we loop over all nodes in the list + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + if (this.nodes[nodeId].clusterSessions.length < targetLevel) { + this._clusterToSmallestNeighbour(this.nodes[nodeId]); + } + } + } + this._updateNodeIndexList(); + this._updateDynamicEdges(); + // if a cluster was formed, we increase the clusterSession + if (this.nodeIndices.length != amountOfNodes) { + this.clusterSession += 1; } } - - this._updateCalculationNodes(); }; + + /** - * This function handles the chains. It is called on every updateClusters(). + * This function determines if the cluster we want to decluster is in the active area + * this means around the zoom center + * + * @param {Node} node + * @returns {boolean} + * @private */ - exports.handleChains = function() { - // after clustering we check how many chains there are - var chainPercentage = this._getChainFraction(); - if (chainPercentage > this.constants.clustering.chainThreshold) { - this._reduceAmountOfChains(1 - this.constants.clustering.chainThreshold / chainPercentage) - - } + exports._nodeInActiveArea = function(node) { + return ( + Math.abs(node.x - this.areaCenter.x) <= this.constants.clustering.activeAreaBoxSize/this.scale + && + Math.abs(node.y - this.areaCenter.y) <= this.constants.clustering.activeAreaBoxSize/this.scale + ) }; + /** - * this functions starts clustering by hubs - * The minimum hub threshold is set globally + * This is an adaptation of the original repositioning function. This is called if the system is clustered initially + * It puts large clusters away from the center and randomizes the order. * - * @private */ - exports._aggregateHubs = function(force) { - this._getHubSize(); - this._formClustersByHub(force,false); + exports.repositionNodes = function() { + for (var i = 0; i < this.nodeIndices.length; i++) { + var node = this.nodes[this.nodeIndices[i]]; + if ((node.xFixed == false || node.yFixed == false)) { + var radius = 10 * 0.1*this.nodeIndices.length * Math.min(100,node.options.mass); + var angle = 2 * Math.PI * Math.random(); + if (node.xFixed == false) {node.x = radius * Math.cos(angle);} + if (node.yFixed == false) {node.y = radius * Math.sin(angle);} + this._repositionBezierNodes(node); + } + } }; /** - * This function is fired by keypress. It forces hubs to form. + * We determine how many connections denote an important hub. + * We take the mean + 2*std as the important hub size. (Assuming a normal distribution of data, ~2.2%) * + * @private */ - exports.forceAggregateHubs = function(doNotStart) { - var isMovingBeforeClustering = this.moving; - var amountOfNodes = this.nodeIndices.length; + exports._getHubSize = function() { + var average = 0; + var averageSquared = 0; + var hubCounter = 0; + var largestHub = 0; + + for (var i = 0; i < this.nodeIndices.length; i++) { + + var node = this.nodes[this.nodeIndices[i]]; + if (node.dynamicEdgesLength > largestHub) { + largestHub = node.dynamicEdgesLength; + } + average += node.dynamicEdgesLength; + averageSquared += Math.pow(node.dynamicEdgesLength,2); + hubCounter += 1; + } + average = average / hubCounter; + averageSquared = averageSquared / hubCounter; + + var variance = averageSquared - Math.pow(average,2); - this._aggregateHubs(true); + var standardDeviation = Math.sqrt(variance); - // update the index list, dynamic edges and labels - this._updateNodeIndexList(); - this._updateDynamicEdges(); - this.updateLabels(); + this.hubThreshold = Math.floor(average + 2*standardDeviation); - // if a cluster was formed, we increase the clusterSession - if (this.nodeIndices.length != amountOfNodes) { - this.clusterSession += 1; + // always have at least one to cluster + if (this.hubThreshold > largestHub) { + this.hubThreshold = largestHub; } - if (doNotStart == false || doNotStart === undefined) { - // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded - if (this.moving != isMovingBeforeClustering) { - this.start(); - } - } + // console.log("average",average,"averageSQ",averageSquared,"var",variance,"std",standardDeviation); + // console.log("hubThreshold:",this.hubThreshold); }; + /** - * If a cluster takes up more than a set percentage of the screen, open the cluster + * We reduce the amount of "extension nodes" or chains. These are not quickly clustered with the outliers and hubs methods + * with this amount we can cluster specifically on these chains. * + * @param {Number} fraction | between 0 and 1, the percentage of chains to reduce * @private */ - exports._openClustersBySize = function() { + exports._reduceAmountOfChains = function(fraction) { + this.hubThreshold = 2; + var reduceAmount = Math.floor(this.nodeIndices.length * fraction); for (var nodeId in this.nodes) { if (this.nodes.hasOwnProperty(nodeId)) { - var node = this.nodes[nodeId]; - if (node.inView() == true) { - if ((node.width*this.scale > this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientWidth) || - (node.height*this.scale > this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientHeight)) { - this.openCluster(node); + if (this.nodes[nodeId].dynamicEdgesLength == 2 && this.nodes[nodeId].dynamicEdges.length >= 2) { + if (reduceAmount > 0) { + this._formClusterFromHub(this.nodes[nodeId],true,true,1); + reduceAmount -= 1; } } } } }; - /** - * This function loops over all nodes in the nodeIndices list. For each node it checks if it is a cluster and if it - * has to be opened based on the current zoom level. + * We get the amount of "extension nodes" or chains. These are not quickly clustered with the outliers and hubs methods + * with this amount we can cluster specifically on these chains. * * @private */ - exports._openClusters = function(recursive,force) { - for (var i = 0; i < this.nodeIndices.length; i++) { - var node = this.nodes[this.nodeIndices[i]]; - this._expandClusterNode(node,recursive,force); - this._updateCalculationNodes(); + exports._getChainFraction = function() { + var chains = 0; + var total = 0; + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + if (this.nodes[nodeId].dynamicEdgesLength == 2 && this.nodes[nodeId].dynamicEdges.length >= 2) { + chains += 1; + } + total += 1; + } } + return chains/total; }; + +/***/ }, +/* 61 */ +/***/ function(module, exports, __webpack_require__) { + + var util = __webpack_require__(1); + var Node = __webpack_require__(40); + /** - * This function checks if a node has to be opened. This is done by checking the zoom level. - * If the node contains child nodes, this function is recursively called on the child nodes as well. - * This recursive behaviour is optional and can be set by the recursive argument. + * Creation of the SectorMixin var. + * + * This contains all the functions the Network object can use to employ the sector system. + * The sector system is always used by Network, though the benefits only apply to the use of clustering. + * If clustering is not used, there is no overhead except for a duplicate object with references to nodes and edges. + */ + + /** + * This function is only called by the setData function of the Network object. + * This loads the global references into the active sector. This initializes the sector. * - * @param {Node} parentNode | to check for cluster and expand - * @param {Boolean} recursive | enabled or disable recursive calling - * @param {Boolean} force | enabled or disable forcing - * @param {Boolean} [openAll] | This will recursively force all nodes in the parent to be released * @private */ - exports._expandClusterNode = function(parentNode, recursive, force, openAll) { - // first check if node is a cluster - if (parentNode.clusterSize > 1) { - // this means that on a double tap event or a zoom event, the cluster fully unpacks if it is smaller than 20 - if (parentNode.clusterSize < this.constants.clustering.sectorThreshold) { - openAll = true; - } - recursive = openAll ? true : recursive; + exports._putDataInSector = function() { + this.sectors["active"][this._sector()].nodes = this.nodes; + this.sectors["active"][this._sector()].edges = this.edges; + this.sectors["active"][this._sector()].nodeIndices = this.nodeIndices; + }; - // if the last child has been added on a smaller scale than current scale decluster - if (parentNode.formationScale < this.scale || force == true) { - // we will check if any of the contained child nodes should be removed from the cluster - for (var containedNodeId in parentNode.containedNodes) { - if (parentNode.containedNodes.hasOwnProperty(containedNodeId)) { - var childNode = parentNode.containedNodes[containedNodeId]; - // force expand will expand the largest cluster size clusters. Since we cluster from outside in, we assume that - // the largest cluster is the one that comes from outside - if (force == true) { - if (childNode.clusterSession == parentNode.clusterSessions[parentNode.clusterSessions.length-1] - || openAll) { - this._expelChildFromParent(parentNode,containedNodeId,recursive,force,openAll); - } - } - else { - if (this._nodeInActiveArea(parentNode)) { - this._expelChildFromParent(parentNode,containedNodeId,recursive,force,openAll); - } - } - } - } - } + /** + * /** + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the supplied (active) sector. If a type is defined, do the specific type + * + * @param {String} sectorId + * @param {String} [sectorType] | "active" or "frozen" + * @private + */ + exports._switchToSector = function(sectorId, sectorType) { + if (sectorType === undefined || sectorType == "active") { + this._switchToActiveSector(sectorId); + } + else { + this._switchToFrozenSector(sectorId); } }; + /** - * ONLY CALLED FROM _expandClusterNode - * - * This function will expel a child_node from a parent_node. This is to de-cluster the node. This function will remove - * the child node from the parent contained_node object and put it back into the global nodes object. - * The same holds for the edge that was connected to the child node. It is moved back into the global edges object. + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the supplied active sector. * - * @param {Node} parentNode | the parent node - * @param {String} containedNodeId | child_node id as it is contained in the containedNodes object of the parent node - * @param {Boolean} recursive | This will also check if the child needs to be expanded. - * With force and recursive both true, the entire cluster is unpacked - * @param {Boolean} force | This will disregard the zoom level and will expel this child from the parent - * @param {Boolean} openAll | This will recursively force all nodes in the parent to be released + * @param sectorId * @private */ - exports._expelChildFromParent = function(parentNode, containedNodeId, recursive, force, openAll) { - var childNode = parentNode.containedNodes[containedNodeId]; - - // if child node has been added on smaller scale than current, kick out - if (childNode.formationScale < this.scale || force == true) { - // unselect all selected items - this._unselectAll(); - - // put the child node back in the global nodes object - this.nodes[containedNodeId] = childNode; - - // release the contained edges from this childNode back into the global edges - this._releaseContainedEdges(parentNode,childNode); - - // reconnect rerouted edges to the childNode - this._connectEdgeBackToChild(parentNode,childNode); - - // validate all edges in dynamicEdges - this._validateEdges(parentNode); - - // undo the changes from the clustering operation on the parent node - parentNode.options.mass -= childNode.options.mass; - parentNode.clusterSize -= childNode.clusterSize; - parentNode.options.fontSize = Math.min(this.constants.clustering.maxFontSize, this.constants.nodes.fontSize + this.constants.clustering.fontSizeMultiplier*(parentNode.clusterSize-1)); - parentNode.dynamicEdgesLength = parentNode.dynamicEdges.length; - - // place the child node near the parent, not at the exact same location to avoid chaos in the system - childNode.x = parentNode.x + parentNode.growthIndicator * (0.5 - Math.random()); - childNode.y = parentNode.y + parentNode.growthIndicator * (0.5 - Math.random()); - - // remove node from the list - delete parentNode.containedNodes[containedNodeId]; + exports._switchToActiveSector = function(sectorId) { + this.nodeIndices = this.sectors["active"][sectorId]["nodeIndices"]; + this.nodes = this.sectors["active"][sectorId]["nodes"]; + this.edges = this.sectors["active"][sectorId]["edges"]; + }; - // check if there are other childs with this clusterSession in the parent. - var othersPresent = false; - for (var childNodeId in parentNode.containedNodes) { - if (parentNode.containedNodes.hasOwnProperty(childNodeId)) { - if (parentNode.containedNodes[childNodeId].clusterSession == childNode.clusterSession) { - othersPresent = true; - break; - } - } - } - // if there are no others, remove the cluster session from the list - if (othersPresent == false) { - parentNode.clusterSessions.pop(); - } - this._repositionBezierNodes(childNode); - // this._repositionBezierNodes(parentNode); + /** + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the supplied active sector. + * + * @private + */ + exports._switchToSupportSector = function() { + this.nodeIndices = this.sectors["support"]["nodeIndices"]; + this.nodes = this.sectors["support"]["nodes"]; + this.edges = this.sectors["support"]["edges"]; + }; - // remove the clusterSession from the child node - childNode.clusterSession = 0; - // recalculate the size of the node on the next time the node is rendered - parentNode.clearSizeCache(); + /** + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the supplied frozen sector. + * + * @param sectorId + * @private + */ + exports._switchToFrozenSector = function(sectorId) { + this.nodeIndices = this.sectors["frozen"][sectorId]["nodeIndices"]; + this.nodes = this.sectors["frozen"][sectorId]["nodes"]; + this.edges = this.sectors["frozen"][sectorId]["edges"]; + }; - // restart the simulation to reorganise all nodes - this.moving = true; - } - // check if a further expansion step is possible if recursivity is enabled - if (recursive == true) { - this._expandClusterNode(childNode,recursive,force,openAll); - } + /** + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the currently active sector. + * + * @private + */ + exports._loadLatestSector = function() { + this._switchToSector(this._sector()); }; /** - * position the bezier nodes at the center of the edges + * This function returns the currently active sector Id * - * @param node + * @returns {String} * @private */ - exports._repositionBezierNodes = function(node) { - for (var i = 0; i < node.dynamicEdges.length; i++) { - node.dynamicEdges[i].positionBezierNode(); - } + exports._sector = function() { + return this.activeSector[this.activeSector.length-1]; }; /** - * This function checks if any nodes at the end of their trees have edges below a threshold length - * This function is called only from updateClusters() - * forceLevelCollapse ignores the length of the edge and collapses one level - * This means that a node with only one edge will be clustered with its connected node + * This function returns the previously active sector Id * + * @returns {String} * @private - * @param {Boolean} force */ - exports._formClusters = function(force) { - if (force == false) { - this._formClustersByZoom(); + exports._previousSector = function() { + if (this.activeSector.length > 1) { + return this.activeSector[this.activeSector.length-2]; } else { - this._forceClustersByZoom(); + throw new TypeError('there are not enough sectors in the this.activeSector array.'); } }; /** - * This function handles the clustering by zooming out, this is based on a minimum edge distance + * We add the active sector at the end of the this.activeSector array + * This ensures it is the currently active sector returned by _sector() and it reaches the top + * of the activeSector stack. When we reverse our steps we move from the end to the beginning of this stack. * + * @param newId * @private */ - exports._formClustersByZoom = function() { - var dx,dy,length, - minLength = this.constants.clustering.clusterEdgeThreshold/this.scale; - - // check if any edges are shorter than minLength and start the clustering - // the clustering favours the node with the larger mass - for (var edgeId in this.edges) { - if (this.edges.hasOwnProperty(edgeId)) { - var edge = this.edges[edgeId]; - if (edge.connected) { - if (edge.toId != edge.fromId) { - dx = (edge.to.x - edge.from.x); - dy = (edge.to.y - edge.from.y); - length = Math.sqrt(dx * dx + dy * dy); - + exports._setActiveSector = function(newId) { + this.activeSector.push(newId); + }; - if (length < minLength) { - // first check which node is larger - var parentNode = edge.from; - var childNode = edge.to; - if (edge.to.options.mass > edge.from.options.mass) { - parentNode = edge.to; - childNode = edge.from; - } - if (childNode.dynamicEdgesLength == 1) { - this._addToCluster(parentNode,childNode,false); - } - else if (parentNode.dynamicEdgesLength == 1) { - this._addToCluster(childNode,parentNode,false); - } - } - } - } - } - } + /** + * We remove the currently active sector id from the active sector stack. This happens when + * we reactivate the previously active sector + * + * @private + */ + exports._forgetLastSector = function() { + this.activeSector.pop(); }; + /** - * This function forces the network to cluster all nodes with only one connecting edge to their - * connected node. + * This function creates a new active sector with the supplied newId. This newId + * is the expanding node id. * + * @param {String} newId | Id of the new active sector * @private */ - exports._forceClustersByZoom = function() { - for (var nodeId in this.nodes) { - // another node could have absorbed this child. - if (this.nodes.hasOwnProperty(nodeId)) { - var childNode = this.nodes[nodeId]; - - // the edges can be swallowed by another decrease - if (childNode.dynamicEdgesLength == 1 && childNode.dynamicEdges.length != 0) { - var edge = childNode.dynamicEdges[0]; - var parentNode = (edge.toId == childNode.id) ? this.nodes[edge.fromId] : this.nodes[edge.toId]; + exports._createNewSector = function(newId) { + // create the new sector + this.sectors["active"][newId] = {"nodes":{}, + "edges":{}, + "nodeIndices":[], + "formationScale": this.scale, + "drawingNode": undefined}; - // group to the largest node - if (childNode.id != parentNode.id) { - if (parentNode.options.mass > childNode.options.mass) { - this._addToCluster(parentNode,childNode,true); - } - else { - this._addToCluster(childNode,parentNode,true); - } + // create the new sector render node. This gives visual feedback that you are in a new sector. + this.sectors["active"][newId]['drawingNode'] = new Node( + {id:newId, + color: { + background: "#eaefef", + border: "495c5e" } - } - } - } + },{},{},this.constants); + this.sectors["active"][newId]['drawingNode'].clusterSize = 2; }; /** - * To keep the nodes of roughly equal size we normalize the cluster levels. - * This function clusters a node to its smallest connected neighbour. + * This function removes the currently active sector. This is called when we create a new + * active sector. * - * @param node + * @param {String} sectorId | Id of the active sector that will be removed * @private */ - exports._clusterToSmallestNeighbour = function(node) { - var smallestNeighbour = -1; - var smallestNeighbourNode = null; - for (var i = 0; i < node.dynamicEdges.length; i++) { - if (node.dynamicEdges[i] !== undefined) { - var neighbour = null; - if (node.dynamicEdges[i].fromId != node.id) { - neighbour = node.dynamicEdges[i].from; - } - else if (node.dynamicEdges[i].toId != node.id) { - neighbour = node.dynamicEdges[i].to; - } - + exports._deleteActiveSector = function(sectorId) { + delete this.sectors["active"][sectorId]; + }; - if (neighbour != null && smallestNeighbour > neighbour.clusterSessions.length) { - smallestNeighbour = neighbour.clusterSessions.length; - smallestNeighbourNode = neighbour; - } - } - } - if (neighbour != null && this.nodes[neighbour.id] !== undefined) { - this._addToCluster(neighbour, node, true); - } + /** + * This function removes the currently active sector. This is called when we reactivate + * the previously active sector. + * + * @param {String} sectorId | Id of the active sector that will be removed + * @private + */ + exports._deleteFrozenSector = function(sectorId) { + delete this.sectors["frozen"][sectorId]; }; /** - * This function forms clusters from hubs, it loops over all nodes + * Freezing an active sector means moving it from the "active" object to the "frozen" object. + * We copy the references, then delete the active entree. * - * @param {Boolean} force | Disregard zoom level - * @param {Boolean} onlyEqual | This only clusters a hub with a specific number of edges + * @param sectorId * @private */ - exports._formClustersByHub = function(force, onlyEqual) { - // we loop over all nodes in the list - for (var nodeId in this.nodes) { - // we check if it is still available since it can be used by the clustering in this loop - if (this.nodes.hasOwnProperty(nodeId)) { - this._formClusterFromHub(this.nodes[nodeId],force,onlyEqual); - } - } + exports._freezeSector = function(sectorId) { + // we move the set references from the active to the frozen stack. + this.sectors["frozen"][sectorId] = this.sectors["active"][sectorId]; + + // we have moved the sector data into the frozen set, we now remove it from the active set + this._deleteActiveSector(sectorId); }; + /** - * This function forms a cluster from a specific preselected hub node + * This is the reverse operation of _freezeSector. Activating means moving the sector from the "frozen" + * object to the "active" object. * - * @param {Node} hubNode | the node we will cluster as a hub - * @param {Boolean} force | Disregard zoom level - * @param {Boolean} onlyEqual | This only clusters a hub with a specific number of edges - * @param {Number} [absorptionSizeOffset] | + * @param sectorId * @private */ - exports._formClusterFromHub = function(hubNode, force, onlyEqual, absorptionSizeOffset) { - if (absorptionSizeOffset === undefined) { - absorptionSizeOffset = 0; - } - // we decide if the node is a hub - if ((hubNode.dynamicEdgesLength >= this.hubThreshold && onlyEqual == false) || - (hubNode.dynamicEdgesLength == this.hubThreshold && onlyEqual == true)) { - // initialize variables - var dx,dy,length; - var minLength = this.constants.clustering.clusterEdgeThreshold/this.scale; - var allowCluster = false; + exports._activateSector = function(sectorId) { + // we move the set references from the frozen to the active stack. + this.sectors["active"][sectorId] = this.sectors["frozen"][sectorId]; - // we create a list of edges because the dynamicEdges change over the course of this loop - var edgesIdarray = []; - var amountOfInitialEdges = hubNode.dynamicEdges.length; - for (var j = 0; j < amountOfInitialEdges; j++) { - edgesIdarray.push(hubNode.dynamicEdges[j].id); - } + // we have moved the sector data into the active set, we now remove it from the frozen stack + this._deleteFrozenSector(sectorId); + }; - // if the hub clustering is not forces, we check if one of the edges connected - // to a cluster is small enough based on the constants.clustering.clusterEdgeThreshold - if (force == false) { - allowCluster = false; - for (j = 0; j < amountOfInitialEdges; j++) { - var edge = this.edges[edgesIdarray[j]]; - if (edge !== undefined) { - if (edge.connected) { - if (edge.toId != edge.fromId) { - dx = (edge.to.x - edge.from.x); - dy = (edge.to.y - edge.from.y); - length = Math.sqrt(dx * dx + dy * dy); - if (length < minLength) { - allowCluster = true; - break; - } - } - } - } - } + /** + * This function merges the data from the currently active sector with a frozen sector. This is used + * in the process of reverting back to the previously active sector. + * The data that is placed in the frozen (the previously active) sector is the node that has been removed from it + * upon the creation of a new active sector. + * + * @param sectorId + * @private + */ + exports._mergeThisWithFrozen = function(sectorId) { + // copy all nodes + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + this.sectors["frozen"][sectorId]["nodes"][nodeId] = this.nodes[nodeId]; } + } - // start the clustering if allowed - if ((!force && allowCluster) || force) { - // we loop over all edges INITIALLY connected to this hub - for (j = 0; j < amountOfInitialEdges; j++) { - edge = this.edges[edgesIdarray[j]]; - // the edge can be clustered by this function in a previous loop - if (edge !== undefined) { - var childNode = this.nodes[(edge.fromId == hubNode.id) ? edge.toId : edge.fromId]; - // we do not want hubs to merge with other hubs nor do we want to cluster itself. - if ((childNode.dynamicEdges.length <= (this.hubThreshold + absorptionSizeOffset)) && - (childNode.id != hubNode.id)) { - this._addToCluster(hubNode,childNode,force); - } - } - } + // copy all edges (if not fully clustered, else there are no edges) + for (var edgeId in this.edges) { + if (this.edges.hasOwnProperty(edgeId)) { + this.sectors["frozen"][sectorId]["edges"][edgeId] = this.edges[edgeId]; } } + + // merge the nodeIndices + for (var i = 0; i < this.nodeIndices.length; i++) { + this.sectors["frozen"][sectorId]["nodeIndices"].push(this.nodeIndices[i]); + } }; - /** - * This function adds the child node to the parent node, creating a cluster if it is not already. + * This clusters the sector to one cluster. It was a single cluster before this process started so + * we revert to that state. The clusterToFit function with a maximum size of 1 node does this. * - * @param {Node} parentNode | this is the node that will house the child node - * @param {Node} childNode | this node will be deleted from the global this.nodes and stored in the parent node - * @param {Boolean} force | true will only update the remainingEdges at the very end of the clustering, ensuring single level collapse * @private */ - exports._addToCluster = function(parentNode, childNode, force) { - // join child node in the parent node - parentNode.containedNodes[childNode.id] = childNode; - - // manage all the edges connected to the child and parent nodes - for (var i = 0; i < childNode.dynamicEdges.length; i++) { - var edge = childNode.dynamicEdges[i]; - if (edge.toId == parentNode.id || edge.fromId == parentNode.id) { // edge connected to parentNode - this._addToContainedEdges(parentNode,childNode,edge); - } - else { - this._connectEdgeToCluster(parentNode,childNode,edge); - } - } - // a contained node has no dynamic edges. - childNode.dynamicEdges = []; - - // remove circular edges from clusters - this._containCircularEdgesFromNode(parentNode,childNode); + exports._collapseThisToSingleCluster = function() { + this.clusterToFit(1,false); + }; - // remove the childNode from the global nodes object - delete this.nodes[childNode.id]; + /** + * We create a new active sector from the node that we want to open. + * + * @param node + * @private + */ + exports._addSector = function(node) { + // this is the currently active sector + var sector = this._sector(); - // update the properties of the child and parent - var massBefore = parentNode.options.mass; - childNode.clusterSession = this.clusterSession; - parentNode.options.mass += childNode.options.mass; - parentNode.clusterSize += childNode.clusterSize; - parentNode.options.fontSize = Math.min(this.constants.clustering.maxFontSize, this.constants.nodes.fontSize + this.constants.clustering.fontSizeMultiplier*parentNode.clusterSize); + // // this should allow me to select nodes from a frozen set. + // if (this.sectors['active'][sector]["nodes"].hasOwnProperty(node.id)) { + // console.log("the node is part of the active sector"); + // } + // else { + // console.log("I dont know what the fuck happened!!"); + // } - // keep track of the clustersessions so we can open the cluster up as it has been formed. - if (parentNode.clusterSessions[parentNode.clusterSessions.length - 1] != this.clusterSession) { - parentNode.clusterSessions.push(this.clusterSession); - } + // when we switch to a new sector, we remove the node that will be expanded from the current nodes list. + delete this.nodes[node.id]; - // forced clusters only open from screen size and double tap - if (force == true) { - // parentNode.formationScale = Math.pow(1 - (1.0/11.0),this.clusterSession+3); - parentNode.formationScale = 0; - } - else { - parentNode.formationScale = this.scale; // The latest child has been added on this scale - } + var unqiueIdentifier = util.randomUUID(); - // recalculate the size of the node on the next time the node is rendered - parentNode.clearSizeCache(); + // we fully freeze the currently active sector + this._freezeSector(sector); - // set the pop-out scale for the childnode - parentNode.containedNodes[childNode.id].formationScale = parentNode.formationScale; + // we create a new active sector. This sector has the Id of the node to ensure uniqueness + this._createNewSector(unqiueIdentifier); - // nullify the movement velocity of the child, this is to avoid hectic behaviour - childNode.clearVelocity(); + // we add the active sector to the sectors array to be able to revert these steps later on + this._setActiveSector(unqiueIdentifier); - // the mass has altered, preservation of energy dictates the velocity to be updated - parentNode.updateVelocity(massBefore); + // we redirect the global references to the new sector's references. this._sector() now returns unqiueIdentifier + this._switchToSector(this._sector()); - // restart the simulation to reorganise all nodes - this.moving = true; + // finally we add the node we removed from our previous active sector to the new active sector + this.nodes[node.id] = node; }; /** - * This function will apply the changes made to the remainingEdges during the formation of the clusters. - * This is a seperate function to allow for level-wise collapsing of the node barnesHutTree. - * It has to be called if a level is collapsed. It is called by _formClusters(). + * We close the sector that is currently open and revert back to the one before. + * If the active sector is the "default" sector, nothing happens. + * * @private */ - exports._updateDynamicEdges = function() { - for (var i = 0; i < this.nodeIndices.length; i++) { - var node = this.nodes[this.nodeIndices[i]]; - node.dynamicEdgesLength = node.dynamicEdges.length; + exports._collapseSector = function() { + // the currently active sector + var sector = this._sector(); - // this corrects for multiple edges pointing at the same other node - var correction = 0; - if (node.dynamicEdgesLength > 1) { - for (var j = 0; j < node.dynamicEdgesLength - 1; j++) { - var edgeToId = node.dynamicEdges[j].toId; - var edgeFromId = node.dynamicEdges[j].fromId; - for (var k = j+1; k < node.dynamicEdgesLength; k++) { - if ((node.dynamicEdges[k].toId == edgeToId && node.dynamicEdges[k].fromId == edgeFromId) || - (node.dynamicEdges[k].fromId == edgeToId && node.dynamicEdges[k].toId == edgeFromId)) { - correction += 1; - } - } - } + // we cannot collapse the default sector + if (sector != "default") { + if ((this.nodeIndices.length == 1) || + (this.sectors["active"][sector]["drawingNode"].width*this.scale < this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientWidth) || + (this.sectors["active"][sector]["drawingNode"].height*this.scale < this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientHeight)) { + var previousSector = this._previousSector(); + + // we collapse the sector back to a single cluster + this._collapseThisToSingleCluster(); + + // we move the remaining nodes, edges and nodeIndices to the previous sector. + // This previous sector is the one we will reactivate + this._mergeThisWithFrozen(previousSector); + + // the previously active (frozen) sector now has all the data from the currently active sector. + // we can now delete the active sector. + this._deleteActiveSector(sector); + + // we activate the previously active (and currently frozen) sector. + this._activateSector(previousSector); + + // we load the references from the newly active sector into the global references + this._switchToSector(previousSector); + + // we forget the previously active sector because we reverted to the one before + this._forgetLastSector(); + + // finally, we update the node index list. + this._updateNodeIndexList(); + + // we refresh the list with calulation nodes and calculation node indices. + this._updateCalculationNodes(); } - node.dynamicEdgesLength -= correction; } }; /** - * This adds an edge from the childNode to the contained edges of the parent node + * This runs a function in all active sectors. This is used in _redraw() and the _initializeForceCalculation(). * - * @param parentNode | Node object - * @param childNode | Node object - * @param edge | Edge object + * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors + * | we dont pass the function itself because then the "this" is the window object + * | instead of the Network object + * @param {*} [argument] | Optional: arguments to pass to the runFunction * @private */ - exports._addToContainedEdges = function(parentNode, childNode, edge) { - // create an array object if it does not yet exist for this childNode - if (!(parentNode.containedEdges.hasOwnProperty(childNode.id))) { - parentNode.containedEdges[childNode.id] = [] + exports._doInAllActiveSectors = function(runFunction,argument) { + var returnValues = []; + if (argument === undefined) { + for (var sector in this.sectors["active"]) { + if (this.sectors["active"].hasOwnProperty(sector)) { + // switch the global references to those of this sector + this._switchToActiveSector(sector); + returnValues.push( this[runFunction]() ); + } + } } - // add this edge to the list - parentNode.containedEdges[childNode.id].push(edge); - - // remove the edge from the global edges object - delete this.edges[edge.id]; - - // remove the edge from the parent object - for (var i = 0; i < parentNode.dynamicEdges.length; i++) { - if (parentNode.dynamicEdges[i].id == edge.id) { - parentNode.dynamicEdges.splice(i,1); - break; + else { + for (var sector in this.sectors["active"]) { + if (this.sectors["active"].hasOwnProperty(sector)) { + // switch the global references to those of this sector + this._switchToActiveSector(sector); + var args = Array.prototype.splice.call(arguments, 1); + if (args.length > 1) { + returnValues.push( this[runFunction](args[0],args[1]) ); + } + else { + returnValues.push( this[runFunction](argument) ); + } + } } } + // we revert the global references back to our active sector + this._loadLatestSector(); + return returnValues; }; + /** - * This function connects an edge that was connected to a child node to the parent node. - * It keeps track of which nodes it has been connected to with the originalId array. + * This runs a function in all active sectors. This is used in _redraw() and the _initializeForceCalculation(). * - * @param {Node} parentNode | Node object - * @param {Node} childNode | Node object - * @param {Edge} edge | Edge object + * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors + * | we dont pass the function itself because then the "this" is the window object + * | instead of the Network object + * @param {*} [argument] | Optional: arguments to pass to the runFunction * @private */ - exports._connectEdgeToCluster = function(parentNode, childNode, edge) { - // handle circular edges - if (edge.toId == edge.fromId) { - this._addToContainedEdges(parentNode, childNode, edge); + exports._doInSupportSector = function(runFunction,argument) { + var returnValues = false; + if (argument === undefined) { + this._switchToSupportSector(); + returnValues = this[runFunction](); } else { - if (edge.toId == childNode.id) { // edge connected to other node on the "to" side - edge.originalToId.push(childNode.id); - edge.to = parentNode; - edge.toId = parentNode.id; + this._switchToSupportSector(); + var args = Array.prototype.splice.call(arguments, 1); + if (args.length > 1) { + returnValues = this[runFunction](args[0],args[1]); } - else { // edge connected to other node with the "from" side - - edge.originalFromId.push(childNode.id); - edge.from = parentNode; - edge.fromId = parentNode.id; + else { + returnValues = this[runFunction](argument); } - - this._addToReroutedEdges(parentNode,childNode,edge); } + // we revert the global references back to our active sector + this._loadLatestSector(); + return returnValues; }; /** - * If a node is connected to itself, a circular edge is drawn. When clustering we want to contain - * these edges inside of the cluster. + * This runs a function in all frozen sectors. This is used in the _redraw(). * - * @param parentNode - * @param childNode + * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors + * | we don't pass the function itself because then the "this" is the window object + * | instead of the Network object + * @param {*} [argument] | Optional: arguments to pass to the runFunction * @private */ - exports._containCircularEdgesFromNode = function(parentNode, childNode) { - // manage all the edges connected to the child and parent nodes - for (var i = 0; i < parentNode.dynamicEdges.length; i++) { - var edge = parentNode.dynamicEdges[i]; - // handle circular edges - if (edge.toId == edge.fromId) { - this._addToContainedEdges(parentNode, childNode, edge); + exports._doInAllFrozenSectors = function(runFunction,argument) { + if (argument === undefined) { + for (var sector in this.sectors["frozen"]) { + if (this.sectors["frozen"].hasOwnProperty(sector)) { + // switch the global references to those of this sector + this._switchToFrozenSector(sector); + this[runFunction](); + } + } + } + else { + for (var sector in this.sectors["frozen"]) { + if (this.sectors["frozen"].hasOwnProperty(sector)) { + // switch the global references to those of this sector + this._switchToFrozenSector(sector); + var args = Array.prototype.splice.call(arguments, 1); + if (args.length > 1) { + this[runFunction](args[0],args[1]); + } + else { + this[runFunction](argument); + } + } } } + this._loadLatestSector(); }; /** - * This adds an edge from the childNode to the rerouted edges of the parent node + * This runs a function in all sectors. This is used in the _redraw(). * - * @param parentNode | Node object - * @param childNode | Node object - * @param edge | Edge object + * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors + * | we don't pass the function itself because then the "this" is the window object + * | instead of the Network object + * @param {*} [argument] | Optional: arguments to pass to the runFunction * @private */ - exports._addToReroutedEdges = function(parentNode, childNode, edge) { - // create an array object if it does not yet exist for this childNode - // we store the edge in the rerouted edges so we can restore it when the cluster pops open - if (!(parentNode.reroutedEdges.hasOwnProperty(childNode.id))) { - parentNode.reroutedEdges[childNode.id] = []; + exports._doInAllSectors = function(runFunction,argument) { + var args = Array.prototype.splice.call(arguments, 1); + if (argument === undefined) { + this._doInAllActiveSectors(runFunction); + this._doInAllFrozenSectors(runFunction); } - parentNode.reroutedEdges[childNode.id].push(edge); + else { + if (args.length > 1) { + this._doInAllActiveSectors(runFunction,args[0],args[1]); + this._doInAllFrozenSectors(runFunction,args[0],args[1]); + } + else { + this._doInAllActiveSectors(runFunction,argument); + this._doInAllFrozenSectors(runFunction,argument); + } + } + }; - // this edge becomes part of the dynamicEdges of the cluster node - parentNode.dynamicEdges.push(edge); - }; + /** + * This clears the nodeIndices list. We cannot use this.nodeIndices = [] because we would break the link with the + * active sector. Thus we clear the nodeIndices in the active sector, then reconnect the this.nodeIndices to it. + * + * @private + */ + exports._clearNodeIndexList = function() { + var sector = this._sector(); + this.sectors["active"][sector]["nodeIndices"] = []; + this.nodeIndices = this.sectors["active"][sector]["nodeIndices"]; + }; /** - * This function connects an edge that was connected to a cluster node back to the child node. + * Draw the encompassing sector node * - * @param parentNode | Node object - * @param childNode | Node object + * @param ctx + * @param sectorType * @private */ - exports._connectEdgeBackToChild = function(parentNode, childNode) { - if (parentNode.reroutedEdges.hasOwnProperty(childNode.id)) { - for (var i = 0; i < parentNode.reroutedEdges[childNode.id].length; i++) { - var edge = parentNode.reroutedEdges[childNode.id][i]; - if (edge.originalFromId[edge.originalFromId.length-1] == childNode.id) { - edge.originalFromId.pop(); - edge.fromId = childNode.id; - edge.from = childNode; - } - else { - edge.originalToId.pop(); - edge.toId = childNode.id; - edge.to = childNode; - } + exports._drawSectorNodes = function(ctx,sectorType) { + var minY = 1e9, maxY = -1e9, minX = 1e9, maxX = -1e9, node; + for (var sector in this.sectors[sectorType]) { + if (this.sectors[sectorType].hasOwnProperty(sector)) { + if (this.sectors[sectorType][sector]["drawingNode"] !== undefined) { - // append this edge to the list of edges connecting to the childnode - childNode.dynamicEdges.push(edge); + this._switchToSector(sector,sectorType); - // remove the edge from the parent object - for (var j = 0; j < parentNode.dynamicEdges.length; j++) { - if (parentNode.dynamicEdges[j].id == edge.id) { - parentNode.dynamicEdges.splice(j,1); - break; + minY = 1e9; maxY = -1e9; minX = 1e9; maxX = -1e9; + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + node.resize(ctx); + if (minX > node.x - 0.5 * node.width) {minX = node.x - 0.5 * node.width;} + if (maxX < node.x + 0.5 * node.width) {maxX = node.x + 0.5 * node.width;} + if (minY > node.y - 0.5 * node.height) {minY = node.y - 0.5 * node.height;} + if (maxY < node.y + 0.5 * node.height) {maxY = node.y + 0.5 * node.height;} + } } + node = this.sectors[sectorType][sector]["drawingNode"]; + node.x = 0.5 * (maxX + minX); + node.y = 0.5 * (maxY + minY); + node.width = 2 * (node.x - minX); + node.height = 2 * (node.y - minY); + node.options.radius = Math.sqrt(Math.pow(0.5*node.width,2) + Math.pow(0.5*node.height,2)); + node.setScale(this.scale); + node._drawCircle(ctx); } } - // remove the entry from the rerouted edges - delete parentNode.reroutedEdges[childNode.id]; } }; + exports._drawAllSectorNodes = function(ctx) { + this._drawSectorNodes(ctx,"frozen"); + this._drawSectorNodes(ctx,"active"); + this._loadLatestSector(); + }; + + +/***/ }, +/* 62 */ +/***/ function(module, exports, __webpack_require__) { + + var Node = __webpack_require__(40); /** - * When loops are clustered, an edge can be both in the rerouted array and the contained array. - * This function is called last to verify that all edges in dynamicEdges are in fact connected to the - * parentNode + * This function can be called from the _doInAllSectors function * - * @param parentNode | Node object + * @param object + * @param overlappingNodes * @private */ - exports._validateEdges = function(parentNode) { - for (var i = 0; i < parentNode.dynamicEdges.length; i++) { - var edge = parentNode.dynamicEdges[i]; - if (parentNode.id != edge.toId && parentNode.id != edge.fromId) { - parentNode.dynamicEdges.splice(i,1); + exports._getNodesOverlappingWith = function(object, overlappingNodes) { + var nodes = this.nodes; + for (var nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + if (nodes[nodeId].isOverlappingWith(object)) { + overlappingNodes.push(nodeId); + } } } }; - /** - * This function released the contained edges back into the global domain and puts them back into the - * dynamic edges of both parent and child. - * - * @param {Node} parentNode | - * @param {Node} childNode | + * retrieve all nodes overlapping with given object + * @param {Object} object An object with parameters left, top, right, bottom + * @return {Number[]} An array with id's of the overlapping nodes * @private */ - exports._releaseContainedEdges = function(parentNode, childNode) { - for (var i = 0; i < parentNode.containedEdges[childNode.id].length; i++) { - var edge = parentNode.containedEdges[childNode.id][i]; + exports._getAllNodesOverlappingWith = function (object) { + var overlappingNodes = []; + this._doInAllActiveSectors("_getNodesOverlappingWith",object,overlappingNodes); + return overlappingNodes; + }; - // put the edge back in the global edges object - this.edges[edge.id] = edge; - // put the edge back in the dynamic edges of the child and parent - childNode.dynamicEdges.push(edge); - parentNode.dynamicEdges.push(edge); - } - // remove the entry from the contained edges - delete parentNode.containedEdges[childNode.id]; + /** + * Return a position object in canvasspace from a single point in screenspace + * + * @param pointer + * @returns {{left: number, top: number, right: number, bottom: number}} + * @private + */ + exports._pointerToPositionObject = function(pointer) { + var x = this._XconvertDOMtoCanvas(pointer.x); + var y = this._YconvertDOMtoCanvas(pointer.y); + return { + left: x, + top: y, + right: x, + bottom: y + }; }; + /** + * Get the top node at the a specific point (like a click) + * + * @param {{x: Number, y: Number}} pointer + * @return {Node | null} node + * @private + */ + exports._getNodeAt = function (pointer) { + // we first check if this is an navigation controls element + var positionObject = this._pointerToPositionObject(pointer); + var overlappingNodes = this._getAllNodesOverlappingWith(positionObject); - - // ------------------- UTILITY FUNCTIONS ---------------------------- // + // if there are overlapping nodes, select the last one, this is the + // one which is drawn on top of the others + if (overlappingNodes.length > 0) { + return this.nodes[overlappingNodes[overlappingNodes.length - 1]]; + } + else { + return null; + } + }; /** - * This updates the node labels for all nodes (for debugging purposes) + * retrieve all edges overlapping with given object, selector is around center + * @param {Object} object An object with parameters left, top, right, bottom + * @return {Number[]} An array with id's of the overlapping nodes + * @private */ - exports.updateLabels = function() { - var nodeId; - // update node labels - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - var node = this.nodes[nodeId]; - if (node.clusterSize > 1) { - node.label = "[".concat(String(node.clusterSize),"]"); - } - } - } - - // update node labels - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - if (node.clusterSize == 1) { - if (node.originalLabel !== undefined) { - node.label = node.originalLabel; - } - else { - node.label = String(node.id); - } + exports._getEdgesOverlappingWith = function (object, overlappingEdges) { + var edges = this.edges; + for (var edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + if (edges[edgeId].isOverlappingWith(object)) { + overlappingEdges.push(edgeId); } } } + }; - // /* Debug Override */ - // for (nodeId in this.nodes) { - // if (this.nodes.hasOwnProperty(nodeId)) { - // node = this.nodes[nodeId]; - // node.label = String(node.level); - // } - // } + /** + * retrieve all nodes overlapping with given object + * @param {Object} object An object with parameters left, top, right, bottom + * @return {Number[]} An array with id's of the overlapping nodes + * @private + */ + exports._getAllEdgesOverlappingWith = function (object) { + var overlappingEdges = []; + this._doInAllActiveSectors("_getEdgesOverlappingWith",object,overlappingEdges); + return overlappingEdges; }; - /** - * We want to keep the cluster level distribution rather small. This means we do not want unclustered nodes - * if the rest of the nodes are already a few cluster levels in. - * To fix this we use this function. It determines the min and max cluster level and sends nodes that have not - * clustered enough to the clusterToSmallestNeighbours function. + * Place holder. To implement change the _getNodeAt to a _getObjectAt. Have the _getObjectAt call + * _getNodeAt and _getEdgesAt, then priortize the selection to user preferences. + * + * @param pointer + * @returns {null} + * @private */ - exports.normalizeClusterLevels = function() { - var maxLevel = 0; - var minLevel = 1e9; - var clusterLevel = 0; - var nodeId; + exports._getEdgeAt = function(pointer) { + var positionObject = this._pointerToPositionObject(pointer); + var overlappingEdges = this._getAllEdgesOverlappingWith(positionObject); - // we loop over all nodes in the list - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - clusterLevel = this.nodes[nodeId].clusterSessions.length; - if (maxLevel < clusterLevel) {maxLevel = clusterLevel;} - if (minLevel > clusterLevel) {minLevel = clusterLevel;} - } + if (overlappingEdges.length > 0) { + return this.edges[overlappingEdges[overlappingEdges.length - 1]]; } - - if (maxLevel - minLevel > this.constants.clustering.clusterLevelDifference) { - var amountOfNodes = this.nodeIndices.length; - var targetLevel = maxLevel - this.constants.clustering.clusterLevelDifference; - // we loop over all nodes in the list - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - if (this.nodes[nodeId].clusterSessions.length < targetLevel) { - this._clusterToSmallestNeighbour(this.nodes[nodeId]); - } - } - } - this._updateNodeIndexList(); - this._updateDynamicEdges(); - // if a cluster was formed, we increase the clusterSession - if (this.nodeIndices.length != amountOfNodes) { - this.clusterSession += 1; - } + else { + return null; } }; - /** - * This function determines if the cluster we want to decluster is in the active area - * this means around the zoom center + * Add object to the selection array. * - * @param {Node} node - * @returns {boolean} + * @param obj * @private */ - exports._nodeInActiveArea = function(node) { - return ( - Math.abs(node.x - this.areaCenter.x) <= this.constants.clustering.activeAreaBoxSize/this.scale - && - Math.abs(node.y - this.areaCenter.y) <= this.constants.clustering.activeAreaBoxSize/this.scale - ) + exports._addToSelection = function(obj) { + if (obj instanceof Node) { + this.selectionObj.nodes[obj.id] = obj; + } + else { + this.selectionObj.edges[obj.id] = obj; + } }; - /** - * This is an adaptation of the original repositioning function. This is called if the system is clustered initially - * It puts large clusters away from the center and randomizes the order. + * Add object to the selection array. * + * @param obj + * @private */ - exports.repositionNodes = function() { - for (var i = 0; i < this.nodeIndices.length; i++) { - var node = this.nodes[this.nodeIndices[i]]; - if ((node.xFixed == false || node.yFixed == false)) { - var radius = 10 * 0.1*this.nodeIndices.length * Math.min(100,node.options.mass); - var angle = 2 * Math.PI * Math.random(); - if (node.xFixed == false) {node.x = radius * Math.cos(angle);} - if (node.yFixed == false) {node.y = radius * Math.sin(angle);} - this._repositionBezierNodes(node); - } + exports._addToHover = function(obj) { + if (obj instanceof Node) { + this.hoverObj.nodes[obj.id] = obj; + } + else { + this.hoverObj.edges[obj.id] = obj; } }; /** - * We determine how many connections denote an important hub. - * We take the mean + 2*std as the important hub size. (Assuming a normal distribution of data, ~2.2%) + * Remove a single option from selection. * + * @param {Object} obj * @private */ - exports._getHubSize = function() { - var average = 0; - var averageSquared = 0; - var hubCounter = 0; - var largestHub = 0; - - for (var i = 0; i < this.nodeIndices.length; i++) { + exports._removeFromSelection = function(obj) { + if (obj instanceof Node) { + delete this.selectionObj.nodes[obj.id]; + } + else { + delete this.selectionObj.edges[obj.id]; + } + }; - var node = this.nodes[this.nodeIndices[i]]; - if (node.dynamicEdgesLength > largestHub) { - largestHub = node.dynamicEdgesLength; + /** + * Unselect all. The selectionObj is useful for this. + * + * @param {Boolean} [doNotTrigger] | ignore trigger + * @private + */ + exports._unselectAll = function(doNotTrigger) { + if (doNotTrigger === undefined) { + doNotTrigger = false; + } + for(var nodeId in this.selectionObj.nodes) { + if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { + this.selectionObj.nodes[nodeId].unselect(); + } + } + for(var edgeId in this.selectionObj.edges) { + if(this.selectionObj.edges.hasOwnProperty(edgeId)) { + this.selectionObj.edges[edgeId].unselect(); } - average += node.dynamicEdgesLength; - averageSquared += Math.pow(node.dynamicEdgesLength,2); - hubCounter += 1; } - average = average / hubCounter; - averageSquared = averageSquared / hubCounter; - var variance = averageSquared - Math.pow(average,2); + this.selectionObj = {nodes:{},edges:{}}; - var standardDeviation = Math.sqrt(variance); + if (doNotTrigger == false) { + this.emit('select', this.getSelection()); + } + }; - this.hubThreshold = Math.floor(average + 2*standardDeviation); + /** + * Unselect all clusters. The selectionObj is useful for this. + * + * @param {Boolean} [doNotTrigger] | ignore trigger + * @private + */ + exports._unselectClusters = function(doNotTrigger) { + if (doNotTrigger === undefined) { + doNotTrigger = false; + } - // always have at least one to cluster - if (this.hubThreshold > largestHub) { - this.hubThreshold = largestHub; + for (var nodeId in this.selectionObj.nodes) { + if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { + if (this.selectionObj.nodes[nodeId].clusterSize > 1) { + this.selectionObj.nodes[nodeId].unselect(); + this._removeFromSelection(this.selectionObj.nodes[nodeId]); + } + } } - // console.log("average",average,"averageSQ",averageSquared,"var",variance,"std",standardDeviation); - // console.log("hubThreshold:",this.hubThreshold); + if (doNotTrigger == false) { + this.emit('select', this.getSelection()); + } }; /** - * We reduce the amount of "extension nodes" or chains. These are not quickly clustered with the outliers and hubs methods - * with this amount we can cluster specifically on these chains. + * return the number of selected nodes * - * @param {Number} fraction | between 0 and 1, the percentage of chains to reduce + * @returns {number} * @private */ - exports._reduceAmountOfChains = function(fraction) { - this.hubThreshold = 2; - var reduceAmount = Math.floor(this.nodeIndices.length * fraction); - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - if (this.nodes[nodeId].dynamicEdgesLength == 2 && this.nodes[nodeId].dynamicEdges.length >= 2) { - if (reduceAmount > 0) { - this._formClusterFromHub(this.nodes[nodeId],true,true,1); - reduceAmount -= 1; - } - } + exports._getSelectedNodeCount = function() { + var count = 0; + for (var nodeId in this.selectionObj.nodes) { + if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { + count += 1; } } + return count; }; /** - * We get the amount of "extension nodes" or chains. These are not quickly clustered with the outliers and hubs methods - * with this amount we can cluster specifically on these chains. + * return the selected node * + * @returns {number} * @private */ - exports._getChainFraction = function() { - var chains = 0; - var total = 0; - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - if (this.nodes[nodeId].dynamicEdgesLength == 2 && this.nodes[nodeId].dynamicEdges.length >= 2) { - chains += 1; - } - total += 1; + exports._getSelectedNode = function() { + for (var nodeId in this.selectionObj.nodes) { + if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { + return this.selectionObj.nodes[nodeId]; } } - return chains/total; + return null; }; - -/***/ }, -/* 65 */ -/***/ function(module, exports, __webpack_require__) { - - var util = __webpack_require__(1); - var Node = __webpack_require__(56); - /** - * Creation of the SectorMixin var. + * return the selected edge * - * This contains all the functions the Network object can use to employ the sector system. - * The sector system is always used by Network, though the benefits only apply to the use of clustering. - * If clustering is not used, there is no overhead except for a duplicate object with references to nodes and edges. + * @returns {number} + * @private */ + exports._getSelectedEdge = function() { + for (var edgeId in this.selectionObj.edges) { + if (this.selectionObj.edges.hasOwnProperty(edgeId)) { + return this.selectionObj.edges[edgeId]; + } + } + return null; + }; + /** - * This function is only called by the setData function of the Network object. - * This loads the global references into the active sector. This initializes the sector. + * return the number of selected edges * + * @returns {number} * @private */ - exports._putDataInSector = function() { - this.sectors["active"][this._sector()].nodes = this.nodes; - this.sectors["active"][this._sector()].edges = this.edges; - this.sectors["active"][this._sector()].nodeIndices = this.nodeIndices; + exports._getSelectedEdgeCount = function() { + var count = 0; + for (var edgeId in this.selectionObj.edges) { + if (this.selectionObj.edges.hasOwnProperty(edgeId)) { + count += 1; + } + } + return count; }; /** - * /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the supplied (active) sector. If a type is defined, do the specific type + * return the number of selected objects. * - * @param {String} sectorId - * @param {String} [sectorType] | "active" or "frozen" + * @returns {number} * @private */ - exports._switchToSector = function(sectorId, sectorType) { - if (sectorType === undefined || sectorType == "active") { - this._switchToActiveSector(sectorId); + exports._getSelectedObjectCount = function() { + var count = 0; + for(var nodeId in this.selectionObj.nodes) { + if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { + count += 1; + } } - else { - this._switchToFrozenSector(sectorId); + for(var edgeId in this.selectionObj.edges) { + if(this.selectionObj.edges.hasOwnProperty(edgeId)) { + count += 1; + } } + return count; }; - /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the supplied active sector. + * Check if anything is selected * - * @param sectorId + * @returns {boolean} * @private */ - exports._switchToActiveSector = function(sectorId) { - this.nodeIndices = this.sectors["active"][sectorId]["nodeIndices"]; - this.nodes = this.sectors["active"][sectorId]["nodes"]; - this.edges = this.sectors["active"][sectorId]["edges"]; + exports._selectionIsEmpty = function() { + for(var nodeId in this.selectionObj.nodes) { + if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { + return false; + } + } + for(var edgeId in this.selectionObj.edges) { + if(this.selectionObj.edges.hasOwnProperty(edgeId)) { + return false; + } + } + return true; }; /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the supplied active sector. + * check if one of the selected nodes is a cluster. * + * @returns {boolean} * @private */ - exports._switchToSupportSector = function() { - this.nodeIndices = this.sectors["support"]["nodeIndices"]; - this.nodes = this.sectors["support"]["nodes"]; - this.edges = this.sectors["support"]["edges"]; + exports._clusterInSelection = function() { + for(var nodeId in this.selectionObj.nodes) { + if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { + if (this.selectionObj.nodes[nodeId].clusterSize > 1) { + return true; + } + } + } + return false; }; - /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the supplied frozen sector. + * select the edges connected to the node that is being selected * - * @param sectorId + * @param {Node} node * @private */ - exports._switchToFrozenSector = function(sectorId) { - this.nodeIndices = this.sectors["frozen"][sectorId]["nodeIndices"]; - this.nodes = this.sectors["frozen"][sectorId]["nodes"]; - this.edges = this.sectors["frozen"][sectorId]["edges"]; + exports._selectConnectedEdges = function(node) { + for (var i = 0; i < node.dynamicEdges.length; i++) { + var edge = node.dynamicEdges[i]; + edge.select(); + this._addToSelection(edge); + } }; - /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the currently active sector. + * select the edges connected to the node that is being selected * + * @param {Node} node * @private */ - exports._loadLatestSector = function() { - this._switchToSector(this._sector()); + exports._hoverConnectedEdges = function(node) { + for (var i = 0; i < node.dynamicEdges.length; i++) { + var edge = node.dynamicEdges[i]; + edge.hover = true; + this._addToHover(edge); + } }; /** - * This function returns the currently active sector Id + * unselect the edges connected to the node that is being selected * - * @returns {String} + * @param {Node} node * @private */ - exports._sector = function() { - return this.activeSector[this.activeSector.length-1]; + exports._unselectConnectedEdges = function(node) { + for (var i = 0; i < node.dynamicEdges.length; i++) { + var edge = node.dynamicEdges[i]; + edge.unselect(); + this._removeFromSelection(edge); + } }; + + /** - * This function returns the previously active sector Id + * This is called when someone clicks on a node. either select or deselect it. + * If there is an existing selection and we don't want to append to it, clear the existing selection * - * @returns {String} + * @param {Node || Edge} object + * @param {Boolean} append + * @param {Boolean} [doNotTrigger] | ignore trigger * @private */ - exports._previousSector = function() { - if (this.activeSector.length > 1) { - return this.activeSector[this.activeSector.length-2]; + exports._selectObject = function(object, append, doNotTrigger, highlightEdges, overrideSelectable) { + if (doNotTrigger === undefined) { + doNotTrigger = false; + } + if (highlightEdges === undefined) { + highlightEdges = true; + } + + if (this._selectionIsEmpty() == false && append == false && this.forceAppendSelection == false) { + this._unselectAll(true); + } + + // selectable allows the object to be selected. Override can be used if needed to bypass this. + if (object.selected == false && (this.constants.selectable == true || overrideSelectable)) { + object.select(); + this._addToSelection(object); + if (object instanceof Node && this.blockConnectingEdgeSelection == false && highlightEdges == true) { + this._selectConnectedEdges(object); + } + } + // do not select the object if selectable is false, only add it to selection to allow drag to work + else if (object.selected == false) { + this._addToSelection(object); + doNotTrigger = true; } else { - throw new TypeError('there are not enough sectors in the this.activeSector array.'); + object.unselect(); + this._removeFromSelection(object); + } + + if (doNotTrigger == false) { + this.emit('select', this.getSelection()); } }; /** - * We add the active sector at the end of the this.activeSector array - * This ensures it is the currently active sector returned by _sector() and it reaches the top - * of the activeSector stack. When we reverse our steps we move from the end to the beginning of this stack. + * This is called when someone clicks on a node. either select or deselect it. + * If there is an existing selection and we don't want to append to it, clear the existing selection * - * @param newId + * @param {Node || Edge} object * @private */ - exports._setActiveSector = function(newId) { - this.activeSector.push(newId); + exports._blurObject = function(object) { + if (object.hover == true) { + object.hover = false; + this.emit("blurNode",{node:object.id}); + } }; - /** - * We remove the currently active sector id from the active sector stack. This happens when - * we reactivate the previously active sector + * This is called when someone clicks on a node. either select or deselect it. + * If there is an existing selection and we don't want to append to it, clear the existing selection * + * @param {Node || Edge} object * @private */ - exports._forgetLastSector = function() { - this.activeSector.pop(); + exports._hoverObject = function(object) { + if (object.hover == false) { + object.hover = true; + this._addToHover(object); + if (object instanceof Node) { + this.emit("hoverNode",{node:object.id}); + } + } + if (object instanceof Node) { + this._hoverConnectedEdges(object); + } }; /** - * This function creates a new active sector with the supplied newId. This newId - * is the expanding node id. + * handles the selection part of the touch, only for navigation controls elements; + * Touch is triggered before tap, also before hold. Hold triggers after a while. + * This is the most responsive solution * - * @param {String} newId | Id of the new active sector + * @param {Object} pointer * @private */ - exports._createNewSector = function(newId) { - // create the new sector - this.sectors["active"][newId] = {"nodes":{}, - "edges":{}, - "nodeIndices":[], - "formationScale": this.scale, - "drawingNode": undefined}; + exports._handleTouch = function(pointer) { + }; - // create the new sector render node. This gives visual feedback that you are in a new sector. - this.sectors["active"][newId]['drawingNode'] = new Node( - {id:newId, - color: { - background: "#eaefef", - border: "495c5e" - } - },{},{},this.constants); - this.sectors["active"][newId]['drawingNode'].clusterSize = 2; + + /** + * handles the selection part of the tap; + * + * @param {Object} pointer + * @private + */ + exports._handleTap = function(pointer) { + var node = this._getNodeAt(pointer); + if (node != null) { + this._selectObject(node, false); + } + else { + var edge = this._getEdgeAt(pointer); + if (edge != null) { + this._selectObject(edge, false); + } + else { + this._unselectAll(); + } + } + var properties = this.getSelection(); + properties['pointer'] = { + DOM: {x: pointer.x, y: pointer.y}, + canvas: {x: this._XconvertDOMtoCanvas(pointer.x), y: this._YconvertDOMtoCanvas(pointer.y)} + } + this.emit("click", properties); + this._redraw(); }; /** - * This function removes the currently active sector. This is called when we create a new - * active sector. + * handles the selection part of the double tap and opens a cluster if needed * - * @param {String} sectorId | Id of the active sector that will be removed + * @param {Object} pointer * @private */ - exports._deleteActiveSector = function(sectorId) { - delete this.sectors["active"][sectorId]; + exports._handleDoubleTap = function(pointer) { + var node = this._getNodeAt(pointer); + if (node != null && node !== undefined) { + // we reset the areaCenter here so the opening of the node will occur + this.areaCenter = {"x" : this._XconvertDOMtoCanvas(pointer.x), + "y" : this._YconvertDOMtoCanvas(pointer.y)}; + this.openCluster(node); + } + var properties = this.getSelection(); + properties['pointer'] = { + DOM: {x: pointer.x, y: pointer.y}, + canvas: {x: this._XconvertDOMtoCanvas(pointer.x), y: this._YconvertDOMtoCanvas(pointer.y)} + } + this.emit("doubleClick", properties); }; /** - * This function removes the currently active sector. This is called when we reactivate - * the previously active sector. + * Handle the onHold selection part * - * @param {String} sectorId | Id of the active sector that will be removed + * @param pointer * @private */ - exports._deleteFrozenSector = function(sectorId) { - delete this.sectors["frozen"][sectorId]; + exports._handleOnHold = function(pointer) { + var node = this._getNodeAt(pointer); + if (node != null) { + this._selectObject(node,true); + } + else { + var edge = this._getEdgeAt(pointer); + if (edge != null) { + this._selectObject(edge,true); + } + } + this._redraw(); }; /** - * Freezing an active sector means moving it from the "active" object to the "frozen" object. - * We copy the references, then delete the active entree. + * handle the onRelease event. These functions are here for the navigation controls module + * and data manipulation module. * - * @param sectorId - * @private + * @private */ - exports._freezeSector = function(sectorId) { - // we move the set references from the active to the frozen stack. - this.sectors["frozen"][sectorId] = this.sectors["active"][sectorId]; - - // we have moved the sector data into the frozen set, we now remove it from the active set - this._deleteActiveSector(sectorId); + exports._handleOnRelease = function(pointer) { + this._manipulationReleaseOverload(pointer); + this._navigationReleaseOverload(pointer); }; + exports._manipulationReleaseOverload = function (pointer) {}; + exports._navigationReleaseOverload = function (pointer) {}; /** - * This is the reverse operation of _freezeSector. Activating means moving the sector from the "frozen" - * object to the "active" object. * - * @param sectorId - * @private + * retrieve the currently selected objects + * @return {{nodes: Array., edges: Array.}} selection */ - exports._activateSector = function(sectorId) { - // we move the set references from the frozen to the active stack. - this.sectors["active"][sectorId] = this.sectors["frozen"][sectorId]; - - // we have moved the sector data into the active set, we now remove it from the frozen stack - this._deleteFrozenSector(sectorId); + exports.getSelection = function() { + var nodeIds = this.getSelectedNodes(); + var edgeIds = this.getSelectedEdges(); + return {nodes:nodeIds, edges:edgeIds}; }; - /** - * This function merges the data from the currently active sector with a frozen sector. This is used - * in the process of reverting back to the previously active sector. - * The data that is placed in the frozen (the previously active) sector is the node that has been removed from it - * upon the creation of a new active sector. * - * @param sectorId - * @private + * retrieve the currently selected nodes + * @return {String[]} selection An array with the ids of the + * selected nodes. */ - exports._mergeThisWithFrozen = function(sectorId) { - // copy all nodes - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - this.sectors["frozen"][sectorId]["nodes"][nodeId] = this.nodes[nodeId]; + exports.getSelectedNodes = function() { + var idArray = []; + if (this.constants.selectable == true) { + for (var nodeId in this.selectionObj.nodes) { + if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { + idArray.push(nodeId); + } } } + return idArray + }; - // copy all edges (if not fully clustered, else there are no edges) - for (var edgeId in this.edges) { - if (this.edges.hasOwnProperty(edgeId)) { - this.sectors["frozen"][sectorId]["edges"][edgeId] = this.edges[edgeId]; + /** + * + * retrieve the currently selected edges + * @return {Array} selection An array with the ids of the + * selected nodes. + */ + exports.getSelectedEdges = function() { + var idArray = []; + if (this.constants.selectable == true) { + for (var edgeId in this.selectionObj.edges) { + if (this.selectionObj.edges.hasOwnProperty(edgeId)) { + idArray.push(edgeId); + } } } - - // merge the nodeIndices - for (var i = 0; i < this.nodeIndices.length; i++) { - this.sectors["frozen"][sectorId]["nodeIndices"].push(this.nodeIndices[i]); - } + return idArray; }; /** - * This clusters the sector to one cluster. It was a single cluster before this process started so - * we revert to that state. The clusterToFit function with a maximum size of 1 node does this. - * - * @private + * select zero or more nodes DEPRICATED + * @param {Number[] | String[]} selection An array with the ids of the + * selected nodes. */ - exports._collapseThisToSingleCluster = function() { - this.clusterToFit(1,false); + exports.setSelection = function() { + console.log("setSelection is deprecated. Please use selectNodes instead.") }; /** - * We create a new active sector from the node that we want to open. - * - * @param node - * @private + * select zero or more nodes with the option to highlight edges + * @param {Number[] | String[]} selection An array with the ids of the + * selected nodes. + * @param {boolean} [highlightEdges] */ - exports._addSector = function(node) { - // this is the currently active sector - var sector = this._sector(); - - // // this should allow me to select nodes from a frozen set. - // if (this.sectors['active'][sector]["nodes"].hasOwnProperty(node.id)) { - // console.log("the node is part of the active sector"); - // } - // else { - // console.log("I dont know what the fuck happened!!"); - // } - - // when we switch to a new sector, we remove the node that will be expanded from the current nodes list. - delete this.nodes[node.id]; - - var unqiueIdentifier = util.randomUUID(); - - // we fully freeze the currently active sector - this._freezeSector(sector); + exports.selectNodes = function(selection, highlightEdges) { + var i, iMax, id; - // we create a new active sector. This sector has the Id of the node to ensure uniqueness - this._createNewSector(unqiueIdentifier); + if (!selection || (selection.length == undefined)) + throw 'Selection must be an array with ids'; - // we add the active sector to the sectors array to be able to revert these steps later on - this._setActiveSector(unqiueIdentifier); + // first unselect any selected node + this._unselectAll(true); - // we redirect the global references to the new sector's references. this._sector() now returns unqiueIdentifier - this._switchToSector(this._sector()); + for (i = 0, iMax = selection.length; i < iMax; i++) { + id = selection[i]; - // finally we add the node we removed from our previous active sector to the new active sector - this.nodes[node.id] = node; + var node = this.nodes[id]; + if (!node) { + throw new RangeError('Node with id "' + id + '" not found'); + } + this._selectObject(node,true,true,highlightEdges,true); + } + this.redraw(); }; /** - * We close the sector that is currently open and revert back to the one before. - * If the active sector is the "default" sector, nothing happens. - * - * @private + * select zero or more edges + * @param {Number[] | String[]} selection An array with the ids of the + * selected nodes. */ - exports._collapseSector = function() { - // the currently active sector - var sector = this._sector(); - - // we cannot collapse the default sector - if (sector != "default") { - if ((this.nodeIndices.length == 1) || - (this.sectors["active"][sector]["drawingNode"].width*this.scale < this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientWidth) || - (this.sectors["active"][sector]["drawingNode"].height*this.scale < this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientHeight)) { - var previousSector = this._previousSector(); - - // we collapse the sector back to a single cluster - this._collapseThisToSingleCluster(); - - // we move the remaining nodes, edges and nodeIndices to the previous sector. - // This previous sector is the one we will reactivate - this._mergeThisWithFrozen(previousSector); - - // the previously active (frozen) sector now has all the data from the currently active sector. - // we can now delete the active sector. - this._deleteActiveSector(sector); - - // we activate the previously active (and currently frozen) sector. - this._activateSector(previousSector); + exports.selectEdges = function(selection) { + var i, iMax, id; - // we load the references from the newly active sector into the global references - this._switchToSector(previousSector); + if (!selection || (selection.length == undefined)) + throw 'Selection must be an array with ids'; - // we forget the previously active sector because we reverted to the one before - this._forgetLastSector(); + // first unselect any selected node + this._unselectAll(true); - // finally, we update the node index list. - this._updateNodeIndexList(); + for (i = 0, iMax = selection.length; i < iMax; i++) { + id = selection[i]; - // we refresh the list with calulation nodes and calculation node indices. - this._updateCalculationNodes(); + var edge = this.edges[id]; + if (!edge) { + throw new RangeError('Edge with id "' + id + '" not found'); } + this._selectObject(edge,true,true,false,true); } + this.redraw(); }; - /** - * This runs a function in all active sectors. This is used in _redraw() and the _initializeForceCalculation(). - * - * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors - * | we dont pass the function itself because then the "this" is the window object - * | instead of the Network object - * @param {*} [argument] | Optional: arguments to pass to the runFunction + * Validate the selection: remove ids of nodes which no longer exist * @private */ - exports._doInAllActiveSectors = function(runFunction,argument) { - var returnValues = []; - if (argument === undefined) { - for (var sector in this.sectors["active"]) { - if (this.sectors["active"].hasOwnProperty(sector)) { - // switch the global references to those of this sector - this._switchToActiveSector(sector); - returnValues.push( this[runFunction]() ); + exports._updateSelection = function () { + for(var nodeId in this.selectionObj.nodes) { + if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { + if (!this.nodes.hasOwnProperty(nodeId)) { + delete this.selectionObj.nodes[nodeId]; } } } - else { - for (var sector in this.sectors["active"]) { - if (this.sectors["active"].hasOwnProperty(sector)) { - // switch the global references to those of this sector - this._switchToActiveSector(sector); - var args = Array.prototype.splice.call(arguments, 1); - if (args.length > 1) { - returnValues.push( this[runFunction](args[0],args[1]) ); - } - else { - returnValues.push( this[runFunction](argument) ); - } + for(var edgeId in this.selectionObj.edges) { + if(this.selectionObj.edges.hasOwnProperty(edgeId)) { + if (!this.edges.hasOwnProperty(edgeId)) { + delete this.selectionObj.edges[edgeId]; } } } - // we revert the global references back to our active sector - this._loadLatestSector(); - return returnValues; }; +/***/ }, +/* 63 */ +/***/ function(module, exports, __webpack_require__) { + + var util = __webpack_require__(1); + var Node = __webpack_require__(40); + var Edge = __webpack_require__(37); + /** - * This runs a function in all active sectors. This is used in _redraw() and the _initializeForceCalculation(). + * clears the toolbar div element of children * - * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors - * | we dont pass the function itself because then the "this" is the window object - * | instead of the Network object - * @param {*} [argument] | Optional: arguments to pass to the runFunction * @private */ - exports._doInSupportSector = function(runFunction,argument) { - var returnValues = false; - if (argument === undefined) { - this._switchToSupportSector(); - returnValues = this[runFunction](); - } - else { - this._switchToSupportSector(); - var args = Array.prototype.splice.call(arguments, 1); - if (args.length > 1) { - returnValues = this[runFunction](args[0],args[1]); - } - else { - returnValues = this[runFunction](argument); - } - } - // we revert the global references back to our active sector - this._loadLatestSector(); - return returnValues; - }; + exports._clearManipulatorBar = function() { + this._recursiveDOMDelete(this.manipulationDiv); + this.manipulationDOM = {}; + this._manipulationReleaseOverload = function () {}; + delete this.sectors['support']['nodes']['targetNode']; + delete this.sectors['support']['nodes']['targetViaNode']; + this.controlNodesActive = false; + this.freezeSimulation = false; + }; /** - * This runs a function in all frozen sectors. This is used in the _redraw(). + * Manipulation UI temporarily overloads certain functions to extend or replace them. To be able to restore + * these functions to their original functionality, we saved them in this.cachedFunctions. + * This function restores these functions to their original function. * - * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors - * | we don't pass the function itself because then the "this" is the window object - * | instead of the Network object - * @param {*} [argument] | Optional: arguments to pass to the runFunction * @private */ - exports._doInAllFrozenSectors = function(runFunction,argument) { - if (argument === undefined) { - for (var sector in this.sectors["frozen"]) { - if (this.sectors["frozen"].hasOwnProperty(sector)) { - // switch the global references to those of this sector - this._switchToFrozenSector(sector); - this[runFunction](); - } - } - } - else { - for (var sector in this.sectors["frozen"]) { - if (this.sectors["frozen"].hasOwnProperty(sector)) { - // switch the global references to those of this sector - this._switchToFrozenSector(sector); - var args = Array.prototype.splice.call(arguments, 1); - if (args.length > 1) { - this[runFunction](args[0],args[1]); - } - else { - this[runFunction](argument); - } - } + exports._restoreOverloadedFunctions = function() { + for (var functionName in this.cachedFunctions) { + if (this.cachedFunctions.hasOwnProperty(functionName)) { + this[functionName] = this.cachedFunctions[functionName]; + delete this.cachedFunctions[functionName]; } } - this._loadLatestSector(); }; - /** - * This runs a function in all sectors. This is used in the _redraw(). + * Enable or disable edit-mode. * - * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors - * | we don't pass the function itself because then the "this" is the window object - * | instead of the Network object - * @param {*} [argument] | Optional: arguments to pass to the runFunction * @private */ - exports._doInAllSectors = function(runFunction,argument) { - var args = Array.prototype.splice.call(arguments, 1); - if (argument === undefined) { - this._doInAllActiveSectors(runFunction); - this._doInAllFrozenSectors(runFunction); + exports._toggleEditMode = function() { + this.editMode = !this.editMode; + var toolbar = this.manipulationDiv; + var closeDiv = this.closeDiv; + var editModeDiv = this.editModeDiv; + if (this.editMode == true) { + toolbar.style.display="block"; + closeDiv.style.display="block"; + editModeDiv.style.display="none"; + closeDiv.onclick = this._toggleEditMode.bind(this); } else { - if (args.length > 1) { - this._doInAllActiveSectors(runFunction,args[0],args[1]); - this._doInAllFrozenSectors(runFunction,args[0],args[1]); - } - else { - this._doInAllActiveSectors(runFunction,argument); - this._doInAllFrozenSectors(runFunction,argument); - } + toolbar.style.display="none"; + closeDiv.style.display="none"; + editModeDiv.style.display="block"; + closeDiv.onclick = null; } + this._createManipulatorBar() }; - /** - * This clears the nodeIndices list. We cannot use this.nodeIndices = [] because we would break the link with the - * active sector. Thus we clear the nodeIndices in the active sector, then reconnect the this.nodeIndices to it. + * main function, creates the main toolbar. Removes functions bound to the select event. Binds all the buttons of the toolbar. * * @private */ - exports._clearNodeIndexList = function() { - var sector = this._sector(); - this.sectors["active"][sector]["nodeIndices"] = []; - this.nodeIndices = this.sectors["active"][sector]["nodeIndices"]; - }; + exports._createManipulatorBar = function() { + // remove bound functions + if (this.boundFunction) { + this.off('select', this.boundFunction); + } + var locale = this.constants.locales[this.constants.locale]; - /** - * Draw the encompassing sector node - * - * @param ctx - * @param sectorType - * @private - */ - exports._drawSectorNodes = function(ctx,sectorType) { - var minY = 1e9, maxY = -1e9, minX = 1e9, maxX = -1e9, node; - for (var sector in this.sectors[sectorType]) { - if (this.sectors[sectorType].hasOwnProperty(sector)) { - if (this.sectors[sectorType][sector]["drawingNode"] !== undefined) { + if (this.edgeBeingEdited !== undefined) { + this.edgeBeingEdited._disableControlNodes(); + this.edgeBeingEdited = undefined; + this.selectedControlNode = null; + this.controlNodesActive = false; + this._redraw(); + } - this._switchToSector(sector,sectorType); + // restore overloaded functions + this._restoreOverloadedFunctions(); - minY = 1e9; maxY = -1e9; minX = 1e9; maxX = -1e9; - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - node.resize(ctx); - if (minX > node.x - 0.5 * node.width) {minX = node.x - 0.5 * node.width;} - if (maxX < node.x + 0.5 * node.width) {maxX = node.x + 0.5 * node.width;} - if (minY > node.y - 0.5 * node.height) {minY = node.y - 0.5 * node.height;} - if (maxY < node.y + 0.5 * node.height) {maxY = node.y + 0.5 * node.height;} - } - } - node = this.sectors[sectorType][sector]["drawingNode"]; - node.x = 0.5 * (maxX + minX); - node.y = 0.5 * (maxY + minY); - node.width = 2 * (node.x - minX); - node.height = 2 * (node.y - minY); - node.options.radius = Math.sqrt(Math.pow(0.5*node.width,2) + Math.pow(0.5*node.height,2)); - node.setScale(this.scale); - node._drawCircle(ctx); - } + // resume calculation + this.freezeSimulation = false; + + // reset global variables + this.blockConnectingEdgeSelection = false; + this.forceAppendSelection = false; + this.manipulationDOM = {}; + + if (this.editMode == true) { + while (this.manipulationDiv.hasChildNodes()) { + this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); + } + + this.manipulationDOM['addNodeSpan'] = document.createElement('span'); + this.manipulationDOM['addNodeSpan'].className = 'network-manipulationUI add'; + this.manipulationDOM['addNodeLabelSpan'] = document.createElement('span'); + this.manipulationDOM['addNodeLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['addNodeLabelSpan'].innerHTML = locale['addNode']; + this.manipulationDOM['addNodeSpan'].appendChild(this.manipulationDOM['addNodeLabelSpan']); + + this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); + this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; + + this.manipulationDOM['addEdgeSpan'] = document.createElement('span'); + this.manipulationDOM['addEdgeSpan'].className = 'network-manipulationUI connect'; + this.manipulationDOM['addEdgeLabelSpan'] = document.createElement('span'); + this.manipulationDOM['addEdgeLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['addEdgeLabelSpan'].innerHTML = locale['addEdge']; + this.manipulationDOM['addEdgeSpan'].appendChild(this.manipulationDOM['addEdgeLabelSpan']); + + this.manipulationDiv.appendChild(this.manipulationDOM['addNodeSpan']); + this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); + this.manipulationDiv.appendChild(this.manipulationDOM['addEdgeSpan']); + + if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) { + this.manipulationDOM['seperatorLineDiv2'] = document.createElement('div'); + this.manipulationDOM['seperatorLineDiv2'].className = 'network-seperatorLine'; + + this.manipulationDOM['editNodeSpan'] = document.createElement('span'); + this.manipulationDOM['editNodeSpan'].className = 'network-manipulationUI edit'; + this.manipulationDOM['editNodeLabelSpan'] = document.createElement('span'); + this.manipulationDOM['editNodeLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['editNodeLabelSpan'].innerHTML = locale['editNode']; + this.manipulationDOM['editNodeSpan'].appendChild(this.manipulationDOM['editNodeLabelSpan']); + + this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv2']); + this.manipulationDiv.appendChild(this.manipulationDOM['editNodeSpan']); + } + else if (this._getSelectedEdgeCount() == 1 && this._getSelectedNodeCount() == 0) { + this.manipulationDOM['seperatorLineDiv3'] = document.createElement('div'); + this.manipulationDOM['seperatorLineDiv3'].className = 'network-seperatorLine'; + + this.manipulationDOM['editEdgeSpan'] = document.createElement('span'); + this.manipulationDOM['editEdgeSpan'].className = 'network-manipulationUI edit'; + this.manipulationDOM['editEdgeLabelSpan'] = document.createElement('span'); + this.manipulationDOM['editEdgeLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['editEdgeLabelSpan'].innerHTML = locale['editEdge']; + this.manipulationDOM['editEdgeSpan'].appendChild(this.manipulationDOM['editEdgeLabelSpan']); + + this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv3']); + this.manipulationDiv.appendChild(this.manipulationDOM['editEdgeSpan']); + } + if (this._selectionIsEmpty() == false) { + this.manipulationDOM['seperatorLineDiv4'] = document.createElement('div'); + this.manipulationDOM['seperatorLineDiv4'].className = 'network-seperatorLine'; + + this.manipulationDOM['deleteSpan'] = document.createElement('span'); + this.manipulationDOM['deleteSpan'].className = 'network-manipulationUI delete'; + this.manipulationDOM['deleteLabelSpan'] = document.createElement('span'); + this.manipulationDOM['deleteLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['deleteLabelSpan'].innerHTML = locale['del']; + this.manipulationDOM['deleteSpan'].appendChild(this.manipulationDOM['deleteLabelSpan']); + + this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv4']); + this.manipulationDiv.appendChild(this.manipulationDOM['deleteSpan']); } + + + // bind the icons + this.manipulationDOM['addNodeSpan'].onclick = this._createAddNodeToolbar.bind(this); + this.manipulationDOM['addEdgeSpan'].onclick = this._createAddEdgeToolbar.bind(this); + if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) { + this.manipulationDOM['editNodeSpan'].onclick = this._editNode.bind(this); + } + else if (this._getSelectedEdgeCount() == 1 && this._getSelectedNodeCount() == 0) { + this.manipulationDOM['editEdgeSpan'].onclick = this._createEditEdgeToolbar.bind(this); + } + if (this._selectionIsEmpty() == false) { + this.manipulationDOM['deleteSpan'].onclick = this._deleteSelected.bind(this); + } + this.closeDiv.onclick = this._toggleEditMode.bind(this); + + var me = this; + this.boundFunction = me._createManipulatorBar; + this.on('select', this.boundFunction); } - }; + else { + while (this.editModeDiv.hasChildNodes()) { + this.editModeDiv.removeChild(this.editModeDiv.firstChild); + } - exports._drawAllSectorNodes = function(ctx) { - this._drawSectorNodes(ctx,"frozen"); - this._drawSectorNodes(ctx,"active"); - this._loadLatestSector(); - }; + this.manipulationDOM['editModeSpan'] = document.createElement('span'); + this.manipulationDOM['editModeSpan'].className = 'network-manipulationUI edit editmode'; + this.manipulationDOM['editModeLabelSpan'] = document.createElement('span'); + this.manipulationDOM['editModeLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['editModeLabelSpan'].innerHTML = locale['edit']; + this.manipulationDOM['editModeSpan'].appendChild(this.manipulationDOM['editModeLabelSpan']); + this.editModeDiv.appendChild(this.manipulationDOM['editModeSpan']); + + this.manipulationDOM['editModeSpan'].onclick = this._toggleEditMode.bind(this); + } + }; -/***/ }, -/* 66 */ -/***/ function(module, exports, __webpack_require__) { - var Node = __webpack_require__(56); /** - * This function can be called from the _doInAllSectors function + * Create the toolbar for adding Nodes * - * @param object - * @param overlappingNodes * @private */ - exports._getNodesOverlappingWith = function(object, overlappingNodes) { - var nodes = this.nodes; - for (var nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - if (nodes[nodeId].isOverlappingWith(object)) { - overlappingNodes.push(nodeId); - } - } + exports._createAddNodeToolbar = function() { + // clear the toolbar + this._clearManipulatorBar(); + if (this.boundFunction) { + this.off('select', this.boundFunction); } - }; - /** - * retrieve all nodes overlapping with given object - * @param {Object} object An object with parameters left, top, right, bottom - * @return {Number[]} An array with id's of the overlapping nodes - * @private - */ - exports._getAllNodesOverlappingWith = function (object) { - var overlappingNodes = []; - this._doInAllActiveSectors("_getNodesOverlappingWith",object,overlappingNodes); - return overlappingNodes; - }; + var locale = this.constants.locales[this.constants.locale]; + + this.manipulationDOM = {}; + this.manipulationDOM['backSpan'] = document.createElement('span'); + this.manipulationDOM['backSpan'].className = 'network-manipulationUI back'; + this.manipulationDOM['backLabelSpan'] = document.createElement('span'); + this.manipulationDOM['backLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['backLabelSpan'].innerHTML = locale['back']; + this.manipulationDOM['backSpan'].appendChild(this.manipulationDOM['backLabelSpan']); + this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); + this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; - /** - * Return a position object in canvasspace from a single point in screenspace - * - * @param pointer - * @returns {{left: number, top: number, right: number, bottom: number}} - * @private - */ - exports._pointerToPositionObject = function(pointer) { - var x = this._XconvertDOMtoCanvas(pointer.x); - var y = this._YconvertDOMtoCanvas(pointer.y); + this.manipulationDOM['descriptionSpan'] = document.createElement('span'); + this.manipulationDOM['descriptionSpan'].className = 'network-manipulationUI none'; + this.manipulationDOM['descriptionLabelSpan'] = document.createElement('span'); + this.manipulationDOM['descriptionLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['descriptionLabelSpan'].innerHTML = locale['addDescription']; + this.manipulationDOM['descriptionSpan'].appendChild(this.manipulationDOM['descriptionLabelSpan']); - return { - left: x, - top: y, - right: x, - bottom: y - }; + this.manipulationDiv.appendChild(this.manipulationDOM['backSpan']); + this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); + this.manipulationDiv.appendChild(this.manipulationDOM['descriptionSpan']); + + // bind the icon + this.manipulationDOM['backSpan'].onclick = this._createManipulatorBar.bind(this); + + // we use the boundFunction so we can reference it when we unbind it from the "select" event. + var me = this; + this.boundFunction = me._addNode; + this.on('select', this.boundFunction); }; /** - * Get the top node at the a specific point (like a click) + * create the toolbar to connect nodes * - * @param {{x: Number, y: Number}} pointer - * @return {Node | null} node * @private */ - exports._getNodeAt = function (pointer) { - // we first check if this is an navigation controls element - var positionObject = this._pointerToPositionObject(pointer); - var overlappingNodes = this._getAllNodesOverlappingWith(positionObject); + exports._createAddEdgeToolbar = function() { + // clear the toolbar + this._clearManipulatorBar(); + this._unselectAll(true); + this.freezeSimulation = true; - // if there are overlapping nodes, select the last one, this is the - // one which is drawn on top of the others - if (overlappingNodes.length > 0) { - return this.nodes[overlappingNodes[overlappingNodes.length - 1]]; - } - else { - return null; + if (this.boundFunction) { + this.off('select', this.boundFunction); } - }; + var locale = this.constants.locales[this.constants.locale]; - /** - * retrieve all edges overlapping with given object, selector is around center - * @param {Object} object An object with parameters left, top, right, bottom - * @return {Number[]} An array with id's of the overlapping nodes - * @private - */ - exports._getEdgesOverlappingWith = function (object, overlappingEdges) { - var edges = this.edges; - for (var edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - if (edges[edgeId].isOverlappingWith(object)) { - overlappingEdges.push(edgeId); - } - } - } - }; + this._unselectAll(); + this.forceAppendSelection = false; + this.blockConnectingEdgeSelection = true; + this.manipulationDOM = {}; + this.manipulationDOM['backSpan'] = document.createElement('span'); + this.manipulationDOM['backSpan'].className = 'network-manipulationUI back'; + this.manipulationDOM['backLabelSpan'] = document.createElement('span'); + this.manipulationDOM['backLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['backLabelSpan'].innerHTML = locale['back']; + this.manipulationDOM['backSpan'].appendChild(this.manipulationDOM['backLabelSpan']); - /** - * retrieve all nodes overlapping with given object - * @param {Object} object An object with parameters left, top, right, bottom - * @return {Number[]} An array with id's of the overlapping nodes - * @private - */ - exports._getAllEdgesOverlappingWith = function (object) { - var overlappingEdges = []; - this._doInAllActiveSectors("_getEdgesOverlappingWith",object,overlappingEdges); - return overlappingEdges; + this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); + this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; + + this.manipulationDOM['descriptionSpan'] = document.createElement('span'); + this.manipulationDOM['descriptionSpan'].className = 'network-manipulationUI none'; + this.manipulationDOM['descriptionLabelSpan'] = document.createElement('span'); + this.manipulationDOM['descriptionLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['descriptionLabelSpan'].innerHTML = locale['edgeDescription']; + this.manipulationDOM['descriptionSpan'].appendChild(this.manipulationDOM['descriptionLabelSpan']); + + this.manipulationDiv.appendChild(this.manipulationDOM['backSpan']); + this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); + this.manipulationDiv.appendChild(this.manipulationDOM['descriptionSpan']); + + // bind the icon + this.manipulationDOM['backSpan'].onclick = this._createManipulatorBar.bind(this); + + // we use the boundFunction so we can reference it when we unbind it from the "select" event. + var me = this; + this.boundFunction = me._handleConnect; + this.on('select', this.boundFunction); + + // temporarily overload functions + this.cachedFunctions["_handleTouch"] = this._handleTouch; + this.cachedFunctions["_manipulationReleaseOverload"] = this._manipulationReleaseOverload; + this.cachedFunctions["_handleDragStart"] = this._handleDragStart; + this.cachedFunctions["_handleDragEnd"] = this._handleDragEnd; + this._handleTouch = this._handleConnect; + this._manipulationReleaseOverload = function () {}; + this._handleDragStart = function () {}; + this._handleDragEnd = this._finishConnect; + + // redraw to show the unselect + this._redraw(); }; /** - * Place holder. To implement change the _getNodeAt to a _getObjectAt. Have the _getObjectAt call - * _getNodeAt and _getEdgesAt, then priortize the selection to user preferences. + * create the toolbar to edit edges * - * @param pointer - * @returns {null} * @private */ - exports._getEdgeAt = function(pointer) { - var positionObject = this._pointerToPositionObject(pointer); - var overlappingEdges = this._getAllEdgesOverlappingWith(positionObject); + exports._createEditEdgeToolbar = function() { + // clear the toolbar + this._clearManipulatorBar(); + this.controlNodesActive = true; - if (overlappingEdges.length > 0) { - return this.edges[overlappingEdges[overlappingEdges.length - 1]]; - } - else { - return null; + if (this.boundFunction) { + this.off('select', this.boundFunction); } + + this.edgeBeingEdited = this._getSelectedEdge(); + this.edgeBeingEdited._enableControlNodes(); + + var locale = this.constants.locales[this.constants.locale]; + + this.manipulationDOM = {}; + this.manipulationDOM['backSpan'] = document.createElement('span'); + this.manipulationDOM['backSpan'].className = 'network-manipulationUI back'; + this.manipulationDOM['backLabelSpan'] = document.createElement('span'); + this.manipulationDOM['backLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['backLabelSpan'].innerHTML = locale['back']; + this.manipulationDOM['backSpan'].appendChild(this.manipulationDOM['backLabelSpan']); + + this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); + this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; + + this.manipulationDOM['descriptionSpan'] = document.createElement('span'); + this.manipulationDOM['descriptionSpan'].className = 'network-manipulationUI none'; + this.manipulationDOM['descriptionLabelSpan'] = document.createElement('span'); + this.manipulationDOM['descriptionLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['descriptionLabelSpan'].innerHTML = locale['editEdgeDescription']; + this.manipulationDOM['descriptionSpan'].appendChild(this.manipulationDOM['descriptionLabelSpan']); + + this.manipulationDiv.appendChild(this.manipulationDOM['backSpan']); + this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); + this.manipulationDiv.appendChild(this.manipulationDOM['descriptionSpan']); + + // bind the icon + this.manipulationDOM['backSpan'].onclick = this._createManipulatorBar.bind(this); + + // temporarily overload functions + this.cachedFunctions["_handleTouch"] = this._handleTouch; + this.cachedFunctions["_manipulationReleaseOverload"] = this._manipulationReleaseOverload; + this.cachedFunctions["_handleTap"] = this._handleTap; + this.cachedFunctions["_handleDragStart"] = this._handleDragStart; + this.cachedFunctions["_handleOnDrag"] = this._handleOnDrag; + this._handleTouch = this._selectControlNode; + this._handleTap = function () {}; + this._handleOnDrag = this._controlNodeDrag; + this._handleDragStart = function () {} + this._manipulationReleaseOverload = this._releaseControlNode; + + // redraw to show the unselect + this._redraw(); }; /** - * Add object to the selection array. + * the function bound to the selection event. It checks if you want to connect a cluster and changes the description + * to walk the user through the process. * - * @param obj * @private */ - exports._addToSelection = function(obj) { - if (obj instanceof Node) { - this.selectionObj.nodes[obj.id] = obj; - } - else { - this.selectionObj.edges[obj.id] = obj; + exports._selectControlNode = function(pointer) { + this.edgeBeingEdited.controlNodes.from.unselect(); + this.edgeBeingEdited.controlNodes.to.unselect(); + this.selectedControlNode = this.edgeBeingEdited._getSelectedControlNode(this._XconvertDOMtoCanvas(pointer.x),this._YconvertDOMtoCanvas(pointer.y)); + if (this.selectedControlNode !== null) { + this.selectedControlNode.select(); + this.freezeSimulation = true; } + this._redraw(); }; + /** - * Add object to the selection array. + * the function bound to the selection event. It checks if you want to connect a cluster and changes the description + * to walk the user through the process. * - * @param obj * @private */ - exports._addToHover = function(obj) { - if (obj instanceof Node) { - this.hoverObj.nodes[obj.id] = obj; - } - else { - this.hoverObj.edges[obj.id] = obj; + exports._controlNodeDrag = function(event) { + var pointer = this._getPointer(event.gesture.center); + if (this.selectedControlNode !== null && this.selectedControlNode !== undefined) { + this.selectedControlNode.x = this._XconvertDOMtoCanvas(pointer.x); + this.selectedControlNode.y = this._YconvertDOMtoCanvas(pointer.y); } + this._redraw(); }; /** - * Remove a single option from selection. * - * @param {Object} obj + * @param pointer * @private */ - exports._removeFromSelection = function(obj) { - if (obj instanceof Node) { - delete this.selectionObj.nodes[obj.id]; + exports._releaseControlNode = function(pointer) { + var newNode = this._getNodeAt(pointer); + if (newNode !== null) { + if (this.edgeBeingEdited.controlNodes.from.selected == true) { + this.edgeBeingEdited._restoreControlNodes(); + this._editEdge(newNode.id, this.edgeBeingEdited.to.id); + this.edgeBeingEdited.controlNodes.from.unselect(); + } + if (this.edgeBeingEdited.controlNodes.to.selected == true) { + this.edgeBeingEdited._restoreControlNodes(); + this._editEdge(this.edgeBeingEdited.from.id, newNode.id); + this.edgeBeingEdited.controlNodes.to.unselect(); + } } else { - delete this.selectionObj.edges[obj.id]; + this.edgeBeingEdited._restoreControlNodes(); } + this.freezeSimulation = false; + this._redraw(); }; /** - * Unselect all. The selectionObj is useful for this. + * the function bound to the selection event. It checks if you want to connect a cluster and changes the description + * to walk the user through the process. * - * @param {Boolean} [doNotTrigger] | ignore trigger * @private */ - exports._unselectAll = function(doNotTrigger) { - if (doNotTrigger === undefined) { - doNotTrigger = false; - } - for(var nodeId in this.selectionObj.nodes) { - if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { - this.selectionObj.nodes[nodeId].unselect(); - } - } - for(var edgeId in this.selectionObj.edges) { - if(this.selectionObj.edges.hasOwnProperty(edgeId)) { - this.selectionObj.edges[edgeId].unselect(); - } - } + exports._handleConnect = function(pointer) { + if (this._getSelectedNodeCount() == 0) { + var node = this._getNodeAt(pointer); - this.selectionObj = {nodes:{},edges:{}}; + if (node != null) { + if (node.clusterSize > 1) { + alert(this.constants.locales[this.constants.locale]['createEdgeError']) + } + else { + this._selectObject(node,false); + var supportNodes = this.sectors['support']['nodes']; - if (doNotTrigger == false) { - this.emit('select', this.getSelection()); - } - }; + // create a node the temporary line can look at + supportNodes['targetNode'] = new Node({id:'targetNode'},{},{},this.constants); + var targetNode = supportNodes['targetNode']; + targetNode.x = node.x; + targetNode.y = node.y; - /** - * Unselect all clusters. The selectionObj is useful for this. - * - * @param {Boolean} [doNotTrigger] | ignore trigger - * @private - */ - exports._unselectClusters = function(doNotTrigger) { - if (doNotTrigger === undefined) { - doNotTrigger = false; - } + // create a temporary edge + this.edges['connectionEdge'] = new Edge({id:"connectionEdge",from:node.id,to:targetNode.id}, this, this.constants); + var connectionEdge = this.edges['connectionEdge']; + connectionEdge.from = node; + connectionEdge.connected = true; + connectionEdge.options.smoothCurves = {enabled: true, + dynamic: false, + type: "continuous", + roundness: 0.5 + }; + connectionEdge.selected = true; + connectionEdge.to = targetNode; - for (var nodeId in this.selectionObj.nodes) { - if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { - if (this.selectionObj.nodes[nodeId].clusterSize > 1) { - this.selectionObj.nodes[nodeId].unselect(); - this._removeFromSelection(this.selectionObj.nodes[nodeId]); + this.cachedFunctions["_handleOnDrag"] = this._handleOnDrag; + this._handleOnDrag = function(event) { + var pointer = this._getPointer(event.gesture.center); + var connectionEdge = this.edges['connectionEdge']; + connectionEdge.to.x = this._XconvertDOMtoCanvas(pointer.x); + connectionEdge.to.y = this._YconvertDOMtoCanvas(pointer.y); + }; + + this.moving = true; + this.start(); } } } + }; - if (doNotTrigger == false) { - this.emit('select', this.getSelection()); + exports._finishConnect = function(event) { + if (this._getSelectedNodeCount() == 1) { + var pointer = this._getPointer(event.gesture.center); + // restore the drag function + this._handleOnDrag = this.cachedFunctions["_handleOnDrag"]; + delete this.cachedFunctions["_handleOnDrag"]; + + // remember the edge id + var connectFromId = this.edges['connectionEdge'].fromId; + + // remove the temporary nodes and edge + delete this.edges['connectionEdge']; + delete this.sectors['support']['nodes']['targetNode']; + delete this.sectors['support']['nodes']['targetViaNode']; + + var node = this._getNodeAt(pointer); + if (node != null) { + if (node.clusterSize > 1) { + alert(this.constants.locales[this.constants.locale]["createEdgeError"]) + } + else { + this._createEdge(connectFromId,node.id); + this._createManipulatorBar(); + } + } + this._unselectAll(); } }; /** - * return the number of selected nodes - * - * @returns {number} - * @private + * Adds a node on the specified location */ - exports._getSelectedNodeCount = function() { - var count = 0; - for (var nodeId in this.selectionObj.nodes) { - if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { - count += 1; + exports._addNode = function() { + if (this._selectionIsEmpty() && this.editMode == true) { + var positionObject = this._pointerToPositionObject(this.pointerPosition); + var defaultData = {id:util.randomUUID(),x:positionObject.left,y:positionObject.top,label:"new",allowedToMoveX:true,allowedToMoveY:true}; + if (this.triggerFunctions.add) { + if (this.triggerFunctions.add.length == 2) { + var me = this; + this.triggerFunctions.add(defaultData, function(finalizedData) { + me.nodesData.add(finalizedData); + me._createManipulatorBar(); + me.moving = true; + me.start(); + }); + } + else { + throw new Error('The function for add does not support two arguments (data,callback)'); + this._createManipulatorBar(); + this.moving = true; + this.start(); + } + } + else { + this.nodesData.add(defaultData); + this._createManipulatorBar(); + this.moving = true; + this.start(); } } - return count; }; + /** - * return the selected node + * connect two nodes with a new edge. * - * @returns {number} * @private */ - exports._getSelectedNode = function() { - for (var nodeId in this.selectionObj.nodes) { - if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { - return this.selectionObj.nodes[nodeId]; + exports._createEdge = function(sourceNodeId,targetNodeId) { + if (this.editMode == true) { + var defaultData = {from:sourceNodeId, to:targetNodeId}; + if (this.triggerFunctions.connect) { + if (this.triggerFunctions.connect.length == 2) { + var me = this; + this.triggerFunctions.connect(defaultData, function(finalizedData) { + me.edgesData.add(finalizedData); + me.moving = true; + me.start(); + }); + } + else { + throw new Error('The function for connect does not support two arguments (data,callback)'); + this.moving = true; + this.start(); + } + } + else { + this.edgesData.add(defaultData); + this.moving = true; + this.start(); } } - return null; }; /** - * return the selected edge + * connect two nodes with a new edge. * - * @returns {number} * @private */ - exports._getSelectedEdge = function() { - for (var edgeId in this.selectionObj.edges) { - if (this.selectionObj.edges.hasOwnProperty(edgeId)) { - return this.selectionObj.edges[edgeId]; + exports._editEdge = function(sourceNodeId,targetNodeId) { + if (this.editMode == true) { + var defaultData = {id: this.edgeBeingEdited.id, from:sourceNodeId, to:targetNodeId}; + if (this.triggerFunctions.editEdge) { + if (this.triggerFunctions.editEdge.length == 2) { + var me = this; + this.triggerFunctions.editEdge(defaultData, function(finalizedData) { + me.edgesData.update(finalizedData); + me.moving = true; + me.start(); + }); + } + else { + throw new Error('The function for edit does not support two arguments (data, callback)'); + this.moving = true; + this.start(); + } + } + else { + this.edgesData.update(defaultData); + this.moving = true; + this.start(); } } - return null; }; - /** - * return the number of selected edges + * Create the toolbar to edit the selected node. The label and the color can be changed. Other colors are derived from the chosen color. * - * @returns {number} * @private */ - exports._getSelectedEdgeCount = function() { - var count = 0; - for (var edgeId in this.selectionObj.edges) { - if (this.selectionObj.edges.hasOwnProperty(edgeId)) { - count += 1; + exports._editNode = function() { + if (this.triggerFunctions.edit && this.editMode == true) { + var node = this._getSelectedNode(); + var data = {id:node.id, + label: node.label, + group: node.options.group, + shape: node.options.shape, + color: { + background:node.options.color.background, + border:node.options.color.border, + highlight: { + background:node.options.color.highlight.background, + border:node.options.color.highlight.border + } + }}; + if (this.triggerFunctions.edit.length == 2) { + var me = this; + this.triggerFunctions.edit(data, function (finalizedData) { + me.nodesData.update(finalizedData); + me._createManipulatorBar(); + me.moving = true; + me.start(); + }); + } + else { + throw new Error('The function for edit does not support two arguments (data, callback)'); } } - return count; + else { + throw new Error('No edit function has been bound to this button'); + } }; + + /** - * return the number of selected objects. + * delete everything in the selection * - * @returns {number} * @private */ - exports._getSelectedObjectCount = function() { - var count = 0; - for(var nodeId in this.selectionObj.nodes) { - if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { - count += 1; + exports._deleteSelected = function() { + if (!this._selectionIsEmpty() && this.editMode == true) { + if (!this._clusterInSelection()) { + var selectedNodes = this.getSelectedNodes(); + var selectedEdges = this.getSelectedEdges(); + if (this.triggerFunctions.del) { + var me = this; + var data = {nodes: selectedNodes, edges: selectedEdges}; + if (this.triggerFunctions.del.length == 2) { + this.triggerFunctions.del(data, function (finalizedData) { + me.edgesData.remove(finalizedData.edges); + me.nodesData.remove(finalizedData.nodes); + me._unselectAll(); + me.moving = true; + me.start(); + }); + } + else { + throw new Error('The function for delete does not support two arguments (data, callback)') + } + } + else { + this.edgesData.remove(selectedEdges); + this.nodesData.remove(selectedNodes); + this._unselectAll(); + this.moving = true; + this.start(); + } } - } - for(var edgeId in this.selectionObj.edges) { - if(this.selectionObj.edges.hasOwnProperty(edgeId)) { - count += 1; + else { + alert(this.constants.locales[this.constants.locale]["deleteClusterError"]); } } - return count; }; - /** - * Check if anything is selected - * - * @returns {boolean} - * @private - */ - exports._selectionIsEmpty = function() { - for(var nodeId in this.selectionObj.nodes) { - if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { - return false; + +/***/ }, +/* 64 */ +/***/ function(module, exports, __webpack_require__) { + + var util = __webpack_require__(1); + var Hammer = __webpack_require__(45); + + exports._cleanNavigation = function() { + // clean hammer bindings + if (this.navigationHammers.existing.length != 0) { + for (var i = 0; i < this.navigationHammers.existing.length; i++) { + this.navigationHammers.existing[i].dispose(); } + this.navigationHammers.existing = []; } - for(var edgeId in this.selectionObj.edges) { - if(this.selectionObj.edges.hasOwnProperty(edgeId)) { - return false; - } + + this._navigationReleaseOverload = function () {}; + + // clean up previous navigation items + if (this.navigationDivs && this.navigationDivs['wrapper'] && this.navigationDivs['wrapper'].parentNode) { + this.navigationDivs['wrapper'].parentNode.removeChild(this.navigationDivs['wrapper']); } - return true; }; - /** - * check if one of the selected nodes is a cluster. + * Creation of the navigation controls nodes. They are drawn over the rest of the nodes and are not affected by scale and translation + * they have a triggerFunction which is called on click. If the position of the navigation controls is dependent + * on this.frame.canvas.clientWidth or this.frame.canvas.clientHeight, we flag horizontalAlignLeft and verticalAlignTop false. + * This means that the location will be corrected by the _relocateNavigation function on a size change of the canvas. * - * @returns {boolean} * @private */ - exports._clusterInSelection = function() { - for(var nodeId in this.selectionObj.nodes) { - if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { - if (this.selectionObj.nodes[nodeId].clusterSize > 1) { - return true; - } - } + exports._loadNavigationElements = function() { + this._cleanNavigation(); + + this.navigationDivs = {}; + var navigationDivs = ['up','down','left','right','zoomIn','zoomOut','zoomExtends']; + var navigationDivActions = ['_moveUp','_moveDown','_moveLeft','_moveRight','_zoomIn','_zoomOut','_zoomExtent']; + + this.navigationDivs['wrapper'] = document.createElement('div'); + this.frame.appendChild(this.navigationDivs['wrapper']); + + for (var i = 0; i < navigationDivs.length; i++) { + this.navigationDivs[navigationDivs[i]] = document.createElement('div'); + this.navigationDivs[navigationDivs[i]].className = 'network-navigation ' + navigationDivs[i]; + this.navigationDivs['wrapper'].appendChild(this.navigationDivs[navigationDivs[i]]); + + var hammer = Hammer(this.navigationDivs[navigationDivs[i]], {prevent_default: true}); + hammer.on('touch', this[navigationDivActions[i]].bind(this)); + this.navigationHammers._new.push(hammer); } - return false; + + this._navigationReleaseOverload = this._stopMovement; + + this.navigationHammers.existing = this.navigationHammers._new; }; + /** - * select the edges connected to the node that is being selected + * this stops all movement induced by the navigation buttons * - * @param {Node} node * @private */ - exports._selectConnectedEdges = function(node) { - for (var i = 0; i < node.dynamicEdges.length; i++) { - var edge = node.dynamicEdges[i]; - edge.select(); - this._addToSelection(edge); - } + exports._zoomExtent = function(event) { + this.zoomExtent({duration:700}); + event.stopPropagation(); }; /** - * select the edges connected to the node that is being selected + * this stops all movement induced by the navigation buttons * - * @param {Node} node * @private */ - exports._hoverConnectedEdges = function(node) { - for (var i = 0; i < node.dynamicEdges.length; i++) { - var edge = node.dynamicEdges[i]; - edge.hover = true; - this._addToHover(edge); - } + exports._stopMovement = function() { + this._xStopMoving(); + this._yStopMoving(); + this._stopZoom(); }; /** - * unselect the edges connected to the node that is being selected + * move the screen up + * By using the increments, instead of adding a fixed number to the translation, we keep fluent and + * instant movement. The onKeypress event triggers immediately, then pauses, then triggers frequently + * To avoid this behaviour, we do the translation in the start loop. * - * @param {Node} node * @private */ - exports._unselectConnectedEdges = function(node) { - for (var i = 0; i < node.dynamicEdges.length; i++) { - var edge = node.dynamicEdges[i]; - edge.unselect(); - this._removeFromSelection(edge); - } + exports._moveUp = function(event) { + this.yIncrement = this.constants.keyboard.speed.y; + this.start(); // if there is no node movement, the calculation wont be done + event.preventDefault(); }; - - /** - * This is called when someone clicks on a node. either select or deselect it. - * If there is an existing selection and we don't want to append to it, clear the existing selection - * - * @param {Node || Edge} object - * @param {Boolean} append - * @param {Boolean} [doNotTrigger] | ignore trigger + * move the screen down * @private */ - exports._selectObject = function(object, append, doNotTrigger, highlightEdges, overrideSelectable) { - if (doNotTrigger === undefined) { - doNotTrigger = false; - } - if (highlightEdges === undefined) { - highlightEdges = true; - } - - if (this._selectionIsEmpty() == false && append == false && this.forceAppendSelection == false) { - this._unselectAll(true); - } - - // selectable allows the object to be selected. Override can be used if needed to bypass this. - if (object.selected == false && (this.constants.selectable == true || overrideSelectable)) { - object.select(); - this._addToSelection(object); - if (object instanceof Node && this.blockConnectingEdgeSelection == false && highlightEdges == true) { - this._selectConnectedEdges(object); - } - } - // do not select the object if selectable is false, only add it to selection to allow drag to work - else if (object.selected == false) { - this._addToSelection(object); - doNotTrigger = true; - } - else { - object.unselect(); - this._removeFromSelection(object); - } - - if (doNotTrigger == false) { - this.emit('select', this.getSelection()); - } + exports._moveDown = function(event) { + this.yIncrement = -this.constants.keyboard.speed.y; + this.start(); // if there is no node movement, the calculation wont be done + event.preventDefault(); }; /** - * This is called when someone clicks on a node. either select or deselect it. - * If there is an existing selection and we don't want to append to it, clear the existing selection - * - * @param {Node || Edge} object + * move the screen left * @private */ - exports._blurObject = function(object) { - if (object.hover == true) { - object.hover = false; - this.emit("blurNode",{node:object.id}); - } + exports._moveLeft = function(event) { + this.xIncrement = this.constants.keyboard.speed.x; + this.start(); // if there is no node movement, the calculation wont be done + event.preventDefault(); }; + /** - * This is called when someone clicks on a node. either select or deselect it. - * If there is an existing selection and we don't want to append to it, clear the existing selection - * - * @param {Node || Edge} object + * move the screen right * @private */ - exports._hoverObject = function(object) { - if (object.hover == false) { - object.hover = true; - this._addToHover(object); - if (object instanceof Node) { - this.emit("hoverNode",{node:object.id}); - } - } - if (object instanceof Node) { - this._hoverConnectedEdges(object); - } + exports._moveRight = function(event) { + this.xIncrement = -this.constants.keyboard.speed.y; + this.start(); // if there is no node movement, the calculation wont be done + event.preventDefault(); }; /** - * handles the selection part of the touch, only for navigation controls elements; - * Touch is triggered before tap, also before hold. Hold triggers after a while. - * This is the most responsive solution - * - * @param {Object} pointer + * Zoom in, using the same method as the movement. * @private */ - exports._handleTouch = function(pointer) { + exports._zoomIn = function(event) { + this.zoomIncrement = this.constants.keyboard.speed.zoom; + this.start(); // if there is no node movement, the calculation wont be done + event.preventDefault(); }; /** - * handles the selection part of the tap; - * - * @param {Object} pointer + * Zoom out * @private */ - exports._handleTap = function(pointer) { - var node = this._getNodeAt(pointer); - if (node != null) { - this._selectObject(node, false); - } - else { - var edge = this._getEdgeAt(pointer); - if (edge != null) { - this._selectObject(edge, false); - } - else { - this._unselectAll(); - } - } - var properties = this.getSelection(); - properties['pointer'] = { - DOM: {x: pointer.x, y: pointer.y}, - canvas: {x: this._XconvertDOMtoCanvas(pointer.x), y: this._YconvertDOMtoCanvas(pointer.y)} - } - this.emit("click", properties); - this._redraw(); + exports._zoomOut = function(event) { + this.zoomIncrement = -this.constants.keyboard.speed.zoom; + this.start(); // if there is no node movement, the calculation wont be done + event.preventDefault(); }; /** - * handles the selection part of the double tap and opens a cluster if needed - * - * @param {Object} pointer + * Stop zooming and unhighlight the zoom controls * @private */ - exports._handleDoubleTap = function(pointer) { - var node = this._getNodeAt(pointer); - if (node != null && node !== undefined) { - // we reset the areaCenter here so the opening of the node will occur - this.areaCenter = {"x" : this._XconvertDOMtoCanvas(pointer.x), - "y" : this._YconvertDOMtoCanvas(pointer.y)}; - this.openCluster(node); - } - var properties = this.getSelection(); - properties['pointer'] = { - DOM: {x: pointer.x, y: pointer.y}, - canvas: {x: this._XconvertDOMtoCanvas(pointer.x), y: this._YconvertDOMtoCanvas(pointer.y)} - } - this.emit("doubleClick", properties); + exports._stopZoom = function(event) { + this.zoomIncrement = 0; + event && event.preventDefault(); }; /** - * Handle the onHold selection part - * - * @param pointer + * Stop moving in the Y direction and unHighlight the up and down * @private */ - exports._handleOnHold = function(pointer) { - var node = this._getNodeAt(pointer); - if (node != null) { - this._selectObject(node,true); - } - else { - var edge = this._getEdgeAt(pointer); - if (edge != null) { - this._selectObject(edge,true); - } - } - this._redraw(); + exports._yStopMoving = function(event) { + this.yIncrement = 0; + event && event.preventDefault(); }; /** - * handle the onRelease event. These functions are here for the navigation controls module - * and data manipulation module. - * - * @private + * Stop moving in the X direction and unHighlight left and right. + * @private */ - exports._handleOnRelease = function(pointer) { - this._manipulationReleaseOverload(pointer); - this._navigationReleaseOverload(pointer); + exports._xStopMoving = function(event) { + this.xIncrement = 0; + event && event.preventDefault(); }; - exports._manipulationReleaseOverload = function (pointer) {}; - exports._navigationReleaseOverload = function (pointer) {}; - /** - * - * retrieve the currently selected objects - * @return {{nodes: Array., edges: Array.}} selection - */ - exports.getSelection = function() { - var nodeIds = this.getSelectedNodes(); - var edgeIds = this.getSelectedEdges(); - return {nodes:nodeIds, edges:edgeIds}; - }; +/***/ }, +/* 65 */ +/***/ function(module, exports, __webpack_require__) { - /** - * - * retrieve the currently selected nodes - * @return {String[]} selection An array with the ids of the - * selected nodes. - */ - exports.getSelectedNodes = function() { - var idArray = []; - if (this.constants.selectable == true) { - for (var nodeId in this.selectionObj.nodes) { - if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { - idArray.push(nodeId); + exports._resetLevels = function() { + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + var node = this.nodes[nodeId]; + if (node.preassignedLevel == false) { + node.level = -1; + node.hierarchyEnumerated = false; } } } - return idArray }; /** + * This is the main function to layout the nodes in a hierarchical way. + * It checks if the node details are supplied correctly * - * retrieve the currently selected edges - * @return {Array} selection An array with the ids of the - * selected nodes. + * @private */ - exports.getSelectedEdges = function() { - var idArray = []; - if (this.constants.selectable == true) { - for (var edgeId in this.selectionObj.edges) { - if (this.selectionObj.edges.hasOwnProperty(edgeId)) { - idArray.push(edgeId); + exports._setupHierarchicalLayout = function() { + if (this.constants.hierarchicalLayout.enabled == true && this.nodeIndices.length > 0) { + // get the size of the largest hubs and check if the user has defined a level for a node. + var hubsize = 0; + var node, nodeId; + var definedLevel = false; + var undefinedLevel = false; + + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + if (node.level != -1) { + definedLevel = true; + } + else { + undefinedLevel = true; + } + if (hubsize < node.edges.length) { + hubsize = node.edges.length; + } } } - } - return idArray; - }; + // if the user defined some levels but not all, alert and run without hierarchical layout + if (undefinedLevel == true && definedLevel == true) { + 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(undefined,true,this.constants.clustering.enabled); + if (!this.constants.clustering.enabled) { + this.start(); + } + } + else { + // setup the system to use hierarchical method. + this._changeConstants(); + + // define levels if undefined by the users. Based on hubsize + if (undefinedLevel == true) { + if (this.constants.hierarchicalLayout.layout == "hubsize") { + this._determineLevels(hubsize); + } + else { + this._determineLevelsDirected(false); + } + + } + // check the distribution of the nodes per level. + var distribution = this._getDistribution(); - /** - * select zero or more nodes DEPRICATED - * @param {Number[] | String[]} selection An array with the ids of the - * selected nodes. - */ - exports.setSelection = function() { - console.log("setSelection is deprecated. Please use selectNodes instead.") + // place the nodes on the canvas. This also stablilizes the system. + this._placeNodesByHierarchy(distribution); + + // start the simulation. + this.start(); + } + } }; /** - * select zero or more nodes with the option to highlight edges - * @param {Number[] | String[]} selection An array with the ids of the - * selected nodes. - * @param {boolean} [highlightEdges] + * This function places the nodes on the canvas based on the hierarchial distribution. + * + * @param {Object} distribution | obtained by the function this._getDistribution() + * @private */ - exports.selectNodes = function(selection, highlightEdges) { - var i, iMax, id; + exports._placeNodesByHierarchy = function(distribution) { + var nodeId, node; - if (!selection || (selection.length == undefined)) - throw 'Selection must be an array with ids'; + // start placing all the level 0 nodes first. Then recursively position their branches. + for (var level in distribution) { + if (distribution.hasOwnProperty(level)) { - // first unselect any selected node - this._unselectAll(true); + for (nodeId in distribution[level].nodes) { + if (distribution[level].nodes.hasOwnProperty(nodeId)) { + node = distribution[level].nodes[nodeId]; + if (this.constants.hierarchicalLayout.direction == "UD" || this.constants.hierarchicalLayout.direction == "DU") { + if (node.xFixed) { + node.x = distribution[level].minPos; + node.xFixed = false; - for (i = 0, iMax = selection.length; i < iMax; i++) { - id = selection[i]; + distribution[level].minPos += distribution[level].nodeSpacing; + } + } + else { + if (node.yFixed) { + node.y = distribution[level].minPos; + node.yFixed = false; - var node = this.nodes[id]; - if (!node) { - throw new RangeError('Node with id "' + id + '" not found'); + distribution[level].minPos += distribution[level].nodeSpacing; + } + } + this._placeBranchNodes(node.edges,node.id,distribution,node.level); + } + } } - this._selectObject(node,true,true,highlightEdges,true); } - this.redraw(); + + // stabilize the system after positioning. This function calls zoomExtent. + this._stabilize(); }; /** - * select zero or more edges - * @param {Number[] | String[]} selection An array with the ids of the - * selected nodes. + * This function get the distribution of levels based on hubsize + * + * @returns {Object} + * @private */ - exports.selectEdges = function(selection) { - var i, iMax, id; - - if (!selection || (selection.length == undefined)) - throw 'Selection must be an array with ids'; + exports._getDistribution = function() { + var distribution = {}; + var nodeId, node, level; - // first unselect any selected node - this._unselectAll(true); + // we fix Y because the hierarchy is vertical, we fix X so we do not give a node an x position for a second time. + // the fix of X is removed after the x value has been set. + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + node.xFixed = true; + node.yFixed = true; + if (this.constants.hierarchicalLayout.direction == "UD" || this.constants.hierarchicalLayout.direction == "DU") { + node.y = this.constants.hierarchicalLayout.levelSeparation*node.level; + } + else { + node.x = this.constants.hierarchicalLayout.levelSeparation*node.level; + } + if (distribution[node.level] === undefined) { + distribution[node.level] = {amount: 0, nodes: {}, minPos:0, nodeSpacing:0}; + } + distribution[node.level].amount += 1; + distribution[node.level].nodes[nodeId] = node; + } + } - for (i = 0, iMax = selection.length; i < iMax; i++) { - id = selection[i]; + // determine the largest amount of nodes of all levels + var maxCount = 0; + for (level in distribution) { + if (distribution.hasOwnProperty(level)) { + if (maxCount < distribution[level].amount) { + maxCount = distribution[level].amount; + } + } + } - var edge = this.edges[id]; - if (!edge) { - throw new RangeError('Edge with id "' + id + '" not found'); + // set the initial position and spacing of each nodes accordingly + for (level in distribution) { + if (distribution.hasOwnProperty(level)) { + distribution[level].nodeSpacing = (maxCount + 1) * this.constants.hierarchicalLayout.nodeSpacing; + distribution[level].nodeSpacing /= (distribution[level].amount + 1); + distribution[level].minPos = distribution[level].nodeSpacing - (0.5 * (distribution[level].amount + 1) * distribution[level].nodeSpacing); } - this._selectObject(edge,true,true,false,true); } - this.redraw(); + + return distribution; }; + /** - * Validate the selection: remove ids of nodes which no longer exist + * this function allocates nodes in levels based on the recursive branching from the largest hubs. + * + * @param hubsize * @private */ - exports._updateSelection = function () { - for(var nodeId in this.selectionObj.nodes) { - if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { - if (!this.nodes.hasOwnProperty(nodeId)) { - delete this.selectionObj.nodes[nodeId]; + exports._determineLevels = function(hubsize) { + var nodeId, node; + + // determine hubs + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + if (node.edges.length == hubsize) { + node.level = 0; } } } - for(var edgeId in this.selectionObj.edges) { - if(this.selectionObj.edges.hasOwnProperty(edgeId)) { - if (!this.edges.hasOwnProperty(edgeId)) { - delete this.selectionObj.edges[edgeId]; + + // branch from hubs + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + if (node.level == 0) { + this._setLevel(1,node.edges,node.id); } } } }; -/***/ }, -/* 67 */ -/***/ function(module, exports, __webpack_require__) { - - var util = __webpack_require__(1); - var Node = __webpack_require__(56); - var Edge = __webpack_require__(57); /** - * clears the toolbar div element of children + * this function allocates nodes in levels based on the direction of the edges * + * @param hubsize * @private */ - exports._clearManipulatorBar = function() { - this._recursiveDOMDelete(this.manipulationDiv); - this.manipulationDOM = {}; + exports._determineLevelsDirected = function() { + var nodeId, node, firstNode; + var minLevel = 10000; - this._manipulationReleaseOverload = function () {}; - delete this.sectors['support']['nodes']['targetNode']; - delete this.sectors['support']['nodes']['targetViaNode']; - this.controlNodesActive = false; - this.freezeSimulation = false; - }; + // set first node to source + firstNode = this.nodes[this.nodeIndices[0]]; + firstNode.level = minLevel; + this._setLevelDirected(minLevel,firstNode.edges,firstNode.id); - /** - * Manipulation UI temporarily overloads certain functions to extend or replace them. To be able to restore - * these functions to their original functionality, we saved them in this.cachedFunctions. - * This function restores these functions to their original function. - * - * @private - */ - exports._restoreOverloadedFunctions = function() { - for (var functionName in this.cachedFunctions) { - if (this.cachedFunctions.hasOwnProperty(functionName)) { - this[functionName] = this.cachedFunctions[functionName]; - delete this.cachedFunctions[functionName]; + // get the minimum level + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + minLevel = node.level < minLevel ? node.level : minLevel; + } + } + + // subtract the minimum from the set so we have a range starting from 0 + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + node.level -= minLevel; } } }; + /** - * Enable or disable edit-mode. + * Since hierarchical layout does not support: + * - smooth curves (based on the physics), + * - clustering (based on dynamic node counts) + * + * We disable both features so there will be no problems. * * @private */ - exports._toggleEditMode = function() { - this.editMode = !this.editMode; - var toolbar = this.manipulationDiv; - var closeDiv = this.closeDiv; - var editModeDiv = this.editModeDiv; - if (this.editMode == true) { - toolbar.style.display="block"; - closeDiv.style.display="block"; - editModeDiv.style.display="none"; - closeDiv.onclick = this._toggleEditMode.bind(this); + exports._changeConstants = function() { + this.constants.clustering.enabled = false; + this.constants.physics.barnesHut.enabled = false; + this.constants.physics.hierarchicalRepulsion.enabled = true; + this._loadSelectedForceSolver(); + if (this.constants.smoothCurves.enabled == true) { + this.constants.smoothCurves.dynamic = false; + } + this._configureSmoothCurves(); + + var config = this.constants.hierarchicalLayout; + config.levelSeparation = Math.abs(config.levelSeparation); + if (config.direction == "RL" || config.direction == "DU") { + config.levelSeparation *= -1; + } + + if (config.direction == "RL" || config.direction == "LR") { + if (this.constants.smoothCurves.enabled == true) { + this.constants.smoothCurves.type = "vertical"; + } } else { - toolbar.style.display="none"; - closeDiv.style.display="none"; - editModeDiv.style.display="block"; - closeDiv.onclick = null; + if (this.constants.smoothCurves.enabled == true) { + this.constants.smoothCurves.type = "horizontal"; + } } - this._createManipulatorBar() }; + /** - * main function, creates the main toolbar. Removes functions bound to the select event. Binds all the buttons of the toolbar. + * This is a recursively called function to enumerate the branches from the largest hubs and place the nodes + * on a X position that ensures there will be no overlap. * + * @param edges + * @param parentId + * @param distribution + * @param parentLevel * @private */ - exports._createManipulatorBar = function() { - // remove bound functions - if (this.boundFunction) { - this.off('select', this.boundFunction); - } - - var locale = this.constants.locales[this.constants.locale]; - - if (this.edgeBeingEdited !== undefined) { - this.edgeBeingEdited._disableControlNodes(); - this.edgeBeingEdited = undefined; - this.selectedControlNode = null; - this.controlNodesActive = false; - this._redraw(); - } - - // restore overloaded functions - this._restoreOverloadedFunctions(); - - // resume calculation - this.freezeSimulation = false; - - // reset global variables - this.blockConnectingEdgeSelection = false; - this.forceAppendSelection = false; - this.manipulationDOM = {}; - - if (this.editMode == true) { - while (this.manipulationDiv.hasChildNodes()) { - this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); + exports._placeBranchNodes = function(edges, parentId, distribution, parentLevel) { + for (var i = 0; i < edges.length; i++) { + var childNode = null; + if (edges[i].toId == parentId) { + childNode = edges[i].from; } - - this.manipulationDOM['addNodeSpan'] = document.createElement('span'); - this.manipulationDOM['addNodeSpan'].className = 'network-manipulationUI add'; - this.manipulationDOM['addNodeLabelSpan'] = document.createElement('span'); - this.manipulationDOM['addNodeLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['addNodeLabelSpan'].innerHTML = locale['addNode']; - this.manipulationDOM['addNodeSpan'].appendChild(this.manipulationDOM['addNodeLabelSpan']); - - this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); - this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; - - this.manipulationDOM['addEdgeSpan'] = document.createElement('span'); - this.manipulationDOM['addEdgeSpan'].className = 'network-manipulationUI connect'; - this.manipulationDOM['addEdgeLabelSpan'] = document.createElement('span'); - this.manipulationDOM['addEdgeLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['addEdgeLabelSpan'].innerHTML = locale['addEdge']; - this.manipulationDOM['addEdgeSpan'].appendChild(this.manipulationDOM['addEdgeLabelSpan']); - - this.manipulationDiv.appendChild(this.manipulationDOM['addNodeSpan']); - this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); - this.manipulationDiv.appendChild(this.manipulationDOM['addEdgeSpan']); - - if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) { - this.manipulationDOM['seperatorLineDiv2'] = document.createElement('div'); - this.manipulationDOM['seperatorLineDiv2'].className = 'network-seperatorLine'; - - this.manipulationDOM['editNodeSpan'] = document.createElement('span'); - this.manipulationDOM['editNodeSpan'].className = 'network-manipulationUI edit'; - this.manipulationDOM['editNodeLabelSpan'] = document.createElement('span'); - this.manipulationDOM['editNodeLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['editNodeLabelSpan'].innerHTML = locale['editNode']; - this.manipulationDOM['editNodeSpan'].appendChild(this.manipulationDOM['editNodeLabelSpan']); - - this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv2']); - this.manipulationDiv.appendChild(this.manipulationDOM['editNodeSpan']); + else { + childNode = edges[i].to; } - else if (this._getSelectedEdgeCount() == 1 && this._getSelectedNodeCount() == 0) { - this.manipulationDOM['seperatorLineDiv3'] = document.createElement('div'); - this.manipulationDOM['seperatorLineDiv3'].className = 'network-seperatorLine'; - this.manipulationDOM['editEdgeSpan'] = document.createElement('span'); - this.manipulationDOM['editEdgeSpan'].className = 'network-manipulationUI edit'; - this.manipulationDOM['editEdgeLabelSpan'] = document.createElement('span'); - this.manipulationDOM['editEdgeLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['editEdgeLabelSpan'].innerHTML = locale['editEdge']; - this.manipulationDOM['editEdgeSpan'].appendChild(this.manipulationDOM['editEdgeLabelSpan']); + // if a node is conneceted to another node on the same level (or higher (means lower level))!, this is not handled here. + var nodeMoved = false; + if (this.constants.hierarchicalLayout.direction == "UD" || this.constants.hierarchicalLayout.direction == "DU") { + if (childNode.xFixed && childNode.level > parentLevel) { + childNode.xFixed = false; + childNode.x = distribution[childNode.level].minPos; + nodeMoved = true; + } + } + else { + if (childNode.yFixed && childNode.level > parentLevel) { + childNode.yFixed = false; + childNode.y = distribution[childNode.level].minPos; + nodeMoved = true; + } + } - this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv3']); - this.manipulationDiv.appendChild(this.manipulationDOM['editEdgeSpan']); + if (nodeMoved == true) { + distribution[childNode.level].minPos += distribution[childNode.level].nodeSpacing; + if (childNode.edges.length > 1) { + this._placeBranchNodes(childNode.edges,childNode.id,distribution,childNode.level); + } } - if (this._selectionIsEmpty() == false) { - this.manipulationDOM['seperatorLineDiv4'] = document.createElement('div'); - this.manipulationDOM['seperatorLineDiv4'].className = 'network-seperatorLine'; + } + }; - this.manipulationDOM['deleteSpan'] = document.createElement('span'); - this.manipulationDOM['deleteSpan'].className = 'network-manipulationUI delete'; - this.manipulationDOM['deleteLabelSpan'] = document.createElement('span'); - this.manipulationDOM['deleteLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['deleteLabelSpan'].innerHTML = locale['del']; - this.manipulationDOM['deleteSpan'].appendChild(this.manipulationDOM['deleteLabelSpan']); - this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv4']); - this.manipulationDiv.appendChild(this.manipulationDOM['deleteSpan']); + /** + * this function is called recursively to enumerate the barnches of the largest hubs and give each node a level. + * + * @param level + * @param edges + * @param parentId + * @private + */ + exports._setLevel = function(level, edges, parentId) { + for (var i = 0; i < edges.length; i++) { + var childNode = null; + if (edges[i].toId == parentId) { + childNode = edges[i].from; + } + else { + childNode = edges[i].to; + } + if (childNode.level == -1 || childNode.level > level) { + childNode.level = level; + if (childNode.edges.length > 1) { + this._setLevel(level+1, childNode.edges, childNode.id); + } } + } + }; - // bind the icons - this.manipulationDOM['addNodeSpan'].onclick = this._createAddNodeToolbar.bind(this); - this.manipulationDOM['addEdgeSpan'].onclick = this._createAddEdgeToolbar.bind(this); - if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) { - this.manipulationDOM['editNodeSpan'].onclick = this._editNode.bind(this); + /** + * this function is called recursively to enumerate the branched of the first node and give each node a level based on edge direction + * + * @param level + * @param edges + * @param parentId + * @private + */ + exports._setLevelDirected = function(level, edges, parentId) { + this.nodes[parentId].hierarchyEnumerated = true; + var childNode, direction; + for (var i = 0; i < edges.length; i++) { + direction = 1; + if (edges[i].toId == parentId) { + childNode = edges[i].from; + direction = -1; } - else if (this._getSelectedEdgeCount() == 1 && this._getSelectedNodeCount() == 0) { - this.manipulationDOM['editEdgeSpan'].onclick = this._createEditEdgeToolbar.bind(this); + else { + childNode = edges[i].to; } - if (this._selectionIsEmpty() == false) { - this.manipulationDOM['deleteSpan'].onclick = this._deleteSelected.bind(this); + if (childNode.level == -1) { + childNode.level = level + direction; } - this.closeDiv.onclick = this._toggleEditMode.bind(this); - - var me = this; - this.boundFunction = me._createManipulatorBar; - this.on('select', this.boundFunction); } - else { - while (this.editModeDiv.hasChildNodes()) { - this.editModeDiv.removeChild(this.editModeDiv.firstChild); - } - - this.manipulationDOM['editModeSpan'] = document.createElement('span'); - this.manipulationDOM['editModeSpan'].className = 'network-manipulationUI edit editmode'; - this.manipulationDOM['editModeLabelSpan'] = document.createElement('span'); - this.manipulationDOM['editModeLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['editModeLabelSpan'].innerHTML = locale['edit']; - this.manipulationDOM['editModeSpan'].appendChild(this.manipulationDOM['editModeLabelSpan']); - this.editModeDiv.appendChild(this.manipulationDOM['editModeSpan']); + for (var i = 0; i < edges.length; i++) { + if (edges[i].toId == parentId) {childNode = edges[i].from;} + else {childNode = edges[i].to;} - this.manipulationDOM['editModeSpan'].onclick = this._toggleEditMode.bind(this); + if (childNode.edges.length > 1 && childNode.hierarchyEnumerated === false) { + this._setLevelDirected(childNode.level, childNode.edges, childNode.id); + } } }; - /** - * Create the toolbar for adding Nodes + * Unfix nodes * * @private */ - exports._createAddNodeToolbar = function() { - // clear the toolbar - this._clearManipulatorBar(); - if (this.boundFunction) { - this.off('select', this.boundFunction); + exports._restoreNodes = function() { + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + this.nodes[nodeId].xFixed = false; + this.nodes[nodeId].yFixed = false; + } } + }; - var locale = this.constants.locales[this.constants.locale]; - - this.manipulationDOM = {}; - this.manipulationDOM['backSpan'] = document.createElement('span'); - this.manipulationDOM['backSpan'].className = 'network-manipulationUI back'; - this.manipulationDOM['backLabelSpan'] = document.createElement('span'); - this.manipulationDOM['backLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['backLabelSpan'].innerHTML = locale['back']; - this.manipulationDOM['backSpan'].appendChild(this.manipulationDOM['backLabelSpan']); - - this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); - this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; - - this.manipulationDOM['descriptionSpan'] = document.createElement('span'); - this.manipulationDOM['descriptionSpan'].className = 'network-manipulationUI none'; - this.manipulationDOM['descriptionLabelSpan'] = document.createElement('span'); - this.manipulationDOM['descriptionLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['descriptionLabelSpan'].innerHTML = locale['addDescription']; - this.manipulationDOM['descriptionSpan'].appendChild(this.manipulationDOM['descriptionLabelSpan']); - this.manipulationDiv.appendChild(this.manipulationDOM['backSpan']); - this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); - this.manipulationDiv.appendChild(this.manipulationDOM['descriptionSpan']); +/***/ }, +/* 66 */ +/***/ function(module, exports, __webpack_require__) { - // bind the icon - this.manipulationDOM['backSpan'].onclick = this._createManipulatorBar.bind(this); + var util = __webpack_require__(1); + var RepulsionMixin = __webpack_require__(68); + var HierarchialRepulsionMixin = __webpack_require__(69); + var BarnesHutMixin = __webpack_require__(70); - // we use the boundFunction so we can reference it when we unbind it from the "select" event. - var me = this; - this.boundFunction = me._addNode; - this.on('select', this.boundFunction); + /** + * Toggling barnes Hut calculation on and off. + * + * @private + */ + exports._toggleBarnesHut = function () { + this.constants.physics.barnesHut.enabled = !this.constants.physics.barnesHut.enabled; + this._loadSelectedForceSolver(); + this.moving = true; + this.start(); }; /** - * create the toolbar to connect nodes + * This loads the node force solver based on the barnes hut or repulsion algorithm * * @private */ - exports._createAddEdgeToolbar = function() { - // clear the toolbar - this._clearManipulatorBar(); - this._unselectAll(true); - this.freezeSimulation = true; - - if (this.boundFunction) { - this.off('select', this.boundFunction); - } - - var locale = this.constants.locales[this.constants.locale]; - - this._unselectAll(); - this.forceAppendSelection = false; - this.blockConnectingEdgeSelection = true; - - this.manipulationDOM = {}; - this.manipulationDOM['backSpan'] = document.createElement('span'); - this.manipulationDOM['backSpan'].className = 'network-manipulationUI back'; - this.manipulationDOM['backLabelSpan'] = document.createElement('span'); - this.manipulationDOM['backLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['backLabelSpan'].innerHTML = locale['back']; - this.manipulationDOM['backSpan'].appendChild(this.manipulationDOM['backLabelSpan']); - - this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); - this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; + exports._loadSelectedForceSolver = function () { + // this overloads the this._calculateNodeForces + if (this.constants.physics.barnesHut.enabled == true) { + this._clearMixin(RepulsionMixin); + this._clearMixin(HierarchialRepulsionMixin); - this.manipulationDOM['descriptionSpan'] = document.createElement('span'); - this.manipulationDOM['descriptionSpan'].className = 'network-manipulationUI none'; - this.manipulationDOM['descriptionLabelSpan'] = document.createElement('span'); - this.manipulationDOM['descriptionLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['descriptionLabelSpan'].innerHTML = locale['edgeDescription']; - this.manipulationDOM['descriptionSpan'].appendChild(this.manipulationDOM['descriptionLabelSpan']); + this.constants.physics.centralGravity = this.constants.physics.barnesHut.centralGravity; + this.constants.physics.springLength = this.constants.physics.barnesHut.springLength; + this.constants.physics.springConstant = this.constants.physics.barnesHut.springConstant; + this.constants.physics.damping = this.constants.physics.barnesHut.damping; - this.manipulationDiv.appendChild(this.manipulationDOM['backSpan']); - this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); - this.manipulationDiv.appendChild(this.manipulationDOM['descriptionSpan']); + this._loadMixin(BarnesHutMixin); + } + else if (this.constants.physics.hierarchicalRepulsion.enabled == true) { + this._clearMixin(BarnesHutMixin); + this._clearMixin(RepulsionMixin); - // bind the icon - this.manipulationDOM['backSpan'].onclick = this._createManipulatorBar.bind(this); + this.constants.physics.centralGravity = this.constants.physics.hierarchicalRepulsion.centralGravity; + this.constants.physics.springLength = this.constants.physics.hierarchicalRepulsion.springLength; + this.constants.physics.springConstant = this.constants.physics.hierarchicalRepulsion.springConstant; + this.constants.physics.damping = this.constants.physics.hierarchicalRepulsion.damping; - // we use the boundFunction so we can reference it when we unbind it from the "select" event. - var me = this; - this.boundFunction = me._handleConnect; - this.on('select', this.boundFunction); + this._loadMixin(HierarchialRepulsionMixin); + } + else { + this._clearMixin(BarnesHutMixin); + this._clearMixin(HierarchialRepulsionMixin); + this.barnesHutTree = undefined; - // temporarily overload functions - this.cachedFunctions["_handleTouch"] = this._handleTouch; - this.cachedFunctions["_manipulationReleaseOverload"] = this._manipulationReleaseOverload; - this.cachedFunctions["_handleDragStart"] = this._handleDragStart; - this.cachedFunctions["_handleDragEnd"] = this._handleDragEnd; - this._handleTouch = this._handleConnect; - this._manipulationReleaseOverload = function () {}; - this._handleDragStart = function () {}; - this._handleDragEnd = this._finishConnect; + this.constants.physics.centralGravity = this.constants.physics.repulsion.centralGravity; + this.constants.physics.springLength = this.constants.physics.repulsion.springLength; + this.constants.physics.springConstant = this.constants.physics.repulsion.springConstant; + this.constants.physics.damping = this.constants.physics.repulsion.damping; - // redraw to show the unselect - this._redraw(); + this._loadMixin(RepulsionMixin); + } }; /** - * create the toolbar to edit edges + * Before calculating the forces, we check if we need to cluster to keep up performance and we check + * if there is more than one node. If it is just one node, we dont calculate anything. * * @private */ - exports._createEditEdgeToolbar = function() { - // clear the toolbar - this._clearManipulatorBar(); - this.controlNodesActive = true; - - if (this.boundFunction) { - this.off('select', this.boundFunction); + exports._initializeForceCalculation = function () { + // stop calculation if there is only one node + if (this.nodeIndices.length == 1) { + this.nodes[this.nodeIndices[0]]._setForce(0, 0); } + else { + // if there are too many nodes on screen, we cluster without repositioning + if (this.nodeIndices.length > this.constants.clustering.clusterThreshold && this.constants.clustering.enabled == true) { + this.clusterToFit(this.constants.clustering.reduceToNodes, false); + } - this.edgeBeingEdited = this._getSelectedEdge(); - this.edgeBeingEdited._enableControlNodes(); + // we now start the force calculation + this._calculateForces(); + } + }; - var locale = this.constants.locales[this.constants.locale]; - this.manipulationDOM = {}; - this.manipulationDOM['backSpan'] = document.createElement('span'); - this.manipulationDOM['backSpan'].className = 'network-manipulationUI back'; - this.manipulationDOM['backLabelSpan'] = document.createElement('span'); - this.manipulationDOM['backLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['backLabelSpan'].innerHTML = locale['back']; - this.manipulationDOM['backSpan'].appendChild(this.manipulationDOM['backLabelSpan']); + /** + * Calculate the external forces acting on the nodes + * Forces are caused by: edges, repulsing forces between nodes, gravity + * @private + */ + exports._calculateForces = function () { + // Gravity is required to keep separated groups from floating off + // the forces are reset to zero in this loop by using _setForce instead + // of _addForce - this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); - this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; + this._calculateGravitationalForces(); + this._calculateNodeForces(); - this.manipulationDOM['descriptionSpan'] = document.createElement('span'); - this.manipulationDOM['descriptionSpan'].className = 'network-manipulationUI none'; - this.manipulationDOM['descriptionLabelSpan'] = document.createElement('span'); - this.manipulationDOM['descriptionLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['descriptionLabelSpan'].innerHTML = locale['editEdgeDescription']; - this.manipulationDOM['descriptionSpan'].appendChild(this.manipulationDOM['descriptionLabelSpan']); + if (this.constants.physics.springConstant > 0) { + if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { + this._calculateSpringForcesWithSupport(); + } + else { + if (this.constants.physics.hierarchicalRepulsion.enabled == true) { + this._calculateHierarchicalSpringForces(); + } + else { + this._calculateSpringForces(); + } + } + } + }; - this.manipulationDiv.appendChild(this.manipulationDOM['backSpan']); - this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); - this.manipulationDiv.appendChild(this.manipulationDOM['descriptionSpan']); - // bind the icon - this.manipulationDOM['backSpan'].onclick = this._createManipulatorBar.bind(this); + /** + * Smooth curves are created by adding invisible nodes in the center of the edges. These nodes are also + * handled in the calculateForces function. We then use a quadratic curve with the center node as control. + * This function joins the datanodes and invisible (called support) nodes into one object. + * We do this so we do not contaminate this.nodes with the support nodes. + * + * @private + */ + exports._updateCalculationNodes = function () { + if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { + this.calculationNodes = {}; + this.calculationNodeIndices = []; - // temporarily overload functions - this.cachedFunctions["_handleTouch"] = this._handleTouch; - this.cachedFunctions["_manipulationReleaseOverload"] = this._manipulationReleaseOverload; - this.cachedFunctions["_handleTap"] = this._handleTap; - this.cachedFunctions["_handleDragStart"] = this._handleDragStart; - this.cachedFunctions["_handleOnDrag"] = this._handleOnDrag; - this._handleTouch = this._selectControlNode; - this._handleTap = function () {}; - this._handleOnDrag = this._controlNodeDrag; - this._handleDragStart = function () {} - this._manipulationReleaseOverload = this._releaseControlNode; + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + this.calculationNodes[nodeId] = this.nodes[nodeId]; + } + } + var supportNodes = this.sectors['support']['nodes']; + for (var supportNodeId in supportNodes) { + if (supportNodes.hasOwnProperty(supportNodeId)) { + if (this.edges.hasOwnProperty(supportNodes[supportNodeId].parentEdgeId)) { + this.calculationNodes[supportNodeId] = supportNodes[supportNodeId]; + } + else { + supportNodes[supportNodeId]._setForce(0, 0); + } + } + } - // redraw to show the unselect - this._redraw(); + for (var idx in this.calculationNodes) { + if (this.calculationNodes.hasOwnProperty(idx)) { + this.calculationNodeIndices.push(idx); + } + } + } + else { + this.calculationNodes = this.nodes; + this.calculationNodeIndices = this.nodeIndices; + } }; /** - * the function bound to the selection event. It checks if you want to connect a cluster and changes the description - * to walk the user through the process. + * this function applies the central gravity effect to keep groups from floating off * * @private */ - exports._selectControlNode = function(pointer) { - this.edgeBeingEdited.controlNodes.from.unselect(); - this.edgeBeingEdited.controlNodes.to.unselect(); - this.selectedControlNode = this.edgeBeingEdited._getSelectedControlNode(this._XconvertDOMtoCanvas(pointer.x),this._YconvertDOMtoCanvas(pointer.y)); - if (this.selectedControlNode !== null) { - this.selectedControlNode.select(); - this.freezeSimulation = true; + exports._calculateGravitationalForces = function () { + var dx, dy, distance, node, i; + var nodes = this.calculationNodes; + var gravity = this.constants.physics.centralGravity; + var gravityForce = 0; + + for (i = 0; i < this.calculationNodeIndices.length; i++) { + node = nodes[this.calculationNodeIndices[i]]; + node.damping = this.constants.physics.damping; // possibly add function to alter damping properties of clusters. + // gravity does not apply when we are in a pocket sector + if (this._sector() == "default" && gravity != 0) { + dx = -node.x; + dy = -node.y; + distance = Math.sqrt(dx * dx + dy * dy); + + gravityForce = (distance == 0) ? 0 : (gravity / distance); + node.fx = dx * gravityForce; + node.fy = dy * gravityForce; + } + else { + node.fx = 0; + node.fy = 0; + } } - this._redraw(); }; + + /** - * the function bound to the selection event. It checks if you want to connect a cluster and changes the description - * to walk the user through the process. + * this function calculates the effects of the springs in the case of unsmooth curves. * * @private */ - exports._controlNodeDrag = function(event) { - var pointer = this._getPointer(event.gesture.center); - if (this.selectedControlNode !== null && this.selectedControlNode !== undefined) { - this.selectedControlNode.x = this._XconvertDOMtoCanvas(pointer.x); - this.selectedControlNode.y = this._YconvertDOMtoCanvas(pointer.y); + exports._calculateSpringForces = function () { + var edgeLength, edge, edgeId; + var dx, dy, fx, fy, springForce, distance; + var edges = this.edges; + + // forces caused by the edges, modelled as springs + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.connected) { + // only calculate forces if nodes are in the same sector + if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { + edgeLength = edge.physics.springLength; + // this implies that the edges between big clusters are longer + edgeLength += (edge.to.clusterSize + edge.from.clusterSize - 2) * this.constants.clustering.edgeGrowth; + + dx = (edge.from.x - edge.to.x); + dy = (edge.from.y - edge.to.y); + distance = Math.sqrt(dx * dx + dy * dy); + + if (distance == 0) { + distance = 0.01; + } + + // the 1/distance is so the fx and fy can be calculated without sine or cosine. + springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance; + + fx = dx * springForce; + fy = dy * springForce; + + edge.from.fx += fx; + edge.from.fy += fy; + edge.to.fx -= fx; + edge.to.fy -= fy; + } + } + } } - this._redraw(); }; + + /** + * This function calculates the springforces on the nodes, accounting for the support nodes. * - * @param pointer * @private */ - exports._releaseControlNode = function(pointer) { - var newNode = this._getNodeAt(pointer); - if (newNode !== null) { - if (this.edgeBeingEdited.controlNodes.from.selected == true) { - this.edgeBeingEdited._restoreControlNodes(); - this._editEdge(newNode.id, this.edgeBeingEdited.to.id); - this.edgeBeingEdited.controlNodes.from.unselect(); - } - if (this.edgeBeingEdited.controlNodes.to.selected == true) { - this.edgeBeingEdited._restoreControlNodes(); - this._editEdge(this.edgeBeingEdited.from.id, newNode.id); - this.edgeBeingEdited.controlNodes.to.unselect(); + exports._calculateSpringForcesWithSupport = function () { + var edgeLength, edge, edgeId, combinedClusterSize; + var edges = this.edges; + + // forces caused by the edges, modelled as springs + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.connected) { + // only calculate forces if nodes are in the same sector + if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { + if (edge.via != null) { + var node1 = edge.to; + var node2 = edge.via; + var node3 = edge.from; + + edgeLength = edge.physics.springLength; + + combinedClusterSize = node1.clusterSize + node3.clusterSize - 2; + + // this implies that the edges between big clusters are longer + edgeLength += combinedClusterSize * this.constants.clustering.edgeGrowth; + this._calculateSpringForce(node1, node2, 0.5 * edgeLength); + this._calculateSpringForce(node2, node3, 0.5 * edgeLength); + } + } + } } } - else { - this.edgeBeingEdited._restoreControlNodes(); - } - this.freezeSimulation = false; - this._redraw(); }; + /** - * the function bound to the selection event. It checks if you want to connect a cluster and changes the description - * to walk the user through the process. + * This is the code actually performing the calculation for the function above. It is split out to avoid repetition. * + * @param node1 + * @param node2 + * @param edgeLength * @private */ - exports._handleConnect = function(pointer) { - if (this._getSelectedNodeCount() == 0) { - var node = this._getNodeAt(pointer); + exports._calculateSpringForce = function (node1, node2, edgeLength) { + var dx, dy, fx, fy, springForce, distance; - if (node != null) { - if (node.clusterSize > 1) { - alert(this.constants.locales[this.constants.locale]['createEdgeError']) - } - else { - this._selectObject(node,false); - var supportNodes = this.sectors['support']['nodes']; + dx = (node1.x - node2.x); + dy = (node1.y - node2.y); + distance = Math.sqrt(dx * dx + dy * dy); - // create a node the temporary line can look at - supportNodes['targetNode'] = new Node({id:'targetNode'},{},{},this.constants); - var targetNode = supportNodes['targetNode']; - targetNode.x = node.x; - targetNode.y = node.y; + if (distance == 0) { + distance = 0.01; + } - // create a temporary edge - this.edges['connectionEdge'] = new Edge({id:"connectionEdge",from:node.id,to:targetNode.id}, this, this.constants); - var connectionEdge = this.edges['connectionEdge']; - connectionEdge.from = node; - connectionEdge.connected = true; - connectionEdge.options.smoothCurves = {enabled: true, - dynamic: false, - type: "continuous", - roundness: 0.5 - }; - connectionEdge.selected = true; - connectionEdge.to = targetNode; + // the 1/distance is so the fx and fy can be calculated without sine or cosine. + springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance; - this.cachedFunctions["_handleOnDrag"] = this._handleOnDrag; - this._handleOnDrag = function(event) { - var pointer = this._getPointer(event.gesture.center); - var connectionEdge = this.edges['connectionEdge']; - connectionEdge.to.x = this._XconvertDOMtoCanvas(pointer.x); - connectionEdge.to.y = this._YconvertDOMtoCanvas(pointer.y); - }; + fx = dx * springForce; + fy = dy * springForce; - this.moving = true; - this.start(); - } + node1.fx += fx; + node1.fy += fy; + node2.fx -= fx; + node2.fy -= fy; + }; + + + exports._cleanupPhysicsConfiguration = function() { + if (this.physicsConfiguration !== undefined) { + while (this.physicsConfiguration.hasChildNodes()) { + this.physicsConfiguration.removeChild(this.physicsConfiguration.firstChild); } + + this.physicsConfiguration.parentNode.removeChild(this.physicsConfiguration); + this.physicsConfiguration = undefined; } - }; + } - exports._finishConnect = function(event) { - if (this._getSelectedNodeCount() == 1) { - var pointer = this._getPointer(event.gesture.center); - // restore the drag function - this._handleOnDrag = this.cachedFunctions["_handleOnDrag"]; - delete this.cachedFunctions["_handleOnDrag"]; + /** + * Load the HTML for the physics config and bind it + * @private + */ + exports._loadPhysicsConfiguration = function () { + if (this.physicsConfiguration === undefined) { + this.backupConstants = {}; + util.deepExtend(this.backupConstants,this.constants); - // remember the edge id - var connectFromId = this.edges['connectionEdge'].fromId; + var hierarchicalLayoutDirections = ["LR", "RL", "UD", "DU"]; + this.physicsConfiguration = document.createElement('div'); + this.physicsConfiguration.className = "PhysicsConfiguration"; + this.physicsConfiguration.innerHTML = '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
Simulation Mode:
Barnes HutRepulsionHierarchical
' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
Options:
' + this.containerElement.parentElement.insertBefore(this.physicsConfiguration, this.containerElement); + this.optionsDiv = document.createElement("div"); + this.optionsDiv.style.fontSize = "14px"; + this.optionsDiv.style.fontFamily = "verdana"; + this.containerElement.parentElement.insertBefore(this.optionsDiv, this.containerElement); - // remove the temporary nodes and edge - delete this.edges['connectionEdge']; - delete this.sectors['support']['nodes']['targetNode']; - delete this.sectors['support']['nodes']['targetViaNode']; + var rangeElement; + rangeElement = document.getElementById('graph_BH_gc'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_gc', -1, "physics_barnesHut_gravitationalConstant"); + rangeElement = document.getElementById('graph_BH_cg'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_cg', 1, "physics_centralGravity"); + rangeElement = document.getElementById('graph_BH_sc'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_sc', 1, "physics_springConstant"); + rangeElement = document.getElementById('graph_BH_sl'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_sl', 1, "physics_springLength"); + rangeElement = document.getElementById('graph_BH_damp'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_damp', 1, "physics_damping"); - var node = this._getNodeAt(pointer); - if (node != null) { - if (node.clusterSize > 1) { - alert(this.constants.locales[this.constants.locale]["createEdgeError"]) - } - else { - this._createEdge(connectFromId,node.id); - this._createManipulatorBar(); - } + rangeElement = document.getElementById('graph_R_nd'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_nd', 1, "physics_repulsion_nodeDistance"); + rangeElement = document.getElementById('graph_R_cg'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_cg', 1, "physics_centralGravity"); + rangeElement = document.getElementById('graph_R_sc'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_sc', 1, "physics_springConstant"); + rangeElement = document.getElementById('graph_R_sl'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_sl', 1, "physics_springLength"); + rangeElement = document.getElementById('graph_R_damp'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_damp', 1, "physics_damping"); + + rangeElement = document.getElementById('graph_H_nd'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_nd', 1, "physics_hierarchicalRepulsion_nodeDistance"); + rangeElement = document.getElementById('graph_H_cg'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_cg', 1, "physics_centralGravity"); + rangeElement = document.getElementById('graph_H_sc'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_sc', 1, "physics_springConstant"); + rangeElement = document.getElementById('graph_H_sl'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_sl', 1, "physics_springLength"); + rangeElement = document.getElementById('graph_H_damp'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_damp', 1, "physics_damping"); + rangeElement = document.getElementById('graph_H_direction'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_direction', hierarchicalLayoutDirections, "hierarchicalLayout_direction"); + rangeElement = document.getElementById('graph_H_levsep'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_levsep', 1, "hierarchicalLayout_levelSeparation"); + rangeElement = document.getElementById('graph_H_nspac'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_nspac', 1, "hierarchicalLayout_nodeSpacing"); + + var radioButton1 = document.getElementById("graph_physicsMethod1"); + var radioButton2 = document.getElementById("graph_physicsMethod2"); + var radioButton3 = document.getElementById("graph_physicsMethod3"); + radioButton2.checked = true; + if (this.constants.physics.barnesHut.enabled) { + radioButton1.checked = true; + } + if (this.constants.hierarchicalLayout.enabled) { + radioButton3.checked = true; } - this._unselectAll(); - } - }; + var graph_toggleSmooth = document.getElementById("graph_toggleSmooth"); + var graph_repositionNodes = document.getElementById("graph_repositionNodes"); + var graph_generateOptions = document.getElementById("graph_generateOptions"); - /** - * Adds a node on the specified location - */ - exports._addNode = function() { - if (this._selectionIsEmpty() && this.editMode == true) { - var positionObject = this._pointerToPositionObject(this.pointerPosition); - var defaultData = {id:util.randomUUID(),x:positionObject.left,y:positionObject.top,label:"new",allowedToMoveX:true,allowedToMoveY:true}; - if (this.triggerFunctions.add) { - if (this.triggerFunctions.add.length == 2) { - var me = this; - this.triggerFunctions.add(defaultData, function(finalizedData) { - me.nodesData.add(finalizedData); - me._createManipulatorBar(); - me.moving = true; - me.start(); - }); - } - else { - throw new Error('The function for add does not support two arguments (data,callback)'); - this._createManipulatorBar(); - this.moving = true; - this.start(); - } + graph_toggleSmooth.onclick = graphToggleSmoothCurves.bind(this); + graph_repositionNodes.onclick = graphRepositionNodes.bind(this); + graph_generateOptions.onclick = graphGenerateOptions.bind(this); + if (this.constants.smoothCurves == true && this.constants.dynamicSmoothCurves == false) { + graph_toggleSmooth.style.background = "#A4FF56"; } else { - this.nodesData.add(defaultData); - this._createManipulatorBar(); - this.moving = true; - this.start(); + graph_toggleSmooth.style.background = "#FF8532"; } + + + switchConfigurations.apply(this); + + radioButton1.onchange = switchConfigurations.bind(this); + radioButton2.onchange = switchConfigurations.bind(this); + radioButton3.onchange = switchConfigurations.bind(this); } }; - /** - * connect two nodes with a new edge. + * This overwrites the this.constants. * + * @param constantsVariableName + * @param value * @private */ - exports._createEdge = function(sourceNodeId,targetNodeId) { - if (this.editMode == true) { - var defaultData = {from:sourceNodeId, to:targetNodeId}; - if (this.triggerFunctions.connect) { - if (this.triggerFunctions.connect.length == 2) { - var me = this; - this.triggerFunctions.connect(defaultData, function(finalizedData) { - me.edgesData.add(finalizedData); - me.moving = true; - me.start(); - }); - } - else { - throw new Error('The function for connect does not support two arguments (data,callback)'); - this.moving = true; - this.start(); - } - } - else { - this.edgesData.add(defaultData); - this.moving = true; - this.start(); - } + exports._overWriteGraphConstants = function (constantsVariableName, value) { + var nameArray = constantsVariableName.split("_"); + if (nameArray.length == 1) { + this.constants[nameArray[0]] = value; + } + else if (nameArray.length == 2) { + this.constants[nameArray[0]][nameArray[1]] = value; + } + else if (nameArray.length == 3) { + this.constants[nameArray[0]][nameArray[1]][nameArray[2]] = value; } }; + /** - * connect two nodes with a new edge. - * - * @private + * this function is bound to the toggle smooth curves button. That is also why it is not in the prototype. */ - exports._editEdge = function(sourceNodeId,targetNodeId) { - if (this.editMode == true) { - var defaultData = {id: this.edgeBeingEdited.id, from:sourceNodeId, to:targetNodeId}; - if (this.triggerFunctions.editEdge) { - if (this.triggerFunctions.editEdge.length == 2) { - var me = this; - this.triggerFunctions.editEdge(defaultData, function(finalizedData) { - me.edgesData.update(finalizedData); - me.moving = true; - me.start(); - }); - } - else { - throw new Error('The function for edit does not support two arguments (data, callback)'); - this.moving = true; - this.start(); - } - } - else { - this.edgesData.update(defaultData); - this.moving = true; - this.start(); - } - } - }; + function graphToggleSmoothCurves () { + this.constants.smoothCurves.enabled = !this.constants.smoothCurves.enabled; + var graph_toggleSmooth = document.getElementById("graph_toggleSmooth"); + if (this.constants.smoothCurves.enabled == true) {graph_toggleSmooth.style.background = "#A4FF56";} + else {graph_toggleSmooth.style.background = "#FF8532";} + + this._configureSmoothCurves(false); + } /** - * Create the toolbar to edit the selected node. The label and the color can be changed. Other colors are derived from the chosen color. + * this function is used to scramble the nodes * - * @private */ - exports._editNode = function() { - if (this.triggerFunctions.edit && this.editMode == true) { - var node = this._getSelectedNode(); - var data = {id:node.id, - label: node.label, - group: node.options.group, - shape: node.options.shape, - color: { - background:node.options.color.background, - border:node.options.color.border, - highlight: { - background:node.options.color.highlight.background, - border:node.options.color.highlight.border - } - }}; - if (this.triggerFunctions.edit.length == 2) { - var me = this; - this.triggerFunctions.edit(data, function (finalizedData) { - me.nodesData.update(finalizedData); - me._createManipulatorBar(); - me.moving = true; - me.start(); - }); - } - else { - throw new Error('The function for edit does not support two arguments (data, callback)'); + function graphRepositionNodes () { + for (var nodeId in this.calculationNodes) { + if (this.calculationNodes.hasOwnProperty(nodeId)) { + this.calculationNodes[nodeId].vx = 0; this.calculationNodes[nodeId].vy = 0; + this.calculationNodes[nodeId].fx = 0; this.calculationNodes[nodeId].fy = 0; } } + if (this.constants.hierarchicalLayout.enabled == true) { + this._setupHierarchicalLayout(); + showValueOfRange.call(this, 'graph_H_nd', 1, "physics_hierarchicalRepulsion_nodeDistance"); + showValueOfRange.call(this, 'graph_H_cg', 1, "physics_centralGravity"); + showValueOfRange.call(this, 'graph_H_sc', 1, "physics_springConstant"); + showValueOfRange.call(this, 'graph_H_sl', 1, "physics_springLength"); + showValueOfRange.call(this, 'graph_H_damp', 1, "physics_damping"); + } else { - throw new Error('No edit function has been bound to this button'); + this.repositionNodes(); } - }; - - - + this.moving = true; + this.start(); + } /** - * delete everything in the selection - * - * @private + * this is used to generate an options file from the playing with physics system. */ - exports._deleteSelected = function() { - if (!this._selectionIsEmpty() && this.editMode == true) { - if (!this._clusterInSelection()) { - var selectedNodes = this.getSelectedNodes(); - var selectedEdges = this.getSelectedEdges(); - if (this.triggerFunctions.del) { - var me = this; - var data = {nodes: selectedNodes, edges: selectedEdges}; - if (this.triggerFunctions.del.length == 2) { - this.triggerFunctions.del(data, function (finalizedData) { - me.edgesData.remove(finalizedData.edges); - me.nodesData.remove(finalizedData.nodes); - me._unselectAll(); - me.moving = true; - me.start(); - }); - } - else { - throw new Error('The function for delete does not support two arguments (data, callback)') + function graphGenerateOptions () { + var options = "No options are required, default values used."; + var optionsSpecific = []; + var radioButton1 = document.getElementById("graph_physicsMethod1"); + var radioButton2 = document.getElementById("graph_physicsMethod2"); + if (radioButton1.checked == true) { + if (this.constants.physics.barnesHut.gravitationalConstant != this.backupConstants.physics.barnesHut.gravitationalConstant) {optionsSpecific.push("gravitationalConstant: " + this.constants.physics.barnesHut.gravitationalConstant);} + if (this.constants.physics.centralGravity != this.backupConstants.physics.barnesHut.centralGravity) {optionsSpecific.push("centralGravity: " + this.constants.physics.centralGravity);} + if (this.constants.physics.springLength != this.backupConstants.physics.barnesHut.springLength) {optionsSpecific.push("springLength: " + this.constants.physics.springLength);} + if (this.constants.physics.springConstant != this.backupConstants.physics.barnesHut.springConstant) {optionsSpecific.push("springConstant: " + this.constants.physics.springConstant);} + if (this.constants.physics.damping != this.backupConstants.physics.barnesHut.damping) {optionsSpecific.push("damping: " + this.constants.physics.damping);} + if (optionsSpecific.length != 0) { + options = "var options = {"; + options += "physics: {barnesHut: {"; + for (var i = 0; i < optionsSpecific.length; i++) { + options += optionsSpecific[i]; + if (i < optionsSpecific.length - 1) { + options += ", " } } - else { - this.edgesData.remove(selectedEdges); - this.nodesData.remove(selectedNodes); - this._unselectAll(); - this.moving = true; - this.start(); + options += '}}' + } + if (this.constants.smoothCurves.enabled != this.backupConstants.smoothCurves.enabled) { + if (optionsSpecific.length == 0) {options = "var options = {";} + else {options += ", "} + options += "smoothCurves: " + this.constants.smoothCurves.enabled; + } + if (options != "No options are required, default values used.") { + options += '};' + } + } + else if (radioButton2.checked == true) { + options = "var options = {"; + options += "physics: {barnesHut: {enabled: false}"; + if (this.constants.physics.repulsion.nodeDistance != this.backupConstants.physics.repulsion.nodeDistance) {optionsSpecific.push("nodeDistance: " + this.constants.physics.repulsion.nodeDistance);} + if (this.constants.physics.centralGravity != this.backupConstants.physics.repulsion.centralGravity) {optionsSpecific.push("centralGravity: " + this.constants.physics.centralGravity);} + if (this.constants.physics.springLength != this.backupConstants.physics.repulsion.springLength) {optionsSpecific.push("springLength: " + this.constants.physics.springLength);} + if (this.constants.physics.springConstant != this.backupConstants.physics.repulsion.springConstant) {optionsSpecific.push("springConstant: " + this.constants.physics.springConstant);} + if (this.constants.physics.damping != this.backupConstants.physics.repulsion.damping) {optionsSpecific.push("damping: " + this.constants.physics.damping);} + if (optionsSpecific.length != 0) { + options += ", repulsion: {"; + for (var i = 0; i < optionsSpecific.length; i++) { + options += optionsSpecific[i]; + if (i < optionsSpecific.length - 1) { + options += ", " + } } + options += '}}' } - else { - alert(this.constants.locales[this.constants.locale]["deleteClusterError"]); + if (optionsSpecific.length == 0) {options += "}"} + if (this.constants.smoothCurves != this.backupConstants.smoothCurves) { + options += ", smoothCurves: " + this.constants.smoothCurves; } + options += '};' } - }; - - -/***/ }, -/* 68 */ -/***/ function(module, exports, __webpack_require__) { - - var util = __webpack_require__(1); - var Hammer = __webpack_require__(19); - - exports._cleanNavigation = function() { - // clean hammer bindings - if (this.navigationHammers.existing.length != 0) { - for (var i = 0; i < this.navigationHammers.existing.length; i++) { - this.navigationHammers.existing[i].dispose(); + else { + options = "var options = {"; + if (this.constants.physics.hierarchicalRepulsion.nodeDistance != this.backupConstants.physics.hierarchicalRepulsion.nodeDistance) {optionsSpecific.push("nodeDistance: " + this.constants.physics.hierarchicalRepulsion.nodeDistance);} + if (this.constants.physics.centralGravity != this.backupConstants.physics.hierarchicalRepulsion.centralGravity) {optionsSpecific.push("centralGravity: " + this.constants.physics.centralGravity);} + if (this.constants.physics.springLength != this.backupConstants.physics.hierarchicalRepulsion.springLength) {optionsSpecific.push("springLength: " + this.constants.physics.springLength);} + if (this.constants.physics.springConstant != this.backupConstants.physics.hierarchicalRepulsion.springConstant) {optionsSpecific.push("springConstant: " + this.constants.physics.springConstant);} + if (this.constants.physics.damping != this.backupConstants.physics.hierarchicalRepulsion.damping) {optionsSpecific.push("damping: " + this.constants.physics.damping);} + if (optionsSpecific.length != 0) { + options += "physics: {hierarchicalRepulsion: {"; + for (var i = 0; i < optionsSpecific.length; i++) { + options += optionsSpecific[i]; + if (i < optionsSpecific.length - 1) { + options += ", "; + } + } + options += '}},'; } - this.navigationHammers.existing = []; + options += 'hierarchicalLayout: {'; + optionsSpecific = []; + if (this.constants.hierarchicalLayout.direction != this.backupConstants.hierarchicalLayout.direction) {optionsSpecific.push("direction: " + this.constants.hierarchicalLayout.direction);} + if (Math.abs(this.constants.hierarchicalLayout.levelSeparation) != this.backupConstants.hierarchicalLayout.levelSeparation) {optionsSpecific.push("levelSeparation: " + this.constants.hierarchicalLayout.levelSeparation);} + if (this.constants.hierarchicalLayout.nodeSpacing != this.backupConstants.hierarchicalLayout.nodeSpacing) {optionsSpecific.push("nodeSpacing: " + this.constants.hierarchicalLayout.nodeSpacing);} + if (optionsSpecific.length != 0) { + for (var i = 0; i < optionsSpecific.length; i++) { + options += optionsSpecific[i]; + if (i < optionsSpecific.length - 1) { + options += ", " + } + } + options += '}' + } + else { + options += "enabled:true}"; + } + options += '};' } - this._navigationReleaseOverload = function () {}; - // clean up previous navigation items - if (this.navigationDivs && this.navigationDivs['wrapper'] && this.navigationDivs['wrapper'].parentNode) { - this.navigationDivs['wrapper'].parentNode.removeChild(this.navigationDivs['wrapper']); - } - }; + this.optionsDiv.innerHTML = options; + } /** - * Creation of the navigation controls nodes. They are drawn over the rest of the nodes and are not affected by scale and translation - * they have a triggerFunction which is called on click. If the position of the navigation controls is dependent - * on this.frame.canvas.clientWidth or this.frame.canvas.clientHeight, we flag horizontalAlignLeft and verticalAlignTop false. - * This means that the location will be corrected by the _relocateNavigation function on a size change of the canvas. + * this is used to switch between barnesHut, repulsion and hierarchical. * - * @private */ - exports._loadNavigationElements = function() { - this._cleanNavigation(); - - this.navigationDivs = {}; - var navigationDivs = ['up','down','left','right','zoomIn','zoomOut','zoomExtends']; - var navigationDivActions = ['_moveUp','_moveDown','_moveLeft','_moveRight','_zoomIn','_zoomOut','_zoomExtent']; - - this.navigationDivs['wrapper'] = document.createElement('div'); - this.frame.appendChild(this.navigationDivs['wrapper']); - - for (var i = 0; i < navigationDivs.length; i++) { - this.navigationDivs[navigationDivs[i]] = document.createElement('div'); - this.navigationDivs[navigationDivs[i]].className = 'network-navigation ' + navigationDivs[i]; - this.navigationDivs['wrapper'].appendChild(this.navigationDivs[navigationDivs[i]]); - - var hammer = Hammer(this.navigationDivs[navigationDivs[i]], {prevent_default: true}); - hammer.on('touch', this[navigationDivActions[i]].bind(this)); - this.navigationHammers._new.push(hammer); + function switchConfigurations () { + var ids = ["graph_BH_table", "graph_R_table", "graph_H_table"]; + var radioButton = document.querySelector('input[name="graph_physicsMethod"]:checked').value; + var tableId = "graph_" + radioButton + "_table"; + var table = document.getElementById(tableId); + table.style.display = "block"; + for (var i = 0; i < ids.length; i++) { + if (ids[i] != tableId) { + table = document.getElementById(ids[i]); + table.style.display = "none"; + } } - - this._navigationReleaseOverload = this._stopMovement; - - this.navigationHammers.existing = this.navigationHammers._new; - }; + this._restoreNodes(); + if (radioButton == "R") { + this.constants.hierarchicalLayout.enabled = false; + this.constants.physics.hierarchicalRepulsion.enabled = false; + this.constants.physics.barnesHut.enabled = false; + } + else if (radioButton == "H") { + if (this.constants.hierarchicalLayout.enabled == false) { + this.constants.hierarchicalLayout.enabled = true; + this.constants.physics.hierarchicalRepulsion.enabled = true; + this.constants.physics.barnesHut.enabled = false; + this.constants.smoothCurves.enabled = false; + this._setupHierarchicalLayout(); + } + } + else { + this.constants.hierarchicalLayout.enabled = false; + this.constants.physics.hierarchicalRepulsion.enabled = false; + this.constants.physics.barnesHut.enabled = true; + } + this._loadSelectedForceSolver(); + var graph_toggleSmooth = document.getElementById("graph_toggleSmooth"); + if (this.constants.smoothCurves.enabled == true) {graph_toggleSmooth.style.background = "#A4FF56";} + else {graph_toggleSmooth.style.background = "#FF8532";} + this.moving = true; + this.start(); + } /** - * this stops all movement induced by the navigation buttons + * this generates the ranges depending on the iniital values. * - * @private + * @param id + * @param map + * @param constantsVariableName */ - exports._zoomExtent = function(event) { - this.zoomExtent({duration:700}); - event.stopPropagation(); - }; + function showValueOfRange (id,map,constantsVariableName) { + var valueId = id + "_value"; + var rangeValue = document.getElementById(id).value; - /** - * this stops all movement induced by the navigation buttons - * - * @private - */ - exports._stopMovement = function() { - this._xStopMoving(); - this._yStopMoving(); - this._stopZoom(); - }; + if (Array.isArray(map)) { + document.getElementById(valueId).value = map[parseInt(rangeValue)]; + this._overWriteGraphConstants(constantsVariableName,map[parseInt(rangeValue)]); + } + else { + document.getElementById(valueId).value = parseInt(map) * parseFloat(rangeValue); + this._overWriteGraphConstants(constantsVariableName, parseInt(map) * parseFloat(rangeValue)); + } + if (constantsVariableName == "hierarchicalLayout_direction" || + constantsVariableName == "hierarchicalLayout_levelSeparation" || + constantsVariableName == "hierarchicalLayout_nodeSpacing") { + this._setupHierarchicalLayout(); + } + this.moving = true; + this.start(); + } - /** - * move the screen up - * By using the increments, instead of adding a fixed number to the translation, we keep fluent and - * instant movement. The onKeypress event triggers immediately, then pauses, then triggers frequently - * To avoid this behaviour, we do the translation in the start loop. - * - * @private - */ - exports._moveUp = function(event) { - this.yIncrement = this.constants.keyboard.speed.y; - this.start(); // if there is no node movement, the calculation wont be done - event.preventDefault(); - }; - /** - * move the screen down - * @private - */ - exports._moveDown = function(event) { - this.yIncrement = -this.constants.keyboard.speed.y; - this.start(); // if there is no node movement, the calculation wont be done - event.preventDefault(); - }; +/***/ }, +/* 67 */ +/***/ function(module, exports, __webpack_require__) { - /** - * move the screen left - * @private - */ - exports._moveLeft = function(event) { - this.xIncrement = this.constants.keyboard.speed.x; - this.start(); // if there is no node movement, the calculation wont be done - event.preventDefault(); - }; + function webpackContext(req) { + throw new Error("Cannot find module '" + req + "'."); + } + webpackContext.keys = function() { return []; }; + webpackContext.resolve = webpackContext; + module.exports = webpackContext; + webpackContext.id = 67; +/***/ }, +/* 68 */ +/***/ function(module, exports, __webpack_require__) { + /** - * move the screen right + * Calculate the forces the nodes apply on each other based on a repulsion field. + * This field is linearly approximated. + * * @private */ - exports._moveRight = function(event) { - this.xIncrement = -this.constants.keyboard.speed.y; - this.start(); // if there is no node movement, the calculation wont be done - event.preventDefault(); - }; + exports._calculateNodeForces = function () { + var dx, dy, angle, distance, fx, fy, combinedClusterSize, + repulsingForce, node1, node2, i, j; + var nodes = this.calculationNodes; + var nodeIndices = this.calculationNodeIndices; - /** - * Zoom in, using the same method as the movement. - * @private - */ - exports._zoomIn = function(event) { - this.zoomIncrement = this.constants.keyboard.speed.zoom; - this.start(); // if there is no node movement, the calculation wont be done - event.preventDefault(); - }; + // approximation constants + var a_base = -2 / 3; + var b = 4 / 3; + // repulsing forces between nodes + var nodeDistance = this.constants.physics.repulsion.nodeDistance; + var minimumDistance = nodeDistance; - /** - * Zoom out - * @private - */ - exports._zoomOut = function(event) { - this.zoomIncrement = -this.constants.keyboard.speed.zoom; - this.start(); // if there is no node movement, the calculation wont be done - event.preventDefault(); - }; + // we loop from i over all but the last entree in the array + // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j + for (i = 0; i < nodeIndices.length - 1; i++) { + node1 = nodes[nodeIndices[i]]; + for (j = i + 1; j < nodeIndices.length; j++) { + node2 = nodes[nodeIndices[j]]; + combinedClusterSize = node1.clusterSize + node2.clusterSize - 2; + dx = node2.x - node1.x; + dy = node2.y - node1.y; + distance = Math.sqrt(dx * dx + dy * dy); - /** - * Stop zooming and unhighlight the zoom controls - * @private - */ - exports._stopZoom = function(event) { - this.zoomIncrement = 0; - event && event.preventDefault(); - }; + // same condition as BarnesHut, making sure nodes are never 100% overlapping. + if (distance == 0) { + distance = 0.1*Math.random(); + dx = distance; + } + minimumDistance = (combinedClusterSize == 0) ? nodeDistance : (nodeDistance * (1 + combinedClusterSize * this.constants.clustering.distanceAmplification)); + var a = a_base / minimumDistance; + if (distance < 2 * minimumDistance) { + if (distance < 0.5 * minimumDistance) { + repulsingForce = 1.0; + } + else { + repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)) + } - /** - * Stop moving in the Y direction and unHighlight the up and down - * @private - */ - exports._yStopMoving = function(event) { - this.yIncrement = 0; - event && event.preventDefault(); - }; + // amplify the repulsion for clusters. + repulsingForce *= (combinedClusterSize == 0) ? 1 : 1 + combinedClusterSize * this.constants.clustering.forceAmplification; + repulsingForce = repulsingForce / Math.max(distance,0.01*minimumDistance); + fx = dx * repulsingForce; + fy = dy * repulsingForce; + node1.fx -= fx; + node1.fy -= fy; + node2.fx += fx; + node2.fy += fy; - /** - * Stop moving in the X direction and unHighlight left and right. - * @private - */ - exports._xStopMoving = function(event) { - this.xIncrement = 0; - event && event.preventDefault(); + } + } + } }; @@ -33956,676 +34057,579 @@ return /******/ (function(modules) { // webpackBootstrap /* 69 */ /***/ function(module, exports, __webpack_require__) { - exports._resetLevels = function() { - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - var node = this.nodes[nodeId]; - if (node.preassignedLevel == false) { - node.level = -1; - node.hierarchyEnumerated = false; - } - } - } - }; - /** - * This is the main function to layout the nodes in a hierarchical way. - * It checks if the node details are supplied correctly + * Calculate the forces the nodes apply on eachother based on a repulsion field. + * This field is linearly approximated. * * @private */ - exports._setupHierarchicalLayout = function() { - if (this.constants.hierarchicalLayout.enabled == true && this.nodeIndices.length > 0) { - // get the size of the largest hubs and check if the user has defined a level for a node. - var hubsize = 0; - var node, nodeId; - var definedLevel = false; - var undefinedLevel = false; + exports._calculateNodeForces = function () { + var dx, dy, distance, fx, fy, + repulsingForce, node1, node2, i, j; - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - if (node.level != -1) { - definedLevel = true; - } - else { - undefinedLevel = true; - } - if (hubsize < node.edges.length) { - hubsize = node.edges.length; - } - } - } + var nodes = this.calculationNodes; + var nodeIndices = this.calculationNodeIndices; - // if the user defined some levels but not all, alert and run without hierarchical layout - if (undefinedLevel == true && definedLevel == true) { - 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(undefined,true,this.constants.clustering.enabled); - if (!this.constants.clustering.enabled) { - this.start(); - } - } - else { - // setup the system to use hierarchical method. - this._changeConstants(); + // repulsing forces between nodes + var nodeDistance = this.constants.physics.hierarchicalRepulsion.nodeDistance; - // define levels if undefined by the users. Based on hubsize - if (undefinedLevel == true) { - if (this.constants.hierarchicalLayout.layout == "hubsize") { - this._determineLevels(hubsize); + // we loop from i over all but the last entree in the array + // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j + for (i = 0; i < nodeIndices.length - 1; i++) { + node1 = nodes[nodeIndices[i]]; + for (j = i + 1; j < nodeIndices.length; j++) { + node2 = nodes[nodeIndices[j]]; + + // nodes only affect nodes on their level + if (node1.level == node2.level) { + + dx = node2.x - node1.x; + dy = node2.y - node1.y; + distance = Math.sqrt(dx * dx + dy * dy); + + + var steepness = 0.05; + if (distance < nodeDistance) { + repulsingForce = -Math.pow(steepness*distance,2) + Math.pow(steepness*nodeDistance,2); } else { - this._determineLevelsDirected(false); + repulsingForce = 0; } + // normalize force with + if (distance == 0) { + distance = 0.01; + } + else { + repulsingForce = repulsingForce / distance; + } + fx = dx * repulsingForce; + fy = dy * repulsingForce; + node1.fx -= fx; + node1.fy -= fy; + node2.fx += fx; + node2.fy += fy; } - // check the distribution of the nodes per level. - var distribution = this._getDistribution(); - - // place the nodes on the canvas. This also stablilizes the system. - this._placeNodesByHierarchy(distribution); - - // start the simulation. - this.start(); } } }; /** - * This function places the nodes on the canvas based on the hierarchial distribution. + * this function calculates the effects of the springs in the case of unsmooth curves. * - * @param {Object} distribution | obtained by the function this._getDistribution() * @private */ - exports._placeNodesByHierarchy = function(distribution) { - var nodeId, node; + exports._calculateHierarchicalSpringForces = function () { + var edgeLength, edge, edgeId; + var dx, dy, fx, fy, springForce, distance; + var edges = this.edges; - // start placing all the level 0 nodes first. Then recursively position their branches. - for (var level in distribution) { - if (distribution.hasOwnProperty(level)) { + var nodes = this.calculationNodes; + var nodeIndices = this.calculationNodeIndices; - for (nodeId in distribution[level].nodes) { - if (distribution[level].nodes.hasOwnProperty(nodeId)) { - node = distribution[level].nodes[nodeId]; - if (this.constants.hierarchicalLayout.direction == "UD" || this.constants.hierarchicalLayout.direction == "DU") { - if (node.xFixed) { - node.x = distribution[level].minPos; - node.xFixed = false; - distribution[level].minPos += distribution[level].nodeSpacing; - } + for (var i = 0; i < nodeIndices.length; i++) { + var node1 = nodes[nodeIndices[i]]; + node1.springFx = 0; + node1.springFy = 0; + } + + + // forces caused by the edges, modelled as springs + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.connected) { + // only calculate forces if nodes are in the same sector + if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { + edgeLength = edge.physics.springLength; + // this implies that the edges between big clusters are longer + edgeLength += (edge.to.clusterSize + edge.from.clusterSize - 2) * this.constants.clustering.edgeGrowth; + + dx = (edge.from.x - edge.to.x); + dy = (edge.from.y - edge.to.y); + distance = Math.sqrt(dx * dx + dy * dy); + + if (distance == 0) { + distance = 0.01; } - else { - if (node.yFixed) { - node.y = distribution[level].minPos; - node.yFixed = false; - distribution[level].minPos += distribution[level].nodeSpacing; - } + // the 1/distance is so the fx and fy can be calculated without sine or cosine. + springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance; + + fx = dx * springForce; + fy = dy * springForce; + + + + if (edge.to.level != edge.from.level) { + edge.to.springFx -= fx; + edge.to.springFy -= fy; + edge.from.springFx += fx; + edge.from.springFy += fy; + } + else { + var factor = 0.5; + edge.to.fx -= factor*fx; + edge.to.fy -= factor*fy; + edge.from.fx += factor*fx; + edge.from.fy += factor*fy; } - this._placeBranchNodes(node.edges,node.id,distribution,node.level); } } } } - // stabilize the system after positioning. This function calls zoomExtent. - this._stabilize(); + // normalize spring forces + var springForce = 1; + var springFx, springFy; + for (i = 0; i < nodeIndices.length; i++) { + var node = nodes[nodeIndices[i]]; + springFx = Math.min(springForce,Math.max(-springForce,node.springFx)); + springFy = Math.min(springForce,Math.max(-springForce,node.springFy)); + + node.fx += springFx; + node.fy += springFy; + } + + // retain energy balance + var totalFx = 0; + var totalFy = 0; + for (i = 0; i < nodeIndices.length; i++) { + var node = nodes[nodeIndices[i]]; + totalFx += node.fx; + totalFy += node.fy; + } + var correctionFx = totalFx / nodeIndices.length; + var correctionFy = totalFy / nodeIndices.length; + + for (i = 0; i < nodeIndices.length; i++) { + var node = nodes[nodeIndices[i]]; + node.fx -= correctionFx; + node.fy -= correctionFy; + } + }; +/***/ }, +/* 70 */ +/***/ function(module, exports, __webpack_require__) { /** - * This function get the distribution of levels based on hubsize + * This function calculates the forces the nodes apply on eachother based on a gravitational model. + * The Barnes Hut method is used to speed up this N-body simulation. * - * @returns {Object} * @private */ - exports._getDistribution = function() { - var distribution = {}; - var nodeId, node, level; + exports._calculateNodeForces = function() { + if (this.constants.physics.barnesHut.gravitationalConstant != 0) { + var node; + var nodes = this.calculationNodes; + var nodeIndices = this.calculationNodeIndices; + var nodeCount = nodeIndices.length; - // we fix Y because the hierarchy is vertical, we fix X so we do not give a node an x position for a second time. - // the fix of X is removed after the x value has been set. - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - node.xFixed = true; - node.yFixed = true; - if (this.constants.hierarchicalLayout.direction == "UD" || this.constants.hierarchicalLayout.direction == "DU") { - node.y = this.constants.hierarchicalLayout.levelSeparation*node.level; - } - else { - node.x = this.constants.hierarchicalLayout.levelSeparation*node.level; - } - if (distribution[node.level] === undefined) { - distribution[node.level] = {amount: 0, nodes: {}, minPos:0, nodeSpacing:0}; - } - distribution[node.level].amount += 1; - distribution[node.level].nodes[nodeId] = node; - } - } + this._formBarnesHutTree(nodes,nodeIndices); - // determine the largest amount of nodes of all levels - var maxCount = 0; - for (level in distribution) { - if (distribution.hasOwnProperty(level)) { - if (maxCount < distribution[level].amount) { - maxCount = distribution[level].amount; - } - } - } + var barnesHutTree = this.barnesHutTree; - // set the initial position and spacing of each nodes accordingly - for (level in distribution) { - if (distribution.hasOwnProperty(level)) { - distribution[level].nodeSpacing = (maxCount + 1) * this.constants.hierarchicalLayout.nodeSpacing; - distribution[level].nodeSpacing /= (distribution[level].amount + 1); - distribution[level].minPos = distribution[level].nodeSpacing - (0.5 * (distribution[level].amount + 1) * distribution[level].nodeSpacing); + // place the nodes one by one recursively + for (var i = 0; i < nodeCount; i++) { + node = nodes[nodeIndices[i]]; + if (node.options.mass > 0) { + // starting with root is irrelevant, it never passes the BarnesHut condition + this._getForceContribution(barnesHutTree.root.children.NW,node); + this._getForceContribution(barnesHutTree.root.children.NE,node); + this._getForceContribution(barnesHutTree.root.children.SW,node); + this._getForceContribution(barnesHutTree.root.children.SE,node); + } } } - - return distribution; }; /** - * this function allocates nodes in levels based on the recursive branching from the largest hubs. + * This function traverses the barnesHutTree. It checks when it can approximate distant nodes with their center of mass. + * If a region contains a single node, we check if it is not itself, then we apply the force. * - * @param hubsize + * @param parentBranch + * @param node * @private */ - exports._determineLevels = function(hubsize) { - var nodeId, node; + exports._getForceContribution = function(parentBranch,node) { + // we get no force contribution from an empty region + if (parentBranch.childrenCount > 0) { + var dx,dy,distance; - // determine hubs - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - if (node.edges.length == hubsize) { - node.level = 0; + // get the distance from the center of mass to the node. + dx = parentBranch.centerOfMass.x - node.x; + dy = parentBranch.centerOfMass.y - node.y; + distance = Math.sqrt(dx * dx + dy * dy); + + // BarnesHut condition + // original condition : s/d < thetaInverted = passed === d/s > 1/theta = passed + // calcSize = 1/s --> d * 1/s > 1/theta = passed + if (distance * parentBranch.calcSize > this.constants.physics.barnesHut.thetaInverted) { + // duplicate code to reduce function calls to speed up program + if (distance == 0) { + distance = 0.1*Math.random(); + dx = distance; } + var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.options.mass / (distance * distance * distance); + var fx = dx * gravityForce; + var fy = dy * gravityForce; + node.fx += fx; + node.fy += fy; } - } - - // branch from hubs - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - if (node.level == 0) { - this._setLevel(1,node.edges,node.id); + else { + // Did not pass the condition, go into children if available + if (parentBranch.childrenCount == 4) { + this._getForceContribution(parentBranch.children.NW,node); + this._getForceContribution(parentBranch.children.NE,node); + this._getForceContribution(parentBranch.children.SW,node); + this._getForceContribution(parentBranch.children.SE,node); + } + else { // parentBranch must have only one node, if it was empty we wouldnt be here + if (parentBranch.children.data.id != node.id) { // if it is not self + // duplicate code to reduce function calls to speed up program + if (distance == 0) { + distance = 0.5*Math.random(); + dx = distance; + } + var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.options.mass / (distance * distance * distance); + var fx = dx * gravityForce; + var fy = dy * gravityForce; + node.fx += fx; + node.fy += fy; + } } } } }; - - /** - * this function allocates nodes in levels based on the direction of the edges + * This function constructs the barnesHut tree recursively. It creates the root, splits it and starts placing the nodes. * - * @param hubsize + * @param nodes + * @param nodeIndices * @private */ - exports._determineLevelsDirected = function() { - var nodeId, node, firstNode; - var minLevel = 10000; + exports._formBarnesHutTree = function(nodes,nodeIndices) { + var node; + var nodeCount = nodeIndices.length; - // set first node to source - firstNode = this.nodes[this.nodeIndices[0]]; - firstNode.level = minLevel; - this._setLevelDirected(minLevel,firstNode.edges,firstNode.id); + var minX = Number.MAX_VALUE, + minY = Number.MAX_VALUE, + maxX =-Number.MAX_VALUE, + maxY =-Number.MAX_VALUE; - // get the minimum level - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - minLevel = node.level < minLevel ? node.level : minLevel; + // get the range of the nodes + for (var i = 0; i < nodeCount; i++) { + var x = nodes[nodeIndices[i]].x; + var y = nodes[nodeIndices[i]].y; + if (nodes[nodeIndices[i]].options.mass > 0) { + if (x < minX) { minX = x; } + if (x > maxX) { maxX = x; } + if (y < minY) { minY = y; } + if (y > maxY) { maxY = y; } } } + // make the range a square + var sizeDiff = Math.abs(maxX - minX) - Math.abs(maxY - minY); // difference between X and Y + if (sizeDiff > 0) {minY -= 0.5 * sizeDiff; maxY += 0.5 * sizeDiff;} // xSize > ySize + else {minX += 0.5 * sizeDiff; maxX -= 0.5 * sizeDiff;} // xSize < ySize - // subtract the minimum from the set so we have a range starting from 0 - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - node.level -= minLevel; + + var minimumTreeSize = 1e-5; + var rootSize = Math.max(minimumTreeSize,Math.abs(maxX - minX)); + var halfRootSize = 0.5 * rootSize; + var centerX = 0.5 * (minX + maxX), centerY = 0.5 * (minY + maxY); + + // construct the barnesHutTree + var barnesHutTree = { + root:{ + centerOfMass: {x:0, y:0}, + mass:0, + range: { + minX: centerX-halfRootSize,maxX:centerX+halfRootSize, + minY: centerY-halfRootSize,maxY:centerY+halfRootSize + }, + size: rootSize, + calcSize: 1 / rootSize, + children: { data:null}, + maxWidth: 0, + level: 0, + childrenCount: 4 + } + }; + this._splitBranch(barnesHutTree.root); + + // place the nodes one by one recursively + for (i = 0; i < nodeCount; i++) { + node = nodes[nodeIndices[i]]; + if (node.options.mass > 0) { + this._placeInTree(barnesHutTree.root,node); } } + + // make global + this.barnesHutTree = barnesHutTree }; /** - * Since hierarchical layout does not support: - * - smooth curves (based on the physics), - * - clustering (based on dynamic node counts) - * - * We disable both features so there will be no problems. + * this updates the mass of a branch. this is increased by adding a node. * + * @param parentBranch + * @param node * @private */ - exports._changeConstants = function() { - this.constants.clustering.enabled = false; - this.constants.physics.barnesHut.enabled = false; - this.constants.physics.hierarchicalRepulsion.enabled = true; - this._loadSelectedForceSolver(); - if (this.constants.smoothCurves.enabled == true) { - this.constants.smoothCurves.dynamic = false; - } - this._configureSmoothCurves(); + exports._updateBranchMass = function(parentBranch, node) { + var totalMass = parentBranch.mass + node.options.mass; + var totalMassInv = 1/totalMass; - var config = this.constants.hierarchicalLayout; - config.levelSeparation = Math.abs(config.levelSeparation); - if (config.direction == "RL" || config.direction == "DU") { - config.levelSeparation *= -1; - } + parentBranch.centerOfMass.x = parentBranch.centerOfMass.x * parentBranch.mass + node.x * node.options.mass; + parentBranch.centerOfMass.x *= totalMassInv; + + parentBranch.centerOfMass.y = parentBranch.centerOfMass.y * parentBranch.mass + node.y * node.options.mass; + parentBranch.centerOfMass.y *= totalMassInv; + + parentBranch.mass = totalMass; + var biggestSize = Math.max(Math.max(node.height,node.radius),node.width); + parentBranch.maxWidth = (parentBranch.maxWidth < biggestSize) ? biggestSize : parentBranch.maxWidth; - if (config.direction == "RL" || config.direction == "LR") { - if (this.constants.smoothCurves.enabled == true) { - this.constants.smoothCurves.type = "vertical"; - } - } - else { - if (this.constants.smoothCurves.enabled == true) { - this.constants.smoothCurves.type = "horizontal"; - } - } }; /** - * This is a recursively called function to enumerate the branches from the largest hubs and place the nodes - * on a X position that ensures there will be no overlap. + * determine in which branch the node will be placed. * - * @param edges - * @param parentId - * @param distribution - * @param parentLevel + * @param parentBranch + * @param node + * @param skipMassUpdate * @private */ - exports._placeBranchNodes = function(edges, parentId, distribution, parentLevel) { - for (var i = 0; i < edges.length; i++) { - var childNode = null; - if (edges[i].toId == parentId) { - childNode = edges[i].from; - } - else { - childNode = edges[i].to; - } + exports._placeInTree = function(parentBranch,node,skipMassUpdate) { + if (skipMassUpdate != true || skipMassUpdate === undefined) { + // update the mass of the branch. + this._updateBranchMass(parentBranch,node); + } - // if a node is conneceted to another node on the same level (or higher (means lower level))!, this is not handled here. - var nodeMoved = false; - if (this.constants.hierarchicalLayout.direction == "UD" || this.constants.hierarchicalLayout.direction == "DU") { - if (childNode.xFixed && childNode.level > parentLevel) { - childNode.xFixed = false; - childNode.x = distribution[childNode.level].minPos; - nodeMoved = true; - } + if (parentBranch.children.NW.range.maxX > node.x) { // in NW or SW + if (parentBranch.children.NW.range.maxY > node.y) { // in NW + this._placeInRegion(parentBranch,node,"NW"); } - else { - if (childNode.yFixed && childNode.level > parentLevel) { - childNode.yFixed = false; - childNode.y = distribution[childNode.level].minPos; - nodeMoved = true; - } + else { // in SW + this._placeInRegion(parentBranch,node,"SW"); } - - if (nodeMoved == true) { - distribution[childNode.level].minPos += distribution[childNode.level].nodeSpacing; - if (childNode.edges.length > 1) { - this._placeBranchNodes(childNode.edges,childNode.id,distribution,childNode.level); - } + } + else { // in NE or SE + if (parentBranch.children.NW.range.maxY > node.y) { // in NE + this._placeInRegion(parentBranch,node,"NE"); + } + else { // in SE + this._placeInRegion(parentBranch,node,"SE"); } } }; /** - * this function is called recursively to enumerate the barnches of the largest hubs and give each node a level. + * actually place the node in a region (or branch) * - * @param level - * @param edges - * @param parentId + * @param parentBranch + * @param node + * @param region * @private */ - exports._setLevel = function(level, edges, parentId) { - for (var i = 0; i < edges.length; i++) { - var childNode = null; - if (edges[i].toId == parentId) { - childNode = edges[i].from; - } - else { - childNode = edges[i].to; - } - if (childNode.level == -1 || childNode.level > level) { - childNode.level = level; - if (childNode.edges.length > 1) { - this._setLevel(level+1, childNode.edges, childNode.id); + exports._placeInRegion = function(parentBranch,node,region) { + switch (parentBranch.children[region].childrenCount) { + case 0: // place node here + parentBranch.children[region].children.data = node; + parentBranch.children[region].childrenCount = 1; + this._updateBranchMass(parentBranch.children[region],node); + break; + case 1: // convert into children + // if there are two nodes exactly overlapping (on init, on opening of cluster etc.) + // we move one node a pixel and we do not put it in the tree. + if (parentBranch.children[region].children.data.x == node.x && + parentBranch.children[region].children.data.y == node.y) { + node.x += Math.random(); + node.y += Math.random(); } - } + else { + this._splitBranch(parentBranch.children[region]); + this._placeInTree(parentBranch.children[region],node); + } + break; + case 4: // place in branch + this._placeInTree(parentBranch.children[region],node); + break; } }; /** - * this function is called recursively to enumerate the branched of the first node and give each node a level based on edge direction + * this function splits a branch into 4 sub branches. If the branch contained a node, we place it in the subbranch + * after the split is complete. * - * @param level - * @param edges - * @param parentId + * @param parentBranch * @private */ - exports._setLevelDirected = function(level, edges, parentId) { - this.nodes[parentId].hierarchyEnumerated = true; - var childNode, direction; - for (var i = 0; i < edges.length; i++) { - direction = 1; - if (edges[i].toId == parentId) { - childNode = edges[i].from; - direction = -1; - } - else { - childNode = edges[i].to; - } - if (childNode.level == -1) { - childNode.level = level + direction; - } + exports._splitBranch = function(parentBranch) { + // if the branch is shaded with a node, replace the node in the new subset. + var containedNode = null; + if (parentBranch.childrenCount == 1) { + containedNode = parentBranch.children.data; + parentBranch.mass = 0; parentBranch.centerOfMass.x = 0; parentBranch.centerOfMass.y = 0; } + parentBranch.childrenCount = 4; + parentBranch.children.data = null; + this._insertRegion(parentBranch,"NW"); + this._insertRegion(parentBranch,"NE"); + this._insertRegion(parentBranch,"SW"); + this._insertRegion(parentBranch,"SE"); - for (var i = 0; i < edges.length; i++) { - if (edges[i].toId == parentId) {childNode = edges[i].from;} - else {childNode = edges[i].to;} - - if (childNode.edges.length > 1 && childNode.hierarchyEnumerated === false) { - this._setLevelDirected(childNode.level, childNode.edges, childNode.id); - } + if (containedNode != null) { + this._placeInTree(parentBranch,containedNode); } }; /** - * Unfix nodes + * This function subdivides the region into four new segments. + * Specifically, this inserts a single new segment. + * It fills the children section of the parentBranch * + * @param parentBranch + * @param region + * @param parentRange * @private */ - exports._restoreNodes = function() { - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - this.nodes[nodeId].xFixed = false; - this.nodes[nodeId].yFixed = false; - } + exports._insertRegion = function(parentBranch, region) { + var minX,maxX,minY,maxY; + var childSize = 0.5 * parentBranch.size; + switch (region) { + case "NW": + minX = parentBranch.range.minX; + maxX = parentBranch.range.minX + childSize; + minY = parentBranch.range.minY; + maxY = parentBranch.range.minY + childSize; + break; + case "NE": + minX = parentBranch.range.minX + childSize; + maxX = parentBranch.range.maxX; + minY = parentBranch.range.minY; + maxY = parentBranch.range.minY + childSize; + break; + case "SW": + minX = parentBranch.range.minX; + maxX = parentBranch.range.minX + childSize; + minY = parentBranch.range.minY + childSize; + maxY = parentBranch.range.maxY; + break; + case "SE": + minX = parentBranch.range.minX + childSize; + maxX = parentBranch.range.maxX; + minY = parentBranch.range.minY + childSize; + maxY = parentBranch.range.maxY; + break; } - }; - - -/***/ }, -/* 70 */ -/***/ function(module, exports, __webpack_require__) { - // English - exports['en'] = { - edit: 'Edit', - del: 'Delete selected', - back: 'Back', - addNode: 'Add Node', - addEdge: 'Add Edge', - editNode: 'Edit Node', - editEdge: 'Edit Edge', - addDescription: 'Click in an empty space to place a new node.', - edgeDescription: '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'] = { - edit: 'Wijzigen', - del: 'Selectie verwijderen', - back: 'Terug', - addNode: 'Node toevoegen', - addEdge: 'Link toevoegen', - editNode: 'Node wijzigen', - editEdge: 'Link wijzigen', - addDescription: 'Klik op een leeg gebied om een nieuwe node te maken.', - edgeDescription: '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.' + parentBranch.children[region] = { + centerOfMass:{x:0,y:0}, + mass:0, + range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY}, + size: 0.5 * parentBranch.size, + calcSize: 2 * parentBranch.calcSize, + children: {data:null}, + maxWidth: 0, + level: parentBranch.level+1, + childrenCount: 0 + }; }; - exports['nl_NL'] = exports['nl']; - exports['nl_BE'] = exports['nl']; - -/***/ }, -/* 71 */ -/***/ function(module, exports, __webpack_require__) { /** - * Canvas shapes used by Network + * This function is for debugging purposed, it draws the tree. + * + * @param ctx + * @param color + * @private */ - if (typeof CanvasRenderingContext2D !== 'undefined') { - - /** - * Draw a circle shape - */ - CanvasRenderingContext2D.prototype.circle = function(x, y, r) { - this.beginPath(); - this.arc(x, y, r, 0, 2*Math.PI, false); - }; - - /** - * Draw a square shape - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r size, width and height of the square - */ - CanvasRenderingContext2D.prototype.square = function(x, y, r) { - this.beginPath(); - this.rect(x - r, y - r, r * 2, r * 2); - }; - - /** - * Draw a triangle shape - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r radius, half the length of the sides of the triangle - */ - CanvasRenderingContext2D.prototype.triangle = function(x, y, r) { - // http://en.wikipedia.org/wiki/Equilateral_triangle - this.beginPath(); - - var s = r * 2; - var s2 = s / 2; - var ir = Math.sqrt(3) / 6 * s; // radius of inner circle - var h = Math.sqrt(s * s - s2 * s2); // height - - this.moveTo(x, y - (h - ir)); - this.lineTo(x + s2, y + ir); - this.lineTo(x - s2, y + ir); - this.lineTo(x, y - (h - ir)); - this.closePath(); - }; - - /** - * Draw a triangle shape in downward orientation - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r radius - */ - CanvasRenderingContext2D.prototype.triangleDown = function(x, y, r) { - // http://en.wikipedia.org/wiki/Equilateral_triangle - this.beginPath(); - - var s = r * 2; - var s2 = s / 2; - var ir = Math.sqrt(3) / 6 * s; // radius of inner circle - var h = Math.sqrt(s * s - s2 * s2); // height - - this.moveTo(x, y + (h - ir)); - this.lineTo(x + s2, y - ir); - this.lineTo(x - s2, y - ir); - this.lineTo(x, y + (h - ir)); - this.closePath(); - }; - - /** - * Draw a star shape, a star with 5 points - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r radius, half the length of the sides of the triangle - */ - CanvasRenderingContext2D.prototype.star = function(x, y, r) { - // http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/ - this.beginPath(); - - for (var n = 0; n < 10; n++) { - var radius = (n % 2 === 0) ? r * 1.3 : r * 0.5; - this.lineTo( - x + radius * Math.sin(n * 2 * Math.PI / 10), - y - radius * Math.cos(n * 2 * Math.PI / 10) - ); - } - - this.closePath(); - }; - - /** - * http://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas - */ - CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) { - var r2d = Math.PI/180; - if( w - ( 2 * r ) < 0 ) { r = ( w / 2 ); } //ensure that the radius isn't too large for x - if( h - ( 2 * r ) < 0 ) { r = ( h / 2 ); } //ensure that the radius isn't too large for y - this.beginPath(); - this.moveTo(x+r,y); - this.lineTo(x+w-r,y); - this.arc(x+w-r,y+r,r,r2d*270,r2d*360,false); - this.lineTo(x+w,y+h-r); - this.arc(x+w-r,y+h-r,r,0,r2d*90,false); - this.lineTo(x+r,y+h); - this.arc(x+r,y+h-r,r,r2d*90,r2d*180,false); - this.lineTo(x,y+r); - this.arc(x+r,y+r,r,r2d*180,r2d*270,false); - }; - - /** - * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - */ - CanvasRenderingContext2D.prototype.ellipse = function(x, y, w, h) { - var kappa = .5522848, - ox = (w / 2) * kappa, // control point offset horizontal - oy = (h / 2) * kappa, // control point offset vertical - xe = x + w, // x-end - ye = y + h, // y-end - xm = x + w / 2, // x-middle - ym = y + h / 2; // y-middle - - this.beginPath(); - this.moveTo(x, ym); - this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - }; - - - - /** - * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - */ - CanvasRenderingContext2D.prototype.database = function(x, y, w, h) { - var f = 1/3; - var wEllipse = w; - var hEllipse = h * f; + exports._drawTree = function(ctx,color) { + if (this.barnesHutTree !== undefined) { - var kappa = .5522848, - ox = (wEllipse / 2) * kappa, // control point offset horizontal - oy = (hEllipse / 2) * kappa, // control point offset vertical - xe = x + wEllipse, // x-end - ye = y + hEllipse, // y-end - xm = x + wEllipse / 2, // x-middle - ym = y + hEllipse / 2, // y-middle - ymb = y + (h - hEllipse/2), // y-midlle, bottom ellipse - yeb = y + h; // y-end, bottom ellipse + ctx.lineWidth = 1; - this.beginPath(); - this.moveTo(xe, ym); + this._drawBranch(this.barnesHutTree.root,ctx,color); + } + }; - this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + /** + * This function is for debugging purposes. It draws the branches recursively. + * + * @param branch + * @param ctx + * @param color + * @private + */ + exports._drawBranch = function(branch,ctx,color) { + if (color === undefined) { + color = "#FF0000"; + } - this.lineTo(xe, ymb); + if (branch.childrenCount == 4) { + this._drawBranch(branch.children.NW,ctx); + this._drawBranch(branch.children.NE,ctx); + this._drawBranch(branch.children.SE,ctx); + this._drawBranch(branch.children.SW,ctx); + } + ctx.strokeStyle = color; + ctx.beginPath(); + ctx.moveTo(branch.range.minX,branch.range.minY); + ctx.lineTo(branch.range.maxX,branch.range.minY); + ctx.stroke(); - this.bezierCurveTo(xe, ymb + oy, xm + ox, yeb, xm, yeb); - this.bezierCurveTo(xm - ox, yeb, x, ymb + oy, x, ymb); + ctx.beginPath(); + ctx.moveTo(branch.range.maxX,branch.range.minY); + ctx.lineTo(branch.range.maxX,branch.range.maxY); + ctx.stroke(); - this.lineTo(x, ym); - }; + ctx.beginPath(); + ctx.moveTo(branch.range.maxX,branch.range.maxY); + ctx.lineTo(branch.range.minX,branch.range.maxY); + ctx.stroke(); + ctx.beginPath(); + ctx.moveTo(branch.range.minX,branch.range.maxY); + ctx.lineTo(branch.range.minX,branch.range.minY); + ctx.stroke(); - /** - * Draw an arrow point (no line) + /* + if (branch.mass > 0) { + ctx.circle(branch.centerOfMass.x, branch.centerOfMass.y, 3*branch.mass); + ctx.stroke(); + } */ - CanvasRenderingContext2D.prototype.arrow = function(x, y, angle, length) { - // tail - var xt = x - length * Math.cos(angle); - var yt = y - length * Math.sin(angle); - - // inner tail - // TODO: allow to customize different shapes - var xi = x - length * 0.9 * Math.cos(angle); - var yi = y - length * 0.9 * Math.sin(angle); - - // left - var xl = xt + length / 3 * Math.cos(angle + 0.5 * Math.PI); - var yl = yt + length / 3 * Math.sin(angle + 0.5 * Math.PI); - - // right - var xr = xt + length / 3 * Math.cos(angle - 0.5 * Math.PI); - var yr = yt + length / 3 * Math.sin(angle - 0.5 * Math.PI); + }; - this.beginPath(); - this.moveTo(x, y); - this.lineTo(xl, yl); - this.lineTo(xi, yi); - this.lineTo(xr, yr); - this.closePath(); - }; - /** - * Sets up the dashedLine functionality for drawing - * Original code came from http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas - * @author David Jordan - * @date 2012-08-08 - */ - CanvasRenderingContext2D.prototype.dashedLine = function(x,y,x2,y2,dashArray){ - if (!dashArray) dashArray=[10,5]; - if (dashLength==0) dashLength = 0.001; // Hack for Safari - var dashCount = dashArray.length; - this.moveTo(x, y); - var dx = (x2-x), dy = (y2-y); - var slope = dy/dx; - var distRemaining = Math.sqrt( dx*dx + dy*dy ); - var dashIndex=0, draw=true; - while (distRemaining>=0.1){ - var dashLength = dashArray[dashIndex++%dashCount]; - if (dashLength > distRemaining) dashLength = distRemaining; - var xStep = Math.sqrt( dashLength*dashLength / (1 + slope*slope) ); - if (dx<0) xStep = -xStep; - x += xStep; - y += slope*xStep; - this[draw ? 'lineTo' : 'moveTo'](x,y); - distRemaining -= dashLength; - draw = !draw; - } - }; +/***/ }, +/* 71 */ +/***/ function(module, exports, __webpack_require__) { - // TODO: add diamond shape + module.exports = function(module) { + if(!module.webpackPolyfill) { + module.deprecate = function() {}; + module.paths = []; + // module.parent = undefined by default + module.children = []; + module.webpackPolyfill = 1; + } + return module; } diff --git a/lib/network/Network.js b/lib/network/Network.js index eaae2ced..ecc89e22 100644 --- a/lib/network/Network.js +++ b/lib/network/Network.js @@ -229,6 +229,7 @@ function Network (container, data, options) { // animation properties this.animationSpeed = 1/this.renderRefreshRate; this.animationEasingFunction = "easeInOutQuint"; + this.animating = false; this.easingTime = 0; this.sourceScale = 0; this.targetScale = 0; @@ -2239,17 +2240,20 @@ Network.prototype._animationStep = function() { // handle the keyboad movement this._handleNavigation(); - var startTime = Date.now(); - this._physicsTick(); - var physicsTime = Date.now() - startTime; - - // run double speed if it is a little graph - if ((this.renderTimestep - this.renderTime > 2 * physicsTime || this.runDoubleSpeed == true) && this.moving == true) { + // check if the physics have settled + if (this.moving == true) { + var startTime = Date.now(); this._physicsTick(); + var physicsTime = Date.now() - startTime; + + // run double speed if it is a little graph + if ((this.renderTimestep - this.renderTime > 2 * physicsTime || this.runDoubleSpeed == true) && this.moving == true) { + this._physicsTick(); - // this makes sure there is no jitter. The decision is taken once to run it at double speed. - if (this.renderTime != 0) { - this.runDoubleSpeed = true + // this makes sure there is no jitter. The decision is taken once to run it at double speed. + if (this.renderTime != 0) { + this.runDoubleSpeed = true + } } } @@ -2270,7 +2274,7 @@ if (typeof window !== 'undefined') { * Schedule a animation step with the refreshrate interval. */ Network.prototype.start = function() { - if (this.moving == true || this.xIncrement != 0 || this.yIncrement != 0 || this.zoomIncrement != 0) { + if (this.moving == true || this.xIncrement != 0 || this.yIncrement != 0 || this.zoomIncrement != 0 || this.animating == true) { if (!this.timer) { if (this.requiresTimeout == true) { this.timer = window.setTimeout(this._animationStep.bind(this), this.renderTimestep); // wait this.renderTimeStep milliseconds and perform the animation step function @@ -2588,12 +2592,12 @@ Network.prototype.animateView = function (options) { } } else { + this.animating = true; this.animationSpeed = 1 / (this.renderRefreshRate * options.animation.duration * 0.001) || 1 / this.renderRefreshRate; this.animationEasingFunction = options.animation.easingFunction; this._classicRedraw = this._redraw; this._redraw = this._transitionRedraw; this._redraw(); - this.moving = true; this.start(); } }; @@ -2645,10 +2649,10 @@ Network.prototype._transitionRedraw = function (easingTime) { ); this._classicRedraw(); - this.moving = true; // cleanup if (this.easingTime >= 1.0) { + this.animating = false; this.easingTime = 0; if (this.lockedOnNodeId != null) { this._redraw = this._lockedRedraw; From 6235267b6939453e58b97b6f5b8b9229c9e85026 Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Thu, 22 Jan 2015 12:35:32 +0100 Subject: [PATCH 07/16] updated docs for better clarity --- dist/vis.js | 16530 ++++++++++++++++++++++---------------------- docs/network.html | 19 +- 2 files changed, 8275 insertions(+), 8274 deletions(-) diff --git a/dist/vis.js b/dist/vis.js index 8663b2f0..3f276a8d 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -5,7 +5,7 @@ * A dynamic, browser-based visualization library. * * @version 3.9.1-SNAPSHOT - * @date 2015-01-19 + * @date 2015-01-22 * * @license * Copyright (C) 2011-2014 Almende B.V, http://almende.com @@ -10164,9 +10164,9 @@ return /******/ (function(modules) { // webpackBootstrap var util = __webpack_require__(1); var DOMutil = __webpack_require__(2); - var Line = __webpack_require__(49); - var Bar = __webpack_require__(50); - var Points = __webpack_require__(51); + var Line = __webpack_require__(51); + var Bar = __webpack_require__(52); + var Points = __webpack_require__(53); /** * /** @@ -12761,7 +12761,7 @@ return /******/ (function(modules) { // webpackBootstrap var DataAxis = __webpack_require__(23); var GraphGroup = __webpack_require__(24); var Legend = __webpack_require__(28); - var BarGraphFunctions = __webpack_require__(50); + var BarGraphFunctions = __webpack_require__(52); var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items @@ -15408,7 +15408,7 @@ return /******/ (function(modules) { // webpackBootstrap var Emitter = __webpack_require__(56); var Hammer = __webpack_require__(45); - var keycharm = __webpack_require__(59); + var keycharm = __webpack_require__(58); var util = __webpack_require__(1); var hammerUtil = __webpack_require__(47); var DataSet = __webpack_require__(3); @@ -15422,10 +15422,10 @@ return /******/ (function(modules) { // webpackBootstrap var Popup = __webpack_require__(41); var MixinLoader = __webpack_require__(54); var Activator = __webpack_require__(55); - var locales = __webpack_require__(52); + var locales = __webpack_require__(49); // Load custom shapes into CanvasRenderingContext2D - __webpack_require__(53); + __webpack_require__(50); /** * @constructor Network @@ -21868,7 +21868,7 @@ return /******/ (function(modules) { // webpackBootstrap // first check if moment.js is already loaded in the browser window, if so, // use this instance. Else, load via commonjs. - module.exports = (typeof window !== 'undefined') && window['moment'] || __webpack_require__(57); + module.exports = (typeof window !== 'undefined') && window['moment'] || __webpack_require__(59); /***/ }, @@ -21878,7 +21878,7 @@ return /******/ (function(modules) { // webpackBootstrap // Only load hammer.js when in a browser environment // (loading hammer.js in a node.js environment gives errors) if (typeof window !== 'undefined') { - module.exports = window['Hammer'] || __webpack_require__(58); + module.exports = window['Hammer'] || __webpack_require__(64); } else { module.exports = function () { @@ -22822,13 +22822,285 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, /* 49 */ +/***/ function(module, exports, __webpack_require__) { + + // English + exports['en'] = { + edit: 'Edit', + del: 'Delete selected', + back: 'Back', + addNode: 'Add Node', + addEdge: 'Add Edge', + editNode: 'Edit Node', + editEdge: 'Edit Edge', + addDescription: 'Click in an empty space to place a new node.', + edgeDescription: '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'] = { + edit: 'Wijzigen', + del: 'Selectie verwijderen', + back: 'Terug', + addNode: 'Node toevoegen', + addEdge: 'Link toevoegen', + editNode: 'Node wijzigen', + editEdge: 'Link wijzigen', + addDescription: 'Klik op een leeg gebied om een nieuwe node te maken.', + edgeDescription: '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']; + + +/***/ }, +/* 50 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Canvas shapes used by Network + */ + if (typeof CanvasRenderingContext2D !== 'undefined') { + + /** + * Draw a circle shape + */ + CanvasRenderingContext2D.prototype.circle = function(x, y, r) { + this.beginPath(); + this.arc(x, y, r, 0, 2*Math.PI, false); + }; + + /** + * Draw a square shape + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r size, width and height of the square + */ + CanvasRenderingContext2D.prototype.square = function(x, y, r) { + this.beginPath(); + this.rect(x - r, y - r, r * 2, r * 2); + }; + + /** + * Draw a triangle shape + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r radius, half the length of the sides of the triangle + */ + CanvasRenderingContext2D.prototype.triangle = function(x, y, r) { + // http://en.wikipedia.org/wiki/Equilateral_triangle + this.beginPath(); + + var s = r * 2; + var s2 = s / 2; + var ir = Math.sqrt(3) / 6 * s; // radius of inner circle + var h = Math.sqrt(s * s - s2 * s2); // height + + this.moveTo(x, y - (h - ir)); + this.lineTo(x + s2, y + ir); + this.lineTo(x - s2, y + ir); + this.lineTo(x, y - (h - ir)); + this.closePath(); + }; + + /** + * Draw a triangle shape in downward orientation + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r radius + */ + CanvasRenderingContext2D.prototype.triangleDown = function(x, y, r) { + // http://en.wikipedia.org/wiki/Equilateral_triangle + this.beginPath(); + + var s = r * 2; + var s2 = s / 2; + var ir = Math.sqrt(3) / 6 * s; // radius of inner circle + var h = Math.sqrt(s * s - s2 * s2); // height + + this.moveTo(x, y + (h - ir)); + this.lineTo(x + s2, y - ir); + this.lineTo(x - s2, y - ir); + this.lineTo(x, y + (h - ir)); + this.closePath(); + }; + + /** + * Draw a star shape, a star with 5 points + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r radius, half the length of the sides of the triangle + */ + CanvasRenderingContext2D.prototype.star = function(x, y, r) { + // http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/ + this.beginPath(); + + for (var n = 0; n < 10; n++) { + var radius = (n % 2 === 0) ? r * 1.3 : r * 0.5; + this.lineTo( + x + radius * Math.sin(n * 2 * Math.PI / 10), + y - radius * Math.cos(n * 2 * Math.PI / 10) + ); + } + + this.closePath(); + }; + + /** + * http://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas + */ + CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) { + var r2d = Math.PI/180; + if( w - ( 2 * r ) < 0 ) { r = ( w / 2 ); } //ensure that the radius isn't too large for x + if( h - ( 2 * r ) < 0 ) { r = ( h / 2 ); } //ensure that the radius isn't too large for y + this.beginPath(); + this.moveTo(x+r,y); + this.lineTo(x+w-r,y); + this.arc(x+w-r,y+r,r,r2d*270,r2d*360,false); + this.lineTo(x+w,y+h-r); + this.arc(x+w-r,y+h-r,r,0,r2d*90,false); + this.lineTo(x+r,y+h); + this.arc(x+r,y+h-r,r,r2d*90,r2d*180,false); + this.lineTo(x,y+r); + this.arc(x+r,y+r,r,r2d*180,r2d*270,false); + }; + + /** + * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + */ + CanvasRenderingContext2D.prototype.ellipse = function(x, y, w, h) { + var kappa = .5522848, + ox = (w / 2) * kappa, // control point offset horizontal + oy = (h / 2) * kappa, // control point offset vertical + xe = x + w, // x-end + ye = y + h, // y-end + xm = x + w / 2, // x-middle + ym = y + h / 2; // y-middle + + this.beginPath(); + this.moveTo(x, ym); + this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + }; + + + + /** + * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + */ + CanvasRenderingContext2D.prototype.database = function(x, y, w, h) { + var f = 1/3; + var wEllipse = w; + var hEllipse = h * f; + + var kappa = .5522848, + ox = (wEllipse / 2) * kappa, // control point offset horizontal + oy = (hEllipse / 2) * kappa, // control point offset vertical + xe = x + wEllipse, // x-end + ye = y + hEllipse, // y-end + xm = x + wEllipse / 2, // x-middle + ym = y + hEllipse / 2, // y-middle + ymb = y + (h - hEllipse/2), // y-midlle, bottom ellipse + yeb = y + h; // y-end, bottom ellipse + + this.beginPath(); + this.moveTo(xe, ym); + + this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + + this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + + this.lineTo(xe, ymb); + + this.bezierCurveTo(xe, ymb + oy, xm + ox, yeb, xm, yeb); + this.bezierCurveTo(xm - ox, yeb, x, ymb + oy, x, ymb); + + this.lineTo(x, ym); + }; + + + /** + * Draw an arrow point (no line) + */ + CanvasRenderingContext2D.prototype.arrow = function(x, y, angle, length) { + // tail + var xt = x - length * Math.cos(angle); + var yt = y - length * Math.sin(angle); + + // inner tail + // TODO: allow to customize different shapes + var xi = x - length * 0.9 * Math.cos(angle); + var yi = y - length * 0.9 * Math.sin(angle); + + // left + var xl = xt + length / 3 * Math.cos(angle + 0.5 * Math.PI); + var yl = yt + length / 3 * Math.sin(angle + 0.5 * Math.PI); + + // right + var xr = xt + length / 3 * Math.cos(angle - 0.5 * Math.PI); + var yr = yt + length / 3 * Math.sin(angle - 0.5 * Math.PI); + + this.beginPath(); + this.moveTo(x, y); + this.lineTo(xl, yl); + this.lineTo(xi, yi); + this.lineTo(xr, yr); + this.closePath(); + }; + + /** + * Sets up the dashedLine functionality for drawing + * Original code came from http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas + * @author David Jordan + * @date 2012-08-08 + */ + CanvasRenderingContext2D.prototype.dashedLine = function(x,y,x2,y2,dashArray){ + if (!dashArray) dashArray=[10,5]; + if (dashLength==0) dashLength = 0.001; // Hack for Safari + var dashCount = dashArray.length; + this.moveTo(x, y); + var dx = (x2-x), dy = (y2-y); + var slope = dy/dx; + var distRemaining = Math.sqrt( dx*dx + dy*dy ); + var dashIndex=0, draw=true; + while (distRemaining>=0.1){ + var dashLength = dashArray[dashIndex++%dashCount]; + if (dashLength > distRemaining) dashLength = distRemaining; + var xStep = Math.sqrt( dashLength*dashLength / (1 + slope*slope) ); + if (dx<0) xStep = -xStep; + x += xStep; + y += slope*xStep; + this[draw ? 'lineTo' : 'moveTo'](x,y); + distRemaining -= dashLength; + draw = !draw; + } + }; + + // TODO: add diamond shape + } + + +/***/ }, +/* 51 */ /***/ function(module, exports, __webpack_require__) { /** * Created by Alex on 11/11/2014. */ var DOMutil = __webpack_require__(2); - var Points = __webpack_require__(51); + var Points = __webpack_require__(53); function Line(groupId, options) { this.groupId = groupId; @@ -23045,14 +23317,14 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 50 */ +/* 52 */ /***/ function(module, exports, __webpack_require__) { /** * Created by Alex on 11/11/2014. */ var DOMutil = __webpack_require__(2); - var Points = __webpack_require__(51); + var Points = __webpack_require__(53); function Bargraph(groupId, options) { this.groupId = groupId; @@ -23279,7 +23551,7 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = Bargraph; /***/ }, -/* 51 */ +/* 53 */ /***/ function(module, exports, __webpack_require__) { /** @@ -23327,422 +23599,150 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = Points; /***/ }, -/* 52 */ +/* 54 */ /***/ function(module, exports, __webpack_require__) { - // English - exports['en'] = { - edit: 'Edit', - del: 'Delete selected', - back: 'Back', - addNode: 'Add Node', - addEdge: 'Add Edge', - editNode: 'Edit Node', - editEdge: 'Edit Edge', - addDescription: 'Click in an empty space to place a new node.', - edgeDescription: '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.' + var PhysicsMixin = __webpack_require__(60); + var ClusterMixin = __webpack_require__(57); + var SectorsMixin = __webpack_require__(62); + var SelectionMixin = __webpack_require__(66); + var ManipulationMixin = __webpack_require__(61); + var NavigationMixin = __webpack_require__(63); + var HierarchicalLayoutMixin = __webpack_require__(65); + + /** + * Load a mixin into the network object + * + * @param {Object} sourceVariable | this object has to contain functions. + * @private + */ + exports._loadMixin = function (sourceVariable) { + for (var mixinFunction in sourceVariable) { + if (sourceVariable.hasOwnProperty(mixinFunction)) { + this[mixinFunction] = sourceVariable[mixinFunction]; + } + } }; - exports['en_EN'] = exports['en']; - exports['en_US'] = exports['en']; - // Dutch - exports['nl'] = { - edit: 'Wijzigen', - del: 'Selectie verwijderen', - back: 'Terug', - addNode: 'Node toevoegen', - addEdge: 'Link toevoegen', - editNode: 'Node wijzigen', - editEdge: 'Link wijzigen', - addDescription: 'Klik op een leeg gebied om een nieuwe node te maken.', - edgeDescription: '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.' + + /** + * removes a mixin from the network object. + * + * @param {Object} sourceVariable | this object has to contain functions. + * @private + */ + exports._clearMixin = function (sourceVariable) { + for (var mixinFunction in sourceVariable) { + if (sourceVariable.hasOwnProperty(mixinFunction)) { + this[mixinFunction] = undefined; + } + } }; - exports['nl_NL'] = exports['nl']; - exports['nl_BE'] = exports['nl']; -/***/ }, -/* 53 */ -/***/ function(module, exports, __webpack_require__) { + /** + * Mixin the physics system and initialize the parameters required. + * + * @private + */ + exports._loadPhysicsSystem = function () { + this._loadMixin(PhysicsMixin); + this._loadSelectedForceSolver(); + if (this.constants.configurePhysics == true) { + this._loadPhysicsConfiguration(); + } + else { + this._cleanupPhysicsConfiguration(); + } + }; + /** - * Canvas shapes used by Network + * Mixin the cluster system and initialize the parameters required. + * + * @private */ - if (typeof CanvasRenderingContext2D !== 'undefined') { + exports._loadClusterSystem = function () { + this.clusterSession = 0; + this.hubThreshold = 5; + this._loadMixin(ClusterMixin); + }; - /** - * Draw a circle shape - */ - CanvasRenderingContext2D.prototype.circle = function(x, y, r) { - this.beginPath(); - this.arc(x, y, r, 0, 2*Math.PI, false); - }; - /** - * Draw a square shape - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r size, width and height of the square - */ - CanvasRenderingContext2D.prototype.square = function(x, y, r) { - this.beginPath(); - this.rect(x - r, y - r, r * 2, r * 2); - }; + /** + * Mixin the sector system and initialize the parameters required + * + * @private + */ + exports._loadSectorSystem = function () { + this.sectors = {}; + this.activeSector = ["default"]; + this.sectors["active"] = {}; + this.sectors["active"]["default"] = {"nodes": {}, + "edges": {}, + "nodeIndices": [], + "formationScale": 1.0, + "drawingNode": undefined }; + this.sectors["frozen"] = {}; + this.sectors["support"] = {"nodes": {}, + "edges": {}, + "nodeIndices": [], + "formationScale": 1.0, + "drawingNode": undefined }; - /** - * Draw a triangle shape - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r radius, half the length of the sides of the triangle - */ - CanvasRenderingContext2D.prototype.triangle = function(x, y, r) { - // http://en.wikipedia.org/wiki/Equilateral_triangle - this.beginPath(); + this.nodeIndices = this.sectors["active"]["default"]["nodeIndices"]; // the node indices list is used to speed up the computation of the repulsion fields - var s = r * 2; - var s2 = s / 2; - var ir = Math.sqrt(3) / 6 * s; // radius of inner circle - var h = Math.sqrt(s * s - s2 * s2); // height + this._loadMixin(SectorsMixin); + }; - this.moveTo(x, y - (h - ir)); - this.lineTo(x + s2, y + ir); - this.lineTo(x - s2, y + ir); - this.lineTo(x, y - (h - ir)); - this.closePath(); - }; - /** - * Draw a triangle shape in downward orientation - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r radius - */ - CanvasRenderingContext2D.prototype.triangleDown = function(x, y, r) { - // http://en.wikipedia.org/wiki/Equilateral_triangle - this.beginPath(); + /** + * Mixin the selection system and initialize the parameters required + * + * @private + */ + exports._loadSelectionSystem = function () { + this.selectionObj = {nodes: {}, edges: {}}; - var s = r * 2; - var s2 = s / 2; - var ir = Math.sqrt(3) / 6 * s; // radius of inner circle - var h = Math.sqrt(s * s - s2 * s2); // height + this._loadMixin(SelectionMixin); + }; - this.moveTo(x, y + (h - ir)); - this.lineTo(x + s2, y - ir); - this.lineTo(x - s2, y - ir); - this.lineTo(x, y + (h - ir)); - this.closePath(); - }; - /** - * Draw a star shape, a star with 5 points - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r radius, half the length of the sides of the triangle - */ - CanvasRenderingContext2D.prototype.star = function(x, y, r) { - // http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/ - this.beginPath(); + /** + * Mixin the navigationUI (User Interface) system and initialize the parameters required + * + * @private + */ + exports._loadManipulationSystem = function () { + // reset global variables -- these are used by the selection of nodes and edges. + this.blockConnectingEdgeSelection = false; + this.forceAppendSelection = false; - for (var n = 0; n < 10; n++) { - var radius = (n % 2 === 0) ? r * 1.3 : r * 0.5; - this.lineTo( - x + radius * Math.sin(n * 2 * Math.PI / 10), - y - radius * Math.cos(n * 2 * Math.PI / 10) - ); + if (this.constants.dataManipulation.enabled == true) { + // load the manipulator HTML elements. All styling done in css. + if (this.manipulationDiv === undefined) { + this.manipulationDiv = document.createElement('div'); + this.manipulationDiv.className = 'network-manipulationDiv'; + if (this.editMode == true) { + this.manipulationDiv.style.display = "block"; + } + else { + this.manipulationDiv.style.display = "none"; + } + this.frame.appendChild(this.manipulationDiv); } - this.closePath(); - }; - - /** - * http://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas - */ - CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) { - var r2d = Math.PI/180; - if( w - ( 2 * r ) < 0 ) { r = ( w / 2 ); } //ensure that the radius isn't too large for x - if( h - ( 2 * r ) < 0 ) { r = ( h / 2 ); } //ensure that the radius isn't too large for y - this.beginPath(); - this.moveTo(x+r,y); - this.lineTo(x+w-r,y); - this.arc(x+w-r,y+r,r,r2d*270,r2d*360,false); - this.lineTo(x+w,y+h-r); - this.arc(x+w-r,y+h-r,r,0,r2d*90,false); - this.lineTo(x+r,y+h); - this.arc(x+r,y+h-r,r,r2d*90,r2d*180,false); - this.lineTo(x,y+r); - this.arc(x+r,y+r,r,r2d*180,r2d*270,false); - }; - - /** - * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - */ - CanvasRenderingContext2D.prototype.ellipse = function(x, y, w, h) { - var kappa = .5522848, - ox = (w / 2) * kappa, // control point offset horizontal - oy = (h / 2) * kappa, // control point offset vertical - xe = x + w, // x-end - ye = y + h, // y-end - xm = x + w / 2, // x-middle - ym = y + h / 2; // y-middle - - this.beginPath(); - this.moveTo(x, ym); - this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - }; - - - - /** - * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - */ - CanvasRenderingContext2D.prototype.database = function(x, y, w, h) { - var f = 1/3; - var wEllipse = w; - var hEllipse = h * f; - - var kappa = .5522848, - ox = (wEllipse / 2) * kappa, // control point offset horizontal - oy = (hEllipse / 2) * kappa, // control point offset vertical - xe = x + wEllipse, // x-end - ye = y + hEllipse, // y-end - xm = x + wEllipse / 2, // x-middle - ym = y + hEllipse / 2, // y-middle - ymb = y + (h - hEllipse/2), // y-midlle, bottom ellipse - yeb = y + h; // y-end, bottom ellipse - - this.beginPath(); - this.moveTo(xe, ym); - - this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - - this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - - this.lineTo(xe, ymb); - - this.bezierCurveTo(xe, ymb + oy, xm + ox, yeb, xm, yeb); - this.bezierCurveTo(xm - ox, yeb, x, ymb + oy, x, ymb); - - this.lineTo(x, ym); - }; - - - /** - * Draw an arrow point (no line) - */ - CanvasRenderingContext2D.prototype.arrow = function(x, y, angle, length) { - // tail - var xt = x - length * Math.cos(angle); - var yt = y - length * Math.sin(angle); - - // inner tail - // TODO: allow to customize different shapes - var xi = x - length * 0.9 * Math.cos(angle); - var yi = y - length * 0.9 * Math.sin(angle); - - // left - var xl = xt + length / 3 * Math.cos(angle + 0.5 * Math.PI); - var yl = yt + length / 3 * Math.sin(angle + 0.5 * Math.PI); - - // right - var xr = xt + length / 3 * Math.cos(angle - 0.5 * Math.PI); - var yr = yt + length / 3 * Math.sin(angle - 0.5 * Math.PI); - - this.beginPath(); - this.moveTo(x, y); - this.lineTo(xl, yl); - this.lineTo(xi, yi); - this.lineTo(xr, yr); - this.closePath(); - }; - - /** - * Sets up the dashedLine functionality for drawing - * Original code came from http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas - * @author David Jordan - * @date 2012-08-08 - */ - CanvasRenderingContext2D.prototype.dashedLine = function(x,y,x2,y2,dashArray){ - if (!dashArray) dashArray=[10,5]; - if (dashLength==0) dashLength = 0.001; // Hack for Safari - var dashCount = dashArray.length; - this.moveTo(x, y); - var dx = (x2-x), dy = (y2-y); - var slope = dy/dx; - var distRemaining = Math.sqrt( dx*dx + dy*dy ); - var dashIndex=0, draw=true; - while (distRemaining>=0.1){ - var dashLength = dashArray[dashIndex++%dashCount]; - if (dashLength > distRemaining) dashLength = distRemaining; - var xStep = Math.sqrt( dashLength*dashLength / (1 + slope*slope) ); - if (dx<0) xStep = -xStep; - x += xStep; - y += slope*xStep; - this[draw ? 'lineTo' : 'moveTo'](x,y); - distRemaining -= dashLength; - draw = !draw; - } - }; - - // TODO: add diamond shape - } - - -/***/ }, -/* 54 */ -/***/ function(module, exports, __webpack_require__) { - - var PhysicsMixin = __webpack_require__(66); - var ClusterMixin = __webpack_require__(60); - var SectorsMixin = __webpack_require__(61); - var SelectionMixin = __webpack_require__(62); - var ManipulationMixin = __webpack_require__(63); - var NavigationMixin = __webpack_require__(64); - var HierarchicalLayoutMixin = __webpack_require__(65); - - /** - * Load a mixin into the network object - * - * @param {Object} sourceVariable | this object has to contain functions. - * @private - */ - exports._loadMixin = function (sourceVariable) { - for (var mixinFunction in sourceVariable) { - if (sourceVariable.hasOwnProperty(mixinFunction)) { - this[mixinFunction] = sourceVariable[mixinFunction]; - } - } - }; - - - /** - * removes a mixin from the network object. - * - * @param {Object} sourceVariable | this object has to contain functions. - * @private - */ - exports._clearMixin = function (sourceVariable) { - for (var mixinFunction in sourceVariable) { - if (sourceVariable.hasOwnProperty(mixinFunction)) { - this[mixinFunction] = undefined; - } - } - }; - - - /** - * Mixin the physics system and initialize the parameters required. - * - * @private - */ - exports._loadPhysicsSystem = function () { - this._loadMixin(PhysicsMixin); - this._loadSelectedForceSolver(); - if (this.constants.configurePhysics == true) { - this._loadPhysicsConfiguration(); - } - else { - this._cleanupPhysicsConfiguration(); - } - }; - - - /** - * Mixin the cluster system and initialize the parameters required. - * - * @private - */ - exports._loadClusterSystem = function () { - this.clusterSession = 0; - this.hubThreshold = 5; - this._loadMixin(ClusterMixin); - }; - - - /** - * Mixin the sector system and initialize the parameters required - * - * @private - */ - exports._loadSectorSystem = function () { - this.sectors = {}; - this.activeSector = ["default"]; - this.sectors["active"] = {}; - this.sectors["active"]["default"] = {"nodes": {}, - "edges": {}, - "nodeIndices": [], - "formationScale": 1.0, - "drawingNode": undefined }; - this.sectors["frozen"] = {}; - this.sectors["support"] = {"nodes": {}, - "edges": {}, - "nodeIndices": [], - "formationScale": 1.0, - "drawingNode": undefined }; - - this.nodeIndices = this.sectors["active"]["default"]["nodeIndices"]; // the node indices list is used to speed up the computation of the repulsion fields - - this._loadMixin(SectorsMixin); - }; - - - /** - * Mixin the selection system and initialize the parameters required - * - * @private - */ - exports._loadSelectionSystem = function () { - this.selectionObj = {nodes: {}, edges: {}}; - - this._loadMixin(SelectionMixin); - }; - - - /** - * Mixin the navigationUI (User Interface) system and initialize the parameters required - * - * @private - */ - exports._loadManipulationSystem = function () { - // reset global variables -- these are used by the selection of nodes and edges. - this.blockConnectingEdgeSelection = false; - this.forceAppendSelection = false; - - if (this.constants.dataManipulation.enabled == true) { - // load the manipulator HTML elements. All styling done in css. - if (this.manipulationDiv === undefined) { - this.manipulationDiv = document.createElement('div'); - this.manipulationDiv.className = 'network-manipulationDiv'; - if (this.editMode == true) { - this.manipulationDiv.style.display = "block"; - } - else { - this.manipulationDiv.style.display = "none"; - } - this.frame.appendChild(this.manipulationDiv); - } - - if (this.editModeDiv === undefined) { - this.editModeDiv = document.createElement('div'); - this.editModeDiv.className = 'network-manipulation-editMode'; - if (this.editMode == true) { - this.editModeDiv.style.display = "none"; - } - else { - this.editModeDiv.style.display = "block"; - } - this.frame.appendChild(this.editModeDiv); - } + if (this.editModeDiv === undefined) { + this.editModeDiv = document.createElement('div'); + this.editModeDiv.className = 'network-manipulation-editMode'; + if (this.editMode == true) { + this.editModeDiv.style.display = "none"; + } + else { + this.editModeDiv.style.display = "block"; + } + this.frame.appendChild(this.editModeDiv); + } if (this.closeDiv === undefined) { this.closeDiv = document.createElement('div'); @@ -23806,7 +23806,7 @@ return /******/ (function(modules) { // webpackBootstrap /* 55 */ /***/ function(module, exports, __webpack_require__) { - var keycharm = __webpack_require__(59); + var keycharm = __webpack_require__(58); var Emitter = __webpack_require__(56); var Hammer = __webpack_require__(45); var util = __webpack_require__(1); @@ -24133,8710 +24133,8723 @@ return /******/ (function(modules) { // webpackBootstrap /* 57 */ /***/ function(module, exports, __webpack_require__) { - var __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(global, module) {//! moment.js - //! version : 2.9.0 - //! authors : Tim Wood, Iskren Chernev, Moment.js contributors - //! license : MIT - //! momentjs.com + /** + * Creation of the ClusterMixin var. + * + * This contains all the functions the Network object can use to employ clustering + */ - (function (undefined) { - /************************************ - Constants - ************************************/ + /** + * This is only called in the constructor of the network object + * + */ + exports.startWithClustering = function() { + // cluster if the data set is big + this.clusterToFit(this.constants.clustering.initialMaxNodes, true); - var moment, - VERSION = '2.9.0', - // the global-scope this is NOT the global object in Node.js - globalScope = (typeof global !== 'undefined' && (typeof window === 'undefined' || window === global.window)) ? global : this, - oldGlobalMoment, - round = Math.round, - hasOwnProperty = Object.prototype.hasOwnProperty, - i, + // updates the lables after clustering + this.updateLabels(); - YEAR = 0, - MONTH = 1, - DATE = 2, - HOUR = 3, - MINUTE = 4, - SECOND = 5, - MILLISECOND = 6, + // this is called here because if clusterin is disabled, the start and stabilize are called in + // the setData function. + if (this.stabilize) { + this._stabilize(); + } + this.start(); + }; - // internal storage for locale config files - locales = {}, + /** + * This function clusters until the initialMaxNodes has been reached + * + * @param {Number} maxNumberOfNodes + * @param {Boolean} reposition + */ + exports.clusterToFit = function(maxNumberOfNodes, reposition) { + var numberOfNodes = this.nodeIndices.length; - // extra moment internal properties (plugins register props here) - momentProperties = [], + var maxLevels = 50; + var level = 0; - // check for nodeJS - hasModule = (typeof module !== 'undefined' && module && module.exports), + // we first cluster the hubs, then we pull in the outliers, repeat + while (numberOfNodes > maxNumberOfNodes && level < maxLevels) { + if (level % 3 == 0) { + this.forceAggregateHubs(true); + this.normalizeClusterLevels(); + } + else { + this.increaseClusterLevel(); // this also includes a cluster normalization + } - // ASP.NET json date format regex - aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, - aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/, + numberOfNodes = this.nodeIndices.length; + level += 1; + } - // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html - // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere - isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/, + // after the clustering we reposition the nodes to reduce the initial chaos + if (level > 0 && reposition == true) { + this.repositionNodes(); + } + this._updateCalculationNodes(); + }; - // format tokens - formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|x|X|zz?|ZZ?|.)/g, - localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, + /** + * This function can be called to open up a specific cluster. It is only called by + * It will unpack the cluster back one level. + * + * @param node | Node object: cluster to open. + */ + exports.openCluster = function(node) { + var isMovingBeforeClustering = this.moving; + if (node.clusterSize > this.constants.clustering.sectorThreshold && this._nodeInActiveArea(node) && + !(this._sector() == "default" && this.nodeIndices.length == 1)) { + // this loads a new sector, loads the nodes and edges and nodeIndices of it. + this._addSector(node); + var level = 0; - // parsing token regexes - parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 - parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 - parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999 - parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 - parseTokenDigits = /\d+/, // nonzero number of digits - parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic. - parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z - parseTokenT = /T/i, // T (ISO separator) - parseTokenOffsetMs = /[\+\-]?\d+/, // 1234567890123 - parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 + // we decluster until we reach a decent number of nodes + while ((this.nodeIndices.length < this.constants.clustering.initialMaxNodes) && (level < 10)) { + this.decreaseClusterLevel(); + level += 1; + } - //strict parsing regexes - parseTokenOneDigit = /\d/, // 0 - 9 - parseTokenTwoDigits = /\d\d/, // 00 - 99 - parseTokenThreeDigits = /\d{3}/, // 000 - 999 - parseTokenFourDigits = /\d{4}/, // 0000 - 9999 - parseTokenSixDigits = /[+-]?\d{6}/, // -999,999 - 999,999 - parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf + } + else { + this._expandClusterNode(node,false,true); - // iso 8601 regex - // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) - isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/, + // update the index list, dynamic edges and labels + this._updateNodeIndexList(); + this._updateDynamicEdges(); + this._updateCalculationNodes(); + this.updateLabels(); + } - isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', + // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded + if (this.moving != isMovingBeforeClustering) { + this.start(); + } + }; - isoDates = [ - ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/], - ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/], - ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/], - ['GGGG-[W]WW', /\d{4}-W\d{2}/], - ['YYYY-DDD', /\d{4}-\d{3}/] - ], - // iso time formats and regexes - isoTimes = [ - ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d+/], - ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], - ['HH:mm', /(T| )\d\d:\d\d/], - ['HH', /(T| )\d\d/] - ], + /** + * This calls the updateClustes with default arguments + */ + exports.updateClustersDefault = function() { + if (this.constants.clustering.enabled == true) { + this.updateClusters(0,false,false); + } + }; - // timezone chunker '+10:00' > ['10', '00'] or '-1530' > ['-', '15', '30'] - parseTimezoneChunker = /([\+\-]|\d\d)/gi, - // getter and setter names - proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), - unitMillisecondFactors = { - 'Milliseconds' : 1, - 'Seconds' : 1e3, - 'Minutes' : 6e4, - 'Hours' : 36e5, - 'Days' : 864e5, - 'Months' : 2592e6, - 'Years' : 31536e6 - }, + /** + * This function can be called to increase the cluster level. This means that the nodes with only one edge connection will + * be clustered with their connected node. This can be repeated as many times as needed. + * This can be called externally (by a keybind for instance) to reduce the complexity of big datasets. + */ + exports.increaseClusterLevel = function() { + this.updateClusters(-1,false,true); + }; - unitAliases = { - ms : 'millisecond', - s : 'second', - m : 'minute', - h : 'hour', - d : 'day', - D : 'date', - w : 'week', - W : 'isoWeek', - M : 'month', - Q : 'quarter', - y : 'year', - DDD : 'dayOfYear', - e : 'weekday', - E : 'isoWeekday', - gg: 'weekYear', - GG: 'isoWeekYear' - }, - camelFunctions = { - dayofyear : 'dayOfYear', - isoweekday : 'isoWeekday', - isoweek : 'isoWeek', - weekyear : 'weekYear', - isoweekyear : 'isoWeekYear' - }, + /** + * This function can be called to decrease the cluster level. This means that the nodes with only one edge connection will + * be unpacked if they are a cluster. This can be repeated as many times as needed. + * This can be called externally (by a key-bind for instance) to look into clusters without zooming. + */ + exports.decreaseClusterLevel = function() { + this.updateClusters(1,false,true); + }; - // format function strings - formatFunctions = {}, - // default relative time thresholds - relativeTimeThresholds = { - 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 - }, + /** + * This is the main clustering function. It clusters and declusters on zoom or forced + * This function clusters on zoom, it can be called with a predefined zoom direction + * If out, check if we can form clusters, if in, check if we can open clusters. + * This function is only called from _zoom() + * + * @param {Number} zoomDirection | -1 / 0 / +1 for zoomOut / determineByZoom / zoomIn + * @param {Boolean} recursive | enabled or disable recursive calling of the opening of clusters + * @param {Boolean} force | enabled or disable forcing + * @param {Boolean} doNotStart | if true do not call start + * + */ + exports.updateClusters = function(zoomDirection,recursive,force,doNotStart) { + var isMovingBeforeClustering = this.moving; + var amountOfNodes = this.nodeIndices.length; - // tokens to ordinalize and pad - ordinalizeTokens = 'DDD w W M D d'.split(' '), - paddedTokens = 'M D H h m s w W'.split(' '), + // on zoom out collapse the sector if the scale is at the level the sector was made + if (this.previousScale > this.scale && zoomDirection == 0) { + this._collapseSector(); + } - formatTokenFunctions = { - M : function () { - return this.month() + 1; - }, - MMM : function (format) { - return this.localeData().monthsShort(this, format); - }, - MMMM : function (format) { - return this.localeData().months(this, format); - }, - D : function () { - return this.date(); - }, - DDD : function () { - return this.dayOfYear(); - }, - d : function () { - return this.day(); - }, - dd : function (format) { - return this.localeData().weekdaysMin(this, format); - }, - ddd : function (format) { - return this.localeData().weekdaysShort(this, format); - }, - dddd : function (format) { - return this.localeData().weekdays(this, format); - }, - w : function () { - return this.week(); - }, - W : function () { - return this.isoWeek(); - }, - YY : function () { - return leftZeroFill(this.year() % 100, 2); - }, - YYYY : function () { - return leftZeroFill(this.year(), 4); - }, - YYYYY : function () { - return leftZeroFill(this.year(), 5); - }, - YYYYYY : function () { - var y = this.year(), sign = y >= 0 ? '+' : '-'; - return sign + leftZeroFill(Math.abs(y), 6); - }, - gg : function () { - return leftZeroFill(this.weekYear() % 100, 2); - }, - gggg : function () { - return leftZeroFill(this.weekYear(), 4); - }, - ggggg : function () { - return leftZeroFill(this.weekYear(), 5); - }, - GG : function () { - return leftZeroFill(this.isoWeekYear() % 100, 2); - }, - GGGG : function () { - return leftZeroFill(this.isoWeekYear(), 4); - }, - GGGGG : function () { - return leftZeroFill(this.isoWeekYear(), 5); - }, - e : function () { - return this.weekday(); - }, - E : function () { - return this.isoWeekday(); - }, - a : function () { - return this.localeData().meridiem(this.hours(), this.minutes(), true); - }, - A : function () { - return this.localeData().meridiem(this.hours(), this.minutes(), false); - }, - H : function () { - return this.hours(); - }, - h : function () { - return this.hours() % 12 || 12; - }, - m : function () { - return this.minutes(); - }, - s : function () { - return this.seconds(); - }, - S : function () { - return toInt(this.milliseconds() / 100); - }, - SS : function () { - return leftZeroFill(toInt(this.milliseconds() / 10), 2); - }, - SSS : function () { - return leftZeroFill(this.milliseconds(), 3); - }, - SSSS : function () { - return leftZeroFill(this.milliseconds(), 3); - }, - Z : function () { - var a = this.utcOffset(), - b = '+'; - if (a < 0) { - a = -a; - b = '-'; - } - return b + leftZeroFill(toInt(a / 60), 2) + ':' + leftZeroFill(toInt(a) % 60, 2); - }, - ZZ : function () { - var a = this.utcOffset(), - b = '+'; - if (a < 0) { - a = -a; - b = '-'; - } - return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2); - }, - z : function () { - return this.zoneAbbr(); - }, - zz : function () { - return this.zoneName(); - }, - x : function () { - return this.valueOf(); - }, - X : function () { - return this.unix(); - }, - Q : function () { - return this.quarter(); - } - }, + // check if we zoom in or out + if (this.previousScale > this.scale || zoomDirection == -1) { // zoom out + // forming clusters when forced pulls outliers in. When not forced, the edge length of the + // outer nodes determines if it is being clustered + this._formClusters(force); + } + else if (this.previousScale < this.scale || zoomDirection == 1) { // zoom in + if (force == true) { + // _openClusters checks for each node if the formationScale of the cluster is smaller than + // the current scale and if so, declusters. When forced, all clusters are reduced by one step + this._openClusters(recursive,force); + } + else { + // if a cluster takes up a set percentage of the active window + this._openClustersBySize(); + } + } + this._updateNodeIndexList(); - deprecations = {}, + // if a cluster was NOT formed and the user zoomed out, we try clustering by hubs + if (this.nodeIndices.length == amountOfNodes && (this.previousScale > this.scale || zoomDirection == -1)) { + this._aggregateHubs(force); + this._updateNodeIndexList(); + } - lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin'], + // we now reduce chains. + if (this.previousScale > this.scale || zoomDirection == -1) { // zoom out + this.handleChains(); + this._updateNodeIndexList(); + } - updateInProgress = false; + this.previousScale = this.scale; - // Pick the first defined of two or three arguments. dfl comes from - // default. - function dfl(a, b, c) { - 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'); - } - } + // rest of the update the index list, dynamic edges and labels + this._updateDynamicEdges(); + this.updateLabels(); - function hasOwnProp(a, b) { - return hasOwnProperty.call(a, b); + // if a cluster was formed, we increase the clusterSession + if (this.nodeIndices.length < amountOfNodes) { // this means a clustering operation has taken place + this.clusterSession += 1; + // if clusters have been made, we normalize the cluster level + this.normalizeClusterLevels(); + } + + if (doNotStart == false || doNotStart === undefined) { + // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded + if (this.moving != isMovingBeforeClustering) { + this.start(); } + } - function defaultParsingFlags() { - // We need to deep clone this object, and es5 standard is not very - // helpful. - return { - empty : false, - unusedTokens : [], - unusedInput : [], - overflow : -2, - charsLeftOver : 0, - nullInput : false, - invalidMonth : null, - invalidFormat : false, - userInvalidated : false, - iso: false - }; + this._updateCalculationNodes(); + }; + + /** + * This function handles the chains. It is called on every updateClusters(). + */ + exports.handleChains = function() { + // after clustering we check how many chains there are + var chainPercentage = this._getChainFraction(); + if (chainPercentage > this.constants.clustering.chainThreshold) { + this._reduceAmountOfChains(1 - this.constants.clustering.chainThreshold / chainPercentage) + + } + }; + + /** + * this functions starts clustering by hubs + * The minimum hub threshold is set globally + * + * @private + */ + exports._aggregateHubs = function(force) { + this._getHubSize(); + this._formClustersByHub(force,false); + }; + + + /** + * This function is fired by keypress. It forces hubs to form. + * + */ + exports.forceAggregateHubs = function(doNotStart) { + var isMovingBeforeClustering = this.moving; + var amountOfNodes = this.nodeIndices.length; + + this._aggregateHubs(true); + + // update the index list, dynamic edges and labels + this._updateNodeIndexList(); + this._updateDynamicEdges(); + this.updateLabels(); + + // if a cluster was formed, we increase the clusterSession + if (this.nodeIndices.length != amountOfNodes) { + this.clusterSession += 1; + } + + if (doNotStart == false || doNotStart === undefined) { + // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded + if (this.moving != isMovingBeforeClustering) { + this.start(); } + } + }; - function printMsg(msg) { - if (moment.suppressDeprecationWarnings === false && - typeof console !== 'undefined' && console.warn) { - console.warn('Deprecation warning: ' + msg); + /** + * If a cluster takes up more than a set percentage of the screen, open the cluster + * + * @private + */ + exports._openClustersBySize = function() { + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + var node = this.nodes[nodeId]; + if (node.inView() == true) { + if ((node.width*this.scale > this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientWidth) || + (node.height*this.scale > this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientHeight)) { + this.openCluster(node); } + } } + } + }; - function deprecate(msg, fn) { - var firstTime = true; - return extend(function () { - if (firstTime) { - printMsg(msg); - firstTime = false; - } - return fn.apply(this, arguments); - }, fn); + + /** + * This function loops over all nodes in the nodeIndices list. For each node it checks if it is a cluster and if it + * has to be opened based on the current zoom level. + * + * @private + */ + exports._openClusters = function(recursive,force) { + for (var i = 0; i < this.nodeIndices.length; i++) { + var node = this.nodes[this.nodeIndices[i]]; + this._expandClusterNode(node,recursive,force); + this._updateCalculationNodes(); + } + }; + + /** + * This function checks if a node has to be opened. This is done by checking the zoom level. + * If the node contains child nodes, this function is recursively called on the child nodes as well. + * This recursive behaviour is optional and can be set by the recursive argument. + * + * @param {Node} parentNode | to check for cluster and expand + * @param {Boolean} recursive | enabled or disable recursive calling + * @param {Boolean} force | enabled or disable forcing + * @param {Boolean} [openAll] | This will recursively force all nodes in the parent to be released + * @private + */ + exports._expandClusterNode = function(parentNode, recursive, force, openAll) { + // first check if node is a cluster + if (parentNode.clusterSize > 1) { + // this means that on a double tap event or a zoom event, the cluster fully unpacks if it is smaller than 20 + if (parentNode.clusterSize < this.constants.clustering.sectorThreshold) { + openAll = true; } + recursive = openAll ? true : recursive; - function deprecateSimple(name, msg) { - if (!deprecations[name]) { - printMsg(msg); - deprecations[name] = true; + // if the last child has been added on a smaller scale than current scale decluster + if (parentNode.formationScale < this.scale || force == true) { + // we will check if any of the contained child nodes should be removed from the cluster + for (var containedNodeId in parentNode.containedNodes) { + if (parentNode.containedNodes.hasOwnProperty(containedNodeId)) { + var childNode = parentNode.containedNodes[containedNodeId]; + + // force expand will expand the largest cluster size clusters. Since we cluster from outside in, we assume that + // the largest cluster is the one that comes from outside + if (force == true) { + if (childNode.clusterSession == parentNode.clusterSessions[parentNode.clusterSessions.length-1] + || openAll) { + this._expelChildFromParent(parentNode,containedNodeId,recursive,force,openAll); + } + } + else { + if (this._nodeInActiveArea(parentNode)) { + this._expelChildFromParent(parentNode,containedNodeId,recursive,force,openAll); + } + } } + } } + } + }; - function padToken(func, count) { - return function (a) { - return leftZeroFill(func.call(this, a), count); - }; + /** + * ONLY CALLED FROM _expandClusterNode + * + * This function will expel a child_node from a parent_node. This is to de-cluster the node. This function will remove + * the child node from the parent contained_node object and put it back into the global nodes object. + * The same holds for the edge that was connected to the child node. It is moved back into the global edges object. + * + * @param {Node} parentNode | the parent node + * @param {String} containedNodeId | child_node id as it is contained in the containedNodes object of the parent node + * @param {Boolean} recursive | This will also check if the child needs to be expanded. + * With force and recursive both true, the entire cluster is unpacked + * @param {Boolean} force | This will disregard the zoom level and will expel this child from the parent + * @param {Boolean} openAll | This will recursively force all nodes in the parent to be released + * @private + */ + exports._expelChildFromParent = function(parentNode, containedNodeId, recursive, force, openAll) { + var childNode = parentNode.containedNodes[containedNodeId]; + + // if child node has been added on smaller scale than current, kick out + if (childNode.formationScale < this.scale || force == true) { + // unselect all selected items + this._unselectAll(); + + // put the child node back in the global nodes object + this.nodes[containedNodeId] = childNode; + + // release the contained edges from this childNode back into the global edges + this._releaseContainedEdges(parentNode,childNode); + + // reconnect rerouted edges to the childNode + this._connectEdgeBackToChild(parentNode,childNode); + + // validate all edges in dynamicEdges + this._validateEdges(parentNode); + + // undo the changes from the clustering operation on the parent node + parentNode.options.mass -= childNode.options.mass; + parentNode.clusterSize -= childNode.clusterSize; + parentNode.options.fontSize = Math.min(this.constants.clustering.maxFontSize, this.constants.nodes.fontSize + this.constants.clustering.fontSizeMultiplier*(parentNode.clusterSize-1)); + parentNode.dynamicEdgesLength = parentNode.dynamicEdges.length; + + // place the child node near the parent, not at the exact same location to avoid chaos in the system + childNode.x = parentNode.x + parentNode.growthIndicator * (0.5 - Math.random()); + childNode.y = parentNode.y + parentNode.growthIndicator * (0.5 - Math.random()); + + // remove node from the list + delete parentNode.containedNodes[containedNodeId]; + + // check if there are other childs with this clusterSession in the parent. + var othersPresent = false; + for (var childNodeId in parentNode.containedNodes) { + if (parentNode.containedNodes.hasOwnProperty(childNodeId)) { + if (parentNode.containedNodes[childNodeId].clusterSession == childNode.clusterSession) { + othersPresent = true; + break; + } + } } - function ordinalizeToken(func, period) { - return function (a) { - return this.localeData().ordinal(func.call(this, a), period); - }; + // if there are no others, remove the cluster session from the list + if (othersPresent == false) { + parentNode.clusterSessions.pop(); } - function monthDiff(a, b) { - // difference in months - var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()), - // b is in (anchor - 1 month, anchor + 1 month) - anchor = a.clone().add(wholeMonthDiff, 'months'), - anchor2, adjust; + this._repositionBezierNodes(childNode); + // this._repositionBezierNodes(parentNode); - if (b - anchor < 0) { - anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); - // linear across the month - adjust = (b - anchor) / (anchor - anchor2); - } else { - anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); - // linear across the month - adjust = (b - anchor) / (anchor2 - anchor); + // remove the clusterSession from the child node + childNode.clusterSession = 0; + + // recalculate the size of the node on the next time the node is rendered + parentNode.clearSizeCache(); + + // restart the simulation to reorganise all nodes + this.moving = true; + } + + // check if a further expansion step is possible if recursivity is enabled + if (recursive == true) { + this._expandClusterNode(childNode,recursive,force,openAll); + } + }; + + + /** + * position the bezier nodes at the center of the edges + * + * @param node + * @private + */ + exports._repositionBezierNodes = function(node) { + for (var i = 0; i < node.dynamicEdges.length; i++) { + node.dynamicEdges[i].positionBezierNode(); + } + }; + + + /** + * This function checks if any nodes at the end of their trees have edges below a threshold length + * This function is called only from updateClusters() + * forceLevelCollapse ignores the length of the edge and collapses one level + * This means that a node with only one edge will be clustered with its connected node + * + * @private + * @param {Boolean} force + */ + exports._formClusters = function(force) { + if (force == false) { + this._formClustersByZoom(); + } + else { + this._forceClustersByZoom(); + } + }; + + + /** + * This function handles the clustering by zooming out, this is based on a minimum edge distance + * + * @private + */ + exports._formClustersByZoom = function() { + var dx,dy,length, + minLength = this.constants.clustering.clusterEdgeThreshold/this.scale; + + // check if any edges are shorter than minLength and start the clustering + // the clustering favours the node with the larger mass + for (var edgeId in this.edges) { + if (this.edges.hasOwnProperty(edgeId)) { + var edge = this.edges[edgeId]; + if (edge.connected) { + if (edge.toId != edge.fromId) { + dx = (edge.to.x - edge.from.x); + dy = (edge.to.y - edge.from.y); + length = Math.sqrt(dx * dx + dy * dy); + + + if (length < minLength) { + // first check which node is larger + var parentNode = edge.from; + var childNode = edge.to; + if (edge.to.options.mass > edge.from.options.mass) { + parentNode = edge.to; + childNode = edge.from; + } + + if (childNode.dynamicEdgesLength == 1) { + this._addToCluster(parentNode,childNode,false); + } + else if (parentNode.dynamicEdgesLength == 1) { + this._addToCluster(childNode,parentNode,false); + } + } } + } + } + } + }; - return -(wholeMonthDiff + adjust); + /** + * This function forces the network to cluster all nodes with only one connecting edge to their + * connected node. + * + * @private + */ + exports._forceClustersByZoom = function() { + for (var nodeId in this.nodes) { + // another node could have absorbed this child. + if (this.nodes.hasOwnProperty(nodeId)) { + var childNode = this.nodes[nodeId]; + + // the edges can be swallowed by another decrease + if (childNode.dynamicEdgesLength == 1 && childNode.dynamicEdges.length != 0) { + var edge = childNode.dynamicEdges[0]; + var parentNode = (edge.toId == childNode.id) ? this.nodes[edge.fromId] : this.nodes[edge.toId]; + + // group to the largest node + if (childNode.id != parentNode.id) { + if (parentNode.options.mass > childNode.options.mass) { + this._addToCluster(parentNode,childNode,true); + } + else { + this._addToCluster(childNode,parentNode,true); + } + } + } } + } + }; - while (ordinalizeTokens.length) { - i = ordinalizeTokens.pop(); - formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i); + + /** + * To keep the nodes of roughly equal size we normalize the cluster levels. + * This function clusters a node to its smallest connected neighbour. + * + * @param node + * @private + */ + exports._clusterToSmallestNeighbour = function(node) { + var smallestNeighbour = -1; + var smallestNeighbourNode = null; + for (var i = 0; i < node.dynamicEdges.length; i++) { + if (node.dynamicEdges[i] !== undefined) { + var neighbour = null; + if (node.dynamicEdges[i].fromId != node.id) { + neighbour = node.dynamicEdges[i].from; + } + else if (node.dynamicEdges[i].toId != node.id) { + neighbour = node.dynamicEdges[i].to; + } + + + if (neighbour != null && smallestNeighbour > neighbour.clusterSessions.length) { + smallestNeighbour = neighbour.clusterSessions.length; + smallestNeighbourNode = neighbour; + } } - while (paddedTokens.length) { - i = paddedTokens.pop(); - formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); + } + + if (neighbour != null && this.nodes[neighbour.id] !== undefined) { + this._addToCluster(neighbour, node, true); + } + }; + + + /** + * This function forms clusters from hubs, it loops over all nodes + * + * @param {Boolean} force | Disregard zoom level + * @param {Boolean} onlyEqual | This only clusters a hub with a specific number of edges + * @private + */ + exports._formClustersByHub = function(force, onlyEqual) { + // we loop over all nodes in the list + for (var nodeId in this.nodes) { + // we check if it is still available since it can be used by the clustering in this loop + if (this.nodes.hasOwnProperty(nodeId)) { + this._formClusterFromHub(this.nodes[nodeId],force,onlyEqual); } - formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); - + } + }; - function meridiemFixWrap(locale, hour, meridiem) { - var isPm; + /** + * This function forms a cluster from a specific preselected hub node + * + * @param {Node} hubNode | the node we will cluster as a hub + * @param {Boolean} force | Disregard zoom level + * @param {Boolean} onlyEqual | This only clusters a hub with a specific number of edges + * @param {Number} [absorptionSizeOffset] | + * @private + */ + exports._formClusterFromHub = function(hubNode, force, onlyEqual, absorptionSizeOffset) { + if (absorptionSizeOffset === undefined) { + absorptionSizeOffset = 0; + } + // we decide if the node is a hub + if ((hubNode.dynamicEdgesLength >= this.hubThreshold && onlyEqual == false) || + (hubNode.dynamicEdgesLength == this.hubThreshold && onlyEqual == true)) { + // initialize variables + var dx,dy,length; + var minLength = this.constants.clustering.clusterEdgeThreshold/this.scale; + var allowCluster = false; - if (meridiem == null) { - // nothing to do - return hour; - } - if (locale.meridiemHour != null) { - return locale.meridiemHour(hour, meridiem); - } else if (locale.isPM != null) { - // Fallback - isPm = locale.isPM(meridiem); - if (isPm && hour < 12) { - hour += 12; - } - if (!isPm && hour === 12) { - hour = 0; - } - return hour; - } else { - // thie is not supposed to happen - return hour; - } + // we create a list of edges because the dynamicEdges change over the course of this loop + var edgesIdarray = []; + var amountOfInitialEdges = hubNode.dynamicEdges.length; + for (var j = 0; j < amountOfInitialEdges; j++) { + edgesIdarray.push(hubNode.dynamicEdges[j].id); } - /************************************ - Constructors - ************************************/ + // if the hub clustering is not forces, we check if one of the edges connected + // to a cluster is small enough based on the constants.clustering.clusterEdgeThreshold + if (force == false) { + allowCluster = false; + for (j = 0; j < amountOfInitialEdges; j++) { + var edge = this.edges[edgesIdarray[j]]; + if (edge !== undefined) { + if (edge.connected) { + if (edge.toId != edge.fromId) { + dx = (edge.to.x - edge.from.x); + dy = (edge.to.y - edge.from.y); + length = Math.sqrt(dx * dx + dy * dy); - function Locale() { + if (length < minLength) { + allowCluster = true; + break; + } + } + } + } + } } - // Moment prototype object - function Moment(config, skipOverflow) { - if (skipOverflow !== false) { - checkOverflow(config); - } - copyConfig(this, config); - this._d = new Date(+config._d); - // Prevent infinite loop in case updateOffset creates new moment - // objects. - if (updateInProgress === false) { - updateInProgress = true; - moment.updateOffset(this); - updateInProgress = false; + // start the clustering if allowed + if ((!force && allowCluster) || force) { + // we loop over all edges INITIALLY connected to this hub + for (j = 0; j < amountOfInitialEdges; j++) { + edge = this.edges[edgesIdarray[j]]; + // the edge can be clustered by this function in a previous loop + if (edge !== undefined) { + var childNode = this.nodes[(edge.fromId == hubNode.id) ? edge.toId : edge.fromId]; + // we do not want hubs to merge with other hubs nor do we want to cluster itself. + if ((childNode.dynamicEdges.length <= (this.hubThreshold + absorptionSizeOffset)) && + (childNode.id != hubNode.id)) { + this._addToCluster(hubNode,childNode,force); + } } + } } + } + }; - // Duration Constructor - function Duration(duration) { - var normalizedInput = normalizeObjectUnits(duration), - years = normalizedInput.year || 0, - quarters = normalizedInput.quarter || 0, - months = normalizedInput.month || 0, - weeks = normalizedInput.week || 0, - days = normalizedInput.day || 0, - hours = normalizedInput.hour || 0, - minutes = normalizedInput.minute || 0, - seconds = normalizedInput.second || 0, - milliseconds = normalizedInput.millisecond || 0; - - // representation for dateAddRemove - this._milliseconds = +milliseconds + - seconds * 1e3 + // 1000 - minutes * 6e4 + // 1000 * 60 - hours * 36e5; // 1000 * 60 * 60 - // Because of dateAddRemove treats 24 hours as different from a - // day when working around DST, we need to store them separately - this._days = +days + - weeks * 7; - // It is impossible translate months into days without knowing - // which months you are are talking about, so we have to store - // it separately. - this._months = +months + - quarters * 3 + - years * 12; - this._data = {}; - this._locale = moment.localeData(); + /** + * This function adds the child node to the parent node, creating a cluster if it is not already. + * + * @param {Node} parentNode | this is the node that will house the child node + * @param {Node} childNode | this node will be deleted from the global this.nodes and stored in the parent node + * @param {Boolean} force | true will only update the remainingEdges at the very end of the clustering, ensuring single level collapse + * @private + */ + exports._addToCluster = function(parentNode, childNode, force) { + // join child node in the parent node + parentNode.containedNodes[childNode.id] = childNode; - this._bubble(); + // manage all the edges connected to the child and parent nodes + for (var i = 0; i < childNode.dynamicEdges.length; i++) { + var edge = childNode.dynamicEdges[i]; + if (edge.toId == parentNode.id || edge.fromId == parentNode.id) { // edge connected to parentNode + this._addToContainedEdges(parentNode,childNode,edge); } + else { + this._connectEdgeToCluster(parentNode,childNode,edge); + } + } + // a contained node has no dynamic edges. + childNode.dynamicEdges = []; - /************************************ - Helpers - ************************************/ + // remove circular edges from clusters + this._containCircularEdgesFromNode(parentNode,childNode); - function extend(a, b) { - for (var i in b) { - if (hasOwnProp(b, i)) { - a[i] = b[i]; - } - } + // remove the childNode from the global nodes object + delete this.nodes[childNode.id]; - if (hasOwnProp(b, 'toString')) { - a.toString = b.toString; - } + // update the properties of the child and parent + var massBefore = parentNode.options.mass; + childNode.clusterSession = this.clusterSession; + parentNode.options.mass += childNode.options.mass; + parentNode.clusterSize += childNode.clusterSize; + parentNode.options.fontSize = Math.min(this.constants.clustering.maxFontSize, this.constants.nodes.fontSize + this.constants.clustering.fontSizeMultiplier*parentNode.clusterSize); - if (hasOwnProp(b, 'valueOf')) { - a.valueOf = b.valueOf; - } + // keep track of the clustersessions so we can open the cluster up as it has been formed. + if (parentNode.clusterSessions[parentNode.clusterSessions.length - 1] != this.clusterSession) { + parentNode.clusterSessions.push(this.clusterSession); + } - return a; - } + // forced clusters only open from screen size and double tap + if (force == true) { + // parentNode.formationScale = Math.pow(1 - (1.0/11.0),this.clusterSession+3); + parentNode.formationScale = 0; + } + else { + parentNode.formationScale = this.scale; // The latest child has been added on this scale + } - function copyConfig(to, from) { - var i, prop, val; + // recalculate the size of the node on the next time the node is rendered + parentNode.clearSizeCache(); - 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; - } + // set the pop-out scale for the childnode + parentNode.containedNodes[childNode.id].formationScale = parentNode.formationScale; - if (momentProperties.length > 0) { - for (i in momentProperties) { - prop = momentProperties[i]; - val = from[prop]; - if (typeof val !== 'undefined') { - to[prop] = val; - } - } - } + // nullify the movement velocity of the child, this is to avoid hectic behaviour + childNode.clearVelocity(); - return to; - } + // the mass has altered, preservation of energy dictates the velocity to be updated + parentNode.updateVelocity(massBefore); - function absRound(number) { - if (number < 0) { - return Math.ceil(number); - } else { - return Math.floor(number); - } - } + // restart the simulation to reorganise all nodes + this.moving = true; + }; - // left zero fill a number - // see http://jsperf.com/left-zero-filling for performance comparison - function leftZeroFill(number, targetLength, forceSign) { - var output = '' + Math.abs(number), - sign = number >= 0; - while (output.length < targetLength) { - output = '0' + output; + /** + * This function will apply the changes made to the remainingEdges during the formation of the clusters. + * This is a seperate function to allow for level-wise collapsing of the node barnesHutTree. + * It has to be called if a level is collapsed. It is called by _formClusters(). + * @private + */ + exports._updateDynamicEdges = function() { + for (var i = 0; i < this.nodeIndices.length; i++) { + var node = this.nodes[this.nodeIndices[i]]; + node.dynamicEdgesLength = node.dynamicEdges.length; + + // this corrects for multiple edges pointing at the same other node + var correction = 0; + if (node.dynamicEdgesLength > 1) { + for (var j = 0; j < node.dynamicEdgesLength - 1; j++) { + var edgeToId = node.dynamicEdges[j].toId; + var edgeFromId = node.dynamicEdges[j].fromId; + for (var k = j+1; k < node.dynamicEdgesLength; k++) { + if ((node.dynamicEdges[k].toId == edgeToId && node.dynamicEdges[k].fromId == edgeFromId) || + (node.dynamicEdges[k].fromId == edgeToId && node.dynamicEdges[k].toId == edgeFromId)) { + correction += 1; + } } - return (sign ? (forceSign ? '+' : '') : '-') + output; + } } + node.dynamicEdgesLength -= correction; + } + }; - 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; - } + /** + * This adds an edge from the childNode to the contained edges of the parent node + * + * @param parentNode | Node object + * @param childNode | Node object + * @param edge | Edge object + * @private + */ + exports._addToContainedEdges = function(parentNode, childNode, edge) { + // create an array object if it does not yet exist for this childNode + if (!(parentNode.containedEdges.hasOwnProperty(childNode.id))) { + parentNode.containedEdges[childNode.id] = [] + } + // add this edge to the list + parentNode.containedEdges[childNode.id].push(edge); - res.milliseconds = +other - +(base.clone().add(res.months, 'M')); + // remove the edge from the global edges object + delete this.edges[edge.id]; - return res; + // remove the edge from the parent object + for (var i = 0; i < parentNode.dynamicEdges.length; i++) { + if (parentNode.dynamicEdges[i].id == edge.id) { + parentNode.dynamicEdges.splice(i,1); + break; } + } + }; - 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; + /** + * This function connects an edge that was connected to a child node to the parent node. + * It keeps track of which nodes it has been connected to with the originalId array. + * + * @param {Node} parentNode | Node object + * @param {Node} childNode | Node object + * @param {Edge} edge | Edge object + * @private + */ + exports._connectEdgeToCluster = function(parentNode, childNode, edge) { + // handle circular edges + if (edge.toId == edge.fromId) { + this._addToContainedEdges(parentNode, childNode, edge); + } + else { + if (edge.toId == childNode.id) { // edge connected to other node on the "to" side + edge.originalToId.push(childNode.id); + edge.to = parentNode; + edge.toId = parentNode.id; } + else { // edge connected to other node with the "from" side - // 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; - }; + edge.originalFromId.push(childNode.id); + edge.from = parentNode; + edge.fromId = parentNode.id; } - function addOrSubtractDurationFromMoment(mom, duration, isAdding, updateOffset) { - var milliseconds = duration._milliseconds, - days = duration._days, - months = duration._months; - updateOffset = updateOffset == null ? true : updateOffset; + this._addToReroutedEdges(parentNode,childNode,edge); + } + }; - if (milliseconds) { - mom._d.setTime(+mom._d + milliseconds * isAdding); - } - if (days) { - rawSetter(mom, 'Date', rawGetter(mom, 'Date') + days * isAdding); - } - if (months) { - rawMonthSetter(mom, rawGetter(mom, 'Month') + months * isAdding); - } - if (updateOffset) { - moment.updateOffset(mom, days || months); - } - } - // check if is an array - function isArray(input) { - return Object.prototype.toString.call(input) === '[object Array]'; + /** + * If a node is connected to itself, a circular edge is drawn. When clustering we want to contain + * these edges inside of the cluster. + * + * @param parentNode + * @param childNode + * @private + */ + exports._containCircularEdgesFromNode = function(parentNode, childNode) { + // manage all the edges connected to the child and parent nodes + for (var i = 0; i < parentNode.dynamicEdges.length; i++) { + var edge = parentNode.dynamicEdges[i]; + // handle circular edges + if (edge.toId == edge.fromId) { + this._addToContainedEdges(parentNode, childNode, edge); } + } + }; - function isDate(input) { - return Object.prototype.toString.call(input) === '[object Date]' || - input instanceof Date; - } - // compare two arrays, return the number of differences - function compareArrays(array1, array2, dontConvert) { - var len = Math.min(array1.length, array2.length), - lengthDiff = Math.abs(array1.length - array2.length), - diffs = 0, - i; - for (i = 0; i < len; i++) { - if ((dontConvert && array1[i] !== array2[i]) || - (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { - diffs++; - } - } - return diffs + lengthDiff; - } + /** + * This adds an edge from the childNode to the rerouted edges of the parent node + * + * @param parentNode | Node object + * @param childNode | Node object + * @param edge | Edge object + * @private + */ + exports._addToReroutedEdges = function(parentNode, childNode, edge) { + // create an array object if it does not yet exist for this childNode + // we store the edge in the rerouted edges so we can restore it when the cluster pops open + if (!(parentNode.reroutedEdges.hasOwnProperty(childNode.id))) { + parentNode.reroutedEdges[childNode.id] = []; + } + parentNode.reroutedEdges[childNode.id].push(edge); - function normalizeUnits(units) { - if (units) { - var lowered = units.toLowerCase().replace(/(.)s$/, '$1'); - units = unitAliases[units] || camelFunctions[lowered] || lowered; - } - return units; - } + // this edge becomes part of the dynamicEdges of the cluster node + parentNode.dynamicEdges.push(edge); + }; - function normalizeObjectUnits(inputObject) { - var normalizedInput = {}, - normalizedProp, - prop; - for (prop in inputObject) { - if (hasOwnProp(inputObject, prop)) { - normalizedProp = normalizeUnits(prop); - if (normalizedProp) { - normalizedInput[normalizedProp] = inputObject[prop]; - } - } - } - return normalizedInput; - } + /** + * This function connects an edge that was connected to a cluster node back to the child node. + * + * @param parentNode | Node object + * @param childNode | Node object + * @private + */ + exports._connectEdgeBackToChild = function(parentNode, childNode) { + if (parentNode.reroutedEdges.hasOwnProperty(childNode.id)) { + for (var i = 0; i < parentNode.reroutedEdges[childNode.id].length; i++) { + var edge = parentNode.reroutedEdges[childNode.id][i]; + if (edge.originalFromId[edge.originalFromId.length-1] == childNode.id) { + edge.originalFromId.pop(); + edge.fromId = childNode.id; + edge.from = childNode; + } + else { + edge.originalToId.pop(); + edge.toId = childNode.id; + edge.to = childNode; + } - function makeList(field) { - var count, setter; + // append this edge to the list of edges connecting to the childnode + childNode.dynamicEdges.push(edge); - if (field.indexOf('week') === 0) { - count = 7; - setter = 'day'; - } - else if (field.indexOf('month') === 0) { - count = 12; - setter = 'month'; - } - else { - return; + // remove the edge from the parent object + for (var j = 0; j < parentNode.dynamicEdges.length; j++) { + if (parentNode.dynamicEdges[j].id == edge.id) { + parentNode.dynamicEdges.splice(j,1); + break; } + } + } + // remove the entry from the rerouted edges + delete parentNode.reroutedEdges[childNode.id]; + } + }; - moment[field] = function (format, index) { - var i, getter, - method = moment._locale[field], - results = []; - if (typeof format === 'number') { - index = format; - format = undefined; - } + /** + * When loops are clustered, an edge can be both in the rerouted array and the contained array. + * This function is called last to verify that all edges in dynamicEdges are in fact connected to the + * parentNode + * + * @param parentNode | Node object + * @private + */ + exports._validateEdges = function(parentNode) { + for (var i = 0; i < parentNode.dynamicEdges.length; i++) { + var edge = parentNode.dynamicEdges[i]; + if (parentNode.id != edge.toId && parentNode.id != edge.fromId) { + parentNode.dynamicEdges.splice(i,1); + } + } + }; - getter = function (i) { - var m = moment().utc().set(setter, i); - return method.call(moment._locale, m, format || ''); - }; - if (index != null) { - return getter(index); - } - else { - for (i = 0; i < count; i++) { - results.push(getter(i)); - } - return results; - } - }; - } + /** + * This function released the contained edges back into the global domain and puts them back into the + * dynamic edges of both parent and child. + * + * @param {Node} parentNode | + * @param {Node} childNode | + * @private + */ + exports._releaseContainedEdges = function(parentNode, childNode) { + for (var i = 0; i < parentNode.containedEdges[childNode.id].length; i++) { + var edge = parentNode.containedEdges[childNode.id][i]; - function toInt(argumentForCoercion) { - var coercedNumber = +argumentForCoercion, - value = 0; + // put the edge back in the global edges object + this.edges[edge.id] = edge; - if (coercedNumber !== 0 && isFinite(coercedNumber)) { - if (coercedNumber >= 0) { - value = Math.floor(coercedNumber); - } else { - value = Math.ceil(coercedNumber); - } - } + // put the edge back in the dynamic edges of the child and parent + childNode.dynamicEdges.push(edge); + parentNode.dynamicEdges.push(edge); + } + // remove the entry from the contained edges + delete parentNode.containedEdges[childNode.id]; - return value; - } + }; - function daysInMonth(year, month) { - return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); - } - function weeksInYear(year, dow, doy) { - return weekOfYear(moment([year, 11, 31 + dow - doy]), dow, doy).week; - } - function daysInYear(year) { - return isLeapYear(year) ? 366 : 365; - } - function isLeapYear(year) { - return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; - } + // ------------------- UTILITY FUNCTIONS ---------------------------- // - function checkOverflow(m) { - var overflow; - if (m._a && m._pf.overflow === -2) { - overflow = - m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH : - m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE : - m._a[HOUR] < 0 || m._a[HOUR] > 24 || - (m._a[HOUR] === 24 && (m._a[MINUTE] !== 0 || - m._a[SECOND] !== 0 || - m._a[MILLISECOND] !== 0)) ? HOUR : - m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE : - m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND : - m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND : - -1; - if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { - overflow = DATE; - } + /** + * This updates the node labels for all nodes (for debugging purposes) + */ + exports.updateLabels = function() { + var nodeId; + // update node labels + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + var node = this.nodes[nodeId]; + if (node.clusterSize > 1) { + node.label = "[".concat(String(node.clusterSize),"]"); + } + } + } - m._pf.overflow = overflow; + // update node labels + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + if (node.clusterSize == 1) { + if (node.originalLabel !== undefined) { + node.label = node.originalLabel; + } + else { + node.label = String(node.id); } + } } + } - function isValid(m) { - if (m._isValid == null) { - m._isValid = !isNaN(m._d.getTime()) && - m._pf.overflow < 0 && - !m._pf.empty && - !m._pf.invalidMonth && - !m._pf.nullInput && - !m._pf.invalidFormat && - !m._pf.userInvalidated; + // /* Debug Override */ + // for (nodeId in this.nodes) { + // if (this.nodes.hasOwnProperty(nodeId)) { + // node = this.nodes[nodeId]; + // node.label = String(node.level); + // } + // } - if (m._strict) { - m._isValid = m._isValid && - m._pf.charsLeftOver === 0 && - m._pf.unusedTokens.length === 0 && - m._pf.bigHour === undefined; - } - } - return m._isValid; - } + }; - 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; + /** + * We want to keep the cluster level distribution rather small. This means we do not want unclustered nodes + * if the rest of the nodes are already a few cluster levels in. + * To fix this we use this function. It determines the min and max cluster level and sends nodes that have not + * clustered enough to the clusterToSmallestNeighbours function. + */ + exports.normalizeClusterLevels = function() { + var maxLevel = 0; + var minLevel = 1e9; + var clusterLevel = 0; + var nodeId; - 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; + // we loop over all nodes in the list + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + clusterLevel = this.nodes[nodeId].clusterSessions.length; + if (maxLevel < clusterLevel) {maxLevel = clusterLevel;} + if (minLevel > clusterLevel) {minLevel = clusterLevel;} } + } - 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) { } + if (maxLevel - minLevel > this.constants.clustering.clusterLevelDifference) { + var amountOfNodes = this.nodeIndices.length; + var targetLevel = maxLevel - this.constants.clustering.clusterLevelDifference; + // we loop over all nodes in the list + for (nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + if (this.nodes[nodeId].clusterSessions.length < targetLevel) { + this._clusterToSmallestNeighbour(this.nodes[nodeId]); } - return locales[name]; + } } - - // Return a moment from input, that is local/utc/utcOffset equivalent to - // model. - function makeAs(input, model) { - var res, diff; - if (model._isUTC) { - res = model.clone(); - diff = (moment.isMoment(input) || isDate(input) ? - +input : +moment(input)) - (+res); - // Use low-level api, because this fn is low-level api. - res._d.setTime(+res._d + diff); - moment.updateOffset(res, false); - return res; - } else { - return moment(input).local(); - } + this._updateNodeIndexList(); + this._updateDynamicEdges(); + // if a cluster was formed, we increase the clusterSession + if (this.nodeIndices.length != amountOfNodes) { + this.clusterSession += 1; } + } + }; - /************************************ - Locale - ************************************/ - extend(Locale.prototype, { + /** + * This function determines if the cluster we want to decluster is in the active area + * this means around the zoom center + * + * @param {Node} node + * @returns {boolean} + * @private + */ + exports._nodeInActiveArea = function(node) { + return ( + Math.abs(node.x - this.areaCenter.x) <= this.constants.clustering.activeAreaBoxSize/this.scale + && + Math.abs(node.y - this.areaCenter.y) <= this.constants.clustering.activeAreaBoxSize/this.scale + ) + }; - set : function (config) { - var prop, i; - for (i in config) { - prop = config[i]; - if (typeof prop === 'function') { - this[i] = prop; - } else { - this['_' + i] = prop; - } - } - // Lenient ordinal parsing accepts just a number in addition to - // number + (possibly) stuff coming from _ordinalParseLenient. - this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + /\d{1,2}/.source); - }, - _months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), - months : function (m) { - return this._months[m.month()]; - }, + /** + * This is an adaptation of the original repositioning function. This is called if the system is clustered initially + * It puts large clusters away from the center and randomizes the order. + * + */ + exports.repositionNodes = function() { + for (var i = 0; i < this.nodeIndices.length; i++) { + var node = this.nodes[this.nodeIndices[i]]; + if ((node.xFixed == false || node.yFixed == false)) { + var radius = 10 * 0.1*this.nodeIndices.length * Math.min(100,node.options.mass); + var angle = 2 * Math.PI * Math.random(); + if (node.xFixed == false) {node.x = radius * Math.cos(angle);} + if (node.yFixed == false) {node.y = radius * Math.sin(angle);} + this._repositionBezierNodes(node); + } + } + }; - _monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), - monthsShort : function (m) { - return this._monthsShort[m.month()]; - }, - monthsParse : function (monthName, format, strict) { - var i, mom, regex; + /** + * We determine how many connections denote an important hub. + * We take the mean + 2*std as the important hub size. (Assuming a normal distribution of data, ~2.2%) + * + * @private + */ + exports._getHubSize = function() { + var average = 0; + var averageSquared = 0; + var hubCounter = 0; + var largestHub = 0; - if (!this._monthsParse) { - this._monthsParse = []; - this._longMonthsParse = []; - this._shortMonthsParse = []; - } + for (var i = 0; i < this.nodeIndices.length; i++) { - for (i = 0; i < 12; i++) { - // make the regex if we don't have it already - mom = moment.utc([2000, i]); - if (strict && !this._longMonthsParse[i]) { - this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i'); - this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i'); - } - if (!strict && !this._monthsParse[i]) { - regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); - this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) { - return i; - } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) { - return i; - } else if (!strict && this._monthsParse[i].test(monthName)) { - return i; - } - } - }, + var node = this.nodes[this.nodeIndices[i]]; + if (node.dynamicEdgesLength > largestHub) { + largestHub = node.dynamicEdgesLength; + } + average += node.dynamicEdgesLength; + averageSquared += Math.pow(node.dynamicEdgesLength,2); + hubCounter += 1; + } + average = average / hubCounter; + averageSquared = averageSquared / hubCounter; - _weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), - weekdays : function (m) { - return this._weekdays[m.day()]; - }, + var variance = averageSquared - Math.pow(average,2); - _weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), - weekdaysShort : function (m) { - return this._weekdaysShort[m.day()]; - }, + var standardDeviation = Math.sqrt(variance); - _weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), - weekdaysMin : function (m) { - return this._weekdaysMin[m.day()]; - }, + this.hubThreshold = Math.floor(average + 2*standardDeviation); - weekdaysParse : function (weekdayName) { - var i, mom, regex; + // always have at least one to cluster + if (this.hubThreshold > largestHub) { + this.hubThreshold = largestHub; + } - if (!this._weekdaysParse) { - this._weekdaysParse = []; - } + // console.log("average",average,"averageSQ",averageSquared,"var",variance,"std",standardDeviation); + // console.log("hubThreshold:",this.hubThreshold); + }; - for (i = 0; i < 7; i++) { - // make the regex if we don't have it already - if (!this._weekdaysParse[i]) { - mom = moment([2000, 1]).day(i); - regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); - this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (this._weekdaysParse[i].test(weekdayName)) { - return i; - } - } - }, - _longDateFormat : { - LTS : 'h:mm:ss A', - 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]; - if (!output && this._longDateFormat[key.toUpperCase()]) { - output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { - return val.slice(1); - }); - this._longDateFormat[key] = output; - } - return output; - }, + /** + * We reduce the amount of "extension nodes" or chains. These are not quickly clustered with the outliers and hubs methods + * with this amount we can cluster specifically on these chains. + * + * @param {Number} fraction | between 0 and 1, the percentage of chains to reduce + * @private + */ + exports._reduceAmountOfChains = function(fraction) { + this.hubThreshold = 2; + var reduceAmount = Math.floor(this.nodeIndices.length * fraction); + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + if (this.nodes[nodeId].dynamicEdgesLength == 2 && this.nodes[nodeId].dynamicEdges.length >= 2) { + if (reduceAmount > 0) { + this._formClusterFromHub(this.nodes[nodeId],true,true,1); + reduceAmount -= 1; + } + } + } + } + }; - isPM : function (input) { - // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays - // Using charAt should be more compatible. - return ((input + '').toLowerCase().charAt(0) === 'p'); - }, + /** + * We get the amount of "extension nodes" or chains. These are not quickly clustered with the outliers and hubs methods + * with this amount we can cluster specifically on these chains. + * + * @private + */ + exports._getChainFraction = function() { + var chains = 0; + var total = 0; + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + if (this.nodes[nodeId].dynamicEdgesLength == 2 && this.nodes[nodeId].dynamicEdges.length >= 2) { + chains += 1; + } + total += 1; + } + } + return chains/total; + }; - _meridiemParse : /[ap]\.?m?\.?/i, - meridiem : function (hours, minutes, isLower) { - if (hours > 11) { - return isLower ? 'pm' : 'PM'; - } else { - return isLower ? 'am' : 'AM'; - } - }, +/***/ }, +/* 58 */ +/***/ function(module, exports, __webpack_require__) { - _calendar : { - sameDay : '[Today at] LT', - nextDay : '[Tomorrow at] LT', - nextWeek : 'dddd [at] LT', - lastDay : '[Yesterday at] LT', - lastWeek : '[Last] dddd [at] LT', - sameElse : 'L' - }, - calendar : function (key, mom, now) { - var output = this._calendar[key]; - return typeof output === 'function' ? output.apply(mom, [now]) : output; - }, + var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;"use strict"; + /** + * Created by Alex on 11/6/2014. + */ - _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' - }, + // https://github.com/umdjs/umd/blob/master/returnExports.js#L40-L60 + // if the module has no dependencies, the above pattern can be simplified to + (function (root, factory) { + if (true) { + // AMD. Register as an anonymous module. + !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + } else if (typeof exports === 'object') { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); + } else { + // Browser globals (root is window) + root.keycharm = factory(); + } + }(this, function () { - 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); - }, + function keycharm(options) { + var preventDefault = options && options.preventDefault || false; - pastFuture : function (diff, output) { - var format = this._relativeTime[diff > 0 ? 'future' : 'past']; - return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); - }, + var container = options && options.container || window; - ordinal : function (number) { - return this._ordinal.replace('%d', number); - }, - _ordinal : '%d', - _ordinalParse : /\d{1,2}/, + var _exportFunctions = {}; + var _bound = {keydown:{}, keyup:{}}; + var _keys = {}; + var i; - preparse : function (string) { - return string; - }, + // a - z + for (i = 97; i <= 122; i++) {_keys[String.fromCharCode(i)] = {code:65 + (i - 97), shift: false};} + // A - Z + for (i = 65; i <= 90; i++) {_keys[String.fromCharCode(i)] = {code:i, shift: true};} + // 0 - 9 + for (i = 0; i <= 9; i++) {_keys['' + i] = {code:48 + i, shift: false};} + // F1 - F12 + for (i = 1; i <= 12; i++) {_keys['F' + i] = {code:111 + i, shift: false};} + // num0 - num9 + for (i = 0; i <= 9; i++) {_keys['num' + i] = {code:96 + i, shift: false};} - postformat : function (string) { - return string; - }, + // numpad misc + _keys['num*'] = {code:106, shift: false}; + _keys['num+'] = {code:107, shift: false}; + _keys['num-'] = {code:109, shift: false}; + _keys['num/'] = {code:111, shift: false}; + _keys['num.'] = {code:110, shift: false}; + // arrows + _keys['left'] = {code:37, shift: false}; + _keys['up'] = {code:38, shift: false}; + _keys['right'] = {code:39, shift: false}; + _keys['down'] = {code:40, shift: false}; + // extra keys + _keys['space'] = {code:32, shift: false}; + _keys['enter'] = {code:13, shift: false}; + _keys['shift'] = {code:16, shift: undefined}; + _keys['esc'] = {code:27, shift: false}; + _keys['backspace'] = {code:8, shift: false}; + _keys['tab'] = {code:9, shift: false}; + _keys['ctrl'] = {code:17, shift: false}; + _keys['alt'] = {code:18, shift: false}; + _keys['delete'] = {code:46, shift: false}; + _keys['pageup'] = {code:33, shift: false}; + _keys['pagedown'] = {code:34, shift: false}; + // symbols + _keys['='] = {code:187, shift: false}; + _keys['-'] = {code:189, shift: false}; + _keys[']'] = {code:221, shift: false}; + _keys['['] = {code:219, shift: false}; - week : function (mom) { - return weekOfYear(mom, this._week.dow, this._week.doy).week; - }, - _week : { - dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. - }, - firstDayOfWeek : function () { - return this._week.dow; - }, + var down = function(event) {handleEvent(event,'keydown');}; + var up = function(event) {handleEvent(event,'keyup');}; - firstDayOfYear : function () { - return this._week.doy; - }, + // handle the actualy bound key with the event + var handleEvent = function(event,type) { + if (_bound[type][event.keyCode] !== undefined) { + var bound = _bound[type][event.keyCode]; + for (var i = 0; i < bound.length; i++) { + if (bound[i].shift === undefined) { + bound[i].fn(event); + } + else if (bound[i].shift == true && event.shiftKey == true) { + bound[i].fn(event); + } + else if (bound[i].shift == false && event.shiftKey == false) { + bound[i].fn(event); + } + } - _invalidDate: 'Invalid date', - invalidDate: function () { - return this._invalidDate; + if (preventDefault == true) { + event.preventDefault(); } - }); + } + }; - /************************************ - Formatting - ************************************/ + // bind a key to a callback + _exportFunctions.bind = function(key, callback, type) { + if (type === undefined) { + type = 'keydown'; + } + if (_keys[key] === undefined) { + throw new Error("unsupported key: " + key); + } + if (_bound[type][_keys[key].code] === undefined) { + _bound[type][_keys[key].code] = []; + } + _bound[type][_keys[key].code].push({fn:callback, shift:_keys[key].shift}); + }; - function removeFormattingTokens(input) { - if (input.match(/\[[\s\S]/)) { - return input.replace(/^\[|\]$/g, ''); + // bind all keys to a call back (demo purposes) + _exportFunctions.bindAll = function(callback, type) { + if (type === undefined) { + type = 'keydown'; + } + for (var key in _keys) { + if (_keys.hasOwnProperty(key)) { + _exportFunctions.bind(key,callback,type); } - return input.replace(/\\/g, ''); - } + } + }; - function makeFormatFunction(format) { - var array = format.match(formattingTokens), i, length; + // get the key label from an event + _exportFunctions.getKey = function(event) { + for (var key in _keys) { + if (_keys.hasOwnProperty(key)) { + if (event.shiftKey == true && _keys[key].shift == true && event.keyCode == _keys[key].code) { + return key; + } + else if (event.shiftKey == false && _keys[key].shift == false && event.keyCode == _keys[key].code) { + return key; + } + else if (event.keyCode == _keys[key].code && key == 'shift') { + return key; + } + } + } + return "unknown key, currently not supported"; + }; - for (i = 0, length = array.length; i < length; i++) { - if (formatTokenFunctions[array[i]]) { - array[i] = formatTokenFunctions[array[i]]; - } else { - array[i] = removeFormattingTokens(array[i]); + // unbind either a specific callback from a key or all of them (by leaving callback undefined) + _exportFunctions.unbind = function(key, callback, type) { + if (type === undefined) { + type = 'keydown'; + } + if (_keys[key] === undefined) { + throw new Error("unsupported key: " + key); + } + if (callback !== undefined) { + var newBindings = []; + var bound = _bound[type][_keys[key].code]; + if (bound !== undefined) { + for (var i = 0; i < bound.length; i++) { + if (!(bound[i].fn == callback && bound[i].shift == _keys[key].shift)) { + newBindings.push(_bound[type][_keys[key].code][i]); } + } } + _bound[type][_keys[key].code] = newBindings; + } + else { + _bound[type][_keys[key].code] = []; + } + }; - return function (mom) { - var output = ''; - for (i = 0; i < length; i++) { - output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; - } - return output; - }; - } + // reset all bound variables. + _exportFunctions.reset = function() { + _bound = {keydown:{}, keyup:{}}; + }; - // format date using native date object - function formatMoment(m, format) { - if (!m.isValid()) { - return m.localeData().invalidDate(); - } + // unbind all listeners and reset all variables. + _exportFunctions.destroy = function() { + _bound = {keydown:{}, keyup:{}}; + container.removeEventListener('keydown', down, true); + container.removeEventListener('keyup', up, true); + }; - format = expandFormat(format, m.localeData()); + // create listeners. + container.addEventListener('keydown',down,true); + container.addEventListener('keyup',up,true); - if (!formatFunctions[format]) { - formatFunctions[format] = makeFormatFunction(format); - } + // return the public functions. + return _exportFunctions; + } - return formatFunctions[format](m); - } + return keycharm; + })); - function expandFormat(format, locale) { - var i = 5; - function replaceLongDateFormatTokens(input) { - return locale.longDateFormat(input) || input; - } - localFormattingTokens.lastIndex = 0; - while (i >= 0 && localFormattingTokens.test(format)) { - format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); - localFormattingTokens.lastIndex = 0; - i -= 1; - } - return format; - } +/***/ }, +/* 59 */ +/***/ function(module, exports, __webpack_require__) { + var __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(global, module) {//! moment.js + //! version : 2.9.0 + //! authors : Tim Wood, Iskren Chernev, Moment.js contributors + //! license : MIT + //! momentjs.com + (function (undefined) { /************************************ - Parsing + Constants ************************************/ + var moment, + VERSION = '2.9.0', + // the global-scope this is NOT the global object in Node.js + globalScope = (typeof global !== 'undefined' && (typeof window === 'undefined' || window === global.window)) ? global : this, + oldGlobalMoment, + round = Math.round, + hasOwnProperty = Object.prototype.hasOwnProperty, + i, - // get the regex to find the next token - function getParseRegexForToken(token, config) { - var a, strict = config._strict; - switch (token) { - case 'Q': - return parseTokenOneDigit; - case 'DDDD': - return parseTokenThreeDigits; - case 'YYYY': - case 'GGGG': - case 'gggg': - return strict ? parseTokenFourDigits : parseTokenOneToFourDigits; - case 'Y': - case 'G': - case 'g': - return parseTokenSignedNumber; - case 'YYYYYY': - case 'YYYYY': - case 'GGGGG': - case 'ggggg': - return strict ? parseTokenSixDigits : parseTokenOneToSixDigits; - case 'S': - if (strict) { - return parseTokenOneDigit; - } - /* falls through */ - case 'SS': - if (strict) { - return parseTokenTwoDigits; - } - /* falls through */ - case 'SSS': - if (strict) { - return parseTokenThreeDigits; - } - /* falls through */ - case 'DDD': - return parseTokenOneToThreeDigits; - case 'MMM': - case 'MMMM': - case 'dd': - case 'ddd': - case 'dddd': - return parseTokenWord; - case 'a': - case 'A': - return config._locale._meridiemParse; - case 'x': - return parseTokenOffsetMs; - case 'X': - return parseTokenTimestampMs; - case 'Z': - case 'ZZ': - return parseTokenTimezone; - case 'T': - return parseTokenT; - case 'SSSS': - return parseTokenDigits; - case 'MM': - case 'DD': - case 'YY': - case 'GG': - case 'gg': - case 'HH': - case 'hh': - case 'mm': - case 'ss': - case 'ww': - case 'WW': - return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits; - case 'M': - case 'D': - case 'd': - case 'H': - case 'h': - case 'm': - case 's': - case 'w': - case 'W': - case 'e': - case 'E': - return parseTokenOneOrTwoDigits; - case 'Do': - return strict ? config._locale._ordinalParse : config._locale._ordinalParseLenient; - default : - a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), 'i')); - return a; - } - } + YEAR = 0, + MONTH = 1, + DATE = 2, + HOUR = 3, + MINUTE = 4, + SECOND = 5, + MILLISECOND = 6, - function utcOffsetFromString(string) { - string = string || ''; - var possibleTzMatches = (string.match(parseTokenTimezone) || []), - tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [], - parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0], - minutes = +(parts[1] * 60) + toInt(parts[2]); + // internal storage for locale config files + locales = {}, - return parts[0] === '+' ? minutes : -minutes; - } + // extra moment internal properties (plugins register props here) + momentProperties = [], - // function to convert string input to date - function addTimeToArrayFromToken(token, input, config) { - var a, datePartArray = config._a; + // check for nodeJS + hasModule = (typeof module !== 'undefined' && module && module.exports), - switch (token) { - // QUARTER - case 'Q': - if (input != null) { - datePartArray[MONTH] = (toInt(input) - 1) * 3; - } - break; - // MONTH - case 'M' : // fall through to MM - case 'MM' : - if (input != null) { - datePartArray[MONTH] = toInt(input) - 1; - } - break; - case 'MMM' : // fall through to MMMM - case 'MMMM' : - a = config._locale.monthsParse(input, token, config._strict); - // if we didn't find a month name, mark the date as invalid. - if (a != null) { - datePartArray[MONTH] = a; - } else { - config._pf.invalidMonth = input; - } - break; - // DAY OF MONTH - case 'D' : // fall through to DD - case 'DD' : - if (input != null) { - datePartArray[DATE] = toInt(input); - } - break; - case 'Do' : - if (input != null) { - datePartArray[DATE] = toInt(parseInt( - input.match(/\d{1,2}/)[0], 10)); - } - break; - // DAY OF YEAR - case 'DDD' : // fall through to DDDD - case 'DDDD' : - if (input != null) { - config._dayOfYear = toInt(input); - } + // ASP.NET json date format regex + aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, + aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/, - break; - // YEAR - case 'YY' : - datePartArray[YEAR] = moment.parseTwoDigitYear(input); - break; - case 'YYYY' : - case 'YYYYY' : - case 'YYYYYY' : - datePartArray[YEAR] = toInt(input); - break; - // AM / PM - case 'a' : // fall through to A - case 'A' : - config._meridiem = input; - // config._isPm = config._locale.isPM(input); - break; - // HOUR - case 'h' : // fall through to hh - case 'hh' : - config._pf.bigHour = true; - /* falls through */ - case 'H' : // fall through to HH - case 'HH' : - datePartArray[HOUR] = toInt(input); - break; - // MINUTE - case 'm' : // fall through to mm - case 'mm' : - datePartArray[MINUTE] = toInt(input); - break; - // SECOND - case 's' : // fall through to ss - case 'ss' : - datePartArray[SECOND] = toInt(input); - break; - // MILLISECOND - case 'S' : - case 'SS' : - case 'SSS' : - case 'SSSS' : - datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000); - break; - // UNIX OFFSET (MILLISECONDS) - case 'x': - config._d = new Date(toInt(input)); - break; - // UNIX TIMESTAMP WITH MS - case 'X': - config._d = new Date(parseFloat(input) * 1000); - break; - // TIMEZONE - case 'Z' : // fall through to ZZ - case 'ZZ' : - config._useUTC = true; - config._tzm = utcOffsetFromString(input); - break; - // WEEKDAY - human - case 'dd': - case 'ddd': - case 'dddd': - 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 || {}; - config._w['d'] = a; - } else { - config._pf.invalidWeekday = input; - } - break; - // WEEK, WEEK DAY - numeric - case 'w': - case 'ww': - case 'W': - case 'WW': - case 'd': - case 'e': - case 'E': - token = token.substr(0, 1); - /* falls through */ - case 'gggg': - case 'GGGG': - case 'GGGGG': - token = token.substr(0, 2); - if (input) { - config._w = config._w || {}; - config._w[token] = toInt(input); - } - break; - case 'gg': - case 'GG': - config._w = config._w || {}; - config._w[token] = moment.parseTwoDigitYear(input); - } - } + // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html + // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere + isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/, + + // format tokens + formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|x|X|zz?|ZZ?|.)/g, + localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, - function dayOfYearFromWeekInfo(config) { - var w, weekYear, week, weekday, dow, doy, temp; + // parsing token regexes + parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 + parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 + parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999 + parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 + parseTokenDigits = /\d+/, // nonzero number of digits + parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic. + parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z + parseTokenT = /T/i, // T (ISO separator) + parseTokenOffsetMs = /[\+\-]?\d+/, // 1234567890123 + parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 - w = config._w; - if (w.GG != null || w.W != null || w.E != null) { - dow = 1; - doy = 4; + //strict parsing regexes + parseTokenOneDigit = /\d/, // 0 - 9 + parseTokenTwoDigits = /\d\d/, // 00 - 99 + parseTokenThreeDigits = /\d{3}/, // 000 - 999 + parseTokenFourDigits = /\d{4}/, // 0000 - 9999 + parseTokenSixDigits = /[+-]?\d{6}/, // -999,999 - 999,999 + parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf - // TODO: We need to take the current isoWeekYear, but that depends on - // how we interpret now (local, utc, fixed offset). So create - // a now version of current config (take local/utc/offset flags, and - // create now). - weekYear = dfl(w.GG, config._a[YEAR], weekOfYear(moment(), 1, 4).year); - week = dfl(w.W, 1); - weekday = dfl(w.E, 1); - } else { - dow = config._locale._week.dow; - doy = config._locale._week.doy; + // iso 8601 regex + // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) + isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/, - weekYear = dfl(w.gg, config._a[YEAR], weekOfYear(moment(), dow, doy).year); - week = dfl(w.w, 1); + isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', - if (w.d != null) { - // weekday -- low day numbers are considered next week - weekday = w.d; - if (weekday < dow) { - ++week; - } - } else if (w.e != null) { - // local weekday -- counting starts from begining of week - weekday = w.e + dow; - } else { - // default to begining of week - weekday = dow; - } - } - temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow); + isoDates = [ + ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/], + ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/], + ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/], + ['GGGG-[W]WW', /\d{4}-W\d{2}/], + ['YYYY-DDD', /\d{4}-\d{3}/] + ], - config._a[YEAR] = temp.year; - config._dayOfYear = temp.dayOfYear; - } + // iso time formats and regexes + isoTimes = [ + ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d+/], + ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], + ['HH:mm', /(T| )\d\d:\d\d/], + ['HH', /(T| )\d\d/] + ], - // convert an array to a date. - // the array should mirror the parameters below - // note: all values past the year are optional and will default to the lowest possible value. - // [year, month, day , hour, minute, second, millisecond] - function dateFromConfig(config) { - var i, date, input = [], currentDate, yearToUse; + // timezone chunker '+10:00' > ['10', '00'] or '-1530' > ['-', '15', '30'] + parseTimezoneChunker = /([\+\-]|\d\d)/gi, - if (config._d) { - return; - } + // getter and setter names + proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), + unitMillisecondFactors = { + 'Milliseconds' : 1, + 'Seconds' : 1e3, + 'Minutes' : 6e4, + 'Hours' : 36e5, + 'Days' : 864e5, + 'Months' : 2592e6, + 'Years' : 31536e6 + }, - currentDate = currentDateArray(config); + unitAliases = { + ms : 'millisecond', + s : 'second', + m : 'minute', + h : 'hour', + d : 'day', + D : 'date', + w : 'week', + W : 'isoWeek', + M : 'month', + Q : 'quarter', + y : 'year', + DDD : 'dayOfYear', + e : 'weekday', + E : 'isoWeekday', + gg: 'weekYear', + GG: 'isoWeekYear' + }, - //compute day of the year from weeks and weekdays - if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { - dayOfYearFromWeekInfo(config); - } + camelFunctions = { + dayofyear : 'dayOfYear', + isoweekday : 'isoWeekday', + isoweek : 'isoWeek', + weekyear : 'weekYear', + isoweekyear : 'isoWeekYear' + }, - //if the day of the year is set, figure out what it is - if (config._dayOfYear) { - yearToUse = dfl(config._a[YEAR], currentDate[YEAR]); + // format function strings + formatFunctions = {}, - if (config._dayOfYear > daysInYear(yearToUse)) { - config._pf._overflowDayOfYear = true; + // default relative time thresholds + relativeTimeThresholds = { + 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 + ordinalizeTokens = 'DDD w W M D d'.split(' '), + paddedTokens = 'M D H h m s w W'.split(' '), + + formatTokenFunctions = { + M : function () { + return this.month() + 1; + }, + MMM : function (format) { + return this.localeData().monthsShort(this, format); + }, + MMMM : function (format) { + return this.localeData().months(this, format); + }, + D : function () { + return this.date(); + }, + DDD : function () { + return this.dayOfYear(); + }, + d : function () { + return this.day(); + }, + dd : function (format) { + return this.localeData().weekdaysMin(this, format); + }, + ddd : function (format) { + return this.localeData().weekdaysShort(this, format); + }, + dddd : function (format) { + return this.localeData().weekdays(this, format); + }, + w : function () { + return this.week(); + }, + W : function () { + return this.isoWeek(); + }, + YY : function () { + return leftZeroFill(this.year() % 100, 2); + }, + YYYY : function () { + return leftZeroFill(this.year(), 4); + }, + YYYYY : function () { + return leftZeroFill(this.year(), 5); + }, + YYYYYY : function () { + var y = this.year(), sign = y >= 0 ? '+' : '-'; + return sign + leftZeroFill(Math.abs(y), 6); + }, + gg : function () { + return leftZeroFill(this.weekYear() % 100, 2); + }, + gggg : function () { + return leftZeroFill(this.weekYear(), 4); + }, + ggggg : function () { + return leftZeroFill(this.weekYear(), 5); + }, + GG : function () { + return leftZeroFill(this.isoWeekYear() % 100, 2); + }, + GGGG : function () { + return leftZeroFill(this.isoWeekYear(), 4); + }, + GGGGG : function () { + return leftZeroFill(this.isoWeekYear(), 5); + }, + e : function () { + return this.weekday(); + }, + E : function () { + return this.isoWeekday(); + }, + a : function () { + return this.localeData().meridiem(this.hours(), this.minutes(), true); + }, + A : function () { + return this.localeData().meridiem(this.hours(), this.minutes(), false); + }, + H : function () { + return this.hours(); + }, + h : function () { + return this.hours() % 12 || 12; + }, + m : function () { + return this.minutes(); + }, + s : function () { + return this.seconds(); + }, + S : function () { + return toInt(this.milliseconds() / 100); + }, + SS : function () { + return leftZeroFill(toInt(this.milliseconds() / 10), 2); + }, + SSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + SSSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + Z : function () { + var a = this.utcOffset(), + b = '+'; + if (a < 0) { + a = -a; + b = '-'; + } + return b + leftZeroFill(toInt(a / 60), 2) + ':' + leftZeroFill(toInt(a) % 60, 2); + }, + ZZ : function () { + var a = this.utcOffset(), + b = '+'; + if (a < 0) { + a = -a; + b = '-'; + } + return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2); + }, + z : function () { + return this.zoneAbbr(); + }, + zz : function () { + return this.zoneName(); + }, + x : function () { + return this.valueOf(); + }, + X : function () { + return this.unix(); + }, + Q : function () { + return this.quarter(); } + }, - date = makeUTCDate(yearToUse, 0, config._dayOfYear); - config._a[MONTH] = date.getUTCMonth(); - config._a[DATE] = date.getUTCDate(); - } + deprecations = {}, - // Default to current date. - // * if no year, month, day of month are given, default to today - // * if day of month is given, default month and year - // * if month is given, default only year - // * if year is given, don't default anything - for (i = 0; i < 3 && config._a[i] == null; ++i) { - config._a[i] = input[i] = currentDate[i]; - } + lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin'], - // Zero out whatever was not defaulted, including time - for (; i < 7; i++) { - config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; - } + updateInProgress = false; - // Check for 24:00:00.000 - if (config._a[HOUR] === 24 && - config._a[MINUTE] === 0 && - config._a[SECOND] === 0 && - config._a[MILLISECOND] === 0) { - config._nextDay = true; - config._a[HOUR] = 0; + // Pick the first defined of two or three arguments. dfl comes from + // default. + function dfl(a, b, c) { + 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'); } + } - config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input); - // Apply timezone offset from input. The actual utcOffset can be changed - // with parseZone. - if (config._tzm != null) { - config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); - } + function hasOwnProp(a, b) { + return hasOwnProperty.call(a, b); + } - if (config._nextDay) { - config._a[HOUR] = 24; + function defaultParsingFlags() { + // We need to deep clone this object, and es5 standard is not very + // helpful. + return { + empty : false, + unusedTokens : [], + unusedInput : [], + overflow : -2, + charsLeftOver : 0, + nullInput : false, + invalidMonth : null, + invalidFormat : false, + userInvalidated : false, + iso: false + }; + } + + function printMsg(msg) { + if (moment.suppressDeprecationWarnings === false && + typeof console !== 'undefined' && console.warn) { + console.warn('Deprecation warning: ' + msg); } } - function dateFromObject(config) { - var normalizedInput; + function deprecate(msg, fn) { + var firstTime = true; + return extend(function () { + if (firstTime) { + printMsg(msg); + firstTime = false; + } + return fn.apply(this, arguments); + }, fn); + } - if (config._d) { - return; + function deprecateSimple(name, msg) { + if (!deprecations[name]) { + printMsg(msg); + deprecations[name] = true; } + } - normalizedInput = normalizeObjectUnits(config._i); - config._a = [ - normalizedInput.year, - normalizedInput.month, - normalizedInput.day || normalizedInput.date, - normalizedInput.hour, - normalizedInput.minute, - normalizedInput.second, - normalizedInput.millisecond - ]; - - dateFromConfig(config); + function padToken(func, count) { + return function (a) { + return leftZeroFill(func.call(this, a), count); + }; + } + function ordinalizeToken(func, period) { + return function (a) { + return this.localeData().ordinal(func.call(this, a), period); + }; } - function currentDateArray(config) { - var now = new Date(); - if (config._useUTC) { - return [ - now.getUTCFullYear(), - now.getUTCMonth(), - now.getUTCDate() - ]; + function monthDiff(a, b) { + // difference in months + var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()), + // b is in (anchor - 1 month, anchor + 1 month) + anchor = a.clone().add(wholeMonthDiff, 'months'), + anchor2, adjust; + + if (b - anchor < 0) { + anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor - anchor2); } else { - return [now.getFullYear(), now.getMonth(), now.getDate()]; + anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor2 - anchor); } - } - // date from string and format string - function makeDateFromStringAndFormat(config) { - if (config._f === moment.ISO_8601) { - parseISO(config); - return; - } + return -(wholeMonthDiff + adjust); + } - config._a = []; - config._pf.empty = true; + while (ordinalizeTokens.length) { + i = ordinalizeTokens.pop(); + formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i); + } + while (paddedTokens.length) { + i = paddedTokens.pop(); + formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); + } + formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); - // This array is used to make a Date, either with `new Date` or `Date.UTC` - var string = '' + config._i, - i, parsedInput, tokens, token, skipped, - stringLength = string.length, - totalParsedInputLength = 0; - tokens = expandFormat(config._f, config._locale).match(formattingTokens) || []; + function meridiemFixWrap(locale, hour, meridiem) { + var isPm; - for (i = 0; i < tokens.length; i++) { - token = tokens[i]; - parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; - if (parsedInput) { - skipped = string.substr(0, string.indexOf(parsedInput)); - if (skipped.length > 0) { - config._pf.unusedInput.push(skipped); - } - string = string.slice(string.indexOf(parsedInput) + parsedInput.length); - totalParsedInputLength += parsedInput.length; - } - // don't parse if it's not a known token - if (formatTokenFunctions[token]) { - if (parsedInput) { - config._pf.empty = false; - } - else { - config._pf.unusedTokens.push(token); - } - addTimeToArrayFromToken(token, parsedInput, config); + if (meridiem == null) { + // nothing to do + return hour; + } + if (locale.meridiemHour != null) { + return locale.meridiemHour(hour, meridiem); + } else if (locale.isPM != null) { + // Fallback + isPm = locale.isPM(meridiem); + if (isPm && hour < 12) { + hour += 12; } - else if (config._strict && !parsedInput) { - config._pf.unusedTokens.push(token); + if (!isPm && hour === 12) { + hour = 0; } + return hour; + } else { + // thie is not supposed to happen + return hour; + } + } + + /************************************ + Constructors + ************************************/ + + function Locale() { + } + + // Moment prototype object + function Moment(config, skipOverflow) { + if (skipOverflow !== false) { + checkOverflow(config); + } + copyConfig(this, config); + this._d = new Date(+config._d); + // Prevent infinite loop in case updateOffset creates new moment + // objects. + if (updateInProgress === false) { + updateInProgress = true; + moment.updateOffset(this); + updateInProgress = false; } + } + + // Duration Constructor + function Duration(duration) { + var normalizedInput = normalizeObjectUnits(duration), + years = normalizedInput.year || 0, + quarters = normalizedInput.quarter || 0, + months = normalizedInput.month || 0, + weeks = normalizedInput.week || 0, + days = normalizedInput.day || 0, + hours = normalizedInput.hour || 0, + minutes = normalizedInput.minute || 0, + seconds = normalizedInput.second || 0, + milliseconds = normalizedInput.millisecond || 0; - // add remaining unparsed input length to the string - config._pf.charsLeftOver = stringLength - totalParsedInputLength; - if (string.length > 0) { - config._pf.unusedInput.push(string); - } + // representation for dateAddRemove + this._milliseconds = +milliseconds + + seconds * 1e3 + // 1000 + minutes * 6e4 + // 1000 * 60 + hours * 36e5; // 1000 * 60 * 60 + // Because of dateAddRemove treats 24 hours as different from a + // day when working around DST, we need to store them separately + this._days = +days + + weeks * 7; + // It is impossible translate months into days without knowing + // which months you are are talking about, so we have to store + // it separately. + this._months = +months + + quarters * 3 + + years * 12; - // clear _12h flag if hour is <= 12 - if (config._pf.bigHour === true && config._a[HOUR] <= 12) { - config._pf.bigHour = undefined; - } - // handle meridiem - config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], - config._meridiem); - dateFromConfig(config); - checkOverflow(config); - } + this._data = {}; - function unescapeFormat(s) { - return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { - return p1 || p2 || p3 || p4; - }); - } + this._locale = moment.localeData(); - // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript - function regexpEscape(s) { - return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + this._bubble(); } - // date from string and array of format strings - function makeDateFromStringAndArray(config) { - var tempConfig, - bestMoment, + /************************************ + Helpers + ************************************/ - scoreToBeat, - i, - currentScore; - if (config._f.length === 0) { - config._pf.invalidFormat = true; - config._d = new Date(NaN); - return; + function extend(a, b) { + for (var i in b) { + if (hasOwnProp(b, i)) { + a[i] = b[i]; + } } - for (i = 0; i < config._f.length; i++) { - currentScore = 0; - tempConfig = copyConfig({}, config); - if (config._useUTC != null) { - tempConfig._useUTC = config._useUTC; - } - tempConfig._pf = defaultParsingFlags(); - tempConfig._f = config._f[i]; - makeDateFromStringAndFormat(tempConfig); + if (hasOwnProp(b, 'toString')) { + a.toString = b.toString; + } - if (!isValid(tempConfig)) { - continue; - } + if (hasOwnProp(b, 'valueOf')) { + a.valueOf = b.valueOf; + } - // if there is any input that was not parsed add a penalty for that format - currentScore += tempConfig._pf.charsLeftOver; + return a; + } - //or tokens - currentScore += tempConfig._pf.unusedTokens.length * 10; + function copyConfig(to, from) { + var i, prop, val; - tempConfig._pf.score = currentScore; + 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 (scoreToBeat == null || currentScore < scoreToBeat) { - scoreToBeat = currentScore; - bestMoment = tempConfig; + if (momentProperties.length > 0) { + for (i in momentProperties) { + prop = momentProperties[i]; + val = from[prop]; + if (typeof val !== 'undefined') { + to[prop] = val; + } } } - extend(config, bestMoment || tempConfig); + return to; } - // date from iso format - function parseISO(config) { - var i, l, - string = config._i, - match = isoRegex.exec(string); - - if (match) { - config._pf.iso = true; - for (i = 0, l = isoDates.length; i < l; i++) { - if (isoDates[i][1].exec(string)) { - // match[5] should be 'T' or undefined - config._f = isoDates[i][0] + (match[6] || ' '); - break; - } - } - for (i = 0, l = isoTimes.length; i < l; i++) { - if (isoTimes[i][1].exec(string)) { - config._f += isoTimes[i][0]; - break; - } - } - if (string.match(parseTokenTimezone)) { - config._f += 'Z'; - } - makeDateFromStringAndFormat(config); + function absRound(number) { + if (number < 0) { + return Math.ceil(number); } else { - config._isValid = false; + return Math.floor(number); } } - // date from iso format or fallback - function makeDateFromString(config) { - parseISO(config); - if (config._isValid === false) { - delete config._isValid; - moment.createFromInputFallback(config); + // left zero fill a number + // see http://jsperf.com/left-zero-filling for performance comparison + function leftZeroFill(number, targetLength, forceSign) { + var output = '' + Math.abs(number), + sign = number >= 0; + + while (output.length < targetLength) { + output = '0' + output; } + return (sign ? (forceSign ? '+' : '') : '-') + output; } - function map(arr, fn) { - var res = [], i; - for (i = 0; i < arr.length; ++i) { - res.push(fn(arr[i], i)); + 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 makeDateFromInput(config) { - var input = config._i, matched; - if (input === undefined) { - config._d = new Date(); - } 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 = map(input.slice(0), function (obj) { - return parseInt(obj, 10); - }); - dateFromConfig(config); - } else if (typeof(input) === 'object') { - dateFromObject(config); - } else if (typeof(input) === 'number') { - // from milliseconds - config._d = new Date(input); + function momentsDifference(base, other) { + var res; + other = makeAs(other, base); + if (base.isBefore(other)) { + res = positiveMomentsDifference(base, other); } else { - moment.createFromInputFallback(config); + res = positiveMomentsDifference(other, base); + res.milliseconds = -res.milliseconds; + res.months = -res.months; } + + return res; } - function makeDate(y, m, d, h, M, s, ms) { - //can't just apply() to create a date: - //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply - var date = new Date(y, m, d, h, M, s, ms); + // 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; + } - //the date constructor doesn't accept years < 1970 - if (y < 1970) { - date.setFullYear(y); - } - return date; + val = typeof val === 'string' ? +val : val; + dur = moment.duration(val, period); + addOrSubtractDurationFromMoment(this, dur, direction); + return this; + }; } - function makeUTCDate(y) { - var date = new Date(Date.UTC.apply(null, arguments)); - if (y < 1970) { - date.setUTCFullYear(y); - } - return date; - } + function addOrSubtractDurationFromMoment(mom, duration, isAdding, updateOffset) { + var milliseconds = duration._milliseconds, + days = duration._days, + months = duration._months; + updateOffset = updateOffset == null ? true : updateOffset; - function parseWeekday(input, locale) { - if (typeof input === 'string') { - if (!isNaN(input)) { - input = parseInt(input, 10); - } - else { - input = locale.weekdaysParse(input); - if (typeof input !== 'number') { - return null; - } - } + if (milliseconds) { + mom._d.setTime(+mom._d + milliseconds * isAdding); + } + if (days) { + rawSetter(mom, 'Date', rawGetter(mom, 'Date') + days * isAdding); + } + if (months) { + rawMonthSetter(mom, rawGetter(mom, 'Month') + months * isAdding); + } + if (updateOffset) { + moment.updateOffset(mom, days || months); } - return input; } - /************************************ - Relative Time - ************************************/ - - - // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize - function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { - return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); + // check if is an array + function isArray(input) { + return Object.prototype.toString.call(input) === '[object Array]'; } - 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.d && ['dd', days] || - months === 1 && ['M'] || - months < relativeTimeThresholds.M && ['MM', months] || - years === 1 && ['y'] || ['yy', years]; + function isDate(input) { + return Object.prototype.toString.call(input) === '[object Date]' || + input instanceof Date; + } - args[2] = withoutSuffix; - args[3] = +posNegDuration > 0; - args[4] = locale; - return substituteTimeAgo.apply({}, args); + // compare two arrays, return the number of differences + function compareArrays(array1, array2, dontConvert) { + var len = Math.min(array1.length, array2.length), + lengthDiff = Math.abs(array1.length - array2.length), + diffs = 0, + i; + for (i = 0; i < len; i++) { + if ((dontConvert && array1[i] !== array2[i]) || + (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { + diffs++; + } + } + return diffs + lengthDiff; } + function normalizeUnits(units) { + if (units) { + var lowered = units.toLowerCase().replace(/(.)s$/, '$1'); + units = unitAliases[units] || camelFunctions[lowered] || lowered; + } + return units; + } - /************************************ - Week of Year - ************************************/ + function normalizeObjectUnits(inputObject) { + var normalizedInput = {}, + normalizedProp, + prop; + for (prop in inputObject) { + if (hasOwnProp(inputObject, prop)) { + normalizedProp = normalizeUnits(prop); + if (normalizedProp) { + normalizedInput[normalizedProp] = inputObject[prop]; + } + } + } - // firstDayOfWeek 0 = sun, 6 = sat - // the day of the week that starts the week - // (usually sunday or monday) - // firstDayOfWeekOfYear 0 = sun, 6 = sat - // the first week is the week that contains the first - // of this day of the week - // (eg. ISO weeks use thursday (4)) - function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { - var end = firstDayOfWeekOfYear - firstDayOfWeek, - daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), - adjustedMoment; + return normalizedInput; + } + function makeList(field) { + var count, setter; - if (daysToDayOfWeek > end) { - daysToDayOfWeek -= 7; + if (field.indexOf('week') === 0) { + count = 7; + setter = 'day'; } - - if (daysToDayOfWeek < end - 7) { - daysToDayOfWeek += 7; + else if (field.indexOf('month') === 0) { + count = 12; + setter = 'month'; + } + else { + return; } - adjustedMoment = moment(mom).add(daysToDayOfWeek, 'd'); - return { - week: Math.ceil(adjustedMoment.dayOfYear() / 7), - year: adjustedMoment.year() - }; - } + moment[field] = function (format, index) { + var i, getter, + method = moment._locale[field], + results = []; - //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday - function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { - var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear; + if (typeof format === 'number') { + index = format; + format = undefined; + } - d = d === 0 ? 7 : d; - weekday = weekday != null ? weekday : firstDayOfWeek; - daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0); - dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; + getter = function (i) { + var m = moment().utc().set(setter, i); + return method.call(moment._locale, m, format || ''); + }; - return { - year: dayOfYear > 0 ? year : year - 1, - dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear + if (index != null) { + return getter(index); + } + else { + for (i = 0; i < count; i++) { + results.push(getter(i)); + } + return results; + } }; } - /************************************ - Top Level Functions - ************************************/ - - function makeMoment(config) { - var input = config._i, - format = config._f, - res; - - 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 = config._locale.preparse(input); - } + function toInt(argumentForCoercion) { + var coercedNumber = +argumentForCoercion, + value = 0; - if (moment.isMoment(input)) { - return new Moment(input, true); - } else if (format) { - if (isArray(format)) { - makeDateFromStringAndArray(config); + if (coercedNumber !== 0 && isFinite(coercedNumber)) { + if (coercedNumber >= 0) { + value = Math.floor(coercedNumber); } else { - makeDateFromStringAndFormat(config); + value = Math.ceil(coercedNumber); } - } else { - makeDateFromInput(config); - } - - res = new Moment(config); - if (res._nextDay) { - // Adding is smart enough around DST - res.add(1, 'd'); - res._nextDay = undefined; } - return res; + return value; } - moment = function (input, format, locale, strict) { - var c; + function daysInMonth(year, month) { + return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); + } - if (typeof(locale) === 'boolean') { - strict = locale; - locale = undefined; - } - // object construction must be done this way. - // https://github.com/moment/moment/issues/1423 - c = {}; - c._isAMomentObject = true; - c._i = input; - c._f = format; - c._l = locale; - c._strict = strict; - c._isUTC = false; - c._pf = defaultParsingFlags(); + function weeksInYear(year, dow, doy) { + return weekOfYear(moment([year, 11, 31 + dow - doy]), dow, doy).week; + } - return makeMoment(c); - }; + function daysInYear(year) { + return isLeapYear(year) ? 366 : 365; + } - moment.suppressDeprecationWarnings = false; + function isLeapYear(year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; + } - 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 + (config._useUTC ? ' UTC' : '')); - } - ); + function checkOverflow(m) { + var overflow; + if (m._a && m._pf.overflow === -2) { + overflow = + m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH : + m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE : + m._a[HOUR] < 0 || m._a[HOUR] > 24 || + (m._a[HOUR] === 24 && (m._a[MINUTE] !== 0 || + m._a[SECOND] !== 0 || + m._a[MILLISECOND] !== 0)) ? HOUR : + m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE : + m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND : + m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND : + -1; - // 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. - // - // moments should either be an array of moment objects or an array, whose - // first element is an array of moment objects. - function pickBy(fn, moments) { - var res, i; - if (moments.length === 1 && isArray(moments[0])) { - moments = moments[0]; - } - if (!moments.length) { - return moment(); - } - res = moments[0]; - for (i = 1; i < moments.length; ++i) { - if (moments[i][fn](res)) { - res = moments[i]; + if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { + overflow = DATE; } + + m._pf.overflow = overflow; } - return res; } - moment.min = function () { - var args = [].slice.call(arguments, 0); - - return pickBy('isBefore', args); - }; + function isValid(m) { + if (m._isValid == null) { + m._isValid = !isNaN(m._d.getTime()) && + m._pf.overflow < 0 && + !m._pf.empty && + !m._pf.invalidMonth && + !m._pf.nullInput && + !m._pf.invalidFormat && + !m._pf.userInvalidated; - moment.max = function () { - var args = [].slice.call(arguments, 0); + if (m._strict) { + m._isValid = m._isValid && + m._pf.charsLeftOver === 0 && + m._pf.unusedTokens.length === 0 && + m._pf.bigHour === undefined; + } + } + return m._isValid; + } - return pickBy('isAfter', args); - }; + function normalizeLocale(key) { + return key ? key.toLowerCase().replace('_', '-') : key; + } - // creating with utc - moment.utc = function (input, format, locale, strict) { - var c; + // 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; - if (typeof(locale) === 'boolean') { - strict = locale; - locale = undefined; + 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++; } - // object construction must be done this way. - // https://github.com/moment/moment/issues/1423 - c = {}; - c._isAMomentObject = true; - c._useUTC = true; - c._isUTC = true; - c._l = locale; - c._i = input; - c._f = format; - c._strict = strict; - c._pf = defaultParsingFlags(); + return null; + } - return makeMoment(c).utc(); - }; + 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]; + } - // creating with unix timestamp (in seconds) - moment.unix = function (input) { - return moment(input * 1000); - }; + // Return a moment from input, that is local/utc/utcOffset equivalent to + // model. + function makeAs(input, model) { + var res, diff; + if (model._isUTC) { + res = model.clone(); + diff = (moment.isMoment(input) || isDate(input) ? + +input : +moment(input)) - (+res); + // Use low-level api, because this fn is low-level api. + res._d.setTime(+res._d + diff); + moment.updateOffset(res, false); + return res; + } else { + return moment(input).local(); + } + } - // duration - moment.duration = function (input, key) { - var duration = input, - // matching against regexp is expensive, do it on demand - match = null, - sign, - ret, - parseIso, - diffRes; + /************************************ + Locale + ************************************/ - if (moment.isDuration(input)) { - duration = { - ms: input._milliseconds, - d: input._days, - M: input._months - }; - } else if (typeof input === 'number') { - duration = {}; - if (key) { - duration[key] = input; - } else { - duration.milliseconds = input; - } - } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) { - sign = (match[1] === '-') ? -1 : 1; - duration = { - y: 0, - d: toInt(match[DATE]) * sign, - h: toInt(match[HOUR]) * sign, - m: toInt(match[MINUTE]) * sign, - s: toInt(match[SECOND]) * sign, - ms: toInt(match[MILLISECOND]) * sign - }; - } else if (!!(match = isoDurationRegex.exec(input))) { - sign = (match[1] === '-') ? -1 : 1; - parseIso = function (inp) { - // We'd normally use ~~inp for this, but unfortunately it also - // converts floats to ints. - // inp may be undefined, so careful calling replace on it. - var res = inp && parseFloat(inp.replace(',', '.')); - // apply sign while we're at it - return (isNaN(res) ? 0 : res) * sign; - }; - duration = { - y: parseIso(match[2]), - M: parseIso(match[3]), - d: parseIso(match[4]), - h: parseIso(match[5]), - m: parseIso(match[6]), - s: parseIso(match[7]), - w: parseIso(match[8]) - }; - } else if (duration == null) {// checks for null or undefined - duration = {}; - } 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; - } + extend(Locale.prototype, { - ret = new Duration(duration); + set : function (config) { + var prop, i; + for (i in config) { + prop = config[i]; + if (typeof prop === 'function') { + this[i] = prop; + } else { + this['_' + i] = prop; + } + } + // Lenient ordinal parsing accepts just a number in addition to + // number + (possibly) stuff coming from _ordinalParseLenient. + this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + /\d{1,2}/.source); + }, - if (moment.isDuration(input) && hasOwnProp(input, '_locale')) { - ret._locale = input._locale; - } + _months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), + months : function (m) { + return this._months[m.month()]; + }, - return ret; - }; + _monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), + monthsShort : function (m) { + return this._monthsShort[m.month()]; + }, - // version number - moment.version = VERSION; + monthsParse : function (monthName, format, strict) { + var i, mom, regex; - // default format - moment.defaultFormat = isoFormat; + if (!this._monthsParse) { + this._monthsParse = []; + this._longMonthsParse = []; + this._shortMonthsParse = []; + } - // constant that refers to the ISO standard - moment.ISO_8601 = function () {}; + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + mom = moment.utc([2000, i]); + if (strict && !this._longMonthsParse[i]) { + this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i'); + this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i'); + } + if (!strict && !this._monthsParse[i]) { + regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); + this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) { + return i; + } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) { + return i; + } else if (!strict && this._monthsParse[i].test(monthName)) { + return i; + } + } + }, - // Plugins that add properties should also add the key here (null value), - // so we can properly clone ourselves. - moment.momentProperties = momentProperties; + _weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), + weekdays : function (m) { + return this._weekdays[m.day()]; + }, - // This function will be called whenever a moment is mutated. - // It is intended to keep the offset in sync with the timezone. - moment.updateOffset = function () {}; + _weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), + weekdaysShort : function (m) { + return this._weekdaysShort[m.day()]; + }, - // This function allows you to set a threshold for relative time strings - moment.relativeTimeThreshold = function (threshold, limit) { - if (relativeTimeThresholds[threshold] === undefined) { - return false; - } - if (limit === undefined) { - return relativeTimeThresholds[threshold]; - } - relativeTimeThresholds[threshold] = limit; - return true; - }; + _weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), + weekdaysMin : function (m) { + return this._weekdaysMin[m.day()]; + }, - moment.lang = deprecate( - 'moment.lang is deprecated. Use moment.locale instead.', - function (key, value) { - return moment.locale(key, value); - } - ); + weekdaysParse : function (weekdayName) { + var i, mom, regex; - // This function will load locale and then set the global locale. If - // no arguments are passed in, it will simply return the current global - // locale key. - moment.locale = function (key, values) { - var data; - if (key) { - if (typeof(values) !== 'undefined') { - data = moment.defineLocale(key, values); + if (!this._weekdaysParse) { + this._weekdaysParse = []; } - else { - data = moment.localeData(key); + + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + if (!this._weekdaysParse[i]) { + mom = moment([2000, 1]).day(i); + regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); + this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (this._weekdaysParse[i].test(weekdayName)) { + return i; + } } + }, - if (data) { - moment.duration._locale = moment._locale = data; + _longDateFormat : { + LTS : 'h:mm:ss A', + 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]; + if (!output && this._longDateFormat[key.toUpperCase()]) { + output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { + return val.slice(1); + }); + this._longDateFormat[key] = output; } - } + return output; + }, - return moment._locale._abbr; - }; + isPM : function (input) { + // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays + // Using charAt should be more compatible. + return ((input + '').toLowerCase().charAt(0) === 'p'); + }, - moment.defineLocale = function (name, values) { - if (values !== null) { - values.abbr = name; - if (!locales[name]) { - locales[name] = new Locale(); + _meridiemParse : /[ap]\.?m?\.?/i, + meridiem : function (hours, minutes, isLower) { + if (hours > 11) { + return isLower ? 'pm' : 'PM'; + } else { + return isLower ? 'am' : 'AM'; } - 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; - } - }; + _calendar : { + sameDay : '[Today at] LT', + nextDay : '[Tomorrow at] LT', + nextWeek : 'dddd [at] LT', + lastDay : '[Yesterday at] LT', + lastWeek : '[Last] dddd [at] LT', + sameElse : 'L' + }, + calendar : function (key, mom, now) { + var output = this._calendar[key]; + return typeof output === 'function' ? output.apply(mom, [now]) : output; + }, - moment.langData = deprecate( - 'moment.langData is deprecated. Use moment.localeData instead.', - function (key) { - return moment.localeData(key); - } - ); + _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' + }, - // returns locale data - moment.localeData = function (key) { - var locale; + 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); + }, - if (key && key._locale && key._locale._abbr) { - key = key._locale._abbr; - } + pastFuture : function (diff, output) { + var format = this._relativeTime[diff > 0 ? 'future' : 'past']; + return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); + }, - if (!key) { - return moment._locale; - } + ordinal : function (number) { + return this._ordinal.replace('%d', number); + }, + _ordinal : '%d', + _ordinalParse : /\d{1,2}/, - if (!isArray(key)) { - //short-circuit everything else - locale = loadLocale(key); - if (locale) { - return locale; - } - key = [key]; - } + preparse : function (string) { + return string; + }, - return chooseLocale(key); - }; + postformat : function (string) { + return string; + }, - // compare moment object - moment.isMoment = function (obj) { - return obj instanceof Moment || - (obj != null && hasOwnProp(obj, '_isAMomentObject')); - }; + week : function (mom) { + return weekOfYear(mom, this._week.dow, this._week.doy).week; + }, - // for typechecking Duration objects - moment.isDuration = function (obj) { - return obj instanceof Duration; - }; + _week : { + dow : 0, // Sunday is the first day of the week. + doy : 6 // The week that contains Jan 1st is the first week of the year. + }, - for (i = lists.length - 1; i >= 0; --i) { - makeList(lists[i]); - } + firstDayOfWeek : function () { + return this._week.dow; + }, - moment.normalizeUnits = function (units) { - return normalizeUnits(units); - }; + firstDayOfYear : function () { + return this._week.doy; + }, - moment.invalid = function (flags) { - var m = moment.utc(NaN); - if (flags != null) { - extend(m._pf, flags); - } - else { - m._pf.userInvalidated = true; + _invalidDate: 'Invalid date', + invalidDate: function () { + return this._invalidDate; } + }); - return m; - }; + /************************************ + Formatting + ************************************/ - moment.parseZone = function () { - return moment.apply(null, arguments).parseZone(); - }; - moment.parseTwoDigitYear = function (input) { - return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); - }; + function removeFormattingTokens(input) { + if (input.match(/\[[\s\S]/)) { + return input.replace(/^\[|\]$/g, ''); + } + return input.replace(/\\/g, ''); + } - moment.isDate = isDate; + function makeFormatFunction(format) { + var array = format.match(formattingTokens), i, length; + + for (i = 0, length = array.length; i < length; i++) { + if (formatTokenFunctions[array[i]]) { + array[i] = formatTokenFunctions[array[i]]; + } else { + array[i] = removeFormattingTokens(array[i]); + } + } + + return function (mom) { + var output = ''; + for (i = 0; i < length; i++) { + output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; + } + return output; + }; + } - /************************************ - Moment Prototype - ************************************/ + // format date using native date object + function formatMoment(m, format) { + if (!m.isValid()) { + return m.localeData().invalidDate(); + } + format = expandFormat(format, m.localeData()); - extend(moment.fn = Moment.prototype, { + if (!formatFunctions[format]) { + formatFunctions[format] = makeFormatFunction(format); + } - clone : function () { - return moment(this); - }, + return formatFunctions[format](m); + } - valueOf : function () { - return +this._d - ((this._offset || 0) * 60000); - }, + function expandFormat(format, locale) { + var i = 5; - unix : function () { - return Math.floor(+this / 1000); - }, + function replaceLongDateFormatTokens(input) { + return locale.longDateFormat(input) || input; + } - toString : function () { - return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); - }, + localFormattingTokens.lastIndex = 0; + while (i >= 0 && localFormattingTokens.test(format)) { + format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); + localFormattingTokens.lastIndex = 0; + i -= 1; + } - toDate : function () { - return this._offset ? new Date(+this) : this._d; - }, + return format; + } - toISOString : function () { - var m = moment(this).utc(); - if (0 < m.year() && m.year() <= 9999) { - if ('function' === typeof Date.prototype.toISOString) { - // native implementation is ~50x faster, use it when we can - return this.toDate().toISOString(); - } else { - return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); - } - } else { - return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); - } - }, - toArray : function () { - var m = this; - return [ - m.year(), - m.month(), - m.date(), - m.hours(), - m.minutes(), - m.seconds(), - m.milliseconds() - ]; - }, + /************************************ + Parsing + ************************************/ - isValid : function () { - return isValid(this); - }, - isDSTShifted : function () { - if (this._a) { - return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0; + // get the regex to find the next token + function getParseRegexForToken(token, config) { + var a, strict = config._strict; + switch (token) { + case 'Q': + return parseTokenOneDigit; + case 'DDDD': + return parseTokenThreeDigits; + case 'YYYY': + case 'GGGG': + case 'gggg': + return strict ? parseTokenFourDigits : parseTokenOneToFourDigits; + case 'Y': + case 'G': + case 'g': + return parseTokenSignedNumber; + case 'YYYYYY': + case 'YYYYY': + case 'GGGGG': + case 'ggggg': + return strict ? parseTokenSixDigits : parseTokenOneToSixDigits; + case 'S': + if (strict) { + return parseTokenOneDigit; } + /* falls through */ + case 'SS': + if (strict) { + return parseTokenTwoDigits; + } + /* falls through */ + case 'SSS': + if (strict) { + return parseTokenThreeDigits; + } + /* falls through */ + case 'DDD': + return parseTokenOneToThreeDigits; + case 'MMM': + case 'MMMM': + case 'dd': + case 'ddd': + case 'dddd': + return parseTokenWord; + case 'a': + case 'A': + return config._locale._meridiemParse; + case 'x': + return parseTokenOffsetMs; + case 'X': + return parseTokenTimestampMs; + case 'Z': + case 'ZZ': + return parseTokenTimezone; + case 'T': + return parseTokenT; + case 'SSSS': + return parseTokenDigits; + case 'MM': + case 'DD': + case 'YY': + case 'GG': + case 'gg': + case 'HH': + case 'hh': + case 'mm': + case 'ss': + case 'ww': + case 'WW': + return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits; + case 'M': + case 'D': + case 'd': + case 'H': + case 'h': + case 'm': + case 's': + case 'w': + case 'W': + case 'e': + case 'E': + return parseTokenOneOrTwoDigits; + case 'Do': + return strict ? config._locale._ordinalParse : config._locale._ordinalParseLenient; + default : + a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), 'i')); + return a; + } + } - return false; - }, - - parsingFlags : function () { - return extend({}, this._pf); - }, - - invalidAt: function () { - return this._pf.overflow; - }, + function utcOffsetFromString(string) { + string = string || ''; + var possibleTzMatches = (string.match(parseTokenTimezone) || []), + tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [], + parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0], + minutes = +(parts[1] * 60) + toInt(parts[2]); - utc : function (keepLocalTime) { - return this.utcOffset(0, keepLocalTime); - }, + return parts[0] === '+' ? minutes : -minutes; + } - local : function (keepLocalTime) { - if (this._isUTC) { - this.utcOffset(0, keepLocalTime); - this._isUTC = false; + // function to convert string input to date + function addTimeToArrayFromToken(token, input, config) { + var a, datePartArray = config._a; - if (keepLocalTime) { - this.subtract(this._dateUtcOffset(), 'm'); - } + switch (token) { + // QUARTER + case 'Q': + if (input != null) { + datePartArray[MONTH] = (toInt(input) - 1) * 3; + } + break; + // MONTH + case 'M' : // fall through to MM + case 'MM' : + if (input != null) { + datePartArray[MONTH] = toInt(input) - 1; + } + break; + case 'MMM' : // fall through to MMMM + case 'MMMM' : + a = config._locale.monthsParse(input, token, config._strict); + // if we didn't find a month name, mark the date as invalid. + if (a != null) { + datePartArray[MONTH] = a; + } else { + config._pf.invalidMonth = input; + } + break; + // DAY OF MONTH + case 'D' : // fall through to DD + case 'DD' : + if (input != null) { + datePartArray[DATE] = toInt(input); + } + break; + case 'Do' : + if (input != null) { + datePartArray[DATE] = toInt(parseInt( + input.match(/\d{1,2}/)[0], 10)); + } + break; + // DAY OF YEAR + case 'DDD' : // fall through to DDDD + case 'DDDD' : + if (input != null) { + config._dayOfYear = toInt(input); } - return this; - }, - format : function (inputString) { - var output = formatMoment(this, inputString || moment.defaultFormat); - return this.localeData().postformat(output); - }, + break; + // YEAR + case 'YY' : + datePartArray[YEAR] = moment.parseTwoDigitYear(input); + break; + case 'YYYY' : + case 'YYYYY' : + case 'YYYYYY' : + datePartArray[YEAR] = toInt(input); + break; + // AM / PM + case 'a' : // fall through to A + case 'A' : + config._meridiem = input; + // config._isPm = config._locale.isPM(input); + break; + // HOUR + case 'h' : // fall through to hh + case 'hh' : + config._pf.bigHour = true; + /* falls through */ + case 'H' : // fall through to HH + case 'HH' : + datePartArray[HOUR] = toInt(input); + break; + // MINUTE + case 'm' : // fall through to mm + case 'mm' : + datePartArray[MINUTE] = toInt(input); + break; + // SECOND + case 's' : // fall through to ss + case 'ss' : + datePartArray[SECOND] = toInt(input); + break; + // MILLISECOND + case 'S' : + case 'SS' : + case 'SSS' : + case 'SSSS' : + datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000); + break; + // UNIX OFFSET (MILLISECONDS) + case 'x': + config._d = new Date(toInt(input)); + break; + // UNIX TIMESTAMP WITH MS + case 'X': + config._d = new Date(parseFloat(input) * 1000); + break; + // TIMEZONE + case 'Z' : // fall through to ZZ + case 'ZZ' : + config._useUTC = true; + config._tzm = utcOffsetFromString(input); + break; + // WEEKDAY - human + case 'dd': + case 'ddd': + case 'dddd': + 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 || {}; + config._w['d'] = a; + } else { + config._pf.invalidWeekday = input; + } + break; + // WEEK, WEEK DAY - numeric + case 'w': + case 'ww': + case 'W': + case 'WW': + case 'd': + case 'e': + case 'E': + token = token.substr(0, 1); + /* falls through */ + case 'gggg': + case 'GGGG': + case 'GGGGG': + token = token.substr(0, 2); + if (input) { + config._w = config._w || {}; + config._w[token] = toInt(input); + } + break; + case 'gg': + case 'GG': + config._w = config._w || {}; + config._w[token] = moment.parseTwoDigitYear(input); + } + } - add : createAdder(1, 'add'), + function dayOfYearFromWeekInfo(config) { + var w, weekYear, week, weekday, dow, doy, temp; - subtract : createAdder(-1, 'subtract'), + w = config._w; + if (w.GG != null || w.W != null || w.E != null) { + dow = 1; + doy = 4; - diff : function (input, units, asFloat) { - var that = makeAs(input, this), - zoneDiff = (that.utcOffset() - this.utcOffset()) * 6e4, - anchor, diff, output, daysAdjust; + // TODO: We need to take the current isoWeekYear, but that depends on + // how we interpret now (local, utc, fixed offset). So create + // a now version of current config (take local/utc/offset flags, and + // create now). + weekYear = dfl(w.GG, config._a[YEAR], weekOfYear(moment(), 1, 4).year); + week = dfl(w.W, 1); + weekday = dfl(w.E, 1); + } else { + dow = config._locale._week.dow; + doy = config._locale._week.doy; - units = normalizeUnits(units); + weekYear = dfl(w.gg, config._a[YEAR], weekOfYear(moment(), dow, doy).year); + week = dfl(w.w, 1); - if (units === 'year' || units === 'month' || units === 'quarter') { - output = monthDiff(this, that); - if (units === 'quarter') { - output = output / 3; - } else if (units === 'year') { - output = output / 12; + if (w.d != null) { + // weekday -- low day numbers are considered next week + weekday = w.d; + if (weekday < dow) { + ++week; } + } else if (w.e != null) { + // local weekday -- counting starts from begining of week + weekday = w.e + dow; } else { - diff = this - that; - output = units === 'second' ? diff / 1e3 : // 1000 - units === 'minute' ? diff / 6e4 : // 1000 * 60 - units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 - units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst - units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst - diff; + // default to begining of week + weekday = dow; } - return asFloat ? output : absRound(output); - }, + } + temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow); - from : function (time, withoutSuffix) { - return moment.duration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix); - }, + config._a[YEAR] = temp.year; + config._dayOfYear = temp.dayOfYear; + } - fromNow : function (withoutSuffix) { - return this.from(moment(), withoutSuffix); - }, + // convert an array to a date. + // the array should mirror the parameters below + // note: all values past the year are optional and will default to the lowest possible value. + // [year, month, day , hour, minute, second, millisecond] + function dateFromConfig(config) { + var i, date, input = [], currentDate, yearToUse; - calendar : function (time) { - // We want to compare the start of today, vs this. - // Getting start-of-today depends on whether we're locat/utc/offset - // or not. - var now = time || moment(), - sod = makeAs(now, this).startOf('day'), - diff = this.diff(sod, 'days', true), - format = diff < -6 ? 'sameElse' : - diff < -1 ? 'lastWeek' : - diff < 0 ? 'lastDay' : - diff < 1 ? 'sameDay' : - diff < 2 ? 'nextDay' : - diff < 7 ? 'nextWeek' : 'sameElse'; - return this.format(this.localeData().calendar(format, this, moment(now))); - }, + if (config._d) { + return; + } - isLeapYear : function () { - return isLeapYear(this.year()); - }, + currentDate = currentDateArray(config); - isDST : function () { - return (this.utcOffset() > this.clone().month(0).utcOffset() || - this.utcOffset() > this.clone().month(5).utcOffset()); - }, + //compute day of the year from weeks and weekdays + if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { + dayOfYearFromWeekInfo(config); + } - day : function (input) { - var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); - if (input != null) { - input = parseWeekday(input, this.localeData()); - return this.add(input - day, 'd'); - } else { - return day; + //if the day of the year is set, figure out what it is + if (config._dayOfYear) { + yearToUse = dfl(config._a[YEAR], currentDate[YEAR]); + + if (config._dayOfYear > daysInYear(yearToUse)) { + config._pf._overflowDayOfYear = true; } - }, - month : makeAccessor('Month', true), + date = makeUTCDate(yearToUse, 0, config._dayOfYear); + config._a[MONTH] = date.getUTCMonth(); + config._a[DATE] = date.getUTCDate(); + } - startOf : function (units) { - units = normalizeUnits(units); - // the following switch intentionally omits break keywords - // to utilize falling through the cases. - switch (units) { - case 'year': - this.month(0); - /* falls through */ - case 'quarter': - case 'month': - this.date(1); - /* falls through */ - case 'week': - case 'isoWeek': - case 'day': - this.hours(0); - /* falls through */ - case 'hour': - this.minutes(0); - /* falls through */ - case 'minute': - this.seconds(0); - /* falls through */ - case 'second': - this.milliseconds(0); - /* falls through */ - } + // Default to current date. + // * if no year, month, day of month are given, default to today + // * if day of month is given, default month and year + // * if month is given, default only year + // * if year is given, don't default anything + for (i = 0; i < 3 && config._a[i] == null; ++i) { + config._a[i] = input[i] = currentDate[i]; + } - // weeks are a special case - if (units === 'week') { - this.weekday(0); - } else if (units === 'isoWeek') { - this.isoWeekday(1); - } + // Zero out whatever was not defaulted, including time + for (; i < 7; i++) { + config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; + } - // quarters are also special - if (units === 'quarter') { - this.month(Math.floor(this.month() / 3) * 3); - } + // Check for 24:00:00.000 + if (config._a[HOUR] === 24 && + config._a[MINUTE] === 0 && + config._a[SECOND] === 0 && + config._a[MILLISECOND] === 0) { + config._nextDay = true; + config._a[HOUR] = 0; + } - return this; - }, + config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input); + // Apply timezone offset from input. The actual utcOffset can be changed + // with parseZone. + if (config._tzm != null) { + config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); + } - endOf: function (units) { - units = normalizeUnits(units); - if (units === undefined || units === 'millisecond') { - return this; - } - return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms'); - }, + if (config._nextDay) { + config._a[HOUR] = 24; + } + } - isAfter: function (input, units) { - var inputMs; - units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); - if (units === 'millisecond') { - input = moment.isMoment(input) ? input : moment(input); - return +this > +input; - } else { - inputMs = moment.isMoment(input) ? +input : +moment(input); - return inputMs < +this.clone().startOf(units); - } - }, + function dateFromObject(config) { + var normalizedInput; - isBefore: function (input, units) { - var inputMs; - units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); - if (units === 'millisecond') { - input = moment.isMoment(input) ? input : moment(input); - return +this < +input; - } else { - inputMs = moment.isMoment(input) ? +input : +moment(input); - return +this.clone().endOf(units) < inputMs; - } - }, + if (config._d) { + return; + } - isBetween: function (from, to, units) { - return this.isAfter(from, units) && this.isBefore(to, units); - }, + normalizedInput = normalizeObjectUnits(config._i); + config._a = [ + normalizedInput.year, + normalizedInput.month, + normalizedInput.day || normalizedInput.date, + normalizedInput.hour, + normalizedInput.minute, + normalizedInput.second, + normalizedInput.millisecond + ]; - isSame: function (input, units) { - var inputMs; - units = normalizeUnits(units || 'millisecond'); - if (units === 'millisecond') { - input = moment.isMoment(input) ? input : moment(input); - return +this === +input; - } else { - inputMs = +moment(input); - return +(this.clone().startOf(units)) <= inputMs && inputMs <= +(this.clone().endOf(units)); - } - }, + dateFromConfig(config); + } - min: deprecate( - '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; - } - ), + function currentDateArray(config) { + var now = new Date(); + if (config._useUTC) { + return [ + now.getUTCFullYear(), + now.getUTCMonth(), + now.getUTCDate() + ]; + } else { + return [now.getFullYear(), now.getMonth(), now.getDate()]; + } + } - max: deprecate( - '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; - } - ), + // date from string and format string + function makeDateFromStringAndFormat(config) { + if (config._f === moment.ISO_8601) { + parseISO(config); + return; + } - zone : deprecate( - 'moment().zone is deprecated, use moment().utcOffset instead. ' + - 'https://github.com/moment/moment/issues/1779', - function (input, keepLocalTime) { - if (input != null) { - if (typeof input !== 'string') { - input = -input; - } + config._a = []; + config._pf.empty = true; - this.utcOffset(input, keepLocalTime); + // This array is used to make a Date, either with `new Date` or `Date.UTC` + var string = '' + config._i, + i, parsedInput, tokens, token, skipped, + stringLength = string.length, + totalParsedInputLength = 0; - return this; - } else { - return -this.utcOffset(); - } - } - ), + tokens = expandFormat(config._f, config._locale).match(formattingTokens) || []; - // keepLocalTime = true means only change the timezone, without - // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]--> - // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset - // +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. - utcOffset : function (input, keepLocalTime) { - var offset = this._offset || 0, - localAdjust; - if (input != null) { - if (typeof input === 'string') { - input = utcOffsetFromString(input); - } - if (Math.abs(input) < 16) { - input = input * 60; - } - if (!this._isUTC && keepLocalTime) { - localAdjust = this._dateUtcOffset(); + for (i = 0; i < tokens.length; i++) { + token = tokens[i]; + parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; + if (parsedInput) { + skipped = string.substr(0, string.indexOf(parsedInput)); + if (skipped.length > 0) { + config._pf.unusedInput.push(skipped); } - this._offset = input; - this._isUTC = true; - if (localAdjust != null) { - this.add(localAdjust, 'm'); + string = string.slice(string.indexOf(parsedInput) + parsedInput.length); + totalParsedInputLength += parsedInput.length; + } + // don't parse if it's not a known token + if (formatTokenFunctions[token]) { + if (parsedInput) { + config._pf.empty = false; } - if (offset !== input) { - if (!keepLocalTime || this._changeInProgress) { - addOrSubtractDurationFromMoment(this, - moment.duration(input - offset, 'm'), 1, false); - } else if (!this._changeInProgress) { - this._changeInProgress = true; - moment.updateOffset(this, true); - this._changeInProgress = null; - } + else { + config._pf.unusedTokens.push(token); } - - return this; - } else { - return this._isUTC ? offset : this._dateUtcOffset(); + addTimeToArrayFromToken(token, parsedInput, config); } - }, + else if (config._strict && !parsedInput) { + config._pf.unusedTokens.push(token); + } + } - isLocal : function () { - return !this._isUTC; - }, + // add remaining unparsed input length to the string + config._pf.charsLeftOver = stringLength - totalParsedInputLength; + if (string.length > 0) { + config._pf.unusedInput.push(string); + } - isUtcOffset : function () { - return this._isUTC; - }, + // clear _12h flag if hour is <= 12 + if (config._pf.bigHour === true && config._a[HOUR] <= 12) { + config._pf.bigHour = undefined; + } + // handle meridiem + config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], + config._meridiem); + dateFromConfig(config); + checkOverflow(config); + } - isUtc : function () { - return this._isUTC && this._offset === 0; - }, + function unescapeFormat(s) { + return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { + return p1 || p2 || p3 || p4; + }); + } - zoneAbbr : function () { - return this._isUTC ? 'UTC' : ''; - }, + // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript + function regexpEscape(s) { + return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } - zoneName : function () { - return this._isUTC ? 'Coordinated Universal Time' : ''; - }, + // date from string and array of format strings + function makeDateFromStringAndArray(config) { + var tempConfig, + bestMoment, - parseZone : function () { - if (this._tzm) { - this.utcOffset(this._tzm); - } else if (typeof this._i === 'string') { - this.utcOffset(utcOffsetFromString(this._i)); - } - return this; - }, + scoreToBeat, + i, + currentScore; - hasAlignedHourOffset : function (input) { - if (!input) { - input = 0; + if (config._f.length === 0) { + config._pf.invalidFormat = true; + config._d = new Date(NaN); + return; + } + + for (i = 0; i < config._f.length; i++) { + currentScore = 0; + tempConfig = copyConfig({}, config); + if (config._useUTC != null) { + tempConfig._useUTC = config._useUTC; } - else { - input = moment(input).utcOffset(); + tempConfig._pf = defaultParsingFlags(); + tempConfig._f = config._f[i]; + makeDateFromStringAndFormat(tempConfig); + + if (!isValid(tempConfig)) { + continue; } - return (this.utcOffset() - input) % 60 === 0; - }, + // if there is any input that was not parsed add a penalty for that format + currentScore += tempConfig._pf.charsLeftOver; - daysInMonth : function () { - return daysInMonth(this.year(), this.month()); - }, + //or tokens + currentScore += tempConfig._pf.unusedTokens.length * 10; - dayOfYear : function (input) { - var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; - return input == null ? dayOfYear : this.add((input - dayOfYear), 'd'); - }, + tempConfig._pf.score = currentScore; - quarter : function (input) { - return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3); - }, + if (scoreToBeat == null || currentScore < scoreToBeat) { + scoreToBeat = currentScore; + bestMoment = tempConfig; + } + } - weekYear : function (input) { - var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year; - return input == null ? year : this.add((input - year), 'y'); - }, + extend(config, bestMoment || tempConfig); + } - isoWeekYear : function (input) { - var year = weekOfYear(this, 1, 4).year; - return input == null ? year : this.add((input - year), 'y'); - }, + // date from iso format + function parseISO(config) { + var i, l, + string = config._i, + match = isoRegex.exec(string); - week : function (input) { - var week = this.localeData().week(this); - return input == null ? week : this.add((input - week) * 7, 'd'); - }, + if (match) { + config._pf.iso = true; + for (i = 0, l = isoDates.length; i < l; i++) { + if (isoDates[i][1].exec(string)) { + // match[5] should be 'T' or undefined + config._f = isoDates[i][0] + (match[6] || ' '); + break; + } + } + for (i = 0, l = isoTimes.length; i < l; i++) { + if (isoTimes[i][1].exec(string)) { + config._f += isoTimes[i][0]; + break; + } + } + if (string.match(parseTokenTimezone)) { + config._f += 'Z'; + } + makeDateFromStringAndFormat(config); + } else { + config._isValid = false; + } + } - isoWeek : function (input) { - var week = weekOfYear(this, 1, 4).week; - return input == null ? week : this.add((input - week) * 7, 'd'); - }, + // date from iso format or fallback + function makeDateFromString(config) { + parseISO(config); + if (config._isValid === false) { + delete config._isValid; + moment.createFromInputFallback(config); + } + } - weekday : function (input) { - var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; - return input == null ? weekday : this.add(input - weekday, 'd'); - }, + function map(arr, fn) { + var res = [], i; + for (i = 0; i < arr.length; ++i) { + res.push(fn(arr[i], i)); + } + return res; + } - isoWeekday : function (input) { - // behaves the same as moment#day except - // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) - // as a setter, sunday should belong to the previous week. - return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); - }, + function makeDateFromInput(config) { + var input = config._i, matched; + if (input === undefined) { + config._d = new Date(); + } 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 = map(input.slice(0), function (obj) { + return parseInt(obj, 10); + }); + dateFromConfig(config); + } else if (typeof(input) === 'object') { + dateFromObject(config); + } else if (typeof(input) === 'number') { + // from milliseconds + config._d = new Date(input); + } else { + moment.createFromInputFallback(config); + } + } - isoWeeksInYear : function () { - return weeksInYear(this.year(), 1, 4); - }, + function makeDate(y, m, d, h, M, s, ms) { + //can't just apply() to create a date: + //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply + var date = new Date(y, m, d, h, M, s, ms); - weeksInYear : function () { - var weekInfo = this.localeData()._week; - return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); - }, + //the date constructor doesn't accept years < 1970 + if (y < 1970) { + date.setFullYear(y); + } + return date; + } - get : function (units) { - units = normalizeUnits(units); - return this[units](); - }, + function makeUTCDate(y) { + var date = new Date(Date.UTC.apply(null, arguments)); + if (y < 1970) { + date.setUTCFullYear(y); + } + return date; + } - set : function (units, value) { - var unit; - if (typeof units === 'object') { - for (unit in units) { - this.set(unit, units[unit]); - } + function parseWeekday(input, locale) { + if (typeof input === 'string') { + if (!isNaN(input)) { + input = parseInt(input, 10); } else { - units = normalizeUnits(units); - if (typeof this[units] === 'function') { - this[units](value); + input = locale.weekdaysParse(input); + if (typeof input !== 'number') { + return null; } } - return this; - }, + } + return input; + } - // If passed a locale key, it will set the locale for this - // instance. Otherwise, it will return the locale configuration - // variables for this instance. - locale : function (key) { - var newLocaleData; + /************************************ + Relative Time + ************************************/ - if (key === undefined) { - return this._locale._abbr; - } else { - newLocaleData = moment.localeData(key); - if (newLocaleData != null) { - this._locale = newLocaleData; - } - return this; - } - }, - lang : deprecate( - 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', - function (key) { - if (key === undefined) { - return this.localeData(); - } else { - return this.locale(key); - } - } - ), + // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize + function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { + return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); + } - localeData : function () { - return this._locale; - }, + 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')), - _dateUtcOffset : function () { - // On Firefox.24 Date#getTimezoneOffset returns a floating point. - // https://github.com/moment/moment/pull/1871 - return -Math.round(this._d.getTimezoneOffset() / 15) * 15; - } + 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.d && ['dd', days] || + months === 1 && ['M'] || + months < relativeTimeThresholds.M && ['MM', months] || + years === 1 && ['y'] || ['yy', years]; + + args[2] = withoutSuffix; + args[3] = +posNegDuration > 0; + args[4] = locale; + return substituteTimeAgo.apply({}, args); + } + + + /************************************ + Week of Year + ************************************/ + + + // firstDayOfWeek 0 = sun, 6 = sat + // the day of the week that starts the week + // (usually sunday or monday) + // firstDayOfWeekOfYear 0 = sun, 6 = sat + // the first week is the week that contains the first + // of this day of the week + // (eg. ISO weeks use thursday (4)) + function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { + var end = firstDayOfWeekOfYear - firstDayOfWeek, + daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), + adjustedMoment; - }); - function rawMonthSetter(mom, value) { - var dayOfMonth; + if (daysToDayOfWeek > end) { + daysToDayOfWeek -= 7; + } - // TODO: Move this out of here! - if (typeof value === 'string') { - value = mom.localeData().monthsParse(value); - // TODO: Another silent failure? - if (typeof value !== 'number') { - return mom; - } + if (daysToDayOfWeek < end - 7) { + daysToDayOfWeek += 7; } - dayOfMonth = Math.min(mom.date(), - daysInMonth(mom.year(), value)); - mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); - return mom; + adjustedMoment = moment(mom).add(daysToDayOfWeek, 'd'); + return { + week: Math.ceil(adjustedMoment.dayOfYear() / 7), + year: adjustedMoment.year() + }; } - function rawGetter(mom, unit) { - return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit](); - } + //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday + function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { + var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear; - function rawSetter(mom, unit, value) { - if (unit === 'Month') { - return rawMonthSetter(mom, value); - } else { - return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); - } - } + d = d === 0 ? 7 : d; + weekday = weekday != null ? weekday : firstDayOfWeek; + daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0); + dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; - function makeAccessor(unit, keepTime) { - return function (value) { - if (value != null) { - rawSetter(this, unit, value); - moment.updateOffset(this, keepTime); - return this; - } else { - return rawGetter(this, unit); - } + return { + year: dayOfYear > 0 ? year : year - 1, + dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear }; } - moment.fn.millisecond = moment.fn.milliseconds = makeAccessor('Milliseconds', false); - moment.fn.second = moment.fn.seconds = makeAccessor('Seconds', false); - moment.fn.minute = moment.fn.minutes = makeAccessor('Minutes', false); - // Setting the hour should keep the time, because the user explicitly - // specified which hour he wants. So trying to maintain the same hour (in - // a new timezone) makes sense. Adding/subtracting hours does not follow - // this rule. - 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.year = makeAccessor('FullYear', true); - moment.fn.years = deprecate('years accessor is deprecated. Use year instead.', makeAccessor('FullYear', true)); + /************************************ + Top Level Functions + ************************************/ - // add plural methods - moment.fn.days = moment.fn.day; - moment.fn.months = moment.fn.month; - moment.fn.weeks = moment.fn.week; - moment.fn.isoWeeks = moment.fn.isoWeek; - moment.fn.quarters = moment.fn.quarter; + function makeMoment(config) { + var input = config._i, + format = config._f, + res; - // add aliased format methods - moment.fn.toJSON = moment.fn.toISOString; + config._locale = config._locale || moment.localeData(config._l); - // alias isUtc for dev-friendliness - moment.fn.isUTC = moment.fn.isUtc; + if (input === null || (format === undefined && input === '')) { + return moment.invalid({nullInput: true}); + } - /************************************ - Duration Prototype - ************************************/ + if (typeof input === 'string') { + config._i = input = config._locale.preparse(input); + } + if (moment.isMoment(input)) { + return new Moment(input, true); + } else if (format) { + if (isArray(format)) { + makeDateFromStringAndArray(config); + } else { + makeDateFromStringAndFormat(config); + } + } else { + makeDateFromInput(config); + } - function daysToYears (days) { - // 400 years have 146097 days (taking into account leap year rules) - return days * 400 / 146097; - } + res = new Moment(config); + if (res._nextDay) { + // Adding is smart enough around DST + res.add(1, 'd'); + res._nextDay = undefined; + } - function yearsToDays (years) { - // years * 365 + absRound(years / 4) - - // absRound(years / 100) + absRound(years / 400); - return years * 146097 / 400; + return res; } - extend(moment.duration.fn = Duration.prototype, { - - _bubble : function () { - var milliseconds = this._milliseconds, - days = this._days, - months = this._months, - data = this._data, - seconds, minutes, hours, years = 0; - - // The following code bubbles up values, see the tests for - // examples of what that means. - data.milliseconds = milliseconds % 1000; + moment = function (input, format, locale, strict) { + var c; - seconds = absRound(milliseconds / 1000); - data.seconds = seconds % 60; + if (typeof(locale) === 'boolean') { + strict = locale; + locale = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c = {}; + c._isAMomentObject = true; + c._i = input; + c._f = format; + c._l = locale; + c._strict = strict; + c._isUTC = false; + c._pf = defaultParsingFlags(); - minutes = absRound(seconds / 60); - data.minutes = minutes % 60; + return makeMoment(c); + }; - hours = absRound(minutes / 60); - data.hours = hours % 24; + moment.suppressDeprecationWarnings = false; - days += absRound(hours / 24); + 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 + (config._useUTC ? ' UTC' : '')); + } + ); - // Accurately convert days to years, assume start from year 0. - years = absRound(daysToYears(days)); - days -= absRound(yearsToDays(years)); + // 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. + // + // moments should either be an array of moment objects or an array, whose + // first element is an array of moment objects. + function pickBy(fn, moments) { + var res, i; + if (moments.length === 1 && isArray(moments[0])) { + moments = moments[0]; + } + if (!moments.length) { + return moment(); + } + res = moments[0]; + for (i = 1; i < moments.length; ++i) { + if (moments[i][fn](res)) { + res = moments[i]; + } + } + return res; + } - // 30 days to a month - // TODO (iskren): Use anchor date (like 1st Jan) to compute this. - months += absRound(days / 30); - days %= 30; + moment.min = function () { + var args = [].slice.call(arguments, 0); - // 12 months -> 1 year - years += absRound(months / 12); - months %= 12; + return pickBy('isBefore', args); + }; - data.days = days; - data.months = months; - data.years = years; - }, + moment.max = function () { + var args = [].slice.call(arguments, 0); - abs : function () { - this._milliseconds = Math.abs(this._milliseconds); - this._days = Math.abs(this._days); - this._months = Math.abs(this._months); + return pickBy('isAfter', args); + }; - 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); + // creating with utc + moment.utc = function (input, format, locale, strict) { + var c; - return this; - }, + if (typeof(locale) === 'boolean') { + strict = locale; + locale = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c = {}; + c._isAMomentObject = true; + c._useUTC = true; + c._isUTC = true; + c._l = locale; + c._i = input; + c._f = format; + c._strict = strict; + c._pf = defaultParsingFlags(); - weeks : function () { - return absRound(this.days() / 7); - }, + return makeMoment(c).utc(); + }; - valueOf : function () { - return this._milliseconds + - this._days * 864e5 + - (this._months % 12) * 2592e6 + - toInt(this._months / 12) * 31536e6; - }, + // creating with unix timestamp (in seconds) + moment.unix = function (input) { + return moment(input * 1000); + }; - humanize : function (withSuffix) { - var output = relativeTime(this, !withSuffix, this.localeData()); + // duration + moment.duration = function (input, key) { + var duration = input, + // matching against regexp is expensive, do it on demand + match = null, + sign, + ret, + parseIso, + diffRes; - if (withSuffix) { - output = this.localeData().pastFuture(+this, output); + if (moment.isDuration(input)) { + duration = { + ms: input._milliseconds, + d: input._days, + M: input._months + }; + } else if (typeof input === 'number') { + duration = {}; + if (key) { + duration[key] = input; + } else { + duration.milliseconds = input; } + } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) { + sign = (match[1] === '-') ? -1 : 1; + duration = { + y: 0, + d: toInt(match[DATE]) * sign, + h: toInt(match[HOUR]) * sign, + m: toInt(match[MINUTE]) * sign, + s: toInt(match[SECOND]) * sign, + ms: toInt(match[MILLISECOND]) * sign + }; + } else if (!!(match = isoDurationRegex.exec(input))) { + sign = (match[1] === '-') ? -1 : 1; + parseIso = function (inp) { + // We'd normally use ~~inp for this, but unfortunately it also + // converts floats to ints. + // inp may be undefined, so careful calling replace on it. + var res = inp && parseFloat(inp.replace(',', '.')); + // apply sign while we're at it + return (isNaN(res) ? 0 : res) * sign; + }; + duration = { + y: parseIso(match[2]), + M: parseIso(match[3]), + d: parseIso(match[4]), + h: parseIso(match[5]), + m: parseIso(match[6]), + s: parseIso(match[7]), + w: parseIso(match[8]) + }; + } else if (duration == null) {// checks for null or undefined + duration = {}; + } else if (typeof duration === 'object' && + ('from' in duration || 'to' in duration)) { + diffRes = momentsDifference(moment(duration.from), moment(duration.to)); - return this.localeData().postformat(output); - }, + duration = {}; + duration.ms = diffRes.milliseconds; + duration.M = diffRes.months; + } - add : function (input, val) { - // supports only 2.0-style add(1, 's') or add(moment) - var dur = moment.duration(input, val); + ret = new Duration(duration); - this._milliseconds += dur._milliseconds; - this._days += dur._days; - this._months += dur._months; + if (moment.isDuration(input) && hasOwnProp(input, '_locale')) { + ret._locale = input._locale; + } - this._bubble(); + return ret; + }; - return this; - }, + // version number + moment.version = VERSION; - subtract : function (input, val) { - var dur = moment.duration(input, val); + // default format + moment.defaultFormat = isoFormat; - this._milliseconds -= dur._milliseconds; - this._days -= dur._days; - this._months -= dur._months; + // constant that refers to the ISO standard + moment.ISO_8601 = function () {}; - this._bubble(); + // Plugins that add properties should also add the key here (null value), + // so we can properly clone ourselves. + moment.momentProperties = momentProperties; - return this; - }, + // This function will be called whenever a moment is mutated. + // It is intended to keep the offset in sync with the timezone. + moment.updateOffset = function () {}; - get : function (units) { - units = normalizeUnits(units); - return this[units.toLowerCase() + 's'](); - }, + // This function allows you to set a threshold for relative time strings + moment.relativeTimeThreshold = function (threshold, limit) { + if (relativeTimeThresholds[threshold] === undefined) { + return false; + } + if (limit === undefined) { + return relativeTimeThresholds[threshold]; + } + relativeTimeThresholds[threshold] = limit; + return true; + }; - as : function (units) { - var days, months; - units = normalizeUnits(units); + moment.lang = deprecate( + 'moment.lang is deprecated. Use moment.locale instead.', + function (key, value) { + return moment.locale(key, value); + } + ); - if (units === 'month' || units === 'year') { - days = this._days + this._milliseconds / 864e5; - months = this._months + daysToYears(days) * 12; - return units === 'month' ? months : months / 12; - } else { - // handle milliseconds separately because of floating point math errors (issue #1867) - days = this._days + Math.round(yearsToDays(this._months / 12)); - switch (units) { - case 'week': return days / 7 + this._milliseconds / 6048e5; - case 'day': return days + this._milliseconds / 864e5; - case 'hour': return days * 24 + this._milliseconds / 36e5; - case 'minute': return days * 24 * 60 + this._milliseconds / 6e4; - case 'second': return days * 24 * 60 * 60 + this._milliseconds / 1000; - // Math.floor prevents floating point math errors here - case 'millisecond': return Math.floor(days * 24 * 60 * 60 * 1000) + this._milliseconds; - default: throw new Error('Unknown unit ' + units); - } + // This function will load locale and then set the global locale. If + // no arguments are passed in, it will simply return the current global + // 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); } - }, - - lang : moment.fn.lang, - locale : moment.fn.locale, - toIsoString : deprecate( - 'toIsoString() is deprecated. Please use toISOString() instead ' + - '(notice the capitals)', - function () { - return this.toISOString(); + if (data) { + moment.duration._locale = moment._locale = data; } - ), + } - 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()), - days = Math.abs(this.days()), - hours = Math.abs(this.hours()), - minutes = Math.abs(this.minutes()), - seconds = Math.abs(this.seconds() + this.milliseconds() / 1000); + return moment._locale._abbr; + }; - if (!this.asSeconds()) { - // this is the same as C#'s (Noda) and python (isodate)... - // but not other JS (goog.date) - return 'P0D'; + moment.defineLocale = function (name, values) { + if (values !== null) { + values.abbr = name; + if (!locales[name]) { + locales[name] = new Locale(); } + locales[name].set(values); - return (this.asSeconds() < 0 ? '-' : '') + - 'P' + - (years ? years + 'Y' : '') + - (months ? months + 'M' : '') + - (days ? days + 'D' : '') + - ((hours || minutes || seconds) ? 'T' : '') + - (hours ? hours + 'H' : '') + - (minutes ? minutes + 'M' : '') + - (seconds ? seconds + 'S' : ''); - }, + // backwards compat for now: also set the locale + moment.locale(name); - localeData : function () { - return this._locale; - }, + return locales[name]; + } else { + // useful for testing + delete locales[name]; + return null; + } + }; - toJSON : function () { - return this.toISOString(); + moment.langData = deprecate( + 'moment.langData is deprecated. Use moment.localeData instead.', + function (key) { + return moment.localeData(key); } - }); + ); - moment.duration.fn.toString = moment.duration.fn.toISOString; + // returns locale data + moment.localeData = function (key) { + var locale; - function makeDurationGetter(name) { - moment.duration.fn[name] = function () { - return this._data[name]; - }; + 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 + moment.isMoment = function (obj) { + return obj instanceof Moment || + (obj != null && hasOwnProp(obj, '_isAMomentObject')); + }; + + // for typechecking Duration objects + moment.isDuration = function (obj) { + return obj instanceof Duration; + }; + + for (i = lists.length - 1; i >= 0; --i) { + makeList(lists[i]); } - for (i in unitMillisecondFactors) { - if (hasOwnProp(unitMillisecondFactors, i)) { - makeDurationGetter(i.toLowerCase()); + moment.normalizeUnits = function (units) { + return normalizeUnits(units); + }; + + moment.invalid = function (flags) { + var m = moment.utc(NaN); + if (flags != null) { + extend(m._pf, flags); + } + else { + m._pf.userInvalidated = true; } - } - 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'); + return m; }; - moment.duration.fn.asMonths = function () { - return this.as('M'); + + moment.parseZone = function () { + return moment.apply(null, arguments).parseZone(); }; - moment.duration.fn.asYears = function () { - return this.as('y'); + + moment.parseTwoDigitYear = function (input) { + return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); }; + moment.isDate = isDate; + /************************************ - Default Locale + Moment Prototype ************************************/ - // Set default locale, other locale will inherit from English. - moment.locale('en', { - ordinalParse: /\d{1,2}(th|st|nd|rd)/, - ordinal : function (number) { - var b = number % 10, - output = (toInt(number % 100 / 10) === 1) ? 'th' : - (b === 1) ? 'st' : - (b === 2) ? 'nd' : - (b === 3) ? 'rd' : 'th'; - return number + output; - } - }); + extend(moment.fn = Moment.prototype, { - /* EMBED_LOCALES */ + clone : function () { + return moment(this); + }, - /************************************ - Exposing Moment - ************************************/ + valueOf : function () { + return +this._d - ((this._offset || 0) * 60000); + }, - function makeGlobal(shouldDeprecate) { - /*global ender:false */ - if (typeof ender !== 'undefined') { - return; - } - oldGlobalMoment = globalScope.moment; - if (shouldDeprecate) { - globalScope.moment = deprecate( - 'Accessing Moment through the global scope is ' + - 'deprecated, and will be removed in an upcoming ' + - 'release.', - moment); - } else { - globalScope.moment = moment; - } - } + unix : function () { + return Math.floor(+this / 1000); + }, - // CommonJS module is defined - if (hasModule) { - module.exports = moment; - } else if (true) { - !(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) { - if (module.config && module.config() && module.config().noGlobal === true) { - // release the global variable - globalScope.moment = oldGlobalMoment; + toString : function () { + return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); + }, + + toDate : function () { + return this._offset ? new Date(+this) : this._d; + }, + + toISOString : function () { + var m = moment(this).utc(); + if (0 < m.year() && m.year() <= 9999) { + if ('function' === typeof Date.prototype.toISOString) { + // native implementation is ~50x faster, use it when we can + return this.toDate().toISOString(); + } else { + return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } + } else { + return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); } + }, - return moment; - }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - makeGlobal(true); - } else { - makeGlobal(); - } - }).call(this); - - /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()), __webpack_require__(71)(module))) + toArray : function () { + var m = this; + return [ + m.year(), + m.month(), + m.date(), + m.hours(), + m.minutes(), + m.seconds(), + m.milliseconds() + ]; + }, -/***/ }, -/* 58 */ -/***/ function(module, exports, __webpack_require__) { + isValid : function () { + return isValid(this); + }, - var __WEBPACK_AMD_DEFINE_RESULT__;/*! Hammer.JS - v1.1.3 - 2014-05-20 - * http://eightmedia.github.io/hammer.js - * - * Copyright (c) 2014 Jorik Tangelder ; - * Licensed under the MIT license */ + isDSTShifted : function () { + if (this._a) { + return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0; + } - (function(window, undefined) { - 'use strict'; + return false; + }, - /** - * @main - * @module hammer - * - * @class Hammer - * @static - */ + parsingFlags : function () { + return extend({}, this._pf); + }, - /** - * Hammer, use this to create instances - * ```` - * var hammertime = new Hammer(myElement); - * ```` - * - * @method Hammer - * @param {HTMLElement} element - * @param {Object} [options={}] - * @return {Hammer.Instance} - */ - var Hammer = function Hammer(element, options) { - return new Hammer.Instance(element, options || {}); - }; + invalidAt: function () { + return this._pf.overflow; + }, - /** - * version, as defined in package.json - * the value will be set at each build - * @property VERSION - * @final - * @type {String} - */ - Hammer.VERSION = '1.1.3'; + utc : function (keepLocalTime) { + return this.utcOffset(0, keepLocalTime); + }, - /** - * default settings. - * more settings are defined per gesture at `/gestures`. Each gesture can be disabled/enabled - * by setting it's name (like `swipe`) to false. - * You can set the defaults for all instances by changing this object before creating an instance. - * @example - * ```` - * Hammer.defaults.drag = false; - * Hammer.defaults.behavior.touchAction = 'pan-y'; - * delete Hammer.defaults.behavior.userSelect; - * ```` - * @property defaults - * @type {Object} - */ - Hammer.defaults = { - /** - * this setting object adds styles and attributes to the element to prevent the browser from doing - * its native behavior. The css properties are auto prefixed for the browsers when needed. - * @property defaults.behavior - * @type {Object} - */ - behavior: { - /** - * Disables text selection to improve the dragging gesture. When the value is `none` it also sets - * `onselectstart=false` for IE on the element. Mainly for desktop browsers. - * @property defaults.behavior.userSelect - * @type {String} - * @default 'none' - */ - userSelect: 'none', + local : function (keepLocalTime) { + if (this._isUTC) { + this.utcOffset(0, keepLocalTime); + this._isUTC = false; - /** - * Specifies whether and how a given region can be manipulated by the user (for instance, by panning or zooming). - * Used by Chrome 35> and IE10>. By default this makes the element blocking any touch event. - * @property defaults.behavior.touchAction - * @type {String} - * @default: 'pan-y' - */ - touchAction: 'pan-y', + if (keepLocalTime) { + this.subtract(this._dateUtcOffset(), 'm'); + } + } + return this; + }, - /** - * Disables the default callout shown when you touch and hold a touch target. - * On iOS, when you touch and hold a touch target such as a link, Safari displays - * a callout containing information about the link. This property allows you to disable that callout. - * @property defaults.behavior.touchCallout - * @type {String} - * @default 'none' - */ - touchCallout: 'none', + format : function (inputString) { + var output = formatMoment(this, inputString || moment.defaultFormat); + return this.localeData().postformat(output); + }, - /** - * Specifies whether zooming is enabled. Used by IE10> - * @property defaults.behavior.contentZooming - * @type {String} - * @default 'none' - */ - contentZooming: 'none', + add : createAdder(1, 'add'), - /** - * Specifies that an entire element should be draggable instead of its contents. - * Mainly for desktop browsers. - * @property defaults.behavior.userDrag - * @type {String} - * @default 'none' - */ - userDrag: 'none', + subtract : createAdder(-1, 'subtract'), - /** - * Overrides the highlight color shown when the user taps a link or a JavaScript - * clickable element in Safari on iPhone. This property obeys the alpha value, if specified. - * - * If you don't specify an alpha value, Safari on iPhone applies a default alpha value - * to the color. To disable tap highlighting, set the alpha value to 0 (invisible). - * If you set the alpha value to 1.0 (opaque), the element is not visible when tapped. - * @property defaults.behavior.tapHighlightColor - * @type {String} - * @default 'rgba(0,0,0,0)' - */ - tapHighlightColor: 'rgba(0,0,0,0)' - } - }; + diff : function (input, units, asFloat) { + var that = makeAs(input, this), + zoneDiff = (that.utcOffset() - this.utcOffset()) * 6e4, + anchor, diff, output, daysAdjust; - /** - * hammer document where the base events are added at - * @property DOCUMENT - * @type {HTMLElement} - * @default window.document - */ - Hammer.DOCUMENT = document; + units = normalizeUnits(units); - /** - * detect support for pointer events - * @property HAS_POINTEREVENTS - * @type {Boolean} - */ - Hammer.HAS_POINTEREVENTS = navigator.pointerEnabled || navigator.msPointerEnabled; + if (units === 'year' || units === 'month' || units === 'quarter') { + output = monthDiff(this, that); + if (units === 'quarter') { + output = output / 3; + } else if (units === 'year') { + output = output / 12; + } + } else { + diff = this - that; + output = units === 'second' ? diff / 1e3 : // 1000 + units === 'minute' ? diff / 6e4 : // 1000 * 60 + units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 + units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst + units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst + diff; + } + return asFloat ? output : absRound(output); + }, - /** - * detect support for touch events - * @property HAS_TOUCHEVENTS - * @type {Boolean} - */ - Hammer.HAS_TOUCHEVENTS = ('ontouchstart' in window); + from : function (time, withoutSuffix) { + return moment.duration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix); + }, - /** - * detect mobile browsers - * @property IS_MOBILE - * @type {Boolean} - */ - Hammer.IS_MOBILE = /mobile|tablet|ip(ad|hone|od)|android|silk/i.test(navigator.userAgent); + fromNow : function (withoutSuffix) { + return this.from(moment(), withoutSuffix); + }, - /** - * detect if we want to support mouseevents at all - * @property NO_MOUSEEVENTS - * @type {Boolean} - */ - Hammer.NO_MOUSEEVENTS = (Hammer.HAS_TOUCHEVENTS && Hammer.IS_MOBILE) || Hammer.HAS_POINTEREVENTS; + calendar : function (time) { + // We want to compare the start of today, vs this. + // Getting start-of-today depends on whether we're locat/utc/offset + // or not. + var now = time || moment(), + sod = makeAs(now, this).startOf('day'), + diff = this.diff(sod, 'days', true), + format = diff < -6 ? 'sameElse' : + diff < -1 ? 'lastWeek' : + diff < 0 ? 'lastDay' : + diff < 1 ? 'sameDay' : + diff < 2 ? 'nextDay' : + diff < 7 ? 'nextWeek' : 'sameElse'; + return this.format(this.localeData().calendar(format, this, moment(now))); + }, - /** - * interval in which Hammer recalculates current velocity/direction/angle in ms - * @property CALCULATE_INTERVAL - * @type {Number} - * @default 25 - */ - Hammer.CALCULATE_INTERVAL = 25; + isLeapYear : function () { + return isLeapYear(this.year()); + }, - /** - * eventtypes per touchevent (start, move, end) are filled by `Event.determineEventTypes` on `setup` - * the object contains the DOM event names per type (`EVENT_START`, `EVENT_MOVE`, `EVENT_END`) - * @property EVENT_TYPES - * @private - * @writeOnce - * @type {Object} - */ - var EVENT_TYPES = {}; + isDST : function () { + return (this.utcOffset() > this.clone().month(0).utcOffset() || + this.utcOffset() > this.clone().month(5).utcOffset()); + }, - /** - * direction strings, for safe comparisons - * @property DIRECTION_DOWN|LEFT|UP|RIGHT - * @final - * @type {String} - * @default 'down' 'left' 'up' 'right' - */ - var DIRECTION_DOWN = Hammer.DIRECTION_DOWN = 'down'; - var DIRECTION_LEFT = Hammer.DIRECTION_LEFT = 'left'; - var DIRECTION_UP = Hammer.DIRECTION_UP = 'up'; - var DIRECTION_RIGHT = Hammer.DIRECTION_RIGHT = 'right'; + day : function (input) { + var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); + if (input != null) { + input = parseWeekday(input, this.localeData()); + return this.add(input - day, 'd'); + } else { + return day; + } + }, - /** - * pointertype strings, for safe comparisons - * @property POINTER_MOUSE|TOUCH|PEN - * @final - * @type {String} - * @default 'mouse' 'touch' 'pen' - */ - var POINTER_MOUSE = Hammer.POINTER_MOUSE = 'mouse'; - var POINTER_TOUCH = Hammer.POINTER_TOUCH = 'touch'; - var POINTER_PEN = Hammer.POINTER_PEN = 'pen'; + month : makeAccessor('Month', true), - /** - * eventtypes - * @property EVENT_START|MOVE|END|RELEASE|TOUCH - * @final - * @type {String} - * @default 'start' 'change' 'move' 'end' 'release' 'touch' - */ - var EVENT_START = Hammer.EVENT_START = 'start'; - var EVENT_MOVE = Hammer.EVENT_MOVE = 'move'; - var EVENT_END = Hammer.EVENT_END = 'end'; - var EVENT_RELEASE = Hammer.EVENT_RELEASE = 'release'; - var EVENT_TOUCH = Hammer.EVENT_TOUCH = 'touch'; + startOf : function (units) { + units = normalizeUnits(units); + // the following switch intentionally omits break keywords + // to utilize falling through the cases. + switch (units) { + case 'year': + this.month(0); + /* falls through */ + case 'quarter': + case 'month': + this.date(1); + /* falls through */ + case 'week': + case 'isoWeek': + case 'day': + this.hours(0); + /* falls through */ + case 'hour': + this.minutes(0); + /* falls through */ + case 'minute': + this.seconds(0); + /* falls through */ + case 'second': + this.milliseconds(0); + /* falls through */ + } - /** - * if the window events are set... - * @property READY - * @writeOnce - * @type {Boolean} - * @default false - */ - Hammer.READY = false; + // weeks are a special case + if (units === 'week') { + this.weekday(0); + } else if (units === 'isoWeek') { + this.isoWeekday(1); + } + + // quarters are also special + if (units === 'quarter') { + this.month(Math.floor(this.month() / 3) * 3); + } + + return this; + }, + + endOf: function (units) { + units = normalizeUnits(units); + if (units === undefined || units === 'millisecond') { + return this; + } + return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms'); + }, + + isAfter: function (input, units) { + var inputMs; + units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); + if (units === 'millisecond') { + input = moment.isMoment(input) ? input : moment(input); + return +this > +input; + } else { + inputMs = moment.isMoment(input) ? +input : +moment(input); + return inputMs < +this.clone().startOf(units); + } + }, + + isBefore: function (input, units) { + var inputMs; + units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); + if (units === 'millisecond') { + input = moment.isMoment(input) ? input : moment(input); + return +this < +input; + } else { + inputMs = moment.isMoment(input) ? +input : +moment(input); + return +this.clone().endOf(units) < inputMs; + } + }, + + isBetween: function (from, to, units) { + return this.isAfter(from, units) && this.isBefore(to, units); + }, - /** - * plugins namespace - * @property plugins - * @type {Object} - */ - Hammer.plugins = Hammer.plugins || {}; + isSame: function (input, units) { + var inputMs; + units = normalizeUnits(units || 'millisecond'); + if (units === 'millisecond') { + input = moment.isMoment(input) ? input : moment(input); + return +this === +input; + } else { + inputMs = +moment(input); + return +(this.clone().startOf(units)) <= inputMs && inputMs <= +(this.clone().endOf(units)); + } + }, - /** - * gestures namespace - * see `/gestures` for the definitions - * @property gestures - * @type {Object} - */ - Hammer.gestures = Hammer.gestures || {}; + min: deprecate( + '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; + } + ), - /** - * setup events to detect gestures on the document - * this function is called when creating an new instance - * @private - */ - function setup() { - if(Hammer.READY) { - return; - } + max: deprecate( + '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; + } + ), - // find what eventtypes we add listeners to - Event.determineEventTypes(); + zone : deprecate( + 'moment().zone is deprecated, use moment().utcOffset instead. ' + + 'https://github.com/moment/moment/issues/1779', + function (input, keepLocalTime) { + if (input != null) { + if (typeof input !== 'string') { + input = -input; + } - // Register all gestures inside Hammer.gestures - Utils.each(Hammer.gestures, function(gesture) { - Detection.register(gesture); - }); + this.utcOffset(input, keepLocalTime); - // Add touch events on the document - Event.onTouch(Hammer.DOCUMENT, EVENT_MOVE, Detection.detect); - Event.onTouch(Hammer.DOCUMENT, EVENT_END, Detection.detect); + return this; + } else { + return -this.utcOffset(); + } + } + ), - // Hammer is ready...! - Hammer.READY = true; - } + // keepLocalTime = true means only change the timezone, without + // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]--> + // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset + // +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. + utcOffset : function (input, keepLocalTime) { + var offset = this._offset || 0, + localAdjust; + if (input != null) { + if (typeof input === 'string') { + input = utcOffsetFromString(input); + } + if (Math.abs(input) < 16) { + input = input * 60; + } + if (!this._isUTC && keepLocalTime) { + localAdjust = this._dateUtcOffset(); + } + this._offset = input; + this._isUTC = true; + if (localAdjust != null) { + this.add(localAdjust, 'm'); + } + if (offset !== input) { + if (!keepLocalTime || this._changeInProgress) { + addOrSubtractDurationFromMoment(this, + moment.duration(input - offset, 'm'), 1, false); + } else if (!this._changeInProgress) { + this._changeInProgress = true; + moment.updateOffset(this, true); + this._changeInProgress = null; + } + } - /** - * @module hammer - * - * @class Utils - * @static - */ - var Utils = Hammer.utils = { - /** - * extend method, could also be used for cloning when `dest` is an empty object. - * changes the dest object - * @method extend - * @param {Object} dest - * @param {Object} src - * @param {Boolean} [merge=false] do a merge - * @return {Object} dest - */ - extend: function extend(dest, src, merge) { - for(var key in src) { - if(!src.hasOwnProperty(key) || (dest[key] !== undefined && merge)) { - continue; + return this; + } else { + return this._isUTC ? offset : this._dateUtcOffset(); } - dest[key] = src[key]; - } - return dest; - }, + }, - /** - * simple addEventListener wrapper - * @method on - * @param {HTMLElement} element - * @param {String} type - * @param {Function} handler - */ - on: function on(element, type, handler) { - element.addEventListener(type, handler, false); - }, + isLocal : function () { + return !this._isUTC; + }, - /** - * simple removeEventListener wrapper - * @method off - * @param {HTMLElement} element - * @param {String} type - * @param {Function} handler - */ - off: function off(element, type, handler) { - element.removeEventListener(type, handler, false); - }, + isUtcOffset : function () { + return this._isUTC; + }, - /** - * forEach over arrays and objects - * @method each - * @param {Object|Array} obj - * @param {Function} iterator - * @param {any} iterator.item - * @param {Number} iterator.index - * @param {Object|Array} iterator.obj the source object - * @param {Object} context value to use as `this` in the iterator - */ - each: function each(obj, iterator, context) { - var i, len; + isUtc : function () { + return this._isUTC && this._offset === 0; + }, - // native forEach on arrays - if('forEach' in obj) { - obj.forEach(iterator, context); - // arrays - } else if(obj.length !== undefined) { - for(i = 0, len = obj.length; i < len; i++) { - if(iterator.call(context, obj[i], i, obj) === false) { - return; - } - } - // objects - } else { - for(i in obj) { - if(obj.hasOwnProperty(i) && - iterator.call(context, obj[i], i, obj) === false) { - return; - } - } - } - }, + zoneAbbr : function () { + return this._isUTC ? 'UTC' : ''; + }, - /** - * find if a string contains the string using indexOf - * @method inStr - * @param {String} src - * @param {String} find - * @return {Boolean} found - */ - inStr: function inStr(src, find) { - return src.indexOf(find) > -1; - }, + zoneName : function () { + return this._isUTC ? 'Coordinated Universal Time' : ''; + }, - /** - * find if a array contains the object using indexOf or a simple polyfill - * @method inArray - * @param {String} src - * @param {String} find - * @return {Boolean|Number} false when not found, or the index - */ - inArray: function inArray(src, find) { - if(src.indexOf) { - var index = src.indexOf(find); - return (index === -1) ? false : index; - } else { - for(var i = 0, len = src.length; i < len; i++) { - if(src[i] === find) { - return i; - } + parseZone : function () { + if (this._tzm) { + this.utcOffset(this._tzm); + } else if (typeof this._i === 'string') { + this.utcOffset(utcOffsetFromString(this._i)); } - return false; - } - }, - - /** - * convert an array-like object (`arguments`, `touchlist`) to an array - * @method toArray - * @param {Object} obj - * @return {Array} - */ - toArray: function toArray(obj) { - return Array.prototype.slice.call(obj, 0); - }, + return this; + }, - /** - * find if a node is in the given parent - * @method hasParent - * @param {HTMLElement} node - * @param {HTMLElement} parent - * @return {Boolean} found - */ - hasParent: function hasParent(node, parent) { - while(node) { - if(node == parent) { - return true; + hasAlignedHourOffset : function (input) { + if (!input) { + input = 0; + } + else { + input = moment(input).utcOffset(); } - node = node.parentNode; - } - return false; - }, - /** - * get the center of all the touches - * @method getCenter - * @param {Array} touches - * @return {Object} center contains `pageX`, `pageY`, `clientX` and `clientY` properties - */ - getCenter: function getCenter(touches) { - var pageX = [], - pageY = [], - clientX = [], - clientY = [], - min = Math.min, - max = Math.max; + return (this.utcOffset() - input) % 60 === 0; + }, - // no need to loop when only one touch - if(touches.length === 1) { - return { - pageX: touches[0].pageX, - pageY: touches[0].pageY, - clientX: touches[0].clientX, - clientY: touches[0].clientY - }; - } + daysInMonth : function () { + return daysInMonth(this.year(), this.month()); + }, - Utils.each(touches, function(touch) { - pageX.push(touch.pageX); - pageY.push(touch.pageY); - clientX.push(touch.clientX); - clientY.push(touch.clientY); - }); + dayOfYear : function (input) { + var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; + return input == null ? dayOfYear : this.add((input - dayOfYear), 'd'); + }, - return { - pageX: (min.apply(Math, pageX) + max.apply(Math, pageX)) / 2, - pageY: (min.apply(Math, pageY) + max.apply(Math, pageY)) / 2, - clientX: (min.apply(Math, clientX) + max.apply(Math, clientX)) / 2, - clientY: (min.apply(Math, clientY) + max.apply(Math, clientY)) / 2 - }; - }, + quarter : function (input) { + return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3); + }, - /** - * calculate the velocity between two points. unit is in px per ms. - * @method getVelocity - * @param {Number} deltaTime - * @param {Number} deltaX - * @param {Number} deltaY - * @return {Object} velocity `x` and `y` - */ - getVelocity: function getVelocity(deltaTime, deltaX, deltaY) { - return { - x: Math.abs(deltaX / deltaTime) || 0, - y: Math.abs(deltaY / deltaTime) || 0 - }; - }, + weekYear : function (input) { + var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year; + return input == null ? year : this.add((input - year), 'y'); + }, - /** - * calculate the angle between two coordinates - * @method getAngle - * @param {Touch} touch1 - * @param {Touch} touch2 - * @return {Number} angle - */ - getAngle: function getAngle(touch1, touch2) { - var x = touch2.clientX - touch1.clientX, - y = touch2.clientY - touch1.clientY; + isoWeekYear : function (input) { + var year = weekOfYear(this, 1, 4).year; + return input == null ? year : this.add((input - year), 'y'); + }, - return Math.atan2(y, x) * 180 / Math.PI; - }, + week : function (input) { + var week = this.localeData().week(this); + return input == null ? week : this.add((input - week) * 7, 'd'); + }, - /** - * do a small comparision to get the direction between two touches. - * @method getDirection - * @param {Touch} touch1 - * @param {Touch} touch2 - * @return {String} direction matches `DIRECTION_LEFT|RIGHT|UP|DOWN` - */ - getDirection: function getDirection(touch1, touch2) { - var x = Math.abs(touch1.clientX - touch2.clientX), - y = Math.abs(touch1.clientY - touch2.clientY); + isoWeek : function (input) { + var week = weekOfYear(this, 1, 4).week; + return input == null ? week : this.add((input - week) * 7, 'd'); + }, - if(x >= y) { - return touch1.clientX - touch2.clientX > 0 ? DIRECTION_LEFT : DIRECTION_RIGHT; - } - return touch1.clientY - touch2.clientY > 0 ? DIRECTION_UP : DIRECTION_DOWN; - }, + weekday : function (input) { + var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; + return input == null ? weekday : this.add(input - weekday, 'd'); + }, - /** - * calculate the distance between two touches - * @method getDistance - * @param {Touch}touch1 - * @param {Touch} touch2 - * @return {Number} distance - */ - getDistance: function getDistance(touch1, touch2) { - var x = touch2.clientX - touch1.clientX, - y = touch2.clientY - touch1.clientY; + isoWeekday : function (input) { + // behaves the same as moment#day except + // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) + // as a setter, sunday should belong to the previous week. + return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); + }, - return Math.sqrt((x * x) + (y * y)); - }, + isoWeeksInYear : function () { + return weeksInYear(this.year(), 1, 4); + }, - /** - * calculate the scale factor between two touchLists - * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out - * @method getScale - * @param {Array} start array of touches - * @param {Array} end array of touches - * @return {Number} scale - */ - getScale: function getScale(start, end) { - // need two fingers... - if(start.length >= 2 && end.length >= 2) { - return this.getDistance(end[0], end[1]) / this.getDistance(start[0], start[1]); - } - return 1; - }, + weeksInYear : function () { + var weekInfo = this.localeData()._week; + return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); + }, - /** - * calculate the rotation degrees between two touchLists - * @method getRotation - * @param {Array} start array of touches - * @param {Array} end array of touches - * @return {Number} rotation - */ - getRotation: function getRotation(start, end) { - // need two fingers - if(start.length >= 2 && end.length >= 2) { - return this.getAngle(end[1], end[0]) - this.getAngle(start[1], start[0]); - } - return 0; - }, + get : function (units) { + units = normalizeUnits(units); + return this[units](); + }, - /** - * find out if the direction is vertical * - * @method isVertical - * @param {String} direction matches `DIRECTION_UP|DOWN` - * @return {Boolean} is_vertical - */ - isVertical: function isVertical(direction) { - return direction == DIRECTION_UP || direction == DIRECTION_DOWN; - }, + set : function (units, value) { + var unit; + if (typeof units === 'object') { + for (unit in units) { + this.set(unit, units[unit]); + } + } + else { + units = normalizeUnits(units); + if (typeof this[units] === 'function') { + this[units](value); + } + } + return this; + }, - /** - * set css properties with their prefixes - * @param {HTMLElement} element - * @param {String} prop - * @param {String} value - * @param {Boolean} [toggle=true] - * @return {Boolean} - */ - setPrefixedCss: function setPrefixedCss(element, prop, value, toggle) { - var prefixes = ['', 'Webkit', 'Moz', 'O', 'ms']; - prop = Utils.toCamelCase(prop); + // If passed a locale key, it will set the locale for this + // instance. Otherwise, it will return the locale configuration + // variables for this instance. + locale : function (key) { + var newLocaleData; - for(var i = 0; i < prefixes.length; i++) { - var p = prop; - // prefixes - if(prefixes[i]) { - p = prefixes[i] + p.slice(0, 1).toUpperCase() + p.slice(1); + if (key === undefined) { + return this._locale._abbr; + } else { + newLocaleData = moment.localeData(key); + if (newLocaleData != null) { + this._locale = newLocaleData; + } + return this; } + }, - // test the style - if(p in element.style) { - element.style[p] = (toggle == null || toggle) && value || ''; - break; + lang : deprecate( + 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', + function (key) { + if (key === undefined) { + return this.localeData(); + } else { + return this.locale(key); + } } - } - }, + ), + + localeData : function () { + return this._locale; + }, - /** - * toggle browser default behavior by setting css properties. - * `userSelect='none'` also sets `element.onselectstart` to false - * `userDrag='none'` also sets `element.ondragstart` to false - * - * @method toggleBehavior - * @param {HtmlElement} element - * @param {Object} props - * @param {Boolean} [toggle=true] - */ - toggleBehavior: function toggleBehavior(element, props, toggle) { - if(!props || !element || !element.style) { - return; + _dateUtcOffset : function () { + // On Firefox.24 Date#getTimezoneOffset returns a floating point. + // https://github.com/moment/moment/pull/1871 + return -Math.round(this._d.getTimezoneOffset() / 15) * 15; } - // set the css properties - Utils.each(props, function(value, prop) { - Utils.setPrefixedCss(element, prop, value, toggle); - }); + }); - var falseFn = toggle && function() { - return false; - }; + function rawMonthSetter(mom, value) { + var dayOfMonth; - // also the disable onselectstart - if(props.userSelect == 'none') { - element.onselectstart = falseFn; - } - // and disable ondragstart - if(props.userDrag == 'none') { - element.ondragstart = falseFn; + // TODO: Move this out of here! + if (typeof value === 'string') { + value = mom.localeData().monthsParse(value); + // TODO: Another silent failure? + if (typeof value !== 'number') { + return mom; + } } - }, - /** - * convert a string with underscores to camelCase - * so prevent_default becomes preventDefault - * @param {String} str - * @return {String} camelCaseStr - */ - toCamelCase: function toCamelCase(str) { - return str.replace(/[_-]([a-z])/g, function(s) { - return s[1].toUpperCase(); - }); + dayOfMonth = Math.min(mom.date(), + daysInMonth(mom.year(), value)); + mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); + return mom; } - }; + function rawGetter(mom, unit) { + return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit](); + } - /** - * @module hammer - */ - /** - * @class Event - * @static - */ - var Event = Hammer.event = { - /** - * when touch events have been fired, this is true - * this is used to stop mouse events - * @property prevent_mouseevents - * @private - * @type {Boolean} - */ - preventMouseEvents: false, + function rawSetter(mom, unit, value) { + if (unit === 'Month') { + return rawMonthSetter(mom, value); + } else { + return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); + } + } - /** - * if EVENT_START has been fired - * @property started - * @private - * @type {Boolean} - */ - started: false, + function makeAccessor(unit, keepTime) { + return function (value) { + if (value != null) { + rawSetter(this, unit, value); + moment.updateOffset(this, keepTime); + return this; + } else { + return rawGetter(this, unit); + } + }; + } - /** - * when the mouse is hold down, this is true - * @property should_detect - * @private - * @type {Boolean} - */ - shouldDetect: false, + moment.fn.millisecond = moment.fn.milliseconds = makeAccessor('Milliseconds', false); + moment.fn.second = moment.fn.seconds = makeAccessor('Seconds', false); + moment.fn.minute = moment.fn.minutes = makeAccessor('Minutes', false); + // Setting the hour should keep the time, because the user explicitly + // specified which hour he wants. So trying to maintain the same hour (in + // a new timezone) makes sense. Adding/subtracting hours does not follow + // this rule. + 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.year = makeAccessor('FullYear', true); + moment.fn.years = deprecate('years accessor is deprecated. Use year instead.', makeAccessor('FullYear', true)); - /** - * simple event binder with a hook and support for multiple types - * @method on - * @param {HTMLElement} element - * @param {String} type - * @param {Function} handler - * @param {Function} [hook] - * @param {Object} hook.type - */ - on: function on(element, type, handler, hook) { - var types = type.split(' '); - Utils.each(types, function(type) { - Utils.on(element, type, handler); - hook && hook(type); - }); - }, + // add plural methods + moment.fn.days = moment.fn.day; + moment.fn.months = moment.fn.month; + moment.fn.weeks = moment.fn.week; + moment.fn.isoWeeks = moment.fn.isoWeek; + moment.fn.quarters = moment.fn.quarter; - /** - * simple event unbinder with a hook and support for multiple types - * @method off - * @param {HTMLElement} element - * @param {String} type - * @param {Function} handler - * @param {Function} [hook] - * @param {Object} hook.type - */ - off: function off(element, type, handler, hook) { - var types = type.split(' '); - Utils.each(types, function(type) { - Utils.off(element, type, handler); - hook && hook(type); - }); - }, + // add aliased format methods + moment.fn.toJSON = moment.fn.toISOString; - /** - * the core touch event handler. - * this finds out if we should to detect gestures - * @method onTouch - * @param {HTMLElement} element - * @param {String} eventType matches `EVENT_START|MOVE|END` - * @param {Function} handler - * @return onTouchHandler {Function} the core event handler - */ - onTouch: function onTouch(element, eventType, handler) { - var self = this; + // alias isUtc for dev-friendliness + moment.fn.isUTC = moment.fn.isUtc; - var onTouchHandler = function onTouchHandler(ev) { - var srcType = ev.type.toLowerCase(), - isPointer = Hammer.HAS_POINTEREVENTS, - isMouse = Utils.inStr(srcType, 'mouse'), - triggerType; + /************************************ + Duration Prototype + ************************************/ - // if we are in a mouseevent, but there has been a touchevent triggered in this session - // we want to do nothing. simply break out of the event. - if(isMouse && self.preventMouseEvents) { - return; - // mousebutton must be down - } else if(isMouse && eventType == EVENT_START && ev.button === 0) { - self.preventMouseEvents = false; - self.shouldDetect = true; - } else if(isPointer && eventType == EVENT_START) { - self.shouldDetect = (ev.buttons === 1 || PointerEvent.matchType(POINTER_TOUCH, ev)); - // just a valid start event, but no mouse - } else if(!isMouse && eventType == EVENT_START) { - self.preventMouseEvents = true; - self.shouldDetect = true; - } + function daysToYears (days) { + // 400 years have 146097 days (taking into account leap year rules) + return days * 400 / 146097; + } - // update the pointer event before entering the detection - if(isPointer && eventType != EVENT_END) { - PointerEvent.updatePointer(eventType, ev); - } + function yearsToDays (years) { + // years * 365 + absRound(years / 4) - + // absRound(years / 100) + absRound(years / 400); + return years * 146097 / 400; + } - // we are in a touch/down state, so allowed detection of gestures - if(self.shouldDetect) { - triggerType = self.doDetect.call(self, ev, eventType, element, handler); - } + extend(moment.duration.fn = Duration.prototype, { - // ...and we are done with the detection - // so reset everything to start each detection totally fresh - if(triggerType == EVENT_END) { - self.preventMouseEvents = false; - self.shouldDetect = false; - PointerEvent.reset(); - // update the pointerevent object after the detection - } + _bubble : function () { + var milliseconds = this._milliseconds, + days = this._days, + months = this._months, + data = this._data, + seconds, minutes, hours, years = 0; - if(isPointer && eventType == EVENT_END) { - PointerEvent.updatePointer(eventType, ev); - } - }; + // The following code bubbles up values, see the tests for + // examples of what that means. + data.milliseconds = milliseconds % 1000; - this.on(element, EVENT_TYPES[eventType], onTouchHandler); - return onTouchHandler; - }, + seconds = absRound(milliseconds / 1000); + data.seconds = seconds % 60; - /** - * the core detection method - * this finds out what hammer-touch-events to trigger - * @method doDetect - * @param {Object} ev - * @param {String} eventType matches `EVENT_START|MOVE|END` - * @param {HTMLElement} element - * @param {Function} handler - * @return {String} triggerType matches `EVENT_START|MOVE|END` - */ - doDetect: function doDetect(ev, eventType, element, handler) { - var touchList = this.getTouchList(ev, eventType); - var touchListLength = touchList.length; - var triggerType = eventType; - var triggerChange = touchList.trigger; // used by fakeMultitouch plugin - var changedLength = touchListLength; + minutes = absRound(seconds / 60); + data.minutes = minutes % 60; - // at each touchstart-like event we want also want to trigger a TOUCH event... - if(eventType == EVENT_START) { - triggerChange = EVENT_TOUCH; - // ...the same for a touchend-like event - } else if(eventType == EVENT_END) { - triggerChange = EVENT_RELEASE; + hours = absRound(minutes / 60); + data.hours = hours % 24; - // keep track of how many touches have been removed - changedLength = touchList.length - ((ev.changedTouches) ? ev.changedTouches.length : 1); - } + days += absRound(hours / 24); - // after there are still touches on the screen, - // we just want to trigger a MOVE event. so change the START or END to a MOVE - // but only after detection has been started, the first time we actualy want a START - if(changedLength > 0 && this.started) { - triggerType = EVENT_MOVE; - } + // Accurately convert days to years, assume start from year 0. + years = absRound(daysToYears(days)); + days -= absRound(yearsToDays(years)); - // detection has been started, we keep track of this, see above - this.started = true; + // 30 days to a month + // TODO (iskren): Use anchor date (like 1st Jan) to compute this. + months += absRound(days / 30); + days %= 30; - // generate some event data, some basic information - var evData = this.collectEventData(element, triggerType, touchList, ev); + // 12 months -> 1 year + years += absRound(months / 12); + months %= 12; - // trigger the triggerType event before the change (TOUCH, RELEASE) events - // but the END event should be at last - if(eventType != EVENT_END) { - handler.call(Detection, evData); - } + data.days = days; + data.months = months; + data.years = years; + }, - // trigger a change (TOUCH, RELEASE) event, this means the length of the touches changed - if(triggerChange) { - evData.changedLength = changedLength; - evData.eventType = triggerChange; + abs : function () { + this._milliseconds = Math.abs(this._milliseconds); + this._days = Math.abs(this._days); + this._months = Math.abs(this._months); - handler.call(Detection, evData); + 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); - evData.eventType = triggerType; - delete evData.changedLength; - } + return this; + }, - // trigger the END event - if(triggerType == EVENT_END) { - handler.call(Detection, evData); + weeks : function () { + return absRound(this.days() / 7); + }, - // ...and we are done with the detection - // so reset everything to start each detection totally fresh - this.started = false; - } + valueOf : function () { + return this._milliseconds + + this._days * 864e5 + + (this._months % 12) * 2592e6 + + toInt(this._months / 12) * 31536e6; + }, - return triggerType; - }, + humanize : function (withSuffix) { + var output = relativeTime(this, !withSuffix, this.localeData()); - /** - * we have different events for each device/browser - * determine what we need and set them in the EVENT_TYPES constant - * the `onTouch` method is bind to these properties. - * @method determineEventTypes - * @return {Object} events - */ - determineEventTypes: function determineEventTypes() { - var types; - if(Hammer.HAS_POINTEREVENTS) { - if(window.PointerEvent) { - types = [ - 'pointerdown', - 'pointermove', - 'pointerup pointercancel lostpointercapture' - ]; - } else { - types = [ - 'MSPointerDown', - 'MSPointerMove', - 'MSPointerUp MSPointerCancel MSLostPointerCapture' - ]; + if (withSuffix) { + output = this.localeData().pastFuture(+this, output); } - } else if(Hammer.NO_MOUSEEVENTS) { - types = [ - 'touchstart', - 'touchmove', - 'touchend touchcancel' - ]; - } else { - types = [ - 'touchstart mousedown', - 'touchmove mousemove', - 'touchend touchcancel mouseup' - ]; - } - EVENT_TYPES[EVENT_START] = types[0]; - EVENT_TYPES[EVENT_MOVE] = types[1]; - EVENT_TYPES[EVENT_END] = types[2]; - return EVENT_TYPES; - }, + return this.localeData().postformat(output); + }, - /** - * create touchList depending on the event - * @method getTouchList - * @param {Object} ev - * @param {String} eventType - * @return {Array} touches - */ - getTouchList: function getTouchList(ev, eventType) { - // get the fake pointerEvent touchlist - if(Hammer.HAS_POINTEREVENTS) { - return PointerEvent.getTouchList(); - } + add : function (input, val) { + // supports only 2.0-style add(1, 's') or add(moment) + var dur = moment.duration(input, val); - // get the touchlist - if(ev.touches) { - if(eventType == EVENT_MOVE) { - return ev.touches; - } + this._milliseconds += dur._milliseconds; + this._days += dur._days; + this._months += dur._months; - var identifiers = []; - var concat = [].concat(Utils.toArray(ev.touches), Utils.toArray(ev.changedTouches)); - var touchList = []; + this._bubble(); - Utils.each(concat, function(touch) { - if(Utils.inArray(identifiers, touch.identifier) === false) { - touchList.push(touch); - } - identifiers.push(touch.identifier); - }); + return this; + }, - return touchList; - } + subtract : function (input, val) { + var dur = moment.duration(input, val); - // make fake touchList from mouse position - ev.identifier = 1; - return [ev]; - }, + this._milliseconds -= dur._milliseconds; + this._days -= dur._days; + this._months -= dur._months; - /** - * collect basic event data - * @method collectEventData - * @param {HTMLElement} element - * @param {String} eventType matches `EVENT_START|MOVE|END` - * @param {Array} touches - * @param {Object} ev - * @return {Object} ev - */ - collectEventData: function collectEventData(element, eventType, touches, ev) { - // find out pointerType - var pointerType = POINTER_TOUCH; - if(Utils.inStr(ev.type, 'mouse') || PointerEvent.matchType(POINTER_MOUSE, ev)) { - pointerType = POINTER_MOUSE; - } else if(PointerEvent.matchType(POINTER_PEN, ev)) { - pointerType = POINTER_PEN; - } + this._bubble(); - return { - center: Utils.getCenter(touches), - timeStamp: Date.now(), - target: ev.target, - touches: touches, - eventType: eventType, - pointerType: pointerType, - srcEvent: ev, + return this; + }, - /** - * prevent the browser default actions - * mostly used to disable scrolling of the browser - */ - preventDefault: function() { - var srcEvent = this.srcEvent; - srcEvent.preventManipulation && srcEvent.preventManipulation(); - srcEvent.preventDefault && srcEvent.preventDefault(); - }, + get : function (units) { + units = normalizeUnits(units); + return this[units.toLowerCase() + 's'](); + }, - /** - * stop bubbling the event up to its parents - */ - stopPropagation: function() { - this.srcEvent.stopPropagation(); - }, + as : function (units) { + var days, months; + units = normalizeUnits(units); - /** - * immediately stop gesture detection - * might be useful after a swipe was detected - * @return {*} - */ - stopDetect: function() { - return Detection.stopDetect(); + if (units === 'month' || units === 'year') { + days = this._days + this._milliseconds / 864e5; + months = this._months + daysToYears(days) * 12; + return units === 'month' ? months : months / 12; + } else { + // handle milliseconds separately because of floating point math errors (issue #1867) + days = this._days + Math.round(yearsToDays(this._months / 12)); + switch (units) { + case 'week': return days / 7 + this._milliseconds / 6048e5; + case 'day': return days + this._milliseconds / 864e5; + case 'hour': return days * 24 + this._milliseconds / 36e5; + case 'minute': return days * 24 * 60 + this._milliseconds / 6e4; + case 'second': return days * 24 * 60 * 60 + this._milliseconds / 1000; + // Math.floor prevents floating point math errors here + case 'millisecond': return Math.floor(days * 24 * 60 * 60 * 1000) + this._milliseconds; + 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 () { + // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js + var years = Math.abs(this.years()), + months = Math.abs(this.months()), + days = Math.abs(this.days()), + hours = Math.abs(this.hours()), + minutes = Math.abs(this.minutes()), + seconds = Math.abs(this.seconds() + this.milliseconds() / 1000); - /** - * @module hammer - * - * @class PointerEvent - * @static - */ - var PointerEvent = Hammer.PointerEvent = { - /** - * holds all pointers, by `identifier` - * @property pointers - * @type {Object} - */ - pointers: {}, + if (!this.asSeconds()) { + // this is the same as C#'s (Noda) and python (isodate)... + // but not other JS (goog.date) + return 'P0D'; + } - /** - * get the pointers as an array - * @method getTouchList - * @return {Array} touchlist - */ - getTouchList: function getTouchList() { - var touchlist = []; - // we can use forEach since pointerEvents only is in IE10 - Utils.each(this.pointers, function(pointer) { - touchlist.push(pointer); - }); - return touchlist; - }, + return (this.asSeconds() < 0 ? '-' : '') + + 'P' + + (years ? years + 'Y' : '') + + (months ? months + 'M' : '') + + (days ? days + 'D' : '') + + ((hours || minutes || seconds) ? 'T' : '') + + (hours ? hours + 'H' : '') + + (minutes ? minutes + 'M' : '') + + (seconds ? seconds + 'S' : ''); + }, - /** - * update the position of a pointer - * @method updatePointer - * @param {String} eventType matches `EVENT_START|MOVE|END` - * @param {Object} pointerEvent - */ - updatePointer: function updatePointer(eventType, pointerEvent) { - if(eventType == EVENT_END || (eventType != EVENT_END && pointerEvent.buttons !== 1)) { - delete this.pointers[pointerEvent.pointerId]; - } else { - pointerEvent.identifier = pointerEvent.pointerId; - this.pointers[pointerEvent.pointerId] = pointerEvent; - } - }, + localeData : function () { + return this._locale; + }, - /** - * check if ev matches pointertype - * @method matchType - * @param {String} pointerType matches `POINTER_MOUSE|TOUCH|PEN` - * @param {PointerEvent} ev - */ - matchType: function matchType(pointerType, ev) { - if(!ev.pointerType) { - return false; + toJSON : function () { + return this.toISOString(); } + }); - var pt = ev.pointerType, - types = {}; - - types[POINTER_MOUSE] = (pt === (ev.MSPOINTER_TYPE_MOUSE || POINTER_MOUSE)); - types[POINTER_TOUCH] = (pt === (ev.MSPOINTER_TYPE_TOUCH || POINTER_TOUCH)); - types[POINTER_PEN] = (pt === (ev.MSPOINTER_TYPE_PEN || POINTER_PEN)); - return types[pointerType]; - }, + moment.duration.fn.toString = moment.duration.fn.toISOString; - /** - * reset the stored pointers - * @method reset - */ - reset: function resetList() { - this.pointers = {}; + function makeDurationGetter(name) { + moment.duration.fn[name] = function () { + return this._data[name]; + }; } - }; - - /** - * @module hammer - * - * @class Detection - * @static - */ - var Detection = Hammer.detection = { - // contains all registred Hammer.gestures in the correct order - gestures: [], + for (i in unitMillisecondFactors) { + if (hasOwnProp(unitMillisecondFactors, i)) { + makeDurationGetter(i.toLowerCase()); + } + } - // data of the current Hammer.gesture detection session - current: null, + 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.as('M'); + }; + moment.duration.fn.asYears = function () { + return this.as('y'); + }; - // the previous Hammer.gesture session data - // is a full clone of the previous gesture.current object - previous: null, + /************************************ + Default Locale + ************************************/ - // when this becomes true, no gestures are fired - stopped: false, - /** - * start Hammer.gesture detection - * @method startDetect - * @param {Hammer.Instance} inst - * @param {Object} eventData - */ - startDetect: function startDetect(inst, eventData) { - // already busy with a Hammer.gesture detection on an element - if(this.current) { - return; + // Set default locale, other locale will inherit from English. + moment.locale('en', { + ordinalParse: /\d{1,2}(th|st|nd|rd)/, + ordinal : function (number) { + var b = number % 10, + output = (toInt(number % 100 / 10) === 1) ? 'th' : + (b === 1) ? 'st' : + (b === 2) ? 'nd' : + (b === 3) ? 'rd' : 'th'; + return number + output; } + }); - this.stopped = false; - - // holds current session - this.current = { - inst: inst, // reference to HammerInstance we're working for - startEvent: Utils.extend({}, eventData), // start eventData for distances, timing etc - lastEvent: false, // last eventData - lastCalcEvent: false, // last eventData for calculations. - futureCalcEvent: false, // last eventData for calculations. - lastCalcData: {}, // last lastCalcData - name: '' // current gesture we're in/detected, can be 'tap', 'hold' etc - }; + /* EMBED_LOCALES */ - this.detect(eventData); - }, + /************************************ + Exposing Moment + ************************************/ - /** - * Hammer.gesture detection - * @method detect - * @param {Object} eventData - * @return {any} - */ - detect: function detect(eventData) { - if(!this.current || this.stopped) { + function makeGlobal(shouldDeprecate) { + /*global ender:false */ + if (typeof ender !== 'undefined') { return; } + oldGlobalMoment = globalScope.moment; + if (shouldDeprecate) { + globalScope.moment = deprecate( + 'Accessing Moment through the global scope is ' + + 'deprecated, and will be removed in an upcoming ' + + 'release.', + moment); + } else { + globalScope.moment = moment; + } + } - // extend event data with calculations about scale, distance etc - eventData = this.extendEventData(eventData); - - // hammer instance and instance options - var inst = this.current.inst, - instOptions = inst.options; - - // call Hammer.gesture handlers - Utils.each(this.gestures, function triggerGesture(gesture) { - // only when the instance options have enabled this gesture - if(!this.stopped && inst.enabled && instOptions[gesture.name]) { - gesture.handler.call(gesture, eventData, inst); + // CommonJS module is defined + if (hasModule) { + module.exports = moment; + } else if (true) { + !(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) { + if (module.config && module.config() && module.config().noGlobal === true) { + // release the global variable + globalScope.moment = oldGlobalMoment; } - }, this); - // store as previous event event - if(this.current) { - this.current.lastEvent = eventData; - } + return moment; + }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + makeGlobal(true); + } else { + makeGlobal(); + } + }).call(this); + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()), __webpack_require__(71)(module))) - if(eventData.eventType == EVENT_END) { - this.stopDetect(); - } +/***/ }, +/* 60 */ +/***/ function(module, exports, __webpack_require__) { - return eventData; - }, + var util = __webpack_require__(1); + var RepulsionMixin = __webpack_require__(67); + var HierarchialRepulsionMixin = __webpack_require__(68); + var BarnesHutMixin = __webpack_require__(69); - /** - * clear the Hammer.gesture vars - * this is called on endDetect, but can also be used when a final Hammer.gesture has been detected - * to stop other Hammer.gestures from being fired - * @method stopDetect - */ - stopDetect: function stopDetect() { - // clone current data to the store as the previous gesture - // used for the double tap gesture, since this is an other gesture detect session - this.previous = Utils.extend({}, this.current); + /** + * Toggling barnes Hut calculation on and off. + * + * @private + */ + exports._toggleBarnesHut = function () { + this.constants.physics.barnesHut.enabled = !this.constants.physics.barnesHut.enabled; + this._loadSelectedForceSolver(); + this.moving = true; + this.start(); + }; - // reset the current - this.current = null; - this.stopped = true; - }, - /** - * calculate velocity, angle and direction - * @method getVelocityData - * @param {Object} ev - * @param {Object} center - * @param {Number} deltaTime - * @param {Number} deltaX - * @param {Number} deltaY - */ - getCalculatedData: function getCalculatedData(ev, center, deltaTime, deltaX, deltaY) { - var cur = this.current, - recalc = false, - calcEv = cur.lastCalcEvent, - calcData = cur.lastCalcData; + /** + * This loads the node force solver based on the barnes hut or repulsion algorithm + * + * @private + */ + exports._loadSelectedForceSolver = function () { + // this overloads the this._calculateNodeForces + if (this.constants.physics.barnesHut.enabled == true) { + this._clearMixin(RepulsionMixin); + this._clearMixin(HierarchialRepulsionMixin); - if(calcEv && ev.timeStamp - calcEv.timeStamp > Hammer.CALCULATE_INTERVAL) { - center = calcEv.center; - deltaTime = ev.timeStamp - calcEv.timeStamp; - deltaX = ev.center.clientX - calcEv.center.clientX; - deltaY = ev.center.clientY - calcEv.center.clientY; - recalc = true; - } + this.constants.physics.centralGravity = this.constants.physics.barnesHut.centralGravity; + this.constants.physics.springLength = this.constants.physics.barnesHut.springLength; + this.constants.physics.springConstant = this.constants.physics.barnesHut.springConstant; + this.constants.physics.damping = this.constants.physics.barnesHut.damping; - if(ev.eventType == EVENT_TOUCH || ev.eventType == EVENT_RELEASE) { - cur.futureCalcEvent = ev; - } + this._loadMixin(BarnesHutMixin); + } + else if (this.constants.physics.hierarchicalRepulsion.enabled == true) { + this._clearMixin(BarnesHutMixin); + this._clearMixin(RepulsionMixin); - if(!cur.lastCalcEvent || recalc) { - calcData.velocity = Utils.getVelocity(deltaTime, deltaX, deltaY); - calcData.angle = Utils.getAngle(center, ev.center); - calcData.direction = Utils.getDirection(center, ev.center); + this.constants.physics.centralGravity = this.constants.physics.hierarchicalRepulsion.centralGravity; + this.constants.physics.springLength = this.constants.physics.hierarchicalRepulsion.springLength; + this.constants.physics.springConstant = this.constants.physics.hierarchicalRepulsion.springConstant; + this.constants.physics.damping = this.constants.physics.hierarchicalRepulsion.damping; - cur.lastCalcEvent = cur.futureCalcEvent || ev; - cur.futureCalcEvent = ev; - } + this._loadMixin(HierarchialRepulsionMixin); + } + else { + this._clearMixin(BarnesHutMixin); + this._clearMixin(HierarchialRepulsionMixin); + this.barnesHutTree = undefined; - ev.velocityX = calcData.velocity.x; - ev.velocityY = calcData.velocity.y; - ev.interimAngle = calcData.angle; - ev.interimDirection = calcData.direction; - }, + this.constants.physics.centralGravity = this.constants.physics.repulsion.centralGravity; + this.constants.physics.springLength = this.constants.physics.repulsion.springLength; + this.constants.physics.springConstant = this.constants.physics.repulsion.springConstant; + this.constants.physics.damping = this.constants.physics.repulsion.damping; - /** - * extend eventData for Hammer.gestures - * @method extendEventData - * @param {Object} ev - * @return {Object} ev - */ - extendEventData: function extendEventData(ev) { - var cur = this.current, - startEv = cur.startEvent, - lastEv = cur.lastEvent || startEv; + this._loadMixin(RepulsionMixin); + } + }; - // update the start touchlist to calculate the scale/rotation - if(ev.eventType == EVENT_TOUCH || ev.eventType == EVENT_RELEASE) { - startEv.touches = []; - Utils.each(ev.touches, function(touch) { - startEv.touches.push({ - clientX: touch.clientX, - clientY: touch.clientY - }); - }); - } + /** + * Before calculating the forces, we check if we need to cluster to keep up performance and we check + * if there is more than one node. If it is just one node, we dont calculate anything. + * + * @private + */ + exports._initializeForceCalculation = function () { + // stop calculation if there is only one node + if (this.nodeIndices.length == 1) { + this.nodes[this.nodeIndices[0]]._setForce(0, 0); + } + else { + // if there are too many nodes on screen, we cluster without repositioning + if (this.nodeIndices.length > this.constants.clustering.clusterThreshold && this.constants.clustering.enabled == true) { + this.clusterToFit(this.constants.clustering.reduceToNodes, false); + } - var deltaTime = ev.timeStamp - startEv.timeStamp, - deltaX = ev.center.clientX - startEv.center.clientX, - deltaY = ev.center.clientY - startEv.center.clientY; + // we now start the force calculation + this._calculateForces(); + } + }; - this.getCalculatedData(ev, lastEv.center, deltaTime, deltaX, deltaY); - Utils.extend(ev, { - startEvent: startEv, + /** + * Calculate the external forces acting on the nodes + * Forces are caused by: edges, repulsing forces between nodes, gravity + * @private + */ + exports._calculateForces = function () { + // Gravity is required to keep separated groups from floating off + // the forces are reset to zero in this loop by using _setForce instead + // of _addForce - deltaTime: deltaTime, - deltaX: deltaX, - deltaY: deltaY, + this._calculateGravitationalForces(); + this._calculateNodeForces(); - distance: Utils.getDistance(startEv.center, ev.center), - angle: Utils.getAngle(startEv.center, ev.center), - direction: Utils.getDirection(startEv.center, ev.center), - scale: Utils.getScale(startEv.touches, ev.touches), - rotation: Utils.getRotation(startEv.touches, ev.touches) - }); + if (this.constants.physics.springConstant > 0) { + if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { + this._calculateSpringForcesWithSupport(); + } + else { + if (this.constants.physics.hierarchicalRepulsion.enabled == true) { + this._calculateHierarchicalSpringForces(); + } + else { + this._calculateSpringForces(); + } + } + } + }; - return ev; - }, - /** - * register new gesture - * @method register - * @param {Object} gesture object, see `gestures/` for documentation - * @return {Array} gestures - */ - register: function register(gesture) { - // add an enable gesture options if there is no given - var options = gesture.defaults || {}; - if(options[gesture.name] === undefined) { - options[gesture.name] = true; - } + /** + * Smooth curves are created by adding invisible nodes in the center of the edges. These nodes are also + * handled in the calculateForces function. We then use a quadratic curve with the center node as control. + * This function joins the datanodes and invisible (called support) nodes into one object. + * We do this so we do not contaminate this.nodes with the support nodes. + * + * @private + */ + exports._updateCalculationNodes = function () { + if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { + this.calculationNodes = {}; + this.calculationNodeIndices = []; - // extend Hammer default options with the Hammer.gesture options - Utils.extend(Hammer.defaults, options, true); + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + this.calculationNodes[nodeId] = this.nodes[nodeId]; + } + } + var supportNodes = this.sectors['support']['nodes']; + for (var supportNodeId in supportNodes) { + if (supportNodes.hasOwnProperty(supportNodeId)) { + if (this.edges.hasOwnProperty(supportNodes[supportNodeId].parentEdgeId)) { + this.calculationNodes[supportNodeId] = supportNodes[supportNodeId]; + } + else { + supportNodes[supportNodeId]._setForce(0, 0); + } + } + } - // set its index - gesture.index = gesture.index || 1000; + for (var idx in this.calculationNodes) { + if (this.calculationNodes.hasOwnProperty(idx)) { + this.calculationNodeIndices.push(idx); + } + } + } + else { + this.calculationNodes = this.nodes; + this.calculationNodeIndices = this.nodeIndices; + } + }; - // add Hammer.gesture to the list - this.gestures.push(gesture); - // sort the list by index - this.gestures.sort(function(a, b) { - if(a.index < b.index) { - return -1; - } - if(a.index > b.index) { - return 1; - } - return 0; - }); + /** + * this function applies the central gravity effect to keep groups from floating off + * + * @private + */ + exports._calculateGravitationalForces = function () { + var dx, dy, distance, node, i; + var nodes = this.calculationNodes; + var gravity = this.constants.physics.centralGravity; + var gravityForce = 0; - return this.gestures; + for (i = 0; i < this.calculationNodeIndices.length; i++) { + node = nodes[this.calculationNodeIndices[i]]; + node.damping = this.constants.physics.damping; // possibly add function to alter damping properties of clusters. + // gravity does not apply when we are in a pocket sector + if (this._sector() == "default" && gravity != 0) { + dx = -node.x; + dy = -node.y; + distance = Math.sqrt(dx * dx + dy * dy); + + gravityForce = (distance == 0) ? 0 : (gravity / distance); + node.fx = dx * gravityForce; + node.fy = dy * gravityForce; + } + else { + node.fx = 0; + node.fy = 0; } + } }; - /** - * @module hammer - */ + /** - * create new hammer instance - * all methods should return the instance itself, so it is chainable. + * this function calculates the effects of the springs in the case of unsmooth curves. * - * @class Instance - * @constructor - * @param {HTMLElement} element - * @param {Object} [options={}] options are merged with `Hammer.defaults` - * @return {Hammer.Instance} + * @private */ - Hammer.Instance = function(element, options) { - var self = this; - - // setup HammerJS window events and register all gestures - // this also sets up the default options - setup(); + exports._calculateSpringForces = function () { + var edgeLength, edge, edgeId; + var dx, dy, fx, fy, springForce, distance; + var edges = this.edges; - /** - * @property element - * @type {HTMLElement} - */ - this.element = element; + // forces caused by the edges, modelled as springs + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.connected) { + // only calculate forces if nodes are in the same sector + if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { + edgeLength = edge.physics.springLength; + // this implies that the edges between big clusters are longer + edgeLength += (edge.to.clusterSize + edge.from.clusterSize - 2) * this.constants.clustering.edgeGrowth; - /** - * @property enabled - * @type {Boolean} - * @protected - */ - this.enabled = true; + dx = (edge.from.x - edge.to.x); + dy = (edge.from.y - edge.to.y); + distance = Math.sqrt(dx * dx + dy * dy); - /** - * options, merged with the defaults - * options with an _ are converted to camelCase - * @property options - * @type {Object} - */ - Utils.each(options, function(value, name) { - delete options[name]; - options[Utils.toCamelCase(name)] = value; - }); + if (distance == 0) { + distance = 0.01; + } - this.options = Utils.extend(Utils.extend({}, Hammer.defaults), options || {}); + // the 1/distance is so the fx and fy can be calculated without sine or cosine. + springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance; - // add some css to the element to prevent the browser from doing its native behavoir - if(this.options.behavior) { - Utils.toggleBehavior(this.element, this.options.behavior, true); - } + fx = dx * springForce; + fy = dy * springForce; - /** - * event start handler on the element to start the detection - * @property eventStartHandler - * @type {Object} - */ - this.eventStartHandler = Event.onTouch(element, EVENT_START, function(ev) { - if(self.enabled && ev.eventType == EVENT_START) { - Detection.startDetect(self, ev); - } else if(ev.eventType == EVENT_TOUCH) { - Detection.detect(ev); + edge.from.fx += fx; + edge.from.fy += fy; + edge.to.fx -= fx; + edge.to.fy -= fy; } - }); - - /** - * keep a list of user event handlers which needs to be removed when calling 'dispose' - * @property eventHandlers - * @type {Array} - */ - this.eventHandlers = []; + } + } + } }; - Hammer.Instance.prototype = { - /** - * bind events to the instance - * @method on - * @chainable - * @param {String} gestures multiple gestures by splitting with a space - * @param {Function} handler - * @param {Object} handler.ev event object - */ - on: function onEvent(gestures, handler) { - var self = this; - Event.on(self.element, gestures, handler, function(type) { - self.eventHandlers.push({ gesture: type, handler: handler }); - }); - return self; - }, - - /** - * unbind events to the instance - * @method off - * @chainable - * @param {String} gestures - * @param {Function} handler - */ - off: function offEvent(gestures, handler) { - var self = this; - - Event.off(self.element, gestures, handler, function(type) { - var index = Utils.inArray({ gesture: type, handler: handler }); - if(index !== false) { - self.eventHandlers.splice(index, 1); - } - }); - return self; - }, - - /** - * trigger gesture event - * @method trigger - * @chainable - * @param {String} gesture - * @param {Object} [eventData] - */ - trigger: function triggerEvent(gesture, eventData) { - // optional - if(!eventData) { - eventData = {}; - } - // create DOM event - var event = Hammer.DOCUMENT.createEvent('Event'); - event.initEvent(gesture, true, true); - event.gesture = eventData; - // trigger on the target if it is in the instance element, - // this is for event delegation tricks - var element = this.element; - if(Utils.hasParent(eventData.target, element)) { - element = eventData.target; - } - element.dispatchEvent(event); - return this; - }, + /** + * This function calculates the springforces on the nodes, accounting for the support nodes. + * + * @private + */ + exports._calculateSpringForcesWithSupport = function () { + var edgeLength, edge, edgeId, combinedClusterSize; + var edges = this.edges; - /** - * enable of disable hammer.js detection - * @method enable - * @chainable - * @param {Boolean} state - */ - enable: function enable(state) { - this.enabled = state; - return this; - }, + // forces caused by the edges, modelled as springs + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.connected) { + // only calculate forces if nodes are in the same sector + if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { + if (edge.via != null) { + var node1 = edge.to; + var node2 = edge.via; + var node3 = edge.from; - /** - * dispose this hammer instance - * @method dispose - * @return {Null} - */ - dispose: function dispose() { - var i, eh; + edgeLength = edge.physics.springLength; - // undo all changes made by stop_browser_behavior - Utils.toggleBehavior(this.element, this.options.behavior, false); + combinedClusterSize = node1.clusterSize + node3.clusterSize - 2; - // unbind all custom event handlers - for(i = -1; (eh = this.eventHandlers[++i]);) { - Utils.off(this.element, eh.gesture, eh.handler); + // this implies that the edges between big clusters are longer + edgeLength += combinedClusterSize * this.constants.clustering.edgeGrowth; + this._calculateSpringForce(node1, node2, 0.5 * edgeLength); + this._calculateSpringForce(node2, node3, 0.5 * edgeLength); + } } - - this.eventHandlers = []; - - // unbind the start event listener - Event.off(this.element, EVENT_TYPES[EVENT_START], this.eventStartHandler); - - return null; + } } + } }; /** - * @module gestures - */ - /** - * Move with x fingers (default 1) around on the page. - * Preventing the default browser behavior is a good way to improve feel and working. - * ```` - * hammertime.on("drag", function(ev) { - * console.log(ev); - * ev.gesture.preventDefault(); - * }); - * ```` + * This is the code actually performing the calculation for the function above. It is split out to avoid repetition. * - * @class Drag - * @static - */ - /** - * @event drag - * @param {Object} ev - */ - /** - * @event dragstart - * @param {Object} ev - */ - /** - * @event dragend - * @param {Object} ev - */ - /** - * @event drapleft - * @param {Object} ev - */ - /** - * @event dragright - * @param {Object} ev - */ - /** - * @event dragup - * @param {Object} ev - */ - /** - * @event dragdown - * @param {Object} ev - */ - - /** - * @param {String} name + * @param node1 + * @param node2 + * @param edgeLength + * @private */ - (function(name) { - var triggered = false; - - function dragGesture(ev, inst) { - var cur = Detection.current; + exports._calculateSpringForce = function (node1, node2, edgeLength) { + var dx, dy, fx, fy, springForce, distance; - // max touches - if(inst.options.dragMaxTouches > 0 && - ev.touches.length > inst.options.dragMaxTouches) { - return; - } + dx = (node1.x - node2.x); + dy = (node1.y - node2.y); + distance = Math.sqrt(dx * dx + dy * dy); - switch(ev.eventType) { - case EVENT_START: - triggered = false; - break; + if (distance == 0) { + distance = 0.01; + } - case EVENT_MOVE: - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(ev.distance < inst.options.dragMinDistance && - cur.name != name) { - return; - } + // the 1/distance is so the fx and fy can be calculated without sine or cosine. + springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance; - var startCenter = cur.startEvent.center; + fx = dx * springForce; + fy = dy * springForce; - // we are dragging! - if(cur.name != name) { - cur.name = name; - if(inst.options.dragDistanceCorrection && ev.distance > 0) { - // When a drag is triggered, set the event center to dragMinDistance pixels from the original event center. - // Without this correction, the dragged distance would jumpstart at dragMinDistance pixels instead of at 0. - // It might be useful to save the original start point somewhere - var factor = Math.abs(inst.options.dragMinDistance / ev.distance); - startCenter.pageX += ev.deltaX * factor; - startCenter.pageY += ev.deltaY * factor; - startCenter.clientX += ev.deltaX * factor; - startCenter.clientY += ev.deltaY * factor; + node1.fx += fx; + node1.fy += fy; + node2.fx -= fx; + node2.fy -= fy; + }; - // recalculate event data using new start point - ev = Detection.extendEventData(ev); - } - } - // lock drag to axis? - if(cur.lastEvent.dragLockToAxis || - ( inst.options.dragLockToAxis && - inst.options.dragLockMinDistance <= ev.distance - )) { - ev.dragLockToAxis = true; - } + exports._cleanupPhysicsConfiguration = function() { + if (this.physicsConfiguration !== undefined) { + while (this.physicsConfiguration.hasChildNodes()) { + this.physicsConfiguration.removeChild(this.physicsConfiguration.firstChild); + } - // keep direction on the axis that the drag gesture started on - var lastDirection = cur.lastEvent.direction; - if(ev.dragLockToAxis && lastDirection !== ev.direction) { - if(Utils.isVertical(lastDirection)) { - ev.direction = (ev.deltaY < 0) ? DIRECTION_UP : DIRECTION_DOWN; - } else { - ev.direction = (ev.deltaX < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT; - } - } + this.physicsConfiguration.parentNode.removeChild(this.physicsConfiguration); + this.physicsConfiguration = undefined; + } + } - // first time, trigger dragstart event - if(!triggered) { - inst.trigger(name + 'start', ev); - triggered = true; - } + /** + * Load the HTML for the physics config and bind it + * @private + */ + exports._loadPhysicsConfiguration = function () { + if (this.physicsConfiguration === undefined) { + this.backupConstants = {}; + util.deepExtend(this.backupConstants,this.constants); - // trigger events - inst.trigger(name, ev); - inst.trigger(name + ev.direction, ev); + var hierarchicalLayoutDirections = ["LR", "RL", "UD", "DU"]; + this.physicsConfiguration = document.createElement('div'); + this.physicsConfiguration.className = "PhysicsConfiguration"; + this.physicsConfiguration.innerHTML = '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
Simulation Mode:
Barnes HutRepulsionHierarchical
' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
Options:
' + this.containerElement.parentElement.insertBefore(this.physicsConfiguration, this.containerElement); + this.optionsDiv = document.createElement("div"); + this.optionsDiv.style.fontSize = "14px"; + this.optionsDiv.style.fontFamily = "verdana"; + this.containerElement.parentElement.insertBefore(this.optionsDiv, this.containerElement); - var isVertical = Utils.isVertical(ev.direction); + var rangeElement; + rangeElement = document.getElementById('graph_BH_gc'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_gc', -1, "physics_barnesHut_gravitationalConstant"); + rangeElement = document.getElementById('graph_BH_cg'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_cg', 1, "physics_centralGravity"); + rangeElement = document.getElementById('graph_BH_sc'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_sc', 1, "physics_springConstant"); + rangeElement = document.getElementById('graph_BH_sl'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_sl', 1, "physics_springLength"); + rangeElement = document.getElementById('graph_BH_damp'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_damp', 1, "physics_damping"); - // block the browser events - if((inst.options.dragBlockVertical && isVertical) || - (inst.options.dragBlockHorizontal && !isVertical)) { - ev.preventDefault(); - } - break; + rangeElement = document.getElementById('graph_R_nd'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_nd', 1, "physics_repulsion_nodeDistance"); + rangeElement = document.getElementById('graph_R_cg'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_cg', 1, "physics_centralGravity"); + rangeElement = document.getElementById('graph_R_sc'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_sc', 1, "physics_springConstant"); + rangeElement = document.getElementById('graph_R_sl'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_sl', 1, "physics_springLength"); + rangeElement = document.getElementById('graph_R_damp'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_damp', 1, "physics_damping"); - case EVENT_RELEASE: - if(triggered && ev.changedLength <= inst.options.dragMaxTouches) { - inst.trigger(name + 'end', ev); - triggered = false; - } - break; + rangeElement = document.getElementById('graph_H_nd'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_nd', 1, "physics_hierarchicalRepulsion_nodeDistance"); + rangeElement = document.getElementById('graph_H_cg'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_cg', 1, "physics_centralGravity"); + rangeElement = document.getElementById('graph_H_sc'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_sc', 1, "physics_springConstant"); + rangeElement = document.getElementById('graph_H_sl'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_sl', 1, "physics_springLength"); + rangeElement = document.getElementById('graph_H_damp'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_damp', 1, "physics_damping"); + rangeElement = document.getElementById('graph_H_direction'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_direction', hierarchicalLayoutDirections, "hierarchicalLayout_direction"); + rangeElement = document.getElementById('graph_H_levsep'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_levsep', 1, "hierarchicalLayout_levelSeparation"); + rangeElement = document.getElementById('graph_H_nspac'); + rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_nspac', 1, "hierarchicalLayout_nodeSpacing"); - case EVENT_END: - triggered = false; - break; - } + var radioButton1 = document.getElementById("graph_physicsMethod1"); + var radioButton2 = document.getElementById("graph_physicsMethod2"); + var radioButton3 = document.getElementById("graph_physicsMethod3"); + radioButton2.checked = true; + if (this.constants.physics.barnesHut.enabled) { + radioButton1.checked = true; + } + if (this.constants.hierarchicalLayout.enabled) { + radioButton3.checked = true; } - Hammer.gestures.Drag = { - name: name, - index: 50, - handler: dragGesture, - defaults: { - /** - * minimal movement that have to be made before the drag event gets triggered - * @property dragMinDistance - * @type {Number} - * @default 10 - */ - dragMinDistance: 10, - - /** - * Set dragDistanceCorrection to true to make the starting point of the drag - * be calculated from where the drag was triggered, not from where the touch started. - * Useful to avoid a jerk-starting drag, which can make fine-adjustments - * through dragging difficult, and be visually unappealing. - * @property dragDistanceCorrection - * @type {Boolean} - * @default true - */ - dragDistanceCorrection: true, - - /** - * set 0 for unlimited, but this can conflict with transform - * @property dragMaxTouches - * @type {Number} - * @default 1 - */ - dragMaxTouches: 1, + var graph_toggleSmooth = document.getElementById("graph_toggleSmooth"); + var graph_repositionNodes = document.getElementById("graph_repositionNodes"); + var graph_generateOptions = document.getElementById("graph_generateOptions"); - /** - * prevent default browser behavior when dragging occurs - * be careful with it, it makes the element a blocking element - * when you are using the drag gesture, it is a good practice to set this true - * @property dragBlockHorizontal - * @type {Boolean} - * @default false - */ - dragBlockHorizontal: false, + graph_toggleSmooth.onclick = graphToggleSmoothCurves.bind(this); + graph_repositionNodes.onclick = graphRepositionNodes.bind(this); + graph_generateOptions.onclick = graphGenerateOptions.bind(this); + if (this.constants.smoothCurves == true && this.constants.dynamicSmoothCurves == false) { + graph_toggleSmooth.style.background = "#A4FF56"; + } + else { + graph_toggleSmooth.style.background = "#FF8532"; + } - /** - * same as `dragBlockHorizontal`, but for vertical movement - * @property dragBlockVertical - * @type {Boolean} - * @default false - */ - dragBlockVertical: false, - /** - * dragLockToAxis keeps the drag gesture on the axis that it started on, - * It disallows vertical directions if the initial direction was horizontal, and vice versa. - * @property dragLockToAxis - * @type {Boolean} - * @default false - */ - dragLockToAxis: false, + switchConfigurations.apply(this); - /** - * drag lock only kicks in when distance > dragLockMinDistance - * This way, locking occurs only when the distance has become large enough to reliably determine the direction - * @property dragLockMinDistance - * @type {Number} - * @default 25 - */ - dragLockMinDistance: 25 - } - }; - })('drag'); + radioButton1.onchange = switchConfigurations.bind(this); + radioButton2.onchange = switchConfigurations.bind(this); + radioButton3.onchange = switchConfigurations.bind(this); + } + }; /** - * @module gestures - */ - /** - * trigger a simple gesture event, so you can do anything in your handler. - * only usable if you know what your doing... + * This overwrites the this.constants. * - * @class Gesture - * @static - */ - /** - * @event gesture - * @param {Object} ev + * @param constantsVariableName + * @param value + * @private */ - Hammer.gestures.Gesture = { - name: 'gesture', - index: 1337, - handler: function releaseGesture(ev, inst) { - inst.trigger(this.name, ev); - } + exports._overWriteGraphConstants = function (constantsVariableName, value) { + var nameArray = constantsVariableName.split("_"); + if (nameArray.length == 1) { + this.constants[nameArray[0]] = value; + } + else if (nameArray.length == 2) { + this.constants[nameArray[0]][nameArray[1]] = value; + } + else if (nameArray.length == 3) { + this.constants[nameArray[0]][nameArray[1]][nameArray[2]] = value; + } }; + /** - * @module gestures + * this function is bound to the toggle smooth curves button. That is also why it is not in the prototype. */ + function graphToggleSmoothCurves () { + this.constants.smoothCurves.enabled = !this.constants.smoothCurves.enabled; + var graph_toggleSmooth = document.getElementById("graph_toggleSmooth"); + if (this.constants.smoothCurves.enabled == true) {graph_toggleSmooth.style.background = "#A4FF56";} + else {graph_toggleSmooth.style.background = "#FF8532";} + + this._configureSmoothCurves(false); + } + /** - * Touch stays at the same place for x time + * this function is used to scramble the nodes * - * @class Hold - * @static - */ - /** - * @event hold - * @param {Object} ev */ + function graphRepositionNodes () { + for (var nodeId in this.calculationNodes) { + if (this.calculationNodes.hasOwnProperty(nodeId)) { + this.calculationNodes[nodeId].vx = 0; this.calculationNodes[nodeId].vy = 0; + this.calculationNodes[nodeId].fx = 0; this.calculationNodes[nodeId].fy = 0; + } + } + if (this.constants.hierarchicalLayout.enabled == true) { + this._setupHierarchicalLayout(); + showValueOfRange.call(this, 'graph_H_nd', 1, "physics_hierarchicalRepulsion_nodeDistance"); + showValueOfRange.call(this, 'graph_H_cg', 1, "physics_centralGravity"); + showValueOfRange.call(this, 'graph_H_sc', 1, "physics_springConstant"); + showValueOfRange.call(this, 'graph_H_sl', 1, "physics_springLength"); + showValueOfRange.call(this, 'graph_H_damp', 1, "physics_damping"); + } + else { + this.repositionNodes(); + } + this.moving = true; + this.start(); + } /** - * @param {String} name + * this is used to generate an options file from the playing with physics system. */ - (function(name) { - var timer; - - function holdGesture(ev, inst) { - var options = inst.options, - current = Detection.current; - - switch(ev.eventType) { - case EVENT_START: - clearTimeout(timer); - - // set the gesture so we can check in the timeout if it still is - current.name = name; - - // set timer and if after the timeout it still is hold, - // we trigger the hold event - timer = setTimeout(function() { - if(current && current.name == name) { - inst.trigger(name, ev); - } - }, options.holdTimeout); - break; - - case EVENT_MOVE: - if(ev.distance > options.holdThreshold) { - clearTimeout(timer); - } - break; - - case EVENT_RELEASE: - clearTimeout(timer); - break; + function graphGenerateOptions () { + var options = "No options are required, default values used."; + var optionsSpecific = []; + var radioButton1 = document.getElementById("graph_physicsMethod1"); + var radioButton2 = document.getElementById("graph_physicsMethod2"); + if (radioButton1.checked == true) { + if (this.constants.physics.barnesHut.gravitationalConstant != this.backupConstants.physics.barnesHut.gravitationalConstant) {optionsSpecific.push("gravitationalConstant: " + this.constants.physics.barnesHut.gravitationalConstant);} + if (this.constants.physics.centralGravity != this.backupConstants.physics.barnesHut.centralGravity) {optionsSpecific.push("centralGravity: " + this.constants.physics.centralGravity);} + if (this.constants.physics.springLength != this.backupConstants.physics.barnesHut.springLength) {optionsSpecific.push("springLength: " + this.constants.physics.springLength);} + if (this.constants.physics.springConstant != this.backupConstants.physics.barnesHut.springConstant) {optionsSpecific.push("springConstant: " + this.constants.physics.springConstant);} + if (this.constants.physics.damping != this.backupConstants.physics.barnesHut.damping) {optionsSpecific.push("damping: " + this.constants.physics.damping);} + if (optionsSpecific.length != 0) { + options = "var options = {"; + options += "physics: {barnesHut: {"; + for (var i = 0; i < optionsSpecific.length; i++) { + options += optionsSpecific[i]; + if (i < optionsSpecific.length - 1) { + options += ", " + } + } + options += '}}' + } + if (this.constants.smoothCurves.enabled != this.backupConstants.smoothCurves.enabled) { + if (optionsSpecific.length == 0) {options = "var options = {";} + else {options += ", "} + options += "smoothCurves: " + this.constants.smoothCurves.enabled; + } + if (options != "No options are required, default values used.") { + options += '};' + } + } + else if (radioButton2.checked == true) { + options = "var options = {"; + options += "physics: {barnesHut: {enabled: false}"; + if (this.constants.physics.repulsion.nodeDistance != this.backupConstants.physics.repulsion.nodeDistance) {optionsSpecific.push("nodeDistance: " + this.constants.physics.repulsion.nodeDistance);} + if (this.constants.physics.centralGravity != this.backupConstants.physics.repulsion.centralGravity) {optionsSpecific.push("centralGravity: " + this.constants.physics.centralGravity);} + if (this.constants.physics.springLength != this.backupConstants.physics.repulsion.springLength) {optionsSpecific.push("springLength: " + this.constants.physics.springLength);} + if (this.constants.physics.springConstant != this.backupConstants.physics.repulsion.springConstant) {optionsSpecific.push("springConstant: " + this.constants.physics.springConstant);} + if (this.constants.physics.damping != this.backupConstants.physics.repulsion.damping) {optionsSpecific.push("damping: " + this.constants.physics.damping);} + if (optionsSpecific.length != 0) { + options += ", repulsion: {"; + for (var i = 0; i < optionsSpecific.length; i++) { + options += optionsSpecific[i]; + if (i < optionsSpecific.length - 1) { + options += ", " + } + } + options += '}}' + } + if (optionsSpecific.length == 0) {options += "}"} + if (this.constants.smoothCurves != this.backupConstants.smoothCurves) { + options += ", smoothCurves: " + this.constants.smoothCurves; + } + options += '};' + } + else { + options = "var options = {"; + if (this.constants.physics.hierarchicalRepulsion.nodeDistance != this.backupConstants.physics.hierarchicalRepulsion.nodeDistance) {optionsSpecific.push("nodeDistance: " + this.constants.physics.hierarchicalRepulsion.nodeDistance);} + if (this.constants.physics.centralGravity != this.backupConstants.physics.hierarchicalRepulsion.centralGravity) {optionsSpecific.push("centralGravity: " + this.constants.physics.centralGravity);} + if (this.constants.physics.springLength != this.backupConstants.physics.hierarchicalRepulsion.springLength) {optionsSpecific.push("springLength: " + this.constants.physics.springLength);} + if (this.constants.physics.springConstant != this.backupConstants.physics.hierarchicalRepulsion.springConstant) {optionsSpecific.push("springConstant: " + this.constants.physics.springConstant);} + if (this.constants.physics.damping != this.backupConstants.physics.hierarchicalRepulsion.damping) {optionsSpecific.push("damping: " + this.constants.physics.damping);} + if (optionsSpecific.length != 0) { + options += "physics: {hierarchicalRepulsion: {"; + for (var i = 0; i < optionsSpecific.length; i++) { + options += optionsSpecific[i]; + if (i < optionsSpecific.length - 1) { + options += ", "; + } + } + options += '}},'; + } + options += 'hierarchicalLayout: {'; + optionsSpecific = []; + if (this.constants.hierarchicalLayout.direction != this.backupConstants.hierarchicalLayout.direction) {optionsSpecific.push("direction: " + this.constants.hierarchicalLayout.direction);} + if (Math.abs(this.constants.hierarchicalLayout.levelSeparation) != this.backupConstants.hierarchicalLayout.levelSeparation) {optionsSpecific.push("levelSeparation: " + this.constants.hierarchicalLayout.levelSeparation);} + if (this.constants.hierarchicalLayout.nodeSpacing != this.backupConstants.hierarchicalLayout.nodeSpacing) {optionsSpecific.push("nodeSpacing: " + this.constants.hierarchicalLayout.nodeSpacing);} + if (optionsSpecific.length != 0) { + for (var i = 0; i < optionsSpecific.length; i++) { + options += optionsSpecific[i]; + if (i < optionsSpecific.length - 1) { + options += ", " } + } + options += '}' } + else { + options += "enabled:true}"; + } + options += '};' + } - Hammer.gestures.Hold = { - name: name, - index: 10, - defaults: { - /** - * @property holdTimeout - * @type {Number} - * @default 500 - */ - holdTimeout: 500, - /** - * movement allowed while holding - * @property holdThreshold - * @type {Number} - * @default 2 - */ - holdThreshold: 2 - }, - handler: holdGesture - }; - })('hold'); + this.optionsDiv.innerHTML = options; + } /** - * @module gestures - */ - /** - * when a touch is being released from the page + * this is used to switch between barnesHut, repulsion and hierarchical. * - * @class Release - * @static - */ - /** - * @event release - * @param {Object} ev */ - Hammer.gestures.Release = { - name: 'release', - index: Infinity, - handler: function releaseGesture(ev, inst) { - if(ev.eventType == EVENT_RELEASE) { - inst.trigger(this.name, ev); - } + function switchConfigurations () { + var ids = ["graph_BH_table", "graph_R_table", "graph_H_table"]; + var radioButton = document.querySelector('input[name="graph_physicsMethod"]:checked').value; + var tableId = "graph_" + radioButton + "_table"; + var table = document.getElementById(tableId); + table.style.display = "block"; + for (var i = 0; i < ids.length; i++) { + if (ids[i] != tableId) { + table = document.getElementById(ids[i]); + table.style.display = "none"; } - }; + } + this._restoreNodes(); + if (radioButton == "R") { + this.constants.hierarchicalLayout.enabled = false; + this.constants.physics.hierarchicalRepulsion.enabled = false; + this.constants.physics.barnesHut.enabled = false; + } + else if (radioButton == "H") { + if (this.constants.hierarchicalLayout.enabled == false) { + this.constants.hierarchicalLayout.enabled = true; + this.constants.physics.hierarchicalRepulsion.enabled = true; + this.constants.physics.barnesHut.enabled = false; + this.constants.smoothCurves.enabled = false; + this._setupHierarchicalLayout(); + } + } + else { + this.constants.hierarchicalLayout.enabled = false; + this.constants.physics.hierarchicalRepulsion.enabled = false; + this.constants.physics.barnesHut.enabled = true; + } + this._loadSelectedForceSolver(); + var graph_toggleSmooth = document.getElementById("graph_toggleSmooth"); + if (this.constants.smoothCurves.enabled == true) {graph_toggleSmooth.style.background = "#A4FF56";} + else {graph_toggleSmooth.style.background = "#FF8532";} + this.moving = true; + this.start(); + } + /** - * @module gestures - */ - /** - * triggers swipe events when the end velocity is above the threshold - * for best usage, set `preventDefault` (on the drag gesture) to `true` - * ```` - * hammertime.on("dragleft swipeleft", function(ev) { - * console.log(ev); - * ev.gesture.preventDefault(); - * }); - * ```` + * this generates the ranges depending on the iniital values. * - * @class Swipe - * @static - */ - /** - * @event swipe - * @param {Object} ev - */ - /** - * @event swipeleft - * @param {Object} ev - */ - /** - * @event swiperight - * @param {Object} ev - */ - /** - * @event swipeup - * @param {Object} ev - */ - /** - * @event swipedown - * @param {Object} ev + * @param id + * @param map + * @param constantsVariableName */ - Hammer.gestures.Swipe = { - name: 'swipe', - index: 40, - defaults: { - /** - * @property swipeMinTouches - * @type {Number} - * @default 1 - */ - swipeMinTouches: 1, + function showValueOfRange (id,map,constantsVariableName) { + var valueId = id + "_value"; + var rangeValue = document.getElementById(id).value; - /** - * @property swipeMaxTouches - * @type {Number} - * @default 1 - */ - swipeMaxTouches: 1, + if (Array.isArray(map)) { + document.getElementById(valueId).value = map[parseInt(rangeValue)]; + this._overWriteGraphConstants(constantsVariableName,map[parseInt(rangeValue)]); + } + else { + document.getElementById(valueId).value = parseInt(map) * parseFloat(rangeValue); + this._overWriteGraphConstants(constantsVariableName, parseInt(map) * parseFloat(rangeValue)); + } - /** - * horizontal swipe velocity - * @property swipeVelocityX - * @type {Number} - * @default 0.6 - */ - swipeVelocityX: 0.6, + if (constantsVariableName == "hierarchicalLayout_direction" || + constantsVariableName == "hierarchicalLayout_levelSeparation" || + constantsVariableName == "hierarchicalLayout_nodeSpacing") { + this._setupHierarchicalLayout(); + } + this.moving = true; + this.start(); + } - /** - * vertical swipe velocity - * @property swipeVelocityY - * @type {Number} - * @default 0.6 - */ - swipeVelocityY: 0.6 - }, - handler: function swipeGesture(ev, inst) { - if(ev.eventType == EVENT_RELEASE) { - var touches = ev.touches.length, - options = inst.options; - // max touches - if(touches < options.swipeMinTouches || - touches > options.swipeMaxTouches) { - return; - } - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(ev.velocityX > options.swipeVelocityX || - ev.velocityY > options.swipeVelocityY) { - // trigger swipe events - inst.trigger(this.name, ev); - inst.trigger(this.name + ev.direction, ev); - } - } +/***/ }, +/* 61 */ +/***/ function(module, exports, __webpack_require__) { + + var util = __webpack_require__(1); + var Node = __webpack_require__(40); + var Edge = __webpack_require__(37); + + /** + * clears the toolbar div element of children + * + * @private + */ + exports._clearManipulatorBar = function() { + this._recursiveDOMDelete(this.manipulationDiv); + this.manipulationDOM = {}; + + this._manipulationReleaseOverload = function () {}; + delete this.sectors['support']['nodes']['targetNode']; + delete this.sectors['support']['nodes']['targetViaNode']; + this.controlNodesActive = false; + this.freezeSimulation = false; + }; + + /** + * Manipulation UI temporarily overloads certain functions to extend or replace them. To be able to restore + * these functions to their original functionality, we saved them in this.cachedFunctions. + * This function restores these functions to their original function. + * + * @private + */ + exports._restoreOverloadedFunctions = function() { + for (var functionName in this.cachedFunctions) { + if (this.cachedFunctions.hasOwnProperty(functionName)) { + this[functionName] = this.cachedFunctions[functionName]; + delete this.cachedFunctions[functionName]; } + } }; /** - * @module gestures - */ - /** - * Single tap and a double tap on a place + * Enable or disable edit-mode. * - * @class Tap - * @static - */ - /** - * @event tap - * @param {Object} ev - */ - /** - * @event doubletap - * @param {Object} ev + * @private */ + exports._toggleEditMode = function() { + this.editMode = !this.editMode; + var toolbar = this.manipulationDiv; + var closeDiv = this.closeDiv; + var editModeDiv = this.editModeDiv; + if (this.editMode == true) { + toolbar.style.display="block"; + closeDiv.style.display="block"; + editModeDiv.style.display="none"; + closeDiv.onclick = this._toggleEditMode.bind(this); + } + else { + toolbar.style.display="none"; + closeDiv.style.display="none"; + editModeDiv.style.display="block"; + closeDiv.onclick = null; + } + this._createManipulatorBar() + }; /** - * @param {String} name + * main function, creates the main toolbar. Removes functions bound to the select event. Binds all the buttons of the toolbar. + * + * @private */ - (function(name) { - var hasMoved = false; + exports._createManipulatorBar = function() { + // remove bound functions + if (this.boundFunction) { + this.off('select', this.boundFunction); + } - function tapGesture(ev, inst) { - var options = inst.options, - current = Detection.current, - prev = Detection.previous, - sincePrev, - didDoubleTap; + var locale = this.constants.locales[this.constants.locale]; - switch(ev.eventType) { - case EVENT_START: - hasMoved = false; - break; + if (this.edgeBeingEdited !== undefined) { + this.edgeBeingEdited._disableControlNodes(); + this.edgeBeingEdited = undefined; + this.selectedControlNode = null; + this.controlNodesActive = false; + this._redraw(); + } - case EVENT_MOVE: - hasMoved = hasMoved || (ev.distance > options.tapMaxDistance); - break; + // restore overloaded functions + this._restoreOverloadedFunctions(); - case EVENT_END: - if(!Utils.inStr(ev.srcEvent.type, 'cancel') && ev.deltaTime < options.tapMaxTime && !hasMoved) { - // previous gesture, for the double tap since these are two different gesture detections - sincePrev = prev && prev.lastEvent && ev.timeStamp - prev.lastEvent.timeStamp; - didDoubleTap = false; + // resume calculation + this.freezeSimulation = false; - // check if double tap - if(prev && prev.name == name && - (sincePrev && sincePrev < options.doubleTapInterval) && - ev.distance < options.doubleTapDistance) { - inst.trigger('doubletap', ev); - didDoubleTap = true; - } + // reset global variables + this.blockConnectingEdgeSelection = false; + this.forceAppendSelection = false; + this.manipulationDOM = {}; - // do a single tap - if(!didDoubleTap || options.tapAlways) { - current.name = name; - inst.trigger(current.name, ev); - } - } - break; - } + if (this.editMode == true) { + while (this.manipulationDiv.hasChildNodes()) { + this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); } - Hammer.gestures.Tap = { - name: name, - index: 100, - handler: tapGesture, - defaults: { - /** - * max time of a tap, this is for the slow tappers - * @property tapMaxTime - * @type {Number} - * @default 250 - */ - tapMaxTime: 250, + this.manipulationDOM['addNodeSpan'] = document.createElement('span'); + this.manipulationDOM['addNodeSpan'].className = 'network-manipulationUI add'; + this.manipulationDOM['addNodeLabelSpan'] = document.createElement('span'); + this.manipulationDOM['addNodeLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['addNodeLabelSpan'].innerHTML = locale['addNode']; + this.manipulationDOM['addNodeSpan'].appendChild(this.manipulationDOM['addNodeLabelSpan']); - /** - * max distance of movement of a tap, this is for the slow tappers - * @property tapMaxDistance - * @type {Number} - * @default 10 - */ - tapMaxDistance: 10, + this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); + this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; - /** - * always trigger the `tap` event, even while double-tapping - * @property tapAlways - * @type {Boolean} - * @default true - */ - tapAlways: true, + this.manipulationDOM['addEdgeSpan'] = document.createElement('span'); + this.manipulationDOM['addEdgeSpan'].className = 'network-manipulationUI connect'; + this.manipulationDOM['addEdgeLabelSpan'] = document.createElement('span'); + this.manipulationDOM['addEdgeLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['addEdgeLabelSpan'].innerHTML = locale['addEdge']; + this.manipulationDOM['addEdgeSpan'].appendChild(this.manipulationDOM['addEdgeLabelSpan']); - /** - * max distance between two taps - * @property doubleTapDistance - * @type {Number} - * @default 20 - */ - doubleTapDistance: 20, + this.manipulationDiv.appendChild(this.manipulationDOM['addNodeSpan']); + this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); + this.manipulationDiv.appendChild(this.manipulationDOM['addEdgeSpan']); - /** - * max time between two taps - * @property doubleTapInterval - * @type {Number} - * @default 300 - */ - doubleTapInterval: 300 - } - }; - })('tap'); + if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) { + this.manipulationDOM['seperatorLineDiv2'] = document.createElement('div'); + this.manipulationDOM['seperatorLineDiv2'].className = 'network-seperatorLine'; - /** - * @module gestures - */ - /** - * when a touch is being touched at the page - * - * @class Touch - * @static - */ - /** - * @event touch - * @param {Object} ev - */ - Hammer.gestures.Touch = { - name: 'touch', - index: -Infinity, - defaults: { - /** - * call preventDefault at touchstart, and makes the element blocking by disabling the scrolling of the page, - * but it improves gestures like transforming and dragging. - * be careful with using this, it can be very annoying for users to be stuck on the page - * @property preventDefault - * @type {Boolean} - * @default false - */ - preventDefault: false, + this.manipulationDOM['editNodeSpan'] = document.createElement('span'); + this.manipulationDOM['editNodeSpan'].className = 'network-manipulationUI edit'; + this.manipulationDOM['editNodeLabelSpan'] = document.createElement('span'); + this.manipulationDOM['editNodeLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['editNodeLabelSpan'].innerHTML = locale['editNode']; + this.manipulationDOM['editNodeSpan'].appendChild(this.manipulationDOM['editNodeLabelSpan']); - /** - * disable mouse events, so only touch (or pen!) input triggers events - * @property preventMouse - * @type {Boolean} - * @default false - */ - preventMouse: false - }, - handler: function touchGesture(ev, inst) { - if(inst.options.preventMouse && ev.pointerType == POINTER_MOUSE) { - ev.stopDetect(); - return; - } + this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv2']); + this.manipulationDiv.appendChild(this.manipulationDOM['editNodeSpan']); + } + else if (this._getSelectedEdgeCount() == 1 && this._getSelectedNodeCount() == 0) { + this.manipulationDOM['seperatorLineDiv3'] = document.createElement('div'); + this.manipulationDOM['seperatorLineDiv3'].className = 'network-seperatorLine'; - if(inst.options.preventDefault) { - ev.preventDefault(); - } + this.manipulationDOM['editEdgeSpan'] = document.createElement('span'); + this.manipulationDOM['editEdgeSpan'].className = 'network-manipulationUI edit'; + this.manipulationDOM['editEdgeLabelSpan'] = document.createElement('span'); + this.manipulationDOM['editEdgeLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['editEdgeLabelSpan'].innerHTML = locale['editEdge']; + this.manipulationDOM['editEdgeSpan'].appendChild(this.manipulationDOM['editEdgeLabelSpan']); - if(ev.eventType == EVENT_TOUCH) { - inst.trigger('touch', ev); - } + this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv3']); + this.manipulationDiv.appendChild(this.manipulationDOM['editEdgeSpan']); + } + if (this._selectionIsEmpty() == false) { + this.manipulationDOM['seperatorLineDiv4'] = document.createElement('div'); + this.manipulationDOM['seperatorLineDiv4'].className = 'network-seperatorLine'; + + this.manipulationDOM['deleteSpan'] = document.createElement('span'); + this.manipulationDOM['deleteSpan'].className = 'network-manipulationUI delete'; + this.manipulationDOM['deleteLabelSpan'] = document.createElement('span'); + this.manipulationDOM['deleteLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['deleteLabelSpan'].innerHTML = locale['del']; + this.manipulationDOM['deleteSpan'].appendChild(this.manipulationDOM['deleteLabelSpan']); + + this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv4']); + this.manipulationDiv.appendChild(this.manipulationDOM['deleteSpan']); + } + + + // bind the icons + this.manipulationDOM['addNodeSpan'].onclick = this._createAddNodeToolbar.bind(this); + this.manipulationDOM['addEdgeSpan'].onclick = this._createAddEdgeToolbar.bind(this); + if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) { + this.manipulationDOM['editNodeSpan'].onclick = this._editNode.bind(this); } + else if (this._getSelectedEdgeCount() == 1 && this._getSelectedNodeCount() == 0) { + this.manipulationDOM['editEdgeSpan'].onclick = this._createEditEdgeToolbar.bind(this); + } + if (this._selectionIsEmpty() == false) { + this.manipulationDOM['deleteSpan'].onclick = this._deleteSelected.bind(this); + } + this.closeDiv.onclick = this._toggleEditMode.bind(this); + + var me = this; + this.boundFunction = me._createManipulatorBar; + this.on('select', this.boundFunction); + } + else { + while (this.editModeDiv.hasChildNodes()) { + this.editModeDiv.removeChild(this.editModeDiv.firstChild); + } + + this.manipulationDOM['editModeSpan'] = document.createElement('span'); + this.manipulationDOM['editModeSpan'].className = 'network-manipulationUI edit editmode'; + this.manipulationDOM['editModeLabelSpan'] = document.createElement('span'); + this.manipulationDOM['editModeLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['editModeLabelSpan'].innerHTML = locale['edit']; + this.manipulationDOM['editModeSpan'].appendChild(this.manipulationDOM['editModeLabelSpan']); + + this.editModeDiv.appendChild(this.manipulationDOM['editModeSpan']); + + this.manipulationDOM['editModeSpan'].onclick = this._toggleEditMode.bind(this); + } }; + + /** - * @module gestures - */ - /** - * User want to scale or rotate with 2 fingers - * Preventing the default browser behavior is a good way to improve feel and working. This can be done with the - * `preventDefault` option. + * Create the toolbar for adding Nodes * - * @class Transform - * @static - */ - /** - * @event transform - * @param {Object} ev - */ - /** - * @event transformstart - * @param {Object} ev - */ - /** - * @event transformend - * @param {Object} ev - */ - /** - * @event pinchin - * @param {Object} ev - */ - /** - * @event pinchout - * @param {Object} ev - */ - /** - * @event rotate - * @param {Object} ev + * @private */ + exports._createAddNodeToolbar = function() { + // clear the toolbar + this._clearManipulatorBar(); + if (this.boundFunction) { + this.off('select', this.boundFunction); + } + + var locale = this.constants.locales[this.constants.locale]; + + this.manipulationDOM = {}; + this.manipulationDOM['backSpan'] = document.createElement('span'); + this.manipulationDOM['backSpan'].className = 'network-manipulationUI back'; + this.manipulationDOM['backLabelSpan'] = document.createElement('span'); + this.manipulationDOM['backLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['backLabelSpan'].innerHTML = locale['back']; + this.manipulationDOM['backSpan'].appendChild(this.manipulationDOM['backLabelSpan']); + + this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); + this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; + + this.manipulationDOM['descriptionSpan'] = document.createElement('span'); + this.manipulationDOM['descriptionSpan'].className = 'network-manipulationUI none'; + this.manipulationDOM['descriptionLabelSpan'] = document.createElement('span'); + this.manipulationDOM['descriptionLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['descriptionLabelSpan'].innerHTML = locale['addDescription']; + this.manipulationDOM['descriptionSpan'].appendChild(this.manipulationDOM['descriptionLabelSpan']); + + this.manipulationDiv.appendChild(this.manipulationDOM['backSpan']); + this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); + this.manipulationDiv.appendChild(this.manipulationDOM['descriptionSpan']); + + // bind the icon + this.manipulationDOM['backSpan'].onclick = this._createManipulatorBar.bind(this); + + // we use the boundFunction so we can reference it when we unbind it from the "select" event. + var me = this; + this.boundFunction = me._addNode; + this.on('select', this.boundFunction); + }; + /** - * @param {String} name + * create the toolbar to connect nodes + * + * @private */ - (function(name) { - var triggered = false; + exports._createAddEdgeToolbar = function() { + // clear the toolbar + this._clearManipulatorBar(); + this._unselectAll(true); + this.freezeSimulation = true; - function transformGesture(ev, inst) { - switch(ev.eventType) { - case EVENT_START: - triggered = false; - break; + if (this.boundFunction) { + this.off('select', this.boundFunction); + } - case EVENT_MOVE: - // at least multitouch - if(ev.touches.length < 2) { - return; - } + var locale = this.constants.locales[this.constants.locale]; - var scaleThreshold = Math.abs(1 - ev.scale); - var rotationThreshold = Math.abs(ev.rotation); + this._unselectAll(); + this.forceAppendSelection = false; + this.blockConnectingEdgeSelection = true; - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(scaleThreshold < inst.options.transformMinScale && - rotationThreshold < inst.options.transformMinRotation) { - return; - } + this.manipulationDOM = {}; + this.manipulationDOM['backSpan'] = document.createElement('span'); + this.manipulationDOM['backSpan'].className = 'network-manipulationUI back'; + this.manipulationDOM['backLabelSpan'] = document.createElement('span'); + this.manipulationDOM['backLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['backLabelSpan'].innerHTML = locale['back']; + this.manipulationDOM['backSpan'].appendChild(this.manipulationDOM['backLabelSpan']); - // we are transforming! - Detection.current.name = name; + this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); + this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; - // first time, trigger dragstart event - if(!triggered) { - inst.trigger(name + 'start', ev); - triggered = true; - } + this.manipulationDOM['descriptionSpan'] = document.createElement('span'); + this.manipulationDOM['descriptionSpan'].className = 'network-manipulationUI none'; + this.manipulationDOM['descriptionLabelSpan'] = document.createElement('span'); + this.manipulationDOM['descriptionLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['descriptionLabelSpan'].innerHTML = locale['edgeDescription']; + this.manipulationDOM['descriptionSpan'].appendChild(this.manipulationDOM['descriptionLabelSpan']); - inst.trigger(name, ev); // basic transform event + this.manipulationDiv.appendChild(this.manipulationDOM['backSpan']); + this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); + this.manipulationDiv.appendChild(this.manipulationDOM['descriptionSpan']); - // trigger rotate event - if(rotationThreshold > inst.options.transformMinRotation) { - inst.trigger('rotate', ev); - } + // bind the icon + this.manipulationDOM['backSpan'].onclick = this._createManipulatorBar.bind(this); - // trigger pinch event - if(scaleThreshold > inst.options.transformMinScale) { - inst.trigger('pinch', ev); - inst.trigger('pinch' + (ev.scale < 1 ? 'in' : 'out'), ev); - } - break; + // we use the boundFunction so we can reference it when we unbind it from the "select" event. + var me = this; + this.boundFunction = me._handleConnect; + this.on('select', this.boundFunction); - case EVENT_RELEASE: - if(triggered && ev.changedLength < 2) { - inst.trigger(name + 'end', ev); - triggered = false; - } - break; - } - } + // temporarily overload functions + this.cachedFunctions["_handleTouch"] = this._handleTouch; + this.cachedFunctions["_manipulationReleaseOverload"] = this._manipulationReleaseOverload; + this.cachedFunctions["_handleDragStart"] = this._handleDragStart; + this.cachedFunctions["_handleDragEnd"] = this._handleDragEnd; + this._handleTouch = this._handleConnect; + this._manipulationReleaseOverload = function () {}; + this._handleDragStart = function () {}; + this._handleDragEnd = this._finishConnect; - Hammer.gestures.Transform = { - name: name, - index: 45, - defaults: { - /** - * minimal scale factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1 - * @property transformMinScale - * @type {Number} - * @default 0.01 - */ - transformMinScale: 0.01, + // redraw to show the unselect + this._redraw(); + }; + + /** + * create the toolbar to edit edges + * + * @private + */ + exports._createEditEdgeToolbar = function() { + // clear the toolbar + this._clearManipulatorBar(); + this.controlNodesActive = true; + + if (this.boundFunction) { + this.off('select', this.boundFunction); + } + + this.edgeBeingEdited = this._getSelectedEdge(); + this.edgeBeingEdited._enableControlNodes(); + + var locale = this.constants.locales[this.constants.locale]; + + this.manipulationDOM = {}; + this.manipulationDOM['backSpan'] = document.createElement('span'); + this.manipulationDOM['backSpan'].className = 'network-manipulationUI back'; + this.manipulationDOM['backLabelSpan'] = document.createElement('span'); + this.manipulationDOM['backLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['backLabelSpan'].innerHTML = locale['back']; + this.manipulationDOM['backSpan'].appendChild(this.manipulationDOM['backLabelSpan']); + + this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); + this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; + + this.manipulationDOM['descriptionSpan'] = document.createElement('span'); + this.manipulationDOM['descriptionSpan'].className = 'network-manipulationUI none'; + this.manipulationDOM['descriptionLabelSpan'] = document.createElement('span'); + this.manipulationDOM['descriptionLabelSpan'].className = 'network-manipulationLabel'; + this.manipulationDOM['descriptionLabelSpan'].innerHTML = locale['editEdgeDescription']; + this.manipulationDOM['descriptionSpan'].appendChild(this.manipulationDOM['descriptionLabelSpan']); + + this.manipulationDiv.appendChild(this.manipulationDOM['backSpan']); + this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); + this.manipulationDiv.appendChild(this.manipulationDOM['descriptionSpan']); + + // bind the icon + this.manipulationDOM['backSpan'].onclick = this._createManipulatorBar.bind(this); - /** - * rotation in degrees - * @property transformMinRotation - * @type {Number} - * @default 1 - */ - transformMinRotation: 1 - }, + // temporarily overload functions + this.cachedFunctions["_handleTouch"] = this._handleTouch; + this.cachedFunctions["_manipulationReleaseOverload"] = this._manipulationReleaseOverload; + this.cachedFunctions["_handleTap"] = this._handleTap; + this.cachedFunctions["_handleDragStart"] = this._handleDragStart; + this.cachedFunctions["_handleOnDrag"] = this._handleOnDrag; + this._handleTouch = this._selectControlNode; + this._handleTap = function () {}; + this._handleOnDrag = this._controlNodeDrag; + this._handleDragStart = function () {} + this._manipulationReleaseOverload = this._releaseControlNode; + + // redraw to show the unselect + this._redraw(); + }; - handler: transformGesture - }; - })('transform'); /** - * @module hammer + * the function bound to the selection event. It checks if you want to connect a cluster and changes the description + * to walk the user through the process. + * + * @private */ + exports._selectControlNode = function(pointer) { + this.edgeBeingEdited.controlNodes.from.unselect(); + this.edgeBeingEdited.controlNodes.to.unselect(); + this.selectedControlNode = this.edgeBeingEdited._getSelectedControlNode(this._XconvertDOMtoCanvas(pointer.x),this._YconvertDOMtoCanvas(pointer.y)); + if (this.selectedControlNode !== null) { + this.selectedControlNode.select(); + this.freezeSimulation = true; + } + this._redraw(); + }; - // AMD export - if(true) { - !(__WEBPACK_AMD_DEFINE_RESULT__ = function() { - return Hammer; - }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - // commonjs export - } else if(typeof module !== 'undefined' && module.exports) { - module.exports = Hammer; - // browser export - } else { - window.Hammer = Hammer; - } - })(window); + /** + * the function bound to the selection event. It checks if you want to connect a cluster and changes the description + * to walk the user through the process. + * + * @private + */ + exports._controlNodeDrag = function(event) { + var pointer = this._getPointer(event.gesture.center); + if (this.selectedControlNode !== null && this.selectedControlNode !== undefined) { + this.selectedControlNode.x = this._XconvertDOMtoCanvas(pointer.x); + this.selectedControlNode.y = this._YconvertDOMtoCanvas(pointer.y); + } + this._redraw(); + }; -/***/ }, -/* 59 */ -/***/ function(module, exports, __webpack_require__) { - var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;"use strict"; /** - * Created by Alex on 11/6/2014. + * + * @param pointer + * @private */ - - // https://github.com/umdjs/umd/blob/master/returnExports.js#L40-L60 - // if the module has no dependencies, the above pattern can be simplified to - (function (root, factory) { - if (true) { - // AMD. Register as an anonymous module. - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - } else if (typeof exports === 'object') { - // Node. Does not work with strict CommonJS, but - // only CommonJS-like environments that support module.exports, - // like Node. - module.exports = factory(); - } else { - // Browser globals (root is window) - root.keycharm = factory(); + exports._releaseControlNode = function(pointer) { + var newNode = this._getNodeAt(pointer); + if (newNode !== null) { + if (this.edgeBeingEdited.controlNodes.from.selected == true) { + this.edgeBeingEdited._restoreControlNodes(); + this._editEdge(newNode.id, this.edgeBeingEdited.to.id); + this.edgeBeingEdited.controlNodes.from.unselect(); + } + if (this.edgeBeingEdited.controlNodes.to.selected == true) { + this.edgeBeingEdited._restoreControlNodes(); + this._editEdge(this.edgeBeingEdited.from.id, newNode.id); + this.edgeBeingEdited.controlNodes.to.unselect(); + } } - }(this, function () { - - function keycharm(options) { - var preventDefault = options && options.preventDefault || false; + else { + this.edgeBeingEdited._restoreControlNodes(); + } + this.freezeSimulation = false; + this._redraw(); + }; - var container = options && options.container || window; + /** + * the function bound to the selection event. It checks if you want to connect a cluster and changes the description + * to walk the user through the process. + * + * @private + */ + exports._handleConnect = function(pointer) { + if (this._getSelectedNodeCount() == 0) { + var node = this._getNodeAt(pointer); - var _exportFunctions = {}; - var _bound = {keydown:{}, keyup:{}}; - var _keys = {}; - var i; + if (node != null) { + if (node.clusterSize > 1) { + alert(this.constants.locales[this.constants.locale]['createEdgeError']) + } + else { + this._selectObject(node,false); + var supportNodes = this.sectors['support']['nodes']; - // a - z - for (i = 97; i <= 122; i++) {_keys[String.fromCharCode(i)] = {code:65 + (i - 97), shift: false};} - // A - Z - for (i = 65; i <= 90; i++) {_keys[String.fromCharCode(i)] = {code:i, shift: true};} - // 0 - 9 - for (i = 0; i <= 9; i++) {_keys['' + i] = {code:48 + i, shift: false};} - // F1 - F12 - for (i = 1; i <= 12; i++) {_keys['F' + i] = {code:111 + i, shift: false};} - // num0 - num9 - for (i = 0; i <= 9; i++) {_keys['num' + i] = {code:96 + i, shift: false};} + // create a node the temporary line can look at + supportNodes['targetNode'] = new Node({id:'targetNode'},{},{},this.constants); + var targetNode = supportNodes['targetNode']; + targetNode.x = node.x; + targetNode.y = node.y; - // numpad misc - _keys['num*'] = {code:106, shift: false}; - _keys['num+'] = {code:107, shift: false}; - _keys['num-'] = {code:109, shift: false}; - _keys['num/'] = {code:111, shift: false}; - _keys['num.'] = {code:110, shift: false}; - // arrows - _keys['left'] = {code:37, shift: false}; - _keys['up'] = {code:38, shift: false}; - _keys['right'] = {code:39, shift: false}; - _keys['down'] = {code:40, shift: false}; - // extra keys - _keys['space'] = {code:32, shift: false}; - _keys['enter'] = {code:13, shift: false}; - _keys['shift'] = {code:16, shift: undefined}; - _keys['esc'] = {code:27, shift: false}; - _keys['backspace'] = {code:8, shift: false}; - _keys['tab'] = {code:9, shift: false}; - _keys['ctrl'] = {code:17, shift: false}; - _keys['alt'] = {code:18, shift: false}; - _keys['delete'] = {code:46, shift: false}; - _keys['pageup'] = {code:33, shift: false}; - _keys['pagedown'] = {code:34, shift: false}; - // symbols - _keys['='] = {code:187, shift: false}; - _keys['-'] = {code:189, shift: false}; - _keys[']'] = {code:221, shift: false}; - _keys['['] = {code:219, shift: false}; + // create a temporary edge + this.edges['connectionEdge'] = new Edge({id:"connectionEdge",from:node.id,to:targetNode.id}, this, this.constants); + var connectionEdge = this.edges['connectionEdge']; + connectionEdge.from = node; + connectionEdge.connected = true; + connectionEdge.options.smoothCurves = {enabled: true, + dynamic: false, + type: "continuous", + roundness: 0.5 + }; + connectionEdge.selected = true; + connectionEdge.to = targetNode; + this.cachedFunctions["_handleOnDrag"] = this._handleOnDrag; + this._handleOnDrag = function(event) { + var pointer = this._getPointer(event.gesture.center); + var connectionEdge = this.edges['connectionEdge']; + connectionEdge.to.x = this._XconvertDOMtoCanvas(pointer.x); + connectionEdge.to.y = this._YconvertDOMtoCanvas(pointer.y); + }; + this.moving = true; + this.start(); + } + } + } + }; - var down = function(event) {handleEvent(event,'keydown');}; - var up = function(event) {handleEvent(event,'keyup');}; + exports._finishConnect = function(event) { + if (this._getSelectedNodeCount() == 1) { + var pointer = this._getPointer(event.gesture.center); + // restore the drag function + this._handleOnDrag = this.cachedFunctions["_handleOnDrag"]; + delete this.cachedFunctions["_handleOnDrag"]; - // handle the actualy bound key with the event - var handleEvent = function(event,type) { - if (_bound[type][event.keyCode] !== undefined) { - var bound = _bound[type][event.keyCode]; - for (var i = 0; i < bound.length; i++) { - if (bound[i].shift === undefined) { - bound[i].fn(event); - } - else if (bound[i].shift == true && event.shiftKey == true) { - bound[i].fn(event); - } - else if (bound[i].shift == false && event.shiftKey == false) { - bound[i].fn(event); - } - } + // remember the edge id + var connectFromId = this.edges['connectionEdge'].fromId; - if (preventDefault == true) { - event.preventDefault(); - } - } - }; + // remove the temporary nodes and edge + delete this.edges['connectionEdge']; + delete this.sectors['support']['nodes']['targetNode']; + delete this.sectors['support']['nodes']['targetViaNode']; - // bind a key to a callback - _exportFunctions.bind = function(key, callback, type) { - if (type === undefined) { - type = 'keydown'; - } - if (_keys[key] === undefined) { - throw new Error("unsupported key: " + key); + var node = this._getNodeAt(pointer); + if (node != null) { + if (node.clusterSize > 1) { + alert(this.constants.locales[this.constants.locale]["createEdgeError"]) } - if (_bound[type][_keys[key].code] === undefined) { - _bound[type][_keys[key].code] = []; + else { + this._createEdge(connectFromId,node.id); + this._createManipulatorBar(); } - _bound[type][_keys[key].code].push({fn:callback, shift:_keys[key].shift}); - }; + } + this._unselectAll(); + } + }; - // bind all keys to a call back (demo purposes) - _exportFunctions.bindAll = function(callback, type) { - if (type === undefined) { - type = 'keydown'; + /** + * Adds a node on the specified location + */ + exports._addNode = function() { + if (this._selectionIsEmpty() && this.editMode == true) { + var positionObject = this._pointerToPositionObject(this.pointerPosition); + var defaultData = {id:util.randomUUID(),x:positionObject.left,y:positionObject.top,label:"new",allowedToMoveX:true,allowedToMoveY:true}; + if (this.triggerFunctions.add) { + if (this.triggerFunctions.add.length == 2) { + var me = this; + this.triggerFunctions.add(defaultData, function(finalizedData) { + me.nodesData.add(finalizedData); + me._createManipulatorBar(); + me.moving = true; + me.start(); + }); } - for (var key in _keys) { - if (_keys.hasOwnProperty(key)) { - _exportFunctions.bind(key,callback,type); - } + else { + throw new Error('The function for add does not support two arguments (data,callback)'); + this._createManipulatorBar(); + this.moving = true; + this.start(); } - }; + } + else { + this.nodesData.add(defaultData); + this._createManipulatorBar(); + this.moving = true; + this.start(); + } + } + }; - // get the key label from an event - _exportFunctions.getKey = function(event) { - for (var key in _keys) { - if (_keys.hasOwnProperty(key)) { - if (event.shiftKey == true && _keys[key].shift == true && event.keyCode == _keys[key].code) { - return key; - } - else if (event.shiftKey == false && _keys[key].shift == false && event.keyCode == _keys[key].code) { - return key; - } - else if (event.keyCode == _keys[key].code && key == 'shift') { - return key; - } - } - } - return "unknown key, currently not supported"; - }; - // unbind either a specific callback from a key or all of them (by leaving callback undefined) - _exportFunctions.unbind = function(key, callback, type) { - if (type === undefined) { - type = 'keydown'; + /** + * connect two nodes with a new edge. + * + * @private + */ + exports._createEdge = function(sourceNodeId,targetNodeId) { + if (this.editMode == true) { + var defaultData = {from:sourceNodeId, to:targetNodeId}; + if (this.triggerFunctions.connect) { + if (this.triggerFunctions.connect.length == 2) { + var me = this; + this.triggerFunctions.connect(defaultData, function(finalizedData) { + me.edgesData.add(finalizedData); + me.moving = true; + me.start(); + }); } - if (_keys[key] === undefined) { - throw new Error("unsupported key: " + key); + else { + throw new Error('The function for connect does not support two arguments (data,callback)'); + this.moving = true; + this.start(); } - if (callback !== undefined) { - var newBindings = []; - var bound = _bound[type][_keys[key].code]; - if (bound !== undefined) { - for (var i = 0; i < bound.length; i++) { - if (!(bound[i].fn == callback && bound[i].shift == _keys[key].shift)) { - newBindings.push(_bound[type][_keys[key].code][i]); - } - } - } - _bound[type][_keys[key].code] = newBindings; + } + else { + this.edgesData.add(defaultData); + this.moving = true; + this.start(); + } + } + }; + + /** + * connect two nodes with a new edge. + * + * @private + */ + exports._editEdge = function(sourceNodeId,targetNodeId) { + if (this.editMode == true) { + var defaultData = {id: this.edgeBeingEdited.id, from:sourceNodeId, to:targetNodeId}; + if (this.triggerFunctions.editEdge) { + if (this.triggerFunctions.editEdge.length == 2) { + var me = this; + this.triggerFunctions.editEdge(defaultData, function(finalizedData) { + me.edgesData.update(finalizedData); + me.moving = true; + me.start(); + }); } else { - _bound[type][_keys[key].code] = []; + throw new Error('The function for edit does not support two arguments (data, callback)'); + this.moving = true; + this.start(); } - }; - - // reset all bound variables. - _exportFunctions.reset = function() { - _bound = {keydown:{}, keyup:{}}; - }; - - // unbind all listeners and reset all variables. - _exportFunctions.destroy = function() { - _bound = {keydown:{}, keyup:{}}; - container.removeEventListener('keydown', down, true); - container.removeEventListener('keyup', up, true); - }; - - // create listeners. - container.addEventListener('keydown',down,true); - container.addEventListener('keyup',up,true); - - // return the public functions. - return _exportFunctions; + } + else { + this.edgesData.update(defaultData); + this.moving = true; + this.start(); + } } - - return keycharm; - })); - - - - -/***/ }, -/* 60 */ -/***/ function(module, exports, __webpack_require__) { + }; /** - * Creation of the ClusterMixin var. + * Create the toolbar to edit the selected node. The label and the color can be changed. Other colors are derived from the chosen color. * - * This contains all the functions the Network object can use to employ clustering + * @private */ + exports._editNode = function() { + if (this.triggerFunctions.edit && this.editMode == true) { + var node = this._getSelectedNode(); + var data = {id:node.id, + label: node.label, + group: node.options.group, + shape: node.options.shape, + color: { + background:node.options.color.background, + border:node.options.color.border, + highlight: { + background:node.options.color.highlight.background, + border:node.options.color.highlight.border + } + }}; + if (this.triggerFunctions.edit.length == 2) { + var me = this; + this.triggerFunctions.edit(data, function (finalizedData) { + me.nodesData.update(finalizedData); + me._createManipulatorBar(); + me.moving = true; + me.start(); + }); + } + else { + throw new Error('The function for edit does not support two arguments (data, callback)'); + } + } + else { + throw new Error('No edit function has been bound to this button'); + } + }; - /** - * This is only called in the constructor of the network object - * - */ - exports.startWithClustering = function() { - // cluster if the data set is big - this.clusterToFit(this.constants.clustering.initialMaxNodes, true); - // updates the lables after clustering - this.updateLabels(); - // this is called here because if clusterin is disabled, the start and stabilize are called in - // the setData function. - if (this.stabilize) { - this._stabilize(); - } - this.start(); - }; /** - * This function clusters until the initialMaxNodes has been reached + * delete everything in the selection * - * @param {Number} maxNumberOfNodes - * @param {Boolean} reposition + * @private */ - exports.clusterToFit = function(maxNumberOfNodes, reposition) { - var numberOfNodes = this.nodeIndices.length; - - var maxLevels = 50; - var level = 0; - - // we first cluster the hubs, then we pull in the outliers, repeat - while (numberOfNodes > maxNumberOfNodes && level < maxLevels) { - if (level % 3 == 0) { - this.forceAggregateHubs(true); - this.normalizeClusterLevels(); + exports._deleteSelected = function() { + if (!this._selectionIsEmpty() && this.editMode == true) { + if (!this._clusterInSelection()) { + var selectedNodes = this.getSelectedNodes(); + var selectedEdges = this.getSelectedEdges(); + if (this.triggerFunctions.del) { + var me = this; + var data = {nodes: selectedNodes, edges: selectedEdges}; + if (this.triggerFunctions.del.length == 2) { + this.triggerFunctions.del(data, function (finalizedData) { + me.edgesData.remove(finalizedData.edges); + me.nodesData.remove(finalizedData.nodes); + me._unselectAll(); + me.moving = true; + me.start(); + }); + } + else { + throw new Error('The function for delete does not support two arguments (data, callback)') + } + } + else { + this.edgesData.remove(selectedEdges); + this.nodesData.remove(selectedNodes); + this._unselectAll(); + this.moving = true; + this.start(); + } } else { - this.increaseClusterLevel(); // this also includes a cluster normalization + alert(this.constants.locales[this.constants.locale]["deleteClusterError"]); } - - numberOfNodes = this.nodeIndices.length; - level += 1; } - - // after the clustering we reposition the nodes to reduce the initial chaos - if (level > 0 && reposition == true) { - this.repositionNodes(); - } - this._updateCalculationNodes(); }; - /** - * This function can be called to open up a specific cluster. It is only called by - * It will unpack the cluster back one level. - * - * @param node | Node object: cluster to open. - */ - exports.openCluster = function(node) { - var isMovingBeforeClustering = this.moving; - if (node.clusterSize > this.constants.clustering.sectorThreshold && this._nodeInActiveArea(node) && - !(this._sector() == "default" && this.nodeIndices.length == 1)) { - // this loads a new sector, loads the nodes and edges and nodeIndices of it. - this._addSector(node); - var level = 0; - // we decluster until we reach a decent number of nodes - while ((this.nodeIndices.length < this.constants.clustering.initialMaxNodes) && (level < 10)) { - this.decreaseClusterLevel(); - level += 1; - } +/***/ }, +/* 62 */ +/***/ function(module, exports, __webpack_require__) { - } - else { - this._expandClusterNode(node,false,true); + var util = __webpack_require__(1); + var Node = __webpack_require__(40); - // update the index list, dynamic edges and labels - this._updateNodeIndexList(); - this._updateDynamicEdges(); - this._updateCalculationNodes(); - this.updateLabels(); - } + /** + * Creation of the SectorMixin var. + * + * This contains all the functions the Network object can use to employ the sector system. + * The sector system is always used by Network, though the benefits only apply to the use of clustering. + * If clustering is not used, there is no overhead except for a duplicate object with references to nodes and edges. + */ - // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded - if (this.moving != isMovingBeforeClustering) { - this.start(); - } + /** + * This function is only called by the setData function of the Network object. + * This loads the global references into the active sector. This initializes the sector. + * + * @private + */ + exports._putDataInSector = function() { + this.sectors["active"][this._sector()].nodes = this.nodes; + this.sectors["active"][this._sector()].edges = this.edges; + this.sectors["active"][this._sector()].nodeIndices = this.nodeIndices; }; /** - * This calls the updateClustes with default arguments + * /** + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the supplied (active) sector. If a type is defined, do the specific type + * + * @param {String} sectorId + * @param {String} [sectorType] | "active" or "frozen" + * @private */ - exports.updateClustersDefault = function() { - if (this.constants.clustering.enabled == true) { - this.updateClusters(0,false,false); + exports._switchToSector = function(sectorId, sectorType) { + if (sectorType === undefined || sectorType == "active") { + this._switchToActiveSector(sectorId); + } + else { + this._switchToFrozenSector(sectorId); } }; /** - * This function can be called to increase the cluster level. This means that the nodes with only one edge connection will - * be clustered with their connected node. This can be repeated as many times as needed. - * This can be called externally (by a keybind for instance) to reduce the complexity of big datasets. + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the supplied active sector. + * + * @param sectorId + * @private */ - exports.increaseClusterLevel = function() { - this.updateClusters(-1,false,true); + exports._switchToActiveSector = function(sectorId) { + this.nodeIndices = this.sectors["active"][sectorId]["nodeIndices"]; + this.nodes = this.sectors["active"][sectorId]["nodes"]; + this.edges = this.sectors["active"][sectorId]["edges"]; }; /** - * This function can be called to decrease the cluster level. This means that the nodes with only one edge connection will - * be unpacked if they are a cluster. This can be repeated as many times as needed. - * This can be called externally (by a key-bind for instance) to look into clusters without zooming. + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the supplied active sector. + * + * @private */ - exports.decreaseClusterLevel = function() { - this.updateClusters(1,false,true); + exports._switchToSupportSector = function() { + this.nodeIndices = this.sectors["support"]["nodeIndices"]; + this.nodes = this.sectors["support"]["nodes"]; + this.edges = this.sectors["support"]["edges"]; }; /** - * This is the main clustering function. It clusters and declusters on zoom or forced - * This function clusters on zoom, it can be called with a predefined zoom direction - * If out, check if we can form clusters, if in, check if we can open clusters. - * This function is only called from _zoom() - * - * @param {Number} zoomDirection | -1 / 0 / +1 for zoomOut / determineByZoom / zoomIn - * @param {Boolean} recursive | enabled or disable recursive calling of the opening of clusters - * @param {Boolean} force | enabled or disable forcing - * @param {Boolean} doNotStart | if true do not call start + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the supplied frozen sector. * + * @param sectorId + * @private */ - exports.updateClusters = function(zoomDirection,recursive,force,doNotStart) { - var isMovingBeforeClustering = this.moving; - var amountOfNodes = this.nodeIndices.length; - - // on zoom out collapse the sector if the scale is at the level the sector was made - if (this.previousScale > this.scale && zoomDirection == 0) { - this._collapseSector(); - } - - // check if we zoom in or out - if (this.previousScale > this.scale || zoomDirection == -1) { // zoom out - // forming clusters when forced pulls outliers in. When not forced, the edge length of the - // outer nodes determines if it is being clustered - this._formClusters(force); - } - else if (this.previousScale < this.scale || zoomDirection == 1) { // zoom in - if (force == true) { - // _openClusters checks for each node if the formationScale of the cluster is smaller than - // the current scale and if so, declusters. When forced, all clusters are reduced by one step - this._openClusters(recursive,force); - } - else { - // if a cluster takes up a set percentage of the active window - this._openClustersBySize(); - } - } - this._updateNodeIndexList(); - - // if a cluster was NOT formed and the user zoomed out, we try clustering by hubs - if (this.nodeIndices.length == amountOfNodes && (this.previousScale > this.scale || zoomDirection == -1)) { - this._aggregateHubs(force); - this._updateNodeIndexList(); - } - - // we now reduce chains. - if (this.previousScale > this.scale || zoomDirection == -1) { // zoom out - this.handleChains(); - this._updateNodeIndexList(); - } - - this.previousScale = this.scale; - - // rest of the update the index list, dynamic edges and labels - this._updateDynamicEdges(); - this.updateLabels(); - - // if a cluster was formed, we increase the clusterSession - if (this.nodeIndices.length < amountOfNodes) { // this means a clustering operation has taken place - this.clusterSession += 1; - // if clusters have been made, we normalize the cluster level - this.normalizeClusterLevels(); - } - - if (doNotStart == false || doNotStart === undefined) { - // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded - if (this.moving != isMovingBeforeClustering) { - this.start(); - } - } - - this._updateCalculationNodes(); + exports._switchToFrozenSector = function(sectorId) { + this.nodeIndices = this.sectors["frozen"][sectorId]["nodeIndices"]; + this.nodes = this.sectors["frozen"][sectorId]["nodes"]; + this.edges = this.sectors["frozen"][sectorId]["edges"]; }; - /** - * This function handles the chains. It is called on every updateClusters(). - */ - exports.handleChains = function() { - // after clustering we check how many chains there are - var chainPercentage = this._getChainFraction(); - if (chainPercentage > this.constants.clustering.chainThreshold) { - this._reduceAmountOfChains(1 - this.constants.clustering.chainThreshold / chainPercentage) - - } - }; /** - * this functions starts clustering by hubs - * The minimum hub threshold is set globally + * This function sets the global references to nodes, edges and nodeIndices back to + * those of the currently active sector. * * @private */ - exports._aggregateHubs = function(force) { - this._getHubSize(); - this._formClustersByHub(force,false); + exports._loadLatestSector = function() { + this._switchToSector(this._sector()); }; /** - * This function is fired by keypress. It forces hubs to form. + * This function returns the currently active sector Id * + * @returns {String} + * @private */ - exports.forceAggregateHubs = function(doNotStart) { - var isMovingBeforeClustering = this.moving; - var amountOfNodes = this.nodeIndices.length; - - this._aggregateHubs(true); - - // update the index list, dynamic edges and labels - this._updateNodeIndexList(); - this._updateDynamicEdges(); - this.updateLabels(); - - // if a cluster was formed, we increase the clusterSession - if (this.nodeIndices.length != amountOfNodes) { - this.clusterSession += 1; - } - - if (doNotStart == false || doNotStart === undefined) { - // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded - if (this.moving != isMovingBeforeClustering) { - this.start(); - } - } + exports._sector = function() { + return this.activeSector[this.activeSector.length-1]; }; + /** - * If a cluster takes up more than a set percentage of the screen, open the cluster + * This function returns the previously active sector Id * + * @returns {String} * @private */ - exports._openClustersBySize = function() { - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - var node = this.nodes[nodeId]; - if (node.inView() == true) { - if ((node.width*this.scale > this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientWidth) || - (node.height*this.scale > this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientHeight)) { - this.openCluster(node); - } - } - } + exports._previousSector = function() { + if (this.activeSector.length > 1) { + return this.activeSector[this.activeSector.length-2]; + } + else { + throw new TypeError('there are not enough sectors in the this.activeSector array.'); } }; /** - * This function loops over all nodes in the nodeIndices list. For each node it checks if it is a cluster and if it - * has to be opened based on the current zoom level. + * We add the active sector at the end of the this.activeSector array + * This ensures it is the currently active sector returned by _sector() and it reaches the top + * of the activeSector stack. When we reverse our steps we move from the end to the beginning of this stack. * + * @param newId * @private */ - exports._openClusters = function(recursive,force) { - for (var i = 0; i < this.nodeIndices.length; i++) { - var node = this.nodes[this.nodeIndices[i]]; - this._expandClusterNode(node,recursive,force); - this._updateCalculationNodes(); - } + exports._setActiveSector = function(newId) { + this.activeSector.push(newId); }; + /** - * This function checks if a node has to be opened. This is done by checking the zoom level. - * If the node contains child nodes, this function is recursively called on the child nodes as well. - * This recursive behaviour is optional and can be set by the recursive argument. + * We remove the currently active sector id from the active sector stack. This happens when + * we reactivate the previously active sector * - * @param {Node} parentNode | to check for cluster and expand - * @param {Boolean} recursive | enabled or disable recursive calling - * @param {Boolean} force | enabled or disable forcing - * @param {Boolean} [openAll] | This will recursively force all nodes in the parent to be released * @private */ - exports._expandClusterNode = function(parentNode, recursive, force, openAll) { - // first check if node is a cluster - if (parentNode.clusterSize > 1) { - // this means that on a double tap event or a zoom event, the cluster fully unpacks if it is smaller than 20 - if (parentNode.clusterSize < this.constants.clustering.sectorThreshold) { - openAll = true; - } - recursive = openAll ? true : recursive; - - // if the last child has been added on a smaller scale than current scale decluster - if (parentNode.formationScale < this.scale || force == true) { - // we will check if any of the contained child nodes should be removed from the cluster - for (var containedNodeId in parentNode.containedNodes) { - if (parentNode.containedNodes.hasOwnProperty(containedNodeId)) { - var childNode = parentNode.containedNodes[containedNodeId]; - - // force expand will expand the largest cluster size clusters. Since we cluster from outside in, we assume that - // the largest cluster is the one that comes from outside - if (force == true) { - if (childNode.clusterSession == parentNode.clusterSessions[parentNode.clusterSessions.length-1] - || openAll) { - this._expelChildFromParent(parentNode,containedNodeId,recursive,force,openAll); - } - } - else { - if (this._nodeInActiveArea(parentNode)) { - this._expelChildFromParent(parentNode,containedNodeId,recursive,force,openAll); - } - } - } - } - } - } + exports._forgetLastSector = function() { + this.activeSector.pop(); }; + /** - * ONLY CALLED FROM _expandClusterNode - * - * This function will expel a child_node from a parent_node. This is to de-cluster the node. This function will remove - * the child node from the parent contained_node object and put it back into the global nodes object. - * The same holds for the edge that was connected to the child node. It is moved back into the global edges object. + * This function creates a new active sector with the supplied newId. This newId + * is the expanding node id. * - * @param {Node} parentNode | the parent node - * @param {String} containedNodeId | child_node id as it is contained in the containedNodes object of the parent node - * @param {Boolean} recursive | This will also check if the child needs to be expanded. - * With force and recursive both true, the entire cluster is unpacked - * @param {Boolean} force | This will disregard the zoom level and will expel this child from the parent - * @param {Boolean} openAll | This will recursively force all nodes in the parent to be released + * @param {String} newId | Id of the new active sector * @private */ - exports._expelChildFromParent = function(parentNode, containedNodeId, recursive, force, openAll) { - var childNode = parentNode.containedNodes[containedNodeId]; - - // if child node has been added on smaller scale than current, kick out - if (childNode.formationScale < this.scale || force == true) { - // unselect all selected items - this._unselectAll(); - - // put the child node back in the global nodes object - this.nodes[containedNodeId] = childNode; - - // release the contained edges from this childNode back into the global edges - this._releaseContainedEdges(parentNode,childNode); - - // reconnect rerouted edges to the childNode - this._connectEdgeBackToChild(parentNode,childNode); - - // validate all edges in dynamicEdges - this._validateEdges(parentNode); - - // undo the changes from the clustering operation on the parent node - parentNode.options.mass -= childNode.options.mass; - parentNode.clusterSize -= childNode.clusterSize; - parentNode.options.fontSize = Math.min(this.constants.clustering.maxFontSize, this.constants.nodes.fontSize + this.constants.clustering.fontSizeMultiplier*(parentNode.clusterSize-1)); - parentNode.dynamicEdgesLength = parentNode.dynamicEdges.length; - - // place the child node near the parent, not at the exact same location to avoid chaos in the system - childNode.x = parentNode.x + parentNode.growthIndicator * (0.5 - Math.random()); - childNode.y = parentNode.y + parentNode.growthIndicator * (0.5 - Math.random()); - - // remove node from the list - delete parentNode.containedNodes[containedNodeId]; + exports._createNewSector = function(newId) { + // create the new sector + this.sectors["active"][newId] = {"nodes":{}, + "edges":{}, + "nodeIndices":[], + "formationScale": this.scale, + "drawingNode": undefined}; - // check if there are other childs with this clusterSession in the parent. - var othersPresent = false; - for (var childNodeId in parentNode.containedNodes) { - if (parentNode.containedNodes.hasOwnProperty(childNodeId)) { - if (parentNode.containedNodes[childNodeId].clusterSession == childNode.clusterSession) { - othersPresent = true; - break; + // create the new sector render node. This gives visual feedback that you are in a new sector. + this.sectors["active"][newId]['drawingNode'] = new Node( + {id:newId, + color: { + background: "#eaefef", + border: "495c5e" } - } - } - // if there are no others, remove the cluster session from the list - if (othersPresent == false) { - parentNode.clusterSessions.pop(); - } - - this._repositionBezierNodes(childNode); - // this._repositionBezierNodes(parentNode); - - // remove the clusterSession from the child node - childNode.clusterSession = 0; - - // recalculate the size of the node on the next time the node is rendered - parentNode.clearSizeCache(); - - // restart the simulation to reorganise all nodes - this.moving = true; - } - - // check if a further expansion step is possible if recursivity is enabled - if (recursive == true) { - this._expandClusterNode(childNode,recursive,force,openAll); - } + },{},{},this.constants); + this.sectors["active"][newId]['drawingNode'].clusterSize = 2; }; /** - * position the bezier nodes at the center of the edges + * This function removes the currently active sector. This is called when we create a new + * active sector. * - * @param node + * @param {String} sectorId | Id of the active sector that will be removed * @private */ - exports._repositionBezierNodes = function(node) { - for (var i = 0; i < node.dynamicEdges.length; i++) { - node.dynamicEdges[i].positionBezierNode(); - } + exports._deleteActiveSector = function(sectorId) { + delete this.sectors["active"][sectorId]; }; /** - * This function checks if any nodes at the end of their trees have edges below a threshold length - * This function is called only from updateClusters() - * forceLevelCollapse ignores the length of the edge and collapses one level - * This means that a node with only one edge will be clustered with its connected node + * This function removes the currently active sector. This is called when we reactivate + * the previously active sector. * + * @param {String} sectorId | Id of the active sector that will be removed * @private - * @param {Boolean} force */ - exports._formClusters = function(force) { - if (force == false) { - this._formClustersByZoom(); - } - else { - this._forceClustersByZoom(); - } + exports._deleteFrozenSector = function(sectorId) { + delete this.sectors["frozen"][sectorId]; }; /** - * This function handles the clustering by zooming out, this is based on a minimum edge distance + * Freezing an active sector means moving it from the "active" object to the "frozen" object. + * We copy the references, then delete the active entree. * + * @param sectorId * @private */ - exports._formClustersByZoom = function() { - var dx,dy,length, - minLength = this.constants.clustering.clusterEdgeThreshold/this.scale; - - // check if any edges are shorter than minLength and start the clustering - // the clustering favours the node with the larger mass - for (var edgeId in this.edges) { - if (this.edges.hasOwnProperty(edgeId)) { - var edge = this.edges[edgeId]; - if (edge.connected) { - if (edge.toId != edge.fromId) { - dx = (edge.to.x - edge.from.x); - dy = (edge.to.y - edge.from.y); - length = Math.sqrt(dx * dx + dy * dy); - - - if (length < minLength) { - // first check which node is larger - var parentNode = edge.from; - var childNode = edge.to; - if (edge.to.options.mass > edge.from.options.mass) { - parentNode = edge.to; - childNode = edge.from; - } + exports._freezeSector = function(sectorId) { + // we move the set references from the active to the frozen stack. + this.sectors["frozen"][sectorId] = this.sectors["active"][sectorId]; - if (childNode.dynamicEdgesLength == 1) { - this._addToCluster(parentNode,childNode,false); - } - else if (parentNode.dynamicEdgesLength == 1) { - this._addToCluster(childNode,parentNode,false); - } - } - } - } - } - } + // we have moved the sector data into the frozen set, we now remove it from the active set + this._deleteActiveSector(sectorId); }; + /** - * This function forces the network to cluster all nodes with only one connecting edge to their - * connected node. + * This is the reverse operation of _freezeSector. Activating means moving the sector from the "frozen" + * object to the "active" object. * + * @param sectorId * @private - */ - exports._forceClustersByZoom = function() { - for (var nodeId in this.nodes) { - // another node could have absorbed this child. - if (this.nodes.hasOwnProperty(nodeId)) { - var childNode = this.nodes[nodeId]; - - // the edges can be swallowed by another decrease - if (childNode.dynamicEdgesLength == 1 && childNode.dynamicEdges.length != 0) { - var edge = childNode.dynamicEdges[0]; - var parentNode = (edge.toId == childNode.id) ? this.nodes[edge.fromId] : this.nodes[edge.toId]; - - // group to the largest node - if (childNode.id != parentNode.id) { - if (parentNode.options.mass > childNode.options.mass) { - this._addToCluster(parentNode,childNode,true); - } - else { - this._addToCluster(childNode,parentNode,true); - } - } - } - } - } + */ + exports._activateSector = function(sectorId) { + // we move the set references from the frozen to the active stack. + this.sectors["active"][sectorId] = this.sectors["frozen"][sectorId]; + + // we have moved the sector data into the active set, we now remove it from the frozen stack + this._deleteFrozenSector(sectorId); }; /** - * To keep the nodes of roughly equal size we normalize the cluster levels. - * This function clusters a node to its smallest connected neighbour. + * This function merges the data from the currently active sector with a frozen sector. This is used + * in the process of reverting back to the previously active sector. + * The data that is placed in the frozen (the previously active) sector is the node that has been removed from it + * upon the creation of a new active sector. * - * @param node + * @param sectorId * @private */ - exports._clusterToSmallestNeighbour = function(node) { - var smallestNeighbour = -1; - var smallestNeighbourNode = null; - for (var i = 0; i < node.dynamicEdges.length; i++) { - if (node.dynamicEdges[i] !== undefined) { - var neighbour = null; - if (node.dynamicEdges[i].fromId != node.id) { - neighbour = node.dynamicEdges[i].from; - } - else if (node.dynamicEdges[i].toId != node.id) { - neighbour = node.dynamicEdges[i].to; - } - + exports._mergeThisWithFrozen = function(sectorId) { + // copy all nodes + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + this.sectors["frozen"][sectorId]["nodes"][nodeId] = this.nodes[nodeId]; + } + } - if (neighbour != null && smallestNeighbour > neighbour.clusterSessions.length) { - smallestNeighbour = neighbour.clusterSessions.length; - smallestNeighbourNode = neighbour; - } + // copy all edges (if not fully clustered, else there are no edges) + for (var edgeId in this.edges) { + if (this.edges.hasOwnProperty(edgeId)) { + this.sectors["frozen"][sectorId]["edges"][edgeId] = this.edges[edgeId]; } } - if (neighbour != null && this.nodes[neighbour.id] !== undefined) { - this._addToCluster(neighbour, node, true); + // merge the nodeIndices + for (var i = 0; i < this.nodeIndices.length; i++) { + this.sectors["frozen"][sectorId]["nodeIndices"].push(this.nodeIndices[i]); } }; /** - * This function forms clusters from hubs, it loops over all nodes + * This clusters the sector to one cluster. It was a single cluster before this process started so + * we revert to that state. The clusterToFit function with a maximum size of 1 node does this. * - * @param {Boolean} force | Disregard zoom level - * @param {Boolean} onlyEqual | This only clusters a hub with a specific number of edges * @private */ - exports._formClustersByHub = function(force, onlyEqual) { - // we loop over all nodes in the list - for (var nodeId in this.nodes) { - // we check if it is still available since it can be used by the clustering in this loop - if (this.nodes.hasOwnProperty(nodeId)) { - this._formClusterFromHub(this.nodes[nodeId],force,onlyEqual); - } - } + exports._collapseThisToSingleCluster = function() { + this.clusterToFit(1,false); }; + /** - * This function forms a cluster from a specific preselected hub node + * We create a new active sector from the node that we want to open. * - * @param {Node} hubNode | the node we will cluster as a hub - * @param {Boolean} force | Disregard zoom level - * @param {Boolean} onlyEqual | This only clusters a hub with a specific number of edges - * @param {Number} [absorptionSizeOffset] | + * @param node * @private */ - exports._formClusterFromHub = function(hubNode, force, onlyEqual, absorptionSizeOffset) { - if (absorptionSizeOffset === undefined) { - absorptionSizeOffset = 0; - } - // we decide if the node is a hub - if ((hubNode.dynamicEdgesLength >= this.hubThreshold && onlyEqual == false) || - (hubNode.dynamicEdgesLength == this.hubThreshold && onlyEqual == true)) { - // initialize variables - var dx,dy,length; - var minLength = this.constants.clustering.clusterEdgeThreshold/this.scale; - var allowCluster = false; + exports._addSector = function(node) { + // this is the currently active sector + var sector = this._sector(); - // we create a list of edges because the dynamicEdges change over the course of this loop - var edgesIdarray = []; - var amountOfInitialEdges = hubNode.dynamicEdges.length; - for (var j = 0; j < amountOfInitialEdges; j++) { - edgesIdarray.push(hubNode.dynamicEdges[j].id); - } + // // this should allow me to select nodes from a frozen set. + // if (this.sectors['active'][sector]["nodes"].hasOwnProperty(node.id)) { + // console.log("the node is part of the active sector"); + // } + // else { + // console.log("I dont know what the fuck happened!!"); + // } - // if the hub clustering is not forces, we check if one of the edges connected - // to a cluster is small enough based on the constants.clustering.clusterEdgeThreshold - if (force == false) { - allowCluster = false; - for (j = 0; j < amountOfInitialEdges; j++) { - var edge = this.edges[edgesIdarray[j]]; - if (edge !== undefined) { - if (edge.connected) { - if (edge.toId != edge.fromId) { - dx = (edge.to.x - edge.from.x); - dy = (edge.to.y - edge.from.y); - length = Math.sqrt(dx * dx + dy * dy); + // when we switch to a new sector, we remove the node that will be expanded from the current nodes list. + delete this.nodes[node.id]; - if (length < minLength) { - allowCluster = true; - break; - } - } - } - } - } - } + var unqiueIdentifier = util.randomUUID(); - // start the clustering if allowed - if ((!force && allowCluster) || force) { - // we loop over all edges INITIALLY connected to this hub - for (j = 0; j < amountOfInitialEdges; j++) { - edge = this.edges[edgesIdarray[j]]; - // the edge can be clustered by this function in a previous loop - if (edge !== undefined) { - var childNode = this.nodes[(edge.fromId == hubNode.id) ? edge.toId : edge.fromId]; - // we do not want hubs to merge with other hubs nor do we want to cluster itself. - if ((childNode.dynamicEdges.length <= (this.hubThreshold + absorptionSizeOffset)) && - (childNode.id != hubNode.id)) { - this._addToCluster(hubNode,childNode,force); - } - } - } - } - } - }; + // we fully freeze the currently active sector + this._freezeSector(sector); + + // we create a new active sector. This sector has the Id of the node to ensure uniqueness + this._createNewSector(unqiueIdentifier); + + // we add the active sector to the sectors array to be able to revert these steps later on + this._setActiveSector(unqiueIdentifier); + // we redirect the global references to the new sector's references. this._sector() now returns unqiueIdentifier + this._switchToSector(this._sector()); + + // finally we add the node we removed from our previous active sector to the new active sector + this.nodes[node.id] = node; + }; /** - * This function adds the child node to the parent node, creating a cluster if it is not already. + * We close the sector that is currently open and revert back to the one before. + * If the active sector is the "default" sector, nothing happens. * - * @param {Node} parentNode | this is the node that will house the child node - * @param {Node} childNode | this node will be deleted from the global this.nodes and stored in the parent node - * @param {Boolean} force | true will only update the remainingEdges at the very end of the clustering, ensuring single level collapse * @private */ - exports._addToCluster = function(parentNode, childNode, force) { - // join child node in the parent node - parentNode.containedNodes[childNode.id] = childNode; - - // manage all the edges connected to the child and parent nodes - for (var i = 0; i < childNode.dynamicEdges.length; i++) { - var edge = childNode.dynamicEdges[i]; - if (edge.toId == parentNode.id || edge.fromId == parentNode.id) { // edge connected to parentNode - this._addToContainedEdges(parentNode,childNode,edge); - } - else { - this._connectEdgeToCluster(parentNode,childNode,edge); - } - } - // a contained node has no dynamic edges. - childNode.dynamicEdges = []; - - // remove circular edges from clusters - this._containCircularEdgesFromNode(parentNode,childNode); - + exports._collapseSector = function() { + // the currently active sector + var sector = this._sector(); - // remove the childNode from the global nodes object - delete this.nodes[childNode.id]; + // we cannot collapse the default sector + if (sector != "default") { + if ((this.nodeIndices.length == 1) || + (this.sectors["active"][sector]["drawingNode"].width*this.scale < this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientWidth) || + (this.sectors["active"][sector]["drawingNode"].height*this.scale < this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientHeight)) { + var previousSector = this._previousSector(); - // update the properties of the child and parent - var massBefore = parentNode.options.mass; - childNode.clusterSession = this.clusterSession; - parentNode.options.mass += childNode.options.mass; - parentNode.clusterSize += childNode.clusterSize; - parentNode.options.fontSize = Math.min(this.constants.clustering.maxFontSize, this.constants.nodes.fontSize + this.constants.clustering.fontSizeMultiplier*parentNode.clusterSize); + // we collapse the sector back to a single cluster + this._collapseThisToSingleCluster(); - // keep track of the clustersessions so we can open the cluster up as it has been formed. - if (parentNode.clusterSessions[parentNode.clusterSessions.length - 1] != this.clusterSession) { - parentNode.clusterSessions.push(this.clusterSession); - } + // we move the remaining nodes, edges and nodeIndices to the previous sector. + // This previous sector is the one we will reactivate + this._mergeThisWithFrozen(previousSector); - // forced clusters only open from screen size and double tap - if (force == true) { - // parentNode.formationScale = Math.pow(1 - (1.0/11.0),this.clusterSession+3); - parentNode.formationScale = 0; - } - else { - parentNode.formationScale = this.scale; // The latest child has been added on this scale - } + // the previously active (frozen) sector now has all the data from the currently active sector. + // we can now delete the active sector. + this._deleteActiveSector(sector); - // recalculate the size of the node on the next time the node is rendered - parentNode.clearSizeCache(); + // we activate the previously active (and currently frozen) sector. + this._activateSector(previousSector); - // set the pop-out scale for the childnode - parentNode.containedNodes[childNode.id].formationScale = parentNode.formationScale; + // we load the references from the newly active sector into the global references + this._switchToSector(previousSector); - // nullify the movement velocity of the child, this is to avoid hectic behaviour - childNode.clearVelocity(); + // we forget the previously active sector because we reverted to the one before + this._forgetLastSector(); - // the mass has altered, preservation of energy dictates the velocity to be updated - parentNode.updateVelocity(massBefore); + // finally, we update the node index list. + this._updateNodeIndexList(); - // restart the simulation to reorganise all nodes - this.moving = true; + // we refresh the list with calulation nodes and calculation node indices. + this._updateCalculationNodes(); + } + } }; /** - * This function will apply the changes made to the remainingEdges during the formation of the clusters. - * This is a seperate function to allow for level-wise collapsing of the node barnesHutTree. - * It has to be called if a level is collapsed. It is called by _formClusters(). + * This runs a function in all active sectors. This is used in _redraw() and the _initializeForceCalculation(). + * + * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors + * | we dont pass the function itself because then the "this" is the window object + * | instead of the Network object + * @param {*} [argument] | Optional: arguments to pass to the runFunction * @private */ - exports._updateDynamicEdges = function() { - for (var i = 0; i < this.nodeIndices.length; i++) { - var node = this.nodes[this.nodeIndices[i]]; - node.dynamicEdgesLength = node.dynamicEdges.length; - - // this corrects for multiple edges pointing at the same other node - var correction = 0; - if (node.dynamicEdgesLength > 1) { - for (var j = 0; j < node.dynamicEdgesLength - 1; j++) { - var edgeToId = node.dynamicEdges[j].toId; - var edgeFromId = node.dynamicEdges[j].fromId; - for (var k = j+1; k < node.dynamicEdgesLength; k++) { - if ((node.dynamicEdges[k].toId == edgeToId && node.dynamicEdges[k].fromId == edgeFromId) || - (node.dynamicEdges[k].fromId == edgeToId && node.dynamicEdges[k].toId == edgeFromId)) { - correction += 1; - } + exports._doInAllActiveSectors = function(runFunction,argument) { + var returnValues = []; + if (argument === undefined) { + for (var sector in this.sectors["active"]) { + if (this.sectors["active"].hasOwnProperty(sector)) { + // switch the global references to those of this sector + this._switchToActiveSector(sector); + returnValues.push( this[runFunction]() ); + } + } + } + else { + for (var sector in this.sectors["active"]) { + if (this.sectors["active"].hasOwnProperty(sector)) { + // switch the global references to those of this sector + this._switchToActiveSector(sector); + var args = Array.prototype.splice.call(arguments, 1); + if (args.length > 1) { + returnValues.push( this[runFunction](args[0],args[1]) ); + } + else { + returnValues.push( this[runFunction](argument) ); } } } - node.dynamicEdgesLength -= correction; } + // we revert the global references back to our active sector + this._loadLatestSector(); + return returnValues; }; /** - * This adds an edge from the childNode to the contained edges of the parent node + * This runs a function in all active sectors. This is used in _redraw() and the _initializeForceCalculation(). * - * @param parentNode | Node object - * @param childNode | Node object - * @param edge | Edge object + * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors + * | we dont pass the function itself because then the "this" is the window object + * | instead of the Network object + * @param {*} [argument] | Optional: arguments to pass to the runFunction * @private */ - exports._addToContainedEdges = function(parentNode, childNode, edge) { - // create an array object if it does not yet exist for this childNode - if (!(parentNode.containedEdges.hasOwnProperty(childNode.id))) { - parentNode.containedEdges[childNode.id] = [] + exports._doInSupportSector = function(runFunction,argument) { + var returnValues = false; + if (argument === undefined) { + this._switchToSupportSector(); + returnValues = this[runFunction](); } - // add this edge to the list - parentNode.containedEdges[childNode.id].push(edge); + else { + this._switchToSupportSector(); + var args = Array.prototype.splice.call(arguments, 1); + if (args.length > 1) { + returnValues = this[runFunction](args[0],args[1]); + } + else { + returnValues = this[runFunction](argument); + } + } + // we revert the global references back to our active sector + this._loadLatestSector(); + return returnValues; + }; - // remove the edge from the global edges object - delete this.edges[edge.id]; - // remove the edge from the parent object - for (var i = 0; i < parentNode.dynamicEdges.length; i++) { - if (parentNode.dynamicEdges[i].id == edge.id) { - parentNode.dynamicEdges.splice(i,1); - break; + /** + * This runs a function in all frozen sectors. This is used in the _redraw(). + * + * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors + * | we don't pass the function itself because then the "this" is the window object + * | instead of the Network object + * @param {*} [argument] | Optional: arguments to pass to the runFunction + * @private + */ + exports._doInAllFrozenSectors = function(runFunction,argument) { + if (argument === undefined) { + for (var sector in this.sectors["frozen"]) { + if (this.sectors["frozen"].hasOwnProperty(sector)) { + // switch the global references to those of this sector + this._switchToFrozenSector(sector); + this[runFunction](); + } + } + } + else { + for (var sector in this.sectors["frozen"]) { + if (this.sectors["frozen"].hasOwnProperty(sector)) { + // switch the global references to those of this sector + this._switchToFrozenSector(sector); + var args = Array.prototype.splice.call(arguments, 1); + if (args.length > 1) { + this[runFunction](args[0],args[1]); + } + else { + this[runFunction](argument); + } + } } } + this._loadLatestSector(); }; + /** - * This function connects an edge that was connected to a child node to the parent node. - * It keeps track of which nodes it has been connected to with the originalId array. + * This runs a function in all sectors. This is used in the _redraw(). * - * @param {Node} parentNode | Node object - * @param {Node} childNode | Node object - * @param {Edge} edge | Edge object + * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors + * | we don't pass the function itself because then the "this" is the window object + * | instead of the Network object + * @param {*} [argument] | Optional: arguments to pass to the runFunction * @private */ - exports._connectEdgeToCluster = function(parentNode, childNode, edge) { - // handle circular edges - if (edge.toId == edge.fromId) { - this._addToContainedEdges(parentNode, childNode, edge); + exports._doInAllSectors = function(runFunction,argument) { + var args = Array.prototype.splice.call(arguments, 1); + if (argument === undefined) { + this._doInAllActiveSectors(runFunction); + this._doInAllFrozenSectors(runFunction); } else { - if (edge.toId == childNode.id) { // edge connected to other node on the "to" side - edge.originalToId.push(childNode.id); - edge.to = parentNode; - edge.toId = parentNode.id; + if (args.length > 1) { + this._doInAllActiveSectors(runFunction,args[0],args[1]); + this._doInAllFrozenSectors(runFunction,args[0],args[1]); } - else { // edge connected to other node with the "from" side - - edge.originalFromId.push(childNode.id); - edge.from = parentNode; - edge.fromId = parentNode.id; + else { + this._doInAllActiveSectors(runFunction,argument); + this._doInAllFrozenSectors(runFunction,argument); } - - this._addToReroutedEdges(parentNode,childNode,edge); } }; /** - * If a node is connected to itself, a circular edge is drawn. When clustering we want to contain - * these edges inside of the cluster. + * This clears the nodeIndices list. We cannot use this.nodeIndices = [] because we would break the link with the + * active sector. Thus we clear the nodeIndices in the active sector, then reconnect the this.nodeIndices to it. * - * @param parentNode - * @param childNode * @private */ - exports._containCircularEdgesFromNode = function(parentNode, childNode) { - // manage all the edges connected to the child and parent nodes - for (var i = 0; i < parentNode.dynamicEdges.length; i++) { - var edge = parentNode.dynamicEdges[i]; - // handle circular edges - if (edge.toId == edge.fromId) { - this._addToContainedEdges(parentNode, childNode, edge); + exports._clearNodeIndexList = function() { + var sector = this._sector(); + this.sectors["active"][sector]["nodeIndices"] = []; + this.nodeIndices = this.sectors["active"][sector]["nodeIndices"]; + }; + + + /** + * Draw the encompassing sector node + * + * @param ctx + * @param sectorType + * @private + */ + exports._drawSectorNodes = function(ctx,sectorType) { + var minY = 1e9, maxY = -1e9, minX = 1e9, maxX = -1e9, node; + for (var sector in this.sectors[sectorType]) { + if (this.sectors[sectorType].hasOwnProperty(sector)) { + if (this.sectors[sectorType][sector]["drawingNode"] !== undefined) { + + this._switchToSector(sector,sectorType); + + minY = 1e9; maxY = -1e9; minX = 1e9; maxX = -1e9; + for (var nodeId in this.nodes) { + if (this.nodes.hasOwnProperty(nodeId)) { + node = this.nodes[nodeId]; + node.resize(ctx); + if (minX > node.x - 0.5 * node.width) {minX = node.x - 0.5 * node.width;} + if (maxX < node.x + 0.5 * node.width) {maxX = node.x + 0.5 * node.width;} + if (minY > node.y - 0.5 * node.height) {minY = node.y - 0.5 * node.height;} + if (maxY < node.y + 0.5 * node.height) {maxY = node.y + 0.5 * node.height;} + } + } + node = this.sectors[sectorType][sector]["drawingNode"]; + node.x = 0.5 * (maxX + minX); + node.y = 0.5 * (maxY + minY); + node.width = 2 * (node.x - minX); + node.height = 2 * (node.y - minY); + node.options.radius = Math.sqrt(Math.pow(0.5*node.width,2) + Math.pow(0.5*node.height,2)); + node.setScale(this.scale); + node._drawCircle(ctx); + } } } }; + exports._drawAllSectorNodes = function(ctx) { + this._drawSectorNodes(ctx,"frozen"); + this._drawSectorNodes(ctx,"active"); + this._loadLatestSector(); + }; + + +/***/ }, +/* 63 */ +/***/ function(module, exports, __webpack_require__) { + + var util = __webpack_require__(1); + var Hammer = __webpack_require__(45); + + exports._cleanNavigation = function() { + // clean hammer bindings + if (this.navigationHammers.existing.length != 0) { + for (var i = 0; i < this.navigationHammers.existing.length; i++) { + this.navigationHammers.existing[i].dispose(); + } + this.navigationHammers.existing = []; + } + + this._navigationReleaseOverload = function () {}; + + // clean up previous navigation items + if (this.navigationDivs && this.navigationDivs['wrapper'] && this.navigationDivs['wrapper'].parentNode) { + this.navigationDivs['wrapper'].parentNode.removeChild(this.navigationDivs['wrapper']); + } + }; /** - * This adds an edge from the childNode to the rerouted edges of the parent node + * Creation of the navigation controls nodes. They are drawn over the rest of the nodes and are not affected by scale and translation + * they have a triggerFunction which is called on click. If the position of the navigation controls is dependent + * on this.frame.canvas.clientWidth or this.frame.canvas.clientHeight, we flag horizontalAlignLeft and verticalAlignTop false. + * This means that the location will be corrected by the _relocateNavigation function on a size change of the canvas. * - * @param parentNode | Node object - * @param childNode | Node object - * @param edge | Edge object * @private */ - exports._addToReroutedEdges = function(parentNode, childNode, edge) { - // create an array object if it does not yet exist for this childNode - // we store the edge in the rerouted edges so we can restore it when the cluster pops open - if (!(parentNode.reroutedEdges.hasOwnProperty(childNode.id))) { - parentNode.reroutedEdges[childNode.id] = []; + exports._loadNavigationElements = function() { + this._cleanNavigation(); + + this.navigationDivs = {}; + var navigationDivs = ['up','down','left','right','zoomIn','zoomOut','zoomExtends']; + var navigationDivActions = ['_moveUp','_moveDown','_moveLeft','_moveRight','_zoomIn','_zoomOut','_zoomExtent']; + + this.navigationDivs['wrapper'] = document.createElement('div'); + this.frame.appendChild(this.navigationDivs['wrapper']); + + for (var i = 0; i < navigationDivs.length; i++) { + this.navigationDivs[navigationDivs[i]] = document.createElement('div'); + this.navigationDivs[navigationDivs[i]].className = 'network-navigation ' + navigationDivs[i]; + this.navigationDivs['wrapper'].appendChild(this.navigationDivs[navigationDivs[i]]); + + var hammer = Hammer(this.navigationDivs[navigationDivs[i]], {prevent_default: true}); + hammer.on('touch', this[navigationDivActions[i]].bind(this)); + this.navigationHammers._new.push(hammer); } - parentNode.reroutedEdges[childNode.id].push(edge); - // this edge becomes part of the dynamicEdges of the cluster node - parentNode.dynamicEdges.push(edge); - }; + this._navigationReleaseOverload = this._stopMovement; + this.navigationHammers.existing = this.navigationHammers._new; + }; /** - * This function connects an edge that was connected to a cluster node back to the child node. + * this stops all movement induced by the navigation buttons * - * @param parentNode | Node object - * @param childNode | Node object * @private */ - exports._connectEdgeBackToChild = function(parentNode, childNode) { - if (parentNode.reroutedEdges.hasOwnProperty(childNode.id)) { - for (var i = 0; i < parentNode.reroutedEdges[childNode.id].length; i++) { - var edge = parentNode.reroutedEdges[childNode.id][i]; - if (edge.originalFromId[edge.originalFromId.length-1] == childNode.id) { - edge.originalFromId.pop(); - edge.fromId = childNode.id; - edge.from = childNode; - } - else { - edge.originalToId.pop(); - edge.toId = childNode.id; - edge.to = childNode; - } - - // append this edge to the list of edges connecting to the childnode - childNode.dynamicEdges.push(edge); - - // remove the edge from the parent object - for (var j = 0; j < parentNode.dynamicEdges.length; j++) { - if (parentNode.dynamicEdges[j].id == edge.id) { - parentNode.dynamicEdges.splice(j,1); - break; - } - } - } - // remove the entry from the rerouted edges - delete parentNode.reroutedEdges[childNode.id]; - } + exports._zoomExtent = function(event) { + this.zoomExtent({duration:700}); + event.stopPropagation(); }; - /** - * When loops are clustered, an edge can be both in the rerouted array and the contained array. - * This function is called last to verify that all edges in dynamicEdges are in fact connected to the - * parentNode + * this stops all movement induced by the navigation buttons * - * @param parentNode | Node object * @private */ - exports._validateEdges = function(parentNode) { - for (var i = 0; i < parentNode.dynamicEdges.length; i++) { - var edge = parentNode.dynamicEdges[i]; - if (parentNode.id != edge.toId && parentNode.id != edge.fromId) { - parentNode.dynamicEdges.splice(i,1); - } - } + exports._stopMovement = function() { + this._xStopMoving(); + this._yStopMoving(); + this._stopZoom(); }; /** - * This function released the contained edges back into the global domain and puts them back into the - * dynamic edges of both parent and child. + * move the screen up + * By using the increments, instead of adding a fixed number to the translation, we keep fluent and + * instant movement. The onKeypress event triggers immediately, then pauses, then triggers frequently + * To avoid this behaviour, we do the translation in the start loop. * - * @param {Node} parentNode | - * @param {Node} childNode | * @private */ - exports._releaseContainedEdges = function(parentNode, childNode) { - for (var i = 0; i < parentNode.containedEdges[childNode.id].length; i++) { - var edge = parentNode.containedEdges[childNode.id][i]; - - // put the edge back in the global edges object - this.edges[edge.id] = edge; + exports._moveUp = function(event) { + this.yIncrement = this.constants.keyboard.speed.y; + this.start(); // if there is no node movement, the calculation wont be done + event.preventDefault(); + }; - // put the edge back in the dynamic edges of the child and parent - childNode.dynamicEdges.push(edge); - parentNode.dynamicEdges.push(edge); - } - // remove the entry from the contained edges - delete parentNode.containedEdges[childNode.id]; + /** + * move the screen down + * @private + */ + exports._moveDown = function(event) { + this.yIncrement = -this.constants.keyboard.speed.y; + this.start(); // if there is no node movement, the calculation wont be done + event.preventDefault(); }; + /** + * move the screen left + * @private + */ + exports._moveLeft = function(event) { + this.xIncrement = this.constants.keyboard.speed.x; + this.start(); // if there is no node movement, the calculation wont be done + event.preventDefault(); + }; - // ------------------- UTILITY FUNCTIONS ---------------------------- // + /** + * move the screen right + * @private + */ + exports._moveRight = function(event) { + this.xIncrement = -this.constants.keyboard.speed.y; + this.start(); // if there is no node movement, the calculation wont be done + event.preventDefault(); + }; /** - * This updates the node labels for all nodes (for debugging purposes) + * Zoom in, using the same method as the movement. + * @private */ - exports.updateLabels = function() { - var nodeId; - // update node labels - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - var node = this.nodes[nodeId]; - if (node.clusterSize > 1) { - node.label = "[".concat(String(node.clusterSize),"]"); - } - } - } - - // update node labels - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - if (node.clusterSize == 1) { - if (node.originalLabel !== undefined) { - node.label = node.originalLabel; - } - else { - node.label = String(node.id); - } - } - } - } + exports._zoomIn = function(event) { + this.zoomIncrement = this.constants.keyboard.speed.zoom; + this.start(); // if there is no node movement, the calculation wont be done + event.preventDefault(); + }; - // /* Debug Override */ - // for (nodeId in this.nodes) { - // if (this.nodes.hasOwnProperty(nodeId)) { - // node = this.nodes[nodeId]; - // node.label = String(node.level); - // } - // } + /** + * Zoom out + * @private + */ + exports._zoomOut = function(event) { + this.zoomIncrement = -this.constants.keyboard.speed.zoom; + this.start(); // if there is no node movement, the calculation wont be done + event.preventDefault(); }; /** - * We want to keep the cluster level distribution rather small. This means we do not want unclustered nodes - * if the rest of the nodes are already a few cluster levels in. - * To fix this we use this function. It determines the min and max cluster level and sends nodes that have not - * clustered enough to the clusterToSmallestNeighbours function. + * Stop zooming and unhighlight the zoom controls + * @private */ - exports.normalizeClusterLevels = function() { - var maxLevel = 0; - var minLevel = 1e9; - var clusterLevel = 0; - var nodeId; + exports._stopZoom = function(event) { + this.zoomIncrement = 0; + event && event.preventDefault(); + }; - // we loop over all nodes in the list - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - clusterLevel = this.nodes[nodeId].clusterSessions.length; - if (maxLevel < clusterLevel) {maxLevel = clusterLevel;} - if (minLevel > clusterLevel) {minLevel = clusterLevel;} - } - } - if (maxLevel - minLevel > this.constants.clustering.clusterLevelDifference) { - var amountOfNodes = this.nodeIndices.length; - var targetLevel = maxLevel - this.constants.clustering.clusterLevelDifference; - // we loop over all nodes in the list - for (nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - if (this.nodes[nodeId].clusterSessions.length < targetLevel) { - this._clusterToSmallestNeighbour(this.nodes[nodeId]); - } - } - } - this._updateNodeIndexList(); - this._updateDynamicEdges(); - // if a cluster was formed, we increase the clusterSession - if (this.nodeIndices.length != amountOfNodes) { - this.clusterSession += 1; - } - } + /** + * Stop moving in the Y direction and unHighlight the up and down + * @private + */ + exports._yStopMoving = function(event) { + this.yIncrement = 0; + event && event.preventDefault(); }; - /** - * This function determines if the cluster we want to decluster is in the active area - * this means around the zoom center - * - * @param {Node} node - * @returns {boolean} + * Stop moving in the X direction and unHighlight left and right. * @private */ - exports._nodeInActiveArea = function(node) { - return ( - Math.abs(node.x - this.areaCenter.x) <= this.constants.clustering.activeAreaBoxSize/this.scale - && - Math.abs(node.y - this.areaCenter.y) <= this.constants.clustering.activeAreaBoxSize/this.scale - ) + exports._xStopMoving = function(event) { + this.xIncrement = 0; + event && event.preventDefault(); }; +/***/ }, +/* 64 */ +/***/ function(module, exports, __webpack_require__) { + + var __WEBPACK_AMD_DEFINE_RESULT__;/*! Hammer.JS - v1.1.3 - 2014-05-20 + * http://eightmedia.github.io/hammer.js + * + * Copyright (c) 2014 Jorik Tangelder ; + * Licensed under the MIT license */ + + (function(window, undefined) { + 'use strict'; + /** - * This is an adaptation of the original repositioning function. This is called if the system is clustered initially - * It puts large clusters away from the center and randomizes the order. + * @main + * @module hammer * + * @class Hammer + * @static */ - exports.repositionNodes = function() { - for (var i = 0; i < this.nodeIndices.length; i++) { - var node = this.nodes[this.nodeIndices[i]]; - if ((node.xFixed == false || node.yFixed == false)) { - var radius = 10 * 0.1*this.nodeIndices.length * Math.min(100,node.options.mass); - var angle = 2 * Math.PI * Math.random(); - if (node.xFixed == false) {node.x = radius * Math.cos(angle);} - if (node.yFixed == false) {node.y = radius * Math.sin(angle);} - this._repositionBezierNodes(node); - } - } - }; - /** - * We determine how many connections denote an important hub. - * We take the mean + 2*std as the important hub size. (Assuming a normal distribution of data, ~2.2%) + * Hammer, use this to create instances + * ```` + * var hammertime = new Hammer(myElement); + * ```` * - * @private + * @method Hammer + * @param {HTMLElement} element + * @param {Object} [options={}] + * @return {Hammer.Instance} */ - exports._getHubSize = function() { - var average = 0; - var averageSquared = 0; - var hubCounter = 0; - var largestHub = 0; + var Hammer = function Hammer(element, options) { + return new Hammer.Instance(element, options || {}); + }; - for (var i = 0; i < this.nodeIndices.length; i++) { + /** + * version, as defined in package.json + * the value will be set at each build + * @property VERSION + * @final + * @type {String} + */ + Hammer.VERSION = '1.1.3'; - var node = this.nodes[this.nodeIndices[i]]; - if (node.dynamicEdgesLength > largestHub) { - largestHub = node.dynamicEdgesLength; - } - average += node.dynamicEdgesLength; - averageSquared += Math.pow(node.dynamicEdgesLength,2); - hubCounter += 1; - } - average = average / hubCounter; - averageSquared = averageSquared / hubCounter; + /** + * default settings. + * more settings are defined per gesture at `/gestures`. Each gesture can be disabled/enabled + * by setting it's name (like `swipe`) to false. + * You can set the defaults for all instances by changing this object before creating an instance. + * @example + * ```` + * Hammer.defaults.drag = false; + * Hammer.defaults.behavior.touchAction = 'pan-y'; + * delete Hammer.defaults.behavior.userSelect; + * ```` + * @property defaults + * @type {Object} + */ + Hammer.defaults = { + /** + * this setting object adds styles and attributes to the element to prevent the browser from doing + * its native behavior. The css properties are auto prefixed for the browsers when needed. + * @property defaults.behavior + * @type {Object} + */ + behavior: { + /** + * Disables text selection to improve the dragging gesture. When the value is `none` it also sets + * `onselectstart=false` for IE on the element. Mainly for desktop browsers. + * @property defaults.behavior.userSelect + * @type {String} + * @default 'none' + */ + userSelect: 'none', - var variance = averageSquared - Math.pow(average,2); + /** + * Specifies whether and how a given region can be manipulated by the user (for instance, by panning or zooming). + * Used by Chrome 35> and IE10>. By default this makes the element blocking any touch event. + * @property defaults.behavior.touchAction + * @type {String} + * @default: 'pan-y' + */ + touchAction: 'pan-y', - var standardDeviation = Math.sqrt(variance); + /** + * Disables the default callout shown when you touch and hold a touch target. + * On iOS, when you touch and hold a touch target such as a link, Safari displays + * a callout containing information about the link. This property allows you to disable that callout. + * @property defaults.behavior.touchCallout + * @type {String} + * @default 'none' + */ + touchCallout: 'none', - this.hubThreshold = Math.floor(average + 2*standardDeviation); + /** + * Specifies whether zooming is enabled. Used by IE10> + * @property defaults.behavior.contentZooming + * @type {String} + * @default 'none' + */ + contentZooming: 'none', - // always have at least one to cluster - if (this.hubThreshold > largestHub) { - this.hubThreshold = largestHub; - } + /** + * Specifies that an entire element should be draggable instead of its contents. + * Mainly for desktop browsers. + * @property defaults.behavior.userDrag + * @type {String} + * @default 'none' + */ + userDrag: 'none', - // console.log("average",average,"averageSQ",averageSquared,"var",variance,"std",standardDeviation); - // console.log("hubThreshold:",this.hubThreshold); + /** + * Overrides the highlight color shown when the user taps a link or a JavaScript + * clickable element in Safari on iPhone. This property obeys the alpha value, if specified. + * + * If you don't specify an alpha value, Safari on iPhone applies a default alpha value + * to the color. To disable tap highlighting, set the alpha value to 0 (invisible). + * If you set the alpha value to 1.0 (opaque), the element is not visible when tapped. + * @property defaults.behavior.tapHighlightColor + * @type {String} + * @default 'rgba(0,0,0,0)' + */ + tapHighlightColor: 'rgba(0,0,0,0)' + } }; - /** - * We reduce the amount of "extension nodes" or chains. These are not quickly clustered with the outliers and hubs methods - * with this amount we can cluster specifically on these chains. - * - * @param {Number} fraction | between 0 and 1, the percentage of chains to reduce - * @private + * hammer document where the base events are added at + * @property DOCUMENT + * @type {HTMLElement} + * @default window.document */ - exports._reduceAmountOfChains = function(fraction) { - this.hubThreshold = 2; - var reduceAmount = Math.floor(this.nodeIndices.length * fraction); - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - if (this.nodes[nodeId].dynamicEdgesLength == 2 && this.nodes[nodeId].dynamicEdges.length >= 2) { - if (reduceAmount > 0) { - this._formClusterFromHub(this.nodes[nodeId],true,true,1); - reduceAmount -= 1; - } - } - } - } - }; + Hammer.DOCUMENT = document; /** - * We get the amount of "extension nodes" or chains. These are not quickly clustered with the outliers and hubs methods - * with this amount we can cluster specifically on these chains. - * - * @private + * detect support for pointer events + * @property HAS_POINTEREVENTS + * @type {Boolean} */ - exports._getChainFraction = function() { - var chains = 0; - var total = 0; - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - if (this.nodes[nodeId].dynamicEdgesLength == 2 && this.nodes[nodeId].dynamicEdges.length >= 2) { - chains += 1; - } - total += 1; - } - } - return chains/total; - }; + Hammer.HAS_POINTEREVENTS = navigator.pointerEnabled || navigator.msPointerEnabled; + /** + * detect support for touch events + * @property HAS_TOUCHEVENTS + * @type {Boolean} + */ + Hammer.HAS_TOUCHEVENTS = ('ontouchstart' in window); -/***/ }, -/* 61 */ -/***/ function(module, exports, __webpack_require__) { + /** + * detect mobile browsers + * @property IS_MOBILE + * @type {Boolean} + */ + Hammer.IS_MOBILE = /mobile|tablet|ip(ad|hone|od)|android|silk/i.test(navigator.userAgent); - var util = __webpack_require__(1); - var Node = __webpack_require__(40); + /** + * detect if we want to support mouseevents at all + * @property NO_MOUSEEVENTS + * @type {Boolean} + */ + Hammer.NO_MOUSEEVENTS = (Hammer.HAS_TOUCHEVENTS && Hammer.IS_MOBILE) || Hammer.HAS_POINTEREVENTS; /** - * Creation of the SectorMixin var. - * - * This contains all the functions the Network object can use to employ the sector system. - * The sector system is always used by Network, though the benefits only apply to the use of clustering. - * If clustering is not used, there is no overhead except for a duplicate object with references to nodes and edges. + * interval in which Hammer recalculates current velocity/direction/angle in ms + * @property CALCULATE_INTERVAL + * @type {Number} + * @default 25 */ + Hammer.CALCULATE_INTERVAL = 25; /** - * This function is only called by the setData function of the Network object. - * This loads the global references into the active sector. This initializes the sector. - * + * eventtypes per touchevent (start, move, end) are filled by `Event.determineEventTypes` on `setup` + * the object contains the DOM event names per type (`EVENT_START`, `EVENT_MOVE`, `EVENT_END`) + * @property EVENT_TYPES * @private + * @writeOnce + * @type {Object} */ - exports._putDataInSector = function() { - this.sectors["active"][this._sector()].nodes = this.nodes; - this.sectors["active"][this._sector()].edges = this.edges; - this.sectors["active"][this._sector()].nodeIndices = this.nodeIndices; - }; + var EVENT_TYPES = {}; + + /** + * direction strings, for safe comparisons + * @property DIRECTION_DOWN|LEFT|UP|RIGHT + * @final + * @type {String} + * @default 'down' 'left' 'up' 'right' + */ + var DIRECTION_DOWN = Hammer.DIRECTION_DOWN = 'down'; + var DIRECTION_LEFT = Hammer.DIRECTION_LEFT = 'left'; + var DIRECTION_UP = Hammer.DIRECTION_UP = 'up'; + var DIRECTION_RIGHT = Hammer.DIRECTION_RIGHT = 'right'; + + /** + * pointertype strings, for safe comparisons + * @property POINTER_MOUSE|TOUCH|PEN + * @final + * @type {String} + * @default 'mouse' 'touch' 'pen' + */ + var POINTER_MOUSE = Hammer.POINTER_MOUSE = 'mouse'; + var POINTER_TOUCH = Hammer.POINTER_TOUCH = 'touch'; + var POINTER_PEN = Hammer.POINTER_PEN = 'pen'; + /** + * eventtypes + * @property EVENT_START|MOVE|END|RELEASE|TOUCH + * @final + * @type {String} + * @default 'start' 'change' 'move' 'end' 'release' 'touch' + */ + var EVENT_START = Hammer.EVENT_START = 'start'; + var EVENT_MOVE = Hammer.EVENT_MOVE = 'move'; + var EVENT_END = Hammer.EVENT_END = 'end'; + var EVENT_RELEASE = Hammer.EVENT_RELEASE = 'release'; + var EVENT_TOUCH = Hammer.EVENT_TOUCH = 'touch'; /** - * /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the supplied (active) sector. If a type is defined, do the specific type - * - * @param {String} sectorId - * @param {String} [sectorType] | "active" or "frozen" - * @private + * if the window events are set... + * @property READY + * @writeOnce + * @type {Boolean} + * @default false */ - exports._switchToSector = function(sectorId, sectorType) { - if (sectorType === undefined || sectorType == "active") { - this._switchToActiveSector(sectorId); - } - else { - this._switchToFrozenSector(sectorId); - } - }; - + Hammer.READY = false; /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the supplied active sector. - * - * @param sectorId - * @private + * plugins namespace + * @property plugins + * @type {Object} */ - exports._switchToActiveSector = function(sectorId) { - this.nodeIndices = this.sectors["active"][sectorId]["nodeIndices"]; - this.nodes = this.sectors["active"][sectorId]["nodes"]; - this.edges = this.sectors["active"][sectorId]["edges"]; - }; - + Hammer.plugins = Hammer.plugins || {}; /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the supplied active sector. - * - * @private + * gestures namespace + * see `/gestures` for the definitions + * @property gestures + * @type {Object} */ - exports._switchToSupportSector = function() { - this.nodeIndices = this.sectors["support"]["nodeIndices"]; - this.nodes = this.sectors["support"]["nodes"]; - this.edges = this.sectors["support"]["edges"]; - }; - + Hammer.gestures = Hammer.gestures || {}; /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the supplied frozen sector. - * - * @param sectorId + * setup events to detect gestures on the document + * this function is called when creating an new instance * @private */ - exports._switchToFrozenSector = function(sectorId) { - this.nodeIndices = this.sectors["frozen"][sectorId]["nodeIndices"]; - this.nodes = this.sectors["frozen"][sectorId]["nodes"]; - this.edges = this.sectors["frozen"][sectorId]["edges"]; - }; + function setup() { + if(Hammer.READY) { + return; + } + // find what eventtypes we add listeners to + Event.determineEventTypes(); - /** - * This function sets the global references to nodes, edges and nodeIndices back to - * those of the currently active sector. - * - * @private - */ - exports._loadLatestSector = function() { - this._switchToSector(this._sector()); - }; + // Register all gestures inside Hammer.gestures + Utils.each(Hammer.gestures, function(gesture) { + Detection.register(gesture); + }); + + // Add touch events on the document + Event.onTouch(Hammer.DOCUMENT, EVENT_MOVE, Detection.detect); + Event.onTouch(Hammer.DOCUMENT, EVENT_END, Detection.detect); + // Hammer is ready...! + Hammer.READY = true; + } /** - * This function returns the currently active sector Id + * @module hammer * - * @returns {String} - * @private + * @class Utils + * @static */ - exports._sector = function() { - return this.activeSector[this.activeSector.length-1]; - }; + var Utils = Hammer.utils = { + /** + * extend method, could also be used for cloning when `dest` is an empty object. + * changes the dest object + * @method extend + * @param {Object} dest + * @param {Object} src + * @param {Boolean} [merge=false] do a merge + * @return {Object} dest + */ + extend: function extend(dest, src, merge) { + for(var key in src) { + if(!src.hasOwnProperty(key) || (dest[key] !== undefined && merge)) { + continue; + } + dest[key] = src[key]; + } + return dest; + }, + /** + * simple addEventListener wrapper + * @method on + * @param {HTMLElement} element + * @param {String} type + * @param {Function} handler + */ + on: function on(element, type, handler) { + element.addEventListener(type, handler, false); + }, - /** - * This function returns the previously active sector Id - * - * @returns {String} - * @private - */ - exports._previousSector = function() { - if (this.activeSector.length > 1) { - return this.activeSector[this.activeSector.length-2]; - } - else { - throw new TypeError('there are not enough sectors in the this.activeSector array.'); - } - }; + /** + * simple removeEventListener wrapper + * @method off + * @param {HTMLElement} element + * @param {String} type + * @param {Function} handler + */ + off: function off(element, type, handler) { + element.removeEventListener(type, handler, false); + }, + /** + * forEach over arrays and objects + * @method each + * @param {Object|Array} obj + * @param {Function} iterator + * @param {any} iterator.item + * @param {Number} iterator.index + * @param {Object|Array} iterator.obj the source object + * @param {Object} context value to use as `this` in the iterator + */ + each: function each(obj, iterator, context) { + var i, len; - /** - * We add the active sector at the end of the this.activeSector array - * This ensures it is the currently active sector returned by _sector() and it reaches the top - * of the activeSector stack. When we reverse our steps we move from the end to the beginning of this stack. - * - * @param newId - * @private - */ - exports._setActiveSector = function(newId) { - this.activeSector.push(newId); - }; + // native forEach on arrays + if('forEach' in obj) { + obj.forEach(iterator, context); + // arrays + } else if(obj.length !== undefined) { + for(i = 0, len = obj.length; i < len; i++) { + if(iterator.call(context, obj[i], i, obj) === false) { + return; + } + } + // objects + } else { + for(i in obj) { + if(obj.hasOwnProperty(i) && + iterator.call(context, obj[i], i, obj) === false) { + return; + } + } + } + }, + /** + * find if a string contains the string using indexOf + * @method inStr + * @param {String} src + * @param {String} find + * @return {Boolean} found + */ + inStr: function inStr(src, find) { + return src.indexOf(find) > -1; + }, - /** - * We remove the currently active sector id from the active sector stack. This happens when - * we reactivate the previously active sector - * - * @private - */ - exports._forgetLastSector = function() { - this.activeSector.pop(); - }; + /** + * find if a array contains the object using indexOf or a simple polyfill + * @method inArray + * @param {String} src + * @param {String} find + * @return {Boolean|Number} false when not found, or the index + */ + inArray: function inArray(src, find) { + if(src.indexOf) { + var index = src.indexOf(find); + return (index === -1) ? false : index; + } else { + for(var i = 0, len = src.length; i < len; i++) { + if(src[i] === find) { + return i; + } + } + return false; + } + }, + /** + * convert an array-like object (`arguments`, `touchlist`) to an array + * @method toArray + * @param {Object} obj + * @return {Array} + */ + toArray: function toArray(obj) { + return Array.prototype.slice.call(obj, 0); + }, - /** - * This function creates a new active sector with the supplied newId. This newId - * is the expanding node id. - * - * @param {String} newId | Id of the new active sector - * @private - */ - exports._createNewSector = function(newId) { - // create the new sector - this.sectors["active"][newId] = {"nodes":{}, - "edges":{}, - "nodeIndices":[], - "formationScale": this.scale, - "drawingNode": undefined}; + /** + * find if a node is in the given parent + * @method hasParent + * @param {HTMLElement} node + * @param {HTMLElement} parent + * @return {Boolean} found + */ + hasParent: function hasParent(node, parent) { + while(node) { + if(node == parent) { + return true; + } + node = node.parentNode; + } + return false; + }, - // create the new sector render node. This gives visual feedback that you are in a new sector. - this.sectors["active"][newId]['drawingNode'] = new Node( - {id:newId, - color: { - background: "#eaefef", - border: "495c5e" + /** + * get the center of all the touches + * @method getCenter + * @param {Array} touches + * @return {Object} center contains `pageX`, `pageY`, `clientX` and `clientY` properties + */ + getCenter: function getCenter(touches) { + var pageX = [], + pageY = [], + clientX = [], + clientY = [], + min = Math.min, + max = Math.max; + + // no need to loop when only one touch + if(touches.length === 1) { + return { + pageX: touches[0].pageX, + pageY: touches[0].pageY, + clientX: touches[0].clientX, + clientY: touches[0].clientY + }; } - },{},{},this.constants); - this.sectors["active"][newId]['drawingNode'].clusterSize = 2; - }; + Utils.each(touches, function(touch) { + pageX.push(touch.pageX); + pageY.push(touch.pageY); + clientX.push(touch.clientX); + clientY.push(touch.clientY); + }); - /** - * This function removes the currently active sector. This is called when we create a new - * active sector. - * - * @param {String} sectorId | Id of the active sector that will be removed - * @private - */ - exports._deleteActiveSector = function(sectorId) { - delete this.sectors["active"][sectorId]; - }; + return { + pageX: (min.apply(Math, pageX) + max.apply(Math, pageX)) / 2, + pageY: (min.apply(Math, pageY) + max.apply(Math, pageY)) / 2, + clientX: (min.apply(Math, clientX) + max.apply(Math, clientX)) / 2, + clientY: (min.apply(Math, clientY) + max.apply(Math, clientY)) / 2 + }; + }, + /** + * calculate the velocity between two points. unit is in px per ms. + * @method getVelocity + * @param {Number} deltaTime + * @param {Number} deltaX + * @param {Number} deltaY + * @return {Object} velocity `x` and `y` + */ + getVelocity: function getVelocity(deltaTime, deltaX, deltaY) { + return { + x: Math.abs(deltaX / deltaTime) || 0, + y: Math.abs(deltaY / deltaTime) || 0 + }; + }, - /** - * This function removes the currently active sector. This is called when we reactivate - * the previously active sector. - * - * @param {String} sectorId | Id of the active sector that will be removed - * @private - */ - exports._deleteFrozenSector = function(sectorId) { - delete this.sectors["frozen"][sectorId]; - }; + /** + * calculate the angle between two coordinates + * @method getAngle + * @param {Touch} touch1 + * @param {Touch} touch2 + * @return {Number} angle + */ + getAngle: function getAngle(touch1, touch2) { + var x = touch2.clientX - touch1.clientX, + y = touch2.clientY - touch1.clientY; + return Math.atan2(y, x) * 180 / Math.PI; + }, - /** - * Freezing an active sector means moving it from the "active" object to the "frozen" object. - * We copy the references, then delete the active entree. - * - * @param sectorId - * @private - */ - exports._freezeSector = function(sectorId) { - // we move the set references from the active to the frozen stack. - this.sectors["frozen"][sectorId] = this.sectors["active"][sectorId]; + /** + * do a small comparision to get the direction between two touches. + * @method getDirection + * @param {Touch} touch1 + * @param {Touch} touch2 + * @return {String} direction matches `DIRECTION_LEFT|RIGHT|UP|DOWN` + */ + getDirection: function getDirection(touch1, touch2) { + var x = Math.abs(touch1.clientX - touch2.clientX), + y = Math.abs(touch1.clientY - touch2.clientY); - // we have moved the sector data into the frozen set, we now remove it from the active set - this._deleteActiveSector(sectorId); - }; + if(x >= y) { + return touch1.clientX - touch2.clientX > 0 ? DIRECTION_LEFT : DIRECTION_RIGHT; + } + return touch1.clientY - touch2.clientY > 0 ? DIRECTION_UP : DIRECTION_DOWN; + }, + /** + * calculate the distance between two touches + * @method getDistance + * @param {Touch}touch1 + * @param {Touch} touch2 + * @return {Number} distance + */ + getDistance: function getDistance(touch1, touch2) { + var x = touch2.clientX - touch1.clientX, + y = touch2.clientY - touch1.clientY; - /** - * This is the reverse operation of _freezeSector. Activating means moving the sector from the "frozen" - * object to the "active" object. - * - * @param sectorId - * @private - */ - exports._activateSector = function(sectorId) { - // we move the set references from the frozen to the active stack. - this.sectors["active"][sectorId] = this.sectors["frozen"][sectorId]; + return Math.sqrt((x * x) + (y * y)); + }, - // we have moved the sector data into the active set, we now remove it from the frozen stack - this._deleteFrozenSector(sectorId); - }; + /** + * calculate the scale factor between two touchLists + * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out + * @method getScale + * @param {Array} start array of touches + * @param {Array} end array of touches + * @return {Number} scale + */ + getScale: function getScale(start, end) { + // need two fingers... + if(start.length >= 2 && end.length >= 2) { + return this.getDistance(end[0], end[1]) / this.getDistance(start[0], start[1]); + } + return 1; + }, + /** + * calculate the rotation degrees between two touchLists + * @method getRotation + * @param {Array} start array of touches + * @param {Array} end array of touches + * @return {Number} rotation + */ + getRotation: function getRotation(start, end) { + // need two fingers + if(start.length >= 2 && end.length >= 2) { + return this.getAngle(end[1], end[0]) - this.getAngle(start[1], start[0]); + } + return 0; + }, - /** - * This function merges the data from the currently active sector with a frozen sector. This is used - * in the process of reverting back to the previously active sector. - * The data that is placed in the frozen (the previously active) sector is the node that has been removed from it - * upon the creation of a new active sector. - * - * @param sectorId - * @private - */ - exports._mergeThisWithFrozen = function(sectorId) { - // copy all nodes - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - this.sectors["frozen"][sectorId]["nodes"][nodeId] = this.nodes[nodeId]; - } - } + /** + * find out if the direction is vertical * + * @method isVertical + * @param {String} direction matches `DIRECTION_UP|DOWN` + * @return {Boolean} is_vertical + */ + isVertical: function isVertical(direction) { + return direction == DIRECTION_UP || direction == DIRECTION_DOWN; + }, + + /** + * set css properties with their prefixes + * @param {HTMLElement} element + * @param {String} prop + * @param {String} value + * @param {Boolean} [toggle=true] + * @return {Boolean} + */ + setPrefixedCss: function setPrefixedCss(element, prop, value, toggle) { + var prefixes = ['', 'Webkit', 'Moz', 'O', 'ms']; + prop = Utils.toCamelCase(prop); + + for(var i = 0; i < prefixes.length; i++) { + var p = prop; + // prefixes + if(prefixes[i]) { + p = prefixes[i] + p.slice(0, 1).toUpperCase() + p.slice(1); + } + + // test the style + if(p in element.style) { + element.style[p] = (toggle == null || toggle) && value || ''; + break; + } + } + }, + + /** + * toggle browser default behavior by setting css properties. + * `userSelect='none'` also sets `element.onselectstart` to false + * `userDrag='none'` also sets `element.ondragstart` to false + * + * @method toggleBehavior + * @param {HtmlElement} element + * @param {Object} props + * @param {Boolean} [toggle=true] + */ + toggleBehavior: function toggleBehavior(element, props, toggle) { + if(!props || !element || !element.style) { + return; + } + + // set the css properties + Utils.each(props, function(value, prop) { + Utils.setPrefixedCss(element, prop, value, toggle); + }); - // copy all edges (if not fully clustered, else there are no edges) - for (var edgeId in this.edges) { - if (this.edges.hasOwnProperty(edgeId)) { - this.sectors["frozen"][sectorId]["edges"][edgeId] = this.edges[edgeId]; - } - } + var falseFn = toggle && function() { + return false; + }; - // merge the nodeIndices - for (var i = 0; i < this.nodeIndices.length; i++) { - this.sectors["frozen"][sectorId]["nodeIndices"].push(this.nodeIndices[i]); - } + // also the disable onselectstart + if(props.userSelect == 'none') { + element.onselectstart = falseFn; + } + // and disable ondragstart + if(props.userDrag == 'none') { + element.ondragstart = falseFn; + } + }, + + /** + * convert a string with underscores to camelCase + * so prevent_default becomes preventDefault + * @param {String} str + * @return {String} camelCaseStr + */ + toCamelCase: function toCamelCase(str) { + return str.replace(/[_-]([a-z])/g, function(s) { + return s[1].toUpperCase(); + }); + } }; /** - * This clusters the sector to one cluster. It was a single cluster before this process started so - * we revert to that state. The clusterToFit function with a maximum size of 1 node does this. - * - * @private + * @module hammer */ - exports._collapseThisToSingleCluster = function() { - this.clusterToFit(1,false); - }; - - /** - * We create a new active sector from the node that we want to open. - * - * @param node - * @private + * @class Event + * @static */ - exports._addSector = function(node) { - // this is the currently active sector - var sector = this._sector(); - - // // this should allow me to select nodes from a frozen set. - // if (this.sectors['active'][sector]["nodes"].hasOwnProperty(node.id)) { - // console.log("the node is part of the active sector"); - // } - // else { - // console.log("I dont know what the fuck happened!!"); - // } + var Event = Hammer.event = { + /** + * when touch events have been fired, this is true + * this is used to stop mouse events + * @property prevent_mouseevents + * @private + * @type {Boolean} + */ + preventMouseEvents: false, - // when we switch to a new sector, we remove the node that will be expanded from the current nodes list. - delete this.nodes[node.id]; + /** + * if EVENT_START has been fired + * @property started + * @private + * @type {Boolean} + */ + started: false, - var unqiueIdentifier = util.randomUUID(); + /** + * when the mouse is hold down, this is true + * @property should_detect + * @private + * @type {Boolean} + */ + shouldDetect: false, - // we fully freeze the currently active sector - this._freezeSector(sector); + /** + * simple event binder with a hook and support for multiple types + * @method on + * @param {HTMLElement} element + * @param {String} type + * @param {Function} handler + * @param {Function} [hook] + * @param {Object} hook.type + */ + on: function on(element, type, handler, hook) { + var types = type.split(' '); + Utils.each(types, function(type) { + Utils.on(element, type, handler); + hook && hook(type); + }); + }, - // we create a new active sector. This sector has the Id of the node to ensure uniqueness - this._createNewSector(unqiueIdentifier); + /** + * simple event unbinder with a hook and support for multiple types + * @method off + * @param {HTMLElement} element + * @param {String} type + * @param {Function} handler + * @param {Function} [hook] + * @param {Object} hook.type + */ + off: function off(element, type, handler, hook) { + var types = type.split(' '); + Utils.each(types, function(type) { + Utils.off(element, type, handler); + hook && hook(type); + }); + }, - // we add the active sector to the sectors array to be able to revert these steps later on - this._setActiveSector(unqiueIdentifier); + /** + * the core touch event handler. + * this finds out if we should to detect gestures + * @method onTouch + * @param {HTMLElement} element + * @param {String} eventType matches `EVENT_START|MOVE|END` + * @param {Function} handler + * @return onTouchHandler {Function} the core event handler + */ + onTouch: function onTouch(element, eventType, handler) { + var self = this; - // we redirect the global references to the new sector's references. this._sector() now returns unqiueIdentifier - this._switchToSector(this._sector()); + var onTouchHandler = function onTouchHandler(ev) { + var srcType = ev.type.toLowerCase(), + isPointer = Hammer.HAS_POINTEREVENTS, + isMouse = Utils.inStr(srcType, 'mouse'), + triggerType; - // finally we add the node we removed from our previous active sector to the new active sector - this.nodes[node.id] = node; - }; + // if we are in a mouseevent, but there has been a touchevent triggered in this session + // we want to do nothing. simply break out of the event. + if(isMouse && self.preventMouseEvents) { + return; + // mousebutton must be down + } else if(isMouse && eventType == EVENT_START && ev.button === 0) { + self.preventMouseEvents = false; + self.shouldDetect = true; + } else if(isPointer && eventType == EVENT_START) { + self.shouldDetect = (ev.buttons === 1 || PointerEvent.matchType(POINTER_TOUCH, ev)); + // just a valid start event, but no mouse + } else if(!isMouse && eventType == EVENT_START) { + self.preventMouseEvents = true; + self.shouldDetect = true; + } - /** - * We close the sector that is currently open and revert back to the one before. - * If the active sector is the "default" sector, nothing happens. - * - * @private - */ - exports._collapseSector = function() { - // the currently active sector - var sector = this._sector(); + // update the pointer event before entering the detection + if(isPointer && eventType != EVENT_END) { + PointerEvent.updatePointer(eventType, ev); + } - // we cannot collapse the default sector - if (sector != "default") { - if ((this.nodeIndices.length == 1) || - (this.sectors["active"][sector]["drawingNode"].width*this.scale < this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientWidth) || - (this.sectors["active"][sector]["drawingNode"].height*this.scale < this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientHeight)) { - var previousSector = this._previousSector(); + // we are in a touch/down state, so allowed detection of gestures + if(self.shouldDetect) { + triggerType = self.doDetect.call(self, ev, eventType, element, handler); + } - // we collapse the sector back to a single cluster - this._collapseThisToSingleCluster(); + // ...and we are done with the detection + // so reset everything to start each detection totally fresh + if(triggerType == EVENT_END) { + self.preventMouseEvents = false; + self.shouldDetect = false; + PointerEvent.reset(); + // update the pointerevent object after the detection + } - // we move the remaining nodes, edges and nodeIndices to the previous sector. - // This previous sector is the one we will reactivate - this._mergeThisWithFrozen(previousSector); + if(isPointer && eventType == EVENT_END) { + PointerEvent.updatePointer(eventType, ev); + } + }; - // the previously active (frozen) sector now has all the data from the currently active sector. - // we can now delete the active sector. - this._deleteActiveSector(sector); + this.on(element, EVENT_TYPES[eventType], onTouchHandler); + return onTouchHandler; + }, - // we activate the previously active (and currently frozen) sector. - this._activateSector(previousSector); + /** + * the core detection method + * this finds out what hammer-touch-events to trigger + * @method doDetect + * @param {Object} ev + * @param {String} eventType matches `EVENT_START|MOVE|END` + * @param {HTMLElement} element + * @param {Function} handler + * @return {String} triggerType matches `EVENT_START|MOVE|END` + */ + doDetect: function doDetect(ev, eventType, element, handler) { + var touchList = this.getTouchList(ev, eventType); + var touchListLength = touchList.length; + var triggerType = eventType; + var triggerChange = touchList.trigger; // used by fakeMultitouch plugin + var changedLength = touchListLength; - // we load the references from the newly active sector into the global references - this._switchToSector(previousSector); + // at each touchstart-like event we want also want to trigger a TOUCH event... + if(eventType == EVENT_START) { + triggerChange = EVENT_TOUCH; + // ...the same for a touchend-like event + } else if(eventType == EVENT_END) { + triggerChange = EVENT_RELEASE; - // we forget the previously active sector because we reverted to the one before - this._forgetLastSector(); + // keep track of how many touches have been removed + changedLength = touchList.length - ((ev.changedTouches) ? ev.changedTouches.length : 1); + } - // finally, we update the node index list. - this._updateNodeIndexList(); + // after there are still touches on the screen, + // we just want to trigger a MOVE event. so change the START or END to a MOVE + // but only after detection has been started, the first time we actualy want a START + if(changedLength > 0 && this.started) { + triggerType = EVENT_MOVE; + } - // we refresh the list with calulation nodes and calculation node indices. - this._updateCalculationNodes(); - } - } - }; + // detection has been started, we keep track of this, see above + this.started = true; + // generate some event data, some basic information + var evData = this.collectEventData(element, triggerType, touchList, ev); - /** - * This runs a function in all active sectors. This is used in _redraw() and the _initializeForceCalculation(). - * - * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors - * | we dont pass the function itself because then the "this" is the window object - * | instead of the Network object - * @param {*} [argument] | Optional: arguments to pass to the runFunction - * @private - */ - exports._doInAllActiveSectors = function(runFunction,argument) { - var returnValues = []; - if (argument === undefined) { - for (var sector in this.sectors["active"]) { - if (this.sectors["active"].hasOwnProperty(sector)) { - // switch the global references to those of this sector - this._switchToActiveSector(sector); - returnValues.push( this[runFunction]() ); - } - } - } - else { - for (var sector in this.sectors["active"]) { - if (this.sectors["active"].hasOwnProperty(sector)) { - // switch the global references to those of this sector - this._switchToActiveSector(sector); - var args = Array.prototype.splice.call(arguments, 1); - if (args.length > 1) { - returnValues.push( this[runFunction](args[0],args[1]) ); - } - else { - returnValues.push( this[runFunction](argument) ); + // trigger the triggerType event before the change (TOUCH, RELEASE) events + // but the END event should be at last + if(eventType != EVENT_END) { + handler.call(Detection, evData); } - } - } - } - // we revert the global references back to our active sector - this._loadLatestSector(); - return returnValues; - }; - - /** - * This runs a function in all active sectors. This is used in _redraw() and the _initializeForceCalculation(). - * - * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors - * | we dont pass the function itself because then the "this" is the window object - * | instead of the Network object - * @param {*} [argument] | Optional: arguments to pass to the runFunction - * @private - */ - exports._doInSupportSector = function(runFunction,argument) { - var returnValues = false; - if (argument === undefined) { - this._switchToSupportSector(); - returnValues = this[runFunction](); - } - else { - this._switchToSupportSector(); - var args = Array.prototype.splice.call(arguments, 1); - if (args.length > 1) { - returnValues = this[runFunction](args[0],args[1]); - } - else { - returnValues = this[runFunction](argument); - } - } - // we revert the global references back to our active sector - this._loadLatestSector(); - return returnValues; - }; + // trigger a change (TOUCH, RELEASE) event, this means the length of the touches changed + if(triggerChange) { + evData.changedLength = changedLength; + evData.eventType = triggerChange; + handler.call(Detection, evData); - /** - * This runs a function in all frozen sectors. This is used in the _redraw(). - * - * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors - * | we don't pass the function itself because then the "this" is the window object - * | instead of the Network object - * @param {*} [argument] | Optional: arguments to pass to the runFunction - * @private - */ - exports._doInAllFrozenSectors = function(runFunction,argument) { - if (argument === undefined) { - for (var sector in this.sectors["frozen"]) { - if (this.sectors["frozen"].hasOwnProperty(sector)) { - // switch the global references to those of this sector - this._switchToFrozenSector(sector); - this[runFunction](); - } - } - } - else { - for (var sector in this.sectors["frozen"]) { - if (this.sectors["frozen"].hasOwnProperty(sector)) { - // switch the global references to those of this sector - this._switchToFrozenSector(sector); - var args = Array.prototype.splice.call(arguments, 1); - if (args.length > 1) { - this[runFunction](args[0],args[1]); - } - else { - this[runFunction](argument); + evData.eventType = triggerType; + delete evData.changedLength; } - } - } - } - this._loadLatestSector(); - }; - - - /** - * This runs a function in all sectors. This is used in the _redraw(). - * - * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors - * | we don't pass the function itself because then the "this" is the window object - * | instead of the Network object - * @param {*} [argument] | Optional: arguments to pass to the runFunction - * @private - */ - exports._doInAllSectors = function(runFunction,argument) { - var args = Array.prototype.splice.call(arguments, 1); - if (argument === undefined) { - this._doInAllActiveSectors(runFunction); - this._doInAllFrozenSectors(runFunction); - } - else { - if (args.length > 1) { - this._doInAllActiveSectors(runFunction,args[0],args[1]); - this._doInAllFrozenSectors(runFunction,args[0],args[1]); - } - else { - this._doInAllActiveSectors(runFunction,argument); - this._doInAllFrozenSectors(runFunction,argument); - } - } - }; + // trigger the END event + if(triggerType == EVENT_END) { + handler.call(Detection, evData); - /** - * This clears the nodeIndices list. We cannot use this.nodeIndices = [] because we would break the link with the - * active sector. Thus we clear the nodeIndices in the active sector, then reconnect the this.nodeIndices to it. - * - * @private - */ - exports._clearNodeIndexList = function() { - var sector = this._sector(); - this.sectors["active"][sector]["nodeIndices"] = []; - this.nodeIndices = this.sectors["active"][sector]["nodeIndices"]; - }; + // ...and we are done with the detection + // so reset everything to start each detection totally fresh + this.started = false; + } + return triggerType; + }, - /** - * Draw the encompassing sector node - * - * @param ctx - * @param sectorType - * @private - */ - exports._drawSectorNodes = function(ctx,sectorType) { - var minY = 1e9, maxY = -1e9, minX = 1e9, maxX = -1e9, node; - for (var sector in this.sectors[sectorType]) { - if (this.sectors[sectorType].hasOwnProperty(sector)) { - if (this.sectors[sectorType][sector]["drawingNode"] !== undefined) { + /** + * we have different events for each device/browser + * determine what we need and set them in the EVENT_TYPES constant + * the `onTouch` method is bind to these properties. + * @method determineEventTypes + * @return {Object} events + */ + determineEventTypes: function determineEventTypes() { + var types; + if(Hammer.HAS_POINTEREVENTS) { + if(window.PointerEvent) { + types = [ + 'pointerdown', + 'pointermove', + 'pointerup pointercancel lostpointercapture' + ]; + } else { + types = [ + 'MSPointerDown', + 'MSPointerMove', + 'MSPointerUp MSPointerCancel MSLostPointerCapture' + ]; + } + } else if(Hammer.NO_MOUSEEVENTS) { + types = [ + 'touchstart', + 'touchmove', + 'touchend touchcancel' + ]; + } else { + types = [ + 'touchstart mousedown', + 'touchmove mousemove', + 'touchend touchcancel mouseup' + ]; + } - this._switchToSector(sector,sectorType); + EVENT_TYPES[EVENT_START] = types[0]; + EVENT_TYPES[EVENT_MOVE] = types[1]; + EVENT_TYPES[EVENT_END] = types[2]; + return EVENT_TYPES; + }, - minY = 1e9; maxY = -1e9; minX = 1e9; maxX = -1e9; - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - node = this.nodes[nodeId]; - node.resize(ctx); - if (minX > node.x - 0.5 * node.width) {minX = node.x - 0.5 * node.width;} - if (maxX < node.x + 0.5 * node.width) {maxX = node.x + 0.5 * node.width;} - if (minY > node.y - 0.5 * node.height) {minY = node.y - 0.5 * node.height;} - if (maxY < node.y + 0.5 * node.height) {maxY = node.y + 0.5 * node.height;} - } + /** + * create touchList depending on the event + * @method getTouchList + * @param {Object} ev + * @param {String} eventType + * @return {Array} touches + */ + getTouchList: function getTouchList(ev, eventType) { + // get the fake pointerEvent touchlist + if(Hammer.HAS_POINTEREVENTS) { + return PointerEvent.getTouchList(); } - node = this.sectors[sectorType][sector]["drawingNode"]; - node.x = 0.5 * (maxX + minX); - node.y = 0.5 * (maxY + minY); - node.width = 2 * (node.x - minX); - node.height = 2 * (node.y - minY); - node.options.radius = Math.sqrt(Math.pow(0.5*node.width,2) + Math.pow(0.5*node.height,2)); - node.setScale(this.scale); - node._drawCircle(ctx); - } - } - } - }; - exports._drawAllSectorNodes = function(ctx) { - this._drawSectorNodes(ctx,"frozen"); - this._drawSectorNodes(ctx,"active"); - this._loadLatestSector(); - }; + // get the touchlist + if(ev.touches) { + if(eventType == EVENT_MOVE) { + return ev.touches; + } + + var identifiers = []; + var concat = [].concat(Utils.toArray(ev.touches), Utils.toArray(ev.changedTouches)); + var touchList = []; + Utils.each(concat, function(touch) { + if(Utils.inArray(identifiers, touch.identifier) === false) { + touchList.push(touch); + } + identifiers.push(touch.identifier); + }); -/***/ }, -/* 62 */ -/***/ function(module, exports, __webpack_require__) { + return touchList; + } - var Node = __webpack_require__(40); + // make fake touchList from mouse position + ev.identifier = 1; + return [ev]; + }, - /** - * This function can be called from the _doInAllSectors function - * - * @param object - * @param overlappingNodes - * @private - */ - exports._getNodesOverlappingWith = function(object, overlappingNodes) { - var nodes = this.nodes; - for (var nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - if (nodes[nodeId].isOverlappingWith(object)) { - overlappingNodes.push(nodeId); - } - } - } - }; + /** + * collect basic event data + * @method collectEventData + * @param {HTMLElement} element + * @param {String} eventType matches `EVENT_START|MOVE|END` + * @param {Array} touches + * @param {Object} ev + * @return {Object} ev + */ + collectEventData: function collectEventData(element, eventType, touches, ev) { + // find out pointerType + var pointerType = POINTER_TOUCH; + if(Utils.inStr(ev.type, 'mouse') || PointerEvent.matchType(POINTER_MOUSE, ev)) { + pointerType = POINTER_MOUSE; + } else if(PointerEvent.matchType(POINTER_PEN, ev)) { + pointerType = POINTER_PEN; + } - /** - * retrieve all nodes overlapping with given object - * @param {Object} object An object with parameters left, top, right, bottom - * @return {Number[]} An array with id's of the overlapping nodes - * @private - */ - exports._getAllNodesOverlappingWith = function (object) { - var overlappingNodes = []; - this._doInAllActiveSectors("_getNodesOverlappingWith",object,overlappingNodes); - return overlappingNodes; - }; + return { + center: Utils.getCenter(touches), + timeStamp: Date.now(), + target: ev.target, + touches: touches, + eventType: eventType, + pointerType: pointerType, + srcEvent: ev, + /** + * prevent the browser default actions + * mostly used to disable scrolling of the browser + */ + preventDefault: function() { + var srcEvent = this.srcEvent; + srcEvent.preventManipulation && srcEvent.preventManipulation(); + srcEvent.preventDefault && srcEvent.preventDefault(); + }, - /** - * Return a position object in canvasspace from a single point in screenspace - * - * @param pointer - * @returns {{left: number, top: number, right: number, bottom: number}} - * @private - */ - exports._pointerToPositionObject = function(pointer) { - var x = this._XconvertDOMtoCanvas(pointer.x); - var y = this._YconvertDOMtoCanvas(pointer.y); + /** + * stop bubbling the event up to its parents + */ + stopPropagation: function() { + this.srcEvent.stopPropagation(); + }, - return { - left: x, - top: y, - right: x, - bottom: y - }; + /** + * immediately stop gesture detection + * might be useful after a swipe was detected + * @return {*} + */ + stopDetect: function() { + return Detection.stopDetect(); + } + }; + } }; /** - * Get the top node at the a specific point (like a click) + * @module hammer * - * @param {{x: Number, y: Number}} pointer - * @return {Node | null} node - * @private + * @class PointerEvent + * @static */ - exports._getNodeAt = function (pointer) { - // we first check if this is an navigation controls element - var positionObject = this._pointerToPositionObject(pointer); - var overlappingNodes = this._getAllNodesOverlappingWith(positionObject); - - // if there are overlapping nodes, select the last one, this is the - // one which is drawn on top of the others - if (overlappingNodes.length > 0) { - return this.nodes[overlappingNodes[overlappingNodes.length - 1]]; - } - else { - return null; - } - }; + var PointerEvent = Hammer.PointerEvent = { + /** + * holds all pointers, by `identifier` + * @property pointers + * @type {Object} + */ + pointers: {}, + /** + * get the pointers as an array + * @method getTouchList + * @return {Array} touchlist + */ + getTouchList: function getTouchList() { + var touchlist = []; + // we can use forEach since pointerEvents only is in IE10 + Utils.each(this.pointers, function(pointer) { + touchlist.push(pointer); + }); + return touchlist; + }, - /** - * retrieve all edges overlapping with given object, selector is around center - * @param {Object} object An object with parameters left, top, right, bottom - * @return {Number[]} An array with id's of the overlapping nodes - * @private - */ - exports._getEdgesOverlappingWith = function (object, overlappingEdges) { - var edges = this.edges; - for (var edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - if (edges[edgeId].isOverlappingWith(object)) { - overlappingEdges.push(edgeId); - } - } - } - }; + /** + * update the position of a pointer + * @method updatePointer + * @param {String} eventType matches `EVENT_START|MOVE|END` + * @param {Object} pointerEvent + */ + updatePointer: function updatePointer(eventType, pointerEvent) { + if(eventType == EVENT_END || (eventType != EVENT_END && pointerEvent.buttons !== 1)) { + delete this.pointers[pointerEvent.pointerId]; + } else { + pointerEvent.identifier = pointerEvent.pointerId; + this.pointers[pointerEvent.pointerId] = pointerEvent; + } + }, + /** + * check if ev matches pointertype + * @method matchType + * @param {String} pointerType matches `POINTER_MOUSE|TOUCH|PEN` + * @param {PointerEvent} ev + */ + matchType: function matchType(pointerType, ev) { + if(!ev.pointerType) { + return false; + } - /** - * retrieve all nodes overlapping with given object - * @param {Object} object An object with parameters left, top, right, bottom - * @return {Number[]} An array with id's of the overlapping nodes - * @private - */ - exports._getAllEdgesOverlappingWith = function (object) { - var overlappingEdges = []; - this._doInAllActiveSectors("_getEdgesOverlappingWith",object,overlappingEdges); - return overlappingEdges; - }; + var pt = ev.pointerType, + types = {}; - /** - * Place holder. To implement change the _getNodeAt to a _getObjectAt. Have the _getObjectAt call - * _getNodeAt and _getEdgesAt, then priortize the selection to user preferences. - * - * @param pointer - * @returns {null} - * @private - */ - exports._getEdgeAt = function(pointer) { - var positionObject = this._pointerToPositionObject(pointer); - var overlappingEdges = this._getAllEdgesOverlappingWith(positionObject); + types[POINTER_MOUSE] = (pt === (ev.MSPOINTER_TYPE_MOUSE || POINTER_MOUSE)); + types[POINTER_TOUCH] = (pt === (ev.MSPOINTER_TYPE_TOUCH || POINTER_TOUCH)); + types[POINTER_PEN] = (pt === (ev.MSPOINTER_TYPE_PEN || POINTER_PEN)); + return types[pointerType]; + }, - if (overlappingEdges.length > 0) { - return this.edges[overlappingEdges[overlappingEdges.length - 1]]; - } - else { - return null; - } + /** + * reset the stored pointers + * @method reset + */ + reset: function resetList() { + this.pointers = {}; + } }; /** - * Add object to the selection array. - * - * @param obj - * @private - */ - exports._addToSelection = function(obj) { - if (obj instanceof Node) { - this.selectionObj.nodes[obj.id] = obj; - } - else { - this.selectionObj.edges[obj.id] = obj; - } - }; - - /** - * Add object to the selection array. + * @module hammer * - * @param obj - * @private + * @class Detection + * @static */ - exports._addToHover = function(obj) { - if (obj instanceof Node) { - this.hoverObj.nodes[obj.id] = obj; - } - else { - this.hoverObj.edges[obj.id] = obj; - } - }; - + var Detection = Hammer.detection = { + // contains all registred Hammer.gestures in the correct order + gestures: [], - /** - * Remove a single option from selection. - * - * @param {Object} obj - * @private - */ - exports._removeFromSelection = function(obj) { - if (obj instanceof Node) { - delete this.selectionObj.nodes[obj.id]; - } - else { - delete this.selectionObj.edges[obj.id]; - } - }; + // data of the current Hammer.gesture detection session + current: null, - /** - * Unselect all. The selectionObj is useful for this. - * - * @param {Boolean} [doNotTrigger] | ignore trigger - * @private - */ - exports._unselectAll = function(doNotTrigger) { - if (doNotTrigger === undefined) { - doNotTrigger = false; - } - for(var nodeId in this.selectionObj.nodes) { - if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { - this.selectionObj.nodes[nodeId].unselect(); - } - } - for(var edgeId in this.selectionObj.edges) { - if(this.selectionObj.edges.hasOwnProperty(edgeId)) { - this.selectionObj.edges[edgeId].unselect(); - } - } + // the previous Hammer.gesture session data + // is a full clone of the previous gesture.current object + previous: null, - this.selectionObj = {nodes:{},edges:{}}; + // when this becomes true, no gestures are fired + stopped: false, - if (doNotTrigger == false) { - this.emit('select', this.getSelection()); - } - }; + /** + * start Hammer.gesture detection + * @method startDetect + * @param {Hammer.Instance} inst + * @param {Object} eventData + */ + startDetect: function startDetect(inst, eventData) { + // already busy with a Hammer.gesture detection on an element + if(this.current) { + return; + } - /** - * Unselect all clusters. The selectionObj is useful for this. - * - * @param {Boolean} [doNotTrigger] | ignore trigger - * @private - */ - exports._unselectClusters = function(doNotTrigger) { - if (doNotTrigger === undefined) { - doNotTrigger = false; - } + this.stopped = false; - for (var nodeId in this.selectionObj.nodes) { - if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { - if (this.selectionObj.nodes[nodeId].clusterSize > 1) { - this.selectionObj.nodes[nodeId].unselect(); - this._removeFromSelection(this.selectionObj.nodes[nodeId]); - } - } - } + // holds current session + this.current = { + inst: inst, // reference to HammerInstance we're working for + startEvent: Utils.extend({}, eventData), // start eventData for distances, timing etc + lastEvent: false, // last eventData + lastCalcEvent: false, // last eventData for calculations. + futureCalcEvent: false, // last eventData for calculations. + lastCalcData: {}, // last lastCalcData + name: '' // current gesture we're in/detected, can be 'tap', 'hold' etc + }; - if (doNotTrigger == false) { - this.emit('select', this.getSelection()); - } - }; + this.detect(eventData); + }, + /** + * Hammer.gesture detection + * @method detect + * @param {Object} eventData + * @return {any} + */ + detect: function detect(eventData) { + if(!this.current || this.stopped) { + return; + } - /** - * return the number of selected nodes - * - * @returns {number} - * @private - */ - exports._getSelectedNodeCount = function() { - var count = 0; - for (var nodeId in this.selectionObj.nodes) { - if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { - count += 1; - } - } - return count; - }; + // extend event data with calculations about scale, distance etc + eventData = this.extendEventData(eventData); - /** - * return the selected node - * - * @returns {number} - * @private - */ - exports._getSelectedNode = function() { - for (var nodeId in this.selectionObj.nodes) { - if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { - return this.selectionObj.nodes[nodeId]; - } - } - return null; - }; + // hammer instance and instance options + var inst = this.current.inst, + instOptions = inst.options; - /** - * return the selected edge - * - * @returns {number} - * @private - */ - exports._getSelectedEdge = function() { - for (var edgeId in this.selectionObj.edges) { - if (this.selectionObj.edges.hasOwnProperty(edgeId)) { - return this.selectionObj.edges[edgeId]; - } - } - return null; - }; + // call Hammer.gesture handlers + Utils.each(this.gestures, function triggerGesture(gesture) { + // only when the instance options have enabled this gesture + if(!this.stopped && inst.enabled && instOptions[gesture.name]) { + gesture.handler.call(gesture, eventData, inst); + } + }, this); + // store as previous event event + if(this.current) { + this.current.lastEvent = eventData; + } - /** - * return the number of selected edges - * - * @returns {number} - * @private - */ - exports._getSelectedEdgeCount = function() { - var count = 0; - for (var edgeId in this.selectionObj.edges) { - if (this.selectionObj.edges.hasOwnProperty(edgeId)) { - count += 1; - } - } - return count; - }; + if(eventData.eventType == EVENT_END) { + this.stopDetect(); + } + return eventData; + }, - /** - * return the number of selected objects. - * - * @returns {number} - * @private - */ - exports._getSelectedObjectCount = function() { - var count = 0; - for(var nodeId in this.selectionObj.nodes) { - if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { - count += 1; - } - } - for(var edgeId in this.selectionObj.edges) { - if(this.selectionObj.edges.hasOwnProperty(edgeId)) { - count += 1; - } - } - return count; - }; + /** + * clear the Hammer.gesture vars + * this is called on endDetect, but can also be used when a final Hammer.gesture has been detected + * to stop other Hammer.gestures from being fired + * @method stopDetect + */ + stopDetect: function stopDetect() { + // clone current data to the store as the previous gesture + // used for the double tap gesture, since this is an other gesture detect session + this.previous = Utils.extend({}, this.current); - /** - * Check if anything is selected - * - * @returns {boolean} - * @private - */ - exports._selectionIsEmpty = function() { - for(var nodeId in this.selectionObj.nodes) { - if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { - return false; - } - } - for(var edgeId in this.selectionObj.edges) { - if(this.selectionObj.edges.hasOwnProperty(edgeId)) { - return false; - } - } - return true; - }; + // reset the current + this.current = null; + this.stopped = true; + }, + /** + * calculate velocity, angle and direction + * @method getVelocityData + * @param {Object} ev + * @param {Object} center + * @param {Number} deltaTime + * @param {Number} deltaX + * @param {Number} deltaY + */ + getCalculatedData: function getCalculatedData(ev, center, deltaTime, deltaX, deltaY) { + var cur = this.current, + recalc = false, + calcEv = cur.lastCalcEvent, + calcData = cur.lastCalcData; - /** - * check if one of the selected nodes is a cluster. - * - * @returns {boolean} - * @private - */ - exports._clusterInSelection = function() { - for(var nodeId in this.selectionObj.nodes) { - if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { - if (this.selectionObj.nodes[nodeId].clusterSize > 1) { - return true; - } - } - } - return false; - }; + if(calcEv && ev.timeStamp - calcEv.timeStamp > Hammer.CALCULATE_INTERVAL) { + center = calcEv.center; + deltaTime = ev.timeStamp - calcEv.timeStamp; + deltaX = ev.center.clientX - calcEv.center.clientX; + deltaY = ev.center.clientY - calcEv.center.clientY; + recalc = true; + } - /** - * select the edges connected to the node that is being selected - * - * @param {Node} node - * @private - */ - exports._selectConnectedEdges = function(node) { - for (var i = 0; i < node.dynamicEdges.length; i++) { - var edge = node.dynamicEdges[i]; - edge.select(); - this._addToSelection(edge); - } - }; + if(ev.eventType == EVENT_TOUCH || ev.eventType == EVENT_RELEASE) { + cur.futureCalcEvent = ev; + } - /** - * select the edges connected to the node that is being selected - * - * @param {Node} node - * @private - */ - exports._hoverConnectedEdges = function(node) { - for (var i = 0; i < node.dynamicEdges.length; i++) { - var edge = node.dynamicEdges[i]; - edge.hover = true; - this._addToHover(edge); - } - }; + if(!cur.lastCalcEvent || recalc) { + calcData.velocity = Utils.getVelocity(deltaTime, deltaX, deltaY); + calcData.angle = Utils.getAngle(center, ev.center); + calcData.direction = Utils.getDirection(center, ev.center); + cur.lastCalcEvent = cur.futureCalcEvent || ev; + cur.futureCalcEvent = ev; + } - /** - * unselect the edges connected to the node that is being selected - * - * @param {Node} node - * @private - */ - exports._unselectConnectedEdges = function(node) { - for (var i = 0; i < node.dynamicEdges.length; i++) { - var edge = node.dynamicEdges[i]; - edge.unselect(); - this._removeFromSelection(edge); - } - }; + ev.velocityX = calcData.velocity.x; + ev.velocityY = calcData.velocity.y; + ev.interimAngle = calcData.angle; + ev.interimDirection = calcData.direction; + }, + /** + * extend eventData for Hammer.gestures + * @method extendEventData + * @param {Object} ev + * @return {Object} ev + */ + extendEventData: function extendEventData(ev) { + var cur = this.current, + startEv = cur.startEvent, + lastEv = cur.lastEvent || startEv; + // update the start touchlist to calculate the scale/rotation + if(ev.eventType == EVENT_TOUCH || ev.eventType == EVENT_RELEASE) { + startEv.touches = []; + Utils.each(ev.touches, function(touch) { + startEv.touches.push({ + clientX: touch.clientX, + clientY: touch.clientY + }); + }); + } + var deltaTime = ev.timeStamp - startEv.timeStamp, + deltaX = ev.center.clientX - startEv.center.clientX, + deltaY = ev.center.clientY - startEv.center.clientY; - /** - * This is called when someone clicks on a node. either select or deselect it. - * If there is an existing selection and we don't want to append to it, clear the existing selection - * - * @param {Node || Edge} object - * @param {Boolean} append - * @param {Boolean} [doNotTrigger] | ignore trigger - * @private - */ - exports._selectObject = function(object, append, doNotTrigger, highlightEdges, overrideSelectable) { - if (doNotTrigger === undefined) { - doNotTrigger = false; - } - if (highlightEdges === undefined) { - highlightEdges = true; - } + this.getCalculatedData(ev, lastEv.center, deltaTime, deltaX, deltaY); - if (this._selectionIsEmpty() == false && append == false && this.forceAppendSelection == false) { - this._unselectAll(true); - } + Utils.extend(ev, { + startEvent: startEv, - // selectable allows the object to be selected. Override can be used if needed to bypass this. - if (object.selected == false && (this.constants.selectable == true || overrideSelectable)) { - object.select(); - this._addToSelection(object); - if (object instanceof Node && this.blockConnectingEdgeSelection == false && highlightEdges == true) { - this._selectConnectedEdges(object); - } - } - // do not select the object if selectable is false, only add it to selection to allow drag to work - else if (object.selected == false) { - this._addToSelection(object); - doNotTrigger = true; - } - else { - object.unselect(); - this._removeFromSelection(object); - } + deltaTime: deltaTime, + deltaX: deltaX, + deltaY: deltaY, - if (doNotTrigger == false) { - this.emit('select', this.getSelection()); - } - }; + distance: Utils.getDistance(startEv.center, ev.center), + angle: Utils.getAngle(startEv.center, ev.center), + direction: Utils.getDirection(startEv.center, ev.center), + scale: Utils.getScale(startEv.touches, ev.touches), + rotation: Utils.getRotation(startEv.touches, ev.touches) + }); + return ev; + }, - /** - * This is called when someone clicks on a node. either select or deselect it. - * If there is an existing selection and we don't want to append to it, clear the existing selection - * - * @param {Node || Edge} object - * @private - */ - exports._blurObject = function(object) { - if (object.hover == true) { - object.hover = false; - this.emit("blurNode",{node:object.id}); - } - }; + /** + * register new gesture + * @method register + * @param {Object} gesture object, see `gestures/` for documentation + * @return {Array} gestures + */ + register: function register(gesture) { + // add an enable gesture options if there is no given + var options = gesture.defaults || {}; + if(options[gesture.name] === undefined) { + options[gesture.name] = true; + } - /** - * This is called when someone clicks on a node. either select or deselect it. - * If there is an existing selection and we don't want to append to it, clear the existing selection - * - * @param {Node || Edge} object - * @private - */ - exports._hoverObject = function(object) { - if (object.hover == false) { - object.hover = true; - this._addToHover(object); - if (object instanceof Node) { - this.emit("hoverNode",{node:object.id}); - } - } - if (object instanceof Node) { - this._hoverConnectedEdges(object); - } - }; + // extend Hammer default options with the Hammer.gesture options + Utils.extend(Hammer.defaults, options, true); + // set its index + gesture.index = gesture.index || 1000; - /** - * handles the selection part of the touch, only for navigation controls elements; - * Touch is triggered before tap, also before hold. Hold triggers after a while. - * This is the most responsive solution - * - * @param {Object} pointer - * @private - */ - exports._handleTouch = function(pointer) { - }; + // add Hammer.gesture to the list + this.gestures.push(gesture); + // sort the list by index + this.gestures.sort(function(a, b) { + if(a.index < b.index) { + return -1; + } + if(a.index > b.index) { + return 1; + } + return 0; + }); - /** - * handles the selection part of the tap; - * - * @param {Object} pointer - * @private - */ - exports._handleTap = function(pointer) { - var node = this._getNodeAt(pointer); - if (node != null) { - this._selectObject(node, false); - } - else { - var edge = this._getEdgeAt(pointer); - if (edge != null) { - this._selectObject(edge, false); - } - else { - this._unselectAll(); + return this.gestures; } - } - var properties = this.getSelection(); - properties['pointer'] = { - DOM: {x: pointer.x, y: pointer.y}, - canvas: {x: this._XconvertDOMtoCanvas(pointer.x), y: this._YconvertDOMtoCanvas(pointer.y)} - } - this.emit("click", properties); - this._redraw(); }; /** - * handles the selection part of the double tap and opens a cluster if needed - * - * @param {Object} pointer - * @private + * @module hammer */ - exports._handleDoubleTap = function(pointer) { - var node = this._getNodeAt(pointer); - if (node != null && node !== undefined) { - // we reset the areaCenter here so the opening of the node will occur - this.areaCenter = {"x" : this._XconvertDOMtoCanvas(pointer.x), - "y" : this._YconvertDOMtoCanvas(pointer.y)}; - this.openCluster(node); - } - var properties = this.getSelection(); - properties['pointer'] = { - DOM: {x: pointer.x, y: pointer.y}, - canvas: {x: this._XconvertDOMtoCanvas(pointer.x), y: this._YconvertDOMtoCanvas(pointer.y)} - } - this.emit("doubleClick", properties); - }; - /** - * Handle the onHold selection part + * create new hammer instance + * all methods should return the instance itself, so it is chainable. * - * @param pointer - * @private + * @class Instance + * @constructor + * @param {HTMLElement} element + * @param {Object} [options={}] options are merged with `Hammer.defaults` + * @return {Hammer.Instance} */ - exports._handleOnHold = function(pointer) { - var node = this._getNodeAt(pointer); - if (node != null) { - this._selectObject(node,true); - } - else { - var edge = this._getEdgeAt(pointer); - if (edge != null) { - this._selectObject(edge,true); - } - } - this._redraw(); - }; + Hammer.Instance = function(element, options) { + var self = this; + // setup HammerJS window events and register all gestures + // this also sets up the default options + setup(); - /** - * handle the onRelease event. These functions are here for the navigation controls module - * and data manipulation module. - * - * @private - */ - exports._handleOnRelease = function(pointer) { - this._manipulationReleaseOverload(pointer); - this._navigationReleaseOverload(pointer); - }; + /** + * @property element + * @type {HTMLElement} + */ + this.element = element; - exports._manipulationReleaseOverload = function (pointer) {}; - exports._navigationReleaseOverload = function (pointer) {}; + /** + * @property enabled + * @type {Boolean} + * @protected + */ + this.enabled = true; - /** - * - * retrieve the currently selected objects - * @return {{nodes: Array., edges: Array.}} selection - */ - exports.getSelection = function() { - var nodeIds = this.getSelectedNodes(); - var edgeIds = this.getSelectedEdges(); - return {nodes:nodeIds, edges:edgeIds}; - }; + /** + * options, merged with the defaults + * options with an _ are converted to camelCase + * @property options + * @type {Object} + */ + Utils.each(options, function(value, name) { + delete options[name]; + options[Utils.toCamelCase(name)] = value; + }); - /** - * - * retrieve the currently selected nodes - * @return {String[]} selection An array with the ids of the - * selected nodes. - */ - exports.getSelectedNodes = function() { - var idArray = []; - if (this.constants.selectable == true) { - for (var nodeId in this.selectionObj.nodes) { - if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { - idArray.push(nodeId); - } - } - } - return idArray - }; + this.options = Utils.extend(Utils.extend({}, Hammer.defaults), options || {}); - /** - * - * retrieve the currently selected edges - * @return {Array} selection An array with the ids of the - * selected nodes. - */ - exports.getSelectedEdges = function() { - var idArray = []; - if (this.constants.selectable == true) { - for (var edgeId in this.selectionObj.edges) { - if (this.selectionObj.edges.hasOwnProperty(edgeId)) { - idArray.push(edgeId); - } + // add some css to the element to prevent the browser from doing its native behavoir + if(this.options.behavior) { + Utils.toggleBehavior(this.element, this.options.behavior, true); } - } - return idArray; - }; + /** + * event start handler on the element to start the detection + * @property eventStartHandler + * @type {Object} + */ + this.eventStartHandler = Event.onTouch(element, EVENT_START, function(ev) { + if(self.enabled && ev.eventType == EVENT_START) { + Detection.startDetect(self, ev); + } else if(ev.eventType == EVENT_TOUCH) { + Detection.detect(ev); + } + }); - /** - * select zero or more nodes DEPRICATED - * @param {Number[] | String[]} selection An array with the ids of the - * selected nodes. - */ - exports.setSelection = function() { - console.log("setSelection is deprecated. Please use selectNodes instead.") + /** + * keep a list of user event handlers which needs to be removed when calling 'dispose' + * @property eventHandlers + * @type {Array} + */ + this.eventHandlers = []; }; + Hammer.Instance.prototype = { + /** + * bind events to the instance + * @method on + * @chainable + * @param {String} gestures multiple gestures by splitting with a space + * @param {Function} handler + * @param {Object} handler.ev event object + */ + on: function onEvent(gestures, handler) { + var self = this; + Event.on(self.element, gestures, handler, function(type) { + self.eventHandlers.push({ gesture: type, handler: handler }); + }); + return self; + }, - /** - * select zero or more nodes with the option to highlight edges - * @param {Number[] | String[]} selection An array with the ids of the - * selected nodes. - * @param {boolean} [highlightEdges] - */ - exports.selectNodes = function(selection, highlightEdges) { - var i, iMax, id; + /** + * unbind events to the instance + * @method off + * @chainable + * @param {String} gestures + * @param {Function} handler + */ + off: function offEvent(gestures, handler) { + var self = this; - if (!selection || (selection.length == undefined)) - throw 'Selection must be an array with ids'; + Event.off(self.element, gestures, handler, function(type) { + var index = Utils.inArray({ gesture: type, handler: handler }); + if(index !== false) { + self.eventHandlers.splice(index, 1); + } + }); + return self; + }, - // first unselect any selected node - this._unselectAll(true); + /** + * trigger gesture event + * @method trigger + * @chainable + * @param {String} gesture + * @param {Object} [eventData] + */ + trigger: function triggerEvent(gesture, eventData) { + // optional + if(!eventData) { + eventData = {}; + } - for (i = 0, iMax = selection.length; i < iMax; i++) { - id = selection[i]; + // create DOM event + var event = Hammer.DOCUMENT.createEvent('Event'); + event.initEvent(gesture, true, true); + event.gesture = eventData; - var node = this.nodes[id]; - if (!node) { - throw new RangeError('Node with id "' + id + '" not found'); - } - this._selectObject(node,true,true,highlightEdges,true); - } - this.redraw(); - }; + // trigger on the target if it is in the instance element, + // this is for event delegation tricks + var element = this.element; + if(Utils.hasParent(eventData.target, element)) { + element = eventData.target; + } + + element.dispatchEvent(event); + return this; + }, + + /** + * enable of disable hammer.js detection + * @method enable + * @chainable + * @param {Boolean} state + */ + enable: function enable(state) { + this.enabled = state; + return this; + }, + /** + * dispose this hammer instance + * @method dispose + * @return {Null} + */ + dispose: function dispose() { + var i, eh; - /** - * select zero or more edges - * @param {Number[] | String[]} selection An array with the ids of the - * selected nodes. - */ - exports.selectEdges = function(selection) { - var i, iMax, id; + // undo all changes made by stop_browser_behavior + Utils.toggleBehavior(this.element, this.options.behavior, false); - if (!selection || (selection.length == undefined)) - throw 'Selection must be an array with ids'; + // unbind all custom event handlers + for(i = -1; (eh = this.eventHandlers[++i]);) { + Utils.off(this.element, eh.gesture, eh.handler); + } - // first unselect any selected node - this._unselectAll(true); + this.eventHandlers = []; - for (i = 0, iMax = selection.length; i < iMax; i++) { - id = selection[i]; + // unbind the start event listener + Event.off(this.element, EVENT_TYPES[EVENT_START], this.eventStartHandler); - var edge = this.edges[id]; - if (!edge) { - throw new RangeError('Edge with id "' + id + '" not found'); + return null; } - this._selectObject(edge,true,true,false,true); - } - this.redraw(); }; + /** - * Validate the selection: remove ids of nodes which no longer exist - * @private + * @module gestures */ - exports._updateSelection = function () { - for(var nodeId in this.selectionObj.nodes) { - if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { - if (!this.nodes.hasOwnProperty(nodeId)) { - delete this.selectionObj.nodes[nodeId]; - } - } - } - for(var edgeId in this.selectionObj.edges) { - if(this.selectionObj.edges.hasOwnProperty(edgeId)) { - if (!this.edges.hasOwnProperty(edgeId)) { - delete this.selectionObj.edges[edgeId]; - } - } - } - }; - - -/***/ }, -/* 63 */ -/***/ function(module, exports, __webpack_require__) { - - var util = __webpack_require__(1); - var Node = __webpack_require__(40); - var Edge = __webpack_require__(37); - /** - * clears the toolbar div element of children + * Move with x fingers (default 1) around on the page. + * Preventing the default browser behavior is a good way to improve feel and working. + * ```` + * hammertime.on("drag", function(ev) { + * console.log(ev); + * ev.gesture.preventDefault(); + * }); + * ```` * - * @private + * @class Drag + * @static */ - exports._clearManipulatorBar = function() { - this._recursiveDOMDelete(this.manipulationDiv); - this.manipulationDOM = {}; - - this._manipulationReleaseOverload = function () {}; - delete this.sectors['support']['nodes']['targetNode']; - delete this.sectors['support']['nodes']['targetViaNode']; - this.controlNodesActive = false; - this.freezeSimulation = false; - }; - /** - * Manipulation UI temporarily overloads certain functions to extend or replace them. To be able to restore - * these functions to their original functionality, we saved them in this.cachedFunctions. - * This function restores these functions to their original function. - * - * @private + * @event drag + * @param {Object} ev */ - exports._restoreOverloadedFunctions = function() { - for (var functionName in this.cachedFunctions) { - if (this.cachedFunctions.hasOwnProperty(functionName)) { - this[functionName] = this.cachedFunctions[functionName]; - delete this.cachedFunctions[functionName]; - } - } - }; - /** - * Enable or disable edit-mode. - * - * @private + * @event dragstart + * @param {Object} ev */ - exports._toggleEditMode = function() { - this.editMode = !this.editMode; - var toolbar = this.manipulationDiv; - var closeDiv = this.closeDiv; - var editModeDiv = this.editModeDiv; - if (this.editMode == true) { - toolbar.style.display="block"; - closeDiv.style.display="block"; - editModeDiv.style.display="none"; - closeDiv.onclick = this._toggleEditMode.bind(this); - } - else { - toolbar.style.display="none"; - closeDiv.style.display="none"; - editModeDiv.style.display="block"; - closeDiv.onclick = null; - } - this._createManipulatorBar() - }; - /** - * main function, creates the main toolbar. Removes functions bound to the select event. Binds all the buttons of the toolbar. - * - * @private + * @event dragend + * @param {Object} ev + */ + /** + * @event drapleft + * @param {Object} ev + */ + /** + * @event dragright + * @param {Object} ev + */ + /** + * @event dragup + * @param {Object} ev + */ + /** + * @event dragdown + * @param {Object} ev */ - exports._createManipulatorBar = function() { - // remove bound functions - if (this.boundFunction) { - this.off('select', this.boundFunction); - } - - var locale = this.constants.locales[this.constants.locale]; - if (this.edgeBeingEdited !== undefined) { - this.edgeBeingEdited._disableControlNodes(); - this.edgeBeingEdited = undefined; - this.selectedControlNode = null; - this.controlNodesActive = false; - this._redraw(); - } + /** + * @param {String} name + */ + (function(name) { + var triggered = false; - // restore overloaded functions - this._restoreOverloadedFunctions(); + function dragGesture(ev, inst) { + var cur = Detection.current; - // resume calculation - this.freezeSimulation = false; + // max touches + if(inst.options.dragMaxTouches > 0 && + ev.touches.length > inst.options.dragMaxTouches) { + return; + } - // reset global variables - this.blockConnectingEdgeSelection = false; - this.forceAppendSelection = false; - this.manipulationDOM = {}; + switch(ev.eventType) { + case EVENT_START: + triggered = false; + break; - if (this.editMode == true) { - while (this.manipulationDiv.hasChildNodes()) { - this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); - } + case EVENT_MOVE: + // when the distance we moved is too small we skip this gesture + // or we can be already in dragging + if(ev.distance < inst.options.dragMinDistance && + cur.name != name) { + return; + } - this.manipulationDOM['addNodeSpan'] = document.createElement('span'); - this.manipulationDOM['addNodeSpan'].className = 'network-manipulationUI add'; - this.manipulationDOM['addNodeLabelSpan'] = document.createElement('span'); - this.manipulationDOM['addNodeLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['addNodeLabelSpan'].innerHTML = locale['addNode']; - this.manipulationDOM['addNodeSpan'].appendChild(this.manipulationDOM['addNodeLabelSpan']); + var startCenter = cur.startEvent.center; - this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); - this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; + // we are dragging! + if(cur.name != name) { + cur.name = name; + if(inst.options.dragDistanceCorrection && ev.distance > 0) { + // When a drag is triggered, set the event center to dragMinDistance pixels from the original event center. + // Without this correction, the dragged distance would jumpstart at dragMinDistance pixels instead of at 0. + // It might be useful to save the original start point somewhere + var factor = Math.abs(inst.options.dragMinDistance / ev.distance); + startCenter.pageX += ev.deltaX * factor; + startCenter.pageY += ev.deltaY * factor; + startCenter.clientX += ev.deltaX * factor; + startCenter.clientY += ev.deltaY * factor; - this.manipulationDOM['addEdgeSpan'] = document.createElement('span'); - this.manipulationDOM['addEdgeSpan'].className = 'network-manipulationUI connect'; - this.manipulationDOM['addEdgeLabelSpan'] = document.createElement('span'); - this.manipulationDOM['addEdgeLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['addEdgeLabelSpan'].innerHTML = locale['addEdge']; - this.manipulationDOM['addEdgeSpan'].appendChild(this.manipulationDOM['addEdgeLabelSpan']); + // recalculate event data using new start point + ev = Detection.extendEventData(ev); + } + } - this.manipulationDiv.appendChild(this.manipulationDOM['addNodeSpan']); - this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); - this.manipulationDiv.appendChild(this.manipulationDOM['addEdgeSpan']); + // lock drag to axis? + if(cur.lastEvent.dragLockToAxis || + ( inst.options.dragLockToAxis && + inst.options.dragLockMinDistance <= ev.distance + )) { + ev.dragLockToAxis = true; + } - if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) { - this.manipulationDOM['seperatorLineDiv2'] = document.createElement('div'); - this.manipulationDOM['seperatorLineDiv2'].className = 'network-seperatorLine'; + // keep direction on the axis that the drag gesture started on + var lastDirection = cur.lastEvent.direction; + if(ev.dragLockToAxis && lastDirection !== ev.direction) { + if(Utils.isVertical(lastDirection)) { + ev.direction = (ev.deltaY < 0) ? DIRECTION_UP : DIRECTION_DOWN; + } else { + ev.direction = (ev.deltaX < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT; + } + } - this.manipulationDOM['editNodeSpan'] = document.createElement('span'); - this.manipulationDOM['editNodeSpan'].className = 'network-manipulationUI edit'; - this.manipulationDOM['editNodeLabelSpan'] = document.createElement('span'); - this.manipulationDOM['editNodeLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['editNodeLabelSpan'].innerHTML = locale['editNode']; - this.manipulationDOM['editNodeSpan'].appendChild(this.manipulationDOM['editNodeLabelSpan']); + // first time, trigger dragstart event + if(!triggered) { + inst.trigger(name + 'start', ev); + triggered = true; + } - this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv2']); - this.manipulationDiv.appendChild(this.manipulationDOM['editNodeSpan']); - } - else if (this._getSelectedEdgeCount() == 1 && this._getSelectedNodeCount() == 0) { - this.manipulationDOM['seperatorLineDiv3'] = document.createElement('div'); - this.manipulationDOM['seperatorLineDiv3'].className = 'network-seperatorLine'; + // trigger events + inst.trigger(name, ev); + inst.trigger(name + ev.direction, ev); - this.manipulationDOM['editEdgeSpan'] = document.createElement('span'); - this.manipulationDOM['editEdgeSpan'].className = 'network-manipulationUI edit'; - this.manipulationDOM['editEdgeLabelSpan'] = document.createElement('span'); - this.manipulationDOM['editEdgeLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['editEdgeLabelSpan'].innerHTML = locale['editEdge']; - this.manipulationDOM['editEdgeSpan'].appendChild(this.manipulationDOM['editEdgeLabelSpan']); + var isVertical = Utils.isVertical(ev.direction); - this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv3']); - this.manipulationDiv.appendChild(this.manipulationDOM['editEdgeSpan']); - } - if (this._selectionIsEmpty() == false) { - this.manipulationDOM['seperatorLineDiv4'] = document.createElement('div'); - this.manipulationDOM['seperatorLineDiv4'].className = 'network-seperatorLine'; + // block the browser events + if((inst.options.dragBlockVertical && isVertical) || + (inst.options.dragBlockHorizontal && !isVertical)) { + ev.preventDefault(); + } + break; - this.manipulationDOM['deleteSpan'] = document.createElement('span'); - this.manipulationDOM['deleteSpan'].className = 'network-manipulationUI delete'; - this.manipulationDOM['deleteLabelSpan'] = document.createElement('span'); - this.manipulationDOM['deleteLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['deleteLabelSpan'].innerHTML = locale['del']; - this.manipulationDOM['deleteSpan'].appendChild(this.manipulationDOM['deleteLabelSpan']); + case EVENT_RELEASE: + if(triggered && ev.changedLength <= inst.options.dragMaxTouches) { + inst.trigger(name + 'end', ev); + triggered = false; + } + break; - this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv4']); - this.manipulationDiv.appendChild(this.manipulationDOM['deleteSpan']); + case EVENT_END: + triggered = false; + break; + } } + Hammer.gestures.Drag = { + name: name, + index: 50, + handler: dragGesture, + defaults: { + /** + * minimal movement that have to be made before the drag event gets triggered + * @property dragMinDistance + * @type {Number} + * @default 10 + */ + dragMinDistance: 10, - // bind the icons - this.manipulationDOM['addNodeSpan'].onclick = this._createAddNodeToolbar.bind(this); - this.manipulationDOM['addEdgeSpan'].onclick = this._createAddEdgeToolbar.bind(this); - if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) { - this.manipulationDOM['editNodeSpan'].onclick = this._editNode.bind(this); - } - else if (this._getSelectedEdgeCount() == 1 && this._getSelectedNodeCount() == 0) { - this.manipulationDOM['editEdgeSpan'].onclick = this._createEditEdgeToolbar.bind(this); - } - if (this._selectionIsEmpty() == false) { - this.manipulationDOM['deleteSpan'].onclick = this._deleteSelected.bind(this); - } - this.closeDiv.onclick = this._toggleEditMode.bind(this); - - var me = this; - this.boundFunction = me._createManipulatorBar; - this.on('select', this.boundFunction); - } - else { - while (this.editModeDiv.hasChildNodes()) { - this.editModeDiv.removeChild(this.editModeDiv.firstChild); - } + /** + * Set dragDistanceCorrection to true to make the starting point of the drag + * be calculated from where the drag was triggered, not from where the touch started. + * Useful to avoid a jerk-starting drag, which can make fine-adjustments + * through dragging difficult, and be visually unappealing. + * @property dragDistanceCorrection + * @type {Boolean} + * @default true + */ + dragDistanceCorrection: true, - this.manipulationDOM['editModeSpan'] = document.createElement('span'); - this.manipulationDOM['editModeSpan'].className = 'network-manipulationUI edit editmode'; - this.manipulationDOM['editModeLabelSpan'] = document.createElement('span'); - this.manipulationDOM['editModeLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['editModeLabelSpan'].innerHTML = locale['edit']; - this.manipulationDOM['editModeSpan'].appendChild(this.manipulationDOM['editModeLabelSpan']); + /** + * set 0 for unlimited, but this can conflict with transform + * @property dragMaxTouches + * @type {Number} + * @default 1 + */ + dragMaxTouches: 1, - this.editModeDiv.appendChild(this.manipulationDOM['editModeSpan']); + /** + * prevent default browser behavior when dragging occurs + * be careful with it, it makes the element a blocking element + * when you are using the drag gesture, it is a good practice to set this true + * @property dragBlockHorizontal + * @type {Boolean} + * @default false + */ + dragBlockHorizontal: false, - this.manipulationDOM['editModeSpan'].onclick = this._toggleEditMode.bind(this); - } - }; + /** + * same as `dragBlockHorizontal`, but for vertical movement + * @property dragBlockVertical + * @type {Boolean} + * @default false + */ + dragBlockVertical: false, + /** + * dragLockToAxis keeps the drag gesture on the axis that it started on, + * It disallows vertical directions if the initial direction was horizontal, and vice versa. + * @property dragLockToAxis + * @type {Boolean} + * @default false + */ + dragLockToAxis: false, + /** + * drag lock only kicks in when distance > dragLockMinDistance + * This way, locking occurs only when the distance has become large enough to reliably determine the direction + * @property dragLockMinDistance + * @type {Number} + * @default 25 + */ + dragLockMinDistance: 25 + } + }; + })('drag'); /** - * Create the toolbar for adding Nodes - * - * @private + * @module gestures */ - exports._createAddNodeToolbar = function() { - // clear the toolbar - this._clearManipulatorBar(); - if (this.boundFunction) { - this.off('select', this.boundFunction); - } - - var locale = this.constants.locales[this.constants.locale]; - - this.manipulationDOM = {}; - this.manipulationDOM['backSpan'] = document.createElement('span'); - this.manipulationDOM['backSpan'].className = 'network-manipulationUI back'; - this.manipulationDOM['backLabelSpan'] = document.createElement('span'); - this.manipulationDOM['backLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['backLabelSpan'].innerHTML = locale['back']; - this.manipulationDOM['backSpan'].appendChild(this.manipulationDOM['backLabelSpan']); - - this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); - this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; - - this.manipulationDOM['descriptionSpan'] = document.createElement('span'); - this.manipulationDOM['descriptionSpan'].className = 'network-manipulationUI none'; - this.manipulationDOM['descriptionLabelSpan'] = document.createElement('span'); - this.manipulationDOM['descriptionLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['descriptionLabelSpan'].innerHTML = locale['addDescription']; - this.manipulationDOM['descriptionSpan'].appendChild(this.manipulationDOM['descriptionLabelSpan']); - - this.manipulationDiv.appendChild(this.manipulationDOM['backSpan']); - this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); - this.manipulationDiv.appendChild(this.manipulationDOM['descriptionSpan']); - - // bind the icon - this.manipulationDOM['backSpan'].onclick = this._createManipulatorBar.bind(this); - - // we use the boundFunction so we can reference it when we unbind it from the "select" event. - var me = this; - this.boundFunction = me._addNode; - this.on('select', this.boundFunction); - }; - - /** - * create the toolbar to connect nodes + * trigger a simple gesture event, so you can do anything in your handler. + * only usable if you know what your doing... * - * @private + * @class Gesture + * @static */ - exports._createAddEdgeToolbar = function() { - // clear the toolbar - this._clearManipulatorBar(); - this._unselectAll(true); - this.freezeSimulation = true; - - if (this.boundFunction) { - this.off('select', this.boundFunction); - } - - var locale = this.constants.locales[this.constants.locale]; - - this._unselectAll(); - this.forceAppendSelection = false; - this.blockConnectingEdgeSelection = true; - - this.manipulationDOM = {}; - this.manipulationDOM['backSpan'] = document.createElement('span'); - this.manipulationDOM['backSpan'].className = 'network-manipulationUI back'; - this.manipulationDOM['backLabelSpan'] = document.createElement('span'); - this.manipulationDOM['backLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['backLabelSpan'].innerHTML = locale['back']; - this.manipulationDOM['backSpan'].appendChild(this.manipulationDOM['backLabelSpan']); - - this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); - this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; - - this.manipulationDOM['descriptionSpan'] = document.createElement('span'); - this.manipulationDOM['descriptionSpan'].className = 'network-manipulationUI none'; - this.manipulationDOM['descriptionLabelSpan'] = document.createElement('span'); - this.manipulationDOM['descriptionLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['descriptionLabelSpan'].innerHTML = locale['edgeDescription']; - this.manipulationDOM['descriptionSpan'].appendChild(this.manipulationDOM['descriptionLabelSpan']); - - this.manipulationDiv.appendChild(this.manipulationDOM['backSpan']); - this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); - this.manipulationDiv.appendChild(this.manipulationDOM['descriptionSpan']); - - // bind the icon - this.manipulationDOM['backSpan'].onclick = this._createManipulatorBar.bind(this); - - // we use the boundFunction so we can reference it when we unbind it from the "select" event. - var me = this; - this.boundFunction = me._handleConnect; - this.on('select', this.boundFunction); - - // temporarily overload functions - this.cachedFunctions["_handleTouch"] = this._handleTouch; - this.cachedFunctions["_manipulationReleaseOverload"] = this._manipulationReleaseOverload; - this.cachedFunctions["_handleDragStart"] = this._handleDragStart; - this.cachedFunctions["_handleDragEnd"] = this._handleDragEnd; - this._handleTouch = this._handleConnect; - this._manipulationReleaseOverload = function () {}; - this._handleDragStart = function () {}; - this._handleDragEnd = this._finishConnect; - - // redraw to show the unselect - this._redraw(); + /** + * @event gesture + * @param {Object} ev + */ + Hammer.gestures.Gesture = { + name: 'gesture', + index: 1337, + handler: function releaseGesture(ev, inst) { + inst.trigger(this.name, ev); + } }; /** - * create the toolbar to edit edges + * @module gestures + */ + /** + * Touch stays at the same place for x time * - * @private + * @class Hold + * @static + */ + /** + * @event hold + * @param {Object} ev */ - exports._createEditEdgeToolbar = function() { - // clear the toolbar - this._clearManipulatorBar(); - this.controlNodesActive = true; - - if (this.boundFunction) { - this.off('select', this.boundFunction); - } - - this.edgeBeingEdited = this._getSelectedEdge(); - this.edgeBeingEdited._enableControlNodes(); - var locale = this.constants.locales[this.constants.locale]; + /** + * @param {String} name + */ + (function(name) { + var timer; - this.manipulationDOM = {}; - this.manipulationDOM['backSpan'] = document.createElement('span'); - this.manipulationDOM['backSpan'].className = 'network-manipulationUI back'; - this.manipulationDOM['backLabelSpan'] = document.createElement('span'); - this.manipulationDOM['backLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['backLabelSpan'].innerHTML = locale['back']; - this.manipulationDOM['backSpan'].appendChild(this.manipulationDOM['backLabelSpan']); + function holdGesture(ev, inst) { + var options = inst.options, + current = Detection.current; - this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div'); - this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine'; + switch(ev.eventType) { + case EVENT_START: + clearTimeout(timer); - this.manipulationDOM['descriptionSpan'] = document.createElement('span'); - this.manipulationDOM['descriptionSpan'].className = 'network-manipulationUI none'; - this.manipulationDOM['descriptionLabelSpan'] = document.createElement('span'); - this.manipulationDOM['descriptionLabelSpan'].className = 'network-manipulationLabel'; - this.manipulationDOM['descriptionLabelSpan'].innerHTML = locale['editEdgeDescription']; - this.manipulationDOM['descriptionSpan'].appendChild(this.manipulationDOM['descriptionLabelSpan']); + // set the gesture so we can check in the timeout if it still is + current.name = name; - this.manipulationDiv.appendChild(this.manipulationDOM['backSpan']); - this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']); - this.manipulationDiv.appendChild(this.manipulationDOM['descriptionSpan']); + // set timer and if after the timeout it still is hold, + // we trigger the hold event + timer = setTimeout(function() { + if(current && current.name == name) { + inst.trigger(name, ev); + } + }, options.holdTimeout); + break; - // bind the icon - this.manipulationDOM['backSpan'].onclick = this._createManipulatorBar.bind(this); + case EVENT_MOVE: + if(ev.distance > options.holdThreshold) { + clearTimeout(timer); + } + break; - // temporarily overload functions - this.cachedFunctions["_handleTouch"] = this._handleTouch; - this.cachedFunctions["_manipulationReleaseOverload"] = this._manipulationReleaseOverload; - this.cachedFunctions["_handleTap"] = this._handleTap; - this.cachedFunctions["_handleDragStart"] = this._handleDragStart; - this.cachedFunctions["_handleOnDrag"] = this._handleOnDrag; - this._handleTouch = this._selectControlNode; - this._handleTap = function () {}; - this._handleOnDrag = this._controlNodeDrag; - this._handleDragStart = function () {} - this._manipulationReleaseOverload = this._releaseControlNode; + case EVENT_RELEASE: + clearTimeout(timer); + break; + } + } - // redraw to show the unselect - this._redraw(); - }; + Hammer.gestures.Hold = { + name: name, + index: 10, + defaults: { + /** + * @property holdTimeout + * @type {Number} + * @default 500 + */ + holdTimeout: 500, + /** + * movement allowed while holding + * @property holdThreshold + * @type {Number} + * @default 2 + */ + holdThreshold: 2 + }, + handler: holdGesture + }; + })('hold'); /** - * the function bound to the selection event. It checks if you want to connect a cluster and changes the description - * to walk the user through the process. - * - * @private + * @module gestures */ - exports._selectControlNode = function(pointer) { - this.edgeBeingEdited.controlNodes.from.unselect(); - this.edgeBeingEdited.controlNodes.to.unselect(); - this.selectedControlNode = this.edgeBeingEdited._getSelectedControlNode(this._XconvertDOMtoCanvas(pointer.x),this._YconvertDOMtoCanvas(pointer.y)); - if (this.selectedControlNode !== null) { - this.selectedControlNode.select(); - this.freezeSimulation = true; - } - this._redraw(); - }; - - /** - * the function bound to the selection event. It checks if you want to connect a cluster and changes the description - * to walk the user through the process. + * when a touch is being released from the page * - * @private + * @class Release + * @static */ - exports._controlNodeDrag = function(event) { - var pointer = this._getPointer(event.gesture.center); - if (this.selectedControlNode !== null && this.selectedControlNode !== undefined) { - this.selectedControlNode.x = this._XconvertDOMtoCanvas(pointer.x); - this.selectedControlNode.y = this._YconvertDOMtoCanvas(pointer.y); - } - this._redraw(); - }; - - /** - * - * @param pointer - * @private + * @event release + * @param {Object} ev */ - exports._releaseControlNode = function(pointer) { - var newNode = this._getNodeAt(pointer); - if (newNode !== null) { - if (this.edgeBeingEdited.controlNodes.from.selected == true) { - this.edgeBeingEdited._restoreControlNodes(); - this._editEdge(newNode.id, this.edgeBeingEdited.to.id); - this.edgeBeingEdited.controlNodes.from.unselect(); - } - if (this.edgeBeingEdited.controlNodes.to.selected == true) { - this.edgeBeingEdited._restoreControlNodes(); - this._editEdge(this.edgeBeingEdited.from.id, newNode.id); - this.edgeBeingEdited.controlNodes.to.unselect(); + Hammer.gestures.Release = { + name: 'release', + index: Infinity, + handler: function releaseGesture(ev, inst) { + if(ev.eventType == EVENT_RELEASE) { + inst.trigger(this.name, ev); + } } - } - else { - this.edgeBeingEdited._restoreControlNodes(); - } - this.freezeSimulation = false; - this._redraw(); }; /** - * the function bound to the selection event. It checks if you want to connect a cluster and changes the description - * to walk the user through the process. + * @module gestures + */ + /** + * triggers swipe events when the end velocity is above the threshold + * for best usage, set `preventDefault` (on the drag gesture) to `true` + * ```` + * hammertime.on("dragleft swipeleft", function(ev) { + * console.log(ev); + * ev.gesture.preventDefault(); + * }); + * ```` * - * @private + * @class Swipe + * @static */ - exports._handleConnect = function(pointer) { - if (this._getSelectedNodeCount() == 0) { - var node = this._getNodeAt(pointer); - - if (node != null) { - if (node.clusterSize > 1) { - alert(this.constants.locales[this.constants.locale]['createEdgeError']) - } - else { - this._selectObject(node,false); - var supportNodes = this.sectors['support']['nodes']; - - // create a node the temporary line can look at - supportNodes['targetNode'] = new Node({id:'targetNode'},{},{},this.constants); - var targetNode = supportNodes['targetNode']; - targetNode.x = node.x; - targetNode.y = node.y; - - // create a temporary edge - this.edges['connectionEdge'] = new Edge({id:"connectionEdge",from:node.id,to:targetNode.id}, this, this.constants); - var connectionEdge = this.edges['connectionEdge']; - connectionEdge.from = node; - connectionEdge.connected = true; - connectionEdge.options.smoothCurves = {enabled: true, - dynamic: false, - type: "continuous", - roundness: 0.5 - }; - connectionEdge.selected = true; - connectionEdge.to = targetNode; + /** + * @event swipe + * @param {Object} ev + */ + /** + * @event swipeleft + * @param {Object} ev + */ + /** + * @event swiperight + * @param {Object} ev + */ + /** + * @event swipeup + * @param {Object} ev + */ + /** + * @event swipedown + * @param {Object} ev + */ + Hammer.gestures.Swipe = { + name: 'swipe', + index: 40, + defaults: { + /** + * @property swipeMinTouches + * @type {Number} + * @default 1 + */ + swipeMinTouches: 1, - this.cachedFunctions["_handleOnDrag"] = this._handleOnDrag; - this._handleOnDrag = function(event) { - var pointer = this._getPointer(event.gesture.center); - var connectionEdge = this.edges['connectionEdge']; - connectionEdge.to.x = this._XconvertDOMtoCanvas(pointer.x); - connectionEdge.to.y = this._YconvertDOMtoCanvas(pointer.y); - }; + /** + * @property swipeMaxTouches + * @type {Number} + * @default 1 + */ + swipeMaxTouches: 1, - this.moving = true; - this.start(); - } - } - } - }; + /** + * horizontal swipe velocity + * @property swipeVelocityX + * @type {Number} + * @default 0.6 + */ + swipeVelocityX: 0.6, - exports._finishConnect = function(event) { - if (this._getSelectedNodeCount() == 1) { - var pointer = this._getPointer(event.gesture.center); - // restore the drag function - this._handleOnDrag = this.cachedFunctions["_handleOnDrag"]; - delete this.cachedFunctions["_handleOnDrag"]; + /** + * vertical swipe velocity + * @property swipeVelocityY + * @type {Number} + * @default 0.6 + */ + swipeVelocityY: 0.6 + }, - // remember the edge id - var connectFromId = this.edges['connectionEdge'].fromId; + handler: function swipeGesture(ev, inst) { + if(ev.eventType == EVENT_RELEASE) { + var touches = ev.touches.length, + options = inst.options; - // remove the temporary nodes and edge - delete this.edges['connectionEdge']; - delete this.sectors['support']['nodes']['targetNode']; - delete this.sectors['support']['nodes']['targetViaNode']; + // max touches + if(touches < options.swipeMinTouches || + touches > options.swipeMaxTouches) { + return; + } - var node = this._getNodeAt(pointer); - if (node != null) { - if (node.clusterSize > 1) { - alert(this.constants.locales[this.constants.locale]["createEdgeError"]) - } - else { - this._createEdge(connectFromId,node.id); - this._createManipulatorBar(); - } + // when the distance we moved is too small we skip this gesture + // or we can be already in dragging + if(ev.velocityX > options.swipeVelocityX || + ev.velocityY > options.swipeVelocityY) { + // trigger swipe events + inst.trigger(this.name, ev); + inst.trigger(this.name + ev.direction, ev); + } + } } - this._unselectAll(); - } }; - /** - * Adds a node on the specified location + * @module gestures */ - exports._addNode = function() { - if (this._selectionIsEmpty() && this.editMode == true) { - var positionObject = this._pointerToPositionObject(this.pointerPosition); - var defaultData = {id:util.randomUUID(),x:positionObject.left,y:positionObject.top,label:"new",allowedToMoveX:true,allowedToMoveY:true}; - if (this.triggerFunctions.add) { - if (this.triggerFunctions.add.length == 2) { - var me = this; - this.triggerFunctions.add(defaultData, function(finalizedData) { - me.nodesData.add(finalizedData); - me._createManipulatorBar(); - me.moving = true; - me.start(); - }); - } - else { - throw new Error('The function for add does not support two arguments (data,callback)'); - this._createManipulatorBar(); - this.moving = true; - this.start(); - } - } - else { - this.nodesData.add(defaultData); - this._createManipulatorBar(); - this.moving = true; - this.start(); - } - } - }; - - /** - * connect two nodes with a new edge. + * Single tap and a double tap on a place * - * @private + * @class Tap + * @static */ - exports._createEdge = function(sourceNodeId,targetNodeId) { - if (this.editMode == true) { - var defaultData = {from:sourceNodeId, to:targetNodeId}; - if (this.triggerFunctions.connect) { - if (this.triggerFunctions.connect.length == 2) { - var me = this; - this.triggerFunctions.connect(defaultData, function(finalizedData) { - me.edgesData.add(finalizedData); - me.moving = true; - me.start(); - }); - } - else { - throw new Error('The function for connect does not support two arguments (data,callback)'); - this.moving = true; - this.start(); - } - } - else { - this.edgesData.add(defaultData); - this.moving = true; - this.start(); - } - } - }; - /** - * connect two nodes with a new edge. - * - * @private + * @event tap + * @param {Object} ev */ - exports._editEdge = function(sourceNodeId,targetNodeId) { - if (this.editMode == true) { - var defaultData = {id: this.edgeBeingEdited.id, from:sourceNodeId, to:targetNodeId}; - if (this.triggerFunctions.editEdge) { - if (this.triggerFunctions.editEdge.length == 2) { - var me = this; - this.triggerFunctions.editEdge(defaultData, function(finalizedData) { - me.edgesData.update(finalizedData); - me.moving = true; - me.start(); - }); - } - else { - throw new Error('The function for edit does not support two arguments (data, callback)'); - this.moving = true; - this.start(); - } - } - else { - this.edgesData.update(defaultData); - this.moving = true; - this.start(); - } - } - }; - /** - * Create the toolbar to edit the selected node. The label and the color can be changed. Other colors are derived from the chosen color. - * - * @private + * @event doubletap + * @param {Object} ev */ - exports._editNode = function() { - if (this.triggerFunctions.edit && this.editMode == true) { - var node = this._getSelectedNode(); - var data = {id:node.id, - label: node.label, - group: node.options.group, - shape: node.options.shape, - color: { - background:node.options.color.background, - border:node.options.color.border, - highlight: { - background:node.options.color.highlight.background, - border:node.options.color.highlight.border - } - }}; - if (this.triggerFunctions.edit.length == 2) { - var me = this; - this.triggerFunctions.edit(data, function (finalizedData) { - me.nodesData.update(finalizedData); - me._createManipulatorBar(); - me.moving = true; - me.start(); - }); - } - else { - throw new Error('The function for edit does not support two arguments (data, callback)'); - } - } - else { - throw new Error('No edit function has been bound to this button'); - } - }; - - - /** - * delete everything in the selection - * - * @private + * @param {String} name */ - exports._deleteSelected = function() { - if (!this._selectionIsEmpty() && this.editMode == true) { - if (!this._clusterInSelection()) { - var selectedNodes = this.getSelectedNodes(); - var selectedEdges = this.getSelectedEdges(); - if (this.triggerFunctions.del) { - var me = this; - var data = {nodes: selectedNodes, edges: selectedEdges}; - if (this.triggerFunctions.del.length == 2) { - this.triggerFunctions.del(data, function (finalizedData) { - me.edgesData.remove(finalizedData.edges); - me.nodesData.remove(finalizedData.nodes); - me._unselectAll(); - me.moving = true; - me.start(); - }); - } - else { - throw new Error('The function for delete does not support two arguments (data, callback)') - } - } - else { - this.edgesData.remove(selectedEdges); - this.nodesData.remove(selectedNodes); - this._unselectAll(); - this.moving = true; - this.start(); - } - } - else { - alert(this.constants.locales[this.constants.locale]["deleteClusterError"]); - } - } - }; + (function(name) { + var hasMoved = false; + + function tapGesture(ev, inst) { + var options = inst.options, + current = Detection.current, + prev = Detection.previous, + sincePrev, + didDoubleTap; + switch(ev.eventType) { + case EVENT_START: + hasMoved = false; + break; -/***/ }, -/* 64 */ -/***/ function(module, exports, __webpack_require__) { + case EVENT_MOVE: + hasMoved = hasMoved || (ev.distance > options.tapMaxDistance); + break; - var util = __webpack_require__(1); - var Hammer = __webpack_require__(45); + case EVENT_END: + if(!Utils.inStr(ev.srcEvent.type, 'cancel') && ev.deltaTime < options.tapMaxTime && !hasMoved) { + // previous gesture, for the double tap since these are two different gesture detections + sincePrev = prev && prev.lastEvent && ev.timeStamp - prev.lastEvent.timeStamp; + didDoubleTap = false; - exports._cleanNavigation = function() { - // clean hammer bindings - if (this.navigationHammers.existing.length != 0) { - for (var i = 0; i < this.navigationHammers.existing.length; i++) { - this.navigationHammers.existing[i].dispose(); + // check if double tap + if(prev && prev.name == name && + (sincePrev && sincePrev < options.doubleTapInterval) && + ev.distance < options.doubleTapDistance) { + inst.trigger('doubletap', ev); + didDoubleTap = true; + } + + // do a single tap + if(!didDoubleTap || options.tapAlways) { + current.name = name; + inst.trigger(current.name, ev); + } + } + break; + } } - this.navigationHammers.existing = []; - } - this._navigationReleaseOverload = function () {}; + Hammer.gestures.Tap = { + name: name, + index: 100, + handler: tapGesture, + defaults: { + /** + * max time of a tap, this is for the slow tappers + * @property tapMaxTime + * @type {Number} + * @default 250 + */ + tapMaxTime: 250, - // clean up previous navigation items - if (this.navigationDivs && this.navigationDivs['wrapper'] && this.navigationDivs['wrapper'].parentNode) { - this.navigationDivs['wrapper'].parentNode.removeChild(this.navigationDivs['wrapper']); - } - }; + /** + * max distance of movement of a tap, this is for the slow tappers + * @property tapMaxDistance + * @type {Number} + * @default 10 + */ + tapMaxDistance: 10, - /** - * Creation of the navigation controls nodes. They are drawn over the rest of the nodes and are not affected by scale and translation - * they have a triggerFunction which is called on click. If the position of the navigation controls is dependent - * on this.frame.canvas.clientWidth or this.frame.canvas.clientHeight, we flag horizontalAlignLeft and verticalAlignTop false. - * This means that the location will be corrected by the _relocateNavigation function on a size change of the canvas. - * - * @private - */ - exports._loadNavigationElements = function() { - this._cleanNavigation(); + /** + * always trigger the `tap` event, even while double-tapping + * @property tapAlways + * @type {Boolean} + * @default true + */ + tapAlways: true, - this.navigationDivs = {}; - var navigationDivs = ['up','down','left','right','zoomIn','zoomOut','zoomExtends']; - var navigationDivActions = ['_moveUp','_moveDown','_moveLeft','_moveRight','_zoomIn','_zoomOut','_zoomExtent']; + /** + * max distance between two taps + * @property doubleTapDistance + * @type {Number} + * @default 20 + */ + doubleTapDistance: 20, - this.navigationDivs['wrapper'] = document.createElement('div'); - this.frame.appendChild(this.navigationDivs['wrapper']); + /** + * max time between two taps + * @property doubleTapInterval + * @type {Number} + * @default 300 + */ + doubleTapInterval: 300 + } + }; + })('tap'); - for (var i = 0; i < navigationDivs.length; i++) { - this.navigationDivs[navigationDivs[i]] = document.createElement('div'); - this.navigationDivs[navigationDivs[i]].className = 'network-navigation ' + navigationDivs[i]; - this.navigationDivs['wrapper'].appendChild(this.navigationDivs[navigationDivs[i]]); + /** + * @module gestures + */ + /** + * when a touch is being touched at the page + * + * @class Touch + * @static + */ + /** + * @event touch + * @param {Object} ev + */ + Hammer.gestures.Touch = { + name: 'touch', + index: -Infinity, + defaults: { + /** + * call preventDefault at touchstart, and makes the element blocking by disabling the scrolling of the page, + * but it improves gestures like transforming and dragging. + * be careful with using this, it can be very annoying for users to be stuck on the page + * @property preventDefault + * @type {Boolean} + * @default false + */ + preventDefault: false, - var hammer = Hammer(this.navigationDivs[navigationDivs[i]], {prevent_default: true}); - hammer.on('touch', this[navigationDivActions[i]].bind(this)); - this.navigationHammers._new.push(hammer); - } + /** + * disable mouse events, so only touch (or pen!) input triggers events + * @property preventMouse + * @type {Boolean} + * @default false + */ + preventMouse: false + }, + handler: function touchGesture(ev, inst) { + if(inst.options.preventMouse && ev.pointerType == POINTER_MOUSE) { + ev.stopDetect(); + return; + } - this._navigationReleaseOverload = this._stopMovement; + if(inst.options.preventDefault) { + ev.preventDefault(); + } - this.navigationHammers.existing = this.navigationHammers._new; + if(ev.eventType == EVENT_TOUCH) { + inst.trigger('touch', ev); + } + } }; - /** - * this stops all movement induced by the navigation buttons - * - * @private + * @module gestures */ - exports._zoomExtent = function(event) { - this.zoomExtent({duration:700}); - event.stopPropagation(); - }; - /** - * this stops all movement induced by the navigation buttons + * User want to scale or rotate with 2 fingers + * Preventing the default browser behavior is a good way to improve feel and working. This can be done with the + * `preventDefault` option. * - * @private + * @class Transform + * @static */ - exports._stopMovement = function() { - this._xStopMoving(); - this._yStopMoving(); - this._stopZoom(); - }; - - /** - * move the screen up - * By using the increments, instead of adding a fixed number to the translation, we keep fluent and - * instant movement. The onKeypress event triggers immediately, then pauses, then triggers frequently - * To avoid this behaviour, we do the translation in the start loop. - * - * @private + * @event transform + * @param {Object} ev */ - exports._moveUp = function(event) { - this.yIncrement = this.constants.keyboard.speed.y; - this.start(); // if there is no node movement, the calculation wont be done - event.preventDefault(); - }; - - /** - * move the screen down - * @private + * @event transformstart + * @param {Object} ev */ - exports._moveDown = function(event) { - this.yIncrement = -this.constants.keyboard.speed.y; - this.start(); // if there is no node movement, the calculation wont be done - event.preventDefault(); - }; - - /** - * move the screen left - * @private + * @event transformend + * @param {Object} ev */ - exports._moveLeft = function(event) { - this.xIncrement = this.constants.keyboard.speed.x; - this.start(); // if there is no node movement, the calculation wont be done - event.preventDefault(); - }; - - /** - * move the screen right - * @private + * @event pinchin + * @param {Object} ev */ - exports._moveRight = function(event) { - this.xIncrement = -this.constants.keyboard.speed.y; - this.start(); // if there is no node movement, the calculation wont be done - event.preventDefault(); - }; - - /** - * Zoom in, using the same method as the movement. - * @private + * @event pinchout + * @param {Object} ev */ - exports._zoomIn = function(event) { - this.zoomIncrement = this.constants.keyboard.speed.zoom; - this.start(); // if there is no node movement, the calculation wont be done - event.preventDefault(); - }; - - /** - * Zoom out - * @private + * @event rotate + * @param {Object} ev */ - exports._zoomOut = function(event) { - this.zoomIncrement = -this.constants.keyboard.speed.zoom; - this.start(); // if there is no node movement, the calculation wont be done - event.preventDefault(); - }; - /** - * Stop zooming and unhighlight the zoom controls - * @private + * @param {String} name */ - exports._stopZoom = function(event) { - this.zoomIncrement = 0; - event && event.preventDefault(); - }; + (function(name) { + var triggered = false; + + function transformGesture(ev, inst) { + switch(ev.eventType) { + case EVENT_START: + triggered = false; + break; + case EVENT_MOVE: + // at least multitouch + if(ev.touches.length < 2) { + return; + } - /** - * Stop moving in the Y direction and unHighlight the up and down - * @private - */ - exports._yStopMoving = function(event) { - this.yIncrement = 0; - event && event.preventDefault(); - }; + var scaleThreshold = Math.abs(1 - ev.scale); + var rotationThreshold = Math.abs(ev.rotation); + + // when the distance we moved is too small we skip this gesture + // or we can be already in dragging + if(scaleThreshold < inst.options.transformMinScale && + rotationThreshold < inst.options.transformMinRotation) { + return; + } + + // we are transforming! + Detection.current.name = name; + + // first time, trigger dragstart event + if(!triggered) { + inst.trigger(name + 'start', ev); + triggered = true; + } + + inst.trigger(name, ev); // basic transform event + + // trigger rotate event + if(rotationThreshold > inst.options.transformMinRotation) { + inst.trigger('rotate', ev); + } + + // trigger pinch event + if(scaleThreshold > inst.options.transformMinScale) { + inst.trigger('pinch', ev); + inst.trigger('pinch' + (ev.scale < 1 ? 'in' : 'out'), ev); + } + break; + + case EVENT_RELEASE: + if(triggered && ev.changedLength < 2) { + inst.trigger(name + 'end', ev); + triggered = false; + } + break; + } + } + + Hammer.gestures.Transform = { + name: name, + index: 45, + defaults: { + /** + * minimal scale factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1 + * @property transformMinScale + * @type {Number} + * @default 0.01 + */ + transformMinScale: 0.01, + + /** + * rotation in degrees + * @property transformMinRotation + * @type {Number} + * @default 1 + */ + transformMinRotation: 1 + }, + handler: transformGesture + }; + })('transform'); /** - * Stop moving in the X direction and unHighlight left and right. - * @private + * @module hammer */ - exports._xStopMoving = function(event) { - this.xIncrement = 0; - event && event.preventDefault(); - }; + // AMD export + if(true) { + !(__WEBPACK_AMD_DEFINE_RESULT__ = function() { + return Hammer; + }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + // commonjs export + } else if(typeof module !== 'undefined' && module.exports) { + module.exports = Hammer; + // browser export + } else { + window.Hammer = Hammer; + } + + })(window); /***/ }, /* 65 */ @@ -33247,744 +33260,718 @@ return /******/ (function(modules) { // webpackBootstrap /* 66 */ /***/ function(module, exports, __webpack_require__) { - var util = __webpack_require__(1); - var RepulsionMixin = __webpack_require__(68); - var HierarchialRepulsionMixin = __webpack_require__(69); - var BarnesHutMixin = __webpack_require__(70); + var Node = __webpack_require__(40); + + /** + * This function can be called from the _doInAllSectors function + * + * @param object + * @param overlappingNodes + * @private + */ + exports._getNodesOverlappingWith = function(object, overlappingNodes) { + var nodes = this.nodes; + for (var nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + if (nodes[nodeId].isOverlappingWith(object)) { + overlappingNodes.push(nodeId); + } + } + } + }; + + /** + * retrieve all nodes overlapping with given object + * @param {Object} object An object with parameters left, top, right, bottom + * @return {Number[]} An array with id's of the overlapping nodes + * @private + */ + exports._getAllNodesOverlappingWith = function (object) { + var overlappingNodes = []; + this._doInAllActiveSectors("_getNodesOverlappingWith",object,overlappingNodes); + return overlappingNodes; + }; + + + /** + * Return a position object in canvasspace from a single point in screenspace + * + * @param pointer + * @returns {{left: number, top: number, right: number, bottom: number}} + * @private + */ + exports._pointerToPositionObject = function(pointer) { + var x = this._XconvertDOMtoCanvas(pointer.x); + var y = this._YconvertDOMtoCanvas(pointer.y); + + return { + left: x, + top: y, + right: x, + bottom: y + }; + }; + + + /** + * Get the top node at the a specific point (like a click) + * + * @param {{x: Number, y: Number}} pointer + * @return {Node | null} node + * @private + */ + exports._getNodeAt = function (pointer) { + // we first check if this is an navigation controls element + var positionObject = this._pointerToPositionObject(pointer); + var overlappingNodes = this._getAllNodesOverlappingWith(positionObject); + + // if there are overlapping nodes, select the last one, this is the + // one which is drawn on top of the others + if (overlappingNodes.length > 0) { + return this.nodes[overlappingNodes[overlappingNodes.length - 1]]; + } + else { + return null; + } + }; + + + /** + * retrieve all edges overlapping with given object, selector is around center + * @param {Object} object An object with parameters left, top, right, bottom + * @return {Number[]} An array with id's of the overlapping nodes + * @private + */ + exports._getEdgesOverlappingWith = function (object, overlappingEdges) { + var edges = this.edges; + for (var edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + if (edges[edgeId].isOverlappingWith(object)) { + overlappingEdges.push(edgeId); + } + } + } + }; + + + /** + * retrieve all nodes overlapping with given object + * @param {Object} object An object with parameters left, top, right, bottom + * @return {Number[]} An array with id's of the overlapping nodes + * @private + */ + exports._getAllEdgesOverlappingWith = function (object) { + var overlappingEdges = []; + this._doInAllActiveSectors("_getEdgesOverlappingWith",object,overlappingEdges); + return overlappingEdges; + }; + + /** + * Place holder. To implement change the _getNodeAt to a _getObjectAt. Have the _getObjectAt call + * _getNodeAt and _getEdgesAt, then priortize the selection to user preferences. + * + * @param pointer + * @returns {null} + * @private + */ + exports._getEdgeAt = function(pointer) { + var positionObject = this._pointerToPositionObject(pointer); + var overlappingEdges = this._getAllEdgesOverlappingWith(positionObject); + + if (overlappingEdges.length > 0) { + return this.edges[overlappingEdges[overlappingEdges.length - 1]]; + } + else { + return null; + } + }; + + + /** + * Add object to the selection array. + * + * @param obj + * @private + */ + exports._addToSelection = function(obj) { + if (obj instanceof Node) { + this.selectionObj.nodes[obj.id] = obj; + } + else { + this.selectionObj.edges[obj.id] = obj; + } + }; /** - * Toggling barnes Hut calculation on and off. + * Add object to the selection array. * + * @param obj * @private */ - exports._toggleBarnesHut = function () { - this.constants.physics.barnesHut.enabled = !this.constants.physics.barnesHut.enabled; - this._loadSelectedForceSolver(); - this.moving = true; - this.start(); + exports._addToHover = function(obj) { + if (obj instanceof Node) { + this.hoverObj.nodes[obj.id] = obj; + } + else { + this.hoverObj.edges[obj.id] = obj; + } }; /** - * This loads the node force solver based on the barnes hut or repulsion algorithm + * Remove a single option from selection. * + * @param {Object} obj * @private */ - exports._loadSelectedForceSolver = function () { - // this overloads the this._calculateNodeForces - if (this.constants.physics.barnesHut.enabled == true) { - this._clearMixin(RepulsionMixin); - this._clearMixin(HierarchialRepulsionMixin); - - this.constants.physics.centralGravity = this.constants.physics.barnesHut.centralGravity; - this.constants.physics.springLength = this.constants.physics.barnesHut.springLength; - this.constants.physics.springConstant = this.constants.physics.barnesHut.springConstant; - this.constants.physics.damping = this.constants.physics.barnesHut.damping; - - this._loadMixin(BarnesHutMixin); - } - else if (this.constants.physics.hierarchicalRepulsion.enabled == true) { - this._clearMixin(BarnesHutMixin); - this._clearMixin(RepulsionMixin); - - this.constants.physics.centralGravity = this.constants.physics.hierarchicalRepulsion.centralGravity; - this.constants.physics.springLength = this.constants.physics.hierarchicalRepulsion.springLength; - this.constants.physics.springConstant = this.constants.physics.hierarchicalRepulsion.springConstant; - this.constants.physics.damping = this.constants.physics.hierarchicalRepulsion.damping; - - this._loadMixin(HierarchialRepulsionMixin); + exports._removeFromSelection = function(obj) { + if (obj instanceof Node) { + delete this.selectionObj.nodes[obj.id]; } else { - this._clearMixin(BarnesHutMixin); - this._clearMixin(HierarchialRepulsionMixin); - this.barnesHutTree = undefined; - - this.constants.physics.centralGravity = this.constants.physics.repulsion.centralGravity; - this.constants.physics.springLength = this.constants.physics.repulsion.springLength; - this.constants.physics.springConstant = this.constants.physics.repulsion.springConstant; - this.constants.physics.damping = this.constants.physics.repulsion.damping; - - this._loadMixin(RepulsionMixin); + delete this.selectionObj.edges[obj.id]; } }; /** - * Before calculating the forces, we check if we need to cluster to keep up performance and we check - * if there is more than one node. If it is just one node, we dont calculate anything. + * Unselect all. The selectionObj is useful for this. * + * @param {Boolean} [doNotTrigger] | ignore trigger * @private */ - exports._initializeForceCalculation = function () { - // stop calculation if there is only one node - if (this.nodeIndices.length == 1) { - this.nodes[this.nodeIndices[0]]._setForce(0, 0); + exports._unselectAll = function(doNotTrigger) { + if (doNotTrigger === undefined) { + doNotTrigger = false; } - else { - // if there are too many nodes on screen, we cluster without repositioning - if (this.nodeIndices.length > this.constants.clustering.clusterThreshold && this.constants.clustering.enabled == true) { - this.clusterToFit(this.constants.clustering.reduceToNodes, false); + for(var nodeId in this.selectionObj.nodes) { + if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { + this.selectionObj.nodes[nodeId].unselect(); + } + } + for(var edgeId in this.selectionObj.edges) { + if(this.selectionObj.edges.hasOwnProperty(edgeId)) { + this.selectionObj.edges[edgeId].unselect(); } + } - // we now start the force calculation - this._calculateForces(); + this.selectionObj = {nodes:{},edges:{}}; + + if (doNotTrigger == false) { + this.emit('select', this.getSelection()); } }; - /** - * Calculate the external forces acting on the nodes - * Forces are caused by: edges, repulsing forces between nodes, gravity + * Unselect all clusters. The selectionObj is useful for this. + * + * @param {Boolean} [doNotTrigger] | ignore trigger * @private */ - exports._calculateForces = function () { - // Gravity is required to keep separated groups from floating off - // the forces are reset to zero in this loop by using _setForce instead - // of _addForce - - this._calculateGravitationalForces(); - this._calculateNodeForces(); + exports._unselectClusters = function(doNotTrigger) { + if (doNotTrigger === undefined) { + doNotTrigger = false; + } - if (this.constants.physics.springConstant > 0) { - if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { - this._calculateSpringForcesWithSupport(); - } - else { - if (this.constants.physics.hierarchicalRepulsion.enabled == true) { - this._calculateHierarchicalSpringForces(); - } - else { - this._calculateSpringForces(); + for (var nodeId in this.selectionObj.nodes) { + if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { + if (this.selectionObj.nodes[nodeId].clusterSize > 1) { + this.selectionObj.nodes[nodeId].unselect(); + this._removeFromSelection(this.selectionObj.nodes[nodeId]); } } } + + if (doNotTrigger == false) { + this.emit('select', this.getSelection()); + } }; /** - * Smooth curves are created by adding invisible nodes in the center of the edges. These nodes are also - * handled in the calculateForces function. We then use a quadratic curve with the center node as control. - * This function joins the datanodes and invisible (called support) nodes into one object. - * We do this so we do not contaminate this.nodes with the support nodes. + * return the number of selected nodes * + * @returns {number} * @private */ - exports._updateCalculationNodes = function () { - if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { - this.calculationNodes = {}; - this.calculationNodeIndices = []; - - for (var nodeId in this.nodes) { - if (this.nodes.hasOwnProperty(nodeId)) { - this.calculationNodes[nodeId] = this.nodes[nodeId]; - } - } - var supportNodes = this.sectors['support']['nodes']; - for (var supportNodeId in supportNodes) { - if (supportNodes.hasOwnProperty(supportNodeId)) { - if (this.edges.hasOwnProperty(supportNodes[supportNodeId].parentEdgeId)) { - this.calculationNodes[supportNodeId] = supportNodes[supportNodeId]; - } - else { - supportNodes[supportNodeId]._setForce(0, 0); - } - } - } - - for (var idx in this.calculationNodes) { - if (this.calculationNodes.hasOwnProperty(idx)) { - this.calculationNodeIndices.push(idx); - } + exports._getSelectedNodeCount = function() { + var count = 0; + for (var nodeId in this.selectionObj.nodes) { + if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { + count += 1; } } - else { - this.calculationNodes = this.nodes; - this.calculationNodeIndices = this.nodeIndices; - } + return count; }; - /** - * this function applies the central gravity effect to keep groups from floating off + * return the selected node * + * @returns {number} * @private */ - exports._calculateGravitationalForces = function () { - var dx, dy, distance, node, i; - var nodes = this.calculationNodes; - var gravity = this.constants.physics.centralGravity; - var gravityForce = 0; - - for (i = 0; i < this.calculationNodeIndices.length; i++) { - node = nodes[this.calculationNodeIndices[i]]; - node.damping = this.constants.physics.damping; // possibly add function to alter damping properties of clusters. - // gravity does not apply when we are in a pocket sector - if (this._sector() == "default" && gravity != 0) { - dx = -node.x; - dy = -node.y; - distance = Math.sqrt(dx * dx + dy * dy); - - gravityForce = (distance == 0) ? 0 : (gravity / distance); - node.fx = dx * gravityForce; - node.fy = dy * gravityForce; - } - else { - node.fx = 0; - node.fy = 0; + exports._getSelectedNode = function() { + for (var nodeId in this.selectionObj.nodes) { + if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { + return this.selectionObj.nodes[nodeId]; } } + return null; }; - - - /** - * this function calculates the effects of the springs in the case of unsmooth curves. + * return the selected edge * + * @returns {number} * @private */ - exports._calculateSpringForces = function () { - var edgeLength, edge, edgeId; - var dx, dy, fx, fy, springForce, distance; - var edges = this.edges; - - // forces caused by the edges, modelled as springs - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.connected) { - // only calculate forces if nodes are in the same sector - if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { - edgeLength = edge.physics.springLength; - // this implies that the edges between big clusters are longer - edgeLength += (edge.to.clusterSize + edge.from.clusterSize - 2) * this.constants.clustering.edgeGrowth; - - dx = (edge.from.x - edge.to.x); - dy = (edge.from.y - edge.to.y); - distance = Math.sqrt(dx * dx + dy * dy); - - if (distance == 0) { - distance = 0.01; - } - - // the 1/distance is so the fx and fy can be calculated without sine or cosine. - springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance; - - fx = dx * springForce; - fy = dy * springForce; - - edge.from.fx += fx; - edge.from.fy += fy; - edge.to.fx -= fx; - edge.to.fy -= fy; - } - } + exports._getSelectedEdge = function() { + for (var edgeId in this.selectionObj.edges) { + if (this.selectionObj.edges.hasOwnProperty(edgeId)) { + return this.selectionObj.edges[edgeId]; } } + return null; }; - - /** - * This function calculates the springforces on the nodes, accounting for the support nodes. + * return the number of selected edges * + * @returns {number} * @private */ - exports._calculateSpringForcesWithSupport = function () { - var edgeLength, edge, edgeId, combinedClusterSize; - var edges = this.edges; - - // forces caused by the edges, modelled as springs - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.connected) { - // only calculate forces if nodes are in the same sector - if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { - if (edge.via != null) { - var node1 = edge.to; - var node2 = edge.via; - var node3 = edge.from; - - edgeLength = edge.physics.springLength; - - combinedClusterSize = node1.clusterSize + node3.clusterSize - 2; - - // this implies that the edges between big clusters are longer - edgeLength += combinedClusterSize * this.constants.clustering.edgeGrowth; - this._calculateSpringForce(node1, node2, 0.5 * edgeLength); - this._calculateSpringForce(node2, node3, 0.5 * edgeLength); - } - } - } + exports._getSelectedEdgeCount = function() { + var count = 0; + for (var edgeId in this.selectionObj.edges) { + if (this.selectionObj.edges.hasOwnProperty(edgeId)) { + count += 1; } } + return count; }; /** - * This is the code actually performing the calculation for the function above. It is split out to avoid repetition. + * return the number of selected objects. * - * @param node1 - * @param node2 - * @param edgeLength + * @returns {number} * @private */ - exports._calculateSpringForce = function (node1, node2, edgeLength) { - var dx, dy, fx, fy, springForce, distance; - - dx = (node1.x - node2.x); - dy = (node1.y - node2.y); - distance = Math.sqrt(dx * dx + dy * dy); - - if (distance == 0) { - distance = 0.01; + exports._getSelectedObjectCount = function() { + var count = 0; + for(var nodeId in this.selectionObj.nodes) { + if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { + count += 1; + } } - - // the 1/distance is so the fx and fy can be calculated without sine or cosine. - springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance; - - fx = dx * springForce; - fy = dy * springForce; - - node1.fx += fx; - node1.fy += fy; - node2.fx -= fx; - node2.fy -= fy; - }; - - - exports._cleanupPhysicsConfiguration = function() { - if (this.physicsConfiguration !== undefined) { - while (this.physicsConfiguration.hasChildNodes()) { - this.physicsConfiguration.removeChild(this.physicsConfiguration.firstChild); + for(var edgeId in this.selectionObj.edges) { + if(this.selectionObj.edges.hasOwnProperty(edgeId)) { + count += 1; } - - this.physicsConfiguration.parentNode.removeChild(this.physicsConfiguration); - this.physicsConfiguration = undefined; } - } + return count; + }; /** - * Load the HTML for the physics config and bind it + * Check if anything is selected + * + * @returns {boolean} * @private */ - exports._loadPhysicsConfiguration = function () { - if (this.physicsConfiguration === undefined) { - this.backupConstants = {}; - util.deepExtend(this.backupConstants,this.constants); - - var hierarchicalLayoutDirections = ["LR", "RL", "UD", "DU"]; - this.physicsConfiguration = document.createElement('div'); - this.physicsConfiguration.className = "PhysicsConfiguration"; - this.physicsConfiguration.innerHTML = '' + - '' + - '' + - '' + - '' + - '' + - '' + - '
Simulation Mode:
Barnes HutRepulsionHierarchical
' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '
Options:
' - this.containerElement.parentElement.insertBefore(this.physicsConfiguration, this.containerElement); - this.optionsDiv = document.createElement("div"); - this.optionsDiv.style.fontSize = "14px"; - this.optionsDiv.style.fontFamily = "verdana"; - this.containerElement.parentElement.insertBefore(this.optionsDiv, this.containerElement); - - var rangeElement; - rangeElement = document.getElementById('graph_BH_gc'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_gc', -1, "physics_barnesHut_gravitationalConstant"); - rangeElement = document.getElementById('graph_BH_cg'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_cg', 1, "physics_centralGravity"); - rangeElement = document.getElementById('graph_BH_sc'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_sc', 1, "physics_springConstant"); - rangeElement = document.getElementById('graph_BH_sl'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_sl', 1, "physics_springLength"); - rangeElement = document.getElementById('graph_BH_damp'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_damp', 1, "physics_damping"); - - rangeElement = document.getElementById('graph_R_nd'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_nd', 1, "physics_repulsion_nodeDistance"); - rangeElement = document.getElementById('graph_R_cg'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_cg', 1, "physics_centralGravity"); - rangeElement = document.getElementById('graph_R_sc'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_sc', 1, "physics_springConstant"); - rangeElement = document.getElementById('graph_R_sl'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_sl', 1, "physics_springLength"); - rangeElement = document.getElementById('graph_R_damp'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_damp', 1, "physics_damping"); - - rangeElement = document.getElementById('graph_H_nd'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_nd', 1, "physics_hierarchicalRepulsion_nodeDistance"); - rangeElement = document.getElementById('graph_H_cg'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_cg', 1, "physics_centralGravity"); - rangeElement = document.getElementById('graph_H_sc'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_sc', 1, "physics_springConstant"); - rangeElement = document.getElementById('graph_H_sl'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_sl', 1, "physics_springLength"); - rangeElement = document.getElementById('graph_H_damp'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_damp', 1, "physics_damping"); - rangeElement = document.getElementById('graph_H_direction'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_direction', hierarchicalLayoutDirections, "hierarchicalLayout_direction"); - rangeElement = document.getElementById('graph_H_levsep'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_levsep', 1, "hierarchicalLayout_levelSeparation"); - rangeElement = document.getElementById('graph_H_nspac'); - rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_nspac', 1, "hierarchicalLayout_nodeSpacing"); - - var radioButton1 = document.getElementById("graph_physicsMethod1"); - var radioButton2 = document.getElementById("graph_physicsMethod2"); - var radioButton3 = document.getElementById("graph_physicsMethod3"); - radioButton2.checked = true; - if (this.constants.physics.barnesHut.enabled) { - radioButton1.checked = true; - } - if (this.constants.hierarchicalLayout.enabled) { - radioButton3.checked = true; - } - - var graph_toggleSmooth = document.getElementById("graph_toggleSmooth"); - var graph_repositionNodes = document.getElementById("graph_repositionNodes"); - var graph_generateOptions = document.getElementById("graph_generateOptions"); - - graph_toggleSmooth.onclick = graphToggleSmoothCurves.bind(this); - graph_repositionNodes.onclick = graphRepositionNodes.bind(this); - graph_generateOptions.onclick = graphGenerateOptions.bind(this); - if (this.constants.smoothCurves == true && this.constants.dynamicSmoothCurves == false) { - graph_toggleSmooth.style.background = "#A4FF56"; + exports._selectionIsEmpty = function() { + for(var nodeId in this.selectionObj.nodes) { + if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { + return false; } - else { - graph_toggleSmooth.style.background = "#FF8532"; + } + for(var edgeId in this.selectionObj.edges) { + if(this.selectionObj.edges.hasOwnProperty(edgeId)) { + return false; } + } + return true; + }; - switchConfigurations.apply(this); - - radioButton1.onchange = switchConfigurations.bind(this); - radioButton2.onchange = switchConfigurations.bind(this); - radioButton3.onchange = switchConfigurations.bind(this); + /** + * check if one of the selected nodes is a cluster. + * + * @returns {boolean} + * @private + */ + exports._clusterInSelection = function() { + for(var nodeId in this.selectionObj.nodes) { + if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { + if (this.selectionObj.nodes[nodeId].clusterSize > 1) { + return true; + } + } } + return false; }; /** - * This overwrites the this.constants. + * select the edges connected to the node that is being selected * - * @param constantsVariableName - * @param value + * @param {Node} node * @private */ - exports._overWriteGraphConstants = function (constantsVariableName, value) { - var nameArray = constantsVariableName.split("_"); - if (nameArray.length == 1) { - this.constants[nameArray[0]] = value; - } - else if (nameArray.length == 2) { - this.constants[nameArray[0]][nameArray[1]] = value; + exports._selectConnectedEdges = function(node) { + for (var i = 0; i < node.dynamicEdges.length; i++) { + var edge = node.dynamicEdges[i]; + edge.select(); + this._addToSelection(edge); } - else if (nameArray.length == 3) { - this.constants[nameArray[0]][nameArray[1]][nameArray[2]] = value; + }; + + /** + * select the edges connected to the node that is being selected + * + * @param {Node} node + * @private + */ + exports._hoverConnectedEdges = function(node) { + for (var i = 0; i < node.dynamicEdges.length; i++) { + var edge = node.dynamicEdges[i]; + edge.hover = true; + this._addToHover(edge); } }; /** - * this function is bound to the toggle smooth curves button. That is also why it is not in the prototype. + * unselect the edges connected to the node that is being selected + * + * @param {Node} node + * @private */ - function graphToggleSmoothCurves () { - this.constants.smoothCurves.enabled = !this.constants.smoothCurves.enabled; - var graph_toggleSmooth = document.getElementById("graph_toggleSmooth"); - if (this.constants.smoothCurves.enabled == true) {graph_toggleSmooth.style.background = "#A4FF56";} - else {graph_toggleSmooth.style.background = "#FF8532";} + exports._unselectConnectedEdges = function(node) { + for (var i = 0; i < node.dynamicEdges.length; i++) { + var edge = node.dynamicEdges[i]; + edge.unselect(); + this._removeFromSelection(edge); + } + }; + + - this._configureSmoothCurves(false); - } /** - * this function is used to scramble the nodes + * This is called when someone clicks on a node. either select or deselect it. + * If there is an existing selection and we don't want to append to it, clear the existing selection * + * @param {Node || Edge} object + * @param {Boolean} append + * @param {Boolean} [doNotTrigger] | ignore trigger + * @private */ - function graphRepositionNodes () { - for (var nodeId in this.calculationNodes) { - if (this.calculationNodes.hasOwnProperty(nodeId)) { - this.calculationNodes[nodeId].vx = 0; this.calculationNodes[nodeId].vy = 0; - this.calculationNodes[nodeId].fx = 0; this.calculationNodes[nodeId].fy = 0; + exports._selectObject = function(object, append, doNotTrigger, highlightEdges, overrideSelectable) { + if (doNotTrigger === undefined) { + doNotTrigger = false; + } + if (highlightEdges === undefined) { + highlightEdges = true; + } + + if (this._selectionIsEmpty() == false && append == false && this.forceAppendSelection == false) { + this._unselectAll(true); + } + + // selectable allows the object to be selected. Override can be used if needed to bypass this. + if (object.selected == false && (this.constants.selectable == true || overrideSelectable)) { + object.select(); + this._addToSelection(object); + if (object instanceof Node && this.blockConnectingEdgeSelection == false && highlightEdges == true) { + this._selectConnectedEdges(object); } } - if (this.constants.hierarchicalLayout.enabled == true) { - this._setupHierarchicalLayout(); - showValueOfRange.call(this, 'graph_H_nd', 1, "physics_hierarchicalRepulsion_nodeDistance"); - showValueOfRange.call(this, 'graph_H_cg', 1, "physics_centralGravity"); - showValueOfRange.call(this, 'graph_H_sc', 1, "physics_springConstant"); - showValueOfRange.call(this, 'graph_H_sl', 1, "physics_springLength"); - showValueOfRange.call(this, 'graph_H_damp', 1, "physics_damping"); + // do not select the object if selectable is false, only add it to selection to allow drag to work + else if (object.selected == false) { + this._addToSelection(object); + doNotTrigger = true; } else { - this.repositionNodes(); + object.unselect(); + this._removeFromSelection(object); } - this.moving = true; - this.start(); - } + + if (doNotTrigger == false) { + this.emit('select', this.getSelection()); + } + }; + /** - * this is used to generate an options file from the playing with physics system. + * This is called when someone clicks on a node. either select or deselect it. + * If there is an existing selection and we don't want to append to it, clear the existing selection + * + * @param {Node || Edge} object + * @private */ - function graphGenerateOptions () { - var options = "No options are required, default values used."; - var optionsSpecific = []; - var radioButton1 = document.getElementById("graph_physicsMethod1"); - var radioButton2 = document.getElementById("graph_physicsMethod2"); - if (radioButton1.checked == true) { - if (this.constants.physics.barnesHut.gravitationalConstant != this.backupConstants.physics.barnesHut.gravitationalConstant) {optionsSpecific.push("gravitationalConstant: " + this.constants.physics.barnesHut.gravitationalConstant);} - if (this.constants.physics.centralGravity != this.backupConstants.physics.barnesHut.centralGravity) {optionsSpecific.push("centralGravity: " + this.constants.physics.centralGravity);} - if (this.constants.physics.springLength != this.backupConstants.physics.barnesHut.springLength) {optionsSpecific.push("springLength: " + this.constants.physics.springLength);} - if (this.constants.physics.springConstant != this.backupConstants.physics.barnesHut.springConstant) {optionsSpecific.push("springConstant: " + this.constants.physics.springConstant);} - if (this.constants.physics.damping != this.backupConstants.physics.barnesHut.damping) {optionsSpecific.push("damping: " + this.constants.physics.damping);} - if (optionsSpecific.length != 0) { - options = "var options = {"; - options += "physics: {barnesHut: {"; - for (var i = 0; i < optionsSpecific.length; i++) { - options += optionsSpecific[i]; - if (i < optionsSpecific.length - 1) { - options += ", " - } - } - options += '}}' - } - if (this.constants.smoothCurves.enabled != this.backupConstants.smoothCurves.enabled) { - if (optionsSpecific.length == 0) {options = "var options = {";} - else {options += ", "} - options += "smoothCurves: " + this.constants.smoothCurves.enabled; - } - if (options != "No options are required, default values used.") { - options += '};' - } + exports._blurObject = function(object) { + if (object.hover == true) { + object.hover = false; + this.emit("blurNode",{node:object.id}); } - else if (radioButton2.checked == true) { - options = "var options = {"; - options += "physics: {barnesHut: {enabled: false}"; - if (this.constants.physics.repulsion.nodeDistance != this.backupConstants.physics.repulsion.nodeDistance) {optionsSpecific.push("nodeDistance: " + this.constants.physics.repulsion.nodeDistance);} - if (this.constants.physics.centralGravity != this.backupConstants.physics.repulsion.centralGravity) {optionsSpecific.push("centralGravity: " + this.constants.physics.centralGravity);} - if (this.constants.physics.springLength != this.backupConstants.physics.repulsion.springLength) {optionsSpecific.push("springLength: " + this.constants.physics.springLength);} - if (this.constants.physics.springConstant != this.backupConstants.physics.repulsion.springConstant) {optionsSpecific.push("springConstant: " + this.constants.physics.springConstant);} - if (this.constants.physics.damping != this.backupConstants.physics.repulsion.damping) {optionsSpecific.push("damping: " + this.constants.physics.damping);} - if (optionsSpecific.length != 0) { - options += ", repulsion: {"; - for (var i = 0; i < optionsSpecific.length; i++) { - options += optionsSpecific[i]; - if (i < optionsSpecific.length - 1) { - options += ", " - } - } - options += '}}' - } - if (optionsSpecific.length == 0) {options += "}"} - if (this.constants.smoothCurves != this.backupConstants.smoothCurves) { - options += ", smoothCurves: " + this.constants.smoothCurves; + }; + + /** + * This is called when someone clicks on a node. either select or deselect it. + * If there is an existing selection and we don't want to append to it, clear the existing selection + * + * @param {Node || Edge} object + * @private + */ + exports._hoverObject = function(object) { + if (object.hover == false) { + object.hover = true; + this._addToHover(object); + if (object instanceof Node) { + this.emit("hoverNode",{node:object.id}); } - options += '};' + } + if (object instanceof Node) { + this._hoverConnectedEdges(object); + } + }; + + + /** + * handles the selection part of the touch, only for navigation controls elements; + * Touch is triggered before tap, also before hold. Hold triggers after a while. + * This is the most responsive solution + * + * @param {Object} pointer + * @private + */ + exports._handleTouch = function(pointer) { + }; + + + /** + * handles the selection part of the tap; + * + * @param {Object} pointer + * @private + */ + exports._handleTap = function(pointer) { + var node = this._getNodeAt(pointer); + if (node != null) { + this._selectObject(node, false); } else { - options = "var options = {"; - if (this.constants.physics.hierarchicalRepulsion.nodeDistance != this.backupConstants.physics.hierarchicalRepulsion.nodeDistance) {optionsSpecific.push("nodeDistance: " + this.constants.physics.hierarchicalRepulsion.nodeDistance);} - if (this.constants.physics.centralGravity != this.backupConstants.physics.hierarchicalRepulsion.centralGravity) {optionsSpecific.push("centralGravity: " + this.constants.physics.centralGravity);} - if (this.constants.physics.springLength != this.backupConstants.physics.hierarchicalRepulsion.springLength) {optionsSpecific.push("springLength: " + this.constants.physics.springLength);} - if (this.constants.physics.springConstant != this.backupConstants.physics.hierarchicalRepulsion.springConstant) {optionsSpecific.push("springConstant: " + this.constants.physics.springConstant);} - if (this.constants.physics.damping != this.backupConstants.physics.hierarchicalRepulsion.damping) {optionsSpecific.push("damping: " + this.constants.physics.damping);} - if (optionsSpecific.length != 0) { - options += "physics: {hierarchicalRepulsion: {"; - for (var i = 0; i < optionsSpecific.length; i++) { - options += optionsSpecific[i]; - if (i < optionsSpecific.length - 1) { - options += ", "; - } - } - options += '}},'; - } - options += 'hierarchicalLayout: {'; - optionsSpecific = []; - if (this.constants.hierarchicalLayout.direction != this.backupConstants.hierarchicalLayout.direction) {optionsSpecific.push("direction: " + this.constants.hierarchicalLayout.direction);} - if (Math.abs(this.constants.hierarchicalLayout.levelSeparation) != this.backupConstants.hierarchicalLayout.levelSeparation) {optionsSpecific.push("levelSeparation: " + this.constants.hierarchicalLayout.levelSeparation);} - if (this.constants.hierarchicalLayout.nodeSpacing != this.backupConstants.hierarchicalLayout.nodeSpacing) {optionsSpecific.push("nodeSpacing: " + this.constants.hierarchicalLayout.nodeSpacing);} - if (optionsSpecific.length != 0) { - for (var i = 0; i < optionsSpecific.length; i++) { - options += optionsSpecific[i]; - if (i < optionsSpecific.length - 1) { - options += ", " - } - } - options += '}' + var edge = this._getEdgeAt(pointer); + if (edge != null) { + this._selectObject(edge, false); } else { - options += "enabled:true}"; + this._unselectAll(); } - options += '};' } + var properties = this.getSelection(); + properties['pointer'] = { + DOM: {x: pointer.x, y: pointer.y}, + canvas: {x: this._XconvertDOMtoCanvas(pointer.x), y: this._YconvertDOMtoCanvas(pointer.y)} + } + this.emit("click", properties); + this._redraw(); + }; - this.optionsDiv.innerHTML = options; - } - /** - * this is used to switch between barnesHut, repulsion and hierarchical. + * handles the selection part of the double tap and opens a cluster if needed * + * @param {Object} pointer + * @private */ - function switchConfigurations () { - var ids = ["graph_BH_table", "graph_R_table", "graph_H_table"]; - var radioButton = document.querySelector('input[name="graph_physicsMethod"]:checked').value; - var tableId = "graph_" + radioButton + "_table"; - var table = document.getElementById(tableId); - table.style.display = "block"; - for (var i = 0; i < ids.length; i++) { - if (ids[i] != tableId) { - table = document.getElementById(ids[i]); - table.style.display = "none"; - } + exports._handleDoubleTap = function(pointer) { + var node = this._getNodeAt(pointer); + if (node != null && node !== undefined) { + // we reset the areaCenter here so the opening of the node will occur + this.areaCenter = {"x" : this._XconvertDOMtoCanvas(pointer.x), + "y" : this._YconvertDOMtoCanvas(pointer.y)}; + this.openCluster(node); } - this._restoreNodes(); - if (radioButton == "R") { - this.constants.hierarchicalLayout.enabled = false; - this.constants.physics.hierarchicalRepulsion.enabled = false; - this.constants.physics.barnesHut.enabled = false; + var properties = this.getSelection(); + properties['pointer'] = { + DOM: {x: pointer.x, y: pointer.y}, + canvas: {x: this._XconvertDOMtoCanvas(pointer.x), y: this._YconvertDOMtoCanvas(pointer.y)} } - else if (radioButton == "H") { - if (this.constants.hierarchicalLayout.enabled == false) { - this.constants.hierarchicalLayout.enabled = true; - this.constants.physics.hierarchicalRepulsion.enabled = true; - this.constants.physics.barnesHut.enabled = false; - this.constants.smoothCurves.enabled = false; - this._setupHierarchicalLayout(); - } + this.emit("doubleClick", properties); + }; + + + /** + * Handle the onHold selection part + * + * @param pointer + * @private + */ + exports._handleOnHold = function(pointer) { + var node = this._getNodeAt(pointer); + if (node != null) { + this._selectObject(node,true); } else { - this.constants.hierarchicalLayout.enabled = false; - this.constants.physics.hierarchicalRepulsion.enabled = false; - this.constants.physics.barnesHut.enabled = true; + var edge = this._getEdgeAt(pointer); + if (edge != null) { + this._selectObject(edge,true); + } } - this._loadSelectedForceSolver(); - var graph_toggleSmooth = document.getElementById("graph_toggleSmooth"); - if (this.constants.smoothCurves.enabled == true) {graph_toggleSmooth.style.background = "#A4FF56";} - else {graph_toggleSmooth.style.background = "#FF8532";} - this.moving = true; - this.start(); - } + this._redraw(); + }; /** - * this generates the ranges depending on the iniital values. + * handle the onRelease event. These functions are here for the navigation controls module + * and data manipulation module. * - * @param id - * @param map - * @param constantsVariableName + * @private */ - function showValueOfRange (id,map,constantsVariableName) { - var valueId = id + "_value"; - var rangeValue = document.getElementById(id).value; + exports._handleOnRelease = function(pointer) { + this._manipulationReleaseOverload(pointer); + this._navigationReleaseOverload(pointer); + }; - if (Array.isArray(map)) { - document.getElementById(valueId).value = map[parseInt(rangeValue)]; - this._overWriteGraphConstants(constantsVariableName,map[parseInt(rangeValue)]); + exports._manipulationReleaseOverload = function (pointer) {}; + exports._navigationReleaseOverload = function (pointer) {}; + + /** + * + * retrieve the currently selected objects + * @return {{nodes: Array., edges: Array.}} selection + */ + exports.getSelection = function() { + var nodeIds = this.getSelectedNodes(); + var edgeIds = this.getSelectedEdges(); + return {nodes:nodeIds, edges:edgeIds}; + }; + + /** + * + * retrieve the currently selected nodes + * @return {String[]} selection An array with the ids of the + * selected nodes. + */ + exports.getSelectedNodes = function() { + var idArray = []; + if (this.constants.selectable == true) { + for (var nodeId in this.selectionObj.nodes) { + if (this.selectionObj.nodes.hasOwnProperty(nodeId)) { + idArray.push(nodeId); + } + } } - else { - document.getElementById(valueId).value = parseInt(map) * parseFloat(rangeValue); - this._overWriteGraphConstants(constantsVariableName, parseInt(map) * parseFloat(rangeValue)); + return idArray + }; + + /** + * + * retrieve the currently selected edges + * @return {Array} selection An array with the ids of the + * selected nodes. + */ + exports.getSelectedEdges = function() { + var idArray = []; + if (this.constants.selectable == true) { + for (var edgeId in this.selectionObj.edges) { + if (this.selectionObj.edges.hasOwnProperty(edgeId)) { + idArray.push(edgeId); + } + } } + return idArray; + }; - if (constantsVariableName == "hierarchicalLayout_direction" || - constantsVariableName == "hierarchicalLayout_levelSeparation" || - constantsVariableName == "hierarchicalLayout_nodeSpacing") { - this._setupHierarchicalLayout(); + + /** + * select zero or more nodes DEPRICATED + * @param {Number[] | String[]} selection An array with the ids of the + * selected nodes. + */ + exports.setSelection = function() { + console.log("setSelection is deprecated. Please use selectNodes instead.") + }; + + + /** + * select zero or more nodes with the option to highlight edges + * @param {Number[] | String[]} selection An array with the ids of the + * selected nodes. + * @param {boolean} [highlightEdges] + */ + exports.selectNodes = function(selection, highlightEdges) { + var i, iMax, id; + + if (!selection || (selection.length == undefined)) + throw 'Selection must be an array with ids'; + + // first unselect any selected node + this._unselectAll(true); + + for (i = 0, iMax = selection.length; i < iMax; i++) { + id = selection[i]; + + var node = this.nodes[id]; + if (!node) { + throw new RangeError('Node with id "' + id + '" not found'); + } + this._selectObject(node,true,true,highlightEdges,true); } - this.moving = true; - this.start(); - } + this.redraw(); + }; + + + /** + * select zero or more edges + * @param {Number[] | String[]} selection An array with the ids of the + * selected nodes. + */ + exports.selectEdges = function(selection) { + var i, iMax, id; + if (!selection || (selection.length == undefined)) + throw 'Selection must be an array with ids'; + // first unselect any selected node + this._unselectAll(true); + for (i = 0, iMax = selection.length; i < iMax; i++) { + id = selection[i]; -/***/ }, -/* 67 */ -/***/ function(module, exports, __webpack_require__) { + var edge = this.edges[id]; + if (!edge) { + throw new RangeError('Edge with id "' + id + '" not found'); + } + this._selectObject(edge,true,true,false,true); + } + this.redraw(); + }; - function webpackContext(req) { - throw new Error("Cannot find module '" + req + "'."); - } - webpackContext.keys = function() { return []; }; - webpackContext.resolve = webpackContext; - module.exports = webpackContext; - webpackContext.id = 67; + /** + * Validate the selection: remove ids of nodes which no longer exist + * @private + */ + exports._updateSelection = function () { + for(var nodeId in this.selectionObj.nodes) { + if(this.selectionObj.nodes.hasOwnProperty(nodeId)) { + if (!this.nodes.hasOwnProperty(nodeId)) { + delete this.selectionObj.nodes[nodeId]; + } + } + } + for(var edgeId in this.selectionObj.edges) { + if(this.selectionObj.edges.hasOwnProperty(edgeId)) { + if (!this.edges.hasOwnProperty(edgeId)) { + delete this.selectionObj.edges[edgeId]; + } + } + } + }; /***/ }, -/* 68 */ +/* 67 */ /***/ function(module, exports, __webpack_require__) { /** @@ -34054,7 +34041,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 69 */ +/* 68 */ /***/ function(module, exports, __webpack_require__) { /** @@ -34213,7 +34200,7 @@ return /******/ (function(modules) { // webpackBootstrap }; /***/ }, -/* 70 */ +/* 69 */ /***/ function(module, exports, __webpack_require__) { /** @@ -34617,6 +34604,19 @@ return /******/ (function(modules) { // webpackBootstrap }; +/***/ }, +/* 70 */ +/***/ function(module, exports, __webpack_require__) { + + function webpackContext(req) { + throw new Error("Cannot find module '" + req + "'."); + } + webpackContext.keys = function() { return []; }; + webpackContext.resolve = webpackContext; + module.exports = webpackContext; + webpackContext.id = 70; + + /***/ }, /* 71 */ /***/ function(module, exports, __webpack_require__) { diff --git a/docs/network.html b/docs/network.html index 28cfcd83..e4775b41 100644 --- a/docs/network.html +++ b/docs/network.html @@ -303,7 +303,8 @@ When using a DataSet, the network is automatically updating to changes in the Da level number no - This level is used in the hierarchical layout. If this is not selected, the level does not do anything. + This level is used in the hierarchical layout. If this is not selected, the level does not do anything. This must be a postive number (min value: 0). + Fractions are possible but only integers are supported. @@ -342,7 +343,7 @@ When using a DataSet, the network is automatically updating to changes in the Da no Horizontal position in pixels. The horizontal position of the node will be fixed unless combined with the allowedToMoveX:true option. - The vertical position y may remain undefined. + The vertical position y may remain undefined. This does not work with hierarchical layout. y @@ -350,7 +351,7 @@ When using a DataSet, the network is automatically updating to changes in the Da no Vertical position in pixels. The vertical position of the node will be fixed unless combined with the allowedToMoveY:true option. - The horizontal position x may remain undefined. + The horizontal position x may remain undefined. This does not work with hierarchical layout. @@ -1000,13 +1001,13 @@ All options defined per-node override these global settings. widthMin Number 16 - The minimum width for a scaled image. Only applicable to shape image. + The minimum width for a scaled image. Only applicable to shape image. This only does something if you supply a value. widthMax Number 64 - The maximum width for a scaled image. Only applicable to shape image. + The maximum width for a scaled image. Only applicable to shape image. This only does something if you supply a value. @@ -1021,14 +1022,14 @@ All options defined per-node override these global settings. Number 10 The minimum radius for a scaled node. Only applicable to shapes dot, - star, triangle, triangleDown, and square. + star, triangle, triangleDown, and square. This only does something if you supply a value. radiusMax Number 30 The maximum radius for a scaled node. Only applicable to shapes dot, - star, triangle, triangleDown, and square. + star, triangle, triangleDown, and square. This only does something if you supply a value. @@ -1224,13 +1225,13 @@ var options = { widthMin Number 1 - The minimum thickness of the line when using per-edge defined values. + The minimum thickness of the line when using per-edge defined values. This does nothing if you have not defined a value. widthMax Number 15 - The maximum thickness of the line when using per-edge defined values. + The maximum thickness of the line when using per-edge defined values. This does nothing if you have not defined a value. From d488cd3a7a7bc2c0cf144bdd466d238cd1888081 Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Thu, 22 Jan 2015 14:14:54 +0100 Subject: [PATCH 08/16] - Fixed scroll being blocked if zoomable is false. (decoupled bindHammer from create) --- HISTORY.md | 3 +- dist/vis.js | 54319 ++++++++++++++++++++------------------- lib/network/Network.js | 29 +- 3 files changed, 27191 insertions(+), 27160 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index a1fc9a65..33365f1f 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -9,7 +9,8 @@ http://visjs.org - Fixed bug where opening a cluster with smoothCurves off caused one child to go crazy. - Fixed bug where zoomExtent does not work as expected. - Fixed nodes color data being overridden when having a group and a dataset update query. -- Decoupled animation from physics simulation +- Decoupled animation from physics simulation. +- Fixed scroll being blocked if zoomable is false. ## 2015-01-16, version 3.9.0 diff --git a/dist/vis.js b/dist/vis.js index 3f276a8d..8d2d0c1f 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -83,67 +83,67 @@ return /******/ (function(modules) { // webpackBootstrap // utils exports.util = __webpack_require__(1); - exports.DOMutil = __webpack_require__(2); + exports.DOMutil = __webpack_require__(6); // data - exports.DataSet = __webpack_require__(3); - exports.DataView = __webpack_require__(4); - exports.Queue = __webpack_require__(5); + exports.DataSet = __webpack_require__(7); + exports.DataView = __webpack_require__(9); + exports.Queue = __webpack_require__(8); // Graph3d - exports.Graph3d = __webpack_require__(6); + exports.Graph3d = __webpack_require__(10); exports.graph3d = { - Camera: __webpack_require__(7), - Filter: __webpack_require__(8), - Point2d: __webpack_require__(9), - Point3d: __webpack_require__(10), - Slider: __webpack_require__(11), - StepNumber: __webpack_require__(12) + Camera: __webpack_require__(14), + Filter: __webpack_require__(15), + Point2d: __webpack_require__(13), + Point3d: __webpack_require__(12), + Slider: __webpack_require__(16), + StepNumber: __webpack_require__(17) }; // Timeline - exports.Timeline = __webpack_require__(13); - exports.Graph2d = __webpack_require__(14); + exports.Timeline = __webpack_require__(18); + exports.Graph2d = __webpack_require__(42); exports.timeline = { - DateUtil: __webpack_require__(15), - DataStep: __webpack_require__(16), - Range: __webpack_require__(17), - stack: __webpack_require__(18), - TimeStep: __webpack_require__(19), + DateUtil: __webpack_require__(24), + DataStep: __webpack_require__(45), + Range: __webpack_require__(21), + stack: __webpack_require__(28), + TimeStep: __webpack_require__(38), components: { items: { - Item: __webpack_require__(31), - BackgroundItem: __webpack_require__(32), - BoxItem: __webpack_require__(33), - PointItem: __webpack_require__(34), - RangeItem: __webpack_require__(35) + Item: __webpack_require__(30), + BackgroundItem: __webpack_require__(34), + BoxItem: __webpack_require__(32), + PointItem: __webpack_require__(33), + RangeItem: __webpack_require__(29) }, - Component: __webpack_require__(20), - CurrentTime: __webpack_require__(21), - CustomTime: __webpack_require__(22), - DataAxis: __webpack_require__(23), - GraphGroup: __webpack_require__(24), - Group: __webpack_require__(25), - BackgroundGroup: __webpack_require__(26), - ItemSet: __webpack_require__(27), - Legend: __webpack_require__(28), - LineGraph: __webpack_require__(29), - TimeAxis: __webpack_require__(30) + Component: __webpack_require__(23), + CurrentTime: __webpack_require__(39), + CustomTime: __webpack_require__(41), + DataAxis: __webpack_require__(44), + GraphGroup: __webpack_require__(46), + Group: __webpack_require__(27), + BackgroundGroup: __webpack_require__(31), + ItemSet: __webpack_require__(26), + Legend: __webpack_require__(50), + LineGraph: __webpack_require__(43), + TimeAxis: __webpack_require__(37) } }; // Network - exports.Network = __webpack_require__(36); + exports.Network = __webpack_require__(51); exports.network = { - Edge: __webpack_require__(37), - Groups: __webpack_require__(38), - Images: __webpack_require__(39), - Node: __webpack_require__(40), - Popup: __webpack_require__(41), - dotparser: __webpack_require__(42), - gephiParser: __webpack_require__(43) + Edge: __webpack_require__(52), + Groups: __webpack_require__(54), + Images: __webpack_require__(55), + Node: __webpack_require__(53), + Popup: __webpack_require__(56), + dotparser: __webpack_require__(57), + gephiParser: __webpack_require__(58) }; // Deprecated since v3.0.0 @@ -152,8 +152,8 @@ return /******/ (function(modules) { // webpackBootstrap }; // bundled external libraries - exports.moment = __webpack_require__(44); - exports.hammer = __webpack_require__(45); + exports.moment = __webpack_require__(2); + exports.hammer = __webpack_require__(19); /***/ }, @@ -164,7 +164,7 @@ return /******/ (function(modules) { // webpackBootstrap // first check if moment.js is already loaded in the browser window, if so, // use this instance. Else, load via commonjs. - var moment = __webpack_require__(44); + var moment = __webpack_require__(2); /** * Test whether given object is a number @@ -1396,31871 +1396,30995 @@ return /******/ (function(modules) { // webpackBootstrap /* 2 */ /***/ function(module, exports, __webpack_require__) { - // DOM utility methods - - /** - * this prepares the JSON container for allocating SVG elements - * @param JSONcontainer - * @private - */ - exports.prepareElements = function(JSONcontainer) { - // cleanup the redundant svgElements; - for (var elementType in JSONcontainer) { - if (JSONcontainer.hasOwnProperty(elementType)) { - JSONcontainer[elementType].redundant = JSONcontainer[elementType].used; - JSONcontainer[elementType].used = []; - } - } - }; - - /** - * this cleans up all the unused SVG elements. By asking for the parentNode, we only need to supply the JSON container from - * which to remove the redundant elements. - * - * @param JSONcontainer - * @private - */ - exports.cleanupElements = function(JSONcontainer) { - // cleanup the redundant svgElements; - for (var elementType in JSONcontainer) { - if (JSONcontainer.hasOwnProperty(elementType)) { - if (JSONcontainer[elementType].redundant) { - for (var i = 0; i < JSONcontainer[elementType].redundant.length; i++) { - JSONcontainer[elementType].redundant[i].parentNode.removeChild(JSONcontainer[elementType].redundant[i]); - } - JSONcontainer[elementType].redundant = []; - } - } - } - }; - - /** - * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer - * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this. - * - * @param elementType - * @param JSONcontainer - * @param svgContainer - * @returns {*} - * @private - */ - exports.getSVGElement = function (elementType, JSONcontainer, svgContainer) { - var element; - // allocate SVG element, if it doesnt yet exist, create one. - if (JSONcontainer.hasOwnProperty(elementType)) { // this element has been created before - // check if there is an redundant element - if (JSONcontainer[elementType].redundant.length > 0) { - element = JSONcontainer[elementType].redundant[0]; - JSONcontainer[elementType].redundant.shift(); - } - else { - // create a new element and add it to the SVG - element = document.createElementNS('http://www.w3.org/2000/svg', elementType); - svgContainer.appendChild(element); - } - } - else { - // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it. - element = document.createElementNS('http://www.w3.org/2000/svg', elementType); - JSONcontainer[elementType] = {used: [], redundant: []}; - svgContainer.appendChild(element); - } - JSONcontainer[elementType].used.push(element); - return element; - }; - - - /** - * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer - * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this. - * - * @param elementType - * @param JSONcontainer - * @param DOMContainer - * @returns {*} - * @private - */ - exports.getDOMElement = function (elementType, JSONcontainer, DOMContainer, insertBefore) { - var element; - // allocate DOM element, if it doesnt yet exist, create one. - if (JSONcontainer.hasOwnProperty(elementType)) { // this element has been created before - // check if there is an redundant element - if (JSONcontainer[elementType].redundant.length > 0) { - element = JSONcontainer[elementType].redundant[0]; - JSONcontainer[elementType].redundant.shift(); - } - else { - // create a new element and add it to the SVG - element = document.createElement(elementType); - if (insertBefore !== undefined) { - DOMContainer.insertBefore(element, insertBefore); - } - else { - DOMContainer.appendChild(element); - } - } - } - else { - // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it. - element = document.createElement(elementType); - JSONcontainer[elementType] = {used: [], redundant: []}; - if (insertBefore !== undefined) { - DOMContainer.insertBefore(element, insertBefore); - } - else { - DOMContainer.appendChild(element); - } - } - JSONcontainer[elementType].used.push(element); - return element; - }; - - - - - /** - * draw a point object. this is a seperate function because it can also be called by the legend. - * The reason the JSONcontainer and the target SVG svgContainer have to be supplied is so the legend can use these functions - * as well. - * - * @param x - * @param y - * @param group - * @param JSONcontainer - * @param svgContainer - * @returns {*} - */ - exports.drawPoint = function(x, y, group, JSONcontainer, svgContainer) { - var point; - if (group.options.drawPoints.style == 'circle') { - point = exports.getSVGElement('circle',JSONcontainer,svgContainer); - point.setAttributeNS(null, "cx", x); - point.setAttributeNS(null, "cy", y); - point.setAttributeNS(null, "r", 0.5 * group.options.drawPoints.size); - } - else { - point = exports.getSVGElement('rect',JSONcontainer,svgContainer); - point.setAttributeNS(null, "x", x - 0.5*group.options.drawPoints.size); - point.setAttributeNS(null, "y", y - 0.5*group.options.drawPoints.size); - point.setAttributeNS(null, "width", group.options.drawPoints.size); - point.setAttributeNS(null, "height", group.options.drawPoints.size); - } - - if(group.options.drawPoints.styles !== undefined) { - point.setAttributeNS(null, "style", group.group.options.drawPoints.styles); - } - point.setAttributeNS(null, "class", group.className + " point"); - return point; - }; + // first check if moment.js is already loaded in the browser window, if so, + // use this instance. Else, load via commonjs. + module.exports = (typeof window !== 'undefined') && window['moment'] || __webpack_require__(3); - /** - * draw a bar SVG element centered on the X coordinate - * - * @param x - * @param y - * @param className - */ - exports.drawBar = function (x, y, width, height, className, JSONcontainer, svgContainer) { - if (height != 0) { - if (height < 0) { - height *= -1; - y -= height; - } - var rect = exports.getSVGElement('rect',JSONcontainer, svgContainer); - rect.setAttributeNS(null, "x", x - 0.5 * width); - rect.setAttributeNS(null, "y", y); - rect.setAttributeNS(null, "width", width); - rect.setAttributeNS(null, "height", height); - rect.setAttributeNS(null, "class", className); - } - }; /***/ }, /* 3 */ /***/ function(module, exports, __webpack_require__) { - var util = __webpack_require__(1); - var Queue = __webpack_require__(5); - - /** - * DataSet - * - * Usage: - * var dataSet = new DataSet({ - * fieldId: '_id', - * type: { - * // ... - * } - * }); - * - * dataSet.add(item); - * dataSet.add(data); - * dataSet.update(item); - * dataSet.update(data); - * dataSet.remove(id); - * dataSet.remove(ids); - * var data = dataSet.get(); - * var data = dataSet.get(id); - * var data = dataSet.get(ids); - * var data = dataSet.get(ids, options, data); - * dataSet.clear(); - * - * A data set can: - * - add/remove/update data - * - gives triggers upon changes in the data - * - can import/export data in various data formats - * - * @param {Array | DataTable} [data] Optional array with initial data - * @param {Object} [options] Available options: - * {String} fieldId Field name of the id in the - * items, 'id' by default. - * {Object. ['10', '00'] or '-1530' > ['-', '15', '30'] + parseTimezoneChunker = /([\+\-]|\d\d)/gi, - if (Array.isArray(data)) { - // Array - for (var i = 0, len = data.length; i < len; i++) { - id = me._addItem(data[i]); - addedIds.push(id); - } - } - else if (util.isDataTable(data)) { - // Google DataTable - var columns = this._getColumnNames(data); - for (var row = 0, rows = data.getNumberOfRows(); row < rows; row++) { - var item = {}; - for (var col = 0, cols = columns.length; col < cols; col++) { - var field = columns[col]; - item[field] = data.getValue(row, col); - } + // getter and setter names + proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), + unitMillisecondFactors = { + 'Milliseconds' : 1, + 'Seconds' : 1e3, + 'Minutes' : 6e4, + 'Hours' : 36e5, + 'Days' : 864e5, + 'Months' : 2592e6, + 'Years' : 31536e6 + }, - id = me._addItem(item); - addedIds.push(id); - } - } - else if (data instanceof Object) { - // Single item - id = me._addItem(data); - addedIds.push(id); - } - else { - throw new Error('Unknown dataType'); - } + unitAliases = { + ms : 'millisecond', + s : 'second', + m : 'minute', + h : 'hour', + d : 'day', + D : 'date', + w : 'week', + W : 'isoWeek', + M : 'month', + Q : 'quarter', + y : 'year', + DDD : 'dayOfYear', + e : 'weekday', + E : 'isoWeekday', + gg: 'weekYear', + GG: 'isoWeekYear' + }, - if (addedIds.length) { - this._trigger('add', {items: addedIds}, senderId); - } + camelFunctions = { + dayofyear : 'dayOfYear', + isoweekday : 'isoWeekday', + isoweek : 'isoWeek', + weekyear : 'weekYear', + isoweekyear : 'isoWeekYear' + }, - return addedIds; - }; + // format function strings + formatFunctions = {}, - /** - * Update existing items. When an item does not exist, it will be created - * @param {Object | Array | DataTable} data - * @param {String} [senderId] Optional sender id - * @return {Array} updatedIds The ids of the added or updated items - */ - DataSet.prototype.update = function (data, senderId) { - var addedIds = []; - var updatedIds = []; - var updatedData = []; - var me = this; - var fieldId = me._fieldId; - - var addOrUpdate = function (item) { - var id = item[fieldId]; - if (me._data[id]) { - // update item - id = me._updateItem(item); - updatedIds.push(id); - updatedData.push(item); - } - else { - // add new item - id = me._addItem(item); - addedIds.push(id); - } - }; - - if (Array.isArray(data)) { - // Array - for (var i = 0, len = data.length; i < len; i++) { - addOrUpdate(data[i]); - } - } - else if (util.isDataTable(data)) { - // Google DataTable - var columns = this._getColumnNames(data); - for (var row = 0, rows = data.getNumberOfRows(); row < rows; row++) { - var item = {}; - for (var col = 0, cols = columns.length; col < cols; col++) { - var field = columns[col]; - item[field] = data.getValue(row, col); - } - - addOrUpdate(item); - } - } - else if (data instanceof Object) { - // Single item - addOrUpdate(data); - } - else { - throw new Error('Unknown dataType'); - } - - if (addedIds.length) { - this._trigger('add', {items: addedIds}, senderId); - } - if (updatedIds.length) { - this._trigger('update', {items: updatedIds, data: updatedData}, senderId); - } - - return addedIds.concat(updatedIds); - }; - - /** - * Get a data item or multiple items. - * - * Usage: - * - * get() - * get(options: Object) - * get(options: Object, data: Array | DataTable) - * - * get(id: Number | String) - * get(id: Number | String, options: Object) - * get(id: Number | String, options: Object, data: Array | DataTable) - * - * get(ids: Number[] | String[]) - * get(ids: Number[] | String[], options: Object) - * get(ids: Number[] | String[], options: Object, data: Array | DataTable) - * - * Where: - * - * {Number | String} id The id of an item - * {Number[] | String{}} ids An array with ids of items - * {Object} options An Object with options. Available options: - * {String} [returnType] Type of data to be - * returned. Can be 'DataTable' or 'Array' (default) - * {Object.} [type] - * {String[]} [fields] field names to be returned - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * {Array | DataTable} [data] If provided, items will be appended to this - * array or table. Required in case of Google - * DataTable. - * - * @throws Error - */ - DataSet.prototype.get = function (args) { - var me = this; - - // parse the arguments - var id, ids, options, data; - var firstType = util.getType(arguments[0]); - if (firstType == 'String' || firstType == 'Number') { - // get(id [, options] [, data]) - id = arguments[0]; - options = arguments[1]; - data = arguments[2]; - } - else if (firstType == 'Array') { - // get(ids [, options] [, data]) - ids = arguments[0]; - options = arguments[1]; - data = arguments[2]; - } - else { - // get([, options] [, data]) - options = arguments[0]; - data = arguments[1]; - } - - // determine the return type - var returnType; - if (options && options.returnType) { - var allowedValues = ["DataTable", "Array", "Object"]; - returnType = allowedValues.indexOf(options.returnType) == -1 ? "Array" : options.returnType; - - if (data && (returnType != util.getType(data))) { - throw new Error('Type of parameter "data" (' + util.getType(data) + ') ' + - 'does not correspond with specified options.type (' + options.type + ')'); - } - if (returnType == 'DataTable' && !util.isDataTable(data)) { - throw new Error('Parameter "data" must be a DataTable ' + - 'when options.type is "DataTable"'); - } - } - else if (data) { - returnType = (util.getType(data) == 'DataTable') ? 'DataTable' : 'Array'; - } - else { - returnType = 'Array'; - } - - // build options - var type = options && options.type || this._options.type; - var filter = options && options.filter; - var items = [], item, itemId, i, len; - - // convert items - if (id != undefined) { - // return a single item - item = me._getItem(id, type); - if (filter && !filter(item)) { - item = null; - } - } - else if (ids != undefined) { - // return a subset of items - for (i = 0, len = ids.length; i < len; i++) { - item = me._getItem(ids[i], type); - if (!filter || filter(item)) { - items.push(item); - } - } - } - else { - // return all items - for (itemId in this._data) { - if (this._data.hasOwnProperty(itemId)) { - item = me._getItem(itemId, type); - if (!filter || filter(item)) { - items.push(item); - } - } - } - } - - // order the results - if (options && options.order && id == undefined) { - this._sort(items, options.order); - } - - // filter fields of the items - if (options && options.fields) { - var fields = options.fields; - if (id != undefined) { - item = this._filterFields(item, fields); - } - else { - for (i = 0, len = items.length; i < len; i++) { - items[i] = this._filterFields(items[i], fields); - } - } - } - - // return the results - if (returnType == 'DataTable') { - var columns = this._getColumnNames(data); - if (id != undefined) { - // append a single item to the data table - me._appendRow(data, columns, item); - } - else { - // copy the items to the provided data table - for (i = 0; i < items.length; i++) { - me._appendRow(data, columns, items[i]); - } - } - return data; - } - else if (returnType == "Object") { - var result = {}; - for (i = 0; i < items.length; i++) { - result[items[i].id] = items[i]; - } - return result; - } - else { - // return an array - if (id != undefined) { - // a single item - return item; - } - else { - // multiple items - if (data) { - // copy the items to the provided array - for (i = 0, len = items.length; i < len; i++) { - data.push(items[i]); - } - return data; - } - else { - // just return our array - return items; - } - } - } - }; - - /** - * Get ids of all items or from a filtered set of items. - * @param {Object} [options] An Object with options. Available options: - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * @return {Array} ids - */ - DataSet.prototype.getIds = function (options) { - var data = this._data, - filter = options && options.filter, - order = options && options.order, - type = options && options.type || this._options.type, - i, - len, - id, - item, - items, - ids = []; - - if (filter) { - // get filtered items - if (order) { - // create ordered list - items = []; - for (id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, type); - if (filter(item)) { - items.push(item); - } - } - } - - this._sort(items, order); - - for (i = 0, len = items.length; i < len; i++) { - ids[i] = items[i][this._fieldId]; - } - } - else { - // create unordered list - for (id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, type); - if (filter(item)) { - ids.push(item[this._fieldId]); - } - } - } - } - } - else { - // get all items - if (order) { - // create an ordered list - items = []; - for (id in data) { - if (data.hasOwnProperty(id)) { - items.push(data[id]); - } - } - - this._sort(items, order); - - for (i = 0, len = items.length; i < len; i++) { - ids[i] = items[i][this._fieldId]; - } - } - else { - // create unordered list - for (id in data) { - if (data.hasOwnProperty(id)) { - item = data[id]; - ids.push(item[this._fieldId]); - } - } - } - } - - return ids; - }; - - /** - * Returns the DataSet itself. Is overwritten for example by the DataView, - * which returns the DataSet it is connected to instead. - */ - DataSet.prototype.getDataSet = function () { - return this; - }; - - /** - * Execute a callback function for every item in the dataset. - * @param {function} callback - * @param {Object} [options] Available options: - * {Object.} [type] - * {String[]} [fields] filter fields - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - */ - DataSet.prototype.forEach = function (callback, options) { - var filter = options && options.filter, - type = options && options.type || this._options.type, - data = this._data, - item, - id; - - if (options && options.order) { - // execute forEach on ordered list - var items = this.get(options); - - for (var i = 0, len = items.length; i < len; i++) { - item = items[i]; - id = item[this._fieldId]; - callback(item, id); - } - } - else { - // unordered - for (id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, type); - if (!filter || filter(item)) { - callback(item, id); - } - } - } - } - }; - - /** - * Map every item in the dataset. - * @param {function} callback - * @param {Object} [options] Available options: - * {Object.} [type] - * {String[]} [fields] filter fields - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * @return {Object[]} mappedItems - */ - DataSet.prototype.map = function (callback, options) { - var filter = options && options.filter, - type = options && options.type || this._options.type, - mappedItems = [], - data = this._data, - item; - - // convert and filter items - for (var id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, type); - if (!filter || filter(item)) { - mappedItems.push(callback(item, id)); - } - } - } - - // order items - if (options && options.order) { - this._sort(mappedItems, options.order); - } - - return mappedItems; - }; - - /** - * Filter the fields of an item - * @param {Object} item - * @param {String[]} fields Field names - * @return {Object} filteredItem - * @private - */ - DataSet.prototype._filterFields = function (item, fields) { - var filteredItem = {}; - - for (var field in item) { - if (item.hasOwnProperty(field) && (fields.indexOf(field) != -1)) { - filteredItem[field] = item[field]; - } - } - - return filteredItem; - }; - - /** - * Sort the provided array with items - * @param {Object[]} items - * @param {String | function} order A field name or custom sort function. - * @private - */ - DataSet.prototype._sort = function (items, order) { - if (util.isString(order)) { - // order by provided field name - var name = order; // field name - items.sort(function (a, b) { - var av = a[name]; - var bv = b[name]; - return (av > bv) ? 1 : ((av < bv) ? -1 : 0); - }); - } - else if (typeof order === 'function') { - // order by sort function - items.sort(order); - } - // TODO: extend order by an Object {field:String, direction:String} - // where direction can be 'asc' or 'desc' - else { - throw new TypeError('Order must be a function or a string'); - } - }; - - /** - * Remove an object by pointer or by id - * @param {String | Number | Object | Array} id Object or id, or an array with - * objects or ids to be removed - * @param {String} [senderId] Optional sender id - * @return {Array} removedIds - */ - DataSet.prototype.remove = function (id, senderId) { - var removedIds = [], - i, len, removedId; - - if (Array.isArray(id)) { - for (i = 0, len = id.length; i < len; i++) { - removedId = this._remove(id[i]); - if (removedId != null) { - removedIds.push(removedId); - } - } - } - else { - removedId = this._remove(id); - if (removedId != null) { - removedIds.push(removedId); - } - } - - if (removedIds.length) { - this._trigger('remove', {items: removedIds}, senderId); - } - - return removedIds; - }; - - /** - * Remove an item by its id - * @param {Number | String | Object} id id or item - * @returns {Number | String | null} id - * @private - */ - DataSet.prototype._remove = function (id) { - if (util.isNumber(id) || util.isString(id)) { - if (this._data[id]) { - delete this._data[id]; - return id; - } - } - else if (id instanceof Object) { - var itemId = id[this._fieldId]; - if (itemId && this._data[itemId]) { - delete this._data[itemId]; - return itemId; - } - } - return null; - }; - - /** - * Clear the data - * @param {String} [senderId] Optional sender id - * @return {Array} removedIds The ids of all removed items - */ - DataSet.prototype.clear = function (senderId) { - var ids = Object.keys(this._data); - - this._data = {}; - - this._trigger('remove', {items: ids}, senderId); - - return ids; - }; - - /** - * Find the item with maximum value of a specified field - * @param {String} field - * @return {Object | null} item Item containing max value, or null if no items - */ - DataSet.prototype.max = function (field) { - var data = this._data, - max = null, - maxField = null; - - for (var id in data) { - if (data.hasOwnProperty(id)) { - var item = data[id]; - var itemField = item[field]; - if (itemField != null && (!max || itemField > maxField)) { - max = item; - maxField = itemField; - } - } - } - - return max; - }; - - /** - * Find the item with minimum value of a specified field - * @param {String} field - * @return {Object | null} item Item containing max value, or null if no items - */ - DataSet.prototype.min = function (field) { - var data = this._data, - min = null, - minField = null; - - for (var id in data) { - if (data.hasOwnProperty(id)) { - var item = data[id]; - var itemField = item[field]; - if (itemField != null && (!min || itemField < minField)) { - min = item; - minField = itemField; - } - } - } - - return min; - }; - - /** - * Find all distinct values of a specified field - * @param {String} field - * @return {Array} values Array containing all distinct values. If data items - * do not contain the specified field are ignored. - * The returned array is unordered. - */ - DataSet.prototype.distinct = function (field) { - var data = this._data; - var values = []; - var fieldType = this._options.type && this._options.type[field] || null; - var count = 0; - var i; - - for (var prop in data) { - if (data.hasOwnProperty(prop)) { - var item = data[prop]; - var value = item[field]; - var exists = false; - for (i = 0; i < count; i++) { - if (values[i] == value) { - exists = true; - break; - } - } - if (!exists && (value !== undefined)) { - values[count] = value; - count++; - } - } - } - - if (fieldType) { - for (i = 0; i < values.length; i++) { - values[i] = util.convert(values[i], fieldType); - } - } - - return values; - }; - - /** - * Add a single item. Will fail when an item with the same id already exists. - * @param {Object} item - * @return {String} id - * @private - */ - DataSet.prototype._addItem = function (item) { - var id = item[this._fieldId]; - - if (id != undefined) { - // check whether this id is already taken - if (this._data[id]) { - // item already exists - throw new Error('Cannot add item: item with id ' + id + ' already exists'); - } - } - else { - // generate an id - id = util.randomUUID(); - item[this._fieldId] = id; - } - - var d = {}; - for (var field in item) { - if (item.hasOwnProperty(field)) { - var fieldType = this._type[field]; // type may be undefined - d[field] = util.convert(item[field], fieldType); - } - } - this._data[id] = d; - - return id; - }; - - /** - * Get an item. Fields can be converted to a specific type - * @param {String} id - * @param {Object.} [types] field types to convert - * @return {Object | null} item - * @private - */ - DataSet.prototype._getItem = function (id, types) { - var field, value; - - // get the item from the dataset - var raw = this._data[id]; - if (!raw) { - return null; - } - - // convert the items field types - var converted = {}; - if (types) { - for (field in raw) { - if (raw.hasOwnProperty(field)) { - value = raw[field]; - converted[field] = util.convert(value, types[field]); - } - } - } - else { - // no field types specified, no converting needed - for (field in raw) { - if (raw.hasOwnProperty(field)) { - value = raw[field]; - converted[field] = value; - } - } - } - return converted; - }; - - /** - * Update a single item: merge with existing item. - * Will fail when the item has no id, or when there does not exist an item - * with the same id. - * @param {Object} item - * @return {String} id - * @private - */ - DataSet.prototype._updateItem = function (item) { - var id = item[this._fieldId]; - if (id == undefined) { - throw new Error('Cannot update item: item has no id (item: ' + JSON.stringify(item) + ')'); - } - var d = this._data[id]; - if (!d) { - // item doesn't exist - throw new Error('Cannot update item: no item with id ' + id + ' found'); - } - - // merge with current item - for (var field in item) { - if (item.hasOwnProperty(field)) { - var fieldType = this._type[field]; // type may be undefined - d[field] = util.convert(item[field], fieldType); - } - } - - return id; - }; - - /** - * Get an array with the column names of a Google DataTable - * @param {DataTable} dataTable - * @return {String[]} columnNames - * @private - */ - DataSet.prototype._getColumnNames = function (dataTable) { - var columns = []; - for (var col = 0, cols = dataTable.getNumberOfColumns(); col < cols; col++) { - columns[col] = dataTable.getColumnId(col) || dataTable.getColumnLabel(col); - } - return columns; - }; - - /** - * Append an item as a row to the dataTable - * @param dataTable - * @param columns - * @param item - * @private - */ - DataSet.prototype._appendRow = function (dataTable, columns, item) { - var row = dataTable.addRow(); - - for (var col = 0, cols = columns.length; col < cols; col++) { - var field = columns[col]; - dataTable.setValue(row, col, item[field]); - } - }; - - module.exports = DataSet; - - -/***/ }, -/* 4 */ -/***/ function(module, exports, __webpack_require__) { - - var util = __webpack_require__(1); - var DataSet = __webpack_require__(3); - - /** - * DataView - * - * a dataview offers a filtered view on a dataset or an other dataview. - * - * @param {DataSet | DataView} data - * @param {Object} [options] Available options: see method get - * - * @constructor DataView - */ - function DataView (data, options) { - this._data = null; - this._ids = {}; // ids of the items currently in memory (just contains a boolean true) - this._options = options || {}; - this._fieldId = 'id'; // name of the field containing id - this._subscribers = {}; // event subscribers - - var me = this; - this.listener = function () { - me._onEvent.apply(me, arguments); - }; - - this.setData(data); - } - - // TODO: implement a function .config() to dynamically update things like configured filter - // and trigger changes accordingly - - /** - * Set a data source for the view - * @param {DataSet | DataView} data - */ - DataView.prototype.setData = function (data) { - var ids, i, len; - - if (this._data) { - // unsubscribe from current dataset - if (this._data.unsubscribe) { - this._data.unsubscribe('*', this.listener); - } - - // trigger a remove of all items in memory - ids = []; - for (var id in this._ids) { - if (this._ids.hasOwnProperty(id)) { - ids.push(id); - } - } - this._ids = {}; - this._trigger('remove', {items: ids}); - } - - this._data = data; - - if (this._data) { - // update fieldId - this._fieldId = this._options.fieldId || - (this._data && this._data.options && this._data.options.fieldId) || - 'id'; - - // trigger an add of all added items - ids = this._data.getIds({filter: this._options && this._options.filter}); - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - this._ids[id] = true; - } - this._trigger('add', {items: ids}); - - // subscribe to new dataset - if (this._data.on) { - this._data.on('*', this.listener); - } - } - }; - - /** - * Get data from the data view - * - * Usage: - * - * get() - * get(options: Object) - * get(options: Object, data: Array | DataTable) - * - * get(id: Number) - * get(id: Number, options: Object) - * get(id: Number, options: Object, data: Array | DataTable) - * - * get(ids: Number[]) - * get(ids: Number[], options: Object) - * get(ids: Number[], options: Object, data: Array | DataTable) - * - * Where: - * - * {Number | String} id The id of an item - * {Number[] | String{}} ids An array with ids of items - * {Object} options An Object with options. Available options: - * {String} [type] Type of data to be returned. Can - * be 'DataTable' or 'Array' (default) - * {Object.} [convert] - * {String[]} [fields] field names to be returned - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * {Array | DataTable} [data] If provided, items will be appended to this - * array or table. Required in case of Google - * DataTable. - * @param args - */ - DataView.prototype.get = function (args) { - var me = this; - - // parse the arguments - var ids, options, data; - var firstType = util.getType(arguments[0]); - if (firstType == 'String' || firstType == 'Number' || firstType == 'Array') { - // get(id(s) [, options] [, data]) - ids = arguments[0]; // can be a single id or an array with ids - options = arguments[1]; - data = arguments[2]; - } - else { - // get([, options] [, data]) - options = arguments[0]; - data = arguments[1]; - } - - // extend the options with the default options and provided options - var viewOptions = util.extend({}, this._options, options); - - // create a combined filter method when needed - if (this._options.filter && options && options.filter) { - viewOptions.filter = function (item) { - return me._options.filter(item) && options.filter(item); - } - } - - // build up the call to the linked data set - var getArguments = []; - if (ids != undefined) { - getArguments.push(ids); - } - getArguments.push(viewOptions); - getArguments.push(data); - - return this._data && this._data.get.apply(this._data, getArguments); - }; - - /** - * Get ids of all items or from a filtered set of items. - * @param {Object} [options] An Object with options. Available options: - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * @return {Array} ids - */ - DataView.prototype.getIds = function (options) { - var ids; - - if (this._data) { - var defaultFilter = this._options.filter; - var filter; - - if (options && options.filter) { - if (defaultFilter) { - filter = function (item) { - return defaultFilter(item) && options.filter(item); - } - } - else { - filter = options.filter; - } - } - else { - filter = defaultFilter; - } - - ids = this._data.getIds({ - filter: filter, - order: options && options.order - }); - } - else { - ids = []; - } - - return ids; - }; - - /** - * Get the DataSet to which this DataView is connected. In case there is a chain - * of multiple DataViews, the root DataSet of this chain is returned. - * @return {DataSet} dataSet - */ - DataView.prototype.getDataSet = function () { - var dataSet = this; - while (dataSet instanceof DataView) { - dataSet = dataSet._data; - } - return dataSet || null; - }; - - /** - * Event listener. Will propagate all events from the connected data set to - * the subscribers of the DataView, but will filter the items and only trigger - * when there are changes in the filtered data set. - * @param {String} event - * @param {Object | null} params - * @param {String} senderId - * @private - */ - DataView.prototype._onEvent = function (event, params, senderId) { - var i, len, id, item, - ids = params && params.items, - data = this._data, - added = [], - updated = [], - removed = []; - - if (ids && data) { - switch (event) { - case 'add': - // filter the ids of the added items - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - item = this.get(id); - if (item) { - this._ids[id] = true; - added.push(id); - } - } - - break; - - case 'update': - // determine the event from the views viewpoint: an updated - // item can be added, updated, or removed from this view. - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - item = this.get(id); - - if (item) { - if (this._ids[id]) { - updated.push(id); - } - else { - this._ids[id] = true; - added.push(id); - } - } - else { - if (this._ids[id]) { - delete this._ids[id]; - removed.push(id); - } - else { - // nothing interesting for me :-( - } - } - } - - break; - - case 'remove': - // filter the ids of the removed items - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - if (this._ids[id]) { - delete this._ids[id]; - removed.push(id); - } - } - - break; - } - - if (added.length) { - this._trigger('add', {items: added}, senderId); - } - if (updated.length) { - this._trigger('update', {items: updated}, senderId); - } - if (removed.length) { - this._trigger('remove', {items: removed}, senderId); - } - } - }; - - // copy subscription functionality from DataSet - DataView.prototype.on = DataSet.prototype.on; - DataView.prototype.off = DataSet.prototype.off; - DataView.prototype._trigger = DataSet.prototype._trigger; - - // TODO: make these functions deprecated (replaced with `on` and `off` since version 0.5) - DataView.prototype.subscribe = DataView.prototype.on; - DataView.prototype.unsubscribe = DataView.prototype.off; - - module.exports = DataView; - -/***/ }, -/* 5 */ -/***/ function(module, exports, __webpack_require__) { - - /** - * A queue - * @param {Object} options - * Available options: - * - delay: number When provided, the queue will be flushed - * automatically after an inactivity of this delay - * in milliseconds. - * Default value is null. - * - max: number When the queue exceeds the given maximum number - * of entries, the queue is flushed automatically. - * Default value of max is Infinity. - * @constructor - */ - function Queue(options) { - // options - this.delay = null; - this.max = Infinity; - - // properties - this._queue = []; - this._timeout = null; - this._extended = null; - - this.setOptions(options); - } - - /** - * Update the configuration of the queue - * @param {Object} options - * Available options: - * - delay: number When provided, the queue will be flushed - * automatically after an inactivity of this delay - * in milliseconds. - * Default value is null. - * - max: number When the queue exceeds the given maximum number - * of entries, the queue is flushed automatically. - * Default value of max is Infinity. - * @param options - */ - Queue.prototype.setOptions = function (options) { - if (options && typeof options.delay !== 'undefined') { - this.delay = options.delay; - } - if (options && typeof options.max !== 'undefined') { - this.max = options.max; - } - - this._flushIfNeeded(); - }; - - /** - * Extend an object with queuing functionality. - * The object will be extended with a function flush, and the methods provided - * in options.replace will be replaced with queued ones. - * @param {Object} object - * @param {Object} options - * Available options: - * - replace: Array. - * A list with method names of the methods - * on the object to be replaced with queued ones. - * - delay: number When provided, the queue will be flushed - * automatically after an inactivity of this delay - * in milliseconds. - * Default value is null. - * - max: number When the queue exceeds the given maximum number - * of entries, the queue is flushed automatically. - * Default value of max is Infinity. - * @return {Queue} Returns the created queue - */ - Queue.extend = function (object, options) { - var queue = new Queue(options); - - if (object.flush !== undefined) { - throw new Error('Target object already has a property flush'); - } - object.flush = function () { - queue.flush(); - }; - - var methods = [{ - name: 'flush', - original: undefined - }]; - - if (options && options.replace) { - for (var i = 0; i < options.replace.length; i++) { - var name = options.replace[i]; - methods.push({ - name: name, - original: object[name] - }); - queue.replace(object, name); - } - } - - queue._extended = { - object: object, - methods: methods - }; - - return queue; - }; - - /** - * Destroy the queue. The queue will first flush all queued actions, and in - * case it has extended an object, will restore the original object. - */ - Queue.prototype.destroy = function () { - this.flush(); - - if (this._extended) { - var object = this._extended.object; - var methods = this._extended.methods; - for (var i = 0; i < methods.length; i++) { - var method = methods[i]; - if (method.original) { - object[method.name] = method.original; - } - else { - delete object[method.name]; - } - } - this._extended = null; - } - }; - - /** - * Replace a method on an object with a queued version - * @param {Object} object Object having the method - * @param {string} method The method name - */ - Queue.prototype.replace = function(object, method) { - var me = this; - var original = object[method]; - if (!original) { - throw new Error('Method ' + method + ' undefined'); - } - - object[method] = function () { - // create an Array with the arguments - var args = []; - for (var i = 0; i < arguments.length; i++) { - args[i] = arguments[i]; - } - - // add this call to the queue - me.queue({ - args: args, - fn: original, - context: this - }); - }; - }; - - /** - * Queue a call - * @param {function | {fn: function, args: Array} | {fn: function, args: Array, context: Object}} entry - */ - Queue.prototype.queue = function(entry) { - if (typeof entry === 'function') { - this._queue.push({fn: entry}); - } - else { - this._queue.push(entry); - } - - this._flushIfNeeded(); - }; - - /** - * Check whether the queue needs to be flushed - * @private - */ - Queue.prototype._flushIfNeeded = function () { - // flush when the maximum is exceeded. - if (this._queue.length > this.max) { - this.flush(); - } - - // flush after a period of inactivity when a delay is configured - clearTimeout(this._timeout); - if (this.queue.length > 0 && typeof this.delay === 'number') { - var me = this; - this._timeout = setTimeout(function () { - me.flush(); - }, this.delay); - } - }; - - /** - * Flush all queued calls - */ - Queue.prototype.flush = function () { - while (this._queue.length > 0) { - var entry = this._queue.shift(); - entry.fn.apply(entry.context || entry.fn, entry.args || []); - } - }; - - module.exports = Queue; - - -/***/ }, -/* 6 */ -/***/ function(module, exports, __webpack_require__) { - - var Emitter = __webpack_require__(56); - var DataSet = __webpack_require__(3); - var DataView = __webpack_require__(4); - var util = __webpack_require__(1); - var Point3d = __webpack_require__(10); - var Point2d = __webpack_require__(9); - var Camera = __webpack_require__(7); - var Filter = __webpack_require__(8); - var Slider = __webpack_require__(11); - var StepNumber = __webpack_require__(12); - - /** - * @constructor Graph3d - * Graph3d displays data in 3d. - * - * Graph3d is developed in javascript as a Google Visualization Chart. - * - * @param {Element} container The DOM element in which the Graph3d will - * be created. Normally a div element. - * @param {DataSet | DataView | Array} [data] - * @param {Object} [options] - */ - function Graph3d(container, data, options) { - if (!(this instanceof Graph3d)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - // create variables and set default values - this.containerElement = container; - this.width = '400px'; - this.height = '400px'; - this.margin = 10; // px - this.defaultXCenter = '55%'; - this.defaultYCenter = '50%'; - - this.xLabel = 'x'; - this.yLabel = 'y'; - this.zLabel = 'z'; - - var passValueFn = function(v) { return v; }; - this.xValueLabel = passValueFn; - this.yValueLabel = passValueFn; - this.zValueLabel = passValueFn; - - this.filterLabel = 'time'; - this.legendLabel = 'value'; - - this.style = Graph3d.STYLE.DOT; - this.showPerspective = true; - this.showGrid = true; - this.keepAspectRatio = true; - this.showShadow = false; - this.showGrayBottom = false; // TODO: this does not work correctly - this.showTooltip = false; - this.verticalRatio = 0.5; // 0.1 to 1.0, where 1.0 results in a 'cube' - - this.animationInterval = 1000; // milliseconds - this.animationPreload = false; - - this.camera = new Camera(); - this.eye = new Point3d(0, 0, -1); // TODO: set eye.z about 3/4 of the width of the window? - - this.dataTable = null; // The original data table - this.dataPoints = null; // The table with point objects - - // the column indexes - this.colX = undefined; - this.colY = undefined; - this.colZ = undefined; - this.colValue = undefined; - this.colFilter = undefined; - - this.xMin = 0; - this.xStep = undefined; // auto by default - this.xMax = 1; - this.yMin = 0; - this.yStep = undefined; // auto by default - this.yMax = 1; - this.zMin = 0; - this.zStep = undefined; // auto by default - this.zMax = 1; - this.valueMin = 0; - this.valueMax = 1; - this.xBarWidth = 1; - this.yBarWidth = 1; - // TODO: customize axis range - - // constants - this.colorAxis = '#4D4D4D'; - this.colorGrid = '#D3D3D3'; - this.colorDot = '#7DC1FF'; - this.colorDotBorder = '#3267D2'; - - // create a frame and canvas - this.create(); - - // apply options (also when undefined) - this.setOptions(options); - - // apply data - if (data) { - this.setData(data); - } - } - - // Extend Graph3d with an Emitter mixin - Emitter(Graph3d.prototype); - - /** - * Calculate the scaling values, dependent on the range in x, y, and z direction - */ - Graph3d.prototype._setScale = function() { - this.scale = new Point3d(1 / (this.xMax - this.xMin), - 1 / (this.yMax - this.yMin), - 1 / (this.zMax - this.zMin)); - - // keep aspect ration between x and y scale if desired - if (this.keepAspectRatio) { - if (this.scale.x < this.scale.y) { - //noinspection JSSuspiciousNameCombination - this.scale.y = this.scale.x; - } - else { - //noinspection JSSuspiciousNameCombination - this.scale.x = this.scale.y; - } - } - - // scale the vertical axis - this.scale.z *= this.verticalRatio; - // TODO: can this be automated? verticalRatio? - - // determine scale for (optional) value - this.scale.value = 1 / (this.valueMax - this.valueMin); - - // position the camera arm - var xCenter = (this.xMax + this.xMin) / 2 * this.scale.x; - var yCenter = (this.yMax + this.yMin) / 2 * this.scale.y; - var zCenter = (this.zMax + this.zMin) / 2 * this.scale.z; - this.camera.setArmLocation(xCenter, yCenter, zCenter); - }; - - - /** - * Convert a 3D location to a 2D location on screen - * http://en.wikipedia.org/wiki/3D_projection - * @param {Point3d} point3d A 3D point with parameters x, y, z - * @return {Point2d} point2d A 2D point with parameters x, y - */ - Graph3d.prototype._convert3Dto2D = function(point3d) { - var translation = this._convertPointToTranslation(point3d); - return this._convertTranslationToScreen(translation); - }; - - /** - * Convert a 3D location its translation seen from the camera - * http://en.wikipedia.org/wiki/3D_projection - * @param {Point3d} point3d A 3D point with parameters x, y, z - * @return {Point3d} translation A 3D point with parameters x, y, z This is - * the translation of the point, seen from the - * camera - */ - Graph3d.prototype._convertPointToTranslation = function(point3d) { - var ax = point3d.x * this.scale.x, - ay = point3d.y * this.scale.y, - az = point3d.z * this.scale.z, - - cx = this.camera.getCameraLocation().x, - cy = this.camera.getCameraLocation().y, - cz = this.camera.getCameraLocation().z, - - // calculate angles - sinTx = Math.sin(this.camera.getCameraRotation().x), - cosTx = Math.cos(this.camera.getCameraRotation().x), - sinTy = Math.sin(this.camera.getCameraRotation().y), - cosTy = Math.cos(this.camera.getCameraRotation().y), - sinTz = Math.sin(this.camera.getCameraRotation().z), - cosTz = Math.cos(this.camera.getCameraRotation().z), - - // calculate translation - dx = cosTy * (sinTz * (ay - cy) + cosTz * (ax - cx)) - sinTy * (az - cz), - dy = sinTx * (cosTy * (az - cz) + sinTy * (sinTz * (ay - cy) + cosTz * (ax - cx))) + cosTx * (cosTz * (ay - cy) - sinTz * (ax-cx)), - dz = cosTx * (cosTy * (az - cz) + sinTy * (sinTz * (ay - cy) + cosTz * (ax - cx))) - sinTx * (cosTz * (ay - cy) - sinTz * (ax-cx)); - - return new Point3d(dx, dy, dz); - }; - - /** - * Convert a translation point to a point on the screen - * @param {Point3d} translation A 3D point with parameters x, y, z This is - * the translation of the point, seen from the - * camera - * @return {Point2d} point2d A 2D point with parameters x, y - */ - Graph3d.prototype._convertTranslationToScreen = function(translation) { - var ex = this.eye.x, - ey = this.eye.y, - ez = this.eye.z, - dx = translation.x, - dy = translation.y, - dz = translation.z; - - // calculate position on screen from translation - var bx; - var by; - if (this.showPerspective) { - bx = (dx - ex) * (ez / dz); - by = (dy - ey) * (ez / dz); - } - else { - bx = dx * -(ez / this.camera.getArmLength()); - by = dy * -(ez / this.camera.getArmLength()); - } - - // shift and scale the point to the center of the screen - // use the width of the graph to scale both horizontally and vertically. - return new Point2d( - this.xcenter + bx * this.frame.canvas.clientWidth, - this.ycenter - by * this.frame.canvas.clientWidth); - }; - - /** - * Set the background styling for the graph - * @param {string | {fill: string, stroke: string, strokeWidth: string}} backgroundColor - */ - Graph3d.prototype._setBackgroundColor = function(backgroundColor) { - var fill = 'white'; - var stroke = 'gray'; - var strokeWidth = 1; - - if (typeof(backgroundColor) === 'string') { - fill = backgroundColor; - stroke = 'none'; - strokeWidth = 0; - } - else if (typeof(backgroundColor) === 'object') { - if (backgroundColor.fill !== undefined) fill = backgroundColor.fill; - if (backgroundColor.stroke !== undefined) stroke = backgroundColor.stroke; - if (backgroundColor.strokeWidth !== undefined) strokeWidth = backgroundColor.strokeWidth; - } - else if (backgroundColor === undefined) { - // use use defaults - } - else { - throw 'Unsupported type of backgroundColor'; - } - - this.frame.style.backgroundColor = fill; - this.frame.style.borderColor = stroke; - this.frame.style.borderWidth = strokeWidth + 'px'; - this.frame.style.borderStyle = 'solid'; - }; - - - /// enumerate the available styles - Graph3d.STYLE = { - BAR: 0, - BARCOLOR: 1, - BARSIZE: 2, - DOT : 3, - DOTLINE : 4, - DOTCOLOR: 5, - DOTSIZE: 6, - GRID : 7, - LINE: 8, - SURFACE : 9 - }; - - /** - * Retrieve the style index from given styleName - * @param {string} styleName Style name such as 'dot', 'grid', 'dot-line' - * @return {Number} styleNumber Enumeration value representing the style, or -1 - * when not found - */ - Graph3d.prototype._getStyleNumber = function(styleName) { - switch (styleName) { - case 'dot': return Graph3d.STYLE.DOT; - case 'dot-line': return Graph3d.STYLE.DOTLINE; - case 'dot-color': return Graph3d.STYLE.DOTCOLOR; - case 'dot-size': return Graph3d.STYLE.DOTSIZE; - case 'line': return Graph3d.STYLE.LINE; - case 'grid': return Graph3d.STYLE.GRID; - case 'surface': return Graph3d.STYLE.SURFACE; - case 'bar': return Graph3d.STYLE.BAR; - case 'bar-color': return Graph3d.STYLE.BARCOLOR; - case 'bar-size': return Graph3d.STYLE.BARSIZE; - } - - return -1; - }; - - /** - * Determine the indexes of the data columns, based on the given style and data - * @param {DataSet} data - * @param {Number} style - */ - Graph3d.prototype._determineColumnIndexes = function(data, style) { - if (this.style === Graph3d.STYLE.DOT || - this.style === Graph3d.STYLE.DOTLINE || - this.style === Graph3d.STYLE.LINE || - this.style === Graph3d.STYLE.GRID || - this.style === Graph3d.STYLE.SURFACE || - this.style === Graph3d.STYLE.BAR) { - // 3 columns expected, and optionally a 4th with filter values - this.colX = 0; - this.colY = 1; - this.colZ = 2; - this.colValue = undefined; - - if (data.getNumberOfColumns() > 3) { - this.colFilter = 3; - } - } - else if (this.style === Graph3d.STYLE.DOTCOLOR || - this.style === Graph3d.STYLE.DOTSIZE || - this.style === Graph3d.STYLE.BARCOLOR || - this.style === Graph3d.STYLE.BARSIZE) { - // 4 columns expected, and optionally a 5th with filter values - this.colX = 0; - this.colY = 1; - this.colZ = 2; - this.colValue = 3; - - if (data.getNumberOfColumns() > 4) { - this.colFilter = 4; - } - } - else { - throw 'Unknown style "' + this.style + '"'; - } - }; - - Graph3d.prototype.getNumberOfRows = function(data) { - return data.length; - } - - - Graph3d.prototype.getNumberOfColumns = function(data) { - var counter = 0; - for (var column in data[0]) { - if (data[0].hasOwnProperty(column)) { - counter++; - } - } - return counter; - } - - - Graph3d.prototype.getDistinctValues = function(data, column) { - var distinctValues = []; - for (var i = 0; i < data.length; i++) { - if (distinctValues.indexOf(data[i][column]) == -1) { - distinctValues.push(data[i][column]); - } - } - return distinctValues; - } - - - Graph3d.prototype.getColumnRange = function(data,column) { - var minMax = {min:data[0][column],max:data[0][column]}; - for (var i = 0; i < data.length; i++) { - if (minMax.min > data[i][column]) { minMax.min = data[i][column]; } - if (minMax.max < data[i][column]) { minMax.max = data[i][column]; } - } - return minMax; - }; - - /** - * Initialize the data from the data table. Calculate minimum and maximum values - * and column index values - * @param {Array | DataSet | DataView} rawData The data containing the items for the Graph. - * @param {Number} style Style Number - */ - Graph3d.prototype._dataInitialize = function (rawData, style) { - var me = this; - - // unsubscribe from the dataTable - if (this.dataSet) { - this.dataSet.off('*', this._onChange); - } - - if (rawData === undefined) - return; - - if (Array.isArray(rawData)) { - rawData = new DataSet(rawData); - } - - var data; - if (rawData instanceof DataSet || rawData instanceof DataView) { - data = rawData.get(); - } - else { - throw new Error('Array, DataSet, or DataView expected'); - } - - if (data.length == 0) - return; - - this.dataSet = rawData; - this.dataTable = data; - - // subscribe to changes in the dataset - this._onChange = function () { - me.setData(me.dataSet); - }; - this.dataSet.on('*', this._onChange); - - // _determineColumnIndexes - // getNumberOfRows (points) - // getNumberOfColumns (x,y,z,v,t,t1,t2...) - // getDistinctValues (unique values?) - // getColumnRange - - // determine the location of x,y,z,value,filter columns - this.colX = 'x'; - this.colY = 'y'; - this.colZ = 'z'; - this.colValue = 'style'; - this.colFilter = 'filter'; - - - - // check if a filter column is provided - if (data[0].hasOwnProperty('filter')) { - if (this.dataFilter === undefined) { - this.dataFilter = new Filter(rawData, this.colFilter, this); - this.dataFilter.setOnLoadCallback(function() {me.redraw();}); - } - } - - - var withBars = this.style == Graph3d.STYLE.BAR || - this.style == Graph3d.STYLE.BARCOLOR || - this.style == Graph3d.STYLE.BARSIZE; - - // determine barWidth from data - if (withBars) { - if (this.defaultXBarWidth !== undefined) { - this.xBarWidth = this.defaultXBarWidth; - } - else { - var dataX = this.getDistinctValues(data,this.colX); - this.xBarWidth = (dataX[1] - dataX[0]) || 1; - } - - if (this.defaultYBarWidth !== undefined) { - this.yBarWidth = this.defaultYBarWidth; - } - else { - var dataY = this.getDistinctValues(data,this.colY); - this.yBarWidth = (dataY[1] - dataY[0]) || 1; - } - } - - // calculate minimums and maximums - var xRange = this.getColumnRange(data,this.colX); - if (withBars) { - xRange.min -= this.xBarWidth / 2; - xRange.max += this.xBarWidth / 2; - } - this.xMin = (this.defaultXMin !== undefined) ? this.defaultXMin : xRange.min; - this.xMax = (this.defaultXMax !== undefined) ? this.defaultXMax : xRange.max; - if (this.xMax <= this.xMin) this.xMax = this.xMin + 1; - this.xStep = (this.defaultXStep !== undefined) ? this.defaultXStep : (this.xMax-this.xMin)/5; - - var yRange = this.getColumnRange(data,this.colY); - if (withBars) { - yRange.min -= this.yBarWidth / 2; - yRange.max += this.yBarWidth / 2; - } - this.yMin = (this.defaultYMin !== undefined) ? this.defaultYMin : yRange.min; - this.yMax = (this.defaultYMax !== undefined) ? this.defaultYMax : yRange.max; - if (this.yMax <= this.yMin) this.yMax = this.yMin + 1; - this.yStep = (this.defaultYStep !== undefined) ? this.defaultYStep : (this.yMax-this.yMin)/5; - - var zRange = this.getColumnRange(data,this.colZ); - this.zMin = (this.defaultZMin !== undefined) ? this.defaultZMin : zRange.min; - this.zMax = (this.defaultZMax !== undefined) ? this.defaultZMax : zRange.max; - if (this.zMax <= this.zMin) this.zMax = this.zMin + 1; - this.zStep = (this.defaultZStep !== undefined) ? this.defaultZStep : (this.zMax-this.zMin)/5; - - if (this.colValue !== undefined) { - var valueRange = this.getColumnRange(data,this.colValue); - this.valueMin = (this.defaultValueMin !== undefined) ? this.defaultValueMin : valueRange.min; - this.valueMax = (this.defaultValueMax !== undefined) ? this.defaultValueMax : valueRange.max; - if (this.valueMax <= this.valueMin) this.valueMax = this.valueMin + 1; - } - - // set the scale dependent on the ranges. - this._setScale(); - }; - - - - /** - * Filter the data based on the current filter - * @param {Array} data - * @return {Array} dataPoints Array with point objects which can be drawn on screen - */ - Graph3d.prototype._getDataPoints = function (data) { - // TODO: store the created matrix dataPoints in the filters instead of reloading each time - var x, y, i, z, obj, point; - - var dataPoints = []; - - if (this.style === Graph3d.STYLE.GRID || - this.style === Graph3d.STYLE.SURFACE) { - // copy all values from the google data table to a matrix - // the provided values are supposed to form a grid of (x,y) positions - - // create two lists with all present x and y values - var dataX = []; - var dataY = []; - for (i = 0; i < this.getNumberOfRows(data); i++) { - x = data[i][this.colX] || 0; - y = data[i][this.colY] || 0; - - if (dataX.indexOf(x) === -1) { - dataX.push(x); - } - if (dataY.indexOf(y) === -1) { - dataY.push(y); - } - } - - var sortNumber = function (a, b) { - return a - b; - }; - dataX.sort(sortNumber); - dataY.sort(sortNumber); - - // create a grid, a 2d matrix, with all values. - var dataMatrix = []; // temporary data matrix - for (i = 0; i < data.length; i++) { - x = data[i][this.colX] || 0; - y = data[i][this.colY] || 0; - z = data[i][this.colZ] || 0; - - var xIndex = dataX.indexOf(x); // TODO: implement Array().indexOf() for Internet Explorer - var yIndex = dataY.indexOf(y); - - if (dataMatrix[xIndex] === undefined) { - dataMatrix[xIndex] = []; - } - - var point3d = new Point3d(); - point3d.x = x; - point3d.y = y; - point3d.z = z; - - obj = {}; - obj.point = point3d; - obj.trans = undefined; - obj.screen = undefined; - obj.bottom = new Point3d(x, y, this.zMin); - - dataMatrix[xIndex][yIndex] = obj; - - dataPoints.push(obj); - } - - // fill in the pointers to the neighbors. - for (x = 0; x < dataMatrix.length; x++) { - for (y = 0; y < dataMatrix[x].length; y++) { - if (dataMatrix[x][y]) { - dataMatrix[x][y].pointRight = (x < dataMatrix.length-1) ? dataMatrix[x+1][y] : undefined; - dataMatrix[x][y].pointTop = (y < dataMatrix[x].length-1) ? dataMatrix[x][y+1] : undefined; - dataMatrix[x][y].pointCross = - (x < dataMatrix.length-1 && y < dataMatrix[x].length-1) ? - dataMatrix[x+1][y+1] : - undefined; - } - } - } - } - else { // 'dot', 'dot-line', etc. - // copy all values from the google data table to a list with Point3d objects - for (i = 0; i < data.length; i++) { - point = new Point3d(); - point.x = data[i][this.colX] || 0; - point.y = data[i][this.colY] || 0; - point.z = data[i][this.colZ] || 0; - - if (this.colValue !== undefined) { - point.value = data[i][this.colValue] || 0; - } - - obj = {}; - obj.point = point; - obj.bottom = new Point3d(point.x, point.y, this.zMin); - obj.trans = undefined; - obj.screen = undefined; - - dataPoints.push(obj); - } - } - - return dataPoints; - }; - - /** - * Create the main frame for the Graph3d. - * This function is executed once when a Graph3d object is created. The frame - * contains a canvas, and this canvas contains all objects like the axis and - * nodes. - */ - Graph3d.prototype.create = function () { - // remove all elements from the container element. - while (this.containerElement.hasChildNodes()) { - this.containerElement.removeChild(this.containerElement.firstChild); - } - - this.frame = document.createElement('div'); - this.frame.style.position = 'relative'; - this.frame.style.overflow = 'hidden'; - - // create the graph canvas (HTML canvas element) - this.frame.canvas = document.createElement( 'canvas' ); - this.frame.canvas.style.position = 'relative'; - this.frame.appendChild(this.frame.canvas); - //if (!this.frame.canvas.getContext) { - { - var noCanvas = document.createElement( 'DIV' ); - noCanvas.style.color = 'red'; - noCanvas.style.fontWeight = 'bold' ; - noCanvas.style.padding = '10px'; - noCanvas.innerHTML = 'Error: your browser does not support HTML canvas'; - this.frame.canvas.appendChild(noCanvas); - } - - this.frame.filter = document.createElement( 'div' ); - this.frame.filter.style.position = 'absolute'; - this.frame.filter.style.bottom = '0px'; - this.frame.filter.style.left = '0px'; - this.frame.filter.style.width = '100%'; - this.frame.appendChild(this.frame.filter); - - // add event listeners to handle moving and zooming the contents - var me = this; - var onmousedown = function (event) {me._onMouseDown(event);}; - var ontouchstart = function (event) {me._onTouchStart(event);}; - var onmousewheel = function (event) {me._onWheel(event);}; - var ontooltip = function (event) {me._onTooltip(event);}; - // TODO: these events are never cleaned up... can give a 'memory leakage' - - util.addEventListener(this.frame.canvas, 'keydown', onkeydown); - util.addEventListener(this.frame.canvas, 'mousedown', onmousedown); - util.addEventListener(this.frame.canvas, 'touchstart', ontouchstart); - util.addEventListener(this.frame.canvas, 'mousewheel', onmousewheel); - util.addEventListener(this.frame.canvas, 'mousemove', ontooltip); - - // add the new graph to the container element - this.containerElement.appendChild(this.frame); - }; - - - /** - * Set a new size for the graph - * @param {string} width Width in pixels or percentage (for example '800px' - * or '50%') - * @param {string} height Height in pixels or percentage (for example '400px' - * or '30%') - */ - Graph3d.prototype.setSize = function(width, height) { - this.frame.style.width = width; - this.frame.style.height = height; - - this._resizeCanvas(); - }; - - /** - * Resize the canvas to the current size of the frame - */ - Graph3d.prototype._resizeCanvas = function() { - this.frame.canvas.style.width = '100%'; - this.frame.canvas.style.height = '100%'; - - this.frame.canvas.width = this.frame.canvas.clientWidth; - this.frame.canvas.height = this.frame.canvas.clientHeight; - - // adjust with for margin - this.frame.filter.style.width = (this.frame.canvas.clientWidth - 2 * 10) + 'px'; - }; - - /** - * Start animation - */ - Graph3d.prototype.animationStart = function() { - if (!this.frame.filter || !this.frame.filter.slider) - throw 'No animation available'; - - this.frame.filter.slider.play(); - }; - - - /** - * Stop animation - */ - Graph3d.prototype.animationStop = function() { - if (!this.frame.filter || !this.frame.filter.slider) return; - - this.frame.filter.slider.stop(); - }; - - - /** - * Resize the center position based on the current values in this.defaultXCenter - * and this.defaultYCenter (which are strings with a percentage or a value - * in pixels). The center positions are the variables this.xCenter - * and this.yCenter - */ - Graph3d.prototype._resizeCenter = function() { - // calculate the horizontal center position - if (this.defaultXCenter.charAt(this.defaultXCenter.length-1) === '%') { - this.xcenter = - parseFloat(this.defaultXCenter) / 100 * - this.frame.canvas.clientWidth; - } - else { - this.xcenter = parseFloat(this.defaultXCenter); // supposed to be in px - } - - // calculate the vertical center position - if (this.defaultYCenter.charAt(this.defaultYCenter.length-1) === '%') { - this.ycenter = - parseFloat(this.defaultYCenter) / 100 * - (this.frame.canvas.clientHeight - this.frame.filter.clientHeight); - } - else { - this.ycenter = parseFloat(this.defaultYCenter); // supposed to be in px - } - }; - - /** - * Set the rotation and distance of the camera - * @param {Object} pos An object with the camera position. The object - * contains three parameters: - * - horizontal {Number} - * The horizontal rotation, between 0 and 2*PI. - * Optional, can be left undefined. - * - vertical {Number} - * The vertical rotation, between 0 and 0.5*PI - * if vertical=0.5*PI, the graph is shown from the - * top. Optional, can be left undefined. - * - distance {Number} - * The (normalized) distance of the camera to the - * center of the graph, a value between 0.71 and 5.0. - * Optional, can be left undefined. - */ - Graph3d.prototype.setCameraPosition = function(pos) { - if (pos === undefined) { - return; - } - - if (pos.horizontal !== undefined && pos.vertical !== undefined) { - this.camera.setArmRotation(pos.horizontal, pos.vertical); - } - - if (pos.distance !== undefined) { - this.camera.setArmLength(pos.distance); - } - - this.redraw(); - }; - - - /** - * Retrieve the current camera rotation - * @return {object} An object with parameters horizontal, vertical, and - * distance - */ - Graph3d.prototype.getCameraPosition = function() { - var pos = this.camera.getArmRotation(); - pos.distance = this.camera.getArmLength(); - return pos; - }; - - /** - * Load data into the 3D Graph - */ - Graph3d.prototype._readData = function(data) { - // read the data - this._dataInitialize(data, this.style); - - - if (this.dataFilter) { - // apply filtering - this.dataPoints = this.dataFilter._getDataPoints(); - } - else { - // no filtering. load all data - this.dataPoints = this._getDataPoints(this.dataTable); - } - - // draw the filter - this._redrawFilter(); - }; - - /** - * Replace the dataset of the Graph3d - * @param {Array | DataSet | DataView} data - */ - Graph3d.prototype.setData = function (data) { - this._readData(data); - this.redraw(); - - // start animation when option is true - if (this.animationAutoStart && this.dataFilter) { - this.animationStart(); - } - }; - - /** - * Update the options. Options will be merged with current options - * @param {Object} options - */ - Graph3d.prototype.setOptions = function (options) { - var cameraPosition = undefined; - - this.animationStop(); - - if (options !== undefined) { - // retrieve parameter values - if (options.width !== undefined) this.width = options.width; - if (options.height !== undefined) this.height = options.height; - - if (options.xCenter !== undefined) this.defaultXCenter = options.xCenter; - if (options.yCenter !== undefined) this.defaultYCenter = options.yCenter; - - if (options.filterLabel !== undefined) this.filterLabel = options.filterLabel; - if (options.legendLabel !== undefined) this.legendLabel = options.legendLabel; - if (options.xLabel !== undefined) this.xLabel = options.xLabel; - if (options.yLabel !== undefined) this.yLabel = options.yLabel; - if (options.zLabel !== undefined) this.zLabel = options.zLabel; - - if (options.xValueLabel !== undefined) this.xValueLabel = options.xValueLabel; - if (options.yValueLabel !== undefined) this.yValueLabel = options.yValueLabel; - if (options.zValueLabel !== undefined) this.zValueLabel = options.zValueLabel; - - if (options.style !== undefined) { - var styleNumber = this._getStyleNumber(options.style); - if (styleNumber !== -1) { - this.style = styleNumber; - } - } - if (options.showGrid !== undefined) this.showGrid = options.showGrid; - if (options.showPerspective !== undefined) this.showPerspective = options.showPerspective; - if (options.showShadow !== undefined) this.showShadow = options.showShadow; - if (options.tooltip !== undefined) this.showTooltip = options.tooltip; - if (options.showAnimationControls !== undefined) this.showAnimationControls = options.showAnimationControls; - if (options.keepAspectRatio !== undefined) this.keepAspectRatio = options.keepAspectRatio; - if (options.verticalRatio !== undefined) this.verticalRatio = options.verticalRatio; - - if (options.animationInterval !== undefined) this.animationInterval = options.animationInterval; - if (options.animationPreload !== undefined) this.animationPreload = options.animationPreload; - if (options.animationAutoStart !== undefined)this.animationAutoStart = options.animationAutoStart; - - if (options.xBarWidth !== undefined) this.defaultXBarWidth = options.xBarWidth; - if (options.yBarWidth !== undefined) this.defaultYBarWidth = options.yBarWidth; - - if (options.xMin !== undefined) this.defaultXMin = options.xMin; - if (options.xStep !== undefined) this.defaultXStep = options.xStep; - if (options.xMax !== undefined) this.defaultXMax = options.xMax; - if (options.yMin !== undefined) this.defaultYMin = options.yMin; - if (options.yStep !== undefined) this.defaultYStep = options.yStep; - if (options.yMax !== undefined) this.defaultYMax = options.yMax; - if (options.zMin !== undefined) this.defaultZMin = options.zMin; - if (options.zStep !== undefined) this.defaultZStep = options.zStep; - if (options.zMax !== undefined) this.defaultZMax = options.zMax; - if (options.valueMin !== undefined) this.defaultValueMin = options.valueMin; - if (options.valueMax !== undefined) this.defaultValueMax = options.valueMax; - - if (options.cameraPosition !== undefined) cameraPosition = options.cameraPosition; - - if (cameraPosition !== undefined) { - this.camera.setArmRotation(cameraPosition.horizontal, cameraPosition.vertical); - this.camera.setArmLength(cameraPosition.distance); - } - else { - this.camera.setArmRotation(1.0, 0.5); - this.camera.setArmLength(1.7); - } - } - - this._setBackgroundColor(options && options.backgroundColor); - - this.setSize(this.width, this.height); - - // re-load the data - if (this.dataTable) { - this.setData(this.dataTable); - } - - // start animation when option is true - if (this.animationAutoStart && this.dataFilter) { - this.animationStart(); - } - }; - - /** - * Redraw the Graph. - */ - Graph3d.prototype.redraw = function() { - if (this.dataPoints === undefined) { - throw 'Error: graph data not initialized'; - } - - this._resizeCanvas(); - this._resizeCenter(); - this._redrawSlider(); - this._redrawClear(); - this._redrawAxis(); - - if (this.style === Graph3d.STYLE.GRID || - this.style === Graph3d.STYLE.SURFACE) { - this._redrawDataGrid(); - } - else if (this.style === Graph3d.STYLE.LINE) { - this._redrawDataLine(); - } - else if (this.style === Graph3d.STYLE.BAR || - this.style === Graph3d.STYLE.BARCOLOR || - this.style === Graph3d.STYLE.BARSIZE) { - this._redrawDataBar(); - } - else { - // style is DOT, DOTLINE, DOTCOLOR, DOTSIZE - this._redrawDataDot(); - } - - this._redrawInfo(); - this._redrawLegend(); - }; - - /** - * Clear the canvas before redrawing - */ - Graph3d.prototype._redrawClear = function() { - var canvas = this.frame.canvas; - var ctx = canvas.getContext('2d'); - - ctx.clearRect(0, 0, canvas.width, canvas.height); - }; - - - /** - * Redraw the legend showing the colors - */ - Graph3d.prototype._redrawLegend = function() { - var y; - - if (this.style === Graph3d.STYLE.DOTCOLOR || - this.style === Graph3d.STYLE.DOTSIZE) { - - var dotSize = this.frame.clientWidth * 0.02; - - var widthMin, widthMax; - if (this.style === Graph3d.STYLE.DOTSIZE) { - widthMin = dotSize / 2; // px - widthMax = dotSize / 2 + dotSize * 2; // Todo: put this in one function - } - else { - widthMin = 20; // px - widthMax = 20; // px - } - - var height = Math.max(this.frame.clientHeight * 0.25, 100); - var top = this.margin; - var right = this.frame.clientWidth - this.margin; - var left = right - widthMax; - var bottom = top + height; - } - - var canvas = this.frame.canvas; - var ctx = canvas.getContext('2d'); - ctx.lineWidth = 1; - ctx.font = '14px arial'; // TODO: put in options - - if (this.style === Graph3d.STYLE.DOTCOLOR) { - // draw the color bar - var ymin = 0; - var ymax = height; // Todo: make height customizable - for (y = ymin; y < ymax; y++) { - var f = (y - ymin) / (ymax - ymin); - - //var width = (dotSize / 2 + (1-f) * dotSize * 2); // Todo: put this in one function - var hue = f * 240; - var color = this._hsv2rgb(hue, 1, 1); - - ctx.strokeStyle = color; - ctx.beginPath(); - ctx.moveTo(left, top + y); - ctx.lineTo(right, top + y); - ctx.stroke(); - } - - ctx.strokeStyle = this.colorAxis; - ctx.strokeRect(left, top, widthMax, height); - } - - if (this.style === Graph3d.STYLE.DOTSIZE) { - // draw border around color bar - ctx.strokeStyle = this.colorAxis; - ctx.fillStyle = this.colorDot; - ctx.beginPath(); - ctx.moveTo(left, top); - ctx.lineTo(right, top); - ctx.lineTo(right - widthMax + widthMin, bottom); - ctx.lineTo(left, bottom); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - } - - if (this.style === Graph3d.STYLE.DOTCOLOR || - this.style === Graph3d.STYLE.DOTSIZE) { - // print values along the color bar - var gridLineLen = 5; // px - var step = new StepNumber(this.valueMin, this.valueMax, (this.valueMax-this.valueMin)/5, true); - step.start(); - if (step.getCurrent() < this.valueMin) { - step.next(); - } - while (!step.end()) { - y = bottom - (step.getCurrent() - this.valueMin) / (this.valueMax - this.valueMin) * height; - - ctx.beginPath(); - ctx.moveTo(left - gridLineLen, y); - ctx.lineTo(left, y); - ctx.stroke(); - - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - ctx.fillStyle = this.colorAxis; - ctx.fillText(step.getCurrent(), left - 2 * gridLineLen, y); - - step.next(); - } - - ctx.textAlign = 'right'; - ctx.textBaseline = 'top'; - var label = this.legendLabel; - ctx.fillText(label, right, bottom + this.margin); - } - }; - - /** - * Redraw the filter - */ - Graph3d.prototype._redrawFilter = function() { - this.frame.filter.innerHTML = ''; - - if (this.dataFilter) { - var options = { - 'visible': this.showAnimationControls - }; - var slider = new Slider(this.frame.filter, options); - this.frame.filter.slider = slider; - - // TODO: css here is not nice here... - this.frame.filter.style.padding = '10px'; - //this.frame.filter.style.backgroundColor = '#EFEFEF'; - - slider.setValues(this.dataFilter.values); - slider.setPlayInterval(this.animationInterval); - - // create an event handler - var me = this; - var onchange = function () { - var index = slider.getIndex(); - - me.dataFilter.selectValue(index); - me.dataPoints = me.dataFilter._getDataPoints(); - - me.redraw(); - }; - slider.setOnChangeCallback(onchange); - } - else { - this.frame.filter.slider = undefined; - } - }; - - /** - * Redraw the slider - */ - Graph3d.prototype._redrawSlider = function() { - if ( this.frame.filter.slider !== undefined) { - this.frame.filter.slider.redraw(); - } - }; - - - /** - * Redraw common information - */ - Graph3d.prototype._redrawInfo = function() { - if (this.dataFilter) { - var canvas = this.frame.canvas; - var ctx = canvas.getContext('2d'); - - ctx.font = '14px arial'; // TODO: put in options - ctx.lineStyle = 'gray'; - ctx.fillStyle = 'gray'; - ctx.textAlign = 'left'; - ctx.textBaseline = 'top'; - - var x = this.margin; - var y = this.margin; - ctx.fillText(this.dataFilter.getLabel() + ': ' + this.dataFilter.getSelectedValue(), x, y); - } - }; - - - /** - * Redraw the axis - */ - Graph3d.prototype._redrawAxis = function() { - var canvas = this.frame.canvas, - ctx = canvas.getContext('2d'), - from, to, step, prettyStep, - text, xText, yText, zText, - offset, xOffset, yOffset, - xMin2d, xMax2d; - - // TODO: get the actual rendered style of the containerElement - //ctx.font = this.containerElement.style.font; - ctx.font = 24 / this.camera.getArmLength() + 'px arial'; - - // calculate the length for the short grid lines - var gridLenX = 0.025 / this.scale.x; - var gridLenY = 0.025 / this.scale.y; - var textMargin = 5 / this.camera.getArmLength(); // px - var armAngle = this.camera.getArmRotation().horizontal; - - // draw x-grid lines - ctx.lineWidth = 1; - prettyStep = (this.defaultXStep === undefined); - step = new StepNumber(this.xMin, this.xMax, this.xStep, prettyStep); - step.start(); - if (step.getCurrent() < this.xMin) { - step.next(); - } - while (!step.end()) { - var x = step.getCurrent(); - - if (this.showGrid) { - from = this._convert3Dto2D(new Point3d(x, this.yMin, this.zMin)); - to = this._convert3Dto2D(new Point3d(x, this.yMax, this.zMin)); - ctx.strokeStyle = this.colorGrid; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); - } - else { - from = this._convert3Dto2D(new Point3d(x, this.yMin, this.zMin)); - to = this._convert3Dto2D(new Point3d(x, this.yMin+gridLenX, this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); - - from = this._convert3Dto2D(new Point3d(x, this.yMax, this.zMin)); - to = this._convert3Dto2D(new Point3d(x, this.yMax-gridLenX, this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); - } - - yText = (Math.cos(armAngle) > 0) ? this.yMin : this.yMax; - text = this._convert3Dto2D(new Point3d(x, yText, this.zMin)); - if (Math.cos(armAngle * 2) > 0) { - ctx.textAlign = 'center'; - ctx.textBaseline = 'top'; - text.y += textMargin; - } - else if (Math.sin(armAngle * 2) < 0){ - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - } - else { - ctx.textAlign = 'left'; - ctx.textBaseline = 'middle'; - } - ctx.fillStyle = this.colorAxis; - ctx.fillText(' ' + this.xValueLabel(step.getCurrent()) + ' ', text.x, text.y); - - step.next(); - } - - // draw y-grid lines - ctx.lineWidth = 1; - prettyStep = (this.defaultYStep === undefined); - step = new StepNumber(this.yMin, this.yMax, this.yStep, prettyStep); - step.start(); - if (step.getCurrent() < this.yMin) { - step.next(); - } - while (!step.end()) { - if (this.showGrid) { - from = this._convert3Dto2D(new Point3d(this.xMin, step.getCurrent(), this.zMin)); - to = this._convert3Dto2D(new Point3d(this.xMax, step.getCurrent(), this.zMin)); - ctx.strokeStyle = this.colorGrid; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); - } - else { - from = this._convert3Dto2D(new Point3d(this.xMin, step.getCurrent(), this.zMin)); - to = this._convert3Dto2D(new Point3d(this.xMin+gridLenY, step.getCurrent(), this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); - - from = this._convert3Dto2D(new Point3d(this.xMax, step.getCurrent(), this.zMin)); - to = this._convert3Dto2D(new Point3d(this.xMax-gridLenY, step.getCurrent(), this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); - } - - xText = (Math.sin(armAngle ) > 0) ? this.xMin : this.xMax; - text = this._convert3Dto2D(new Point3d(xText, step.getCurrent(), this.zMin)); - if (Math.cos(armAngle * 2) < 0) { - ctx.textAlign = 'center'; - ctx.textBaseline = 'top'; - text.y += textMargin; - } - else if (Math.sin(armAngle * 2) > 0){ - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - } - else { - ctx.textAlign = 'left'; - ctx.textBaseline = 'middle'; - } - ctx.fillStyle = this.colorAxis; - ctx.fillText(' ' + this.yValueLabel(step.getCurrent()) + ' ', text.x, text.y); - - step.next(); - } - - // draw z-grid lines and axis - ctx.lineWidth = 1; - prettyStep = (this.defaultZStep === undefined); - step = new StepNumber(this.zMin, this.zMax, this.zStep, prettyStep); - step.start(); - if (step.getCurrent() < this.zMin) { - step.next(); - } - xText = (Math.cos(armAngle ) > 0) ? this.xMin : this.xMax; - yText = (Math.sin(armAngle ) < 0) ? this.yMin : this.yMax; - while (!step.end()) { - // TODO: make z-grid lines really 3d? - from = this._convert3Dto2D(new Point3d(xText, yText, step.getCurrent())); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(from.x - textMargin, from.y); - ctx.stroke(); - - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - ctx.fillStyle = this.colorAxis; - ctx.fillText(this.zValueLabel(step.getCurrent()) + ' ', from.x - 5, from.y); - - step.next(); - } - ctx.lineWidth = 1; - from = this._convert3Dto2D(new Point3d(xText, yText, this.zMin)); - to = this._convert3Dto2D(new Point3d(xText, yText, this.zMax)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); - - // draw x-axis - ctx.lineWidth = 1; - // line at yMin - xMin2d = this._convert3Dto2D(new Point3d(this.xMin, this.yMin, this.zMin)); - xMax2d = this._convert3Dto2D(new Point3d(this.xMax, this.yMin, this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(xMin2d.x, xMin2d.y); - ctx.lineTo(xMax2d.x, xMax2d.y); - ctx.stroke(); - // line at ymax - xMin2d = this._convert3Dto2D(new Point3d(this.xMin, this.yMax, this.zMin)); - xMax2d = this._convert3Dto2D(new Point3d(this.xMax, this.yMax, this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(xMin2d.x, xMin2d.y); - ctx.lineTo(xMax2d.x, xMax2d.y); - ctx.stroke(); - - // draw y-axis - ctx.lineWidth = 1; - // line at xMin - from = this._convert3Dto2D(new Point3d(this.xMin, this.yMin, this.zMin)); - to = this._convert3Dto2D(new Point3d(this.xMin, this.yMax, this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); - // line at xMax - from = this._convert3Dto2D(new Point3d(this.xMax, this.yMin, this.zMin)); - to = this._convert3Dto2D(new Point3d(this.xMax, this.yMax, this.zMin)); - ctx.strokeStyle = this.colorAxis; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); - - // draw x-label - var xLabel = this.xLabel; - if (xLabel.length > 0) { - yOffset = 0.1 / this.scale.y; - xText = (this.xMin + this.xMax) / 2; - yText = (Math.cos(armAngle) > 0) ? this.yMin - yOffset: this.yMax + yOffset; - text = this._convert3Dto2D(new Point3d(xText, yText, this.zMin)); - if (Math.cos(armAngle * 2) > 0) { - ctx.textAlign = 'center'; - ctx.textBaseline = 'top'; - } - else if (Math.sin(armAngle * 2) < 0){ - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - } - else { - ctx.textAlign = 'left'; - ctx.textBaseline = 'middle'; - } - ctx.fillStyle = this.colorAxis; - ctx.fillText(xLabel, text.x, text.y); - } + // default relative time thresholds + relativeTimeThresholds = { + 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 + }, - // draw y-label - var yLabel = this.yLabel; - if (yLabel.length > 0) { - xOffset = 0.1 / this.scale.x; - xText = (Math.sin(armAngle ) > 0) ? this.xMin - xOffset : this.xMax + xOffset; - yText = (this.yMin + this.yMax) / 2; - text = this._convert3Dto2D(new Point3d(xText, yText, this.zMin)); - if (Math.cos(armAngle * 2) < 0) { - ctx.textAlign = 'center'; - ctx.textBaseline = 'top'; - } - else if (Math.sin(armAngle * 2) > 0){ - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - } - else { - ctx.textAlign = 'left'; - ctx.textBaseline = 'middle'; - } - ctx.fillStyle = this.colorAxis; - ctx.fillText(yLabel, text.x, text.y); - } + // tokens to ordinalize and pad + ordinalizeTokens = 'DDD w W M D d'.split(' '), + paddedTokens = 'M D H h m s w W'.split(' '), - // draw z-label - var zLabel = this.zLabel; - if (zLabel.length > 0) { - offset = 30; // pixels. // TODO: relate to the max width of the values on the z axis? - xText = (Math.cos(armAngle ) > 0) ? this.xMin : this.xMax; - yText = (Math.sin(armAngle ) < 0) ? this.yMin : this.yMax; - zText = (this.zMin + this.zMax) / 2; - text = this._convert3Dto2D(new Point3d(xText, yText, zText)); - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - ctx.fillStyle = this.colorAxis; - ctx.fillText(zLabel, text.x - offset, text.y); - } - }; + formatTokenFunctions = { + M : function () { + return this.month() + 1; + }, + MMM : function (format) { + return this.localeData().monthsShort(this, format); + }, + MMMM : function (format) { + return this.localeData().months(this, format); + }, + D : function () { + return this.date(); + }, + DDD : function () { + return this.dayOfYear(); + }, + d : function () { + return this.day(); + }, + dd : function (format) { + return this.localeData().weekdaysMin(this, format); + }, + ddd : function (format) { + return this.localeData().weekdaysShort(this, format); + }, + dddd : function (format) { + return this.localeData().weekdays(this, format); + }, + w : function () { + return this.week(); + }, + W : function () { + return this.isoWeek(); + }, + YY : function () { + return leftZeroFill(this.year() % 100, 2); + }, + YYYY : function () { + return leftZeroFill(this.year(), 4); + }, + YYYYY : function () { + return leftZeroFill(this.year(), 5); + }, + YYYYYY : function () { + var y = this.year(), sign = y >= 0 ? '+' : '-'; + return sign + leftZeroFill(Math.abs(y), 6); + }, + gg : function () { + return leftZeroFill(this.weekYear() % 100, 2); + }, + gggg : function () { + return leftZeroFill(this.weekYear(), 4); + }, + ggggg : function () { + return leftZeroFill(this.weekYear(), 5); + }, + GG : function () { + return leftZeroFill(this.isoWeekYear() % 100, 2); + }, + GGGG : function () { + return leftZeroFill(this.isoWeekYear(), 4); + }, + GGGGG : function () { + return leftZeroFill(this.isoWeekYear(), 5); + }, + e : function () { + return this.weekday(); + }, + E : function () { + return this.isoWeekday(); + }, + a : function () { + return this.localeData().meridiem(this.hours(), this.minutes(), true); + }, + A : function () { + return this.localeData().meridiem(this.hours(), this.minutes(), false); + }, + H : function () { + return this.hours(); + }, + h : function () { + return this.hours() % 12 || 12; + }, + m : function () { + return this.minutes(); + }, + s : function () { + return this.seconds(); + }, + S : function () { + return toInt(this.milliseconds() / 100); + }, + SS : function () { + return leftZeroFill(toInt(this.milliseconds() / 10), 2); + }, + SSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + SSSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + Z : function () { + var a = this.utcOffset(), + b = '+'; + if (a < 0) { + a = -a; + b = '-'; + } + return b + leftZeroFill(toInt(a / 60), 2) + ':' + leftZeroFill(toInt(a) % 60, 2); + }, + ZZ : function () { + var a = this.utcOffset(), + b = '+'; + if (a < 0) { + a = -a; + b = '-'; + } + return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2); + }, + z : function () { + return this.zoneAbbr(); + }, + zz : function () { + return this.zoneName(); + }, + x : function () { + return this.valueOf(); + }, + X : function () { + return this.unix(); + }, + Q : function () { + return this.quarter(); + } + }, - /** - * Calculate the color based on the given value. - * @param {Number} H Hue, a value be between 0 and 360 - * @param {Number} S Saturation, a value between 0 and 1 - * @param {Number} V Value, a value between 0 and 1 - */ - Graph3d.prototype._hsv2rgb = function(H, S, V) { - var R, G, B, C, Hi, X; + deprecations = {}, - C = V * S; - Hi = Math.floor(H/60); // hi = 0,1,2,3,4,5 - X = C * (1 - Math.abs(((H/60) % 2) - 1)); + lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin'], - switch (Hi) { - case 0: R = C; G = X; B = 0; break; - case 1: R = X; G = C; B = 0; break; - case 2: R = 0; G = C; B = X; break; - case 3: R = 0; G = X; B = C; break; - case 4: R = X; G = 0; B = C; break; - case 5: R = C; G = 0; B = X; break; + updateInProgress = false; - default: R = 0; G = 0; B = 0; break; - } + // Pick the first defined of two or three arguments. dfl comes from + // default. + function dfl(a, b, c) { + 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'); + } + } - return 'RGB(' + parseInt(R*255) + ',' + parseInt(G*255) + ',' + parseInt(B*255) + ')'; - }; + function hasOwnProp(a, b) { + return hasOwnProperty.call(a, b); + } + function defaultParsingFlags() { + // We need to deep clone this object, and es5 standard is not very + // helpful. + return { + empty : false, + unusedTokens : [], + unusedInput : [], + overflow : -2, + charsLeftOver : 0, + nullInput : false, + invalidMonth : null, + invalidFormat : false, + userInvalidated : false, + iso: false + }; + } - /** - * Draw all datapoints as a grid - * This function can be used when the style is 'grid' - */ - Graph3d.prototype._redrawDataGrid = function() { - var canvas = this.frame.canvas, - ctx = canvas.getContext('2d'), - point, right, top, cross, - i, - topSideVisible, fillStyle, strokeStyle, lineWidth, - h, s, v, zAvg; + function printMsg(msg) { + if (moment.suppressDeprecationWarnings === false && + typeof console !== 'undefined' && console.warn) { + console.warn('Deprecation warning: ' + msg); + } + } + function deprecate(msg, fn) { + var firstTime = true; + return extend(function () { + if (firstTime) { + printMsg(msg); + firstTime = false; + } + return fn.apply(this, arguments); + }, fn); + } - if (this.dataPoints === undefined || this.dataPoints.length <= 0) - return; // TODO: throw exception? + function deprecateSimple(name, msg) { + if (!deprecations[name]) { + printMsg(msg); + deprecations[name] = true; + } + } - // calculate the translations and screen position of all points - for (i = 0; i < this.dataPoints.length; i++) { - var trans = this._convertPointToTranslation(this.dataPoints[i].point); - var screen = this._convertTranslationToScreen(trans); + function padToken(func, count) { + return function (a) { + return leftZeroFill(func.call(this, a), count); + }; + } + function ordinalizeToken(func, period) { + return function (a) { + return this.localeData().ordinal(func.call(this, a), period); + }; + } - this.dataPoints[i].trans = trans; - this.dataPoints[i].screen = screen; + function monthDiff(a, b) { + // difference in months + var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()), + // b is in (anchor - 1 month, anchor + 1 month) + anchor = a.clone().add(wholeMonthDiff, 'months'), + anchor2, adjust; - // calculate the translation of the point at the bottom (needed for sorting) - var transBottom = this._convertPointToTranslation(this.dataPoints[i].bottom); - this.dataPoints[i].dist = this.showPerspective ? transBottom.length() : -transBottom.z; - } + if (b - anchor < 0) { + anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor - anchor2); + } else { + anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor2 - anchor); + } - // sort the points on depth of their (x,y) position (not on z) - var sortDepth = function (a, b) { - return b.dist - a.dist; - }; - this.dataPoints.sort(sortDepth); + return -(wholeMonthDiff + adjust); + } - if (this.style === Graph3d.STYLE.SURFACE) { - for (i = 0; i < this.dataPoints.length; i++) { - point = this.dataPoints[i]; - right = this.dataPoints[i].pointRight; - top = this.dataPoints[i].pointTop; - cross = this.dataPoints[i].pointCross; + while (ordinalizeTokens.length) { + i = ordinalizeTokens.pop(); + formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i); + } + while (paddedTokens.length) { + i = paddedTokens.pop(); + formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); + } + formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); - if (point !== undefined && right !== undefined && top !== undefined && cross !== undefined) { - if (this.showGrayBottom || this.showShadow) { - // calculate the cross product of the two vectors from center - // to left and right, in order to know whether we are looking at the - // bottom or at the top side. We can also use the cross product - // for calculating light intensity - var aDiff = Point3d.subtract(cross.trans, point.trans); - var bDiff = Point3d.subtract(top.trans, right.trans); - var crossproduct = Point3d.crossProduct(aDiff, bDiff); - var len = crossproduct.length(); - // FIXME: there is a bug with determining the surface side (shadow or colored) + function meridiemFixWrap(locale, hour, meridiem) { + var isPm; - topSideVisible = (crossproduct.z > 0); + if (meridiem == null) { + // nothing to do + return hour; } - else { - topSideVisible = true; + if (locale.meridiemHour != null) { + return locale.meridiemHour(hour, meridiem); + } else if (locale.isPM != null) { + // Fallback + isPm = locale.isPM(meridiem); + if (isPm && hour < 12) { + hour += 12; + } + if (!isPm && hour === 12) { + hour = 0; + } + return hour; + } else { + // thie is not supposed to happen + return hour; } + } - if (topSideVisible) { - // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 - zAvg = (point.point.z + right.point.z + top.point.z + cross.point.z) / 4; - h = (1 - (zAvg - this.zMin) * this.scale.z / this.verticalRatio) * 240; - s = 1; // saturation - - if (this.showShadow) { - v = Math.min(1 + (crossproduct.x / len) / 2, 1); // value. TODO: scale - fillStyle = this._hsv2rgb(h, s, v); - strokeStyle = fillStyle; - } - else { - v = 1; - fillStyle = this._hsv2rgb(h, s, v); - strokeStyle = this.colorAxis; - } - } - else { - fillStyle = 'gray'; - strokeStyle = this.colorAxis; - } - lineWidth = 0.5; + /************************************ + Constructors + ************************************/ - ctx.lineWidth = lineWidth; - ctx.fillStyle = fillStyle; - ctx.strokeStyle = strokeStyle; - ctx.beginPath(); - ctx.moveTo(point.screen.x, point.screen.y); - ctx.lineTo(right.screen.x, right.screen.y); - ctx.lineTo(cross.screen.x, cross.screen.y); - ctx.lineTo(top.screen.x, top.screen.y); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - } + function Locale() { } - } - else { // grid style - for (i = 0; i < this.dataPoints.length; i++) { - point = this.dataPoints[i]; - right = this.dataPoints[i].pointRight; - top = this.dataPoints[i].pointTop; - if (point !== undefined) { - if (this.showPerspective) { - lineWidth = 2 / -point.trans.z; + // Moment prototype object + function Moment(config, skipOverflow) { + if (skipOverflow !== false) { + checkOverflow(config); } - else { - lineWidth = 2 * -(this.eye.z / this.camera.getArmLength()); + copyConfig(this, config); + this._d = new Date(+config._d); + // Prevent infinite loop in case updateOffset creates new moment + // objects. + if (updateInProgress === false) { + updateInProgress = true; + moment.updateOffset(this); + updateInProgress = false; } - } + } - if (point !== undefined && right !== undefined) { - // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 - zAvg = (point.point.z + right.point.z) / 2; - h = (1 - (zAvg - this.zMin) * this.scale.z / this.verticalRatio) * 240; + // Duration Constructor + function Duration(duration) { + var normalizedInput = normalizeObjectUnits(duration), + years = normalizedInput.year || 0, + quarters = normalizedInput.quarter || 0, + months = normalizedInput.month || 0, + weeks = normalizedInput.week || 0, + days = normalizedInput.day || 0, + hours = normalizedInput.hour || 0, + minutes = normalizedInput.minute || 0, + seconds = normalizedInput.second || 0, + milliseconds = normalizedInput.millisecond || 0; - ctx.lineWidth = lineWidth; - ctx.strokeStyle = this._hsv2rgb(h, 1, 1); - ctx.beginPath(); - ctx.moveTo(point.screen.x, point.screen.y); - ctx.lineTo(right.screen.x, right.screen.y); - ctx.stroke(); - } + // representation for dateAddRemove + this._milliseconds = +milliseconds + + seconds * 1e3 + // 1000 + minutes * 6e4 + // 1000 * 60 + hours * 36e5; // 1000 * 60 * 60 + // Because of dateAddRemove treats 24 hours as different from a + // day when working around DST, we need to store them separately + this._days = +days + + weeks * 7; + // It is impossible translate months into days without knowing + // which months you are are talking about, so we have to store + // it separately. + this._months = +months + + quarters * 3 + + years * 12; - if (point !== undefined && top !== undefined) { - // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 - zAvg = (point.point.z + top.point.z) / 2; - h = (1 - (zAvg - this.zMin) * this.scale.z / this.verticalRatio) * 240; + this._data = {}; - ctx.lineWidth = lineWidth; - ctx.strokeStyle = this._hsv2rgb(h, 1, 1); - ctx.beginPath(); - ctx.moveTo(point.screen.x, point.screen.y); - ctx.lineTo(top.screen.x, top.screen.y); - ctx.stroke(); - } + this._locale = moment.localeData(); + + this._bubble(); } - } - }; + /************************************ + Helpers + ************************************/ - /** - * Draw all datapoints as dots. - * This function can be used when the style is 'dot' or 'dot-line' - */ - Graph3d.prototype._redrawDataDot = function() { - var canvas = this.frame.canvas; - var ctx = canvas.getContext('2d'); - var i; - if (this.dataPoints === undefined || this.dataPoints.length <= 0) - return; // TODO: throw exception? + function extend(a, b) { + for (var i in b) { + if (hasOwnProp(b, i)) { + a[i] = b[i]; + } + } - // calculate the translations of all points - for (i = 0; i < this.dataPoints.length; i++) { - var trans = this._convertPointToTranslation(this.dataPoints[i].point); - var screen = this._convertTranslationToScreen(trans); - this.dataPoints[i].trans = trans; - this.dataPoints[i].screen = screen; + if (hasOwnProp(b, 'toString')) { + a.toString = b.toString; + } - // calculate the distance from the point at the bottom to the camera - var transBottom = this._convertPointToTranslation(this.dataPoints[i].bottom); - this.dataPoints[i].dist = this.showPerspective ? transBottom.length() : -transBottom.z; - } + if (hasOwnProp(b, 'valueOf')) { + a.valueOf = b.valueOf; + } - // order the translated points by depth - var sortDepth = function (a, b) { - return b.dist - a.dist; - }; - this.dataPoints.sort(sortDepth); + return a; + } - // draw the datapoints as colored circles - var dotSize = this.frame.clientWidth * 0.02; // px - for (i = 0; i < this.dataPoints.length; i++) { - var point = this.dataPoints[i]; + function copyConfig(to, from) { + var i, prop, val; - if (this.style === Graph3d.STYLE.DOTLINE) { - // draw a vertical line from the bottom to the graph value - //var from = this._convert3Dto2D(new Point3d(point.point.x, point.point.y, this.zMin)); - var from = this._convert3Dto2D(point.bottom); - ctx.lineWidth = 1; - ctx.strokeStyle = this.colorGrid; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(point.screen.x, point.screen.y); - ctx.stroke(); - } + 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; + } - // calculate radius for the circle - var size; - if (this.style === Graph3d.STYLE.DOTSIZE) { - size = dotSize/2 + 2*dotSize * (point.point.value - this.valueMin) / (this.valueMax - this.valueMin); - } - else { - size = dotSize; - } + if (momentProperties.length > 0) { + for (i in momentProperties) { + prop = momentProperties[i]; + val = from[prop]; + if (typeof val !== 'undefined') { + to[prop] = val; + } + } + } - var radius; - if (this.showPerspective) { - radius = size / -point.trans.z; - } - else { - radius = size * -(this.eye.z / this.camera.getArmLength()); - } - if (radius < 0) { - radius = 0; + return to; } - var hue, color, borderColor; - if (this.style === Graph3d.STYLE.DOTCOLOR ) { - // calculate the color based on the value - hue = (1 - (point.point.value - this.valueMin) * this.scale.value) * 240; - color = this._hsv2rgb(hue, 1, 1); - borderColor = this._hsv2rgb(hue, 1, 0.8); - } - else if (this.style === Graph3d.STYLE.DOTSIZE) { - color = this.colorDot; - borderColor = this.colorDotBorder; - } - else { - // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 - hue = (1 - (point.point.z - this.zMin) * this.scale.z / this.verticalRatio) * 240; - color = this._hsv2rgb(hue, 1, 1); - borderColor = this._hsv2rgb(hue, 1, 0.8); + function absRound(number) { + if (number < 0) { + return Math.ceil(number); + } else { + return Math.floor(number); + } } - // draw the circle - ctx.lineWidth = 1.0; - ctx.strokeStyle = borderColor; - ctx.fillStyle = color; - ctx.beginPath(); - ctx.arc(point.screen.x, point.screen.y, radius, 0, Math.PI*2, true); - ctx.fill(); - ctx.stroke(); - } - }; - - /** - * Draw all datapoints as bars. - * This function can be used when the style is 'bar', 'bar-color', or 'bar-size' - */ - Graph3d.prototype._redrawDataBar = function() { - var canvas = this.frame.canvas; - var ctx = canvas.getContext('2d'); - var i, j, surface, corners; - - if (this.dataPoints === undefined || this.dataPoints.length <= 0) - return; // TODO: throw exception? + // left zero fill a number + // see http://jsperf.com/left-zero-filling for performance comparison + function leftZeroFill(number, targetLength, forceSign) { + var output = '' + Math.abs(number), + sign = number >= 0; - // calculate the translations of all points - for (i = 0; i < this.dataPoints.length; i++) { - var trans = this._convertPointToTranslation(this.dataPoints[i].point); - var screen = this._convertTranslationToScreen(trans); - this.dataPoints[i].trans = trans; - this.dataPoints[i].screen = screen; + while (output.length < targetLength) { + output = '0' + output; + } + return (sign ? (forceSign ? '+' : '') : '-') + output; + } - // calculate the distance from the point at the bottom to the camera - var transBottom = this._convertPointToTranslation(this.dataPoints[i].bottom); - this.dataPoints[i].dist = this.showPerspective ? transBottom.length() : -transBottom.z; - } + function positiveMomentsDifference(base, other) { + var res = {milliseconds: 0, months: 0}; - // order the translated points by depth - var sortDepth = function (a, b) { - return b.dist - a.dist; - }; - this.dataPoints.sort(sortDepth); + res.months = other.month() - base.month() + + (other.year() - base.year()) * 12; + if (base.clone().add(res.months, 'M').isAfter(other)) { + --res.months; + } - // draw the datapoints as bars - var xWidth = this.xBarWidth / 2; - var yWidth = this.yBarWidth / 2; - for (i = 0; i < this.dataPoints.length; i++) { - var point = this.dataPoints[i]; + res.milliseconds = +other - +(base.clone().add(res.months, 'M')); - // determine color - var hue, color, borderColor; - if (this.style === Graph3d.STYLE.BARCOLOR ) { - // calculate the color based on the value - hue = (1 - (point.point.value - this.valueMin) * this.scale.value) * 240; - color = this._hsv2rgb(hue, 1, 1); - borderColor = this._hsv2rgb(hue, 1, 0.8); - } - else if (this.style === Graph3d.STYLE.BARSIZE) { - color = this.colorDot; - borderColor = this.colorDotBorder; - } - else { - // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0 - hue = (1 - (point.point.z - this.zMin) * this.scale.z / this.verticalRatio) * 240; - color = this._hsv2rgb(hue, 1, 1); - borderColor = this._hsv2rgb(hue, 1, 0.8); + return res; } - // calculate size for the bar - if (this.style === Graph3d.STYLE.BARSIZE) { - xWidth = (this.xBarWidth / 2) * ((point.point.value - this.valueMin) / (this.valueMax - this.valueMin) * 0.8 + 0.2); - yWidth = (this.yBarWidth / 2) * ((point.point.value - this.valueMin) / (this.valueMax - this.valueMin) * 0.8 + 0.2); + 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; } - // calculate all corner points - var me = this; - var point3d = point.point; - var top = [ - {point: new Point3d(point3d.x - xWidth, point3d.y - yWidth, point3d.z)}, - {point: new Point3d(point3d.x + xWidth, point3d.y - yWidth, point3d.z)}, - {point: new Point3d(point3d.x + xWidth, point3d.y + yWidth, point3d.z)}, - {point: new Point3d(point3d.x - xWidth, point3d.y + yWidth, point3d.z)} - ]; - var bottom = [ - {point: new Point3d(point3d.x - xWidth, point3d.y - yWidth, this.zMin)}, - {point: new Point3d(point3d.x + xWidth, point3d.y - yWidth, this.zMin)}, - {point: new Point3d(point3d.x + xWidth, point3d.y + yWidth, this.zMin)}, - {point: new Point3d(point3d.x - xWidth, point3d.y + yWidth, this.zMin)} - ]; + // 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; + } - // calculate screen location of the points - top.forEach(function (obj) { - obj.screen = me._convert3Dto2D(obj.point); - }); - bottom.forEach(function (obj) { - obj.screen = me._convert3Dto2D(obj.point); - }); + val = typeof val === 'string' ? +val : val; + dur = moment.duration(val, period); + addOrSubtractDurationFromMoment(this, dur, direction); + return this; + }; + } - // create five sides, calculate both corner points and center points - var surfaces = [ - {corners: top, center: Point3d.avg(bottom[0].point, bottom[2].point)}, - {corners: [top[0], top[1], bottom[1], bottom[0]], center: Point3d.avg(bottom[1].point, bottom[0].point)}, - {corners: [top[1], top[2], bottom[2], bottom[1]], center: Point3d.avg(bottom[2].point, bottom[1].point)}, - {corners: [top[2], top[3], bottom[3], bottom[2]], center: Point3d.avg(bottom[3].point, bottom[2].point)}, - {corners: [top[3], top[0], bottom[0], bottom[3]], center: Point3d.avg(bottom[0].point, bottom[3].point)} - ]; - point.surfaces = surfaces; + function addOrSubtractDurationFromMoment(mom, duration, isAdding, updateOffset) { + var milliseconds = duration._milliseconds, + days = duration._days, + months = duration._months; + updateOffset = updateOffset == null ? true : updateOffset; - // calculate the distance of each of the surface centers to the camera - for (j = 0; j < surfaces.length; j++) { - surface = surfaces[j]; - var transCenter = this._convertPointToTranslation(surface.center); - surface.dist = this.showPerspective ? transCenter.length() : -transCenter.z; - // TODO: this dept calculation doesn't work 100% of the cases due to perspective, - // but the current solution is fast/simple and works in 99.9% of all cases - // the issue is visible in example 14, with graph.setCameraPosition({horizontal: 2.97, vertical: 0.5, distance: 0.9}) + if (milliseconds) { + mom._d.setTime(+mom._d + milliseconds * isAdding); + } + if (days) { + rawSetter(mom, 'Date', rawGetter(mom, 'Date') + days * isAdding); + } + if (months) { + rawMonthSetter(mom, rawGetter(mom, 'Month') + months * isAdding); + } + if (updateOffset) { + moment.updateOffset(mom, days || months); + } } - // order the surfaces by their (translated) depth - surfaces.sort(function (a, b) { - var diff = b.dist - a.dist; - if (diff) return diff; + // check if is an array + function isArray(input) { + return Object.prototype.toString.call(input) === '[object Array]'; + } - // if equal depth, sort the top surface last - if (a.corners === top) return 1; - if (b.corners === top) return -1; + function isDate(input) { + return Object.prototype.toString.call(input) === '[object Date]' || + input instanceof Date; + } - // both are equal - return 0; - }); + // compare two arrays, return the number of differences + function compareArrays(array1, array2, dontConvert) { + var len = Math.min(array1.length, array2.length), + lengthDiff = Math.abs(array1.length - array2.length), + diffs = 0, + i; + for (i = 0; i < len; i++) { + if ((dontConvert && array1[i] !== array2[i]) || + (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { + diffs++; + } + } + return diffs + lengthDiff; + } - // draw the ordered surfaces - ctx.lineWidth = 1; - ctx.strokeStyle = borderColor; - ctx.fillStyle = color; - // NOTE: we start at j=2 instead of j=0 as we don't need to draw the two surfaces at the backside - for (j = 2; j < surfaces.length; j++) { - surface = surfaces[j]; - corners = surface.corners; - ctx.beginPath(); - ctx.moveTo(corners[3].screen.x, corners[3].screen.y); - ctx.lineTo(corners[0].screen.x, corners[0].screen.y); - ctx.lineTo(corners[1].screen.x, corners[1].screen.y); - ctx.lineTo(corners[2].screen.x, corners[2].screen.y); - ctx.lineTo(corners[3].screen.x, corners[3].screen.y); - ctx.fill(); - ctx.stroke(); + function normalizeUnits(units) { + if (units) { + var lowered = units.toLowerCase().replace(/(.)s$/, '$1'); + units = unitAliases[units] || camelFunctions[lowered] || lowered; + } + return units; } - } - }; + function normalizeObjectUnits(inputObject) { + var normalizedInput = {}, + normalizedProp, + prop; - /** - * Draw a line through all datapoints. - * This function can be used when the style is 'line' - */ - Graph3d.prototype._redrawDataLine = function() { - var canvas = this.frame.canvas, - ctx = canvas.getContext('2d'), - point, i; + for (prop in inputObject) { + if (hasOwnProp(inputObject, prop)) { + normalizedProp = normalizeUnits(prop); + if (normalizedProp) { + normalizedInput[normalizedProp] = inputObject[prop]; + } + } + } - if (this.dataPoints === undefined || this.dataPoints.length <= 0) - return; // TODO: throw exception? + return normalizedInput; + } - // calculate the translations of all points - for (i = 0; i < this.dataPoints.length; i++) { - var trans = this._convertPointToTranslation(this.dataPoints[i].point); - var screen = this._convertTranslationToScreen(trans); + function makeList(field) { + var count, setter; - this.dataPoints[i].trans = trans; - this.dataPoints[i].screen = screen; - } + if (field.indexOf('week') === 0) { + count = 7; + setter = 'day'; + } + else if (field.indexOf('month') === 0) { + count = 12; + setter = 'month'; + } + else { + return; + } - // start the line - if (this.dataPoints.length > 0) { - point = this.dataPoints[0]; + moment[field] = function (format, index) { + var i, getter, + method = moment._locale[field], + results = []; - ctx.lineWidth = 1; // TODO: make customizable - ctx.strokeStyle = 'blue'; // TODO: make customizable - ctx.beginPath(); - ctx.moveTo(point.screen.x, point.screen.y); - } + if (typeof format === 'number') { + index = format; + format = undefined; + } - // draw the datapoints as colored circles - for (i = 1; i < this.dataPoints.length; i++) { - point = this.dataPoints[i]; - ctx.lineTo(point.screen.x, point.screen.y); - } + getter = function (i) { + var m = moment().utc().set(setter, i); + return method.call(moment._locale, m, format || ''); + }; - // finish the line - if (this.dataPoints.length > 0) { - ctx.stroke(); - } - }; + if (index != null) { + return getter(index); + } + else { + for (i = 0; i < count; i++) { + results.push(getter(i)); + } + return results; + } + }; + } - /** - * Start a moving operation inside the provided parent element - * @param {Event} event The event that occurred (required for - * retrieving the mouse position) - */ - Graph3d.prototype._onMouseDown = function(event) { - event = event || window.event; + function toInt(argumentForCoercion) { + var coercedNumber = +argumentForCoercion, + value = 0; - // check if mouse is still down (may be up when focus is lost for example - // in an iframe) - if (this.leftButtonDown) { - this._onMouseUp(event); - } + if (coercedNumber !== 0 && isFinite(coercedNumber)) { + if (coercedNumber >= 0) { + value = Math.floor(coercedNumber); + } else { + value = Math.ceil(coercedNumber); + } + } - // only react on left mouse button down - this.leftButtonDown = event.which ? (event.which === 1) : (event.button === 1); - if (!this.leftButtonDown && !this.touchDown) return; + return value; + } - // get mouse position (different code for IE and all other browsers) - this.startMouseX = getMouseX(event); - this.startMouseY = getMouseY(event); + function daysInMonth(year, month) { + return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); + } - this.startStart = new Date(this.start); - this.startEnd = new Date(this.end); - this.startArmRotation = this.camera.getArmRotation(); + function weeksInYear(year, dow, doy) { + return weekOfYear(moment([year, 11, 31 + dow - doy]), dow, doy).week; + } - this.frame.style.cursor = 'move'; + function daysInYear(year) { + return isLeapYear(year) ? 366 : 365; + } - // add event listeners to handle moving the contents - // we store the function onmousemove and onmouseup in the graph, so we can - // remove the eventlisteners lateron in the function mouseUp() - var me = this; - this.onmousemove = function (event) {me._onMouseMove(event);}; - this.onmouseup = function (event) {me._onMouseUp(event);}; - util.addEventListener(document, 'mousemove', me.onmousemove); - util.addEventListener(document, 'mouseup', me.onmouseup); - util.preventDefault(event); - }; + function isLeapYear(year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; + } + function checkOverflow(m) { + var overflow; + if (m._a && m._pf.overflow === -2) { + overflow = + m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH : + m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE : + m._a[HOUR] < 0 || m._a[HOUR] > 24 || + (m._a[HOUR] === 24 && (m._a[MINUTE] !== 0 || + m._a[SECOND] !== 0 || + m._a[MILLISECOND] !== 0)) ? HOUR : + m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE : + m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND : + m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND : + -1; - /** - * Perform moving operating. - * This function activated from within the funcion Graph.mouseDown(). - * @param {Event} event Well, eehh, the event - */ - Graph3d.prototype._onMouseMove = function (event) { - event = event || window.event; + if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { + overflow = DATE; + } - // calculate change in mouse position - var diffX = parseFloat(getMouseX(event)) - this.startMouseX; - var diffY = parseFloat(getMouseY(event)) - this.startMouseY; + m._pf.overflow = overflow; + } + } - var horizontalNew = this.startArmRotation.horizontal + diffX / 200; - var verticalNew = this.startArmRotation.vertical + diffY / 200; + function isValid(m) { + if (m._isValid == null) { + m._isValid = !isNaN(m._d.getTime()) && + m._pf.overflow < 0 && + !m._pf.empty && + !m._pf.invalidMonth && + !m._pf.nullInput && + !m._pf.invalidFormat && + !m._pf.userInvalidated; - var snapAngle = 4; // degrees - var snapValue = Math.sin(snapAngle / 360 * 2 * Math.PI); + if (m._strict) { + m._isValid = m._isValid && + m._pf.charsLeftOver === 0 && + m._pf.unusedTokens.length === 0 && + m._pf.bigHour === undefined; + } + } + return m._isValid; + } - // snap horizontally to nice angles at 0pi, 0.5pi, 1pi, 1.5pi, etc... - // the -0.001 is to take care that the vertical axis is always drawn at the left front corner - if (Math.abs(Math.sin(horizontalNew)) < snapValue) { - horizontalNew = Math.round((horizontalNew / Math.PI)) * Math.PI - 0.001; - } - if (Math.abs(Math.cos(horizontalNew)) < snapValue) { - horizontalNew = (Math.round((horizontalNew/ Math.PI - 0.5)) + 0.5) * Math.PI - 0.001; - } + function normalizeLocale(key) { + return key ? key.toLowerCase().replace('_', '-') : key; + } - // snap vertically to nice angles - if (Math.abs(Math.sin(verticalNew)) < snapValue) { - verticalNew = Math.round((verticalNew / Math.PI)) * Math.PI; - } - if (Math.abs(Math.cos(verticalNew)) < snapValue) { - verticalNew = (Math.round((verticalNew/ Math.PI - 0.5)) + 0.5) * Math.PI; - } + // 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; - this.camera.setArmRotation(horizontalNew, verticalNew); - this.redraw(); + 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; + } - // fire a cameraPositionChange event - var parameters = this.getCameraPosition(); - this.emit('cameraPositionChange', parameters); + 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]; + } - util.preventDefault(event); - }; + // Return a moment from input, that is local/utc/utcOffset equivalent to + // model. + function makeAs(input, model) { + var res, diff; + if (model._isUTC) { + res = model.clone(); + diff = (moment.isMoment(input) || isDate(input) ? + +input : +moment(input)) - (+res); + // Use low-level api, because this fn is low-level api. + res._d.setTime(+res._d + diff); + moment.updateOffset(res, false); + return res; + } else { + return moment(input).local(); + } + } + /************************************ + Locale + ************************************/ - /** - * Stop moving operating. - * This function activated from within the funcion Graph.mouseDown(). - * @param {event} event The event - */ - Graph3d.prototype._onMouseUp = function (event) { - this.frame.style.cursor = 'auto'; - this.leftButtonDown = false; - // remove event listeners here - util.removeEventListener(document, 'mousemove', this.onmousemove); - util.removeEventListener(document, 'mouseup', this.onmouseup); - util.preventDefault(event); - }; + extend(Locale.prototype, { - /** - * After having moved the mouse, a tooltip should pop up when the mouse is resting on a data point - * @param {Event} event A mouse move event - */ - Graph3d.prototype._onTooltip = function (event) { - var delay = 300; // ms - var boundingRect = this.frame.getBoundingClientRect(); - var mouseX = getMouseX(event) - boundingRect.left; - var mouseY = getMouseY(event) - boundingRect.top; + set : function (config) { + var prop, i; + for (i in config) { + prop = config[i]; + if (typeof prop === 'function') { + this[i] = prop; + } else { + this['_' + i] = prop; + } + } + // Lenient ordinal parsing accepts just a number in addition to + // number + (possibly) stuff coming from _ordinalParseLenient. + this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + /\d{1,2}/.source); + }, - if (!this.showTooltip) { - return; - } + _months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), + months : function (m) { + return this._months[m.month()]; + }, - if (this.tooltipTimeout) { - clearTimeout(this.tooltipTimeout); - } + _monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), + monthsShort : function (m) { + return this._monthsShort[m.month()]; + }, - // (delayed) display of a tooltip only if no mouse button is down - if (this.leftButtonDown) { - this._hideTooltip(); - return; - } + monthsParse : function (monthName, format, strict) { + var i, mom, regex; - if (this.tooltip && this.tooltip.dataPoint) { - // tooltip is currently visible - var dataPoint = this._dataPointFromXY(mouseX, mouseY); - if (dataPoint !== this.tooltip.dataPoint) { - // datapoint changed - if (dataPoint) { - this._showTooltip(dataPoint); - } - else { - this._hideTooltip(); - } - } - } - else { - // tooltip is currently not visible - var me = this; - this.tooltipTimeout = setTimeout(function () { - me.tooltipTimeout = null; + if (!this._monthsParse) { + this._monthsParse = []; + this._longMonthsParse = []; + this._shortMonthsParse = []; + } - // show a tooltip if we have a data point - var dataPoint = me._dataPointFromXY(mouseX, mouseY); - if (dataPoint) { - me._showTooltip(dataPoint); - } - }, delay); - } - }; + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + mom = moment.utc([2000, i]); + if (strict && !this._longMonthsParse[i]) { + this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i'); + this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i'); + } + if (!strict && !this._monthsParse[i]) { + regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); + this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) { + return i; + } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) { + return i; + } else if (!strict && this._monthsParse[i].test(monthName)) { + return i; + } + } + }, - /** - * Event handler for touchstart event on mobile devices - */ - Graph3d.prototype._onTouchStart = function(event) { - this.touchDown = true; + _weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), + weekdays : function (m) { + return this._weekdays[m.day()]; + }, - var me = this; - this.ontouchmove = function (event) {me._onTouchMove(event);}; - this.ontouchend = function (event) {me._onTouchEnd(event);}; - util.addEventListener(document, 'touchmove', me.ontouchmove); - util.addEventListener(document, 'touchend', me.ontouchend); + _weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), + weekdaysShort : function (m) { + return this._weekdaysShort[m.day()]; + }, - this._onMouseDown(event); - }; + _weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), + weekdaysMin : function (m) { + return this._weekdaysMin[m.day()]; + }, - /** - * Event handler for touchmove event on mobile devices - */ - Graph3d.prototype._onTouchMove = function(event) { - this._onMouseMove(event); - }; + weekdaysParse : function (weekdayName) { + var i, mom, regex; - /** - * Event handler for touchend event on mobile devices - */ - Graph3d.prototype._onTouchEnd = function(event) { - this.touchDown = false; + if (!this._weekdaysParse) { + this._weekdaysParse = []; + } - util.removeEventListener(document, 'touchmove', this.ontouchmove); - util.removeEventListener(document, 'touchend', this.ontouchend); + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + if (!this._weekdaysParse[i]) { + mom = moment([2000, 1]).day(i); + regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); + this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (this._weekdaysParse[i].test(weekdayName)) { + return i; + } + } + }, - this._onMouseUp(event); - }; + _longDateFormat : { + LTS : 'h:mm:ss A', + 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]; + if (!output && this._longDateFormat[key.toUpperCase()]) { + output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { + return val.slice(1); + }); + this._longDateFormat[key] = output; + } + return output; + }, + isPM : function (input) { + // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays + // Using charAt should be more compatible. + return ((input + '').toLowerCase().charAt(0) === 'p'); + }, - /** - * Event handler for mouse wheel event, used to zoom the graph - * Code from http://adomas.org/javascript-mouse-wheel/ - * @param {event} event The event - */ - Graph3d.prototype._onWheel = function(event) { - if (!event) /* For IE. */ - event = window.event; + _meridiemParse : /[ap]\.?m?\.?/i, + meridiem : function (hours, minutes, isLower) { + if (hours > 11) { + return isLower ? 'pm' : 'PM'; + } else { + return isLower ? 'am' : 'AM'; + } + }, - // retrieve delta - var delta = 0; - if (event.wheelDelta) { /* IE/Opera. */ - delta = event.wheelDelta/120; - } else if (event.detail) { /* Mozilla case. */ - // In Mozilla, sign of delta is different than in IE. - // Also, delta is multiple of 3. - delta = -event.detail/3; - } - // If delta is nonzero, handle it. - // Basically, delta is now positive if wheel was scrolled up, - // and negative, if wheel was scrolled down. - if (delta) { - var oldLength = this.camera.getArmLength(); - var newLength = oldLength * (1 - delta / 10); + _calendar : { + sameDay : '[Today at] LT', + nextDay : '[Tomorrow at] LT', + nextWeek : 'dddd [at] LT', + lastDay : '[Yesterday at] LT', + lastWeek : '[Last] dddd [at] LT', + sameElse : 'L' + }, + calendar : function (key, mom, now) { + var output = this._calendar[key]; + return typeof output === 'function' ? output.apply(mom, [now]) : output; + }, - this.camera.setArmLength(newLength); - this.redraw(); + _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' + }, - this._hideTooltip(); - } + 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); + }, - // fire a cameraPositionChange event - var parameters = this.getCameraPosition(); - this.emit('cameraPositionChange', parameters); + pastFuture : function (diff, output) { + var format = this._relativeTime[diff > 0 ? 'future' : 'past']; + return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); + }, - // Prevent default actions caused by mouse wheel. - // That might be ugly, but we handle scrolls somehow - // anyway, so don't bother here.. - util.preventDefault(event); - }; + ordinal : function (number) { + return this._ordinal.replace('%d', number); + }, + _ordinal : '%d', + _ordinalParse : /\d{1,2}/, - /** - * Test whether a point lies inside given 2D triangle - * @param {Point2d} point - * @param {Point2d[]} triangle - * @return {boolean} Returns true if given point lies inside or on the edge of the triangle - * @private - */ - Graph3d.prototype._insideTriangle = function (point, triangle) { - var a = triangle[0], - b = triangle[1], - c = triangle[2]; + preparse : function (string) { + return string; + }, - function sign (x) { - return x > 0 ? 1 : x < 0 ? -1 : 0; - } + postformat : function (string) { + return string; + }, - var as = sign((b.x - a.x) * (point.y - a.y) - (b.y - a.y) * (point.x - a.x)); - var bs = sign((c.x - b.x) * (point.y - b.y) - (c.y - b.y) * (point.x - b.x)); - var cs = sign((a.x - c.x) * (point.y - c.y) - (a.y - c.y) * (point.x - c.x)); + week : function (mom) { + return weekOfYear(mom, this._week.dow, this._week.doy).week; + }, - // each of the three signs must be either equal to each other or zero - return (as == 0 || bs == 0 || as == bs) && - (bs == 0 || cs == 0 || bs == cs) && - (as == 0 || cs == 0 || as == cs); - }; + _week : { + dow : 0, // Sunday is the first day of the week. + doy : 6 // The week that contains Jan 1st is the first week of the year. + }, - /** - * Find a data point close to given screen position (x, y) - * @param {Number} x - * @param {Number} y - * @return {Object | null} The closest data point or null if not close to any data point - * @private - */ - Graph3d.prototype._dataPointFromXY = function (x, y) { - var i, - distMax = 100, // px - dataPoint = null, - closestDataPoint = null, - closestDist = null, - center = new Point2d(x, y); + firstDayOfWeek : function () { + return this._week.dow; + }, - if (this.style === Graph3d.STYLE.BAR || - this.style === Graph3d.STYLE.BARCOLOR || - this.style === Graph3d.STYLE.BARSIZE) { - // the data points are ordered from far away to closest - for (i = this.dataPoints.length - 1; i >= 0; i--) { - dataPoint = this.dataPoints[i]; - var surfaces = dataPoint.surfaces; - if (surfaces) { - for (var s = surfaces.length - 1; s >= 0; s--) { - // split each surface in two triangles, and see if the center point is inside one of these - var surface = surfaces[s]; - var corners = surface.corners; - var triangle1 = [corners[0].screen, corners[1].screen, corners[2].screen]; - var triangle2 = [corners[2].screen, corners[3].screen, corners[0].screen]; - if (this._insideTriangle(center, triangle1) || - this._insideTriangle(center, triangle2)) { - // return immediately at the first hit - return dataPoint; - } + firstDayOfYear : function () { + return this._week.doy; + }, + + _invalidDate: 'Invalid date', + invalidDate: function () { + return this._invalidDate; } - } - } - } - else { - // find the closest data point, using distance to the center of the point on 2d screen - for (i = 0; i < this.dataPoints.length; i++) { - dataPoint = this.dataPoints[i]; - var point = dataPoint.screen; - if (point) { - var distX = Math.abs(x - point.x); - var distY = Math.abs(y - point.y); - var dist = Math.sqrt(distX * distX + distY * distY); + }); - if ((closestDist === null || dist < closestDist) && dist < distMax) { - closestDist = dist; - closestDataPoint = dataPoint; + /************************************ + Formatting + ************************************/ + + + function removeFormattingTokens(input) { + if (input.match(/\[[\s\S]/)) { + return input.replace(/^\[|\]$/g, ''); } - } + return input.replace(/\\/g, ''); } - } + function makeFormatFunction(format) { + var array = format.match(formattingTokens), i, length; - return closestDataPoint; - }; + for (i = 0, length = array.length; i < length; i++) { + if (formatTokenFunctions[array[i]]) { + array[i] = formatTokenFunctions[array[i]]; + } else { + array[i] = removeFormattingTokens(array[i]); + } + } - /** - * Display a tooltip for given data point - * @param {Object} dataPoint - * @private - */ - Graph3d.prototype._showTooltip = function (dataPoint) { - var content, line, dot; + return function (mom) { + var output = ''; + for (i = 0; i < length; i++) { + output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; + } + return output; + }; + } - if (!this.tooltip) { - content = document.createElement('div'); - content.style.position = 'absolute'; - content.style.padding = '10px'; - content.style.border = '1px solid #4d4d4d'; - content.style.color = '#1a1a1a'; - content.style.background = 'rgba(255,255,255,0.7)'; - content.style.borderRadius = '2px'; - content.style.boxShadow = '5px 5px 10px rgba(128,128,128,0.5)'; + // format date using native date object + function formatMoment(m, format) { + if (!m.isValid()) { + return m.localeData().invalidDate(); + } - line = document.createElement('div'); - line.style.position = 'absolute'; - line.style.height = '40px'; - line.style.width = '0'; - line.style.borderLeft = '1px solid #4d4d4d'; + format = expandFormat(format, m.localeData()); - dot = document.createElement('div'); - dot.style.position = 'absolute'; - dot.style.height = '0'; - dot.style.width = '0'; - dot.style.border = '5px solid #4d4d4d'; - dot.style.borderRadius = '5px'; + if (!formatFunctions[format]) { + formatFunctions[format] = makeFormatFunction(format); + } - this.tooltip = { - dataPoint: null, - dom: { - content: content, - line: line, - dot: dot - } - }; - } - else { - content = this.tooltip.dom.content; - line = this.tooltip.dom.line; - dot = this.tooltip.dom.dot; - } + return formatFunctions[format](m); + } - this._hideTooltip(); + function expandFormat(format, locale) { + var i = 5; - this.tooltip.dataPoint = dataPoint; - if (typeof this.showTooltip === 'function') { - content.innerHTML = this.showTooltip(dataPoint.point); - } - else { - content.innerHTML = '' + - '' + - '' + - '' + - '
x:' + dataPoint.point.x + '
y:' + dataPoint.point.y + '
z:' + dataPoint.point.z + '
'; - } + function replaceLongDateFormatTokens(input) { + return locale.longDateFormat(input) || input; + } - content.style.left = '0'; - content.style.top = '0'; - this.frame.appendChild(content); - this.frame.appendChild(line); - this.frame.appendChild(dot); + localFormattingTokens.lastIndex = 0; + while (i >= 0 && localFormattingTokens.test(format)) { + format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); + localFormattingTokens.lastIndex = 0; + i -= 1; + } - // calculate sizes - var contentWidth = content.offsetWidth; - var contentHeight = content.offsetHeight; - var lineHeight = line.offsetHeight; - var dotWidth = dot.offsetWidth; - var dotHeight = dot.offsetHeight; + return format; + } - var left = dataPoint.screen.x - contentWidth / 2; - left = Math.min(Math.max(left, 10), this.frame.clientWidth - 10 - contentWidth); - line.style.left = dataPoint.screen.x + 'px'; - line.style.top = (dataPoint.screen.y - lineHeight) + 'px'; - content.style.left = left + 'px'; - content.style.top = (dataPoint.screen.y - lineHeight - contentHeight) + 'px'; - dot.style.left = (dataPoint.screen.x - dotWidth / 2) + 'px'; - dot.style.top = (dataPoint.screen.y - dotHeight / 2) + 'px'; - }; + /************************************ + Parsing + ************************************/ - /** - * Hide the tooltip when displayed - * @private - */ - Graph3d.prototype._hideTooltip = function () { - if (this.tooltip) { - this.tooltip.dataPoint = null; - for (var prop in this.tooltip.dom) { - if (this.tooltip.dom.hasOwnProperty(prop)) { - var elem = this.tooltip.dom[prop]; - if (elem && elem.parentNode) { - elem.parentNode.removeChild(elem); + // get the regex to find the next token + function getParseRegexForToken(token, config) { + var a, strict = config._strict; + switch (token) { + case 'Q': + return parseTokenOneDigit; + case 'DDDD': + return parseTokenThreeDigits; + case 'YYYY': + case 'GGGG': + case 'gggg': + return strict ? parseTokenFourDigits : parseTokenOneToFourDigits; + case 'Y': + case 'G': + case 'g': + return parseTokenSignedNumber; + case 'YYYYYY': + case 'YYYYY': + case 'GGGGG': + case 'ggggg': + return strict ? parseTokenSixDigits : parseTokenOneToSixDigits; + case 'S': + if (strict) { + return parseTokenOneDigit; + } + /* falls through */ + case 'SS': + if (strict) { + return parseTokenTwoDigits; + } + /* falls through */ + case 'SSS': + if (strict) { + return parseTokenThreeDigits; + } + /* falls through */ + case 'DDD': + return parseTokenOneToThreeDigits; + case 'MMM': + case 'MMMM': + case 'dd': + case 'ddd': + case 'dddd': + return parseTokenWord; + case 'a': + case 'A': + return config._locale._meridiemParse; + case 'x': + return parseTokenOffsetMs; + case 'X': + return parseTokenTimestampMs; + case 'Z': + case 'ZZ': + return parseTokenTimezone; + case 'T': + return parseTokenT; + case 'SSSS': + return parseTokenDigits; + case 'MM': + case 'DD': + case 'YY': + case 'GG': + case 'gg': + case 'HH': + case 'hh': + case 'mm': + case 'ss': + case 'ww': + case 'WW': + return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits; + case 'M': + case 'D': + case 'd': + case 'H': + case 'h': + case 'm': + case 's': + case 'w': + case 'W': + case 'e': + case 'E': + return parseTokenOneOrTwoDigits; + case 'Do': + return strict ? config._locale._ordinalParse : config._locale._ordinalParseLenient; + default : + a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), 'i')); + return a; } - } } - } - }; - /**--------------------------------------------------------------------------**/ - - - /** - * Get the horizontal mouse position from a mouse event - * @param {Event} event - * @return {Number} mouse x - */ - function getMouseX (event) { - if ('clientX' in event) return event.clientX; - return event.targetTouches[0] && event.targetTouches[0].clientX || 0; - } + function utcOffsetFromString(string) { + string = string || ''; + var possibleTzMatches = (string.match(parseTokenTimezone) || []), + tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [], + parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0], + minutes = +(parts[1] * 60) + toInt(parts[2]); - /** - * Get the vertical mouse position from a mouse event - * @param {Event} event - * @return {Number} mouse y - */ - function getMouseY (event) { - if ('clientY' in event) return event.clientY; - return event.targetTouches[0] && event.targetTouches[0].clientY || 0; - } + return parts[0] === '+' ? minutes : -minutes; + } - module.exports = Graph3d; + // function to convert string input to date + function addTimeToArrayFromToken(token, input, config) { + var a, datePartArray = config._a; + switch (token) { + // QUARTER + case 'Q': + if (input != null) { + datePartArray[MONTH] = (toInt(input) - 1) * 3; + } + break; + // MONTH + case 'M' : // fall through to MM + case 'MM' : + if (input != null) { + datePartArray[MONTH] = toInt(input) - 1; + } + break; + case 'MMM' : // fall through to MMMM + case 'MMMM' : + a = config._locale.monthsParse(input, token, config._strict); + // if we didn't find a month name, mark the date as invalid. + if (a != null) { + datePartArray[MONTH] = a; + } else { + config._pf.invalidMonth = input; + } + break; + // DAY OF MONTH + case 'D' : // fall through to DD + case 'DD' : + if (input != null) { + datePartArray[DATE] = toInt(input); + } + break; + case 'Do' : + if (input != null) { + datePartArray[DATE] = toInt(parseInt( + input.match(/\d{1,2}/)[0], 10)); + } + break; + // DAY OF YEAR + case 'DDD' : // fall through to DDDD + case 'DDDD' : + if (input != null) { + config._dayOfYear = toInt(input); + } -/***/ }, -/* 7 */ -/***/ function(module, exports, __webpack_require__) { + break; + // YEAR + case 'YY' : + datePartArray[YEAR] = moment.parseTwoDigitYear(input); + break; + case 'YYYY' : + case 'YYYYY' : + case 'YYYYYY' : + datePartArray[YEAR] = toInt(input); + break; + // AM / PM + case 'a' : // fall through to A + case 'A' : + config._meridiem = input; + // config._isPm = config._locale.isPM(input); + break; + // HOUR + case 'h' : // fall through to hh + case 'hh' : + config._pf.bigHour = true; + /* falls through */ + case 'H' : // fall through to HH + case 'HH' : + datePartArray[HOUR] = toInt(input); + break; + // MINUTE + case 'm' : // fall through to mm + case 'mm' : + datePartArray[MINUTE] = toInt(input); + break; + // SECOND + case 's' : // fall through to ss + case 'ss' : + datePartArray[SECOND] = toInt(input); + break; + // MILLISECOND + case 'S' : + case 'SS' : + case 'SSS' : + case 'SSSS' : + datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000); + break; + // UNIX OFFSET (MILLISECONDS) + case 'x': + config._d = new Date(toInt(input)); + break; + // UNIX TIMESTAMP WITH MS + case 'X': + config._d = new Date(parseFloat(input) * 1000); + break; + // TIMEZONE + case 'Z' : // fall through to ZZ + case 'ZZ' : + config._useUTC = true; + config._tzm = utcOffsetFromString(input); + break; + // WEEKDAY - human + case 'dd': + case 'ddd': + case 'dddd': + 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 || {}; + config._w['d'] = a; + } else { + config._pf.invalidWeekday = input; + } + break; + // WEEK, WEEK DAY - numeric + case 'w': + case 'ww': + case 'W': + case 'WW': + case 'd': + case 'e': + case 'E': + token = token.substr(0, 1); + /* falls through */ + case 'gggg': + case 'GGGG': + case 'GGGGG': + token = token.substr(0, 2); + if (input) { + config._w = config._w || {}; + config._w[token] = toInt(input); + } + break; + case 'gg': + case 'GG': + config._w = config._w || {}; + config._w[token] = moment.parseTwoDigitYear(input); + } + } - var Point3d = __webpack_require__(10); + function dayOfYearFromWeekInfo(config) { + var w, weekYear, week, weekday, dow, doy, temp; - /** - * @class Camera - * The camera is mounted on a (virtual) camera arm. The camera arm can rotate - * The camera is always looking in the direction of the origin of the arm. - * This way, the camera always rotates around one fixed point, the location - * of the camera arm. - * - * Documentation: - * http://en.wikipedia.org/wiki/3D_projection - */ - function Camera() { - this.armLocation = new Point3d(); - this.armRotation = {}; - this.armRotation.horizontal = 0; - this.armRotation.vertical = 0; - this.armLength = 1.7; + w = config._w; + if (w.GG != null || w.W != null || w.E != null) { + dow = 1; + doy = 4; - this.cameraLocation = new Point3d(); - this.cameraRotation = new Point3d(0.5*Math.PI, 0, 0); + // TODO: We need to take the current isoWeekYear, but that depends on + // how we interpret now (local, utc, fixed offset). So create + // a now version of current config (take local/utc/offset flags, and + // create now). + weekYear = dfl(w.GG, config._a[YEAR], weekOfYear(moment(), 1, 4).year); + week = dfl(w.W, 1); + weekday = dfl(w.E, 1); + } else { + dow = config._locale._week.dow; + doy = config._locale._week.doy; - this.calculateCameraOrientation(); - } + weekYear = dfl(w.gg, config._a[YEAR], weekOfYear(moment(), dow, doy).year); + week = dfl(w.w, 1); - /** - * Set the location (origin) of the arm - * @param {Number} x Normalized value of x - * @param {Number} y Normalized value of y - * @param {Number} z Normalized value of z - */ - Camera.prototype.setArmLocation = function(x, y, z) { - this.armLocation.x = x; - this.armLocation.y = y; - this.armLocation.z = z; + if (w.d != null) { + // weekday -- low day numbers are considered next week + weekday = w.d; + if (weekday < dow) { + ++week; + } + } else if (w.e != null) { + // local weekday -- counting starts from begining of week + weekday = w.e + dow; + } else { + // default to begining of week + weekday = dow; + } + } + temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow); - this.calculateCameraOrientation(); - }; + config._a[YEAR] = temp.year; + config._dayOfYear = temp.dayOfYear; + } - /** - * Set the rotation of the camera arm - * @param {Number} horizontal The horizontal rotation, between 0 and 2*PI. - * Optional, can be left undefined. - * @param {Number} vertical The vertical rotation, between 0 and 0.5*PI - * if vertical=0.5*PI, the graph is shown from the - * top. Optional, can be left undefined. - */ - Camera.prototype.setArmRotation = function(horizontal, vertical) { - if (horizontal !== undefined) { - this.armRotation.horizontal = horizontal; - } + // convert an array to a date. + // the array should mirror the parameters below + // note: all values past the year are optional and will default to the lowest possible value. + // [year, month, day , hour, minute, second, millisecond] + function dateFromConfig(config) { + var i, date, input = [], currentDate, yearToUse; - if (vertical !== undefined) { - this.armRotation.vertical = vertical; - if (this.armRotation.vertical < 0) this.armRotation.vertical = 0; - if (this.armRotation.vertical > 0.5*Math.PI) this.armRotation.vertical = 0.5*Math.PI; - } + if (config._d) { + return; + } - if (horizontal !== undefined || vertical !== undefined) { - this.calculateCameraOrientation(); - } - }; + currentDate = currentDateArray(config); - /** - * Retrieve the current arm rotation - * @return {object} An object with parameters horizontal and vertical - */ - Camera.prototype.getArmRotation = function() { - var rot = {}; - rot.horizontal = this.armRotation.horizontal; - rot.vertical = this.armRotation.vertical; + //compute day of the year from weeks and weekdays + if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { + dayOfYearFromWeekInfo(config); + } - return rot; - }; + //if the day of the year is set, figure out what it is + if (config._dayOfYear) { + yearToUse = dfl(config._a[YEAR], currentDate[YEAR]); - /** - * Set the (normalized) length of the camera arm. - * @param {Number} length A length between 0.71 and 5.0 - */ - Camera.prototype.setArmLength = function(length) { - if (length === undefined) - return; + if (config._dayOfYear > daysInYear(yearToUse)) { + config._pf._overflowDayOfYear = true; + } - this.armLength = length; + date = makeUTCDate(yearToUse, 0, config._dayOfYear); + config._a[MONTH] = date.getUTCMonth(); + config._a[DATE] = date.getUTCDate(); + } - // Radius must be larger than the corner of the graph, - // which has a distance of sqrt(0.5^2+0.5^2) = 0.71 from the center of the - // graph - if (this.armLength < 0.71) this.armLength = 0.71; - if (this.armLength > 5.0) this.armLength = 5.0; + // Default to current date. + // * if no year, month, day of month are given, default to today + // * if day of month is given, default month and year + // * if month is given, default only year + // * if year is given, don't default anything + for (i = 0; i < 3 && config._a[i] == null; ++i) { + config._a[i] = input[i] = currentDate[i]; + } - this.calculateCameraOrientation(); - }; + // Zero out whatever was not defaulted, including time + for (; i < 7; i++) { + config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; + } - /** - * Retrieve the arm length - * @return {Number} length - */ - Camera.prototype.getArmLength = function() { - return this.armLength; - }; + // Check for 24:00:00.000 + if (config._a[HOUR] === 24 && + config._a[MINUTE] === 0 && + config._a[SECOND] === 0 && + config._a[MILLISECOND] === 0) { + config._nextDay = true; + config._a[HOUR] = 0; + } - /** - * Retrieve the camera location - * @return {Point3d} cameraLocation - */ - Camera.prototype.getCameraLocation = function() { - return this.cameraLocation; - }; + config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input); + // Apply timezone offset from input. The actual utcOffset can be changed + // with parseZone. + if (config._tzm != null) { + config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); + } - /** - * Retrieve the camera rotation - * @return {Point3d} cameraRotation - */ - Camera.prototype.getCameraRotation = function() { - return this.cameraRotation; - }; + if (config._nextDay) { + config._a[HOUR] = 24; + } + } - /** - * Calculate the location and rotation of the camera based on the - * position and orientation of the camera arm - */ - Camera.prototype.calculateCameraOrientation = function() { - // calculate location of the camera - this.cameraLocation.x = this.armLocation.x - this.armLength * Math.sin(this.armRotation.horizontal) * Math.cos(this.armRotation.vertical); - this.cameraLocation.y = this.armLocation.y - this.armLength * Math.cos(this.armRotation.horizontal) * Math.cos(this.armRotation.vertical); - this.cameraLocation.z = this.armLocation.z + this.armLength * Math.sin(this.armRotation.vertical); + function dateFromObject(config) { + var normalizedInput; - // calculate rotation of the camera - this.cameraRotation.x = Math.PI/2 - this.armRotation.vertical; - this.cameraRotation.y = 0; - this.cameraRotation.z = -this.armRotation.horizontal; - }; + if (config._d) { + return; + } - module.exports = Camera; + normalizedInput = normalizeObjectUnits(config._i); + config._a = [ + normalizedInput.year, + normalizedInput.month, + normalizedInput.day || normalizedInput.date, + normalizedInput.hour, + normalizedInput.minute, + normalizedInput.second, + normalizedInput.millisecond + ]; -/***/ }, -/* 8 */ -/***/ function(module, exports, __webpack_require__) { + dateFromConfig(config); + } - var DataView = __webpack_require__(4); + function currentDateArray(config) { + var now = new Date(); + if (config._useUTC) { + return [ + now.getUTCFullYear(), + now.getUTCMonth(), + now.getUTCDate() + ]; + } else { + return [now.getFullYear(), now.getMonth(), now.getDate()]; + } + } - /** - * @class Filter - * - * @param {DataSet} data The google data table - * @param {Number} column The index of the column to be filtered - * @param {Graph} graph The graph - */ - function Filter (data, column, graph) { - this.data = data; - this.column = column; - this.graph = graph; // the parent graph + // date from string and format string + function makeDateFromStringAndFormat(config) { + if (config._f === moment.ISO_8601) { + parseISO(config); + return; + } - this.index = undefined; - this.value = undefined; + config._a = []; + config._pf.empty = true; - // read all distinct values and select the first one - this.values = graph.getDistinctValues(data.get(), this.column); + // This array is used to make a Date, either with `new Date` or `Date.UTC` + var string = '' + config._i, + i, parsedInput, tokens, token, skipped, + stringLength = string.length, + totalParsedInputLength = 0; - // sort both numeric and string values correctly - this.values.sort(function (a, b) { - return a > b ? 1 : a < b ? -1 : 0; - }); + tokens = expandFormat(config._f, config._locale).match(formattingTokens) || []; - if (this.values.length > 0) { - this.selectValue(0); - } + for (i = 0; i < tokens.length; i++) { + token = tokens[i]; + parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; + if (parsedInput) { + skipped = string.substr(0, string.indexOf(parsedInput)); + if (skipped.length > 0) { + config._pf.unusedInput.push(skipped); + } + string = string.slice(string.indexOf(parsedInput) + parsedInput.length); + totalParsedInputLength += parsedInput.length; + } + // don't parse if it's not a known token + if (formatTokenFunctions[token]) { + if (parsedInput) { + config._pf.empty = false; + } + else { + config._pf.unusedTokens.push(token); + } + addTimeToArrayFromToken(token, parsedInput, config); + } + else if (config._strict && !parsedInput) { + config._pf.unusedTokens.push(token); + } + } - // create an array with the filtered datapoints. this will be loaded afterwards - this.dataPoints = []; + // add remaining unparsed input length to the string + config._pf.charsLeftOver = stringLength - totalParsedInputLength; + if (string.length > 0) { + config._pf.unusedInput.push(string); + } - this.loaded = false; - this.onLoadCallback = undefined; + // clear _12h flag if hour is <= 12 + if (config._pf.bigHour === true && config._a[HOUR] <= 12) { + config._pf.bigHour = undefined; + } + // handle meridiem + config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], + config._meridiem); + dateFromConfig(config); + checkOverflow(config); + } - if (graph.animationPreload) { - this.loaded = false; - this.loadInBackground(); - } - else { - this.loaded = true; - } - }; + function unescapeFormat(s) { + return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { + return p1 || p2 || p3 || p4; + }); + } + // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript + function regexpEscape(s) { + return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } - /** - * Return the label - * @return {string} label - */ - Filter.prototype.isLoaded = function() { - return this.loaded; - }; + // date from string and array of format strings + function makeDateFromStringAndArray(config) { + var tempConfig, + bestMoment, + scoreToBeat, + i, + currentScore; - /** - * Return the loaded progress - * @return {Number} percentage between 0 and 100 - */ - Filter.prototype.getLoadedProgress = function() { - var len = this.values.length; + if (config._f.length === 0) { + config._pf.invalidFormat = true; + config._d = new Date(NaN); + return; + } - var i = 0; - while (this.dataPoints[i]) { - i++; - } + for (i = 0; i < config._f.length; i++) { + currentScore = 0; + tempConfig = copyConfig({}, config); + if (config._useUTC != null) { + tempConfig._useUTC = config._useUTC; + } + tempConfig._pf = defaultParsingFlags(); + tempConfig._f = config._f[i]; + makeDateFromStringAndFormat(tempConfig); - return Math.round(i / len * 100); - }; + if (!isValid(tempConfig)) { + continue; + } + // if there is any input that was not parsed add a penalty for that format + currentScore += tempConfig._pf.charsLeftOver; - /** - * Return the label - * @return {string} label - */ - Filter.prototype.getLabel = function() { - return this.graph.filterLabel; - }; + //or tokens + currentScore += tempConfig._pf.unusedTokens.length * 10; + tempConfig._pf.score = currentScore; - /** - * Return the columnIndex of the filter - * @return {Number} columnIndex - */ - Filter.prototype.getColumn = function() { - return this.column; - }; + if (scoreToBeat == null || currentScore < scoreToBeat) { + scoreToBeat = currentScore; + bestMoment = tempConfig; + } + } - /** - * Return the currently selected value. Returns undefined if there is no selection - * @return {*} value - */ - Filter.prototype.getSelectedValue = function() { - if (this.index === undefined) - return undefined; + extend(config, bestMoment || tempConfig); + } - return this.values[this.index]; - }; + // date from iso format + function parseISO(config) { + var i, l, + string = config._i, + match = isoRegex.exec(string); - /** - * Retrieve all values of the filter - * @return {Array} values - */ - Filter.prototype.getValues = function() { - return this.values; - }; + if (match) { + config._pf.iso = true; + for (i = 0, l = isoDates.length; i < l; i++) { + if (isoDates[i][1].exec(string)) { + // match[5] should be 'T' or undefined + config._f = isoDates[i][0] + (match[6] || ' '); + break; + } + } + for (i = 0, l = isoTimes.length; i < l; i++) { + if (isoTimes[i][1].exec(string)) { + config._f += isoTimes[i][0]; + break; + } + } + if (string.match(parseTokenTimezone)) { + config._f += 'Z'; + } + makeDateFromStringAndFormat(config); + } else { + config._isValid = false; + } + } - /** - * Retrieve one value of the filter - * @param {Number} index - * @return {*} value - */ - Filter.prototype.getValue = function(index) { - if (index >= this.values.length) - throw 'Error: index out of range'; + // date from iso format or fallback + function makeDateFromString(config) { + parseISO(config); + if (config._isValid === false) { + delete config._isValid; + moment.createFromInputFallback(config); + } + } - return this.values[index]; - }; + function map(arr, fn) { + var res = [], i; + for (i = 0; i < arr.length; ++i) { + res.push(fn(arr[i], i)); + } + return res; + } + function makeDateFromInput(config) { + var input = config._i, matched; + if (input === undefined) { + config._d = new Date(); + } 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 = map(input.slice(0), function (obj) { + return parseInt(obj, 10); + }); + dateFromConfig(config); + } else if (typeof(input) === 'object') { + dateFromObject(config); + } else if (typeof(input) === 'number') { + // from milliseconds + config._d = new Date(input); + } else { + moment.createFromInputFallback(config); + } + } - /** - * Retrieve the (filtered) dataPoints for the currently selected filter index - * @param {Number} [index] (optional) - * @return {Array} dataPoints - */ - Filter.prototype._getDataPoints = function(index) { - if (index === undefined) - index = this.index; + function makeDate(y, m, d, h, M, s, ms) { + //can't just apply() to create a date: + //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply + var date = new Date(y, m, d, h, M, s, ms); - if (index === undefined) - return []; + //the date constructor doesn't accept years < 1970 + if (y < 1970) { + date.setFullYear(y); + } + return date; + } - var dataPoints; - if (this.dataPoints[index]) { - dataPoints = this.dataPoints[index]; - } - else { - var f = {}; - f.column = this.column; - f.value = this.values[index]; + function makeUTCDate(y) { + var date = new Date(Date.UTC.apply(null, arguments)); + if (y < 1970) { + date.setUTCFullYear(y); + } + return date; + } - var dataView = new DataView(this.data,{filter: function (item) {return (item[f.column] == f.value);}}).get(); - dataPoints = this.graph._getDataPoints(dataView); + function parseWeekday(input, locale) { + if (typeof input === 'string') { + if (!isNaN(input)) { + input = parseInt(input, 10); + } + else { + input = locale.weekdaysParse(input); + if (typeof input !== 'number') { + return null; + } + } + } + return input; + } - this.dataPoints[index] = dataPoints; - } + /************************************ + Relative Time + ************************************/ - return dataPoints; - }; + // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize + function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { + return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); + } + 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')), - /** - * Set a callback function when the filter is fully loaded. - */ - Filter.prototype.setOnLoadCallback = function(callback) { - this.onLoadCallback = callback; - }; + 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.d && ['dd', days] || + months === 1 && ['M'] || + months < relativeTimeThresholds.M && ['MM', months] || + years === 1 && ['y'] || ['yy', years]; + args[2] = withoutSuffix; + args[3] = +posNegDuration > 0; + args[4] = locale; + return substituteTimeAgo.apply({}, args); + } - /** - * Add a value to the list with available values for this filter - * No double entries will be created. - * @param {Number} index - */ - Filter.prototype.selectValue = function(index) { - if (index >= this.values.length) - throw 'Error: index out of range'; - this.index = index; - this.value = this.values[index]; - }; + /************************************ + Week of Year + ************************************/ - /** - * Load all filtered rows in the background one by one - * Start this method without providing an index! - */ - Filter.prototype.loadInBackground = function(index) { - if (index === undefined) - index = 0; - var frame = this.graph.frame; + // firstDayOfWeek 0 = sun, 6 = sat + // the day of the week that starts the week + // (usually sunday or monday) + // firstDayOfWeekOfYear 0 = sun, 6 = sat + // the first week is the week that contains the first + // of this day of the week + // (eg. ISO weeks use thursday (4)) + function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { + var end = firstDayOfWeekOfYear - firstDayOfWeek, + daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), + adjustedMoment; - if (index < this.values.length) { - var dataPointsTemp = this._getDataPoints(index); - //this.graph.redrawInfo(); // TODO: not neat - // create a progress box - if (frame.progress === undefined) { - frame.progress = document.createElement('DIV'); - frame.progress.style.position = 'absolute'; - frame.progress.style.color = 'gray'; - frame.appendChild(frame.progress); - } - var progress = this.getLoadedProgress(); - frame.progress.innerHTML = 'Loading animation... ' + progress + '%'; - // TODO: this is no nice solution... - frame.progress.style.bottom = 60 + 'px'; // TODO: use height of slider - frame.progress.style.left = 10 + 'px'; + if (daysToDayOfWeek > end) { + daysToDayOfWeek -= 7; + } - var me = this; - setTimeout(function() {me.loadInBackground(index+1);}, 10); - this.loaded = false; - } - else { - this.loaded = true; + if (daysToDayOfWeek < end - 7) { + daysToDayOfWeek += 7; + } - // remove the progress box - if (frame.progress !== undefined) { - frame.removeChild(frame.progress); - frame.progress = undefined; + adjustedMoment = moment(mom).add(daysToDayOfWeek, 'd'); + return { + week: Math.ceil(adjustedMoment.dayOfYear() / 7), + year: adjustedMoment.year() + }; } - if (this.onLoadCallback) - this.onLoadCallback(); - } - }; - - module.exports = Filter; - - -/***/ }, -/* 9 */ -/***/ function(module, exports, __webpack_require__) { + //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday + function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { + var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear; - /** - * @prototype Point2d - * @param {Number} [x] - * @param {Number} [y] - */ - function Point2d (x, y) { - this.x = x !== undefined ? x : 0; - this.y = y !== undefined ? y : 0; - } + d = d === 0 ? 7 : d; + weekday = weekday != null ? weekday : firstDayOfWeek; + daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0); + dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; - module.exports = Point2d; + return { + year: dayOfYear > 0 ? year : year - 1, + dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear + }; + } + /************************************ + Top Level Functions + ************************************/ -/***/ }, -/* 10 */ -/***/ function(module, exports, __webpack_require__) { + function makeMoment(config) { + var input = config._i, + format = config._f, + res; - /** - * @prototype Point3d - * @param {Number} [x] - * @param {Number} [y] - * @param {Number} [z] - */ - function Point3d(x, y, z) { - this.x = x !== undefined ? x : 0; - this.y = y !== undefined ? y : 0; - this.z = z !== undefined ? z : 0; - }; + config._locale = config._locale || moment.localeData(config._l); - /** - * Subtract the two provided points, returns a-b - * @param {Point3d} a - * @param {Point3d} b - * @return {Point3d} a-b - */ - Point3d.subtract = function(a, b) { - var sub = new Point3d(); - sub.x = a.x - b.x; - sub.y = a.y - b.y; - sub.z = a.z - b.z; - return sub; - }; + if (input === null || (format === undefined && input === '')) { + return moment.invalid({nullInput: true}); + } - /** - * Add the two provided points, returns a+b - * @param {Point3d} a - * @param {Point3d} b - * @return {Point3d} a+b - */ - Point3d.add = function(a, b) { - var sum = new Point3d(); - sum.x = a.x + b.x; - sum.y = a.y + b.y; - sum.z = a.z + b.z; - return sum; - }; + if (typeof input === 'string') { + config._i = input = config._locale.preparse(input); + } - /** - * Calculate the average of two 3d points - * @param {Point3d} a - * @param {Point3d} b - * @return {Point3d} The average, (a+b)/2 - */ - Point3d.avg = function(a, b) { - return new Point3d( - (a.x + b.x) / 2, - (a.y + b.y) / 2, - (a.z + b.z) / 2 - ); - }; + if (moment.isMoment(input)) { + return new Moment(input, true); + } else if (format) { + if (isArray(format)) { + makeDateFromStringAndArray(config); + } else { + makeDateFromStringAndFormat(config); + } + } else { + makeDateFromInput(config); + } - /** - * Calculate the cross product of the two provided points, returns axb - * Documentation: http://en.wikipedia.org/wiki/Cross_product - * @param {Point3d} a - * @param {Point3d} b - * @return {Point3d} cross product axb - */ - Point3d.crossProduct = function(a, b) { - var crossproduct = new Point3d(); + res = new Moment(config); + if (res._nextDay) { + // Adding is smart enough around DST + res.add(1, 'd'); + res._nextDay = undefined; + } - crossproduct.x = a.y * b.z - a.z * b.y; - crossproduct.y = a.z * b.x - a.x * b.z; - crossproduct.z = a.x * b.y - a.y * b.x; + return res; + } - return crossproduct; - }; + moment = function (input, format, locale, strict) { + var c; + if (typeof(locale) === 'boolean') { + strict = locale; + locale = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c = {}; + c._isAMomentObject = true; + c._i = input; + c._f = format; + c._l = locale; + c._strict = strict; + c._isUTC = false; + c._pf = defaultParsingFlags(); - /** - * Rtrieve the length of the vector (or the distance from this point to the origin - * @return {Number} length - */ - Point3d.prototype.length = function() { - return Math.sqrt( - this.x * this.x + - this.y * this.y + - this.z * this.z - ); - }; + return makeMoment(c); + }; - module.exports = Point3d; + 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 + (config._useUTC ? ' UTC' : '')); + } + ); -/***/ }, -/* 11 */ -/***/ function(module, exports, __webpack_require__) { + // 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. + // + // moments should either be an array of moment objects or an array, whose + // first element is an array of moment objects. + function pickBy(fn, moments) { + var res, i; + if (moments.length === 1 && isArray(moments[0])) { + moments = moments[0]; + } + if (!moments.length) { + return moment(); + } + res = moments[0]; + for (i = 1; i < moments.length; ++i) { + if (moments[i][fn](res)) { + res = moments[i]; + } + } + return res; + } - var util = __webpack_require__(1); + moment.min = function () { + var args = [].slice.call(arguments, 0); - /** - * @constructor Slider - * - * An html slider control with start/stop/prev/next buttons - * @param {Element} container The element where the slider will be created - * @param {Object} options Available options: - * {boolean} visible If true (default) the - * slider is visible. - */ - function Slider(container, options) { - if (container === undefined) { - throw 'Error: No container element defined'; - } - this.container = container; - this.visible = (options && options.visible != undefined) ? options.visible : true; + return pickBy('isBefore', args); + }; - if (this.visible) { - this.frame = document.createElement('DIV'); - //this.frame.style.backgroundColor = '#E5E5E5'; - this.frame.style.width = '100%'; - this.frame.style.position = 'relative'; - this.container.appendChild(this.frame); + moment.max = function () { + var args = [].slice.call(arguments, 0); - this.frame.prev = document.createElement('INPUT'); - this.frame.prev.type = 'BUTTON'; - this.frame.prev.value = 'Prev'; - this.frame.appendChild(this.frame.prev); + return pickBy('isAfter', args); + }; - this.frame.play = document.createElement('INPUT'); - this.frame.play.type = 'BUTTON'; - this.frame.play.value = 'Play'; - this.frame.appendChild(this.frame.play); + // creating with utc + moment.utc = function (input, format, locale, strict) { + var c; - this.frame.next = document.createElement('INPUT'); - this.frame.next.type = 'BUTTON'; - this.frame.next.value = 'Next'; - this.frame.appendChild(this.frame.next); + if (typeof(locale) === 'boolean') { + strict = locale; + locale = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c = {}; + c._isAMomentObject = true; + c._useUTC = true; + c._isUTC = true; + c._l = locale; + c._i = input; + c._f = format; + c._strict = strict; + c._pf = defaultParsingFlags(); - this.frame.bar = document.createElement('INPUT'); - this.frame.bar.type = 'BUTTON'; - this.frame.bar.style.position = 'absolute'; - this.frame.bar.style.border = '1px solid red'; - this.frame.bar.style.width = '100px'; - this.frame.bar.style.height = '6px'; - this.frame.bar.style.borderRadius = '2px'; - this.frame.bar.style.MozBorderRadius = '2px'; - this.frame.bar.style.border = '1px solid #7F7F7F'; - this.frame.bar.style.backgroundColor = '#E5E5E5'; - this.frame.appendChild(this.frame.bar); + return makeMoment(c).utc(); + }; - this.frame.slide = document.createElement('INPUT'); - this.frame.slide.type = 'BUTTON'; - this.frame.slide.style.margin = '0px'; - this.frame.slide.value = ' '; - this.frame.slide.style.position = 'relative'; - this.frame.slide.style.left = '-100px'; - this.frame.appendChild(this.frame.slide); + // creating with unix timestamp (in seconds) + moment.unix = function (input) { + return moment(input * 1000); + }; - // create events - var me = this; - this.frame.slide.onmousedown = function (event) {me._onMouseDown(event);}; - this.frame.prev.onclick = function (event) {me.prev(event);}; - this.frame.play.onclick = function (event) {me.togglePlay(event);}; - this.frame.next.onclick = function (event) {me.next(event);}; - } + // duration + moment.duration = function (input, key) { + var duration = input, + // matching against regexp is expensive, do it on demand + match = null, + sign, + ret, + parseIso, + diffRes; - this.onChangeCallback = undefined; + if (moment.isDuration(input)) { + duration = { + ms: input._milliseconds, + d: input._days, + M: input._months + }; + } else if (typeof input === 'number') { + duration = {}; + if (key) { + duration[key] = input; + } else { + duration.milliseconds = input; + } + } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) { + sign = (match[1] === '-') ? -1 : 1; + duration = { + y: 0, + d: toInt(match[DATE]) * sign, + h: toInt(match[HOUR]) * sign, + m: toInt(match[MINUTE]) * sign, + s: toInt(match[SECOND]) * sign, + ms: toInt(match[MILLISECOND]) * sign + }; + } else if (!!(match = isoDurationRegex.exec(input))) { + sign = (match[1] === '-') ? -1 : 1; + parseIso = function (inp) { + // We'd normally use ~~inp for this, but unfortunately it also + // converts floats to ints. + // inp may be undefined, so careful calling replace on it. + var res = inp && parseFloat(inp.replace(',', '.')); + // apply sign while we're at it + return (isNaN(res) ? 0 : res) * sign; + }; + duration = { + y: parseIso(match[2]), + M: parseIso(match[3]), + d: parseIso(match[4]), + h: parseIso(match[5]), + m: parseIso(match[6]), + s: parseIso(match[7]), + w: parseIso(match[8]) + }; + } else if (duration == null) {// checks for null or undefined + duration = {}; + } else if (typeof duration === 'object' && + ('from' in duration || 'to' in duration)) { + diffRes = momentsDifference(moment(duration.from), moment(duration.to)); - this.values = []; - this.index = undefined; + duration = {}; + duration.ms = diffRes.milliseconds; + duration.M = diffRes.months; + } - this.playTimeout = undefined; - this.playInterval = 1000; // milliseconds - this.playLoop = true; - } + ret = new Duration(duration); - /** - * Select the previous index - */ - Slider.prototype.prev = function() { - var index = this.getIndex(); - if (index > 0) { - index--; - this.setIndex(index); - } - }; + if (moment.isDuration(input) && hasOwnProp(input, '_locale')) { + ret._locale = input._locale; + } - /** - * Select the next index - */ - Slider.prototype.next = function() { - var index = this.getIndex(); - if (index < this.values.length - 1) { - index++; - this.setIndex(index); - } - }; + return ret; + }; - /** - * Select the next index - */ - Slider.prototype.playNext = function() { - var start = new Date(); + // version number + moment.version = VERSION; - var index = this.getIndex(); - if (index < this.values.length - 1) { - index++; - this.setIndex(index); - } - else if (this.playLoop) { - // jump to the start - index = 0; - this.setIndex(index); - } + // default format + moment.defaultFormat = isoFormat; - var end = new Date(); - var diff = (end - start); + // constant that refers to the ISO standard + moment.ISO_8601 = function () {}; - // calculate how much time it to to set the index and to execute the callback - // function. - var interval = Math.max(this.playInterval - diff, 0); - // document.title = diff // TODO: cleanup + // Plugins that add properties should also add the key here (null value), + // so we can properly clone ourselves. + moment.momentProperties = momentProperties; - var me = this; - this.playTimeout = setTimeout(function() {me.playNext();}, interval); - }; + // This function will be called whenever a moment is mutated. + // It is intended to keep the offset in sync with the timezone. + moment.updateOffset = function () {}; - /** - * Toggle start or stop playing - */ - Slider.prototype.togglePlay = function() { - if (this.playTimeout === undefined) { - this.play(); - } else { - this.stop(); - } - }; + // This function allows you to set a threshold for relative time strings + moment.relativeTimeThreshold = function (threshold, limit) { + if (relativeTimeThresholds[threshold] === undefined) { + return false; + } + if (limit === undefined) { + return relativeTimeThresholds[threshold]; + } + relativeTimeThresholds[threshold] = limit; + return true; + }; - /** - * Start playing - */ - Slider.prototype.play = function() { - // Test whether already playing - if (this.playTimeout) return; + moment.lang = deprecate( + 'moment.lang is deprecated. Use moment.locale instead.', + function (key, value) { + return moment.locale(key, value); + } + ); - this.playNext(); + // This function will load locale and then set the global locale. If + // no arguments are passed in, it will simply return the current global + // 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 (this.frame) { - this.frame.play.value = 'Stop'; - } - }; + if (data) { + moment.duration._locale = moment._locale = data; + } + } - /** - * Stop playing - */ - Slider.prototype.stop = function() { - clearInterval(this.playTimeout); - this.playTimeout = undefined; + return moment._locale._abbr; + }; - if (this.frame) { - this.frame.play.value = 'Play'; - } - }; + moment.defineLocale = function (name, values) { + if (values !== null) { + values.abbr = name; + if (!locales[name]) { + locales[name] = new Locale(); + } + locales[name].set(values); - /** - * Set a callback function which will be triggered when the value of the - * slider bar has changed. - */ - Slider.prototype.setOnChangeCallback = function(callback) { - this.onChangeCallback = callback; - }; + // backwards compat for now: also set the locale + moment.locale(name); - /** - * Set the interval for playing the list - * @param {Number} interval The interval in milliseconds - */ - Slider.prototype.setPlayInterval = function(interval) { - this.playInterval = interval; - }; + return locales[name]; + } else { + // useful for testing + delete locales[name]; + return null; + } + }; - /** - * Retrieve the current play interval - * @return {Number} interval The interval in milliseconds - */ - Slider.prototype.getPlayInterval = function(interval) { - return this.playInterval; - }; + moment.langData = deprecate( + 'moment.langData is deprecated. Use moment.localeData instead.', + function (key) { + return moment.localeData(key); + } + ); - /** - * Set looping on or off - * @pararm {boolean} doLoop If true, the slider will jump to the start when - * the end is passed, and will jump to the end - * when the start is passed. - */ - Slider.prototype.setPlayLoop = function(doLoop) { - this.playLoop = doLoop; - }; + // returns locale data + moment.localeData = function (key) { + var locale; + if (key && key._locale && key._locale._abbr) { + key = key._locale._abbr; + } - /** - * Execute the onchange callback function - */ - Slider.prototype.onChange = function() { - if (this.onChangeCallback !== undefined) { - this.onChangeCallback(); - } - }; + if (!key) { + return moment._locale; + } - /** - * redraw the slider on the correct place - */ - Slider.prototype.redraw = function() { - if (this.frame) { - // resize the bar - this.frame.bar.style.top = (this.frame.clientHeight/2 - - this.frame.bar.offsetHeight/2) + 'px'; - this.frame.bar.style.width = (this.frame.clientWidth - - this.frame.prev.clientWidth - - this.frame.play.clientWidth - - this.frame.next.clientWidth - 30) + 'px'; + if (!isArray(key)) { + //short-circuit everything else + locale = loadLocale(key); + if (locale) { + return locale; + } + key = [key]; + } - // position the slider button - var left = this.indexToLeft(this.index); - this.frame.slide.style.left = (left) + 'px'; - } - }; + return chooseLocale(key); + }; + // compare moment object + moment.isMoment = function (obj) { + return obj instanceof Moment || + (obj != null && hasOwnProp(obj, '_isAMomentObject')); + }; - /** - * Set the list with values for the slider - * @param {Array} values A javascript array with values (any type) - */ - Slider.prototype.setValues = function(values) { - this.values = values; + // for typechecking Duration objects + moment.isDuration = function (obj) { + return obj instanceof Duration; + }; - if (this.values.length > 0) - this.setIndex(0); - else - this.index = undefined; - }; + for (i = lists.length - 1; i >= 0; --i) { + makeList(lists[i]); + } - /** - * Select a value by its index - * @param {Number} index - */ - Slider.prototype.setIndex = function(index) { - if (index < this.values.length) { - this.index = index; + moment.normalizeUnits = function (units) { + return normalizeUnits(units); + }; - this.redraw(); - this.onChange(); - } - else { - throw 'Error: index out of range'; - } - }; + moment.invalid = function (flags) { + var m = moment.utc(NaN); + if (flags != null) { + extend(m._pf, flags); + } + else { + m._pf.userInvalidated = true; + } - /** - * retrieve the index of the currently selected vaue - * @return {Number} index - */ - Slider.prototype.getIndex = function() { - return this.index; - }; + return m; + }; + moment.parseZone = function () { + return moment.apply(null, arguments).parseZone(); + }; - /** - * retrieve the currently selected value - * @return {*} value - */ - Slider.prototype.get = function() { - return this.values[this.index]; - }; + moment.parseTwoDigitYear = function (input) { + return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); + }; + moment.isDate = isDate; - Slider.prototype._onMouseDown = function(event) { - // only react on left mouse button down - var leftButtonDown = event.which ? (event.which === 1) : (event.button === 1); - if (!leftButtonDown) return; + /************************************ + Moment Prototype + ************************************/ - this.startClientX = event.clientX; - this.startSlideX = parseFloat(this.frame.slide.style.left); - this.frame.style.cursor = 'move'; + extend(moment.fn = Moment.prototype, { - // add event listeners to handle moving the contents - // we store the function onmousemove and onmouseup in the graph, so we can - // remove the eventlisteners lateron in the function mouseUp() - var me = this; - this.onmousemove = function (event) {me._onMouseMove(event);}; - this.onmouseup = function (event) {me._onMouseUp(event);}; - util.addEventListener(document, 'mousemove', this.onmousemove); - util.addEventListener(document, 'mouseup', this.onmouseup); - util.preventDefault(event); - }; + clone : function () { + return moment(this); + }, + valueOf : function () { + return +this._d - ((this._offset || 0) * 60000); + }, - Slider.prototype.leftToIndex = function (left) { - var width = parseFloat(this.frame.bar.style.width) - - this.frame.slide.clientWidth - 10; - var x = left - 3; + unix : function () { + return Math.floor(+this / 1000); + }, - var index = Math.round(x / width * (this.values.length-1)); - if (index < 0) index = 0; - if (index > this.values.length-1) index = this.values.length-1; + toString : function () { + return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); + }, - return index; - }; + toDate : function () { + return this._offset ? new Date(+this) : this._d; + }, - Slider.prototype.indexToLeft = function (index) { - var width = parseFloat(this.frame.bar.style.width) - - this.frame.slide.clientWidth - 10; + toISOString : function () { + var m = moment(this).utc(); + if (0 < m.year() && m.year() <= 9999) { + if ('function' === typeof Date.prototype.toISOString) { + // native implementation is ~50x faster, use it when we can + return this.toDate().toISOString(); + } else { + return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } + } else { + return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } + }, - var x = index / (this.values.length-1) * width; - var left = x + 3; + toArray : function () { + var m = this; + return [ + m.year(), + m.month(), + m.date(), + m.hours(), + m.minutes(), + m.seconds(), + m.milliseconds() + ]; + }, - return left; - }; + isValid : function () { + return isValid(this); + }, + isDSTShifted : function () { + if (this._a) { + return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0; + } + return false; + }, - Slider.prototype._onMouseMove = function (event) { - var diff = event.clientX - this.startClientX; - var x = this.startSlideX + diff; + parsingFlags : function () { + return extend({}, this._pf); + }, - var index = this.leftToIndex(x); + invalidAt: function () { + return this._pf.overflow; + }, - this.setIndex(index); + utc : function (keepLocalTime) { + return this.utcOffset(0, keepLocalTime); + }, - util.preventDefault(); - }; + local : function (keepLocalTime) { + if (this._isUTC) { + this.utcOffset(0, keepLocalTime); + this._isUTC = false; + if (keepLocalTime) { + this.subtract(this._dateUtcOffset(), 'm'); + } + } + return this; + }, - Slider.prototype._onMouseUp = function (event) { - this.frame.style.cursor = 'auto'; + format : function (inputString) { + var output = formatMoment(this, inputString || moment.defaultFormat); + return this.localeData().postformat(output); + }, - // remove event listeners - util.removeEventListener(document, 'mousemove', this.onmousemove); - util.removeEventListener(document, 'mouseup', this.onmouseup); + add : createAdder(1, 'add'), - util.preventDefault(); - }; + subtract : createAdder(-1, 'subtract'), - module.exports = Slider; + diff : function (input, units, asFloat) { + var that = makeAs(input, this), + zoneDiff = (that.utcOffset() - this.utcOffset()) * 6e4, + anchor, diff, output, daysAdjust; + units = normalizeUnits(units); -/***/ }, -/* 12 */ -/***/ function(module, exports, __webpack_require__) { + if (units === 'year' || units === 'month' || units === 'quarter') { + output = monthDiff(this, that); + if (units === 'quarter') { + output = output / 3; + } else if (units === 'year') { + output = output / 12; + } + } else { + diff = this - that; + output = units === 'second' ? diff / 1e3 : // 1000 + units === 'minute' ? diff / 6e4 : // 1000 * 60 + units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 + units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst + units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst + diff; + } + return asFloat ? output : absRound(output); + }, - /** - * @prototype StepNumber - * The class StepNumber is an iterator for Numbers. You provide a start and end - * value, and a best step size. StepNumber itself rounds to fixed values and - * a finds the step that best fits the provided step. - * - * If prettyStep is true, the step size is chosen as close as possible to the - * provided step, but being a round value like 1, 2, 5, 10, 20, 50, .... - * - * Example usage: - * var step = new StepNumber(0, 10, 2.5, true); - * step.start(); - * while (!step.end()) { - * alert(step.getCurrent()); - * step.next(); - * } - * - * Version: 1.0 - * - * @param {Number} start The start value - * @param {Number} end The end value - * @param {Number} step Optional. Step size. Must be a positive value. - * @param {boolean} prettyStep Optional. If true, the step size is rounded - * To a pretty step size (like 1, 2, 5, 10, 20, 50, ...) - */ - function StepNumber(start, end, step, prettyStep) { - // set default values - this._start = 0; - this._end = 0; - this._step = 1; - this.prettyStep = true; - this.precision = 5; + from : function (time, withoutSuffix) { + return moment.duration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix); + }, - this._current = 0; - this.setRange(start, end, step, prettyStep); - }; + fromNow : function (withoutSuffix) { + return this.from(moment(), withoutSuffix); + }, - /** - * Set a new range: start, end and step. - * - * @param {Number} start The start value - * @param {Number} end The end value - * @param {Number} step Optional. Step size. Must be a positive value. - * @param {boolean} prettyStep Optional. If true, the step size is rounded - * To a pretty step size (like 1, 2, 5, 10, 20, 50, ...) - */ - StepNumber.prototype.setRange = function(start, end, step, prettyStep) { - this._start = start ? start : 0; - this._end = end ? end : 0; + calendar : function (time) { + // We want to compare the start of today, vs this. + // Getting start-of-today depends on whether we're locat/utc/offset + // or not. + var now = time || moment(), + sod = makeAs(now, this).startOf('day'), + diff = this.diff(sod, 'days', true), + format = diff < -6 ? 'sameElse' : + diff < -1 ? 'lastWeek' : + diff < 0 ? 'lastDay' : + diff < 1 ? 'sameDay' : + diff < 2 ? 'nextDay' : + diff < 7 ? 'nextWeek' : 'sameElse'; + return this.format(this.localeData().calendar(format, this, moment(now))); + }, - this.setStep(step, prettyStep); - }; + isLeapYear : function () { + return isLeapYear(this.year()); + }, - /** - * Set a new step size - * @param {Number} step New step size. Must be a positive value - * @param {boolean} prettyStep Optional. If true, the provided step is rounded - * to a pretty step size (like 1, 2, 5, 10, 20, 50, ...) - */ - StepNumber.prototype.setStep = function(step, prettyStep) { - if (step === undefined || step <= 0) - return; + isDST : function () { + return (this.utcOffset() > this.clone().month(0).utcOffset() || + this.utcOffset() > this.clone().month(5).utcOffset()); + }, - if (prettyStep !== undefined) - this.prettyStep = prettyStep; + day : function (input) { + var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); + if (input != null) { + input = parseWeekday(input, this.localeData()); + return this.add(input - day, 'd'); + } else { + return day; + } + }, - if (this.prettyStep === true) - this._step = StepNumber.calculatePrettyStep(step); - else - this._step = step; - }; + month : makeAccessor('Month', true), - /** - * Calculate a nice step size, closest to the desired step size. - * Returns a value in one of the ranges 1*10^n, 2*10^n, or 5*10^n, where n is an - * integer Number. For example 1, 2, 5, 10, 20, 50, etc... - * @param {Number} step Desired step size - * @return {Number} Nice step size - */ - StepNumber.calculatePrettyStep = function (step) { - var log10 = function (x) {return Math.log(x) / Math.LN10;}; + startOf : function (units) { + units = normalizeUnits(units); + // the following switch intentionally omits break keywords + // to utilize falling through the cases. + switch (units) { + case 'year': + this.month(0); + /* falls through */ + case 'quarter': + case 'month': + this.date(1); + /* falls through */ + case 'week': + case 'isoWeek': + case 'day': + this.hours(0); + /* falls through */ + case 'hour': + this.minutes(0); + /* falls through */ + case 'minute': + this.seconds(0); + /* falls through */ + case 'second': + this.milliseconds(0); + /* falls through */ + } - // try three steps (multiple of 1, 2, or 5 - var step1 = Math.pow(10, Math.round(log10(step))), - step2 = 2 * Math.pow(10, Math.round(log10(step / 2))), - step5 = 5 * Math.pow(10, Math.round(log10(step / 5))); + // weeks are a special case + if (units === 'week') { + this.weekday(0); + } else if (units === 'isoWeek') { + this.isoWeekday(1); + } - // choose the best step (closest to minimum step) - var prettyStep = step1; - if (Math.abs(step2 - step) <= Math.abs(prettyStep - step)) prettyStep = step2; - if (Math.abs(step5 - step) <= Math.abs(prettyStep - step)) prettyStep = step5; + // quarters are also special + if (units === 'quarter') { + this.month(Math.floor(this.month() / 3) * 3); + } - // for safety - if (prettyStep <= 0) { - prettyStep = 1; - } + return this; + }, - return prettyStep; - }; + endOf: function (units) { + units = normalizeUnits(units); + if (units === undefined || units === 'millisecond') { + return this; + } + return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms'); + }, - /** - * returns the current value of the step - * @return {Number} current value - */ - StepNumber.prototype.getCurrent = function () { - return parseFloat(this._current.toPrecision(this.precision)); - }; + isAfter: function (input, units) { + var inputMs; + units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); + if (units === 'millisecond') { + input = moment.isMoment(input) ? input : moment(input); + return +this > +input; + } else { + inputMs = moment.isMoment(input) ? +input : +moment(input); + return inputMs < +this.clone().startOf(units); + } + }, - /** - * returns the current step size - * @return {Number} current step size - */ - StepNumber.prototype.getStep = function () { - return this._step; - }; + isBefore: function (input, units) { + var inputMs; + units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); + if (units === 'millisecond') { + input = moment.isMoment(input) ? input : moment(input); + return +this < +input; + } else { + inputMs = moment.isMoment(input) ? +input : +moment(input); + return +this.clone().endOf(units) < inputMs; + } + }, - /** - * Set the current value to the largest value smaller than start, which - * is a multiple of the step size - */ - StepNumber.prototype.start = function() { - this._current = this._start - this._start % this._step; - }; + isBetween: function (from, to, units) { + return this.isAfter(from, units) && this.isBefore(to, units); + }, - /** - * Do a step, add the step size to the current value - */ - StepNumber.prototype.next = function () { - this._current += this._step; - }; + isSame: function (input, units) { + var inputMs; + units = normalizeUnits(units || 'millisecond'); + if (units === 'millisecond') { + input = moment.isMoment(input) ? input : moment(input); + return +this === +input; + } else { + inputMs = +moment(input); + return +(this.clone().startOf(units)) <= inputMs && inputMs <= +(this.clone().endOf(units)); + } + }, - /** - * Returns true whether the end is reached - * @return {boolean} True if the current value has passed the end value. - */ - StepNumber.prototype.end = function () { - return (this._current > this._end); - }; + min: deprecate( + '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; + } + ), - module.exports = StepNumber; + max: deprecate( + '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; + } + ), + zone : deprecate( + 'moment().zone is deprecated, use moment().utcOffset instead. ' + + 'https://github.com/moment/moment/issues/1779', + function (input, keepLocalTime) { + if (input != null) { + if (typeof input !== 'string') { + input = -input; + } -/***/ }, -/* 13 */ -/***/ function(module, exports, __webpack_require__) { + this.utcOffset(input, keepLocalTime); - var Emitter = __webpack_require__(56); - var Hammer = __webpack_require__(45); - var util = __webpack_require__(1); - var DataSet = __webpack_require__(3); - var DataView = __webpack_require__(4); - var Range = __webpack_require__(17); - var Core = __webpack_require__(46); - var TimeAxis = __webpack_require__(30); - var CurrentTime = __webpack_require__(21); - var CustomTime = __webpack_require__(22); - var ItemSet = __webpack_require__(27); + return this; + } else { + return -this.utcOffset(); + } + } + ), - /** - * Create a timeline visualization - * @param {HTMLElement} container - * @param {vis.DataSet | Array | google.visualization.DataTable} [items] - * @param {vis.DataSet | Array | google.visualization.DataTable} [groups] - * @param {Object} [options] See Timeline.setOptions for the available options. - * @constructor - * @extends Core - */ - function Timeline (container, items, groups, options) { - if (!(this instanceof Timeline)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } + // keepLocalTime = true means only change the timezone, without + // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]--> + // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset + // +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. + utcOffset : function (input, keepLocalTime) { + var offset = this._offset || 0, + localAdjust; + if (input != null) { + if (typeof input === 'string') { + input = utcOffsetFromString(input); + } + if (Math.abs(input) < 16) { + input = input * 60; + } + if (!this._isUTC && keepLocalTime) { + localAdjust = this._dateUtcOffset(); + } + this._offset = input; + this._isUTC = true; + if (localAdjust != null) { + this.add(localAdjust, 'm'); + } + if (offset !== input) { + if (!keepLocalTime || this._changeInProgress) { + addOrSubtractDurationFromMoment(this, + moment.duration(input - offset, 'm'), 1, false); + } else if (!this._changeInProgress) { + this._changeInProgress = true; + moment.updateOffset(this, true); + this._changeInProgress = null; + } + } - // if the third element is options, the forth is groups (optionally); - if (!(Array.isArray(groups) || groups instanceof DataSet) && groups instanceof Object) { - var forthArgument = options; - options = groups; - groups = forthArgument; - } + return this; + } else { + return this._isUTC ? offset : this._dateUtcOffset(); + } + }, - var me = this; - this.defaultOptions = { - start: null, - end: null, + isLocal : function () { + return !this._isUTC; + }, - autoResize: true, + isUtcOffset : function () { + return this._isUTC; + }, - orientation: 'bottom', - width: null, - height: null, - maxHeight: null, - minHeight: null - }; - this.options = util.deepExtend({}, this.defaultOptions); + isUtc : function () { + return this._isUTC && this._offset === 0; + }, - // Create the DOM, props, and emitter - this._create(container); + zoneAbbr : function () { + return this._isUTC ? 'UTC' : ''; + }, - // all components listed here will be repainted automatically - this.components = []; + zoneName : function () { + return this._isUTC ? 'Coordinated Universal Time' : ''; + }, - this.body = { - dom: this.dom, - domProps: this.props, - emitter: { - on: this.on.bind(this), - off: this.off.bind(this), - emit: this.emit.bind(this) - }, - hiddenDates: [], - util: { - snap: null, // will be specified after TimeAxis is created - toScreen: me._toScreen.bind(me), - toGlobalScreen: me._toGlobalScreen.bind(me), // this refers to the root.width - toTime: me._toTime.bind(me), - toGlobalTime : me._toGlobalTime.bind(me) - } - }; + parseZone : function () { + if (this._tzm) { + this.utcOffset(this._tzm); + } else if (typeof this._i === 'string') { + this.utcOffset(utcOffsetFromString(this._i)); + } + return this; + }, - // range - this.range = new Range(this.body); - this.components.push(this.range); - this.body.range = this.range; + hasAlignedHourOffset : function (input) { + if (!input) { + input = 0; + } + else { + input = moment(input).utcOffset(); + } - // time axis - this.timeAxis = new TimeAxis(this.body); - this.components.push(this.timeAxis); - this.body.util.snap = this.timeAxis.snap.bind(this.timeAxis); + return (this.utcOffset() - input) % 60 === 0; + }, - // current time bar - this.currentTime = new CurrentTime(this.body); - this.components.push(this.currentTime); + daysInMonth : function () { + return daysInMonth(this.year(), this.month()); + }, - // custom time bar - // Note: time bar will be attached in this.setOptions when selected - this.customTime = new CustomTime(this.body); - this.components.push(this.customTime); + dayOfYear : function (input) { + var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; + return input == null ? dayOfYear : this.add((input - dayOfYear), 'd'); + }, - // item set - this.itemSet = new ItemSet(this.body); - this.components.push(this.itemSet); + quarter : function (input) { + return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3); + }, - this.itemsData = null; // DataSet - this.groupsData = null; // DataSet + weekYear : function (input) { + var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year; + return input == null ? year : this.add((input - year), 'y'); + }, - // apply options - if (options) { - this.setOptions(options); - } + isoWeekYear : function (input) { + var year = weekOfYear(this, 1, 4).year; + return input == null ? year : this.add((input - year), 'y'); + }, - // IMPORTANT: THIS HAPPENS BEFORE SET ITEMS! - if (groups) { - this.setGroups(groups); - } + week : function (input) { + var week = this.localeData().week(this); + return input == null ? week : this.add((input - week) * 7, 'd'); + }, - // create itemset - if (items) { - this.setItems(items); - } - else { - this.redraw(); - } - } + isoWeek : function (input) { + var week = weekOfYear(this, 1, 4).week; + return input == null ? week : this.add((input - week) * 7, 'd'); + }, - // Extend the functionality from Core - Timeline.prototype = new Core(); + weekday : function (input) { + var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; + return input == null ? weekday : this.add(input - weekday, 'd'); + }, - /** - * Set items - * @param {vis.DataSet | Array | google.visualization.DataTable | null} items - */ - Timeline.prototype.setItems = function(items) { - var initialLoad = (this.itemsData == null); + isoWeekday : function (input) { + // behaves the same as moment#day except + // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) + // as a setter, sunday should belong to the previous week. + return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); + }, - // convert to type DataSet when needed - var newDataSet; - if (!items) { - newDataSet = null; - } - else if (items instanceof DataSet || items instanceof DataView) { - newDataSet = items; - } - else { - // turn an array into a dataset - newDataSet = new DataSet(items, { - type: { - start: 'Date', - end: 'Date' - } - }); - } + isoWeeksInYear : function () { + return weeksInYear(this.year(), 1, 4); + }, - // set items - this.itemsData = newDataSet; - this.itemSet && this.itemSet.setItems(newDataSet); + weeksInYear : function () { + var weekInfo = this.localeData()._week; + return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); + }, - if (initialLoad) { - if (this.options.start != undefined || this.options.end != undefined) { - if (this.options.start == undefined || this.options.end == undefined) { - var dataRange = this._getDataRange(); - } + get : function (units) { + units = normalizeUnits(units); + return this[units](); + }, - var start = this.options.start != undefined ? this.options.start : dataRange.start; - var end = this.options.end != undefined ? this.options.end : dataRange.end; + set : function (units, value) { + var unit; + if (typeof units === 'object') { + for (unit in units) { + this.set(unit, units[unit]); + } + } + else { + units = normalizeUnits(units); + if (typeof this[units] === 'function') { + this[units](value); + } + } + return this; + }, - this.setWindow(start, end, {animate: false}); - } - else { - this.fit({animate: false}); - } - } - }; + // If passed a locale key, it will set the locale for this + // instance. Otherwise, it will return the locale configuration + // variables for this instance. + locale : function (key) { + var newLocaleData; - /** - * Set groups - * @param {vis.DataSet | Array | google.visualization.DataTable} groups - */ - Timeline.prototype.setGroups = function(groups) { - // convert to type DataSet when needed - var newDataSet; - if (!groups) { - newDataSet = null; - } - else if (groups instanceof DataSet || groups instanceof DataView) { - newDataSet = groups; - } - else { - // turn an array into a dataset - newDataSet = new DataSet(groups); - } + if (key === undefined) { + return this._locale._abbr; + } else { + newLocaleData = moment.localeData(key); + if (newLocaleData != null) { + this._locale = newLocaleData; + } + return this; + } + }, - this.groupsData = newDataSet; - this.itemSet.setGroups(newDataSet); - }; + lang : deprecate( + 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', + function (key) { + if (key === undefined) { + return this.localeData(); + } else { + return this.locale(key); + } + } + ), - /** - * Set selected items by their id. Replaces the current selection - * Unknown id's are silently ignored. - * @param {string[] | string} [ids] An array with zero or more id's of the items to be - * selected. If ids is an empty array, all items will be - * unselected. - * @param {Object} [options] Available options: - * `focus: boolean` - * If true, focus will be set to the selected item(s) - * `animate: boolean | number` - * If true (default), the range is animated - * smoothly to the new window. - * If a number, the number is taken as duration - * for the animation. Default duration is 500 ms. - * Only applicable when option focus is true. - */ - Timeline.prototype.setSelection = function(ids, options) { - this.itemSet && this.itemSet.setSelection(ids); + localeData : function () { + return this._locale; + }, - if (options && options.focus) { - this.focus(ids, options); - } - }; + _dateUtcOffset : function () { + // On Firefox.24 Date#getTimezoneOffset returns a floating point. + // https://github.com/moment/moment/pull/1871 + return -Math.round(this._d.getTimezoneOffset() / 15) * 15; + } - /** - * Get the selected items by their id - * @return {Array} ids The ids of the selected items - */ - Timeline.prototype.getSelection = function() { - return this.itemSet && this.itemSet.getSelection() || []; - }; + }); - /** - * Adjust the visible window such that the selected item (or multiple items) - * are centered on screen. - * @param {String | String[]} id An item id or array with item ids - * @param {Object} [options] Available options: - * `animate: boolean | number` - * If true (default), the range is animated - * smoothly to the new window. - * If a number, the number is taken as duration - * for the animation. Default duration is 500 ms. - * Only applicable when option focus is true - */ - Timeline.prototype.focus = function(id, options) { - if (!this.itemsData || id == undefined) return; + function rawMonthSetter(mom, value) { + var dayOfMonth; - var ids = Array.isArray(id) ? id : [id]; + // TODO: Move this out of here! + if (typeof value === 'string') { + value = mom.localeData().monthsParse(value); + // TODO: Another silent failure? + if (typeof value !== 'number') { + return mom; + } + } - // get the specified item(s) - var itemsData = this.itemsData.getDataSet().get(ids, { - type: { - start: 'Date', - end: 'Date' + dayOfMonth = Math.min(mom.date(), + daysInMonth(mom.year(), value)); + mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); + return mom; } - }); - - // calculate minimum start and maximum end of specified items - var start = null; - var end = null; - itemsData.forEach(function (itemData) { - var s = itemData.start.valueOf(); - var e = 'end' in itemData ? itemData.end.valueOf() : itemData.start.valueOf(); - if (start === null || s < start) { - start = s; + function rawGetter(mom, unit) { + return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit](); } - if (end === null || e > end) { - end = e; + function rawSetter(mom, unit, value) { + if (unit === 'Month') { + return rawMonthSetter(mom, value); + } else { + return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); + } } - }); - if (start !== null && end !== null) { - // calculate the new middle and interval for the window - var middle = (start + end) / 2; - var interval = Math.max((this.range.end - this.range.start), (end - start) * 1.1); + function makeAccessor(unit, keepTime) { + return function (value) { + if (value != null) { + rawSetter(this, unit, value); + moment.updateOffset(this, keepTime); + return this; + } else { + return rawGetter(this, unit); + } + }; + } - var animate = (options && options.animate !== undefined) ? options.animate : true; - this.range.setRange(middle - interval / 2, middle + interval / 2, animate); - } - }; + moment.fn.millisecond = moment.fn.milliseconds = makeAccessor('Milliseconds', false); + moment.fn.second = moment.fn.seconds = makeAccessor('Seconds', false); + moment.fn.minute = moment.fn.minutes = makeAccessor('Minutes', false); + // Setting the hour should keep the time, because the user explicitly + // specified which hour he wants. So trying to maintain the same hour (in + // a new timezone) makes sense. Adding/subtracting hours does not follow + // this rule. + 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.year = makeAccessor('FullYear', true); + moment.fn.years = deprecate('years accessor is deprecated. Use year instead.', makeAccessor('FullYear', true)); - /** - * Get the data range of the item set. - * @returns {{min: Date, max: Date}} range A range with a start and end Date. - * When no minimum is found, min==null - * When no maximum is found, max==null - */ - Timeline.prototype.getItemRange = function() { - // calculate min from start filed - var dataset = this.itemsData.getDataSet(), - min = null, - max = null; + // add plural methods + moment.fn.days = moment.fn.day; + moment.fn.months = moment.fn.month; + moment.fn.weeks = moment.fn.week; + moment.fn.isoWeeks = moment.fn.isoWeek; + moment.fn.quarters = moment.fn.quarter; - if (dataset) { - // calculate the minimum value of the field 'start' - var minItem = dataset.min('start'); - min = minItem ? util.convert(minItem.start, 'Date').valueOf() : null; - // Note: we convert first to Date and then to number because else - // a conversion from ISODate to Number will fail + // add aliased format methods + moment.fn.toJSON = moment.fn.toISOString; - // calculate maximum value of fields 'start' and 'end' - var maxStartItem = dataset.max('start'); - if (maxStartItem) { - max = util.convert(maxStartItem.start, 'Date').valueOf(); - } - var maxEndItem = dataset.max('end'); - if (maxEndItem) { - if (max == null) { - max = util.convert(maxEndItem.end, 'Date').valueOf(); - } - else { - max = Math.max(max, util.convert(maxEndItem.end, 'Date').valueOf()); - } - } - } + // alias isUtc for dev-friendliness + moment.fn.isUTC = moment.fn.isUtc; - return { - min: (min != null) ? new Date(min) : null, - max: (max != null) ? new Date(max) : null - }; - }; + /************************************ + Duration Prototype + ************************************/ - module.exports = Timeline; + 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; + } -/***/ }, -/* 14 */ -/***/ function(module, exports, __webpack_require__) { + extend(moment.duration.fn = Duration.prototype, { - var Emitter = __webpack_require__(56); - var Hammer = __webpack_require__(45); - var util = __webpack_require__(1); - var DataSet = __webpack_require__(3); - var DataView = __webpack_require__(4); - var Range = __webpack_require__(17); - var Core = __webpack_require__(46); - var TimeAxis = __webpack_require__(30); - var CurrentTime = __webpack_require__(21); - var CustomTime = __webpack_require__(22); - var LineGraph = __webpack_require__(29); + _bubble : function () { + var milliseconds = this._milliseconds, + days = this._days, + months = this._months, + data = this._data, + seconds, minutes, hours, years = 0; - /** - * Create a timeline visualization - * @param {HTMLElement} container - * @param {vis.DataSet | Array | google.visualization.DataTable} [items] - * @param {Object} [options] See Graph2d.setOptions for the available options. - * @constructor - * @extends Core - */ - function Graph2d (container, items, groups, options) { - // if the third element is options, the forth is groups (optionally); - if (!(Array.isArray(groups) || groups instanceof DataSet) && groups instanceof Object) { - var forthArgument = options; - options = groups; - groups = forthArgument; - } + // The following code bubbles up values, see the tests for + // examples of what that means. + data.milliseconds = milliseconds % 1000; - var me = this; - this.defaultOptions = { - start: null, - end: null, + seconds = absRound(milliseconds / 1000); + data.seconds = seconds % 60; - autoResize: true, + minutes = absRound(seconds / 60); + data.minutes = minutes % 60; - orientation: 'bottom', - width: null, - height: null, - maxHeight: null, - minHeight: null - }; - this.options = util.deepExtend({}, this.defaultOptions); + hours = absRound(minutes / 60); + data.hours = hours % 24; - // Create the DOM, props, and emitter - this._create(container); + days += absRound(hours / 24); - // all components listed here will be repainted automatically - this.components = []; + // Accurately convert days to years, assume start from year 0. + years = absRound(daysToYears(days)); + days -= absRound(yearsToDays(years)); - this.body = { - dom: this.dom, - domProps: this.props, - emitter: { - on: this.on.bind(this), - off: this.off.bind(this), - emit: this.emit.bind(this) - }, - hiddenDates: [], - util: { - snap: null, // will be specified after TimeAxis is created - toScreen: me._toScreen.bind(me), - toGlobalScreen: me._toGlobalScreen.bind(me), // this refers to the root.width - toTime: me._toTime.bind(me), - toGlobalTime : me._toGlobalTime.bind(me) - } - }; + // 30 days to a month + // TODO (iskren): Use anchor date (like 1st Jan) to compute this. + months += absRound(days / 30); + days %= 30; - // range - this.range = new Range(this.body); - this.components.push(this.range); - this.body.range = this.range; + // 12 months -> 1 year + years += absRound(months / 12); + months %= 12; - // time axis - this.timeAxis = new TimeAxis(this.body); - this.components.push(this.timeAxis); - this.body.util.snap = this.timeAxis.snap.bind(this.timeAxis); + data.days = days; + data.months = months; + data.years = years; + }, - // current time bar - this.currentTime = new CurrentTime(this.body); - this.components.push(this.currentTime); + abs : function () { + this._milliseconds = Math.abs(this._milliseconds); + this._days = Math.abs(this._days); + this._months = Math.abs(this._months); - // custom time bar - // Note: time bar will be attached in this.setOptions when selected - this.customTime = new CustomTime(this.body); - this.components.push(this.customTime); + 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); - // item set - this.linegraph = new LineGraph(this.body); - this.components.push(this.linegraph); + return this; + }, - this.itemsData = null; // DataSet - this.groupsData = null; // DataSet + weeks : function () { + return absRound(this.days() / 7); + }, - // apply options - if (options) { - this.setOptions(options); - } + valueOf : function () { + return this._milliseconds + + this._days * 864e5 + + (this._months % 12) * 2592e6 + + toInt(this._months / 12) * 31536e6; + }, - // IMPORTANT: THIS HAPPENS BEFORE SET ITEMS! - if (groups) { - this.setGroups(groups); - } + humanize : function (withSuffix) { + var output = relativeTime(this, !withSuffix, this.localeData()); - // create itemset - if (items) { - this.setItems(items); - } - else { - this.redraw(); - } - } + if (withSuffix) { + output = this.localeData().pastFuture(+this, output); + } - // Extend the functionality from Core - Graph2d.prototype = new Core(); + return this.localeData().postformat(output); + }, - /** - * Set items - * @param {vis.DataSet | Array | google.visualization.DataTable | null} items - */ - Graph2d.prototype.setItems = function(items) { - var initialLoad = (this.itemsData == null); + add : function (input, val) { + // supports only 2.0-style add(1, 's') or add(moment) + var dur = moment.duration(input, val); - // convert to type DataSet when needed - var newDataSet; - if (!items) { - newDataSet = null; - } - else if (items instanceof DataSet || items instanceof DataView) { - newDataSet = items; - } - else { - // turn an array into a dataset - newDataSet = new DataSet(items, { - type: { - start: 'Date', - end: 'Date' - } - }); - } + this._milliseconds += dur._milliseconds; + this._days += dur._days; + this._months += dur._months; - // set items - this.itemsData = newDataSet; - this.linegraph && this.linegraph.setItems(newDataSet); + this._bubble(); - if (initialLoad) { - if (this.options.start != undefined || this.options.end != undefined) { - var start = this.options.start != undefined ? this.options.start : null; - var end = this.options.end != undefined ? this.options.end : null; + return this; + }, - this.setWindow(start, end, {animate: false}); - } - else { - this.fit({animate: false}); - } - } - }; + subtract : function (input, val) { + var dur = moment.duration(input, val); - /** - * Set groups - * @param {vis.DataSet | Array | google.visualization.DataTable} groups - */ - Graph2d.prototype.setGroups = function(groups) { - // convert to type DataSet when needed - var newDataSet; - if (!groups) { - newDataSet = null; - } - else if (groups instanceof DataSet || groups instanceof DataView) { - newDataSet = groups; - } - else { - // turn an array into a dataset - newDataSet = new DataSet(groups); - } + this._milliseconds -= dur._milliseconds; + this._days -= dur._days; + this._months -= dur._months; - this.groupsData = newDataSet; - this.linegraph.setGroups(newDataSet); - }; + this._bubble(); - /** - * Returns an object containing an SVG element with the icon of the group (size determined by iconWidth and iconHeight), the label of the group (content) and the yAxisOrientation of the group (left or right). - * @param groupId - * @param width - * @param height - */ - Graph2d.prototype.getLegend = function(groupId, width, height) { - if (width === undefined) {width = 15;} - if (height === undefined) {height = 15;} - if (this.linegraph.groups[groupId] !== undefined) { - return this.linegraph.groups[groupId].getLegend(width,height); - } - else { - return "cannot find group:" + groupId; - } - } + return this; + }, - /** - * This checks if the visible option of the supplied group (by ID) is true or false. - * @param groupId - * @returns {*} - */ - Graph2d.prototype.isGroupVisible = function(groupId) { - if (this.linegraph.groups[groupId] !== undefined) { - return (this.linegraph.groups[groupId].visible && (this.linegraph.options.groups.visibility[groupId] === undefined || this.linegraph.options.groups.visibility[groupId] == true)); - } - else { - return false; - } - } + get : function (units) { + units = normalizeUnits(units); + return this[units.toLowerCase() + 's'](); + }, + as : function (units) { + var days, months; + units = normalizeUnits(units); - /** - * Get the data range of the item set. - * @returns {{min: Date, max: Date}} range A range with a start and end Date. - * When no minimum is found, min==null - * When no maximum is found, max==null - */ - Graph2d.prototype.getItemRange = function() { - var min = null; - var max = null; + if (units === 'month' || units === 'year') { + days = this._days + this._milliseconds / 864e5; + months = this._months + daysToYears(days) * 12; + return units === 'month' ? months : months / 12; + } else { + // handle milliseconds separately because of floating point math errors (issue #1867) + days = this._days + Math.round(yearsToDays(this._months / 12)); + switch (units) { + case 'week': return days / 7 + this._milliseconds / 6048e5; + case 'day': return days + this._milliseconds / 864e5; + case 'hour': return days * 24 + this._milliseconds / 36e5; + case 'minute': return days * 24 * 60 + this._milliseconds / 6e4; + case 'second': return days * 24 * 60 * 60 + this._milliseconds / 1000; + // Math.floor prevents floating point math errors here + case 'millisecond': return Math.floor(days * 24 * 60 * 60 * 1000) + this._milliseconds; + default: throw new Error('Unknown unit ' + units); + } + } + }, - // calculate min from start filed - for (var groupId in this.linegraph.groups) { - if (this.linegraph.groups.hasOwnProperty(groupId)) { - if (this.linegraph.groups[groupId].visible == true) { - for (var i = 0; i < this.linegraph.groups[groupId].itemsData.length; i++) { - var item = this.linegraph.groups[groupId].itemsData[i]; - var value = util.convert(item.x, 'Date').valueOf(); - min = min == null ? value : min > value ? value : min; - max = max == null ? value : max < value ? value : max; - } - } - } - } + lang : moment.fn.lang, + locale : moment.fn.locale, - return { - min: (min != null) ? new Date(min) : null, - max: (max != null) ? new Date(max) : null - }; - }; + toIsoString : deprecate( + 'toIsoString() is deprecated. Please use toISOString() instead ' + + '(notice the capitals)', + function () { + return this.toISOString(); + } + ), + 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()), + days = Math.abs(this.days()), + hours = Math.abs(this.hours()), + minutes = Math.abs(this.minutes()), + seconds = Math.abs(this.seconds() + this.milliseconds() / 1000); + if (!this.asSeconds()) { + // this is the same as C#'s (Noda) and python (isodate)... + // but not other JS (goog.date) + return 'P0D'; + } - module.exports = Graph2d; + return (this.asSeconds() < 0 ? '-' : '') + + 'P' + + (years ? years + 'Y' : '') + + (months ? months + 'M' : '') + + (days ? days + 'D' : '') + + ((hours || minutes || seconds) ? 'T' : '') + + (hours ? hours + 'H' : '') + + (minutes ? minutes + 'M' : '') + + (seconds ? seconds + 'S' : ''); + }, + localeData : function () { + return this._locale; + }, -/***/ }, -/* 15 */ -/***/ function(module, exports, __webpack_require__) { + toJSON : function () { + return this.toISOString(); + } + }); - /** - * Created by Alex on 10/3/2014. - */ - var moment = __webpack_require__(44); + moment.duration.fn.toString = moment.duration.fn.toISOString; + function makeDurationGetter(name) { + moment.duration.fn[name] = function () { + return this._data[name]; + }; + } - /** - * used in Core to convert the options into a volatile variable - * - * @param Core - */ - exports.convertHiddenOptions = function(body, hiddenDates) { - body.hiddenDates = []; - if (hiddenDates) { - if (Array.isArray(hiddenDates) == true) { - for (var i = 0; i < hiddenDates.length; i++) { - if (hiddenDates[i].repeat === undefined) { - var dateItem = {}; - dateItem.start = moment(hiddenDates[i].start).toDate().valueOf(); - dateItem.end = moment(hiddenDates[i].end).toDate().valueOf(); - body.hiddenDates.push(dateItem); + for (i in unitMillisecondFactors) { + if (hasOwnProp(unitMillisecondFactors, i)) { + makeDurationGetter(i.toLowerCase()); } - } - body.hiddenDates.sort(function (a, b) { - return a.start - b.start; - }); // sort by start time } - } - }; + 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.as('M'); + }; + moment.duration.fn.asYears = function () { + return this.as('y'); + }; - /** - * create new entrees for the repeating hidden dates - * @param body - * @param hiddenDates - */ - exports.updateHiddenDates = function (body, hiddenDates) { - if (hiddenDates && body.domProps.centerContainer.width !== undefined) { - exports.convertHiddenOptions(body, hiddenDates); + /************************************ + Default Locale + ************************************/ - var start = moment(body.range.start); - var end = moment(body.range.end); - var totalRange = (body.range.end - body.range.start); - var pixelTime = totalRange / body.domProps.centerContainer.width; + // Set default locale, other locale will inherit from English. + moment.locale('en', { + ordinalParse: /\d{1,2}(th|st|nd|rd)/, + ordinal : function (number) { + var b = number % 10, + output = (toInt(number % 100 / 10) === 1) ? 'th' : + (b === 1) ? 'st' : + (b === 2) ? 'nd' : + (b === 3) ? 'rd' : 'th'; + return number + output; + } + }); - for (var i = 0; i < hiddenDates.length; i++) { - if (hiddenDates[i].repeat !== undefined) { - var startDate = moment(hiddenDates[i].start); - var endDate = moment(hiddenDates[i].end); + /* EMBED_LOCALES */ - if (startDate._d == "Invalid Date") { - throw new Error("Supplied start date is not valid: " + hiddenDates[i].start); + /************************************ + Exposing Moment + ************************************/ + + function makeGlobal(shouldDeprecate) { + /*global ender:false */ + if (typeof ender !== 'undefined') { + return; } - if (endDate._d == "Invalid Date") { - throw new Error("Supplied end date is not valid: " + hiddenDates[i].end); + oldGlobalMoment = globalScope.moment; + if (shouldDeprecate) { + globalScope.moment = deprecate( + 'Accessing Moment through the global scope is ' + + 'deprecated, and will be removed in an upcoming ' + + 'release.', + moment); + } else { + globalScope.moment = moment; } + } - var duration = endDate - startDate; - if (duration >= 4 * pixelTime) { + // CommonJS module is defined + if (hasModule) { + module.exports = moment; + } else if (true) { + !(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) { + if (module.config && module.config() && module.config().noGlobal === true) { + // release the global variable + globalScope.moment = oldGlobalMoment; + } - var offset = 0; - var runUntil = end.clone(); - switch (hiddenDates[i].repeat) { - case "daily": // case of time - if (startDate.day() != endDate.day()) { - offset = 1; - } - startDate.dayOfYear(start.dayOfYear()); - startDate.year(start.year()); - startDate.subtract(7,'days'); + return moment; + }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + makeGlobal(true); + } else { + makeGlobal(); + } + }).call(this); + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()), __webpack_require__(5)(module))) - endDate.dayOfYear(start.dayOfYear()); - endDate.year(start.year()); - endDate.subtract(7 - offset,'days'); +/***/ }, +/* 4 */ +/***/ function(module, exports, __webpack_require__) { - runUntil.add(1, 'weeks'); - break; - case "weekly": - var dayOffset = endDate.diff(startDate,'days') - var day = startDate.day(); + function webpackContext(req) { + throw new Error("Cannot find module '" + req + "'."); + } + webpackContext.keys = function() { return []; }; + webpackContext.resolve = webpackContext; + module.exports = webpackContext; + webpackContext.id = 4; - // set the start date to the range.start - startDate.date(start.date()); - startDate.month(start.month()); - startDate.year(start.year()); - endDate = startDate.clone(); - // force - startDate.day(day); - endDate.day(day); - endDate.add(dayOffset,'days'); +/***/ }, +/* 5 */ +/***/ function(module, exports, __webpack_require__) { - startDate.subtract(1,'weeks'); - endDate.subtract(1,'weeks'); + module.exports = function(module) { + if(!module.webpackPolyfill) { + module.deprecate = function() {}; + module.paths = []; + // module.parent = undefined by default + module.children = []; + module.webpackPolyfill = 1; + } + return module; + } - runUntil.add(1, 'weeks'); - break - case "monthly": - if (startDate.month() != endDate.month()) { - offset = 1; - } - startDate.month(start.month()); - startDate.year(start.year()); - startDate.subtract(1,'months'); - endDate.month(start.month()); - endDate.year(start.year()); - endDate.subtract(1,'months'); - endDate.add(offset,'months'); +/***/ }, +/* 6 */ +/***/ function(module, exports, __webpack_require__) { - runUntil.add(1, 'months'); - break; - case "yearly": - if (startDate.year() != endDate.year()) { - offset = 1; - } - startDate.year(start.year()); - startDate.subtract(1,'years'); - endDate.year(start.year()); - endDate.subtract(1,'years'); - endDate.add(offset,'years'); + // DOM utility methods - runUntil.add(1, 'years'); - break; - default: - console.log("Wrong repeat format, allowed are: daily, weekly, monthly, yearly. Given:", hiddenDates[i].repeat); - return; - } - while (startDate < runUntil) { - body.hiddenDates.push({start: startDate.valueOf(), end: endDate.valueOf()}); - switch (hiddenDates[i].repeat) { - case "daily": - startDate.add(1, 'days'); - endDate.add(1, 'days'); - break; - case "weekly": - startDate.add(1, 'weeks'); - endDate.add(1, 'weeks'); - break - case "monthly": - startDate.add(1, 'months'); - endDate.add(1, 'months'); - break; - case "yearly": - startDate.add(1, 'y'); - endDate.add(1, 'y'); - break; - default: - console.log("Wrong repeat format, allowed are: daily, weekly, monthly, yearly. Given:", hiddenDates[i].repeat); - return; - } - } - body.hiddenDates.push({start: startDate.valueOf(), end: endDate.valueOf()}); + /** + * this prepares the JSON container for allocating SVG elements + * @param JSONcontainer + * @private + */ + exports.prepareElements = function(JSONcontainer) { + // cleanup the redundant svgElements; + for (var elementType in JSONcontainer) { + if (JSONcontainer.hasOwnProperty(elementType)) { + JSONcontainer[elementType].redundant = JSONcontainer[elementType].used; + JSONcontainer[elementType].used = []; + } + } + }; + + /** + * this cleans up all the unused SVG elements. By asking for the parentNode, we only need to supply the JSON container from + * which to remove the redundant elements. + * + * @param JSONcontainer + * @private + */ + exports.cleanupElements = function(JSONcontainer) { + // cleanup the redundant svgElements; + for (var elementType in JSONcontainer) { + if (JSONcontainer.hasOwnProperty(elementType)) { + if (JSONcontainer[elementType].redundant) { + for (var i = 0; i < JSONcontainer[elementType].redundant.length; i++) { + JSONcontainer[elementType].redundant[i].parentNode.removeChild(JSONcontainer[elementType].redundant[i]); } + JSONcontainer[elementType].redundant = []; } } - // remove duplicates, merge where possible - exports.removeDuplicates(body); - // ensure the new positions are not on hidden dates - var startHidden = exports.isHidden(body.range.start, body.hiddenDates); - var endHidden = exports.isHidden(body.range.end,body.hiddenDates); - var rangeStart = body.range.start; - var rangeEnd = body.range.end; - if (startHidden.hidden == true) {rangeStart = body.range.startToFront == true ? startHidden.startDate - 1 : startHidden.endDate + 1;} - if (endHidden.hidden == true) {rangeEnd = body.range.endToFront == true ? endHidden.startDate - 1 : endHidden.endDate + 1;} - if (startHidden.hidden == true || endHidden.hidden == true) { - body.range._applyRange(rangeStart, rangeEnd); - } } + }; - } + /** + * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer + * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this. + * + * @param elementType + * @param JSONcontainer + * @param svgContainer + * @returns {*} + * @private + */ + exports.getSVGElement = function (elementType, JSONcontainer, svgContainer) { + var element; + // allocate SVG element, if it doesnt yet exist, create one. + if (JSONcontainer.hasOwnProperty(elementType)) { // this element has been created before + // check if there is an redundant element + if (JSONcontainer[elementType].redundant.length > 0) { + element = JSONcontainer[elementType].redundant[0]; + JSONcontainer[elementType].redundant.shift(); + } + else { + // create a new element and add it to the SVG + element = document.createElementNS('http://www.w3.org/2000/svg', elementType); + svgContainer.appendChild(element); + } + } + else { + // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it. + element = document.createElementNS('http://www.w3.org/2000/svg', elementType); + JSONcontainer[elementType] = {used: [], redundant: []}; + svgContainer.appendChild(element); + } + JSONcontainer[elementType].used.push(element); + return element; + }; /** - * remove duplicates from the hidden dates list. Duplicates are evil. They mess everything up. - * Scales with N^2 - * @param body + * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer + * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this. + * + * @param elementType + * @param JSONcontainer + * @param DOMContainer + * @returns {*} + * @private */ - exports.removeDuplicates = function(body) { - var hiddenDates = body.hiddenDates; - var safeDates = []; - for (var i = 0; i < hiddenDates.length; i++) { - for (var j = 0; j < hiddenDates.length; j++) { - if (i != j && hiddenDates[j].remove != true && hiddenDates[i].remove != true) { - // j inside i - if (hiddenDates[j].start >= hiddenDates[i].start && hiddenDates[j].end <= hiddenDates[i].end) { - hiddenDates[j].remove = true; - } - // j start inside i - else if (hiddenDates[j].start >= hiddenDates[i].start && hiddenDates[j].start <= hiddenDates[i].end) { - hiddenDates[i].end = hiddenDates[j].end; - hiddenDates[j].remove = true; - } - // j end inside i - else if (hiddenDates[j].end >= hiddenDates[i].start && hiddenDates[j].end <= hiddenDates[i].end) { - hiddenDates[i].start = hiddenDates[j].start; - hiddenDates[j].remove = true; - } + exports.getDOMElement = function (elementType, JSONcontainer, DOMContainer, insertBefore) { + var element; + // allocate DOM element, if it doesnt yet exist, create one. + if (JSONcontainer.hasOwnProperty(elementType)) { // this element has been created before + // check if there is an redundant element + if (JSONcontainer[elementType].redundant.length > 0) { + element = JSONcontainer[elementType].redundant[0]; + JSONcontainer[elementType].redundant.shift(); + } + else { + // create a new element and add it to the SVG + element = document.createElement(elementType); + if (insertBefore !== undefined) { + DOMContainer.insertBefore(element, insertBefore); + } + else { + DOMContainer.appendChild(element); } } } - - for (var i = 0; i < hiddenDates.length; i++) { - if (hiddenDates[i].remove !== true) { - safeDates.push(hiddenDates[i]); + else { + // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it. + element = document.createElement(elementType); + JSONcontainer[elementType] = {used: [], redundant: []}; + if (insertBefore !== undefined) { + DOMContainer.insertBefore(element, insertBefore); + } + else { + DOMContainer.appendChild(element); } } + JSONcontainer[elementType].used.push(element); + return element; + }; + - body.hiddenDates = safeDates; - body.hiddenDates.sort(function (a, b) { - return a.start - b.start; - }); // sort by start time - } - exports.printDates = function(dates) { - for (var i =0; i < dates.length; i++) { - console.log(i, new Date(dates[i].start),new Date(dates[i].end), dates[i].start, dates[i].end, dates[i].remove); - } - } /** - * Used in TimeStep to avoid the hidden times. - * @param timeStep - * @param previousTime + * draw a point object. this is a seperate function because it can also be called by the legend. + * The reason the JSONcontainer and the target SVG svgContainer have to be supplied is so the legend can use these functions + * as well. + * + * @param x + * @param y + * @param group + * @param JSONcontainer + * @param svgContainer + * @returns {*} */ - exports.stepOverHiddenDates = function(timeStep, previousTime) { - var stepInHidden = false; - var currentValue = timeStep.current.valueOf(); - for (var i = 0; i < timeStep.hiddenDates.length; i++) { - var startDate = timeStep.hiddenDates[i].start; - var endDate = timeStep.hiddenDates[i].end; - if (currentValue >= startDate && currentValue < endDate) { - stepInHidden = true; - break; - } + exports.drawPoint = function(x, y, group, JSONcontainer, svgContainer) { + var point; + if (group.options.drawPoints.style == 'circle') { + point = exports.getSVGElement('circle',JSONcontainer,svgContainer); + point.setAttributeNS(null, "cx", x); + point.setAttributeNS(null, "cy", y); + point.setAttributeNS(null, "r", 0.5 * group.options.drawPoints.size); + } + else { + point = exports.getSVGElement('rect',JSONcontainer,svgContainer); + point.setAttributeNS(null, "x", x - 0.5*group.options.drawPoints.size); + point.setAttributeNS(null, "y", y - 0.5*group.options.drawPoints.size); + point.setAttributeNS(null, "width", group.options.drawPoints.size); + point.setAttributeNS(null, "height", group.options.drawPoints.size); } - if (stepInHidden == true && currentValue < timeStep._end.valueOf() && currentValue != previousTime) { - var prevValue = moment(previousTime); - var newValue = moment(endDate); - //check if the next step should be major - if (prevValue.year() != newValue.year()) {timeStep.switchedYear = true;} - else if (prevValue.month() != newValue.month()) {timeStep.switchedMonth = true;} - else if (prevValue.dayOfYear() != newValue.dayOfYear()) {timeStep.switchedDay = true;} + if(group.options.drawPoints.styles !== undefined) { + point.setAttributeNS(null, "style", group.group.options.drawPoints.styles); + } + point.setAttributeNS(null, "class", group.className + " point"); + return point; + }; - timeStep.current = newValue.toDate(); + /** + * draw a bar SVG element centered on the X coordinate + * + * @param x + * @param y + * @param className + */ + exports.drawBar = function (x, y, width, height, className, JSONcontainer, svgContainer) { + if (height != 0) { + if (height < 0) { + height *= -1; + y -= height; + } + var rect = exports.getSVGElement('rect',JSONcontainer, svgContainer); + rect.setAttributeNS(null, "x", x - 0.5 * width); + rect.setAttributeNS(null, "y", y); + rect.setAttributeNS(null, "width", width); + rect.setAttributeNS(null, "height", height); + rect.setAttributeNS(null, "class", className); } }; +/***/ }, +/* 7 */ +/***/ function(module, exports, __webpack_require__) { - ///** - // * Used in TimeStep to avoid the hidden times. - // * @param timeStep - // * @param previousTime - // */ - //exports.checkFirstStep = function(timeStep) { - // var stepInHidden = false; - // var currentValue = timeStep.current.valueOf(); - // for (var i = 0; i < timeStep.hiddenDates.length; i++) { - // var startDate = timeStep.hiddenDates[i].start; - // var endDate = timeStep.hiddenDates[i].end; - // if (currentValue >= startDate && currentValue < endDate) { - // stepInHidden = true; - // break; - // } - // } - // - // if (stepInHidden == true && currentValue <= timeStep._end.valueOf()) { - // var newValue = moment(endDate); - // timeStep.current = newValue.toDate(); - // } - //}; + var util = __webpack_require__(1); + var Queue = __webpack_require__(8); /** - * replaces the Core toScreen methods - * @param Core - * @param time - * @param width - * @returns {number} + * DataSet + * + * Usage: + * var dataSet = new DataSet({ + * fieldId: '_id', + * type: { + * // ... + * } + * }); + * + * dataSet.add(item); + * dataSet.add(data); + * dataSet.update(item); + * dataSet.update(data); + * dataSet.remove(id); + * dataSet.remove(ids); + * var data = dataSet.get(); + * var data = dataSet.get(id); + * var data = dataSet.get(ids); + * var data = dataSet.get(ids, options, data); + * dataSet.clear(); + * + * A data set can: + * - add/remove/update data + * - gives triggers upon changes in the data + * - can import/export data in various data formats + * + * @param {Array | DataTable} [data] Optional array with initial data + * @param {Object} [options] Available options: + * {String} fieldId Field name of the id in the + * items, 'id' by default. + * {Object.