diff --git a/HISTORY.md b/HISTORY.md index 94b2007f..5e6955ca 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -7,17 +7,28 @@ http://visjs.org ### Timeline - Large refactoring of the Timeline, simplifying the code. -- Performance improvements. +- Great performance improvements. - Improved layout of box-items inside groups. +- Items can now be dragged from one group to another. +- Implemented option `stack` to enable/disable stacking of items. +- Option `editable` can now be used to enable/disable individual manipulation + actions (`add`, `updateTime`, `updateGroup`, `remove`). - Function `setWindow` now accepts an object with properties `start` and `end`. - Fixed option `autoResize` forcing a repaint of the Timeline with every check rather than when the Timeline is actually resized. - Fixed `select` event fired repeatedly when clicking an empty place on the Timeline, deselecting selected items). - Fixed initial visible window in case items exceed `zoomMax`. Thanks @Remper. +- Fixed an offset in newly created items when using groups. +- Fixed height of a group not reckoning with the height of the group label. - Option `order` is now deprecated. This was needed for performance improvements. -- Minor bug fixes. - More examples added. +- Minor bug fixes. + +### Graph + +- added recalculate hierarchical layout to update node event. +- added arrowScaleFactor to scale the arrows on the edges. ### DataSet diff --git a/Jakefile.js b/Jakefile.js index c85d1b40..e4546709 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -38,7 +38,7 @@ task('build', {async: true}, function () { src: [ './src/timeline/component/css/timeline.css', './src/timeline/component/css/panel.css', - './src/timeline/component/css/groupset.css', + './src/timeline/component/css/labelset.css', './src/timeline/component/css/itemset.css', './src/timeline/component/css/item.css', './src/timeline/component/css/timeaxis.css', @@ -64,8 +64,8 @@ task('build', {async: true}, function () { './src/DataSet.js', './src/DataView.js', + './src/timeline/stack.js', './src/timeline/TimeStep.js', - './src/timeline/Stack.js', './src/timeline/Range.js', './src/timeline/component/Component.js', './src/timeline/component/Panel.js', @@ -76,7 +76,6 @@ task('build', {async: true}, function () { './src/timeline/component/ItemSet.js', './src/timeline/component/item/*.js', './src/timeline/component/Group.js', - './src/timeline/component/GroupSet.js', './src/timeline/Timeline.js', './src/graph/dotparser.js', diff --git a/dist/vis.css b/dist/vis.css index 46d6b19c..17b2cf75 100644 --- a/dist/vis.css +++ b/dist/vis.css @@ -32,9 +32,6 @@ display: none; } -.vis.timeline .groupset { - position: relative; -} .vis.timeline .labelset { position: relative; @@ -57,16 +54,12 @@ box-sizing: border-box; } -.vis.timeline.bottom .labelset .vlabel, -.vis.timeline.top .vpanel.side-content, -.vis.timeline.top .groupset .itemset { +.vis.timeline.top .labelset .vlabel { border-top: 1px solid #bfbfbf; border-bottom: none; } -.vis.timeline.top .labelset .vlabel, -.vis.timeline.bottom .vpanel.side-content, -.vis.timeline.bottom .groupset .itemset { +.vis.timeline.bottom .labelset .vlabel { border-top: none; border-bottom: 1px solid #bfbfbf; } @@ -101,6 +94,21 @@ 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; diff --git a/dist/vis.js b/dist/vis.js index 696a8166..f6cf32e1 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -5,7 +5,7 @@ * A dynamic, browser-based visualization library. * * @version 0.7.5-SNAPSHOT - * @date 2014-04-22 + * @date 2014-05-01 * * @license * Copyright (C) 2011-2014 Almende B.V, http://almende.com @@ -1247,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. @@ -1256,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 @@ -1279,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); + } } /** @@ -2448,6 +2458,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 @@ -2903,176 +3026,6 @@ TimeStep.prototype.getLabelMajor = function(date) { } }; -// TODO: turn Stack into a Mixin? - -/** - * @constructor Stack - * Stacks items on top of each other. - * @param {Object} [options] - */ -function Stack (options) { - this.options = options || {}; - this.defaultOptions = { - order: function (a, b) { - // Order: ranges over non-ranges, ranged ordered by width, - // and non-ranges 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, - axis: 20 - } - }; -} - -/** - * Set options for the stack - * @param {Object} options Available options: - * {Number} [margin.item=10] - * {Number} [margin.axis=20] - * {function} [order] Stacking order - */ -Stack.prototype.setOptions = function setOptions (options) { - util.extend(this.options, options); -}; - -/** - * Order an array with items using a predefined order function for items - * @param {Item[]} items - */ -Stack.prototype.order = function order(items) { - //order the items - var order = this.options.order || this.defaultOptions.order; - if (!(typeof order === 'function')) { - throw new Error('Option order must be a function'); - } - items.sort(order); -}; - -/** - * Order items by their start data - * @param {Item[]} items - */ -Stack.prototype.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.prototype.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 events such that they don't overlap each - * other. - * @param {Item[]} items All visible items - * @param {boolean} [force=false] If true, all items will be re-stacked. - * If false (default), only items having a - * top===null will be re-stacked - * @private - */ -Stack.prototype.stack = function stack (items, force) { - var i, - iMax, - options = this.options, - marginItem, - marginAxis; - - if (options.margin && options.margin.item !== undefined) { - marginItem = options.margin.item; - } - else { - marginItem = this.defaultOptions.margin.item - } - if (options.margin && options.margin.axis !== undefined) { - marginAxis = options.margin.axis; - } - else { - marginAxis = this.defaultOptions.margin.axis - } - - 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 = marginAxis; - - 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 && this.collision(item, other, marginItem)) { - collidingItem = other; - break; - } - } - - if (collidingItem != null) { - // There is a collision. Reposition the event above the colliding element - item.top = collidingItem.top + collidingItem.height + marginItem; - } - } while (collidingItem); - } - } -}; - -/** - * 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. @@ -3669,7 +3622,7 @@ Component.prototype.repaint = function repaint() { * Test whether the component is resized since the last time _isResized() was * called. * @return {Boolean} Returns true if the component is resized - * @private + * @protected */ Component.prototype._isResized = function _isResized() { var resized = (this._previousWidth !== this.width || this._previousHeight !== this.height); @@ -3699,7 +3652,7 @@ function Panel(options) { this.options = options || {}; // create frame - this.frame = document.createElement('div'); + this.frame = (typeof document !== 'undefined') ? document.createElement('div') : null; } Panel.prototype = new Component(); @@ -3944,7 +3897,8 @@ RootPanel.prototype.getFrame = function getFrame() { RootPanel.prototype.repaint = function repaint() { // update class name var options = this.options; - var className = 'vis timeline rootpanel ' + options.orientation + (options.editable ? ' editable' : ''); + 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; @@ -4181,10 +4135,10 @@ TimeAxis.prototype.repaint = function () { TimeAxis.prototype._repaintLabels = function () { var orientation = this.getOption('orientation'); - // calculate range and step + // 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) * 5).valueOf() + 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; @@ -4717,6 +4671,8 @@ CustomTime.prototype._onDragEnd = function (event) { 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 @@ -4725,27 +4681,30 @@ CustomTime.prototype._onDragEnd = function (event) { * 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 */ -function ItemSet(backgroundPanel, axisPanel, options) { +function ItemSet(backgroundPanel, axisPanel, sidePanel, options) { this.id = util.randomUUID(); // one options object is shared by this itemset and all its items this.options = options || {}; 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); }, @@ -4757,22 +4716,29 @@ function ItemSet(backgroundPanel, axisPanel, options) { } }; - this.items = {}; // object with an Item for every data item - this.orderedItems = { - byStart: [], - byEnd: [] + // 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.visibleItems = []; // visible, ordered items - this.visibleItemsStart = 0; // start index of visible items in this.orderedItems // TODO: cleanup - this.visibleItemsEnd = 0; // start index of visible items in this.orderedItems // TODO: cleanup + + 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(Object.create(this.options)); this.stackDirty = true; // if true, all items will be restacked on next repaint this.touchParams = {}; // stores properties while dragging - // create the HTML DOM + this._create(); } @@ -4812,6 +4778,15 @@ ItemSet.prototype._create = function _create(){ 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, { @@ -4850,7 +4825,17 @@ ItemSet.prototype._create = function _create(){ * 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); +}; + +/** + * Mark the ItemSet dirty so it will refresh everything with next repaint + */ +ItemSet.prototype.markDirty = function markDirty() { + this.groupIds = []; + this.stackDirty = true; +}; /** * Hide the component from the DOM @@ -4865,6 +4850,11 @@ ItemSet.prototype.hide = function hide() { if (this.dom.background.parentNode) { this.dom.background.parentNode.removeChild(this.dom.background); } + + // remove the labelset containing all group labels + if (this.dom.labelSet.parentNode) { + this.dom.labelSet.parentNode.removeChild(this.dom.labelSet); + } }; /** @@ -4881,6 +4871,11 @@ ItemSet.prototype.show = function show() { 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); + } }; /** @@ -4966,138 +4961,132 @@ ItemSet.prototype.getFrame = function getFrame() { * @return {boolean} Returns true if the component is resized */ ItemSet.prototype.repaint = function repaint() { - var asSize = util.option.asSize, + var margin = this.options.margin, + range = this.range, + asSize = util.option.asSize, asString = util.option.asString, options = this.options, orientation = this.getOption('orientation'), + resized = false, frame = this.frame; + // TODO: document this feature to specify one margin for both item and axis distance + if (typeof margin === 'number') { + margin = { + item: margin, + axis: margin + }; + } + // update className frame.className = 'itemset' + (options.className ? (' ' + asString(options.className)) : ''); + // reorder the groups (if needed) + resized = this._orderGroups() || resized; + // check whether zoomed (in that case we need to re-stack everything) + // TODO: would be nicer to get this as a trigger from Range var visibleInterval = 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; - /* TODO: implement+fix smarter way to update visible items - // find the first visible item - // TODO: use faster search, not linear - var byEnd = this.orderedItems.byEnd; - var start = 0; - var item = null; - while ((item = byEnd[start]) && - (('end' in item.data) ? item.data.end : item.data.start) < this.range.start) { - start++; - } + // 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; - // find the last visible item - // TODO: use faster search, not linear - var byStart = this.orderedItems.byStart; - var end = 0; - while ((item = byStart[end]) && item.data.start < this.range.end) { - end++; - } + // reposition frame + 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 - console.log('visible items', start, end); // TODO: cleanup - console.log('visible item ids', byStart[start] && byStart[start].id, byEnd[end-1] && byEnd[end-1].id); // TODO: cleanup + // calculate actual size and position + this.top = frame.offsetTop; + this.left = frame.offsetLeft; + this.width = frame.offsetWidth; + this.height = height; - this.visibleItems = []; - var i = start; - item = byStart[i]; - var lastItem = byEnd[end]; - while (item && item !== lastItem) { - this.visibleItems.push(item); - item = byStart[++i]; - } - this.stack.order(this.visibleItems); + // reposition axis + 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'); - // show visible items - for (var i = 0, ii = this.visibleItems.length; i < ii; i++) { - item = this.visibleItems[i]; + // check if this component is resized + resized = this._isResized() || resized; - if (!item.displayed) item.show(); - item.top = null; // reset stacking position + return resized; +}; - // reposition item horizontally - item.repositionX(); - } - */ +/** + * 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]; - // simple, brute force calculation of visible items - // TODO: replace with a faster, more sophisticated solution - this.visibleItems = []; - for (var id in this.items) { - if (this.items.hasOwnProperty(id)) { - var item = this.items[id]; - if (item.isVisible(this.range)) { - if (!item.displayed) item.show(); + return firstGroup || null; +}; - // reposition item horizontally - item.repositionX(); +/** + * 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]; - this.visibleItems.push(item); - } - else { - if (item.displayed) item.hide(); - } + if (this.groupsData) { + // remove the group holding all ungrouped items + if (ungrouped) { + ungrouped.hide(); + delete this.groups[UNGROUPED]; } } - - // reposition visible items vertically - //this.stack.order(this.visibleItems); // TODO: improve ordering - var force = this.stackDirty || zoomed; // force re-stacking of all items if true - this.stack.stack(this.visibleItems, force); - this.stackDirty = false; - for (var i = 0, ii = this.visibleItems.length; i < ii; i++) { - this.visibleItems[i].repositionY(); - } - - // recalculate the height of the itemset - var marginAxis = (options.margin && 'axis' in options.margin) ? options.margin.axis : this.itemOptions.margin.axis, - marginItem = (options.margin && 'item' in options.margin) ? options.margin.item : this.itemOptions.margin.item, - height; - - // determine the height from the stacked items - 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) + marginAxis + marginItem; - } else { - height = marginAxis + marginItem; - } - - // reposition frame - 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; + // 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 axis - 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'); + for (var itemId in this.items) { + if (this.items.hasOwnProperty(itemId)) { + ungrouped.add(this.items[itemId]); + } + } - return this._isResized(); + ungrouped.show(); + } + } }; /** @@ -5124,6 +5113,14 @@ ItemSet.prototype.getAxis = function getAxis() { return this.dom.axis; }; +/** + * Get the element for the labelset + * @return {HTMLElement} labelSet + */ +ItemSet.prototype.getLabelSet = function getLabelSet() { + return this.dom.labelSet; +}; + /** * Set items * @param {vis.DataSet | null} items @@ -5141,12 +5138,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); }); @@ -5158,24 +5155,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 @@ -5199,7 +5258,7 @@ ItemSet.prototype.removeItem = function removeItem (id) { /** * Handle updated items * @param {Number[]} ids - * @private + * @protected */ ItemSet.prototype._onUpdate = function _onUpdate(ids) { var me = this, @@ -5219,31 +5278,29 @@ ItemSet.prototype._onUpdate = function _onUpdate(ids) { if (item) { // update item if (!constructor || !(item instanceof constructor)) { - // item type has changed, hide and delete the item - item.hide(); + // item type has changed, delete the item and recreate it + me._removeItem(item); item = null; } else { - item.data = itemData; // TODO: create a method item.setData ? + me._updateItem(item, itemData); } } if (!item) { // create item if (constructor) { - item = new constructor(me, itemData, me.options, itemOptions); - item.id = id; + 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 + '"'); } } - - me.items[id] = item; }); this._order(); - this.stackDirty = true; // force re-stacking of all items next repaint this.emit('change'); }; @@ -5251,14 +5308,14 @@ ItemSet.prototype._onUpdate = function _onUpdate(ids) { /** * Handle added items * @param {Number[]} ids - * @private + * @protected */ ItemSet.prototype._onAdd = ItemSet.prototype._onUpdate; /** * Handle removed items * @param {Number[]} ids - * @private + * @protected */ ItemSet.prototype._onRemove = function _onRemove(ids) { var count = 0; @@ -5267,13 +5324,7 @@ ItemSet.prototype._onRemove = function _onRemove(ids) { var item = me.items[id]; if (item) { count++; - item.hide(); - delete me.items[id]; - delete me.visibleItems[id]; - - // remove from selection - var index = me.selection.indexOf(id); - if (index != -1) me.selection.splice(index, 1); + me._removeItem(item); } }); @@ -5286,146 +5337,392 @@ ItemSet.prototype._onRemove = function _onRemove(ids) { }; /** - * Order the items + * Update the order of item in all groups * @private */ ItemSet.prototype._order = function _order() { - var array = util.toArray(this.items); - this.orderedItems.byStart = array; - this.orderedItems.byEnd = [].concat(array); + // reorder the items in all groups + // TODO: optimization: only reorder groups affected by the changed items + util.forEach(this.groups, function (group) { + group.order(); + }); +}; - // reorder the items - this.stack.orderByStart(this.orderedItems.byStart); - this.stack.orderByEnd(this.orderedItems.byEnd); +/** + * Handle updated groups + * @param {Number[]} ids + * @private + */ +ItemSet.prototype._onUpdateGroups = function _onUpdateGroups(ids) { + this._onAddGroups(ids); }; /** - * Start dragging the selected events - * @param {Event} event + * Handle changed groups + * @param {Number[]} ids * @private */ -ItemSet.prototype._onDragStart = function (event) { - if (!this.options.editable) { - return; - } +ItemSet.prototype._onAddGroups = function _onAddGroups(ids) { + var me = this; - var item = ItemSet.itemFromTarget(event), - me = this; + ids.forEach(function (id) { + var groupData = me.groupsData.get(id); + var group = me.groups[id]; - if (item && item.selected) { - var dragLeftItem = event.target.dragLeftItem; - var dragRightItem = event.target.dragRightItem; + if (!group) { + // check for reserved ids + if (id == UNGROUPED) { + throw new Error('Illegal group id. ' + id + ' is a reserved id.'); + } - if (dragLeftItem) { - this.touchParams.itemProps = [{ - item: dragLeftItem, - start: item.data.start.valueOf() - }]; - } - else if (dragRightItem) { - this.touchParams.itemProps = [{ - item: dragRightItem, - end: item.data.end.valueOf() - }]; + 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 { - this.touchParams.itemProps = this.getSelection().map(function (id) { - var item = me.items[id]; - var props = { - item: item - }; + // update group + group.setData(groupData); + } + }); - if ('start' in item.data) { - props.start = item.data.start.valueOf() - } - if ('end' in item.data) { - props.end = item.data.end.valueOf() - } + this.emit('change'); +}; - return props; +/** + * 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; } - event.stopPropagation(); + return changed; + } + else { + return false; } }; /** - * Drag selected items - * @param {Event} event + * Add a new item + * @param {Item} item * @private */ -ItemSet.prototype._onDrag = function (event) { - if (this.touchParams.itemProps) { - var snap = this.options.snap || null, - deltaX = event.gesture.deltaX, - scale = (this.width / (this.range.end - this.range.start)), - offset = deltaX / scale; +ItemSet.prototype._addItem = function _addItem(item) { + this.items[item.id] = item; - // move - this.touchParams.itemProps.forEach(function (props) { - if ('start' in props) { - 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; - } - }); + // add to group + var groupId = this.groupsData ? item.data.group : UNGROUPED; + var group = this.groups[groupId]; + if (group) group.add(item); +}; - // TODO: implement onMoving handler +/** + * Update an existing item + * @param {Item} item + * @param {Object} itemData + * @private + */ +ItemSet.prototype._updateItem = function _updateItem(item, itemData) { + var oldGroupId = item.data.group; - // TODO: implement dragging from one group to another + item.data = itemData; + item.repaint(); - this.stackDirty = true; // force re-stacking of all items next repaint - this.emit('change'); + // update group + if (oldGroupId != item.data.group) { + var oldGroup = this.groups[oldGroupId]; + if (oldGroup) oldGroup.remove(item); - event.stopPropagation(); + var groupId = this.groupsData ? item.data.group : UNGROUPED; + var group = this.groups[groupId]; + if (group) group.add(item); } }; /** - * End of dragging selected items - * @param {Event} event + * 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._onDragEnd = function (event) { - if (this.touchParams.itemProps) { - // prepare a change set for the changed items - var changes = [], - me = this, - dataset = this._myDataSet(); +ItemSet.prototype._removeItem = function _removeItem(item) { + // remove from DOM + item.hide(); - this.touchParams.itemProps.forEach(function (props) { - var id = props.item.id, - item = me.itemsData.get(id); + // remove from items + delete this.items[item.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']); - } - 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']); - } + // remove from selection + var index = this.selection.indexOf(item.id); + if (index != -1) this.selection.splice(index, 1); - // only apply changes when start or end is actually changed - if (changed) { - me.options.onMove(item, function (item) { - if (item) { - // apply changes - item[dataset.fieldId] = id; // ensure the item contains its id (can be undefined) - changes.push(item); + // 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 + * @param {Event} event + * @private + */ +ItemSet.prototype._onDragStart = function (event) { + if (!this.options.editable.updateTime && !this.options.editable.updateGroup) { + return; + } + + var item = ItemSet.itemFromTarget(event), + me = this, + props; + + if (item && item.selected) { + var dragLeftItem = event.target.dragLeftItem; + var dragRightItem = event.target.dragRightItem; + + if (dragLeftItem) { + 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) { + 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) { + var item = me.items[id]; + var props = { + item: item + }; + + if (me.options.editable.updateTime) { + if ('start' in item.data) props.start = item.data.start.valueOf(); + if ('end' in item.data) props.end = item.data.end.valueOf(); + } + if (me.options.editable.updateGroup) { + if ('group' in item.data) props.group = item.data.group; + } + + return props; + }); + } + + event.stopPropagation(); + } +}; + +/** + * Drag selected items + * @param {Event} event + * @private + */ +ItemSet.prototype._onDrag = function (event) { + if (this.touchParams.itemProps) { + var snap = this.options.snap || null, + deltaX = event.gesture.deltaX, + scale = (this.width / (this.range.end - this.range.start)), + offset = deltaX / scale; + + // move + this.touchParams.itemProps.forEach(function (props) { + if ('start' in props) { + 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 + + this.stackDirty = true; // force re-stacking of all items next repaint + this.emit('change'); + + event.stopPropagation(); + } +}; + +/** + * End of dragging selected items + * @param {Event} event + * @private + */ +ItemSet.prototype._onDragEnd = function (event) { + if (this.touchParams.itemProps) { + // prepare a change set for the changed items + var changes = [], + me = this, + dataset = this._myDataSet(); + + this.touchParams.itemProps.forEach(function (props) { + var id = props.item.id, + itemData = me.itemsData.get(id); + + var changed = false; + if ('start' in props.item.data) { + changed = (props.start != props.item.data.start.valueOf()); + itemData.start = util.convert(props.item.data.start, dataset.convert['start']); + } + if ('end' in props.item.data) { + changed = changed || (props.end != props.item.data.end.valueOf()); + 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(itemData, function (itemData) { + if (itemData) { + // apply changes + itemData[dataset.fieldId] = id; // ensure the item contains its id (can be undefined) + changes.push(itemData); } else { // restore original values if ('start' in props) props.item.data.start = props.start; if ('end' in props) props.item.data.end = props.end; - this.stackDirty = true; // force re-stacking of all items next repaint - this.emit('change'); + me.stackDirty = true; // force re-stacking of all items next repaint + me.emit('change'); } }); } @@ -5459,6 +5756,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 @@ -5492,15 +5807,15 @@ 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 || {}; @@ -5532,6 +5847,33 @@ Item.prototype.unselect = function unselect() { 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; +}; + /** * Show the Item in the DOM (when not already visible) * @return {Boolean} changed @@ -5572,13 +5914,12 @@ Item.prototype.repositionY = function repositionY() { /** * 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'; @@ -5587,7 +5928,7 @@ Item.prototype._repaintDeleteButton = function (anchor) { Hammer(deleteButton, { preventDefault: true }).on('tap', function (event) { - parent.removeItem(id); + me.parent.removeFromDataSet(me); event.stopPropagation(); }); @@ -5606,14 +5947,13 @@ 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: { width: 0, @@ -5632,10 +5972,10 @@ function ItemBox (parent, data, options, defaultOptions) { } } - Item.call(this, parent, data, options, defaultOptions); + 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 @@ -5838,14 +6178,13 @@ ItemBox.prototype.repositionY = function repositionY () { /** * @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, @@ -5865,10 +6204,10 @@ function ItemPoint (parent, data, options, defaultOptions) { } } - Item.call(this, parent, data, options, defaultOptions); + 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 @@ -5877,9 +6216,10 @@ ItemPoint.prototype = new Item (null, null); */ ItemPoint.prototype.isVisible = function isVisible (range) { // determine visibility - var interval = (range.end - range.start); - return (this.data.start > range.start - interval) && (this.data.start < range.end); -} + // 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 @@ -5958,10 +6298,11 @@ ItemPoint.prototype.repaint = function repaint() { this.props.content.height = dom.content.offsetHeight; // resize contents - dom.content.style.marginLeft = 1.5 * this.props.dot.width + 'px'; + 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; } @@ -6002,7 +6343,7 @@ ItemPoint.prototype.hide = function hide() { ItemPoint.prototype.repositionX = function repositionX() { var start = this.defaultOptions.toScreen(this.data.start); - this.left = start - this.props.dot.width / 2; + this.left = start - this.props.dot.width; // reposition point this.dom.point.style.left = this.left + 'px'; @@ -6024,19 +6365,18 @@ ItemPoint.prototype.repositionY = function repositionY () { 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: { width: 0 @@ -6053,10 +6393,10 @@ function ItemRange (parent, data, options, defaultOptions) { } } - Item.call(this, parent, data, options, defaultOptions); + Item.call(this, data, options, defaultOptions); } -ItemRange.prototype = new Item (null, null); +ItemRange.prototype = new Item (null); ItemRange.prototype.baseClassName = 'item range'; @@ -6233,10 +6573,10 @@ ItemRange.prototype.repositionY = function repositionY() { /** * 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'; @@ -6263,10 +6603,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'; @@ -6294,14 +6634,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, @@ -6309,10 +6648,10 @@ function ItemRangeOverflow (parent, data, options, defaultOptions) { } }; - 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'; @@ -6351,27 +6690,16 @@ ItemRangeOverflow.prototype.repositionX = function repositionX() { /** * @constructor Group - * @param {Panel} groupPanel - * @param {Panel} labelPanel - * @param {Panel} backgroundPanel - * @param {Panel} axisPanel * @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 (groupPanel, labelPanel, backgroundPanel, axisPanel, groupId, options) { - this.id = util.randomUUID(); - this.groupPanel = groupPanel; - this.labelPanel = labelPanel; - this.backgroundPanel = backgroundPanel; - this.axisPanel = axisPanel; - +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, @@ -6379,20 +6707,17 @@ function Group (groupPanel, labelPanel, backgroundPanel, axisPanel, groupId, opt } }; - this.dom = {}; - - this.top = 0; - this.left = 0; - this.width = 0; - this.height = 0; + 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: [] + }; this._create(); -} -Group.prototype = new Component(); - -// TODO: comment -Group.prototype.setOptions = Component.prototype.setOptions; + this.setData(data); +} /** * Create DOM elements for the group @@ -6407,6 +6732,15 @@ Group.prototype._create = function() { inner.className = 'inner'; label.appendChild(inner); this.dom.inner = inner; + + var foreground = document.createElement('div'); + foreground.className = 'group'; + foreground['timeline-group'] = this; + this.dom.foreground = foreground; + + this.dom.background = document.createElement('div'); + + this.dom.axis = document.createElement('div'); }; /** @@ -6434,599 +6768,377 @@ Group.prototype.setData = function 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} itemsData - */ -Group.prototype.setItems = function setItems(itemsData) { - if (this.itemSet) { - // remove current item set - this.itemSet.setItems(); - this.itemSet.hide(); - this.groupPanel.frame.removeChild(this.itemSet.getFrame()); - this.itemSet = null; - } - - if (itemsData) { - var groupId = this.groupId; - - var me = this; - var itemSetOptions = util.extend(this.options, { - height: function () { - // FIXME: setting height doesn't yet work - return Math.max(me.props.label.height, me.itemSet.height); - } - }); - this.itemSet = new ItemSet(this.backgroundPanel, this.axisPanel, itemSetOptions); - this.itemSet.on('change', this.emit.bind(this, 'change')); // propagate change event - this.itemSet.parent = this; - this.groupPanel.frame.appendChild(this.itemSet.getFrame()); - - if (this.range) this.itemSet.setRange(this.range); - - this.view = new DataView(itemsData, { - filter: function (item) { - return item.group == groupId; - } - }); - this.itemSet.setItems(this.view); - } -}; - -/** - * hide the group, detach from DOM if needed + * Get the foreground container element + * @return {HTMLElement} foreground */ -Group.prototype.show = function show() { - if (!this.dom.label.parentNode) { - this.labelPanel.frame.appendChild(this.dom.label); - } - - var itemSetFrame = this.itemSet && this.itemSet.getFrame(); - if (itemSetFrame) { - if (itemSetFrame.parentNode) { - itemSetFrame.parentNode.removeChild(itemSetFrame); - } - this.groupPanel.frame.appendChild(itemSetFrame); - - this.itemSet.show(); - } +Group.prototype.getForeground = function getForeground() { + return this.dom.foreground; }; /** - * hide the group, detach from DOM if needed + * Get the background container element + * @return {HTMLElement} background */ -Group.prototype.hide = function hide() { - if (this.dom.label.parentNode) { - this.dom.label.parentNode.removeChild(this.dom.label); - } - - if (this.itemSet) { - this.itemSet.hide(); - } - - var itemSetFrame = this.itemset && this.itemSet.getFrame(); - if (itemSetFrame && itemSetFrame.parentNode) { - itemSetFrame.parentNode.removeChild(itemSetFrame); - } +Group.prototype.getBackground = function getBackground() { + return this.dom.background; }; /** - * Set range (start and end). - * @param {Range | Object} range A Range or an object containing start and end. + * Get the axis container element + * @return {HTMLElement} axis */ -Group.prototype.setRange = function (range) { - this.range = range; - - if (this.itemSet) this.itemSet.setRange(range); +Group.prototype.getAxis = function getAxis() { + return this.dom.axis; }; /** - * 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. + * Get the width of the group label + * @return {number} width */ -Group.prototype.setSelection = function setSelection(ids) { - if (this.itemSet) this.itemSet.setSelection(ids); +Group.prototype.getLabelWidth = function getLabelWidth() { + return this.props.label.width; }; -/** - * Get the selected items by their id - * @return {Array} ids The ids of the selected items - */ -Group.prototype.getSelection = function getSelection() { - return this.itemSet ? this.itemSet.getSelection() : []; -}; /** - * Repaint the group - * @return {boolean} Returns true if the component is resized + * 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() { +Group.prototype.repaint = function repaint(range, margin, restack) { var resized = false; - this.show(); + this.visibleItems = this._updateVisibleItems(this.orderedItems, this.visibleItems, range); + + // 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(); + } - if (this.itemSet) { - resized = this.itemSet.repaint() || resized; + // 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); + + // 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; - // calculate inner size of the label + // recalculate size of label resized = util.updateProperty(this.props.label, 'width', this.dom.inner.clientWidth) || resized; resized = util.updateProperty(this.props.label, 'height', this.dom.inner.clientHeight) || resized; - this.height = this.itemSet ? this.itemSet.height : 0; - - this.dom.label.style.height = this.height + 'px'; + // apply new height + foreground.style.height = height + 'px'; + this.dom.label.style.height = height + 'px'; return resized; }; /** - * An GroupSet holds a set of groups - * @param {Panel} contentPanel Panel where the ItemSets will be created - * @param {Panel} labelPanel Panel where the labels will be created - * @param {Panel} backgroundPanel Panel where the vertical lines of box - * items are created - * @param {Panel} axisPanel Panel on the axis where the dots of box - * items will be created - * @param {Object} [options] See GroupSet.setOptions for the available - * options. - * @constructor GroupSet - * @extends Panel - */ -function GroupSet(contentPanel, labelPanel, backgroundPanel, axisPanel, options) { - this.id = util.randomUUID(); - - this.contentPanel = contentPanel; - this.labelPanel = labelPanel; - this.backgroundPanel = backgroundPanel; - this.axisPanel = axisPanel; - this.options = options || {}; - - 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 - this.groupIds = []; // list with ordered group ids - - this.dom = {}; - this.props = { - labels: { - width: 0 - } - }; - - // TODO: implement right orientation of the labels (left/right) - - 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); - } - }; - - // create HTML DOM - this._create(); -} - -GroupSet.prototype = new Panel(); - -/** - * Create the HTML DOM elements for the GroupSet - * @private - */ -GroupSet.prototype._create = function _create () { - // TODO: reimplement groupSet DOM elements - var frame = document.createElement('div'); - frame.className = 'groupset'; - frame['timeline-groupset'] = this; - this.frame = frame; - - this.labelSet = new Panel({ - className: 'labelset', - width: '100%', - height: '100%' - }); - this.labelPanel.appendChild(this.labelSet); -}; - -/** - * Get the frame element of component - * @returns {null} Get frame is not supported by GroupSet - */ -GroupSet.prototype.getFrame = function getFrame() { - return this.frame; -}; - -/** - * 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; - -/** - * Set range (start and end). - * @param {Range | Object} range A Range or an object containing start and end. - */ -GroupSet.prototype.setRange = function (range) { - this.range = range; - - for (var id in this.groups) { - if (this.groups.hasOwnProperty(id)) { - this.groups[id].setRange(range); - } - } -}; - -/** - * Set items - * @param {vis.DataSet | null} items + * Show this group: attach to the DOM */ -GroupSet.prototype.setItems = function setItems(items) { - this.itemsData = items; - - for (var id in this.groups) { - if (this.groups.hasOwnProperty(id)) { - var group = this.groups[id]; - // TODO: every group will emit a change event, causing a lot of unnecessary repaints. improve this. - group.setItems(items); - } +Group.prototype.show = function show() { + if (!this.dom.label.parentNode) { + this.itemSet.getLabelSet().appendChild(this.dom.label); } -}; - -/** - * Get items - * @return {vis.DataSet | null} items - */ -GroupSet.prototype.getItems = function getItems() { - return this.itemsData; -}; - -/** - * 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; -}; - -/** - * Set groups - * @param {vis.DataSet} groups - */ -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); + if (!this.dom.foreground.parentNode) { + this.itemSet.getForeground().appendChild(this.dom.foreground); } - // replace the dataset - if (!groups) { - this.groupsData = null; - } - else if (groups instanceof DataSet) { - this.groupsData = groups; - } - else { - this.groupsData = new DataSet({ - convert: { - start: 'Date', - end: 'Date' - } - }); - this.groupsData.add(groups); + if (!this.dom.background.parentNode) { + this.itemSet.getBackground().appendChild(this.dom.background); } - if (this.groupsData) { - // subscribe to new dataset - var id = this.id; - util.forEach(this.listeners, function (callback, event) { - me.groupsData.on(event, callback, id); - }); - - // draw all new groups - ids = this.groupsData.getIds(); - this._onAdd(ids); + if (!this.dom.axis.parentNode) { + this.itemSet.getAxis().appendChild(this.dom.axis); } - - this.emit('change'); }; /** - * Get groups - * @return {vis.DataSet | null} groups - */ -GroupSet.prototype.getGroups = function getGroups() { - return this.groupsData; -}; - -/** - * 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. + * Hide this group: remove from the DOM */ -GroupSet.prototype.setSelection = function setSelection(ids) { - var selection = [], - groups = this.groups; - - // iterate over each of the groups - for (var id in groups) { - if (groups.hasOwnProperty(id)) { - var group = groups[id]; - group.setSelection(ids); - } +Group.prototype.hide = function hide() { + var label = this.dom.label; + if (label.parentNode) { + label.parentNode.removeChild(label); } - return selection; -}; - -/** - * Get the selected items by their id - * @return {Array} ids The ids of the selected items - */ -GroupSet.prototype.getSelection = function getSelection() { - var selection = [], - groups = this.groups; + var foreground = this.dom.foreground; + if (foreground.parentNode) { + foreground.parentNode.removeChild(foreground); + } - // iterate over each of the groups - for (var id in groups) { - if (groups.hasOwnProperty(id)) { - var group = groups[id]; - selection = selection.concat(group.getSelection()); - } + var background = this.dom.background; + if (background.parentNode) { + background.parentNode.removeChild(background); } - return selection; + var axis = this.dom.axis; + if (axis.parentNode) { + axis.parentNode.removeChild(axis); + } }; /** - * Repaint the component - * @return {boolean} Returns true if the component was resized since previous repaint + * Add an item to the group + * @param {Item} item */ -GroupSet.prototype.repaint = function repaint() { - var i, id, group, - asSize = util.option.asSize, - asString = util.option.asString, - options = this.options, - orientation = this.getOption('orientation'), - frame = this.frame, - resized = false, - groups = this.groups; - - // repaint all groups in order - this.groupIds.forEach(function (id) { - var groupResized = groups[id].repaint(); - resized = resized || groupResized; - }); - - // reposition the labels and calculate the maximum label width - var maxWidth = 0; - for (id in groups) { - if (groups.hasOwnProperty(id)) { - group = groups[id]; - maxWidth = Math.max(maxWidth, group.props.label.width); - } - } - resized = util.updateProperty(this.props.labels, 'width', maxWidth) || resized; +Group.prototype.add = function add(item) { + this.items[item.id] = item; + item.setParent(this); - // recalculate the height of the groupset, and recalculate top positions of the groups - var fixedHeight = (asSize(options.height) != null); - var height; - if (!fixedHeight) { - // height is not specified, calculate the sum of the height of all groups - height = 0; - - this.groupIds.forEach(function (id) { - var group = groups[id]; - group.top = height; - if (group.itemSet) group.itemSet.top = group.top; // TODO: this is an ugly hack - height += group.height; - }); + 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); } - - // update classname - frame.className = 'groupset' + (options.className ? (' ' + asString(options.className)) : ''); - - // calculate actual size and position - this.top = frame.offsetTop; - this.left = frame.offsetLeft; - this.width = frame.offsetWidth; - this.height = height; - - return resized; }; /** - * Update the groupIds. Requires a repaint afterwards - * @private + * Remove an item from the group + * @param {Item} item */ -GroupSet.prototype._updateGroupIds = function () { - // reorder the groups - this.groupIds = this.groupsData.getIds({ - order: this.options.groupOrder - }); +Group.prototype.remove = function remove(item) { + delete this.items[item.id]; + item.setParent(this.itemSet); - // hide the groups now, they will be shown again in the next repaint - // in correct order - var groups = this.groups; - this.groupIds.forEach(function (id) { - groups[id].hide(); - }); + // remove from visible items + var index = this.visibleItems.indexOf(item); + if (index != -1) this.visibleItems.splice(index, 1); + + // TODO: also remove from ordered items? }; /** - * Get the width of the group labels - * @return {Number} width + * Remove an item from the corresponding DataSet + * @param {Item} item */ -GroupSet.prototype.getLabelsWidth = function getLabelsWidth() { - return this.props.labels.width; +Group.prototype.removeFromDataSet = function removeFromDataSet(item) { + this.itemSet.removeItem(item.id); }; /** - * Hide the component from the DOM + * Reorder the items */ -GroupSet.prototype.hide = function hide() { - // hide labelset - this.labelPanel.removeChild(this.labelSet); +Group.prototype.order = function order() { + var array = util.toArray(this.items); + this.orderedItems.byStart = array; + this.orderedItems.byEnd = this._constructByEndArray(array); - // hide each of the groups - for (var groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - this.groups[groupId].hide(); - } - } + stack.orderByStart(this.orderedItems.byStart); + stack.orderByEnd(this.orderedItems.byEnd); }; /** - * Show the component in the DOM (when not already visible). - * @return {Boolean} changed + * Create an array containing all items being a range (having an end date) + * @param {Item[]} array + * @returns {ItemRange[]} + * @private */ -GroupSet.prototype.show = function show() { - // show label set - if (!this.labelPanel.hasChild(this.labelSet)) { - this.labelPanel.removeChild(this.labelSet); - } +Group.prototype._constructByEndArray = function _constructByEndArray(array) { + var endArray = []; - // show each of the groups - for (var groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - this.groups[groupId].show(); + for (var i = 0; i < array.length; i++) { + if (array[i] instanceof ItemRange) { + endArray.push(array[i]); } } + return endArray; }; /** - * Handle updated groups - * @param {Number[]} ids + * 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._onUpdate = function _onUpdate(ids) { - this._onAdd(ids); -}; +Group.prototype._updateVisibleItems = function _updateVisibleItems(orderedItems, visibleItems, range) { + var initialPosByStart, + newVisibleItems = [], + i; -/** - * Handle changed groups - * @param {Number[]} ids - * @private - */ -GroupSet.prototype._onAdd = function _onAdd(ids) { - var me = this; + // 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); + } + } - ids.forEach(function (id) { - var group = me.groups[id]; - if (!group) { - var groupOptions = Object.create(me.options); - util.extend(groupOptions, { - height: null - }); + // 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); + } + else { + initialPosByStart = orderedItems.byStart.indexOf(newVisibleItems[0]); + } - group = new Group(me, me.labelSet, me.backgroundPanel, me.axisPanel, id, groupOptions); - group.on('change', me.emit.bind(me, 'change')); // propagate change event - group.setRange(me.range); - group.setItems(me.itemsData); // attach items data - me.groups[id] = group; - group.parent = me; - } + // use visible search to find a visible ItemRange (only based on endTime) + var initialPosByEnd = this._binarySearch(orderedItems, range, true); - // update group data - group.setData(me.groupsData.get(id)); - }); + // 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 = initialPosByStart + 1; i < orderedItems.byStart.length; i++) { + if (this._checkIfInvisible(orderedItems.byStart[i], newVisibleItems, range)) {break;} + } + } - this._updateGroupIds(); + // 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;} + } + } - this.emit('change'); + return newVisibleItems; }; /** - * Handle removed groups - * @param {Number[]} ids + * 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._onRemove = function _onRemove(ids) { - var groups = this.groups; - ids.forEach(function (id) { - var group = groups[id]; +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;} - if (group) { - group.setItems(); // detach items data - group.hide(); // FIXME: for some reason when doing setItems after hide, setItems again makes the label visible - delete groups[id]; - } - }); + var interval = range.end - range.start; - this._updateGroupIds(); + var found = false; + var low = 0; + var high = array.length; + var guess = Math.floor(0.5*(high+low)); + var newGuess; - this.emit('change'); + 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 { + guess = -1; + } + } + 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; + } + } + } + } + return guess; }; /** - * Find the GroupSet 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 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.groupSetFromTarget = function groupSetFromTarget (event) { - var target = event.target; - while (target) { - if (target.hasOwnProperty('timeline-groupset')) { - return target['timeline-groupset']; +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); } - target = target.parentNode; + return false; + } + else { + return true; } - - return null; }; /** - * Find the Group from an event target: - * searches for the two elements having attributes 'timeline-groupset' and - * 'timeline-itemset' in the event target's element, then finds the right group. - * @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) { - // find the groupSet - var groupSet = GroupSet.groupSetFromTarget(event); - - // find the ItemSet - var itemSet = ItemSet.itemSetFromTarget(event); - - // find the right group - if (groupSet && itemSet) { - for (var groupId in groupSet.groups) { - if (groupSet.groups.hasOwnProperty(groupId)) { - var group = groupSet.groups[groupId]; - if (group.itemSet == itemSet) { - return group; - } - } - } +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); + } + else { + if (item.displayed) item.hide(); } - - return null; }; /** @@ -7046,7 +7158,15 @@ function Timeline (container, items, options) { orientation: 'bottom', direction: 'horizontal', // 'horizontal' or 'vertical' autoResize: true, - editable: false, + stacking: true, + + editable: { + updateTime: false, + updateGroup: false, + add: false, + remove: false + }, + selectable: true, snap: null, // will be specified after timeaxis is created @@ -7124,8 +7244,8 @@ function Timeline (container, items, options) { right: null, height: '100%', width: function () { - if (me.groupSet) { - return me.groupSet.getLabelsWidth(); + if (me.itemSet) { + return me.itemSet.getLabelsWidth(); } else { return 0; @@ -7267,11 +7387,19 @@ function Timeline (container, items, options) { me.emit('timechanged', time); }); - this.itemSet = null; - this.groupSet = null; - - // 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 @@ -7281,7 +7409,7 @@ function Timeline (container, items, options) { this.setOptions(options); } - // create itemset and groupset + // create itemset if (items) { this.setItems(items); } @@ -7297,6 +7425,17 @@ Emitter(Timeline.prototype); 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); @@ -7312,6 +7451,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) { @@ -7346,6 +7488,11 @@ Timeline.prototype.setOptions = function (options) { } } + // TODO: remove deprecation error one day (deprecated since version 0.8.0) + if (options && options.order) { + throw new Error('Option order is deprecated. There is no replacement for this feature.'); + } + // repaint everything this.rootPanel.repaint(); }; @@ -7386,22 +7533,22 @@ 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.itemSet || this.groupSet).setItems(newDataSet); + this.itemSet.setItems(newDataSet); if (initialLoad && (this.options.start == undefined || this.options.end == undefined)) { // apply the data range as range @@ -7428,72 +7575,46 @@ Timeline.prototype.setItems = function(items) { end = util.convert(this.options.end, 'Date'); } - // apply range if there is a min or max available - if (start != null || end != null) { - this.range.setRange(start, end); + // skip range set if there is no start and end date + if (start === null && end === null) { + return; + } + + // if start and end dates are set but cannot be satisfyed due to zoom restrictions — correct end date + if (start != null && end != null) { + var diff = end.valueOf() - start.valueOf(); + if (this.options.zoomMax != undefined && this.options.zoomMax < diff) { + end = new Date(start.valueOf() + this.options.zoomMax); + } + if (this.options.zoomMin != undefined && this.options.zoomMin > diff) { + end = new Date(start.valueOf() + this.options.zoomMin); + } } + + this.range.setRange(start, end); } }; /** * Set groups - * @param {vis.DataSet | Array | google.visualization.DataTable} groupSet + * @param {vis.DataSet | Array | google.visualization.DataTable} groups */ -Timeline.prototype.setGroups = function(groupSet) { - var me = this; - this.groupsData = groupSet; - - // create options for the itemset or groupset - var options = util.extend(Object.create(this.options), { - top: null, - bottom: null, - right: null, - left: null, - width: null, - height: null - }); - - if (this.groupsData) { - // Create a GroupSet - - // remove itemset if existing - if (this.itemSet) { - this.itemSet.hide(); // TODO: not so nice having to hide here - this.contentPanel.removeChild(this.itemSet); - this.itemSet.setItems(); // disconnect from itemset - this.itemSet = null; - } - - // create new GroupSet when needed - if (!this.groupSet) { - this.groupSet = new GroupSet(this.contentPanel, this.sideContentPanel, this.backgroundPanel, this.axisPanel, options); - this.groupSet.on('change', this.rootPanel.repaint.bind(this.rootPanel)); - this.groupSet.setRange(this.range); - this.groupSet.setItems(this.itemsData); - this.groupSet.setGroups(this.groupsData); - this.contentPanel.appendChild(this.groupSet); - } - else { - this.groupSet.setGroups(this.groupsData); - } +Timeline.prototype.setGroups = function(groups) { + // convert to type DataSet when needed + var newDataSet; + if (!groups) { + newDataSet = null; + } + else if (groups instanceof DataSet || groups instanceof DataView) { + newDataSet = groups; } else { - // ItemSet - if (this.groupSet) { - this.groupSet.hide(); // TODO: not so nice having to hide here - //this.groupSet.setGroups(); // disconnect from groupset - this.groupSet.setItems(); // disconnect from itemset - this.contentPanel.removeChild(this.groupSet); - this.groupSet = null; - } - - // create new items - this.itemSet = new ItemSet(this.backgroundPanel, this.axisPanel, options); - this.itemSet.setRange(this.range); - this.itemSet.setItems(this.itemsData); - this.itemSet.on('change', me.rootPanel.repaint.bind(me.rootPanel)); - this.contentPanel.appendChild(this.itemSet); + // turn an array into a dataset + newDataSet = new DataSet(groups); } + + this.groupsData = newDataSet; + this.itemSet.setGroups(newDataSet); }; /** @@ -7543,9 +7664,7 @@ Timeline.prototype.getItemRange = function getItemRange() { * unselected. */ Timeline.prototype.setSelection = function setSelection (ids) { - var itemOrGroupSet = (this.itemSet || this.groupSet); - - if (itemOrGroupSet) itemOrGroupSet.setSelection(ids); + this.itemSet.setSelection(ids); }; /** @@ -7553,28 +7672,36 @@ Timeline.prototype.setSelection = function setSelection (ids) { * @return {Array} ids The ids of the selected items */ Timeline.prototype.getSelection = function getSelection() { - var itemOrGroupSet = (this.itemSet || this.groupSet); - - return itemOrGroupSet ? itemOrGroupSet.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 */ -// TODO: implement support for setWindow({start: ..., end: ...}) -// TODO: rename setWindow to setRange? 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); + } }; /** * Get the visible window * @return {{start: Date, end: Date}} Visible range */ -// TODO: rename getWindow to getRange? Timeline.prototype.getWindow = function setWindow() { var range = this.range.getRange(); return { @@ -7624,7 +7751,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); @@ -7642,7 +7769,7 @@ 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)), @@ -7652,7 +7779,7 @@ Timeline.prototype._onAddItem = function (event) { 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; } @@ -9138,6 +9265,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) { @@ -9783,6 +9911,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 @@ -9843,6 +9972,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 @@ -10259,7 +10391,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)); @@ -10299,7 +10431,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(); @@ -10373,7 +10505,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(); @@ -10424,7 +10556,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(); @@ -11241,6 +11373,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) { @@ -11255,6 +11394,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"); @@ -11264,6 +11406,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)) { @@ -11281,6 +11427,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 = []; @@ -11378,7 +11527,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; @@ -11417,6 +11569,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; @@ -11663,6 +11823,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; @@ -11680,6 +11847,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. @@ -11705,6 +11880,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 @@ -12071,7 +12254,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. @@ -12096,7 +12279,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; @@ -12105,7 +12288,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); @@ -12547,8 +12730,6 @@ var manipulationMixin = { /** * Adds a node on the specified location - * - * @param {Object} pointer */ _addNode : function() { if (this._selectionIsEmpty() && this.editMode == true) { @@ -13383,6 +13564,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) { @@ -14233,9 +14415,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;} @@ -14247,7 +14430,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]); @@ -14562,7 +14745,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(); } } @@ -15232,15 +15415,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": [], @@ -15273,7 +15456,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. @@ -15438,6 +15621,7 @@ function Graph (container, data, options) { fontSize: 14, // px fontFace: 'arial', fontFill: 'white', + arrowScaleFactor: 1, dash: { length: 10, gap: 5, @@ -15736,6 +15920,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) { @@ -15992,6 +16177,7 @@ Graph.prototype.setOptions = function (options) { } } + if (options.edges.color !== undefined) { if (util.isString(options.edges.color)) { this.constants.edges.color = {}; @@ -16321,7 +16507,7 @@ Graph.prototype._handleOnDrag = function(event) { this.drag.translation.x + diffX, this.drag.translation.y + diffY); this._redraw(); - this.moved = true; + this.moving = true; } }; @@ -16724,12 +16910,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); @@ -17174,7 +17361,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) { @@ -17189,6 +17381,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) { @@ -17259,7 +17456,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) { @@ -17378,7 +17579,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; @@ -17404,6 +17610,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) { @@ -17428,7 +17641,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)) { @@ -17476,7 +17693,7 @@ var vis = { DataSet: DataSet, DataView: DataView, Range: Range, - Stack: Stack, + stack: stack, TimeStep: TimeStep, components: { diff --git a/dist/vis.min.css b/dist/vis.min.css index 6b32bc70..4dd85675 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;-moz-box-sizing:border-box;box-sizing:border-box}.vis.timeline .vpanel.side{border-right:1px solid #bfbfbf}.vis.timeline .vpanel.side.hidden{display:none}.vis.timeline .groupset{position:relative}.vis.timeline .labelset{position:relative;width:100%;overflow:hidden;-moz-box-sizing:border-box;box-sizing:border-box}.vis.timeline .labelset .vlabel{position:relative;left:0;top:0;width:100%;color:#4d4d4d;-moz-box-sizing:border-box;box-sizing:border-box}.vis.timeline.bottom .labelset .vlabel,.vis.timeline.top .groupset .itemset,.vis.timeline.top .vpanel.side-content{border-top:1px solid #bfbfbf;border-bottom:none}.vis.timeline.bottom .groupset .itemset,.vis.timeline.bottom .vpanel.side-content,.vis.timeline.top .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;-moz-box-sizing:border-box;box-sizing:border-box}.vis.timeline .axis{overflow:visible}.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.dot.selected,.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 .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 +.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;-moz-box-sizing:border-box;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;-moz-box-sizing:border-box;box-sizing:border-box}.vis.timeline .labelset .vlabel{position:relative;left:0;top:0;width:100%;color:#4d4d4d;-moz-box-sizing:border-box;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;-moz-box-sizing:border-box;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;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.dot.selected,.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 .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 a7ae2cb0..27de3e90 100644 --- a/dist/vis.min.js +++ b/dist/vis.min.js @@ -5,7 +5,7 @@ * A dynamic, browser-based visualization library. * * @version 0.7.5-SNAPSHOT - * @date 2014-04-22 + * @date 2014-05-01 * * @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(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||(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,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""}},Stack.prototype.setOptions=function(t){util.extend(this.options,t)},Stack.prototype.order=function t(e){var t=this.options.order||this.defaultOptions.order;if("function"!=typeof t)throw new Error("Option order must be a function");e.sort(t)},Stack.prototype.orderByStart=function(t){t.sort(function(t,e){return t.data.start-e.data.start})},Stack.prototype.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.prototype.stack=function(t,e){var i,s,n,o,a=this.options;if(n=a.margin&&void 0!==a.margin.item?a.margin.item:this.defaultOptions.margin.item,o=a.margin&&void 0!==a.margin.axis?a.margin.axis:this.defaultOptions.margin.axis,e)for(i=0,s=t.length;s>i;i++)t[i].top=null;for(i=0,s=t.length;s>i;i++){var r=t[i];if(null===r.top){r.top=o;do{for(var h=null,d=0,c=t.length;c>d;d++){var l=t[d];if(null!==l.top&&l!==r&&this.collision(r,l,n)){h=l;break}}null!=h&&(r.top=h.top+h.height+n)}while(h)}}},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.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="vis timeline rootpanel "+t.orientation+(t.editable?" editable":"");t.className&&(e+=" "+util.option.asString(e)),this.frame.className=e;var i=this._repaintChilds();this.frame.style.maxHeight=util.option.asSize(this.options.maxHeight,""),this._updateSize();var s=this._isResized()||i;s&&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(5*(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())},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),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=Component.prototype.setOptions,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)},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)},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=util.option.asSize,e=util.option.asString,i=this.options,s=this.getOption("orientation"),n=this.frame;n.className="itemset"+(i.className?" "+e(i.className):"");var o=this.range.end-this.range.start,a=o!=this.lastVisibleInterval||this.width!=this.lastWidth;this.lastVisibleInterval=o,this.lastWidth=this.width,this.visibleItems=[];for(var r in this.items)if(this.items.hasOwnProperty(r)){var h=this.items[r];h.isVisible(this.range)?(h.displayed||h.show(),h.repositionX(),this.visibleItems.push(h)):h.displayed&&h.hide()}var d=this.stackDirty||a;this.stack.stack(this.visibleItems,d),this.stackDirty=!1;for(var c=0,l=this.visibleItems.length;l>c;c++)this.visibleItems[c].repositionY();var u,p=i.margin&&"axis"in i.margin?i.margin.axis:this.itemOptions.margin.axis,g=i.margin&&"item"in i.margin?i.margin.item:this.itemOptions.margin.item,m=this.visibleItems;if(m.length){var f=m[0].top,v=m[0].top+m[0].height;util.forEach(m,function(t){f=Math.min(f,t.top),v=Math.max(v,t.top+t.height)}),u=v-f+p+g}else u=p+g;return n.style.left=t(i.left,""),n.style.right=t(i.right,""),n.style.top=t("top"==s?"0":""),n.style.bottom=t("top"==s?"":"0"),n.style.width=t(i.width,"100%"),n.style.height=t(u),this.top=n.offsetTop,this.left=n.offsetLeft,this.width=n.offsetWidth,this.height=u,this.dom.axis.style.left=t(i.left,"0"),this.dom.axis.style.right=t(i.right,""),this.dom.axis.style.width=t(i.width,"100%"),this.dom.axis.style.height=t(0),this.dom.axis.style.top=t("top"==s?"0":""),this.dom.axis.style.bottom=t("top"==s?"":"0"),this._isResized()},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.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(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?o.data=n:(o.hide(),o=null)),!o){if(!r)throw new TypeError('Unknown item type "'+a+'"');o=new r(e,n,e.options,s),o.id=t}e.items[t]=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];if(s){e++,s.hide(),delete i.items[t],delete i.visibleItems[t];var n=i.selection.indexOf(t);-1!=n&&i.selection.splice(n,1)}}),e&&(this._order(),this.stackDirty=!0,this.emit("change"))},ItemSet.prototype._order=function(){var t=util.toArray(this.items);this.orderedItems.byStart=t,this.orderedItems.byEnd=[].concat(t),this.stack.orderByStart(this.orderedItems.byStart),this.stack.orderByEnd(this.orderedItems.byEnd)},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=this.width/(this.range.end-this.range.start),n=i/s;this.touchParams.itemProps.forEach(function(t){if("start"in t){var i=new Date(t.start+n);t.item.data.start=e?e(i):i}if("end"in t){var s=new Date(t.end+n);t.item.data.end=e?e(s):s}}),this.stackDirty=!0,this.emit("change"),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),a=!1;"start"in t.item.data&&(a=t.start!=t.item.data.start.valueOf(),o.start=util.convert(t.item.data.start,s.convert.start)),"end"in t.item.data&&(a=a||t.end!=t.item.data.end.valueOf(),o.end=util.convert(t.item.data.end,s.convert.end)),a&&i.options.onMove(o,function(i){i?(i[s.fieldId]=n,e.push(i)):("start"in t&&(t.item.data.start=t.start),"end"in t&&(t.item.data.end=t.end),this.stackDirty=!0,this.emit("change"))})}),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.displayed&&this.repaint()},Item.prototype.unselect=function(){this.selected=!1,this.displayed&&this.repaint()},Item.prototype.show=function(){return!1},Item.prototype.hide=function(){return!1},Item.prototype.repaint=function(){},Item.prototype.repositionX=function(){},Item.prototype.repositionY=function(){},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.isVisible=function(t){var e=(t.end-t.start)/4;return this.data.start>t.start-e&&this.data.startt.start-e&&this.data.startt.start},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&&!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.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.width=a&&(a=864e5),n=new Date(n.valueOf()-.05*a),o=new Date(o.valueOf()+.05*a)}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=util.extend(Object.create(this.options),{top:null,bottom:null,right:null,left:null,width:null,height:null});this.groupsData?(this.itemSet&&(this.itemSet.hide(),this.contentPanel.removeChild(this.itemSet),this.itemSet.setItems(),this.itemSet=null),this.groupSet?this.groupSet.setGroups(this.groupsData):(this.groupSet=new GroupSet(this.contentPanel,this.sideContentPanel,this.backgroundPanel,this.axisPanel,i),this.groupSet.on("change",this.rootPanel.repaint.bind(this.rootPanel)),this.groupSet.setRange(this.range),this.groupSet.setItems(this.itemsData),this.groupSet.setGroups(this.groupsData),this.contentPanel.appendChild(this.groupSet))):(this.groupSet&&(this.groupSet.hide(),this.groupSet.setItems(),this.contentPanel.removeChild(this.groupSet),this.groupSet=null),this.itemSet=new ItemSet(this.backgroundPanel,this.axisPanel,i),this.itemSet.setRange(this.range),this.itemSet.setItems(this.itemsData),this.itemSet.on("change",e.rootPanel.repaint.bind(e.rootPanel)),this.contentPanel.appendChild(this.itemSet))},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){var e=this.itemSet||this.groupSet;e&&e.setSelection(t)},Timeline.prototype.getSelection=function(){var t=this.itemSet||this.groupSet;return t?t.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=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){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,a={start:this.timeAxis.snap(this._toTime(o)),content:"new item"},r=util.randomUUID();a[this.itemsData.fieldId]=r;var h=GroupSet.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(){C=0,I=D.charAt(0)}function s(){C++,I=D.charAt(C)}function n(){return D.charAt(C+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="";" "==I||" "==I||"\n"==I||"\r"==I;)s();do{var t=!1;if("#"==I){for(var e=C-1;" "==D.charAt(e)||" "==D.charAt(e);)e--;if("\n"==D.charAt(e)||""==D.charAt(e)){for(;""!=I&&"\n"!=I;)s();t=!0}}if("/"==I&&"/"==n()){for(;""!=I&&"\n"!=I;)s();t=!0}if("/"==I&&"*"==n()){for(;""!=I;){if("*"==I&&"/"==n()){s(),s();break}s()}t=!0}for(;" "==I||" "==I||"\n"==I||"\r"==I;)s()}while(t);if(""==I)return void(N=E.DELIMITER);var i=I+n();if(T[i])return N=E.DELIMITER,M=i,s(),void s();if(T[I])return N=E.DELIMITER,M=I,void s();if(o(I)||"-"==I){for(M+=I,s();o(I);)M+=I,s();return"false"==M?M=!1:"true"==M?M=!0:isNaN(Number(M))||(M=Number(M)),void(N=E.IDENTIFIER)}if('"'==I){for(s();""!=I&&('"'!=I||'"'==I&&'"'==n());)M+=I,'"'==I&&s(),s();if('"'!=I)throw b('End of string " expected');return s(),void(N=E.IDENTIFIER)}for(N=E.UNKNOWN;""!=I;)M+=I,s();throw new SyntaxError('Syntax error in part "'+S(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 "'+S(M,30)+'" (char '+C+")")}function S(t,e){return t.length<=e?t:t.substr(0,27)+"..."}function w(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)}),w(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="",C=0,I="",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;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;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,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,S=.25*Math.max(100,this.length);b.width||b.resize(t),b.width>b.height?(v=b.x+.5*b.width,y=b.y-S,_={x:v,y:b.y,angle:.9*Math.PI}):(v=b.x+S,y=b.y-.5*b.height,_={x:b.x,y:y,angle:.6*Math.PI}),t.beginPath(),t.arc(v,y,S,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,S,.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=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 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.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,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,a.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],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){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,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&&w(t[s])!==w(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 S(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 w(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[Se]<0||t._a[Se]>59?Se:t._a[we]<0||t._a[we]>59?we:t._a[xe]<0||t._a[xe]>999?xe:-1,t._pf._overflowDayOfYear&&(ve>e||e>_e)&&(e=_e),t._pf.overflow=e)}function I(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 P(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 k(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]]:k(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?Ve:ke;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 Pe;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Fe;case"a":case"A":return P(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(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])+w(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*(w(e)-1));break;case"M":case"MM":null!=e&&(n[ye]=w(e)-1);break;case"MMM":case"MMMM":s=P(i._l).monthsParse(e),null!=s?n[ye]=s:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(n[_e]=w(e));break;case"Do":null!=e&&(n[_e]=w(parseInt(e,10)));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=w(e));break;case"YY":n[ve]=le.parseTwoDigitYear(e);break;case"YYYY":case"YYYYY":case"YYYYYY":n[ve]=w(e);break;case"a":case"A":i._isPm=P(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":n[be]=w(e);break;case"m":case"mm":n[Se]=w(e);break;case"s":case"ss":n[we]=w(e);break;case"S":case"SS":case"SSS":case"SSSS":n[xe]=w(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=P(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]+=w((t._tzm||0)/60),l[Se]+=w((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=P(t._l),r=""+t._i,h=r.length,d=0;for(s=F(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),C(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=Ce.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=P().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,Se=4,we=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,Ie=/(\-)?(?:(\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?/,Pe=/\d{1,3}/,ke=/\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}/,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 w(this.milliseconds()/100)},SS:function(){return g(w(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(w(t/60),2)+":"+g(w(t)%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+g(w(t/60),2)+g(w(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=Ie.exec(t))?(i="-"===a[1]?-1:1,o={y:0,d:w(a[_e])*i,h:w(a[be])*i,m:w(a[Se])*i,s:w(a[we])*i,ms:w(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]||P(t),i=le.duration.fn._lang=le.fn._lang=P(t),i._abbr):le.fn._lang._abbr},le.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),P(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)S(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 w(t)+(w(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),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=P(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*w(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===w(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):S[t.which]?S[t.which]:w[t.which]?w[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 C)t[e]?i=!0:C[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||S.hasOwnProperty(t)&&(_[S[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){C[t]=0,n||(n=m(e[0],[]));var o,r=function(){M=n,++C[t],p()},h=function(t){d(i,t),"keyup"!==n&&(I=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={},C={},I=!1,M=!1,N=1;20>N;++N)S[111+N]="f"+N;for(N=0;9>=N;++N)S[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||(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.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="vis timeline rootpanel "+t.orientation+(t.editable?" editable":"");t.className&&(e+=" "+util.option.asString(e)),this.frame.className=e;var i=this._repaintChilds();this.frame.style.maxHeight=util.option.asSize(this.options.maxHeight,""),this._updateSize();var s=this._isResized()||i;s&&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=Component.prototype.setOptions,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;r.className="itemset"+(n.className?" "+s(n.className):"");var h=this.range.end-this.range.start,d=h!=this.lastVisibleInterval||this.width!=this.lastWidth;this.lastVisibleInterval=h,this.lastWidth=this.width;var c=d||this.stackDirty,l=0;return util.forEach(this.groups,function(i){a=i.repaint(e,t,c)||a,l+=i.height}),this.stackDirty=!1,a=this._orderGroups()||a,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(l),this.top=r.offsetTop,this.left=r.offsetLeft,this.width=r.offsetWidth,this.height=l,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._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.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){i[t].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&&!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),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++)this.visibleItems[n].repositionY();var a,r=this.visibleItems;if(r.length){var h=r[0].top,d=r[0].top+r[0].height;util.forEach(r,function(t){h=Math.min(h,t.top),d=Math.max(d,t.top+t.height)}),a=d-h+e.axis+e.item}else a=e.axis+e.item;var c=this.dom.foreground;return this.top=c.offsetTop,this.left=c.offsetLeft,this.width=c.offsetWidth,s=util.updateProperty(this,"height",a)||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,c.style.height=a+"px",this.dom.label.style.height=a+"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]=a&&(a=864e5),n=new Date(n.valueOf()-.05*a),o=new Date(o.valueOf()+.05*a)}if(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)return;if(null!=n&&null!=o){var r=o.valueOf()-n.valueOf();void 0!=this.options.zoomMax&&this.options.zoomMaxr&&(o=new Date(n.valueOf()+this.options.zoomMin))}this.range.setRange(n,o)}},Timeline.prototype.setGroups=function(t){var e;e=t?t instanceof DataSet||t instanceof DataView?t:new DataSet(t):null,this.groupsData=e,this.itemSet.setGroups(e)},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){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 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?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 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(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=F(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}/,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}/,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=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),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/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 8a664610..26c12b91 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,7 +481,7 @@ 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. @@ -535,6 +564,13 @@ var options = { visible. + + stack + Boolean + true + If true (default), items will be stacked on top of each other such that they are not overlapping. + + start Date | Number | String @@ -792,6 +828,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/examples/timeline/01_basic.html b/examples/timeline/01_basic.html index 514eefd1..a9b2c2df 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 + Test with a lot of data

