diff --git a/css/style.css b/css/style.css index 60e54dab..81f2465b 100644 --- a/css/style.css +++ b/css/style.css @@ -1,11 +1,21 @@ +body { + font-family: 'dejavu sans', verdana, arial, serif; + font-size: 11pt; +} + +h1 { + font-size: 48px; + line-height: 0.9em; +} #menu { position: absolute; - left: -170px; + left: -200px; top: 35px; - background-color: #a7c8f9; - padding: 15px; - border-radius: 3px; + padding: 0 20px; + border-radius: 2px; + background-color: #f5f5f5; + box-shadow: 5px 5px 15px rgba(128,128,128,0.5); } #forkme { @@ -16,7 +26,8 @@ } div.nav { - text-align: center; + text-align: left; + padding-left: 24px; } div.nav ul { @@ -52,14 +63,14 @@ div.nav ul li ul li { div.nav a { color: #2B7CE9; - color: white; - font-weight: bold; } .subtitle { - color: gray; text-transform: uppercase; font-size: 11pt; + font-weight: normal; + font-style: italic; + margin-left: 40px; } .download td { diff --git a/dist/vis.css b/dist/vis.css index a841904e..1f2c2de7 100644 --- a/dist/vis.css +++ b/dist/vis.css @@ -7,81 +7,76 @@ overflow: hidden; border: 1px solid #bfbfbf; - -moz-box-sizing: border-box; box-sizing: border-box; + + /* FIXME: there is an issue with the height of the items when panel height is animated + -webkit-transition: height 4s ease-in-out; + transition: height 4s ease-in-out; + /**/ } .vis.timeline .vpanel { position: absolute; overflow: hidden; -} - -.vis.timeline .groupset { - position: absolute; - padding: 0; - margin: 0; + box-sizing: border-box; } -.vis.timeline .labels { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - - padding: 0; - margin: 0; - +.vis.timeline .vpanel.side { border-right: 1px solid #bfbfbf; - -moz-box-sizing: border-box; - box-sizing: border-box; } -.vis.timeline .labels .label-set { - position: absolute; - top: 0; - left: 0; +.vis.timeline .vpanel.side.hidden { + display: none; +} + + +.vis.timeline .labelset { + position: relative; width: 100%; - height: 100%; overflow: hidden; - border-top: none; - border-bottom: 1px solid #bfbfbf; + box-sizing: border-box; } -.vis.timeline .labels .label-set .vlabel { - position: absolute; +.vis.timeline .labelset .vlabel { + position: relative; left: 0; top: 0; width: 100%; color: #4d4d4d; + + box-sizing: border-box; } -.vis.timeline.top .labels .label-set .vlabel, -.vis.timeline.top .groupset .itemset-axis { +.vis.timeline.top .labelset .vlabel { border-top: 1px solid #bfbfbf; border-bottom: none; } -.vis.timeline.bottom .labels .label-set .vlabel, -.vis.timeline.bottom .groupset .itemset-axis { +.vis.timeline.bottom .labelset .vlabel { border-top: none; border-bottom: 1px solid #bfbfbf; } -.vis.timeline .labels .label-set .vlabel .inner { +.vis.timeline .labelset .vlabel .inner { display: inline-block; padding: 5px; } .vis.timeline .itemset { - position: absolute; + position: relative; padding: 0; margin: 0; - overflow: hidden; + + box-sizing: border-box; + + /* FIXME: get transition working for rootpanel and itemset + -webkit-transition: height 4s ease-in-out; + transition: height 4s ease-in-out; + /**/ } .vis.timeline .background { @@ -90,8 +85,23 @@ .vis.timeline .foreground { } -.vis.timeline .itemset-axis { - position: absolute; +.vis.timeline .axis { + overflow: visible; +} + +.vis.timeline .group { + position: relative; + box-sizing: border-box; +} + +.vis.timeline.top .group { + border-top: 1px solid #bfbfbf; + border-bottom: none; +} + +.vis.timeline.bottom .group { + border-top: none; + border-bottom: 1px solid #bfbfbf; } @@ -99,9 +109,15 @@ position: absolute; color: #1A1A1A; border-color: #97B0F8; + border-width: 1px; background-color: #D5DDF6; display: inline-block; padding: 5px; + + /* TODO: enable css transitions + -webkit-transition: top .4s ease-in-out, bottom .4s ease-in-out; + transition: top .4s ease-in-out, bottom .4s ease-in-out; + /**/ } .vis.timeline .item.selected { @@ -116,49 +132,30 @@ .vis.timeline .item.point.selected { background-color: #FFF785; - z-index: 999; -} -.vis.timeline .item.point.selected .dot { - border-color: #FFC200; -} - -.vis.timeline .item.cluster { - /* TODO: use another color or pattern? */ - background: #97B0F8 url('img/cluster_bg.png'); - color: white; -} -.vis.timeline .item.cluster.point { - border-color: #D5DDF6; } .vis.timeline .item.box { text-align: center; border-style: solid; - border-width: 1px; - border-radius: 5px; - -moz-border-radius: 5px; /* For Firefox 3.6 and older */ + border-radius: 2px; } .vis.timeline .item.point { background: none; } -.vis.timeline .dot, .vis.timeline .item.dot { - padding: 0; - border: 5px solid #97B0F8; position: absolute; - border-radius: 5px; - -moz-border-radius: 5px; /* For Firefox 3.6 and older */ + padding: 0; + border-width: 4px; + border-style: solid; + border-radius: 4px; } .vis.timeline .item.range, .vis.timeline .item.rangeoverflow{ border-style: solid; - border-width: 1px; border-radius: 2px; - -moz-border-radius: 2px; /* For Firefox 3.6 and older */ - -moz-box-sizing: border-box; box-sizing: border-box; } @@ -179,6 +176,11 @@ width: 0; border-left-width: 1px; border-left-style: solid; + + /* TODO: enable css transitions + -webkit-transition: height .4s ease-in-out, top .4s ease-in-out; + transition: height .4s ease-in-out, top .4s ease-in-out; + /**/ } .vis.timeline .item .content { @@ -220,18 +222,18 @@ z-index: 10001; /* a little higher z-index than .drag-left */ } -.vis.timeline .axis { - position: relative; +.vis.timeline .timeaxis { + position: absolute; } -.vis.timeline .axis .text { +.vis.timeline .timeaxis .text { position: absolute; color: #4d4d4d; padding: 3px; white-space: nowrap; } -.vis.timeline .axis .text.measure { +.vis.timeline .timeaxis .text.measure { position: absolute; padding-left: 0; padding-right: 0; @@ -240,13 +242,13 @@ visibility: hidden; } -.vis.timeline .axis .grid.vertical { +.vis.timeline .timeaxis .grid.vertical { position: absolute; width: 0; border-right: 1px solid; } -.vis.timeline .axis .grid.horizontal { +.vis.timeline .timeaxis .grid.horizontal { position: absolute; left: 0; width: 100%; @@ -254,11 +256,11 @@ border-bottom: 1px solid; } -.vis.timeline .axis .grid.minor { +.vis.timeline .timeaxis .grid.minor { border-color: #e5e5e5; } -.vis.timeline .axis .grid.major { +.vis.timeline .timeaxis .grid.major { border-color: #bfbfbf; } diff --git a/dist/vis.js b/dist/vis.js index 391a3601..21df11ec 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -4,8 +4,8 @@ * * A dynamic, browser-based visualization library. * - * @version 0.7.4 - * @date 2014-04-18 + * @version 1.0.0 + * @date 2014-05-02 * * @license * Copyright (C) 2011-2014 Almende B.V, http://almende.com @@ -407,6 +407,23 @@ util.extend = function (a, b) { return a; }; +/** + * Test whether all elements in two arrays are equal. + * @param {Array} a + * @param {Array} b + * @return {boolean} Returns true if both arrays have the same length and same + * elements. + */ +util.equalArray = function (a, b) { + if (a.length != b.length) return false; + + for (var i = 1, len = a.length; i < len; i++) { + if (a[i] != b[i]) return false; + } + + return true; +}; + /** * Convert an object to another type * @param {Boolean | Number | String | Date | Moment | Null | undefined} object @@ -750,6 +767,22 @@ util.forEach = function forEach (object, callback) { } }; +/** + * Convert an object into an array: all objects properties are put into the + * array. The resulting array is unordered. + * @param {Object} object + * @param {Array} array + */ +util.toArray = function toArray(object) { + var array = []; + + for (var prop in object) { + if (object.hasOwnProperty(prop)) array.push(object[prop]); + } + + return array; +} + /** * Update a property in an object * @param {Object} object @@ -757,7 +790,7 @@ util.forEach = function forEach (object, callback) { * @param {*} value * @return {Boolean} changed */ -util.updateProperty = function updateProp (object, key, value) { +util.updateProperty = function updateProperty (object, key, value) { if (object[key] !== value) { object[key] = value; return true; @@ -965,6 +998,8 @@ util.option.asElement = function (value, defaultValue) { util.GiveDec = function GiveDec(Hex) { + var Value; + if (Hex == "A") Value = 10; else if (Hex == "B") @@ -978,12 +1013,15 @@ util.GiveDec = function GiveDec(Hex) { else if (Hex == "F") Value = 15; else - Value = eval(Hex) + Value = eval(Hex); + return Value; }; util.GiveHex = function GiveHex(Dec) { - if (Dec == 10) + var Value; + + if(Dec == 10) Value = "A"; else if (Dec == 11) Value = "B"; @@ -997,6 +1035,7 @@ util.GiveHex = function GiveHex(Dec) { Value = "F"; else Value = "" + Dec; + return Value; }; @@ -1208,6 +1247,7 @@ util.copyObject = function copyObject(objectFrom, objectTo) { * - 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. @@ -1217,9 +1257,15 @@ util.copyObject = function copyObject(objectFrom, objectTo) { * @constructor DataSet */ // TODO: add a DataSet constructor DataSet(data, options) -function DataSet (options) { +function DataSet (data, options) { this.id = util.randomUUID(); + // correctly read optional arguments + if (data && !Array.isArray(data) && !util.isDataTable(data)) { + options = data; + data = null; + } + this.options = options || {}; this.data = {}; // map with data indexed by id this.fieldId = this.options.fieldId || 'id'; // name of the field containing id @@ -1240,10 +1286,13 @@ function DataSet (options) { } } - // event subscribers - this.subscribers = {}; + this.subscribers = {}; // event subscribers + this.internalIds = {}; // internally generated id's - this.internalIds = {}; // internally generated id's + // add initial data when provided + if (data) { + this.add(data); + } } /** @@ -1693,7 +1742,6 @@ DataSet.prototype.getIds = function (options) { /** * Execute a callback function for every item in the dataset. - * The order of the items is not determined. * @param {function} callback * @param {Object} [options] Available options: * {Object.} [convert] @@ -1939,9 +1987,8 @@ DataSet.prototype.min = function (field) { /** * Find all distinct values of a specified field * @param {String} field - * @return {Array} values Array containing all distinct values. If the data - * items do not contain the specified field, an array - * containing a single value undefined is returned. + * @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) { @@ -1961,7 +2008,7 @@ DataSet.prototype.distinct = function (field) { break; } } - if (!exists) { + if (!exists && (value !== undefined)) { values[count] = value; count++; } @@ -2409,6 +2456,119 @@ DataView.prototype._trigger = DataSet.prototype._trigger; DataView.prototype.subscribe = DataView.prototype.on; DataView.prototype.unsubscribe = DataView.prototype.off; +/** + * Utility functions for ordering and stacking of items + */ +var stack = {}; + +/** + * Order items by their start data + * @param {Item[]} items + */ +stack.orderByStart = function orderByStart(items) { + items.sort(function (a, b) { + return a.data.start - b.data.start; + }); +}; + +/** + * Order items by their end date. If they have no end date, their start date + * is used. + * @param {Item[]} items + */ +stack.orderByEnd = function orderByEnd(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; + }); +}; + +/** + * Adjust vertical positions of the items such that they don't overlap each + * other. + * @param {Item[]} items + * All visible items + * @param {{item: 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 + */ +stack.stack = function _stack (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; + } + } + + // calculate new, non-overlapping positions + for (i = 0, iMax = items.length; i < iMax; i++) { + var item = items[i]; + if (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 && stack.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; + } + } while (collidingItem); + } + } +}; + +/** + * Adjust vertical positions of the items without stacking them + * @param {Item[]} items + * All visible items + * @param {{item: number, axis: number}} margin + * Margins between items and between items and the axis. + */ +stack.nostack = function nostack (items, margin) { + var i, iMax; + + // reset top position of all items + for (i = 0, iMax = items.length; i < iMax; i++) { + items[i].top = margin.axis; + } +}; + +/** + * 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 {Number} margin A minimum required margin. + * If margin is provided, the two items will be + * marked colliding when they overlap or + * when the margin between the two is smaller than + * the requested margin. + * @return {boolean} true if a and b collide, else false + */ +stack.collision = function collision (a, b, margin) { + return ((a.left - margin) < (b.left + b.width) && + (a.left + a.width + margin) > b.left && + (a.top - margin) < (b.top + b.height) && + (a.top + a.height + margin) > b.top); +}; + /** * @constructor TimeStep * The class TimeStep is an iterator for dates. You provide a start date and an @@ -2864,216 +3024,44 @@ TimeStep.prototype.getLabelMajor = function(date) { } }; -/** - * @constructor Stack - * Stacks items on top of each other. - * @param {ItemSet} itemset - * @param {Object} [options] - */ -function Stack (itemset, options) { - this.itemset = itemset; - - this.options = options || {}; - this.defaultOptions = { - order: function (a, b) { - //return (b.width - a.width) || (a.left - b.left); // TODO: cleanup - // Order: ranges over non-ranges, ranged ordered by width, and - // lastly ordered by start. - if (a instanceof ItemRange) { - if (b instanceof ItemRange) { - var aInt = (a.data.end - a.data.start); - var bInt = (b.data.end - b.data.start); - return (aInt - bInt) || (a.data.start - b.data.start); - } - else { - return -1; - } - } - else { - if (b instanceof ItemRange) { - return 1; - } - else { - return (a.data.start - b.data.start); - } - } - }, - margin: { - item: 10 - } - }; - - this.ordered = []; // ordered items -} - -/** - * Set options for the stack - * @param {Object} options Available options: - * {ItemSet} itemset - * {Number} margin - * {function} order Stacking order - */ -Stack.prototype.setOptions = function setOptions (options) { - util.extend(this.options, options); - - // TODO: register on data changes at the connected itemset, and update the changed part only and immediately -}; - -/** - * Stack the items such that they don't overlap. The items will have a minimal - * distance equal to options.margin.item. - */ -Stack.prototype.update = function update() { - this._order(); - this._stack(); -}; - -/** - * Order the items. If a custom order function has been provided via the options, - * then this will be used. - * @private - */ -Stack.prototype._order = function _order () { - var items = this.itemset.items; - if (!items) { - throw new Error('Cannot stack items: ItemSet does not contain items'); - } - - // TODO: store the sorted items, to have less work later on - var ordered = []; - var index = 0; - // items is a map (no array) - util.forEach(items, function (item) { - if (item.visible) { - ordered[index] = item; - index++; - } - }); - - //if a customer stack order function exists, use it. - var order = this.options.order || this.defaultOptions.order; - if (!(typeof order === 'function')) { - throw new Error('Option order must be a function'); - } - - ordered.sort(order); - - this.ordered = ordered; -}; - -/** - * Adjust vertical positions of the events such that they don't overlap each - * other. - * @private - */ -Stack.prototype._stack = function _stack () { - var i, - iMax, - ordered = this.ordered, - options = this.options, - orientation = options.orientation || this.defaultOptions.orientation, - axisOnTop = (orientation == 'top'), - margin; - - if (options.margin && options.margin.item !== undefined) { - margin = options.margin.item; - } - else { - margin = this.defaultOptions.margin.item - } - - // calculate new, non-overlapping positions - for (i = 0, iMax = ordered.length; i < iMax; i++) { - var item = ordered[i]; - var collidingItem = null; - 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 - collidingItem = this.checkOverlap(ordered, i, 0, i - 1, margin); - if (collidingItem != null) { - // There is a collision. Reposition the event above the colliding element - if (axisOnTop) { - item.top = collidingItem.top + collidingItem.height + margin; - } - else { - item.top = collidingItem.top - item.height - margin; - } - } - } while (collidingItem); - } -}; - -/** - * Check if the destiny position of given item overlaps with any - * of the other items from index itemStart to itemEnd. - * @param {Array} items Array with items - * @param {int} itemIndex Number of the item to be checked for overlap - * @param {int} itemStart First item to be checked. - * @param {int} itemEnd Last item to be checked. - * @return {Object | null} colliding item, or undefined when no collisions - * @param {Number} margin A minimum required margin. - * If margin is provided, the two items will be - * marked colliding when they overlap or - * when the margin between the two is smaller than - * the requested margin. - */ -Stack.prototype.checkOverlap = function checkOverlap (items, itemIndex, - itemStart, itemEnd, margin) { - var collision = this.collision; - - // we loop from end to start, as we suppose that the chance of a - // collision is larger for items at the end, so check these first. - var a = items[itemIndex]; - for (var i = itemEnd; i >= itemStart; i--) { - var b = items[i]; - if (collision(a, b, margin)) { - if (i != itemIndex) { - return b; - } - } - } - - return null; -}; - -/** - * Test if the two provided items collide - * The items must have parameters left, width, top, and height. - * @param {Component} a The first item - * @param {Component} b The second item - * @param {Number} margin A minimum required margin. - * If margin is provided, the two items will be - * marked colliding when they overlap or - * when the margin between the two is smaller than - * the requested margin. - * @return {boolean} true if a and b collide, else false - */ -Stack.prototype.collision = function collision (a, b, margin) { - return ((a.left - margin) < (b.left + b.width) && - (a.left + a.width + margin) > b.left && - (a.top - margin) < (b.top + b.height) && - (a.top + a.height + margin) > b.top); -}; - /** * @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 {Object} [options] See description at Range.setOptions - * @extends Controller + * @param {RootPanel} root Root panel, used to subscribe to events + * @param {Panel} parent Parent panel, used to attach to the DOM + * @param {Object} [options] See description at Range.setOptions */ -function Range(options) { +function Range(root, parent, options) { this.id = util.randomUUID(); this.start = null; // Number this.end = null; // Number + this.root = root; + this.parent = parent; this.options = options || {}; + // drag listeners for dragging + this.root.on('dragstart', this._onDragStart.bind(this)); + this.root.on('drag', this._onDrag.bind(this)); + this.root.on('dragend', this._onDragEnd.bind(this)); + + // ignore dragging when holding + this.root.on('hold', this._onHold.bind(this)); + + // mouse wheel for zooming + this.root.on('mousewheel', this._onMouseWheel.bind(this)); + this.root.on('DOMMouseScroll', this._onMouseWheel.bind(this)); // For FF + + // pinch to zoom + this.root.on('touch', this._onTouch.bind(this)); + this.root.on('pinch', this._onPinch.bind(this)); + this.setOptions(options); } -// extend the Range prototype with an event emitter mixin +// turn Range into an event emitter Emitter(Range.prototype); /** @@ -3106,59 +3094,6 @@ function validateDirection (direction) { } } -/** - * Add listeners for mouse and touch events to the component - * @param {Controller} controller - * @param {Component} component Should be a rootpanel - * @param {String} event Available events: 'move', 'zoom' - * @param {String} direction Available directions: 'horizontal', 'vertical' - */ -Range.prototype.subscribe = function (controller, component, event, direction) { - var me = this; - - if (event == 'move') { - // drag start listener - controller.on('dragstart', function (event) { - me._onDragStart(event, component); - }); - - // drag listener - controller.on('drag', function (event) { - me._onDrag(event, component, direction); - }); - - // drag end listener - controller.on('dragend', function (event) { - me._onDragEnd(event, component); - }); - - // ignore dragging when holding - controller.on('hold', function (event) { - me._onHold(); - }); - } - else if (event == 'zoom') { - // mouse wheel - function mousewheel (event) { - me._onMouseWheel(event, component, direction); - } - controller.on('mousewheel', mousewheel); - controller.on('DOMMouseScroll', mousewheel); // For FF - - // pinch - controller.on('touch', function (event) { - me._onTouch(event); - }); - controller.on('pinch', function (event) { - me._onPinch(event, component, direction); - }); - } - else { - throw new TypeError('Unknown event "' + event + '". ' + - 'Choose "move" or "zoom".'); - } -}; - /** * Set a new start and end range * @param {Number} [start] @@ -3168,8 +3103,8 @@ Range.prototype.setRange = function(start, end) { var changed = this._applyRange(start, end); if (changed) { var params = { - start: this.start, - end: this.end + start: new Date(this.start), + end: new Date(this.end) }; this.emit('rangechange', params); this.emit('rangechanged', params); @@ -3337,10 +3272,9 @@ var touchParams = {}; /** * Start dragging horizontally or vertically * @param {Event} event - * @param {Object} component * @private */ -Range.prototype._onDragStart = function(event, component) { +Range.prototype._onDragStart = 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 (touchParams.ignore) return; @@ -3350,7 +3284,7 @@ Range.prototype._onDragStart = function(event, component) { touchParams.start = this.start; touchParams.end = this.end; - var frame = component.frame; + var frame = this.parent.frame; if (frame) { frame.style.cursor = 'move'; } @@ -3359,11 +3293,10 @@ Range.prototype._onDragStart = function(event, component) { /** * Perform dragging operating. * @param {Event} event - * @param {Component} component - * @param {String} direction 'horizontal' or 'vertical' * @private */ -Range.prototype._onDrag = function (event, component, direction) { +Range.prototype._onDrag = function (event) { + var direction = this.options.direction; validateDirection(direction); // TODO: reckon with option movable @@ -3375,38 +3308,37 @@ Range.prototype._onDrag = function (event, component, direction) { var delta = (direction == 'horizontal') ? event.gesture.deltaX : event.gesture.deltaY, interval = (touchParams.end - touchParams.start), - width = (direction == 'horizontal') ? component.width : component.height, + width = (direction == 'horizontal') ? this.parent.width : this.parent.height, diffRange = -delta / width * interval; this._applyRange(touchParams.start + diffRange, touchParams.end + diffRange); this.emit('rangechange', { - start: this.start, - end: this.end + start: new Date(this.start), + end: new Date(this.end) }); }; /** * Stop dragging operating. * @param {event} event - * @param {Component} component * @private */ -Range.prototype._onDragEnd = function (event, component) { +Range.prototype._onDragEnd = 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 (touchParams.ignore) return; // TODO: reckon with option movable - if (component.frame) { - component.frame.style.cursor = 'auto'; + if (this.parent.frame) { + this.parent.frame.style.cursor = 'auto'; } // fire a rangechanged event this.emit('rangechanged', { - start: this.start, - end: this.end + start: new Date(this.start), + end: new Date(this.end) }); }; @@ -3414,13 +3346,9 @@ Range.prototype._onDragEnd = function (event, component) { * Event handler for mouse wheel event, used to zoom * Code from http://adomas.org/javascript-mouse-wheel/ * @param {Event} event - * @param {Component} component - * @param {String} direction 'horizontal' or 'vertical' * @private */ -Range.prototype._onMouseWheel = function(event, component, direction) { - validateDirection(direction); - +Range.prototype._onMouseWheel = function(event) { // TODO: reckon with option zoomable // retrieve delta @@ -3451,8 +3379,8 @@ Range.prototype._onMouseWheel = function(event, component, direction) { // calculate center, the date to zoom around var gesture = util.fakeGesture(this, event), - pointer = getPointer(gesture.center, component.frame), - pointerDate = this._pointerToDate(component, direction, pointer); + pointer = getPointer(gesture.center, this.parent.frame), + pointerDate = this._pointerToDate(pointer); this.zoom(scale, pointerDate); } @@ -3491,24 +3419,23 @@ Range.prototype._onHold = function () { /** * Handle pinch event * @param {Event} event - * @param {Component} component - * @param {String} direction 'horizontal' or 'vertical' * @private */ -Range.prototype._onPinch = function (event, component, direction) { +Range.prototype._onPinch = function (event) { + var direction = this.options.direction; touchParams.ignore = true; // TODO: reckon with option zoomable if (event.gesture.touches.length > 1) { if (!touchParams.center) { - touchParams.center = getPointer(event.gesture.center, component.frame); + touchParams.center = getPointer(event.gesture.center, this.parent.frame); } var scale = 1 / event.gesture.scale, - initDate = this._pointerToDate(component, direction, touchParams.center), - center = getPointer(event.gesture.center, component.frame), - date = this._pointerToDate(component, direction, center), + initDate = this._pointerToDate(touchParams.center), + center = getPointer(event.gesture.center, this.parent.frame), + date = this._pointerToDate(this.parent, center), delta = date - initDate; // TODO: utilize delta // calculate new start and end @@ -3522,21 +3449,23 @@ Range.prototype._onPinch = function (event, component, direction) { /** * Helper function to calculate the center date for zooming - * @param {Component} component * @param {{x: Number, y: Number}} pointer - * @param {String} direction 'horizontal' or 'vertical' * @return {number} date * @private */ -Range.prototype._pointerToDate = function (component, direction, pointer) { +Range.prototype._pointerToDate = function (pointer) { var conversion; + var direction = this.options.direction; + + validateDirection(direction); + if (direction == 'horizontal') { - var width = component.width; + var width = this.parent.width; conversion = this.conversion(width); return pointer.x / conversion.scale + conversion.offset; } else { - var height = component.height; + var height = this.parent.height; conversion = this.conversion(height); return pointer.y / conversion.scale + conversion.offset; } @@ -3616,225 +3545,39 @@ Range.prototype.moveTo = function(moveTo) { }; /** - * @constructor Controller - * - * A Controller controls the reflows and repaints of all components, - * and is used as an event bus for all components. + * Prototype for visual components */ -function Controller () { - var me = this; - - this.id = util.randomUUID(); - this.components = {}; - - /** - * Listen for a 'request-reflow' event. The controller will schedule a reflow - * @param {Boolean} [force] If true, an immediate reflow is forced. Default - * is false. - */ - var reflowTimer = null; - this.on('request-reflow', function requestReflow(force) { - if (force) { - me.reflow(); - } - else { - if (!reflowTimer) { - reflowTimer = setTimeout(function () { - reflowTimer = null; - me.reflow(); - }, 0); - } - } - }); +function Component () { + this.id = null; + this.parent = null; + this.childs = null; + this.options = null; - /** - * Request a repaint. The controller will schedule a repaint - * @param {Boolean} [force] If true, an immediate repaint is forced. Default - * is false. - */ - var repaintTimer = null; - this.on('request-repaint', function requestRepaint(force) { - if (force) { - me.repaint(); - } - else { - if (!repaintTimer) { - repaintTimer = setTimeout(function () { - repaintTimer = null; - me.repaint(); - }, 0); - } - } - }); + this.top = 0; + this.left = 0; + this.width = 0; + this.height = 0; } -// Extend controller with Emitter mixin -Emitter(Controller.prototype); +// Turn the Component into an event emitter +Emitter(Component.prototype); /** - * Add a component to the controller - * @param {Component} component + * Set parameters for the frame. Parameters will be merged in current parameter + * set. + * @param {Object} options Available parameters: + * {String | function} [className] + * {String | Number | function} [left] + * {String | Number | function} [top] + * {String | Number | function} [width] + * {String | Number | function} [height] */ -Controller.prototype.add = function add(component) { - // validate the component - if (component.id == undefined) { - throw new Error('Component has no field id'); - } - if (!(component instanceof Component) && !(component instanceof Controller)) { - throw new TypeError('Component must be an instance of ' + - 'prototype Component or Controller'); - } +Component.prototype.setOptions = function setOptions(options) { + if (options) { + util.extend(this.options, options); - // add the component - component.setController(this); - this.components[component.id] = component; -}; - -/** - * Remove a component from the controller - * @param {Component | String} component - */ -Controller.prototype.remove = function remove(component) { - var id; - for (id in this.components) { - if (this.components.hasOwnProperty(id)) { - if (id == component || this.components[id] === component) { - break; - } - } - } - - if (id) { - // unregister the controller (gives the component the ability to unregister - // event listeners and clean up other stuff) - this.components[id].setController(null); - - delete this.components[id]; - } -}; - -/** - * Repaint all components - */ -Controller.prototype.repaint = function repaint() { - var changed = false; - - // cancel any running repaint request - if (this.repaintTimer) { - clearTimeout(this.repaintTimer); - this.repaintTimer = undefined; - } - - var done = {}; - - function repaint(component, id) { - if (!(id in done)) { - // first repaint the components on which this component is dependent - if (component.depends) { - component.depends.forEach(function (dep) { - repaint(dep, dep.id); - }); - } - if (component.parent) { - repaint(component.parent, component.parent.id); - } - - // repaint the component itself and mark as done - changed = component.repaint() || changed; - done[id] = true; - } - } - - util.forEach(this.components, repaint); - - this.emit('repaint'); - - // immediately reflow when needed - if (changed) { - this.reflow(); - } - // TODO: limit the number of nested reflows/repaints, prevent loop -}; - -/** - * Reflow all components - */ -Controller.prototype.reflow = function reflow() { - var resized = false; - - // cancel any running repaint request - if (this.reflowTimer) { - clearTimeout(this.reflowTimer); - this.reflowTimer = undefined; - } - - var done = {}; - - function reflow(component, id) { - if (!(id in done)) { - // first reflow the components on which this component is dependent - if (component.depends) { - component.depends.forEach(function (dep) { - reflow(dep, dep.id); - }); - } - if (component.parent) { - reflow(component.parent, component.parent.id); - } - - // reflow the component itself and mark as done - resized = component.reflow() || resized; - done[id] = true; - } - } - - util.forEach(this.components, reflow); - - this.emit('reflow'); - - // immediately repaint when needed - if (resized) { - this.repaint(); - } - // TODO: limit the number of nested reflows/repaints, prevent loop -}; - -/** - * Prototype for visual components - */ -function Component () { - this.id = null; - this.parent = null; - this.depends = null; - this.controller = null; - this.options = null; - - this.frame = null; // main DOM element - this.top = 0; - this.left = 0; - this.width = 0; - this.height = 0; -} - -/** - * Set parameters for the frame. Parameters will be merged in current parameter - * set. - * @param {Object} options Available parameters: - * {String | function} [className] - * {String | Number | function} [left] - * {String | Number | function} [top] - * {String | Number | function} [width] - * {String | Number | function} [height] - */ -Component.prototype.setOptions = function setOptions(options) { - if (options) { - util.extend(this.options, options); - - if (this.controller) { - this.requestRepaint(); - this.requestReflow(); - } - } + this.repaint(); + } }; /** @@ -3855,46 +3598,18 @@ Component.prototype.getOption = function getOption(name) { return value; }; -/** - * Set controller for this component, or remove current controller by passing - * null as parameter value. - * @param {Controller | null} controller - */ -Component.prototype.setController = function setController (controller) { - this.controller = controller || null; -}; - -/** - * Get controller of this component - * @return {Controller} controller - */ -Component.prototype.getController = function getController () { - return this.controller; -}; - -/** - * Get the container element of the component, which can be used by a child to - * add its own widgets. Not all components do have a container for childs, in - * that case null is returned. - * @returns {HTMLElement | null} container - */ -// TODO: get rid of the getContainer and getFrame methods, provide these via the options -Component.prototype.getContainer = function getContainer() { - // should be implemented by the component - return null; -}; - /** * Get the frame element of the component, the outer HTML DOM element. * @returns {HTMLElement | null} frame */ Component.prototype.getFrame = function getFrame() { - return this.frame; + // should be implemented by the component + return null; }; /** * Repaint the component - * @return {Boolean} changed + * @return {boolean} Returns true if the component is resized */ Component.prototype.repaint = function repaint() { // should be implemented by the component @@ -3902,73 +3617,22 @@ Component.prototype.repaint = function repaint() { }; /** - * Reflow the component - * @return {Boolean} resized - */ -Component.prototype.reflow = function reflow() { - // should be implemented by the component - return false; -}; - -/** - * Hide the component from the DOM - * @return {Boolean} changed - */ -Component.prototype.hide = function hide() { - if (this.frame && this.frame.parentNode) { - this.frame.parentNode.removeChild(this.frame); - return true; - } - else { - return false; - } -}; - -/** - * Show the component in the DOM (when not already visible). - * A repaint will be executed when the component is not visible - * @return {Boolean} changed + * 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.show = function show() { - if (!this.frame || !this.frame.parentNode) { - return this.repaint(); - } - else { - return false; - } -}; +Component.prototype._isResized = function _isResized() { + var resized = (this._previousWidth !== this.width || this._previousHeight !== this.height); -/** - * Request a repaint. The controller will schedule a repaint - */ -Component.prototype.requestRepaint = function requestRepaint() { - if (this.controller) { - this.controller.emit('request-repaint'); - } - else { - throw new Error('Cannot request a repaint: no controller configured'); - // TODO: just do a repaint when no parent is configured? - } -}; + this._previousWidth = this.width; + this._previousHeight = this.height; -/** - * Request a reflow. The controller will schedule a reflow - */ -Component.prototype.requestReflow = function requestReflow() { - if (this.controller) { - this.controller.emit('request-reflow'); - } - else { - throw new Error('Cannot request a reflow: no controller configured'); - // TODO: just do a reflow when no parent is configured? - } + return resized; }; /** * A panel can contain components - * @param {Component} [parent] - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) * @param {Object} [options] Available parameters: * {String | Number | function} [left] * {String | Number | function} [top] @@ -3978,12 +3642,15 @@ Component.prototype.requestReflow = function requestReflow() { * @constructor Panel * @extends Component */ -function Panel(parent, depends, options) { +function Panel(options) { this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; + this.parent = null; + this.childs = []; this.options = options || {}; + + // create frame + this.frame = (typeof document !== 'undefined') ? document.createElement('div') : null; } Panel.prototype = new Component(); @@ -4000,81 +3667,139 @@ Panel.prototype = new Component(); Panel.prototype.setOptions = Component.prototype.setOptions; /** - * Get the container element of the panel, which can be used by a child to - * add its own widgets. - * @returns {HTMLElement} container + * Get the outer frame of the panel + * @returns {HTMLElement} frame */ -Panel.prototype.getContainer = function () { +Panel.prototype.getFrame = function () { return this.frame; }; /** - * Repaint the component - * @return {Boolean} changed + * Append a child to the panel + * @param {Component} child */ -Panel.prototype.repaint = function () { - var changed = 0, - update = util.updateProperty, - asSize = util.option.asSize, - options = this.options, - frame = this.frame; - if (!frame) { - frame = document.createElement('div'); - frame.className = 'vpanel'; +Panel.prototype.appendChild = function (child) { + this.childs.push(child); + child.parent = this; + + // attach to the DOM + var frame = child.getFrame(); + if (frame) { + if (frame.parentNode) { + frame.parentNode.removeChild(frame); + } + this.frame.appendChild(frame); + } +}; + +/** + * Insert a child to the panel + * @param {Component} child + * @param {Component} beforeChild + */ +Panel.prototype.insertBefore = function (child, beforeChild) { + var index = this.childs.indexOf(beforeChild); + if (index != -1) { + this.childs.splice(index, 0, child); + child.parent = this; + + // attach to the DOM + var frame = child.getFrame(); + if (frame) { + if (frame.parentNode) { + frame.parentNode.removeChild(frame); + } - var className = options.className; - if (className) { - if (typeof className == 'function') { - util.addClassName(frame, String(className())); + var beforeFrame = beforeChild.getFrame(); + if (beforeFrame) { + this.frame.insertBefore(frame, beforeFrame); } else { - util.addClassName(frame, String(className)); + this.frame.appendChild(frame); } } - - this.frame = frame; - changed += 1; } - if (!frame.parentNode) { - if (!this.parent) { - throw new Error('Cannot repaint panel: no parent attached'); - } - var parentContainer = this.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint panel: parent has no container element'); +}; + +/** + * Remove a child from the panel + * @param {Component} child + */ +Panel.prototype.removeChild = function (child) { + var index = this.childs.indexOf(child); + if (index != -1) { + this.childs.splice(index, 1); + child.parent = null; + + // remove from the DOM + var frame = child.getFrame(); + if (frame && frame.parentNode) { + this.frame.removeChild(frame); } - parentContainer.appendChild(frame); - changed += 1; } +}; - changed += update(frame.style, 'top', asSize(options.top, '0px')); - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - changed += update(frame.style, 'height', asSize(options.height, '100%')); - - return (changed > 0); +/** + * Test whether the panel contains given child + * @param {Component} child + */ +Panel.prototype.hasChild = function (child) { + var index = this.childs.indexOf(child); + return (index != -1); }; /** - * Reflow the component - * @return {Boolean} resized + * Repaint the component + * @return {boolean} Returns true if the component was resized since previous repaint */ -Panel.prototype.reflow = function () { - var changed = 0, - update = util.updateProperty, - frame = this.frame; +Panel.prototype.repaint = function () { + var asString = util.option.asString, + options = this.options, + frame = this.getFrame(); - if (frame) { - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - changed += update(this, 'width', frame.offsetWidth); - changed += update(this, 'height', frame.offsetHeight); - } - else { - changed += 1; + // update className + frame.className = 'vpanel' + (options.className ? (' ' + asString(options.className)) : ''); + + // repaint the child components + var childsResized = this._repaintChilds(); + + // update frame size + this._updateSize(); + + return this._isResized() || childsResized; +}; + +/** + * Repaint all childs of the panel + * @return {boolean} Returns true if the component is resized + * @private + */ +Panel.prototype._repaintChilds = function () { + var resized = false; + for (var i = 0, ii = this.childs.length; i < ii; i++) { + resized = this.childs[i].repaint() || resized; } + return resized; +}; + +/** + * Apply the size from options to the panel, and recalculate it's actual size. + * @private + */ +Panel.prototype._updateSize = function () { + // apply size + this.frame.style.top = util.option.asSize(this.options.top); + this.frame.style.bottom = util.option.asSize(this.options.bottom); + this.frame.style.left = util.option.asSize(this.options.left); + this.frame.style.right = util.option.asSize(this.options.right); + this.frame.style.width = util.option.asSize(this.options.width, '100%'); + this.frame.style.height = util.option.asSize(this.options.height, ''); - return (changed > 0); + // get actual size + this.top = this.frame.offsetTop; + this.left = this.frame.offsetLeft; + this.width = this.frame.offsetWidth; + this.height = this.frame.offsetHeight; }; /** @@ -4089,32 +3814,53 @@ function RootPanel(container, options) { this.id = util.randomUUID(); this.container = container; - // create functions to be used as DOM event listeners - var me = this; - this.hammer = null; + this.options = options || {}; + this.defaultOptions = { + autoResize: true + }; + + // create the HTML DOM + this._create(); + + // attach the root panel to the provided container + if (!this.container) throw new Error('Cannot repaint root panel: no container attached'); + this.container.appendChild(this.getFrame()); + + + this._initWatch(); +} + +RootPanel.prototype = new Panel(); + +/** + * Create the HTML DOM for the root panel + */ +RootPanel.prototype._create = function _create() { + // create frame + this.frame = document.createElement('div'); + + // create event listeners for all interesting events, these events will be + // emitted via emitter + this.hammer = Hammer(this.frame, { + prevent_default: true + }); + this.listeners = {}; - // create listeners for all interesting events, these events will be emitted - // via the controller + var me = this; var events = [ 'touch', 'pinch', 'tap', 'doubletap', 'hold', 'dragstart', 'drag', 'dragend', 'mousewheel', 'DOMMouseScroll' // DOMMouseScroll is for Firefox ]; - this.listeners = {}; events.forEach(function (event) { - me.listeners[event] = function () { + var listener = function () { var args = [event].concat(Array.prototype.slice.call(arguments, 0)); - me.controller.emit.apply(me.controller, args); + me.emit.apply(me, args); }; + me.hammer.on(event, listener); + me.listeners[event] = listener; }); - - this.options = options || {}; - this.defaultOptions = { - autoResize: true - }; -} - -RootPanel.prototype = new Panel(); +}; /** * Set options. Will extend the current options. @@ -4126,80 +3872,54 @@ RootPanel.prototype = new Panel(); * {String | Number | function} [height] * {Boolean | function} [autoResize] */ -RootPanel.prototype.setOptions = Component.prototype.setOptions; - -/** - * Repaint the component - * @return {Boolean} changed - */ -RootPanel.prototype.repaint = function () { - var changed = 0, - update = util.updateProperty, - asSize = util.option.asSize, - options = this.options, - frame = this.frame; - - if (!frame) { - frame = document.createElement('div'); - - this.frame = frame; - - this._registerListeners(); +RootPanel.prototype.setOptions = function setOptions(options) { + if (options) { + util.extend(this.options, options); - changed += 1; - } - if (!frame.parentNode) { - if (!this.container) { - throw new Error('Cannot repaint root panel: no container attached'); - } - this.container.appendChild(frame); - changed += 1; - } + this.repaint(); - frame.className = 'vis timeline rootpanel ' + options.orientation + - (options.editable ? ' editable' : ''); - var className = options.className; - if (className) { - util.addClassName(frame, util.option.asString(className)); + this._initWatch(); } +}; - changed += update(frame.style, 'top', asSize(options.top, '0px')); - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - changed += update(frame.style, 'height', asSize(options.height, '100%')); - - this._updateWatch(); - - return (changed > 0); +/** + * Get the frame of the root panel + */ +RootPanel.prototype.getFrame = function getFrame() { + return this.frame; }; /** - * Reflow the component - * @return {Boolean} resized + * Repaint the root panel */ -RootPanel.prototype.reflow = function () { - var changed = 0, - update = util.updateProperty, - frame = this.frame; +RootPanel.prototype.repaint = function repaint() { + // update class name + var options = this.options; + var editable = options.editable.updateTime || options.editable.updateGroup; + var className = 'vis timeline rootpanel ' + options.orientation + (editable ? ' editable' : ''); + if (options.className) className += ' ' + util.option.asString(className); + this.frame.className = className; - if (frame) { - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - changed += update(this, 'width', frame.offsetWidth); - changed += update(this, 'height', frame.offsetHeight); - } - else { - changed += 1; - } + // repaint the child components + var childsResized = this._repaintChilds(); + + // update frame size + this.frame.style.maxHeight = util.option.asSize(this.options.maxHeight, ''); + this._updateSize(); - return (changed > 0); + // if the root panel or any of its childs is resized, repaint again, + // as other components may need to be resized accordingly + var resized = this._isResized() || childsResized; + if (resized) { + setTimeout(this.repaint.bind(this), 0); + } }; /** - * Update watching for resize, depending on the current option + * Initialize watching when option autoResize is true * @private */ -RootPanel.prototype._updateWatch = function () { +RootPanel.prototype._initWatch = function _initWatch() { var autoResize = this.getOption('autoResize'); if (autoResize) { this._watch(); @@ -4214,12 +3934,12 @@ RootPanel.prototype._updateWatch = function () { * automatically redraw itself. * @private */ -RootPanel.prototype._watch = function () { +RootPanel.prototype._watch = function _watch() { var me = this; this._unwatch(); - var checkSize = function () { + var checkSize = function checkSize() { var autoResize = me.getOption('autoResize'); if (!autoResize) { // stop watching when the option autoResize is changed to false @@ -4229,9 +3949,12 @@ RootPanel.prototype._watch = function () { if (me.frame) { // check whether the frame is resized - if ((me.frame.clientWidth != me.width) || - (me.frame.clientHeight != me.height)) { - me.requestReflow(); + if ((me.frame.clientWidth != me.lastWidth) || + (me.frame.clientHeight != me.lastHeight)) { + me.lastWidth = me.frame.clientWidth; + me.lastHeight = me.frame.clientHeight; + me.repaint(); + // TODO: emit a resize event instead? } } }; @@ -4246,7 +3969,7 @@ RootPanel.prototype._watch = function () { * Stop watching for a resize of the frame. * @private */ -RootPanel.prototype._unwatch = function () { +RootPanel.prototype._unwatch = function _unwatch() { if (this.watchTimer) { clearInterval(this.watchTimer); this.watchTimer = undefined; @@ -4255,70 +3978,15 @@ RootPanel.prototype._unwatch = function () { // TODO: remove event listener on window.resize }; -/** - * Set controller for this component, or remove current controller by passing - * null as parameter value. - * @param {Controller | null} controller - */ -RootPanel.prototype.setController = function setController (controller) { - this.controller = controller || null; - - if (this.controller) { - this._registerListeners(); - } - else { - this._unregisterListeners(); - } -}; - -/** - * Register event emitters emitted by the rootpanel - * @private - */ -RootPanel.prototype._registerListeners = function () { - if (this.frame && this.controller && !this.hammer) { - this.hammer = Hammer(this.frame, { - prevent_default: true - }); - - for (var event in this.listeners) { - if (this.listeners.hasOwnProperty(event)) { - this.hammer.on(event, this.listeners[event]); - } - } - } -}; - -/** - * Unregister event emitters from the rootpanel - * @private - */ -RootPanel.prototype._unregisterListeners = function () { - if (this.hammer) { - for (var event in this.listeners) { - if (this.listeners.hasOwnProperty(event)) { - this.hammer.off(event, this.listeners[event]); - } - } - - this.hammer = null; - } -}; - /** * A horizontal time axis - * @param {Component} parent - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) * @param {Object} [options] See TimeAxis.setOptions for the available * options. * @constructor TimeAxis * @extends Component */ -function TimeAxis (parent, depends, options) { +function TimeAxis (options) { this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; this.dom = { majorLines: [], @@ -4349,8 +4017,10 @@ function TimeAxis (parent, depends, options) { showMajorLabels: true }; - this.conversion = null; this.range = null; + + // create the HTML DOM + this._create(); } TimeAxis.prototype = new Component(); @@ -4358,6 +4028,13 @@ TimeAxis.prototype = new Component(); // TODO: comment options TimeAxis.prototype.setOptions = Component.prototype.setOptions; +/** + * Create the HTML DOM for the TimeAxis + */ +TimeAxis.prototype._create = function _create() { + this.frame = document.createElement('div'); +}; + /** * Set a range (start and end) * @param {Range | Object} range A Range or an object containing start and end. @@ -4371,126 +4048,70 @@ TimeAxis.prototype.setRange = function (range) { }; /** - * 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 - */ -TimeAxis.prototype.toTime = function(x) { - var conversion = this.conversion; - return new Date(x / conversion.scale + conversion.offset); -}; - -/** - * 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 + * Get the outer frame of the time axis + * @return {HTMLElement} frame */ -TimeAxis.prototype.toScreen = function(time) { - var conversion = this.conversion; - return (time.valueOf() - conversion.offset) * conversion.scale; +TimeAxis.prototype.getFrame = function getFrame() { + return this.frame; }; /** * Repaint the component - * @return {Boolean} changed + * @return {boolean} Returns true if the component is resized */ TimeAxis.prototype.repaint = function () { - var changed = 0, - update = util.updateProperty, - asSize = util.option.asSize, + var asSize = util.option.asSize, options = this.options, - orientation = this.getOption('orientation'), props = this.props, - step = this.step; - - var frame = this.frame; - if (!frame) { - frame = document.createElement('div'); - this.frame = frame; - changed += 1; - } - frame.className = 'axis'; - // TODO: custom className? - - if (!frame.parentNode) { - if (!this.parent) { - throw new Error('Cannot repaint time axis: no parent attached'); - } - var parentContainer = this.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint time axis: parent has no container element'); - } - parentContainer.appendChild(frame); + frame = this.frame; - changed += 1; - } + // update classname + frame.className = 'timeaxis'; // TODO: add className from options if defined var parent = frame.parentNode; if (parent) { - var beforeChild = frame.nextSibling; - parent.removeChild(frame); // take frame offline while updating (is almost twice as fast) - - var defaultTop = (orientation == 'bottom' && this.props.parentHeight && this.height) ? - (this.props.parentHeight - this.height) + 'px' : - '0px'; - changed += update(frame.style, 'top', asSize(options.top, defaultTop)); - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); - - // get characters width and height - this._repaintMeasureChars(); - - if (this.step) { - this._repaintStart(); + // calculate character width and height + this._calculateCharSize(); - step.first(); - var xFirstMajorLabel = undefined; - var max = 0; - while (step.hasNext() && max < 1000) { - max++; - var cur = step.getCurrent(), - x = this.toScreen(cur), - isMajor = step.isMajor(); - - // TODO: lines must have a width, such that we can create css backgrounds - - if (this.getOption('showMinorLabels')) { - this._repaintMinorText(x, step.getLabelMinor()); - } - - if (isMajor && this.getOption('showMajorLabels')) { - if (x > 0) { - if (xFirstMajorLabel == undefined) { - xFirstMajorLabel = x; - } - this._repaintMajorText(x, step.getLabelMajor()); - } - this._repaintMajorLine(x); - } - else { - this._repaintMinorLine(x); - } + // TODO: recalculate sizes only needed when parent is resized or options is changed + var orientation = this.getOption('orientation'), + showMinorLabels = this.getOption('showMinorLabels'), + showMajorLabels = this.getOption('showMajorLabels'); - step.next(); - } + // determine the width and height of the elemens for the axis + var parentHeight = this.parent.height; + props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; + props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; + this.height = props.minorLabelHeight + props.majorLabelHeight; + this.width = frame.offsetWidth; // TODO: only update the width when the frame is resized? - // create a major label on the left when needed - if (this.getOption('showMajorLabels')) { - var leftTime = this.toTime(0), - leftText = step.getLabelMajor(leftTime), - widthText = leftText.length * (props.majorCharWidth || 10) + 10; // upper bound estimation + props.minorLineHeight = parentHeight + props.minorLabelHeight; + props.minorLineWidth = 1; // TODO: really calculate width + props.majorLineHeight = parentHeight + this.height; + props.majorLineWidth = 1; // TODO: really calculate width - if (xFirstMajorLabel == undefined || widthText < xFirstMajorLabel) { - this._repaintMajorText(0, leftText); - } - } + // take frame offline while updating (is almost twice as fast) + var beforeChild = frame.nextSibling; + parent.removeChild(frame); - this._repaintEnd(); + // TODO: top/bottom positioning should be determined by options set in the Timeline, not here + if (orientation == 'top') { + frame.style.top = '0'; + frame.style.left = '0'; + frame.style.bottom = ''; + frame.style.width = asSize(options.width, '100%'); + frame.style.height = this.height + 'px'; + } + else { // bottom + frame.style.top = ''; + frame.style.bottom = '0'; + frame.style.left = '0'; + frame.style.width = asSize(options.width, '100%'); + frame.style.height = this.height + 'px'; } + this._repaintLabels(); + this._repaintLine(); // put frame online again @@ -4502,34 +4123,80 @@ TimeAxis.prototype.repaint = function () { } } - return (changed > 0); + return this._isResized(); }; /** - * Start a repaint. Move all DOM elements to a redundant list, where they - * can be picked for re-use, or can be cleaned up in the end + * Repaint major and minor text labels and vertical grid lines * @private */ -TimeAxis.prototype._repaintStart = function () { - var dom = this.dom, - redundant = dom.redundant; +TimeAxis.prototype._repaintLabels = function () { + var orientation = this.getOption('orientation'); - redundant.majorLines = dom.majorLines; - redundant.majorTexts = dom.majorTexts; - redundant.minorLines = dom.minorLines; - redundant.minorTexts = dom.minorTexts; + // calculate range and step (step such that we have space for 7 characters per label) + var start = util.convert(this.range.start, 'Number'), + end = util.convert(this.range.end, 'Number'), + minimumStep = this.options.toTime((this.props.minorCharWidth || 10) * 7).valueOf() + -this.options.toTime(0).valueOf(); + var step = new TimeStep(new Date(start), new Date(end), minimumStep); + 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.majorLines = dom.majorLines; + dom.redundant.majorTexts = dom.majorTexts; + dom.redundant.minorLines = dom.minorLines; + dom.redundant.minorTexts = dom.minorTexts; dom.majorLines = []; dom.majorTexts = []; dom.minorLines = []; dom.minorTexts = []; -}; -/** - * End a repaint. Cleanup leftover DOM elements in the redundant list - * @private - */ -TimeAxis.prototype._repaintEnd = function () { + step.first(); + var xFirstMajorLabel = undefined; + var max = 0; + while (step.hasNext() && max < 1000) { + max++; + var cur = step.getCurrent(), + x = this.options.toScreen(cur), + isMajor = step.isMajor(); + + // TODO: lines must have a width, such that we can create css backgrounds + + if (this.getOption('showMinorLabels')) { + this._repaintMinorText(x, step.getLabelMinor(), orientation); + } + + if (isMajor && this.getOption('showMajorLabels')) { + if (x > 0) { + if (xFirstMajorLabel == undefined) { + xFirstMajorLabel = x; + } + this._repaintMajorText(x, step.getLabelMajor(), orientation); + } + this._repaintMajorLine(x, orientation); + } + else { + this._repaintMinorLine(x, orientation); + } + + step.next(); + } + + // create a major label on the left when needed + if (this.getOption('showMajorLabels')) { + var leftTime = this.options.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); + } + } + + // Cleanup leftover DOM elements from the redundant list util.forEach(this.dom.redundant, function (arr) { while (arr.length) { var elem = arr.pop(); @@ -4540,14 +4207,14 @@ TimeAxis.prototype._repaintEnd = function () { }); }; - /** * Create a minor label for the axis at position x * @param {Number} x * @param {String} text + * @param {String} orientation "top" or "bottom" (default) * @private */ -TimeAxis.prototype._repaintMinorText = function (x, text) { +TimeAxis.prototype._repaintMinorText = function (x, text, orientation) { // reuse redundant label var label = this.dom.redundant.minorTexts.shift(); @@ -4562,8 +4229,16 @@ TimeAxis.prototype._repaintMinorText = function (x, text) { this.dom.minorTexts.push(label); label.childNodes[0].nodeValue = text; + + if (orientation == 'top') { + label.style.top = this.props.majorLabelHeight + 'px'; + label.style.bottom = ''; + } + else { + label.style.top = ''; + label.style.bottom = this.props.majorLabelHeight + 'px'; + } label.style.left = x + 'px'; - label.style.top = this.props.minorLabelTop + 'px'; //label.title = title; // TODO: this is a heavy operation }; @@ -4571,9 +4246,10 @@ TimeAxis.prototype._repaintMinorText = function (x, text) { * Create a Major label for the axis at position x * @param {Number} x * @param {String} text + * @param {String} orientation "top" or "bottom" (default) * @private */ -TimeAxis.prototype._repaintMajorText = function (x, text) { +TimeAxis.prototype._repaintMajorText = function (x, text, orientation) { // reuse redundant label var label = this.dom.redundant.majorTexts.shift(); @@ -4588,17 +4264,26 @@ TimeAxis.prototype._repaintMajorText = function (x, text) { this.dom.majorTexts.push(label); label.childNodes[0].nodeValue = text; - label.style.top = this.props.majorLabelTop + 'px'; - label.style.left = x + 'px'; //label.title = title; // TODO: this is a heavy operation + + if (orientation == 'top') { + label.style.top = '0px'; + label.style.bottom = ''; + } + else { + label.style.top = ''; + label.style.bottom = '0px'; + } + label.style.left = x + 'px'; }; /** * Create a minor line for the axis at position x * @param {Number} x + * @param {String} orientation "top" or "bottom" (default) * @private */ -TimeAxis.prototype._repaintMinorLine = function (x) { +TimeAxis.prototype._repaintMinorLine = function (x, orientation) { // reuse redundant line var line = this.dom.redundant.minorLines.shift(); @@ -4611,7 +4296,14 @@ TimeAxis.prototype._repaintMinorLine = function (x) { this.dom.minorLines.push(line); var props = this.props; - line.style.top = props.minorLineTop + 'px'; + if (orientation == 'top') { + line.style.top = this.props.majorLabelHeight + 'px'; + line.style.bottom = ''; + } + else { + line.style.top = ''; + line.style.bottom = this.props.majorLabelHeight + 'px'; + } line.style.height = props.minorLineHeight + 'px'; line.style.left = (x - props.minorLineWidth / 2) + 'px'; }; @@ -4619,9 +4311,10 @@ TimeAxis.prototype._repaintMinorLine = function (x) { /** * Create a Major line for the axis at position x * @param {Number} x + * @param {String} orientation "top" or "bottom" (default) * @private */ -TimeAxis.prototype._repaintMajorLine = function (x) { +TimeAxis.prototype._repaintMajorLine = function (x, orientation) { // reuse redundant line var line = this.dom.redundant.majorLines.shift(); @@ -4634,7 +4327,14 @@ TimeAxis.prototype._repaintMajorLine = function (x) { this.dom.majorLines.push(line); var props = this.props; - line.style.top = props.majorLineTop + 'px'; + if (orientation == 'top') { + line.style.top = '0px'; + line.style.bottom = ''; + } + else { + line.style.top = ''; + line.style.bottom = '0px'; + } line.style.left = (x - props.majorLineWidth / 2) + 'px'; line.style.height = props.majorLineHeight + 'px'; }; @@ -4647,7 +4347,7 @@ TimeAxis.prototype._repaintMajorLine = function (x) { TimeAxis.prototype._repaintLine = function() { var line = this.dom.line, frame = this.frame, - options = this.options; + orientation = this.getOption('orientation'); // line before all axis elements if (this.getOption('showMinorLabels') || this.getOption('showMajorLabels')) { @@ -4664,167 +4364,54 @@ TimeAxis.prototype._repaintLine = function() { this.dom.line = line; } - line.style.top = this.props.lineTop + 'px'; + if (orientation == 'top') { + line.style.top = this.height + 'px'; + line.style.bottom = ''; + } + else { + line.style.top = ''; + line.style.bottom = this.height + 'px'; + } } else { - if (line && line.parentElement) { - frame.removeChild(line.line); + if (line && line.parentNode) { + line.parentNode.removeChild(line); delete this.dom.line; } } }; /** - * Create characters used to determine the size of text on the axis + * 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._repaintMeasureChars = function () { - // calculate the width and height of a single character - // this is used to calculate the step size, and also the positioning of the - // axis - var dom = this.dom, - text; - - if (!dom.measureCharMinor) { - text = document.createTextNode('0'); +TimeAxis.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 = 'text minor measure'; - measureCharMinor.appendChild(text); + measureCharMinor.appendChild(textMinor); this.frame.appendChild(measureCharMinor); - dom.measureCharMinor = measureCharMinor; + this.props.minorCharHeight = measureCharMinor.clientHeight; + this.props.minorCharWidth = measureCharMinor.clientWidth; + + this.frame.removeChild(measureCharMinor); } - if (!dom.measureCharMajor) { - text = document.createTextNode('0'); + if (!('majorCharHeight' in this.props)) { + var textMajor = document.createTextNode('0'); var measureCharMajor = document.createElement('DIV'); measureCharMajor.className = 'text major measure'; - measureCharMajor.appendChild(text); + measureCharMajor.appendChild(textMajor); this.frame.appendChild(measureCharMajor); - dom.measureCharMajor = measureCharMajor; - } -}; - -/** - * Reflow the component - * @return {Boolean} resized - */ -TimeAxis.prototype.reflow = function () { - var changed = 0, - update = util.updateProperty, - frame = this.frame, - range = this.range; - - if (!range) { - throw new Error('Cannot repaint time axis: no range configured'); - } - - if (frame) { - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - - // calculate size of a character - var props = this.props, - showMinorLabels = this.getOption('showMinorLabels'), - showMajorLabels = this.getOption('showMajorLabels'), - measureCharMinor = this.dom.measureCharMinor, - measureCharMajor = this.dom.measureCharMajor; - if (measureCharMinor) { - props.minorCharHeight = measureCharMinor.clientHeight; - props.minorCharWidth = measureCharMinor.clientWidth; - } - if (measureCharMajor) { - props.majorCharHeight = measureCharMajor.clientHeight; - props.majorCharWidth = measureCharMajor.clientWidth; - } - - var parentHeight = frame.parentNode ? frame.parentNode.offsetHeight : 0; - if (parentHeight != props.parentHeight) { - props.parentHeight = parentHeight; - changed += 1; - } - switch (this.getOption('orientation')) { - case 'bottom': - props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; - props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; - - props.minorLabelTop = 0; - props.majorLabelTop = props.minorLabelTop + props.minorLabelHeight; - - props.minorLineTop = -this.top; - props.minorLineHeight = Math.max(this.top + props.majorLabelHeight, 0); - props.minorLineWidth = 1; // TODO: really calculate width - - props.majorLineTop = -this.top; - props.majorLineHeight = Math.max(this.top + props.minorLabelHeight + props.majorLabelHeight, 0); - props.majorLineWidth = 1; // TODO: really calculate width - - props.lineTop = 0; - - break; - - case 'top': - props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; - props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; - - props.majorLabelTop = 0; - props.minorLabelTop = props.majorLabelTop + props.majorLabelHeight; - - props.minorLineTop = props.minorLabelTop; - props.minorLineHeight = Math.max(parentHeight - props.majorLabelHeight - this.top); - props.minorLineWidth = 1; // TODO: really calculate width - - props.majorLineTop = 0; - props.majorLineHeight = Math.max(parentHeight - this.top); - props.majorLineWidth = 1; // TODO: really calculate width - - props.lineTop = props.majorLabelHeight + props.minorLabelHeight; - - break; - - default: - throw new Error('Unkown orientation "' + this.getOption('orientation') + '"'); - } - - var height = props.minorLabelHeight + props.majorLabelHeight; - changed += update(this, 'width', frame.offsetWidth); - changed += update(this, 'height', height); - - // calculate range and step - this._updateConversion(); - - var start = util.convert(range.start, 'Number'), - end = util.convert(range.end, 'Number'), - minimumStep = this.toTime((props.minorCharWidth || 10) * 5).valueOf() - -this.toTime(0).valueOf(); - this.step = new TimeStep(new Date(start), new Date(end), minimumStep); - changed += update(props.range, 'start', start); - changed += update(props.range, 'end', end); - changed += update(props.range, 'minimumStep', minimumStep.valueOf()); - } - - return (changed > 0); -}; - -/** - * Calculate the scale and offset to convert a position on screen to the - * corresponding date and vice versa. - * After the method _updateConversion is executed once, the methods toTime - * and toScreen can be used. - * @private - */ -TimeAxis.prototype._updateConversion = function() { - var range = this.range; - if (!range) { - throw new Error('No range configured'); - } + this.props.majorCharHeight = measureCharMajor.clientHeight; + this.props.majorCharWidth = measureCharMajor.clientWidth; - if (range.conversion) { - this.conversion = range.conversion(this.width); - } - else { - this.conversion = Range.conversion(range.start, range.end, this.width); + this.frame.removeChild(measureCharMajor); } }; @@ -4840,24 +4427,23 @@ TimeAxis.prototype.snap = function snap (date) { /** * A current time bar - * @param {Component} parent - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) + * @param {Range} range * @param {Object} [options] Available parameters: * {Boolean} [showCurrentTime] * @constructor CurrentTime * @extends Component */ -function CurrentTime (parent, depends, options) { +function CurrentTime (range, options) { this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; + this.range = range; this.options = options || {}; this.defaultOptions = { showCurrentTime: false }; + + this._create(); } CurrentTime.prototype = new Component(); @@ -4865,96 +4451,87 @@ CurrentTime.prototype = new Component(); CurrentTime.prototype.setOptions = Component.prototype.setOptions; /** - * Get the container element of the bar, which can be used by a child to - * add its own widgets. - * @returns {HTMLElement} container + * Create the HTML DOM for the current time bar + * @private */ -CurrentTime.prototype.getContainer = function () { - return this.frame; +CurrentTime.prototype._create = function _create () { + var bar = document.createElement('div'); + bar.className = 'currenttime'; + bar.style.position = 'absolute'; + bar.style.top = '0px'; + bar.style.height = '100%'; + + this.bar = bar; +}; + +/** + * Get the frame element of the current time bar + * @returns {HTMLElement} frame + */ +CurrentTime.prototype.getFrame = function getFrame() { + return this.bar; }; /** * Repaint the component - * @return {Boolean} changed + * @return {boolean} Returns true if the component is resized */ -CurrentTime.prototype.repaint = function () { - var bar = this.frame, - parent = this.parent, - parentContainer = parent.parent.getContainer(); +CurrentTime.prototype.repaint = function repaint() { + var parent = this.parent; - if (!parent) { - throw new Error('Cannot repaint bar: no parent attached'); - } + var now = new Date(); + var x = this.options.toScreen(now); - if (!parentContainer) { - throw new Error('Cannot repaint bar: parent has no container element'); - } + this.bar.style.left = x + 'px'; + this.bar.title = 'Current time: ' + now; - if (!this.getOption('showCurrentTime')) { - if (bar) { - parentContainer.removeChild(bar); - delete this.frame; - } + return false; +}; - return false; - } +/** + * Start auto refreshing the current time bar + */ +CurrentTime.prototype.start = function start() { + var me = this; - if (!bar) { - bar = document.createElement('div'); - bar.className = 'currenttime'; - bar.style.position = 'absolute'; - bar.style.top = '0px'; - bar.style.height = '100%'; + function update () { + me.stop(); - parentContainer.appendChild(bar); - this.frame = bar; - } + // determine interval to refresh + var scale = me.range.conversion(me.parent.width).scale; + var interval = 1 / scale / 10; + if (interval < 30) interval = 30; + if (interval > 1000) interval = 1000; - if (!parent.conversion) { - parent._updateConversion(); - } + me.repaint(); - var now = new Date(); - var x = parent.toScreen(now); + // start a timer to adjust for the new time + me.currentTimeTimer = setTimeout(update, interval); + } - bar.style.left = x + 'px'; - bar.title = 'Current time: ' + now; + update(); +}; - // start a timer to adjust for the new time +/** + * Stop auto refreshing the current time bar + */ +CurrentTime.prototype.stop = function stop() { if (this.currentTimeTimer !== undefined) { clearTimeout(this.currentTimeTimer); delete this.currentTimeTimer; } - - var timeline = this; - var interval = 1 / parent.conversion.scale / 2; - - if (interval < 30) { - interval = 30; - } - - this.currentTimeTimer = setTimeout(function() { - timeline.repaint(); - }, interval); - - return false; }; /** * A custom time bar - * @param {Component} parent - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) * @param {Object} [options] Available parameters: * {Boolean} [showCustomTime] * @constructor CustomTime * @extends Component */ -function CustomTime (parent, depends, options) { +function CustomTime (options) { this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; this.options = options || {}; this.defaultOptions = { @@ -4963,85 +4540,61 @@ function CustomTime (parent, depends, options) { this.customTime = new Date(); this.eventParams = {}; // stores state parameters while dragging the bar + + // create the DOM + this._create(); } CustomTime.prototype = new Component(); -Emitter(CustomTime.prototype); - CustomTime.prototype.setOptions = Component.prototype.setOptions; /** - * Get the container element of the bar, which can be used by a child to - * add its own widgets. - * @returns {HTMLElement} container + * Create the DOM for the custom time + * @private */ -CustomTime.prototype.getContainer = function () { - return this.frame; +CustomTime.prototype._create = function _create () { + 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)); +}; + +/** + * Get the frame element of the custom time bar + * @returns {HTMLElement} frame + */ +CustomTime.prototype.getFrame = function getFrame() { + return this.bar; }; /** * Repaint the component - * @return {Boolean} changed + * @return {boolean} Returns true if the component is resized */ CustomTime.prototype.repaint = function () { - var bar = this.frame, - parent = this.parent; - - if (!parent) { - throw new Error('Cannot repaint bar: no parent attached'); - } - - var parentContainer = parent.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint bar: parent has no container element'); - } - - if (!this.getOption('showCustomTime')) { - if (bar) { - parentContainer.removeChild(bar); - delete this.frame; - } - - return false; - } - - if (!bar) { - bar = document.createElement('div'); - bar.className = 'customtime'; - bar.style.position = 'absolute'; - bar.style.top = '0px'; - bar.style.height = '100%'; - - parentContainer.appendChild(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); - - this.frame = bar; + var x = this.options.toScreen(this.customTime); - // 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)); - } - - if (!parent.conversion) { - parent._updateConversion(); - } - - var x = parent.toScreen(this.customTime); - - bar.style.left = x + 'px'; - bar.title = 'Time: ' + this.customTime; + this.bar.style.left = x + 'px'; + this.bar.title = 'Time: ' + this.customTime; return false; }; @@ -5069,6 +4622,7 @@ CustomTime.prototype.getCustomTime = function() { * @private */ CustomTime.prototype._onDragStart = function(event) { + this.eventParams.dragging = true; this.eventParams.customTime = this.customTime; event.stopPropagation(); @@ -5081,18 +4635,18 @@ CustomTime.prototype._onDragStart = function(event) { * @private */ CustomTime.prototype._onDrag = function (event) { + if (!this.eventParams.dragging) return; + var deltaX = event.gesture.deltaX, - x = this.parent.toScreen(this.eventParams.customTime) + deltaX, - time = this.parent.toTime(x); + x = this.options.toScreen(this.eventParams.customTime) + deltaX, + time = this.options.toTime(x); this.setCustomTime(time); // fire a timechange event - if (this.controller) { - this.controller.emit('timechange', { - time: this.customTime - }) - } + this.emit('timechange', { + time: new Date(this.customTime.valueOf()) + }); event.stopPropagation(); event.preventDefault(); @@ -5104,89 +4658,86 @@ CustomTime.prototype._onDrag = function (event) { * @private */ CustomTime.prototype._onDragEnd = function (event) { + if (!this.eventParams.dragging) return; + // fire a timechanged event - if (this.controller) { - this.controller.emit('timechanged', { - time: this.customTime - }) - } + this.emit('timechanged', { + time: new Date(this.customTime.valueOf()) + }); event.stopPropagation(); event.preventDefault(); }; +var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items + /** * 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 {Component} parent - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) - * @param {Object} [options] See ItemSet.setOptions for the available - * options. + * @param {Panel} backgroundPanel Panel which can be used to display the + * vertical lines of box items. + * @param {Panel} axisPanel Panel on the axis where the dots of box-items + * can be displayed. + * @param {Panel} sidePanel Left side panel holding labels + * @param {Object} [options] See ItemSet.setOptions for the available options. * @constructor ItemSet * @extends Panel */ -// TODO: improve performance by replacing all Array.forEach with a for loop -function ItemSet(parent, depends, options) { +function ItemSet(backgroundPanel, axisPanel, sidePanel, options) { this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; - - // event listeners - this.eventListeners = { - dragstart: this._onDragStart.bind(this), - drag: this._onDrag.bind(this), - dragend: this._onDragEnd.bind(this) - }; // one options object is shared by this itemset and all its items this.options = options || {}; - this.defaultOptions = { - type: 'box', - align: 'center', - orientation: 'bottom', - margin: { - axis: 20, - item: 10 - }, - padding: 5 - }; - + this.backgroundPanel = backgroundPanel; + this.axisPanel = axisPanel; + this.sidePanel = sidePanel; + this.itemOptions = Object.create(this.options); this.dom = {}; + this.hammer = null; var me = this; - this.itemsData = null; // DataSet - this.range = null; // Range or Object {start: number, end: number} + this.itemsData = null; // DataSet + this.groupsData = null; // DataSet + this.range = null; // Range or Object {start: number, end: number} - // data change listeners - this.listeners = { + // listeners for the DataSet of the items + this.itemListeners = { 'add': function (event, params, senderId) { - if (senderId != me.id) { - me._onAdd(params.items); - } + if (senderId != me.id) me._onAdd(params.items); }, 'update': function (event, params, senderId) { - if (senderId != me.id) { - me._onUpdate(params.items); - } + if (senderId != me.id) me._onUpdate(params.items); }, 'remove': function (event, params, senderId) { - if (senderId != me.id) { - me._onRemove(params.items); - } + if (senderId != me.id) me._onRemove(params.items); + } + }; + + // listeners for the DataSet of the groups + this.groupListeners = { + 'add': function (event, params, senderId) { + if (senderId != me.id) me._onAddGroups(params.items); + }, + 'update': function (event, params, senderId) { + if (senderId != me.id) me._onUpdateGroups(params.items); + }, + 'remove': function (event, params, senderId) { + if (senderId != me.id) me._onRemoveGroups(params.items); } }; 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.queue = {}; // queue with id/actions: 'add', 'update', 'delete' - this.stack = new Stack(this, Object.create(this.options)); - this.conversion = null; + this.stackDirty = true; // if true, all items will be restacked on next repaint this.touchParams = {}; // stores properties while dragging + // create the HTML DOM - // TODO: ItemSet should also attach event listeners for rangechange and rangechanged, like timeaxis + this._create(); } ItemSet.prototype = new Panel(); @@ -5199,6 +4750,51 @@ ItemSet.types = { point: ItemPoint }; +/** + * Create the HTML DOM for the ItemSet + */ +ItemSet.prototype._create = function _create(){ + var frame = document.createElement('div'); + frame['timeline-itemset'] = this; + this.frame = frame; + + // create background panel + var background = document.createElement('div'); + background.className = 'background'; + this.backgroundPanel.frame.appendChild(background); + this.dom.background = background; + + // create foreground panel + var foreground = document.createElement('div'); + foreground.className = 'foreground'; + frame.appendChild(foreground); + this.dom.foreground = foreground; + + // create axis panel + var axis = document.createElement('div'); + axis.className = 'axis'; + this.dom.axis = axis; + this.axisPanel.frame.appendChild(axis); + + // create labelset + var labelSet = document.createElement('div'); + labelSet.className = 'labelset'; + this.dom.labelSet = labelSet; + this.sidePanel.frame.appendChild(labelSet); + + // create ungrouped Group + this._updateUngrouped(); + + // attach event listeners + // TODO: use event listeners from the rootpanel to improve performance? + this.hammer = Hammer(frame, { + 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 options for the ItemSet. Existing options will be extended/overwritten. * @param {Object} [options] The following options are available: @@ -5227,56 +4823,58 @@ ItemSet.types = { * Function to let items snap to nice dates when * dragging items. */ -ItemSet.prototype.setOptions = Component.prototype.setOptions; - - +ItemSet.prototype.setOptions = function setOptions(options) { + Component.prototype.setOptions.call(this, options); +}; /** - * Set controller for this component - * @param {Controller | null} controller + * Mark the ItemSet dirty so it will refresh everything with next repaint */ -ItemSet.prototype.setController = function setController (controller) { - var event; +ItemSet.prototype.markDirty = function markDirty() { + this.groupIds = []; + this.stackDirty = true; +}; - // unregister old event listeners - if (this.controller) { - for (event in this.eventListeners) { - if (this.eventListeners.hasOwnProperty(event)) { - this.controller.off(event, this.eventListeners[event]); - } - } +/** + * Hide the component from the DOM + */ +ItemSet.prototype.hide = function hide() { + // remove the axis with dots + if (this.dom.axis.parentNode) { + this.dom.axis.parentNode.removeChild(this.dom.axis); } - this.controller = controller || null; + // remove the background with vertical lines + if (this.dom.background.parentNode) { + this.dom.background.parentNode.removeChild(this.dom.background); + } - // register new event listeners - if (this.controller) { - for (event in this.eventListeners) { - if (this.eventListeners.hasOwnProperty(event)) { - this.controller.on(event, this.eventListeners[event]); - } - } + // remove the labelset containing all group labels + if (this.dom.labelSet.parentNode) { + this.dom.labelSet.parentNode.removeChild(this.dom.labelSet); } }; -// attach event listeners for dragging items to the controller -(function (me) { - var _controller = null; - var _onDragStart = null; - var _onDrag = null; - var _onDragEnd = null; - - Object.defineProperty(me, 'controller', { - get: function () { - return _controller; - }, - - set: function (controller) { +/** + * Show the component in the DOM (when not already visible). + * @return {Boolean} changed + */ +ItemSet.prototype.show = function show() { + // show axis with dots + if (!this.dom.axis.parentNode) { + this.axisPanel.frame.appendChild(this.dom.axis); + } - } - }); -}) (this); + // show background with vertical lines + if (!this.dom.background.parentNode) { + this.backgroundPanel.frame.appendChild(this.dom.background); + } + // show labelset containing labels + if (!this.dom.labelSet.parentNode) { + this.sidePanel.frame.appendChild(this.dom.labelSet); + } +}; /** * Set range (start and end). @@ -5298,7 +4896,7 @@ ItemSet.prototype.setRange = function setRange(range) { * unselected. */ ItemSet.prototype.setSelection = function setSelection(ids) { - var i, ii, id, item, selection; + var i, ii, id, item; if (ids) { if (!Array.isArray(ids)) { @@ -5322,10 +4920,6 @@ ItemSet.prototype.setSelection = function setSelection(ids) { item.select(); } } - - if (this.controller) { - this.requestRepaint(); - } } }; @@ -5352,184 +4946,145 @@ ItemSet.prototype._deselect = function _deselect(id) { } }; +/** + * Return the item sets frame + * @returns {HTMLElement} frame + */ +ItemSet.prototype.getFrame = function getFrame() { + return this.frame; +}; + /** * Repaint the component - * @return {Boolean} changed + * @return {boolean} Returns true if the component is resized */ ItemSet.prototype.repaint = function repaint() { - var changed = 0, - update = util.updateProperty, + var margin = this.options.margin, + range = this.range, asSize = util.option.asSize, + asString = util.option.asString, options = this.options, orientation = this.getOption('orientation'), - defaultOptions = this.defaultOptions, + resized = false, frame = this.frame; - if (!frame) { - frame = document.createElement('div'); - frame.className = 'itemset'; - frame['timeline-itemset'] = this; - - var className = options.className; - if (className) { - util.addClassName(frame, util.option.asString(className)); - } - - // create background panel - var background = document.createElement('div'); - background.className = 'background'; - frame.appendChild(background); - this.dom.background = background; + // TODO: document this feature to specify one margin for both item and axis distance + if (typeof margin === 'number') { + margin = { + item: margin, + axis: margin + }; + } - // create foreground panel - var foreground = document.createElement('div'); - foreground.className = 'foreground'; - frame.appendChild(foreground); - this.dom.foreground = foreground; + // update className + frame.className = 'itemset' + (options.className ? (' ' + asString(options.className)) : ''); - // create axis panel - var axis = document.createElement('div'); - axis.className = 'itemset-axis'; - //frame.appendChild(axis); - this.dom.axis = axis; + // reorder the groups (if needed) + resized = this._orderGroups() || resized; - this.frame = frame; - changed += 1; - } + // 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 = this.range.end - this.range.start; + var zoomed = (visibleInterval != this.lastVisibleInterval) || (this.width != this.lastWidth); + if (zoomed) this.stackDirty = true; + this.lastVisibleInterval = visibleInterval; + this.lastWidth = this.width; - if (!this.parent) { - throw new Error('Cannot repaint itemset: no parent attached'); - } - var parentContainer = this.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint itemset: parent has no container element'); - } - if (!frame.parentNode) { - parentContainer.appendChild(frame); - changed += 1; - } - if (!this.dom.axis.parentNode) { - parentContainer.appendChild(this.dom.axis); - changed += 1; - } + // repaint all groups + var restack = this.stackDirty, + firstGroup = this._firstGroup(), + firstMargin = { + item: margin.item, + axis: margin.axis + }, + nonFirstMargin = { + item: margin.item, + axis: margin.item / 2 + }, + height = 0, + minHeight = margin.axis + margin.item; + util.forEach(this.groups, function (group) { + var groupMargin = (group == firstGroup) ? firstMargin : nonFirstMargin; + resized = group.repaint(range, groupMargin, restack) || resized; + height += group.height; + }); + height = Math.max(height, minHeight); + this.stackDirty = false; // reposition frame - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'top', asSize(options.top, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); + frame.style.left = asSize(options.left, ''); + frame.style.right = asSize(options.right, ''); + frame.style.top = asSize((orientation == 'top') ? '0' : ''); + frame.style.bottom = asSize((orientation == 'top') ? '' : '0'); + frame.style.width = asSize(options.width, '100%'); + frame.style.height = asSize(height); + //frame.style.height = asSize('height' in options ? options.height : height); // TODO: reckon with height + + // calculate actual size and position + this.top = frame.offsetTop; + this.left = frame.offsetLeft; + this.width = frame.offsetWidth; + this.height = height; // reposition axis - changed += update(this.dom.axis.style, 'left', asSize(options.left, '0px')); - changed += update(this.dom.axis.style, 'width', asSize(options.width, '100%')); - if (orientation == 'bottom') { - changed += update(this.dom.axis.style, 'top', (this.height + this.top) + 'px'); - } - else { // orientation == 'top' - changed += update(this.dom.axis.style, 'top', this.top + 'px'); - } - - this._updateConversion(); - - var me = this, - queue = this.queue, - itemsData = this.itemsData, - items = this.items, - dataOptions = { - // TODO: cleanup - // fields: [(itemsData && itemsData.fieldId || 'id'), 'start', 'end', 'content', 'type', 'className'] - }; - - // show/hide added/changed/removed items - for (var id in queue) { - if (queue.hasOwnProperty(id)) { - var entry = queue[id], - item = items[id], - action = entry.action; - - //noinspection FallthroughInSwitchStatementJS - switch (action) { - case 'add': - case 'update': - var itemData = itemsData && itemsData.get(id, dataOptions); - - if (itemData) { - var type = itemData.type || - (itemData.start && itemData.end && 'range') || - options.type || - 'box'; - var constructor = ItemSet.types[type]; - - // TODO: how to handle items with invalid data? hide them and give a warning? or throw an error? - if (item) { - // update item - if (!constructor || !(item instanceof constructor)) { - // item type has changed, hide and delete the item - changed += item.hide(); - item = null; - } - else { - item.data = itemData; // TODO: create a method item.setData ? - changed++; - } - } - - if (!item) { - // create item - if (constructor) { - item = new constructor(me, itemData, options, defaultOptions); - item.id = entry.id; // we take entry.id, as id itself is stringified - changed++; - } - else { - throw new TypeError('Unknown item type "' + type + '"'); - } - } + this.dom.axis.style.left = asSize(options.left, '0'); + this.dom.axis.style.right = asSize(options.right, ''); + this.dom.axis.style.width = asSize(options.width, '100%'); + this.dom.axis.style.height = asSize(0); + this.dom.axis.style.top = asSize((orientation == 'top') ? '0' : ''); + this.dom.axis.style.bottom = asSize((orientation == 'top') ? '' : '0'); - // force a repaint (not only a reposition) - item.repaint(); - - items[id] = item; - } + // check if this component is resized + resized = this._isResized() || resized; - // update queue - delete queue[id]; - break; + return resized; +}; - case 'remove': - if (item) { - // remove the item from the set selected items - if (item.selected) { - me._deselect(id); - } +/** + * Get the first group, aligned with the axis + * @return {Group | null} firstGroup + * @private + */ +ItemSet.prototype._firstGroup = function _firstGroup() { + var firstGroupIndex = (this.options.orientation == 'top') ? 0 : (this.groupIds.length - 1); + var firstGroupId = this.groupIds[firstGroupIndex]; + var firstGroup = this.groups[firstGroupId] || this.groups[UNGROUPED]; - // remove DOM of the item - changed += item.hide(); - } + return firstGroup || null; +}; - // update lists - delete items[id]; - delete queue[id]; - break; +/** + * Create or delete the group holding all ungrouped items. This group is used when + * there are no groups specified. + * @protected + */ +ItemSet.prototype._updateUngrouped = function _updateUngrouped() { + var ungrouped = this.groups[UNGROUPED]; - default: - console.log('Error: unknown action "' + action + '"'); - } + if (this.groupsData) { + // remove the group holding all ungrouped items + if (ungrouped) { + ungrouped.hide(); + delete this.groups[UNGROUPED]; } } + 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; - // reposition all items. Show items only when in the visible area - util.forEach(this.items, function (item) { - if (item.visible) { - changed += item.show(); - item.reposition(); - } - else { - changed += item.hide(); - } - }); + for (var itemId in this.items) { + if (this.items.hasOwnProperty(itemId)) { + ungrouped.add(this.items[itemId]); + } + } - return (changed > 0); + ungrouped.show(); + } + } }; /** @@ -5557,87 +5112,11 @@ ItemSet.prototype.getAxis = function getAxis() { }; /** - * Reflow the component - * @return {Boolean} resized - */ -ItemSet.prototype.reflow = function reflow () { - var changed = 0, - options = this.options, - marginAxis = (options.margin && 'axis' in options.margin) ? options.margin.axis : this.defaultOptions.margin.axis, - marginItem = (options.margin && 'item' in options.margin) ? options.margin.item : this.defaultOptions.margin.item, - update = util.updateProperty, - asNumber = util.option.asNumber, - asSize = util.option.asSize, - frame = this.frame; - - if (frame) { - this._updateConversion(); - - util.forEach(this.items, function (item) { - changed += item.reflow(); - }); - - // TODO: stack.update should be triggered via an event, in stack itself - // TODO: only update the stack when there are changed items - this.stack.update(); - - var maxHeight = asNumber(options.maxHeight); - var fixedHeight = (asSize(options.height) != null); - var height; - if (fixedHeight) { - height = frame.offsetHeight; - } - else { - // height is not specified, determine the height from the height and positioned items - var visibleItems = this.stack.ordered; // TODO: not so nice way to get the filtered items - 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)); - }); - height = (max - min) + marginAxis + marginItem; - } - else { - height = marginAxis + marginItem; - } - } - if (maxHeight != null) { - height = Math.min(height, maxHeight); - } - changed += update(this, 'height', height); - - // calculate height from items - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - changed += update(this, 'width', frame.offsetWidth); - } - else { - changed += 1; - } - - return (changed > 0); -}; - -/** - * Hide this component from the DOM - * @return {Boolean} changed + * Get the element for the labelset + * @return {HTMLElement} labelSet */ -ItemSet.prototype.hide = function hide() { - var changed = false; - - // remove the DOM - if (this.frame && this.frame.parentNode) { - this.frame.parentNode.removeChild(this.frame); - changed = true; - } - if (this.dom.axis && this.dom.axis.parentNode) { - this.dom.axis.parentNode.removeChild(this.dom.axis); - changed = true; - } - - return changed; +ItemSet.prototype.getLabelSet = function getLabelSet() { + return this.dom.labelSet; }; /** @@ -5657,12 +5136,12 @@ ItemSet.prototype.setItems = function setItems(items) { this.itemsData = items; } else { - throw new TypeError('Data must be an instance of DataSet'); + throw new TypeError('Data must be an instance of DataSet or DataView'); } if (oldItemsData) { // unsubscribe from old dataset - util.forEach(this.listeners, function (callback, event) { + util.forEach(this.itemListeners, function (callback, event) { oldItemsData.unsubscribe(event, callback); }); @@ -5674,24 +5153,86 @@ ItemSet.prototype.setItems = function setItems(items) { if (this.itemsData) { // subscribe to new dataset var id = this.id; - util.forEach(this.listeners, function (callback, event) { + util.forEach(this.itemListeners, function (callback, event) { me.itemsData.on(event, callback, id); }); - // draw all new items + // add all new items ids = this.itemsData.getIds(); this._onAdd(ids); + + // update the group holding all ungrouped items + this._updateUngrouped(); } }; /** - * Get the current items items + * Get the current items * @returns {vis.DataSet | null} */ ItemSet.prototype.getItems = function getItems() { return this.itemsData; }; +/** + * Set groups + * @param {vis.DataSet} groups + */ +ItemSet.prototype.setGroups = function setGroups(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._onRemoveGroups(ids); + } + + // 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.emit('change'); +}; + +/** + * Get the current groups + * @returns {vis.DataSet | null} groups + */ +ItemSet.prototype.getGroups = function getGroups() { + return this.groupsData; +}; + /** * Remove an item by its id * @param {String | Number} id @@ -5704,7 +5245,9 @@ ItemSet.prototype.removeItem = function removeItem (id) { // confirm deletion this.options.onRemove(item, function (item) { if (item) { - dataset.remove(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); } }); } @@ -5713,95 +5256,308 @@ ItemSet.prototype.removeItem = function removeItem (id) { /** * Handle updated items * @param {Number[]} ids - * @private + * @protected */ ItemSet.prototype._onUpdate = function _onUpdate(ids) { - this._toQueue('update', ids); + var me = this, + items = this.items, + itemOptions = this.itemOptions; + + ids.forEach(function (id) { + var itemData = me.itemsData.get(id), + item = items[id], + type = itemData.type || + (itemData.start && itemData.end && 'range') || + me.options.type || + 'box'; + + 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.options, itemOptions); + item.id = id; // TODO: not so nice setting id afterwards + me._addItem(item); + } + else { + throw new TypeError('Unknown item type "' + type + '"'); + } + } + }); + + this._order(); + this.stackDirty = true; // force re-stacking of all items next repaint + this.emit('change'); }; /** - * Handle changed items + * Handle added items * @param {Number[]} ids - * @private + * @protected */ -ItemSet.prototype._onAdd = function _onAdd(ids) { - this._toQueue('add', ids); -}; +ItemSet.prototype._onAdd = ItemSet.prototype._onUpdate; /** * Handle removed items * @param {Number[]} ids - * @private + * @protected */ ItemSet.prototype._onRemove = function _onRemove(ids) { - this._toQueue('remove', ids); -}; - -/** - * Put items in the queue to be added/updated/remove - * @param {String} action can be 'add', 'update', 'remove' - * @param {Number[]} ids - */ -ItemSet.prototype._toQueue = function _toQueue(action, ids) { - var queue = this.queue; + var count = 0; + var me = this; ids.forEach(function (id) { - queue[id] = { - id: id, - action: action - }; + var item = me.items[id]; + if (item) { + count++; + me._removeItem(item); + } }); - if (this.controller) { - //this.requestReflow(); - this.requestRepaint(); + if (count) { + // update order + this._order(); + this.stackDirty = true; // force re-stacking of all items next repaint + this.emit('change'); } }; /** - * Calculate the scale and offset to convert a position on screen to the - * corresponding date and vice versa. - * After the method _updateConversion is executed once, the methods toTime - * and toScreen can be used. + * Update the order of item in all groups * @private */ -ItemSet.prototype._updateConversion = function _updateConversion() { - var range = this.range; - if (!range) { - throw new Error('No range configured'); - } - - if (range.conversion) { - this.conversion = range.conversion(this.width); - } - else { - this.conversion = Range.conversion(range.start, range.end, this.width); - } +ItemSet.prototype._order = function _order() { + // reorder the items in all groups + // TODO: optimization: only reorder groups affected by the changed items + util.forEach(this.groups, function (group) { + group.order(); + }); }; /** - * Convert a position on screen (pixels) to a datetime - * Before this method can be used, the method _updateConversion must be - * executed once. - * @param {int} x Position on the screen in pixels - * @return {Date} time The datetime the corresponds with given position x + * Handle updated groups + * @param {Number[]} ids + * @private */ -ItemSet.prototype.toTime = function toTime(x) { - var conversion = this.conversion; - return new Date(x / conversion.scale + conversion.offset); +ItemSet.prototype._onUpdateGroups = function _onUpdateGroups(ids) { + this._onAddGroups(ids); }; /** - * Convert a datetime (Date object) into a position on the screen - * Before this method can be used, the method _updateConversion must be - * executed once. - * @param {Date} time A date - * @return {int} x The position on the screen in pixels which corresponds - * with the given date. + * Handle changed groups + * @param {Number[]} ids + * @private */ -ItemSet.prototype.toScreen = function toScreen(time) { - var conversion = this.conversion; - return (time.valueOf() - conversion.offset) * conversion.scale; -}; +ItemSet.prototype._onAddGroups = function _onAddGroups(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) { + 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); + } + }); + + this.emit('change'); +}; + +/** + * Handle removed groups + * @param {Number[]} ids + * @private + */ +ItemSet.prototype._onRemoveGroups = function _onRemoveGroups(ids) { + var groups = this.groups; + ids.forEach(function (id) { + var group = groups[id]; + + if (group) { + group.hide(); + delete groups[id]; + } + }); + + this.markDirty(); + + this.emit('change'); +}; + +/** + * 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 + }); + + 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) { + var group = groups[groupId]; + group.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; + } +}; + +/** + * Add a new item + * @param {Item} item + * @private + */ +ItemSet.prototype._addItem = function _addItem(item) { + this.items[item.id] = item; + + // add to group + var groupId = this.groupsData ? item.data.group : UNGROUPED; + var group = this.groups[groupId]; + if (group) group.add(item); +}; + +/** + * Update an existing item + * @param {Item} item + * @param {Object} itemData + * @private + */ +ItemSet.prototype._updateItem = function _updateItem(item, itemData) { + var oldGroupId = item.data.group; + + item.data = itemData; + item.repaint(); + + // update group + if (oldGroupId != item.data.group) { + var oldGroup = this.groups[oldGroupId]; + if (oldGroup) oldGroup.remove(item); + + var groupId = this.groupsData ? item.data.group : UNGROUPED; + var group = this.groups[groupId]; + if (group) group.add(item); + } +}; + +/** + * 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 _removeItem(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 + var groupId = this.groupsData ? item.data.group : UNGROUPED; + var group = this.groups[groupId]; + if (group) group.remove(item); +}; + +/** + * Create an array containing all items being a range (having an end date) + * @param array + * @returns {Array} + * @private + */ +ItemSet.prototype._constructByEndArray = function _constructByEndArray(array) { + var endArray = []; + + for (var i = 0; i < array.length; i++) { + if (array[i] instanceof ItemRange) { + endArray.push(array[i]); + } + } + return endArray; +}; + +/** + * Get the width of the group labels + * @return {Number} width + */ +ItemSet.prototype.getLabelsWidth = function getLabelsWidth() { + var width = 0; + + util.forEach(this.groups, function (group) { + width = Math.max(width, group.getLabelWidth()); + }); + + return width; +}; + +/** + * Get the height of the itemsets background + * @return {Number} height + */ +ItemSet.prototype.getBackgroundHeight = function getBackgroundHeight() { + return this.height; +}; /** * Start dragging the selected events @@ -5809,28 +5565,45 @@ ItemSet.prototype.toScreen = function toScreen(time) { * @private */ ItemSet.prototype._onDragStart = function (event) { - if (!this.options.editable) { + if (!this.options.editable.updateTime && !this.options.editable.updateGroup) { return; } var item = ItemSet.itemFromTarget(event), - me = this; + me = this, + props; if (item && item.selected) { var dragLeftItem = event.target.dragLeftItem; var dragRightItem = event.target.dragRightItem; if (dragLeftItem) { - this.touchParams.itemProps = [{ - item: dragLeftItem, - start: item.data.start.valueOf() - }]; + props = { + item: dragLeftItem + }; + + 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; + } + + this.touchParams.itemProps = [props]; } else if (dragRightItem) { - this.touchParams.itemProps = [{ - item: dragRightItem, - end: item.data.end.valueOf() - }]; + props = { + item: dragRightItem + }; + + 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) { @@ -5839,11 +5612,12 @@ ItemSet.prototype._onDragStart = function (event) { item: item }; - if ('start' in item.data) { - props.start = item.data.start.valueOf() + 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 ('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; @@ -5863,7 +5637,8 @@ ItemSet.prototype._onDrag = function (event) { if (this.touchParams.itemProps) { var snap = this.options.snap || null, deltaX = event.gesture.deltaX, - offset = deltaX / this.conversion.scale; + scale = (this.width / (this.range.end - this.range.start)), + offset = deltaX / scale; // move this.touchParams.itemProps.forEach(function (props) { @@ -5871,17 +5646,31 @@ ItemSet.prototype._onDrag = function (event) { var start = new Date(props.start + offset); props.item.data.start = snap ? snap(start) : start; } + if ('end' in props) { var end = new Date(props.end + offset); props.item.data.end = snap ? snap(end) : end; } + + if ('group' in props) { + // drag from one group to another + var group = ItemSet.groupFromTarget(event); + if (group && group.groupId != props.item.data.group) { + var oldGroup = props.item.parent; + oldGroup.remove(props.item); + oldGroup.order(); + group.add(props.item); + group.order(); + + props.item.data.group = group.groupId; + } + } }); // TODO: implement onMoving handler - // TODO: implement dragging from one group to another - - this.requestReflow(); + this.stackDirty = true; // force re-stacking of all items next repaint + this.emit('change'); event.stopPropagation(); } @@ -5897,35 +5686,41 @@ ItemSet.prototype._onDragEnd = function (event) { // prepare a change set for the changed items var changes = [], me = this, - dataset = this._myDataSet(), - type; + dataset = this._myDataSet(); this.touchParams.itemProps.forEach(function (props) { var id = props.item.id, - item = me.itemsData.get(id); + itemData = me.itemsData.get(id); var changed = false; if ('start' in props.item.data) { changed = (props.start != props.item.data.start.valueOf()); - item.start = util.convert(props.item.data.start, dataset.convert['start']); + itemData.start = util.convert(props.item.data.start, dataset.convert['start']); } if ('end' in props.item.data) { changed = changed || (props.end != props.item.data.end.valueOf()); - item.end = util.convert(props.item.data.end, dataset.convert['end']); + itemData.end = util.convert(props.item.data.end, dataset.convert['end']); + } + 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(item, function (item) { - if (item) { + me.options.onMove(itemData, function (itemData) { + if (itemData) { // apply changes - changes.push(item); + itemData[dataset.fieldId] = id; // ensure the item contains its id (can be undefined) + changes.push(itemData); } else { // restore original values if ('start' in props) props.item.data.start = props.start; if ('end' in props) props.item.data.end = props.end; - me.requestReflow(); + + me.stackDirty = true; // force re-stacking of all items next repaint + me.emit('change'); } }); } @@ -5959,6 +5754,24 @@ ItemSet.itemFromTarget = function itemFromTarget (event) { 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 groupFromTarget (event) { + var target = event.target; + while (target) { + if (target.hasOwnProperty('timeline-group')) { + return target['timeline-group']; + } + target = target.parentNode; + } + + return null; +}; + /** * Find the ItemSet from an event target: * searches for the attribute 'timeline-itemset' in the event target's element tree @@ -5992,27 +5805,28 @@ ItemSet.prototype._myDataSet = function _myDataSet() { }; /** * @constructor Item - * @param {ItemSet} parent * @param {Object} data Object containing (optional) parameters type, * start, end, content, group, className. * @param {Object} [options] Options to set initial property values * @param {Object} [defaultOptions] default options * // TODO: describe available options */ -function Item (parent, data, options, defaultOptions) { - this.parent = parent; +function Item (data, options, defaultOptions) { + this.id = null; + this.parent = null; this.data = data; this.dom = null; this.options = options || {}; this.defaultOptions = defaultOptions || {}; this.selected = false; - this.visible = false; - this.top = 0; - this.left = 0; - this.width = 0; - this.height = 0; - this.offset = 0; + this.displayed = false; + this.dirty = true; + + this.top = null; + this.left = null; + this.width = null; + this.height = null; } /** @@ -6020,7 +5834,7 @@ function Item (parent, data, options, defaultOptions) { */ Item.prototype.select = function select() { this.selected = true; - if (this.visible) this.repaint(); + if (this.displayed) this.repaint(); }; /** @@ -6028,7 +5842,34 @@ Item.prototype.select = function select() { */ Item.prototype.unselect = function unselect() { this.selected = false; - if (this.visible) this.repaint(); + if (this.displayed) this.repaint(); +}; + +/** + * Set a parent for the item + * @param {ItemSet | Group} parent + */ +Item.prototype.setParent = function setParent(parent) { + if (this.displayed) { + this.hide(); + this.parent = parent; + if (this.parent) { + this.show(); + } + } + else { + this.parent = parent; + } +}; + +/** + * 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 isVisible (range) { + // Should be implemented by Item implementations + return false; }; /** @@ -6049,40 +5890,34 @@ Item.prototype.hide = function hide() { /** * Repaint the item - * @return {Boolean} changed */ Item.prototype.repaint = function repaint() { // should be implemented by the item - return false; }; /** - * Reflow the item - * @return {Boolean} resized + * Reposition the Item horizontally */ -Item.prototype.reflow = function reflow() { +Item.prototype.repositionX = function repositionX() { // should be implemented by the item - return false; }; /** - * Give the item a display offset in pixels - * @param {Number} offset Offset on screen in pixels + * Reposition the Item vertically */ -Item.prototype.setOffset = function setOffset(offset) { - this.offset = offset; +Item.prototype.repositionY = function repositionY() { + // 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 - * @private + * @protected */ Item.prototype._repaintDeleteButton = function (anchor) { - if (this.selected && this.options.editable && !this.dom.deleteButton) { + if (this.selected && this.options.editable.remove && !this.dom.deleteButton) { // create and show button - var parent = this.parent; - var id = this.id; + var me = this; var deleteButton = document.createElement('div'); deleteButton.className = 'delete'; @@ -6091,7 +5926,7 @@ Item.prototype._repaintDeleteButton = function (anchor) { Hammer(deleteButton, { preventDefault: true }).on('tap', function (event) { - parent.removeItem(id); + me.parent.removeFromDataSet(me); event.stopPropagation(); }); @@ -6110,319 +5945,244 @@ Item.prototype._repaintDeleteButton = function (anchor) { /** * @constructor ItemBox * @extends Item - * @param {ItemSet} parent * @param {Object} data Object containing parameters start * content, className. * @param {Object} [options] Options to set initial property values * @param {Object} [defaultOptions] default options * // TODO: describe available options */ -function ItemBox (parent, data, options, defaultOptions) { +function ItemBox (data, options, defaultOptions) { this.props = { dot: { - left: 0, - top: 0, width: 0, height: 0 }, line: { - top: 0, - left: 0, width: 0, height: 0 } }; - Item.call(this, parent, data, options, defaultOptions); + // validate data + if (data) { + if (data.start == undefined) { + throw new Error('Property "start" missing in item ' + data); + } + } + + Item.call(this, data, options, defaultOptions); } -ItemBox.prototype = new Item (null, null); +ItemBox.prototype = new Item (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 + */ +ItemBox.prototype.isVisible = function isVisible (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 - * @return {Boolean} changed */ ItemBox.prototype.repaint = function repaint() { - // TODO: make an efficient repaint - var changed = false; var dom = this.dom; - if (!dom) { - this._create(); + // create DOM + this.dom = {}; dom = this.dom; - changed = true; + + // 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; } - if (dom) { - if (!this.parent) { - throw new Error('Cannot repaint item: no parent attached'); - } + // append DOM to parent DOM + if (!this.parent) { + throw new Error('Cannot repaint item: no parent attached'); + } + if (!dom.box.parentNode) { + var foreground = this.parent.getForeground(); + if (!foreground) throw new Error('Cannot repaint time axis: parent has no foreground container element'); + foreground.appendChild(dom.box); + } + if (!dom.line.parentNode) { + var background = this.parent.getBackground(); + if (!background) throw new Error('Cannot repaint time axis: parent has no background container element'); + background.appendChild(dom.line); + } + if (!dom.dot.parentNode) { + var axis = this.parent.getAxis(); + if (!background) throw new Error('Cannot repaint time axis: parent has no axis container element'); + axis.appendChild(dom.dot); + } + this.displayed = true; - if (!dom.box.parentNode) { - var foreground = this.parent.getForeground(); - if (!foreground) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no foreground container element'); - } - foreground.appendChild(dom.box); - changed = true; + // update contents + if (this.data.content != this.content) { + this.content = this.data.content; + if (this.content instanceof Element) { + dom.content.innerHTML = ''; + dom.content.appendChild(this.content); } - - if (!dom.line.parentNode) { - var background = this.parent.getBackground(); - if (!background) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no background container element'); - } - background.appendChild(dom.line); - changed = true; + else if (this.data.content != undefined) { + dom.content.innerHTML = this.content; } - - if (!dom.dot.parentNode) { - var axis = this.parent.getAxis(); - if (!background) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no axis container element'); - } - axis.appendChild(dom.dot); - changed = true; + else { + throw new Error('Property "content" missing in item ' + this.data.id); } - this._repaintDeleteButton(dom.box); + this.dirty = true; + } - // update contents - if (this.data.content != this.content) { - this.content = this.data.content; - if (this.content instanceof Element) { - dom.content.innerHTML = ''; - dom.content.appendChild(this.content); - } - else if (this.data.content != undefined) { - dom.content.innerHTML = this.content; - } - else { - throw new Error('Property "content" missing in item ' + this.data.id); - } - changed = true; - } + // update class + var className = (this.data.className? ' ' + this.data.className : '') + + (this.selected ? ' selected' : ''); + if (this.className != className) { + this.className = className; + dom.box.className = 'item box' + className; + dom.line.className = 'item line' + className; + dom.dot.className = 'item dot' + className; - // update class - var className = (this.data.className? ' ' + this.data.className : '') + - (this.selected ? ' selected' : ''); - if (this.className != className) { - this.className = className; - dom.box.className = 'item box' + className; - dom.line.className = 'item line' + className; - dom.dot.className = 'item dot' + className; - changed = true; - } + this.dirty = true; } - return changed; + // recalculate size + if (this.dirty) { + 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; + } + + this._repaintDeleteButton(dom.box); }; /** - * Show the item in the DOM (when not already visible). The items DOM will + * Show the item in the DOM (when not already displayed). The items DOM will * be created when needed. - * @return {Boolean} changed */ ItemBox.prototype.show = function show() { - if (!this.dom || !this.dom.box.parentNode) { - return this.repaint(); - } - else { - return false; + if (!this.displayed) { + this.repaint(); } }; /** * Hide the item from the DOM (when visible) - * @return {Boolean} changed */ ItemBox.prototype.hide = function hide() { - var changed = false, - dom = this.dom; - if (dom) { - if (dom.box.parentNode) { - dom.box.parentNode.removeChild(dom.box); - changed = true; - } - if (dom.line.parentNode) { - dom.line.parentNode.removeChild(dom.line); - } - if (dom.dot.parentNode) { - dom.dot.parentNode.removeChild(dom.dot); - } + 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); + + this.top = null; + this.left = null; + + this.displayed = false; } - return changed; }; /** - * Reflow the item: calculate its actual size and position from the DOM - * @return {boolean} resized returns true if the axis is resized - * @override + * Reposition the item horizontally + * @Override */ -ItemBox.prototype.reflow = function reflow() { - var changed = 0, - update, - dom, - props, - options, - margin, - start, - align, - orientation, - top, +ItemBox.prototype.repositionX = function repositionX() { + var start = this.defaultOptions.toScreen(this.data.start), + align = this.options.align || this.defaultOptions.align, left, - data, - range; + box = this.dom.box, + line = this.dom.line, + dot = this.dom.dot; - if (this.data.start == undefined) { - throw new Error('Property "start" missing in item ' + this.data.id); + // calculate left position of the box + if (align == 'right') { + this.left = start - this.width; } - - data = this.data; - range = this.parent && this.parent.range; - if (data && range) { - // TODO: account for the width of the item - var interval = (range.end - range.start); - this.visible = (data.start > range.start - interval) && (data.start < range.end + interval); + else if (align == 'left') { + this.left = start; } else { - this.visible = false; + // default or 'center' + this.left = start - this.width / 2; } - if (this.visible) { - dom = this.dom; - if (dom) { - update = util.updateProperty; - props = this.props; - options = this.options; - start = this.parent.toScreen(this.data.start) + this.offset; - align = options.align || this.defaultOptions.align; - margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; - orientation = options.orientation || this.defaultOptions.orientation; - - changed += update(props.dot, 'height', dom.dot.offsetHeight); - changed += update(props.dot, 'width', dom.dot.offsetWidth); - changed += update(props.line, 'width', dom.line.offsetWidth); - changed += update(props.line, 'height', dom.line.offsetHeight); - changed += update(props.line, 'top', dom.line.offsetTop); - changed += update(this, 'width', dom.box.offsetWidth); - changed += update(this, 'height', dom.box.offsetHeight); - if (align == 'right') { - left = start - this.width; - } - else if (align == 'left') { - left = start; - } - else { - // default or 'center' - left = start - this.width / 2; - } - changed += update(this, 'left', left); - - changed += update(props.line, 'left', start - props.line.width / 2); - changed += update(props.dot, 'left', start - props.dot.width / 2); - changed += update(props.dot, 'top', -props.dot.height / 2); - if (orientation == 'top') { - top = margin; - - changed += update(this, 'top', top); - } - else { - // default or 'bottom' - var parentHeight = this.parent.height; - top = parentHeight - this.height - margin; + // reposition box + box.style.left = this.left + 'px'; - changed += update(this, 'top', top); - } - } - else { - changed += 1; - } - } + // reposition line + line.style.left = (start - this.props.line.width / 2) + 'px'; - return (changed > 0); + // reposition dot + dot.style.left = (start - this.props.dot.width / 2) + 'px'; }; /** - * Create an items DOM - * @private + * Reposition the item vertically + * @Override */ -ItemBox.prototype._create = function _create() { - var dom = this.dom; - if (!dom) { - this.dom = dom = {}; +ItemBox.prototype.repositionY = function repositionY () { + var orientation = this.options.orientation || this.defaultOptions.orientation, + box = this.dom.box, + line = this.dom.line, + dot = this.dom.dot; - // create the box - dom.box = document.createElement('DIV'); - // className is updated in repaint() + if (orientation == 'top') { + box.style.top = (this.top || 0) + 'px'; + box.style.bottom = ''; - // 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.style.top = '0'; + line.style.bottom = ''; + line.style.height = (this.parent.top + this.top + 1) + 'px'; + } + else { // orientation 'bottom' + box.style.top = ''; + box.style.bottom = (this.top || 0) + 'px'; - // 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; + line.style.top = (this.parent.top + this.parent.height - this.top - 1) + 'px'; + line.style.bottom = '0'; + line.style.height = ''; } -}; - -/** - * Reposition the item, recalculate its left, top, and width, using the current - * range and size of the items itemset - * @override - */ -ItemBox.prototype.reposition = function reposition() { - var dom = this.dom, - props = this.props, - orientation = this.options.orientation || this.defaultOptions.orientation; - - if (dom) { - var box = dom.box, - line = dom.line, - dot = dom.dot; - - box.style.left = this.left + 'px'; - box.style.top = this.top + 'px'; - - line.style.left = props.line.left + 'px'; - if (orientation == 'top') { - line.style.top = 0 + 'px'; - line.style.height = this.top + 'px'; - } - else { - // orientation 'bottom' - line.style.top = (this.top + this.height) + 'px'; - line.style.height = Math.max(this.parent.height - this.top - this.height + - this.props.dot.height / 2, 0) + 'px'; - } - dot.style.left = props.dot.left + 'px'; - dot.style.top = props.dot.top + 'px'; - } + dot.style.top = (-this.props.dot.height / 2) + 'px'; }; /** * @constructor ItemPoint * @extends Item - * @param {ItemSet} parent * @param {Object} data Object containing parameters start * content, className. * @param {Object} [options] Options to set initial property values * @param {Object} [defaultOptions] default options * // TODO: describe available options */ -function ItemPoint (parent, data, options, defaultOptions) { +function ItemPoint (data, options, defaultOptions) { this.props = { dot: { top: 0, @@ -6435,320 +6195,302 @@ function ItemPoint (parent, data, options, defaultOptions) { } }; - Item.call(this, parent, data, options, defaultOptions); + // validate data + if (data) { + if (data.start == undefined) { + throw new Error('Property "start" missing in item ' + data); + } + } + + Item.call(this, data, options, defaultOptions); } -ItemPoint.prototype = new Item (null, null); +ItemPoint.prototype = new Item (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 + */ +ItemPoint.prototype.isVisible = function isVisible (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 - * @return {Boolean} changed */ ItemPoint.prototype.repaint = function repaint() { - // TODO: make an efficient repaint - var changed = false; var dom = this.dom; - if (!dom) { - this._create(); + // create DOM + this.dom = {}; dom = this.dom; - changed = true; + + // background box + dom.point = document.createElement('div'); + // className is updated in repaint() + + // 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; } - if (dom) { - if (!this.parent) { - throw new Error('Cannot repaint item: no parent attached'); - } + // append DOM to parent DOM + if (!this.parent) { + throw new Error('Cannot repaint item: no parent attached'); + } + if (!dom.point.parentNode) { var foreground = this.parent.getForeground(); if (!foreground) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no foreground container element'); + throw new Error('Cannot repaint time axis: parent has no foreground container element'); } + foreground.appendChild(dom.point); + } + this.displayed = true; - if (!dom.point.parentNode) { - foreground.appendChild(dom.point); - foreground.appendChild(dom.point); - changed = true; + // update contents + if (this.data.content != this.content) { + this.content = this.data.content; + if (this.content instanceof Element) { + dom.content.innerHTML = ''; + dom.content.appendChild(this.content); } - - // update contents - if (this.data.content != this.content) { - this.content = this.data.content; - if (this.content instanceof Element) { - dom.content.innerHTML = ''; - dom.content.appendChild(this.content); - } - else if (this.data.content != undefined) { - dom.content.innerHTML = this.content; - } - else { - throw new Error('Property "content" missing in item ' + this.data.id); - } - changed = true; + else if (this.data.content != undefined) { + dom.content.innerHTML = this.content; + } + else { + throw new Error('Property "content" missing in item ' + this.data.id); } - this._repaintDeleteButton(dom.point); + this.dirty = true; + } + + // update class + var className = (this.data.className? ' ' + this.data.className : '') + + (this.selected ? ' selected' : ''); + if (this.className != className) { + this.className = className; + dom.point.className = 'item point' + className; + dom.dot.className = 'item dot' + className; - // update class - var className = (this.data.className? ' ' + this.data.className : '') + - (this.selected ? ' selected' : ''); - if (this.className != className) { - this.className = className; - dom.point.className = 'item point' + className; - changed = true; - } + this.dirty = true; } - return changed; + // recalculate size + if (this.dirty) { + 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; + + // 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; + } + + this._repaintDeleteButton(dom.point); }; /** * Show the item in the DOM (when not already visible). The items DOM will * be created when needed. - * @return {Boolean} changed */ ItemPoint.prototype.show = function show() { - if (!this.dom || !this.dom.point.parentNode) { - return this.repaint(); - } - else { - return false; + if (!this.displayed) { + this.repaint(); } }; /** * Hide the item from the DOM (when visible) - * @return {Boolean} changed */ ItemPoint.prototype.hide = function hide() { - var changed = false, - dom = this.dom; - if (dom) { - if (dom.point.parentNode) { - dom.point.parentNode.removeChild(dom.point); - changed = true; + if (this.displayed) { + if (this.dom.point.parentNode) { + this.dom.point.parentNode.removeChild(this.dom.point); } - } - return changed; -}; - -/** - * Reflow the item: calculate its actual size from the DOM - * @return {boolean} resized returns true if the axis is resized - * @override - */ -ItemPoint.prototype.reflow = function reflow() { - var changed = 0, - update, - dom, - props, - options, - margin, - orientation, - start, - top, - data, - range; - if (this.data.start == undefined) { - throw new Error('Property "start" missing in item ' + this.data.id); - } - - data = this.data; - range = this.parent && this.parent.range; - if (data && range) { - // TODO: account for the width of the item - var interval = (range.end - range.start); - this.visible = (data.start > range.start - interval) && (data.start < range.end); - } - else { - this.visible = false; - } - - if (this.visible) { - dom = this.dom; - if (dom) { - update = util.updateProperty; - props = this.props; - options = this.options; - orientation = options.orientation || this.defaultOptions.orientation; - margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; - start = this.parent.toScreen(this.data.start) + this.offset; - - changed += update(this, 'width', dom.point.offsetWidth); - changed += update(this, 'height', dom.point.offsetHeight); - changed += update(props.dot, 'width', dom.dot.offsetWidth); - changed += update(props.dot, 'height', dom.dot.offsetHeight); - changed += update(props.content, 'height', dom.content.offsetHeight); - - if (orientation == 'top') { - top = margin; - } - else { - // default or 'bottom' - var parentHeight = this.parent.height; - top = Math.max(parentHeight - this.height - margin, 0); - } - changed += update(this, 'top', top); - changed += update(this, 'left', start - props.dot.width / 2); - changed += update(props.content, 'marginLeft', 1.5 * props.dot.width); - //changed += update(props.content, 'marginRight', 0.5 * props.dot.width); // TODO + this.top = null; + this.left = null; - changed += update(props.dot, 'top', (this.height - props.dot.height) / 2); - } - else { - changed += 1; - } + this.displayed = false; } - - return (changed > 0); }; /** - * Create an items DOM - * @private + * Reposition the item horizontally + * @Override */ -ItemPoint.prototype._create = function _create() { - var dom = this.dom; - if (!dom) { - this.dom = dom = {}; - - // background box - dom.point = document.createElement('div'); - // className is updated in repaint() - - // contents box, right from the dot - dom.content = document.createElement('div'); - dom.content.className = 'content'; - dom.point.appendChild(dom.content); +ItemPoint.prototype.repositionX = function repositionX() { + var start = this.defaultOptions.toScreen(this.data.start); - // dot at start - dom.dot = document.createElement('div'); - dom.dot.className = 'dot'; - dom.point.appendChild(dom.dot); + this.left = start - this.props.dot.width; - // attach this item as attribute - dom.point['timeline-item'] = this; - } + // reposition point + this.dom.point.style.left = this.left + 'px'; }; /** - * Reposition the item, recalculate its left, top, and width, using the current - * range and size of the items itemset - * @override + * Reposition the item vertically + * @Override */ -ItemPoint.prototype.reposition = function reposition() { - var dom = this.dom, - props = this.props; +ItemPoint.prototype.repositionY = function repositionY () { + var orientation = this.options.orientation || this.defaultOptions.orientation, + point = this.dom.point; - if (dom) { - dom.point.style.top = this.top + 'px'; - dom.point.style.left = this.left + 'px'; - - dom.content.style.marginLeft = props.content.marginLeft + 'px'; - //dom.content.style.marginRight = props.content.marginRight + 'px'; // TODO - - dom.dot.style.top = props.dot.top + 'px'; + if (orientation == 'top') { + point.style.top = this.top + 'px'; + point.style.bottom = ''; + } + else { + point.style.top = ''; + point.style.bottom = this.top + 'px'; } }; /** * @constructor ItemRange * @extends Item - * @param {ItemSet} parent * @param {Object} data Object containing parameters start, end * content, className. * @param {Object} [options] Options to set initial property values * @param {Object} [defaultOptions] default options * // TODO: describe available options */ -function ItemRange (parent, data, options, defaultOptions) { +function ItemRange (data, options, defaultOptions) { this.props = { content: { - left: 0, width: 0 } }; - Item.call(this, parent, data, options, defaultOptions); + // 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, options, defaultOptions); } -ItemRange.prototype = new Item (null, null); +ItemRange.prototype = new Item (null); + +ItemRange.prototype.baseClassName = 'item range'; + +/** + * 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 + */ +ItemRange.prototype.isVisible = function isVisible (range) { + // determine visibility + return (this.data.start < range.end) && (this.data.end > range.start); +}; /** * Repaint the item - * @return {Boolean} changed */ ItemRange.prototype.repaint = function repaint() { - // TODO: make an efficient repaint - var changed = false; var dom = this.dom; - if (!dom) { - this._create(); + // create DOM + this.dom = {}; dom = this.dom; - changed = true; + + // background box + dom.box = document.createElement('div'); + // className is updated in repaint() + + // 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; } - if (dom) { - if (!this.parent) { - throw new Error('Cannot repaint item: no parent attached'); - } + // append DOM to parent DOM + if (!this.parent) { + throw new Error('Cannot repaint item: no parent attached'); + } + if (!dom.box.parentNode) { var foreground = this.parent.getForeground(); if (!foreground) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no foreground container element'); + throw new Error('Cannot repaint time axis: parent has no foreground container element'); } + foreground.appendChild(dom.box); + } + this.displayed = true; - if (!dom.box.parentNode) { - foreground.appendChild(dom.box); - changed = true; + // update contents + if (this.data.content != this.content) { + this.content = this.data.content; + if (this.content instanceof Element) { + dom.content.innerHTML = ''; + dom.content.appendChild(this.content); } - - // update content - if (this.data.content != this.content) { - this.content = this.data.content; - if (this.content instanceof Element) { - dom.content.innerHTML = ''; - dom.content.appendChild(this.content); - } - else if (this.data.content != undefined) { - dom.content.innerHTML = this.content; - } - else { - throw new Error('Property "content" missing in item ' + this.data.id); - } - changed = true; + else if (this.data.content != undefined) { + dom.content.innerHTML = this.content; + } + else { + throw new Error('Property "content" missing in item ' + this.data.id); } - this._repaintDeleteButton(dom.box); - this._repaintDragLeft(); - this._repaintDragRight(); + this.dirty = true; + } - // update class - var className = (this.data.className ? (' ' + this.data.className) : '') + - (this.selected ? ' selected' : ''); - if (this.className != className) { - this.className = className; - dom.box.className = 'item range' + className; - changed = true; - } + // update class + var className = (this.data.className ? (' ' + this.data.className) : '') + + (this.selected ? ' selected' : ''); + if (this.className != className) { + this.className = className; + dom.box.className = this.baseClassName + className; + + this.dirty = true; } - return changed; + // recalculate size + if (this.dirty) { + this.props.content.width = this.dom.content.offsetWidth; + this.height = this.dom.box.offsetHeight; + + this.dirty = false; + } + + this._repaintDeleteButton(dom.box); + this._repaintDragLeft(); + this._repaintDragRight(); }; /** * Show the item in the DOM (when not already visible). The items DOM will * be created when needed. - * @return {Boolean} changed */ ItemRange.prototype.show = function show() { - if (!this.dom || !this.dom.box.parentNode) { - return this.repaint(); - } - else { - return false; + if (!this.displayed) { + this.repaint(); } }; @@ -6757,163 +6499,82 @@ ItemRange.prototype.show = function show() { * @return {Boolean} changed */ ItemRange.prototype.hide = function hide() { - var changed = false, - dom = this.dom; - if (dom) { - if (dom.box.parentNode) { - dom.box.parentNode.removeChild(dom.box); - changed = true; + if (this.displayed) { + var box = this.dom.box; + + if (box.parentNode) { + box.parentNode.removeChild(box); } + + this.top = null; + this.left = null; + + this.displayed = false; } - return changed; }; /** - * Reflow the item: calculate its actual size from the DOM - * @return {boolean} resized returns true if the axis is resized - * @override + * Reposition the item horizontally + * @Override */ -ItemRange.prototype.reflow = function reflow() { - var changed = 0, - dom, - props, - options, - margin, - padding, - parent, - start, - end, - data, - range, - update, - box, - parentWidth, - contentLeft, - orientation, - top; +ItemRange.prototype.repositionX = function repositionX() { + var props = this.props, + parentWidth = this.parent.width, + start = this.defaultOptions.toScreen(this.data.start), + end = this.defaultOptions.toScreen(this.data.end), + padding = 'padding' in this.options ? this.options.padding : this.defaultOptions.padding, + contentLeft; - if (this.data.start == undefined) { - throw new Error('Property "start" missing in item ' + this.data.id); + // limit the width of the this, as browsers cannot draw very wide divs + if (start < -parentWidth) { + start = -parentWidth; } - if (this.data.end == undefined) { - throw new Error('Property "end" missing in item ' + this.data.id); + if (end > 2 * parentWidth) { + end = 2 * parentWidth; } - data = this.data; - range = this.parent && this.parent.range; - if (data && range) { - // TODO: account for the width of the item. Take some margin - this.visible = (data.start < range.end) && (data.end > range.start); + // when range exceeds left of the window, position the contents at the left of the visible area + if (start < 0) { + contentLeft = Math.min(-start, + (end - start - props.content.width - 2 * padding)); + // TODO: remove the need for options.padding. it's terrible. } else { - this.visible = false; + contentLeft = 0; } - if (this.visible) { - dom = this.dom; - if (dom) { - props = this.props; - options = this.options; - parent = this.parent; - start = parent.toScreen(this.data.start) + this.offset; - end = parent.toScreen(this.data.end) + this.offset; - update = util.updateProperty; - box = dom.box; - parentWidth = parent.width; - orientation = options.orientation || this.defaultOptions.orientation; - margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; - padding = options.padding || this.defaultOptions.padding; - - changed += update(props.content, 'width', dom.content.offsetWidth); - - changed += update(this, 'height', box.offsetHeight); - - // 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; - } - - // when range exceeds left of the window, position the contents at the left of the visible area - if (start < 0) { - contentLeft = Math.min(-start, - (end - start - props.content.width - 2 * padding)); - // TODO: remove the need for options.padding. it's terrible. - } - else { - contentLeft = 0; - } - changed += update(props.content, 'left', contentLeft); - - if (orientation == 'top') { - top = margin; - changed += update(this, 'top', top); - } - else { - // default or 'bottom' - top = parent.height - this.height - margin; - changed += update(this, 'top', top); - } - - changed += update(this, 'left', start); - changed += update(this, 'width', Math.max(end - start, 1)); // TODO: reckon with border width; - } - else { - changed += 1; - } - } + this.left = start; + this.width = Math.max(end - start, 1); - return (changed > 0); + this.dom.box.style.left = this.left + 'px'; + this.dom.box.style.width = this.width + 'px'; + this.dom.content.style.left = contentLeft + 'px'; }; /** - * Create an items DOM - * @private + * Reposition the item vertically + * @Override */ -ItemRange.prototype._create = function _create() { - var dom = this.dom; - if (!dom) { - this.dom = dom = {}; - // background box - dom.box = document.createElement('div'); - // className is updated in repaint() - - // contents box - dom.content = document.createElement('div'); - dom.content.className = 'content'; - dom.box.appendChild(dom.content); +ItemRange.prototype.repositionY = function repositionY() { + var orientation = this.options.orientation || this.defaultOptions.orientation, + box = this.dom.box; - // attach this item as attribute - dom.box['timeline-item'] = this; + if (orientation == 'top') { + box.style.top = this.top + 'px'; + box.style.bottom = ''; } -}; - -/** - * Reposition the item, recalculate its left, top, and width, using the current - * range and size of the items itemset - * @override - */ -ItemRange.prototype.reposition = function reposition() { - var dom = this.dom, - props = this.props; - - if (dom) { - dom.box.style.top = this.top + 'px'; - dom.box.style.left = this.left + 'px'; - dom.box.style.width = this.width + 'px'; - - dom.content.style.left = props.content.left + 'px'; + else { + box.style.top = ''; + box.style.bottom = this.top + 'px'; } }; /** * Repaint a drag area on the left side of the range when the range is selected - * @private + * @protected */ ItemRange.prototype._repaintDragLeft = function () { - if (this.selected && this.options.editable && !this.dom.dragLeft) { + if (this.selected && this.options.editable.updateTime && !this.dom.dragLeft) { // create and show drag area var dragLeft = document.createElement('div'); dragLeft.className = 'drag-left'; @@ -6940,10 +6601,10 @@ ItemRange.prototype._repaintDragLeft = function () { /** * Repaint a drag area on the right side of the range when the range is selected - * @private + * @protected */ ItemRange.prototype._repaintDragRight = function () { - if (this.selected && this.options.editable && !this.dom.dragRight) { + if (this.selected && this.options.editable.updateTime && !this.dom.dragRight) { // create and show drag area var dragRight = document.createElement('div'); dragRight.className = 'drag-right'; @@ -6971,14 +6632,13 @@ ItemRange.prototype._repaintDragRight = function () { /** * @constructor ItemRangeOverflow * @extends ItemRange - * @param {ItemSet} parent * @param {Object} data Object containing parameters start, end * content, className. * @param {Object} [options] Options to set initial property values * @param {Object} [defaultOptions] default options * // TODO: describe available options */ -function ItemRangeOverflow (parent, data, options, defaultOptions) { +function ItemRangeOverflow (data, options, defaultOptions) { this.props = { content: { left: 0, @@ -6986,125 +6646,58 @@ function ItemRangeOverflow (parent, data, options, defaultOptions) { } }; - // define a private property _width, which is the with of the range box - // adhering to the ranges start and end date. The property width has a - // getter which returns the max of border width and content width - this._width = 0; - Object.defineProperty(this, 'width', { - get: function () { - return (this.props.content && this._width < this.props.content.width) ? - this.props.content.width : - this._width; - }, - - set: function (width) { - this._width = width; - } - }); - - ItemRange.call(this, parent, data, options, defaultOptions); + ItemRange.call(this, data, options, defaultOptions); } -ItemRangeOverflow.prototype = new ItemRange (null, null); +ItemRangeOverflow.prototype = new ItemRange (null); + +ItemRangeOverflow.prototype.baseClassName = 'item rangeoverflow'; /** - * Repaint the item - * @return {Boolean} changed + * Reposition the item horizontally + * @Override */ -ItemRangeOverflow.prototype.repaint = function repaint() { - // TODO: make an efficient repaint - var changed = false; - var dom = this.dom; +ItemRangeOverflow.prototype.repositionX = function repositionX() { + var parentWidth = this.parent.width, + start = this.defaultOptions.toScreen(this.data.start), + end = this.defaultOptions.toScreen(this.data.end), + padding = 'padding' in this.options ? this.options.padding : this.defaultOptions.padding, + contentLeft; - if (!dom) { - this._create(); - dom = this.dom; - changed = true; + // limit the width of the this, as browsers cannot draw very wide divs + if (start < -parentWidth) { + start = -parentWidth; } - - if (dom) { - if (!this.parent) { - throw new Error('Cannot repaint item: no parent attached'); - } - var foreground = this.parent.getForeground(); - if (!foreground) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no foreground container element'); - } - - if (!dom.box.parentNode) { - foreground.appendChild(dom.box); - changed = true; - } - - // update content - if (this.data.content != this.content) { - this.content = this.data.content; - if (this.content instanceof Element) { - dom.content.innerHTML = ''; - dom.content.appendChild(this.content); - } - else if (this.data.content != undefined) { - dom.content.innerHTML = this.content; - } - else { - throw new Error('Property "content" missing in item ' + this.id); - } - changed = true; - } - - this._repaintDeleteButton(dom.box); - this._repaintDragLeft(); - this._repaintDragRight(); - - // update class - var className = (this.data.className? ' ' + this.data.className : '') + - (this.selected ? ' selected' : ''); - if (this.className != className) { - this.className = className; - dom.box.className = 'item rangeoverflow' + className; - changed = true; - } + if (end > 2 * parentWidth) { + end = 2 * parentWidth; } - return changed; -}; - -/** - * Reposition the item, recalculate its left, top, and width, using the current - * range and size of the items itemset - * @override - */ -ItemRangeOverflow.prototype.reposition = function reposition() { - var dom = this.dom, - props = this.props; + // when range exceeds left of the window, position the contents at the left of the visible area + contentLeft = Math.max(-start, 0); - if (dom) { - dom.box.style.top = this.top + 'px'; - dom.box.style.left = this.left + 'px'; - dom.box.style.width = this._width + 'px'; + this.left = start; + var boxWidth = Math.max(end - start, 1); + this.width = (this.props.content.width < boxWidth) ? + boxWidth : + start + contentLeft + this.props.content.width; - dom.content.style.left = props.content.left + 'px'; - } + this.dom.box.style.left = this.left + 'px'; + this.dom.box.style.width = boxWidth + 'px'; + this.dom.content.style.left = contentLeft + 'px'; }; /** * @constructor Group - * @param {GroupSet} parent * @param {Number | String} groupId - * @param {Object} [options] Options to set initial property values - * // TODO: describe available options - * @extends Component + * @param {Object} data + * @param {ItemSet} itemSet */ -function Group (parent, groupId, options) { - this.id = util.randomUUID(); - this.parent = parent; - +function Group (groupId, data, itemSet) { this.groupId = groupId; - this.itemset = null; // ItemSet - this.options = options || {}; - this.options.top = 0; + this.itemSet = itemSet; + + this.dom = {}; this.props = { label: { width: 0, @@ -7112,691 +6705,438 @@ function Group (parent, groupId, options) { } }; - this.top = 0; - this.left = 0; - this.width = 0; - this.height = 0; -} - -Group.prototype = new Component(); + this.items = {}; // items filtered by groupId of this group + this.visibleItems = []; // items currently visible in window + this.orderedItems = { // items sorted by start and by end + byStart: [], + byEnd: [] + }; -// TODO: comment -Group.prototype.setOptions = Component.prototype.setOptions; + this._create(); -/** - * Get the container element of the panel, which can be used by a child to - * add its own widgets. - * @returns {HTMLElement} container - */ -Group.prototype.getContainer = function () { - return this.parent.getContainer(); -}; + this.setData(data); +} /** - * Set item set for the group. The group will create a view on the itemset, - * filtered by the groups id. - * @param {DataSet | DataView} items + * Create DOM elements for the group + * @private */ -Group.prototype.setItems = function setItems(items) { - if (this.itemset) { - // remove current item set - this.itemset.hide(); - this.itemset.setItems(); - - this.parent.controller.remove(this.itemset); - this.itemset = null; - } +Group.prototype._create = function() { + var label = document.createElement('div'); + label.className = 'vlabel'; + this.dom.label = label; - if (items) { - var groupId = this.groupId; + var inner = document.createElement('div'); + inner.className = 'inner'; + label.appendChild(inner); + this.dom.inner = inner; - var itemsetOptions = Object.create(this.options); - this.itemset = new ItemSet(this, null, itemsetOptions); - this.itemset.setRange(this.parent.range); + var foreground = document.createElement('div'); + foreground.className = 'group'; + foreground['timeline-group'] = this; + this.dom.foreground = foreground; - this.view = new DataView(items, { - filter: function (item) { - return item.group == groupId; - } - }); - this.itemset.setItems(this.view); + this.dom.background = document.createElement('div'); - this.parent.controller.add(this.itemset); - } + this.dom.axis = document.createElement('div'); }; /** - * Set selected items by their id. Replaces the current selection. - * Unknown id's are silently ignored. - * @param {Array} [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. + * Set the group data for this group + * @param {Object} data Group data, can contain properties content and className */ -Group.prototype.setSelection = function setSelection(ids) { - if (this.itemset) this.itemset.setSelection(ids); +Group.prototype.setData = function setData(data) { + // update contents + var content = data && data.content; + if (content instanceof Element) { + this.dom.inner.appendChild(content); + } + else if (content != undefined) { + this.dom.inner.innerHTML = content; + } + else { + this.dom.inner.innerHTML = this.groupId; + } + + // update className + var className = data && data.className; + if (className) { + util.addClassName(this.dom.label, className); + } }; /** - * Get the selected items by their id - * @return {Array} ids The ids of the selected items + * Get the foreground container element + * @return {HTMLElement} foreground */ -Group.prototype.getSelection = function getSelection() { - return this.itemset ? this.itemset.getSelection() : []; +Group.prototype.getForeground = function getForeground() { + return this.dom.foreground; }; /** - * Repaint the item - * @return {Boolean} changed + * Get the background container element + * @return {HTMLElement} background */ -Group.prototype.repaint = function repaint() { - return false; +Group.prototype.getBackground = function getBackground() { + return this.dom.background; }; /** - * Reflow the item - * @return {Boolean} resized + * Get the axis container element + * @return {HTMLElement} axis */ -Group.prototype.reflow = function reflow() { - var changed = 0, - update = util.updateProperty; - - changed += update(this, 'top', this.itemset ? this.itemset.top : 0); - changed += update(this, 'height', this.itemset ? this.itemset.height : 0); - - // TODO: reckon with the height of the group label - - if (this.label) { - var inner = this.label.firstChild; - changed += update(this.props.label, 'width', inner.clientWidth); - changed += update(this.props.label, 'height', inner.clientHeight); - } - else { - changed += update(this.props.label, 'width', 0); - changed += update(this.props.label, 'height', 0); - } - - return (changed > 0); +Group.prototype.getAxis = function getAxis() { + return this.dom.axis; }; /** - * An GroupSet holds a set of groups - * @param {Component} parent - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) - * @param {Object} [options] See GroupSet.setOptions for the available - * options. - * @constructor GroupSet - * @extends Panel + * Get the width of the group label + * @return {number} width */ -function GroupSet(parent, depends, options) { - this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; - - this.options = options || {}; +Group.prototype.getLabelWidth = function getLabelWidth() { + return this.props.label.width; +}; - this.range = null; // Range or Object {start: number, end: number} - this.itemsData = null; // DataSet with items - this.groupsData = null; // DataSet with groups - this.groups = {}; // map with groups +/** + * Repaint this group + * @param {{start: number, end: number}} range + * @param {{item: number, axis: number}} margin + * @param {boolean} [restack=false] Force restacking of all items + * @return {boolean} Returns true if the group is resized + */ +Group.prototype.repaint = function repaint(range, margin, restack) { + var resized = false; - this.dom = {}; - this.props = { - labels: { - width: 0 - } - }; + this.visibleItems = this._updateVisibleItems(this.orderedItems, this.visibleItems, range); - // TODO: implement right orientation of the labels + // 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.stackDirty = false; + for (var i = 0, ii = this.visibleItems.length; i < ii; i++) { + var item = this.visibleItems[i]; + item.repositionY(); + } - // changes in groups are queued key/value map containing id/action - this.queue = {}; + // recalculate the height of the group + var height; + var visibleItems = this.visibleItems; + 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)); + }); + height = (max - min) + margin.axis + margin.item; + } + else { + height = margin.axis + margin.item; + } + height = Math.max(height, this.props.label.height); - var me = this; - this.listeners = { - 'add': function (event, params) { - me._onAdd(params.items); - }, - 'update': function (event, params) { - me._onUpdate(params.items); - }, - 'remove': function (event, params) { - me._onRemove(params.items); - } - }; -} + // 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; -GroupSet.prototype = new Panel(); + // 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; -/** - * Set options for the GroupSet. Existing options will be extended/overwritten. - * @param {Object} [options] The following options are available: - * {String | function} groupsOrder - * TODO: describe options - */ -GroupSet.prototype.setOptions = Component.prototype.setOptions; + // apply new height + foreground.style.height = height + 'px'; + this.dom.label.style.height = height + 'px'; -GroupSet.prototype.setRange = function (range) { - // TODO: implement setRange + return resized; }; /** - * Set items - * @param {vis.DataSet | null} items + * Show this group: attach to the DOM */ -GroupSet.prototype.setItems = function setItems(items) { - this.itemsData = items; +Group.prototype.show = function show() { + if (!this.dom.label.parentNode) { + this.itemSet.getLabelSet().appendChild(this.dom.label); + } - for (var id in this.groups) { - if (this.groups.hasOwnProperty(id)) { - var group = this.groups[id]; - group.setItems(items); - } + if (!this.dom.foreground.parentNode) { + this.itemSet.getForeground().appendChild(this.dom.foreground); } -}; -/** - * Get items - * @return {vis.DataSet | null} items - */ -GroupSet.prototype.getItems = function getItems() { - return this.itemsData; -}; + if (!this.dom.background.parentNode) { + this.itemSet.getBackground().appendChild(this.dom.background); + } -/** - * Set range (start and end). - * @param {Range | Object} range A Range or an object containing start and end. - */ -GroupSet.prototype.setRange = function setRange(range) { - this.range = range; + if (!this.dom.axis.parentNode) { + this.itemSet.getAxis().appendChild(this.dom.axis); + } }; /** - * Set groups - * @param {vis.DataSet} groups + * Hide this group: remove from the DOM */ -GroupSet.prototype.setGroups = function setGroups(groups) { - var me = this, - ids; - - // unsubscribe from current dataset - if (this.groupsData) { - util.forEach(this.listeners, function (callback, event) { - me.groupsData.unsubscribe(event, callback); - }); - - // remove all drawn groups - ids = this.groupsData.getIds(); - this._onRemove(ids); +Group.prototype.hide = function hide() { + var label = this.dom.label; + if (label.parentNode) { + label.parentNode.removeChild(label); } - // replace the dataset - if (!groups) { - this.groupsData = null; + var foreground = this.dom.foreground; + if (foreground.parentNode) { + foreground.parentNode.removeChild(foreground); } - else if (groups instanceof DataSet) { - this.groupsData = groups; + + var background = this.dom.background; + if (background.parentNode) { + background.parentNode.removeChild(background); } - else { - this.groupsData = new DataSet({ - convert: { - start: 'Date', - end: 'Date' - } - }); - this.groupsData.add(groups); + + var axis = this.dom.axis; + if (axis.parentNode) { + axis.parentNode.removeChild(axis); } +}; - if (this.groupsData) { - // subscribe to new dataset - var id = this.id; - util.forEach(this.listeners, function (callback, event) { - me.groupsData.on(event, callback, id); - }); +/** + * Add an item to the group + * @param {Item} item + */ +Group.prototype.add = function add(item) { + this.items[item.id] = item; + item.setParent(this); - // draw all new groups - ids = this.groupsData.getIds(); - this._onAdd(ids); + if (item instanceof ItemRange && this.visibleItems.indexOf(item) == -1) { + var range = this.itemSet.range; // TODO: not nice accessing the range like this + this._checkIfVisible(item, this.visibleItems, range); } }; /** - * Get groups - * @return {vis.DataSet | null} groups + * Remove an item from the group + * @param {Item} item */ -GroupSet.prototype.getGroups = function getGroups() { - return this.groupsData; +Group.prototype.remove = function remove(item) { + delete this.items[item.id]; + item.setParent(this.itemSet); + + // remove from visible items + var index = this.visibleItems.indexOf(item); + if (index != -1) this.visibleItems.splice(index, 1); + + // TODO: also remove from ordered items? }; /** - * Set selected items by their id. Replaces the current selection. - * Unknown id's are silently ignored. - * @param {Array} [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. + * Remove an item from the corresponding DataSet + * @param {Item} item */ -GroupSet.prototype.setSelection = function setSelection(ids) { - var selection = [], - groups = this.groups; +Group.prototype.removeFromDataSet = function removeFromDataSet(item) { + this.itemSet.removeItem(item.id); +}; - // iterate over each of the groups - for (var id in groups) { - if (groups.hasOwnProperty(id)) { - var group = groups[id]; - group.setSelection(ids); - } - } +/** + * Reorder the items + */ +Group.prototype.order = function order() { + var array = util.toArray(this.items); + this.orderedItems.byStart = array; + this.orderedItems.byEnd = this._constructByEndArray(array); - return selection; + stack.orderByStart(this.orderedItems.byStart); + stack.orderByEnd(this.orderedItems.byEnd); }; /** - * Get the selected items by their id - * @return {Array} ids The ids of the selected items + * Create an array containing all items being a range (having an end date) + * @param {Item[]} array + * @returns {ItemRange[]} + * @private */ -GroupSet.prototype.getSelection = function getSelection() { - var selection = [], - groups = this.groups; +Group.prototype._constructByEndArray = function _constructByEndArray(array) { + var endArray = []; - // iterate over each of the groups - for (var id in groups) { - if (groups.hasOwnProperty(id)) { - var group = groups[id]; - selection = selection.concat(group.getSelection()); + for (var i = 0; i < array.length; i++) { + if (array[i] instanceof ItemRange) { + endArray.push(array[i]); } } - - return selection; + return endArray; }; /** - * Repaint the component - * @return {Boolean} changed + * 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 */ -GroupSet.prototype.repaint = function repaint() { - var changed = 0, - i, id, group, label, - update = util.updateProperty, - asSize = util.option.asSize, - asElement = util.option.asElement, - options = this.options, - frame = this.dom.frame, - labels = this.dom.labels, - labelSet = this.dom.labelSet; +Group.prototype._updateVisibleItems = function _updateVisibleItems(orderedItems, visibleItems, range) { + var initialPosByStart, + newVisibleItems = [], + i; - // create frame - if (!this.parent) { - throw new Error('Cannot repaint groupset: no parent attached'); - } - var parentContainer = this.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint groupset: parent has no container element'); - } - if (!frame) { - frame = document.createElement('div'); - frame.className = 'groupset'; - frame['timeline-groupset'] = this; - this.dom.frame = frame; - - var className = options.className; - if (className) { - util.addClassName(frame, util.option.asString(className)); + // first check if the items that were in view previously are still in view. + // this handles the case for the ItemRange that is both before and after the current one. + if (visibleItems.length > 0) { + for (i = 0; i < visibleItems.length; i++) { + this._checkIfVisible(visibleItems[i], newVisibleItems, range); } - - changed += 1; - } - if (!frame.parentNode) { - parentContainer.appendChild(frame); - changed += 1; } - // create labels - var labelContainer = asElement(options.labelContainer); - if (!labelContainer) { - throw new Error('Cannot repaint groupset: option "labelContainer" not defined'); - } - if (!labels) { - labels = document.createElement('div'); - labels.className = 'labels'; - this.dom.labels = labels; + // If there were no visible items previously, use binarySearch to find a visible ItemPoint or ItemRange (based on startTime) + if (newVisibleItems.length == 0) { + initialPosByStart = this._binarySearch(orderedItems, range, false); } - if (!labelSet) { - labelSet = document.createElement('div'); - labelSet.className = 'label-set'; - labels.appendChild(labelSet); - this.dom.labelSet = labelSet; - } - if (!labels.parentNode || labels.parentNode != labelContainer) { - if (labels.parentNode) { - labels.parentNode.removeChild(labels.parentNode); - } - labelContainer.appendChild(labels); + else { + initialPosByStart = orderedItems.byStart.indexOf(newVisibleItems[0]); } - // reposition frame - changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); - changed += update(frame.style, 'top', asSize(options.top, '0px')); - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - - // reposition labels - changed += update(labelSet.style, 'top', asSize(options.top, '0px')); - changed += update(labelSet.style, 'height', asSize(options.height, this.height + 'px')); - - var me = this, - queue = this.queue, - groups = this.groups, - groupsData = this.groupsData; - - // show/hide added/changed/removed groups - var ids = Object.keys(queue); - if (ids.length) { - ids.forEach(function (id) { - var action = queue[id]; - var group = groups[id]; - - //noinspection FallthroughInSwitchStatementJS - switch (action) { - case 'add': - case 'update': - if (!group) { - var groupOptions = Object.create(me.options); - util.extend(groupOptions, { - height: null, - maxHeight: null - }); - - group = new Group(me, id, groupOptions); - group.setItems(me.itemsData); // attach items data - groups[id] = group; - - me.controller.add(group); - } - - // TODO: update group data - group.data = groupsData.get(id); + // use visible search to find a visible ItemRange (only based on endTime) + var initialPosByEnd = this._binarySearch(orderedItems, range, true); - delete queue[id]; - break; - - case 'remove': - if (group) { - group.setItems(); // detach items data - delete groups[id]; - - me.controller.remove(group); - } - - // update lists - delete queue[id]; - break; - - default: - console.log('Error: unknown action "' + action + '"'); - } - }); - - // the groupset depends on each of the groups - //this.depends = this.groups; // TODO: gives a circular reference through the parent - - // TODO: apply dependencies of the groupset - - // update the top positions of the groups in the correct order - var orderedGroups = this.groupsData.getIds({ - order: this.options.groupOrder - }); - for (i = 0; i < orderedGroups.length; i++) { - (function (group, prevGroup) { - var top = 0; - if (prevGroup) { - top = function () { - // TODO: top must reckon with options.maxHeight - return prevGroup.top + prevGroup.height; - } - } - group.setOptions({ - top: top - }); - })(groups[orderedGroups[i]], groups[orderedGroups[i - 1]]); - } - - // (re)create the labels - while (labelSet.firstChild) { - labelSet.removeChild(labelSet.firstChild); + // if we found a initial ID to use, trace it up and down until we meet an invisible item. + if (initialPosByStart != -1) { + for (i = initialPosByStart; i >= 0; i--) { + if (this._checkIfInvisible(orderedItems.byStart[i], newVisibleItems, range)) {break;} } - for (i = 0; i < orderedGroups.length; i++) { - id = orderedGroups[i]; - label = this._createLabel(id); - labelSet.appendChild(label); + for (i = initialPosByStart + 1; i < orderedItems.byStart.length; i++) { + if (this._checkIfInvisible(orderedItems.byStart[i], newVisibleItems, range)) {break;} } - - changed++; } - // reposition the labels - // TODO: labels are not displayed correctly when orientation=='top' - // TODO: width of labelPanel is not immediately updated on a change in groups - for (id in groups) { - if (groups.hasOwnProperty(id)) { - group = groups[id]; - label = group.label; - if (label) { - label.style.top = group.top + 'px'; - label.style.height = group.height + 'px'; - } + // if we found a initial ID to use, trace it up and down until we meet an invisible item. + if (initialPosByEnd != -1) { + for (i = initialPosByEnd; i >= 0; i--) { + if (this._checkIfInvisible(orderedItems.byEnd[i], newVisibleItems, range)) {break;} + } + for (i = initialPosByEnd + 1; i < orderedItems.byEnd.length; i++) { + if (this._checkIfInvisible(orderedItems.byEnd[i], newVisibleItems, range)) {break;} } } - return (changed > 0); + return newVisibleItems; }; /** - * Create a label for group with given id - * @param {Number} id - * @return {Element} label + * This function does a binary search for a visible item. The user can select either the this.orderedItems.byStart or .byEnd + * arrays. This is done by giving a boolean value true if you want to use the byEnd. + * This is done to be able to select the correct if statement (we do not want to check if an item is visible, we want to check + * if the time we selected (start or end) is within the current range). + * + * The trick is that every interval has to either enter the screen at the initial load or by dragging. The case of the ItemRange that is + * before and after the current range is handled by simply checking if it was in view before and if it is again. For all the rest, + * either the start OR end time has to be in the range. + * + * @param {{byStart: Item[], byEnd: Item[]}} orderedItems + * @param {{start: number, end: number}} range + * @param {Boolean} byEnd + * @returns {number} * @private */ -GroupSet.prototype._createLabel = function(id) { - var group = this.groups[id]; - var label = document.createElement('div'); - label.className = 'vlabel'; - var inner = document.createElement('div'); - inner.className = 'inner'; - label.appendChild(inner); - - var content = group.data && group.data.content; - if (content instanceof Element) { - inner.appendChild(content); - } - else if (content != undefined) { - inner.innerHTML = content; - } - - var className = group.data && group.data.className; - if (className) { - util.addClassName(label, className); - } +Group.prototype._binarySearch = function _binarySearch(orderedItems, range, byEnd) { + var array = []; + var byTime = byEnd ? 'end' : 'start'; + if (byEnd == true) {array = orderedItems.byEnd; } + else {array = orderedItems.byStart;} - group.label = label; // TODO: not so nice, parking labels in the group this way!!! + var interval = range.end - range.start; - return label; -}; + var found = false; + var low = 0; + var high = array.length; + var guess = Math.floor(0.5*(high+low)); + var newGuess; -/** - * Get container element - * @return {HTMLElement} container - */ -GroupSet.prototype.getContainer = function getContainer() { - return this.dom.frame; -}; - -/** - * Get the width of the group labels - * @return {Number} width - */ -GroupSet.prototype.getLabelsWidth = function getContainer() { - return this.props.labels.width; -}; - -/** - * Reflow the component - * @return {Boolean} resized - */ -GroupSet.prototype.reflow = function reflow() { - var changed = 0, - id, group, - options = this.options, - update = util.updateProperty, - asNumber = util.option.asNumber, - asSize = util.option.asSize, - frame = this.dom.frame; - - if (frame) { - var maxHeight = asNumber(options.maxHeight); - var fixedHeight = (asSize(options.height) != null); - var height; - if (fixedHeight) { - height = frame.offsetHeight; + if (high == 0) {guess = -1;} + else if (high == 1) { + if ((array[guess].data[byTime] > range.start - interval) && (array[guess].data[byTime] < range.end)) { + guess = 0; } else { - // height is not specified, calculate the sum of the height of all groups - height = 0; - - for (id in this.groups) { - if (this.groups.hasOwnProperty(id)) { - group = this.groups[id]; - height += group.height; - } - } - } - if (maxHeight != null) { - height = Math.min(height, maxHeight); + guess = -1; } - changed += update(this, 'height', height); - - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - changed += update(this, 'width', frame.offsetWidth); } - - // calculate the maximum width of the labels - var width = 0; - for (id in this.groups) { - if (this.groups.hasOwnProperty(id)) { - group = this.groups[id]; - var labelWidth = group.props && group.props.label && group.props.label.width || 0; - width = Math.max(width, labelWidth); + else { + high -= 1; + while (found == false) { + if ((array[guess].data[byTime] > range.start - interval) && (array[guess].data[byTime] < range.end)) { + found = true; + } + else { + if (array[guess].data[byTime] < range.start - interval) { // it is too small --> increase low + low = Math.floor(0.5*(high+low)); + } + else { // it is too big --> decrease high + high = Math.floor(0.5*(high+low)); + } + newGuess = Math.floor(0.5*(high+low)); + // not in list; + if (guess == newGuess) { + guess = -1; + found = true; + } + else { + guess = newGuess; + } + } } } - changed += update(this.props.labels, 'width', width); - - return (changed > 0); + return guess; }; /** - * Hide the component from the DOM - * @return {Boolean} changed + * this function checks if an item is invisible. If it is NOT we make it visible + * and add it to the global visible items. If it is, return true. + * + * @param {Item} item + * @param {Item[]} visibleItems + * @param {{start:number, end:number}} range + * @returns {boolean} + * @private */ -GroupSet.prototype.hide = function hide() { - if (this.dom.frame && this.dom.frame.parentNode) { - this.dom.frame.parentNode.removeChild(this.dom.frame); - return true; - } - else { +Group.prototype._checkIfInvisible = function _checkIfInvisible(item, visibleItems, range) { + if (item.isVisible(range)) { + if (!item.displayed) item.show(); + item.repositionX(); + if (visibleItems.indexOf(item) == -1) { + visibleItems.push(item); + } return false; } -}; - -/** - * Show the component in the DOM (when not already visible). - * A repaint will be executed when the component is not visible - * @return {Boolean} changed - */ -GroupSet.prototype.show = function show() { - if (!this.dom.frame || !this.dom.frame.parentNode) { - return this.repaint(); - } else { - return false; - } -}; - -/** - * Handle updated groups - * @param {Number[]} ids - * @private - */ -GroupSet.prototype._onUpdate = function _onUpdate(ids) { - this._toQueue(ids, 'update'); -}; - -/** - * Handle changed groups - * @param {Number[]} ids - * @private - */ -GroupSet.prototype._onAdd = function _onAdd(ids) { - this._toQueue(ids, 'add'); -}; - -/** - * Handle removed groups - * @param {Number[]} ids - * @private - */ -GroupSet.prototype._onRemove = function _onRemove(ids) { - this._toQueue(ids, 'remove'); -}; - -/** - * Put groups in the queue to be added/updated/remove - * @param {Number[]} ids - * @param {String} action can be 'add', 'update', 'remove' - */ -GroupSet.prototype._toQueue = function _toQueue(ids, action) { - var queue = this.queue; - ids.forEach(function (id) { - queue[id] = action; - }); - - if (this.controller) { - //this.requestReflow(); - this.requestRepaint(); + return true; } }; /** - * Find the Group from an event target: - * searches for the attribute 'timeline-groupset' in the event target's element - * tree, then finds the right group in this groupset - * @param {Event} event - * @return {Group | null} group + * 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 */ -GroupSet.groupFromTarget = function groupFromTarget (event) { - var groupset, - target = event.target; - - while (target) { - if (target.hasOwnProperty('timeline-groupset')) { - groupset = target['timeline-groupset']; - break; - } - target = target.parentNode; +Group.prototype._checkIfVisible = function _checkIfVisible(item, visibleItems, range) { + if (item.isVisible(range)) { + if (!item.displayed) item.show(); + // reposition item horizontally + item.repositionX(); + visibleItems.push(item); } - - if (groupset) { - for (var groupId in groupset.groups) { - if (groupset.groups.hasOwnProperty(groupId)) { - var group = groupset.groups[groupId]; - if (group.itemset && ItemSet.itemSetFromTarget(event) == group.itemset) { - return group; - } - } - } + else { + if (item.displayed) item.hide(); } - - return null; }; /** @@ -7807,12 +7147,24 @@ GroupSet.groupFromTarget = function groupFromTarget (event) { * @constructor */ function Timeline (container, items, options) { + // validate arguments + if (!container) throw new Error('No container element provided'); + var me = this; var now = moment().hours(0).minutes(0).seconds(0).milliseconds(0); this.options = { orientation: 'bottom', + direction: 'horizontal', // 'horizontal' or 'vertical' autoResize: true, - editable: false, + stack: true, + + editable: { + updateTime: false, + updateGroup: false, + add: false, + remove: false + }, + selectable: true, snap: null, // will be specified after timeaxis is created @@ -7828,6 +7180,14 @@ function Timeline (container, items, options) { showCurrentTime: false, showCustomTime: false, + type: 'box', + align: 'center', + margin: { + axis: 20, + item: 10 + }, + padding: 5, + onAdd: function (item, callback) { callback(item); }, @@ -7839,112 +7199,205 @@ function Timeline (container, items, options) { }, onRemove: function (item, callback) { callback(item); - } - }; + }, - // controller - this.controller = new Controller(); + toScreen: me._toScreen.bind(me), + toTime: me._toTime.bind(me) + }; // root panel - if (!container) { - throw new Error('No container element provided'); - } - var rootOptions = Object.create(this.options); - rootOptions.height = function () { - // TODO: change to height - if (me.options.height) { - // fixed height - return me.options.height; - } - else { - // auto height - return (me.timeaxis.height + me.content.height) + 'px'; + var rootOptions = util.extend(Object.create(this.options), { + height: function () { + if (me.options.height) { + // fixed height + return me.options.height; + } + else { + // auto height + // TODO: implement a css based solution to automatically have the right hight + return (me.timeAxis.height + me.contentPanel.height) + 'px'; + } } - }; + }); this.rootPanel = new RootPanel(container, rootOptions); - this.controller.add(this.rootPanel); // single select (or unselect) when tapping an item - this.controller.on('tap', this._onSelectItem.bind(this)); + this.rootPanel.on('tap', this._onSelectItem.bind(this)); // multi select when holding mouse/touch, or on ctrl+click - this.controller.on('hold', this._onMultiSelectItem.bind(this)); + this.rootPanel.on('hold', this._onMultiSelectItem.bind(this)); // add item on doubletap - this.controller.on('doubletap', this._onAddItem.bind(this)); + this.rootPanel.on('doubletap', this._onAddItem.bind(this)); - // item panel - var itemOptions = Object.create(this.options); - itemOptions.left = function () { - return me.labelPanel.width; - }; - itemOptions.width = function () { - return me.rootPanel.width - me.labelPanel.width; - }; - itemOptions.top = null; - itemOptions.height = null; - this.itemPanel = new Panel(this.rootPanel, [], itemOptions); - this.controller.add(this.itemPanel); - - // label panel - var labelOptions = Object.create(this.options); - labelOptions.top = null; - labelOptions.left = null; - labelOptions.height = null; - labelOptions.width = function () { - if (me.content && typeof me.content.getLabelsWidth === 'function') { - return me.content.getLabelsWidth(); - } - else { - return 0; + // side panel + var sideOptions = util.extend(Object.create(this.options), { + top: function () { + return (sideOptions.orientation == 'top') ? '0' : ''; + }, + bottom: function () { + return (sideOptions.orientation == 'top') ? '' : '0'; + }, + left: '0', + right: null, + height: '100%', + width: function () { + if (me.itemSet) { + return me.itemSet.getLabelsWidth(); + } + else { + return 0; + } + }, + className: function () { + return 'side' + (me.groupsData ? '' : ' hidden'); } - }; - this.labelPanel = new Panel(this.rootPanel, [], labelOptions); - this.controller.add(this.labelPanel); + }); + this.sidePanel = new Panel(sideOptions); + this.rootPanel.appendChild(this.sidePanel); + + // main panel (contains time axis and itemsets) + var mainOptions = util.extend(Object.create(this.options), { + left: function () { + // we align left to enable a smooth resizing of the window + return me.sidePanel.width; + }, + right: null, + height: '100%', + width: function () { + return me.rootPanel.width - me.sidePanel.width; + }, + className: 'main' + }); + this.mainPanel = new Panel(mainOptions); + this.rootPanel.appendChild(this.mainPanel); // range + // TODO: move range inside rootPanel? var rangeOptions = Object.create(this.options); - this.range = new Range(rangeOptions); + this.range = new Range(this.rootPanel, this.mainPanel, rangeOptions); this.range.setRange( now.clone().add('days', -3).valueOf(), now.clone().add('days', 4).valueOf() ); - - this.range.subscribe(this.controller, this.rootPanel, 'move', 'horizontal'); - this.range.subscribe(this.controller, this.rootPanel, 'zoom', 'horizontal'); this.range.on('rangechange', function (properties) { - var force = true; - me.controller.emit('rangechange', properties); - me.controller.emit('request-reflow', force); + me.rootPanel.repaint(); + me.emit('rangechange', properties); }); this.range.on('rangechanged', function (properties) { - var force = true; - me.controller.emit('rangechanged', properties); - me.controller.emit('request-reflow', force); + me.rootPanel.repaint(); + me.emit('rangechanged', properties); + }); + + // panel with time axis + var timeAxisOptions = util.extend(Object.create(rootOptions), { + range: this.range, + left: null, + top: null, + width: null, + height: null + }); + this.timeAxis = new TimeAxis(timeAxisOptions); + this.timeAxis.setRange(this.range); + this.options.snap = this.timeAxis.snap.bind(this.timeAxis); + this.mainPanel.appendChild(this.timeAxis); + + // content panel (contains itemset(s)) + var contentOptions = util.extend(Object.create(this.options), { + top: function () { + return (me.options.orientation == 'top') ? (me.timeAxis.height + 'px') : ''; + }, + bottom: function () { + return (me.options.orientation == 'top') ? '' : (me.timeAxis.height + 'px'); + }, + left: null, + right: null, + height: null, + width: null, + className: 'content' + }); + this.contentPanel = new Panel(contentOptions); + this.mainPanel.appendChild(this.contentPanel); + + // content panel (contains the vertical lines of box items) + var backgroundOptions = util.extend(Object.create(this.options), { + top: function () { + return (me.options.orientation == 'top') ? (me.timeAxis.height + 'px') : ''; + }, + bottom: function () { + return (me.options.orientation == 'top') ? '' : (me.timeAxis.height + 'px'); + }, + left: null, + right: null, + height: function () { + return me.contentPanel.height; + }, + width: null, + className: 'background' + }); + this.backgroundPanel = new Panel(backgroundOptions); + this.mainPanel.insertBefore(this.backgroundPanel, this.contentPanel); + + // panel with axis holding the dots of item boxes + var axisPanelOptions = util.extend(Object.create(rootOptions), { + left: 0, + top: function () { + return (me.options.orientation == 'top') ? (me.timeAxis.height + 'px') : ''; + }, + bottom: function () { + return (me.options.orientation == 'top') ? '' : (me.timeAxis.height + 'px'); + }, + width: '100%', + height: 0, + className: 'axis' }); + this.axisPanel = new Panel(axisPanelOptions); + this.mainPanel.appendChild(this.axisPanel); - // time axis - var timeaxisOptions = Object.create(rootOptions); - timeaxisOptions.range = this.range; - timeaxisOptions.left = null; - timeaxisOptions.top = null; - timeaxisOptions.width = '100%'; - timeaxisOptions.height = null; - this.timeaxis = new TimeAxis(this.itemPanel, [], timeaxisOptions); - this.timeaxis.setRange(this.range); - this.controller.add(this.timeaxis); - this.options.snap = this.timeaxis.snap.bind(this.timeaxis); + // content panel (contains itemset(s)) + var sideContentOptions = util.extend(Object.create(this.options), { + top: function () { + return (me.options.orientation == 'top') ? (me.timeAxis.height + 'px') : ''; + }, + bottom: function () { + return (me.options.orientation == 'top') ? '' : (me.timeAxis.height + 'px'); + }, + left: null, + right: null, + height: null, + width: null, + className: 'side-content' + }); + this.sideContentPanel = new Panel(sideContentOptions); + this.sidePanel.appendChild(this.sideContentPanel); // current time bar - this.currenttime = new CurrentTime(this.timeaxis, [], rootOptions); - this.controller.add(this.currenttime); + // Note: time bar will be attached in this.setOptions when selected + this.currentTime = new CurrentTime(this.range, rootOptions); // custom time bar - this.customtime = new CustomTime(this.timeaxis, [], rootOptions); - this.controller.add(this.customtime); + // Note: time bar will be attached in this.setOptions when selected + this.customTime = new CustomTime(rootOptions); + this.customTime.on('timechange', function (time) { + me.emit('timechange', time); + }); + this.customTime.on('timechanged', function (time) { + me.emit('timechanged', time); + }); - // create groupset - this.setGroups(null); + // itemset containing items and groups + var itemOptions = util.extend(Object.create(this.options), { + left: null, + right: null, + top: null, + bottom: null, + width: null, + height: null + }); + this.itemSet = new ItemSet(this.backgroundPanel, this.axisPanel, this.sideContentPanel, itemOptions); + this.itemSet.setRange(this.range); + this.itemSet.on('change', me.rootPanel.repaint.bind(me.rootPanel)); + this.contentPanel.appendChild(this.itemSet); this.itemsData = null; // DataSet this.groupsData = null; // DataSet @@ -7954,30 +7407,14 @@ function Timeline (container, items, options) { this.setOptions(options); } - // create itemset and groupset + // create itemset if (items) { this.setItems(items); } } -/** - * Add an event listener to the timeline - * @param {String} event Available events: select, rangechange, rangechanged, - * timechange, timechanged - * @param {function} callback - */ -Timeline.prototype.on = function on (event, callback) { - this.controller.on(event, callback); -}; - -/** - * Add an event listener from the timeline - * @param {String} event - * @param {function} callback - */ -Timeline.prototype.off = function off (event, callback) { - this.controller.off(event, callback); -}; +// turn Timeline into an event emitter +Emitter(Timeline.prototype); /** * Set options @@ -7986,6 +7423,17 @@ Timeline.prototype.off = function off (event, callback) { Timeline.prototype.setOptions = function (options) { util.extend(this.options, options); + if ('editable' in options) { + var isBoolean = typeof options.editable === 'boolean'; + + this.options.editable = { + updateTime: isBoolean ? options.editable : (options.editable.updateTime || false), + updateGroup: isBoolean ? options.editable : (options.editable.updateGroup || false), + add: isBoolean ? options.editable : (options.editable.add || false), + remove: isBoolean ? options.editable : (options.editable.remove || false) + }; + } + // force update of range (apply new min/max etc.) // both start and end are optional this.range.setRange(options.start, options.end); @@ -8001,6 +7449,9 @@ Timeline.prototype.setOptions = function (options) { } } + // force the itemSet to refresh: options like orientation and margins may be changed + this.itemSet.markDirty(); + // validate the callback functions var validateCallback = (function (fn) { if (!(this.options[fn] instanceof Function) || this.options[fn].length != 2) { @@ -8009,8 +7460,39 @@ Timeline.prototype.setOptions = function (options) { }).bind(this); ['onAdd', 'onUpdate', 'onRemove', 'onMove'].forEach(validateCallback); - this.controller.reflow(); - this.controller.repaint(); + // add/remove the current time bar + if (this.options.showCurrentTime) { + if (!this.mainPanel.hasChild(this.currentTime)) { + this.mainPanel.appendChild(this.currentTime); + this.currentTime.start(); + } + } + else { + if (this.mainPanel.hasChild(this.currentTime)) { + this.currentTime.stop(); + this.mainPanel.removeChild(this.currentTime); + } + } + + // add/remove the custom time bar + if (this.options.showCustomTime) { + if (!this.mainPanel.hasChild(this.customTime)) { + this.mainPanel.appendChild(this.customTime); + } + } + else { + if (this.mainPanel.hasChild(this.customTime)) { + this.mainPanel.removeChild(this.customTime); + } + } + + // 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.'); + } + + // repaint everything + this.rootPanel.repaint(); }; /** @@ -8018,11 +7500,11 @@ Timeline.prototype.setOptions = function (options) { * @param {Date} time */ Timeline.prototype.setCustomTime = function (time) { - if (!this.customtime) { + if (!this.customTime) { throw new Error('Cannot get custom time: Custom time bar is not enabled'); } - this.customtime.setCustomTime(time); + this.customTime.setCustomTime(time); }; /** @@ -8030,11 +7512,11 @@ Timeline.prototype.setCustomTime = function (time) { * @return {Date} customTime */ Timeline.prototype.getCustomTime = function() { - if (!this.customtime) { + if (!this.customTime) { throw new Error('Cannot get custom time: Custom time bar is not enabled'); } - return this.customtime.getCustomTime(); + return this.customTime.getCustomTime(); }; /** @@ -8049,52 +7531,30 @@ Timeline.prototype.setItems = function(items) { if (!items) { newDataSet = null; } - else if (items instanceof DataSet) { + else if (items instanceof DataSet || items instanceof DataView) { newDataSet = items; } - if (!(items instanceof DataSet)) { - newDataSet = new DataSet({ + else { + // turn an array into a dataset + newDataSet = new DataSet(items, { convert: { start: 'Date', end: 'Date' } }); - newDataSet.add(items); } // set items this.itemsData = newDataSet; - this.content.setItems(newDataSet); + this.itemSet.setItems(newDataSet); if (initialLoad && (this.options.start == undefined || this.options.end == undefined)) { - // apply the data range as range - var dataRange = this.getItemRange(); + this.fit(); - // 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); - } - - // override specified start and/or end date - if (this.options.start != undefined) { - start = util.convert(this.options.start, 'Date'); - } - if (this.options.end != undefined) { - end = util.convert(this.options.end, 'Date'); - } + var start = (this.options.start != undefined) ? util.convert(this.options.start, 'Date') : null; + var end = (this.options.end != undefined) ? util.convert(this.options.end, 'Date') : null; - // apply range if there is a min or max available - if (start != null || end != null) { - this.range.setRange(start, end); - } + this.setWindow(start, end); } }; @@ -8102,77 +7562,50 @@ Timeline.prototype.setItems = function(items) { * Set groups * @param {vis.DataSet | Array | google.visualization.DataTable} groups */ -Timeline.prototype.setGroups = function(groups) { - var me = this; - this.groupsData = groups; +Timeline.prototype.setGroups = function setGroups(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); + } - // switch content type between ItemSet or GroupSet when needed - var Type = this.groupsData ? GroupSet : ItemSet; - if (!(this.content instanceof Type)) { - // remove old content set - if (this.content) { - this.content.hide(); - if (this.content.setItems) { - this.content.setItems(); // disconnect from items - } - if (this.content.setGroups) { - this.content.setGroups(); // disconnect from groups - } - this.controller.remove(this.content); - } + this.groupsData = newDataSet; + this.itemSet.setGroups(newDataSet); +}; - // create new content set - var options = Object.create(this.options); - util.extend(options, { - top: function () { - if (me.options.orientation == 'top') { - return me.timeaxis.height; - } - else { - return me.itemPanel.height - me.timeaxis.height - me.content.height; - } - }, - left: null, - width: '100%', - height: function () { - if (me.options.height) { - // fixed height - return me.itemPanel.height - me.timeaxis.height; - } - else { - // auto height - return null; - } - }, - maxHeight: function () { - // TODO: change maxHeight to be a css string like '100%' or '300px' - if (me.options.maxHeight) { - if (!util.isNumber(me.options.maxHeight)) { - throw new TypeError('Number expected for property maxHeight'); - } - return me.options.maxHeight - me.timeaxis.height; - } - else { - return null; - } - }, - labelContainer: function () { - return me.labelPanel.getContainer(); - } - }); +/** + * Set Timeline window such that it fits all items + */ +Timeline.prototype.fit = function fit() { + // apply the data range as range + var dataRange = this.getItemRange(); - this.content = new Type(this.itemPanel, [this.timeaxis], options); - if (this.content.setRange) { - this.content.setRange(this.range); + // 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 } - if (this.content.setItems) { - this.content.setItems(this.itemsData); - } - if (this.content.setGroups) { - this.content.setGroups(this.groupsData); - } - this.controller.add(this.content); + start = new Date(start.valueOf() - interval * 0.05); + end = new Date(end.valueOf() + interval * 0.05); + } + + // skip range set if there is no start and end date + if (start === null && end === null) { + return; } + + this.range.setRange(start, end); }; /** @@ -8222,7 +7655,7 @@ Timeline.prototype.getItemRange = function getItemRange() { * unselected. */ Timeline.prototype.setSelection = function setSelection (ids) { - if (this.content) this.content.setSelection(ids); + this.itemSet.setSelection(ids); }; /** @@ -8230,17 +7663,30 @@ Timeline.prototype.setSelection = function setSelection (ids) { * @return {Array} ids The ids of the selected items */ Timeline.prototype.getSelection = function getSelection() { - return this.content ? this.content.getSelection() : []; + return this.itemSet.getSelection(); }; /** * Set the visible window. Both parameters are optional, you can change only - * start or only end. + * 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} [start] Start date of visible window * @param {Date | Number | String} [end] End date of visible window */ Timeline.prototype.setWindow = function setWindow(start, end) { - this.range.setRange(start, end); + if (arguments.length == 1) { + var range = arguments[0]; + this.range.setRange(range.start, range.end); + } + else { + this.range.setRange(start, end); + } }; /** @@ -8271,14 +7717,20 @@ Timeline.prototype._onSelectItem = function (event) { return; } - var item = ItemSet.itemFromTarget(event); + var oldSelection = this.getSelection(); + var item = ItemSet.itemFromTarget(event); var selection = item ? [item.id] : []; this.setSelection(selection); - this.controller.emit('select', { - items: this.getSelection() - }); + var newSelection = this.getSelection(); + + // if selection is changed, emit a select event + if (!util.equalArray(oldSelection, newSelection)) { + this.emit('select', { + items: this.getSelection() + }); + } event.stopPropagation(); }; @@ -8290,7 +7742,7 @@ Timeline.prototype._onSelectItem = function (event) { */ Timeline.prototype._onAddItem = function (event) { if (!this.options.selectable) return; - if (!this.options.editable) return; + if (!this.options.editable.add) return; var me = this, item = ItemSet.itemFromTarget(event); @@ -8308,17 +7760,17 @@ Timeline.prototype._onAddItem = function (event) { } else { // add item - var xAbs = vis.util.getAbsoluteLeft(this.rootPanel.frame); + var xAbs = vis.util.getAbsoluteLeft(this.contentPanel.frame); var x = event.gesture.center.pageX - xAbs; var newItem = { - start: this.timeaxis.snap(this._toTime(x)), + start: this.timeAxis.snap(this._toTime(x)), content: 'new item' }; var id = util.randomUUID(); newItem[this.itemsData.fieldId] = id; - var group = GroupSet.groupFromTarget(event); + var group = ItemSet.groupFromTarget(event); if (group) { newItem.group = group.groupId; } @@ -8327,15 +7779,7 @@ Timeline.prototype._onAddItem = function (event) { this.options.onAdd(newItem, function (item) { if (item) { me.itemsData.add(newItem); - - // select the created item after it is repainted - me.controller.once('repaint', function () { - me.setSelection([id]); - - me.controller.emit('select', { - items: me.getSelection() - }); - }.bind(me)); + // TODO: need to trigger a repaint? } }); } @@ -8367,7 +7811,7 @@ Timeline.prototype._onMultiSelectItem = function (event) { } this.setSelection(selection); - this.controller.emit('select', { + this.emit('select', { items: this.getSelection() }); @@ -8382,7 +7826,7 @@ Timeline.prototype._onMultiSelectItem = function (event) { * @private */ Timeline.prototype._toTime = function _toTime(x) { - var conversion = this.range.conversion(this.content.width); + var conversion = this.range.conversion(this.mainPanel.width); return new Date(x / conversion.scale + conversion.offset); }; @@ -8394,7 +7838,7 @@ Timeline.prototype._toTime = function _toTime(x) { * @private */ Timeline.prototype._toScreen = function _toScreen(time) { - var conversion = this.range.conversion(this.content.width); + var conversion = this.range.conversion(this.mainPanel.width); return (time.valueOf() - conversion.offset) * conversion.scale; }; @@ -9812,6 +9256,7 @@ Node.prototype.discreteStep = function(interval) { /** * 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) { if (!this.xFixed) { @@ -10457,6 +9902,7 @@ function Edge (properties, graph, constants) { this.customLength = false; this.selected = false; this.smooth = constants.smoothCurves; + this.arrowScaleFactor = constants.edges.arrowScaleFactor; this.from = null; // a node this.to = null; // a node @@ -10517,6 +9963,9 @@ Edge.prototype.setProperties = function(properties, constants) { if (properties.length !== undefined) {this.length = properties.length; this.customLength = true;} + // scale the arrow + if (properties.arrowScaleFactor !== undefined) {this.arrowScaleFactor = properties.arrowScaleFactor;} + // Added to support dashed lines // David Jordan // 2012-08-08 @@ -10933,7 +10382,7 @@ Edge.prototype._drawArrowCenter = function(ctx) { this._line(ctx); var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var length = 10 + 5 * this.width; // TODO: make customizable? + var length = (10 + 5 * this.width) * this.arrowScaleFactor; // draw an arrow halfway the line if (this.smooth == true) { var midpointX = 0.5*(0.5*(this.from.x + this.via.x) + 0.5*(this.to.x + this.via.x)); @@ -10973,7 +10422,7 @@ Edge.prototype._drawArrowCenter = function(ctx) { // draw all arrows var angle = 0.2 * Math.PI; - var length = 10 + 5 * this.width; // TODO: make customizable? + var length = (10 + 5 * this.width) * this.arrowScaleFactor; point = this._pointOnCircle(x, y, radius, 0.5); ctx.arrow(point.x, point.y, angle, length); ctx.fill(); @@ -11047,7 +10496,7 @@ Edge.prototype._drawArrow = function(ctx) { ctx.stroke(); // draw arrow at the end of the line - length = 10 + 5 * this.width; + length = (10 + 5 * this.width) * this.arrowScaleFactor; ctx.arrow(xTo, yTo, angle, length); ctx.fill(); ctx.stroke(); @@ -11098,7 +10547,7 @@ Edge.prototype._drawArrow = function(ctx) { ctx.stroke(); // draw all arrows - length = 10 + 5 * this.width; // TODO: make customizable? + var length = (10 + 5 * this.width) * this.arrowScaleFactor; ctx.arrow(arrow.x, arrow.y, arrow.angle, length); ctx.fill(); ctx.stroke(); @@ -11915,6 +11364,13 @@ var physicsMixin = { } }, + /** + * This overwrites the this.constants. + * + * @param constantsVariableName + * @param value + * @private + */ _overWriteGraphConstants: function (constantsVariableName, value) { var nameArray = constantsVariableName.split("_"); if (nameArray.length == 1) { @@ -11929,6 +11385,9 @@ var physicsMixin = { } }; +/** + * 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 = !this.constants.smoothCurves; var graph_toggleSmooth = document.getElementById("graph_toggleSmooth"); @@ -11938,6 +11397,10 @@ function graphToggleSmoothCurves () { this._configureSmoothCurves(false); }; +/** + * this function is used to scramble the nodes + * + */ function graphRepositionNodes () { for (var nodeId in this.calculationNodes) { if (this.calculationNodes.hasOwnProperty(nodeId)) { @@ -11955,6 +11418,9 @@ function graphRepositionNodes () { 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 = []; @@ -12052,7 +11518,10 @@ function graphGenerateOptions () { }; - +/** + * 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; @@ -12091,6 +11560,14 @@ function switchConfigurations () { } + +/** + * this generates the ranges depending on the iniital values. + * + * @param id + * @param map + * @param constantsVariableName + */ function showValueOfRange (id,map,constantsVariableName) { var valueId = id + "_value"; var rangeValue = document.getElementById(id).value; @@ -12337,6 +11814,13 @@ var barnesHutMixin = { }, + /** + * this updates the mass of a branch. this is increased by adding a node. + * + * @param parentBranch + * @param node + * @private + */ _updateBranchMass : function(parentBranch, node) { var totalMass = parentBranch.mass + node.mass; var totalMassInv = 1/totalMass; @@ -12354,6 +11838,14 @@ var barnesHutMixin = { }, + /** + * determine in which branch the node will be placed. + * + * @param parentBranch + * @param node + * @param skipMassUpdate + * @private + */ _placeInTree : function(parentBranch,node,skipMassUpdate) { if (skipMassUpdate != true || skipMassUpdate === undefined) { // update the mass of the branch. @@ -12379,6 +11871,14 @@ var barnesHutMixin = { }, + /** + * actually place the node in a region (or branch) + * + * @param parentBranch + * @param node + * @param region + * @private + */ _placeInRegion : function(parentBranch,node,region) { switch (parentBranch.children[region].childrenCount) { case 0: // place node here @@ -12745,7 +12245,7 @@ var HierarchicalLayoutMixin = { */ _getDistribution : function() { var distribution = {}; - var nodeId, node; + 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. @@ -12770,7 +12270,7 @@ var HierarchicalLayoutMixin = { // determine the largest amount of nodes of all levels var maxCount = 0; - for (var level in distribution) { + for (level in distribution) { if (distribution.hasOwnProperty(level)) { if (maxCount < distribution[level].amount) { maxCount = distribution[level].amount; @@ -12779,7 +12279,7 @@ var HierarchicalLayoutMixin = { } // set the initial position and spacing of each nodes accordingly - for (var level in distribution) { + for (level in distribution) { if (distribution.hasOwnProperty(level)) { distribution[level].nodeSpacing = (maxCount + 1) * this.constants.hierarchicalLayout.nodeSpacing; distribution[level].nodeSpacing /= (distribution[level].amount + 1); @@ -13221,8 +12721,6 @@ var manipulationMixin = { /** * Adds a node on the specified location - * - * @param {Object} pointer */ _addNode : function() { if (this._selectionIsEmpty() && this.editMode == true) { @@ -13654,7 +13152,7 @@ var SectorMixin = { // console.log("the node is part of the active sector"); // } // else { -// console.log("I dont know what happened!!"); +// 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. @@ -14057,6 +13555,7 @@ var ClusterMixin = { * @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 * */ updateClusters : function(zoomDirection,recursive,force,doNotStart) { @@ -14907,9 +14406,10 @@ var ClusterMixin = { var maxLevel = 0; var minLevel = 1e9; var clusterLevel = 0; + var nodeId; // we loop over all nodes in the list - for (var nodeId in this.nodes) { + for (nodeId in this.nodes) { if (this.nodes.hasOwnProperty(nodeId)) { clusterLevel = this.nodes[nodeId].clusterSessions.length; if (maxLevel < clusterLevel) {maxLevel = clusterLevel;} @@ -14921,7 +14421,7 @@ var ClusterMixin = { var amountOfNodes = this.nodeIndices.length; var targetLevel = maxLevel - this.constants.clustering.clusterLevelDifference; // we loop over all nodes in the list - for (var nodeId in this.nodes) { + for (nodeId in this.nodes) { if (this.nodes.hasOwnProperty(nodeId)) { if (this.nodes[nodeId].clusterSessions.length < targetLevel) { this._clusterToSmallestNeighbour(this.nodes[nodeId]); @@ -15236,7 +14736,7 @@ var SelectionMixin = { } for(var edgeId in this.selectionObj.edges) { if(this.selectionObj.edges.hasOwnProperty(edgeId)) { - this.selectionObj.edges[edgeId].unselect();; + this.selectionObj.edges[edgeId].unselect(); } } @@ -15906,15 +15406,15 @@ var graphMixinLoaders = { * @private */ _loadSectorSystem: function () { - this.sectors = { }, - this.activeSector = ["default"]; - this.sectors["active"] = { }, - this.sectors["active"]["default"] = {"nodes": {}, + 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["frozen"] = {}; this.sectors["support"] = {"nodes": {}, "edges": {}, "nodeIndices": [], @@ -15947,7 +15447,7 @@ var graphMixinLoaders = { _loadManipulationSystem: function () { // reset global variables -- these are used by the selection of nodes and edges. this.blockConnectingEdgeSelection = false; - this.forceAppendSelection = false + this.forceAppendSelection = false; if (this.constants.dataManipulation.enabled == true) { // load the manipulator HTML elements. All styling done in css. @@ -16112,6 +15612,7 @@ function Graph (container, data, options) { fontSize: 14, // px fontFace: 'arial', fontFill: 'white', + arrowScaleFactor: 1, dash: { length: 10, gap: 5, @@ -16410,6 +15911,7 @@ Graph.prototype._centerGraph = function(range) { * 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. */ Graph.prototype.zoomExtent = function(initialZoom, disableStart) { if (initialZoom === undefined) { @@ -16666,6 +16168,7 @@ Graph.prototype.setOptions = function (options) { } } + if (options.edges.color !== undefined) { if (util.isString(options.edges.color)) { this.constants.edges.color = {}; @@ -16995,7 +16498,7 @@ Graph.prototype._handleOnDrag = function(event) { this.drag.translation.x + diffX, this.drag.translation.y + diffY); this._redraw(); - this.moved = true; + this.moving = true; } }; @@ -17398,12 +16901,13 @@ Graph.prototype._updateNodes = function(ids) { // create node node = new Node(properties, this.images, this.groups, this.constants); nodes[id] = node; - - if (!node.isFixed()) { - this.moving = true; - } } } + this.moving = true; + if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) { + this._resetLevels(); + this._setupHierarchicalLayout(); + } this._updateNodeIndexList(); this._reconnectEdges(); this._updateValueRange(nodes); @@ -17848,7 +17352,12 @@ Graph.prototype._stabilize = function() { this.emit("stabilized",{iterations:count}); }; - +/** + * 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 + */ Graph.prototype._freezeDefinedNodes = function() { var nodes = this.nodes; for (var id in nodes) { @@ -17863,6 +17372,11 @@ Graph.prototype._freezeDefinedNodes = function() { } }; +/** + * Unfreezes the nodes that have been frozen by _freezeDefinedNodes. + * + * @private + */ Graph.prototype._restoreFrozenNodes = function() { var nodes = this.nodes; for (var id in nodes) { @@ -17933,7 +17447,11 @@ Graph.prototype._discreteStepNodes = function() { } }; - +/** + * A single simulation step (or "tick") in the physics simulation + * + * @private + */ Graph.prototype._physicsTick = function() { if (!this.freezeSimulation) { if (this.moving) { @@ -18052,7 +17570,12 @@ Graph.prototype.toggleFreeze = function() { }; - +/** + * This function cleans the support nodes if they are not needed and adds them when they are. + * + * @param {boolean} [disableStart] + * @private + */ Graph.prototype._configureSmoothCurves = function(disableStart) { if (disableStart === undefined) { disableStart = true; @@ -18078,6 +17601,13 @@ Graph.prototype._configureSmoothCurves = function(disableStart) { } }; + +/** + * 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 + */ Graph.prototype._createBezierNodes = function() { if (this.constants.smoothCurves == true) { for (var edgeId in this.edges) { @@ -18102,7 +17632,11 @@ Graph.prototype._createBezierNodes = function() { } }; - +/** + * load the functions that load the mixins into the prototype. + * + * @private + */ Graph.prototype._initializeMixinLoaders = function () { for (var mixinFunction in graphMixinLoaders) { if (graphMixinLoaders.hasOwnProperty(mixinFunction)) { @@ -18147,11 +17681,10 @@ Graph.prototype.storePosition = function() { var vis = { util: util, - Controller: Controller, DataSet: DataSet, DataView: DataView, Range: Range, - Stack: Stack, + stack: stack, TimeStep: TimeStep, components: { @@ -23091,4 +22624,4 @@ module.exports = mousetrap; },{}]},{},[1]) (1) -}); +}); \ No newline at end of file diff --git a/dist/vis.min.css b/dist/vis.min.css index 7ae07c0c..6f9c3d0e 100644 --- a/dist/vis.min.css +++ b/dist/vis.min.css @@ -1 +1 @@ -.vis.timeline.rootpanel{position:relative;overflow:hidden;border:1px solid #bfbfbf;-moz-box-sizing:border-box;box-sizing:border-box}.vis.timeline .vpanel{position:absolute;overflow:hidden}.vis.timeline .groupset{position:absolute;padding:0;margin:0}.vis.timeline .labels{position:absolute;top:0;left:0;width:100%;height:100%;padding:0;margin:0;border-right:1px solid #bfbfbf;-moz-box-sizing:border-box;box-sizing:border-box}.vis.timeline .labels .label-set{position:absolute;top:0;left:0;width:100%;height:100%;overflow:hidden;border-top:none;border-bottom:1px solid #bfbfbf}.vis.timeline .labels .label-set .vlabel{position:absolute;left:0;top:0;width:100%;color:#4d4d4d}.vis.timeline.top .groupset .itemset-axis,.vis.timeline.top .labels .label-set .vlabel{border-top:1px solid #bfbfbf;border-bottom:none}.vis.timeline.bottom .groupset .itemset-axis,.vis.timeline.bottom .labels .label-set .vlabel{border-top:none;border-bottom:1px solid #bfbfbf}.vis.timeline .labels .label-set .vlabel .inner{display:inline-block;padding:5px}.vis.timeline .itemset{position:absolute;padding:0;margin:0;overflow:hidden}.vis.timeline .itemset-axis{position:absolute}.vis.timeline .item{position:absolute;color:#1A1A1A;border-color:#97B0F8;background-color:#D5DDF6;display:inline-block;padding:5px}.vis.timeline .item.selected{border-color:#FFC200;background-color:#FFF785;z-index:999}.vis.timeline.editable .item.selected{cursor:move}.vis.timeline .item.point.selected{background-color:#FFF785;z-index:999}.vis.timeline .item.point.selected .dot{border-color:#FFC200}.vis.timeline .item.cluster{background:#97B0F8 url(img/cluster_bg.png);color:#fff}.vis.timeline .item.cluster.point{border-color:#D5DDF6}.vis.timeline .item.box{text-align:center;border-style:solid;border-width:1px;border-radius:5px;-moz-border-radius:5px}.vis.timeline .item.point{background:0 0}.vis.timeline .dot,.vis.timeline .item.dot{padding:0;border:5px solid #97B0F8;position:absolute;border-radius:5px;-moz-border-radius:5px}.vis.timeline .item.range,.vis.timeline .item.rangeoverflow{border-style:solid;border-width:1px;border-radius:2px;-moz-border-radius:2px;-moz-box-sizing:border-box;box-sizing:border-box}.vis.timeline .item.range .content,.vis.timeline .item.rangeoverflow .content{position:relative;display:inline-block}.vis.timeline .item.range .content{overflow:hidden;max-width:100%}.vis.timeline .item.line{padding:0;position:absolute;width:0;border-left-width:1px;border-left-style:solid}.vis.timeline .item .content{white-space:nowrap;overflow:hidden}.vis.timeline .item .delete{background:url(img/timeline/delete.png) no-repeat top center;position:absolute;width:24px;height:24px;top:0;right:-24px;cursor:pointer}.vis.timeline .item.range .drag-left,.vis.timeline .item.rangeoverflow .drag-left{position:absolute;width:24px;height:100%;top:0;left:-4px;cursor:w-resize;z-index:10000}.vis.timeline .item.range .drag-right,.vis.timeline .item.rangeoverflow .drag-right{position:absolute;width:24px;height:100%;top:0;right:-4px;cursor:e-resize;z-index:10001}.vis.timeline .axis{position:relative}.vis.timeline .axis .text{position:absolute;color:#4d4d4d;padding:3px;white-space:nowrap}.vis.timeline .axis .text.measure{position:absolute;padding-left:0;padding-right:0;margin-left:0;margin-right:0;visibility:hidden}.vis.timeline .axis .grid.vertical{position:absolute;width:0;border-right:1px solid}.vis.timeline .axis .grid.horizontal{position:absolute;left:0;width:100%;height:0;border-bottom:1px solid}.vis.timeline .axis .grid.minor{border-color:#e5e5e5}.vis.timeline .axis .grid.major{border-color:#bfbfbf}.vis.timeline .currenttime{background-color:#FF7F6E;width:2px;z-index:9}.vis.timeline .customtime{background-color:#6E94FF;width:2px;cursor:move;z-index:9}div.graph-manipulationDiv{border-width:0;border-bottom:1px;border-style:solid;border-color:#d6d9d8;background:#fff;background:-moz-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#fff),color-stop(48%,#fcfcfc),color-stop(50%,#fafafa),color-stop(100%,#fcfcfc));background:-webkit-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:-o-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:-ms-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:linear-gradient(to bottom,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#fcfcfc', GradientType=0);width:600px;height:30px;z-index:10;position:absolute}div.graph-manipulation-editMode{height:30px;z-index:10;position:absolute;margin-top:20px}div.graph-manipulation-closeDiv{height:30px;width:30px;z-index:11;position:absolute;margin-top:3px;margin-left:590px;background-position:0 0;background-repeat:no-repeat;background-image:url(img/graph/cross.png);cursor:pointer;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}span.graph-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.graph-manipulationUI:hover{box-shadow:1px 1px 8px rgba(0,0,0,.2)}span.graph-manipulationUI:active{box-shadow:1px 1px 8px rgba(0,0,0,.5)}span.graph-manipulationUI.back{background-image:url(img/graph/backIcon.png)}span.graph-manipulationUI.none:hover{box-shadow:1px 1px 8px rgba(0,0,0,0);cursor:default}span.graph-manipulationUI.none:active{box-shadow:1px 1px 8px rgba(0,0,0,0)}span.graph-manipulationUI.none{padding:0}span.graph-manipulationUI.notification{margin:2px;font-weight:700}span.graph-manipulationUI.add{background-image:url(img/graph/addNodeIcon.png)}span.graph-manipulationUI.edit{background-image:url(img/graph/editIcon.png)}span.graph-manipulationUI.edit.editmode{background-color:#fcfcfc;border-style:solid;border-width:1px;border-color:#ccc}span.graph-manipulationUI.connect{background-image:url(img/graph/connectIcon.png)}span.graph-manipulationUI.delete{background-image:url(img/graph/deleteIcon.png)}span.graph-manipulationLabel{margin:0 0 0 23px;line-height:25px}div.graph-seperatorLine{display:inline-block;width:1px;height:20px;background-color:#bdbdbd;margin:5px 7px 0 15px}div.graph-navigation{width:34px;height:34px;z-index:10;-moz-border-radius:17px;border-radius:17px;position:absolute;display:inline-block;background-position:2px 2px;background-repeat:no-repeat;cursor:pointer;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}div.graph-navigation:hover{box-shadow:0 0 3px 3px rgba(56,207,21,.3)}div.graph-navigation.active,div.graph-navigation:active{box-shadow:0 0 1px 3px rgba(56,207,21,.95)}div.graph-navigation.up{background-image:url(img/graph/upArrow.png);bottom:50px;left:55px}div.graph-navigation.down{background-image:url(img/graph/downArrow.png);bottom:10px;left:55px}div.graph-navigation.left{background-image:url(img/graph/leftArrow.png);bottom:10px;left:15px}div.graph-navigation.right{background-image:url(img/graph/rightArrow.png);bottom:10px;left:95px}div.graph-navigation.zoomIn{background-image:url(img/graph/plus.png);bottom:10px;right:15px}div.graph-navigation.zoomOut{background-image:url(img/graph/minus.png);bottom:10px;right:55px}div.graph-navigation.zoomExtends{background-image:url(img/graph/zoomExtends.png);bottom:50px;right:15px} \ No newline at end of file +.vis.timeline.rootpanel{position:relative;overflow:hidden;border:1px solid #bfbfbf;box-sizing:border-box}.vis.timeline .vpanel{position:absolute;overflow:hidden;box-sizing:border-box}.vis.timeline .vpanel.side{border-right:1px solid #bfbfbf}.vis.timeline .vpanel.side.hidden{display:none}.vis.timeline .labelset{position:relative;width:100%;overflow:hidden;box-sizing:border-box}.vis.timeline .labelset .vlabel{position:relative;left:0;top:0;width:100%;color:#4d4d4d;box-sizing:border-box}.vis.timeline.top .labelset .vlabel{border-top:1px solid #bfbfbf;border-bottom:none}.vis.timeline.bottom .labelset .vlabel{border-top:none;border-bottom:1px solid #bfbfbf}.vis.timeline .labelset .vlabel .inner{display:inline-block;padding:5px}.vis.timeline .itemset{position:relative;padding:0;margin:0;box-sizing:border-box}.vis.timeline .axis{overflow:visible}.vis.timeline .group{position:relative;box-sizing:border-box}.vis.timeline.top .group{border-top:1px solid #bfbfbf;border-bottom:none}.vis.timeline.bottom .group{border-top:none;border-bottom:1px solid #bfbfbf}.vis.timeline .item{position:absolute;color:#1A1A1A;border-color:#97B0F8;border-width:1px;background-color:#D5DDF6;display:inline-block;padding:5px}.vis.timeline .item.selected{border-color:#FFC200;background-color:#FFF785;z-index:999}.vis.timeline.editable .item.selected{cursor:move}.vis.timeline .item.point.selected{background-color:#FFF785}.vis.timeline .item.box{text-align:center;border-style:solid;border-radius:2px}.vis.timeline .item.point{background:0 0}.vis.timeline .item.dot{position:absolute;padding:0;border-width:4px;border-style:solid;border-radius:4px}.vis.timeline .item.range,.vis.timeline .item.rangeoverflow{border-style:solid;border-radius:2px;box-sizing:border-box}.vis.timeline .item.range .content,.vis.timeline .item.rangeoverflow .content{position:relative;display:inline-block}.vis.timeline .item.range .content{overflow:hidden;max-width:100%}.vis.timeline .item.line{padding:0;position:absolute;width:0;border-left-width:1px;border-left-style:solid}.vis.timeline .item .content{white-space:nowrap;overflow:hidden}.vis.timeline .item .delete{background:url(img/timeline/delete.png) no-repeat top center;position:absolute;width:24px;height:24px;top:0;right:-24px;cursor:pointer}.vis.timeline .item.range .drag-left,.vis.timeline .item.rangeoverflow .drag-left{position:absolute;width:24px;height:100%;top:0;left:-4px;cursor:w-resize;z-index:10000}.vis.timeline .item.range .drag-right,.vis.timeline .item.rangeoverflow .drag-right{position:absolute;width:24px;height:100%;top:0;right:-4px;cursor:e-resize;z-index:10001}.vis.timeline .timeaxis{position:absolute}.vis.timeline .timeaxis .text{position:absolute;color:#4d4d4d;padding:3px;white-space:nowrap}.vis.timeline .timeaxis .text.measure{position:absolute;padding-left:0;padding-right:0;margin-left:0;margin-right:0;visibility:hidden}.vis.timeline .timeaxis .grid.vertical{position:absolute;width:0;border-right:1px solid}.vis.timeline .timeaxis .grid.horizontal{position:absolute;left:0;width:100%;height:0;border-bottom: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:9}.vis.timeline .customtime{background-color:#6E94FF;width:2px;cursor:move;z-index:9}div.graph-manipulationDiv{border-width:0;border-bottom:1px;border-style:solid;border-color:#d6d9d8;background:#fff;background:-moz-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#fff),color-stop(48%,#fcfcfc),color-stop(50%,#fafafa),color-stop(100%,#fcfcfc));background:-webkit-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:-o-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:-ms-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:linear-gradient(to bottom,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#fcfcfc', GradientType=0);width:600px;height:30px;z-index:10;position:absolute}div.graph-manipulation-editMode{height:30px;z-index:10;position:absolute;margin-top:20px}div.graph-manipulation-closeDiv{height:30px;width:30px;z-index:11;position:absolute;margin-top:3px;margin-left:590px;background-position:0 0;background-repeat:no-repeat;background-image:url(img/graph/cross.png);cursor:pointer;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}span.graph-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.graph-manipulationUI:hover{box-shadow:1px 1px 8px rgba(0,0,0,.2)}span.graph-manipulationUI:active{box-shadow:1px 1px 8px rgba(0,0,0,.5)}span.graph-manipulationUI.back{background-image:url(img/graph/backIcon.png)}span.graph-manipulationUI.none:hover{box-shadow:1px 1px 8px rgba(0,0,0,0);cursor:default}span.graph-manipulationUI.none:active{box-shadow:1px 1px 8px rgba(0,0,0,0)}span.graph-manipulationUI.none{padding:0}span.graph-manipulationUI.notification{margin:2px;font-weight:700}span.graph-manipulationUI.add{background-image:url(img/graph/addNodeIcon.png)}span.graph-manipulationUI.edit{background-image:url(img/graph/editIcon.png)}span.graph-manipulationUI.edit.editmode{background-color:#fcfcfc;border-style:solid;border-width:1px;border-color:#ccc}span.graph-manipulationUI.connect{background-image:url(img/graph/connectIcon.png)}span.graph-manipulationUI.delete{background-image:url(img/graph/deleteIcon.png)}span.graph-manipulationLabel{margin:0 0 0 23px;line-height:25px}div.graph-seperatorLine{display:inline-block;width:1px;height:20px;background-color:#bdbdbd;margin:5px 7px 0 15px}div.graph-navigation{width:34px;height:34px;z-index:10;-moz-border-radius:17px;border-radius:17px;position:absolute;display:inline-block;background-position:2px 2px;background-repeat:no-repeat;cursor:pointer;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}div.graph-navigation:hover{box-shadow:0 0 3px 3px rgba(56,207,21,.3)}div.graph-navigation.active,div.graph-navigation:active{box-shadow:0 0 1px 3px rgba(56,207,21,.95)}div.graph-navigation.up{background-image:url(img/graph/upArrow.png);bottom:50px;left:55px}div.graph-navigation.down{background-image:url(img/graph/downArrow.png);bottom:10px;left:55px}div.graph-navigation.left{background-image:url(img/graph/leftArrow.png);bottom:10px;left:15px}div.graph-navigation.right{background-image:url(img/graph/rightArrow.png);bottom:10px;left:95px}div.graph-navigation.zoomIn{background-image:url(img/graph/plus.png);bottom:10px;right:15px}div.graph-navigation.zoomOut{background-image:url(img/graph/minus.png);bottom:10px;right:55px}div.graph-navigation.zoomExtends{background-image:url(img/graph/zoomExtends.png);bottom:50px;right:15px} \ No newline at end of file diff --git a/dist/vis.min.js b/dist/vis.min.js index 934e5823..02c20511 100644 --- a/dist/vis.min.js +++ b/dist/vis.min.js @@ -4,8 +4,8 @@ * * A dynamic, browser-based visualization library. * - * @version 0.7.4 - * @date 2014-04-18 + * @version 1.0.0 + * @date 2014-05-02 * * @license * Copyright (C) 2011-2014 Almende B.V, http://almende.com @@ -22,12 +22,12 @@ * License for the specific language governing permissions and limitations under * the License. */ -!function(t){if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else{var e;"undefined"!=typeof window?e=window:"undefined"!=typeof global?e=global:"undefined"!=typeof self&&(e=self),e.vis=t()}}(function(){var define,module,exports;return function t(e,i,s){function n(r,a){if(!i[r]){if(!e[r]){var h="function"==typeof require&&require;if(!a&&h)return h(r,!0);if(o)return o(r,!0);throw new Error("Cannot find module '"+r+"'")}var d=i[r]={exports:{}};e[r][0].call(d.exports,function(t){var i=e[r][1][t];return n(i?i:t)},d,d.exports,t,e,i,s)}return i[r].exports}for(var o="function"==typeof require&&require,r=0;ri;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,s,n;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),r=o.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),s=new Array(r),n=0;r>n;){var a,h;n in o&&(a=o[n],h=t.call(i,a,n,o),s[n]=h),n++}return s}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var s=[],n=arguments[1],o=0;i>o;o++)if(o in e){var r=e[o];t.call(n,r,o,e)&&s.push(r)}return s}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],s=i.length;return function(n){if("object"!=typeof n&&"function"!=typeof n||null===n)throw new TypeError("Object.keys called on non-object");var o=[];for(var r in n)t.call(n,r)&&o.push(r);if(e)for(var a=0;s>a;a++)t.call(n,i[a])&&o.push(i[a]);return o}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,s=function(){},n=function(){return i.apply(this instanceof s&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return s.prototype=this.prototype,n.prototype=new s,n}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw new Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,s=function(){},n=function(){return i.apply(this instanceof s&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return s.prototype=this.prototype,n.prototype=new s,n});var util={};util.isNumber=function(t){return t instanceof Number||"number"==typeof t},util.isString=function(t){return t instanceof String||"string"==typeof t},util.isDate=function(t){if(t instanceof Date)return!0;if(util.isString(t)){var e=ASPDateRegex.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},util.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},util.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},util.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var s=arguments[e];for(var n in s)s.hasOwnProperty(n)&&void 0!==s[n]&&(t[n]=s[n])}return t},util.convert=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw new Error("Type must be a string");switch(e){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(util.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(moment.isMoment(t))return new Date(t.valueOf());if(util.isString(t))return i=ASPDateRegex.exec(t),i?new Date(Number(i[1])):moment(t).toDate();throw new Error("Cannot convert object of type "+util.getType(t)+" to type Date");case"Moment":if(util.isNumber(t))return moment(t);if(t instanceof Date)return moment(t.valueOf());if(moment.isMoment(t))return moment(t);if(util.isString(t))return i=ASPDateRegex.exec(t),moment(i?Number(i[1]):t);throw new Error("Cannot convert object of type "+util.getType(t)+" to type Date");case"ISODate":if(util.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(moment.isMoment(t))return t.toDate().toISOString();if(util.isString(t))return i=ASPDateRegex.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw new Error("Cannot convert object of type "+util.getType(t)+" to type ISODate");case"ASPDate":if(util.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(util.isString(t)){i=ASPDateRegex.exec(t);var s;return s=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+s+")/"}throw new Error("Cannot convert object of type "+util.getType(t)+" to type ASPDate");default:throw new Error("Cannot convert object of type "+util.getType(t)+' to type "'+e+'"')}};var ASPDateRegex=/^\/?Date\((\-?\d+)/i;util.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":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},util.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,s=t.offsetLeft,n=t.offsetParent;null!=n&&n!=i&&n!=e;)s+=n.offsetLeft,s-=n.scrollLeft,n=n.offsetParent;return s},util.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,s=t.offsetTop,n=t.offsetParent;null!=n&&n!=i&&n!=e;)s+=n.offsetTop,s-=n.scrollTop,n=n.offsetParent;return s},util.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,s=document.body;return e+(i&&i.scrollTop||s&&s.scrollTop||0)-(i&&i.clientTop||s&&s.clientTop||0)},util.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,s=document.body;return e+(i&&i.scrollLeft||s&&s.scrollLeft||0)-(i&&i.clientLeft||s&&s.clientLeft||0)},util.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},util.removeClassName=function(t,e){var i=t.className.split(" "),s=i.indexOf(e);-1!=s&&(i.splice(s,1),t.className=i.join(" "))},util.forEach=function(t,e){var i,s;if(t instanceof Array)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)},util.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},util.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)},util.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)},util.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},util.fakeGesture=function(t,e){var i=null,s=Hammer.event.collectEventData(this,i,e);return isNaN(s.center.pageX)&&(s.center.pageX=e.pageX),isNaN(s.center.pageY)&&(s.center.pageY=e.pageY),s},util.option={},util.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},util.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},util.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?String(t):e||null},util.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),util.isString(t)?t:util.isNumber(t)?t+"px":e||null},util.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null},util.GiveDec=function GiveDec(Hex){return Value="A"==Hex?10:"B"==Hex?11:"C"==Hex?12:"D"==Hex?13:"E"==Hex?14:"F"==Hex?15:eval(Hex)},util.GiveHex=function(t){return Value=10==t?"A":11==t?"B":12==t?"C":13==t?"D":14==t?"E":15==t?"F":""+t},util.parseColor=function(t){var e;if(util.isString(t))if(util.isValidHex(t)){var i=util.hexToHSV(t),s={h:i.h,s:.45*i.s,v:Math.min(1,1.05*i.v)},n={h:i.h,s:Math.min(1,1.25*i.v),v:.6*i.v},o=util.HSVToHex(n.h,n.h,n.v),r=util.HSVToHex(s.h,s.s,s.v);e={background:t,border:o,highlight:{background:r,border:o}}}else e={background:t,border:t,highlight:{background:t,border:t}};else e={},e.background=t.background||"white",e.border=t.border||e.background,util.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border);return e},util.hexToRGB=function(t){t=t.replace("#","").toUpperCase();var e=util.GiveDec(t.substring(0,1)),i=util.GiveDec(t.substring(1,2)),s=util.GiveDec(t.substring(2,3)),n=util.GiveDec(t.substring(3,4)),o=util.GiveDec(t.substring(4,5)),r=util.GiveDec(t.substring(5,6)),a=16*e+i,h=16*s+n,i=16*o+r;return{r:a,g:h,b:i}},util.RGBToHex=function(t,e,i){var s=util.GiveHex(Math.floor(t/16)),n=util.GiveHex(t%16),o=util.GiveHex(Math.floor(e/16)),r=util.GiveHex(e%16),a=util.GiveHex(Math.floor(i/16)),h=util.GiveHex(i%16),d=s+n+o+r+a+h;return"#"+d},util.RGBToHSV=function(t,e,i){t/=255,e/=255,i/=255; -var s=Math.min(t,Math.min(e,i)),n=Math.max(t,Math.max(e,i));if(s==n)return{h:0,s:0,v:s};var o=t==s?e-i:i==s?t-e:i-t,r=t==s?3:i==s?1:5,a=60*(r-o/(n-s))/360,h=(n-s)/n,d=n;return{h:a,s:h,v:d}},util.HSVToRGB=function(t,e,i){var s,n,o,r=Math.floor(6*t),a=6*t-r,h=i*(1-e),d=i*(1-a*e),c=i*(1-(1-a)*e);switch(r%6){case 0:s=i,n=c,o=h;break;case 1:s=d,n=i,o=h;break;case 2:s=h,n=i,o=c;break;case 3:s=h,n=d,o=i;break;case 4:s=c,n=h,o=i;break;case 5:s=i,n=h,o=d}return{r:Math.floor(255*s),g:Math.floor(255*n),b:Math.floor(255*o)}},util.HSVToHex=function(t,e,i){var s=util.HSVToRGB(t,e,i);return util.RGBToHex(s.r,s.g,s.b)},util.hexToHSV=function(t){var e=util.hexToRGB(t);return util.RGBToHSV(e.r,e.g,e.b)},util.isValidHex=function(t){var e=/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(t);return e},util.copyObject=function(t,e){for(var i in t)t.hasOwnProperty(i)&&("object"==typeof t[i]?(e[i]={},util.copyObject(t[i],e[i])):e[i]=t[i])},DataSet.prototype.on=function(t,e){var i=this.subscribers[t];i||(i=[],this.subscribers[t]=i),i.push({callback:e})},DataSet.prototype.subscribe=DataSet.prototype.on,DataSet.prototype.off=function(t,e){var i=this.subscribers[t];i&&(this.subscribers[t]=i.filter(function(t){return t.callback!=e}))},DataSet.prototype.unsubscribe=DataSet.prototype.off,DataSet.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 n=0;no;o++)i=n._addItem(t[o]),s.push(i);else if(util.isDataTable(t))for(var a=this._getColumnNames(t),h=0,d=t.getNumberOfRows();d>h;h++){for(var c={},l=0,u=a.length;u>l;l++){var p=a[l];c[p]=t.getValue(h,l)}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},DataSet.prototype.update=function(t,e){var i=[],s=[],n=this,o=n.fieldId,r=function(t){var e=t[o];n.data[e]?(e=n._updateItem(t),s.push(e)):(e=n._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)r(t[a]);else if(util.isDataTable(t))for(var d=this._getColumnNames(t),c=0,l=t.getNumberOfRows();l>c;c++){for(var u={},p=0,g=d.length;g>p;p++){var f=d[p];u[f]=t.getValue(c,p)}r(u)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");r(t)}return i.length&&this._trigger("add",{items:i},e),s.length&&this._trigger("update",{items:s},e),i.concat(s)},DataSet.prototype.get=function(){var t,e,i,s,n=this,o=this.showInternalIds,r=util.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.type){if(a="DataTable"==i.type?"DataTable":"Array",s&&a!=util.getType(s))throw new Error('Type of parameter "data" ('+util.getType(s)+") does not correspond with specified options.type ("+i.type+")");if("DataTable"==a&&!util.isDataTable(s))throw new Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else a=s&&"DataTable"==util.getType(s)?"DataTable":"Array";void 0!=i&&void 0!=i.showInternalIds&&(this.showInternalIds=i.showInternalIds);var h,d,c,l,u=i&&i.convert||this.options.convert,p=i&&i.filter,g=[];if(void 0!=t)h=n._getItem(t,u),p&&!p(h)&&(h=null);else if(void 0!=e)for(c=0,l=e.length;l>c;c++)h=n._getItem(e[c],u),(!p||p(h))&&g.push(h);else for(d in this.data)this.data.hasOwnProperty(d)&&(h=n._getItem(d,u),(!p||p(h))&&g.push(h));if(this.showInternalIds=o,i&&i.order&&void 0==t&&this._sort(g,i.order),i&&i.fields){var f=i.fields;if(void 0!=t)h=this._filterFields(h,f);else for(c=0,l=g.length;l>c;c++)g[c]=this._filterFields(g[c],f)}if("DataTable"==a){var m=this._getColumnNames(s);if(void 0!=t)n._appendRow(s,m,h);else for(c=0,l=g.length;l>c;c++)n._appendRow(s,m,g[c]);return s}if(void 0!=t)return h;if(s){for(c=0,l=g.length;l>c;c++)s.push(g[c]);return s}return g},DataSet.prototype.getIds=function(t){var e,i,s,n,o,r=this.data,a=t&&t.filter,h=t&&t.order,d=t&&t.convert||this.options.convert,c=[];if(a)if(h){o=[];for(s in r)r.hasOwnProperty(s)&&(n=this._getItem(s,d),a(n)&&o.push(n));for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(s in r)r.hasOwnProperty(s)&&(n=this._getItem(s,d),a(n)&&c.push(n[this.fieldId]));else if(h){o=[];for(s in r)r.hasOwnProperty(s)&&o.push(r[s]);for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(s in r)r.hasOwnProperty(s)&&(n=r[s],c.push(n[this.fieldId]));return c},DataSet.prototype.forEach=function(t,e){var i,s,n=e&&e.filter,o=e&&e.convert||this.options.convert,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,o),(!n||n(i))&&t(i,s))},DataSet.prototype.map=function(t,e){var i,s=e&&e.filter,n=e&&e.convert||this.options.convert,o=[],r=this.data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,n),(!s||s(i))&&o.push(t(i,a)));return e&&e.order&&this._sort(o,e.order),o},DataSet.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},DataSet.prototype._sort=function(t,e){if(util.isString(e)){var i=e;t.sort(function(t,e){var s=t[i],n=e[i];return s>n?1:n>s?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},DataSet.prototype.remove=function(t,e){var i,s,n,o=[];if(t instanceof Array)for(i=0,s=t.length;s>i;i++)n=this._remove(t[i]),null!=n&&o.push(n);else n=this._remove(t),null!=n&&o.push(n);return o.length&&this._trigger("remove",{items:o},e),o},DataSet.prototype._remove=function(t){if(util.isNumber(t)||util.isString(t)){if(this.data[t])return delete this.data[t],delete this.internalIds[t],t}else if(t instanceof Object){var e=t[this.fieldId];if(e&&this.data[e])return delete this.data[e],delete this.internalIds[e],e}return null},DataSet.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},DataSet.prototype.max=function(t){var e=this.data,i=null,s=null;for(var n in e)if(e.hasOwnProperty(n)){var o=e[n],r=o[t];null!=r&&(!i||r>s)&&(i=o,s=r)}return i},DataSet.prototype.min=function(t){var e=this.data,i=null,s=null;for(var n in e)if(e.hasOwnProperty(n)){var o=e[n],r=o[t];null!=r&&(!i||s>r)&&(i=o,s=r)}return i},DataSet.prototype.distinct=function(t){var e=this.data,i=[],s=this.options.convert[t],n=0;for(var o in e)if(e.hasOwnProperty(o)){for(var r=e[o],a=util.convert(r[t],s),h=!1,d=0;n>d;d++)if(i[d]==a){h=!0;break}h||(i[n]=a,n++)}return i},DataSet.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw new Error("Cannot add item: item with id "+e+" already exists")}else e=util.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var s in t)if(t.hasOwnProperty(s)){var n=this.convert[s];i[s]=util.convert(t[s],n)}return this.data[e]=i,e},DataSet.prototype._getItem=function(t,e){var i,s,n=this.data[t];if(!n)return null;var o={},r=this.fieldId,a=this.internalIds;if(e)for(i in n)n.hasOwnProperty(i)&&(s=n[i],i==r&&s in a&&!this.showInternalIds||(o[i]=util.convert(s,e[i])));else for(i in n)n.hasOwnProperty(i)&&(s=n[i],i==r&&s in a&&!this.showInternalIds||(o[i]=s));return o},DataSet.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw new Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw new Error("Cannot update item: no item with id "+e+" found");for(var s in t)if(t.hasOwnProperty(s)){var n=this.convert[s];i[s]=util.convert(t[s],n)}return e},DataSet.prototype.isInternalId=function(t){return t in this.internalIds},DataSet.prototype._getColumnNames=function(t){for(var e=[],i=0,s=t.getNumberOfColumns();s>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},DataSet.prototype._appendRow=function(t,e,i){for(var s=t.addRow(),n=0,o=e.length;o>n;n++){var r=e[n];t.setValue(s,n,i[r])}},DataView.prototype.setData=function(t){var e,i,s;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var n in this.ids)this.ids.hasOwnProperty(n)&&e.push(n);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++)n=e[i],this.ids[n]=!0;this._trigger("add",{items:e}),this.data.on&&this.data.on("*",this.listener)}},DataView.prototype.get=function(){var t,e,i,s=this,n=util.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 o=util.extend({},this.options,e);this.options.filter&&e&&e.filter&&(o.filter=function(t){return s.options.filter(t)&&e.filter(t)});var r=[];return void 0!=t&&r.push(t),r.push(o),r.push(i),this.data&&this.data.get.apply(this.data,r)},DataView.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},DataView.prototype._onEvent=function(t,e,i){var s,n,o,r,a=e&&e.items,h=this.data,d=[],c=[],l=[];if(a&&h){switch(t){case"add":for(s=0,n=a.length;n>s;s++)o=a[s],r=this.get(o),r&&(this.ids[o]=!0,d.push(o));break;case"update":for(s=0,n=a.length;n>s;s++)o=a[s],r=this.get(o),r?this.ids[o]?c.push(o):(this.ids[o]=!0,d.push(o)):this.ids[o]&&(delete this.ids[o],l.push(o));break;case"remove":for(s=0,n=a.length;n>s;s++)o=a[s],this.ids[o]&&(delete this.ids[o],l.push(o))}d.length&&this._trigger("add",{items:d},i),c.length&&this._trigger("update",{items:c},i),l.length&&this._trigger("remove",{items:l},i)}},DataView.prototype.on=DataSet.prototype.on,DataView.prototype.off=DataSet.prototype.off,DataView.prototype._trigger=DataSet.prototype._trigger,DataView.prototype.subscribe=DataView.prototype.on,DataView.prototype.unsubscribe=DataView.prototype.off,TimeStep=function(t,e,i){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale=TimeStep.SCALE.DAY,this.step=1,this.setRange(t,e,i)},TimeStep.SCALE={MILLISECOND:1,SECOND:2,MINUTE:3,HOUR:4,DAY:5,WEEKDAY:6,MONTH:7,YEAR:8},TimeStep.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)},TimeStep.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},TimeStep.prototype.roundToMinor=function(){switch(this.scale){case TimeStep.SCALE.YEAR:this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case TimeStep.SCALE.MONTH:this.current.setDate(1);case TimeStep.SCALE.DAY:case TimeStep.SCALE.WEEKDAY:this.current.setHours(0);case TimeStep.SCALE.HOUR:this.current.setMinutes(0);case TimeStep.SCALE.MINUTE:this.current.setSeconds(0);case TimeStep.SCALE.SECOND:this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step)}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(this.current.getMonth()<6)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current=new Date(this.current.valueOf()+1e3*this.step);break;case TimeStep.SCALE.MINUTE:this.current=new Date(this.current.valueOf()+1e3*this.step*60);break;case TimeStep.SCALE.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 TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}else switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()+this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()+this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()+this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},TimeStep.prototype.setAutoScale=function(t){this.autoScale=t},TimeStep.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,s=864e5,n=36e5,o=6e4,r=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*s>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*s>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),s>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),s/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*n>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),n>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1)}},TimeStep.prototype.snap=function(t){var e=new Date(t.valueOf());if(this.scale==TimeStep.SCALE.YEAR){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(this.scale==TimeStep.SCALE.MONTH)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(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){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(this.scale==TimeStep.SCALE.HOUR){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(this.scale==TimeStep.SCALE.MINUTE){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(this.scale==TimeStep.SCALE.SECOND)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(this.scale==TimeStep.SCALE.MILLISECOND){var s=this.step>5?this.step/2:1;e.setMilliseconds(Math.round(e.getMilliseconds()/s)*s)}return e},TimeStep.prototype.isMajor=function(){switch(this.scale){case TimeStep.SCALE.MILLISECOND:return 0==this.current.getMilliseconds();case TimeStep.SCALE.SECOND:return 0==this.current.getSeconds();case TimeStep.SCALE.MINUTE:return 0==this.current.getHours()&&0==this.current.getMinutes();case TimeStep.SCALE.HOUR:return 0==this.current.getHours();case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return 1==this.current.getDate();case TimeStep.SCALE.MONTH:return 0==this.current.getMonth();case TimeStep.SCALE.YEAR:return!1;default:return!1}},TimeStep.prototype.getLabelMinor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return moment(t).format("SSS");case TimeStep.SCALE.SECOND:return moment(t).format("s");case TimeStep.SCALE.MINUTE:return moment(t).format("HH:mm");case TimeStep.SCALE.HOUR:return moment(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return moment(t).format("ddd D");case TimeStep.SCALE.DAY:return moment(t).format("D");case TimeStep.SCALE.MONTH:return moment(t).format("MMM");case TimeStep.SCALE.YEAR:return moment(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return moment(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return moment(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return moment(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return moment(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return moment(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},Stack.prototype.setOptions=function(t){util.extend(this.options,t)},Stack.prototype.update=function(){this._order(),this._stack()},Stack.prototype._order=function(){var t=this.itemset.items;if(!t)throw new Error("Cannot stack items: ItemSet does not contain items");var e=[],i=0;util.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var s=this.options.order||this.defaultOptions.order;if("function"!=typeof s)throw new Error("Option order must be a function");e.sort(s),this.ordered=e},Stack.prototype._stack=function(){var t,e,i,s=this.ordered,n=this.options,o=n.orientation||this.defaultOptions.orientation,r="top"==o;for(i=n.margin&&void 0!==n.margin.item?n.margin.item:this.defaultOptions.margin.item,t=0,e=s.length;e>t;t++){var a=s[t],h=null;do h=this.checkOverlap(s,t,0,t-1,i),null!=h&&(a.top=r?h.top+h.height+i:h.top-a.height-i);while(h)}},Stack.prototype.checkOverlap=function(t,e,i,s,n){for(var o=this.collision,r=t[e],a=s;a>=i;a--){var h=t[a];if(o(r,h,n)&&a!=e)return h}return null},Stack.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},Emitter(Range.prototype),Range.prototype.setOptions=function(t){util.extend(this.options,t),null!==this.start&&null!==this.end&&this.setRange(this.start,this.end)},Range.prototype.subscribe=function(t,e,i,s){function n(t){o._onMouseWheel(t,e,s)}var o=this;if("move"==i)t.on("dragstart",function(t){o._onDragStart(t,e)}),t.on("drag",function(t){o._onDrag(t,e,s)}),t.on("dragend",function(t){o._onDragEnd(t,e)}),t.on("hold",function(){o._onHold()});else{if("zoom"!=i)throw new TypeError('Unknown event "'+i+'". Choose "move" or "zoom".');t.on("mousewheel",n),t.on("DOMMouseScroll",n),t.on("touch",function(t){o._onTouch(t)}),t.on("pinch",function(t){o._onPinch(t,e,s)})}},Range.prototype.setRange=function(t,e){var i=this._applyRange(t,e);if(i){var s={start:this.start,end:this.end};this.emit("rangechange",s),this.emit("rangechanged",s)}},Range.prototype._applyRange=function(t,e){var i,s=null!=t?util.convert(t,"Date").valueOf():this.start,n=null!=e?util.convert(e,"Date").valueOf():this.end,o=null!=this.options.max?util.convert(this.options.max,"Date").valueOf():null,r=null!=this.options.min?util.convert(this.options.min,"Date").valueOf():null;if(isNaN(s)||null===s)throw new Error('Invalid start "'+t+'"');if(isNaN(n)||null===n)throw new Error('Invalid end "'+e+'"');if(s>n&&(n=s),null!==r&&r>s&&(i=r-s,s+=i,n+=i,null!=o&&n>o&&(n=o)),null!==o&&n>o&&(i=n-o,s-=i,n-=i,null!=r&&r>s&&(s=r)),null!==this.options.zoomMin){var a=parseFloat(this.options.zoomMin);0>a&&(a=0),a>n-s&&(this.end-this.start===a?(s=this.start,n=this.end):(i=a-(n-s),s-=i/2,n+=i/2))}if(null!==this.options.zoomMax){var h=parseFloat(this.options.zoomMax);0>h&&(h=0),n-s>h&&(this.end-this.start===h?(s=this.start,n=this.end):(i=n-s-h,s+=i/2,n-=i/2))}var d=this.start!=s||this.end!=n;return this.start=s,this.end=n,d},Range.prototype.getRange=function(){return{start:this.start,end:this.end}},Range.prototype.conversion=function(t){return Range.conversion(this.start,this.end,t)},Range.conversion=function(t,e,i){return 0!=i&&e-t!=0?{offset:t,scale:i/(e-t)}:{offset:0,scale:1}};var touchParams={};Range.prototype._onDragStart=function(t,e){if(!touchParams.ignore){touchParams.start=this.start,touchParams.end=this.end;var i=e.frame;i&&(i.style.cursor="move")}},Range.prototype._onDrag=function(t,e,i){if(validateDirection(i),!touchParams.ignore){var s="horizontal"==i?t.gesture.deltaX:t.gesture.deltaY,n=touchParams.end-touchParams.start,o="horizontal"==i?e.width:e.height,r=-s/o*n;this._applyRange(touchParams.start+r,touchParams.end+r),this.emit("rangechange",{start:this.start,end:this.end})}},Range.prototype._onDragEnd=function(t,e){touchParams.ignore||(e.frame&&(e.frame.style.cursor="auto"),this.emit("rangechanged",{start:this.start,end:this.end}))},Range.prototype._onMouseWheel=function(t,e,i){validateDirection(i);var s=0;if(t.wheelDelta?s=t.wheelDelta/120:t.detail&&(s=-t.detail/3),s){var n;n=0>s?1-s/5:1/(1+s/5);var o=util.fakeGesture(this,t),r=getPointer(o.center,e.frame),a=this._pointerToDate(e,i,r);this.zoom(n,a)}t.preventDefault()},Range.prototype._onTouch=function(t){touchParams.start=this.start,touchParams.end=this.end,touchParams.ignore=!1,touchParams.center=null;var e=ItemSet.itemFromTarget(t);e&&e.selected&&this.options.editable&&(touchParams.ignore=!0)},Range.prototype._onHold=function(){touchParams.ignore=!0},Range.prototype._onPinch=function(t,e,i){if(touchParams.ignore=!0,t.gesture.touches.length>1){touchParams.center||(touchParams.center=getPointer(t.gesture.center,e.frame));var s=1/t.gesture.scale,n=this._pointerToDate(e,i,touchParams.center),o=getPointer(t.gesture.center,e.frame),r=(this._pointerToDate(e,i,o),parseInt(n+(touchParams.start-n)*s)),a=parseInt(n+(touchParams.end-n)*s);this.setRange(r,a)}},Range.prototype._pointerToDate=function(t,e,i){var s;if("horizontal"==e){var n=t.width;return s=this.conversion(n),i.x/s.scale+s.offset}var o=t.height;return s=this.conversion(o),i.y/s.scale+s.offset},Range.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2);var i=e+(this.start-e)*t,s=e+(this.end-e)*t;this.setRange(i,s)},Range.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},Range.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,s=this.start-i,n=this.end-i;this.setRange(s,n)},Emitter(Controller.prototype),Controller.prototype.add=function(t){if(void 0==t.id)throw new Error("Component has no field id");if(!(t instanceof Component||t instanceof Controller))throw new TypeError("Component must be an instance of prototype Component or Controller");t.setController(this),this.components[t.id]=t},Controller.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]===t))break;e&&(this.components[e].setController(null),delete this.components[e])},Controller.prototype.repaint=function t(){function t(s,n){n in i||(s.depends&&s.depends.forEach(function(e){t(e,e.id)}),s.parent&&t(s.parent,s.parent.id),e=s.repaint()||e,i[n]=!0)}var e=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var i={};util.forEach(this.components,t),this.emit("repaint"),e&&this.reflow()},Controller.prototype.reflow=function e(){function e(s,n){n in i||(s.depends&&s.depends.forEach(function(t){e(t,t.id)}),s.parent&&e(s.parent,s.parent.id),t=s.reflow()||t,i[n]=!0)}var t=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var i={};util.forEach(this.components,e),this.emit("reflow"),t&&this.repaint()},Component.prototype.setOptions=function(t){t&&(util.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},Component.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},Component.prototype.setController=function(t){this.controller=t||null},Component.prototype.getController=function(){return this.controller},Component.prototype.getContainer=function(){return null},Component.prototype.getFrame=function(){return this.frame},Component.prototype.repaint=function(){return!1},Component.prototype.reflow=function(){return!1},Component.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},Component.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},Component.prototype.requestRepaint=function(){if(!this.controller)throw new Error("Cannot request a repaint: no controller configured");this.controller.emit("request-repaint")},Component.prototype.requestReflow=function(){if(!this.controller)throw new Error("Cannot request a reflow: no controller configured");this.controller.emit("request-reflow")},Panel.prototype=new Component,Panel.prototype.setOptions=Component.prototype.setOptions,Panel.prototype.getContainer=function(){return this.frame},Panel.prototype.repaint=function(){var t=0,e=util.updateProperty,i=util.option.asSize,s=this.options,n=this.frame;if(!n){n=document.createElement("div"),n.className="vpanel";var o=s.className;o&&("function"==typeof o?util.addClassName(n,String(o())):util.addClassName(n,String(o))),this.frame=n,t+=1}if(!n.parentNode){if(!this.parent)throw new Error("Cannot repaint panel: no parent attached");var r=this.parent.getContainer();if(!r)throw new Error("Cannot repaint panel: parent has no container element");r.appendChild(n),t+=1}return t+=e(n.style,"top",i(s.top,"0px")),t+=e(n.style,"left",i(s.left,"0px")),t+=e(n.style,"width",i(s.width,"100%")),t+=e(n.style,"height",i(s.height,"100%")),t>0},Panel.prototype.reflow=function(){var t=0,e=util.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},RootPanel.prototype=new Panel,RootPanel.prototype.setOptions=Component.prototype.setOptions,RootPanel.prototype.repaint=function(){var t=0,e=util.updateProperty,i=util.option.asSize,s=this.options,n=this.frame;if(n||(n=document.createElement("div"),this.frame=n,this._registerListeners(),t+=1),!n.parentNode){if(!this.container)throw new Error("Cannot repaint root panel: no container attached");this.container.appendChild(n),t+=1}n.className="vis timeline rootpanel "+s.orientation+(s.editable?" editable":"");var o=s.className;return o&&util.addClassName(n,util.option.asString(o)),t+=e(n.style,"top",i(s.top,"0px")),t+=e(n.style,"left",i(s.left,"0px")),t+=e(n.style,"width",i(s.width,"100%")),t+=e(n.style,"height",i(s.height,"100%")),this._updateWatch(),t>0},RootPanel.prototype.reflow=function(){var t=0,e=util.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},RootPanel.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},RootPanel.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?void(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow()):void t._unwatch()};util.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},RootPanel.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},RootPanel.prototype.setController=function(t){this.controller=t||null,this.controller?this._registerListeners():this._unregisterListeners()},RootPanel.prototype._registerListeners=function(){if(this.frame&&this.controller&&!this.hammer){this.hammer=Hammer(this.frame,{prevent_default:!0});for(var t in this.listeners)this.listeners.hasOwnProperty(t)&&this.hammer.on(t,this.listeners[t])}},RootPanel.prototype._unregisterListeners=function(){if(this.hammer){for(var t in this.listeners)this.listeners.hasOwnProperty(t)&&this.hammer.off(t,this.listeners[t]);this.hammer=null}},TimeAxis.prototype=new Component,TimeAxis.prototype.setOptions=Component.prototype.setOptions,TimeAxis.prototype.setRange=function(t){if(!(t instanceof Range||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},TimeAxis.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},TimeAxis.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},TimeAxis.prototype.repaint=function(){var t=0,e=util.updateProperty,i=util.option.asSize,s=this.options,n=this.getOption("orientation"),o=this.props,r=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis",!a.parentNode){if(!this.parent)throw new Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw new Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var d=a.parentNode;if(d){var c=a.nextSibling;d.removeChild(a);var l="bottom"==n&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px"; -if(t+=e(a.style,"top",i(s.top,l)),t+=e(a.style,"left",i(s.left,"0px")),t+=e(a.style,"width",i(s.width,"100%")),t+=e(a.style,"height",i(s.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),r.first();for(var u=void 0,p=0;r.hasNext()&&1e3>p;){p++;var g=r.getCurrent(),f=this.toScreen(g),m=r.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(f,r.getLabelMinor()),m&&this.getOption("showMajorLabels")?(f>0&&(void 0==u&&(u=f),this._repaintMajorText(f,r.getLabelMajor())),this._repaintMajorLine(f)):this._repaintMinorLine(f),r.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=r.getLabelMajor(v),_=y.length*(o.majorCharWidth||10)+10;(void 0==u||u>_)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),c?d.insertBefore(a,c):d.appendChild(a)}return t>0},TimeAxis.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},TimeAxis.prototype._repaintEnd=function(){util.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},TimeAxis.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var s=document.createTextNode("");i=document.createElement("div"),i.appendChild(s),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},TimeAxis.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var s=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(s),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},TimeAxis.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},TimeAxis.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},TimeAxis.prototype._repaintLine=function(){{var t=this.dom.line,e=this.frame;this.options}this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&t.parentElement&&(e.removeChild(t.line),delete this.dom.line)},TimeAxis.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var s=document.createElement("DIV");s.className="text major measure",s.appendChild(t),this.frame.appendChild(s),e.measureCharMajor=s}},TimeAxis.prototype.reflow=function(){var t=0,e=util.updateProperty,i=this.frame,s=this.range;if(!s)throw new Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var n=this.props,o=this.getOption("showMinorLabels"),r=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(n.minorCharHeight=a.clientHeight,n.minorCharWidth=a.clientWidth),h&&(n.majorCharHeight=h.clientHeight,n.majorCharWidth=h.clientWidth);var d=i.parentNode?i.parentNode.offsetHeight:0;switch(d!=n.parentHeight&&(n.parentHeight=d,t+=1),this.getOption("orientation")){case"bottom":n.minorLabelHeight=o?n.minorCharHeight:0,n.majorLabelHeight=r?n.majorCharHeight:0,n.minorLabelTop=0,n.majorLabelTop=n.minorLabelTop+n.minorLabelHeight,n.minorLineTop=-this.top,n.minorLineHeight=Math.max(this.top+n.majorLabelHeight,0),n.minorLineWidth=1,n.majorLineTop=-this.top,n.majorLineHeight=Math.max(this.top+n.minorLabelHeight+n.majorLabelHeight,0),n.majorLineWidth=1,n.lineTop=0;break;case"top":n.minorLabelHeight=o?n.minorCharHeight:0,n.majorLabelHeight=r?n.majorCharHeight:0,n.majorLabelTop=0,n.minorLabelTop=n.majorLabelTop+n.majorLabelHeight,n.minorLineTop=n.minorLabelTop,n.minorLineHeight=Math.max(d-n.majorLabelHeight-this.top),n.minorLineWidth=1,n.majorLineTop=0,n.majorLineHeight=Math.max(d-this.top),n.majorLineWidth=1,n.lineTop=n.majorLabelHeight+n.minorLabelHeight;break;default:throw new Error('Unkown orientation "'+this.getOption("orientation")+'"')}var c=n.minorLabelHeight+n.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",c),this._updateConversion();var l=util.convert(s.start,"Number"),u=util.convert(s.end,"Number"),p=this.toTime(5*(n.minorCharWidth||10)).valueOf()-this.toTime(0).valueOf();this.step=new TimeStep(new Date(l),new Date(u),p),t+=e(n.range,"start",l),t+=e(n.range,"end",u),t+=e(n.range,"minimumStep",p.valueOf())}return t>0},TimeAxis.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):Range.conversion(t.start,t.end,this.width)},TimeAxis.prototype.snap=function(t){return this.step.snap(t)},CurrentTime.prototype=new Component,CurrentTime.prototype.setOptions=Component.prototype.setOptions,CurrentTime.prototype.getContainer=function(){return this.frame},CurrentTime.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCurrentTime"))return t&&(i.removeChild(t),delete this.frame),!1;t||(t=document.createElement("div"),t.className="currenttime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t),this.frame=t),e.conversion||e._updateConversion();var s=new Date,n=e.toScreen(s);t.style.left=n+"px",t.title="Current time: "+s,void 0!==this.currentTimeTimer&&(clearTimeout(this.currentTimeTimer),delete this.currentTimeTimer);var o=this,r=1/e.conversion.scale/2;return 30>r&&(r=30),this.currentTimeTimer=setTimeout(function(){o.repaint()},r),!1},CustomTime.prototype=new Component,Emitter(CustomTime.prototype),CustomTime.prototype.setOptions=Component.prototype.setOptions,CustomTime.prototype.getContainer=function(){return this.frame},CustomTime.prototype.repaint=function(){var t=this.frame,e=this.parent;if(!e)throw new Error("Cannot repaint bar: no parent attached");var i=e.parent.getContainer();if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCustomTime"))return t&&(i.removeChild(t),delete this.frame),!1;if(!t){t=document.createElement("div"),t.className="customtime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t);var s=document.createElement("div");s.style.position="relative",s.style.top="0px",s.style.left="-10px",s.style.height="100%",s.style.width="20px",t.appendChild(s),this.frame=t,this.hammer=Hammer(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))}e.conversion||e._updateConversion();var n=e.toScreen(this.customTime);return t.style.left=n+"px",t.title="Time: "+this.customTime,!1},CustomTime.prototype.setCustomTime=function(t){this.customTime=new Date(t.valueOf()),this.repaint()},CustomTime.prototype.getCustomTime=function(){return new Date(this.customTime.valueOf())},CustomTime.prototype._onDragStart=function(t){this.eventParams.customTime=this.customTime,t.stopPropagation(),t.preventDefault()},CustomTime.prototype._onDrag=function(t){var e=t.gesture.deltaX,i=this.parent.toScreen(this.eventParams.customTime)+e,s=this.parent.toTime(i);this.setCustomTime(s),this.controller&&this.controller.emit("timechange",{time:this.customTime}),t.stopPropagation(),t.preventDefault()},CustomTime.prototype._onDragEnd=function(t){this.controller&&this.controller.emit("timechanged",{time:this.customTime}),t.stopPropagation(),t.preventDefault()},ItemSet.prototype=new Panel,ItemSet.types={box:ItemBox,range:ItemRange,rangeoverflow:ItemRangeOverflow,point:ItemPoint},ItemSet.prototype.setOptions=Component.prototype.setOptions,ItemSet.prototype.setController=function(t){var e;if(this.controller)for(e in this.eventListeners)this.eventListeners.hasOwnProperty(e)&&this.controller.off(e,this.eventListeners[e]);if(this.controller=t||null,this.controller)for(e in this.eventListeners)this.eventListeners.hasOwnProperty(e)&&this.controller.on(e,this.eventListeners[e])},function(t){var e=null;Object.defineProperty(t,"controller",{get:function(){return e},set:function(){}})}(this),ItemSet.prototype.setRange=function(t){if(!(t instanceof Range||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},ItemSet.prototype.setSelection=function(t){var e,i,s,n;if(t){if(!Array.isArray(t))throw new TypeError("Array expected");for(e=0,i=this.selection.length;i>e;e++)s=this.selection[e],n=this.items[s],n&&n.unselect();for(this.selection=[],e=0,i=t.length;i>e;e++)s=t[e],n=this.items[s],n&&(this.selection.push(s),n.select());this.controller&&this.requestRepaint()}},ItemSet.prototype.getSelection=function(){return this.selection.concat([])},ItemSet.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}},ItemSet.prototype.repaint=function(){var t=0,e=util.updateProperty,i=util.option.asSize,s=this.options,n=this.getOption("orientation"),o=this.defaultOptions,r=this.frame;if(!r){r=document.createElement("div"),r.className="itemset",r["timeline-itemset"]=this;var a=s.className;a&&util.addClassName(r,util.option.asString(a));var h=document.createElement("div");h.className="background",r.appendChild(h),this.dom.background=h;var d=document.createElement("div");d.className="foreground",r.appendChild(d),this.dom.foreground=d;var c=document.createElement("div");c.className="itemset-axis",this.dom.axis=c,this.frame=r,t+=1}if(!this.parent)throw new Error("Cannot repaint itemset: no parent attached");var l=this.parent.getContainer();if(!l)throw new Error("Cannot repaint itemset: parent has no container element");r.parentNode||(l.appendChild(r),t+=1),this.dom.axis.parentNode||(l.appendChild(this.dom.axis),t+=1),t+=e(r.style,"left",i(s.left,"0px")),t+=e(r.style,"top",i(s.top,"0px")),t+=e(r.style,"width",i(s.width,"100%")),t+=e(r.style,"height",i(s.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(s.left,"0px")),t+=e(this.dom.axis.style,"width",i(s.width,"100%")),t+="bottom"==n?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var u=this,p=this.queue,g=this.itemsData,f=this.items,m={};for(var v in p)if(p.hasOwnProperty(v)){var y=p[v],_=f[v],b=y.action;switch(b){case"add":case"update":var w=g&&g.get(v,m);if(w){var S=w.type||w.start&&w.end&&"range"||s.type||"box",x=ItemSet.types[S];if(_&&(x&&_ instanceof x?(_.data=w,t++):(t+=_.hide(),_=null)),!_){if(!x)throw new TypeError('Unknown item type "'+S+'"');_=new x(u,w,s,o),_.id=y.id,t++}_.repaint(),f[v]=_}delete p[v];break;case"remove":_&&(_.selected&&u._deselect(v),t+=_.hide()),delete f[v],delete p[v];break;default:console.log('Error: unknown action "'+b+'"')}}return util.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},ItemSet.prototype.getForeground=function(){return this.dom.foreground},ItemSet.prototype.getBackground=function(){return this.dom.background},ItemSet.prototype.getAxis=function(){return this.dom.axis},ItemSet.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&"axis"in e.margin?e.margin.axis:this.defaultOptions.margin.axis,s=e.margin&&"item"in e.margin?e.margin.item:this.defaultOptions.margin.item,n=util.updateProperty,o=util.option.asNumber,r=util.option.asSize,a=this.frame;if(a){this._updateConversion(),util.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,d=o(e.maxHeight),c=null!=r(e.height);if(c)h=a.offsetHeight;else{var l=this.stack.ordered;if(l.length){var u=l[0].top,p=l[0].top+l[0].height;util.forEach(l,function(t){u=Math.min(u,t.top),p=Math.max(p,t.top+t.height)}),h=p-u+i+s}else h=i+s}null!=d&&(h=Math.min(h,d)),t+=n(this,"height",h),t+=n(this,"top",a.offsetTop),t+=n(this,"left",a.offsetLeft),t+=n(this,"width",a.offsetWidth)}else t+=1;return t>0},ItemSet.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t},ItemSet.prototype.setItems=function(t){var e,i=this,s=this.itemsData;if(t){if(!(t instanceof DataSet||t instanceof DataView))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(s&&(util.forEach(this.listeners,function(t,e){s.unsubscribe(e,t)}),e=s.getIds(),this._onRemove(e)),this.itemsData){var n=this.id;util.forEach(this.listeners,function(t,e){i.itemsData.on(e,t,n)}),e=this.itemsData.getIds(),this._onAdd(e)}},ItemSet.prototype.getItems=function(){return this.itemsData},ItemSet.prototype.removeItem=function(t){var e=this.itemsData.get(t),i=this._myDataSet();e&&this.options.onRemove(e,function(t){t&&i.remove(t)})},ItemSet.prototype._onUpdate=function(t){this._toQueue("update",t)},ItemSet.prototype._onAdd=function(t){this._toQueue("add",t)},ItemSet.prototype._onRemove=function(t){this._toQueue("remove",t)},ItemSet.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]={id:e,action:t}}),this.controller&&this.requestRepaint()},ItemSet.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):Range.conversion(t.start,t.end,this.width)},ItemSet.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},ItemSet.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},ItemSet.prototype._onDragStart=function(t){if(this.options.editable){var e=ItemSet.itemFromTarget(t),i=this;if(e&&e.selected){var s=t.target.dragLeftItem,n=t.target.dragRightItem;this.touchParams.itemProps=s?[{item:s,start:e.data.start.valueOf()}]:n?[{item:n,end:e.data.end.valueOf()}]:this.getSelection().map(function(t){var e=i.items[t],s={item:e};return"start"in e.data&&(s.start=e.data.start.valueOf()),"end"in e.data&&(s.end=e.data.end.valueOf()),s}),t.stopPropagation()}}},ItemSet.prototype._onDrag=function(t){if(this.touchParams.itemProps){var e=this.options.snap||null,i=t.gesture.deltaX,s=i/this.conversion.scale;this.touchParams.itemProps.forEach(function(t){if("start"in t){var i=new Date(t.start+s);t.item.data.start=e?e(i):i}if("end"in t){var n=new Date(t.end+s);t.item.data.end=e?e(n):n}}),this.requestReflow(),t.stopPropagation()}},ItemSet.prototype._onDragEnd=function(t){if(this.touchParams.itemProps){var e=[],i=this,s=this._myDataSet();this.touchParams.itemProps.forEach(function(t){var n=t.item.id,o=i.itemsData.get(n),r=!1;"start"in t.item.data&&(r=t.start!=t.item.data.start.valueOf(),o.start=util.convert(t.item.data.start,s.convert.start)),"end"in t.item.data&&(r=r||t.end!=t.item.data.end.valueOf(),o.end=util.convert(t.item.data.end,s.convert.end)),r&&i.options.onMove(o,function(s){s?e.push(s):("start"in t&&(t.item.data.start=t.start),"end"in t&&(t.item.data.end=t.end),i.requestReflow())})}),this.touchParams.itemProps=null,e.length&&s.update(e),t.stopPropagation()}},ItemSet.itemFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-item"))return e["timeline-item"];e=e.parentNode}return null},ItemSet.itemSetFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-itemset"))return e["timeline-itemset"];e=e.parentNode}return null},ItemSet.prototype._myDataSet=function(){for(var t=this.itemsData;t instanceof DataView;)t=t.data;return t},Item.prototype.select=function(){this.selected=!0,this.visible&&this.repaint()},Item.prototype.unselect=function(){this.selected=!1,this.visible&&this.repaint()},Item.prototype.show=function(){return!1},Item.prototype.hide=function(){return!1},Item.prototype.repaint=function(){return!1},Item.prototype.reflow=function(){return!1},Item.prototype.setOffset=function(t){this.offset=t},Item.prototype._repaintDeleteButton=function(t){if(this.selected&&this.options.editable&&!this.dom.deleteButton){var e=this.parent,i=this.id,s=document.createElement("div");s.className="delete",s.title="Delete this item",Hammer(s,{preventDefault:!0}).on("tap",function(t){e.removeItem(i),t.stopPropagation()}),t.appendChild(s),this.dom.deleteButton=s}else!this.selected&&this.dom.deleteButton&&(this.dom.deleteButton.parentNode&&this.dom.deleteButton.parentNode.removeChild(this.dom.deleteButton),this.dom.deleteButton=null)},ItemBox.prototype=new Item(null,null),ItemBox.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");if(!e.box.parentNode){var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");i.appendChild(e.box),t=!0}if(!e.line.parentNode){var s=this.parent.getBackground();if(!s)throw new Error("Cannot repaint time axis: parent has no background container element");s.appendChild(e.line),t=!0}if(!e.dot.parentNode){var n=this.parent.getAxis();if(!s)throw new Error("Cannot repaint time axis: parent has no axis container element");n.appendChild(e.dot),t=!0}if(this._repaintDeleteButton(e.box),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var o=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=o&&(this.className=o,e.box.className="item box"+o,e.line.className="item line"+o,e.dot.className="item dot"+o,t=!0)}return t},ItemBox.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},ItemBox.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},ItemBox.prototype.reflow=function(){var t,e,i,s,n,o,r,a,h,d,c,l,u=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(c=this.data,l=this.parent&&this.parent.range,c&&l){var p=l.end-l.start;this.visible=c.start>l.start-p&&c.start0},ItemBox.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot",t.box["timeline-item"]=this)},ItemBox.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var s=t.box,n=t.line,o=t.dot;s.style.left=this.left+"px",s.style.top=this.top+"px",n.style.left=e.line.left+"px","top"==i?(n.style.top="0px",n.style.height=this.top+"px"):(n.style.top=this.top+this.height+"px",n.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),o.style.left=e.dot.left+"px",o.style.top=e.dot.top+"px"}},ItemPoint.prototype=new Item(null,null),ItemPoint.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}this._repaintDeleteButton(e.point);var s=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=s&&(this.className=s,e.point.className="item point"+s,t=!0)}return t},ItemPoint.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},ItemPoint.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},ItemPoint.prototype.reflow=function(){var t,e,i,s,n,o,r,a,h,d,c=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(h=this.data,d=this.parent&&this.parent.range,h&&d){var l=d.end-d.start;this.visible=h.start>d.start-l&&h.start0},ItemPoint.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot),t.point["timeline-item"]=this)},ItemPoint.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},ItemRange.prototype=new Item(null,null),ItemRange.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}this._repaintDeleteButton(e.box),this._repaintDragLeft(),this._repaintDragRight();var s=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=s&&(this.className=s,e.box.className="item range"+s,t=!0)}return t},ItemRange.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},ItemRange.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},ItemRange.prototype.reflow=function(){var t,e,i,s,n,o,r,a,h,d,c,l,u,p,g,f,m=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw new Error('Property "end" missing in item '+this.data.id);return h=this.data,d=this.parent&&this.parent.range,this.visible=h&&d?h.startd.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,o=this.parent,r=o.toScreen(this.data.start)+this.offset,a=o.toScreen(this.data.end)+this.offset,c=util.updateProperty,l=t.box,u=o.width,g=i.orientation||this.defaultOptions.orientation,s=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,n=i.padding||this.defaultOptions.padding,m+=c(e.content,"width",t.content.offsetWidth),m+=c(this,"height",l.offsetHeight),-u>r&&(r=-u),a>2*u&&(a=2*u),p=0>r?Math.min(-r,a-r-e.content.width-2*n):0,m+=c(e.content,"left",p),"top"==g?(f=s,m+=c(this,"top",f)):(f=o.height-this.height-s,m+=c(this,"top",f)),m+=c(this,"left",r),m+=c(this,"width",Math.max(a-r,1))):m+=1),m>0},ItemRange.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content),t.box["timeline-item"]=this)},ItemRange.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},ItemRange.prototype._repaintDragLeft=function(){if(this.selected&&this.options.editable&&!this.dom.dragLeft){var t=document.createElement("div");t.className="drag-left",t.dragLeftItem=this,Hammer(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)},ItemRange.prototype._repaintDragRight=function(){if(this.selected&&this.options.editable&&!this.dom.dragRight){var t=document.createElement("div");t.className="drag-right",t.dragRightItem=this,Hammer(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)},ItemRangeOverflow.prototype=new ItemRange(null,null),ItemRangeOverflow.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.id);e.content.innerHTML=this.content}t=!0}this._repaintDeleteButton(e.box),this._repaintDragLeft(),this._repaintDragRight();var s=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=s&&(this.className=s,e.box.className="item rangeoverflow"+s,t=!0)}return t},ItemRangeOverflow.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this._width+"px",t.content.style.left=e.content.left+"px")},Group.prototype=new Component,Group.prototype.setOptions=Component.prototype.setOptions,Group.prototype.getContainer=function(){return this.parent.getContainer()},Group.prototype.setItems=function(t){if(this.itemset&&(this.itemset.hide(),this.itemset.setItems(),this.parent.controller.remove(this.itemset),this.itemset=null),t){var e=this.groupId,i=Object.create(this.options);this.itemset=new ItemSet(this,null,i),this.itemset.setRange(this.parent.range),this.view=new DataView(t,{filter:function(t){return t.group==e}}),this.itemset.setItems(this.view),this.parent.controller.add(this.itemset)}},Group.prototype.setSelection=function(t){this.itemset&&this.itemset.setSelection(t)},Group.prototype.getSelection=function(){return this.itemset?this.itemset.getSelection():[]},Group.prototype.repaint=function(){return!1},Group.prototype.reflow=function(){var t=0,e=util.updateProperty;if(t+=e(this,"top",this.itemset?this.itemset.top:0),t+=e(this,"height",this.itemset?this.itemset.height:0),this.label){var i=this.label.firstChild;t+=e(this.props.label,"width",i.clientWidth),t+=e(this.props.label,"height",i.clientHeight)}else t+=e(this.props.label,"width",0),t+=e(this.props.label,"height",0);return t>0},GroupSet.prototype=new Panel,GroupSet.prototype.setOptions=Component.prototype.setOptions,GroupSet.prototype.setRange=function(){},GroupSet.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},GroupSet.prototype.getItems=function(){return this.itemsData},GroupSet.prototype.setRange=function(t){this.range=t},GroupSet.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(util.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof DataSet?this.groupsData=t:(this.groupsData=new DataSet({convert:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var s=this.id;util.forEach(this.listeners,function(t,e){i.groupsData.on(e,t,s)}),e=this.groupsData.getIds(),this._onAdd(e)}},GroupSet.prototype.getGroups=function(){return this.groupsData},GroupSet.prototype.setSelection=function(t){var e=[],i=this.groups;for(var s in i)if(i.hasOwnProperty(s)){var n=i[s];n.setSelection(t)}return e},GroupSet.prototype.getSelection=function(){var t=[],e=this.groups;for(var i in e)if(e.hasOwnProperty(i)){var s=e[i];t=t.concat(s.getSelection())}return t},GroupSet.prototype.repaint=function(){var t,e,i,s,n=0,o=util.updateProperty,r=util.option.asSize,a=util.option.asElement,h=this.options,d=this.dom.frame,c=this.dom.labels,l=this.dom.labelSet;if(!this.parent)throw new Error("Cannot repaint groupset: no parent attached");var u=this.parent.getContainer();if(!u)throw new Error("Cannot repaint groupset: parent has no container element");if(!d){d=document.createElement("div"),d.className="groupset",d["timeline-groupset"]=this,this.dom.frame=d;var p=h.className;p&&util.addClassName(d,util.option.asString(p)),n+=1}d.parentNode||(u.appendChild(d),n+=1);var g=a(h.labelContainer);if(!g)throw new Error('Cannot repaint groupset: option "labelContainer" not defined');c||(c=document.createElement("div"),c.className="labels",this.dom.labels=c),l||(l=document.createElement("div"),l.className="label-set",c.appendChild(l),this.dom.labelSet=l),c.parentNode&&c.parentNode==g||(c.parentNode&&c.parentNode.removeChild(c.parentNode),g.appendChild(c)),n+=o(d.style,"height",r(h.height,this.height+"px")),n+=o(d.style,"top",r(h.top,"0px")),n+=o(d.style,"left",r(h.left,"0px")),n+=o(d.style,"width",r(h.width,"100%")),n+=o(l.style,"top",r(h.top,"0px")),n+=o(l.style,"height",r(h.height,this.height+"px")); -var f=this,m=this.queue,v=this.groups,y=this.groupsData,_=Object.keys(m);if(_.length){_.forEach(function(t){var e=m[t],i=v[t];switch(e){case"add":case"update":if(!i){var s=Object.create(f.options);util.extend(s,{height:null,maxHeight:null}),i=new Group(f,t,s),i.setItems(f.itemsData),v[t]=i,f.controller.add(i)}i.data=y.get(t),delete m[t];break;case"remove":i&&(i.setItems(),delete v[t],f.controller.remove(i)),delete m[t];break;default:console.log('Error: unknown action "'+e+'"')}});var b=this.groupsData.getIds({order:this.options.groupOrder});for(t=0;t0},GroupSet.prototype._createLabel=function(t){var e=this.groups[t],i=document.createElement("div");i.className="vlabel";var s=document.createElement("div");s.className="inner",i.appendChild(s);var n=e.data&&e.data.content;n instanceof Element?s.appendChild(n):void 0!=n&&(s.innerHTML=n);var o=e.data&&e.data.className;return o&&util.addClassName(i,o),e.label=i,i},GroupSet.prototype.getContainer=function(){return this.dom.frame},GroupSet.prototype.getLabelsWidth=function(){return this.props.labels.width},GroupSet.prototype.reflow=function(){var t,e,i=0,s=this.options,n=util.updateProperty,o=util.option.asNumber,r=util.option.asSize,a=this.dom.frame;if(a){var h,d=o(s.maxHeight),c=null!=r(s.height);if(c)h=a.offsetHeight;else{h=0;for(t in this.groups)this.groups.hasOwnProperty(t)&&(e=this.groups[t],h+=e.height)}null!=d&&(h=Math.min(h,d)),i+=n(this,"height",h),i+=n(this,"top",a.offsetTop),i+=n(this,"left",a.offsetLeft),i+=n(this,"width",a.offsetWidth)}var l=0;for(t in this.groups)if(this.groups.hasOwnProperty(t)){e=this.groups[t];var u=e.props&&e.props.label&&e.props.label.width||0;l=Math.max(l,u)}return i+=n(this.props.labels,"width",l),i>0},GroupSet.prototype.hide=function(){return this.dom.frame&&this.dom.frame.parentNode?(this.dom.frame.parentNode.removeChild(this.dom.frame),!0):!1},GroupSet.prototype.show=function(){return this.dom.frame&&this.dom.frame.parentNode?!1:this.repaint()},GroupSet.prototype._onUpdate=function(t){this._toQueue(t,"update")},GroupSet.prototype._onAdd=function(t){this._toQueue(t,"add")},GroupSet.prototype._onRemove=function(t){this._toQueue(t,"remove")},GroupSet.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},GroupSet.groupFromTarget=function(t){for(var e,i=t.target;i;){if(i.hasOwnProperty("timeline-groupset")){e=i["timeline-groupset"];break}i=i.parentNode}if(e)for(var s in e.groups)if(e.groups.hasOwnProperty(s)){var n=e.groups[s];if(n.itemset&&ItemSet.itemSetFromTarget(t)==n.itemset)return n}return null},Timeline.prototype.on=function(t,e){this.controller.on(t,e)},Timeline.prototype.off=function(t,e){this.controller.off(t,e)},Timeline.prototype.setOptions=function(t){util.extend(this.options,t),this.range.setRange(t.start,t.end),("editable"in t||"selectable"in t)&&this.setSelection(this.options.selectable?this.getSelection():[]);var e=function(t){if(!(this.options[t]instanceof Function)||2!=this.options[t].length)throw new Error("option "+t+" must be a function "+t+"(item, callback)")}.bind(this);["onAdd","onUpdate","onRemove","onMove"].forEach(e),this.controller.reflow(),this.controller.repaint()},Timeline.prototype.setCustomTime=function(t){if(!this.customtime)throw new Error("Cannot get custom time: Custom time bar is not enabled");this.customtime.setCustomTime(t)},Timeline.prototype.getCustomTime=function(){if(!this.customtime)throw new Error("Cannot get custom time: Custom time bar is not enabled");return this.customtime.getCustomTime()},Timeline.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof DataSet&&(e=t):e=null,t instanceof DataSet||(e=new DataSet({convert:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var s=this.getItemRange(),n=s.min,o=s.max;if(null!=n&&null!=o){var r=o.valueOf()-n.valueOf();0>=r&&(r=864e5),n=new Date(n.valueOf()-.05*r),o=new Date(o.valueOf()+.05*r)}void 0!=this.options.start&&(n=util.convert(this.options.start,"Date")),void 0!=this.options.end&&(o=util.convert(this.options.end,"Date")),(null!=n||null!=o)&&this.range.setRange(n,o)}},Timeline.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?GroupSet:ItemSet;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var s=Object.create(this.options);util.extend(s,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.itemPanel.height-e.timeaxis.height-e.content.height},left:null,width:"100%",height:function(){return e.options.height?e.itemPanel.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!util.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null},labelContainer:function(){return e.labelPanel.getContainer()}}),this.content=new i(this.itemPanel,[this.timeaxis],s),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},Timeline.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var s=t.min("start");e=s?s.start.valueOf():null;var n=t.max("start");n&&(i=n.start.valueOf());var o=t.max("end");o&&(i=null==i?o.end.valueOf():Math.max(i,o.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},Timeline.prototype.setSelection=function(t){this.content&&this.content.setSelection(t)},Timeline.prototype.getSelection=function(){return this.content?this.content.getSelection():[]},Timeline.prototype.setWindow=function(t,e){this.range.setRange(t,e)},Timeline.prototype.getWindow=function(){var t=this.range.getRange();return{start:new Date(t.start),end:new Date(t.end)}},Timeline.prototype._onSelectItem=function(t){if(this.options.selectable){var e=t.gesture.srcEvent&&t.gesture.srcEvent.ctrlKey,i=t.gesture.srcEvent&&t.gesture.srcEvent.shiftKey;if(e||i)return void this._onMultiSelectItem(t);var s=ItemSet.itemFromTarget(t),n=s?[s.id]:[];this.setSelection(n),this.controller.emit("select",{items:this.getSelection()}),t.stopPropagation()}},Timeline.prototype._onAddItem=function(t){if(this.options.selectable&&this.options.editable){var e=this,i=ItemSet.itemFromTarget(t);if(i){var s=e.itemsData.get(i.id);this.options.onUpdate(s,function(t){t&&e.itemsData.update(t)})}else{var n=vis.util.getAbsoluteLeft(this.rootPanel.frame),o=t.gesture.center.pageX-n,r={start:this.timeaxis.snap(this._toTime(o)),content:"new item"},a=util.randomUUID();r[this.itemsData.fieldId]=a;var h=GroupSet.groupFromTarget(t);h&&(r.group=h.groupId),this.options.onAdd(r,function(t){t&&(e.itemsData.add(r),e.controller.once("repaint",function(){e.setSelection([a]),e.controller.emit("select",{items:e.getSelection()})}.bind(e)))})}}},Timeline.prototype._onMultiSelectItem=function(t){if(this.options.selectable){var e,i=ItemSet.itemFromTarget(t);if(i){e=this.getSelection();var s=e.indexOf(i.id);-1==s?e.push(i.id):e.splice(s,1),this.setSelection(e),this.controller.emit("select",{items:this.getSelection()}),t.stopPropagation()}}},Timeline.prototype._toTime=function(t){var e=this.range.conversion(this.content.width);return new Date(t/e.scale+e.offset)},Timeline.prototype._toScreen=function(t){var e=this.range.conversion(this.content.width);return(t.valueOf()-e.offset)*e.scale},function(t){function e(t){return D=t,u()}function i(){C=0,M=D.charAt(0)}function s(){C++,M=D.charAt(C)}function n(){return D.charAt(C+1)}function o(t){return O.test(t)}function r(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t,e,i){for(var s=e.split("."),n=t;s.length;){var o=s.shift();s.length?(n[o]||(n[o]={}),n=n[o]):n[o]=i}}function h(t,e){for(var i,s,n=null,o=[t],a=t;a.parent;)o.push(a.parent),a=a.parent;if(a.nodes)for(i=0,s=a.nodes.length;s>i;i++)if(e.id===a.nodes[i].id){n=a.nodes[i];break}for(n||(n={id:e.id},t.node&&(n.attr=r(n.attr,t.node))),i=o.length-1;i>=0;i--){var h=o[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(n)&&h.nodes.push(n)}e.attr&&(n.attr=r(n.attr,e.attr))}function d(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=r({},t.edge);e.attr=r(i,e.attr)}}function c(t,e,i,s,n){var o={from:e,to:i,type:s};return t.edge&&(o.attr=r({},t.edge)),o.attr=r(o.attr||{},n),o}function l(){for(N=E.NULL,I="";" "==M||" "==M||"\n"==M||"\r"==M;)s();do{var t=!1;if("#"==M){for(var e=C-1;" "==D.charAt(e)||" "==D.charAt(e);)e--;if("\n"==D.charAt(e)||""==D.charAt(e)){for(;""!=M&&"\n"!=M;)s();t=!0}}if("/"==M&&"/"==n()){for(;""!=M&&"\n"!=M;)s();t=!0}if("/"==M&&"*"==n()){for(;""!=M;){if("*"==M&&"/"==n()){s(),s();break}s()}t=!0}for(;" "==M||" "==M||"\n"==M||"\r"==M;)s()}while(t);if(""==M)return void(N=E.DELIMITER);var i=M+n();if(T[i])return N=E.DELIMITER,I=i,s(),void s();if(T[M])return N=E.DELIMITER,I=M,void s();if(o(M)||"-"==M){for(I+=M,s();o(M);)I+=M,s();return"false"==I?I=!1:"true"==I?I=!0:isNaN(Number(I))||(I=Number(I)),void(N=E.IDENTIFIER)}if('"'==M){for(s();""!=M&&('"'!=M||'"'==M&&'"'==n());)I+=M,'"'==M&&s(),s();if('"'!=M)throw b('End of string " expected');return s(),void(N=E.IDENTIFIER)}for(N=E.UNKNOWN;""!=M;)I+=M,s();throw new SyntaxError('Syntax error in part "'+w(I,30)+'"')}function u(){var t={};if(i(),l(),"strict"==I&&(t.strict=!0,l()),("graph"==I||"digraph"==I)&&(t.type=I,l()),N==E.IDENTIFIER&&(t.id=I,l()),"{"!=I)throw b("Angle bracket { expected");if(l(),p(t),"}"!=I)throw b("Angle bracket } expected");if(l(),""!==I)throw b("End of file expected");return l(),delete t.node,delete t.edge,delete t.graph,t}function p(t){for(;""!==I&&"}"!=I;)g(t),";"==I&&l()}function g(t){var e=f(t);if(e)return void y(t,e);var i=m(t);if(!i){if(N!=E.IDENTIFIER)throw b("Identifier expected");var s=I;if(l(),"="==I){if(l(),N!=E.IDENTIFIER)throw b("Identifier expected");t[s]=I,l()}else v(t,s)}}function f(t){var e=null;if("subgraph"==I&&(e={},e.type="subgraph",l(),N==E.IDENTIFIER&&(e.id=I,l())),"{"==I){if(l(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,p(e),"}"!=I)throw b("Angle bracket } expected");l(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function m(t){return"node"==I?(l(),t.node=_(),"node"):"edge"==I?(l(),t.edge=_(),"edge"):"graph"==I?(l(),t.graph=_(),"graph"):null}function v(t,e){var i={id:e},s=_();s&&(i.attr=s),h(t,i),y(t,e)}function y(t,e){for(;"->"==I||"--"==I;){var i,s=I;l();var n=f(t);if(n)i=n;else{if(N!=E.IDENTIFIER)throw b("Identifier or subgraph expected");i=I,h(t,{id:i}),l()}var o=_(),r=c(t,e,i,s,o);d(t,r),e=i}}function _(){for(var t=null;"["==I;){for(l(),t={};""!==I&&"]"!=I;){if(N!=E.IDENTIFIER)throw b("Attribute name expected");var e=I;if(l(),"="!=I)throw b("Equal sign = expected");if(l(),N!=E.IDENTIFIER)throw b("Attribute value expected");var i=I;a(t,e,i),l(),","==I&&l()}if("]"!=I)throw b("Bracket ] expected");l()}return t}function b(t){return new SyntaxError(t+', got "'+w(I,30)+'" (char '+C+")")}function w(t,e){return t.length<=e?t:t.substr(0,27)+"..."}function S(t,e,i){t instanceof Array?t.forEach(function(t){e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}):e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}function x(t){function i(t){var e={from:t.from,to:t.to};return r(e,t.attr),e.style="->"==t.type?"arrow":"line",e}var s=e(t),n={nodes:[],edges:[],options:{}};return s.nodes&&s.nodes.forEach(function(t){var e={id:t.id,label:String(t.label||t.id)};r(e,t.attr),e.image&&(e.shape="image"),n.nodes.push(e)}),s.edges&&s.edges.forEach(function(t){var e,s;e=t.from instanceof Object?t.from.nodes:{id:t.from},s=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=i(t);n.edges.push(e)}),S(e,s,function(e,s){var o=c(n,e.id,s.id,t.type,t.attr),r=i(o);n.edges.push(r)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=i(t);n.edges.push(e)})}),s.attr&&(n.options=s.attr),n}var E={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},T={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},D="",C=0,M="",I="",N=E.NULL,O=/[a-zA-Z_0-9.:#]/;t.parseDOT=e,t.DOTToGraph=x}("undefined"!=typeof util?util:exports),"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,n=s/2,o=Math.sqrt(3)/6*s,r=Math.sqrt(s*s-n*n);this.moveTo(t,e-(r-o)),this.lineTo(t+n,e+o),this.lineTo(t-n,e+o),this.lineTo(t,e-(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var s=2*i,n=s/2,o=Math.sqrt(3)/6*s,r=Math.sqrt(s*s-n*n);this.moveTo(t,e+(r-o)),this.lineTo(t+n,e-o),this.lineTo(t-n,e-o),this.lineTo(t,e+(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var s=0;10>s;s++){var n=s%2===0?1.3*i:.5*i;this.lineTo(t+n*Math.sin(2*s*Math.PI/10),e-n*Math.cos(2*s*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,s,n){var o=Math.PI/180;0>i-2*n&&(n=i/2),0>s-2*n&&(n=s/2),this.beginPath(),this.moveTo(t+n,e),this.lineTo(t+i-n,e),this.arc(t+i-n,e+n,n,270*o,360*o,!1),this.lineTo(t+i,e+s-n),this.arc(t+i-n,e+s-n,n,0,90*o,!1),this.lineTo(t+n,e+s),this.arc(t+n,e+s-n,n,90*o,180*o,!1),this.lineTo(t,e+n),this.arc(t+n,e+n,n,180*o,270*o,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,s){var n=.5522848,o=i/2*n,r=s/2*n,a=t+i,h=e+s,d=t+i/2,c=e+s/2;this.beginPath(),this.moveTo(t,c),this.bezierCurveTo(t,c-r,d-o,e,d,e),this.bezierCurveTo(d+o,e,a,c-r,a,c),this.bezierCurveTo(a,c+r,d+o,h,d,h),this.bezierCurveTo(d-o,h,t,c+r,t,c)},CanvasRenderingContext2D.prototype.database=function(t,e,i,s){var n=1/3,o=i,r=s*n,a=.5522848,h=o/2*a,d=r/2*a,c=t+o,l=e+r,u=t+o/2,p=e+r/2,g=e+(s-r/2),f=e+s;this.beginPath(),this.moveTo(c,p),this.bezierCurveTo(c,p+d,u+h,l,u,l),this.bezierCurveTo(u-h,l,t,p+d,t,p),this.bezierCurveTo(t,p-d,u-h,e,u,e),this.bezierCurveTo(u+h,e,c,p-d,c,p),this.lineTo(c,g),this.bezierCurveTo(c,g+d,u+h,f,u,f),this.bezierCurveTo(u-h,f,t,g+d,t,g),this.lineTo(t,p)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,s){var n=t-s*Math.cos(i),o=e-s*Math.sin(i),r=t-.9*s*Math.cos(i),a=e-.9*s*Math.sin(i),h=n+s/3*Math.cos(i+.5*Math.PI),d=o+s/3*Math.sin(i+.5*Math.PI),c=n+s/3*Math.cos(i-.5*Math.PI),l=o+s/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,d),this.lineTo(r,a),this.lineTo(c,l),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,s,n){n||(n=[10,5]),0==u&&(u=.001);var o=n.length;this.moveTo(t,e);for(var r=i-t,a=s-e,h=a/r,d=Math.sqrt(r*r+a*a),c=0,l=!0;d>=.1;){var u=n[c++%o];u>d&&(u=d);var p=Math.sqrt(u*u/(1+h*h));0>r&&(p=-p),t+=p,e+=h*p,this[l?"lineTo":"moveTo"](t,e),d-=u,l=!l}}),Node.prototype.resetCluster=function(){this.formationScale=void 0,this.clusterSize=1,this.containedNodes={},this.containedEdges={},this.clusterSessions=[]},Node.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},Node.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&(this.edges.splice(e,1),this.dynamicEdges.splice(e,1)),this.dynamicEdgesLength=this.dynamicEdges.length},Node.prototype.setProperties=function(t,e){if(t){if(this.originalLabel=void 0,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.group&&(this.group=t.group),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.mass&&(this.mass=t.mass),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(this.group){var i=this.grouplist.get(this.group);for(var s in i)i.hasOwnProperty(s)&&(this[s]=i[s])}if(void 0!==t.shape&&(this.shape=t.shape),void 0!==t.image&&(this.image=t.image),void 0!==t.radius&&(this.radius=t.radius),void 0!==t.color&&(this.color=util.parseColor(t.color)),void 0!==t.fontColor&&(this.fontColor=t.fontColor),void 0!==t.fontSize&&(this.fontSize=t.fontSize),void 0!==t.fontFace&&(this.fontFace=t.fontFace),void 0!==this.image&&""!=this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!==t.x&&!t.allowedToMoveX,this.yFixed=this.yFixed||void 0!==t.y&&!t.allowedToMoveY,this.radiusFixed=this.radiusFixed||void 0!==t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.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"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()}},Node.prototype.select=function(){this.selected=!0,this._reset()},Node.prototype.unselect=function(){this.selected=!1,this._reset()},Node.prototype.clearSizeCache=function(){this._reset()},Node.prototype._reset=function(){this.width=void 0,this.height=void 0},Node.prototype.getTitle=function(){return"function"==typeof this.title?this.title():this.title},Node.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var s=this.width/2,n=this.height/2,o=Math.sin(e)*s,r=Math.cos(e)*n;return s*n/Math.sqrt(o*o+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}},Node.prototype._setForce=function(t,e){this.fx=t,this.fy=e},Node.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},Node.prototype.discreteStep=function(t){if(!this.xFixed){var e=this.damping*this.vx,i=(this.fx-e)/this.mass;this.vx+=i*t,this.x+=this.vx*t}if(!this.yFixed){var s=this.damping*this.vy,n=(this.fy-s)/this.mass;this.vy+=n*t,this.y+=this.vy*t}},Node.prototype.discreteStepLimited=function(t,e){if(this.xFixed)this.fx=0;else{var i=this.damping*this.vx,s=(this.fx-i)/this.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;else{var n=this.damping*this.vy,o=(this.fy-n)/this.mass;this.vy+=o*t,this.vy=Math.abs(this.vy)>e?this.vy>0?e:-e:this.vy,this.y+=this.vy*t}},Node.prototype.isFixed=function(){return this.xFixed&&this.yFixed},Node.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t},Node.prototype.isSelected=function(){return this.selected},Node.prototype.getValue=function(){return this.value},Node.prototype.getDistance=function(t,e){var i=this.x-t,s=this.y-e;return Math.sqrt(i*i+s*s)},Node.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value)if(e==t)this.radius=(this.radiusMin+this.radiusMax)/2;else{var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}this.baseRadiusValue=this.radius},Node.prototype.draw=function(){throw"Draw method not initialized for node"},Node.prototype.resize=function(){throw"Resize method not initialized for node"},Node.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},Node.prototype._resizeImage=function(){if(!this.width||!this.height){var t,e;if(this.value){this.radius=this.baseRadiusValue;var i=this.imageObj.height/this.imageObj.width;void 0!==i?(t=this.radius||this.imageObj.width,e=this.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.radius+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-t)}},Node.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;if(0!=this.imageObj.width){if(this.clusterSize>1){var i=this.clusterSize>1?10:0;i*=this.graphScaleInv,i=Math.min(.2*this.width,i),t.globalAlpha=.5,t.drawImage(this.imageObj,this.left-i,this.top-i,this.width+2*i,this.height+2*i)}t.globalAlpha=1,t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2}else e=this.y;this._label(t,this.label,this.x,e,void 0,"top")},Node.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)}},Node.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=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*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.radius),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.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.radius+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-s}},Node.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=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*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?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),s=Math.max(i.width,i.height)+2*e;this.radius=s/2,this.width=s,this.height=s,this.radius+=.5*Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.radius-.5*s}},Node.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.circle(this.x,this.y,this.radius+2*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.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?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*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?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.ellipse(this.left,this.top,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._drawDot=function(t){this._drawShape(t,"circle")},Node.prototype._drawTriangle=function(t){this._drawShape(t,"triangle")},Node.prototype._drawTriangleDown=function(t){this._drawShape(t,"triangleDown")},Node.prototype._drawSquare=function(t){this._drawShape(t,"square")},Node.prototype._drawStar=function(t){this._drawShape(t,"star")},Node.prototype._resizeShape=function(){if(!this.width){this.radius=this.baseRadiusValue;var t=2*this.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.radius+=.5*Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-t}},Node.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=2,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.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?s:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t[e](this.x,this.y,this.radius+n*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?s:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t[e](this.x,this.y,this.radius),t.fill(),t.stroke(),this.label&&this._label(t,this.label,this.x,this.y+this.height/2,void 0,"top")},Node.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.radius+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-(i.width+2*e)}},Node.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)},Node.prototype._label=function(t,e,i,s,n,o){if(e&&this.fontSize*this.graphScale>this.fontDrawThreshold){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle=this.fontColor||"black",t.textAlign=n||"center",t.textBaseline=o||"middle";for(var r=e.split("\n"),a=r.length,h=this.fontSize+4,d=s+(1-a)/2*h,c=0;a>c;c++)t.fillText(r[c],i,d),d+=h}},Node.prototype.getTextSize=function(t){if(void 0!==this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,s=0,n=0,o=e.length;o>n;n++)s=Math.max(s,t.measureText(e[n]).width);return{width:s,height:i}}return{width:0,height:0}},Node.prototype.inArea=function(){return void 0!==this.width?this.x+this.width*this.graphScaleInv>=this.canvasTopLeft.x&&this.x-this.width*this.graphScaleInv=this.canvasTopLeft.y&&this.y-this.height*this.graphScaleInv=this.canvasTopLeft.x&&this.x=this.canvasTopLeft.y&&this.yh}return!1},Edge.prototype._drawLine=function(t){if(t.strokeStyle=1==this.selected?this.color.highlight:this.color.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var e;if(this.label){if(1==this.smooth){var i=.5*(.5*(this.from.x+this.via.x)+.5*(this.to.x+this.via.x)),s=.5*(.5*(this.from.y+this.via.y)+.5*(this.to.y+this.via.y));e={x:i,y:s}}else e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}}else{var n,o,r=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(n=a.x+a.width/2,o=a.y-r):(n=a.x+r,o=a.y-a.height/2),this._circle(t,n,o,r),e=this._pointOnCircle(n,o,r,.5),this._label(t,this.label,e.x,e.y)}},Edge.prototype._getLineWidth=function(){return 1==this.selected?Math.min(2*this.width,this.widthMax)*this.graphScaleInv:this.width*this.graphScaleInv},Edge.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),1==this.smooth?t.quadraticCurveTo(this.via.x,this.via.y,this.to.x,this.to.y):t.lineTo(this.to.x,this.to.y),t.stroke()},Edge.prototype._circle=function(t,e,i,s){t.beginPath(),t.arc(e,i,s,0,2*Math.PI,!1),t.stroke()},Edge.prototype._label=function(t,e,i,s){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle=this.fontFill;var n=t.measureText(e).width,o=this.fontSize,r=i-n/2,a=s-o/2;t.fillRect(r,a,n,o),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,r,a)}},Edge.prototype._drawDashLine=function(t){if(t.strokeStyle=1==this.selected?this.color.highlight:this.color.color,t.lineWidth=this._getLineWidth(),void 0!==t.mozDash||void 0!==t.setLineDash){t.beginPath(),t.moveTo(this.from.x,this.from.y);var e=[0];e=void 0!==this.dash.length&&void 0!==this.dash.gap?[this.dash.length,this.dash.gap]:[5,5],"undefined"!=typeof t.setLineDash?(t.setLineDash(e),t.lineDashOffset=0):(t.mozDash=e,t.mozDashOffset=0),1==this.smooth?t.quadraticCurveTo(this.via.x,this.via.y,this.to.x,this.to.y):t.lineTo(this.to.x,this.to.y),t.stroke(),"undefined"!=typeof t.setLineDash?(t.setLineDash([0]),t.lineDashOffset=0):(t.mozDash=[0],t.mozDashOffset=0)}else t.beginPath(),t.lineCap="round",void 0!==this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!==this.dash.length&&void 0!==this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke();if(this.label){var i;if(1==this.smooth){var s=.5*(.5*(this.from.x+this.via.x)+.5*(this.to.x+this.via.x)),n=.5*(.5*(this.from.y+this.via.y)+.5*(this.to.y+this.via.y));i={x:s,y:n}}else i=this._pointOnLine(.5);this._label(t,this.label,i.x,i.y)}},Edge.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}},Edge.prototype._pointOnCircle=function(t,e,i,s){var n=2*(s-3/8)*Math.PI;return{x:t+i*Math.cos(n),y:e-i*Math.sin(n)}},Edge.prototype._drawArrowCenter=function(t){var e;if(1==this.selected?(t.strokeStyle=this.color.highlight,t.fillStyle=this.color.highlight):(t.strokeStyle=this.color.color,t.fillStyle=this.color.color),t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),s=10+5*this.width;if(1==this.smooth){var n=.5*(.5*(this.from.x+this.via.x)+.5*(this.to.x+this.via.x)),o=.5*(.5*(this.from.y+this.via.y)+.5*(this.to.y+this.via.y));e={x:n,y:o}}else e=this._pointOnLine(.5);t.arrow(e.x,e.y,i,s),t.fill(),t.stroke(),this.label&&this._label(t,this.label,e.x,e.y)}else{var r,a,h=.25*Math.max(100,this.length),d=this.from;d.width||d.resize(t),d.width>d.height?(r=d.x+.5*d.width,a=d.y-h):(r=d.x+h,a=d.y-.5*d.height),this._circle(t,r,a,h);var i=.2*Math.PI,s=10+5*this.width;e=this._pointOnCircle(r,a,h,.5),t.arrow(e.x,e.y,i,s),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(r,a,h,.5),this._label(t,this.label,e.x,e.y))}},Edge.prototype._drawArrow=function(t){1==this.selected?(t.strokeStyle=this.color.highlight,t.fillStyle=this.color.highlight):(t.strokeStyle=this.color.color,t.fillStyle=this.color.color),t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var s=this.to.x-this.from.x,n=this.to.y-this.from.y,o=Math.sqrt(s*s+n*n),r=this.from.distanceToBorder(t,e+Math.PI),a=(o-r)/o,h=a*this.from.x+(1-a)*this.to.x,d=a*this.from.y+(1-a)*this.to.y;1==this.smooth&&(e=Math.atan2(this.to.y-this.via.y,this.to.x-this.via.x),s=this.to.x-this.via.x,n=this.to.y-this.via.y,o=Math.sqrt(s*s+n*n));var c,l,u=this.to.distanceToBorder(t,e),p=(o-u)/o;if(1==this.smooth?(c=(1-p)*this.via.x+p*this.to.x,l=(1-p)*this.via.y+p*this.to.y):(c=(1-p)*this.from.x+p*this.to.x,l=(1-p)*this.from.y+p*this.to.y),t.beginPath(),t.moveTo(h,d),1==this.smooth?t.quadraticCurveTo(this.via.x,this.via.y,c,l):t.lineTo(c,l),t.stroke(),i=10+5*this.width,t.arrow(c,l,e,i),t.fill(),t.stroke(),this.label){var g;if(1==this.smooth){var f=.5*(.5*(this.from.x+this.via.x)+.5*(this.to.x+this.via.x)),m=.5*(.5*(this.from.y+this.via.y)+.5*(this.to.y+this.via.y));g={x:f,y:m}}else g=this._pointOnLine(.5);this._label(t,this.label,g.x,g.y)}}else{var v,y,_,b=this.from,w=.25*Math.max(100,this.length);b.width||b.resize(t),b.width>b.height?(v=b.x+.5*b.width,y=b.y-w,_={x:v,y:b.y,angle:.9*Math.PI}):(v=b.x+w,y=b.y-.5*b.height,_={x:b.x,y:y,angle:.6*Math.PI}),t.beginPath(),t.arc(v,y,w,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(_.x,_.y,_.angle,i),t.fill(),t.stroke(),this.label&&(g=this._pointOnCircle(v,y,w,.5),this._label(t,this.label,g.x,g.y))}},Edge.prototype._getDistanceToEdge=function(t,e,i,s,n,o){if(1==this.smooth){var r,a,h,d,c,l,u=1e9;for(r=0;10>r;r++)a=.1*r,h=Math.pow(1-a,2)*t+2*a*(1-a)*this.via.x+Math.pow(a,2)*i,d=Math.pow(1-a,2)*e+2*a*(1-a)*this.via.y+Math.pow(a,2)*s,c=Math.abs(n-h),l=Math.abs(o-d),u=Math.min(u,Math.sqrt(c*c+l*l));return u}var p=i-t,g=s-e,f=p*p+g*g,m=((n-t)*p+(o-e)*g)/f;m>1?m=1:0>m&&(m=0);var h=t+m*p,d=e+m*g,c=h-n,l=d-o;return Math.sqrt(c*c+l*l)},Edge.prototype.setScale=function(t){this.graphScaleInv=1/t},Edge.prototype.select=function(){this.selected=!0},Edge.prototype.unselect=function(){this.selected=!1},Edge.prototype.positionBezierNode=function(){null!==this.via&&(this.via.x=.5*(this.from.x+this.to.x),this.via.y=.5*(this.from.y+this.to.y))},Popup.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},Popup.prototype.setText=function(t){this.frame.innerHTML=t},Popup.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,s=this.frame.parentNode.clientHeight,n=this.frame.parentNode.clientWidth,o=this.y-e;o+e+this.padding>s&&(o=s-e-this.padding),on&&(r=n-i-this.padding),rthis.constants.clustering.clusterThreshold&&1==this.constants.clustering.enabled&&this.clusterToFit(this.constants.clustering.reduceToNodes,!1),this._calculateForces())},_calculateForces:function(){this._calculateGravitationalForces(),this._calculateNodeForces(),1==this.constants.smoothCurves?this._calculateSpringForcesWithSupport():this._calculateSpringForces()},_updateCalculationNodes:function(){if(1==this.constants.smoothCurves){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},_calculateGravitationalForces:function(){var t,e,i,s,n,o=this.calculationNodes,r=this.constants.physics.centralGravity,a=0;for(n=0;nSimulation 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=showValueOfRange.bind(this,"graph_BH_gc",-1,"physics_barnesHut_gravitationalConstant"),e=document.getElementById("graph_BH_cg"),e.onchange=showValueOfRange.bind(this,"graph_BH_cg",1,"physics_centralGravity"),e=document.getElementById("graph_BH_sc"),e.onchange=showValueOfRange.bind(this,"graph_BH_sc",1,"physics_springConstant"),e=document.getElementById("graph_BH_sl"),e.onchange=showValueOfRange.bind(this,"graph_BH_sl",1,"physics_springLength"),e=document.getElementById("graph_BH_damp"),e.onchange=showValueOfRange.bind(this,"graph_BH_damp",1,"physics_damping"),e=document.getElementById("graph_R_nd"),e.onchange=showValueOfRange.bind(this,"graph_R_nd",1,"physics_repulsion_nodeDistance"),e=document.getElementById("graph_R_cg"),e.onchange=showValueOfRange.bind(this,"graph_R_cg",1,"physics_centralGravity"),e=document.getElementById("graph_R_sc"),e.onchange=showValueOfRange.bind(this,"graph_R_sc",1,"physics_springConstant"),e=document.getElementById("graph_R_sl"),e.onchange=showValueOfRange.bind(this,"graph_R_sl",1,"physics_springLength"),e=document.getElementById("graph_R_damp"),e.onchange=showValueOfRange.bind(this,"graph_R_damp",1,"physics_damping"),e=document.getElementById("graph_H_nd"),e.onchange=showValueOfRange.bind(this,"graph_H_nd",1,"physics_hierarchicalRepulsion_nodeDistance"),e=document.getElementById("graph_H_cg"),e.onchange=showValueOfRange.bind(this,"graph_H_cg",1,"physics_centralGravity"),e=document.getElementById("graph_H_sc"),e.onchange=showValueOfRange.bind(this,"graph_H_sc",1,"physics_springConstant"),e=document.getElementById("graph_H_sl"),e.onchange=showValueOfRange.bind(this,"graph_H_sl",1,"physics_springLength"),e=document.getElementById("graph_H_damp"),e.onchange=showValueOfRange.bind(this,"graph_H_damp",1,"physics_damping"),e=document.getElementById("graph_H_direction"),e.onchange=showValueOfRange.bind(this,"graph_H_direction",t,"hierarchicalLayout_direction"),e=document.getElementById("graph_H_levsep"),e.onchange=showValueOfRange.bind(this,"graph_H_levsep",1,"hierarchicalLayout_levelSeparation"),e=document.getElementById("graph_H_nspac"),e.onchange=showValueOfRange.bind(this,"graph_H_nspac",1,"hierarchicalLayout_nodeSpacing");var i=document.getElementById("graph_physicsMethod1"),s=document.getElementById("graph_physicsMethod2"),n=document.getElementById("graph_physicsMethod3");s.checked=!0,this.constants.physics.barnesHut.enabled&&(i.checked=!0),this.constants.hierarchicalLayout.enabled&&(n.checked=!0);var o=document.getElementById("graph_toggleSmooth"),r=document.getElementById("graph_repositionNodes"),a=document.getElementById("graph_generateOptions");o.onclick=graphToggleSmoothCurves.bind(this),r.onclick=graphRepositionNodes.bind(this),a.onclick=graphGenerateOptions.bind(this),o.style.background=1==this.constants.smoothCurves?"#A4FF56":"#FF8532",switchConfigurations.apply(this),i.onchange=switchConfigurations.bind(this),s.onchange=switchConfigurations.bind(this),n.onchange=switchConfigurations.bind(this)}},_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)}},hierarchalRepulsionMixin={_calculateNodeForces:function(){var t,e,i,s,n,o,r,a,h,d,c=this.calculationNodes,l=this.calculationNodeIndices,u=5,p=.5*-u,g=this.constants.physics.hierarchicalRepulsion.nodeDistance,f=g;for(h=0;hi&&(o=m*i+u,0==i?i=.01:o/=i,s=t*o,n=e*o,r.fx-=s,r.fy-=n,a.fx+=s,a.fy+=n)}}},barnesHutMixin={_calculateNodeForces:function(){if(0!=this.constants.physics.barnesHut.gravitationalConstant){var t,e=this.calculationNodes,i=this.calculationNodeIndices,s=i.length;this._formBarnesHutTree(e,i);for(var n=this.barnesHutTree,o=0;s>o;o++)t=e[i[o]],this._getForceContribution(n.root.children.NW,t),this._getForceContribution(n.root.children.NE,t),this._getForceContribution(n.root.children.SW,t),this._getForceContribution(n.root.children.SE,t)}},_getForceContribution:function(t,e){if(t.childrenCount>0){var i,s,n;if(i=t.centerOfMass.x-e.x,s=t.centerOfMass.y-e.y,n=Math.sqrt(i*i+s*s),n*t.calcSize>this.constants.physics.barnesHut.theta){0==n&&(n=.1*Math.random(),i=n);var o=this.constants.physics.barnesHut.gravitationalConstant*t.mass*e.mass/(n*n*n),r=i*o,a=s*o;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==n&&(n=.5*Math.random(),i=n);var o=this.constants.physics.barnesHut.gravitationalConstant*t.mass*e.mass/(n*n*n),r=i*o,a=s*o;e.fx+=r,e.fy+=a}}},_formBarnesHutTree:function(t,e){for(var i,s=e.length,n=Number.MAX_VALUE,o=Number.MAX_VALUE,r=-Number.MAX_VALUE,a=-Number.MAX_VALUE,h=0;s>h;h++){var d=t[e[h]].x,c=t[e[h]].y;n>d&&(n=d),d>r&&(r=d),o>c&&(o=c),c>a&&(a=c)}var l=Math.abs(r-n)-Math.abs(a-o);l>0?(o-=.5*l,a+=.5*l):(n+=.5*l,r-=.5*l);var u=1e-5,p=Math.max(u,Math.abs(r-n)),g=.5*p,f=.5*(n+r),m=.5*(o+a),v={root:{centerOfMass:{x:0,y:0},mass:0,range:{minX:f-g,maxX:f+g,minY:m-g,maxY:m+g},size:p,calcSize:1/p,children:{data:null},maxWidth:0,level:0,childrenCount:4}};for(this._splitBranch(v.root),h=0;s>h;h++)i=t[e[h]],this._placeInTree(v.root,i);this.barnesHutTree=v},_updateBranchMass:function(t,e){var i=t.mass+e.mass,s=1/i;t.centerOfMass.x=t.centerOfMass.x*t.mass+e.x*e.mass,t.centerOfMass.x*=s,t.centerOfMass.y=t.centerOfMass.y*t.mass+e.y*e.mass,t.centerOfMass.y*=s,t.mass=i;var n=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")},_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)}},_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)},_insertRegion:function(t,e){var i,s,n,o,r=.5*t.size;switch(e){case"NW":i=t.range.minX,s=t.range.minX+r,n=t.range.minY,o=t.range.minY+r;break;case"NE":i=t.range.minX+r,s=t.range.maxX,n=t.range.minY,o=t.range.minY+r;break;case"SW":i=t.range.minX,s=t.range.minX+r,n=t.range.minY+r,o=t.range.maxY;break;case"SE":i=t.range.minX+r,s=t.range.maxX,n=t.range.minY+r,o=t.range.maxY}t.children[e]={centerOfMass:{x:0,y:0},mass:0,range:{minX:i,maxX:s,minY:n,maxY:o},size:.5*t.size,calcSize:2*t.calcSize,children:{data:null},maxWidth:0,level:t.level+1,childrenCount:0}},_drawTree:function(t,e){void 0!==this.barnesHutTree&&(t.lineWidth=1,this._drawBranch(this.barnesHutTree.root,t,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()}},repulsionMixin={_calculateNodeForces:function(){var t,e,i,s,n,o,r,a,h,d,c,l=this.calculationNodes,u=this.calculationNodeIndices,p=-2/3,g=4/3,f=this.constants.physics.repulsion.nodeDistance,m=f;for(d=0;di&&(r=.5*m>i?1:v*i+g,r*=0==o?1:1+o*this.constants.clustering.forceAmplification,r/=i,s=t*r,n=e*r,a.fx-=s,a.fy-=n,h.fx+=s,h.fy+=n)}}},HierarchicalLayoutMixin={_resetLevels:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];0==e.preassignedLevel&&(e.level=-1)}},_setupHierarchicalLayout:function(){if(1==this.constants.hierarchicalLayout.enabled){"RL"==this.constants.hierarchicalLayout.direction||"DU"==this.constants.hierarchicalLayout.direction?this.constants.hierarchicalLayout.levelSeparation*=-1:this.constants.hierarchicalLayout.levelSeparation=Math.abs(this.constants.hierarchicalLayout.levelSeparation);var t,e,i=0,s=!1,n=!1;for(e in this.nodes)this.nodes.hasOwnProperty(e)&&(t=this.nodes[e],-1!=t.level?s=!0:n=!0,is&&(o.xFixed=!1,o.x=i[o.level].minPos,r=!0):o.yFixed&&o.level>s&&(o.yFixed=!1,o.y=i[o.level].minPos,r=!0),1==r&&(i[o.level].minPos+=i[o.level].nodeSpacing,o.edges.length>1&&this._placeBranchNodes(o.edges,o.id,i,o.level))}},_setLevel:function(t,e,i){for(var s=0;st)&&(n.level=t,e.length>1&&this._setLevel(t+1,n.edges,n.id))}},_restoreNodes:function(){for(nodeId in this.nodes)this.nodes.hasOwnProperty(nodeId)&&(this.nodes[nodeId].xFixed=!1,this.nodes[nodeId].yFixed=!1)}},manipulationMixin={_clearManipulatorBar:function(){for(;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild)},_restoreOverloadedFunctions:function(){for(var t in this.cachedFunctions)this.cachedFunctions.hasOwnProperty(t)&&(this[t]=this.cachedFunctions[t])},_toggleEditMode:function(){this.editMode=!this.editMode;var t=document.getElementById("graph-manipulationDiv"),e=document.getElementById("graph-manipulation-closeDiv"),i=document.getElementById("graph-manipulation-editMode");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()},_createManipulatorBar:function(){if(this.boundFunction&&this.off("select",this.boundFunction),this._restoreOverloadedFunctions(),this.freezeSimulation=!1,this.blockConnectingEdgeSelection=!1,this.forceAppendSelection=!1,1==this.editMode){for(;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);this.manipulationDiv.innerHTML=""+this.constants.labels.add+"
"+this.constants.labels.link+"",1==this._getSelectedNodeCount()&&this.triggerFunctions.edit&&(this.manipulationDiv.innerHTML+="
"+this.constants.labels.editNode+""),0==this._selectionIsEmpty()&&(this.manipulationDiv.innerHTML+="
"+this.constants.labels.del+"");var t=document.getElementById("graph-manipulate-addNode");t.onclick=this._createAddNodeToolbar.bind(this);var e=document.getElementById("graph-manipulate-connectNode");if(e.onclick=this._createAddEdgeToolbar.bind(this),1==this._getSelectedNodeCount()&&this.triggerFunctions.edit){var i=document.getElementById("graph-manipulate-editNode");i.onclick=this._editNode.bind(this)}if(0==this._selectionIsEmpty()){var s=document.getElementById("graph-manipulate-delete");s.onclick=this._deleteSelected.bind(this)}var n=document.getElementById("graph-manipulation-closeDiv");n.onclick=this._toggleEditMode.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)}else{this.editModeDiv.innerHTML=""+this.constants.labels.edit+"";var o=document.getElementById("graph-manipulate-editModeButton");o.onclick=this._toggleEditMode.bind(this)}},_createAddNodeToolbar:function(){this._clearManipulatorBar(),this.boundFunction&&this.off("select",this.boundFunction),this.manipulationDiv.innerHTML=""+this.constants.labels.back+"
"+this.constants.labels.addDescription+"";var t=document.getElementById("graph-manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._addNode.bind(this),this.on("select",this.boundFunction)},_createAddEdgeToolbar:function(){this._clearManipulatorBar(),this._unselectAll(!0),this.freezeSimulation=!0,this.boundFunction&&this.off("select",this.boundFunction),this._unselectAll(),this.forceAppendSelection=!1,this.blockConnectingEdgeSelection=!0,this.manipulationDiv.innerHTML=""+this.constants.labels.back+"
"+this.constants.labels.linkDescription+"";var t=document.getElementById("graph-manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._handleConnect.bind(this),this.on("select",this.boundFunction),this.cachedFunctions._handleTouch=this._handleTouch,this.cachedFunctions._handleOnRelease=this._handleOnRelease,this._handleTouch=this._handleConnect,this._handleOnRelease=this._finishConnect,this._redraw()},_handleConnect:function(t){if(0==this._getSelectedNodeCount()){var e=this._getNodeAt(t);null!=e&&(e.clusterSize>1?alert("Cannot create edges to a cluster."):(this._selectObject(e,!1),this.sectors.support.nodes.targetNode=new Node({id:"targetNode"},{},{},this.constants),this.sectors.support.nodes.targetNode.x=e.x,this.sectors.support.nodes.targetNode.y=e.y,this.sectors.support.nodes.targetViaNode=new Node({id:"targetViaNode"},{},{},this.constants),this.sectors.support.nodes.targetViaNode.x=e.x,this.sectors.support.nodes.targetViaNode.y=e.y,this.sectors.support.nodes.targetViaNode.parentEdgeId="connectionEdge",this.edges.connectionEdge=new Edge({id:"connectionEdge",from:e.id,to:this.sectors.support.nodes.targetNode.id},this,this.constants),this.edges.connectionEdge.from=e,this.edges.connectionEdge.connected=!0,this.edges.connectionEdge.smooth=!0,this.edges.connectionEdge.selected=!0,this.edges.connectionEdge.to=this.sectors.support.nodes.targetNode,this.edges.connectionEdge.via=this.sectors.support.nodes.targetViaNode,this.cachedFunctions._handleOnDrag=this._handleOnDrag,this._handleOnDrag=function(t){var e=this._getPointer(t.gesture.center);this.sectors.support.nodes.targetNode.x=this._canvasToX(e.x),this.sectors.support.nodes.targetNode.y=this._canvasToY(e.y),this.sectors.support.nodes.targetViaNode.x=.5*(this._canvasToX(e.x)+this.edges.connectionEdge.from.x),this.sectors.support.nodes.targetViaNode.y=this._canvasToY(e.y)},this.moving=!0,this.start()))}},_finishConnect:function(t){if(1==this._getSelectedNodeCount()){this._handleOnDrag=this.cachedFunctions._handleOnDrag,delete this.cachedFunctions._handleOnDrag;var e=this.edges.connectionEdge.fromId;delete this.edges.connectionEdge,delete this.sectors.support.nodes.targetNode,delete this.sectors.support.nodes.targetViaNode;var i=this._getNodeAt(t);null!=i&&(i.clusterSize>1?alert("Cannot create edges to a cluster."):(this._createEdge(e,i.id),this._createManipulatorBar())),this._unselectAll()}},_addNode:function(){if(this._selectionIsEmpty()&&1==this.editMode){var t=this._pointerToPositionObject(this.pointerPosition),e={id:util.randomUUID(),x:t.left,y:t.top,label:"new",allowedToMoveX:!0,allowedToMoveY:!0};if(this.triggerFunctions.add)if(2==this.triggerFunctions.add.length){var i=this;this.triggerFunctions.add(e,function(t){i.nodesData.add(t),i._createManipulatorBar(),i.moving=!0,i.start()})}else alert(this.constants.labels.addError),this._createManipulatorBar(),this.moving=!0,this.start();else this.nodesData.add(e),this._createManipulatorBar(),this.moving=!0,this.start()}},_createEdge:function(t,e){if(1==this.editMode){var i={from:t,to:e};if(this.triggerFunctions.connect)if(2==this.triggerFunctions.connect.length){var s=this;this.triggerFunctions.connect(i,function(t){s.edgesData.add(t),s.moving=!0,s.start()})}else alert(this.constants.labels.linkError),this.moving=!0,this.start();else this.edgesData.add(i),this.moving=!0,this.start()}},_editNode:function(){if(this.triggerFunctions.edit&&1==this.editMode){var t=this._getSelectedNode(),e={id:t.id,label:t.label,group:t.group,shape:t.shape,color:{background:t.color.background,border:t.color.border,highlight:{background:t.color.highlight.background,border:t.color.highlight.border}}};if(2==this.triggerFunctions.edit.length){var i=this;this.triggerFunctions.edit(e,function(t){i.nodesData.update(t),i._createManipulatorBar(),i.moving=!0,i.start()})}else alert(this.constants.labels.editError)}else alert(this.constants.labels.editBoundError)},_deleteSelected:function(){if(!this._selectionIsEmpty()&&1==this.editMode)if(this._clusterInSelection())alert(this.constants.labels.deleteClusterError);else{var t=this.getSelectedNodes(),e=this.getSelectedEdges();if(this.triggerFunctions.del){var i=this,s={nodes:t,edges:e};(this.triggerFunctions.del.length=2)?this.triggerFunctions.del(s,function(t){i.edgesData.remove(t.edges),i.nodesData.remove(t.nodes),i._unselectAll(),i.moving=!0,i.start()}):alert(this.constants.labels.deleteError)}else this.edgesData.remove(e),this.nodesData.remove(t),this._unselectAll(),this.moving=!0,this.start()}}},SectorMixin={_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},_switchToSector:function(t,e){void 0===e||"active"==e?this._switchToActiveSector(t):this._switchToFrozenSector(t)},_switchToActiveSector:function(t){this.nodeIndices=this.sectors.active[t].nodeIndices,this.nodes=this.sectors.active[t].nodes,this.edges=this.sectors.active[t].edges},_switchToSupportSector:function(){this.nodeIndices=this.sectors.support.nodeIndices,this.nodes=this.sectors.support.nodes,this.edges=this.sectors.support.edges},_switchToFrozenSector:function(t){this.nodeIndices=this.sectors.frozen[t].nodeIndices,this.nodes=this.sectors.frozen[t].nodes,this.edges=this.sectors.frozen[t].edges},_loadLatestSector:function(){this._switchToSector(this._sector())},_sector:function(){return this.activeSector[this.activeSector.length-1]},_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.")},_setActiveSector:function(t){this.activeSector.push(t)},_forgetLastSector:function(){this.activeSector.pop()},_createNewSector:function(t){this.sectors.active[t]={nodes:{},edges:{},nodeIndices:[],formationScale:this.scale,drawingNode:void 0},this.sectors.active[t].drawingNode=new Node({id:t,color:{background:"#eaefef",border:"495c5e"}},{},{},this.constants),this.sectors.active[t].drawingNode.clusterSize=2},_deleteActiveSector:function(t){delete this.sectors.active[t]},_deleteFrozenSector:function(t){delete this.sectors.frozen[t]},_freezeSector:function(t){this.sectors.frozen[t]=this.sectors.active[t],this._deleteActiveSector(t)},_activateSector:function(t){this.sectors.active[t]=this.sectors.frozen[t],this._deleteFrozenSector(t)},_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](s[0],s[1]):this[t](e)}this._loadLatestSector()},_doInSupportSector:function(t,e){if(void 0===e)this._switchToSupportSector(),this[t]();else{this._switchToSupportSector();var i=Array.prototype.splice.call(arguments,1);i.length>1?this[t](i[0],i[1]):this[t](e)}this._loadLatestSector()},_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()},_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))},_clearNodeIndexList:function(){var t=this._sector();this.sectors.active[t].nodeIndices=[],this.nodeIndices=this.sectors.active[t].nodeIndices},_drawSectorNodes:function(t,e){var i,s=1e9,n=-1e9,o=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,n=-1e9,o=1e9,r=-1e9;for(var h in this.nodes)this.nodes.hasOwnProperty(h)&&(i=this.nodes[h],i.resize(t),o>i.x-.5*i.width&&(o=i.x-.5*i.width),ri.y-.5*i.height&&(s=i.y-.5*i.height),nt&&s>n;)n%3==0?(this.forceAggregateHubs(!0),this.normalizeClusterLevels()):this.increaseClusterLevel(),i=this.nodeIndices.length,n+=1;n>0&&1==e&&this.repositionNodes(),this._updateCalculationNodes()},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()},updateClustersDefault:function(){1==this.constants.clustering.enabled&&this.updateClusters(0,!1,!1)},increaseClusterLevel:function(){this.updateClusters(-1,!1,!0)},decreaseClusterLevel:function(){this.updateClusters(1,!1,!0)},updateClusters:function(t,e,i,s){var n=this.moving,o=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)},_aggregateHubs:function(t){this._getHubSize(),this._formClustersByHub(t,!1)},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()},_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)}},_openClusters:function(t,e){for(var i=0;i1&&(t.clusterSizei)){var r=o.from,a=o.to;o.to.mass>o.from.mass&&(r=o.to,a=o.from),1==a.dynamicEdgesLength?this._addToCluster(r,a,!1):1==r.dynamicEdgesLength&&this._addToCluster(a,r,!1)}}},_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.mass>e.mass?this._addToCluster(s,e,!0):this._addToCluster(e,s,!0))}}},_clusterToSmallestNeighbour:function(t){for(var e=-1,i=null,s=0;sn.clusterSessions.length&&(e=n.clusterSessions.length,i=n)}null!=n&&void 0!==this.nodes[n.id]&&this._addToCluster(n,t,!0)},_formClustersByHub:function(t,e){for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&this._formClusterFromHub(this.nodes[i],t,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 n,o,r,a=this.constants.clustering.clusterEdgeThreshold/this.scale,h=!1,d=[],c=t.dynamicEdges.length,l=0;c>l;l++)d.push(t.dynamicEdges[l].id);if(0==e)for(h=!1,l=0;c>l;l++){var u=this.edges[d[l]];if(void 0!==u&&u.connected&&u.toId!=u.fromId&&(n=u.to.x-u.from.x,o=u.to.y-u.from.y,r=Math.sqrt(n*n+o*o),a>r)){h=!0;break}}if(!e&&h||e)for(l=0;c>l;l++)if(u=this.edges[d[l]],void 0!==u){var p=this.nodes[u.fromId==t.id?u.toId:u.fromId];p.dynamicEdges.length<=this.hubThreshold+s&&p.id!=t.id&&this._addToCluster(t,p,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)))},normalizeClusterLevels:function(){var t=0,e=1e9,i=0;for(var s in this.nodes)this.nodes.hasOwnProperty(s)&&(i=this.nodes[s].clusterSessions.length,i>t&&(t=i),e>i&&(e=i));if(t-e>this.constants.clustering.clusterLevelDifference){var n=this.nodeIndices.length,o=t-this.constants.clustering.clusterLevelDifference;for(var s in this.nodes)this.nodes.hasOwnProperty(s)&&this.nodes[s].clusterSessions.lengths&&(s=o.dynamicEdgesLength),t+=o.dynamicEdgesLength,e+=Math.pow(o.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)},_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)},_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}},SelectionMixin={_getNodesOverlappingWith:function(t,e){var i=this.nodes;for(var s in i)i.hasOwnProperty(s)&&i[s].isOverlappingWith(t)&&e.push(s)},_getAllNodesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getNodesOverlappingWith",t,e),e},_pointerToPositionObject:function(t){var e=this._canvasToX(t.x),i=this._canvasToY(t.y);return{left:e,top:i,right:e,bottom:i}},_getNodeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllNodesOverlappingWith(e);return i.length>0?this.nodes[i[i.length-1]]:null},_getEdgesOverlappingWith:function(t,e){var i=this.edges;for(var s in i)i.hasOwnProperty(s)&&i[s].isOverlappingWith(t)&&e.push(s)},_getAllEdgesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getEdgesOverlappingWith",t,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},_addToSelection:function(t){t instanceof Node?this.selectionObj.nodes[t.id]=t:this.selectionObj.edges[t.id]=t},_removeFromSelection:function(t){t instanceof Node?delete this.selectionObj.nodes[t.id]:delete this.selectionObj.edges[t.id]},_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())},_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())},_getSelectedNodeCount:function(){var t=0;for(var e in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(e)&&(t+=1);return t},_getSelectedNode:function(){for(var t in this.selectionObj.nodes)if(this.selectionObj.nodes.hasOwnProperty(t))return this.selectionObj.nodes[t];return null},_getSelectedEdgeCount:function(){var t=0;for(var e in this.selectionObj.edges)this.selectionObj.edges.hasOwnProperty(e)&&(t+=1);return t},_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},_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},_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},_selectConnectedEdges:function(t){for(var e=0;ee;e++){s=t[e];var n=this.nodes[s];if(!n)throw new RangeError('Node with id "'+s+'" not found');this._selectObject(n,!0,!0)}this.redraw()},_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])}},NavigationMixin={_cleanNavigation:function(){var t=document.getElementById("graph-navigation_wrapper");null!=t&&this.containerElement.removeChild(t),document.onmouseup=null},_loadNavigationElements:function(){this._cleanNavigation(),this.navigationDivs={};var t=["up","down","left","right","zoomIn","zoomOut","zoomExtends"],e=["_moveUp","_moveDown","_moveLeft","_moveRight","_zoomIn","_zoomOut","zoomExtent"];this.navigationDivs.wrapper=document.createElement("div"),this.navigationDivs.wrapper.id="graph-navigation_wrapper",this.navigationDivs.wrapper.style.position="absolute",this.navigationDivs.wrapper.style.width=this.frame.canvas.clientWidth+"px",this.navigationDivs.wrapper.style.height=this.frame.canvas.clientHeight+"px",this.containerElement.insertBefore(this.navigationDivs.wrapper,this.frame);for(var i=0;it.x&&(s=t.x),nt.y&&(e=t.y),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 o=Math.min(this.frame.canvas.clientWidth/600,this.frame.canvas.clientHeight/600);i*=o}else{var r=1.1*(Math.abs(s.minX)+Math.abs(s.maxX)),a=1.1*(Math.abs(s.minY)+Math.abs(s.maxY)),h=this.frame.canvas.clientWidth/r,d=this.frame.canvas.clientHeight/a;i=d>=h?h:d}i>1&&(i=1),this._setScale(i),this._centerGraph(s),0==e&&(this.moving=!0,this.start())},Graph.prototype._updateNodeIndexList=function(){this._clearNodeIndexList();for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodeIndices.push(t)},Graph.prototype.setData=function(t,e){if(void 0===e&&(e=!1),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(this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var i=vis.util.DOTToGraph(t.dot);return void this.setData(i)}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this._putDataInSector(),e||(this.stabilize&&this._stabilize(),this.start())},Graph.prototype.setOptions=function(t){if(t){var e;if(void 0!==t.width&&(this.width=t.width),void 0!==t.height&&(this.height=t.height),void 0!==t.stabilize&&(this.stabilize=t.stabilize),void 0!==t.selectable&&(this.selectable=t.selectable),void 0!==t.smoothCurves&&(this.constants.smoothCurves=t.smoothCurves),void 0!==t.freezeForStabilization&&(this.constants.freezeForStabilization=t.freezeForStabilization),void 0!==t.configurePhysics&&(this.constants.configurePhysics=t.configurePhysics),void 0!==t.stabilizationIterations&&(this.constants.stabilizationIterations=t.stabilizationIterations),void 0!==t.labels)for(e in t.labels)t.labels.hasOwnProperty(e)&&(this.constants.labels[e]=t.labels[e]);if(t.onAdd&&(this.triggerFunctions.add=t.onAdd),t.onEdit&&(this.triggerFunctions.edit=t.onEdit),t.onConnect&&(this.triggerFunctions.connect=t.onConnect),t.onDelete&&(this.triggerFunctions.del=t.onDelete),t.physics){if(t.physics.barnesHut){this.constants.physics.barnesHut.enabled=!0;for(e in t.physics.barnesHut)t.physics.barnesHut.hasOwnProperty(e)&&(this.constants.physics.barnesHut[e]=t.physics.barnesHut[e])}if(t.physics.repulsion){this.constants.physics.barnesHut.enabled=!1;for(e in t.physics.repulsion)t.physics.repulsion.hasOwnProperty(e)&&(this.constants.physics.repulsion[e]=t.physics.repulsion[e])}}if(t.hierarchicalLayout){this.constants.hierarchicalLayout.enabled=!0;for(e in t.hierarchicalLayout)t.hierarchicalLayout.hasOwnProperty(e)&&(this.constants.hierarchicalLayout[e]=t.hierarchicalLayout[e])}else void 0!==t.hierarchicalLayout&&(this.constants.hierarchicalLayout.enabled=!1);if(t.clustering){this.constants.clustering.enabled=!0;for(e in t.clustering)t.clustering.hasOwnProperty(e)&&(this.constants.clustering[e]=t.clustering[e])}else void 0!==t.clustering&&(this.constants.clustering.enabled=!1);if(t.navigation){this.constants.navigation.enabled=!0;for(e in t.navigation)t.navigation.hasOwnProperty(e)&&(this.constants.navigation[e]=t.navigation[e])}else void 0!==t.navigation&&(this.constants.navigation.enabled=!1);if(t.keyboard){this.constants.keyboard.enabled=!0;for(e in t.keyboard)t.keyboard.hasOwnProperty(e)&&(this.constants.keyboard[e]=t.keyboard[e])}else void 0!==t.keyboard&&(this.constants.keyboard.enabled=!1);if(t.dataManipulation){this.constants.dataManipulation.enabled=!0;for(e in t.dataManipulation)t.dataManipulation.hasOwnProperty(e)&&(this.constants.dataManipulation[e]=t.dataManipulation[e])}else void 0!==t.dataManipulation&&(this.constants.dataManipulation.enabled=!1);if(t.edges){for(e in t.edges)t.edges.hasOwnProperty(e)&&"object"!=typeof t.edges[e]&&(this.constants.edges[e]=t.edges[e]);void 0!==t.edges.color&&(util.isString(t.edges.color)?(this.constants.edges.color={},this.constants.edges.color.color=t.edges.color,this.constants.edges.color.highlight=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))),t.edges.fontColor||void 0!==t.edges.color&&(util.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.edges.dash&&(void 0!==t.edges.dash.length&&(this.constants.edges.dash.length=t.edges.dash.length),void 0!==t.edges.dash.gap&&(this.constants.edges.dash.gap=t.edges.dash.gap),void 0!==t.edges.dash.altLength&&(this.constants.edges.dash.altLength=t.edges.dash.altLength))}if(t.nodes){for(e in t.nodes)t.nodes.hasOwnProperty(e)&&(this.constants.nodes[e]=t.nodes[e]);t.nodes.color&&(this.constants.nodes.color=util.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var s=t.groups[i];this.groups.add(i,s)}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=util.parseColor(t.tooltip.color))}}this._loadPhysicsSystem(),this._loadNavigationControls(),this._loadManipulationSystem(),this._configureSmoothCurves(),this._createKeyBinds(),this.setSize(this.width,this.height),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1),this._redraw()},Graph.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="graph-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=document.createElement("DIV");t.style.color="red",t.style.fontWeight="bold",t.style.padding="10px",t.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(t)}var e=this;this.drag={},this.pinch={},this.hammer=Hammer(this.frame.canvas,{prevent_default:!0}),this.hammer.on("tap",e._onTap.bind(e)),this.hammer.on("doubletap",e._onDoubleTap.bind(e)),this.hammer.on("hold",e._onHold.bind(e)),this.hammer.on("pinch",e._onPinch.bind(e)),this.hammer.on("touch",e._onTouch.bind(e)),this.hammer.on("dragstart",e._onDragStart.bind(e)),this.hammer.on("drag",e._onDrag.bind(e)),this.hammer.on("dragend",e._onDragEnd.bind(e)),this.hammer.on("release",e._onRelease.bind(e)),this.hammer.on("mousewheel",e._onMouseWheel.bind(e)),this.hammer.on("DOMMouseScroll",e._onMouseWheel.bind(e)),this.hammer.on("mousemove",e._onMouseMoveTitle.bind(e)),this.containerElement.appendChild(this.frame)},Graph.prototype._createKeyBinds=function(){var t=this;this.mousetrap=mousetrap,this.mousetrap.reset(),1==this.constants.keyboard.enabled&&(this.mousetrap.bind("up",this._moveUp.bind(t),"keydown"),this.mousetrap.bind("up",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("down",this._moveDown.bind(t),"keydown"),this.mousetrap.bind("down",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("left",this._moveLeft.bind(t),"keydown"),this.mousetrap.bind("left",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("right",this._moveRight.bind(t),"keydown"),this.mousetrap.bind("right",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("=",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("=",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("-",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("-",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("[",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("[",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("]",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("]",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pageup",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("pageup",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pagedown",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("pagedown",this._stopZoom.bind(t),"keyup")),1==this.constants.dataManipulation.enabled&&(this.mousetrap.bind("escape",this._createManipulatorBar.bind(t)),this.mousetrap.bind("del",this._deleteSelected.bind(t)))},Graph.prototype._getPointer=function(t){return{x:t.pageX-vis.util.getAbsoluteLeft(this.frame.canvas),y:t.pageY-vis.util.getAbsoluteTop(this.frame.canvas)}},Graph.prototype._onTouch=function(t){this.drag.pointer=this._getPointer(t.gesture.center),this.drag.pinched=!1,this.pinch.scale=this._getScale(),this._handleTouch(this.drag.pointer)},Graph.prototype._onDragStart=function(){this._handleDragStart()},Graph.prototype._handleDragStart=function(){var t=this.drag,e=this._getNodeAt(t.pointer);if(t.dragging=!0,t.selection=[],t.translation=this._getTranslation(),t.nodeId=null,null!=e){t.nodeId=e.id,e.isSelected()||this._selectObject(e,!1);for(var i in this.selectionObj.nodes)if(this.selectionObj.nodes.hasOwnProperty(i)){var s=this.selectionObj.nodes[i],n={id:s.id,node:s,x:s.x,y:s.y,xFixed:s.xFixed,yFixed:s.yFixed};s.xFixed=!0,s.yFixed=!0,t.selection.push(n)}}},Graph.prototype._onDrag=function(t){this._handleOnDrag(t)},Graph.prototype._handleOnDrag=function(t){if(!this.drag.pinched){var e=this._getPointer(t.gesture.center),i=this,s=this.drag,n=s.selection;if(n&&n.length){var o=e.x-s.pointer.x,r=e.y-s.pointer.y;n.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._canvasToX(i._xToCanvas(t.x)+o)),t.yFixed||(e.y=i._canvasToY(i._yToCanvas(t.y)+r))}),this.moving||(this.moving=!0,this.start())}else{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(),this.moved=!0}}},Graph.prototype._onDragEnd=function(){this.drag.dragging=!1;var t=this.drag.selection;t&&t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed})},Graph.prototype._onTap=function(t){var e=this._getPointer(t.gesture.center);this.pointerPosition=e,this._handleTap(e)},Graph.prototype._onDoubleTap=function(t){var e=this._getPointer(t.gesture.center);this._handleDoubleTap(e)},Graph.prototype._onHold=function(t){var e=this._getPointer(t.gesture.center);this.pointerPosition=e,this._handleOnHold(e)},Graph.prototype._onRelease=function(t){var e=this._getPointer(t.gesture.center);this._handleOnRelease(e)},Graph.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)},Graph.prototype._zoom=function(t,e){var i=this._getScale();1e-5>t&&(t=1e-5),t>10&&(t=10);var s=this._getTranslation(),n=t/i,o=(1-n)*e.x+s.x*n,r=(1-n)*e.y+s.y*n;return this.areaCenter={x:this._canvasToX(e.x),y:this._canvasToY(e.y)},this._setScale(t),this._setTranslation(o,r),this.updateClustersDefault(),this._redraw(),t},Graph.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 n=util.fakeGesture(this,t),o=this._getPointer(n.center);this._zoom(i,o)}t.preventDefault()},Graph.prototype._onMouseMoveTitle=function(t){var e=util.fakeGesture(this,t),i=this._getPointer(e.center);this.popupNode&&this._checkHidePopup(i);var s=this,n=function(){s._checkShowPopup(i)};this.popupTimer&&clearInterval(this.popupTimer),this.drag.dragging||(this.popupTimer=setTimeout(n,this.constants.tooltip.delay))},Graph.prototype._checkShowPopup=function(t){var e,i={left:this._canvasToX(t.x),top:this._canvasToY(t.y),right:this._canvasToX(t.x),bottom:this._canvasToY(t.y)},s=this.popupNode;if(void 0==this.popupNode){var n=this.nodes;for(e in n)if(n.hasOwnProperty(e)){var o=n[e];if(void 0!==o.getTitle()&&o.isOverlappingWith(i)){this.popupNode=o;break}}}if(void 0===this.popupNode){var r=this.edges;for(e in r)if(r.hasOwnProperty(e)){var a=r[e];if(a.connected&&void 0!==a.getTitle()&&a.isOverlappingWith(i)){this.popupNode=a;break}}}if(this.popupNode){if(this.popupNode!=s){var h=this;h.popup||(h.popup=new Popup(h.frame,h.constants.tooltip)),h.popup.setPosition(t.x-3,t.y-3),h.popup.setText(h.popupNode.getTitle()),h.popup.show()}}else this.popup&&this.popup.hide()},Graph.prototype._checkHidePopup=function(t){this.popupNode&&this._getNodeAt(t)||(this.popupNode=void 0,this.popup&&this.popup.hide())},Graph.prototype.setSize=function(t,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.frame.canvas.height=this.frame.canvas.clientHeight,void 0!==this.manipulationDiv&&(this.manipulationDiv.style.width=this.frame.canvas.clientWidth+"px"),void 0!==this.navigationDivs&&void 0!==this.navigationDivs.wrapper&&(this.navigationDivs.wrapper.style.width=this.frame.canvas.clientWidth+"px",this.navigationDivs.wrapper.style.height=this.frame.canvas.clientHeight+"px"),this.emit("resize",{width:this.frame.canvas.width,height:this.frame.canvas.height})},Graph.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof DataSet||t instanceof DataView)this.nodesData=t;else if(t instanceof Array)this.nodesData=new DataSet,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new DataSet}if(e&&util.forEach(this.nodesListeners,function(t,i){e.off(i,t)}),this.nodes={},this.nodesData){var i=this;util.forEach(this.nodesListeners,function(t,e){i.nodesData.on(e,t)});var s=this.nodesData.getIds();this._addNodes(s)}this._updateSelection()},Graph.prototype._addNodes=function(t){for(var e,i=0,s=t.length;s>i;i++){e=t[i];var n=this.nodesData.get(e),o=new Node(n,this.images,this.groups,this.constants);if(this.nodes[e]=o,!(0!=o.xFixed&&0!=o.yFixed||null!==o.x&&null!==o.y)){var r=1*t.length,a=2*Math.PI*Math.random();0==o.xFixed&&(o.x=r*Math.cos(a)),0==o.yFixed&&(o.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()},Graph.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,s=0,n=t.length;n>s;s++){var o=t[s],r=e[o],a=i.get(o);r?r.setProperties(a,this.constants):(r=new Node(properties,this.images,this.groups,this.constants),e[o]=r,r.isFixed()||(this.moving=!0))}this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(e)},Graph.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,s=t.length;s>i;i++){var n=t[i];delete e[n]}this._updateNodeIndexList(),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this._updateCalculationNodes(),this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},Graph.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof DataSet||t instanceof DataView)this.edgesData=t;else if(t instanceof Array)this.edgesData=new DataSet,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new DataSet}if(e&&util.forEach(this.edgesListeners,function(t,i){e.off(i,t)}),this.edges={},this.edgesData){var i=this;util.forEach(this.edgesListeners,function(t,e){i.edgesData.on(e,t)});var s=this.edgesData.getIds();this._addEdges(s)}this._reconnectEdges()},Graph.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,s=0,n=t.length;n>s;s++){var o=t[s],r=e[o];r&&r.disconnect();var a=i.get(o,{showInternalIds:!0});e[o]=new Edge(a,this,this.constants)}this.moving=!0,this._updateValueRange(e),this._createBezierNodes(),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this._updateCalculationNodes()},Graph.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,s=0,n=t.length;n>s;s++){var o=t[s],r=i.get(o),a=e[o];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new Edge(r,this,this.constants),this.edges[o]=a)}this._createBezierNodes(),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this.moving=!0,this._updateValueRange(e)},Graph.prototype._removeEdges=function(t){for(var e=this.edges,i=0,s=t.length;s>i;i++){var n=t[i],o=e[n];o&&(null!=o.via&&delete this.sectors.support.nodes[o.via.id],o.disconnect(),delete e[n])}this.moving=!0,this._updateValueRange(e),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this._updateCalculationNodes()},Graph.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[]);for(t in i)if(i.hasOwnProperty(t)){var s=i[t];s.from=null,s.to=null,s.connect()}},Graph.prototype._updateValueRange=function(t){var e,i=void 0,s=void 0;for(e in t)if(t.hasOwnProperty(e)){var n=t[e].getValue();void 0!==n&&(i=void 0===i?n:Math.min(n,i),s=void 0===s?n:Math.max(n,s))}if(void 0!==i&&void 0!==s)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,s)},Graph.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},Graph.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this.canvasTopLeft={x:this._canvasToX(0),y:this._canvasToY(0)},this.canvasBottomRight={x:this._canvasToX(this.frame.canvas.clientWidth),y:this._canvasToY(this.frame.canvas.clientHeight)},this._doInAllSectors("_drawAllSectorNodes",t),this._doInAllSectors("_drawEdges",t),this._doInAllSectors("_drawNodes",t,!1),t.restore()},Graph.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)},Graph.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},Graph.prototype._setScale=function(t){this.scale=t},Graph.prototype._getScale=function(){return this.scale},Graph.prototype._canvasToX=function(t){return(t-this.translation.x)/this.scale},Graph.prototype._xToCanvas=function(t){return t*this.scale+this.translation.x},Graph.prototype._canvasToY=function(t){return(t-this.translation.y)/this.scale},Graph.prototype._yToCanvas=function(t){return t*this.scale+this.translation.y},Graph.prototype._drawNodes=function(t,e){void 0===e&&(e=!1);var i=this.nodes,s=[];for(var n in i)i.hasOwnProperty(n)&&(i[n].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight),i[n].isSelected()?s.push(n):(i[n].inArea()||e)&&i[n].draw(t));for(var o=0,r=s.length;r>o;o++)(i[s[o]].inArea()||e)&&i[s[o]].draw(t)},Graph.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)}},Graph.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 n=this.constants.minVelocity/Math.max(this.scale,.05);this.moving=n>.5*this.constants.maxVelocity?!0:this._isMoving(n)}},Graph.prototype._physicsTick=function(){this.freezeSimulation||this.moving&&(this._doInAllActiveSectors("_initializeForceCalculation"),this._doInAllActiveSectors("_discreteStepNodes"),this.constants.smoothCurves&&this._doInSupportSector("_discreteStepNodes"),this._findCenter(this._getRange()))},Graph.prototype._animationStep=function(){this.timer=void 0,this._handleNavigation(),this.start();var t=Date.now(),e=1;this._physicsTick();for(var i=Date.now()-t;is;++s)i[s].apply(this,e)}return this},i.prototype.listeners=function(t){return this._callbacks=this._callbacks||{},this._callbacks[t]||[]},i.prototype.hasListeners=function(t){return!!this.listeners(t).length}},{}],3:[function(t,e){!function(t,i){"use strict";function s(){if(!n.READY){n.event.determineEventTypes();for(var t in n.gestures)n.gestures.hasOwnProperty(t)&&n.detection.register(n.gestures[t]);n.event.onTouch(n.DOCUMENT,n.EVENT_MOVE,n.detection.detect),n.event.onTouch(n.DOCUMENT,n.EVENT_END,n.detection.detect),n.READY=!0}}var n=function(t,e){return new n.Instance(t,e||{})};n.defaults={stop_browser_behavior:{userSelect:"none",touchAction:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}},n.HAS_POINTEREVENTS=navigator.pointerEnabled||navigator.msPointerEnabled,n.HAS_TOUCHEVENTS="ontouchstart"in t,n.MOBILE_REGEX=/mobile|tablet|ip(ad|hone|od)|android/i,n.NO_MOUSEEVENTS=n.HAS_TOUCHEVENTS&&navigator.userAgent.match(n.MOBILE_REGEX),n.EVENT_TYPES={},n.DIRECTION_DOWN="down",n.DIRECTION_LEFT="left",n.DIRECTION_UP="up",n.DIRECTION_RIGHT="right",n.POINTER_MOUSE="mouse",n.POINTER_TOUCH="touch",n.POINTER_PEN="pen",n.EVENT_START="start",n.EVENT_MOVE="move",n.EVENT_END="end",n.DOCUMENT=document,n.plugins={},n.READY=!1,n.Instance=function(t,e){var i=this;return s(),this.element=t,this.enabled=!0,this.options=n.utils.extend(n.utils.extend({},n.defaults),e||{}),this.options.stop_browser_behavior&&n.utils.stopDefaultBrowserBehavior(this.element,this.options.stop_browser_behavior),n.event.onTouch(t,n.EVENT_START,function(t){i.enabled&&n.detection.startDetect(i,t)}),this},n.Instance.prototype={on:function(t,e){for(var i=t.split(" "),s=0;s0&&e==n.EVENT_END?e=n.EVENT_MOVE:c||(e=n.EVENT_END),c||null===o?o=h:h=o,i.call(n.detection,s.collectEventData(t,e,h)),n.HAS_POINTEREVENTS&&e==n.EVENT_END&&(c=n.PointerEvent.updatePointer(e,h))),c||(o=null,r=!1,a=!1,n.PointerEvent.reset())}})},determineEventTypes:function(){var t;t=n.HAS_POINTEREVENTS?n.PointerEvent.getEvents():n.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],n.EVENT_TYPES[n.EVENT_START]=t[0],n.EVENT_TYPES[n.EVENT_MOVE]=t[1],n.EVENT_TYPES[n.EVENT_END]=t[2]},getTouchList:function(t){return n.HAS_POINTEREVENTS?n.PointerEvent.getTouchList():t.touches?t.touches:[{identifier:1,pageX:t.pageX,pageY:t.pageY,target:t.target}]},collectEventData:function(t,e,i){var s=this.getTouchList(i,e),o=n.POINTER_TOUCH;return(i.type.match(/mouse/)||n.PointerEvent.matchType(n.POINTER_MOUSE,i))&&(o=n.POINTER_MOUSE),{center:n.utils.getCenter(s),timeStamp:(new Date).getTime(),target:i.target,touches:s,eventType:e,pointerType:o,srcEvent:i,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return n.detection.stopDetect()}}}},n.PointerEvent={pointers:{},getTouchList:function(){var t=this,e=[];return Object.keys(t.pointers).sort().forEach(function(i){e.push(t.pointers[i])}),e},updatePointer:function(t,e){return t==n.EVENT_END?this.pointers={}:(e.identifier=e.pointerId,this.pointers[e.pointerId]=e),Object.keys(this.pointers).length},matchType:function(t,e){if(!e.pointerType)return!1;var i={};return i[n.POINTER_MOUSE]=e.pointerType==e.MSPOINTER_TYPE_MOUSE||e.pointerType==n.POINTER_MOUSE,i[n.POINTER_TOUCH]=e.pointerType==e.MSPOINTER_TYPE_TOUCH||e.pointerType==n.POINTER_TOUCH,i[n.POINTER_PEN]=e.pointerType==e.MSPOINTER_TYPE_PEN||e.pointerType==n.POINTER_PEN,i[t]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},n.utils={extend:function(t,e,s){for(var n in e)t[n]!==i&&s||(t[n]=e[n]);return t},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){for(var e=[],i=[],s=0,n=t.length;n>s;s++)e.push(t[s].pageX),i.push(t[s].pageY);return{pageX:(Math.min.apply(Math,e)+Math.max.apply(Math,e))/2,pageY:(Math.min.apply(Math,i)+Math.max.apply(Math,i))/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.pageY-t.pageY,s=e.pageX-t.pageX;return 180*Math.atan2(i,s)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.pageX-e.pageX),s=Math.abs(t.pageY-e.pageY);return i>=s?t.pageX-e.pageX>0?n.DIRECTION_LEFT:n.DIRECTION_RIGHT:t.pageY-e.pageY>0?n.DIRECTION_UP:n.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,s=e.pageY-t.pageY;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==n.DIRECTION_UP||t==n.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){var i,s=["webkit","khtml","moz","ms","o",""];if(e&&t.style){for(var n=0;ni;i++){var o=this.gestures[i];if(!this.stopped&&e[o.name]!==!1&&o.handler.call(o,t,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=t),t.eventType==n.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t}},stopDetect:function(){this.previous=n.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(t){var e=this.current.startEvent;if(e&&(t.touches.length!=e.touches.length||t.touches===e.touches)){e.touches=[];for(var i=0,s=t.touches.length;s>i;i++)e.touches.push(n.utils.extend({},t.touches[i]))}var o=t.timeStamp-e.timeStamp,r=t.center.pageX-e.center.pageX,a=t.center.pageY-e.center.pageY,h=n.utils.getVelocity(o,r,a);return n.utils.extend(t,{deltaTime:o,deltaX:r,deltaY:a,velocityX:h.x,velocityY:h.y,distance:n.utils.getDistance(e.center,t.center),angle:n.utils.getAngle(e.center,t.center),direction:n.utils.getDirection(e.center,t.center),scale:n.utils.getScale(e.touches,t.touches),rotation:n.utils.getRotation(e.touches,t.touches),startEvent:e}),t},register:function(t){var e=t.defaults||{};return e[t.name]===i&&(e[t.name]=!0),n.utils.extend(n.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}},n.gestures=n.gestures||{},n.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,e){switch(t.eventType){case n.EVENT_START:clearTimeout(this.timer),n.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==n.detection.current.name&&e.trigger("hold",t)},e.options.hold_timeout);break;case n.EVENT_MOVE:t.distance>e.options.hold_threshold&&clearTimeout(this.timer);break;case n.EVENT_END:clearTimeout(this.timer)}}},n.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(t,e){if(t.eventType==n.EVENT_END){var i=n.detection.previous,s=!1;if(t.deltaTime>e.options.tap_max_touchtime||t.distance>e.options.tap_max_distance)return;i&&"tap"==i.name&&t.timeStamp-i.lastEvent.timeStamp0&&t.touches.length>e.options.swipe_max_touches)return;(t.velocityX>e.options.swipe_velocity||t.velocityY>e.options.swipe_velocity)&&(e.trigger(this.name,t),e.trigger(this.name+t.direction,t))}}},n.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,drag_max_touches:1,drag_block_horizontal:!1,drag_block_vertical:!1,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(t,e){if(n.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),void(this.triggered=!1);if(!(e.options.drag_max_touches>0&&t.touches.length>e.options.drag_max_touches))switch(t.eventType){case n.EVENT_START:this.triggered=!1;break;case n.EVENT_MOVE:if(t.distancee.options.transform_min_rotation&&e.trigger("rotate",t),i>e.options.transform_min_scale&&(e.trigger("pinch",t),e.trigger("pinch"+(t.scale<1?"in":"out"),t));break;case n.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},n.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(t,e){return e.options.prevent_mouseevents&&t.pointerType==n.POINTER_MOUSE?void t.stopDetect():(e.options.prevent_default&&t.preventDefault(),void(t.eventType==n.EVENT_START&&e.trigger(this.name,t)))}},n.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==n.EVENT_END&&e.trigger(this.name,t)}},"object"==typeof e&&"object"==typeof e.exports?e.exports=n:(t.Hammer=n,"function"==typeof t.define&&t.define.amd&&t.define("hammer",[],function(){return n}))}(this)},{}],4:[function(t,e){var i="undefined"!=typeof self?self:"undefined"!=typeof window?window:{};(function(s){function n(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function o(t,e){function i(){le.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+t)}var s=!0;return l(function(){return s&&(i(),s=!1),e.apply(this,arguments)},e)}function r(t,e){return function(i){return g(t.call(this,i),e)}}function a(t,e){return function(i){return this.lang().ordinal(t.call(this,i),e)}}function h(){}function d(t){C(t),l(this,t)}function c(t){var e=b(t),i=e.year||0,s=e.quarter||0,n=e.month||0,o=e.week||0,r=e.day||0,a=e.hour||0,h=e.minute||0,d=e.second||0,c=e.millisecond||0;this._milliseconds=+c+1e3*d+6e4*h+36e5*a,this._days=+r+7*o,this._months=+n+3*s+12*i,this._data={},this._bubble()}function l(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return e.hasOwnProperty("toString")&&(t.toString=e.toString),e.hasOwnProperty("valueOf")&&(t.valueOf=e.valueOf),t}function u(t){var e,i={};for(e in t)t.hasOwnProperty(e)&&Te.hasOwnProperty(e)&&(i[e]=t[e]);return i}function p(t){return 0>t?Math.ceil(t):Math.floor(t)}function g(t,e,i){for(var s=""+Math.abs(t),n=t>=0;s.lengths;s++)(i&&t[s]!==e[s]||!i&&S(t[s])!==S(e[s]))&&r++;return r+o}function _(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=ti[t]||ei[e]||e}return t}function b(t){var e,i,s={};for(i in t)t.hasOwnProperty(i)&&(e=_(i),e&&(s[e]=t[i]));return s}function w(t){var e,i;if(0===t.indexOf("week"))e=7,i="day";else{if(0!==t.indexOf("month"))return;e=12,i="month"}le[t]=function(n,o){var r,a,h=le.fn._lang[t],d=[];if("number"==typeof n&&(o=n,n=s),a=function(t){var e=le().utc().set(i,t);return h.call(le.fn._lang,e,n||"")},null!=o)return a(o);for(r=0;e>r;r++)d.push(a(r));return d}}function S(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=e>=0?Math.floor(e):Math.ceil(e)),i}function x(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function E(t,e,i){return ee(le([t,11,31+e-i]),e,i).week}function T(t){return D(t)?366:365}function D(t){return t%4===0&&t%100!==0||t%400===0}function C(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[ye]<0||t._a[ye]>11?ye:t._a[_e]<1||t._a[_e]>x(t._a[ve],t._a[ye])?_e:t._a[be]<0||t._a[be]>23?be:t._a[we]<0||t._a[we]>59?we:t._a[Se]<0||t._a[Se]>59?Se:t._a[xe]<0||t._a[xe]>999?xe:-1,t._pf._overflowDayOfYear&&(ve>e||e>_e)&&(e=_e),t._pf.overflow=e)}function M(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._isValid}function I(t){return t?t.toLowerCase().replace("_","-"):t}function N(t,e){return e._isUTC?le(t).zone(e._offset||0):le(t).local()}function O(t,e){return e.abbr=t,Ee[t]||(Ee[t]=new h),Ee[t].set(e),Ee[t]}function L(t){delete Ee[t]}function k(e){var i,s,n,o,r=0,a=function(e){if(!Ee[e]&&De)try{t("./lang/"+e)}catch(i){}return Ee[e]};if(!e)return le.fn._lang;if(!m(e)){if(s=a(e))return s;e=[e]}for(;r0;){if(s=a(o.slice(0,i).join("-")))return s;if(n&&n.length>=i&&y(o,n,!0)>=i-1)break;i--}r++}return le.fn._lang}function P(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function A(t){var e,i,s=t.match(Ne);for(e=0,i=s.length;i>e;e++)s[e]=oi[s[e]]?oi[s[e]]:P(s[e]);return function(n){var o="";for(e=0;i>e;e++)o+=s[e]instanceof Function?s[e].call(n,t):s[e];return o}}function z(t,e){return t.isValid()?(e=F(e,t.lang()),ii[e]||(ii[e]=A(e)),ii[e](t)):t.lang().invalidDate()}function F(t,e){function i(t){return e.longDateFormat(t)||t}var s=5;for(Oe.lastIndex=0;s>=0&&Oe.test(t);)t=t.replace(Oe,i),Oe.lastIndex=0,s-=1;return t}function R(t,e){var i,s=e._strict;switch(t){case"Q":return We;case"DDDD":return je;case"YYYY":case"GGGG":case"gggg":return s?Ue:Pe;case"Y":case"G":case"g":return qe;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return s?Ve:Ae;case"S":if(s)return We;case"SS":if(s)return Be;case"SSS":if(s)return je;case"DDD":return ke;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Fe;case"a":case"A":return k(e._l)._meridiemParse;case"X":return Ye;case"Z":case"ZZ":return Re;case"T":return He;case"SSSS":return ze;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return s?Be:Le;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return Le;case"Do":return Ge;default:return i=new RegExp(V(U(t.replace("\\","")),"i"))}}function H(t){t=t||"";var e=t.match(Re)||[],i=e[e.length-1]||[],s=(i+"").match($e)||["-",0,0],n=+(60*s[1])+S(s[2]);return"+"===s[0]?-n:n}function Y(t,e,i){var s,n=i._a;switch(t){case"Q":null!=e&&(n[ye]=3*(S(e)-1));break;case"M":case"MM":null!=e&&(n[ye]=S(e)-1);break;case"MMM":case"MMMM":s=k(i._l).monthsParse(e),null!=s?n[ye]=s:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(n[_e]=S(e));break;case"Do":null!=e&&(n[_e]=S(parseInt(e,10)));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=S(e));break;case"YY":n[ve]=le.parseTwoDigitYear(e);break;case"YYYY":case"YYYYY":case"YYYYYY":n[ve]=S(e);break;case"a":case"A":i._isPm=k(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":n[be]=S(e);break;case"m":case"mm":n[we]=S(e);break;case"s":case"ss":n[Se]=S(e);break;case"S":case"SS":case"SSS":case"SSSS":n[xe]=S(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=H(e);break;case"w":case"ww":case"W":case"WW":case"d":case"dd":case"ddd":case"dddd":case"e":case"E":t=t.substr(0,1);case"gg":case"gggg":case"GG":case"GGGG":case"GGGGG":t=t.substr(0,2),e&&(i._w=i._w||{},i._w[t]=e)}}function G(t){var e,i,s,n,o,r,a,h,d,c,l=[];if(!t._d){for(s=B(t),t._w&&null==t._a[_e]&&null==t._a[ye]&&(o=function(e){var i=parseInt(e,10);return e?e.length<3?i>68?1900+i:2e3+i:i:null==t._a[ve]?le().weekYear():t._a[ve]},r=t._w,null!=r.GG||null!=r.W||null!=r.E?a=ie(o(r.GG),r.W||1,r.E,4,1):(h=k(t._l),d=null!=r.d?$(r.d,h):null!=r.e?parseInt(r.e,10)+h._week.dow:0,c=parseInt(r.w,10)||1,null!=r.d&&dT(n)&&(t._pf._overflowDayOfYear=!0),i=Q(n,0,t._dayOfYear),t._a[ye]=i.getUTCMonth(),t._a[_e]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=l[e]=s[e];for(;7>e;e++)t._a[e]=l[e]=null==t._a[e]?2===e?1:0:t._a[e];l[be]+=S((t._tzm||0)/60),l[we]+=S((t._tzm||0)%60),t._d=(t._useUTC?Q:K).apply(null,l)}}function W(t){var e;t._d||(e=b(t._i),t._a=[e.year,e.month,e.day,e.hour,e.minute,e.second,e.millisecond],G(t))}function B(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function j(t){t._a=[],t._pf.empty=!0;var e,i,s,n,o,r=k(t._l),a=""+t._i,h=a.length,d=0;for(s=F(t._f,r).match(Ne)||[],e=0;e0&&t._pf.unusedInput.push(o),a=a.slice(a.indexOf(i)+i.length),d+=i.length),oi[n]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(n),Y(n,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(n);t._pf.charsLeftOver=h-d,a.length>0&&t._pf.unusedInput.push(a),t._isPm&&t._a[be]<12&&(t._a[be]+=12),t._isPm===!1&&12===t._a[be]&&(t._a[be]=0),G(t),C(t)}function U(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,s,n){return e||i||s||n})}function V(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function q(t){var e,i,s,o,r;if(0===t._f.length)return t._pf.invalidFormat=!0,void(t._d=new Date(0/0));for(o=0;or)&&(s=r,i=e));l(t,i||e)}function X(t){var e,i,s=t._i,n=Xe.exec(s);if(n){for(t._pf.iso=!0,e=0,i=Ke.length;i>e;e++)if(Ke[e][1].exec(s)){t._f=Ke[e][0]+(n[6]||" ");break}for(e=0,i=Qe.length;i>e;e++)if(Qe[e][1].exec(s)){t._f+=Qe[e][0];break}s.match(Re)&&(t._f+="Z"),j(t)}else le.createFromInputFallback(t)}function Z(t){var e=t._i,i=Ce.exec(e);e===s?t._d=new Date:i?t._d=new Date(+i[1]):"string"==typeof e?X(t):m(e)?(t._a=e.slice(0),G(t)):v(e)?t._d=new Date(+e):"object"==typeof e?W(t):"number"==typeof e?t._d=new Date(e):le.createFromInputFallback(t)}function K(t,e,i,s,n,o,r){var a=new Date(t,e,i,s,n,o,r);return 1970>t&&a.setFullYear(t),a}function Q(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function $(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 J(t,e,i,s,n){return n.relativeTime(e||1,!!i,t,s)}function te(t,e,i){var s=me(Math.abs(t)/1e3),n=me(s/60),o=me(n/60),r=me(o/24),a=me(r/365),h=45>s&&["s",s]||1===n&&["m"]||45>n&&["mm",n]||1===o&&["h"]||22>o&&["hh",o]||1===r&&["d"]||25>=r&&["dd",r]||45>=r&&["M"]||345>r&&["MM",me(r/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,J.apply({},h)}function ee(t,e,i){var s,n=i-e,o=i-t.day();return o>n&&(o-=7),n-7>o&&(o+=7),s=le(t).add("d",o),{week:Math.ceil(s.dayOfYear()/7),year:s.year()}}function ie(t,e,i,s,n){var o,r,a=Q(t,0,1).getUTCDay();return i=null!=i?i:n,o=n-a+(a>s?7:0)-(n>a?7:0),r=7*(e-1)+(i-n)+o+1,{year:r>0?t:t-1,dayOfYear:r>0?r:T(t-1)+r}}function se(t){var e=t._i,i=t._f;return null===e||i===s&&""===e?le.invalid({nullInput:!0}):("string"==typeof e&&(t._i=e=k().preparse(e)),le.isMoment(e)?(t=u(e),t._d=new Date(+e._d)):i?m(i)?q(t):j(t):Z(t),new d(t))}function ne(t,e){var i;return"string"==typeof e&&(e=t.lang().monthsParse(e),"number"!=typeof e)?t:(i=Math.min(t.date(),x(t.year(),e)),t._d["set"+(t._isUTC?"UTC":"")+"Month"](e,i),t)}function oe(t,e){return t._d["get"+(t._isUTC?"UTC":"")+e]()}function re(t,e,i){return"Month"===e?ne(t,i):t._d["set"+(t._isUTC?"UTC":"")+e](i)}function ae(t,e){return function(i){return null!=i?(re(this,t,i),le.updateOffset(this,e),this):oe(this,t)}}function he(t){le.duration.fn[t]=function(){return this._data[t]}}function de(t,e){le.duration.fn["as"+t]=function(){return+this/e}}function ce(t){"undefined"==typeof ender&&(ue=fe.moment,fe.moment=t?o("Accessing Moment through the global scope is deprecated, and will be removed in an upcoming release.",le):le)}for(var le,ue,pe,ge="2.6.0",fe="undefined"!=typeof i?i:this,me=Math.round,ve=0,ye=1,_e=2,be=3,we=4,Se=5,xe=6,Ee={},Te={_isAMomentObject:null,_i:null,_f:null,_l:null,_strict:null,_isUTC:null,_offset:null,_pf:null,_lang:null},De="undefined"!=typeof e&&e.exports,Ce=/^\/?Date\((\-?\d+)/i,Me=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,Ie=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,Ne=/(\[[^\[]*\])|(\\)?(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|zz?|ZZ?|.)/g,Oe=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,Le=/\d\d?/,ke=/\d{1,3}/,Pe=/\d{1,4}/,Ae=/[+\-]?\d{1,6}/,ze=/\d+/,Fe=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Re=/Z|[\+\-]\d\d:?\d\d/gi,He=/T/i,Ye=/[\+\-]?\d+(\.\d{1,3})?/,Ge=/\d{1,2}/,We=/\d/,Be=/\d\d/,je=/\d{3}/,Ue=/\d{4}/,Ve=/[+-]?\d{6}/,qe=/[+-]?\d+/,Xe=/^\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)?)?$/,Ze="YYYY-MM-DDTHH:mm:ssZ",Ke=[["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}/]],Qe=[["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/]],$e=/([\+\-]|\d\d)/gi,Je=("Date|Hours|Minutes|Seconds|Milliseconds".split("|"),{Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6}),ti={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"},ei={dayofyear:"dayOfYear",isoweekday:"isoWeekday",isoweek:"isoWeek",weekyear:"weekYear",isoweekyear:"isoWeekYear"},ii={},si="DDD w W M D d".split(" "),ni="M D H h m s w W".split(" "),oi={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return g(this.year()%100,2)},YYYY:function(){return g(this.year(),4)},YYYYY:function(){return g(this.year(),5)},YYYYYY:function(){var t=this.year(),e=t>=0?"+":"-";return e+g(Math.abs(t),6)},gg:function(){return g(this.weekYear()%100,2)},gggg:function(){return g(this.weekYear(),4)},ggggg:function(){return g(this.weekYear(),5)},GG:function(){return g(this.isoWeekYear()%100,2)},GGGG:function(){return g(this.isoWeekYear(),4)},GGGGG:function(){return g(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().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 S(this.milliseconds()/100)},SS:function(){return g(S(this.milliseconds()/10),2)},SSS:function(){return g(this.milliseconds(),3)},SSSS:function(){return g(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+g(S(t/60),2)+":"+g(S(t)%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+g(S(t/60),2)+g(S(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},ri=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];si.length;)pe=si.pop(),oi[pe+"o"]=a(oi[pe],pe);for(;ni.length;)pe=ni.pop(),oi[pe+pe]=r(oi[pe],2);for(oi.DDDD=r(oi.DDD,3),l(h.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e},_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){var e,i,s;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=le.utc([2e3,e]),s="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=new RegExp(s.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_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=le([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:{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){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_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 n=this._relativeTime[i];return"function"==typeof n?n(t,e,i,s):n.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",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return ee(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),le=function(t,e,i,o){var r;return"boolean"==typeof i&&(o=i,i=s),r={},r._isAMomentObject=!0,r._i=t,r._f=e,r._l=i,r._strict=o,r._isUTC=!1,r._pf=n(),se(r)},le.suppressDeprecationWarnings=!1,le.createFromInputFallback=o("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)}),le.utc=function(t,e,i,o){var r;return"boolean"==typeof i&&(o=i,i=s),r={},r._isAMomentObject=!0,r._useUTC=!0,r._isUTC=!0,r._l=i,r._i=t,r._f=e,r._strict=o,r._pf=n(),se(r).utc()},le.unix=function(t){return le(1e3*t) -},le.duration=function(t,e){var i,s,n,o=t,r=null;return le.isDuration(t)?o={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(o={},e?o[e]=t:o.milliseconds=t):(r=Me.exec(t))?(i="-"===r[1]?-1:1,o={y:0,d:S(r[_e])*i,h:S(r[be])*i,m:S(r[we])*i,s:S(r[Se])*i,ms:S(r[xe])*i}):(r=Ie.exec(t))&&(i="-"===r[1]?-1:1,n=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},o={y:n(r[2]),M:n(r[3]),d:n(r[4]),h:n(r[5]),m:n(r[6]),s:n(r[7]),w:n(r[8])}),s=new c(o),le.isDuration(t)&&t.hasOwnProperty("_lang")&&(s._lang=t._lang),s},le.version=ge,le.defaultFormat=Ze,le.momentProperties=Te,le.updateOffset=function(){},le.lang=function(t,e){var i;return t?(e?O(I(t),e):null===e?(L(t),t="en"):Ee[t]||k(t),i=le.duration.fn._lang=le.fn._lang=k(t),i._abbr):le.fn._lang._abbr},le.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),k(t)},le.isMoment=function(t){return t instanceof d||null!=t&&t.hasOwnProperty("_isAMomentObject")},le.isDuration=function(t){return t instanceof c},pe=ri.length-1;pe>=0;--pe)w(ri[pe]);le.normalizeUnits=function(t){return _(t)},le.invalid=function(t){var e=le.utc(0/0);return null!=t?l(e._pf,t):e._pf.userInvalidated=!0,e},le.parseZone=function(){return le.apply(null,arguments).parseZone()},le.parseTwoDigitYear=function(t){return S(t)+(S(t)>68?1900:2e3)},l(le.fn=d.prototype,{clone:function(){return le(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().lang("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=le(this).utc();return 00:!1},parsingFlags:function(){return l({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(t){var e=z(this,t||le.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?le.duration(+e,t):le.duration(t,e),f(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?le.duration(+e,t):le.duration(t,e),f(this,i,-1),this},diff:function(t,e,i){var s,n,o=N(t,this),r=6e4*(this.zone()-o.zone());return e=_(e),"year"===e||"month"===e?(s=432e5*(this.daysInMonth()+o.daysInMonth()),n=12*(this.year()-o.year())+(this.month()-o.month()),n+=(this-le(this).startOf("month")-(o-le(o).startOf("month")))/s,n-=6e4*(this.zone()-le(this).startOf("month").zone()-(o.zone()-le(o).startOf("month").zone()))/s,"year"===e&&(n/=12)):(s=this-o,n="second"===e?s/1e3:"minute"===e?s/6e4:"hour"===e?s/36e5:"day"===e?(s-r)/864e5:"week"===e?(s-r)/6048e5:s),i?n:p(n)},from:function(t,e){return le.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(le(),t)},calendar:function(){var t=N(le(),this).startOf("day"),e=this.diff(t,"days",!0),i=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse";return this.format(this.lang().calendar(i,this))},isLeapYear:function(){return D(this.year())},isDST:function(){return this.zone()+le(t).startOf(e)},isBefore:function(t,e){return e="undefined"!=typeof e?e:"millisecond",+this.clone().startOf(e)<+le(t).startOf(e)},isSame:function(t,e){return e=e||"ms",+this.clone().startOf(e)===+N(t,this).startOf(e)},min:function(t){return t=le.apply(null,arguments),this>t?this:t},max:function(t){return t=le.apply(null,arguments),t>this?this:t},zone:function(t,e){var i=this._offset||0;return null==t?this._isUTC?i:this._d.getTimezoneOffset():("string"==typeof t&&(t=H(t)),Math.abs(t)<16&&(t=60*t),this._offset=t,this._isUTC=!0,i!==t&&(!e||this._changeInProgress?f(this,le.duration(i-t,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,le.updateOffset(this,!0),this._changeInProgress=null)),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(t){return t=t?le(t).zone():0,(this.zone()-t)%60===0},daysInMonth:function(){return x(this.year(),this.month())},dayOfYear:function(t){var e=me((le(this).startOf("day")-le(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},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=ee(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==t?e:this.add("y",t-e)},isoWeekYear:function(t){var e=ee(this,1,4).year;return null==t?e:this.add("y",t-e)},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},isoWeek:function(t){var e=ee(this,1,4).week;return null==t?e:this.add("d",7*(t-e))},weekday:function(t){var e=(this.day()+7-this.lang()._week.dow)%7;return null==t?e:this.add("d",t-e)},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},isoWeeksInYear:function(){return E(this.year(),1,4)},weeksInYear:function(){var t=this._lang._week;return E(this.year(),t.dow,t.doy)},get:function(t){return t=_(t),this[t]()},set:function(t,e){return t=_(t),"function"==typeof this[t]&&this[t](e),this},lang:function(t){return t===s?this._lang:(this._lang=k(t),this)}}),le.fn.millisecond=le.fn.milliseconds=ae("Milliseconds",!1),le.fn.second=le.fn.seconds=ae("Seconds",!1),le.fn.minute=le.fn.minutes=ae("Minutes",!1),le.fn.hour=le.fn.hours=ae("Hours",!0),le.fn.date=ae("Date",!0),le.fn.dates=o("dates accessor is deprecated. Use date instead.",ae("Date",!0)),le.fn.year=ae("FullYear",!0),le.fn.years=o("years accessor is deprecated. Use year instead.",ae("FullYear",!0)),le.fn.days=le.fn.day,le.fn.months=le.fn.month,le.fn.weeks=le.fn.week,le.fn.isoWeeks=le.fn.isoWeek,le.fn.quarters=le.fn.quarter,le.fn.toJSON=le.fn.toISOString,l(le.duration.fn=c.prototype,{_bubble:function(){var t,e,i,s,n=this._milliseconds,o=this._days,r=this._months,a=this._data;a.milliseconds=n%1e3,t=p(n/1e3),a.seconds=t%60,e=p(t/60),a.minutes=e%60,i=p(e/60),a.hours=i%24,o+=p(i/24),a.days=o%30,r+=p(o/30),a.months=r%12,s=p(r/12),a.years=s},weeks:function(){return p(this.days()/7)},valueOf:function(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*S(this._months/12)},humanize:function(t){var e=+this,i=te(e,!t,this.lang());return t&&(i=this.lang().pastFuture(e,i)),this.lang().postformat(i)},add:function(t,e){var i=le.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=le.duration(t,e);return this._milliseconds-=i._milliseconds,this._days-=i._days,this._months-=i._months,this._bubble(),this},get:function(t){return t=_(t),this[t.toLowerCase()+"s"]()},as:function(t){return t=_(t),this["as"+t.charAt(0).toUpperCase()+t.slice(1)+"s"]()},lang:le.fn.lang,toIsoString:function(){var t=Math.abs(this.years()),e=Math.abs(this.months()),i=Math.abs(this.days()),s=Math.abs(this.hours()),n=Math.abs(this.minutes()),o=Math.abs(this.seconds()+this.milliseconds()/1e3);return this.asSeconds()?(this.asSeconds()<0?"-":"")+"P"+(t?t+"Y":"")+(e?e+"M":"")+(i?i+"D":"")+(s||n||o?"T":"")+(s?s+"H":"")+(n?n+"M":"")+(o?o+"S":""):"P0D"}});for(pe in Je)Je.hasOwnProperty(pe)&&(de(pe,Je[pe]),he(pe.toLowerCase()));de("Weeks",6048e5),le.duration.fn.asMonths=function(){return(+this-31536e6*this.years())/2592e6+12*this.years()},le.lang("en",{ordinal:function(t){var e=t%10,i=1===S(t%100/10)?"th":1===e?"st":2===e?"nd":3===e?"rd":"th";return t+i}}),De?e.exports=le:"function"==typeof define&&define.amd?(define("moment",function(t,e,i){return i.config&&i.config()&&i.config().noGlobal===!0&&(fe.moment=ue),le}),ce(!0)):ce()}).call(this)},{}],5:[function(t,e){function i(t,e,i){return t.addEventListener?t.addEventListener(e,i,!1):void t.attachEvent("on"+e,i)}function s(t){return"keypress"==t.type?String.fromCharCode(t.which):w[t.which]?w[t.which]:S[t.which]?S[t.which]:String.fromCharCode(t.which).toLowerCase()}function n(t){var e=t.target||t.srcElement,i=e.tagName;return(" "+e.className+" ").indexOf(" mousetrap ")>-1?!1:"INPUT"==i||"SELECT"==i||"TEXTAREA"==i||e.contentEditable&&"true"==e.contentEditable}function o(t,e){return t.sort().join(",")===e.sort().join(",")}function r(t){t=t||{};var e,i=!1;for(e in C)t[e]?i=!0:C[e]=0;i||(I=!1)}function a(t,e,i,s,n){var r,a,h=[];if(!T[t])return[];for("keyup"==i&&u(t)&&(e=[t]),r=0;r95&&112>t||w.hasOwnProperty(t)&&(_[w[t]]=t)}return _}function f(t,e,i){return i||(i=g()[t]?"keydown":"keypress"),"keypress"==i&&e.length&&(i="keydown"),i}function m(t,e,i,n){C[t]=0,n||(n=f(e[0],[]));var o,a=function(){I=n,++C[t],p()},h=function(t){d(i,t),"keyup"!==n&&(M=s(t)),setTimeout(r,10)};for(o=0;o1)return m(t,d,e,i);for(h="+"===t?["+"]:t.split("+"),o=0;o":".","?":"/","|":"\\"},E={option:"alt",command:"meta","return":"enter",escape:"esc"},T={},D={},C={},M=!1,I=!1,N=1;20>N;++N)w[111+N]="f"+N;for(N=0;9>=N;++N)w[N+96]=N;i(document,"keypress",l),i(document,"keydown",l),i(document,"keyup",l);var O={bind:function(t,e,i){return y(t instanceof Array?t:[t],e,i),D[t+":"+i]=e,this},unbind:function(t,e){return D[t+":"+e]&&(delete D[t+":"+e],this.bind(t,function(){},e)),this},trigger:function(t,e){return D[t+":"+e](),this},reset:function(){return T={},D={},this}};e.exports=O},{}]},{},[1])(1)}); \ No newline at end of file +!function(t){if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else{var e;"undefined"!=typeof window?e=window:"undefined"!=typeof global?e=global:"undefined"!=typeof self&&(e=self),e.vis=t()}}(function(){var define,module,exports;return function t(e,i,s){function n(a,r){if(!i[a]){if(!e[a]){var h="function"==typeof require&&require;if(!r&&h)return h(a,!0);if(o)return o(a,!0);throw new Error("Cannot find module '"+a+"'")}var d=i[a]={exports:{}};e[a][0].call(d.exports,function(t){var i=e[a][1][t];return n(i?i:t)},d,d.exports,t,e,i,s)}return i[a].exports}for(var o="function"==typeof require&&require,a=0;ai;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,s,n;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),a=o.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),s=new Array(a),n=0;a>n;){var r,h;n in o&&(r=o[n],h=t.call(i,r,n,o),s[n]=h),n++}return s}),Array.prototype.filter||(Array.prototype.filter=function(t){"use strict";if(null==this)throw new TypeError;var e=Object(this),i=e.length>>>0;if("function"!=typeof t)throw new TypeError;for(var s=[],n=arguments[1],o=0;i>o;o++)if(o in e){var a=e[o];t.call(n,a,o,e)&&s.push(a)}return s}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],s=i.length;return function(n){if("object"!=typeof n&&"function"!=typeof n||null===n)throw new TypeError("Object.keys called on non-object");var o=[];for(var a in n)t.call(n,a)&&o.push(a);if(e)for(var r=0;s>r;r++)t.call(n,i[r])&&o.push(i[r]);return o}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,s=function(){},n=function(){return i.apply(this instanceof s&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return s.prototype=this.prototype,n.prototype=new s,n}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw new Error("Object.create implementation only accepts the first parameter.");return e.prototype=t,new e}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,s=function(){},n=function(){return i.apply(this instanceof s&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return s.prototype=this.prototype,n.prototype=new s,n});var util={};util.isNumber=function(t){return t instanceof Number||"number"==typeof t},util.isString=function(t){return t instanceof String||"string"==typeof t},util.isDate=function(t){if(t instanceof Date)return!0;if(util.isString(t)){var e=ASPDateRegex.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},util.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},util.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},util.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var s=arguments[e];for(var n in s)s.hasOwnProperty(n)&&void 0!==s[n]&&(t[n]=s[n])}return t},util.equalArray=function(t,e){if(t.length!=e.length)return!1;for(var i=1,s=t.length;s>i;i++)if(t[i]!=e[i])return!1;return!0},util.convert=function(t,e){var i;if(void 0===t)return void 0;if(null===t)return null;if(!e)return t;if("string"!=typeof e&&!(e instanceof String))throw new Error("Type must be a string");switch(e){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(util.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(moment.isMoment(t))return new Date(t.valueOf());if(util.isString(t))return i=ASPDateRegex.exec(t),i?new Date(Number(i[1])):moment(t).toDate();throw new Error("Cannot convert object of type "+util.getType(t)+" to type Date");case"Moment":if(util.isNumber(t))return moment(t);if(t instanceof Date)return moment(t.valueOf());if(moment.isMoment(t))return moment(t);if(util.isString(t))return i=ASPDateRegex.exec(t),moment(i?Number(i[1]):t);throw new Error("Cannot convert object of type "+util.getType(t)+" to type Date");case"ISODate":if(util.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(moment.isMoment(t))return t.toDate().toISOString();if(util.isString(t))return i=ASPDateRegex.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw new Error("Cannot convert object of type "+util.getType(t)+" to type ISODate");case"ASPDate":if(util.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(util.isString(t)){i=ASPDateRegex.exec(t);var s;return s=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+s+")/"}throw new Error("Cannot convert object of type "+util.getType(t)+" to type ASPDate");default:throw new Error("Cannot convert object of type "+util.getType(t)+' to type "'+e+'"')}};var ASPDateRegex=/^\/?Date\((\-?\d+)/i;util.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":t instanceof Array?"Array":t instanceof Date?"Date":"Object":"number"==e?"Number":"boolean"==e?"Boolean":"string"==e?"String":e},util.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,s=t.offsetLeft,n=t.offsetParent;null!=n&&n!=i&&n!=e;)s+=n.offsetLeft,s-=n.scrollLeft,n=n.offsetParent;return s},util.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,s=t.offsetTop,n=t.offsetParent;null!=n&&n!=i&&n!=e;)s+=n.offsetTop,s-=n.scrollTop,n=n.offsetParent;return s},util.getPageY=function(t){if("pageY"in t)return t.pageY;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientY:t.clientY;var i=document.documentElement,s=document.body;return e+(i&&i.scrollTop||s&&s.scrollTop||0)-(i&&i.clientTop||s&&s.clientTop||0)},util.getPageX=function(t){if("pageY"in t)return t.pageX;var e;e="targetTouches"in t&&t.targetTouches.length?t.targetTouches[0].clientX:t.clientX;var i=document.documentElement,s=document.body;return e+(i&&i.scrollLeft||s&&s.scrollLeft||0)-(i&&i.clientLeft||s&&s.clientLeft||0)},util.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},util.removeClassName=function(t,e){var i=t.className.split(" "),s=i.indexOf(e);-1!=s&&(i.splice(s,1),t.className=i.join(" "))},util.forEach=function(t,e){var i,s;if(t instanceof Array)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)},util.toArray=function(t){var e=[];for(var i in t)t.hasOwnProperty(i)&&e.push(t[i]);return e},util.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},util.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)},util.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)},util.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},util.fakeGesture=function(t,e){var i=null,s=Hammer.event.collectEventData(this,i,e);return isNaN(s.center.pageX)&&(s.center.pageX=e.pageX),isNaN(s.center.pageY)&&(s.center.pageY=e.pageY),s},util.option={},util.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},util.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},util.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?String(t):e||null},util.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),util.isString(t)?t:util.isNumber(t)?t+"px":e||null +},util.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null},util.GiveDec=function GiveDec(Hex){var Value;return Value="A"==Hex?10:"B"==Hex?11:"C"==Hex?12:"D"==Hex?13:"E"==Hex?14:"F"==Hex?15:eval(Hex)},util.GiveHex=function(t){var e;return e=10==t?"A":11==t?"B":12==t?"C":13==t?"D":14==t?"E":15==t?"F":""+t},util.parseColor=function(t){var e;if(util.isString(t))if(util.isValidHex(t)){var i=util.hexToHSV(t),s={h:i.h,s:.45*i.s,v:Math.min(1,1.05*i.v)},n={h:i.h,s:Math.min(1,1.25*i.v),v:.6*i.v},o=util.HSVToHex(n.h,n.h,n.v),a=util.HSVToHex(s.h,s.s,s.v);e={background:t,border:o,highlight:{background:a,border:o}}}else e={background:t,border:t,highlight:{background:t,border:t}};else e={},e.background=t.background||"white",e.border=t.border||e.background,util.isString(t.highlight)?e.highlight={border:t.highlight,background:t.highlight}:(e.highlight={},e.highlight.background=t.highlight&&t.highlight.background||e.background,e.highlight.border=t.highlight&&t.highlight.border||e.border);return e},util.hexToRGB=function(t){t=t.replace("#","").toUpperCase();var e=util.GiveDec(t.substring(0,1)),i=util.GiveDec(t.substring(1,2)),s=util.GiveDec(t.substring(2,3)),n=util.GiveDec(t.substring(3,4)),o=util.GiveDec(t.substring(4,5)),a=util.GiveDec(t.substring(5,6)),r=16*e+i,h=16*s+n,i=16*o+a;return{r:r,g:h,b:i}},util.RGBToHex=function(t,e,i){var s=util.GiveHex(Math.floor(t/16)),n=util.GiveHex(t%16),o=util.GiveHex(Math.floor(e/16)),a=util.GiveHex(e%16),r=util.GiveHex(Math.floor(i/16)),h=util.GiveHex(i%16),d=s+n+o+a+r+h;return"#"+d},util.RGBToHSV=function(t,e,i){t/=255,e/=255,i/=255;var s=Math.min(t,Math.min(e,i)),n=Math.max(t,Math.max(e,i));if(s==n)return{h:0,s:0,v:s};var o=t==s?e-i:i==s?t-e:i-t,a=t==s?3:i==s?1:5,r=60*(a-o/(n-s))/360,h=(n-s)/n,d=n;return{h:r,s:h,v:d}},util.HSVToRGB=function(t,e,i){var s,n,o,a=Math.floor(6*t),r=6*t-a,h=i*(1-e),d=i*(1-r*e),c=i*(1-(1-r)*e);switch(a%6){case 0:s=i,n=c,o=h;break;case 1:s=d,n=i,o=h;break;case 2:s=h,n=i,o=c;break;case 3:s=h,n=d,o=i;break;case 4:s=c,n=h,o=i;break;case 5:s=i,n=h,o=d}return{r:Math.floor(255*s),g:Math.floor(255*n),b:Math.floor(255*o)}},util.HSVToHex=function(t,e,i){var s=util.HSVToRGB(t,e,i);return util.RGBToHex(s.r,s.g,s.b)},util.hexToHSV=function(t){var e=util.hexToRGB(t);return util.RGBToHSV(e.r,e.g,e.b)},util.isValidHex=function(t){var e=/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(t);return e},util.copyObject=function(t,e){for(var i in t)t.hasOwnProperty(i)&&("object"==typeof t[i]?(e[i]={},util.copyObject(t[i],e[i])):e[i]=t[i])},DataSet.prototype.on=function(t,e){var i=this.subscribers[t];i||(i=[],this.subscribers[t]=i),i.push({callback:e})},DataSet.prototype.subscribe=DataSet.prototype.on,DataSet.prototype.off=function(t,e){var i=this.subscribers[t];i&&(this.subscribers[t]=i.filter(function(t){return t.callback!=e}))},DataSet.prototype.unsubscribe=DataSet.prototype.off,DataSet.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 n=0;no;o++)i=n._addItem(t[o]),s.push(i);else if(util.isDataTable(t))for(var r=this._getColumnNames(t),h=0,d=t.getNumberOfRows();d>h;h++){for(var c={},l=0,u=r.length;u>l;l++){var p=r[l];c[p]=t.getValue(h,l)}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},DataSet.prototype.update=function(t,e){var i=[],s=[],n=this,o=n.fieldId,a=function(t){var e=t[o];n.data[e]?(e=n._updateItem(t),s.push(e)):(e=n._addItem(t),i.push(e))};if(t instanceof Array)for(var r=0,h=t.length;h>r;r++)a(t[r]);else if(util.isDataTable(t))for(var d=this._getColumnNames(t),c=0,l=t.getNumberOfRows();l>c;c++){for(var u={},p=0,g=d.length;g>p;p++){var m=d[p];u[m]=t.getValue(c,p)}a(u)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");a(t)}return i.length&&this._trigger("add",{items:i},e),s.length&&this._trigger("update",{items:s},e),i.concat(s)},DataSet.prototype.get=function(){var t,e,i,s,n=this,o=this.showInternalIds,a=util.getType(arguments[0]);"String"==a||"Number"==a?(t=arguments[0],i=arguments[1],s=arguments[2]):"Array"==a?(e=arguments[0],i=arguments[1],s=arguments[2]):(i=arguments[0],s=arguments[1]);var r;if(i&&i.type){if(r="DataTable"==i.type?"DataTable":"Array",s&&r!=util.getType(s))throw new Error('Type of parameter "data" ('+util.getType(s)+") does not correspond with specified options.type ("+i.type+")");if("DataTable"==r&&!util.isDataTable(s))throw new Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else r=s&&"DataTable"==util.getType(s)?"DataTable":"Array";void 0!=i&&void 0!=i.showInternalIds&&(this.showInternalIds=i.showInternalIds);var h,d,c,l,u=i&&i.convert||this.options.convert,p=i&&i.filter,g=[];if(void 0!=t)h=n._getItem(t,u),p&&!p(h)&&(h=null);else if(void 0!=e)for(c=0,l=e.length;l>c;c++)h=n._getItem(e[c],u),(!p||p(h))&&g.push(h);else for(d in this.data)this.data.hasOwnProperty(d)&&(h=n._getItem(d,u),(!p||p(h))&&g.push(h));if(this.showInternalIds=o,i&&i.order&&void 0==t&&this._sort(g,i.order),i&&i.fields){var m=i.fields;if(void 0!=t)h=this._filterFields(h,m);else for(c=0,l=g.length;l>c;c++)g[c]=this._filterFields(g[c],m)}if("DataTable"==r){var f=this._getColumnNames(s);if(void 0!=t)n._appendRow(s,f,h);else for(c=0,l=g.length;l>c;c++)n._appendRow(s,f,g[c]);return s}if(void 0!=t)return h;if(s){for(c=0,l=g.length;l>c;c++)s.push(g[c]);return s}return g},DataSet.prototype.getIds=function(t){var e,i,s,n,o,a=this.data,r=t&&t.filter,h=t&&t.order,d=t&&t.convert||this.options.convert,c=[];if(r)if(h){o=[];for(s in a)a.hasOwnProperty(s)&&(n=this._getItem(s,d),r(n)&&o.push(n));for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(s in a)a.hasOwnProperty(s)&&(n=this._getItem(s,d),r(n)&&c.push(n[this.fieldId]));else if(h){o=[];for(s in a)a.hasOwnProperty(s)&&o.push(a[s]);for(this._sort(o,h),e=0,i=o.length;i>e;e++)c[e]=o[e][this.fieldId]}else for(s in a)a.hasOwnProperty(s)&&(n=a[s],c.push(n[this.fieldId]));return c},DataSet.prototype.forEach=function(t,e){var i,s,n=e&&e.filter,o=e&&e.convert||this.options.convert,a=this.data;if(e&&e.order)for(var r=this.get(e),h=0,d=r.length;d>h;h++)i=r[h],s=i[this.fieldId],t(i,s);else for(s in a)a.hasOwnProperty(s)&&(i=this._getItem(s,o),(!n||n(i))&&t(i,s))},DataSet.prototype.map=function(t,e){var i,s=e&&e.filter,n=e&&e.convert||this.options.convert,o=[],a=this.data;for(var r in a)a.hasOwnProperty(r)&&(i=this._getItem(r,n),(!s||s(i))&&o.push(t(i,r)));return e&&e.order&&this._sort(o,e.order),o},DataSet.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},DataSet.prototype._sort=function(t,e){if(util.isString(e)){var i=e;t.sort(function(t,e){var s=t[i],n=e[i];return s>n?1:n>s?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},DataSet.prototype.remove=function(t,e){var i,s,n,o=[];if(t instanceof Array)for(i=0,s=t.length;s>i;i++)n=this._remove(t[i]),null!=n&&o.push(n);else n=this._remove(t),null!=n&&o.push(n);return o.length&&this._trigger("remove",{items:o},e),o},DataSet.prototype._remove=function(t){if(util.isNumber(t)||util.isString(t)){if(this.data[t])return delete this.data[t],delete this.internalIds[t],t}else if(t instanceof Object){var e=t[this.fieldId];if(e&&this.data[e])return delete this.data[e],delete this.internalIds[e],e}return null},DataSet.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},DataSet.prototype.max=function(t){var e=this.data,i=null,s=null;for(var n in e)if(e.hasOwnProperty(n)){var o=e[n],a=o[t];null!=a&&(!i||a>s)&&(i=o,s=a)}return i},DataSet.prototype.min=function(t){var e=this.data,i=null,s=null;for(var n in e)if(e.hasOwnProperty(n)){var o=e[n],a=o[t];null!=a&&(!i||s>a)&&(i=o,s=a)}return i},DataSet.prototype.distinct=function(t){var e=this.data,i=[],s=this.options.convert[t],n=0;for(var o in e)if(e.hasOwnProperty(o)){for(var a=e[o],r=util.convert(a[t],s),h=!1,d=0;n>d;d++)if(i[d]==r){h=!0;break}h||void 0===r||(i[n]=r,n++)}return i},DataSet.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw new Error("Cannot add item: item with id "+e+" already exists")}else e=util.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var s in t)if(t.hasOwnProperty(s)){var n=this.convert[s];i[s]=util.convert(t[s],n)}return this.data[e]=i,e},DataSet.prototype._getItem=function(t,e){var i,s,n=this.data[t];if(!n)return null;var o={},a=this.fieldId,r=this.internalIds;if(e)for(i in n)n.hasOwnProperty(i)&&(s=n[i],i==a&&s in r&&!this.showInternalIds||(o[i]=util.convert(s,e[i])));else for(i in n)n.hasOwnProperty(i)&&(s=n[i],i==a&&s in r&&!this.showInternalIds||(o[i]=s));return o},DataSet.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw new Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw new Error("Cannot update item: no item with id "+e+" found");for(var s in t)if(t.hasOwnProperty(s)){var n=this.convert[s];i[s]=util.convert(t[s],n)}return e},DataSet.prototype.isInternalId=function(t){return t in this.internalIds},DataSet.prototype._getColumnNames=function(t){for(var e=[],i=0,s=t.getNumberOfColumns();s>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},DataSet.prototype._appendRow=function(t,e,i){for(var s=t.addRow(),n=0,o=e.length;o>n;n++){var a=e[n];t.setValue(s,n,i[a])}},DataView.prototype.setData=function(t){var e,i,s;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var n in this.ids)this.ids.hasOwnProperty(n)&&e.push(n);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++)n=e[i],this.ids[n]=!0;this._trigger("add",{items:e}),this.data.on&&this.data.on("*",this.listener)}},DataView.prototype.get=function(){var t,e,i,s=this,n=util.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 o=util.extend({},this.options,e);this.options.filter&&e&&e.filter&&(o.filter=function(t){return s.options.filter(t)&&e.filter(t)});var a=[];return void 0!=t&&a.push(t),a.push(o),a.push(i),this.data&&this.data.get.apply(this.data,a)},DataView.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},DataView.prototype._onEvent=function(t,e,i){var s,n,o,a,r=e&&e.items,h=this.data,d=[],c=[],l=[];if(r&&h){switch(t){case"add":for(s=0,n=r.length;n>s;s++)o=r[s],a=this.get(o),a&&(this.ids[o]=!0,d.push(o));break;case"update":for(s=0,n=r.length;n>s;s++)o=r[s],a=this.get(o),a?this.ids[o]?c.push(o):(this.ids[o]=!0,d.push(o)):this.ids[o]&&(delete this.ids[o],l.push(o));break;case"remove":for(s=0,n=r.length;n>s;s++)o=r[s],this.ids[o]&&(delete this.ids[o],l.push(o))}d.length&&this._trigger("add",{items:d},i),c.length&&this._trigger("update",{items:c},i),l.length&&this._trigger("remove",{items:l},i)}},DataView.prototype.on=DataSet.prototype.on,DataView.prototype.off=DataSet.prototype.off,DataView.prototype._trigger=DataSet.prototype._trigger,DataView.prototype.subscribe=DataView.prototype.on,DataView.prototype.unsubscribe=DataView.prototype.off;var stack={};stack.orderByStart=function(t){t.sort(function(t,e){return t.data.start-e.data.start})},stack.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})},stack.stack=function(t,e,i){var s,n;if(i)for(s=0,n=t.length;n>s;s++)t[s].top=null;for(s=0,n=t.length;n>s;s++){var o=t[s];if(null===o.top){o.top=e.axis;do{for(var a=null,r=0,h=t.length;h>r;r++){var d=t[r];if(null!==d.top&&d!==o&&stack.collision(o,d,e.item)){a=d;break}}null!=a&&(o.top=a.top+a.height+e.item)}while(a)}}},stack.nostack=function(t,e){var i,s;for(i=0,s=t.length;s>i;i++)t[i].top=e.axis},stack.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},TimeStep=function(t,e,i){this.current=new Date,this._start=new Date,this._end=new Date,this.autoScale=!0,this.scale=TimeStep.SCALE.DAY,this.step=1,this.setRange(t,e,i)},TimeStep.SCALE={MILLISECOND:1,SECOND:2,MINUTE:3,HOUR:4,DAY:5,WEEKDAY:6,MONTH:7,YEAR:8},TimeStep.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)},TimeStep.prototype.first=function(){this.current=new Date(this._start.valueOf()),this.roundToMinor()},TimeStep.prototype.roundToMinor=function(){switch(this.scale){case TimeStep.SCALE.YEAR:this.current.setFullYear(this.step*Math.floor(this.current.getFullYear()/this.step)),this.current.setMonth(0);case TimeStep.SCALE.MONTH:this.current.setDate(1);case TimeStep.SCALE.DAY:case TimeStep.SCALE.WEEKDAY:this.current.setHours(0);case TimeStep.SCALE.HOUR:this.current.setMinutes(0);case TimeStep.SCALE.MINUTE:this.current.setSeconds(0);case TimeStep.SCALE.SECOND:this.current.setMilliseconds(0)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.setMilliseconds(this.current.getMilliseconds()-this.current.getMilliseconds()%this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()-this.current.getSeconds()%this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()-this.current.getMinutes()%this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()-this.current.getHours()%this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()-1-(this.current.getDate()-1)%this.step+1);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()-this.current.getMonth()%this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()-this.current.getFullYear()%this.step)}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(this.current.getMonth()<6)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current=new Date(this.current.valueOf()+1e3*this.step);break;case TimeStep.SCALE.MINUTE:this.current=new Date(this.current.valueOf()+1e3*this.step*60);break;case TimeStep.SCALE.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 TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}else switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current=new Date(this.current.valueOf()+this.step);break;case TimeStep.SCALE.SECOND:this.current.setSeconds(this.current.getSeconds()+this.step);break;case TimeStep.SCALE.MINUTE:this.current.setMinutes(this.current.getMinutes()+this.step);break;case TimeStep.SCALE.HOUR:this.current.setHours(this.current.getHours()+this.step);break;case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:this.current.setDate(this.current.getDate()+this.step);break;case TimeStep.SCALE.MONTH:this.current.setMonth(this.current.getMonth()+this.step);break;case TimeStep.SCALE.YEAR:this.current.setFullYear(this.current.getFullYear()+this.step)}if(1!=this.step)switch(this.scale){case TimeStep.SCALE.MILLISECOND:this.current.getMilliseconds()0&&(this.step=e),this.autoScale=!1},TimeStep.prototype.setAutoScale=function(t){this.autoScale=t},TimeStep.prototype.setMinimumStep=function(t){if(void 0!=t){var e=31104e6,i=2592e6,s=864e5,n=36e5,o=6e4,a=1e3,r=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*s>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*s>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),s>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),s/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*n>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),n>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*a>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*a>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*r>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*r>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*r>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*r>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),r>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1)}},TimeStep.prototype.snap=function(t){var e=new Date(t.valueOf());if(this.scale==TimeStep.SCALE.YEAR){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(this.scale==TimeStep.SCALE.MONTH)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(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){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(this.scale==TimeStep.SCALE.HOUR){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(this.scale==TimeStep.SCALE.MINUTE){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(this.scale==TimeStep.SCALE.SECOND)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(this.scale==TimeStep.SCALE.MILLISECOND){var s=this.step>5?this.step/2:1;e.setMilliseconds(Math.round(e.getMilliseconds()/s)*s)}return e},TimeStep.prototype.isMajor=function(){switch(this.scale){case TimeStep.SCALE.MILLISECOND:return 0==this.current.getMilliseconds();case TimeStep.SCALE.SECOND:return 0==this.current.getSeconds();case TimeStep.SCALE.MINUTE:return 0==this.current.getHours()&&0==this.current.getMinutes();case TimeStep.SCALE.HOUR:return 0==this.current.getHours();case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return 1==this.current.getDate();case TimeStep.SCALE.MONTH:return 0==this.current.getMonth();case TimeStep.SCALE.YEAR:return!1;default:return!1}},TimeStep.prototype.getLabelMinor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return moment(t).format("SSS");case TimeStep.SCALE.SECOND:return moment(t).format("s");case TimeStep.SCALE.MINUTE:return moment(t).format("HH:mm");case TimeStep.SCALE.HOUR:return moment(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return moment(t).format("ddd D");case TimeStep.SCALE.DAY:return moment(t).format("D");case TimeStep.SCALE.MONTH:return moment(t).format("MMM");case TimeStep.SCALE.YEAR:return moment(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return moment(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return moment(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return moment(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return moment(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return moment(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},Emitter(Range.prototype),Range.prototype.setOptions=function(t){util.extend(this.options,t),null!==this.start&&null!==this.end&&this.setRange(this.start,this.end)},Range.prototype.setRange=function(t,e){var i=this._applyRange(t,e);if(i){var s={start:new Date(this.start),end:new Date(this.end)};this.emit("rangechange",s),this.emit("rangechanged",s)}},Range.prototype._applyRange=function(t,e){var i,s=null!=t?util.convert(t,"Date").valueOf():this.start,n=null!=e?util.convert(e,"Date").valueOf():this.end,o=null!=this.options.max?util.convert(this.options.max,"Date").valueOf():null,a=null!=this.options.min?util.convert(this.options.min,"Date").valueOf():null;if(isNaN(s)||null===s)throw new Error('Invalid start "'+t+'"');if(isNaN(n)||null===n)throw new Error('Invalid end "'+e+'"');if(s>n&&(n=s),null!==a&&a>s&&(i=a-s,s+=i,n+=i,null!=o&&n>o&&(n=o)),null!==o&&n>o&&(i=n-o,s-=i,n-=i,null!=a&&a>s&&(s=a)),null!==this.options.zoomMin){var r=parseFloat(this.options.zoomMin);0>r&&(r=0),r>n-s&&(this.end-this.start===r?(s=this.start,n=this.end):(i=r-(n-s),s-=i/2,n+=i/2))}if(null!==this.options.zoomMax){var h=parseFloat(this.options.zoomMax);0>h&&(h=0),n-s>h&&(this.end-this.start===h?(s=this.start,n=this.end):(i=n-s-h,s+=i/2,n-=i/2))}var d=this.start!=s||this.end!=n;return this.start=s,this.end=n,d},Range.prototype.getRange=function(){return{start:this.start,end:this.end}},Range.prototype.conversion=function(t){return Range.conversion(this.start,this.end,t)},Range.conversion=function(t,e,i){return 0!=i&&e-t!=0?{offset:t,scale:i/(e-t)}:{offset:0,scale:1}};var touchParams={};Range.prototype._onDragStart=function(){if(!touchParams.ignore){touchParams.start=this.start,touchParams.end=this.end;var t=this.parent.frame;t&&(t.style.cursor="move")}},Range.prototype._onDrag=function(t){var e=this.options.direction;if(validateDirection(e),!touchParams.ignore){var i="horizontal"==e?t.gesture.deltaX:t.gesture.deltaY,s=touchParams.end-touchParams.start,n="horizontal"==e?this.parent.width:this.parent.height,o=-i/n*s;this._applyRange(touchParams.start+o,touchParams.end+o),this.emit("rangechange",{start:new Date(this.start),end:new Date(this.end)})}},Range.prototype._onDragEnd=function(){touchParams.ignore||(this.parent.frame&&(this.parent.frame.style.cursor="auto"),this.emit("rangechanged",{start:new Date(this.start),end:new Date(this.end)}))},Range.prototype._onMouseWheel=function(t){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=util.fakeGesture(this,t),n=getPointer(s.center,this.parent.frame),o=this._pointerToDate(n);this.zoom(i,o)}t.preventDefault()},Range.prototype._onTouch=function(t){touchParams.start=this.start,touchParams.end=this.end,touchParams.ignore=!1,touchParams.center=null;var e=ItemSet.itemFromTarget(t);e&&e.selected&&this.options.editable&&(touchParams.ignore=!0)},Range.prototype._onHold=function(){touchParams.ignore=!0},Range.prototype._onPinch=function(t){this.options.direction;if(touchParams.ignore=!0,t.gesture.touches.length>1){touchParams.center||(touchParams.center=getPointer(t.gesture.center,this.parent.frame));var e=1/t.gesture.scale,i=this._pointerToDate(touchParams.center),s=getPointer(t.gesture.center,this.parent.frame),n=(this._pointerToDate(this.parent,s),parseInt(i+(touchParams.start-i)*e)),o=parseInt(i+(touchParams.end-i)*e);this.setRange(n,o)}},Range.prototype._pointerToDate=function(t){var e,i=this.options.direction;if(validateDirection(i),"horizontal"==i){var s=this.parent.width;return e=this.conversion(s),t.x/e.scale+e.offset}var n=this.parent.height;return e=this.conversion(n),t.y/e.scale+e.offset},Range.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2);var i=e+(this.start-e)*t,s=e+(this.end-e)*t;this.setRange(i,s)},Range.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},Range.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,s=this.start-i,n=this.end-i;this.setRange(s,n)},Emitter(Component.prototype),Component.prototype.setOptions=function(t){t&&(util.extend(this.options,t),this.repaint())},Component.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},Component.prototype.getFrame=function(){return null},Component.prototype.repaint=function(){return!1},Component.prototype._isResized=function(){var t=this._previousWidth!==this.width||this._previousHeight!==this.height;return this._previousWidth=this.width,this._previousHeight=this.height,t},Panel.prototype=new Component,Panel.prototype.setOptions=Component.prototype.setOptions,Panel.prototype.getFrame=function(){return this.frame},Panel.prototype.appendChild=function(t){this.childs.push(t),t.parent=this;var e=t.getFrame();e&&(e.parentNode&&e.parentNode.removeChild(e),this.frame.appendChild(e))},Panel.prototype.insertBefore=function(t,e){var i=this.childs.indexOf(e);if(-1!=i){this.childs.splice(i,0,t),t.parent=this;var s=t.getFrame();if(s){s.parentNode&&s.parentNode.removeChild(s);var n=e.getFrame();n?this.frame.insertBefore(s,n):this.frame.appendChild(s)}}},Panel.prototype.removeChild=function(t){var e=this.childs.indexOf(t);if(-1!=e){this.childs.splice(e,1),t.parent=null;var i=t.getFrame();i&&i.parentNode&&this.frame.removeChild(i)}},Panel.prototype.hasChild=function(t){var e=this.childs.indexOf(t);return-1!=e},Panel.prototype.repaint=function(){var t=util.option.asString,e=this.options,i=this.getFrame();i.className="vpanel"+(e.className?" "+t(e.className):"");var s=this._repaintChilds();return this._updateSize(),this._isResized()||s},Panel.prototype._repaintChilds=function(){for(var t=!1,e=0,i=this.childs.length;i>e;e++)t=this.childs[e].repaint()||t;return t},Panel.prototype._updateSize=function(){this.frame.style.top=util.option.asSize(this.options.top),this.frame.style.bottom=util.option.asSize(this.options.bottom),this.frame.style.left=util.option.asSize(this.options.left),this.frame.style.right=util.option.asSize(this.options.right),this.frame.style.width=util.option.asSize(this.options.width,"100%"),this.frame.style.height=util.option.asSize(this.options.height,""),this.top=this.frame.offsetTop,this.left=this.frame.offsetLeft,this.width=this.frame.offsetWidth,this.height=this.frame.offsetHeight},RootPanel.prototype=new Panel,RootPanel.prototype._create=function(){this.frame=document.createElement("div"),this.hammer=Hammer(this.frame,{prevent_default:!0}),this.listeners={};var t=this,e=["touch","pinch","tap","doubletap","hold","dragstart","drag","dragend","mousewheel","DOMMouseScroll"];e.forEach(function(e){var i=function(){var i=[e].concat(Array.prototype.slice.call(arguments,0));t.emit.apply(t,i)};t.hammer.on(e,i),t.listeners[e]=i})},RootPanel.prototype.setOptions=function(t){t&&(util.extend(this.options,t),this.repaint(),this._initWatch())},RootPanel.prototype.getFrame=function(){return this.frame},RootPanel.prototype.repaint=function(){var t=this.options,e=t.editable.updateTime||t.editable.updateGroup,i="vis timeline rootpanel "+t.orientation+(e?" editable":"");t.className&&(i+=" "+util.option.asString(i)),this.frame.className=i;var s=this._repaintChilds();this.frame.style.maxHeight=util.option.asSize(this.options.maxHeight,""),this._updateSize();var n=this._isResized()||s;n&&setTimeout(this.repaint.bind(this),0)},RootPanel.prototype._initWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},RootPanel.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?void(t.frame&&(t.frame.clientWidth!=t.lastWidth||t.frame.clientHeight!=t.lastHeight)&&(t.lastWidth=t.frame.clientWidth,t.lastHeight=t.frame.clientHeight,t.repaint())):void t._unwatch()};util.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},RootPanel.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},TimeAxis.prototype=new Component,TimeAxis.prototype.setOptions=Component.prototype.setOptions,TimeAxis.prototype._create=function(){this.frame=document.createElement("div")},TimeAxis.prototype.setRange=function(t){if(!(t instanceof Range||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},TimeAxis.prototype.getFrame=function(){return this.frame},TimeAxis.prototype.repaint=function(){var t=util.option.asSize,e=this.options,i=this.props,s=this.frame;s.className="timeaxis";var n=s.parentNode;if(n){this._calculateCharSize();var o=this.getOption("orientation"),a=this.getOption("showMinorLabels"),r=this.getOption("showMajorLabels"),h=this.parent.height;i.minorLabelHeight=a?i.minorCharHeight:0,i.majorLabelHeight=r?i.majorCharHeight:0,this.height=i.minorLabelHeight+i.majorLabelHeight,this.width=s.offsetWidth,i.minorLineHeight=h+i.minorLabelHeight,i.minorLineWidth=1,i.majorLineHeight=h+this.height,i.majorLineWidth=1;var d=s.nextSibling;n.removeChild(s),"top"==o?(s.style.top="0",s.style.left="0",s.style.bottom="",s.style.width=t(e.width,"100%"),s.style.height=this.height+"px"):(s.style.top="",s.style.bottom="0",s.style.left="0",s.style.width=t(e.width,"100%"),s.style.height=this.height+"px"),this._repaintLabels(),this._repaintLine(),d?n.insertBefore(s,d):n.appendChild(s)}return this._isResized()},TimeAxis.prototype._repaintLabels=function(){var t=this.getOption("orientation"),e=util.convert(this.range.start,"Number"),i=util.convert(this.range.end,"Number"),s=this.options.toTime(7*(this.props.minorCharWidth||10)).valueOf()-this.options.toTime(0).valueOf(),n=new TimeStep(new Date(e),new Date(i),s);this.step=n;var o=this.dom;o.redundant.majorLines=o.majorLines,o.redundant.majorTexts=o.majorTexts,o.redundant.minorLines=o.minorLines,o.redundant.minorTexts=o.minorTexts,o.majorLines=[],o.majorTexts=[],o.minorLines=[],o.minorTexts=[],n.first(); +for(var a=void 0,r=0;n.hasNext()&&1e3>r;){r++;var h=n.getCurrent(),d=this.options.toScreen(h),c=n.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(d,n.getLabelMinor(),t),c&&this.getOption("showMajorLabels")?(d>0&&(void 0==a&&(a=d),this._repaintMajorText(d,n.getLabelMajor(),t)),this._repaintMajorLine(d,t)):this._repaintMinorLine(d,t),n.next()}if(this.getOption("showMajorLabels")){var l=this.options.toTime(0),u=n.getLabelMajor(l),p=u.length*(this.props.majorCharWidth||10)+10;(void 0==a||a>p)&&this._repaintMajorText(0,u,t)}util.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},TimeAxis.prototype._repaintMinorText=function(t,e,i){var s=this.dom.redundant.minorTexts.shift();if(!s){var n=document.createTextNode("");s=document.createElement("div"),s.appendChild(n),s.className="text minor",this.frame.appendChild(s)}this.dom.minorTexts.push(s),s.childNodes[0].nodeValue=e,"top"==i?(s.style.top=this.props.majorLabelHeight+"px",s.style.bottom=""):(s.style.top="",s.style.bottom=this.props.majorLabelHeight+"px"),s.style.left=t+"px"},TimeAxis.prototype._repaintMajorText=function(t,e,i){var s=this.dom.redundant.majorTexts.shift();if(!s){var n=document.createTextNode(e);s=document.createElement("div"),s.className="text major",s.appendChild(n),this.frame.appendChild(s)}this.dom.majorTexts.push(s),s.childNodes[0].nodeValue=e,"top"==i?(s.style.top="0px",s.style.bottom=""):(s.style.top="",s.style.bottom="0px"),s.style.left=t+"px"},TimeAxis.prototype._repaintMinorLine=function(t,e){var i=this.dom.redundant.minorLines.shift();i||(i=document.createElement("div"),i.className="grid vertical minor",this.frame.appendChild(i)),this.dom.minorLines.push(i);var s=this.props;"top"==e?(i.style.top=this.props.majorLabelHeight+"px",i.style.bottom=""):(i.style.top="",i.style.bottom=this.props.majorLabelHeight+"px"),i.style.height=s.minorLineHeight+"px",i.style.left=t-s.minorLineWidth/2+"px"},TimeAxis.prototype._repaintMajorLine=function(t,e){var i=this.dom.redundant.majorLines.shift();i||(i=document.createElement("DIV"),i.className="grid vertical major",this.frame.appendChild(i)),this.dom.majorLines.push(i);var s=this.props;"top"==e?(i.style.top="0px",i.style.bottom=""):(i.style.top="",i.style.bottom="0px"),i.style.left=t-s.majorLineWidth/2+"px",i.style.height=s.majorLineHeight+"px"},TimeAxis.prototype._repaintLine=function(){var t=this.dom.line,e=this.frame,i=this.getOption("orientation");this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),"top"==i?(t.style.top=this.height+"px",t.style.bottom=""):(t.style.top="",t.style.bottom=this.height+"px")):t&&t.parentNode&&(t.parentNode.removeChild(t),delete this.dom.line)},TimeAxis.prototype._calculateCharSize=function(){if(!("minorCharHeight"in this.props)){var t=document.createTextNode("0"),e=document.createElement("DIV");e.className="text minor measure",e.appendChild(t),this.frame.appendChild(e),this.props.minorCharHeight=e.clientHeight,this.props.minorCharWidth=e.clientWidth,this.frame.removeChild(e)}if(!("majorCharHeight"in this.props)){var i=document.createTextNode("0"),s=document.createElement("DIV");s.className="text major measure",s.appendChild(i),this.frame.appendChild(s),this.props.majorCharHeight=s.clientHeight,this.props.majorCharWidth=s.clientWidth,this.frame.removeChild(s)}},TimeAxis.prototype.snap=function(t){return this.step.snap(t)},CurrentTime.prototype=new Component,CurrentTime.prototype.setOptions=Component.prototype.setOptions,CurrentTime.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},CurrentTime.prototype.getFrame=function(){return this.bar},CurrentTime.prototype.repaint=function(){var t=(this.parent,new Date),e=this.options.toScreen(t);return this.bar.style.left=e+"px",this.bar.title="Current time: "+t,!1},CurrentTime.prototype.start=function(){function t(){e.stop();var i=e.range.conversion(e.parent.width).scale,s=1/i/10;30>s&&(s=30),s>1e3&&(s=1e3),e.repaint(),e.currentTimeTimer=setTimeout(t,s)}var e=this;t()},CurrentTime.prototype.stop=function(){void 0!==this.currentTimeTimer&&(clearTimeout(this.currentTimeTimer),delete this.currentTimeTimer)},CustomTime.prototype=new Component,CustomTime.prototype.setOptions=Component.prototype.setOptions,CustomTime.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=Hammer(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))},CustomTime.prototype.getFrame=function(){return this.bar},CustomTime.prototype.repaint=function(){var t=this.options.toScreen(this.customTime);return this.bar.style.left=t+"px",this.bar.title="Time: "+this.customTime,!1},CustomTime.prototype.setCustomTime=function(t){this.customTime=new Date(t.valueOf()),this.repaint()},CustomTime.prototype.getCustomTime=function(){return new Date(this.customTime.valueOf())},CustomTime.prototype._onDragStart=function(t){this.eventParams.dragging=!0,this.eventParams.customTime=this.customTime,t.stopPropagation(),t.preventDefault()},CustomTime.prototype._onDrag=function(t){if(this.eventParams.dragging){var e=t.gesture.deltaX,i=this.options.toScreen(this.eventParams.customTime)+e,s=this.options.toTime(i);this.setCustomTime(s),this.emit("timechange",{time:new Date(this.customTime.valueOf())}),t.stopPropagation(),t.preventDefault()}},CustomTime.prototype._onDragEnd=function(t){this.eventParams.dragging&&(this.emit("timechanged",{time:new Date(this.customTime.valueOf())}),t.stopPropagation(),t.preventDefault())};var UNGROUPED="__ungrouped__";ItemSet.prototype=new Panel,ItemSet.types={box:ItemBox,range:ItemRange,rangeoverflow:ItemRangeOverflow,point:ItemPoint},ItemSet.prototype._create=function(){var t=document.createElement("div");t["timeline-itemset"]=this,this.frame=t;var e=document.createElement("div");e.className="background",this.backgroundPanel.frame.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,this.axisPanel.frame.appendChild(s);var n=document.createElement("div");n.className="labelset",this.dom.labelSet=n,this.sidePanel.frame.appendChild(n),this._updateUngrouped(),this.hammer=Hammer(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))},ItemSet.prototype.setOptions=function(t){Component.prototype.setOptions.call(this,t)},ItemSet.prototype.markDirty=function(){this.groupIds=[],this.stackDirty=!0},ItemSet.prototype.hide=function(){this.dom.axis.parentNode&&this.dom.axis.parentNode.removeChild(this.dom.axis),this.dom.background.parentNode&&this.dom.background.parentNode.removeChild(this.dom.background),this.dom.labelSet.parentNode&&this.dom.labelSet.parentNode.removeChild(this.dom.labelSet)},ItemSet.prototype.show=function(){this.dom.axis.parentNode||this.axisPanel.frame.appendChild(this.dom.axis),this.dom.background.parentNode||this.backgroundPanel.frame.appendChild(this.dom.background),this.dom.labelSet.parentNode||this.sidePanel.frame.appendChild(this.dom.labelSet)},ItemSet.prototype.setRange=function(t){if(!(t instanceof Range||t&&t.start&&t.end))throw new TypeError("Range must be an instance of Range, or an object containing start and end.");this.range=t},ItemSet.prototype.setSelection=function(t){var e,i,s,n;if(t){if(!Array.isArray(t))throw new TypeError("Array expected");for(e=0,i=this.selection.length;i>e;e++)s=this.selection[e],n=this.items[s],n&&n.unselect();for(this.selection=[],e=0,i=t.length;i>e;e++)s=t[e],n=this.items[s],n&&(this.selection.push(s),n.select())}},ItemSet.prototype.getSelection=function(){return this.selection.concat([])},ItemSet.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}},ItemSet.prototype.getFrame=function(){return this.frame},ItemSet.prototype.repaint=function(){var t=this.options.margin,e=this.range,i=util.option.asSize,s=util.option.asString,n=this.options,o=this.getOption("orientation"),a=!1,r=this.frame;"number"==typeof t&&(t={item:t,axis:t}),r.className="itemset"+(n.className?" "+s(n.className):""),a=this._orderGroups()||a;var h=this.range.end-this.range.start,d=h!=this.lastVisibleInterval||this.width!=this.lastWidth;d&&(this.stackDirty=!0),this.lastVisibleInterval=h,this.lastWidth=this.width;var c=this.stackDirty,l=this._firstGroup(),u={item:t.item,axis:t.axis},p={item:t.item,axis:t.item/2},g=0,m=t.axis+t.item;return util.forEach(this.groups,function(t){var i=t==l?u:p;a=t.repaint(e,i,c)||a,g+=t.height}),g=Math.max(g,m),this.stackDirty=!1,r.style.left=i(n.left,""),r.style.right=i(n.right,""),r.style.top=i("top"==o?"0":""),r.style.bottom=i("top"==o?"":"0"),r.style.width=i(n.width,"100%"),r.style.height=i(g),this.top=r.offsetTop,this.left=r.offsetLeft,this.width=r.offsetWidth,this.height=g,this.dom.axis.style.left=i(n.left,"0"),this.dom.axis.style.right=i(n.right,""),this.dom.axis.style.width=i(n.width,"100%"),this.dom.axis.style.height=i(0),this.dom.axis.style.top=i("top"==o?"0":""),this.dom.axis.style.bottom=i("top"==o?"":"0"),a=this._isResized()||a},ItemSet.prototype._firstGroup=function(){var t="top"==this.options.orientation?0:this.groupIds.length-1,e=this.groupIds[t],i=this.groups[e]||this.groups[UNGROUPED];return i||null},ItemSet.prototype._updateUngrouped=function(){var t=this.groups[UNGROUPED];if(this.groupsData)t&&(t.hide(),delete this.groups[UNGROUPED]);else if(!t){var e=null,i=null;t=new Group(e,i,this),this.groups[UNGROUPED]=t;for(var s in this.items)this.items.hasOwnProperty(s)&&t.add(this.items[s]);t.show()}},ItemSet.prototype.getForeground=function(){return this.dom.foreground},ItemSet.prototype.getBackground=function(){return this.dom.background},ItemSet.prototype.getAxis=function(){return this.dom.axis},ItemSet.prototype.getLabelSet=function(){return this.dom.labelSet},ItemSet.prototype.setItems=function(t){var e,i=this,s=this.itemsData;if(t){if(!(t instanceof DataSet||t instanceof DataView))throw new TypeError("Data must be an instance of DataSet or DataView");this.itemsData=t}else this.itemsData=null;if(s&&(util.forEach(this.itemListeners,function(t,e){s.unsubscribe(e,t)}),e=s.getIds(),this._onRemove(e)),this.itemsData){var n=this.id;util.forEach(this.itemListeners,function(t,e){i.itemsData.on(e,t,n)}),e=this.itemsData.getIds(),this._onAdd(e),this._updateUngrouped()}},ItemSet.prototype.getItems=function(){return this.itemsData},ItemSet.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(util.forEach(this.groupListeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemoveGroups(e)),t){if(!(t instanceof DataSet||t instanceof DataView))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;util.forEach(this.groupListeners,function(t,e){i.groupsData.on(e,t,s)}),e=this.groupsData.getIds(),this._onAddGroups(e)}this._updateUngrouped(),this._order(),this.emit("change")},ItemSet.prototype.getGroups=function(){return this.groupsData},ItemSet.prototype.removeItem=function(t){var e=this.itemsData.get(t),i=this._myDataSet();e&&this.options.onRemove(e,function(e){e&&i.remove(t)})},ItemSet.prototype._onUpdate=function(t){var e=this,i=this.items,s=this.itemOptions;t.forEach(function(t){var n=e.itemsData.get(t),o=i[t],a=n.type||n.start&&n.end&&"range"||e.options.type||"box",r=ItemSet.types[a];if(o&&(r&&o instanceof r?e._updateItem(o,n):(e._removeItem(o),o=null)),!o){if(!r)throw new TypeError('Unknown item type "'+a+'"');o=new r(n,e.options,s),o.id=t,e._addItem(o)}}),this._order(),this.stackDirty=!0,this.emit("change")},ItemSet.prototype._onAdd=ItemSet.prototype._onUpdate,ItemSet.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.emit("change"))},ItemSet.prototype._order=function(){util.forEach(this.groups,function(t){t.order()})},ItemSet.prototype._onUpdateGroups=function(t){this._onAddGroups(t)},ItemSet.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==UNGROUPED)throw new Error("Illegal group id. "+t+" is a reserved id.");var n=Object.create(e.options);util.extend(n,{height:null}),s=new Group(t,i,e),e.groups[t]=s;for(var o in e.items)if(e.items.hasOwnProperty(o)){var a=e.items[o];a.data.group==t&&s.add(a)}s.order(),s.show()}}),this.emit("change")},ItemSet.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.emit("change")},ItemSet.prototype._orderGroups=function(){if(this.groupsData){var t=this.groupsData.getIds({order:this.options.groupOrder}),e=!util.equalArray(t,this.groupIds);if(e){var i=this.groups;t.forEach(function(t){var e=i[t];e.hide()}),t.forEach(function(t){i[t].show()}),this.groupIds=t}return e}return!1},ItemSet.prototype._addItem=function(t){this.items[t.id]=t;var e=this.groupsData?t.data.group:UNGROUPED,i=this.groups[e];i&&i.add(t)},ItemSet.prototype._updateItem=function(t,e){var i=t.data.group;if(t.data=e,t.repaint(),i!=t.data.group){var s=this.groups[i];s&&s.remove(t);var n=this.groupsData?t.data.group:UNGROUPED,o=this.groups[n];o&&o.add(t)}},ItemSet.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);var i=this.groupsData?t.data.group:UNGROUPED,s=this.groups[i];s&&s.remove(t)},ItemSet.prototype._constructByEndArray=function(t){for(var e=[],i=0;it.start-e&&this.data.startt.start-e&&this.data.startt.start},ItemRange.prototype.repaint=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.parent)throw new Error("Cannot repaint item: no parent attached");if(!t.box.parentNode){var e=this.parent.getForeground();if(!e)throw new Error("Cannot repaint time axis: parent has no foreground container element");e.appendChild(t.box)}if(this.displayed=!0,this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)t.content.innerHTML="",t.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);t.content.innerHTML=this.content}this.dirty=!0}var i=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=i&&(this.className=i,t.box.className=this.baseClassName+i,this.dirty=!0),this.dirty&&(this.props.content.width=this.dom.content.offsetWidth,this.height=this.dom.box.offsetHeight,this.dirty=!1),this._repaintDeleteButton(t.box),this._repaintDragLeft(),this._repaintDragRight()},ItemRange.prototype.show=function(){this.displayed||this.repaint()},ItemRange.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}},ItemRange.prototype.repositionX=function(){var t,e=this.props,i=this.parent.width,s=this.defaultOptions.toScreen(this.data.start),n=this.defaultOptions.toScreen(this.data.end),o="padding"in this.options?this.options.padding:this.defaultOptions.padding;-i>s&&(s=-i),n>2*i&&(n=2*i),t=0>s?Math.min(-s,n-s-e.content.width-2*o):0,this.left=s,this.width=Math.max(n-s,1),this.dom.box.style.left=this.left+"px",this.dom.box.style.width=this.width+"px",this.dom.content.style.left=t+"px"},ItemRange.prototype.repositionY=function(){var t=this.options.orientation||this.defaultOptions.orientation,e=this.dom.box;"top"==t?(e.style.top=this.top+"px",e.style.bottom=""):(e.style.top="",e.style.bottom=this.top+"px")},ItemRange.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,Hammer(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)},ItemRange.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,Hammer(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)},ItemRangeOverflow.prototype=new ItemRange(null),ItemRangeOverflow.prototype.baseClassName="item rangeoverflow",ItemRangeOverflow.prototype.repositionX=function(){{var t,e=this.parent.width,i=this.defaultOptions.toScreen(this.data.start),s=this.defaultOptions.toScreen(this.data.end);"padding"in this.options?this.options.padding:this.defaultOptions.padding}-e>i&&(i=-e),s>2*e&&(s=2*e),t=Math.max(-i,0),this.left=i;var n=Math.max(s-i,1);this.width=this.props.content.widthn;n++){var a=this.visibleItems[n];a.repositionY()}var r,h=this.visibleItems;if(h.length){var d=h[0].top,c=h[0].top+h[0].height;util.forEach(h,function(t){d=Math.min(d,t.top),c=Math.max(c,t.top+t.height)}),r=c-d+e.axis+e.item}else r=e.axis+e.item;r=Math.max(r,this.props.label.height);var l=this.dom.foreground;return this.top=l.offsetTop,this.left=l.offsetLeft,this.width=l.offsetWidth,s=util.updateProperty(this,"height",r)||s,s=util.updateProperty(this.props.label,"width",this.dom.inner.clientWidth)||s,s=util.updateProperty(this.props.label,"height",this.dom.inner.clientHeight)||s,l.style.height=r+"px",this.dom.label.style.height=r+"px",s},Group.prototype.show=function(){this.dom.label.parentNode||this.itemSet.getLabelSet().appendChild(this.dom.label),this.dom.foreground.parentNode||this.itemSet.getForeground().appendChild(this.dom.foreground),this.dom.background.parentNode||this.itemSet.getBackground().appendChild(this.dom.background),this.dom.axis.parentNode||this.itemSet.getAxis().appendChild(this.dom.axis)},Group.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)},Group.prototype.add=function(t){if(this.items[t.id]=t,t.setParent(this),t instanceof ItemRange&&-1==this.visibleItems.indexOf(t)){var e=this.itemSet.range;this._checkIfVisible(t,this.visibleItems,e)}},Group.prototype.remove=function(t){delete this.items[t.id],t.setParent(this.itemSet);var e=this.visibleItems.indexOf(t);-1!=e&&this.visibleItems.splice(e,1)},Group.prototype.removeFromDataSet=function(t){this.itemSet.removeItem(t.id)},Group.prototype.order=function(){var t=util.toArray(this.items);this.orderedItems.byStart=t,this.orderedItems.byEnd=this._constructByEndArray(t),stack.orderByStart(this.orderedItems.byStart),stack.orderByEnd(this.orderedItems.byEnd)},Group.prototype._constructByEndArray=function(t){for(var e=[],i=0;i0)for(n=0;n=0&&!this._checkIfInvisible(t.byStart[n],o,i);n--);for(n=s+1;n=0&&!this._checkIfInvisible(t.byEnd[n],o,i);n--);for(n=a+1;ne.start-a&&s[c].data[n]e.start-a&&s[c].data[n]=s&&(s=864e5),e=new Date(e.valueOf()-.05*s),i=new Date(i.valueOf()+.05*s)}(null!==e||null!==i)&&this.range.setRange(e,i)},Timeline.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var s=t.min("start");e=s?s.start.valueOf():null;var n=t.max("start");n&&(i=n.start.valueOf());var o=t.max("end");o&&(i=null==i?o.end.valueOf():Math.max(i,o.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},Timeline.prototype.setSelection=function(t){this.itemSet.setSelection(t)},Timeline.prototype.getSelection=function(){return this.itemSet.getSelection()},Timeline.prototype.setWindow=function(t,e){if(1==arguments.length){var i=arguments[0];this.range.setRange(i.start,i.end)}else this.range.setRange(t,e)},Timeline.prototype.getWindow=function(){var t=this.range.getRange();return{start:new Date(t.start),end:new Date(t.end)}},Timeline.prototype._onSelectItem=function(t){if(this.options.selectable){var e=t.gesture.srcEvent&&t.gesture.srcEvent.ctrlKey,i=t.gesture.srcEvent&&t.gesture.srcEvent.shiftKey;if(e||i)return void this._onMultiSelectItem(t);var s=this.getSelection(),n=ItemSet.itemFromTarget(t),o=n?[n.id]:[];this.setSelection(o);var a=this.getSelection();util.equalArray(s,a)||this.emit("select",{items:this.getSelection()}),t.stopPropagation()}},Timeline.prototype._onAddItem=function(t){if(this.options.selectable&&this.options.editable.add){var e=this,i=ItemSet.itemFromTarget(t);if(i){var s=e.itemsData.get(i.id);this.options.onUpdate(s,function(t){t&&e.itemsData.update(t)})}else{var n=vis.util.getAbsoluteLeft(this.contentPanel.frame),o=t.gesture.center.pageX-n,a={start:this.timeAxis.snap(this._toTime(o)),content:"new item"},r=util.randomUUID();a[this.itemsData.fieldId]=r;var h=ItemSet.groupFromTarget(t);h&&(a.group=h.groupId),this.options.onAdd(a,function(t){t&&e.itemsData.add(a)})}}},Timeline.prototype._onMultiSelectItem=function(t){if(this.options.selectable){var e,i=ItemSet.itemFromTarget(t);if(i){e=this.getSelection();var s=e.indexOf(i.id);-1==s?e.push(i.id):e.splice(s,1),this.setSelection(e),this.emit("select",{items:this.getSelection()}),t.stopPropagation()}}},Timeline.prototype._toTime=function(t){var e=this.range.conversion(this.mainPanel.width);return new Date(t/e.scale+e.offset)},Timeline.prototype._toScreen=function(t){var e=this.range.conversion(this.mainPanel.width);return(t.valueOf()-e.offset)*e.scale},function(t){function e(t){return D=t,u()}function i(){I=0,C=D.charAt(0)}function s(){I++,C=D.charAt(I)}function n(){return D.charAt(I+1)}function o(t){return O.test(t)}function a(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function r(t,e,i){for(var s=e.split("."),n=t;s.length;){var o=s.shift();s.length?(n[o]||(n[o]={}),n=n[o]):n[o]=i}}function h(t,e){for(var i,s,n=null,o=[t],r=t;r.parent;)o.push(r.parent),r=r.parent;if(r.nodes)for(i=0,s=r.nodes.length;s>i;i++)if(e.id===r.nodes[i].id){n=r.nodes[i];break}for(n||(n={id:e.id},t.node&&(n.attr=a(n.attr,t.node))),i=o.length-1;i>=0;i--){var h=o[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(n)&&h.nodes.push(n)}e.attr&&(n.attr=a(n.attr,e.attr))}function d(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,n){var o={from:e,to:i,type:s};return t.edge&&(o.attr=a({},t.edge)),o.attr=a(o.attr||{},n),o}function l(){for(N=E.NULL,M="";" "==C||" "==C||"\n"==C||"\r"==C;)s();do{var t=!1;if("#"==C){for(var e=I-1;" "==D.charAt(e)||" "==D.charAt(e);)e--;if("\n"==D.charAt(e)||""==D.charAt(e)){for(;""!=C&&"\n"!=C;)s();t=!0}}if("/"==C&&"/"==n()){for(;""!=C&&"\n"!=C;)s();t=!0}if("/"==C&&"*"==n()){for(;""!=C;){if("*"==C&&"/"==n()){s(),s();break}s()}t=!0}for(;" "==C||" "==C||"\n"==C||"\r"==C;)s()}while(t);if(""==C)return void(N=E.DELIMITER);var i=C+n();if(T[i])return N=E.DELIMITER,M=i,s(),void s();if(T[C])return N=E.DELIMITER,M=C,void s();if(o(C)||"-"==C){for(M+=C,s();o(C);)M+=C,s();return"false"==M?M=!1:"true"==M?M=!0:isNaN(Number(M))||(M=Number(M)),void(N=E.IDENTIFIER)}if('"'==C){for(s();""!=C&&('"'!=C||'"'==C&&'"'==n());)M+=C,'"'==C&&s(),s();if('"'!=C)throw b('End of string " expected');return s(),void(N=E.IDENTIFIER)}for(N=E.UNKNOWN;""!=C;)M+=C,s();throw new SyntaxError('Syntax error in part "'+w(M,30)+'"')}function u(){var t={};if(i(),l(),"strict"==M&&(t.strict=!0,l()),("graph"==M||"digraph"==M)&&(t.type=M,l()),N==E.IDENTIFIER&&(t.id=M,l()),"{"!=M)throw b("Angle bracket { expected");if(l(),p(t),"}"!=M)throw b("Angle bracket } expected");if(l(),""!==M)throw b("End of file expected");return l(),delete t.node,delete t.edge,delete t.graph,t}function p(t){for(;""!==M&&"}"!=M;)g(t),";"==M&&l()}function g(t){var e=m(t);if(e)return void y(t,e);var i=f(t);if(!i){if(N!=E.IDENTIFIER)throw b("Identifier expected");var s=M;if(l(),"="==M){if(l(),N!=E.IDENTIFIER)throw b("Identifier expected");t[s]=M,l()}else v(t,s)}}function m(t){var e=null;if("subgraph"==M&&(e={},e.type="subgraph",l(),N==E.IDENTIFIER&&(e.id=M,l())),"{"==M){if(l(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,p(e),"}"!=M)throw b("Angle bracket } expected");l(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function f(t){return"node"==M?(l(),t.node=_(),"node"):"edge"==M?(l(),t.edge=_(),"edge"):"graph"==M?(l(),t.graph=_(),"graph"):null}function v(t,e){var i={id:e},s=_();s&&(i.attr=s),h(t,i),y(t,e)}function y(t,e){for(;"->"==M||"--"==M;){var i,s=M;l();var n=m(t);if(n)i=n;else{if(N!=E.IDENTIFIER)throw b("Identifier or subgraph expected");i=M,h(t,{id:i}),l()}var o=_(),a=c(t,e,i,s,o);d(t,a),e=i}}function _(){for(var t=null;"["==M;){for(l(),t={};""!==M&&"]"!=M;){if(N!=E.IDENTIFIER)throw b("Attribute name expected");var e=M;if(l(),"="!=M)throw b("Equal sign = expected");if(l(),N!=E.IDENTIFIER)throw b("Attribute value expected");var i=M;r(t,e,i),l(),","==M&&l()}if("]"!=M)throw b("Bracket ] expected");l()}return t}function b(t){return new SyntaxError(t+', got "'+w(M,30)+'" (char '+I+")")}function w(t,e){return t.length<=e?t:t.substr(0,27)+"..."}function S(t,e,i){t instanceof Array?t.forEach(function(t){e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}):e instanceof Array?e.forEach(function(e){i(t,e)}):i(t,e)}function x(t){function i(t){var e={from:t.from,to:t.to};return a(e,t.attr),e.style="->"==t.type?"arrow":"line",e}var s=e(t),n={nodes:[],edges:[],options:{}};return s.nodes&&s.nodes.forEach(function(t){var e={id:t.id,label:String(t.label||t.id)};a(e,t.attr),e.image&&(e.shape="image"),n.nodes.push(e)}),s.edges&&s.edges.forEach(function(t){var e,s;e=t.from instanceof Object?t.from.nodes:{id:t.from},s=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=i(t);n.edges.push(e)}),S(e,s,function(e,s){var o=c(n,e.id,s.id,t.type,t.attr),a=i(o);n.edges.push(a)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=i(t);n.edges.push(e)})}),s.attr&&(n.options=s.attr),n}var E={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},T={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},D="",I=0,C="",M="",N=E.NULL,O=/[a-zA-Z_0-9.:#]/;t.parseDOT=e,t.DOTToGraph=x}("undefined"!=typeof util?util:exports),"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,n=s/2,o=Math.sqrt(3)/6*s,a=Math.sqrt(s*s-n*n);this.moveTo(t,e-(a-o)),this.lineTo(t+n,e+o),this.lineTo(t-n,e+o),this.lineTo(t,e-(a-o)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var s=2*i,n=s/2,o=Math.sqrt(3)/6*s,a=Math.sqrt(s*s-n*n);this.moveTo(t,e+(a-o)),this.lineTo(t+n,e-o),this.lineTo(t-n,e-o),this.lineTo(t,e+(a-o)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var s=0;10>s;s++){var n=s%2===0?1.3*i:.5*i;this.lineTo(t+n*Math.sin(2*s*Math.PI/10),e-n*Math.cos(2*s*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,s,n){var o=Math.PI/180;0>i-2*n&&(n=i/2),0>s-2*n&&(n=s/2),this.beginPath(),this.moveTo(t+n,e),this.lineTo(t+i-n,e),this.arc(t+i-n,e+n,n,270*o,360*o,!1),this.lineTo(t+i,e+s-n),this.arc(t+i-n,e+s-n,n,0,90*o,!1),this.lineTo(t+n,e+s),this.arc(t+n,e+s-n,n,90*o,180*o,!1),this.lineTo(t,e+n),this.arc(t+n,e+n,n,180*o,270*o,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,s){var n=.5522848,o=i/2*n,a=s/2*n,r=t+i,h=e+s,d=t+i/2,c=e+s/2;this.beginPath(),this.moveTo(t,c),this.bezierCurveTo(t,c-a,d-o,e,d,e),this.bezierCurveTo(d+o,e,r,c-a,r,c),this.bezierCurveTo(r,c+a,d+o,h,d,h),this.bezierCurveTo(d-o,h,t,c+a,t,c)},CanvasRenderingContext2D.prototype.database=function(t,e,i,s){var n=1/3,o=i,a=s*n,r=.5522848,h=o/2*r,d=a/2*r,c=t+o,l=e+a,u=t+o/2,p=e+a/2,g=e+(s-a/2),m=e+s;this.beginPath(),this.moveTo(c,p),this.bezierCurveTo(c,p+d,u+h,l,u,l),this.bezierCurveTo(u-h,l,t,p+d,t,p),this.bezierCurveTo(t,p-d,u-h,e,u,e),this.bezierCurveTo(u+h,e,c,p-d,c,p),this.lineTo(c,g),this.bezierCurveTo(c,g+d,u+h,m,u,m),this.bezierCurveTo(u-h,m,t,g+d,t,g),this.lineTo(t,p)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,s){var n=t-s*Math.cos(i),o=e-s*Math.sin(i),a=t-.9*s*Math.cos(i),r=e-.9*s*Math.sin(i),h=n+s/3*Math.cos(i+.5*Math.PI),d=o+s/3*Math.sin(i+.5*Math.PI),c=n+s/3*Math.cos(i-.5*Math.PI),l=o+s/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,d),this.lineTo(a,r),this.lineTo(c,l),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,s,n){n||(n=[10,5]),0==u&&(u=.001);var o=n.length;this.moveTo(t,e);for(var a=i-t,r=s-e,h=r/a,d=Math.sqrt(a*a+r*r),c=0,l=!0;d>=.1;){var u=n[c++%o];u>d&&(u=d);var p=Math.sqrt(u*u/(1+h*h));0>a&&(p=-p),t+=p,e+=h*p,this[l?"lineTo":"moveTo"](t,e),d-=u,l=!l}}),Node.prototype.resetCluster=function(){this.formationScale=void 0,this.clusterSize=1,this.containedNodes={},this.containedEdges={},this.clusterSessions=[]},Node.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},Node.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&(this.edges.splice(e,1),this.dynamicEdges.splice(e,1)),this.dynamicEdgesLength=this.dynamicEdges.length},Node.prototype.setProperties=function(t,e){if(t){if(this.originalLabel=void 0,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.group&&(this.group=t.group),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.mass&&(this.mass=t.mass),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(this.group){var i=this.grouplist.get(this.group);for(var s in i)i.hasOwnProperty(s)&&(this[s]=i[s])}if(void 0!==t.shape&&(this.shape=t.shape),void 0!==t.image&&(this.image=t.image),void 0!==t.radius&&(this.radius=t.radius),void 0!==t.color&&(this.color=util.parseColor(t.color)),void 0!==t.fontColor&&(this.fontColor=t.fontColor),void 0!==t.fontSize&&(this.fontSize=t.fontSize),void 0!==t.fontFace&&(this.fontFace=t.fontFace),void 0!==this.image&&""!=this.image){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!==t.x&&!t.allowedToMoveX,this.yFixed=this.yFixed||void 0!==t.y&&!t.allowedToMoveY,this.radiusFixed=this.radiusFixed||void 0!==t.radius,"image"==this.shape&&(this.radiusMin=e.nodes.widthMin,this.radiusMax=e.nodes.widthMax),this.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"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()}},Node.prototype.select=function(){this.selected=!0,this._reset()},Node.prototype.unselect=function(){this.selected=!1,this._reset()},Node.prototype.clearSizeCache=function(){this._reset()},Node.prototype._reset=function(){this.width=void 0,this.height=void 0},Node.prototype.getTitle=function(){return"function"==typeof this.title?this.title():this.title},Node.prototype.distanceToBorder=function(t,e){var i=1;switch(this.width||this.resize(t),this.shape){case"circle":case"dot":return this.radius+i;case"ellipse":var s=this.width/2,n=this.height/2,o=Math.sin(e)*s,a=Math.cos(e)*n;return s*n/Math.sqrt(o*o+a*a);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}},Node.prototype._setForce=function(t,e){this.fx=t,this.fy=e},Node.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},Node.prototype.discreteStep=function(t){if(!this.xFixed){var e=this.damping*this.vx,i=(this.fx-e)/this.mass;this.vx+=i*t,this.x+=this.vx*t}if(!this.yFixed){var s=this.damping*this.vy,n=(this.fy-s)/this.mass;this.vy+=n*t,this.y+=this.vy*t}},Node.prototype.discreteStepLimited=function(t,e){if(this.xFixed)this.fx=0;else{var i=this.damping*this.vx,s=(this.fx-i)/this.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;else{var n=this.damping*this.vy,o=(this.fy-n)/this.mass;this.vy+=o*t,this.vy=Math.abs(this.vy)>e?this.vy>0?e:-e:this.vy,this.y+=this.vy*t}},Node.prototype.isFixed=function(){return this.xFixed&&this.yFixed},Node.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t},Node.prototype.isSelected=function(){return this.selected},Node.prototype.getValue=function(){return this.value},Node.prototype.getDistance=function(t,e){var i=this.x-t,s=this.y-e;return Math.sqrt(i*i+s*s)},Node.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value)if(e==t)this.radius=(this.radiusMin+this.radiusMax)/2;else{var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}this.baseRadiusValue=this.radius},Node.prototype.draw=function(){throw"Draw method not initialized for node"},Node.prototype.resize=function(){throw"Resize method not initialized for node"},Node.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},Node.prototype._resizeImage=function(){if(!this.width||!this.height){var t,e;if(this.value){this.radius=this.baseRadiusValue;var i=this.imageObj.height/this.imageObj.width;void 0!==i?(t=this.radius||this.imageObj.width,e=this.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.radius+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-t)}},Node.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;if(0!=this.imageObj.width){if(this.clusterSize>1){var i=this.clusterSize>1?10:0;i*=this.graphScaleInv,i=Math.min(.2*this.width,i),t.globalAlpha=.5,t.drawImage(this.imageObj,this.left-i,this.top-i,this.width+2*i,this.height+2*i)}t.globalAlpha=1,t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2}else e=this.y;this._label(t,this.label,this.x,e,void 0,"top")},Node.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)}},Node.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=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*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.radius),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.roundRect(this.left,this.top,this.width,this.height,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.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.radius+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-s}},Node.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=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*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?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.database(this.x-this.width/2,this.y-.5*this.height,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),s=Math.max(i.width,i.height)+2*e;this.radius=s/2,this.width=s,this.height=s,this.radius+=.5*Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.radius-.5*s}},Node.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e=2.5,i=2;t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.circle(this.x,this.y,this.radius+2*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.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?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*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?i:1)+(this.clusterSize>1?e:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.ellipse(this.left,this.top,this.width,this.height),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},Node.prototype._drawDot=function(t){this._drawShape(t,"circle")},Node.prototype._drawTriangle=function(t){this._drawShape(t,"triangle")},Node.prototype._drawTriangleDown=function(t){this._drawShape(t,"triangleDown")},Node.prototype._drawSquare=function(t){this._drawShape(t,"square")},Node.prototype._drawStar=function(t){this._drawShape(t,"star")},Node.prototype._resizeShape=function(){if(!this.width){this.radius=this.baseRadiusValue;var t=2*this.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.radius+=.5*Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-t}},Node.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=2,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.color.highlight.border:this.color.border,this.clusterSize>1&&(t.lineWidth=(this.selected?s:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t[e](this.x,this.y,this.radius+n*t.lineWidth),t.stroke()),t.lineWidth=(this.selected?s:1)+(this.clusterSize>1?i:0),t.lineWidth*=this.graphScaleInv,t.lineWidth=Math.min(.1*this.width,t.lineWidth),t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t[e](this.x,this.y,this.radius),t.fill(),t.stroke(),this.label&&this._label(t,this.label,this.x,this.y+this.height/2,void 0,"top")},Node.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.radius+=Math.min(this.clusterSize-1,this.maxNodeSizeIncrements)*this.clusterSizeRadiusFactor,this.growthIndicator=this.width-(i.width+2*e)}},Node.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)},Node.prototype._label=function(t,e,i,s,n,o){if(e&&this.fontSize*this.graphScale>this.fontDrawThreshold){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle=this.fontColor||"black",t.textAlign=n||"center",t.textBaseline=o||"middle";for(var a=e.split("\n"),r=a.length,h=this.fontSize+4,d=s+(1-r)/2*h,c=0;r>c;c++)t.fillText(a[c],i,d),d+=h}},Node.prototype.getTextSize=function(t){if(void 0!==this.label){t.font=(this.selected?"bold ":"")+this.fontSize+"px "+this.fontFace;for(var e=this.label.split("\n"),i=(this.fontSize+4)*e.length,s=0,n=0,o=e.length;o>n;n++)s=Math.max(s,t.measureText(e[n]).width);return{width:s,height:i}}return{width:0,height:0}},Node.prototype.inArea=function(){return void 0!==this.width?this.x+this.width*this.graphScaleInv>=this.canvasTopLeft.x&&this.x-this.width*this.graphScaleInv=this.canvasTopLeft.y&&this.y-this.height*this.graphScaleInv=this.canvasTopLeft.x&&this.x=this.canvasTopLeft.y&&this.yh}return!1},Edge.prototype._drawLine=function(t){if(t.strokeStyle=1==this.selected?this.color.highlight:this.color.color,t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var e;if(this.label){if(1==this.smooth){var i=.5*(.5*(this.from.x+this.via.x)+.5*(this.to.x+this.via.x)),s=.5*(.5*(this.from.y+this.via.y)+.5*(this.to.y+this.via.y));e={x:i,y:s}}else e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}}else{var n,o,a=this.length/4,r=this.from;r.width||r.resize(t),r.width>r.height?(n=r.x+r.width/2,o=r.y-a):(n=r.x+a,o=r.y-r.height/2),this._circle(t,n,o,a),e=this._pointOnCircle(n,o,a,.5),this._label(t,this.label,e.x,e.y)}},Edge.prototype._getLineWidth=function(){return 1==this.selected?Math.min(2*this.width,this.widthMax)*this.graphScaleInv:this.width*this.graphScaleInv},Edge.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),1==this.smooth?t.quadraticCurveTo(this.via.x,this.via.y,this.to.x,this.to.y):t.lineTo(this.to.x,this.to.y),t.stroke()},Edge.prototype._circle=function(t,e,i,s){t.beginPath(),t.arc(e,i,s,0,2*Math.PI,!1),t.stroke()},Edge.prototype._label=function(t,e,i,s){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle=this.fontFill;var n=t.measureText(e).width,o=this.fontSize,a=i-n/2,r=s-o/2; +t.fillRect(a,r,n,o),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,a,r)}},Edge.prototype._drawDashLine=function(t){if(t.strokeStyle=1==this.selected?this.color.highlight:this.color.color,t.lineWidth=this._getLineWidth(),void 0!==t.mozDash||void 0!==t.setLineDash){t.beginPath(),t.moveTo(this.from.x,this.from.y);var e=[0];e=void 0!==this.dash.length&&void 0!==this.dash.gap?[this.dash.length,this.dash.gap]:[5,5],"undefined"!=typeof t.setLineDash?(t.setLineDash(e),t.lineDashOffset=0):(t.mozDash=e,t.mozDashOffset=0),1==this.smooth?t.quadraticCurveTo(this.via.x,this.via.y,this.to.x,this.to.y):t.lineTo(this.to.x,this.to.y),t.stroke(),"undefined"!=typeof t.setLineDash?(t.setLineDash([0]),t.lineDashOffset=0):(t.mozDash=[0],t.mozDashOffset=0)}else t.beginPath(),t.lineCap="round",void 0!==this.dash.altLength?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]):void 0!==this.dash.length&&void 0!==this.dash.gap?t.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,[this.dash.length,this.dash.gap]):(t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y)),t.stroke();if(this.label){var i;if(1==this.smooth){var s=.5*(.5*(this.from.x+this.via.x)+.5*(this.to.x+this.via.x)),n=.5*(.5*(this.from.y+this.via.y)+.5*(this.to.y+this.via.y));i={x:s,y:n}}else i=this._pointOnLine(.5);this._label(t,this.label,i.x,i.y)}},Edge.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}},Edge.prototype._pointOnCircle=function(t,e,i,s){var n=2*(s-3/8)*Math.PI;return{x:t+i*Math.cos(n),y:e-i*Math.sin(n)}},Edge.prototype._drawArrowCenter=function(t){var e;if(1==this.selected?(t.strokeStyle=this.color.highlight,t.fillStyle=this.color.highlight):(t.strokeStyle=this.color.color,t.fillStyle=this.color.color),t.lineWidth=this._getLineWidth(),this.from!=this.to){this._line(t);var i=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x),s=(10+5*this.width)*this.arrowScaleFactor;if(1==this.smooth){var n=.5*(.5*(this.from.x+this.via.x)+.5*(this.to.x+this.via.x)),o=.5*(.5*(this.from.y+this.via.y)+.5*(this.to.y+this.via.y));e={x:n,y:o}}else e=this._pointOnLine(.5);t.arrow(e.x,e.y,i,s),t.fill(),t.stroke(),this.label&&this._label(t,this.label,e.x,e.y)}else{var a,r,h=.25*Math.max(100,this.length),d=this.from;d.width||d.resize(t),d.width>d.height?(a=d.x+.5*d.width,r=d.y-h):(a=d.x+h,r=d.y-.5*d.height),this._circle(t,a,r,h);var i=.2*Math.PI,s=(10+5*this.width)*this.arrowScaleFactor;e=this._pointOnCircle(a,r,h,.5),t.arrow(e.x,e.y,i,s),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(a,r,h,.5),this._label(t,this.label,e.x,e.y))}},Edge.prototype._drawArrow=function(t){1==this.selected?(t.strokeStyle=this.color.highlight,t.fillStyle=this.color.highlight):(t.strokeStyle=this.color.color,t.fillStyle=this.color.color),t.lineWidth=this._getLineWidth();var e,i;if(this.from!=this.to){e=Math.atan2(this.to.y-this.from.y,this.to.x-this.from.x);var s=this.to.x-this.from.x,n=this.to.y-this.from.y,o=Math.sqrt(s*s+n*n),a=this.from.distanceToBorder(t,e+Math.PI),r=(o-a)/o,h=r*this.from.x+(1-r)*this.to.x,d=r*this.from.y+(1-r)*this.to.y;1==this.smooth&&(e=Math.atan2(this.to.y-this.via.y,this.to.x-this.via.x),s=this.to.x-this.via.x,n=this.to.y-this.via.y,o=Math.sqrt(s*s+n*n));var c,l,u=this.to.distanceToBorder(t,e),p=(o-u)/o;if(1==this.smooth?(c=(1-p)*this.via.x+p*this.to.x,l=(1-p)*this.via.y+p*this.to.y):(c=(1-p)*this.from.x+p*this.to.x,l=(1-p)*this.from.y+p*this.to.y),t.beginPath(),t.moveTo(h,d),1==this.smooth?t.quadraticCurveTo(this.via.x,this.via.y,c,l):t.lineTo(c,l),t.stroke(),i=(10+5*this.width)*this.arrowScaleFactor,t.arrow(c,l,e,i),t.fill(),t.stroke(),this.label){var g;if(1==this.smooth){var m=.5*(.5*(this.from.x+this.via.x)+.5*(this.to.x+this.via.x)),f=.5*(.5*(this.from.y+this.via.y)+.5*(this.to.y+this.via.y));g={x:m,y:f}}else g=this._pointOnLine(.5);this._label(t,this.label,g.x,g.y)}}else{var v,y,_,b=this.from,w=.25*Math.max(100,this.length);b.width||b.resize(t),b.width>b.height?(v=b.x+.5*b.width,y=b.y-w,_={x:v,y:b.y,angle:.9*Math.PI}):(v=b.x+w,y=b.y-.5*b.height,_={x:b.x,y:y,angle:.6*Math.PI}),t.beginPath(),t.arc(v,y,w,0,2*Math.PI,!1),t.stroke();var i=(10+5*this.width)*this.arrowScaleFactor;t.arrow(_.x,_.y,_.angle,i),t.fill(),t.stroke(),this.label&&(g=this._pointOnCircle(v,y,w,.5),this._label(t,this.label,g.x,g.y))}},Edge.prototype._getDistanceToEdge=function(t,e,i,s,n,o){if(1==this.smooth){var a,r,h,d,c,l,u=1e9;for(a=0;10>a;a++)r=.1*a,h=Math.pow(1-r,2)*t+2*r*(1-r)*this.via.x+Math.pow(r,2)*i,d=Math.pow(1-r,2)*e+2*r*(1-r)*this.via.y+Math.pow(r,2)*s,c=Math.abs(n-h),l=Math.abs(o-d),u=Math.min(u,Math.sqrt(c*c+l*l));return u}var p=i-t,g=s-e,m=p*p+g*g,f=((n-t)*p+(o-e)*g)/m;f>1?f=1:0>f&&(f=0);var h=t+f*p,d=e+f*g,c=h-n,l=d-o;return Math.sqrt(c*c+l*l)},Edge.prototype.setScale=function(t){this.graphScaleInv=1/t},Edge.prototype.select=function(){this.selected=!0},Edge.prototype.unselect=function(){this.selected=!1},Edge.prototype.positionBezierNode=function(){null!==this.via&&(this.via.x=.5*(this.from.x+this.to.x),this.via.y=.5*(this.from.y+this.to.y))},Popup.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},Popup.prototype.setText=function(t){this.frame.innerHTML=t},Popup.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,s=this.frame.parentNode.clientHeight,n=this.frame.parentNode.clientWidth,o=this.y-e;o+e+this.padding>s&&(o=s-e-this.padding),on&&(a=n-i-this.padding),athis.constants.clustering.clusterThreshold&&1==this.constants.clustering.enabled&&this.clusterToFit(this.constants.clustering.reduceToNodes,!1),this._calculateForces())},_calculateForces:function(){this._calculateGravitationalForces(),this._calculateNodeForces(),1==this.constants.smoothCurves?this._calculateSpringForcesWithSupport():this._calculateSpringForces()},_updateCalculationNodes:function(){if(1==this.constants.smoothCurves){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},_calculateGravitationalForces:function(){var t,e,i,s,n,o=this.calculationNodes,a=this.constants.physics.centralGravity,r=0;for(n=0;nSimulation 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=showValueOfRange.bind(this,"graph_BH_gc",-1,"physics_barnesHut_gravitationalConstant"),e=document.getElementById("graph_BH_cg"),e.onchange=showValueOfRange.bind(this,"graph_BH_cg",1,"physics_centralGravity"),e=document.getElementById("graph_BH_sc"),e.onchange=showValueOfRange.bind(this,"graph_BH_sc",1,"physics_springConstant"),e=document.getElementById("graph_BH_sl"),e.onchange=showValueOfRange.bind(this,"graph_BH_sl",1,"physics_springLength"),e=document.getElementById("graph_BH_damp"),e.onchange=showValueOfRange.bind(this,"graph_BH_damp",1,"physics_damping"),e=document.getElementById("graph_R_nd"),e.onchange=showValueOfRange.bind(this,"graph_R_nd",1,"physics_repulsion_nodeDistance"),e=document.getElementById("graph_R_cg"),e.onchange=showValueOfRange.bind(this,"graph_R_cg",1,"physics_centralGravity"),e=document.getElementById("graph_R_sc"),e.onchange=showValueOfRange.bind(this,"graph_R_sc",1,"physics_springConstant"),e=document.getElementById("graph_R_sl"),e.onchange=showValueOfRange.bind(this,"graph_R_sl",1,"physics_springLength"),e=document.getElementById("graph_R_damp"),e.onchange=showValueOfRange.bind(this,"graph_R_damp",1,"physics_damping"),e=document.getElementById("graph_H_nd"),e.onchange=showValueOfRange.bind(this,"graph_H_nd",1,"physics_hierarchicalRepulsion_nodeDistance"),e=document.getElementById("graph_H_cg"),e.onchange=showValueOfRange.bind(this,"graph_H_cg",1,"physics_centralGravity"),e=document.getElementById("graph_H_sc"),e.onchange=showValueOfRange.bind(this,"graph_H_sc",1,"physics_springConstant"),e=document.getElementById("graph_H_sl"),e.onchange=showValueOfRange.bind(this,"graph_H_sl",1,"physics_springLength"),e=document.getElementById("graph_H_damp"),e.onchange=showValueOfRange.bind(this,"graph_H_damp",1,"physics_damping"),e=document.getElementById("graph_H_direction"),e.onchange=showValueOfRange.bind(this,"graph_H_direction",t,"hierarchicalLayout_direction"),e=document.getElementById("graph_H_levsep"),e.onchange=showValueOfRange.bind(this,"graph_H_levsep",1,"hierarchicalLayout_levelSeparation"),e=document.getElementById("graph_H_nspac"),e.onchange=showValueOfRange.bind(this,"graph_H_nspac",1,"hierarchicalLayout_nodeSpacing");var i=document.getElementById("graph_physicsMethod1"),s=document.getElementById("graph_physicsMethod2"),n=document.getElementById("graph_physicsMethod3");s.checked=!0,this.constants.physics.barnesHut.enabled&&(i.checked=!0),this.constants.hierarchicalLayout.enabled&&(n.checked=!0);var o=document.getElementById("graph_toggleSmooth"),a=document.getElementById("graph_repositionNodes"),r=document.getElementById("graph_generateOptions");o.onclick=graphToggleSmoothCurves.bind(this),a.onclick=graphRepositionNodes.bind(this),r.onclick=graphGenerateOptions.bind(this),o.style.background=1==this.constants.smoothCurves?"#A4FF56":"#FF8532",switchConfigurations.apply(this),i.onchange=switchConfigurations.bind(this),s.onchange=switchConfigurations.bind(this),n.onchange=switchConfigurations.bind(this)}},_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)}},hierarchalRepulsionMixin={_calculateNodeForces:function(){var t,e,i,s,n,o,a,r,h,d,c=this.calculationNodes,l=this.calculationNodeIndices,u=5,p=.5*-u,g=this.constants.physics.hierarchicalRepulsion.nodeDistance,m=g;for(h=0;hi&&(o=f*i+u,0==i?i=.01:o/=i,s=t*o,n=e*o,a.fx-=s,a.fy-=n,r.fx+=s,r.fy+=n)}}},barnesHutMixin={_calculateNodeForces:function(){if(0!=this.constants.physics.barnesHut.gravitationalConstant){var t,e=this.calculationNodes,i=this.calculationNodeIndices,s=i.length;this._formBarnesHutTree(e,i);for(var n=this.barnesHutTree,o=0;s>o;o++)t=e[i[o]],this._getForceContribution(n.root.children.NW,t),this._getForceContribution(n.root.children.NE,t),this._getForceContribution(n.root.children.SW,t),this._getForceContribution(n.root.children.SE,t)}},_getForceContribution:function(t,e){if(t.childrenCount>0){var i,s,n;if(i=t.centerOfMass.x-e.x,s=t.centerOfMass.y-e.y,n=Math.sqrt(i*i+s*s),n*t.calcSize>this.constants.physics.barnesHut.theta){0==n&&(n=.1*Math.random(),i=n);var o=this.constants.physics.barnesHut.gravitationalConstant*t.mass*e.mass/(n*n*n),a=i*o,r=s*o;e.fx+=a,e.fy+=r}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==n&&(n=.5*Math.random(),i=n);var o=this.constants.physics.barnesHut.gravitationalConstant*t.mass*e.mass/(n*n*n),a=i*o,r=s*o;e.fx+=a,e.fy+=r}}},_formBarnesHutTree:function(t,e){for(var i,s=e.length,n=Number.MAX_VALUE,o=Number.MAX_VALUE,a=-Number.MAX_VALUE,r=-Number.MAX_VALUE,h=0;s>h;h++){var d=t[e[h]].x,c=t[e[h]].y;n>d&&(n=d),d>a&&(a=d),o>c&&(o=c),c>r&&(r=c)}var l=Math.abs(a-n)-Math.abs(r-o);l>0?(o-=.5*l,r+=.5*l):(n+=.5*l,a-=.5*l);var u=1e-5,p=Math.max(u,Math.abs(a-n)),g=.5*p,m=.5*(n+a),f=.5*(o+r),v={root:{centerOfMass:{x:0,y:0},mass:0,range:{minX:m-g,maxX:m+g,minY:f-g,maxY:f+g},size:p,calcSize:1/p,children:{data:null},maxWidth:0,level:0,childrenCount:4}};for(this._splitBranch(v.root),h=0;s>h;h++)i=t[e[h]],this._placeInTree(v.root,i);this.barnesHutTree=v},_updateBranchMass:function(t,e){var i=t.mass+e.mass,s=1/i;t.centerOfMass.x=t.centerOfMass.x*t.mass+e.x*e.mass,t.centerOfMass.x*=s,t.centerOfMass.y=t.centerOfMass.y*t.mass+e.y*e.mass,t.centerOfMass.y*=s,t.mass=i;var n=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")},_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)}},_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)},_insertRegion:function(t,e){var i,s,n,o,a=.5*t.size;switch(e){case"NW":i=t.range.minX,s=t.range.minX+a,n=t.range.minY,o=t.range.minY+a;break;case"NE":i=t.range.minX+a,s=t.range.maxX,n=t.range.minY,o=t.range.minY+a;break;case"SW":i=t.range.minX,s=t.range.minX+a,n=t.range.minY+a,o=t.range.maxY;break;case"SE":i=t.range.minX+a,s=t.range.maxX,n=t.range.minY+a,o=t.range.maxY}t.children[e]={centerOfMass:{x:0,y:0},mass:0,range:{minX:i,maxX:s,minY:n,maxY:o},size:.5*t.size,calcSize:2*t.calcSize,children:{data:null},maxWidth:0,level:t.level+1,childrenCount:0}},_drawTree:function(t,e){void 0!==this.barnesHutTree&&(t.lineWidth=1,this._drawBranch(this.barnesHutTree.root,t,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()}},repulsionMixin={_calculateNodeForces:function(){var t,e,i,s,n,o,a,r,h,d,c,l=this.calculationNodes,u=this.calculationNodeIndices,p=-2/3,g=4/3,m=this.constants.physics.repulsion.nodeDistance,f=m;for(d=0;di&&(a=.5*f>i?1:v*i+g,a*=0==o?1:1+o*this.constants.clustering.forceAmplification,a/=i,s=t*a,n=e*a,r.fx-=s,r.fy-=n,h.fx+=s,h.fy+=n)}}},HierarchicalLayoutMixin={_resetLevels:function(){for(var t in this.nodes)if(this.nodes.hasOwnProperty(t)){var e=this.nodes[t];0==e.preassignedLevel&&(e.level=-1)}},_setupHierarchicalLayout:function(){if(1==this.constants.hierarchicalLayout.enabled){"RL"==this.constants.hierarchicalLayout.direction||"DU"==this.constants.hierarchicalLayout.direction?this.constants.hierarchicalLayout.levelSeparation*=-1:this.constants.hierarchicalLayout.levelSeparation=Math.abs(this.constants.hierarchicalLayout.levelSeparation);var t,e,i=0,s=!1,n=!1;for(e in this.nodes)this.nodes.hasOwnProperty(e)&&(t=this.nodes[e],-1!=t.level?s=!0:n=!0,is&&(o.xFixed=!1,o.x=i[o.level].minPos,a=!0):o.yFixed&&o.level>s&&(o.yFixed=!1,o.y=i[o.level].minPos,a=!0),1==a&&(i[o.level].minPos+=i[o.level].nodeSpacing,o.edges.length>1&&this._placeBranchNodes(o.edges,o.id,i,o.level))}},_setLevel:function(t,e,i){for(var s=0;st)&&(n.level=t,e.length>1&&this._setLevel(t+1,n.edges,n.id))}},_restoreNodes:function(){for(nodeId in this.nodes)this.nodes.hasOwnProperty(nodeId)&&(this.nodes[nodeId].xFixed=!1,this.nodes[nodeId].yFixed=!1)}},manipulationMixin={_clearManipulatorBar:function(){for(;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild) +},_restoreOverloadedFunctions:function(){for(var t in this.cachedFunctions)this.cachedFunctions.hasOwnProperty(t)&&(this[t]=this.cachedFunctions[t])},_toggleEditMode:function(){this.editMode=!this.editMode;var t=document.getElementById("graph-manipulationDiv"),e=document.getElementById("graph-manipulation-closeDiv"),i=document.getElementById("graph-manipulation-editMode");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()},_createManipulatorBar:function(){if(this.boundFunction&&this.off("select",this.boundFunction),this._restoreOverloadedFunctions(),this.freezeSimulation=!1,this.blockConnectingEdgeSelection=!1,this.forceAppendSelection=!1,1==this.editMode){for(;this.manipulationDiv.hasChildNodes();)this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);this.manipulationDiv.innerHTML=""+this.constants.labels.add+"
"+this.constants.labels.link+"",1==this._getSelectedNodeCount()&&this.triggerFunctions.edit&&(this.manipulationDiv.innerHTML+="
"+this.constants.labels.editNode+""),0==this._selectionIsEmpty()&&(this.manipulationDiv.innerHTML+="
"+this.constants.labels.del+"");var t=document.getElementById("graph-manipulate-addNode");t.onclick=this._createAddNodeToolbar.bind(this);var e=document.getElementById("graph-manipulate-connectNode");if(e.onclick=this._createAddEdgeToolbar.bind(this),1==this._getSelectedNodeCount()&&this.triggerFunctions.edit){var i=document.getElementById("graph-manipulate-editNode");i.onclick=this._editNode.bind(this)}if(0==this._selectionIsEmpty()){var s=document.getElementById("graph-manipulate-delete");s.onclick=this._deleteSelected.bind(this)}var n=document.getElementById("graph-manipulation-closeDiv");n.onclick=this._toggleEditMode.bind(this),this.boundFunction=this._createManipulatorBar.bind(this),this.on("select",this.boundFunction)}else{this.editModeDiv.innerHTML=""+this.constants.labels.edit+"";var o=document.getElementById("graph-manipulate-editModeButton");o.onclick=this._toggleEditMode.bind(this)}},_createAddNodeToolbar:function(){this._clearManipulatorBar(),this.boundFunction&&this.off("select",this.boundFunction),this.manipulationDiv.innerHTML=""+this.constants.labels.back+"
"+this.constants.labels.addDescription+"";var t=document.getElementById("graph-manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._addNode.bind(this),this.on("select",this.boundFunction)},_createAddEdgeToolbar:function(){this._clearManipulatorBar(),this._unselectAll(!0),this.freezeSimulation=!0,this.boundFunction&&this.off("select",this.boundFunction),this._unselectAll(),this.forceAppendSelection=!1,this.blockConnectingEdgeSelection=!0,this.manipulationDiv.innerHTML=""+this.constants.labels.back+"
"+this.constants.labels.linkDescription+"";var t=document.getElementById("graph-manipulate-back");t.onclick=this._createManipulatorBar.bind(this),this.boundFunction=this._handleConnect.bind(this),this.on("select",this.boundFunction),this.cachedFunctions._handleTouch=this._handleTouch,this.cachedFunctions._handleOnRelease=this._handleOnRelease,this._handleTouch=this._handleConnect,this._handleOnRelease=this._finishConnect,this._redraw()},_handleConnect:function(t){if(0==this._getSelectedNodeCount()){var e=this._getNodeAt(t);null!=e&&(e.clusterSize>1?alert("Cannot create edges to a cluster."):(this._selectObject(e,!1),this.sectors.support.nodes.targetNode=new Node({id:"targetNode"},{},{},this.constants),this.sectors.support.nodes.targetNode.x=e.x,this.sectors.support.nodes.targetNode.y=e.y,this.sectors.support.nodes.targetViaNode=new Node({id:"targetViaNode"},{},{},this.constants),this.sectors.support.nodes.targetViaNode.x=e.x,this.sectors.support.nodes.targetViaNode.y=e.y,this.sectors.support.nodes.targetViaNode.parentEdgeId="connectionEdge",this.edges.connectionEdge=new Edge({id:"connectionEdge",from:e.id,to:this.sectors.support.nodes.targetNode.id},this,this.constants),this.edges.connectionEdge.from=e,this.edges.connectionEdge.connected=!0,this.edges.connectionEdge.smooth=!0,this.edges.connectionEdge.selected=!0,this.edges.connectionEdge.to=this.sectors.support.nodes.targetNode,this.edges.connectionEdge.via=this.sectors.support.nodes.targetViaNode,this.cachedFunctions._handleOnDrag=this._handleOnDrag,this._handleOnDrag=function(t){var e=this._getPointer(t.gesture.center);this.sectors.support.nodes.targetNode.x=this._canvasToX(e.x),this.sectors.support.nodes.targetNode.y=this._canvasToY(e.y),this.sectors.support.nodes.targetViaNode.x=.5*(this._canvasToX(e.x)+this.edges.connectionEdge.from.x),this.sectors.support.nodes.targetViaNode.y=this._canvasToY(e.y)},this.moving=!0,this.start()))}},_finishConnect:function(t){if(1==this._getSelectedNodeCount()){this._handleOnDrag=this.cachedFunctions._handleOnDrag,delete this.cachedFunctions._handleOnDrag;var e=this.edges.connectionEdge.fromId;delete this.edges.connectionEdge,delete this.sectors.support.nodes.targetNode,delete this.sectors.support.nodes.targetViaNode;var i=this._getNodeAt(t);null!=i&&(i.clusterSize>1?alert("Cannot create edges to a cluster."):(this._createEdge(e,i.id),this._createManipulatorBar())),this._unselectAll()}},_addNode:function(){if(this._selectionIsEmpty()&&1==this.editMode){var t=this._pointerToPositionObject(this.pointerPosition),e={id:util.randomUUID(),x:t.left,y:t.top,label:"new",allowedToMoveX:!0,allowedToMoveY:!0};if(this.triggerFunctions.add)if(2==this.triggerFunctions.add.length){var i=this;this.triggerFunctions.add(e,function(t){i.nodesData.add(t),i._createManipulatorBar(),i.moving=!0,i.start()})}else alert(this.constants.labels.addError),this._createManipulatorBar(),this.moving=!0,this.start();else this.nodesData.add(e),this._createManipulatorBar(),this.moving=!0,this.start()}},_createEdge:function(t,e){if(1==this.editMode){var i={from:t,to:e};if(this.triggerFunctions.connect)if(2==this.triggerFunctions.connect.length){var s=this;this.triggerFunctions.connect(i,function(t){s.edgesData.add(t),s.moving=!0,s.start()})}else alert(this.constants.labels.linkError),this.moving=!0,this.start();else this.edgesData.add(i),this.moving=!0,this.start()}},_editNode:function(){if(this.triggerFunctions.edit&&1==this.editMode){var t=this._getSelectedNode(),e={id:t.id,label:t.label,group:t.group,shape:t.shape,color:{background:t.color.background,border:t.color.border,highlight:{background:t.color.highlight.background,border:t.color.highlight.border}}};if(2==this.triggerFunctions.edit.length){var i=this;this.triggerFunctions.edit(e,function(t){i.nodesData.update(t),i._createManipulatorBar(),i.moving=!0,i.start()})}else alert(this.constants.labels.editError)}else alert(this.constants.labels.editBoundError)},_deleteSelected:function(){if(!this._selectionIsEmpty()&&1==this.editMode)if(this._clusterInSelection())alert(this.constants.labels.deleteClusterError);else{var t=this.getSelectedNodes(),e=this.getSelectedEdges();if(this.triggerFunctions.del){var i=this,s={nodes:t,edges:e};(this.triggerFunctions.del.length=2)?this.triggerFunctions.del(s,function(t){i.edgesData.remove(t.edges),i.nodesData.remove(t.nodes),i._unselectAll(),i.moving=!0,i.start()}):alert(this.constants.labels.deleteError)}else this.edgesData.remove(e),this.nodesData.remove(t),this._unselectAll(),this.moving=!0,this.start()}}},SectorMixin={_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},_switchToSector:function(t,e){void 0===e||"active"==e?this._switchToActiveSector(t):this._switchToFrozenSector(t)},_switchToActiveSector:function(t){this.nodeIndices=this.sectors.active[t].nodeIndices,this.nodes=this.sectors.active[t].nodes,this.edges=this.sectors.active[t].edges},_switchToSupportSector:function(){this.nodeIndices=this.sectors.support.nodeIndices,this.nodes=this.sectors.support.nodes,this.edges=this.sectors.support.edges},_switchToFrozenSector:function(t){this.nodeIndices=this.sectors.frozen[t].nodeIndices,this.nodes=this.sectors.frozen[t].nodes,this.edges=this.sectors.frozen[t].edges},_loadLatestSector:function(){this._switchToSector(this._sector())},_sector:function(){return this.activeSector[this.activeSector.length-1]},_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.")},_setActiveSector:function(t){this.activeSector.push(t)},_forgetLastSector:function(){this.activeSector.pop()},_createNewSector:function(t){this.sectors.active[t]={nodes:{},edges:{},nodeIndices:[],formationScale:this.scale,drawingNode:void 0},this.sectors.active[t].drawingNode=new Node({id:t,color:{background:"#eaefef",border:"495c5e"}},{},{},this.constants),this.sectors.active[t].drawingNode.clusterSize=2},_deleteActiveSector:function(t){delete this.sectors.active[t]},_deleteFrozenSector:function(t){delete this.sectors.frozen[t]},_freezeSector:function(t){this.sectors.frozen[t]=this.sectors.active[t],this._deleteActiveSector(t)},_activateSector:function(t){this.sectors.active[t]=this.sectors.frozen[t],this._deleteFrozenSector(t)},_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](s[0],s[1]):this[t](e)}this._loadLatestSector()},_doInSupportSector:function(t,e){if(void 0===e)this._switchToSupportSector(),this[t]();else{this._switchToSupportSector();var i=Array.prototype.splice.call(arguments,1);i.length>1?this[t](i[0],i[1]):this[t](e)}this._loadLatestSector()},_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()},_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))},_clearNodeIndexList:function(){var t=this._sector();this.sectors.active[t].nodeIndices=[],this.nodeIndices=this.sectors.active[t].nodeIndices},_drawSectorNodes:function(t,e){var i,s=1e9,n=-1e9,o=1e9,a=-1e9;for(var r in this.sectors[e])if(this.sectors[e].hasOwnProperty(r)&&void 0!==this.sectors[e][r].drawingNode){this._switchToSector(r,e),s=1e9,n=-1e9,o=1e9,a=-1e9;for(var h in this.nodes)this.nodes.hasOwnProperty(h)&&(i=this.nodes[h],i.resize(t),o>i.x-.5*i.width&&(o=i.x-.5*i.width),ai.y-.5*i.height&&(s=i.y-.5*i.height),nt&&s>n;)n%3==0?(this.forceAggregateHubs(!0),this.normalizeClusterLevels()):this.increaseClusterLevel(),i=this.nodeIndices.length,n+=1;n>0&&1==e&&this.repositionNodes(),this._updateCalculationNodes()},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()},updateClustersDefault:function(){1==this.constants.clustering.enabled&&this.updateClusters(0,!1,!1)},increaseClusterLevel:function(){this.updateClusters(-1,!1,!0)},decreaseClusterLevel:function(){this.updateClusters(1,!1,!0)},updateClusters:function(t,e,i,s){var n=this.moving,o=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)},_aggregateHubs:function(t){this._getHubSize(),this._formClustersByHub(t,!1)},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()},_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)}},_openClusters:function(t,e){for(var i=0;i1&&(t.clusterSizei)){var a=o.from,r=o.to;o.to.mass>o.from.mass&&(a=o.to,r=o.from),1==r.dynamicEdgesLength?this._addToCluster(a,r,!1):1==a.dynamicEdgesLength&&this._addToCluster(r,a,!1)}}},_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.mass>e.mass?this._addToCluster(s,e,!0):this._addToCluster(e,s,!0))}}},_clusterToSmallestNeighbour:function(t){for(var e=-1,i=null,s=0;sn.clusterSessions.length&&(e=n.clusterSessions.length,i=n)}null!=n&&void 0!==this.nodes[n.id]&&this._addToCluster(n,t,!0)},_formClustersByHub:function(t,e){for(var i in this.nodes)this.nodes.hasOwnProperty(i)&&this._formClusterFromHub(this.nodes[i],t,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 n,o,a,r=this.constants.clustering.clusterEdgeThreshold/this.scale,h=!1,d=[],c=t.dynamicEdges.length,l=0;c>l;l++)d.push(t.dynamicEdges[l].id);if(0==e)for(h=!1,l=0;c>l;l++){var u=this.edges[d[l]];if(void 0!==u&&u.connected&&u.toId!=u.fromId&&(n=u.to.x-u.from.x,o=u.to.y-u.from.y,a=Math.sqrt(n*n+o*o),r>a)){h=!0;break}}if(!e&&h||e)for(l=0;c>l;l++)if(u=this.edges[d[l]],void 0!==u){var p=this.nodes[u.fromId==t.id?u.toId:u.fromId];p.dynamicEdges.length<=this.hubThreshold+s&&p.id!=t.id&&this._addToCluster(t,p,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)))},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 n=this.nodeIndices.length,o=e-this.constants.clustering.clusterLevelDifference;for(t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodes[t].clusterSessions.lengths&&(s=o.dynamicEdgesLength),t+=o.dynamicEdgesLength,e+=Math.pow(o.dynamicEdgesLength,2),i+=1}t/=i,e/=i;var a=e-Math.pow(t,2),r=Math.sqrt(a);this.hubThreshold=Math.floor(t+2*r),this.hubThreshold>s&&(this.hubThreshold=s)},_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)},_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}},SelectionMixin={_getNodesOverlappingWith:function(t,e){var i=this.nodes;for(var s in i)i.hasOwnProperty(s)&&i[s].isOverlappingWith(t)&&e.push(s)},_getAllNodesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getNodesOverlappingWith",t,e),e},_pointerToPositionObject:function(t){var e=this._canvasToX(t.x),i=this._canvasToY(t.y);return{left:e,top:i,right:e,bottom:i}},_getNodeAt:function(t){var e=this._pointerToPositionObject(t),i=this._getAllNodesOverlappingWith(e);return i.length>0?this.nodes[i[i.length-1]]:null},_getEdgesOverlappingWith:function(t,e){var i=this.edges;for(var s in i)i.hasOwnProperty(s)&&i[s].isOverlappingWith(t)&&e.push(s)},_getAllEdgesOverlappingWith:function(t){var e=[];return this._doInAllActiveSectors("_getEdgesOverlappingWith",t,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},_addToSelection:function(t){t instanceof Node?this.selectionObj.nodes[t.id]=t:this.selectionObj.edges[t.id]=t},_removeFromSelection:function(t){t instanceof Node?delete this.selectionObj.nodes[t.id]:delete this.selectionObj.edges[t.id]},_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())},_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())},_getSelectedNodeCount:function(){var t=0;for(var e in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(e)&&(t+=1);return t},_getSelectedNode:function(){for(var t in this.selectionObj.nodes)if(this.selectionObj.nodes.hasOwnProperty(t))return this.selectionObj.nodes[t];return null},_getSelectedEdgeCount:function(){var t=0;for(var e in this.selectionObj.edges)this.selectionObj.edges.hasOwnProperty(e)&&(t+=1);return t},_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},_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},_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},_selectConnectedEdges:function(t){for(var e=0;ee;e++){s=t[e];var n=this.nodes[s];if(!n)throw new RangeError('Node with id "'+s+'" not found');this._selectObject(n,!0,!0)}this.redraw()},_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])}},NavigationMixin={_cleanNavigation:function(){var t=document.getElementById("graph-navigation_wrapper");null!=t&&this.containerElement.removeChild(t),document.onmouseup=null},_loadNavigationElements:function(){this._cleanNavigation(),this.navigationDivs={};var t=["up","down","left","right","zoomIn","zoomOut","zoomExtends"],e=["_moveUp","_moveDown","_moveLeft","_moveRight","_zoomIn","_zoomOut","zoomExtent"];this.navigationDivs.wrapper=document.createElement("div"),this.navigationDivs.wrapper.id="graph-navigation_wrapper",this.navigationDivs.wrapper.style.position="absolute",this.navigationDivs.wrapper.style.width=this.frame.canvas.clientWidth+"px",this.navigationDivs.wrapper.style.height=this.frame.canvas.clientHeight+"px",this.containerElement.insertBefore(this.navigationDivs.wrapper,this.frame);for(var i=0;it.x&&(s=t.x),nt.y&&(e=t.y),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 o=Math.min(this.frame.canvas.clientWidth/600,this.frame.canvas.clientHeight/600);i*=o}else{var a=1.1*(Math.abs(s.minX)+Math.abs(s.maxX)),r=1.1*(Math.abs(s.minY)+Math.abs(s.maxY)),h=this.frame.canvas.clientWidth/a,d=this.frame.canvas.clientHeight/r;i=d>=h?h:d}i>1&&(i=1),this._setScale(i),this._centerGraph(s),0==e&&(this.moving=!0,this.start())},Graph.prototype._updateNodeIndexList=function(){this._clearNodeIndexList();for(var t in this.nodes)this.nodes.hasOwnProperty(t)&&this.nodeIndices.push(t)},Graph.prototype.setData=function(t,e){if(void 0===e&&(e=!1),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(this.setOptions(t&&t.options),t&&t.dot){if(t&&t.dot){var i=vis.util.DOTToGraph(t.dot);return void this.setData(i)}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this._putDataInSector(),e||(this.stabilize&&this._stabilize(),this.start())},Graph.prototype.setOptions=function(t){if(t){var e;if(void 0!==t.width&&(this.width=t.width),void 0!==t.height&&(this.height=t.height),void 0!==t.stabilize&&(this.stabilize=t.stabilize),void 0!==t.selectable&&(this.selectable=t.selectable),void 0!==t.smoothCurves&&(this.constants.smoothCurves=t.smoothCurves),void 0!==t.freezeForStabilization&&(this.constants.freezeForStabilization=t.freezeForStabilization),void 0!==t.configurePhysics&&(this.constants.configurePhysics=t.configurePhysics),void 0!==t.stabilizationIterations&&(this.constants.stabilizationIterations=t.stabilizationIterations),void 0!==t.labels)for(e in t.labels)t.labels.hasOwnProperty(e)&&(this.constants.labels[e]=t.labels[e]);if(t.onAdd&&(this.triggerFunctions.add=t.onAdd),t.onEdit&&(this.triggerFunctions.edit=t.onEdit),t.onConnect&&(this.triggerFunctions.connect=t.onConnect),t.onDelete&&(this.triggerFunctions.del=t.onDelete),t.physics){if(t.physics.barnesHut){this.constants.physics.barnesHut.enabled=!0;for(e in t.physics.barnesHut)t.physics.barnesHut.hasOwnProperty(e)&&(this.constants.physics.barnesHut[e]=t.physics.barnesHut[e])}if(t.physics.repulsion){this.constants.physics.barnesHut.enabled=!1;for(e in t.physics.repulsion)t.physics.repulsion.hasOwnProperty(e)&&(this.constants.physics.repulsion[e]=t.physics.repulsion[e])}}if(t.hierarchicalLayout){this.constants.hierarchicalLayout.enabled=!0;for(e in t.hierarchicalLayout)t.hierarchicalLayout.hasOwnProperty(e)&&(this.constants.hierarchicalLayout[e]=t.hierarchicalLayout[e])}else void 0!==t.hierarchicalLayout&&(this.constants.hierarchicalLayout.enabled=!1);if(t.clustering){this.constants.clustering.enabled=!0;for(e in t.clustering)t.clustering.hasOwnProperty(e)&&(this.constants.clustering[e]=t.clustering[e])}else void 0!==t.clustering&&(this.constants.clustering.enabled=!1);if(t.navigation){this.constants.navigation.enabled=!0;for(e in t.navigation)t.navigation.hasOwnProperty(e)&&(this.constants.navigation[e]=t.navigation[e])}else void 0!==t.navigation&&(this.constants.navigation.enabled=!1);if(t.keyboard){this.constants.keyboard.enabled=!0;for(e in t.keyboard)t.keyboard.hasOwnProperty(e)&&(this.constants.keyboard[e]=t.keyboard[e])}else void 0!==t.keyboard&&(this.constants.keyboard.enabled=!1);if(t.dataManipulation){this.constants.dataManipulation.enabled=!0;for(e in t.dataManipulation)t.dataManipulation.hasOwnProperty(e)&&(this.constants.dataManipulation[e]=t.dataManipulation[e])}else void 0!==t.dataManipulation&&(this.constants.dataManipulation.enabled=!1);if(t.edges){for(e in t.edges)t.edges.hasOwnProperty(e)&&"object"!=typeof t.edges[e]&&(this.constants.edges[e]=t.edges[e]);void 0!==t.edges.color&&(util.isString(t.edges.color)?(this.constants.edges.color={},this.constants.edges.color.color=t.edges.color,this.constants.edges.color.highlight=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))),t.edges.fontColor||void 0!==t.edges.color&&(util.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.edges.dash&&(void 0!==t.edges.dash.length&&(this.constants.edges.dash.length=t.edges.dash.length),void 0!==t.edges.dash.gap&&(this.constants.edges.dash.gap=t.edges.dash.gap),void 0!==t.edges.dash.altLength&&(this.constants.edges.dash.altLength=t.edges.dash.altLength))}if(t.nodes){for(e in t.nodes)t.nodes.hasOwnProperty(e)&&(this.constants.nodes[e]=t.nodes[e]);t.nodes.color&&(this.constants.nodes.color=util.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var s=t.groups[i];this.groups.add(i,s)}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=util.parseColor(t.tooltip.color))}}this._loadPhysicsSystem(),this._loadNavigationControls(),this._loadManipulationSystem(),this._configureSmoothCurves(),this._createKeyBinds(),this.setSize(this.width,this.height),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1),this._redraw()},Graph.prototype._create=function(){for(;this.containerElement.hasChildNodes();)this.containerElement.removeChild(this.containerElement.firstChild);if(this.frame=document.createElement("div"),this.frame.className="graph-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=document.createElement("DIV");t.style.color="red",t.style.fontWeight="bold",t.style.padding="10px",t.innerHTML="Error: your browser does not support HTML canvas",this.frame.canvas.appendChild(t)}var e=this;this.drag={},this.pinch={},this.hammer=Hammer(this.frame.canvas,{prevent_default:!0}),this.hammer.on("tap",e._onTap.bind(e)),this.hammer.on("doubletap",e._onDoubleTap.bind(e)),this.hammer.on("hold",e._onHold.bind(e)),this.hammer.on("pinch",e._onPinch.bind(e)),this.hammer.on("touch",e._onTouch.bind(e)),this.hammer.on("dragstart",e._onDragStart.bind(e)),this.hammer.on("drag",e._onDrag.bind(e)),this.hammer.on("dragend",e._onDragEnd.bind(e)),this.hammer.on("release",e._onRelease.bind(e)),this.hammer.on("mousewheel",e._onMouseWheel.bind(e)),this.hammer.on("DOMMouseScroll",e._onMouseWheel.bind(e)),this.hammer.on("mousemove",e._onMouseMoveTitle.bind(e)),this.containerElement.appendChild(this.frame)},Graph.prototype._createKeyBinds=function(){var t=this;this.mousetrap=mousetrap,this.mousetrap.reset(),1==this.constants.keyboard.enabled&&(this.mousetrap.bind("up",this._moveUp.bind(t),"keydown"),this.mousetrap.bind("up",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("down",this._moveDown.bind(t),"keydown"),this.mousetrap.bind("down",this._yStopMoving.bind(t),"keyup"),this.mousetrap.bind("left",this._moveLeft.bind(t),"keydown"),this.mousetrap.bind("left",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("right",this._moveRight.bind(t),"keydown"),this.mousetrap.bind("right",this._xStopMoving.bind(t),"keyup"),this.mousetrap.bind("=",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("=",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("-",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("-",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("[",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("[",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("]",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("]",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pageup",this._zoomIn.bind(t),"keydown"),this.mousetrap.bind("pageup",this._stopZoom.bind(t),"keyup"),this.mousetrap.bind("pagedown",this._zoomOut.bind(t),"keydown"),this.mousetrap.bind("pagedown",this._stopZoom.bind(t),"keyup")),1==this.constants.dataManipulation.enabled&&(this.mousetrap.bind("escape",this._createManipulatorBar.bind(t)),this.mousetrap.bind("del",this._deleteSelected.bind(t)))},Graph.prototype._getPointer=function(t){return{x:t.pageX-vis.util.getAbsoluteLeft(this.frame.canvas),y:t.pageY-vis.util.getAbsoluteTop(this.frame.canvas)}},Graph.prototype._onTouch=function(t){this.drag.pointer=this._getPointer(t.gesture.center),this.drag.pinched=!1,this.pinch.scale=this._getScale(),this._handleTouch(this.drag.pointer)},Graph.prototype._onDragStart=function(){this._handleDragStart()},Graph.prototype._handleDragStart=function(){var t=this.drag,e=this._getNodeAt(t.pointer);if(t.dragging=!0,t.selection=[],t.translation=this._getTranslation(),t.nodeId=null,null!=e){t.nodeId=e.id,e.isSelected()||this._selectObject(e,!1);for(var i in this.selectionObj.nodes)if(this.selectionObj.nodes.hasOwnProperty(i)){var s=this.selectionObj.nodes[i],n={id:s.id,node:s,x:s.x,y:s.y,xFixed:s.xFixed,yFixed:s.yFixed};s.xFixed=!0,s.yFixed=!0,t.selection.push(n)}}},Graph.prototype._onDrag=function(t){this._handleOnDrag(t)},Graph.prototype._handleOnDrag=function(t){if(!this.drag.pinched){var e=this._getPointer(t.gesture.center),i=this,s=this.drag,n=s.selection;if(n&&n.length){var o=e.x-s.pointer.x,a=e.y-s.pointer.y;n.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._canvasToX(i._xToCanvas(t.x)+o)),t.yFixed||(e.y=i._canvasToY(i._yToCanvas(t.y)+a))}),this.moving||(this.moving=!0,this.start())}else{var r=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+r,this.drag.translation.y+h),this._redraw(),this.moving=!0}}},Graph.prototype._onDragEnd=function(){this.drag.dragging=!1;var t=this.drag.selection;t&&t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed})},Graph.prototype._onTap=function(t){var e=this._getPointer(t.gesture.center);this.pointerPosition=e,this._handleTap(e)},Graph.prototype._onDoubleTap=function(t){var e=this._getPointer(t.gesture.center);this._handleDoubleTap(e)},Graph.prototype._onHold=function(t){var e=this._getPointer(t.gesture.center);this.pointerPosition=e,this._handleOnHold(e)},Graph.prototype._onRelease=function(t){var e=this._getPointer(t.gesture.center);this._handleOnRelease(e)},Graph.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)},Graph.prototype._zoom=function(t,e){var i=this._getScale();1e-5>t&&(t=1e-5),t>10&&(t=10);var s=this._getTranslation(),n=t/i,o=(1-n)*e.x+s.x*n,a=(1-n)*e.y+s.y*n;return this.areaCenter={x:this._canvasToX(e.x),y:this._canvasToY(e.y)},this._setScale(t),this._setTranslation(o,a),this.updateClustersDefault(),this._redraw(),t},Graph.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 n=util.fakeGesture(this,t),o=this._getPointer(n.center);this._zoom(i,o)}t.preventDefault()},Graph.prototype._onMouseMoveTitle=function(t){var e=util.fakeGesture(this,t),i=this._getPointer(e.center);this.popupNode&&this._checkHidePopup(i);var s=this,n=function(){s._checkShowPopup(i)};this.popupTimer&&clearInterval(this.popupTimer),this.drag.dragging||(this.popupTimer=setTimeout(n,this.constants.tooltip.delay))},Graph.prototype._checkShowPopup=function(t){var e,i={left:this._canvasToX(t.x),top:this._canvasToY(t.y),right:this._canvasToX(t.x),bottom:this._canvasToY(t.y)},s=this.popupNode;if(void 0==this.popupNode){var n=this.nodes;for(e in n)if(n.hasOwnProperty(e)){var o=n[e];if(void 0!==o.getTitle()&&o.isOverlappingWith(i)){this.popupNode=o;break}}}if(void 0===this.popupNode){var a=this.edges;for(e in a)if(a.hasOwnProperty(e)){var r=a[e];if(r.connected&&void 0!==r.getTitle()&&r.isOverlappingWith(i)){this.popupNode=r;break}}}if(this.popupNode){if(this.popupNode!=s){var h=this;h.popup||(h.popup=new Popup(h.frame,h.constants.tooltip)),h.popup.setPosition(t.x-3,t.y-3),h.popup.setText(h.popupNode.getTitle()),h.popup.show()}}else this.popup&&this.popup.hide()},Graph.prototype._checkHidePopup=function(t){this.popupNode&&this._getNodeAt(t)||(this.popupNode=void 0,this.popup&&this.popup.hide())},Graph.prototype.setSize=function(t,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.frame.canvas.height=this.frame.canvas.clientHeight,void 0!==this.manipulationDiv&&(this.manipulationDiv.style.width=this.frame.canvas.clientWidth+"px"),void 0!==this.navigationDivs&&void 0!==this.navigationDivs.wrapper&&(this.navigationDivs.wrapper.style.width=this.frame.canvas.clientWidth+"px",this.navigationDivs.wrapper.style.height=this.frame.canvas.clientHeight+"px"),this.emit("resize",{width:this.frame.canvas.width,height:this.frame.canvas.height})},Graph.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof DataSet||t instanceof DataView)this.nodesData=t;else if(t instanceof Array)this.nodesData=new DataSet,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new DataSet}if(e&&util.forEach(this.nodesListeners,function(t,i){e.off(i,t)}),this.nodes={},this.nodesData){var i=this;util.forEach(this.nodesListeners,function(t,e){i.nodesData.on(e,t)});var s=this.nodesData.getIds();this._addNodes(s)}this._updateSelection()},Graph.prototype._addNodes=function(t){for(var e,i=0,s=t.length;s>i;i++){e=t[i];var n=this.nodesData.get(e),o=new Node(n,this.images,this.groups,this.constants);if(this.nodes[e]=o,!(0!=o.xFixed&&0!=o.yFixed||null!==o.x&&null!==o.y)){var a=1*t.length,r=2*Math.PI*Math.random();0==o.xFixed&&(o.x=a*Math.cos(r)),0==o.yFixed&&(o.y=a*Math.sin(r))}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()},Graph.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,s=0,n=t.length;n>s;s++){var o=t[s],a=e[o],r=i.get(o);a?a.setProperties(r,this.constants):(a=new Node(properties,this.images,this.groups,this.constants),e[o]=a)}this.moving=!0,1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this._updateNodeIndexList(),this._reconnectEdges(),this._updateValueRange(e)},Graph.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,s=t.length;s>i;i++){var n=t[i];delete e[n]}this._updateNodeIndexList(),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this._updateCalculationNodes(),this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},Graph.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof DataSet||t instanceof DataView)this.edgesData=t;else if(t instanceof Array)this.edgesData=new DataSet,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new DataSet}if(e&&util.forEach(this.edgesListeners,function(t,i){e.off(i,t)}),this.edges={},this.edgesData){var i=this;util.forEach(this.edgesListeners,function(t,e){i.edgesData.on(e,t)});var s=this.edgesData.getIds();this._addEdges(s)}this._reconnectEdges()},Graph.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,s=0,n=t.length;n>s;s++){var o=t[s],a=e[o];a&&a.disconnect();var r=i.get(o,{showInternalIds:!0});e[o]=new Edge(r,this,this.constants)}this.moving=!0,this._updateValueRange(e),this._createBezierNodes(),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this._updateCalculationNodes()},Graph.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,s=0,n=t.length;n>s;s++){var o=t[s],a=i.get(o),r=e[o];r?(r.disconnect(),r.setProperties(a,this.constants),r.connect()):(r=new Edge(a,this,this.constants),this.edges[o]=r)}this._createBezierNodes(),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this.moving=!0,this._updateValueRange(e)},Graph.prototype._removeEdges=function(t){for(var e=this.edges,i=0,s=t.length;s>i;i++){var n=t[i],o=e[n];o&&(null!=o.via&&delete this.sectors.support.nodes[o.via.id],o.disconnect(),delete e[n])}this.moving=!0,this._updateValueRange(e),1==this.constants.hierarchicalLayout.enabled&&0==this.initializing&&(this._resetLevels(),this._setupHierarchicalLayout()),this._updateCalculationNodes()},Graph.prototype._reconnectEdges=function(){var t,e=this.nodes,i=this.edges;for(t in e)e.hasOwnProperty(t)&&(e[t].edges=[]);for(t in i)if(i.hasOwnProperty(t)){var s=i[t];s.from=null,s.to=null,s.connect()}},Graph.prototype._updateValueRange=function(t){var e,i=void 0,s=void 0;for(e in t)if(t.hasOwnProperty(e)){var n=t[e].getValue();void 0!==n&&(i=void 0===i?n:Math.min(n,i),s=void 0===s?n:Math.max(n,s))}if(void 0!==i&&void 0!==s)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,s)},Graph.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},Graph.prototype._redraw=function(){var t=this.frame.canvas.getContext("2d"),e=this.frame.canvas.width,i=this.frame.canvas.height;t.clearRect(0,0,e,i),t.save(),t.translate(this.translation.x,this.translation.y),t.scale(this.scale,this.scale),this.canvasTopLeft={x:this._canvasToX(0),y:this._canvasToY(0)},this.canvasBottomRight={x:this._canvasToX(this.frame.canvas.clientWidth),y:this._canvasToY(this.frame.canvas.clientHeight)},this._doInAllSectors("_drawAllSectorNodes",t),this._doInAllSectors("_drawEdges",t),this._doInAllSectors("_drawNodes",t,!1),t.restore()},Graph.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)},Graph.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},Graph.prototype._setScale=function(t){this.scale=t},Graph.prototype._getScale=function(){return this.scale},Graph.prototype._canvasToX=function(t){return(t-this.translation.x)/this.scale},Graph.prototype._xToCanvas=function(t){return t*this.scale+this.translation.x},Graph.prototype._canvasToY=function(t){return(t-this.translation.y)/this.scale},Graph.prototype._yToCanvas=function(t){return t*this.scale+this.translation.y},Graph.prototype._drawNodes=function(t,e){void 0===e&&(e=!1);var i=this.nodes,s=[];for(var n in i)i.hasOwnProperty(n)&&(i[n].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight),i[n].isSelected()?s.push(n):(i[n].inArea()||e)&&i[n].draw(t));for(var o=0,a=s.length;a>o;o++)(i[s[o]].inArea()||e)&&i[s[o]].draw(t)},Graph.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)}},Graph.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 n=this.constants.minVelocity/Math.max(this.scale,.05);this.moving=n>.5*this.constants.maxVelocity?!0:this._isMoving(n)}},Graph.prototype._physicsTick=function(){this.freezeSimulation||this.moving&&(this._doInAllActiveSectors("_initializeForceCalculation"),this._doInAllActiveSectors("_discreteStepNodes"),this.constants.smoothCurves&&this._doInSupportSector("_discreteStepNodes"),this._findCenter(this._getRange()))},Graph.prototype._animationStep=function(){this.timer=void 0,this._handleNavigation(),this.start();var t=Date.now(),e=1;this._physicsTick();for(var i=Date.now()-t;is;++s)i[s].apply(this,e)}return this},i.prototype.listeners=function(t){return this._callbacks=this._callbacks||{},this._callbacks[t]||[]},i.prototype.hasListeners=function(t){return!!this.listeners(t).length}},{}],3:[function(t,e){!function(t,i){"use strict";function s(){if(!n.READY){n.event.determineEventTypes();for(var t in n.gestures)n.gestures.hasOwnProperty(t)&&n.detection.register(n.gestures[t]);n.event.onTouch(n.DOCUMENT,n.EVENT_MOVE,n.detection.detect),n.event.onTouch(n.DOCUMENT,n.EVENT_END,n.detection.detect),n.READY=!0}}var n=function(t,e){return new n.Instance(t,e||{})};n.defaults={stop_browser_behavior:{userSelect:"none",touchAction:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}},n.HAS_POINTEREVENTS=navigator.pointerEnabled||navigator.msPointerEnabled,n.HAS_TOUCHEVENTS="ontouchstart"in t,n.MOBILE_REGEX=/mobile|tablet|ip(ad|hone|od)|android/i,n.NO_MOUSEEVENTS=n.HAS_TOUCHEVENTS&&navigator.userAgent.match(n.MOBILE_REGEX),n.EVENT_TYPES={},n.DIRECTION_DOWN="down",n.DIRECTION_LEFT="left",n.DIRECTION_UP="up",n.DIRECTION_RIGHT="right",n.POINTER_MOUSE="mouse",n.POINTER_TOUCH="touch",n.POINTER_PEN="pen",n.EVENT_START="start",n.EVENT_MOVE="move",n.EVENT_END="end",n.DOCUMENT=document,n.plugins={},n.READY=!1,n.Instance=function(t,e){var i=this; +return s(),this.element=t,this.enabled=!0,this.options=n.utils.extend(n.utils.extend({},n.defaults),e||{}),this.options.stop_browser_behavior&&n.utils.stopDefaultBrowserBehavior(this.element,this.options.stop_browser_behavior),n.event.onTouch(t,n.EVENT_START,function(t){i.enabled&&n.detection.startDetect(i,t)}),this},n.Instance.prototype={on:function(t,e){for(var i=t.split(" "),s=0;s0&&e==n.EVENT_END?e=n.EVENT_MOVE:c||(e=n.EVENT_END),c||null===o?o=h:h=o,i.call(n.detection,s.collectEventData(t,e,h)),n.HAS_POINTEREVENTS&&e==n.EVENT_END&&(c=n.PointerEvent.updatePointer(e,h))),c||(o=null,a=!1,r=!1,n.PointerEvent.reset())}})},determineEventTypes:function(){var t;t=n.HAS_POINTEREVENTS?n.PointerEvent.getEvents():n.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],n.EVENT_TYPES[n.EVENT_START]=t[0],n.EVENT_TYPES[n.EVENT_MOVE]=t[1],n.EVENT_TYPES[n.EVENT_END]=t[2]},getTouchList:function(t){return n.HAS_POINTEREVENTS?n.PointerEvent.getTouchList():t.touches?t.touches:[{identifier:1,pageX:t.pageX,pageY:t.pageY,target:t.target}]},collectEventData:function(t,e,i){var s=this.getTouchList(i,e),o=n.POINTER_TOUCH;return(i.type.match(/mouse/)||n.PointerEvent.matchType(n.POINTER_MOUSE,i))&&(o=n.POINTER_MOUSE),{center:n.utils.getCenter(s),timeStamp:(new Date).getTime(),target:i.target,touches:s,eventType:e,pointerType:o,srcEvent:i,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return n.detection.stopDetect()}}}},n.PointerEvent={pointers:{},getTouchList:function(){var t=this,e=[];return Object.keys(t.pointers).sort().forEach(function(i){e.push(t.pointers[i])}),e},updatePointer:function(t,e){return t==n.EVENT_END?this.pointers={}:(e.identifier=e.pointerId,this.pointers[e.pointerId]=e),Object.keys(this.pointers).length},matchType:function(t,e){if(!e.pointerType)return!1;var i={};return i[n.POINTER_MOUSE]=e.pointerType==e.MSPOINTER_TYPE_MOUSE||e.pointerType==n.POINTER_MOUSE,i[n.POINTER_TOUCH]=e.pointerType==e.MSPOINTER_TYPE_TOUCH||e.pointerType==n.POINTER_TOUCH,i[n.POINTER_PEN]=e.pointerType==e.MSPOINTER_TYPE_PEN||e.pointerType==n.POINTER_PEN,i[t]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},n.utils={extend:function(t,e,s){for(var n in e)t[n]!==i&&s||(t[n]=e[n]);return t},hasParent:function(t,e){for(;t;){if(t==e)return!0;t=t.parentNode}return!1},getCenter:function(t){for(var e=[],i=[],s=0,n=t.length;n>s;s++)e.push(t[s].pageX),i.push(t[s].pageY);return{pageX:(Math.min.apply(Math,e)+Math.max.apply(Math,e))/2,pageY:(Math.min.apply(Math,i)+Math.max.apply(Math,i))/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.pageY-t.pageY,s=e.pageX-t.pageX;return 180*Math.atan2(i,s)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.pageX-e.pageX),s=Math.abs(t.pageY-e.pageY);return i>=s?t.pageX-e.pageX>0?n.DIRECTION_LEFT:n.DIRECTION_RIGHT:t.pageY-e.pageY>0?n.DIRECTION_UP:n.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,s=e.pageY-t.pageY;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==n.DIRECTION_UP||t==n.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){var i,s=["webkit","khtml","moz","ms","o",""];if(e&&t.style){for(var n=0;ni;i++){var o=this.gestures[i];if(!this.stopped&&e[o.name]!==!1&&o.handler.call(o,t,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=t),t.eventType==n.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t}},stopDetect:function(){this.previous=n.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(t){var e=this.current.startEvent;if(e&&(t.touches.length!=e.touches.length||t.touches===e.touches)){e.touches=[];for(var i=0,s=t.touches.length;s>i;i++)e.touches.push(n.utils.extend({},t.touches[i]))}var o=t.timeStamp-e.timeStamp,a=t.center.pageX-e.center.pageX,r=t.center.pageY-e.center.pageY,h=n.utils.getVelocity(o,a,r);return n.utils.extend(t,{deltaTime:o,deltaX:a,deltaY:r,velocityX:h.x,velocityY:h.y,distance:n.utils.getDistance(e.center,t.center),angle:n.utils.getAngle(e.center,t.center),direction:n.utils.getDirection(e.center,t.center),scale:n.utils.getScale(e.touches,t.touches),rotation:n.utils.getRotation(e.touches,t.touches),startEvent:e}),t},register:function(t){var e=t.defaults||{};return e[t.name]===i&&(e[t.name]=!0),n.utils.extend(n.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}},n.gestures=n.gestures||{},n.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,e){switch(t.eventType){case n.EVENT_START:clearTimeout(this.timer),n.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==n.detection.current.name&&e.trigger("hold",t)},e.options.hold_timeout);break;case n.EVENT_MOVE:t.distance>e.options.hold_threshold&&clearTimeout(this.timer);break;case n.EVENT_END:clearTimeout(this.timer)}}},n.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(t,e){if(t.eventType==n.EVENT_END){var i=n.detection.previous,s=!1;if(t.deltaTime>e.options.tap_max_touchtime||t.distance>e.options.tap_max_distance)return;i&&"tap"==i.name&&t.timeStamp-i.lastEvent.timeStamp0&&t.touches.length>e.options.swipe_max_touches)return;(t.velocityX>e.options.swipe_velocity||t.velocityY>e.options.swipe_velocity)&&(e.trigger(this.name,t),e.trigger(this.name+t.direction,t))}}},n.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,drag_max_touches:1,drag_block_horizontal:!1,drag_block_vertical:!1,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(t,e){if(n.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),void(this.triggered=!1);if(!(e.options.drag_max_touches>0&&t.touches.length>e.options.drag_max_touches))switch(t.eventType){case n.EVENT_START:this.triggered=!1;break;case n.EVENT_MOVE:if(t.distancee.options.transform_min_rotation&&e.trigger("rotate",t),i>e.options.transform_min_scale&&(e.trigger("pinch",t),e.trigger("pinch"+(t.scale<1?"in":"out"),t));break;case n.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},n.gestures.Touch={name:"touch",index:-1/0,defaults:{prevent_default:!1,prevent_mouseevents:!1},handler:function(t,e){return e.options.prevent_mouseevents&&t.pointerType==n.POINTER_MOUSE?void t.stopDetect():(e.options.prevent_default&&t.preventDefault(),void(t.eventType==n.EVENT_START&&e.trigger(this.name,t)))}},n.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==n.EVENT_END&&e.trigger(this.name,t)}},"object"==typeof e&&"object"==typeof e.exports?e.exports=n:(t.Hammer=n,"function"==typeof t.define&&t.define.amd&&t.define("hammer",[],function(){return n}))}(this)},{}],4:[function(t,e){var i="undefined"!=typeof self?self:"undefined"!=typeof window?window:{};(function(s){function n(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function o(t,e){function i(){le.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+t)}var s=!0;return l(function(){return s&&(i(),s=!1),e.apply(this,arguments)},e)}function a(t,e){return function(i){return g(t.call(this,i),e)}}function r(t,e){return function(i){return this.lang().ordinal(t.call(this,i),e)}}function h(){}function d(t){I(t),l(this,t)}function c(t){var e=b(t),i=e.year||0,s=e.quarter||0,n=e.month||0,o=e.week||0,a=e.day||0,r=e.hour||0,h=e.minute||0,d=e.second||0,c=e.millisecond||0;this._milliseconds=+c+1e3*d+6e4*h+36e5*r,this._days=+a+7*o,this._months=+n+3*s+12*i,this._data={},this._bubble()}function l(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return e.hasOwnProperty("toString")&&(t.toString=e.toString),e.hasOwnProperty("valueOf")&&(t.valueOf=e.valueOf),t}function u(t){var e,i={};for(e in t)t.hasOwnProperty(e)&&Te.hasOwnProperty(e)&&(i[e]=t[e]);return i}function p(t){return 0>t?Math.ceil(t):Math.floor(t)}function g(t,e,i){for(var s=""+Math.abs(t),n=t>=0;s.lengths;s++)(i&&t[s]!==e[s]||!i&&S(t[s])!==S(e[s]))&&a++;return a+o}function _(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=ti[t]||ei[e]||e}return t}function b(t){var e,i,s={};for(i in t)t.hasOwnProperty(i)&&(e=_(i),e&&(s[e]=t[i]));return s}function w(t){var e,i;if(0===t.indexOf("week"))e=7,i="day";else{if(0!==t.indexOf("month"))return;e=12,i="month"}le[t]=function(n,o){var a,r,h=le.fn._lang[t],d=[];if("number"==typeof n&&(o=n,n=s),r=function(t){var e=le().utc().set(i,t);return h.call(le.fn._lang,e,n||"")},null!=o)return r(o);for(a=0;e>a;a++)d.push(r(a));return d}}function S(t){var e=+t,i=0;return 0!==e&&isFinite(e)&&(i=e>=0?Math.floor(e):Math.ceil(e)),i}function x(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function E(t,e,i){return ee(le([t,11,31+e-i]),e,i).week}function T(t){return D(t)?366:365}function D(t){return t%4===0&&t%100!==0||t%400===0}function I(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[ye]<0||t._a[ye]>11?ye:t._a[_e]<1||t._a[_e]>x(t._a[ve],t._a[ye])?_e:t._a[be]<0||t._a[be]>23?be:t._a[we]<0||t._a[we]>59?we:t._a[Se]<0||t._a[Se]>59?Se:t._a[xe]<0||t._a[xe]>999?xe:-1,t._pf._overflowDayOfYear&&(ve>e||e>_e)&&(e=_e),t._pf.overflow=e)}function C(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._isValid}function M(t){return t?t.toLowerCase().replace("_","-"):t}function N(t,e){return e._isUTC?le(t).zone(e._offset||0):le(t).local()}function O(t,e){return e.abbr=t,Ee[t]||(Ee[t]=new h),Ee[t].set(e),Ee[t]}function L(t){delete Ee[t]}function k(e){var i,s,n,o,a=0,r=function(e){if(!Ee[e]&&De)try{t("./lang/"+e)}catch(i){}return Ee[e]};if(!e)return le.fn._lang;if(!f(e)){if(s=r(e))return s;e=[e]}for(;a0;){if(s=r(o.slice(0,i).join("-")))return s;if(n&&n.length>=i&&y(o,n,!0)>=i-1)break;i--}a++}return le.fn._lang}function P(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function A(t){var e,i,s=t.match(Ne);for(e=0,i=s.length;i>e;e++)s[e]=oi[s[e]]?oi[s[e]]:P(s[e]);return function(n){var o="";for(e=0;i>e;e++)o+=s[e]instanceof Function?s[e].call(n,t):s[e];return o}}function F(t,e){return t.isValid()?(e=z(e,t.lang()),ii[e]||(ii[e]=A(e)),ii[e](t)):t.lang().invalidDate()}function z(t,e){function i(t){return e.longDateFormat(t)||t}var s=5;for(Oe.lastIndex=0;s>=0&&Oe.test(t);)t=t.replace(Oe,i),Oe.lastIndex=0,s-=1;return t}function R(t,e){var i,s=e._strict;switch(t){case"Q":return We;case"DDDD":return je;case"YYYY":case"GGGG":case"gggg":return s?Ve:Pe;case"Y":case"G":case"g":return Xe;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return s?Ue:Ae;case"S":if(s)return We;case"SS":if(s)return Be;case"SSS":if(s)return je;case"DDD":return ke;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return ze;case"a":case"A":return k(e._l)._meridiemParse;case"X":return Ye;case"Z":case"ZZ":return Re;case"T":return He;case"SSSS":return Fe;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return s?Be:Le;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return Le;case"Do":return Ge;default:return i=new RegExp(U(V(t.replace("\\","")),"i"))}}function H(t){t=t||"";var e=t.match(Re)||[],i=e[e.length-1]||[],s=(i+"").match(Je)||["-",0,0],n=+(60*s[1])+S(s[2]);return"+"===s[0]?-n:n}function Y(t,e,i){var s,n=i._a;switch(t){case"Q":null!=e&&(n[ye]=3*(S(e)-1));break;case"M":case"MM":null!=e&&(n[ye]=S(e)-1);break;case"MMM":case"MMMM":s=k(i._l).monthsParse(e),null!=s?n[ye]=s:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(n[_e]=S(e));break;case"Do":null!=e&&(n[_e]=S(parseInt(e,10)));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=S(e));break;case"YY":n[ve]=le.parseTwoDigitYear(e);break;case"YYYY":case"YYYYY":case"YYYYYY":n[ve]=S(e);break;case"a":case"A":i._isPm=k(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":n[be]=S(e);break;case"m":case"mm":n[we]=S(e);break;case"s":case"ss":n[Se]=S(e);break;case"S":case"SS":case"SSS":case"SSSS":n[xe]=S(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=H(e);break;case"w":case"ww":case"W":case"WW":case"d":case"dd":case"ddd":case"dddd":case"e":case"E":t=t.substr(0,1);case"gg":case"gggg":case"GG":case"GGGG":case"GGGGG":t=t.substr(0,2),e&&(i._w=i._w||{},i._w[t]=e)}}function G(t){var e,i,s,n,o,a,r,h,d,c,l=[];if(!t._d){for(s=B(t),t._w&&null==t._a[_e]&&null==t._a[ye]&&(o=function(e){var i=parseInt(e,10);return e?e.length<3?i>68?1900+i:2e3+i:i:null==t._a[ve]?le().weekYear():t._a[ve]},a=t._w,null!=a.GG||null!=a.W||null!=a.E?r=ie(o(a.GG),a.W||1,a.E,4,1):(h=k(t._l),d=null!=a.d?J(a.d,h):null!=a.e?parseInt(a.e,10)+h._week.dow:0,c=parseInt(a.w,10)||1,null!=a.d&&dT(n)&&(t._pf._overflowDayOfYear=!0),i=$(n,0,t._dayOfYear),t._a[ye]=i.getUTCMonth(),t._a[_e]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=l[e]=s[e];for(;7>e;e++)t._a[e]=l[e]=null==t._a[e]?2===e?1:0:t._a[e];l[be]+=S((t._tzm||0)/60),l[we]+=S((t._tzm||0)%60),t._d=(t._useUTC?$:K).apply(null,l)}}function W(t){var e;t._d||(e=b(t._i),t._a=[e.year,e.month,e.day,e.hour,e.minute,e.second,e.millisecond],G(t))}function B(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function j(t){t._a=[],t._pf.empty=!0;var e,i,s,n,o,a=k(t._l),r=""+t._i,h=r.length,d=0;for(s=z(t._f,a).match(Ne)||[],e=0;e0&&t._pf.unusedInput.push(o),r=r.slice(r.indexOf(i)+i.length),d+=i.length),oi[n]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(n),Y(n,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(n);t._pf.charsLeftOver=h-d,r.length>0&&t._pf.unusedInput.push(r),t._isPm&&t._a[be]<12&&(t._a[be]+=12),t._isPm===!1&&12===t._a[be]&&(t._a[be]=0),G(t),I(t)}function V(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,s,n){return e||i||s||n})}function U(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function X(t){var e,i,s,o,a;if(0===t._f.length)return t._pf.invalidFormat=!0,void(t._d=new Date(0/0));for(o=0;oa)&&(s=a,i=e));l(t,i||e)}function q(t){var e,i,s=t._i,n=qe.exec(s);if(n){for(t._pf.iso=!0,e=0,i=Ke.length;i>e;e++)if(Ke[e][1].exec(s)){t._f=Ke[e][0]+(n[6]||" ");break}for(e=0,i=$e.length;i>e;e++)if($e[e][1].exec(s)){t._f+=$e[e][0];break}s.match(Re)&&(t._f+="Z"),j(t)}else le.createFromInputFallback(t)}function Z(t){var e=t._i,i=Ie.exec(e);e===s?t._d=new Date:i?t._d=new Date(+i[1]):"string"==typeof e?q(t):f(e)?(t._a=e.slice(0),G(t)):v(e)?t._d=new Date(+e):"object"==typeof e?W(t):"number"==typeof e?t._d=new Date(e):le.createFromInputFallback(t)}function K(t,e,i,s,n,o,a){var r=new Date(t,e,i,s,n,o,a);return 1970>t&&r.setFullYear(t),r}function $(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function J(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 Q(t,e,i,s,n){return n.relativeTime(e||1,!!i,t,s)}function te(t,e,i){var s=fe(Math.abs(t)/1e3),n=fe(s/60),o=fe(n/60),a=fe(o/24),r=fe(a/365),h=45>s&&["s",s]||1===n&&["m"]||45>n&&["mm",n]||1===o&&["h"]||22>o&&["hh",o]||1===a&&["d"]||25>=a&&["dd",a]||45>=a&&["M"]||345>a&&["MM",fe(a/30)]||1===r&&["y"]||["yy",r];return h[2]=e,h[3]=t>0,h[4]=i,Q.apply({},h)}function ee(t,e,i){var s,n=i-e,o=i-t.day();return o>n&&(o-=7),n-7>o&&(o+=7),s=le(t).add("d",o),{week:Math.ceil(s.dayOfYear()/7),year:s.year()}}function ie(t,e,i,s,n){var o,a,r=$(t,0,1).getUTCDay();return i=null!=i?i:n,o=n-r+(r>s?7:0)-(n>r?7:0),a=7*(e-1)+(i-n)+o+1,{year:a>0?t:t-1,dayOfYear:a>0?a:T(t-1)+a}}function se(t){var e=t._i,i=t._f;return null===e||i===s&&""===e?le.invalid({nullInput:!0}):("string"==typeof e&&(t._i=e=k().preparse(e)),le.isMoment(e)?(t=u(e),t._d=new Date(+e._d)):i?f(i)?X(t):j(t):Z(t),new d(t))}function ne(t,e){var i;return"string"==typeof e&&(e=t.lang().monthsParse(e),"number"!=typeof e)?t:(i=Math.min(t.date(),x(t.year(),e)),t._d["set"+(t._isUTC?"UTC":"")+"Month"](e,i),t)}function oe(t,e){return t._d["get"+(t._isUTC?"UTC":"")+e]()}function ae(t,e,i){return"Month"===e?ne(t,i):t._d["set"+(t._isUTC?"UTC":"")+e](i)}function re(t,e){return function(i){return null!=i?(ae(this,t,i),le.updateOffset(this,e),this):oe(this,t)}}function he(t){le.duration.fn[t]=function(){return this._data[t]}}function de(t,e){le.duration.fn["as"+t]=function(){return+this/e}}function ce(t){"undefined"==typeof ender&&(ue=me.moment,me.moment=t?o("Accessing Moment through the global scope is deprecated, and will be removed in an upcoming release.",le):le)}for(var le,ue,pe,ge="2.6.0",me="undefined"!=typeof i?i:this,fe=Math.round,ve=0,ye=1,_e=2,be=3,we=4,Se=5,xe=6,Ee={},Te={_isAMomentObject:null,_i:null,_f:null,_l:null,_strict:null,_isUTC:null,_offset:null,_pf:null,_lang:null},De="undefined"!=typeof e&&e.exports,Ie=/^\/?Date\((\-?\d+)/i,Ce=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,Me=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,Ne=/(\[[^\[]*\])|(\\)?(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|zz?|ZZ?|.)/g,Oe=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,Le=/\d\d?/,ke=/\d{1,3}/,Pe=/\d{1,4}/,Ae=/[+\-]?\d{1,6}/,Fe=/\d+/,ze=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Re=/Z|[\+\-]\d\d:?\d\d/gi,He=/T/i,Ye=/[\+\-]?\d+(\.\d{1,3})?/,Ge=/\d{1,2}/,We=/\d/,Be=/\d\d/,je=/\d{3}/,Ve=/\d{4}/,Ue=/[+-]?\d{6}/,Xe=/[+-]?\d+/,qe=/^\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)?)?$/,Ze="YYYY-MM-DDTHH:mm:ssZ",Ke=[["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}/]],$e=[["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/]],Je=/([\+\-]|\d\d)/gi,Qe=("Date|Hours|Minutes|Seconds|Milliseconds".split("|"),{Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6}),ti={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"},ei={dayofyear:"dayOfYear",isoweekday:"isoWeekday",isoweek:"isoWeek",weekyear:"weekYear",isoweekyear:"isoWeekYear"},ii={},si="DDD w W M D d".split(" "),ni="M D H h m s w W".split(" "),oi={M:function(){return this.month()+1},MMM:function(t){return this.lang().monthsShort(this,t)},MMMM:function(t){return this.lang().months(this,t)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(t){return this.lang().weekdaysMin(this,t)},ddd:function(t){return this.lang().weekdaysShort(this,t)},dddd:function(t){return this.lang().weekdays(this,t)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return g(this.year()%100,2)},YYYY:function(){return g(this.year(),4)},YYYYY:function(){return g(this.year(),5)},YYYYYY:function(){var t=this.year(),e=t>=0?"+":"-";return e+g(Math.abs(t),6)},gg:function(){return g(this.weekYear()%100,2)},gggg:function(){return g(this.weekYear(),4)},ggggg:function(){return g(this.weekYear(),5)},GG:function(){return g(this.isoWeekYear()%100,2)},GGGG:function(){return g(this.isoWeekYear(),4)},GGGGG:function(){return g(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().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 S(this.milliseconds()/100)},SS:function(){return g(S(this.milliseconds()/10),2)},SSS:function(){return g(this.milliseconds(),3)},SSSS:function(){return g(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+g(S(t/60),2)+":"+g(S(t)%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+g(S(t/60),2)+g(S(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},ai=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];si.length;)pe=si.pop(),oi[pe+"o"]=r(oi[pe],pe);for(;ni.length;)pe=ni.pop(),oi[pe+pe]=a(oi[pe],2);for(oi.DDDD=a(oi.DDD,3),l(h.prototype,{set:function(t){var e,i;for(i in t)e=t[i],"function"==typeof e?this[i]=e:this["_"+i]=e},_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){var e,i,s;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=le.utc([2e3,e]),s="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=new RegExp(s.replace(".",""),"i")),this._monthsParse[e].test(t))return e},_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=le([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:{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){var i=this._calendar[t];return"function"==typeof i?i.apply(e):i},_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 n=this._relativeTime[i];return"function"==typeof n?n(t,e,i,s):n.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",preparse:function(t){return t},postformat:function(t){return t},week:function(t){return ee(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),le=function(t,e,i,o){var a;return"boolean"==typeof i&&(o=i,i=s),a={},a._isAMomentObject=!0,a._i=t,a._f=e,a._l=i,a._strict=o,a._isUTC=!1,a._pf=n(),se(a)},le.suppressDeprecationWarnings=!1,le.createFromInputFallback=o("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)}),le.utc=function(t,e,i,o){var a;return"boolean"==typeof i&&(o=i,i=s),a={},a._isAMomentObject=!0,a._useUTC=!0,a._isUTC=!0,a._l=i,a._i=t,a._f=e,a._strict=o,a._pf=n(),se(a).utc()},le.unix=function(t){return le(1e3*t)},le.duration=function(t,e){var i,s,n,o=t,a=null;return le.isDuration(t)?o={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(o={},e?o[e]=t:o.milliseconds=t):(a=Ce.exec(t))?(i="-"===a[1]?-1:1,o={y:0,d:S(a[_e])*i,h:S(a[be])*i,m:S(a[we])*i,s:S(a[Se])*i,ms:S(a[xe])*i}):(a=Me.exec(t))&&(i="-"===a[1]?-1:1,n=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},o={y:n(a[2]),M:n(a[3]),d:n(a[4]),h:n(a[5]),m:n(a[6]),s:n(a[7]),w:n(a[8])}),s=new c(o),le.isDuration(t)&&t.hasOwnProperty("_lang")&&(s._lang=t._lang),s},le.version=ge,le.defaultFormat=Ze,le.momentProperties=Te,le.updateOffset=function(){},le.lang=function(t,e){var i;return t?(e?O(M(t),e):null===e?(L(t),t="en"):Ee[t]||k(t),i=le.duration.fn._lang=le.fn._lang=k(t),i._abbr):le.fn._lang._abbr},le.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),k(t)},le.isMoment=function(t){return t instanceof d||null!=t&&t.hasOwnProperty("_isAMomentObject")},le.isDuration=function(t){return t instanceof c},pe=ai.length-1;pe>=0;--pe)w(ai[pe]);le.normalizeUnits=function(t){return _(t)},le.invalid=function(t){var e=le.utc(0/0);return null!=t?l(e._pf,t):e._pf.userInvalidated=!0,e},le.parseZone=function(){return le.apply(null,arguments).parseZone()},le.parseTwoDigitYear=function(t){return S(t)+(S(t)>68?1900:2e3)},l(le.fn=d.prototype,{clone:function(){return le(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().lang("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=le(this).utc();return 00:!1},parsingFlags:function(){return l({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(t){var e=F(this,t||le.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?le.duration(+e,t):le.duration(t,e),m(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?le.duration(+e,t):le.duration(t,e),m(this,i,-1),this},diff:function(t,e,i){var s,n,o=N(t,this),a=6e4*(this.zone()-o.zone()); +return e=_(e),"year"===e||"month"===e?(s=432e5*(this.daysInMonth()+o.daysInMonth()),n=12*(this.year()-o.year())+(this.month()-o.month()),n+=(this-le(this).startOf("month")-(o-le(o).startOf("month")))/s,n-=6e4*(this.zone()-le(this).startOf("month").zone()-(o.zone()-le(o).startOf("month").zone()))/s,"year"===e&&(n/=12)):(s=this-o,n="second"===e?s/1e3:"minute"===e?s/6e4:"hour"===e?s/36e5:"day"===e?(s-a)/864e5:"week"===e?(s-a)/6048e5:s),i?n:p(n)},from:function(t,e){return le.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(le(),t)},calendar:function(){var t=N(le(),this).startOf("day"),e=this.diff(t,"days",!0),i=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse";return this.format(this.lang().calendar(i,this))},isLeapYear:function(){return D(this.year())},isDST:function(){return this.zone()+le(t).startOf(e)},isBefore:function(t,e){return e="undefined"!=typeof e?e:"millisecond",+this.clone().startOf(e)<+le(t).startOf(e)},isSame:function(t,e){return e=e||"ms",+this.clone().startOf(e)===+N(t,this).startOf(e)},min:function(t){return t=le.apply(null,arguments),this>t?this:t},max:function(t){return t=le.apply(null,arguments),t>this?this:t},zone:function(t,e){var i=this._offset||0;return null==t?this._isUTC?i:this._d.getTimezoneOffset():("string"==typeof t&&(t=H(t)),Math.abs(t)<16&&(t=60*t),this._offset=t,this._isUTC=!0,i!==t&&(!e||this._changeInProgress?m(this,le.duration(i-t,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,le.updateOffset(this,!0),this._changeInProgress=null)),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(t){return t=t?le(t).zone():0,(this.zone()-t)%60===0},daysInMonth:function(){return x(this.year(),this.month())},dayOfYear:function(t){var e=fe((le(this).startOf("day")-le(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},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=ee(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==t?e:this.add("y",t-e)},isoWeekYear:function(t){var e=ee(this,1,4).year;return null==t?e:this.add("y",t-e)},week:function(t){var e=this.lang().week(this);return null==t?e:this.add("d",7*(t-e))},isoWeek:function(t){var e=ee(this,1,4).week;return null==t?e:this.add("d",7*(t-e))},weekday:function(t){var e=(this.day()+7-this.lang()._week.dow)%7;return null==t?e:this.add("d",t-e)},isoWeekday:function(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)},isoWeeksInYear:function(){return E(this.year(),1,4)},weeksInYear:function(){var t=this._lang._week;return E(this.year(),t.dow,t.doy)},get:function(t){return t=_(t),this[t]()},set:function(t,e){return t=_(t),"function"==typeof this[t]&&this[t](e),this},lang:function(t){return t===s?this._lang:(this._lang=k(t),this)}}),le.fn.millisecond=le.fn.milliseconds=re("Milliseconds",!1),le.fn.second=le.fn.seconds=re("Seconds",!1),le.fn.minute=le.fn.minutes=re("Minutes",!1),le.fn.hour=le.fn.hours=re("Hours",!0),le.fn.date=re("Date",!0),le.fn.dates=o("dates accessor is deprecated. Use date instead.",re("Date",!0)),le.fn.year=re("FullYear",!0),le.fn.years=o("years accessor is deprecated. Use year instead.",re("FullYear",!0)),le.fn.days=le.fn.day,le.fn.months=le.fn.month,le.fn.weeks=le.fn.week,le.fn.isoWeeks=le.fn.isoWeek,le.fn.quarters=le.fn.quarter,le.fn.toJSON=le.fn.toISOString,l(le.duration.fn=c.prototype,{_bubble:function(){var t,e,i,s,n=this._milliseconds,o=this._days,a=this._months,r=this._data;r.milliseconds=n%1e3,t=p(n/1e3),r.seconds=t%60,e=p(t/60),r.minutes=e%60,i=p(e/60),r.hours=i%24,o+=p(i/24),r.days=o%30,a+=p(o/30),r.months=a%12,s=p(a/12),r.years=s},weeks:function(){return p(this.days()/7)},valueOf:function(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*S(this._months/12)},humanize:function(t){var e=+this,i=te(e,!t,this.lang());return t&&(i=this.lang().pastFuture(e,i)),this.lang().postformat(i)},add:function(t,e){var i=le.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=le.duration(t,e);return this._milliseconds-=i._milliseconds,this._days-=i._days,this._months-=i._months,this._bubble(),this},get:function(t){return t=_(t),this[t.toLowerCase()+"s"]()},as:function(t){return t=_(t),this["as"+t.charAt(0).toUpperCase()+t.slice(1)+"s"]()},lang:le.fn.lang,toIsoString:function(){var t=Math.abs(this.years()),e=Math.abs(this.months()),i=Math.abs(this.days()),s=Math.abs(this.hours()),n=Math.abs(this.minutes()),o=Math.abs(this.seconds()+this.milliseconds()/1e3);return this.asSeconds()?(this.asSeconds()<0?"-":"")+"P"+(t?t+"Y":"")+(e?e+"M":"")+(i?i+"D":"")+(s||n||o?"T":"")+(s?s+"H":"")+(n?n+"M":"")+(o?o+"S":""):"P0D"}});for(pe in Qe)Qe.hasOwnProperty(pe)&&(de(pe,Qe[pe]),he(pe.toLowerCase()));de("Weeks",6048e5),le.duration.fn.asMonths=function(){return(+this-31536e6*this.years())/2592e6+12*this.years()},le.lang("en",{ordinal:function(t){var e=t%10,i=1===S(t%100/10)?"th":1===e?"st":2===e?"nd":3===e?"rd":"th";return t+i}}),De?e.exports=le:"function"==typeof define&&define.amd?(define("moment",function(t,e,i){return i.config&&i.config()&&i.config().noGlobal===!0&&(me.moment=ue),le}),ce(!0)):ce()}).call(this)},{}],5:[function(t,e){function i(t,e,i){return t.addEventListener?t.addEventListener(e,i,!1):void t.attachEvent("on"+e,i)}function s(t){return"keypress"==t.type?String.fromCharCode(t.which):w[t.which]?w[t.which]:S[t.which]?S[t.which]:String.fromCharCode(t.which).toLowerCase()}function n(t){var e=t.target||t.srcElement,i=e.tagName;return(" "+e.className+" ").indexOf(" mousetrap ")>-1?!1:"INPUT"==i||"SELECT"==i||"TEXTAREA"==i||e.contentEditable&&"true"==e.contentEditable}function o(t,e){return t.sort().join(",")===e.sort().join(",")}function a(t){t=t||{};var e,i=!1;for(e in I)t[e]?i=!0:I[e]=0;i||(M=!1)}function r(t,e,i,s,n){var a,r,h=[];if(!T[t])return[];for("keyup"==i&&u(t)&&(e=[t]),a=0;a95&&112>t||w.hasOwnProperty(t)&&(_[w[t]]=t)}return _}function m(t,e,i){return i||(i=g()[t]?"keydown":"keypress"),"keypress"==i&&e.length&&(i="keydown"),i}function f(t,e,i,n){I[t]=0,n||(n=m(e[0],[]));var o,r=function(){M=n,++I[t],p()},h=function(t){d(i,t),"keyup"!==n&&(C=s(t)),setTimeout(a,10)};for(o=0;o1)return f(t,d,e,i);for(h="+"===t?["+"]:t.split("+"),o=0;o":".","?":"/","|":"\\"},E={option:"alt",command:"meta","return":"enter",escape:"esc"},T={},D={},I={},C=!1,M=!1,N=1;20>N;++N)w[111+N]="f"+N;for(N=0;9>=N;++N)w[N+96]=N;i(document,"keypress",l),i(document,"keydown",l),i(document,"keyup",l);var O={bind:function(t,e,i){return y(t instanceof Array?t:[t],e,i),D[t+":"+i]=e,this},unbind:function(t,e){return D[t+":"+e]&&(delete D[t+":"+e],this.bind(t,function(){},e)),this},trigger:function(t,e){return D[t+":"+e](),this},reset:function(){return T={},D={},this}};e.exports=O},{}]},{},[1])(1)}); \ No newline at end of file diff --git a/docs/dataset.html b/docs/dataset.html index cbb2ec8f..0828e37e 100644 --- a/docs/dataset.html +++ b/docs/dataset.html @@ -20,10 +20,10 @@
  • Overview
  • Example
  • Construction
  • -
  • Data Manipulation
  • -
  • Data Filtering
  • -
  • Data Formatting
  • +
  • Methods
  • Subscriptions
  • +
  • Data Manipulation
  • +
  • Data Selection
  • Data Policy
  • @@ -107,7 +107,7 @@ console.log('formatted items', items);

    -var data = new vis.DataSet(options)
    +var data = new vis.DataSet([data] [, options])
     

    @@ -116,6 +116,11 @@ var data = new vis.DataSet(options) Data Manipulation.

    +

    + The parameter datacode> is optional and can be an Array or + Google DataTable with items. +

    +

    The parameter options is optional and is an object which can contain the following properties: @@ -160,6 +165,294 @@ var data = new vis.DataSet(options) +

    Methods

    + +

    DataSet contains the following methods.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MethodReturn TypeDescription
    add(data [, senderId])Number[]Add data to the DataSet. Adding an item will fail when there already is an item with the same id. The function returns an array with the ids of the added items. See section Data Manipulation.
    clear([senderId])Number[]Clear all data from the DataSet. The function returns an array with the ids of the removed items.
    distinct(field)ArrayFind all distinct values of a specified field. Returns an unordered array containing all distinct values. If data items do not contain the specified field are ignored.
    forEach(callback [, options])none + Execute a callback function for every item in the dataset. + The available options are described in section Data Selection. +
    + get([options] [, data])
    + get(id [,options] [, data])
    + get(ids [, options] [, data]) +
    Object | Array | DataTable + Get a single item, multiple items, or all items from the DataSet. + Usage examples can be found in section Getting Data, and the available options are described in section Data Selection. If parameter data isprovided, items will be appended to this array or table, which is required in case of Google DataTable. +
    + getIds([options]) + Number[] + Get ids of all items or of a filtered set of items. + Available options are described in section Data Selection, except that options fields and convert are not applicable in case of getIds. +
    map(callback [, options])Array + Map every item in the DataSet. + The available options are described in section Data Selection. +
    max(field)Object | null + Find the item with maximum value of specified field. Returns null if no item is found. +
    min(field)Object | null + Find the item with minimum value of specified field. Returns null if no item is found. +
    off(event, callback)none + Unsubscribe from an event, remove an event listener. See section Subscriptions. +
    on(event, callback)none + Subscribe to an event, add an event listener. See section Subscriptions. +
    + remove(id [, senderId])
    + remove(ids [, senderId]) +
    Number[] + Remove on ore multiple items by id or by the items themselves. Returns an array with the ids of the removed items. See section Data Manipulation. +
    + update(id [, senderId])
    + update(ids [, senderId]) +
    Number[] + Update on ore existing items. When an item doesn't exist, it will be created. Returns an array with the ids of the removed items. See section Data Manipulation. +
    + + +

    Subscriptions

    + +

    + One can subscribe on changes in a DataSet. + A subscription can be created using the method on, + and removed with off. +

    + +
    +// create a DataSet
    +var data = new vis.DataSet();
    +
    +// subscribe to any change in the DataSet
    +data.on('*', function (event, properties, senderId) {
    +  console.log('event:', event, 'properties:', properties, 'senderId:', senderId);
    +});
    +
    +// add an item
    +data.add({id: 1, text: 'item 1'});              // triggers an 'add' event
    +data.update({id: 1, text: 'item 1 (updated)'}); // triggers an 'update' event
    +data.remove(1);                                 // triggers an 'remove' event
    +
    + + +

    On

    + +

    + Subscribe to an event. +

    + +Syntax: +
    DataSet.on(event, callback)
    + +Where: +
      +
    • + event is a String containing any of the events listed + in section Events. +
    • +
    • + callback is a callback function which will be called + each time the event occurs. The callback function is described in + section Callback. +
    • +
    + +

    Off

    + +

    + Unsubscribe from an event. +

    + +Syntax: +
    DataSet.off(event, callback)
    + +Where event and callback correspond with the +parameters used to subscribe to the event. + +

    Events

    + +

    + The following events are available for subscription: +

    + + + + + + + + + + + + + + + + + + + + + + +
    EventDescription
    add + The add event is triggered when an item + or a set of items is added, or when an item is updated while + not yet existing. +
    update + The update event is triggered when an existing item + or a set of existing items is updated. +
    remove + The remove event is triggered when an item + or a set of items is removed. +
    * + The * event is triggered when any of the events + add, update, and remove + occurs. +
    + +

    Callback

    + +

    + The callback functions of subscribers are called with the following + parameters: +

    + +
    +function (event, properties, senderId) {
    +  // handle the event
    +});
    +
    + +

    + where the parameters are defined as +

    + + + + + + + + + + + + + + + + + + + + + + +
    ParameterTypeDescription
    eventString + Any of the available events: add, + update, or remove. +
    propertiesObject | null + Optional properties providing more information on the event. + In case of the events add, + update, and remove, + properties is always an object containing a property + items, which contains an array with the ids of the affected + items. +
    senderIdString | Number + An senderId, optionally provided by the application code + which triggered the event. If senderId is not provided, the + argument will be null. +
    + +

    Data Manipulation

    @@ -317,70 +610,18 @@ Syntax:

    -

    Data Filtering

    +

    Data Selection

    - Data can be retrieved from the DataSet using the method get. - This method can return a single item or a list with items. + The DataSet contains functionality to format, filter, and sort data retrieved via the + methods get, getIds, forEach, and map. These methods have the following syntax:

    -

    A single item can be retrieved by its id:

    -
    -var item1 = dataset.get(1);
    -
    - -

    A selection of items can be retrieved by providing an array with ids:

    - -
    -var items = dataset.get([1, 3, 4]); // retrieve items 1, 3, and 4
    -
    - -

    All items can be retrieved by simply calling get without - specifying an id:

    - -
    -var items = dataset.get();          // retrieve all items
    -
    - -

    - Items can be filtered on specific properties by providing a filter - function. A filter function is executed for each of the items in the - DataSet, and is called with the item as parameter. The function must - return a boolean. All items for which the filter function returns - true will be emitted. -

    - -
    -// retrieve all items having a property group with value 2
    -var group2 = dataset.get({
    -  filter: function (item) {
    -    return (item.group == 2);
    -  }
    -});
    -
    -// retrieve all items having a property balance with a value above zero
    -var positiveBalance = dataset.get({
    -  filter: function (item) {
    -    return (item.balance > 0);
    -  }
    -});
    -
    -
    - - -

    Data Formatting

    - -

    - The DataSet contains functionality to format data retrieved via the - method get. The method get has the following - syntax: -

    - -
    -var item  = DataSet.get(id, options);   // retrieve a single item
    -var items = DataSet.get(ids, options);  // retrieve a selection of items
    -var items = DataSet.get(options);       // retrieve all items or a filtered set
    +DataSet.get([id] [, options] [, data]);
    +DataSet.getIds([options]);
    +DataSet.forEach(callback [, options]);
    +DataSet.map(callback [, options]);
     

    @@ -466,6 +707,59 @@ var items = data.get({ }); +

    Getting Data

    + +

    + Data can be retrieved from the DataSet using the method get. + This method can return a single item or a list with items. +

    + +

    A single item can be retrieved by its id:

    + +
    +var item1 = dataset.get(1);
    +
    + +

    A selection of items can be retrieved by providing an array with ids:

    + +
    +var items = dataset.get([1, 3, 4]); // retrieve items 1, 3, and 4
    +
    + +

    All items can be retrieved by simply calling get without + specifying an id:

    + +
    +var items = dataset.get();          // retrieve all items
    +
    + + +

    Data Filtering

    + +

    + Items can be filtered on specific properties by providing a filter + function. A filter function is executed for each of the items in the + DataSet, and is called with the item as parameter. The function must + return a boolean. All items for which the filter function returns + true will be emitted. +

    + +
    +// retrieve all items having a property group with value 2
    +var group2 = dataset.get({
    +  filter: function (item) {
    +    return (item.group == 2);
    +  }
    +});
    +
    +// retrieve all items having a property balance with a value above zero
    +var positiveBalance = dataset.get({
    +  filter: function (item) {
    +    return (item.balance > 0);
    +  }
    +});
    +
    +

    Data Types

    @@ -541,163 +835,6 @@ var items = data.get({ -

    Subscriptions

    - -

    - One can subscribe on changes in a DataSet. - A subscription can be created using the method on, - and removed with off. -

    - -
    -// create a DataSet
    -var data = new vis.DataSet();
    -
    -// subscribe to any change in the DataSet
    -data.on('*', function (event, properties, senderId) {
    -  console.log('event:', event, 'properties:', properties, 'senderId:', senderId);
    -});
    -
    -// add an item
    -data.add({id: 1, text: 'item 1'});              // triggers an 'add' event
    -data.update({id: 1, text: 'item 1 (updated)'}); // triggers an 'update' event
    -data.remove(1);                                 // triggers an 'remove' event
    -
    - - -

    On

    - -

    - Subscribe to an event. -

    - -Syntax: -
    DataSet.on(event, callback)
    - -Where: -
      -
    • - event is a String containing any of the events listed - in section Events. -
    • -
    • - callback is a callback function which will be called - each time the event occurs. The callback function is described in - section Callback. -
    • -
    - -

    Off

    - -

    - Unsubscribe from an event. -

    - -Syntax: -
    DataSet.off(event, callback)
    - -Where event and callback correspond with the -parameters used to subscribe to the event. - -

    Events

    - -

    - The following events are available for subscription: -

    - - - - - - - - - - - - - - - - - - - - - - -
    EventDescription
    add - The add event is triggered when an item - or a set of items is added, or when an item is updated while - not yet existing. -
    update - The update event is triggered when an existing item - or a set of existing items is updated. -
    remove - The remove event is triggered when an item - or a set of items is removed. -
    * - The * event is triggered when any of the events - add, update, and remove - occurs. -
    - -

    Callback

    - -

    - The callback functions of subscribers are called with the following - parameters: -

    - -
    -function (event, properties, senderId) {
    -  // handle the event
    -});
    -
    - -

    - where the parameters are defined as -

    - - - - - - - - - - - - - - - - - - - - - - -
    ParameterTypeDescription
    eventString - Any of the available events: add, - update, or remove. -
    propertiesObject | null - Optional properties providing more information on the event. - In case of the events add, - update, and remove, - properties is always an object containing a property - items, which contains an array with the ids of the affected - items. -
    senderIdString | Number - An senderId, optionally provided by the application code - which triggered the event. If senderId is not provided, the - argument will be null. -
    - - -

    Data Policy

    All code and data is processed and rendered in the browser. diff --git a/docs/graph.html b/docs/graph.html index bac86e1b..579cbb5c 100644 --- a/docs/graph.html +++ b/docs/graph.html @@ -490,7 +490,12 @@ var edges = [ Required Description - + + arrowScaleFactor + Number + no + If you are using arrows, this will scale the arrow. Values < 1 give smaller arrows, > 1 larger arrows. Default: 1. + color String | Object @@ -1062,7 +1067,12 @@ var options = { Default Description - + + arrowScaleFactor + Number + 1 + If you are using arrows, this will scale the arrow. Values < 1 give smaller arrows, > 1 larger arrows. Default: 1. + color String | Object diff --git a/docs/timeline.html b/docs/timeline.html index 70243349..7142712e 100644 --- a/docs/timeline.html +++ b/docs/timeline.html @@ -347,12 +347,41 @@ var options = { editable - Boolean + Boolean | Object false - If true, the items on the timeline can be dragged. Only applicable when option selectable is true. See also the callbacks onAdd, onUpdate, onMove, and onRemove, described in detail in section Editing Items. + If true, the items in the timeline can be manipulated. Only applicable when option selectable is true. See also the callbacks onAdd, onUpdate, onMove, and onRemove. When editable is an object, one can enable or disable individual manipulation actions. + See section Editing Items for a detailed explanation. + + editable.add + Boolean + false + If true, new items can be created by double tapping an empty space in the Timeline. See section Editing Items for a detailed explanation. + + + + editable.remove + Boolean + false + If true, items can be deleted by first selecting them, and then clicking the delete button on the top right of the item. See section Editing Items for a detailed explanation. + + + + editable.updateGroup + Boolean + false + If true, items can be dragged from one group to another. Only applicable when the Timeline has groups. See section Editing Items for a detailed explanation. + + + + editable.updateTime + Boolean + false + If true, items can be dragged to another moment in time. See section Editing Items for a detailed explanation. + + end Date | Number | String @@ -428,7 +457,7 @@ var options = { onAdd Function none - Callback function triggered when an item is about to be added: when the user double taps an empty space in the Timeline. See section Editing Items for more information. Only applicable when both options selectable and editable are set true. + Callback function triggered when an item is about to be added: when the user double taps an empty space in the Timeline. See section Editing Items for more information. Only applicable when both options selectable and editable.add are set true. @@ -436,7 +465,7 @@ var options = { onUpdate Function none - Callback function triggered when an item is about to be updated, when the user double taps an item in the Timeline. See section Editing Items for more information. Only applicable when both options selectable and editable are set true. + Callback function triggered when an item is about to be updated, when the user double taps an item in the Timeline. See section Editing Items for more information. Only applicable when both options selectable and editable.updateTime or editable.updateGroup are set true. @@ -444,7 +473,7 @@ var options = { onMove Function none - Callback function triggered when an item has been moved: after the user has dragged the item to an other position. See section Editing Items for more information. Only applicable when both options selectable and editable are set true. + Callback function triggered when an item has been moved: after the user has dragged the item to an other position. See section Editing Items for more information. Only applicable when both options selectable and editable.updateTime or editable.updateGroup are set true. @@ -452,10 +481,11 @@ var options = { onRemove Function none - Callback function triggered when an item is about to be removed: when the user tapped the delete button on the top right of a selected item. See section Editing Items for more information. Only applicable when both options selectable and editable are set true. + Callback function triggered when an item is about to be removed: when the user tapped the delete button on the top right of a selected item. See section Editing Items for more information. Only applicable when both options selectable and editable.remove are set true. + orientation @@ -483,8 +514,7 @@ var options = {

     .vis.timeline .item {
       padding: 10px;
    -}
    -  
    +} @@ -534,6 +564,13 @@ var options = { visible. + + stack + Boolean + true + If true (default), items will be stacked on top of each other such that they do not overlap. + + start Date | Number | String @@ -591,6 +628,13 @@ var options = { Description + + fit() + none + Adjust the visible window such that it fits all items. + + + getCustomTime() Date @@ -791,6 +835,24 @@ timeline.off('select', onSelect); When the Timeline is configured to be editable (both options selectable and editable are true), the user can move items by dragging them, can create a new item by double tapping on an empty space, can update an item by double tapping it, and can delete a selected item by clicking the delete button on the top right.

    +

    Option editable accepts a boolean or an object. When editable is a boolean, all manipulation actions will be either enabled or disabled. When editable is an object, one can enable individual manipulation actions:

    + +
    // enable or disable all manipulation actions
    +var options = {
    +  editable: true       // true or false
    +};
    +
    +// enable or disable individual manipulation actions
    +var options = {
    +  editable: {
    +    add: true,         // add new items by double tapping
    +    updateTime: true,  // drag items horizontally
    +    updateGroup: true, // drag items from one group to another
    +    remove: true       // delete an item by tapping the delete button top right
    +  }
    +};
    + +

    One can specify callback functions to validate changes made by the user. There are a number of callback functions for this purpose:

    diff --git a/download/vis.zip b/download/vis.zip index 7aca06c4..656a5205 100644 Binary files a/download/vis.zip and b/download/vis.zip differ diff --git a/examples/timeline/01_basic.html b/examples/timeline/01_basic.html index 514eefd1..5dc030e0 100644 --- a/examples/timeline/01_basic.html +++ b/examples/timeline/01_basic.html @@ -18,12 +18,12 @@ - + +

    Drag items around, create new items, and remove items.

    +
    + + + + + +

    + Test with a lot of data +

    +

    + + + +

    +
    + + + + \ No newline at end of file diff --git a/examples/timeline/03_much_data.html b/examples/timeline/03_much_data.html deleted file mode 100644 index dcbdf3e1..00000000 --- a/examples/timeline/03_much_data.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - Timeline | a lot of data - - - - - - - - - - -

    - Test with a lot of data -

    -

    - - - -

    -
    - - - - \ No newline at end of file diff --git a/examples/timeline/05_groups.html b/examples/timeline/05_groups.html index a103d1a3..982cb7fd 100644 --- a/examples/timeline/05_groups.html +++ b/examples/timeline/05_groups.html @@ -60,7 +60,7 @@ // create visualization var container = document.getElementById('visualization'); var options = { - groupOrder: 'content' + groupOrder: 'content' // groupOrder can be a property name or a sorting function }; var timeline = new vis.Timeline(container); diff --git a/examples/timeline/08_edit_items.html b/examples/timeline/08_edit_items.html index fe431ce9..a8c1bd88 100644 --- a/examples/timeline/08_edit_items.html +++ b/examples/timeline/08_edit_items.html @@ -18,8 +18,7 @@
    + + + +

    + This example demonstrate custom ordering of groups. +

    +
    + + + + \ No newline at end of file diff --git a/examples/timeline/10_limit_move_and_zoom.html b/examples/timeline/10_limit_move_and_zoom.html new file mode 100644 index 00000000..a2b8504e --- /dev/null +++ b/examples/timeline/10_limit_move_and_zoom.html @@ -0,0 +1,51 @@ + + + + Timeline | Limit move and zoom + + + + + + + +

    + The visible range is limited in this demo: +

    +
      +
    • minimum visible date is limited to 2012-01-01 using option min
    • +
    • maximum visible date is limited to 2013-01-01 (excluded) using option max
    • +
    • visible zoom interval is limited to a minimum of 24 hours using option zoomMin
    • +
    • visible zoom interval is limited to a maximum of about 3 months using option zoomMax
    • +
    +
    + + + + \ No newline at end of file diff --git a/examples/timeline/11_points.html b/examples/timeline/11_points.html new file mode 100755 index 00000000..901459f2 --- /dev/null +++ b/examples/timeline/11_points.html @@ -0,0 +1,58 @@ + + + + Timeline | Points + + + + + + + +

    World War II timeline

    +

    Source: http://www.onwar.com/chrono/index.htm

    +
    + +
    + + + + diff --git a/examples/timeline/12_custom_styling.html b/examples/timeline/12_custom_styling.html new file mode 100644 index 00000000..410bef45 --- /dev/null +++ b/examples/timeline/12_custom_styling.html @@ -0,0 +1,88 @@ + + + + Timeline | Custom styling + + + + + + + + + +
    + + + + \ No newline at end of file diff --git a/examples/timeline/13_past_and_future.html b/examples/timeline/13_past_and_future.html new file mode 100644 index 00000000..019dde17 --- /dev/null +++ b/examples/timeline/13_past_and_future.html @@ -0,0 +1,88 @@ + + + Timeline | Past and future + + + + + + + + +

    + When the custom time bar is shown, the user can drag this bar to a specific + time. The Timeline sends an event that the custom time is changed, after + which the contents of the timeline can be changed according to the specified + time in past or future. +

    + +
     
    +

    + +
    + + + + + + diff --git a/examples/timeline/14_a_lot_of_grouped_data.html b/examples/timeline/14_a_lot_of_grouped_data.html new file mode 100644 index 00000000..de4d7b47 --- /dev/null +++ b/examples/timeline/14_a_lot_of_grouped_data.html @@ -0,0 +1,109 @@ + + + Timeline | A lot of grouped data + + + + + + + + +

    Timeline grouping performance

    + +

    + Choose a number of items: + 100, + 1000, + 10000, + 100000 +

    +

    + Current number of items: 100 +

    + +
    + + + + + diff --git a/examples/timeline/15_item_class_names.html b/examples/timeline/15_item_class_names.html new file mode 100755 index 00000000..43dd348f --- /dev/null +++ b/examples/timeline/15_item_class_names.html @@ -0,0 +1,115 @@ + + + Timeline | Item class names + + + + + + + + +

    This page demonstrates the Timeline with custom css classes for individual items.

    + +
    + + + + diff --git a/examples/timeline/index.html b/examples/timeline/index.html index 4017ec88..122e148e 100644 --- a/examples/timeline/index.html +++ b/examples/timeline/index.html @@ -13,13 +13,22 @@

    vis.js timeline examples

    01_basic.html

    -

    02_dataset.html

    -

    03_much_data.html

    +

    02_dataset.html

    +

    03_a_lot_of_data.html

    04_html_data.html

    05_groups.html

    06_event_listeners.html

    07_custom_time_bar.html

    08_edit_items.html

    +

    09_order_groups.html

    +

    10_limit_range_and_zoom.html

    +

    11_points.html

    +

    12_custom_styling.html

    +

    13_past_and_future.html

    +

    14_a_lot_of_grouped_data.html

    +

    15_item_class_names.html

    + +

    requirejs_example.html

    diff --git a/examples/timeline/test.html b/examples/timeline/test.html deleted file mode 100644 index ed386290..00000000 --- a/examples/timeline/test.html +++ /dev/null @@ -1,69 +0,0 @@ - - - - Timeline | a lot of data - - - - - - - - - - -

    - Test with a lot of data -

    -

    - - - -

    -
    - - - - \ No newline at end of file diff --git a/examples/timeline/test2.html b/examples/timeline/test2.html deleted file mode 100644 index 75ddc0a2..00000000 --- a/examples/timeline/test2.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - Timeline | Basic demo - - - - - - - -
    - - - - \ No newline at end of file diff --git a/img/external-link-icons/external-link-icon-white.png b/img/external-link-icons/external-link-icon-white.png new file mode 100644 index 00000000..29b21e95 Binary files /dev/null and b/img/external-link-icons/external-link-icon-white.png differ diff --git a/img/external-link-icons/external-link-icon.png b/img/external-link-icons/external-link-icon.png index 29b21e95..e3993e2e 100644 Binary files a/img/external-link-icons/external-link-icon.png and b/img/external-link-icons/external-link-icon.png differ diff --git a/img/gallery/timeline/02_dataset.png b/img/gallery/timeline/02_dataset.png deleted file mode 100644 index 8be3e577..00000000 Binary files a/img/gallery/timeline/02_dataset.png and /dev/null differ diff --git a/img/gallery/timeline/02_interactive.png b/img/gallery/timeline/02_interactive.png new file mode 100644 index 00000000..a651939a Binary files /dev/null and b/img/gallery/timeline/02_interactive.png differ diff --git a/img/gallery/timeline/03_much_data.png b/img/gallery/timeline/03_a_lot_of_data.png similarity index 100% rename from img/gallery/timeline/03_much_data.png rename to img/gallery/timeline/03_a_lot_of_data.png diff --git a/img/gallery/timeline/09_order_groups.png b/img/gallery/timeline/09_order_groups.png new file mode 100644 index 00000000..d5aa1565 Binary files /dev/null and b/img/gallery/timeline/09_order_groups.png differ diff --git a/img/gallery/timeline/10_limit_move_and_zoom.png b/img/gallery/timeline/10_limit_move_and_zoom.png new file mode 100644 index 00000000..d7cb64b3 Binary files /dev/null and b/img/gallery/timeline/10_limit_move_and_zoom.png differ diff --git a/img/gallery/timeline/11_points.png b/img/gallery/timeline/11_points.png new file mode 100644 index 00000000..2d2c257c Binary files /dev/null and b/img/gallery/timeline/11_points.png differ diff --git a/img/gallery/timeline/12_custom_styling.png b/img/gallery/timeline/12_custom_styling.png new file mode 100644 index 00000000..43a34eee Binary files /dev/null and b/img/gallery/timeline/12_custom_styling.png differ diff --git a/img/gallery/timeline/13_past_and_future.png b/img/gallery/timeline/13_past_and_future.png new file mode 100644 index 00000000..45f7fd43 Binary files /dev/null and b/img/gallery/timeline/13_past_and_future.png differ diff --git a/img/gallery/timeline/14_a_lot_of_grouped_data.png b/img/gallery/timeline/14_a_lot_of_grouped_data.png new file mode 100644 index 00000000..2077a041 Binary files /dev/null and b/img/gallery/timeline/14_a_lot_of_grouped_data.png differ diff --git a/img/gallery/timeline/15_item_class_names.png b/img/gallery/timeline/15_item_class_names.png new file mode 100644 index 00000000..379f0a36 Binary files /dev/null and b/img/gallery/timeline/15_item_class_names.png differ diff --git a/index.html b/index.html index fc614b45..5bfedec6 100644 --- a/index.html +++ b/index.html @@ -74,7 +74,7 @@ bower install vis

    download

    Click here to download vis.js -(version 0.7.4) +(version 1.0.0)

    Example

    @@ -135,15 +135,15 @@ The source code of the examples can be found in the
    @@ -176,6 +176,48 @@ The source code of the examples can be found in the
    edit items
    + + + + + + +

    Graph