- +

\ No newline at end of file diff --git a/examples/timeline/09_order_groups.html b/examples/timeline/09_order_groups.html index 22dcbb36..ef588668 100644 --- a/examples/timeline/09_order_groups.html +++ b/examples/timeline/09_order_groups.html @@ -34,12 +34,12 @@ // create a dataset with items var items = new vis.DataSet([ - {id: 0, group: 0, content: 'item 0', start: new Date(2014, 3, 17)}, - {id: 1, group: 0, content: 'item 1', start: new Date(2014, 3, 19)}, - {id: 2, group: 1, content: 'item 2', start: new Date(2014, 3, 16)}, - {id: 3, group: 1, content: 'item 3', start: new Date(2014, 3, 23)}, - {id: 4, group: 1, content: 'item 4', start: new Date(2014, 3, 22)}, - {id: 5, group: 2, content: 'item 5', start: new Date(2014, 3, 24)} + {id: 0, group: 0, content: 'item 0', start: new Date(2014, 3, 17), end: new Date(2014, 3, 21)}, + {id: 1, group: 0, content: 'item 1', start: new Date(2014, 3, 19), end: new Date(2014, 3, 20)}, + {id: 2, group: 1, content: 'item 2', start: new Date(2014, 3, 16), end: new Date(2014, 3, 24)}, + {id: 3, group: 1, content: 'item 3', start: new Date(2014, 3, 23), end: new Date(2014, 3, 24)}, + {id: 4, group: 1, content: 'item 4', start: new Date(2014, 3, 22), end: new Date(2014, 3, 26)}, + {id: 5, group: 2, content: 'item 5', start: new Date(2014, 3, 24), end: new Date(2014, 3, 27)} ]); // create visualization @@ -52,7 +52,8 @@ // 0 when a == b groupOrder: function (a, b) { return a.value - b.value; - } + }, + editable: true }; var timeline = new vis.Timeline(container); diff --git a/examples/timeline/index.html b/examples/timeline/index.html index 5d8f7bd9..8372ce6a 100644 --- a/examples/timeline/index.html +++ b/examples/timeline/index.html @@ -13,7 +13,7 @@

vis.js timeline examples

01_basic.html

-

02_dataset.html

+

02_dataset.html

03_much_data.html

04_html_data.html

05_groups.html

diff --git a/src/graph/Edge.js b/src/graph/Edge.js index 0d5a0bb3..54bea6ff 100644 --- a/src/graph/Edge.js +++ b/src/graph/Edge.js @@ -35,6 +35,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 @@ -95,6 +96,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 @@ -511,7 +515,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)); @@ -551,7 +555,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(); @@ -625,7 +629,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(); @@ -676,7 +680,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(); diff --git a/src/graph/Graph.js b/src/graph/Graph.js index a9d68a0b..c88c1412 100644 --- a/src/graph/Graph.js +++ b/src/graph/Graph.js @@ -73,6 +73,7 @@ function Graph (container, data, options) { fontSize: 14, // px fontFace: 'arial', fontFill: 'white', + arrowScaleFactor: 1, dash: { length: 10, gap: 5, @@ -371,6 +372,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) { @@ -627,6 +629,7 @@ Graph.prototype.setOptions = function (options) { } } + if (options.edges.color !== undefined) { if (util.isString(options.edges.color)) { this.constants.edges.color = {}; @@ -956,7 +959,7 @@ Graph.prototype._handleOnDrag = function(event) { this.drag.translation.x + diffX, this.drag.translation.y + diffY); this._redraw(); - this.moved = true; + this.moving = true; } }; @@ -1359,12 +1362,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); @@ -1809,7 +1813,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) { @@ -1824,6 +1833,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) { @@ -1894,7 +1908,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) { @@ -2013,7 +2031,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; @@ -2039,6 +2062,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) { @@ -2063,7 +2093,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)) { diff --git a/src/graph/Node.js b/src/graph/Node.js index 7e14242b..0c87a5b1 100644 --- a/src/graph/Node.js +++ b/src/graph/Node.js @@ -356,6 +356,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) { diff --git a/src/graph/graphMixins/ClusterMixin.js b/src/graph/graphMixins/ClusterMixin.js index 9d6554eb..03da8b05 100644 --- a/src/graph/graphMixins/ClusterMixin.js +++ b/src/graph/graphMixins/ClusterMixin.js @@ -137,6 +137,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) { @@ -987,9 +988,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;} @@ -1001,7 +1003,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]); diff --git a/src/graph/graphMixins/HierarchicalLayoutMixin.js b/src/graph/graphMixins/HierarchicalLayoutMixin.js index 560978fc..01bb3c6c 100644 --- a/src/graph/graphMixins/HierarchicalLayoutMixin.js +++ b/src/graph/graphMixins/HierarchicalLayoutMixin.js @@ -123,7 +123,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. @@ -148,7 +148,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; @@ -157,7 +157,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); diff --git a/src/graph/graphMixins/ManipulationMixin.js b/src/graph/graphMixins/ManipulationMixin.js index 09147d7a..22d1dd6f 100644 --- a/src/graph/graphMixins/ManipulationMixin.js +++ b/src/graph/graphMixins/ManipulationMixin.js @@ -288,8 +288,6 @@ var manipulationMixin = { /** * Adds a node on the specified location - * - * @param {Object} pointer */ _addNode : function() { if (this._selectionIsEmpty() && this.editMode == true) { diff --git a/src/graph/graphMixins/MixinLoader.js b/src/graph/graphMixins/MixinLoader.js index 23f7dc07..a4b36126 100644 --- a/src/graph/graphMixins/MixinLoader.js +++ b/src/graph/graphMixins/MixinLoader.js @@ -67,15 +67,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": [], @@ -108,7 +108,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. diff --git a/src/graph/graphMixins/SelectionMixin.js b/src/graph/graphMixins/SelectionMixin.js index 9efaa064..b33e7843 100644 --- a/src/graph/graphMixins/SelectionMixin.js +++ b/src/graph/graphMixins/SelectionMixin.js @@ -174,7 +174,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(); } } diff --git a/src/graph/graphMixins/physics/BarnesHut.js b/src/graph/graphMixins/physics/BarnesHut.js index 826c27c7..4b9f039c 100644 --- a/src/graph/graphMixins/physics/BarnesHut.js +++ b/src/graph/graphMixins/physics/BarnesHut.js @@ -156,6 +156,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; @@ -173,6 +180,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. @@ -198,6 +213,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 diff --git a/src/graph/graphMixins/physics/PhysicsMixin.js b/src/graph/graphMixins/physics/PhysicsMixin.js index 946307b5..f98d1f9e 100644 --- a/src/graph/graphMixins/physics/PhysicsMixin.js +++ b/src/graph/graphMixins/physics/PhysicsMixin.js @@ -464,6 +464,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) { @@ -478,6 +485,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"); @@ -487,6 +497,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)) { @@ -504,6 +518,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 = []; @@ -601,7 +618,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; @@ -640,6 +660,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; diff --git a/src/module/exports.js b/src/module/exports.js index a2f25d6e..7c2cd456 100644 --- a/src/module/exports.js +++ b/src/module/exports.js @@ -7,7 +7,7 @@ var vis = { DataSet: DataSet, DataView: DataView, Range: Range, - Stack: Stack, + stack: stack, TimeStep: TimeStep, components: { diff --git a/src/timeline/Stack.js b/src/timeline/Stack.js deleted file mode 100644 index 57a2ef66..00000000 --- a/src/timeline/Stack.js +++ /dev/null @@ -1,169 +0,0 @@ -// TODO: turn Stack into a Mixin? - -/** - * @constructor Stack - * Stacks items on top of each other. - * @param {Object} [options] - */ -function Stack (options) { - this.options = options || {}; - this.defaultOptions = { - order: function (a, b) { - // Order: ranges over non-ranges, ranged ordered by width, - // and non-ranges 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, - axis: 20 - } - }; -} - -/** - * Set options for the stack - * @param {Object} options Available options: - * {Number} [margin.item=10] - * {Number} [margin.axis=20] - * {function} [order] Stacking order - */ -Stack.prototype.setOptions = function setOptions (options) { - util.extend(this.options, options); -}; - -/** - * Order an array with items using a predefined order function for items - * @param {Item[]} items - */ -Stack.prototype.order = function order(items) { - //order the items - var order = this.options.order || this.defaultOptions.order; - if (!(typeof order === 'function')) { - throw new Error('Option order must be a function'); - } - items.sort(order); -}; - -/** - * Order items by their start data - * @param {Item[]} items - */ -Stack.prototype.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.prototype.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 events such that they don't overlap each - * other. - * @param {Item[]} items All visible items - * @param {boolean} [force=false] If true, all items will be re-stacked. - * If false (default), only items having a - * top===null will be re-stacked - * @private - */ -Stack.prototype.stack = function stack (items, force) { - var i, - iMax, - options = this.options, - marginItem, - marginAxis; - - if (options.margin && options.margin.item !== undefined) { - marginItem = options.margin.item; - } - else { - marginItem = this.defaultOptions.margin.item - } - if (options.margin && options.margin.axis !== undefined) { - marginAxis = options.margin.axis; - } - else { - marginAxis = this.defaultOptions.margin.axis - } - - 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 = marginAxis; - - 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 && this.collision(item, other, marginItem)) { - collidingItem = other; - break; - } - } - - if (collidingItem != null) { - // There is a collision. Reposition the event above the colliding element - item.top = collidingItem.top + collidingItem.height + marginItem; - } - } while (collidingItem); - } - } -}; - -/** - * 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); -}; diff --git a/src/timeline/Timeline.js b/src/timeline/Timeline.js index 6ba4bb54..edcf0411 100644 --- a/src/timeline/Timeline.js +++ b/src/timeline/Timeline.js @@ -15,7 +15,15 @@ function Timeline (container, items, options) { orientation: 'bottom', direction: 'horizontal', // 'horizontal' or 'vertical' autoResize: true, - editable: false, + stacking: true, + + editable: { + updateTime: false, + updateGroup: false, + add: false, + remove: false + }, + selectable: true, snap: null, // will be specified after timeaxis is created @@ -93,8 +101,8 @@ function Timeline (container, items, options) { right: null, height: '100%', width: function () { - if (me.groupSet) { - return me.groupSet.getLabelsWidth(); + if (me.itemSet) { + return me.itemSet.getLabelsWidth(); } else { return 0; @@ -236,11 +244,19 @@ function Timeline (container, items, options) { me.emit('timechanged', time); }); - this.itemSet = null; - this.groupSet = null; - - // 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 @@ -250,7 +266,7 @@ function Timeline (container, items, options) { this.setOptions(options); } - // create itemset and groupset + // create itemset if (items) { this.setItems(items); } @@ -266,6 +282,17 @@ Emitter(Timeline.prototype); 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); @@ -281,6 +308,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) { @@ -360,22 +390,22 @@ 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.itemSet || this.groupSet).setItems(newDataSet); + this.itemSet.setItems(newDataSet); if (initialLoad && (this.options.start == undefined || this.options.end == undefined)) { // apply the data range as range @@ -424,63 +454,24 @@ Timeline.prototype.setItems = function(items) { /** * Set groups - * @param {vis.DataSet | Array | google.visualization.DataTable} groupSet + * @param {vis.DataSet | Array | google.visualization.DataTable} groups */ -Timeline.prototype.setGroups = function(groupSet) { - var me = this; - this.groupsData = groupSet; - - // create options for the itemset or groupset - var options = util.extend(Object.create(this.options), { - top: null, - bottom: null, - right: null, - left: null, - width: null, - height: null - }); - - if (this.groupsData) { - // Create a GroupSet - - // remove itemset if existing - if (this.itemSet) { - this.itemSet.hide(); // TODO: not so nice having to hide here - this.contentPanel.removeChild(this.itemSet); - this.itemSet.setItems(); // disconnect from itemset - this.itemSet = null; - } - - // create new GroupSet when needed - if (!this.groupSet) { - this.groupSet = new GroupSet(this.contentPanel, this.sideContentPanel, this.backgroundPanel, this.axisPanel, options); - this.groupSet.on('change', this.rootPanel.repaint.bind(this.rootPanel)); - this.groupSet.setRange(this.range); - this.groupSet.setItems(this.itemsData); - this.groupSet.setGroups(this.groupsData); - this.contentPanel.appendChild(this.groupSet); - } - else { - this.groupSet.setGroups(this.groupsData); - } +Timeline.prototype.setGroups = function(groups) { + // convert to type DataSet when needed + var newDataSet; + if (!groups) { + newDataSet = null; + } + else if (groups instanceof DataSet || groups instanceof DataView) { + newDataSet = groups; } else { - // ItemSet - if (this.groupSet) { - this.groupSet.hide(); // TODO: not so nice having to hide here - //this.groupSet.setGroups(); // disconnect from groupset - this.groupSet.setItems(); // disconnect from itemset - this.contentPanel.removeChild(this.groupSet); - this.groupSet = null; - } - - // create new items - this.itemSet = new ItemSet(this.backgroundPanel, this.axisPanel, options); - this.itemSet.setRange(this.range); - this.itemSet.setItems(this.itemsData); - this.itemSet.on('change', me.rootPanel.repaint.bind(me.rootPanel)); - this.contentPanel.appendChild(this.itemSet); + // turn an array into a dataset + newDataSet = new DataSet(groups); } + + this.groupsData = newDataSet; + this.itemSet.setGroups(newDataSet); }; /** @@ -530,9 +521,7 @@ Timeline.prototype.getItemRange = function getItemRange() { * unselected. */ Timeline.prototype.setSelection = function setSelection (ids) { - var itemOrGroupSet = (this.itemSet || this.groupSet); - - if (itemOrGroupSet) itemOrGroupSet.setSelection(ids); + this.itemSet.setSelection(ids); }; /** @@ -540,9 +529,7 @@ Timeline.prototype.setSelection = function setSelection (ids) { * @return {Array} ids The ids of the selected items */ Timeline.prototype.getSelection = function getSelection() { - var itemOrGroupSet = (this.itemSet || this.groupSet); - - return itemOrGroupSet ? itemOrGroupSet.getSelection() : []; + return this.itemSet.getSelection(); }; /** @@ -621,7 +608,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); @@ -639,7 +626,7 @@ 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)), @@ -649,7 +636,7 @@ Timeline.prototype._onAddItem = function (event) { 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; } diff --git a/src/timeline/component/Component.js b/src/timeline/component/Component.js index 437e8015..76ac811c 100644 --- a/src/timeline/component/Component.js +++ b/src/timeline/component/Component.js @@ -74,7 +74,7 @@ Component.prototype.repaint = function repaint() { * Test whether the component is resized since the last time _isResized() was * called. * @return {Boolean} Returns true if the component is resized - * @private + * @protected */ Component.prototype._isResized = function _isResized() { var resized = (this._previousWidth !== this.width || this._previousHeight !== this.height); diff --git a/src/timeline/component/Group.js b/src/timeline/component/Group.js index 282bc97d..f1fa1791 100644 --- a/src/timeline/component/Group.js +++ b/src/timeline/component/Group.js @@ -1,26 +1,15 @@ /** * @constructor Group - * @param {Panel} groupPanel - * @param {Panel} labelPanel - * @param {Panel} backgroundPanel - * @param {Panel} axisPanel * @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 (groupPanel, labelPanel, backgroundPanel, axisPanel, groupId, options) { - this.id = util.randomUUID(); - this.groupPanel = groupPanel; - this.labelPanel = labelPanel; - this.backgroundPanel = backgroundPanel; - this.axisPanel = axisPanel; - +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, @@ -28,20 +17,17 @@ function Group (groupPanel, labelPanel, backgroundPanel, axisPanel, groupId, opt } }; - this.dom = {}; - - this.top = 0; - this.left = 0; - this.width = 0; - this.height = 0; + 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: [] + }; this._create(); -} -Group.prototype = new Component(); - -// TODO: comment -Group.prototype.setOptions = Component.prototype.setOptions; + this.setData(data); +} /** * Create DOM elements for the group @@ -56,6 +42,15 @@ Group.prototype._create = function() { inner.className = 'inner'; label.appendChild(inner); this.dom.inner = inner; + + var foreground = document.createElement('div'); + foreground.className = 'group'; + foreground['timeline-group'] = this; + this.dom.foreground = foreground; + + this.dom.background = document.createElement('div'); + + this.dom.axis = document.createElement('div'); }; /** @@ -83,131 +78,375 @@ Group.prototype.setData = function 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} itemsData + * Get the foreground container element + * @return {HTMLElement} foreground */ -Group.prototype.setItems = function setItems(itemsData) { - if (this.itemSet) { - // remove current item set - this.itemSet.setItems(); - this.itemSet.hide(); - this.groupPanel.frame.removeChild(this.itemSet.getFrame()); - this.itemSet = null; - } +Group.prototype.getForeground = function getForeground() { + return this.dom.foreground; +}; - if (itemsData) { - var groupId = this.groupId; +/** + * Get the background container element + * @return {HTMLElement} background + */ +Group.prototype.getBackground = function getBackground() { + return this.dom.background; +}; - var me = this; - var itemSetOptions = util.extend(this.options, { - height: function () { - // FIXME: setting height doesn't yet work - return Math.max(me.props.label.height, me.itemSet.height); - } - }); - this.itemSet = new ItemSet(this.backgroundPanel, this.axisPanel, itemSetOptions); - this.itemSet.on('change', this.emit.bind(this, 'change')); // propagate change event - this.itemSet.parent = this; - this.groupPanel.frame.appendChild(this.itemSet.getFrame()); +/** + * Get the axis container element + * @return {HTMLElement} axis + */ +Group.prototype.getAxis = function getAxis() { + return this.dom.axis; +}; - if (this.range) this.itemSet.setRange(this.range); +/** + * Get the width of the group label + * @return {number} width + */ +Group.prototype.getLabelWidth = function getLabelWidth() { + return this.props.label.width; +}; - this.view = new DataView(itemsData, { - filter: function (item) { - return item.group == groupId; - } + +/** + * 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.visibleItems = this._updateVisibleItems(this.orderedItems, this.visibleItems, range); + + // 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(); + } + + // 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)); }); - this.itemSet.setItems(this.view); + height = (max - min) + margin.axis + margin.item; + } + else { + height = margin.axis + margin.item; } + height = Math.max(height, this.props.label.height); + + // calculate actual size and position + var foreground = this.dom.foreground; + this.top = foreground.offsetTop; + this.left = foreground.offsetLeft; + this.width = foreground.offsetWidth; + resized = util.updateProperty(this, 'height', height) || resized; + + // recalculate size of label + resized = util.updateProperty(this.props.label, 'width', this.dom.inner.clientWidth) || resized; + resized = util.updateProperty(this.props.label, 'height', this.dom.inner.clientHeight) || resized; + + // apply new height + foreground.style.height = height + 'px'; + this.dom.label.style.height = height + 'px'; + + return resized; }; /** - * hide the group, detach from DOM if needed + * Show this group: attach to the DOM */ Group.prototype.show = function show() { if (!this.dom.label.parentNode) { - this.labelPanel.frame.appendChild(this.dom.label); + this.itemSet.getLabelSet().appendChild(this.dom.label); } - var itemSetFrame = this.itemSet && this.itemSet.getFrame(); - if (itemSetFrame) { - if (itemSetFrame.parentNode) { - itemSetFrame.parentNode.removeChild(itemSetFrame); - } - this.groupPanel.frame.appendChild(itemSetFrame); + if (!this.dom.foreground.parentNode) { + this.itemSet.getForeground().appendChild(this.dom.foreground); + } + + if (!this.dom.background.parentNode) { + this.itemSet.getBackground().appendChild(this.dom.background); + } - this.itemSet.show(); + if (!this.dom.axis.parentNode) { + this.itemSet.getAxis().appendChild(this.dom.axis); } }; /** - * hide the group, detach from DOM if needed + * Hide this group: remove from the DOM */ Group.prototype.hide = function hide() { - if (this.dom.label.parentNode) { - this.dom.label.parentNode.removeChild(this.dom.label); + var label = this.dom.label; + if (label.parentNode) { + label.parentNode.removeChild(label); } - if (this.itemSet) { - this.itemSet.hide(); + var foreground = this.dom.foreground; + if (foreground.parentNode) { + foreground.parentNode.removeChild(foreground); } - var itemSetFrame = this.itemset && this.itemSet.getFrame(); - if (itemSetFrame && itemSetFrame.parentNode) { - itemSetFrame.parentNode.removeChild(itemSetFrame); + var background = this.dom.background; + if (background.parentNode) { + background.parentNode.removeChild(background); + } + + var axis = this.dom.axis; + if (axis.parentNode) { + axis.parentNode.removeChild(axis); } }; /** - * Set range (start and end). - * @param {Range | Object} range A Range or an object containing start and end. + * Add an item to the group + * @param {Item} item */ -Group.prototype.setRange = function (range) { - this.range = range; +Group.prototype.add = function add(item) { + this.items[item.id] = item; + item.setParent(this); - if (this.itemSet) this.itemSet.setRange(range); + 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); + } }; /** - * 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 group + * @param {Item} item */ -Group.prototype.setSelection = function setSelection(ids) { - if (this.itemSet) this.itemSet.setSelection(ids); +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? }; /** - * Get the selected items by their id - * @return {Array} ids The ids of the selected items + * Remove an item from the corresponding DataSet + * @param {Item} item */ -Group.prototype.getSelection = function getSelection() { - return this.itemSet ? this.itemSet.getSelection() : []; +Group.prototype.removeFromDataSet = function removeFromDataSet(item) { + this.itemSet.removeItem(item.id); }; /** - * Repaint the group - * @return {boolean} Returns true if the component is resized + * Reorder the items */ -Group.prototype.repaint = function repaint() { - var resized = false; +Group.prototype.order = function order() { + var array = util.toArray(this.items); + this.orderedItems.byStart = array; + this.orderedItems.byEnd = this._constructByEndArray(array); - this.show(); + stack.orderByStart(this.orderedItems.byStart); + stack.orderByEnd(this.orderedItems.byEnd); +}; - if (this.itemSet) { - resized = this.itemSet.repaint() || resized; +/** + * Create an array containing all items being a range (having an end date) + * @param {Item[]} array + * @returns {ItemRange[]} + * @private + */ +Group.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; +}; - // calculate inner size of the 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; +/** + * Update the visible items + * @param {{byStart: Item[], byEnd: Item[]}} orderedItems All items ordered by start date and by end date + * @param {Item[]} visibleItems The previously visible items. + * @param {{start: number, end: number}} range Visible range + * @return {Item[]} visibleItems The new visible items. + * @private + */ +Group.prototype._updateVisibleItems = function _updateVisibleItems(orderedItems, visibleItems, range) { + var initialPosByStart, + newVisibleItems = [], + i; + + // 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); + } + } + + // 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); + } + else { + initialPosByStart = orderedItems.byStart.indexOf(newVisibleItems[0]); + } - this.height = this.itemSet ? this.itemSet.height : 0; + // use visible search to find a visible ItemRange (only based on endTime) + var initialPosByEnd = this._binarySearch(orderedItems, range, true); - this.dom.label.style.height = this.height + 'px'; + // 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 = initialPosByStart + 1; i < orderedItems.byStart.length; i++) { + if (this._checkIfInvisible(orderedItems.byStart[i], newVisibleItems, range)) {break;} + } + } - return resized; + // 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 newVisibleItems; +}; + +/** + * 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 + */ +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;} + + var interval = range.end - range.start; + + var found = false; + var low = 0; + var high = array.length; + var guess = Math.floor(0.5*(high+low)); + var newGuess; + + 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 { + guess = -1; + } + } + 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; + } + } + } + } + return guess; +}; + +/** + * 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 + */ +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; + } + else { + return true; + } +}; + +/** + * this function is very similar to the _checkIfInvisible() but it does not + * return booleans, hides the item if it should not be seen and always adds to + * the visibleItems. + * this one is for brute forcing and hiding. + * + * @param {Item} item + * @param {Array} visibleItems + * @param {{start:number, end:number}} range + * @private + */ +Group.prototype._checkIfVisible = function _checkIfVisible(item, visibleItems, range) { + if (item.isVisible(range)) { + if (!item.displayed) item.show(); + // reposition item horizontally + item.repositionX(); + visibleItems.push(item); + } + else { + if (item.displayed) item.hide(); + } }; diff --git a/src/timeline/component/GroupSet.js b/src/timeline/component/GroupSet.js deleted file mode 100644 index 1e94fa3c..00000000 --- a/src/timeline/component/GroupSet.js +++ /dev/null @@ -1,465 +0,0 @@ -/** - * An GroupSet holds a set of groups - * @param {Panel} contentPanel Panel where the ItemSets will be created - * @param {Panel} labelPanel Panel where the labels will be created - * @param {Panel} backgroundPanel Panel where the vertical lines of box - * items are created - * @param {Panel} axisPanel Panel on the axis where the dots of box - * items will be created - * @param {Object} [options] See GroupSet.setOptions for the available - * options. - * @constructor GroupSet - * @extends Panel - */ -function GroupSet(contentPanel, labelPanel, backgroundPanel, axisPanel, options) { - this.id = util.randomUUID(); - - this.contentPanel = contentPanel; - this.labelPanel = labelPanel; - this.backgroundPanel = backgroundPanel; - this.axisPanel = axisPanel; - this.options = options || {}; - - 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 - this.groupIds = []; // list with ordered group ids - - this.dom = {}; - this.props = { - labels: { - width: 0 - } - }; - - // TODO: implement right orientation of the labels (left/right) - - 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); - } - }; - - // create HTML DOM - this._create(); -} - -GroupSet.prototype = new Panel(); - -/** - * Create the HTML DOM elements for the GroupSet - * @private - */ -GroupSet.prototype._create = function _create () { - // TODO: reimplement groupSet DOM elements - var frame = document.createElement('div'); - frame.className = 'groupset'; - frame['timeline-groupset'] = this; - this.frame = frame; - - this.labelSet = new Panel({ - className: 'labelset', - width: '100%', - height: '100%' - }); - this.labelPanel.appendChild(this.labelSet); -}; - -/** - * Get the frame element of component - * @returns {null} Get frame is not supported by GroupSet - */ -GroupSet.prototype.getFrame = function getFrame() { - return this.frame; -}; - -/** - * 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; - -/** - * Set range (start and end). - * @param {Range | Object} range A Range or an object containing start and end. - */ -GroupSet.prototype.setRange = function (range) { - this.range = range; - - for (var id in this.groups) { - if (this.groups.hasOwnProperty(id)) { - this.groups[id].setRange(range); - } - } -}; - -/** - * Set items - * @param {vis.DataSet | null} items - */ -GroupSet.prototype.setItems = function setItems(items) { - this.itemsData = items; - - for (var id in this.groups) { - if (this.groups.hasOwnProperty(id)) { - var group = this.groups[id]; - // TODO: every group will emit a change event, causing a lot of unnecessary repaints. improve this. - group.setItems(items); - } - } -}; - -/** - * Get items - * @return {vis.DataSet | null} items - */ -GroupSet.prototype.getItems = function getItems() { - return this.itemsData; -}; - -/** - * 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; -}; - -/** - * Set groups - * @param {vis.DataSet} groups - */ -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); - } - - // replace the dataset - if (!groups) { - this.groupsData = null; - } - else if (groups instanceof DataSet) { - this.groupsData = groups; - } - else { - this.groupsData = new DataSet({ - convert: { - start: 'Date', - end: 'Date' - } - }); - this.groupsData.add(groups); - } - - if (this.groupsData) { - // subscribe to new dataset - var id = this.id; - util.forEach(this.listeners, function (callback, event) { - me.groupsData.on(event, callback, id); - }); - - // draw all new groups - ids = this.groupsData.getIds(); - this._onAdd(ids); - } - - this.emit('change'); -}; - -/** - * Get groups - * @return {vis.DataSet | null} groups - */ -GroupSet.prototype.getGroups = function getGroups() { - return this.groupsData; -}; - -/** - * 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. - */ -GroupSet.prototype.setSelection = function setSelection(ids) { - var selection = [], - groups = this.groups; - - // iterate over each of the groups - for (var id in groups) { - if (groups.hasOwnProperty(id)) { - var group = groups[id]; - group.setSelection(ids); - } - } - - return selection; -}; - -/** - * Get the selected items by their id - * @return {Array} ids The ids of the selected items - */ -GroupSet.prototype.getSelection = function getSelection() { - var selection = [], - groups = this.groups; - - // iterate over each of the groups - for (var id in groups) { - if (groups.hasOwnProperty(id)) { - var group = groups[id]; - selection = selection.concat(group.getSelection()); - } - } - - return selection; -}; - -/** - * Repaint the component - * @return {boolean} Returns true if the component was resized since previous repaint - */ -GroupSet.prototype.repaint = function repaint() { - var i, id, group, - asSize = util.option.asSize, - asString = util.option.asString, - options = this.options, - orientation = this.getOption('orientation'), - frame = this.frame, - resized = false, - groups = this.groups; - - // repaint all groups in order - this.groupIds.forEach(function (id) { - var groupResized = groups[id].repaint(); - resized = resized || groupResized; - }); - - // reposition the labels and calculate the maximum label width - var maxWidth = 0; - for (id in groups) { - if (groups.hasOwnProperty(id)) { - group = groups[id]; - maxWidth = Math.max(maxWidth, group.props.label.width); - } - } - resized = util.updateProperty(this.props.labels, 'width', maxWidth) || resized; - - // recalculate the height of the groupset, and recalculate top positions of the groups - var fixedHeight = (asSize(options.height) != null); - var height; - if (!fixedHeight) { - // height is not specified, calculate the sum of the height of all groups - height = 0; - - this.groupIds.forEach(function (id) { - var group = groups[id]; - group.top = height; - if (group.itemSet) group.itemSet.top = group.top; // TODO: this is an ugly hack - height += group.height; - }); - } - - // update classname - frame.className = 'groupset' + (options.className ? (' ' + asString(options.className)) : ''); - - // calculate actual size and position - this.top = frame.offsetTop; - this.left = frame.offsetLeft; - this.width = frame.offsetWidth; - this.height = height; - - return resized; -}; - -/** - * Update the groupIds. Requires a repaint afterwards - * @private - */ -GroupSet.prototype._updateGroupIds = function () { - // reorder the groups - this.groupIds = this.groupsData.getIds({ - order: this.options.groupOrder - }); - - // hide the groups now, they will be shown again in the next repaint - // in correct order - var groups = this.groups; - this.groupIds.forEach(function (id) { - groups[id].hide(); - }); -}; - -/** - * Get the width of the group labels - * @return {Number} width - */ -GroupSet.prototype.getLabelsWidth = function getLabelsWidth() { - return this.props.labels.width; -}; - -/** - * Hide the component from the DOM - */ -GroupSet.prototype.hide = function hide() { - // hide labelset - this.labelPanel.removeChild(this.labelSet); - - // hide each of the groups - for (var groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - this.groups[groupId].hide(); - } - } -}; - -/** - * Show the component in the DOM (when not already visible). - * @return {Boolean} changed - */ -GroupSet.prototype.show = function show() { - // show label set - if (!this.labelPanel.hasChild(this.labelSet)) { - this.labelPanel.removeChild(this.labelSet); - } - - // show each of the groups - for (var groupId in this.groups) { - if (this.groups.hasOwnProperty(groupId)) { - this.groups[groupId].show(); - } - } -}; - -/** - * Handle updated groups - * @param {Number[]} ids - * @private - */ -GroupSet.prototype._onUpdate = function _onUpdate(ids) { - this._onAdd(ids); -}; - -/** - * Handle changed groups - * @param {Number[]} ids - * @private - */ -GroupSet.prototype._onAdd = function _onAdd(ids) { - var me = this; - - ids.forEach(function (id) { - var group = me.groups[id]; - if (!group) { - var groupOptions = Object.create(me.options); - util.extend(groupOptions, { - height: null - }); - - group = new Group(me, me.labelSet, me.backgroundPanel, me.axisPanel, id, groupOptions); - group.on('change', me.emit.bind(me, 'change')); // propagate change event - group.setRange(me.range); - group.setItems(me.itemsData); // attach items data - me.groups[id] = group; - group.parent = me; - } - - // update group data - group.setData(me.groupsData.get(id)); - }); - - this._updateGroupIds(); - - this.emit('change'); -}; - -/** - * Handle removed groups - * @param {Number[]} ids - * @private - */ -GroupSet.prototype._onRemove = function _onRemove(ids) { - var groups = this.groups; - ids.forEach(function (id) { - var group = groups[id]; - - if (group) { - group.setItems(); // detach items data - group.hide(); // FIXME: for some reason when doing setItems after hide, setItems again makes the label visible - delete groups[id]; - } - }); - - this._updateGroupIds(); - - this.emit('change'); -}; - -/** - * Find the GroupSet 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 - */ -GroupSet.groupSetFromTarget = function groupSetFromTarget (event) { - var target = event.target; - while (target) { - if (target.hasOwnProperty('timeline-groupset')) { - return target['timeline-groupset']; - } - target = target.parentNode; - } - - return null; -}; - -/** - * Find the Group from an event target: - * searches for the two elements having attributes 'timeline-groupset' and - * 'timeline-itemset' in the event target's element, then finds the right group. - * @param {Event} event - * @return {Group | null} group - */ -GroupSet.groupFromTarget = function groupFromTarget (event) { - // find the groupSet - var groupSet = GroupSet.groupSetFromTarget(event); - - // find the ItemSet - var itemSet = ItemSet.itemSetFromTarget(event); - - // find the right group - if (groupSet && itemSet) { - for (var groupId in groupSet.groups) { - if (groupSet.groups.hasOwnProperty(groupId)) { - var group = groupSet.groups[groupId]; - if (group.itemSet == itemSet) { - return group; - } - } - } - } - - return null; -}; diff --git a/src/timeline/component/ItemSet.js b/src/timeline/component/ItemSet.js index 42690650..a4a89bef 100644 --- a/src/timeline/component/ItemSet.js +++ b/src/timeline/component/ItemSet.js @@ -1,3 +1,5 @@ +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 @@ -6,27 +8,30 @@ * 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 */ -function ItemSet(backgroundPanel, axisPanel, options) { +function ItemSet(backgroundPanel, axisPanel, sidePanel, options) { this.id = util.randomUUID(); // one options object is shared by this itemset and all its items this.options = options || {}; 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); }, @@ -38,22 +43,29 @@ function ItemSet(backgroundPanel, axisPanel, options) { } }; - this.items = {}; // object with an Item for every data item - this.orderedItems = { - byStart: [], - byEnd: [] + // 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.visibleItems = []; // visible, ordered items - this.visibleItemsStart = 0; // start index of visible items in this.orderedItems // TODO: cleanup - this.visibleItemsEnd = 0; // start index of visible items in this.orderedItems // TODO: cleanup + + 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(Object.create(this.options)); this.stackDirty = true; // if true, all items will be restacked on next repaint this.touchParams = {}; // stores properties while dragging - // create the HTML DOM + this._create(); } @@ -93,6 +105,15 @@ ItemSet.prototype._create = function _create(){ 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, { @@ -131,7 +152,17 @@ ItemSet.prototype._create = function _create(){ * 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); +}; + +/** + * Mark the ItemSet dirty so it will refresh everything with next repaint + */ +ItemSet.prototype.markDirty = function markDirty() { + this.groupIds = []; + this.stackDirty = true; +}; /** * Hide the component from the DOM @@ -146,6 +177,11 @@ ItemSet.prototype.hide = function hide() { if (this.dom.background.parentNode) { this.dom.background.parentNode.removeChild(this.dom.background); } + + // remove the labelset containing all group labels + if (this.dom.labelSet.parentNode) { + this.dom.labelSet.parentNode.removeChild(this.dom.labelSet); + } }; /** @@ -162,6 +198,11 @@ ItemSet.prototype.show = function show() { 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); + } }; /** @@ -247,113 +288,57 @@ ItemSet.prototype.getFrame = function getFrame() { * @return {boolean} Returns true if the component is resized */ ItemSet.prototype.repaint = function repaint() { - var asSize = util.option.asSize, + var margin = this.options.margin, + range = this.range, + asSize = util.option.asSize, asString = util.option.asString, options = this.options, orientation = this.getOption('orientation'), + resized = false, frame = this.frame; + // TODO: document this feature to specify one margin for both item and axis distance + if (typeof margin === 'number') { + margin = { + item: margin, + axis: margin + }; + } + // update className frame.className = 'itemset' + (options.className ? (' ' + asString(options.className)) : ''); + // reorder the groups (if needed) + resized = this._orderGroups() || resized; + // check whether zoomed (in that case we need to re-stack everything) + // TODO: would be nicer to get this as a trigger from Range var visibleInterval = 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; - /* TODO: implement+fix smarter way to update visible items - // find the first visible item - // TODO: use faster search, not linear - var byEnd = this.orderedItems.byEnd; - var start = 0; - var item = null; - while ((item = byEnd[start]) && - (('end' in item.data) ? item.data.end : item.data.start) < this.range.start) { - start++; - } - - // find the last visible item - // TODO: use faster search, not linear - var byStart = this.orderedItems.byStart; - var end = 0; - while ((item = byStart[end]) && item.data.start < this.range.end) { - end++; - } - - console.log('visible items', start, end); // TODO: cleanup - console.log('visible item ids', byStart[start] && byStart[start].id, byEnd[end-1] && byEnd[end-1].id); // TODO: cleanup - - this.visibleItems = []; - var i = start; - item = byStart[i]; - var lastItem = byEnd[end]; - while (item && item !== lastItem) { - this.visibleItems.push(item); - item = byStart[++i]; - } - this.stack.order(this.visibleItems); - - // show visible items - for (var i = 0, ii = this.visibleItems.length; i < ii; i++) { - item = this.visibleItems[i]; - - if (!item.displayed) item.show(); - item.top = null; // reset stacking position - - // reposition item horizontally - item.repositionX(); - } - */ - - // simple, brute force calculation of visible items - // TODO: replace with a faster, more sophisticated solution - this.visibleItems = []; - for (var id in this.items) { - if (this.items.hasOwnProperty(id)) { - var item = this.items[id]; - if (item.isVisible(this.range)) { - if (!item.displayed) item.show(); - - // reposition item horizontally - item.repositionX(); - - this.visibleItems.push(item); - } - else { - if (item.displayed) item.hide(); - } - } - } - - // reposition visible items vertically - //this.stack.order(this.visibleItems); // TODO: improve ordering - var force = this.stackDirty || zoomed; // force re-stacking of all items if true - this.stack.stack(this.visibleItems, force); + // 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; - for (var i = 0, ii = this.visibleItems.length; i < ii; i++) { - this.visibleItems[i].repositionY(); - } - - // recalculate the height of the itemset - var marginAxis = (options.margin && 'axis' in options.margin) ? options.margin.axis : this.itemOptions.margin.axis, - marginItem = (options.margin && 'item' in options.margin) ? options.margin.item : this.itemOptions.margin.item, - height; - - // determine the height from the stacked items - 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) + marginAxis + marginItem; - } - else { - height = marginAxis + marginItem; - } // reposition frame frame.style.left = asSize(options.left, ''); @@ -378,7 +363,57 @@ ItemSet.prototype.repaint = function repaint() { this.dom.axis.style.top = asSize((orientation == 'top') ? '0' : ''); this.dom.axis.style.bottom = asSize((orientation == 'top') ? '' : '0'); - return this._isResized(); + // check if this component is resized + resized = this._isResized() || resized; + + return resized; +}; + +/** + * 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]; + + return firstGroup || null; +}; + +/** + * 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]; + + 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; + + for (var itemId in this.items) { + if (this.items.hasOwnProperty(itemId)) { + ungrouped.add(this.items[itemId]); + } + } + + ungrouped.show(); + } + } }; /** @@ -405,6 +440,14 @@ ItemSet.prototype.getAxis = function getAxis() { return this.dom.axis; }; +/** + * Get the element for the labelset + * @return {HTMLElement} labelSet + */ +ItemSet.prototype.getLabelSet = function getLabelSet() { + return this.dom.labelSet; +}; + /** * Set items * @param {vis.DataSet | null} items @@ -422,12 +465,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); }); @@ -439,24 +482,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 @@ -480,7 +585,7 @@ ItemSet.prototype.removeItem = function removeItem (id) { /** * Handle updated items * @param {Number[]} ids - * @private + * @protected */ ItemSet.prototype._onUpdate = function _onUpdate(ids) { var me = this, @@ -500,31 +605,29 @@ ItemSet.prototype._onUpdate = function _onUpdate(ids) { if (item) { // update item if (!constructor || !(item instanceof constructor)) { - // item type has changed, hide and delete the item - item.hide(); + // item type has changed, delete the item and recreate it + me._removeItem(item); item = null; } else { - item.data = itemData; // TODO: create a method item.setData ? + me._updateItem(item, itemData); } } if (!item) { // create item if (constructor) { - item = new constructor(me, itemData, me.options, itemOptions); - item.id = id; + 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 + '"'); } } - - me.items[id] = item; }); this._order(); - this.stackDirty = true; // force re-stacking of all items next repaint this.emit('change'); }; @@ -532,14 +635,14 @@ ItemSet.prototype._onUpdate = function _onUpdate(ids) { /** * Handle added items * @param {Number[]} ids - * @private + * @protected */ ItemSet.prototype._onAdd = ItemSet.prototype._onUpdate; /** * Handle removed items * @param {Number[]} ids - * @private + * @protected */ ItemSet.prototype._onRemove = function _onRemove(ids) { var count = 0; @@ -548,13 +651,7 @@ ItemSet.prototype._onRemove = function _onRemove(ids) { var item = me.items[id]; if (item) { count++; - item.hide(); - delete me.items[id]; - delete me.visibleItems[id]; - - // remove from selection - var index = me.selection.indexOf(id); - if (index != -1) me.selection.splice(index, 1); + me._removeItem(item); } }); @@ -567,17 +664,228 @@ ItemSet.prototype._onRemove = function _onRemove(ids) { }; /** - * Order the items + * Update the order of item in all groups * @private */ ItemSet.prototype._order = function _order() { - var array = util.toArray(this.items); - this.orderedItems.byStart = array; - this.orderedItems.byEnd = [].concat(array); + // reorder the items in all groups + // TODO: optimization: only reorder groups affected by the changed items + util.forEach(this.groups, function (group) { + group.order(); + }); +}; - // reorder the items - this.stack.orderByStart(this.orderedItems.byStart); - this.stack.orderByEnd(this.orderedItems.byEnd); +/** + * Handle updated groups + * @param {Number[]} ids + * @private + */ +ItemSet.prototype._onUpdateGroups = function _onUpdateGroups(ids) { + this._onAddGroups(ids); +}; + +/** + * Handle changed groups + * @param {Number[]} ids + * @private + */ +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; }; /** @@ -586,28 +894,45 @@ ItemSet.prototype._order = function _order() { * @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) { @@ -616,11 +941,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; @@ -649,16 +975,29 @@ 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.stackDirty = true; // force re-stacking of all items next repaint this.emit('change'); @@ -680,25 +1019,29 @@ ItemSet.prototype._onDragEnd = function (event) { 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 - item[dataset.fieldId] = id; // ensure the item contains its id (can be undefined) - changes.push(item); + itemData[dataset.fieldId] = id; // ensure the item contains its id (can be undefined) + changes.push(itemData); } else { // restore original values @@ -740,6 +1083,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 diff --git a/src/timeline/component/RootPanel.js b/src/timeline/component/RootPanel.js index 4ec47e6b..3cf1915a 100644 --- a/src/timeline/component/RootPanel.js +++ b/src/timeline/component/RootPanel.js @@ -91,7 +91,8 @@ RootPanel.prototype.getFrame = function getFrame() { RootPanel.prototype.repaint = function repaint() { // update class name var options = this.options; - var className = 'vis timeline rootpanel ' + options.orientation + (options.editable ? ' editable' : ''); + 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; diff --git a/src/timeline/component/TimeAxis.js b/src/timeline/component/TimeAxis.js index feaf074c..f56d56da 100644 --- a/src/timeline/component/TimeAxis.js +++ b/src/timeline/component/TimeAxis.js @@ -153,10 +153,10 @@ TimeAxis.prototype.repaint = function () { TimeAxis.prototype._repaintLabels = function () { var orientation = this.getOption('orientation'); - // calculate range and step + // 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) * 5).valueOf() + 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; diff --git a/src/timeline/component/css/itemset.css b/src/timeline/component/css/itemset.css index f185baa4..0864aedf 100644 --- a/src/timeline/component/css/itemset.css +++ b/src/timeline/component/css/itemset.css @@ -22,3 +22,18 @@ .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; +} diff --git a/src/timeline/component/css/groupset.css b/src/timeline/component/css/labelset.css similarity index 64% rename from src/timeline/component/css/groupset.css rename to src/timeline/component/css/labelset.css index 69fb5a52..0daa809f 100644 --- a/src/timeline/component/css/groupset.css +++ b/src/timeline/component/css/labelset.css @@ -1,6 +1,3 @@ -.vis.timeline .groupset { - position: relative; -} .vis.timeline .labelset { position: relative; @@ -23,16 +20,12 @@ box-sizing: border-box; } -.vis.timeline.bottom .labelset .vlabel, -.vis.timeline.top .vpanel.side-content, -.vis.timeline.top .groupset .itemset { +.vis.timeline.top .labelset .vlabel { border-top: 1px solid #bfbfbf; border-bottom: none; } -.vis.timeline.top .labelset .vlabel, -.vis.timeline.bottom .vpanel.side-content, -.vis.timeline.bottom .groupset .itemset { +.vis.timeline.bottom .labelset .vlabel { border-top: none; border-bottom: 1px solid #bfbfbf; } diff --git a/src/timeline/component/item/Item.js b/src/timeline/component/item/Item.js index 0ca1b757..15b4d272 100644 --- a/src/timeline/component/item/Item.js +++ b/src/timeline/component/item/Item.js @@ -1,14 +1,14 @@ /** * @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 || {}; @@ -40,6 +40,33 @@ Item.prototype.unselect = function unselect() { 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; +}; + /** * Show the Item in the DOM (when not already visible) * @return {Boolean} changed @@ -80,13 +107,12 @@ Item.prototype.repositionY = function repositionY() { /** * 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'; @@ -95,7 +121,7 @@ Item.prototype._repaintDeleteButton = function (anchor) { Hammer(deleteButton, { preventDefault: true }).on('tap', function (event) { - parent.removeItem(id); + me.parent.removeFromDataSet(me); event.stopPropagation(); }); diff --git a/src/timeline/component/item/ItemBox.js b/src/timeline/component/item/ItemBox.js index 05aa8ffb..463814ff 100644 --- a/src/timeline/component/item/ItemBox.js +++ b/src/timeline/component/item/ItemBox.js @@ -1,14 +1,13 @@ /** * @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: { width: 0, @@ -27,10 +26,10 @@ function ItemBox (parent, data, options, defaultOptions) { } } - Item.call(this, parent, data, options, defaultOptions); + 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 diff --git a/src/timeline/component/item/ItemPoint.js b/src/timeline/component/item/ItemPoint.js index 3fe16be1..bccdebfe 100644 --- a/src/timeline/component/item/ItemPoint.js +++ b/src/timeline/component/item/ItemPoint.js @@ -1,14 +1,13 @@ /** * @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, @@ -28,10 +27,10 @@ function ItemPoint (parent, data, options, defaultOptions) { } } - Item.call(this, parent, data, options, defaultOptions); + 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 @@ -40,9 +39,10 @@ ItemPoint.prototype = new Item (null, null); */ ItemPoint.prototype.isVisible = function isVisible (range) { // determine visibility - var interval = (range.end - range.start); - return (this.data.start > range.start - interval) && (this.data.start < range.end); -} + // 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 @@ -121,10 +121,11 @@ ItemPoint.prototype.repaint = function repaint() { this.props.content.height = dom.content.offsetHeight; // resize contents - dom.content.style.marginLeft = 1.5 * this.props.dot.width + 'px'; + 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; } @@ -165,7 +166,7 @@ ItemPoint.prototype.hide = function hide() { ItemPoint.prototype.repositionX = function repositionX() { var start = this.defaultOptions.toScreen(this.data.start); - this.left = start - this.props.dot.width / 2; + this.left = start - this.props.dot.width; // reposition point this.dom.point.style.left = this.left + 'px'; @@ -187,4 +188,4 @@ ItemPoint.prototype.repositionY = function repositionY () { point.style.top = ''; point.style.bottom = this.top + 'px'; } -} +}; diff --git a/src/timeline/component/item/ItemRange.js b/src/timeline/component/item/ItemRange.js index 122e1304..6adb6acf 100644 --- a/src/timeline/component/item/ItemRange.js +++ b/src/timeline/component/item/ItemRange.js @@ -1,14 +1,13 @@ /** * @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: { width: 0 @@ -25,10 +24,10 @@ function ItemRange (parent, data, options, defaultOptions) { } } - Item.call(this, parent, data, options, defaultOptions); + Item.call(this, data, options, defaultOptions); } -ItemRange.prototype = new Item (null, null); +ItemRange.prototype = new Item (null); ItemRange.prototype.baseClassName = 'item range'; @@ -205,10 +204,10 @@ ItemRange.prototype.repositionY = function repositionY() { /** * 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'; @@ -235,10 +234,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'; diff --git a/src/timeline/component/item/ItemRangeOverflow.js b/src/timeline/component/item/ItemRangeOverflow.js index a94c7cab..156123f6 100644 --- a/src/timeline/component/item/ItemRangeOverflow.js +++ b/src/timeline/component/item/ItemRangeOverflow.js @@ -1,14 +1,13 @@ /** * @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, @@ -16,10 +15,10 @@ function ItemRangeOverflow (parent, data, options, defaultOptions) { } }; - 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'; diff --git a/src/timeline/stack.js b/src/timeline/stack.js new file mode 100644 index 00000000..97cee61c --- /dev/null +++ b/src/timeline/stack.js @@ -0,0 +1,112 @@ +/** + * 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); +}; diff --git a/test/timeline_groups.html b/test/timeline_groups.html index d6ad61b5..6dff9219 100644 --- a/test/timeline_groups.html +++ b/test/timeline_groups.html @@ -12,7 +12,6 @@ #visualization { box-sizing: border-box; width: 100%; - height: 300px; } @@ -49,7 +48,7 @@ var itemCount = 20; // create a data set with groups - var names = ['John', 'Alston', 'Lee', 'Grant']; + var names = ['John (0)', 'Alston (1)', 'Lee (2)', 'Grant (3)']; var groups = new vis.DataSet(); for (var g = 0; g < groupCount; g++) { groups.add({id: g, content: names[g]}); @@ -73,7 +72,13 @@ // create visualization var container = document.getElementById('visualization'); var options = { - editable: true, + editable: { + add: true, + remove: true, + updateTime: true, + updateGroup: true + }, + stack: false, //height: 200, groupOrder: 'content' };