From 1f6064b491c473d2b957aadadaa05bbc3e2393aa Mon Sep 17 00:00:00 2001 From: josdejong Date: Tue, 14 Jan 2014 17:29:19 +0100 Subject: [PATCH] Released version 0.3.0 --- dist/vis.css | 235 + dist/vis.js | 15765 ++++++++++++++++ dist/vis.min.js | 29 + docs/css/prettify.css | 102 +- docs/css/style.css | 78 +- docs/dataset.html | 1095 +- docs/dataview.html | 272 +- docs/graph.html | 1636 +- docs/index.html | 255 +- docs/timeline.html | 883 +- download/vis.zip | Bin 0 -> 941597 bytes examples/graph/01_basic_usage.html | 68 +- examples/graph/02_random_nodes.html | 168 +- examples/graph/03_images.html | 144 +- examples/graph/04_shapes.html | 114 +- examples/graph/05_social_network.html | 116 +- examples/graph/06_groups.html | 282 +- examples/graph/07_selections.html | 88 +- examples/graph/08_mobile_friendly.html | 174 +- examples/graph/09_sizing.html | 126 +- examples/graph/10_multiline_text.html | 72 +- examples/graph/11_custom_style.html | 228 +- examples/graph/12_scalable_images.html | 132 +- examples/graph/13_dashed_lines.html | 104 +- examples/graph/14_dot_language.html | 20 +- .../graph/15_dot_language_playground.html | 344 +- examples/graph/16_dynamic_data.html | 448 +- examples/graph/17_network_info.html | 280 +- examples/graph/graphviz/graphviz_gallery.html | 120 +- examples/graph/index.html | 42 +- examples/timeline/01_basic.html | 37 +- examples/timeline/02_dataset.html | 100 +- examples/timeline/03_much_data.html | 3 +- examples/timeline/04_html_data.html | 99 +- examples/timeline/05_groups.html | 101 +- examples/timeline/index.html | 16 +- .../timeline/requirejs/requirejs_example.html | 8 +- examples/timeline/requirejs/scripts/main.js | 28 +- index.html | 63 +- package.js | 0 updateversion.js | 78 +- vis.js | 14667 -------------- vis.min.js | 29 - 43 files changed, 19997 insertions(+), 18652 deletions(-) create mode 100644 dist/vis.css create mode 100644 dist/vis.js create mode 100644 dist/vis.min.js create mode 100644 download/vis.zip create mode 100644 package.js delete mode 100644 vis.js delete mode 100644 vis.min.js diff --git a/dist/vis.css b/dist/vis.css new file mode 100644 index 00000000..4f54a95f --- /dev/null +++ b/dist/vis.css @@ -0,0 +1,235 @@ +.vis.timeline { +} + + +.vis.timeline.rootpanel { + position: relative; + overflow: hidden; + + border: 1px solid #bfbfbf; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.vis.timeline .panel { + position: absolute; + overflow: hidden; +} + + +.vis.timeline .groupset { + position: absolute; + padding: 0; + margin: 0; +} + +.vis.timeline .labels { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + + padding: 0; + margin: 0; + + border-right: 1px solid #bfbfbf; + box-sizing: border-box; + -moz-box-sizing: border-box; +} + +.vis.timeline .labels .label-set { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + + overflow: hidden; + + border-top: none; + border-bottom: 1px solid #bfbfbf; +} + +.vis.timeline .labels .label-set .label { + position: absolute; + left: 0; + top: 0; + width: 100%; + color: #4d4d4d; +} + +.vis.timeline.top .labels .label-set .label, +.vis.timeline.top .groupset .itemset-axis { + border-top: 1px solid #bfbfbf; + border-bottom: none; +} + +.vis.timeline.bottom .labels .label-set .label, +.vis.timeline.bottom .groupset .itemset-axis { + border-top: none; + border-bottom: 1px solid #bfbfbf; +} + +.vis.timeline .labels .label-set .label .inner { + display: inline-block; + padding: 5px; +} + + +.vis.timeline .itemset { + position: absolute; + padding: 0; + margin: 0; + overflow: hidden; +} + +.vis.timeline .background { +} + +.vis.timeline .foreground { +} + +.vis.timeline .itemset-axis { + position: absolute; +} + + +.vis.timeline .item { + position: absolute; + color: #1A1A1A; + border-color: #97B0F8; + background-color: #D5DDF6; + display: inline-block; +} + +.vis.timeline .item.selected { + border-color: #FFC200; + background-color: #FFF785; + z-index: 999; +} + +.vis.timeline .item.cluster { + /* TODO: use another color or pattern? */ + background: #97B0F8 url('img/cluster_bg.png'); + color: white; +} +.vis.timeline .item.cluster.point { + border-color: #D5DDF6; +} + +.vis.timeline .item.box { + text-align: center; + border-style: solid; + border-width: 1px; + border-radius: 5px; + -moz-border-radius: 5px; /* For Firefox 3.6 and older */ +} + +.vis.timeline .item.point { + background: none; +} + +.vis.timeline .dot { + border: 5px solid #97B0F8; + position: absolute; + border-radius: 5px; + -moz-border-radius: 5px; /* For Firefox 3.6 and older */ +} + +.vis.timeline .item.range { + overflow: hidden; + border-style: solid; + border-width: 1px; + border-radius: 2px; + -moz-border-radius: 2px; /* For Firefox 3.6 and older */ +} + +.vis.timeline .item.rangeoverflow { + border-style: solid; + border-width: 1px; + border-radius: 2px; + -moz-border-radius: 2px; /* For Firefox 3.6 and older */ +} + +.vis.timeline .item.range .drag-left, .vis.timeline .item.rangeoverflow .drag-left { + cursor: w-resize; + z-index: 1000; +} + +.vis.timeline .item.range .drag-right, .vis.timeline .item.rangeoverflow .drag-right { + cursor: e-resize; + z-index: 1000; +} + +.vis.timeline .item.range .content, .vis.timeline .item.rangeoverflow .content { + position: relative; + display: inline-block; +} + +.vis.timeline .item.line { + position: absolute; + width: 0; + border-left-width: 1px; + border-left-style: solid; +} + +.vis.timeline .item .content { + margin: 5px; + white-space: nowrap; + overflow: hidden; +} + +.vis.timeline .axis { + position: relative; +} + +.vis.timeline .axis .text { + position: absolute; + color: #4d4d4d; + padding: 3px; + white-space: nowrap; +} + +.vis.timeline .axis .text.measure { + position: absolute; + padding-left: 0; + padding-right: 0; + margin-left: 0; + margin-right: 0; + visibility: hidden; +} + +.vis.timeline .axis .grid.vertical { + position: absolute; + width: 0; + border-right: 1px solid; +} + +.vis.timeline .axis .grid.horizontal { + position: absolute; + left: 0; + width: 100%; + height: 0; + border-bottom: 1px solid; +} + +.vis.timeline .axis .grid.minor { + border-color: #e5e5e5; +} + +.vis.timeline .axis .grid.major { + border-color: #bfbfbf; +} + +.vis.timeline .currenttime { + background-color: #FF7F6E; + width: 2px; + z-index: 9; +} +.vis.timeline .customtime { + background-color: #6E94FF; + width: 2px; + cursor: move; + z-index: 9; +} diff --git a/dist/vis.js b/dist/vis.js new file mode 100644 index 00000000..7594f2f9 --- /dev/null +++ b/dist/vis.js @@ -0,0 +1,15765 @@ +/** + * vis.js + * https://github.com/almende/vis + * + * A dynamic, browser-based visualization library. + * + * @version 0.3.0 + * @date 2014-01-14 + * + * @license + * Copyright (C) 2011-2013 Almende B.V, http://almende.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +!function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.vis=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o>> 0; + + // 4. If IsCallable(callback) is false, throw a TypeError exception. + // See: http://es5.github.com/#x9.11 + if (typeof callback !== "function") { + throw new TypeError(callback + " is not a function"); + } + + // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. + if (thisArg) { + T = thisArg; + } + + // 6. Let A be a new array created as if by the expression new Array(len) where Array is + // the standard built-in constructor with that name and len is the value of len. + A = new Array(len); + + // 7. Let k be 0 + k = 0; + + // 8. Repeat, while k < len + while(k < len) { + + var kValue, mappedValue; + + // a. Let Pk be ToString(k). + // This is implicit for LHS operands of the in operator + // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. + // This step can be combined with c + // c. If kPresent is true, then + if (k in O) { + + // i. Let kValue be the result of calling the Get internal method of O with argument Pk. + kValue = O[ k ]; + + // ii. Let mappedValue be the result of calling the Call internal method of callback + // with T as the this value and argument list containing kValue, k, and O. + mappedValue = callback.call(T, kValue, k, O); + + // iii. Call the DefineOwnProperty internal method of A with arguments + // Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true}, + // and false. + + // In browsers that support Object.defineProperty, use the following: + // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true }); + + // For best browser support, use the following: + A[ k ] = mappedValue; + } + // d. Increase k by 1. + k++; + } + + // 9. return A + return A; + }; +} + +// Internet Explorer 8 and older does not support Array.filter, so we define it +// here in that case. +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter +if (!Array.prototype.filter) { + Array.prototype.filter = function(fun /*, thisp */) { + "use strict"; + + if (this == null) { + throw new TypeError(); + } + + var t = Object(this); + var len = t.length >>> 0; + if (typeof fun != "function") { + throw new TypeError(); + } + + var res = []; + var thisp = arguments[1]; + for (var i = 0; i < len; i++) { + if (i in t) { + var val = t[i]; // in case fun mutates this + if (fun.call(thisp, val, i, t)) + res.push(val); + } + } + + return res; + }; +} + + +// Internet Explorer 8 and older does not support Object.keys, so we define it +// here in that case. +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys +if (!Object.keys) { + Object.keys = (function () { + var hasOwnProperty = Object.prototype.hasOwnProperty, + hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), + dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' + ], + dontEnumsLength = dontEnums.length; + + return function (obj) { + if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) { + throw new TypeError('Object.keys called on non-object'); + } + + var result = []; + + for (var prop in obj) { + if (hasOwnProperty.call(obj, prop)) result.push(prop); + } + + if (hasDontEnumBug) { + for (var i=0; i < dontEnumsLength; i++) { + if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]); + } + } + return result; + } + })() +} + +// Internet Explorer 8 and older does not support Array.isArray, +// so we define it here in that case. +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/isArray +if(!Array.isArray) { + Array.isArray = function (vArg) { + return Object.prototype.toString.call(vArg) === "[object Array]"; + }; +} + +// Internet Explorer 8 and older does not support Function.bind, +// so we define it here in that case. +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind +if (!Function.prototype.bind) { + Function.prototype.bind = function (oThis) { + if (typeof this !== "function") { + // closest thing possible to the ECMAScript 5 internal IsCallable function + throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); + } + + var aArgs = Array.prototype.slice.call(arguments, 1), + fToBind = this, + fNOP = function () {}, + fBound = function () { + return fToBind.apply(this instanceof fNOP && oThis + ? this + : oThis, + aArgs.concat(Array.prototype.slice.call(arguments))); + }; + + fNOP.prototype = this.prototype; + fBound.prototype = new fNOP(); + + return fBound; + }; +} + +// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create +if (!Object.create) { + Object.create = function (o) { + if (arguments.length > 1) { + throw new Error('Object.create implementation only accepts the first parameter.'); + } + function F() {} + F.prototype = o; + return new F(); + }; +} + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind +if (!Function.prototype.bind) { + Function.prototype.bind = function (oThis) { + if (typeof this !== "function") { + // closest thing possible to the ECMAScript 5 internal IsCallable function + throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); + } + + var aArgs = Array.prototype.slice.call(arguments, 1), + fToBind = this, + fNOP = function () {}, + fBound = function () { + return fToBind.apply(this instanceof fNOP && oThis + ? this + : oThis, + aArgs.concat(Array.prototype.slice.call(arguments))); + }; + + fNOP.prototype = this.prototype; + fBound.prototype = new fNOP(); + + return fBound; + }; +} + +/** + * utility functions + */ +var util = {}; + +/** + * Test whether given object is a number + * @param {*} object + * @return {Boolean} isNumber + */ +util.isNumber = function isNumber(object) { + return (object instanceof Number || typeof object == 'number'); +}; + +/** + * Test whether given object is a string + * @param {*} object + * @return {Boolean} isString + */ +util.isString = function isString(object) { + return (object instanceof String || typeof object == 'string'); +}; + +/** + * Test whether given object is a Date, or a String containing a Date + * @param {Date | String} object + * @return {Boolean} isDate + */ +util.isDate = function isDate(object) { + if (object instanceof Date) { + return true; + } + else if (util.isString(object)) { + // test whether this string contains a date + var match = ASPDateRegex.exec(object); + if (match) { + return true; + } + else if (!isNaN(Date.parse(object))) { + return true; + } + } + + return false; +}; + +/** + * Test whether given object is an instance of google.visualization.DataTable + * @param {*} object + * @return {Boolean} isDataTable + */ +util.isDataTable = function isDataTable(object) { + return (typeof (google) !== 'undefined') && + (google.visualization) && + (google.visualization.DataTable) && + (object instanceof google.visualization.DataTable); +}; + +/** + * Create a semi UUID + * source: http://stackoverflow.com/a/105074/1262753 + * @return {String} uuid + */ +util.randomUUID = function randomUUID () { + var S4 = function () { + return Math.floor( + Math.random() * 0x10000 /* 65536 */ + ).toString(16); + }; + + return ( + S4() + S4() + '-' + + S4() + '-' + + S4() + '-' + + S4() + '-' + + S4() + S4() + S4() + ); +}; + +/** + * Extend object a with the properties of object b or a series of objects + * Only properties with defined values are copied + * @param {Object} a + * @param {... Object} b + * @return {Object} a + */ +util.extend = function (a, b) { + for (var i = 1, len = arguments.length; i < len; i++) { + var other = arguments[i]; + for (var prop in other) { + if (other.hasOwnProperty(prop) && other[prop] !== undefined) { + a[prop] = other[prop]; + } + } + } + + return a; +}; + +/** + * Convert an object to another type + * @param {Boolean | Number | String | Date | Moment | Null | undefined} object + * @param {String | undefined} type Name of the type. Available types: + * 'Boolean', 'Number', 'String', + * 'Date', 'Moment', ISODate', 'ASPDate'. + * @return {*} object + * @throws Error + */ +util.convert = function convert(object, type) { + var match; + + if (object === undefined) { + return undefined; + } + if (object === null) { + return null; + } + + if (!type) { + return object; + } + if (!(typeof type === 'string') && !(type instanceof String)) { + throw new Error('Type must be a string'); + } + + //noinspection FallthroughInSwitchStatementJS + switch (type) { + case 'boolean': + case 'Boolean': + return Boolean(object); + + case 'number': + case 'Number': + return Number(object.valueOf()); + + case 'string': + case 'String': + return String(object); + + case 'Date': + if (util.isNumber(object)) { + return new Date(object); + } + if (object instanceof Date) { + return new Date(object.valueOf()); + } + else if (moment.isMoment(object)) { + return new Date(object.valueOf()); + } + if (util.isString(object)) { + match = ASPDateRegex.exec(object); + if (match) { + // object is an ASP date + return new Date(Number(match[1])); // parse number + } + else { + return moment(object).toDate(); // parse string + } + } + else { + throw new Error( + 'Cannot convert object of type ' + util.getType(object) + + ' to type Date'); + } + + case 'Moment': + if (util.isNumber(object)) { + return moment(object); + } + if (object instanceof Date) { + return moment(object.valueOf()); + } + else if (moment.isMoment(object)) { + return moment(object); + } + if (util.isString(object)) { + match = ASPDateRegex.exec(object); + if (match) { + // object is an ASP date + return moment(Number(match[1])); // parse number + } + else { + return moment(object); // parse string + } + } + else { + throw new Error( + 'Cannot convert object of type ' + util.getType(object) + + ' to type Date'); + } + + case 'ISODate': + if (util.isNumber(object)) { + return new Date(object); + } + else if (object instanceof Date) { + return object.toISOString(); + } + else if (moment.isMoment(object)) { + return object.toDate().toISOString(); + } + else if (util.isString(object)) { + match = ASPDateRegex.exec(object); + if (match) { + // object is an ASP date + return new Date(Number(match[1])).toISOString(); // parse number + } + else { + return new Date(object).toISOString(); // parse string + } + } + else { + throw new Error( + 'Cannot convert object of type ' + util.getType(object) + + ' to type ISODate'); + } + + case 'ASPDate': + if (util.isNumber(object)) { + return '/Date(' + object + ')/'; + } + else if (object instanceof Date) { + return '/Date(' + object.valueOf() + ')/'; + } + else if (util.isString(object)) { + match = ASPDateRegex.exec(object); + var value; + if (match) { + // object is an ASP date + value = new Date(Number(match[1])).valueOf(); // parse number + } + else { + value = new Date(object).valueOf(); // parse string + } + return '/Date(' + value + ')/'; + } + else { + throw new Error( + 'Cannot convert object of type ' + util.getType(object) + + ' to type ASPDate'); + } + + default: + throw new Error('Cannot convert object of type ' + util.getType(object) + + ' to type "' + type + '"'); + } +}; + +// parse ASP.Net Date pattern, +// for example '/Date(1198908717056)/' or '/Date(1198908717056-0700)/' +// code from http://momentjs.com/ +var ASPDateRegex = /^\/?Date\((\-?\d+)/i; + +/** + * Get the type of an object, for example util.getType([]) returns 'Array' + * @param {*} object + * @return {String} type + */ +util.getType = function getType(object) { + var type = typeof object; + + if (type == 'object') { + if (object == null) { + return 'null'; + } + if (object instanceof Boolean) { + return 'Boolean'; + } + if (object instanceof Number) { + return 'Number'; + } + if (object instanceof String) { + return 'String'; + } + if (object instanceof Array) { + return 'Array'; + } + if (object instanceof Date) { + return 'Date'; + } + return 'Object'; + } + else if (type == 'number') { + return 'Number'; + } + else if (type == 'boolean') { + return 'Boolean'; + } + else if (type == 'string') { + return 'String'; + } + + return type; +}; + +/** + * Retrieve the absolute left value of a DOM element + * @param {Element} elem A dom element, for example a div + * @return {number} left The absolute left position of this element + * in the browser page. + */ +util.getAbsoluteLeft = function getAbsoluteLeft (elem) { + var doc = document.documentElement; + var body = document.body; + + var left = elem.offsetLeft; + var e = elem.offsetParent; + while (e != null && e != body && e != doc) { + left += e.offsetLeft; + left -= e.scrollLeft; + e = e.offsetParent; + } + return left; +}; + +/** + * Retrieve the absolute top value of a DOM element + * @param {Element} elem A dom element, for example a div + * @return {number} top The absolute top position of this element + * in the browser page. + */ +util.getAbsoluteTop = function getAbsoluteTop (elem) { + var doc = document.documentElement; + var body = document.body; + + var top = elem.offsetTop; + var e = elem.offsetParent; + while (e != null && e != body && e != doc) { + top += e.offsetTop; + top -= e.scrollTop; + e = e.offsetParent; + } + return top; +}; + +/** + * Get the absolute, vertical mouse position from an event. + * @param {Event} event + * @return {Number} pageY + */ +util.getPageY = function getPageY (event) { + if ('pageY' in event) { + return event.pageY; + } + else { + var clientY; + if (('targetTouches' in event) && event.targetTouches.length) { + clientY = event.targetTouches[0].clientY; + } + else { + clientY = event.clientY; + } + + var doc = document.documentElement; + var body = document.body; + return clientY + + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - + ( doc && doc.clientTop || body && body.clientTop || 0 ); + } +}; + +/** + * Get the absolute, horizontal mouse position from an event. + * @param {Event} event + * @return {Number} pageX + */ +util.getPageX = function getPageX (event) { + if ('pageY' in event) { + return event.pageX; + } + else { + var clientX; + if (('targetTouches' in event) && event.targetTouches.length) { + clientX = event.targetTouches[0].clientX; + } + else { + clientX = event.clientX; + } + + var doc = document.documentElement; + var body = document.body; + return clientX + + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - + ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + } +}; + +/** + * add a className to the given elements style + * @param {Element} elem + * @param {String} className + */ +util.addClassName = function addClassName(elem, className) { + var classes = elem.className.split(' '); + if (classes.indexOf(className) == -1) { + classes.push(className); // add the class to the array + elem.className = classes.join(' '); + } +}; + +/** + * add a className to the given elements style + * @param {Element} elem + * @param {String} className + */ +util.removeClassName = function removeClassname(elem, className) { + var classes = elem.className.split(' '); + var index = classes.indexOf(className); + if (index != -1) { + classes.splice(index, 1); // remove the class from the array + elem.className = classes.join(' '); + } +}; + +/** + * For each method for both arrays and objects. + * In case of an array, the built-in Array.forEach() is applied. + * In case of an Object, the method loops over all properties of the object. + * @param {Object | Array} object An Object or Array + * @param {function} callback Callback method, called for each item in + * the object or array with three parameters: + * callback(value, index, object) + */ +util.forEach = function forEach (object, callback) { + var i, + len; + if (object instanceof Array) { + // array + for (i = 0, len = object.length; i < len; i++) { + callback(object[i], i, object); + } + } + else { + // object + for (i in object) { + if (object.hasOwnProperty(i)) { + callback(object[i], i, object); + } + } + } +}; + +/** + * Update a property in an object + * @param {Object} object + * @param {String} key + * @param {*} value + * @return {Boolean} changed + */ +util.updateProperty = function updateProp (object, key, value) { + if (object[key] !== value) { + object[key] = value; + return true; + } + else { + return false; + } +}; + +/** + * Add and event listener. Works for all browsers + * @param {Element} element An html element + * @param {string} action The action, for example "click", + * without the prefix "on" + * @param {function} listener The callback function to be executed + * @param {boolean} [useCapture] + */ +util.addEventListener = function addEventListener(element, action, listener, useCapture) { + if (element.addEventListener) { + if (useCapture === undefined) + useCapture = false; + + if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) { + action = "DOMMouseScroll"; // For Firefox + } + + element.addEventListener(action, listener, useCapture); + } else { + element.attachEvent("on" + action, listener); // IE browsers + } +}; + +/** + * Remove an event listener from an element + * @param {Element} element An html dom element + * @param {string} action The name of the event, for example "mousedown" + * @param {function} listener The listener function + * @param {boolean} [useCapture] + */ +util.removeEventListener = function removeEventListener(element, action, listener, useCapture) { + if (element.removeEventListener) { + // non-IE browsers + if (useCapture === undefined) + useCapture = false; + + if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) { + action = "DOMMouseScroll"; // For Firefox + } + + element.removeEventListener(action, listener, useCapture); + } else { + // IE browsers + element.detachEvent("on" + action, listener); + } +}; + + +/** + * Get HTML element which is the target of the event + * @param {Event} event + * @return {Element} target element + */ +util.getTarget = function getTarget(event) { + // code from http://www.quirksmode.org/js/events_properties.html + if (!event) { + event = window.event; + } + + var target; + + if (event.target) { + target = event.target; + } + else if (event.srcElement) { + target = event.srcElement; + } + + if (target.nodeType != undefined && target.nodeType == 3) { + // defeat Safari bug + target = target.parentNode; + } + + return target; +}; + +/** + * Stop event propagation + */ +util.stopPropagation = function stopPropagation(event) { + if (!event) + event = window.event; + + if (event.stopPropagation) { + event.stopPropagation(); // non-IE browsers + } + else { + event.cancelBubble = true; // IE browsers + } +}; + +/** + * Fake a hammer.js gesture. Event can be a ScrollEvent or MouseMoveEvent + * @param {Element} element + * @param {Event} event + */ +util.fakeGesture = function fakeGesture (element, event) { + var eventType = null; + + // for hammer.js 1.0.5 + return Hammer.event.collectEventData(this, eventType, event); + + // for hammer.js 1.0.6 + //var touches = Hammer.event.getTouchList(event, eventType); + //return Hammer.event.collectEventData(this, eventType, touches, event); +}; + +/** + * Cancels the event if it is cancelable, without stopping further propagation of the event. + */ +util.preventDefault = function preventDefault (event) { + if (!event) + event = window.event; + + if (event.preventDefault) { + event.preventDefault(); // non-IE browsers + } + else { + event.returnValue = false; // IE browsers + } +}; + + +util.option = {}; + +/** + * Convert a value into a boolean + * @param {Boolean | function | undefined} value + * @param {Boolean} [defaultValue] + * @returns {Boolean} bool + */ +util.option.asBoolean = function (value, defaultValue) { + if (typeof value == 'function') { + value = value(); + } + + if (value != null) { + return (value != false); + } + + return defaultValue || null; +}; + +/** + * Convert a value into a number + * @param {Boolean | function | undefined} value + * @param {Number} [defaultValue] + * @returns {Number} number + */ +util.option.asNumber = function (value, defaultValue) { + if (typeof value == 'function') { + value = value(); + } + + if (value != null) { + return Number(value) || defaultValue || null; + } + + return defaultValue || null; +}; + +/** + * Convert a value into a string + * @param {String | function | undefined} value + * @param {String} [defaultValue] + * @returns {String} str + */ +util.option.asString = function (value, defaultValue) { + if (typeof value == 'function') { + value = value(); + } + + if (value != null) { + return String(value); + } + + return defaultValue || null; +}; + +/** + * Convert a size or location into a string with pixels or a percentage + * @param {String | Number | function | undefined} value + * @param {String} [defaultValue] + * @returns {String} size + */ +util.option.asSize = function (value, defaultValue) { + if (typeof value == 'function') { + value = value(); + } + + if (util.isString(value)) { + return value; + } + else if (util.isNumber(value)) { + return value + 'px'; + } + else { + return defaultValue || null; + } +}; + +/** + * Convert a value into a DOM element + * @param {HTMLElement | function | undefined} value + * @param {HTMLElement} [defaultValue] + * @returns {HTMLElement | null} dom + */ +util.option.asElement = function (value, defaultValue) { + if (typeof value == 'function') { + value = value(); + } + + return value || defaultValue || null; +}; + +/** + * Event listener (singleton) + */ +// TODO: replace usage of the event listener for the EventBus +var events = { + 'listeners': [], + + /** + * Find a single listener by its object + * @param {Object} object + * @return {Number} index -1 when not found + */ + 'indexOf': function (object) { + var listeners = this.listeners; + for (var i = 0, iMax = this.listeners.length; i < iMax; i++) { + var listener = listeners[i]; + if (listener && listener.object == object) { + return i; + } + } + return -1; + }, + + /** + * Add an event listener + * @param {Object} object + * @param {String} event The name of an event, for example 'select' + * @param {function} callback The callback method, called when the + * event takes place + */ + 'addListener': function (object, event, callback) { + var index = this.indexOf(object); + var listener = this.listeners[index]; + if (!listener) { + listener = { + 'object': object, + 'events': {} + }; + this.listeners.push(listener); + } + + var callbacks = listener.events[event]; + if (!callbacks) { + callbacks = []; + listener.events[event] = callbacks; + } + + // add the callback if it does not yet exist + if (callbacks.indexOf(callback) == -1) { + callbacks.push(callback); + } + }, + + /** + * Remove an event listener + * @param {Object} object + * @param {String} event The name of an event, for example 'select' + * @param {function} callback The registered callback method + */ + 'removeListener': function (object, event, callback) { + var index = this.indexOf(object); + var listener = this.listeners[index]; + if (listener) { + var callbacks = listener.events[event]; + if (callbacks) { + index = callbacks.indexOf(callback); + if (index != -1) { + callbacks.splice(index, 1); + } + + // remove the array when empty + if (callbacks.length == 0) { + delete listener.events[event]; + } + } + + // count the number of registered events. remove listener when empty + var count = 0; + var events = listener.events; + for (var e in events) { + if (events.hasOwnProperty(e)) { + count++; + } + } + if (count == 0) { + delete this.listeners[index]; + } + } + }, + + /** + * Remove all registered event listeners + */ + 'removeAllListeners': function () { + this.listeners = []; + }, + + /** + * Trigger an event. All registered event handlers will be called + * @param {Object} object + * @param {String} event + * @param {Object} properties (optional) + */ + 'trigger': function (object, event, properties) { + var index = this.indexOf(object); + var listener = this.listeners[index]; + if (listener) { + var callbacks = listener.events[event]; + if (callbacks) { + for (var i = 0, iMax = callbacks.length; i < iMax; i++) { + callbacks[i](properties); + } + } + } + } +}; + +/** + * An event bus can be used to emit events, and to subscribe to events + * @constructor EventBus + */ +function EventBus() { + this.subscriptions = []; +} + +/** + * Subscribe to an event + * @param {String | RegExp} event The event can be a regular expression, or + * a string with wildcards, like 'server.*'. + * @param {function} callback. Callback are called with three parameters: + * {String} event, {*} [data], {*} [source] + * @param {*} [target] + * @returns {String} id A subscription id + */ +EventBus.prototype.on = function (event, callback, target) { + var regexp = (event instanceof RegExp) ? + event : + new RegExp(event.replace('*', '\\w+')); + + var subscription = { + id: util.randomUUID(), + event: event, + regexp: regexp, + callback: (typeof callback === 'function') ? callback : null, + target: target + }; + + this.subscriptions.push(subscription); + + return subscription.id; +}; + +/** + * Unsubscribe from an event + * @param {String | Object} filter Filter for subscriptions to be removed + * Filter can be a string containing a + * subscription id, or an object containing + * one or more of the fields id, event, + * callback, and target. + */ +EventBus.prototype.off = function (filter) { + var i = 0; + while (i < this.subscriptions.length) { + var subscription = this.subscriptions[i]; + + var match = true; + if (filter instanceof Object) { + // filter is an object. All fields must match + for (var prop in filter) { + if (filter.hasOwnProperty(prop)) { + if (filter[prop] !== subscription[prop]) { + match = false; + } + } + } + } + else { + // filter is a string, filter on id + match = (subscription.id == filter); + } + + if (match) { + this.subscriptions.splice(i, 1); + } + else { + i++; + } + } +}; + +/** + * Emit an event + * @param {String} event + * @param {*} [data] + * @param {*} [source] + */ +EventBus.prototype.emit = function (event, data, source) { + for (var i =0; i < this.subscriptions.length; i++) { + var subscription = this.subscriptions[i]; + if (subscription.regexp.test(event)) { + if (subscription.callback) { + subscription.callback(event, data, source); + } + } + } +}; + +/** + * DataSet + * + * Usage: + * var dataSet = new DataSet({ + * fieldId: '_id', + * convert: { + * // ... + * } + * }); + * + * dataSet.add(item); + * dataSet.add(data); + * dataSet.update(item); + * dataSet.update(data); + * dataSet.remove(id); + * dataSet.remove(ids); + * var data = dataSet.get(); + * var data = dataSet.get(id); + * var data = dataSet.get(ids); + * var data = dataSet.get(ids, options, data); + * dataSet.clear(); + * + * A data set can: + * - add/remove/update data + * - gives triggers upon changes in the data + * - can import/export data in various data formats + * + * @param {Object} [options] Available options: + * {String} fieldId Field name of the id in the + * items, 'id' by default. + * {Object.} [convert] + * {String[]} [fields] field names to be returned + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * {Array | DataTable} [data] If provided, items will be appended to this + * array or table. Required in case of Google + * DataTable. + * + * @throws Error + */ +DataSet.prototype.get = function (args) { + var me = this; + + // parse the arguments + var id, ids, options, data; + var firstType = util.getType(arguments[0]); + if (firstType == 'String' || firstType == 'Number') { + // get(id [, options] [, data]) + id = arguments[0]; + options = arguments[1]; + data = arguments[2]; + } + else if (firstType == 'Array') { + // get(ids [, options] [, data]) + ids = arguments[0]; + options = arguments[1]; + data = arguments[2]; + } + else { + // get([, options] [, data]) + options = arguments[0]; + data = arguments[1]; + } + + // determine the return type + var type; + if (options && options.type) { + type = (options.type == 'DataTable') ? 'DataTable' : 'Array'; + + if (data && (type != util.getType(data))) { + throw new Error('Type of parameter "data" (' + util.getType(data) + ') ' + + 'does not correspond with specified options.type (' + options.type + ')'); + } + if (type == 'DataTable' && !util.isDataTable(data)) { + throw new Error('Parameter "data" must be a DataTable ' + + 'when options.type is "DataTable"'); + } + } + else if (data) { + type = (util.getType(data) == 'DataTable') ? 'DataTable' : 'Array'; + } + else { + type = 'Array'; + } + + // build options + var convert = options && options.convert || this.options.convert; + var filter = options && options.filter; + var items = [], item, itemId, i, len; + + // convert items + if (id != undefined) { + // return a single item + item = me._getItem(id, convert); + if (filter && !filter(item)) { + item = null; + } + } + else if (ids != undefined) { + // return a subset of items + for (i = 0, len = ids.length; i < len; i++) { + item = me._getItem(ids[i], convert); + if (!filter || filter(item)) { + items.push(item); + } + } + } + else { + // return all items + for (itemId in this.data) { + if (this.data.hasOwnProperty(itemId)) { + item = me._getItem(itemId, convert); + if (!filter || filter(item)) { + items.push(item); + } + } + } + } + + // order the results + if (options && options.order && id == undefined) { + this._sort(items, options.order); + } + + // filter fields of the items + if (options && options.fields) { + var fields = options.fields; + if (id != undefined) { + item = this._filterFields(item, fields); + } + else { + for (i = 0, len = items.length; i < len; i++) { + items[i] = this._filterFields(items[i], fields); + } + } + } + + // return the results + if (type == 'DataTable') { + var columns = this._getColumnNames(data); + if (id != undefined) { + // append a single item to the data table + me._appendRow(data, columns, item); + } + else { + // copy the items to the provided data table + for (i = 0, len = items.length; i < len; i++) { + me._appendRow(data, columns, items[i]); + } + } + return data; + } + else { + // return an array + if (id != undefined) { + // a single item + return item; + } + else { + // multiple items + if (data) { + // copy the items to the provided array + for (i = 0, len = items.length; i < len; i++) { + data.push(items[i]); + } + return data; + } + else { + // just return our array + return items; + } + } + } +}; + +/** + * Get ids of all items or from a filtered set of items. + * @param {Object} [options] An Object with options. Available options: + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * @return {Array} ids + */ +DataSet.prototype.getIds = function (options) { + var data = this.data, + filter = options && options.filter, + order = options && options.order, + convert = options && options.convert || this.options.convert, + i, + len, + id, + item, + items, + ids = []; + + if (filter) { + // get filtered items + if (order) { + // create ordered list + items = []; + for (id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, convert); + if (filter(item)) { + items.push(item); + } + } + } + + this._sort(items, order); + + for (i = 0, len = items.length; i < len; i++) { + ids[i] = items[i][this.fieldId]; + } + } + else { + // create unordered list + for (id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, convert); + if (filter(item)) { + ids.push(item[this.fieldId]); + } + } + } + } + } + else { + // get all items + if (order) { + // create an ordered list + items = []; + for (id in data) { + if (data.hasOwnProperty(id)) { + items.push(data[id]); + } + } + + this._sort(items, order); + + for (i = 0, len = items.length; i < len; i++) { + ids[i] = items[i][this.fieldId]; + } + } + else { + // create unordered list + for (id in data) { + if (data.hasOwnProperty(id)) { + item = data[id]; + ids.push(item[this.fieldId]); + } + } + } + } + + return ids; +}; + +/** + * Execute a callback function for every item in the dataset. + * The order of the items is not determined. + * @param {function} callback + * @param {Object} [options] Available options: + * {Object.} [convert] + * {String[]} [fields] filter fields + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + */ +DataSet.prototype.forEach = function (callback, options) { + var filter = options && options.filter, + convert = options && options.convert || this.options.convert, + data = this.data, + item, + id; + + if (options && options.order) { + // execute forEach on ordered list + var items = this.get(options); + + for (var i = 0, len = items.length; i < len; i++) { + item = items[i]; + id = item[this.fieldId]; + callback(item, id); + } + } + else { + // unordered + for (id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, convert); + if (!filter || filter(item)) { + callback(item, id); + } + } + } + } +}; + +/** + * Map every item in the dataset. + * @param {function} callback + * @param {Object} [options] Available options: + * {Object.} [convert] + * {String[]} [fields] filter fields + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * @return {Object[]} mappedItems + */ +DataSet.prototype.map = function (callback, options) { + var filter = options && options.filter, + convert = options && options.convert || this.options.convert, + mappedItems = [], + data = this.data, + item; + + // convert and filter items + for (var id in data) { + if (data.hasOwnProperty(id)) { + item = this._getItem(id, convert); + if (!filter || filter(item)) { + mappedItems.push(callback(item, id)); + } + } + } + + // order items + if (options && options.order) { + this._sort(mappedItems, options.order); + } + + return mappedItems; +}; + +/** + * Filter the fields of an item + * @param {Object} item + * @param {String[]} fields Field names + * @return {Object} filteredItem + * @private + */ +DataSet.prototype._filterFields = function (item, fields) { + var filteredItem = {}; + + for (var field in item) { + if (item.hasOwnProperty(field) && (fields.indexOf(field) != -1)) { + filteredItem[field] = item[field]; + } + } + + return filteredItem; +}; + +/** + * Sort the provided array with items + * @param {Object[]} items + * @param {String | function} order A field name or custom sort function. + * @private + */ +DataSet.prototype._sort = function (items, order) { + if (util.isString(order)) { + // order by provided field name + var name = order; // field name + items.sort(function (a, b) { + var av = a[name]; + var bv = b[name]; + return (av > bv) ? 1 : ((av < bv) ? -1 : 0); + }); + } + else if (typeof order === 'function') { + // order by sort function + items.sort(order); + } + // TODO: extend order by an Object {field:String, direction:String} + // where direction can be 'asc' or 'desc' + else { + throw new TypeError('Order must be a function or a string'); + } +}; + +/** + * Remove an object by pointer or by id + * @param {String | Number | Object | Array} id Object or id, or an array with + * objects or ids to be removed + * @param {String} [senderId] Optional sender id + * @return {Array} removedIds + */ +DataSet.prototype.remove = function (id, senderId) { + var removedIds = [], + i, len, removedId; + + if (id instanceof Array) { + for (i = 0, len = id.length; i < len; i++) { + removedId = this._remove(id[i]); + if (removedId != null) { + removedIds.push(removedId); + } + } + } + else { + removedId = this._remove(id); + if (removedId != null) { + removedIds.push(removedId); + } + } + + if (removedIds.length) { + this._trigger('remove', {items: removedIds}, senderId); + } + + return removedIds; +}; + +/** + * Remove an item by its id + * @param {Number | String | Object} id id or item + * @returns {Number | String | null} id + * @private + */ +DataSet.prototype._remove = function (id) { + if (util.isNumber(id) || util.isString(id)) { + if (this.data[id]) { + delete this.data[id]; + delete this.internalIds[id]; + return id; + } + } + else if (id instanceof Object) { + var itemId = id[this.fieldId]; + if (itemId && this.data[itemId]) { + delete this.data[itemId]; + delete this.internalIds[itemId]; + return itemId; + } + } + return null; +}; + +/** + * Clear the data + * @param {String} [senderId] Optional sender id + * @return {Array} removedIds The ids of all removed items + */ +DataSet.prototype.clear = function (senderId) { + var ids = Object.keys(this.data); + + this.data = {}; + this.internalIds = {}; + + this._trigger('remove', {items: ids}, senderId); + + return ids; +}; + +/** + * Find the item with maximum value of a specified field + * @param {String} field + * @return {Object | null} item Item containing max value, or null if no items + */ +DataSet.prototype.max = function (field) { + var data = this.data, + max = null, + maxField = null; + + for (var id in data) { + if (data.hasOwnProperty(id)) { + var item = data[id]; + var itemField = item[field]; + if (itemField != null && (!max || itemField > maxField)) { + max = item; + maxField = itemField; + } + } + } + + return max; +}; + +/** + * Find the item with minimum value of a specified field + * @param {String} field + * @return {Object | null} item Item containing max value, or null if no items + */ +DataSet.prototype.min = function (field) { + var data = this.data, + min = null, + minField = null; + + for (var id in data) { + if (data.hasOwnProperty(id)) { + var item = data[id]; + var itemField = item[field]; + if (itemField != null && (!min || itemField < minField)) { + min = item; + minField = itemField; + } + } + } + + return min; +}; + +/** + * Find all distinct values of a specified field + * @param {String} field + * @return {Array} values Array containing all distinct values. If the data + * items do not contain the specified field, an array + * containing a single value undefined is returned. + * The returned array is unordered. + */ +DataSet.prototype.distinct = function (field) { + var data = this.data, + values = [], + fieldType = this.options.convert[field], + count = 0; + + for (var prop in data) { + if (data.hasOwnProperty(prop)) { + var item = data[prop]; + var value = util.convert(item[field], fieldType); + var exists = false; + for (var i = 0; i < count; i++) { + if (values[i] == value) { + exists = true; + break; + } + } + if (!exists) { + values[count] = value; + count++; + } + } + } + + return values; +}; + +/** + * Add a single item. Will fail when an item with the same id already exists. + * @param {Object} item + * @return {String} id + * @private + */ +DataSet.prototype._addItem = function (item) { + var id = item[this.fieldId]; + + if (id != undefined) { + // check whether this id is already taken + if (this.data[id]) { + // item already exists + throw new Error('Cannot add item: item with id ' + id + ' already exists'); + } + } + else { + // generate an id + id = util.randomUUID(); + item[this.fieldId] = id; + this.internalIds[id] = item; + } + + var d = {}; + for (var field in item) { + if (item.hasOwnProperty(field)) { + var fieldType = this.convert[field]; // type may be undefined + d[field] = util.convert(item[field], fieldType); + } + } + this.data[id] = d; + + return id; +}; + +/** + * Get an item. Fields can be converted to a specific type + * @param {String} id + * @param {Object.} [convert] field types to convert + * @return {Object | null} item + * @private + */ +DataSet.prototype._getItem = function (id, convert) { + var field, value; + + // get the item from the dataset + var raw = this.data[id]; + if (!raw) { + return null; + } + + // convert the items field types + var converted = {}, + fieldId = this.fieldId, + internalIds = this.internalIds; + if (convert) { + for (field in raw) { + if (raw.hasOwnProperty(field)) { + value = raw[field]; + // output all fields, except internal ids + if ((field != fieldId) || !(value in internalIds)) { + converted[field] = util.convert(value, convert[field]); + } + } + } + } + else { + // no field types specified, no converting needed + for (field in raw) { + if (raw.hasOwnProperty(field)) { + value = raw[field]; + // output all fields, except internal ids + if ((field != fieldId) || !(value in internalIds)) { + converted[field] = value; + } + } + } + } + + return converted; +}; + +/** + * Update a single item: merge with existing item. + * Will fail when the item has no id, or when there does not exist an item + * with the same id. + * @param {Object} item + * @return {String} id + * @private + */ +DataSet.prototype._updateItem = function (item) { + var id = item[this.fieldId]; + if (id == undefined) { + throw new Error('Cannot update item: item has no id (item: ' + JSON.stringify(item) + ')'); + } + var d = this.data[id]; + if (!d) { + // item doesn't exist + throw new Error('Cannot update item: no item with id ' + id + ' found'); + } + + // merge with current item + for (var field in item) { + if (item.hasOwnProperty(field)) { + var fieldType = this.convert[field]; // type may be undefined + d[field] = util.convert(item[field], fieldType); + } + } + + return id; +}; + +/** + * Get an array with the column names of a Google DataTable + * @param {DataTable} dataTable + * @return {String[]} columnNames + * @private + */ +DataSet.prototype._getColumnNames = function (dataTable) { + var columns = []; + for (var col = 0, cols = dataTable.getNumberOfColumns(); col < cols; col++) { + columns[col] = dataTable.getColumnId(col) || dataTable.getColumnLabel(col); + } + return columns; +}; + +/** + * Append an item as a row to the dataTable + * @param dataTable + * @param columns + * @param item + * @private + */ +DataSet.prototype._appendRow = function (dataTable, columns, item) { + var row = dataTable.addRow(); + + for (var col = 0, cols = columns.length; col < cols; col++) { + var field = columns[col]; + dataTable.setValue(row, col, item[field]); + } +}; + +/** + * DataView + * + * a dataview offers a filtered view on a dataset or an other dataview. + * + * @param {DataSet | DataView} data + * @param {Object} [options] Available options: see method get + * + * @constructor DataView + */ +function DataView (data, options) { + this.id = util.randomUUID(); + + this.data = null; + this.ids = {}; // ids of the items currently in memory (just contains a boolean true) + this.options = options || {}; + this.fieldId = 'id'; // name of the field containing id + this.subscribers = {}; // event subscribers + + var me = this; + this.listener = function () { + me._onEvent.apply(me, arguments); + }; + + this.setData(data); +} + +// TODO: implement a function .config() to dynamically update things like configured filter +// and trigger changes accordingly + +/** + * Set a data source for the view + * @param {DataSet | DataView} data + */ +DataView.prototype.setData = function (data) { + var ids, dataItems, i, len; + + if (this.data) { + // unsubscribe from current dataset + if (this.data.unsubscribe) { + this.data.unsubscribe('*', this.listener); + } + + // trigger a remove of all items in memory + ids = []; + for (var id in this.ids) { + if (this.ids.hasOwnProperty(id)) { + ids.push(id); + } + } + this.ids = {}; + this._trigger('remove', {items: ids}); + } + + this.data = data; + + if (this.data) { + // update fieldId + this.fieldId = this.options.fieldId || + (this.data && this.data.options && this.data.options.fieldId) || + 'id'; + + // trigger an add of all added items + ids = this.data.getIds({filter: this.options && this.options.filter}); + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + this.ids[id] = true; + } + this._trigger('add', {items: ids}); + + // subscribe to new dataset + if (this.data.subscribe) { + this.data.subscribe('*', this.listener); + } + } +}; + +/** + * Get data from the data view + * + * Usage: + * + * get() + * get(options: Object) + * get(options: Object, data: Array | DataTable) + * + * get(id: Number) + * get(id: Number, options: Object) + * get(id: Number, options: Object, data: Array | DataTable) + * + * get(ids: Number[]) + * get(ids: Number[], options: Object) + * get(ids: Number[], options: Object, data: Array | DataTable) + * + * Where: + * + * {Number | String} id The id of an item + * {Number[] | String{}} ids An array with ids of items + * {Object} options An Object with options. Available options: + * {String} [type] Type of data to be returned. Can + * be 'DataTable' or 'Array' (default) + * {Object.} [convert] + * {String[]} [fields] field names to be returned + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * {Array | DataTable} [data] If provided, items will be appended to this + * array or table. Required in case of Google + * DataTable. + * @param args + */ +DataView.prototype.get = function (args) { + var me = this; + + // parse the arguments + var ids, options, data; + var firstType = util.getType(arguments[0]); + if (firstType == 'String' || firstType == 'Number' || firstType == 'Array') { + // get(id(s) [, options] [, data]) + ids = arguments[0]; // can be a single id or an array with ids + options = arguments[1]; + data = arguments[2]; + } + else { + // get([, options] [, data]) + options = arguments[0]; + data = arguments[1]; + } + + // extend the options with the default options and provided options + var viewOptions = util.extend({}, this.options, options); + + // create a combined filter method when needed + if (this.options.filter && options && options.filter) { + viewOptions.filter = function (item) { + return me.options.filter(item) && options.filter(item); + } + } + + // build up the call to the linked data set + var getArguments = []; + if (ids != undefined) { + getArguments.push(ids); + } + getArguments.push(viewOptions); + getArguments.push(data); + + return this.data && this.data.get.apply(this.data, getArguments); +}; + +/** + * Get ids of all items or from a filtered set of items. + * @param {Object} [options] An Object with options. Available options: + * {function} [filter] filter items + * {String | function} [order] Order the items by + * a field name or custom sort function. + * @return {Array} ids + */ +DataView.prototype.getIds = function (options) { + var ids; + + if (this.data) { + var defaultFilter = this.options.filter; + var filter; + + if (options && options.filter) { + if (defaultFilter) { + filter = function (item) { + return defaultFilter(item) && options.filter(item); + } + } + else { + filter = options.filter; + } + } + else { + filter = defaultFilter; + } + + ids = this.data.getIds({ + filter: filter, + order: options && options.order + }); + } + else { + ids = []; + } + + return ids; +}; + +/** + * Event listener. Will propagate all events from the connected data set to + * the subscribers of the DataView, but will filter the items and only trigger + * when there are changes in the filtered data set. + * @param {String} event + * @param {Object | null} params + * @param {String} senderId + * @private + */ +DataView.prototype._onEvent = function (event, params, senderId) { + var i, len, id, item, + ids = params && params.items, + data = this.data, + added = [], + updated = [], + removed = []; + + if (ids && data) { + switch (event) { + case 'add': + // filter the ids of the added items + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + item = this.get(id); + if (item) { + this.ids[id] = true; + added.push(id); + } + } + + break; + + case 'update': + // determine the event from the views viewpoint: an updated + // item can be added, updated, or removed from this view. + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + item = this.get(id); + + if (item) { + if (this.ids[id]) { + updated.push(id); + } + else { + this.ids[id] = true; + added.push(id); + } + } + else { + if (this.ids[id]) { + delete this.ids[id]; + removed.push(id); + } + else { + // nothing interesting for me :-( + } + } + } + + break; + + case 'remove': + // filter the ids of the removed items + for (i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + if (this.ids[id]) { + delete this.ids[id]; + removed.push(id); + } + } + + break; + } + + if (added.length) { + this._trigger('add', {items: added}, senderId); + } + if (updated.length) { + this._trigger('update', {items: updated}, senderId); + } + if (removed.length) { + this._trigger('remove', {items: removed}, senderId); + } + } +}; + +// copy subscription functionality from DataSet +DataView.prototype.subscribe = DataSet.prototype.subscribe; +DataView.prototype.unsubscribe = DataSet.prototype.unsubscribe; +DataView.prototype._trigger = DataSet.prototype._trigger; + +/** + * @constructor TimeStep + * The class TimeStep is an iterator for dates. You provide a start date and an + * end date. The class itself determines the best scale (step size) based on the + * provided start Date, end Date, and minimumStep. + * + * If minimumStep is provided, the step size is chosen as close as possible + * to the minimumStep but larger than minimumStep. If minimumStep is not + * provided, the scale is set to 1 DAY. + * The minimumStep should correspond with the onscreen size of about 6 characters + * + * Alternatively, you can set a scale by hand. + * After creation, you can initialize the class by executing first(). Then you + * can iterate from the start date to the end date via next(). You can check if + * the end date is reached with the function hasNext(). After each step, you can + * retrieve the current date via getCurrent(). + * The TimeStep has scales ranging from milliseconds, seconds, minutes, hours, + * days, to years. + * + * Version: 1.2 + * + * @param {Date} [start] The start date, for example new Date(2010, 9, 21) + * or new Date(2010, 9, 21, 23, 45, 00) + * @param {Date} [end] The end date + * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds + */ +TimeStep = function(start, end, minimumStep) { + // variables + this.current = new Date(); + this._start = new Date(); + this._end = new Date(); + + this.autoScale = true; + this.scale = TimeStep.SCALE.DAY; + this.step = 1; + + // initialize the range + this.setRange(start, end, minimumStep); +}; + +/// enum scale +TimeStep.SCALE = { + MILLISECOND: 1, + SECOND: 2, + MINUTE: 3, + HOUR: 4, + DAY: 5, + WEEKDAY: 6, + MONTH: 7, + YEAR: 8 +}; + + +/** + * Set a new range + * If minimumStep is provided, the step size is chosen as close as possible + * to the minimumStep but larger than minimumStep. If minimumStep is not + * provided, the scale is set to 1 DAY. + * The minimumStep should correspond with the onscreen size of about 6 characters + * @param {Date} [start] The start date and time. + * @param {Date} [end] The end date and time. + * @param {int} [minimumStep] Optional. Minimum step size in milliseconds + */ +TimeStep.prototype.setRange = function(start, end, minimumStep) { + if (!(start instanceof Date) || !(end instanceof Date)) { + throw "No legal start or end date in method setRange"; + } + + this._start = (start != undefined) ? new Date(start.valueOf()) : new Date(); + this._end = (end != undefined) ? new Date(end.valueOf()) : new Date(); + + if (this.autoScale) { + this.setMinimumStep(minimumStep); + } +}; + +/** + * Set the range iterator to the start date. + */ +TimeStep.prototype.first = function() { + this.current = new Date(this._start.valueOf()); + this.roundToMinor(); +}; + +/** + * Round the current date to the first minor date value + * This must be executed once when the current date is set to start Date + */ +TimeStep.prototype.roundToMinor = function() { + // round to floor + // IMPORTANT: we have no breaks in this switch! (this is no bug) + //noinspection FallthroughInSwitchStatementJS + switch (this.scale) { + case 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: // intentional fall through + 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); + //case TimeStep.SCALE.MILLISECOND: // nothing to do for milliseconds + } + + if (this.step != 1) { + // round down to the first minor value that is a multiple of the current step size + switch (this.scale) { + case 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: // intentional fall through + 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); break; + default: break; + } + } +}; + +/** + * Check if the there is a next step + * @return {boolean} true if the current date has not passed the end date + */ +TimeStep.prototype.hasNext = function () { + return (this.current.valueOf() <= this._end.valueOf()); +}; + +/** + * Do the next step + */ +TimeStep.prototype.next = function() { + var prev = this.current.valueOf(); + + // Two cases, needed to prevent issues with switching daylight savings + // (end of March and end of October) + if (this.current.getMonth() < 6) { + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: + + this.current = new Date(this.current.valueOf() + this.step); break; + case TimeStep.SCALE.SECOND: this.current = new Date(this.current.valueOf() + this.step * 1000); break; + case TimeStep.SCALE.MINUTE: this.current = new Date(this.current.valueOf() + this.step * 1000 * 60); break; + case TimeStep.SCALE.HOUR: + this.current = new Date(this.current.valueOf() + this.step * 1000 * 60 * 60); + // in case of skipping an hour for daylight savings, adjust the hour again (else you get: 0h 5h 9h ... instead of 0h 4h 8h ...) + var h = this.current.getHours(); + this.current.setHours(h - (h % this.step)); + break; + case TimeStep.SCALE.WEEKDAY: // intentional fall through + 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); break; + default: break; + } + } + 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: // intentional fall through + 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); break; + default: break; + } + } + + if (this.step != 1) { + // round down to the correct major value + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: if(this.current.getMilliseconds() < this.step) this.current.setMilliseconds(0); break; + case TimeStep.SCALE.SECOND: if(this.current.getSeconds() < this.step) this.current.setSeconds(0); break; + case TimeStep.SCALE.MINUTE: if(this.current.getMinutes() < this.step) this.current.setMinutes(0); break; + case TimeStep.SCALE.HOUR: if(this.current.getHours() < this.step) this.current.setHours(0); break; + case TimeStep.SCALE.WEEKDAY: // intentional fall through + case TimeStep.SCALE.DAY: if(this.current.getDate() < this.step+1) this.current.setDate(1); break; + case TimeStep.SCALE.MONTH: if(this.current.getMonth() < this.step) this.current.setMonth(0); break; + case TimeStep.SCALE.YEAR: break; // nothing to do for year + default: break; + } + } + + // safety mechanism: if current time is still unchanged, move to the end + if (this.current.valueOf() == prev) { + this.current = new Date(this._end.valueOf()); + } +}; + + +/** + * Get the current datetime + * @return {Date} current The current date + */ +TimeStep.prototype.getCurrent = function() { + return this.current; +}; + +/** + * Set a custom scale. Autoscaling will be disabled. + * For example setScale(SCALE.MINUTES, 5) will result + * in minor steps of 5 minutes, and major steps of an hour. + * + * @param {TimeStep.SCALE} newScale + * A scale. Choose from SCALE.MILLISECOND, + * SCALE.SECOND, SCALE.MINUTE, SCALE.HOUR, + * SCALE.WEEKDAY, SCALE.DAY, SCALE.MONTH, + * SCALE.YEAR. + * @param {Number} newStep A step size, by default 1. Choose for + * example 1, 2, 5, or 10. + */ +TimeStep.prototype.setScale = function(newScale, newStep) { + this.scale = newScale; + + if (newStep > 0) { + this.step = newStep; + } + + this.autoScale = false; +}; + +/** + * Enable or disable autoscaling + * @param {boolean} enable If true, autoascaling is set true + */ +TimeStep.prototype.setAutoScale = function (enable) { + this.autoScale = enable; +}; + + +/** + * Automatically determine the scale that bests fits the provided minimum step + * @param {Number} [minimumStep] The minimum step size in milliseconds + */ +TimeStep.prototype.setMinimumStep = function(minimumStep) { + if (minimumStep == undefined) { + return; + } + + var stepYear = (1000 * 60 * 60 * 24 * 30 * 12); + var stepMonth = (1000 * 60 * 60 * 24 * 30); + var stepDay = (1000 * 60 * 60 * 24); + var stepHour = (1000 * 60 * 60); + var stepMinute = (1000 * 60); + var stepSecond = (1000); + var stepMillisecond= (1); + + // find the smallest step that is larger than the provided minimumStep + if (stepYear*1000 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 1000;} + if (stepYear*500 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 500;} + if (stepYear*100 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 100;} + if (stepYear*50 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 50;} + if (stepYear*10 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 10;} + if (stepYear*5 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 5;} + if (stepYear > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 1;} + if (stepMonth*3 > minimumStep) {this.scale = TimeStep.SCALE.MONTH; this.step = 3;} + if (stepMonth > minimumStep) {this.scale = TimeStep.SCALE.MONTH; this.step = 1;} + if (stepDay*5 > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 5;} + if (stepDay*2 > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 2;} + if (stepDay > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 1;} + if (stepDay/2 > minimumStep) {this.scale = TimeStep.SCALE.WEEKDAY; this.step = 1;} + if (stepHour*4 > minimumStep) {this.scale = TimeStep.SCALE.HOUR; this.step = 4;} + if (stepHour > minimumStep) {this.scale = TimeStep.SCALE.HOUR; this.step = 1;} + if (stepMinute*15 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 15;} + if (stepMinute*10 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 10;} + if (stepMinute*5 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 5;} + if (stepMinute > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 1;} + if (stepSecond*15 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 15;} + if (stepSecond*10 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 10;} + if (stepSecond*5 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 5;} + if (stepSecond > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 1;} + if (stepMillisecond*200 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 200;} + if (stepMillisecond*100 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 100;} + if (stepMillisecond*50 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 50;} + if (stepMillisecond*10 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 10;} + if (stepMillisecond*5 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 5;} + if (stepMillisecond > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 1;} +}; + +/** + * Snap a date to a rounded value. The snap intervals are dependent on the + * current scale and step. + * @param {Date} date the date to be snapped + */ +TimeStep.prototype.snap = function(date) { + if (this.scale == TimeStep.SCALE.YEAR) { + var year = date.getFullYear() + Math.round(date.getMonth() / 12); + date.setFullYear(Math.round(year / this.step) * this.step); + date.setMonth(0); + date.setDate(0); + date.setHours(0); + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + } + else if (this.scale == TimeStep.SCALE.MONTH) { + if (date.getDate() > 15) { + date.setDate(1); + date.setMonth(date.getMonth() + 1); + // important: first set Date to 1, after that change the month. + } + else { + date.setDate(1); + } + + date.setHours(0); + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + } + else if (this.scale == TimeStep.SCALE.DAY || + this.scale == TimeStep.SCALE.WEEKDAY) { + //noinspection FallthroughInSwitchStatementJS + switch (this.step) { + case 5: + case 2: + date.setHours(Math.round(date.getHours() / 24) * 24); break; + default: + date.setHours(Math.round(date.getHours() / 12) * 12); break; + } + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + } + else if (this.scale == TimeStep.SCALE.HOUR) { + switch (this.step) { + case 4: + date.setMinutes(Math.round(date.getMinutes() / 60) * 60); break; + default: + date.setMinutes(Math.round(date.getMinutes() / 30) * 30); break; + } + date.setSeconds(0); + date.setMilliseconds(0); + } else if (this.scale == TimeStep.SCALE.MINUTE) { + //noinspection FallthroughInSwitchStatementJS + switch (this.step) { + case 15: + case 10: + date.setMinutes(Math.round(date.getMinutes() / 5) * 5); + date.setSeconds(0); + break; + case 5: + date.setSeconds(Math.round(date.getSeconds() / 60) * 60); break; + default: + date.setSeconds(Math.round(date.getSeconds() / 30) * 30); break; + } + date.setMilliseconds(0); + } + else if (this.scale == TimeStep.SCALE.SECOND) { + //noinspection FallthroughInSwitchStatementJS + switch (this.step) { + case 15: + case 10: + date.setSeconds(Math.round(date.getSeconds() / 5) * 5); + date.setMilliseconds(0); + break; + case 5: + date.setMilliseconds(Math.round(date.getMilliseconds() / 1000) * 1000); break; + default: + date.setMilliseconds(Math.round(date.getMilliseconds() / 500) * 500); break; + } + } + else if (this.scale == TimeStep.SCALE.MILLISECOND) { + var step = this.step > 5 ? this.step / 2 : 1; + date.setMilliseconds(Math.round(date.getMilliseconds() / step) * step); + } +}; + +/** + * Check if the current value is a major value (for example when the step + * is DAY, a major value is each first day of the MONTH) + * @return {boolean} true if current date is major, else false. + */ +TimeStep.prototype.isMajor = function() { + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: + return (this.current.getMilliseconds() == 0); + case TimeStep.SCALE.SECOND: + return (this.current.getSeconds() == 0); + case TimeStep.SCALE.MINUTE: + return (this.current.getHours() == 0) && (this.current.getMinutes() == 0); + // Note: this is no bug. Major label is equal for both minute and hour scale + case TimeStep.SCALE.HOUR: + return (this.current.getHours() == 0); + case TimeStep.SCALE.WEEKDAY: // intentional fall through + case TimeStep.SCALE.DAY: + return (this.current.getDate() == 1); + case TimeStep.SCALE.MONTH: + return (this.current.getMonth() == 0); + case TimeStep.SCALE.YEAR: + return false; + default: + return false; + } +}; + + +/** + * Returns formatted text for the minor axislabel, depending on the current + * date and the scale. For example when scale is MINUTE, the current time is + * formatted as "hh:mm". + * @param {Date} [date] custom date. if not provided, current date is taken + */ +TimeStep.prototype.getLabelMinor = function(date) { + if (date == undefined) { + date = this.current; + } + + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND: return moment(date).format('SSS'); + case TimeStep.SCALE.SECOND: return moment(date).format('s'); + case TimeStep.SCALE.MINUTE: return moment(date).format('HH:mm'); + case TimeStep.SCALE.HOUR: return moment(date).format('HH:mm'); + case TimeStep.SCALE.WEEKDAY: return moment(date).format('ddd D'); + case TimeStep.SCALE.DAY: return moment(date).format('D'); + case TimeStep.SCALE.MONTH: return moment(date).format('MMM'); + case TimeStep.SCALE.YEAR: return moment(date).format('YYYY'); + default: return ''; + } +}; + + +/** + * Returns formatted text for the major axis label, depending on the current + * date and the scale. For example when scale is MINUTE, the major scale is + * hours, and the hour will be formatted as "hh". + * @param {Date} [date] custom date. if not provided, current date is taken + */ +TimeStep.prototype.getLabelMajor = function(date) { + if (date == undefined) { + date = this.current; + } + + //noinspection FallthroughInSwitchStatementJS + switch (this.scale) { + case TimeStep.SCALE.MILLISECOND:return moment(date).format('HH:mm:ss'); + case TimeStep.SCALE.SECOND: return moment(date).format('D MMMM HH:mm'); + case TimeStep.SCALE.MINUTE: + case TimeStep.SCALE.HOUR: return moment(date).format('ddd D MMMM'); + case TimeStep.SCALE.WEEKDAY: + case TimeStep.SCALE.DAY: return moment(date).format('MMMM YYYY'); + case TimeStep.SCALE.MONTH: return moment(date).format('YYYY'); + case TimeStep.SCALE.YEAR: return ''; + default: return ''; + } +}; + +/** + * @constructor Stack + * Stacks items on top of each other. + * @param {ItemSet} parent + * @param {Object} [options] + */ +function Stack (parent, options) { + this.parent = parent; + + this.options = options || {}; + this.defaultOptions = { + order: function (a, b) { + //return (b.width - a.width) || (a.left - b.left); // TODO: cleanup + // Order: ranges over non-ranges, ranged ordered by width, and + // lastly ordered by start. + if (a instanceof ItemRange) { + if (b instanceof ItemRange) { + var aInt = (a.data.end - a.data.start); + var bInt = (b.data.end - b.data.start); + return (aInt - bInt) || (a.data.start - b.data.start); + } + else { + return -1; + } + } + else { + if (b instanceof ItemRange) { + return 1; + } + else { + return (a.data.start - b.data.start); + } + } + }, + margin: { + item: 10 + } + }; + + this.ordered = []; // ordered items +} + +/** + * Set options for the stack + * @param {Object} options Available options: + * {ItemSet} parent + * {Number} margin + * {function} order Stacking order + */ +Stack.prototype.setOptions = function setOptions (options) { + util.extend(this.options, options); + + // TODO: register on data changes at the connected parent itemset, and update the changed part only and immediately +}; + +/** + * Stack the items such that they don't overlap. The items will have a minimal + * distance equal to options.margin.item. + */ +Stack.prototype.update = function update() { + this._order(); + this._stack(); +}; + +/** + * Order the items. The items are ordered by width first, and by left position + * second. + * If a custom order function has been provided via the options, then this will + * be used. + * @private + */ +Stack.prototype._order = function _order () { + var items = this.parent.items; + if (!items) { + throw new Error('Cannot stack items: parent does not contain items'); + } + + // TODO: store the sorted items, to have less work later on + var ordered = []; + var index = 0; + // items is a map (no array) + util.forEach(items, function (item) { + if (item.visible) { + ordered[index] = item; + index++; + } + }); + + //if a customer stack order function exists, use it. + var order = this.options.order || this.defaultOptions.order; + if (!(typeof order === 'function')) { + throw new Error('Option order must be a function'); + } + + ordered.sort(order); + + this.ordered = ordered; +}; + +/** + * Adjust vertical positions of the events such that they don't overlap each + * other. + * @private + */ +Stack.prototype._stack = function _stack () { + var i, + iMax, + ordered = this.ordered, + options = this.options, + orientation = options.orientation || this.defaultOptions.orientation, + axisOnTop = (orientation == 'top'), + margin; + + if (options.margin && options.margin.item !== undefined) { + margin = options.margin.item; + } + else { + margin = this.defaultOptions.margin.item + } + + // calculate new, non-overlapping positions + for (i = 0, iMax = ordered.length; i < iMax; i++) { + var item = ordered[i]; + var collidingItem = null; + do { + // TODO: optimize checking for overlap. when there is a gap without items, + // you only need to check for items from the next item on, not from zero + collidingItem = this.checkOverlap(ordered, i, 0, i - 1, margin); + if (collidingItem != null) { + // There is a collision. Reposition the event above the colliding element + if (axisOnTop) { + item.top = collidingItem.top + collidingItem.height + margin; + } + else { + item.top = collidingItem.top - item.height - margin; + } + } + } while (collidingItem); + } +}; + +/** + * Check if the destiny position of given item overlaps with any + * of the other items from index itemStart to itemEnd. + * @param {Array} items Array with items + * @param {int} itemIndex Number of the item to be checked for overlap + * @param {int} itemStart First item to be checked. + * @param {int} itemEnd Last item to be checked. + * @return {Object | null} colliding item, or undefined when no collisions + * @param {Number} margin A minimum required margin. + * If margin is provided, the two items will be + * marked colliding when they overlap or + * when the margin between the two is smaller than + * the requested margin. + */ +Stack.prototype.checkOverlap = function checkOverlap (items, itemIndex, + itemStart, itemEnd, margin) { + var collision = this.collision; + + // we loop from end to start, as we suppose that the chance of a + // collision is larger for items at the end, so check these first. + var a = items[itemIndex]; + for (var i = itemEnd; i >= itemStart; i--) { + var b = items[i]; + if (collision(a, b, margin)) { + if (i != itemIndex) { + return b; + } + } + } + + return null; +}; + +/** + * Test if the two provided items collide + * The items must have parameters left, width, top, and height. + * @param {Component} a The first item + * @param {Component} b The second item + * @param {Number} margin A minimum required margin. + * If margin is provided, the two items will be + * marked colliding when they overlap or + * when the margin between the two is smaller than + * the requested margin. + * @return {boolean} true if a and b collide, else false + */ +Stack.prototype.collision = function collision (a, b, margin) { + return ((a.left - margin) < (b.left + b.getWidth()) && + (a.left + a.getWidth() + margin) > b.left && + (a.top - margin) < (b.top + b.height) && + (a.top + a.height + margin) > b.top); +}; + +/** + * @constructor Range + * A Range controls a numeric range with a start and end value. + * The Range adjusts the range based on mouse events or programmatic changes, + * and triggers events when the range is changing or has been changed. + * @param {Object} [options] See description at Range.setOptions + * @extends Controller + */ +function Range(options) { + this.id = util.randomUUID(); + this.start = null; // Number + this.end = null; // Number + + this.options = options || {}; + + this.setOptions(options); +} + +/** + * Set options for the range controller + * @param {Object} options Available options: + * {Number} min Minimum value for start + * {Number} max Maximum value for end + * {Number} zoomMin Set a minimum value for + * (end - start). + * {Number} zoomMax Set a maximum value for + * (end - start). + */ +Range.prototype.setOptions = function (options) { + util.extend(this.options, options); + + // re-apply range with new limitations + if (this.start !== null && this.end !== null) { + this.setRange(this.start, this.end); + } +}; + +/** + * Test whether direction has a valid value + * @param {String} direction 'horizontal' or 'vertical' + */ +function validateDirection (direction) { + if (direction != 'horizontal' && direction != 'vertical') { + throw new TypeError('Unknown direction "' + direction + '". ' + + 'Choose "horizontal" or "vertical".'); + } +} + +/** + * Add listeners for mouse and touch events to the component + * @param {Component} component + * @param {String} event Available events: 'move', 'zoom' + * @param {String} direction Available directions: 'horizontal', 'vertical' + */ +Range.prototype.subscribe = function (component, event, direction) { + var me = this; + + if (event == 'move') { + // drag start listener + component.on('dragstart', function (event) { + me._onDragStart(event, component); + }); + + // drag listener + component.on('drag', function (event) { + me._onDrag(event, component, direction); + }); + + // drag end listener + component.on('dragend', function (event) { + me._onDragEnd(event, component); + }); + } + else if (event == 'zoom') { + // mouse wheel + function mousewheel (event) { + me._onMouseWheel(event, component, direction); + } + component.on('mousewheel', mousewheel); + component.on('DOMMouseScroll', mousewheel); // For FF + + // pinch + component.on('touch', function (event) { + me._onTouch(); + }); + component.on('pinch', function (event) { + me._onPinch(event, component, direction); + }); + } + else { + throw new TypeError('Unknown event "' + event + '". ' + + 'Choose "move" or "zoom".'); + } +}; + +/** + * Event handler + * @param {String} event name of the event, for example 'click', 'mousemove' + * @param {function} callback callback handler, invoked with the raw HTML Event + * as parameter. + */ +Range.prototype.on = function (event, callback) { + events.addListener(this, event, callback); +}; + +/** + * Trigger an event + * @param {String} event name of the event, available events: 'rangechange', + * 'rangechanged' + * @private + */ +Range.prototype._trigger = function (event) { + events.trigger(this, event, { + start: this.start, + end: this.end + }); +}; + +/** + * Set a new start and end range + * @param {Number} [start] + * @param {Number} [end] + */ +Range.prototype.setRange = function(start, end) { + var changed = this._applyRange(start, end); + if (changed) { + this._trigger('rangechange'); + this._trigger('rangechanged'); + } +}; + +/** + * Set a new start and end range. This method is the same as setRange, but + * does not trigger a range change and range changed event, and it returns + * true when the range is changed + * @param {Number} [start] + * @param {Number} [end] + * @return {Boolean} changed + * @private + */ +Range.prototype._applyRange = function(start, end) { + var newStart = (start != null) ? util.convert(start, 'Number') : this.start, + newEnd = (end != null) ? util.convert(end, 'Number') : this.end, + max = (this.options.max != null) ? util.convert(this.options.max, 'Date').valueOf() : null, + min = (this.options.min != null) ? util.convert(this.options.min, 'Date').valueOf() : null, + diff; + + // check for valid number + if (isNaN(newStart) || newStart === null) { + throw new Error('Invalid start "' + start + '"'); + } + if (isNaN(newEnd) || newEnd === null) { + throw new Error('Invalid end "' + end + '"'); + } + + // prevent start < end + if (newEnd < newStart) { + newEnd = newStart; + } + + // prevent start < min + if (min !== null) { + if (newStart < min) { + diff = (min - newStart); + newStart += diff; + newEnd += diff; + + // prevent end > max + if (max != null) { + if (newEnd > max) { + newEnd = max; + } + } + } + } + + // prevent end > max + if (max !== null) { + if (newEnd > max) { + diff = (newEnd - max); + newStart -= diff; + newEnd -= diff; + + // prevent start < min + if (min != null) { + if (newStart < min) { + newStart = min; + } + } + } + } + + // prevent (end-start) < zoomMin + if (this.options.zoomMin !== null) { + var zoomMin = parseFloat(this.options.zoomMin); + if (zoomMin < 0) { + zoomMin = 0; + } + if ((newEnd - newStart) < zoomMin) { + if ((this.end - this.start) === zoomMin) { + // ignore this action, we are already zoomed to the minimum + newStart = this.start; + newEnd = this.end; + } + else { + // zoom to the minimum + diff = (zoomMin - (newEnd - newStart)); + newStart -= diff / 2; + newEnd += diff / 2; + } + } + } + + // prevent (end-start) > zoomMax + if (this.options.zoomMax !== null) { + var zoomMax = parseFloat(this.options.zoomMax); + if (zoomMax < 0) { + zoomMax = 0; + } + if ((newEnd - newStart) > zoomMax) { + if ((this.end - this.start) === zoomMax) { + // ignore this action, we are already zoomed to the maximum + newStart = this.start; + newEnd = this.end; + } + else { + // zoom to the maximum + diff = ((newEnd - newStart) - zoomMax); + newStart += diff / 2; + newEnd -= diff / 2; + } + } + } + + var changed = (this.start != newStart || this.end != newEnd); + + this.start = newStart; + this.end = newEnd; + + return changed; +}; + +/** + * Retrieve the current range. + * @return {Object} An object with start and end properties + */ +Range.prototype.getRange = function() { + return { + start: this.start, + end: this.end + }; +}; + +/** + * Calculate the conversion offset and scale for current range, based on + * the provided width + * @param {Number} width + * @returns {{offset: number, scale: number}} conversion + */ +Range.prototype.conversion = function (width) { + return Range.conversion(this.start, this.end, width); +}; + +/** + * Static method to calculate the conversion offset and scale for a range, + * based on the provided start, end, and width + * @param {Number} start + * @param {Number} end + * @param {Number} width + * @returns {{offset: number, scale: number}} conversion + */ +Range.conversion = function (start, end, width) { + if (width != 0 && (end - start != 0)) { + return { + offset: start, + scale: width / (end - start) + } + } + else { + return { + offset: 0, + scale: 1 + }; + } +}; + +// global (private) object to store drag params +var touchParams = {}; + +/** + * Start dragging horizontally or vertically + * @param {Event} event + * @param {Object} component + * @private + */ +Range.prototype._onDragStart = function(event, component) { + // refuse to drag when we where pinching to prevent the timeline make a jump + // when releasing the fingers in opposite order from the touch screen + if (touchParams.pinching) return; + + touchParams.start = this.start; + touchParams.end = this.end; + + var frame = component.frame; + if (frame) { + frame.style.cursor = 'move'; + } +}; + +/** + * Perform dragging operating. + * @param {Event} event + * @param {Component} component + * @param {String} direction 'horizontal' or 'vertical' + * @private + */ +Range.prototype._onDrag = function (event, component, direction) { + validateDirection(direction); + + // refuse to drag when we where pinching to prevent the timeline make a jump + // when releasing the fingers in opposite order from the touch screen + if (touchParams.pinching) return; + + var delta = (direction == 'horizontal') ? event.gesture.deltaX : event.gesture.deltaY, + interval = (touchParams.end - touchParams.start), + width = (direction == 'horizontal') ? component.width : component.height, + diffRange = -delta / width * interval; + + this._applyRange(touchParams.start + diffRange, touchParams.end + diffRange); + + // fire a rangechange event + this._trigger('rangechange'); +}; + +/** + * Stop dragging operating. + * @param {event} event + * @param {Component} component + * @private + */ +Range.prototype._onDragEnd = function (event, component) { + // refuse to drag when we where pinching to prevent the timeline make a jump + // when releasing the fingers in opposite order from the touch screen + if (touchParams.pinching) return; + + if (component.frame) { + component.frame.style.cursor = 'auto'; + } + + // fire a rangechanged event + this._trigger('rangechanged'); +}; + +/** + * Event handler for mouse wheel event, used to zoom + * Code from http://adomas.org/javascript-mouse-wheel/ + * @param {Event} event + * @param {Component} component + * @param {String} direction 'horizontal' or 'vertical' + * @private + */ +Range.prototype._onMouseWheel = function(event, component, direction) { + validateDirection(direction); + + // retrieve delta + var delta = 0; + if (event.wheelDelta) { /* IE/Opera. */ + delta = event.wheelDelta / 120; + } else if (event.detail) { /* Mozilla case. */ + // In Mozilla, sign of delta is different than in IE. + // Also, delta is multiple of 3. + delta = -event.detail / 3; + } + + // If delta is nonzero, handle it. + // Basically, delta is now positive if wheel was scrolled up, + // and negative, if wheel was scrolled down. + if (delta) { + // perform the zoom action. Delta is normally 1 or -1 + + // adjust a negative delta such that zooming in with delta 0.1 + // equals zooming out with a delta -0.1 + var scale; + if (delta < 0) { + scale = 1 - (delta / 5); + } + else { + scale = 1 / (1 + (delta / 5)) ; + } + + // calculate center, the date to zoom around + var gesture = util.fakeGesture(this, event), + pointer = getPointer(gesture.touches[0], component.frame), + pointerDate = this._pointerToDate(component, direction, pointer); + + this.zoom(scale, pointerDate); + } + + // Prevent default actions caused by mouse wheel + // (else the page and timeline both zoom and scroll) + util.preventDefault(event); +}; + +/** + * On start of a touch gesture, initialize scale to 1 + * @private + */ +Range.prototype._onTouch = function () { + touchParams.start = this.start; + touchParams.end = this.end; + touchParams.pinching = false; + touchParams.center = null; +}; + +/** + * Handle pinch event + * @param {Event} event + * @param {Component} component + * @param {String} direction 'horizontal' or 'vertical' + * @private + */ +Range.prototype._onPinch = function (event, component, direction) { + touchParams.pinching = true; + + if (event.gesture.touches.length > 1) { + if (!touchParams.center) { + touchParams.center = getPointer(event.gesture.center, component.frame); + } + + var scale = 1 / event.gesture.scale, + initDate = this._pointerToDate(component, direction, touchParams.center), + center = getPointer(event.gesture.center, component.frame), + date = this._pointerToDate(component, direction, center), + delta = date - initDate; // TODO: utilize delta + + // calculate new start and end + var newStart = parseInt(initDate + (touchParams.start - initDate) * scale); + var newEnd = parseInt(initDate + (touchParams.end - initDate) * scale); + + // apply new range + this.setRange(newStart, newEnd); + } +}; + +/** + * Helper function to calculate the center date for zooming + * @param {Component} component + * @param {{x: Number, y: Number}} pointer + * @param {String} direction 'horizontal' or 'vertical' + * @return {number} date + * @private + */ +Range.prototype._pointerToDate = function (component, direction, pointer) { + var conversion; + if (direction == 'horizontal') { + var width = component.width; + conversion = this.conversion(width); + return pointer.x / conversion.scale + conversion.offset; + } + else { + var height = component.height; + conversion = this.conversion(height); + return pointer.y / conversion.scale + conversion.offset; + } +}; + +/** + * Get the pointer location relative to the location of the dom element + * @param {{pageX: Number, pageY: Number}} touch + * @param {Element} element HTML DOM element + * @return {{x: Number, y: Number}} pointer + * @private + */ +function getPointer (touch, element) { + return { + x: touch.pageX - vis.util.getAbsoluteLeft(element), + y: touch.pageY - vis.util.getAbsoluteTop(element) + }; +} + +/** + * Zoom the range the given scale in or out. Start and end date will + * be adjusted, and the timeline will be redrawn. You can optionally give a + * date around which to zoom. + * For example, try scale = 0.9 or 1.1 + * @param {Number} scale Scaling factor. Values above 1 will zoom out, + * values below 1 will zoom in. + * @param {Number} [center] Value representing a date around which will + * be zoomed. + */ +Range.prototype.zoom = function(scale, center) { + // if centerDate is not provided, take it half between start Date and end Date + if (center == null) { + center = (this.start + this.end) / 2; + } + + // calculate new start and end + var newStart = center + (this.start - center) * scale; + var newEnd = center + (this.end - center) * scale; + + this.setRange(newStart, newEnd); +}; + +/** + * Move the range with a given delta to the left or right. Start and end + * value will be adjusted. For example, try delta = 0.1 or -0.1 + * @param {Number} delta Moving amount. Positive value will move right, + * negative value will move left + */ +Range.prototype.move = function(delta) { + // zoom start Date and end Date relative to the centerDate + var diff = (this.end - this.start); + + // apply new values + var newStart = this.start + diff * delta; + var newEnd = this.end + diff * delta; + + // TODO: reckon with min and max range + + this.start = newStart; + this.end = newEnd; +}; + +/** + * Move the range to a new center point + * @param {Number} moveTo New center point of the range + */ +Range.prototype.moveTo = function(moveTo) { + var center = (this.start + this.end) / 2; + + var diff = center - moveTo; + + // calculate new start and end + var newStart = this.start - diff; + var newEnd = this.end - diff; + + this.setRange(newStart, newEnd); +}; + +/** + * @constructor Controller + * + * A Controller controls the reflows and repaints of all visual components + */ +function Controller () { + this.id = util.randomUUID(); + this.components = {}; + + this.repaintTimer = undefined; + this.reflowTimer = undefined; +} + +/** + * Add a component to the controller + * @param {Component} component + */ +Controller.prototype.add = function add(component) { + // validate the component + if (component.id == undefined) { + throw new Error('Component has no field id'); + } + if (!(component instanceof Component) && !(component instanceof Controller)) { + throw new TypeError('Component must be an instance of ' + + 'prototype Component or Controller'); + } + + // add the component + component.controller = this; + this.components[component.id] = component; +}; + +/** + * Remove a component from the controller + * @param {Component | String} component + */ +Controller.prototype.remove = function remove(component) { + var id; + for (id in this.components) { + if (this.components.hasOwnProperty(id)) { + if (id == component || this.components[id] == component) { + break; + } + } + } + + if (id) { + delete this.components[id]; + } +}; + +/** + * Request a reflow. The controller will schedule a reflow + * @param {Boolean} [force] If true, an immediate reflow is forced. Default + * is false. + */ +Controller.prototype.requestReflow = function requestReflow(force) { + if (force) { + this.reflow(); + } + else { + if (!this.reflowTimer) { + var me = this; + this.reflowTimer = setTimeout(function () { + me.reflowTimer = undefined; + me.reflow(); + }, 0); + } + } +}; + +/** + * Request a repaint. The controller will schedule a repaint + * @param {Boolean} [force] If true, an immediate repaint is forced. Default + * is false. + */ +Controller.prototype.requestRepaint = function requestRepaint(force) { + if (force) { + this.repaint(); + } + else { + if (!this.repaintTimer) { + var me = this; + this.repaintTimer = setTimeout(function () { + me.repaintTimer = undefined; + me.repaint(); + }, 0); + } + } +}; + +/** + * Repaint all components + */ +Controller.prototype.repaint = function repaint() { + var changed = false; + + // cancel any running repaint request + if (this.repaintTimer) { + clearTimeout(this.repaintTimer); + this.repaintTimer = undefined; + } + + var done = {}; + + function repaint(component, id) { + if (!(id in done)) { + // first repaint the components on which this component is dependent + if (component.depends) { + component.depends.forEach(function (dep) { + repaint(dep, dep.id); + }); + } + if (component.parent) { + repaint(component.parent, component.parent.id); + } + + // repaint the component itself and mark as done + changed = component.repaint() || changed; + done[id] = true; + } + } + + util.forEach(this.components, repaint); + + // immediately reflow when needed + if (changed) { + this.reflow(); + } + // TODO: limit the number of nested reflows/repaints, prevent loop +}; + +/** + * Reflow all components + */ +Controller.prototype.reflow = function reflow() { + var resized = false; + + // cancel any running repaint request + if (this.reflowTimer) { + clearTimeout(this.reflowTimer); + this.reflowTimer = undefined; + } + + var done = {}; + + function reflow(component, id) { + if (!(id in done)) { + // first reflow the components on which this component is dependent + if (component.depends) { + component.depends.forEach(function (dep) { + reflow(dep, dep.id); + }); + } + if (component.parent) { + reflow(component.parent, component.parent.id); + } + + // reflow the component itself and mark as done + resized = component.reflow() || resized; + done[id] = true; + } + } + + util.forEach(this.components, reflow); + + // immediately repaint when needed + if (resized) { + this.repaint(); + } + // TODO: limit the number of nested reflows/repaints, prevent loop +}; + +/** + * Prototype for visual components + */ +function Component () { + this.id = null; + this.parent = null; + this.depends = null; + this.controller = null; + this.options = null; + + this.frame = null; // main DOM element + this.top = 0; + this.left = 0; + this.width = 0; + this.height = 0; +} + +/** + * Set parameters for the frame. Parameters will be merged in current parameter + * set. + * @param {Object} options Available parameters: + * {String | function} [className] + * {EventBus} [eventBus] + * {String | Number | function} [left] + * {String | Number | function} [top] + * {String | Number | function} [width] + * {String | Number | function} [height] + */ +Component.prototype.setOptions = function setOptions(options) { + if (options) { + util.extend(this.options, options); + + if (this.controller) { + this.requestRepaint(); + this.requestReflow(); + } + } +}; + +/** + * Get an option value by name + * The function will first check this.options object, and else will check + * this.defaultOptions. + * @param {String} name + * @return {*} value + */ +Component.prototype.getOption = function getOption(name) { + var value; + if (this.options) { + value = this.options[name]; + } + if (value === undefined && this.defaultOptions) { + value = this.defaultOptions[name]; + } + return value; +}; + +/** + * Get the container element of the component, which can be used by a child to + * add its own widgets. Not all components do have a container for childs, in + * that case null is returned. + * @returns {HTMLElement | null} container + */ +// TODO: get rid of the getContainer and getFrame methods, provide these via the options +Component.prototype.getContainer = function getContainer() { + // should be implemented by the component + return null; +}; + +/** + * Get the frame element of the component, the outer HTML DOM element. + * @returns {HTMLElement | null} frame + */ +Component.prototype.getFrame = function getFrame() { + return this.frame; +}; + +/** + * Repaint the component + * @return {Boolean} changed + */ +Component.prototype.repaint = function repaint() { + // should be implemented by the component + return false; +}; + +/** + * Reflow the component + * @return {Boolean} resized + */ +Component.prototype.reflow = function reflow() { + // should be implemented by the component + return false; +}; + +/** + * Hide the component from the DOM + * @return {Boolean} changed + */ +Component.prototype.hide = function hide() { + if (this.frame && this.frame.parentNode) { + this.frame.parentNode.removeChild(this.frame); + return true; + } + else { + return false; + } +}; + +/** + * Show the component in the DOM (when not already visible). + * A repaint will be executed when the component is not visible + * @return {Boolean} changed + */ +Component.prototype.show = function show() { + if (!this.frame || !this.frame.parentNode) { + return this.repaint(); + } + else { + return false; + } +}; + +/** + * Request a repaint. The controller will schedule a repaint + */ +Component.prototype.requestRepaint = function requestRepaint() { + if (this.controller) { + this.controller.requestRepaint(); + } + else { + throw new Error('Cannot request a repaint: no controller configured'); + // TODO: just do a repaint when no parent is configured? + } +}; + +/** + * Request a reflow. The controller will schedule a reflow + */ +Component.prototype.requestReflow = function requestReflow() { + if (this.controller) { + this.controller.requestReflow(); + } + else { + throw new Error('Cannot request a reflow: no controller configured'); + // TODO: just do a reflow when no parent is configured? + } +}; + +/** + * A panel can contain components + * @param {Component} [parent] + * @param {Component[]} [depends] Components on which this components depends + * (except for the parent) + * @param {Object} [options] Available parameters: + * {String | Number | function} [left] + * {String | Number | function} [top] + * {String | Number | function} [width] + * {String | Number | function} [height] + * {String | function} [className] + * @constructor Panel + * @extends Component + */ +function Panel(parent, depends, options) { + this.id = util.randomUUID(); + this.parent = parent; + this.depends = depends; + + this.options = options || {}; +} + +Panel.prototype = new Component(); + +/** + * Set options. Will extend the current options. + * @param {Object} [options] Available parameters: + * {String | function} [className] + * {String | Number | function} [left] + * {String | Number | function} [top] + * {String | Number | function} [width] + * {String | Number | function} [height] + */ +Panel.prototype.setOptions = Component.prototype.setOptions; + +/** + * Get the container element of the panel, which can be used by a child to + * add its own widgets. + * @returns {HTMLElement} container + */ +Panel.prototype.getContainer = function () { + return this.frame; +}; + +/** + * Repaint the component + * @return {Boolean} changed + */ +Panel.prototype.repaint = function () { + var changed = 0, + update = util.updateProperty, + asSize = util.option.asSize, + options = this.options, + frame = this.frame; + if (!frame) { + frame = document.createElement('div'); + frame.className = 'panel'; + + var className = options.className; + if (className) { + if (typeof className == 'function') { + util.addClassName(frame, String(className())); + } + else { + util.addClassName(frame, String(className)); + } + } + + this.frame = frame; + changed += 1; + } + if (!frame.parentNode) { + if (!this.parent) { + throw new Error('Cannot repaint panel: no parent attached'); + } + var parentContainer = this.parent.getContainer(); + if (!parentContainer) { + throw new Error('Cannot repaint panel: parent has no container element'); + } + parentContainer.appendChild(frame); + changed += 1; + } + + changed += update(frame.style, 'top', asSize(options.top, '0px')); + changed += update(frame.style, 'left', asSize(options.left, '0px')); + changed += update(frame.style, 'width', asSize(options.width, '100%')); + changed += update(frame.style, 'height', asSize(options.height, '100%')); + + return (changed > 0); +}; + +/** + * Reflow the component + * @return {Boolean} resized + */ +Panel.prototype.reflow = function () { + var changed = 0, + update = util.updateProperty, + frame = this.frame; + + if (frame) { + changed += update(this, 'top', frame.offsetTop); + changed += update(this, 'left', frame.offsetLeft); + changed += update(this, 'width', frame.offsetWidth); + changed += update(this, 'height', frame.offsetHeight); + } + else { + changed += 1; + } + + return (changed > 0); +}; + +/** + * A root panel can hold components. The root panel must be initialized with + * a DOM element as container. + * @param {HTMLElement} container + * @param {Object} [options] Available parameters: see RootPanel.setOptions. + * @constructor RootPanel + * @extends Panel + */ +function RootPanel(container, options) { + this.id = util.randomUUID(); + this.container = container; + + this.options = options || {}; + this.defaultOptions = { + autoResize: true + }; + + this.listeners = {}; // event listeners +} + +RootPanel.prototype = new Panel(); + +/** + * Set options. Will extend the current options. + * @param {Object} [options] Available parameters: + * {String | function} [className] + * {String | Number | function} [left] + * {String | Number | function} [top] + * {String | Number | function} [width] + * {String | Number | function} [height] + * {Boolean | function} [autoResize] + */ +RootPanel.prototype.setOptions = Component.prototype.setOptions; + +/** + * Repaint the component + * @return {Boolean} changed + */ +RootPanel.prototype.repaint = function () { + var changed = 0, + update = util.updateProperty, + asSize = util.option.asSize, + options = this.options, + frame = this.frame; + + if (!frame) { + frame = document.createElement('div'); + + this.frame = frame; + + changed += 1; + } + if (!frame.parentNode) { + if (!this.container) { + throw new Error('Cannot repaint root panel: no container attached'); + } + this.container.appendChild(frame); + changed += 1; + } + + frame.className = 'vis timeline rootpanel ' + options.orientation; + var className = options.className; + if (className) { + util.addClassName(frame, util.option.asString(className)); + } + + changed += update(frame.style, 'top', asSize(options.top, '0px')); + changed += update(frame.style, 'left', asSize(options.left, '0px')); + changed += update(frame.style, 'width', asSize(options.width, '100%')); + changed += update(frame.style, 'height', asSize(options.height, '100%')); + + this._updateEventEmitters(); + this._updateWatch(); + + return (changed > 0); +}; + +/** + * Reflow the component + * @return {Boolean} resized + */ +RootPanel.prototype.reflow = function () { + var changed = 0, + update = util.updateProperty, + frame = this.frame; + + if (frame) { + changed += update(this, 'top', frame.offsetTop); + changed += update(this, 'left', frame.offsetLeft); + changed += update(this, 'width', frame.offsetWidth); + changed += update(this, 'height', frame.offsetHeight); + } + else { + changed += 1; + } + + return (changed > 0); +}; + +/** + * Update watching for resize, depending on the current option + * @private + */ +RootPanel.prototype._updateWatch = function () { + var autoResize = this.getOption('autoResize'); + if (autoResize) { + this._watch(); + } + else { + this._unwatch(); + } +}; + +/** + * Watch for changes in the size of the frame. On resize, the Panel will + * automatically redraw itself. + * @private + */ +RootPanel.prototype._watch = function () { + var me = this; + + this._unwatch(); + + var checkSize = function () { + var autoResize = me.getOption('autoResize'); + if (!autoResize) { + // stop watching when the option autoResize is changed to false + me._unwatch(); + return; + } + + if (me.frame) { + // check whether the frame is resized + if ((me.frame.clientWidth != me.width) || + (me.frame.clientHeight != me.height)) { + me.requestReflow(); + } + } + }; + + // TODO: automatically cleanup the event listener when the frame is deleted + util.addEventListener(window, 'resize', checkSize); + + this.watchTimer = setInterval(checkSize, 1000); +}; + +/** + * Stop watching for a resize of the frame. + * @private + */ +RootPanel.prototype._unwatch = function () { + if (this.watchTimer) { + clearInterval(this.watchTimer); + this.watchTimer = undefined; + } + + // TODO: remove event listener on window.resize +}; + +/** + * Event handler + * @param {String} event name of the event, for example 'click', 'mousemove' + * @param {function} callback callback handler, invoked with the raw HTML Event + * as parameter. + */ +RootPanel.prototype.on = function (event, callback) { + // register the listener at this component + var arr = this.listeners[event]; + if (!arr) { + arr = []; + this.listeners[event] = arr; + } + arr.push(callback); + + this._updateEventEmitters(); +}; + +/** + * Update the event listeners for all event emitters + * @private + */ +RootPanel.prototype._updateEventEmitters = function () { + if (this.listeners) { + var me = this; + util.forEach(this.listeners, function (listeners, event) { + if (!me.emitters) { + me.emitters = {}; + } + if (!(event in me.emitters)) { + // create event + var frame = me.frame; + if (frame) { + //console.log('Created a listener for event ' + event + ' on component ' + me.id); // TODO: cleanup logging + var callback = function(event) { + listeners.forEach(function (listener) { + // TODO: filter on event target! + listener(event); + }); + }; + me.emitters[event] = callback; + + if (!me.hammer) { + me.hammer = Hammer(frame, { + prevent_default: true + }); + } + me.hammer.on(event, callback); + } + } + }); + + // TODO: be able to delete event listeners + // TODO: be able to move event listeners to a parent when available + } +}; + +/** + * A horizontal time axis + * @param {Component} parent + * @param {Component[]} [depends] Components on which this components depends + * (except for the parent) + * @param {Object} [options] See TimeAxis.setOptions for the available + * options. + * @constructor TimeAxis + * @extends Component + */ +function TimeAxis (parent, depends, options) { + this.id = util.randomUUID(); + this.parent = parent; + this.depends = depends; + + this.dom = { + majorLines: [], + majorTexts: [], + minorLines: [], + minorTexts: [], + redundant: { + majorLines: [], + majorTexts: [], + minorLines: [], + minorTexts: [] + } + }; + this.props = { + range: { + start: 0, + end: 0, + minimumStep: 0 + }, + lineTop: 0 + }; + + this.options = options || {}; + this.defaultOptions = { + orientation: 'bottom', // supported: 'top', 'bottom' + // TODO: implement timeaxis orientations 'left' and 'right' + showMinorLabels: true, + showMajorLabels: true + }; + + this.conversion = null; + this.range = null; +} + +TimeAxis.prototype = new Component(); + +// TODO: comment options +TimeAxis.prototype.setOptions = Component.prototype.setOptions; + +/** + * Set a range (start and end) + * @param {Range | Object} range A Range or an object containing start and end. + */ +TimeAxis.prototype.setRange = function (range) { + if (!(range instanceof Range) && (!range || !range.start || !range.end)) { + throw new TypeError('Range must be an instance of Range, ' + + 'or an object containing start and end.'); + } + this.range = range; +}; + +/** + * Convert a position on screen (pixels) to a datetime + * @param {int} x Position on the screen in pixels + * @return {Date} time The datetime the corresponds with given position x + */ +TimeAxis.prototype.toTime = function(x) { + var conversion = this.conversion; + return new Date(x / conversion.scale + conversion.offset); +}; + +/** + * Convert a datetime (Date object) into a position on the screen + * @param {Date} time A date + * @return {int} x The position on the screen in pixels which corresponds + * with the given date. + * @private + */ +TimeAxis.prototype.toScreen = function(time) { + var conversion = this.conversion; + return (time.valueOf() - conversion.offset) * conversion.scale; +}; + +/** + * Repaint the component + * @return {Boolean} changed + */ +TimeAxis.prototype.repaint = function () { + var changed = 0, + update = util.updateProperty, + asSize = util.option.asSize, + options = this.options, + orientation = this.getOption('orientation'), + props = this.props, + step = this.step; + + var frame = this.frame; + if (!frame) { + frame = document.createElement('div'); + this.frame = frame; + changed += 1; + } + frame.className = 'axis'; + // TODO: custom className? + + if (!frame.parentNode) { + if (!this.parent) { + throw new Error('Cannot repaint time axis: no parent attached'); + } + var parentContainer = this.parent.getContainer(); + if (!parentContainer) { + throw new Error('Cannot repaint time axis: parent has no container element'); + } + parentContainer.appendChild(frame); + + changed += 1; + } + + var parent = frame.parentNode; + if (parent) { + var beforeChild = frame.nextSibling; + parent.removeChild(frame); // take frame offline while updating (is almost twice as fast) + + var defaultTop = (orientation == 'bottom' && this.props.parentHeight && this.height) ? + (this.props.parentHeight - this.height) + 'px' : + '0px'; + changed += update(frame.style, 'top', asSize(options.top, defaultTop)); + changed += update(frame.style, 'left', asSize(options.left, '0px')); + changed += update(frame.style, 'width', asSize(options.width, '100%')); + changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); + + // get characters width and height + this._repaintMeasureChars(); + + if (this.step) { + this._repaintStart(); + + step.first(); + var xFirstMajorLabel = undefined; + var max = 0; + while (step.hasNext() && max < 1000) { + max++; + var cur = step.getCurrent(), + x = this.toScreen(cur), + isMajor = step.isMajor(); + + // TODO: lines must have a width, such that we can create css backgrounds + + if (this.getOption('showMinorLabels')) { + this._repaintMinorText(x, step.getLabelMinor()); + } + + if (isMajor && this.getOption('showMajorLabels')) { + if (x > 0) { + if (xFirstMajorLabel == undefined) { + xFirstMajorLabel = x; + } + this._repaintMajorText(x, step.getLabelMajor()); + } + this._repaintMajorLine(x); + } + else { + this._repaintMinorLine(x); + } + + step.next(); + } + + // create a major label on the left when needed + if (this.getOption('showMajorLabels')) { + var leftTime = this.toTime(0), + leftText = step.getLabelMajor(leftTime), + widthText = leftText.length * (props.majorCharWidth || 10) + 10; // upper bound estimation + + if (xFirstMajorLabel == undefined || widthText < xFirstMajorLabel) { + this._repaintMajorText(0, leftText); + } + } + + this._repaintEnd(); + } + + this._repaintLine(); + + // put frame online again + if (beforeChild) { + parent.insertBefore(frame, beforeChild); + } + else { + parent.appendChild(frame) + } + } + + return (changed > 0); +}; + +/** + * Start a repaint. Move all DOM elements to a redundant list, where they + * can be picked for re-use, or can be cleaned up in the end + * @private + */ +TimeAxis.prototype._repaintStart = function () { + var dom = this.dom, + redundant = dom.redundant; + + redundant.majorLines = dom.majorLines; + redundant.majorTexts = dom.majorTexts; + redundant.minorLines = dom.minorLines; + redundant.minorTexts = dom.minorTexts; + + dom.majorLines = []; + dom.majorTexts = []; + dom.minorLines = []; + dom.minorTexts = []; +}; + +/** + * End a repaint. Cleanup leftover DOM elements in the redundant list + * @private + */ +TimeAxis.prototype._repaintEnd = function () { + util.forEach(this.dom.redundant, function (arr) { + while (arr.length) { + var elem = arr.pop(); + if (elem && elem.parentNode) { + elem.parentNode.removeChild(elem); + } + } + }); +}; + + +/** + * Create a minor label for the axis at position x + * @param {Number} x + * @param {String} text + * @private + */ +TimeAxis.prototype._repaintMinorText = function (x, text) { + // reuse redundant label + var label = this.dom.redundant.minorTexts.shift(); + + if (!label) { + // create new label + var content = document.createTextNode(''); + label = document.createElement('div'); + label.appendChild(content); + label.className = 'text minor'; + this.frame.appendChild(label); + } + this.dom.minorTexts.push(label); + + label.childNodes[0].nodeValue = text; + label.style.left = x + 'px'; + label.style.top = this.props.minorLabelTop + 'px'; + //label.title = title; // TODO: this is a heavy operation +}; + +/** + * Create a Major label for the axis at position x + * @param {Number} x + * @param {String} text + * @private + */ +TimeAxis.prototype._repaintMajorText = function (x, text) { + // reuse redundant label + var label = this.dom.redundant.majorTexts.shift(); + + if (!label) { + // create label + var content = document.createTextNode(text); + label = document.createElement('div'); + label.className = 'text major'; + label.appendChild(content); + this.frame.appendChild(label); + } + this.dom.majorTexts.push(label); + + label.childNodes[0].nodeValue = text; + label.style.top = this.props.majorLabelTop + 'px'; + label.style.left = x + 'px'; + //label.title = title; // TODO: this is a heavy operation +}; + +/** + * Create a minor line for the axis at position x + * @param {Number} x + * @private + */ +TimeAxis.prototype._repaintMinorLine = function (x) { + // reuse redundant line + var line = this.dom.redundant.minorLines.shift(); + + if (!line) { + // create vertical line + line = document.createElement('div'); + line.className = 'grid vertical minor'; + this.frame.appendChild(line); + } + this.dom.minorLines.push(line); + + var props = this.props; + line.style.top = props.minorLineTop + 'px'; + line.style.height = props.minorLineHeight + 'px'; + line.style.left = (x - props.minorLineWidth / 2) + 'px'; +}; + +/** + * Create a Major line for the axis at position x + * @param {Number} x + * @private + */ +TimeAxis.prototype._repaintMajorLine = function (x) { + // reuse redundant line + var line = this.dom.redundant.majorLines.shift(); + + if (!line) { + // create vertical line + line = document.createElement('DIV'); + line.className = 'grid vertical major'; + this.frame.appendChild(line); + } + this.dom.majorLines.push(line); + + var props = this.props; + line.style.top = props.majorLineTop + 'px'; + line.style.left = (x - props.majorLineWidth / 2) + 'px'; + line.style.height = props.majorLineHeight + 'px'; +}; + + +/** + * Repaint the horizontal line for the axis + * @private + */ +TimeAxis.prototype._repaintLine = function() { + var line = this.dom.line, + frame = this.frame, + options = this.options; + + // line before all axis elements + if (this.getOption('showMinorLabels') || this.getOption('showMajorLabels')) { + if (line) { + // put this line at the end of all childs + frame.removeChild(line); + frame.appendChild(line); + } + else { + // create the axis line + line = document.createElement('div'); + line.className = 'grid horizontal major'; + frame.appendChild(line); + this.dom.line = line; + } + + line.style.top = this.props.lineTop + 'px'; + } + else { + if (line && line.parentElement) { + frame.removeChild(line.line); + delete this.dom.line; + } + } +}; + +/** + * Create characters used to determine the size of text on the axis + * @private + */ +TimeAxis.prototype._repaintMeasureChars = function () { + // calculate the width and height of a single character + // this is used to calculate the step size, and also the positioning of the + // axis + var dom = this.dom, + text; + + if (!dom.measureCharMinor) { + text = document.createTextNode('0'); + var measureCharMinor = document.createElement('DIV'); + measureCharMinor.className = 'text minor measure'; + measureCharMinor.appendChild(text); + this.frame.appendChild(measureCharMinor); + + dom.measureCharMinor = measureCharMinor; + } + + if (!dom.measureCharMajor) { + text = document.createTextNode('0'); + var measureCharMajor = document.createElement('DIV'); + measureCharMajor.className = 'text major measure'; + measureCharMajor.appendChild(text); + this.frame.appendChild(measureCharMajor); + + dom.measureCharMajor = measureCharMajor; + } +}; + +/** + * Reflow the component + * @return {Boolean} resized + */ +TimeAxis.prototype.reflow = function () { + var changed = 0, + update = util.updateProperty, + frame = this.frame, + range = this.range; + + if (!range) { + throw new Error('Cannot repaint time axis: no range configured'); + } + + if (frame) { + changed += update(this, 'top', frame.offsetTop); + changed += update(this, 'left', frame.offsetLeft); + + // calculate size of a character + var props = this.props, + showMinorLabels = this.getOption('showMinorLabels'), + showMajorLabels = this.getOption('showMajorLabels'), + measureCharMinor = this.dom.measureCharMinor, + measureCharMajor = this.dom.measureCharMajor; + if (measureCharMinor) { + props.minorCharHeight = measureCharMinor.clientHeight; + props.minorCharWidth = measureCharMinor.clientWidth; + } + if (measureCharMajor) { + props.majorCharHeight = measureCharMajor.clientHeight; + props.majorCharWidth = measureCharMajor.clientWidth; + } + + var parentHeight = frame.parentNode ? frame.parentNode.offsetHeight : 0; + if (parentHeight != props.parentHeight) { + props.parentHeight = parentHeight; + changed += 1; + } + switch (this.getOption('orientation')) { + case 'bottom': + props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; + props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; + + props.minorLabelTop = 0; + props.majorLabelTop = props.minorLabelTop + props.minorLabelHeight; + + props.minorLineTop = -this.top; + props.minorLineHeight = Math.max(this.top + props.majorLabelHeight, 0); + props.minorLineWidth = 1; // TODO: really calculate width + + props.majorLineTop = -this.top; + props.majorLineHeight = Math.max(this.top + props.minorLabelHeight + props.majorLabelHeight, 0); + props.majorLineWidth = 1; // TODO: really calculate width + + props.lineTop = 0; + + break; + + case 'top': + props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; + props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; + + props.majorLabelTop = 0; + props.minorLabelTop = props.majorLabelTop + props.majorLabelHeight; + + props.minorLineTop = props.minorLabelTop; + props.minorLineHeight = Math.max(parentHeight - props.majorLabelHeight - this.top); + props.minorLineWidth = 1; // TODO: really calculate width + + props.majorLineTop = 0; + props.majorLineHeight = Math.max(parentHeight - this.top); + props.majorLineWidth = 1; // TODO: really calculate width + + props.lineTop = props.majorLabelHeight + props.minorLabelHeight; + + break; + + default: + throw new Error('Unkown orientation "' + this.getOption('orientation') + '"'); + } + + var height = props.minorLabelHeight + props.majorLabelHeight; + changed += update(this, 'width', frame.offsetWidth); + changed += update(this, 'height', height); + + // calculate range and step + this._updateConversion(); + + var start = util.convert(range.start, 'Number'), + end = util.convert(range.end, 'Number'), + minimumStep = this.toTime((props.minorCharWidth || 10) * 5).valueOf() + -this.toTime(0).valueOf(); + this.step = new TimeStep(new Date(start), new Date(end), minimumStep); + changed += update(props.range, 'start', start); + changed += update(props.range, 'end', end); + changed += update(props.range, 'minimumStep', minimumStep.valueOf()); + } + + return (changed > 0); +}; + +/** + * Calculate the scale and offset to convert a position on screen to the + * corresponding date and vice versa. + * After the method _updateConversion is executed once, the methods toTime + * and toScreen can be used. + * @private + */ +TimeAxis.prototype._updateConversion = function() { + var range = this.range; + if (!range) { + throw new Error('No range configured'); + } + + if (range.conversion) { + this.conversion = range.conversion(this.width); + } + else { + this.conversion = Range.conversion(range.start, range.end, this.width); + } +}; + +/** + * A current time bar + * @param {Component} parent + * @param {Component[]} [depends] Components on which this components depends + * (except for the parent) + * @param {Object} [options] Available parameters: + * {Boolean} [showCurrentTime] + * @constructor CurrentTime + * @extends Component + */ + +function CurrentTime (parent, depends, options) { + this.id = util.randomUUID(); + this.parent = parent; + this.depends = depends; + + this.options = options || {}; + this.defaultOptions = { + showCurrentTime: false + }; +} + +CurrentTime.prototype = new Component(); + +CurrentTime.prototype.setOptions = Component.prototype.setOptions; + +/** + * Get the container element of the bar, which can be used by a child to + * add its own widgets. + * @returns {HTMLElement} container + */ +CurrentTime.prototype.getContainer = function () { + return this.frame; +}; + +/** + * Repaint the component + * @return {Boolean} changed + */ +CurrentTime.prototype.repaint = function () { + var bar = this.frame, + parent = this.parent, + parentContainer = parent.parent.getContainer(); + + if (!parent) { + throw new Error('Cannot repaint bar: no parent attached'); + } + + if (!parentContainer) { + throw new Error('Cannot repaint bar: parent has no container element'); + } + + if (!this.getOption('showCurrentTime')) { + if (bar) { + parentContainer.removeChild(bar); + delete this.frame; + } + + return; + } + + if (!bar) { + bar = document.createElement('div'); + bar.className = 'currenttime'; + bar.style.position = 'absolute'; + bar.style.top = '0px'; + bar.style.height = '100%'; + + parentContainer.appendChild(bar); + this.frame = bar; + } + + if (!parent.conversion) { + parent._updateConversion(); + } + + var now = new Date(); + var x = parent.toScreen(now); + + bar.style.left = x + 'px'; + bar.title = 'Current time: ' + now; + + // start a timer to adjust for the new time + if (this.currentTimeTimer !== undefined) { + clearTimeout(this.currentTimeTimer); + delete this.currentTimeTimer; + } + + var timeline = this; + var interval = 1 / parent.conversion.scale / 2; + + if (interval < 30) { + interval = 30; + } + + this.currentTimeTimer = setTimeout(function() { + timeline.repaint(); + }, interval); + + return false; +}; + +/** + * A custom time bar + * @param {Component} parent + * @param {Component[]} [depends] Components on which this components depends + * (except for the parent) + * @param {Object} [options] Available parameters: + * {Boolean} [showCustomTime] + * @constructor CustomTime + * @extends Component + */ + +function CustomTime (parent, depends, options) { + this.id = util.randomUUID(); + this.parent = parent; + this.depends = depends; + + this.options = options || {}; + this.defaultOptions = { + showCustomTime: false + }; + + this.listeners = []; + this.customTime = new Date(); +} + +CustomTime.prototype = new Component(); + +CustomTime.prototype.setOptions = Component.prototype.setOptions; + +/** + * Get the container element of the bar, which can be used by a child to + * add its own widgets. + * @returns {HTMLElement} container + */ +CustomTime.prototype.getContainer = function () { + return this.frame; +}; + +/** + * Repaint the component + * @return {Boolean} changed + */ +CustomTime.prototype.repaint = function () { + var bar = this.frame, + parent = this.parent, + parentContainer = parent.parent.getContainer(); + + if (!parent) { + throw new Error('Cannot repaint bar: no parent attached'); + } + + if (!parentContainer) { + throw new Error('Cannot repaint bar: parent has no container element'); + } + + if (!this.getOption('showCustomTime')) { + if (bar) { + parentContainer.removeChild(bar); + delete this.frame; + } + + return; + } + + if (!bar) { + bar = document.createElement('div'); + bar.className = 'customtime'; + bar.style.position = 'absolute'; + bar.style.top = '0px'; + bar.style.height = '100%'; + + parentContainer.appendChild(bar); + + var drag = document.createElement('div'); + drag.style.position = 'relative'; + drag.style.top = '0px'; + drag.style.left = '-10px'; + drag.style.height = '100%'; + drag.style.width = '20px'; + bar.appendChild(drag); + + this.frame = bar; + + this.subscribe(this, 'movetime'); + } + + if (!parent.conversion) { + parent._updateConversion(); + } + + var x = parent.toScreen(this.customTime); + + bar.style.left = x + 'px'; + bar.title = 'Time: ' + this.customTime; + + return false; +}; + +/** + * Set custom time. + * @param {Date} time + */ +CustomTime.prototype._setCustomTime = function(time) { + this.customTime = new Date(time.valueOf()); + this.repaint(); +}; + +/** + * Retrieve the current custom time. + * @return {Date} customTime + */ +CustomTime.prototype._getCustomTime = function() { + return new Date(this.customTime.valueOf()); +}; + +/** + * Add listeners for mouse and touch events to the component + * @param {Component} component + */ +CustomTime.prototype.subscribe = function (component, event) { + var me = this; + var listener = { + component: component, + event: event, + callback: function (event) { + me._onMouseDown(event, listener); + }, + params: {} + }; + + component.on('mousedown', listener.callback); + me.listeners.push(listener); + +}; + +/** + * Event handler + * @param {String} event name of the event, for example 'click', 'mousemove' + * @param {function} callback callback handler, invoked with the raw HTML Event + * as parameter. + */ +CustomTime.prototype.on = function (event, callback) { + var bar = this.frame; + if (!bar) { + throw new Error('Cannot add event listener: no parent attached'); + } + + events.addListener(this, event, callback); + util.addEventListener(bar, event, callback); +}; + +/** + * Start moving horizontally + * @param {Event} event + * @param {Object} listener Listener containing the component and params + * @private + */ +CustomTime.prototype._onMouseDown = function(event, listener) { + event = event || window.event; + var params = listener.params; + + // only react on left mouse button down + var leftButtonDown = event.which ? (event.which == 1) : (event.button == 1); + if (!leftButtonDown) { + return; + } + + // get mouse position + params.mouseX = util.getPageX(event); + params.moved = false; + + params.customTime = this.customTime; + + // add event listeners to handle moving the custom time bar + var me = this; + if (!params.onMouseMove) { + params.onMouseMove = function (event) { + me._onMouseMove(event, listener); + }; + util.addEventListener(document, 'mousemove', params.onMouseMove); + } + if (!params.onMouseUp) { + params.onMouseUp = function (event) { + me._onMouseUp(event, listener); + }; + util.addEventListener(document, 'mouseup', params.onMouseUp); + } + + util.stopPropagation(event); + util.preventDefault(event); +}; + +/** + * Perform moving operating. + * This function activated from within the funcion CustomTime._onMouseDown(). + * @param {Event} event + * @param {Object} listener + * @private + */ +CustomTime.prototype._onMouseMove = function (event, listener) { + event = event || window.event; + var params = listener.params; + var parent = this.parent; + + // calculate change in mouse position + var mouseX = util.getPageX(event); + + if (params.mouseX === undefined) { + params.mouseX = mouseX; + } + + var diff = mouseX - params.mouseX; + + // if mouse movement is big enough, register it as a "moved" event + if (Math.abs(diff) >= 1) { + params.moved = true; + } + + var x = parent.toScreen(params.customTime); + var xnew = x + diff; + var time = parent.toTime(xnew); + this._setCustomTime(time); + + // fire a timechange event + events.trigger(this, 'timechange', {customTime: this.customTime}); + + util.preventDefault(event); +}; + +/** + * Stop moving operating. + * This function activated from within the function CustomTime._onMouseDown(). + * @param {event} event + * @param {Object} listener + * @private + */ +CustomTime.prototype._onMouseUp = function (event, listener) { + event = event || window.event; + var params = listener.params; + + // remove event listeners here, important for Safari + if (params.onMouseMove) { + util.removeEventListener(document, 'mousemove', params.onMouseMove); + params.onMouseMove = null; + } + if (params.onMouseUp) { + util.removeEventListener(document, 'mouseup', params.onMouseUp); + params.onMouseUp = null; + } + + if (params.moved) { + // fire a timechanged event + events.trigger(this, 'timechanged', {customTime: this.customTime}); + } +}; + +/** + * An ItemSet holds a set of items and ranges which can be displayed in a + * range. The width is determined by the parent of the ItemSet, and the height + * is determined by the size of the items. + * @param {Component} parent + * @param {Component[]} [depends] Components on which this components depends + * (except for the parent) + * @param {Object} [options] See ItemSet.setOptions for the available + * options. + * @constructor ItemSet + * @extends Panel + */ +// TODO: improve performance by replacing all Array.forEach with a for loop +function ItemSet(parent, depends, options) { + this.id = util.randomUUID(); + this.parent = parent; + this.depends = depends; + + // one options object is shared by this itemset and all its items + this.options = options || {}; + this.defaultOptions = { + type: 'box', + align: 'center', + orientation: 'bottom', + margin: { + axis: 20, + item: 10 + }, + padding: 5 + }; + + this.dom = {}; + + var me = this; + this.itemsData = null; // DataSet + this.range = null; // Range or Object {start: number, end: number} + + this.listeners = { + 'add': function (event, params, senderId) { + if (senderId != me.id) { + me._onAdd(params.items); + } + }, + 'update': function (event, params, senderId) { + if (senderId != me.id) { + me._onUpdate(params.items); + } + }, + 'remove': function (event, params, senderId) { + if (senderId != me.id) { + me._onRemove(params.items); + } + } + }; + + this.items = {}; // object with an Item for every data item + this.queue = {}; // queue with id/actions: 'add', 'update', 'delete' + this.stack = new Stack(this, Object.create(this.options)); + this.conversion = null; + + // TODO: ItemSet should also attach event listeners for rangechange and rangechanged, like timeaxis +} + +ItemSet.prototype = new Panel(); + +// available item types will be registered here +ItemSet.types = { + box: ItemBox, + range: ItemRange, + rangeoverflow: ItemRangeOverflow, + point: ItemPoint +}; + +/** + * Set options for the ItemSet. Existing options will be extended/overwritten. + * @param {Object} [options] The following options are available: + * {String | function} [className] + * class name for the itemset + * {String} [type] + * Default type for the items. Choose from 'box' + * (default), 'point', or 'range'. The default + * Style can be overwritten by individual items. + * {String} align + * Alignment for the items, only applicable for + * ItemBox. Choose 'center' (default), 'left', or + * 'right'. + * {String} orientation + * Orientation of the item set. Choose 'top' or + * 'bottom' (default). + * {Number} margin.axis + * Margin between the axis and the items in pixels. + * Default is 20. + * {Number} margin.item + * Margin between items in pixels. Default is 10. + * {Number} padding + * Padding of the contents of an item in pixels. + * Must correspond with the items css. Default is 5. + */ +ItemSet.prototype.setOptions = Component.prototype.setOptions; + +/** + * Set range (start and end). + * @param {Range | Object} range A Range or an object containing start and end. + */ +ItemSet.prototype.setRange = function setRange(range) { + if (!(range instanceof Range) && (!range || !range.start || !range.end)) { + throw new TypeError('Range must be an instance of Range, ' + + 'or an object containing start and end.'); + } + this.range = range; +}; + +/** + * Repaint the component + * @return {Boolean} changed + */ +ItemSet.prototype.repaint = function repaint() { + var changed = 0, + update = util.updateProperty, + asSize = util.option.asSize, + options = this.options, + orientation = this.getOption('orientation'), + defaultOptions = this.defaultOptions, + frame = this.frame; + + if (!frame) { + frame = document.createElement('div'); + frame.className = 'itemset'; + + var className = options.className; + if (className) { + util.addClassName(frame, util.option.asString(className)); + } + + // create background panel + var background = document.createElement('div'); + background.className = 'background'; + frame.appendChild(background); + this.dom.background = background; + + // create foreground panel + var foreground = document.createElement('div'); + foreground.className = 'foreground'; + frame.appendChild(foreground); + this.dom.foreground = foreground; + + // create axis panel + var axis = document.createElement('div'); + axis.className = 'itemset-axis'; + //frame.appendChild(axis); + this.dom.axis = axis; + + this.frame = frame; + changed += 1; + } + + if (!this.parent) { + throw new Error('Cannot repaint itemset: no parent attached'); + } + var parentContainer = this.parent.getContainer(); + if (!parentContainer) { + throw new Error('Cannot repaint itemset: parent has no container element'); + } + if (!frame.parentNode) { + parentContainer.appendChild(frame); + changed += 1; + } + if (!this.dom.axis.parentNode) { + parentContainer.appendChild(this.dom.axis); + changed += 1; + } + + // reposition frame + changed += update(frame.style, 'left', asSize(options.left, '0px')); + changed += update(frame.style, 'top', asSize(options.top, '0px')); + changed += update(frame.style, 'width', asSize(options.width, '100%')); + changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); + + // reposition axis + changed += update(this.dom.axis.style, 'left', asSize(options.left, '0px')); + changed += update(this.dom.axis.style, 'width', asSize(options.width, '100%')); + if (orientation == 'bottom') { + changed += update(this.dom.axis.style, 'top', (this.height + this.top) + 'px'); + } + else { // orientation == 'top' + changed += update(this.dom.axis.style, 'top', this.top + 'px'); + } + + this._updateConversion(); + + var me = this, + queue = this.queue, + itemsData = this.itemsData, + items = this.items, + dataOptions = { + // TODO: cleanup + // fields: [(itemsData && itemsData.fieldId || 'id'), 'start', 'end', 'content', 'type', 'className'] + }; + + // show/hide added/changed/removed items + Object.keys(queue).forEach(function (id) { + //var entry = queue[id]; + var action = queue[id]; + var item = items[id]; + //var item = entry.item; + //noinspection FallthroughInSwitchStatementJS + switch (action) { + case 'add': + case 'update': + var itemData = itemsData && itemsData.get(id, dataOptions); + + if (itemData) { + var type = itemData.type || + (itemData.start && itemData.end && 'range') || + options.type || + 'box'; + var constructor = ItemSet.types[type]; + + // TODO: how to handle items with invalid data? hide them and give a warning? or throw an error? + if (item) { + // update item + if (!constructor || !(item instanceof constructor)) { + // item type has changed, hide and delete the item + changed += item.hide(); + item = null; + } + else { + item.data = itemData; // TODO: create a method item.setData ? + changed++; + } + } + + if (!item) { + // create item + if (constructor) { + item = new constructor(me, itemData, options, defaultOptions); + changed++; + } + else { + throw new TypeError('Unknown item type "' + type + '"'); + } + } + + // force a repaint (not only a reposition) + item.repaint(); + + items[id] = item; + } + + // update queue + delete queue[id]; + break; + + case 'remove': + if (item) { + // remove DOM of the item + changed += item.hide(); + } + + // update lists + delete items[id]; + delete queue[id]; + break; + + default: + console.log('Error: unknown action "' + action + '"'); + } + }); + + // reposition all items. Show items only when in the visible area + util.forEach(this.items, function (item) { + if (item.visible) { + changed += item.show(); + item.reposition(); + } + else { + changed += item.hide(); + } + }); + + return (changed > 0); +}; + +/** + * Get the foreground container element + * @return {HTMLElement} foreground + */ +ItemSet.prototype.getForeground = function getForeground() { + return this.dom.foreground; +}; + +/** + * Get the background container element + * @return {HTMLElement} background + */ +ItemSet.prototype.getBackground = function getBackground() { + return this.dom.background; +}; + +/** + * Get the axis container element + * @return {HTMLElement} axis + */ +ItemSet.prototype.getAxis = function getAxis() { + return this.dom.axis; +}; + +/** + * Reflow the component + * @return {Boolean} resized + */ +ItemSet.prototype.reflow = function reflow () { + var changed = 0, + options = this.options, + marginAxis = options.margin && options.margin.axis || this.defaultOptions.margin.axis, + marginItem = options.margin && options.margin.item || this.defaultOptions.margin.item, + update = util.updateProperty, + asNumber = util.option.asNumber, + asSize = util.option.asSize, + frame = this.frame; + + if (frame) { + this._updateConversion(); + + util.forEach(this.items, function (item) { + changed += item.reflow(); + }); + + // TODO: stack.update should be triggered via an event, in stack itself + // TODO: only update the stack when there are changed items + this.stack.update(); + + var maxHeight = asNumber(options.maxHeight); + var fixedHeight = (asSize(options.height) != null); + var height; + if (fixedHeight) { + height = frame.offsetHeight; + } + else { + // height is not specified, determine the height from the height and positioned items + var visibleItems = this.stack.ordered; // TODO: not so nice way to get the filtered items + if (visibleItems.length) { + var min = visibleItems[0].top; + var max = visibleItems[0].top + visibleItems[0].height; + util.forEach(visibleItems, function (item) { + min = Math.min(min, item.top); + max = Math.max(max, (item.top + item.height)); + }); + height = (max - min) + marginAxis + marginItem; + } + else { + height = marginAxis + marginItem; + } + } + if (maxHeight != null) { + height = Math.min(height, maxHeight); + } + changed += update(this, 'height', height); + + // calculate height from items + changed += update(this, 'top', frame.offsetTop); + changed += update(this, 'left', frame.offsetLeft); + changed += update(this, 'width', frame.offsetWidth); + } + else { + changed += 1; + } + + return (changed > 0); +}; + +/** + * Hide this component from the DOM + * @return {Boolean} changed + */ +ItemSet.prototype.hide = function hide() { + var changed = false; + + // remove the DOM + if (this.frame && this.frame.parentNode) { + this.frame.parentNode.removeChild(this.frame); + changed = true; + } + if (this.dom.axis && this.dom.axis.parentNode) { + this.dom.axis.parentNode.removeChild(this.dom.axis); + changed = true; + } + + return changed; +}; + +/** + * Set items + * @param {vis.DataSet | null} items + */ +ItemSet.prototype.setItems = function setItems(items) { + var me = this, + ids, + oldItemsData = this.itemsData; + + // replace the dataset + if (!items) { + this.itemsData = null; + } + else if (items instanceof DataSet || items instanceof DataView) { + this.itemsData = items; + } + else { + throw new TypeError('Data must be an instance of DataSet'); + } + + if (oldItemsData) { + // unsubscribe from old dataset + util.forEach(this.listeners, function (callback, event) { + oldItemsData.unsubscribe(event, callback); + }); + + // remove all drawn items + ids = oldItemsData.getIds(); + this._onRemove(ids); + } + + if (this.itemsData) { + // subscribe to new dataset + var id = this.id; + util.forEach(this.listeners, function (callback, event) { + me.itemsData.subscribe(event, callback, id); + }); + + // draw all new items + ids = this.itemsData.getIds(); + this._onAdd(ids); + } +}; + +/** + * Get the current items items + * @returns {vis.DataSet | null} + */ +ItemSet.prototype.getItems = function getItems() { + return this.itemsData; +}; + +/** + * Handle updated items + * @param {Number[]} ids + * @private + */ +ItemSet.prototype._onUpdate = function _onUpdate(ids) { + this._toQueue('update', ids); +}; + +/** + * Handle changed items + * @param {Number[]} ids + * @private + */ +ItemSet.prototype._onAdd = function _onAdd(ids) { + this._toQueue('add', ids); +}; + +/** + * Handle removed items + * @param {Number[]} ids + * @private + */ +ItemSet.prototype._onRemove = function _onRemove(ids) { + this._toQueue('remove', ids); +}; + +/** + * Put items in the queue to be added/updated/remove + * @param {String} action can be 'add', 'update', 'remove' + * @param {Number[]} ids + */ +ItemSet.prototype._toQueue = function _toQueue(action, ids) { + var queue = this.queue; + ids.forEach(function (id) { + queue[id] = action; + }); + + if (this.controller) { + //this.requestReflow(); + this.requestRepaint(); + } +}; + +/** + * Calculate the scale and offset to convert a position on screen to the + * corresponding date and vice versa. + * After the method _updateConversion is executed once, the methods toTime + * and toScreen can be used. + * @private + */ +ItemSet.prototype._updateConversion = function _updateConversion() { + var range = this.range; + if (!range) { + throw new Error('No range configured'); + } + + if (range.conversion) { + this.conversion = range.conversion(this.width); + } + else { + this.conversion = Range.conversion(range.start, range.end, this.width); + } +}; + +/** + * Convert a position on screen (pixels) to a datetime + * Before this method can be used, the method _updateConversion must be + * executed once. + * @param {int} x Position on the screen in pixels + * @return {Date} time The datetime the corresponds with given position x + */ +ItemSet.prototype.toTime = function toTime(x) { + var conversion = this.conversion; + return new Date(x / conversion.scale + conversion.offset); +}; + +/** + * Convert a datetime (Date object) into a position on the screen + * Before this method can be used, the method _updateConversion must be + * executed once. + * @param {Date} time A date + * @return {int} x The position on the screen in pixels which corresponds + * with the given date. + */ +ItemSet.prototype.toScreen = function toScreen(time) { + var conversion = this.conversion; + return (time.valueOf() - conversion.offset) * conversion.scale; +}; + +/** + * @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; + this.data = data; + this.dom = null; + this.options = options || {}; + this.defaultOptions = defaultOptions || {}; + + this.selected = false; + this.visible = false; + this.top = 0; + this.left = 0; + this.width = 0; + this.height = 0; +} + +/** + * Select current item + */ +Item.prototype.select = function select() { + this.selected = true; +}; + +/** + * Unselect current item + */ +Item.prototype.unselect = function unselect() { + this.selected = false; +}; + +/** + * Show the Item in the DOM (when not already visible) + * @return {Boolean} changed + */ +Item.prototype.show = function show() { + return false; +}; + +/** + * Hide the Item from the DOM (when visible) + * @return {Boolean} changed + */ +Item.prototype.hide = function hide() { + return false; +}; + +/** + * Repaint the item + * @return {Boolean} changed + */ +Item.prototype.repaint = function repaint() { + // should be implemented by the item + return false; +}; + +/** + * Reflow the item + * @return {Boolean} resized + */ +Item.prototype.reflow = function reflow() { + // should be implemented by the item + return false; +}; + +/** + * Return the items width + * @return {Integer} width + */ +Item.prototype.getWidth = function getWidth() { + return this.width; +} + +/** + * @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) { + this.props = { + dot: { + left: 0, + top: 0, + width: 0, + height: 0 + }, + line: { + top: 0, + left: 0, + width: 0, + height: 0 + } + }; + + Item.call(this, parent, data, options, defaultOptions); +} + +ItemBox.prototype = new Item (null, null); + +/** + * Select the item + * @override + */ +ItemBox.prototype.select = function select() { + this.selected = true; + // TODO: select and unselect +}; + +/** + * Unselect the item + * @override + */ +ItemBox.prototype.unselect = function unselect() { + this.selected = false; + // TODO: select and unselect +}; + +/** + * Repaint the item + * @return {Boolean} changed + */ +ItemBox.prototype.repaint = function repaint() { + // TODO: make an efficient repaint + var changed = false; + var dom = this.dom; + + if (!dom) { + this._create(); + dom = this.dom; + changed = true; + } + + if (dom) { + if (!this.parent) { + throw new Error('Cannot repaint item: no parent attached'); + } + + if (!dom.box.parentNode) { + var foreground = this.parent.getForeground(); + if (!foreground) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no foreground container element'); + } + foreground.appendChild(dom.box); + changed = true; + } + + if (!dom.line.parentNode) { + var background = this.parent.getBackground(); + if (!background) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no background container element'); + } + background.appendChild(dom.line); + changed = true; + } + + if (!dom.dot.parentNode) { + var axis = this.parent.getAxis(); + if (!background) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no axis container element'); + } + axis.appendChild(dom.dot); + changed = true; + } + + // update contents + if (this.data.content != this.content) { + this.content = this.data.content; + if (this.content instanceof Element) { + dom.content.innerHTML = ''; + dom.content.appendChild(this.content); + } + else if (this.data.content != undefined) { + dom.content.innerHTML = this.content; + } + else { + throw new Error('Property "content" missing in item ' + this.data.id); + } + changed = true; + } + + // update class + var className = (this.data.className? ' ' + this.data.className : '') + + (this.selected ? ' selected' : ''); + if (this.className != className) { + this.className = className; + dom.box.className = 'item box' + className; + dom.line.className = 'item line' + className; + dom.dot.className = 'item dot' + className; + changed = true; + } + } + + return changed; +}; + +/** + * Show the item in the DOM (when not already visible). The items DOM will + * be created when needed. + * @return {Boolean} changed + */ +ItemBox.prototype.show = function show() { + if (!this.dom || !this.dom.box.parentNode) { + return this.repaint(); + } + else { + return false; + } +}; + +/** + * Hide the item from the DOM (when visible) + * @return {Boolean} changed + */ +ItemBox.prototype.hide = function hide() { + var changed = false, + dom = this.dom; + if (dom) { + if (dom.box.parentNode) { + dom.box.parentNode.removeChild(dom.box); + changed = true; + } + if (dom.line.parentNode) { + dom.line.parentNode.removeChild(dom.line); + } + if (dom.dot.parentNode) { + dom.dot.parentNode.removeChild(dom.dot); + } + } + return changed; +}; + +/** + * Reflow the item: calculate its actual size and position from the DOM + * @return {boolean} resized returns true if the axis is resized + * @override + */ +ItemBox.prototype.reflow = function reflow() { + var changed = 0, + update, + dom, + props, + options, + margin, + start, + align, + orientation, + top, + left, + data, + range; + + if (this.data.start == undefined) { + throw new Error('Property "start" missing in item ' + this.data.id); + } + + data = this.data; + range = this.parent && this.parent.range; + if (data && range) { + // TODO: account for the width of the item + var interval = (range.end - range.start); + this.visible = (data.start > range.start - interval) && (data.start < range.end + interval); + } + else { + this.visible = false; + } + + if (this.visible) { + dom = this.dom; + if (dom) { + update = util.updateProperty; + props = this.props; + options = this.options; + start = this.parent.toScreen(this.data.start); + align = options.align || this.defaultOptions.align; + margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; + orientation = options.orientation || this.defaultOptions.orientation; + + changed += update(props.dot, 'height', dom.dot.offsetHeight); + changed += update(props.dot, 'width', dom.dot.offsetWidth); + changed += update(props.line, 'width', dom.line.offsetWidth); + changed += update(props.line, 'height', dom.line.offsetHeight); + changed += update(props.line, 'top', dom.line.offsetTop); + changed += update(this, 'width', dom.box.offsetWidth); + changed += update(this, 'height', dom.box.offsetHeight); + if (align == 'right') { + left = start - this.width; + } + else if (align == 'left') { + left = start; + } + else { + // default or 'center' + left = start - this.width / 2; + } + changed += update(this, 'left', left); + + changed += update(props.line, 'left', start - props.line.width / 2); + changed += update(props.dot, 'left', start - props.dot.width / 2); + changed += update(props.dot, 'top', -props.dot.height / 2); + if (orientation == 'top') { + top = margin; + + changed += update(this, 'top', top); + } + else { + // default or 'bottom' + var parentHeight = this.parent.height; + top = parentHeight - this.height - margin; + + changed += update(this, 'top', top); + } + } + else { + changed += 1; + } + } + + return (changed > 0); +}; + +/** + * Create an items DOM + * @private + */ +ItemBox.prototype._create = function _create() { + var dom = this.dom; + if (!dom) { + this.dom = dom = {}; + + // create the box + dom.box = document.createElement('DIV'); + // className is updated in repaint() + + // contents box (inside the background box). used for making margins + dom.content = document.createElement('DIV'); + dom.content.className = 'content'; + dom.box.appendChild(dom.content); + + // line to axis + dom.line = document.createElement('DIV'); + dom.line.className = 'line'; + + // dot on axis + dom.dot = document.createElement('DIV'); + dom.dot.className = 'dot'; + } +}; + +/** + * Reposition the item, recalculate its left, top, and width, using the current + * range and size of the items itemset + * @override + */ +ItemBox.prototype.reposition = function reposition() { + var dom = this.dom, + props = this.props, + orientation = this.options.orientation || this.defaultOptions.orientation; + + if (dom) { + var box = dom.box, + line = dom.line, + dot = dom.dot; + + box.style.left = this.left + 'px'; + box.style.top = this.top + 'px'; + + line.style.left = props.line.left + 'px'; + if (orientation == 'top') { + line.style.top = 0 + 'px'; + line.style.height = this.top + 'px'; + } + else { + // orientation 'bottom' + line.style.top = (this.top + this.height) + 'px'; + line.style.height = Math.max(this.parent.height - this.top - this.height + + this.props.dot.height / 2, 0) + 'px'; + } + + dot.style.left = props.dot.left + 'px'; + dot.style.top = props.dot.top + 'px'; + } +}; + +/** + * @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) { + this.props = { + dot: { + top: 0, + width: 0, + height: 0 + }, + content: { + height: 0, + marginLeft: 0 + } + }; + + Item.call(this, parent, data, options, defaultOptions); +} + +ItemPoint.prototype = new Item (null, null); + +/** + * Select the item + * @override + */ +ItemPoint.prototype.select = function select() { + this.selected = true; + // TODO: select and unselect +}; + +/** + * Unselect the item + * @override + */ +ItemPoint.prototype.unselect = function unselect() { + this.selected = false; + // TODO: select and unselect +}; + +/** + * Repaint the item + * @return {Boolean} changed + */ +ItemPoint.prototype.repaint = function repaint() { + // TODO: make an efficient repaint + var changed = false; + var dom = this.dom; + + if (!dom) { + this._create(); + dom = this.dom; + changed = true; + } + + if (dom) { + if (!this.parent) { + throw new Error('Cannot repaint item: no parent attached'); + } + var foreground = this.parent.getForeground(); + if (!foreground) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no foreground container element'); + } + + if (!dom.point.parentNode) { + foreground.appendChild(dom.point); + foreground.appendChild(dom.point); + changed = true; + } + + // update contents + if (this.data.content != this.content) { + this.content = this.data.content; + if (this.content instanceof Element) { + dom.content.innerHTML = ''; + dom.content.appendChild(this.content); + } + else if (this.data.content != undefined) { + dom.content.innerHTML = this.content; + } + else { + throw new Error('Property "content" missing in item ' + this.data.id); + } + changed = true; + } + + // update class + var className = (this.data.className? ' ' + this.data.className : '') + + (this.selected ? ' selected' : ''); + if (this.className != className) { + this.className = className; + dom.point.className = 'item point' + className; + changed = true; + } + } + + return changed; +}; + +/** + * Show the item in the DOM (when not already visible). The items DOM will + * be created when needed. + * @return {Boolean} changed + */ +ItemPoint.prototype.show = function show() { + if (!this.dom || !this.dom.point.parentNode) { + return this.repaint(); + } + else { + return false; + } +}; + +/** + * Hide the item from the DOM (when visible) + * @return {Boolean} changed + */ +ItemPoint.prototype.hide = function hide() { + var changed = false, + dom = this.dom; + if (dom) { + if (dom.point.parentNode) { + dom.point.parentNode.removeChild(dom.point); + changed = true; + } + } + return changed; +}; + +/** + * Reflow the item: calculate its actual size from the DOM + * @return {boolean} resized returns true if the axis is resized + * @override + */ +ItemPoint.prototype.reflow = function reflow() { + var changed = 0, + update, + dom, + props, + options, + margin, + orientation, + start, + top, + data, + range; + + if (this.data.start == undefined) { + throw new Error('Property "start" missing in item ' + this.data.id); + } + + data = this.data; + range = this.parent && this.parent.range; + if (data && range) { + // TODO: account for the width of the item + var interval = (range.end - range.start); + this.visible = (data.start > range.start - interval) && (data.start < range.end); + } + else { + this.visible = false; + } + + if (this.visible) { + dom = this.dom; + if (dom) { + update = util.updateProperty; + props = this.props; + options = this.options; + orientation = options.orientation || this.defaultOptions.orientation; + margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; + start = this.parent.toScreen(this.data.start); + + changed += update(this, 'width', dom.point.offsetWidth); + changed += update(this, 'height', dom.point.offsetHeight); + changed += update(props.dot, 'width', dom.dot.offsetWidth); + changed += update(props.dot, 'height', dom.dot.offsetHeight); + changed += update(props.content, 'height', dom.content.offsetHeight); + + if (orientation == 'top') { + top = margin; + } + else { + // default or 'bottom' + var parentHeight = this.parent.height; + top = Math.max(parentHeight - this.height - margin, 0); + } + changed += update(this, 'top', top); + changed += update(this, 'left', start - props.dot.width / 2); + changed += update(props.content, 'marginLeft', 1.5 * props.dot.width); + //changed += update(props.content, 'marginRight', 0.5 * props.dot.width); // TODO + + changed += update(props.dot, 'top', (this.height - props.dot.height) / 2); + } + else { + changed += 1; + } + } + + return (changed > 0); +}; + +/** + * Create an items DOM + * @private + */ +ItemPoint.prototype._create = function _create() { + var dom = this.dom; + if (!dom) { + this.dom = dom = {}; + + // background box + dom.point = document.createElement('div'); + // className is updated in repaint() + + // contents box, right from the dot + dom.content = document.createElement('div'); + dom.content.className = 'content'; + dom.point.appendChild(dom.content); + + // dot at start + dom.dot = document.createElement('div'); + dom.dot.className = 'dot'; + dom.point.appendChild(dom.dot); + } +}; + +/** + * Reposition the item, recalculate its left, top, and width, using the current + * range and size of the items itemset + * @override + */ +ItemPoint.prototype.reposition = function reposition() { + var dom = this.dom, + props = this.props; + + if (dom) { + dom.point.style.top = this.top + 'px'; + dom.point.style.left = this.left + 'px'; + + dom.content.style.marginLeft = props.content.marginLeft + 'px'; + //dom.content.style.marginRight = props.content.marginRight + 'px'; // TODO + + dom.dot.style.top = props.dot.top + 'px'; + } +}; + +/** + * @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) { + this.props = { + content: { + left: 0, + width: 0 + } + }; + + Item.call(this, parent, data, options, defaultOptions); +} + +ItemRange.prototype = new Item (null, null); + +/** + * Select the item + * @override + */ +ItemRange.prototype.select = function select() { + this.selected = true; + // TODO: select and unselect +}; + +/** + * Unselect the item + * @override + */ +ItemRange.prototype.unselect = function unselect() { + this.selected = false; + // TODO: select and unselect +}; + +/** + * Repaint the item + * @return {Boolean} changed + */ +ItemRange.prototype.repaint = function repaint() { + // TODO: make an efficient repaint + var changed = false; + var dom = this.dom; + + if (!dom) { + this._create(); + dom = this.dom; + changed = true; + } + + if (dom) { + if (!this.parent) { + throw new Error('Cannot repaint item: no parent attached'); + } + var foreground = this.parent.getForeground(); + if (!foreground) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no foreground container element'); + } + + if (!dom.box.parentNode) { + foreground.appendChild(dom.box); + changed = true; + } + + // update content + if (this.data.content != this.content) { + this.content = this.data.content; + if (this.content instanceof Element) { + dom.content.innerHTML = ''; + dom.content.appendChild(this.content); + } + else if (this.data.content != undefined) { + dom.content.innerHTML = this.content; + } + else { + throw new Error('Property "content" missing in item ' + this.data.id); + } + changed = true; + } + + // update class + var className = this.data.className ? (' ' + this.data.className) : ''; + if (this.className != className) { + this.className = className; + dom.box.className = 'item range' + className; + changed = true; + } + } + + return changed; +}; + +/** + * Show the item in the DOM (when not already visible). The items DOM will + * be created when needed. + * @return {Boolean} changed + */ +ItemRange.prototype.show = function show() { + if (!this.dom || !this.dom.box.parentNode) { + return this.repaint(); + } + else { + return false; + } +}; + +/** + * Hide the item from the DOM (when visible) + * @return {Boolean} changed + */ +ItemRange.prototype.hide = function hide() { + var changed = false, + dom = this.dom; + if (dom) { + if (dom.box.parentNode) { + dom.box.parentNode.removeChild(dom.box); + changed = true; + } + } + return changed; +}; + +/** + * Reflow the item: calculate its actual size from the DOM + * @return {boolean} resized returns true if the axis is resized + * @override + */ +ItemRange.prototype.reflow = function reflow() { + var changed = 0, + dom, + props, + options, + margin, + padding, + parent, + start, + end, + data, + range, + update, + box, + parentWidth, + contentLeft, + orientation, + top; + + if (this.data.start == undefined) { + throw new Error('Property "start" missing in item ' + this.data.id); + } + if (this.data.end == undefined) { + throw new Error('Property "end" missing in item ' + this.data.id); + } + + data = this.data; + range = this.parent && this.parent.range; + if (data && range) { + // TODO: account for the width of the item. Take some margin + this.visible = (data.start < range.end) && (data.end > range.start); + } + else { + this.visible = false; + } + + if (this.visible) { + dom = this.dom; + if (dom) { + props = this.props; + options = this.options; + parent = this.parent; + start = parent.toScreen(this.data.start); + end = parent.toScreen(this.data.end); + update = util.updateProperty; + box = dom.box; + parentWidth = parent.width; + orientation = options.orientation || this.defaultOptions.orientation; + margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; + padding = options.padding || this.defaultOptions.padding; + + changed += update(props.content, 'width', dom.content.offsetWidth); + + changed += update(this, 'height', box.offsetHeight); + + // limit the width of the this, as browsers cannot draw very wide divs + if (start < -parentWidth) { + start = -parentWidth; + } + if (end > 2 * parentWidth) { + end = 2 * parentWidth; + } + + // when range exceeds left of the window, position the contents at the left of the visible area + if (start < 0) { + contentLeft = Math.min(-start, + (end - start - props.content.width - 2 * padding)); + // TODO: remove the need for options.padding. it's terrible. + } + else { + contentLeft = 0; + } + changed += update(props.content, 'left', contentLeft); + + if (orientation == 'top') { + top = margin; + changed += update(this, 'top', top); + } + else { + // default or 'bottom' + top = parent.height - this.height - margin; + changed += update(this, 'top', top); + } + + changed += update(this, 'left', start); + changed += update(this, 'width', Math.max(end - start, 1)); // TODO: reckon with border width; + } + else { + changed += 1; + } + } + + return (changed > 0); +}; + +/** + * Create an items DOM + * @private + */ +ItemRange.prototype._create = function _create() { + var dom = this.dom; + if (!dom) { + this.dom = dom = {}; + // background box + dom.box = document.createElement('div'); + // className is updated in repaint() + + // contents box + dom.content = document.createElement('div'); + dom.content.className = 'content'; + dom.box.appendChild(dom.content); + } +}; + +/** + * Reposition the item, recalculate its left, top, and width, using the current + * range and size of the items itemset + * @override + */ +ItemRange.prototype.reposition = function reposition() { + var dom = this.dom, + props = this.props; + + if (dom) { + dom.box.style.top = this.top + 'px'; + dom.box.style.left = this.left + 'px'; + dom.box.style.width = this.width + 'px'; + + dom.content.style.left = props.content.left + 'px'; + } +}; + +/** + * @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) { + this.props = { + content: { + left: 0, + width: 0 + } + }; + + ItemRange.call(this, parent, data, options, defaultOptions); +} + +ItemRangeOverflow.prototype = new ItemRange (null, null); + +/** + * Repaint the item + * @return {Boolean} changed + */ +ItemRangeOverflow.prototype.repaint = function repaint() { + // TODO: make an efficient repaint + var changed = false; + var dom = this.dom; + + if (!dom) { + this._create(); + dom = this.dom; + changed = true; + } + + if (dom) { + if (!this.parent) { + throw new Error('Cannot repaint item: no parent attached'); + } + var foreground = this.parent.getForeground(); + if (!foreground) { + throw new Error('Cannot repaint time axis: ' + + 'parent has no foreground container element'); + } + + if (!dom.box.parentNode) { + foreground.appendChild(dom.box); + changed = true; + } + + // update content + if (this.data.content != this.content) { + this.content = this.data.content; + if (this.content instanceof Element) { + dom.content.innerHTML = ''; + dom.content.appendChild(this.content); + } + else if (this.data.content != undefined) { + dom.content.innerHTML = this.content; + } + else { + throw new Error('Property "content" missing in item ' + this.data.id); + } + changed = true; + } + + // update class + var className = this.data.className ? (' ' + this.data.className) : ''; + if (this.className != className) { + this.className = className; + dom.box.className = 'item rangeoverflow' + className; + changed = true; + } + } + + return changed; +}; + +/** + * Return the items width + * @return {Number} width + */ +ItemRangeOverflow.prototype.getWidth = function getWidth() { + if (this.props.content !== undefined && this.width < this.props.content.width) + return this.props.content.width; + else + return this.width; +}; + +/** + * @constructor Group + * @param {GroupSet} parent + * @param {Number | String} groupId + * @param {Object} [options] Options to set initial property values + * // TODO: describe available options + * @extends Component + */ +function Group (parent, groupId, options) { + this.id = util.randomUUID(); + this.parent = parent; + + this.groupId = groupId; + this.itemset = null; // ItemSet + this.options = options || {}; + this.options.top = 0; + + this.props = { + label: { + width: 0, + height: 0 + } + }; + + this.top = 0; + this.left = 0; + this.width = 0; + this.height = 0; +} + +Group.prototype = new Component(); + +// TODO: comment +Group.prototype.setOptions = Component.prototype.setOptions; + +/** + * Get the container element of the panel, which can be used by a child to + * add its own widgets. + * @returns {HTMLElement} container + */ +Group.prototype.getContainer = function () { + return this.parent.getContainer(); +}; + +/** + * Set item set for the group. The group will create a view on the itemset, + * filtered by the groups id. + * @param {DataSet | DataView} items + */ +Group.prototype.setItems = function setItems(items) { + if (this.itemset) { + // remove current item set + this.itemset.hide(); + this.itemset.setItems(); + + this.parent.controller.remove(this.itemset); + this.itemset = null; + } + + if (items) { + var groupId = this.groupId; + + var itemsetOptions = Object.create(this.options); + this.itemset = new ItemSet(this, null, itemsetOptions); + this.itemset.setRange(this.parent.range); + + this.view = new DataView(items, { + filter: function (item) { + return item.group == groupId; + } + }); + this.itemset.setItems(this.view); + + this.parent.controller.add(this.itemset); + } +}; + +/** + * Repaint the item + * @return {Boolean} changed + */ +Group.prototype.repaint = function repaint() { + return false; +}; + +/** + * Reflow the item + * @return {Boolean} resized + */ +Group.prototype.reflow = function reflow() { + var changed = 0, + update = util.updateProperty; + + changed += update(this, 'top', this.itemset ? this.itemset.top : 0); + changed += update(this, 'height', this.itemset ? this.itemset.height : 0); + + // TODO: reckon with the height of the group label + + if (this.label) { + var inner = this.label.firstChild; + changed += update(this.props.label, 'width', inner.clientWidth); + changed += update(this.props.label, 'height', inner.clientHeight); + } + else { + changed += update(this.props.label, 'width', 0); + changed += update(this.props.label, 'height', 0); + } + + return (changed > 0); +}; + +/** + * An GroupSet holds a set of groups + * @param {Component} parent + * @param {Component[]} [depends] Components on which this components depends + * (except for the parent) + * @param {Object} [options] See GroupSet.setOptions for the available + * options. + * @constructor GroupSet + * @extends Panel + */ +function GroupSet(parent, depends, options) { + this.id = util.randomUUID(); + this.parent = parent; + this.depends = depends; + + 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.dom = {}; + this.props = { + labels: { + width: 0 + } + }; + + // TODO: implement right orientation of the labels + + // changes in groups are queued key/value map containing id/action + this.queue = {}; + + 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); + } + }; +} + +GroupSet.prototype = new Panel(); + +/** + * 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; + +GroupSet.prototype.setRange = function (range) { + // TODO: implement setRange +}; + +/** + * 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]; + 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.subscribe(event, callback, id); + }); + + // draw all new groups + ids = this.groupsData.getIds(); + this._onAdd(ids); + } +}; + +/** + * Get groups + * @return {vis.DataSet | null} groups + */ +GroupSet.prototype.getGroups = function getGroups() { + return this.groupsData; +}; + +/** + * Repaint the component + * @return {Boolean} changed + */ +GroupSet.prototype.repaint = function repaint() { + var changed = 0, + i, id, group, label, + update = util.updateProperty, + asSize = util.option.asSize, + asElement = util.option.asElement, + options = this.options, + frame = this.dom.frame, + labels = this.dom.labels, + labelSet = this.dom.labelSet; + + // create frame + if (!this.parent) { + throw new Error('Cannot repaint groupset: no parent attached'); + } + var parentContainer = this.parent.getContainer(); + if (!parentContainer) { + throw new Error('Cannot repaint groupset: parent has no container element'); + } + if (!frame) { + frame = document.createElement('div'); + frame.className = 'groupset'; + this.dom.frame = frame; + + var className = options.className; + if (className) { + util.addClassName(frame, util.option.asString(className)); + } + + changed += 1; + } + if (!frame.parentNode) { + parentContainer.appendChild(frame); + changed += 1; + } + + // create labels + var labelContainer = asElement(options.labelContainer); + if (!labelContainer) { + throw new Error('Cannot repaint groupset: option "labelContainer" not defined'); + } + if (!labels) { + labels = document.createElement('div'); + labels.className = 'labels'; + this.dom.labels = labels; + } + if (!labelSet) { + labelSet = document.createElement('div'); + labelSet.className = 'label-set'; + labels.appendChild(labelSet); + this.dom.labelSet = labelSet; + } + if (!labels.parentNode || labels.parentNode != labelContainer) { + if (labels.parentNode) { + labels.parentNode.removeChild(labels.parentNode); + } + labelContainer.appendChild(labels); + } + + // reposition frame + changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); + changed += update(frame.style, 'top', asSize(options.top, '0px')); + changed += update(frame.style, 'left', asSize(options.left, '0px')); + changed += update(frame.style, 'width', asSize(options.width, '100%')); + + // reposition labels + changed += update(labelSet.style, 'top', asSize(options.top, '0px')); + changed += update(labelSet.style, 'height', asSize(options.height, this.height + 'px')); + + var me = this, + queue = this.queue, + groups = this.groups, + groupsData = this.groupsData; + + // show/hide added/changed/removed groups + var ids = Object.keys(queue); + if (ids.length) { + ids.forEach(function (id) { + var action = queue[id]; + var group = groups[id]; + + //noinspection FallthroughInSwitchStatementJS + switch (action) { + case 'add': + case 'update': + if (!group) { + var groupOptions = Object.create(me.options); + util.extend(groupOptions, { + height: null, + maxHeight: null + }); + + group = new Group(me, id, groupOptions); + group.setItems(me.itemsData); // attach items data + groups[id] = group; + + me.controller.add(group); + } + + // TODO: update group data + group.data = groupsData.get(id); + + delete queue[id]; + break; + + case 'remove': + if (group) { + group.setItems(); // detach items data + delete groups[id]; + + me.controller.remove(group); + } + + // update lists + delete queue[id]; + break; + + default: + console.log('Error: unknown action "' + action + '"'); + } + }); + + // the groupset depends on each of the groups + //this.depends = this.groups; // TODO: gives a circular reference through the parent + + // TODO: apply dependencies of the groupset + + // update the top positions of the groups in the correct order + var orderedGroups = this.groupsData.getIds({ + order: this.options.groupOrder + }); + for (i = 0; i < orderedGroups.length; i++) { + (function (group, prevGroup) { + var top = 0; + if (prevGroup) { + top = function () { + // TODO: top must reckon with options.maxHeight + return prevGroup.top + prevGroup.height; + } + } + group.setOptions({ + top: top + }); + })(groups[orderedGroups[i]], groups[orderedGroups[i - 1]]); + } + + // (re)create the labels + while (labelSet.firstChild) { + labelSet.removeChild(labelSet.firstChild); + } + for (i = 0; i < orderedGroups.length; i++) { + id = orderedGroups[i]; + label = this._createLabel(id); + labelSet.appendChild(label); + } + + changed++; + } + + // reposition the labels + // TODO: labels are not displayed correctly when orientation=='top' + // TODO: width of labelPanel is not immediately updated on a change in groups + for (id in groups) { + if (groups.hasOwnProperty(id)) { + group = groups[id]; + label = group.label; + if (label) { + label.style.top = group.top + 'px'; + label.style.height = group.height + 'px'; + } + } + } + + return (changed > 0); +}; + +/** + * Create a label for group with given id + * @param {Number} id + * @return {Element} label + * @private + */ +GroupSet.prototype._createLabel = function(id) { + var group = this.groups[id]; + var label = document.createElement('div'); + label.className = 'label'; + var inner = document.createElement('div'); + inner.className = 'inner'; + label.appendChild(inner); + + var content = group.data && group.data.content; + if (content instanceof Element) { + inner.appendChild(content); + } + else if (content != undefined) { + inner.innerHTML = content; + } + + var className = group.data && group.data.className; + if (className) { + util.addClassName(label, className); + } + + group.label = label; // TODO: not so nice, parking labels in the group this way!!! + + return label; +}; + +/** + * Get container element + * @return {HTMLElement} container + */ +GroupSet.prototype.getContainer = function getContainer() { + return this.dom.frame; +}; + +/** + * Get the width of the group labels + * @return {Number} width + */ +GroupSet.prototype.getLabelsWidth = function getContainer() { + return this.props.labels.width; +}; + +/** + * Reflow the component + * @return {Boolean} resized + */ +GroupSet.prototype.reflow = function reflow() { + var changed = 0, + id, group, + options = this.options, + update = util.updateProperty, + asNumber = util.option.asNumber, + asSize = util.option.asSize, + frame = this.dom.frame; + + if (frame) { + var maxHeight = asNumber(options.maxHeight); + var fixedHeight = (asSize(options.height) != null); + var height; + if (fixedHeight) { + height = frame.offsetHeight; + } + else { + // height is not specified, calculate the sum of the height of all groups + height = 0; + + for (id in this.groups) { + if (this.groups.hasOwnProperty(id)) { + group = this.groups[id]; + height += group.height; + } + } + } + if (maxHeight != null) { + height = Math.min(height, maxHeight); + } + changed += update(this, 'height', height); + + changed += update(this, 'top', frame.offsetTop); + changed += update(this, 'left', frame.offsetLeft); + changed += update(this, 'width', frame.offsetWidth); + } + + // calculate the maximum width of the labels + var width = 0; + for (id in this.groups) { + if (this.groups.hasOwnProperty(id)) { + group = this.groups[id]; + var labelWidth = group.props && group.props.label && group.props.label.width || 0; + width = Math.max(width, labelWidth); + } + } + changed += update(this.props.labels, 'width', width); + + return (changed > 0); +}; + +/** + * Hide the component from the DOM + * @return {Boolean} changed + */ +GroupSet.prototype.hide = function hide() { + if (this.dom.frame && this.dom.frame.parentNode) { + this.dom.frame.parentNode.removeChild(this.dom.frame); + return true; + } + else { + return false; + } +}; + +/** + * Show the component in the DOM (when not already visible). + * A repaint will be executed when the component is not visible + * @return {Boolean} changed + */ +GroupSet.prototype.show = function show() { + if (!this.dom.frame || !this.dom.frame.parentNode) { + return this.repaint(); + } + else { + return false; + } +}; + +/** + * Handle updated groups + * @param {Number[]} ids + * @private + */ +GroupSet.prototype._onUpdate = function _onUpdate(ids) { + this._toQueue(ids, 'update'); +}; + +/** + * Handle changed groups + * @param {Number[]} ids + * @private + */ +GroupSet.prototype._onAdd = function _onAdd(ids) { + this._toQueue(ids, 'add'); +}; + +/** + * Handle removed groups + * @param {Number[]} ids + * @private + */ +GroupSet.prototype._onRemove = function _onRemove(ids) { + this._toQueue(ids, 'remove'); +}; + +/** + * Put groups in the queue to be added/updated/remove + * @param {Number[]} ids + * @param {String} action can be 'add', 'update', 'remove' + */ +GroupSet.prototype._toQueue = function _toQueue(ids, action) { + var queue = this.queue; + ids.forEach(function (id) { + queue[id] = action; + }); + + if (this.controller) { + //this.requestReflow(); + this.requestRepaint(); + } +}; + +/** + * Create a timeline visualization + * @param {HTMLElement} container + * @param {vis.DataSet | Array | DataTable} [items] + * @param {Object} [options] See Timeline.setOptions for the available options. + * @constructor + */ +function Timeline (container, items, options) { + var me = this; + var now = moment().hours(0).minutes(0).seconds(0).milliseconds(0); + this.options = { + orientation: 'bottom', + min: null, + max: null, + zoomMin: 10, // milliseconds + zoomMax: 1000 * 60 * 60 * 24 * 365 * 10000, // milliseconds + // moveable: true, // TODO: option moveable + // zoomable: true, // TODO: option zoomable + showMinorLabels: true, + showMajorLabels: true, + showCurrentTime: false, + showCustomTime: false, + autoResize: false + }; + + // controller + this.controller = new Controller(); + + // root panel + if (!container) { + throw new Error('No container element provided'); + } + var rootOptions = Object.create(this.options); + rootOptions.height = function () { + // TODO: change to height + if (me.options.height) { + // fixed height + return me.options.height; + } + else { + // auto height + return (me.timeaxis.height + me.content.height) + 'px'; + } + }; + this.rootPanel = new RootPanel(container, rootOptions); + this.controller.add(this.rootPanel); + + // item panel + var itemOptions = Object.create(this.options); + itemOptions.left = function () { + return me.labelPanel.width; + }; + itemOptions.width = function () { + return me.rootPanel.width - me.labelPanel.width; + }; + itemOptions.top = null; + itemOptions.height = null; + this.itemPanel = new Panel(this.rootPanel, [], itemOptions); + this.controller.add(this.itemPanel); + + // label panel + var labelOptions = Object.create(this.options); + labelOptions.top = null; + labelOptions.left = null; + labelOptions.height = null; + labelOptions.width = function () { + if (me.content && typeof me.content.getLabelsWidth === 'function') { + return me.content.getLabelsWidth(); + } + else { + return 0; + } + }; + this.labelPanel = new Panel(this.rootPanel, [], labelOptions); + this.controller.add(this.labelPanel); + + // range + var rangeOptions = Object.create(this.options); + this.range = new Range(rangeOptions); + this.range.setRange( + now.clone().add('days', -3).valueOf(), + now.clone().add('days', 4).valueOf() + ); + + // TODO: reckon with options moveable and zoomable + this.range.subscribe(this.rootPanel, 'move', 'horizontal'); + this.range.subscribe(this.rootPanel, 'zoom', 'horizontal'); + this.range.on('rangechange', function () { + var force = true; + me.controller.requestReflow(force); + }); + this.range.on('rangechanged', function () { + var force = true; + me.controller.requestReflow(force); + }); + + // TODO: put the listeners in setOptions, be able to dynamically change with options moveable and zoomable + + // time axis + var timeaxisOptions = Object.create(rootOptions); + timeaxisOptions.range = this.range; + timeaxisOptions.left = null; + timeaxisOptions.top = null; + timeaxisOptions.width = '100%'; + timeaxisOptions.height = null; + this.timeaxis = new TimeAxis(this.itemPanel, [], timeaxisOptions); + this.timeaxis.setRange(this.range); + this.controller.add(this.timeaxis); + + // current time bar + this.currenttime = new CurrentTime(this.timeaxis, [], rootOptions); + this.controller.add(this.currenttime); + + // custom time bar + this.customtime = new CustomTime(this.timeaxis, [], rootOptions); + this.controller.add(this.customtime); + + // create groupset + this.setGroups(null); + + this.itemsData = null; // DataSet + this.groupsData = null; // DataSet + + // apply options + if (options) { + this.setOptions(options); + } + + // create itemset and groupset + if (items) { + this.setItems(items); + } +} + +/** + * Set options + * @param {Object} options TODO: describe the available options + */ +Timeline.prototype.setOptions = function (options) { + util.extend(this.options, options); + + // force update of range + // options.start and options.end can be undefined + //this.range.setRange(options.start, options.end); + this.range.setRange(); + + this.controller.reflow(); + this.controller.repaint(); +}; + +/** + * Set a custom time bar + * @param {Date} time + */ +Timeline.prototype.setCustomTime = function (time) { + this.customtime._setCustomTime(time); +}; + +/** + * Retrieve the current custom time. + * @return {Date} customTime + */ +Timeline.prototype.getCustomTime = function() { + return new Date(this.customtime.customTime.valueOf()); +}; + +/** + * Set items + * @param {vis.DataSet | Array | DataTable | null} items + */ +Timeline.prototype.setItems = function(items) { + var initialLoad = (this.itemsData == null); + + // convert to type DataSet when needed + var newItemSet; + if (!items) { + newItemSet = null; + } + else if (items instanceof DataSet) { + newItemSet = items; + } + if (!(items instanceof DataSet)) { + newItemSet = new DataSet({ + convert: { + start: 'Date', + end: 'Date' + } + }); + newItemSet.add(items); + } + + // set items + this.itemsData = newItemSet; + this.content.setItems(newItemSet); + + if (initialLoad && (this.options.start == undefined || this.options.end == undefined)) { + // apply the data range as range + var dataRange = this.getItemRange(); + + // add 5% space on both sides + var min = dataRange.min; + var max = dataRange.max; + if (min != null && max != null) { + var interval = (max.valueOf() - min.valueOf()); + if (interval <= 0) { + // prevent an empty interval + interval = 24 * 60 * 60 * 1000; // 1 day + } + min = new Date(min.valueOf() - interval * 0.05); + max = new Date(max.valueOf() + interval * 0.05); + } + + // override specified start and/or end date + if (this.options.start != undefined) { + min = util.convert(this.options.start, 'Date'); + } + if (this.options.end != undefined) { + max = util.convert(this.options.end, 'Date'); + } + + // apply range if there is a min or max available + if (min != null || max != null) { + this.range.setRange(min, max); + } + } +}; + +/** + * Set groups + * @param {vis.DataSet | Array | DataTable} groups + */ +Timeline.prototype.setGroups = function(groups) { + var me = this; + this.groupsData = groups; + + // switch content type between ItemSet or GroupSet when needed + var Type = this.groupsData ? GroupSet : ItemSet; + if (!(this.content instanceof Type)) { + // remove old content set + if (this.content) { + this.content.hide(); + if (this.content.setItems) { + this.content.setItems(); // disconnect from items + } + if (this.content.setGroups) { + this.content.setGroups(); // disconnect from groups + } + this.controller.remove(this.content); + } + + // create new content set + var options = Object.create(this.options); + util.extend(options, { + top: function () { + if (me.options.orientation == 'top') { + return me.timeaxis.height; + } + else { + return me.itemPanel.height - me.timeaxis.height - me.content.height; + } + }, + left: null, + width: '100%', + height: function () { + if (me.options.height) { + // fixed height + return me.itemPanel.height - me.timeaxis.height; + } + else { + // auto height + return null; + } + }, + maxHeight: function () { + // TODO: change maxHeight to be a css string like '100%' or '300px' + if (me.options.maxHeight) { + if (!util.isNumber(me.options.maxHeight)) { + throw new TypeError('Number expected for property maxHeight'); + } + return me.options.maxHeight - me.timeaxis.height; + } + else { + return null; + } + }, + labelContainer: function () { + return me.labelPanel.getContainer(); + } + }); + + this.content = new Type(this.itemPanel, [this.timeaxis], options); + if (this.content.setRange) { + this.content.setRange(this.range); + } + if (this.content.setItems) { + this.content.setItems(this.itemsData); + } + if (this.content.setGroups) { + this.content.setGroups(this.groupsData); + } + this.controller.add(this.content); + } +}; + +/** + * Get the data range of the item set. + * @returns {{min: Date, max: Date}} range A range with a start and end Date. + * When no minimum is found, min==null + * When no maximum is found, max==null + */ +Timeline.prototype.getItemRange = function getItemRange() { + // calculate min from start filed + var itemsData = this.itemsData, + min = null, + max = null; + + if (itemsData) { + // calculate the minimum value of the field 'start' + var minItem = itemsData.min('start'); + min = minItem ? minItem.start.valueOf() : null; + + // calculate maximum value of fields 'start' and 'end' + var maxStartItem = itemsData.max('start'); + if (maxStartItem) { + max = maxStartItem.start.valueOf(); + } + var maxEndItem = itemsData.max('end'); + if (maxEndItem) { + if (max == null) { + max = maxEndItem.end.valueOf(); + } + else { + max = Math.max(max, maxEndItem.end.valueOf()); + } + } + } + + return { + min: (min != null) ? new Date(min) : null, + max: (max != null) ? new Date(max) : null + }; +}; + +(function(exports) { + /** + * Parse a text source containing data in DOT language into a JSON object. + * The object contains two lists: one with nodes and one with edges. + * + * DOT language reference: http://www.graphviz.org/doc/info/lang.html + * + * @param {String} data Text containing a graph in DOT-notation + * @return {Object} graph An object containing two parameters: + * {Object[]} nodes + * {Object[]} edges + */ + function parseDOT (data) { + dot = data; + return parseGraph(); + } + + // token types enumeration + var TOKENTYPE = { + NULL : 0, + DELIMITER : 1, + IDENTIFIER: 2, + UNKNOWN : 3 + }; + + // map with all delimiters + var DELIMITERS = { + '{': true, + '}': true, + '[': true, + ']': true, + ';': true, + '=': true, + ',': true, + + '->': true, + '--': true + }; + + var dot = ''; // current dot file + var index = 0; // current index in dot file + var c = ''; // current token character in expr + var token = ''; // current token + var tokenType = TOKENTYPE.NULL; // type of the token + + /** + * Get the first character from the dot file. + * The character is stored into the char c. If the end of the dot file is + * reached, the function puts an empty string in c. + */ + function first() { + index = 0; + c = dot.charAt(0); + } + + /** + * Get the next character from the dot file. + * The character is stored into the char c. If the end of the dot file is + * reached, the function puts an empty string in c. + */ + function next() { + index++; + c = dot.charAt(index); + } + + /** + * Preview the next character from the dot file. + * @return {String} cNext + */ + function nextPreview() { + return dot.charAt(index + 1); + } + + /** + * Test whether given character is alphabetic or numeric + * @param {String} c + * @return {Boolean} isAlphaNumeric + */ + var regexAlphaNumeric = /[a-zA-Z_0-9.:#]/; + function isAlphaNumeric(c) { + return regexAlphaNumeric.test(c); + } + + /** + * Merge all properties of object b into object b + * @param {Object} a + * @param {Object} b + * @return {Object} a + */ + function merge (a, b) { + if (!a) { + a = {}; + } + + if (b) { + for (var name in b) { + if (b.hasOwnProperty(name)) { + a[name] = b[name]; + } + } + } + return a; + } + + /** + * Set a value in an object, where the provided parameter name can be a + * path with nested parameters. For example: + * + * var obj = {a: 2}; + * setValue(obj, 'b.c', 3); // obj = {a: 2, b: {c: 3}} + * + * @param {Object} obj + * @param {String} path A parameter name or dot-separated parameter path, + * like "color.highlight.border". + * @param {*} value + */ + function setValue(obj, path, value) { + var keys = path.split('.'); + var o = obj; + while (keys.length) { + var key = keys.shift(); + if (keys.length) { + // this isn't the end point + if (!o[key]) { + o[key] = {}; + } + o = o[key]; + } + else { + // this is the end point + o[key] = value; + } + } + } + + /** + * Add a node to a graph object. If there is already a node with + * the same id, their attributes will be merged. + * @param {Object} graph + * @param {Object} node + */ + function addNode(graph, node) { + var i, len; + var current = null; + + // find root graph (in case of subgraph) + var graphs = [graph]; // list with all graphs from current graph to root graph + var root = graph; + while (root.parent) { + graphs.push(root.parent); + root = root.parent; + } + + // find existing node (at root level) by its id + if (root.nodes) { + for (i = 0, len = root.nodes.length; i < len; i++) { + if (node.id === root.nodes[i].id) { + current = root.nodes[i]; + break; + } + } + } + + if (!current) { + // this is a new node + current = { + id: node.id + }; + if (graph.node) { + // clone default attributes + current.attr = merge(current.attr, graph.node); + } + } + + // add node to this (sub)graph and all its parent graphs + for (i = graphs.length - 1; i >= 0; i--) { + var g = graphs[i]; + + if (!g.nodes) { + g.nodes = []; + } + if (g.nodes.indexOf(current) == -1) { + g.nodes.push(current); + } + } + + // merge attributes + if (node.attr) { + current.attr = merge(current.attr, node.attr); + } + } + + /** + * Add an edge to a graph object + * @param {Object} graph + * @param {Object} edge + */ + function addEdge(graph, edge) { + if (!graph.edges) { + graph.edges = []; + } + graph.edges.push(edge); + if (graph.edge) { + var attr = merge({}, graph.edge); // clone default attributes + edge.attr = merge(attr, edge.attr); // merge attributes + } + } + + /** + * Create an edge to a graph object + * @param {Object} graph + * @param {String | Number | Object} from + * @param {String | Number | Object} to + * @param {String} type + * @param {Object | null} attr + * @return {Object} edge + */ + function createEdge(graph, from, to, type, attr) { + var edge = { + from: from, + to: to, + type: type + }; + + if (graph.edge) { + edge.attr = merge({}, graph.edge); // clone default attributes + } + edge.attr = merge(edge.attr || {}, attr); // merge attributes + + return edge; + } + + /** + * Get next token in the current dot file. + * The token and token type are available as token and tokenType + */ + function getToken() { + tokenType = TOKENTYPE.NULL; + token = ''; + + // skip over whitespaces + while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter + next(); + } + + do { + var isComment = false; + + // skip comment + if (c == '#') { + // find the previous non-space character + var i = index - 1; + while (dot.charAt(i) == ' ' || dot.charAt(i) == '\t') { + i--; + } + if (dot.charAt(i) == '\n' || dot.charAt(i) == '') { + // the # is at the start of a line, this is indeed a line comment + while (c != '' && c != '\n') { + next(); + } + isComment = true; + } + } + if (c == '/' && nextPreview() == '/') { + // skip line comment + while (c != '' && c != '\n') { + next(); + } + isComment = true; + } + if (c == '/' && nextPreview() == '*') { + // skip block comment + while (c != '') { + if (c == '*' && nextPreview() == '/') { + // end of block comment found. skip these last two characters + next(); + next(); + break; + } + else { + next(); + } + } + isComment = true; + } + + // skip over whitespaces + while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter + next(); + } + } + while (isComment); + + // check for end of dot file + if (c == '') { + // token is still empty + tokenType = TOKENTYPE.DELIMITER; + return; + } + + // check for delimiters consisting of 2 characters + var c2 = c + nextPreview(); + if (DELIMITERS[c2]) { + tokenType = TOKENTYPE.DELIMITER; + token = c2; + next(); + next(); + return; + } + + // check for delimiters consisting of 1 character + if (DELIMITERS[c]) { + tokenType = TOKENTYPE.DELIMITER; + token = c; + next(); + return; + } + + // check for an identifier (number or string) + // TODO: more precise parsing of numbers/strings (and the port separator ':') + if (isAlphaNumeric(c) || c == '-') { + token += c; + next(); + + while (isAlphaNumeric(c)) { + token += c; + next(); + } + if (token == 'false') { + token = false; // convert to boolean + } + else if (token == 'true') { + token = true; // convert to boolean + } + else if (!isNaN(Number(token))) { + token = Number(token); // convert to number + } + tokenType = TOKENTYPE.IDENTIFIER; + return; + } + + // check for a string enclosed by double quotes + if (c == '"') { + next(); + while (c != '' && (c != '"' || (c == '"' && nextPreview() == '"'))) { + token += c; + if (c == '"') { // skip the escape character + next(); + } + next(); + } + if (c != '"') { + throw newSyntaxError('End of string " expected'); + } + next(); + tokenType = TOKENTYPE.IDENTIFIER; + return; + } + + // something unknown is found, wrong characters, a syntax error + tokenType = TOKENTYPE.UNKNOWN; + while (c != '') { + token += c; + next(); + } + throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"'); + } + + /** + * Parse a graph. + * @returns {Object} graph + */ + function parseGraph() { + var graph = {}; + + first(); + getToken(); + + // optional strict keyword + if (token == 'strict') { + graph.strict = true; + getToken(); + } + + // graph or digraph keyword + if (token == 'graph' || token == 'digraph') { + graph.type = token; + getToken(); + } + + // optional graph id + if (tokenType == TOKENTYPE.IDENTIFIER) { + graph.id = token; + getToken(); + } + + // open angle bracket + if (token != '{') { + throw newSyntaxError('Angle bracket { expected'); + } + getToken(); + + // statements + parseStatements(graph); + + // close angle bracket + if (token != '}') { + throw newSyntaxError('Angle bracket } expected'); + } + getToken(); + + // end of file + if (token !== '') { + throw newSyntaxError('End of file expected'); + } + getToken(); + + // remove temporary default properties + delete graph.node; + delete graph.edge; + delete graph.graph; + + return graph; + } + + /** + * Parse a list with statements. + * @param {Object} graph + */ + function parseStatements (graph) { + while (token !== '' && token != '}') { + parseStatement(graph); + if (token == ';') { + getToken(); + } + } + } + + /** + * Parse a single statement. Can be a an attribute statement, node + * statement, a series of node statements and edge statements, or a + * parameter. + * @param {Object} graph + */ + function parseStatement(graph) { + // parse subgraph + var subgraph = parseSubgraph(graph); + if (subgraph) { + // edge statements + parseEdge(graph, subgraph); + + return; + } + + // parse an attribute statement + var attr = parseAttributeStatement(graph); + if (attr) { + return; + } + + // parse node + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier expected'); + } + var id = token; // id can be a string or a number + getToken(); + + if (token == '=') { + // id statement + getToken(); + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier expected'); + } + graph[id] = token; + getToken(); + // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] " + } + else { + parseNodeStatement(graph, id); + } + } + + /** + * Parse a subgraph + * @param {Object} graph parent graph object + * @return {Object | null} subgraph + */ + function parseSubgraph (graph) { + var subgraph = null; + + // optional subgraph keyword + if (token == 'subgraph') { + subgraph = {}; + subgraph.type = 'subgraph'; + getToken(); + + // optional graph id + if (tokenType == TOKENTYPE.IDENTIFIER) { + subgraph.id = token; + getToken(); + } + } + + // open angle bracket + if (token == '{') { + getToken(); + + if (!subgraph) { + subgraph = {}; + } + subgraph.parent = graph; + subgraph.node = graph.node; + subgraph.edge = graph.edge; + subgraph.graph = graph.graph; + + // statements + parseStatements(subgraph); + + // close angle bracket + if (token != '}') { + throw newSyntaxError('Angle bracket } expected'); + } + getToken(); + + // remove temporary default properties + delete subgraph.node; + delete subgraph.edge; + delete subgraph.graph; + delete subgraph.parent; + + // register at the parent graph + if (!graph.subgraphs) { + graph.subgraphs = []; + } + graph.subgraphs.push(subgraph); + } + + return subgraph; + } + + /** + * parse an attribute statement like "node [shape=circle fontSize=16]". + * Available keywords are 'node', 'edge', 'graph'. + * The previous list with default attributes will be replaced + * @param {Object} graph + * @returns {String | null} keyword Returns the name of the parsed attribute + * (node, edge, graph), or null if nothing + * is parsed. + */ + function parseAttributeStatement (graph) { + // attribute statements + if (token == 'node') { + getToken(); + + // node attributes + graph.node = parseAttributeList(); + return 'node'; + } + else if (token == 'edge') { + getToken(); + + // edge attributes + graph.edge = parseAttributeList(); + return 'edge'; + } + else if (token == 'graph') { + getToken(); + + // graph attributes + graph.graph = parseAttributeList(); + return 'graph'; + } + + return null; + } + + /** + * parse a node statement + * @param {Object} graph + * @param {String | Number} id + */ + function parseNodeStatement(graph, id) { + // node statement + var node = { + id: id + }; + var attr = parseAttributeList(); + if (attr) { + node.attr = attr; + } + addNode(graph, node); + + // edge statements + parseEdge(graph, id); + } + + /** + * Parse an edge or a series of edges + * @param {Object} graph + * @param {String | Number} from Id of the from node + */ + function parseEdge(graph, from) { + while (token == '->' || token == '--') { + var to; + var type = token; + getToken(); + + var subgraph = parseSubgraph(graph); + if (subgraph) { + to = subgraph; + } + else { + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Identifier or subgraph expected'); + } + to = token; + addNode(graph, { + id: to + }); + getToken(); + } + + // parse edge attributes + var attr = parseAttributeList(); + + // create edge + var edge = createEdge(graph, from, to, type, attr); + addEdge(graph, edge); + + from = to; + } + } + + /** + * Parse a set with attributes, + * for example [label="1.000", shape=solid] + * @return {Object | null} attr + */ + function parseAttributeList() { + var attr = null; + + while (token == '[') { + getToken(); + attr = {}; + while (token !== '' && token != ']') { + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Attribute name expected'); + } + var name = token; + + getToken(); + if (token != '=') { + throw newSyntaxError('Equal sign = expected'); + } + getToken(); + + if (tokenType != TOKENTYPE.IDENTIFIER) { + throw newSyntaxError('Attribute value expected'); + } + var value = token; + setValue(attr, name, value); // name can be a path + + getToken(); + if (token ==',') { + getToken(); + } + } + + if (token != ']') { + throw newSyntaxError('Bracket ] expected'); + } + getToken(); + } + + return attr; + } + + /** + * Create a syntax error with extra information on current token and index. + * @param {String} message + * @returns {SyntaxError} err + */ + function newSyntaxError(message) { + return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ')'); + } + + /** + * Chop off text after a maximum length + * @param {String} text + * @param {Number} maxLength + * @returns {String} + */ + function chop (text, maxLength) { + return (text.length <= maxLength) ? text : (text.substr(0, 27) + '...'); + } + + /** + * Execute a function fn for each pair of elements in two arrays + * @param {Array | *} array1 + * @param {Array | *} array2 + * @param {function} fn + */ + function forEach2(array1, array2, fn) { + if (array1 instanceof Array) { + array1.forEach(function (elem1) { + if (array2 instanceof Array) { + array2.forEach(function (elem2) { + fn(elem1, elem2); + }); + } + else { + fn(elem1, array2); + } + }); + } + else { + if (array2 instanceof Array) { + array2.forEach(function (elem2) { + fn(array1, elem2); + }); + } + else { + fn(array1, array2); + } + } + } + + /** + * Convert a string containing a graph in DOT language into a map containing + * with nodes and edges in the format of graph. + * @param {String} data Text containing a graph in DOT-notation + * @return {Object} graphData + */ + function DOTToGraph (data) { + // parse the DOT file + var dotData = parseDOT(data); + var graphData = { + nodes: [], + edges: [], + options: {} + }; + + // copy the nodes + if (dotData.nodes) { + dotData.nodes.forEach(function (dotNode) { + var graphNode = { + id: dotNode.id, + label: String(dotNode.label || dotNode.id) + }; + merge(graphNode, dotNode.attr); + if (graphNode.image) { + graphNode.shape = 'image'; + } + graphData.nodes.push(graphNode); + }); + } + + // copy the edges + if (dotData.edges) { + /** + * Convert an edge in DOT format to an edge with VisGraph format + * @param {Object} dotEdge + * @returns {Object} graphEdge + */ + function convertEdge(dotEdge) { + var graphEdge = { + from: dotEdge.from, + to: dotEdge.to + }; + merge(graphEdge, dotEdge.attr); + graphEdge.style = (dotEdge.type == '->') ? 'arrow' : 'line'; + return graphEdge; + } + + dotData.edges.forEach(function (dotEdge) { + var from, to; + if (dotEdge.from instanceof Object) { + from = dotEdge.from.nodes; + } + else { + from = { + id: dotEdge.from + } + } + + if (dotEdge.to instanceof Object) { + to = dotEdge.to.nodes; + } + else { + to = { + id: dotEdge.to + } + } + + if (dotEdge.from instanceof Object && dotEdge.from.edges) { + dotEdge.from.edges.forEach(function (subEdge) { + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); + } + + forEach2(from, to, function (from, to) { + var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr); + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); + + if (dotEdge.to instanceof Object && dotEdge.to.edges) { + dotEdge.to.edges.forEach(function (subEdge) { + var graphEdge = convertEdge(subEdge); + graphData.edges.push(graphEdge); + }); + } + }); + } + + // copy the options + if (dotData.attr) { + graphData.options = dotData.attr; + } + + return graphData; + } + + // exports + exports.parseDOT = parseDOT; + exports.DOTToGraph = DOTToGraph; + +})(typeof util !== 'undefined' ? util : exports); + +/** + * Canvas shapes used by the Graph + */ +if (typeof CanvasRenderingContext2D !== 'undefined') { + + /** + * Draw a circle shape + */ + CanvasRenderingContext2D.prototype.circle = function(x, y, r) { + this.beginPath(); + this.arc(x, y, r, 0, 2*Math.PI, false); + }; + + /** + * Draw a square shape + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r size, width and height of the square + */ + CanvasRenderingContext2D.prototype.square = function(x, y, r) { + this.beginPath(); + this.rect(x - r, y - r, r * 2, r * 2); + }; + + /** + * Draw a triangle shape + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r radius, half the length of the sides of the triangle + */ + CanvasRenderingContext2D.prototype.triangle = function(x, y, r) { + // http://en.wikipedia.org/wiki/Equilateral_triangle + this.beginPath(); + + var s = r * 2; + var s2 = s / 2; + var ir = Math.sqrt(3) / 6 * s; // radius of inner circle + var h = Math.sqrt(s * s - s2 * s2); // height + + this.moveTo(x, y - (h - ir)); + this.lineTo(x + s2, y + ir); + this.lineTo(x - s2, y + ir); + this.lineTo(x, y - (h - ir)); + this.closePath(); + }; + + /** + * Draw a triangle shape in downward orientation + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r radius + */ + CanvasRenderingContext2D.prototype.triangleDown = function(x, y, r) { + // http://en.wikipedia.org/wiki/Equilateral_triangle + this.beginPath(); + + var s = r * 2; + var s2 = s / 2; + var ir = Math.sqrt(3) / 6 * s; // radius of inner circle + var h = Math.sqrt(s * s - s2 * s2); // height + + this.moveTo(x, y + (h - ir)); + this.lineTo(x + s2, y - ir); + this.lineTo(x - s2, y - ir); + this.lineTo(x, y + (h - ir)); + this.closePath(); + }; + + /** + * Draw a star shape, a star with 5 points + * @param {Number} x horizontal center + * @param {Number} y vertical center + * @param {Number} r radius, half the length of the sides of the triangle + */ + CanvasRenderingContext2D.prototype.star = function(x, y, r) { + // http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/ + this.beginPath(); + + for (var n = 0; n < 10; n++) { + var radius = (n % 2 === 0) ? r * 1.3 : r * 0.5; + this.lineTo( + x + radius * Math.sin(n * 2 * Math.PI / 10), + y - radius * Math.cos(n * 2 * Math.PI / 10) + ); + } + + this.closePath(); + }; + + /** + * http://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas + */ + CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) { + var r2d = Math.PI/180; + if( w - ( 2 * r ) < 0 ) { r = ( w / 2 ); } //ensure that the radius isn't too large for x + if( h - ( 2 * r ) < 0 ) { r = ( h / 2 ); } //ensure that the radius isn't too large for y + this.beginPath(); + this.moveTo(x+r,y); + this.lineTo(x+w-r,y); + this.arc(x+w-r,y+r,r,r2d*270,r2d*360,false); + this.lineTo(x+w,y+h-r); + this.arc(x+w-r,y+h-r,r,0,r2d*90,false); + this.lineTo(x+r,y+h); + this.arc(x+r,y+h-r,r,r2d*90,r2d*180,false); + this.lineTo(x,y+r); + this.arc(x+r,y+r,r,r2d*180,r2d*270,false); + }; + + /** + * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + */ + CanvasRenderingContext2D.prototype.ellipse = function(x, y, w, h) { + var kappa = .5522848, + ox = (w / 2) * kappa, // control point offset horizontal + oy = (h / 2) * kappa, // control point offset vertical + xe = x + w, // x-end + ye = y + h, // y-end + xm = x + w / 2, // x-middle + ym = y + h / 2; // y-middle + + this.beginPath(); + this.moveTo(x, ym); + this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + }; + + + + /** + * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas + */ + CanvasRenderingContext2D.prototype.database = function(x, y, w, h) { + var f = 1/3; + var wEllipse = w; + var hEllipse = h * f; + + var kappa = .5522848, + ox = (wEllipse / 2) * kappa, // control point offset horizontal + oy = (hEllipse / 2) * kappa, // control point offset vertical + xe = x + wEllipse, // x-end + ye = y + hEllipse, // y-end + xm = x + wEllipse / 2, // x-middle + ym = y + hEllipse / 2, // y-middle + ymb = y + (h - hEllipse/2), // y-midlle, bottom ellipse + yeb = y + h; // y-end, bottom ellipse + + this.beginPath(); + this.moveTo(xe, ym); + + this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); + this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); + + this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); + this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); + + this.lineTo(xe, ymb); + + this.bezierCurveTo(xe, ymb + oy, xm + ox, yeb, xm, yeb); + this.bezierCurveTo(xm - ox, yeb, x, ymb + oy, x, ymb); + + this.lineTo(x, ym); + }; + + + /** + * Draw an arrow point (no line) + */ + CanvasRenderingContext2D.prototype.arrow = function(x, y, angle, length) { + // tail + var xt = x - length * Math.cos(angle); + var yt = y - length * Math.sin(angle); + + // inner tail + // TODO: allow to customize different shapes + var xi = x - length * 0.9 * Math.cos(angle); + var yi = y - length * 0.9 * Math.sin(angle); + + // left + var xl = xt + length / 3 * Math.cos(angle + 0.5 * Math.PI); + var yl = yt + length / 3 * Math.sin(angle + 0.5 * Math.PI); + + // right + var xr = xt + length / 3 * Math.cos(angle - 0.5 * Math.PI); + var yr = yt + length / 3 * Math.sin(angle - 0.5 * Math.PI); + + this.beginPath(); + this.moveTo(x, y); + this.lineTo(xl, yl); + this.lineTo(xi, yi); + this.lineTo(xr, yr); + this.closePath(); + }; + + /** + * Sets up the dashedLine functionality for drawing + * Original code came from http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas + * @author David Jordan + * @date 2012-08-08 + */ + CanvasRenderingContext2D.prototype.dashedLine = function(x,y,x2,y2,dashArray){ + if (!dashArray) dashArray=[10,5]; + if (dashLength==0) dashLength = 0.001; // Hack for Safari + var dashCount = dashArray.length; + this.moveTo(x, y); + var dx = (x2-x), dy = (y2-y); + var slope = dy/dx; + var distRemaining = Math.sqrt( dx*dx + dy*dy ); + var dashIndex=0, draw=true; + while (distRemaining>=0.1){ + var dashLength = dashArray[dashIndex++%dashCount]; + if (dashLength > distRemaining) dashLength = distRemaining; + var xStep = Math.sqrt( dashLength*dashLength / (1 + slope*slope) ); + if (dx<0) xStep = -xStep; + x += xStep; + y += slope*xStep; + this[draw ? 'lineTo' : 'moveTo'](x,y); + distRemaining -= dashLength; + draw = !draw; + } + }; + + // TODO: add diamond shape +} + +/** + * @class Node + * A node. A node can be connected to other nodes via one or multiple edges. + * @param {object} properties An object containing properties for the node. All + * properties are optional, except for the id. + * {number} id Id of the node. Required + * {string} label Text label for the node + * {number} x Horizontal position of the node + * {number} y Vertical position of the node + * {string} shape Node shape, available: + * "database", "circle", "ellipse", + * "box", "image", "text", "dot", + * "star", "triangle", "triangleDown", + * "square" + * {string} image An image url + * {string} title An title text, can be HTML + * {anytype} group A group name or number + * @param {Graph.Images} imagelist A list with images. Only needed + * when the node has an image + * @param {Graph.Groups} grouplist A list with groups. Needed for + * retrieving group properties + * @param {Object} constants An object with default values for + * example for the color + */ +function Node(properties, imagelist, grouplist, constants) { + this.selected = false; + + this.edges = []; // all edges connected to this node + this.group = constants.nodes.group; + + this.fontSize = constants.nodes.fontSize; + this.fontFace = constants.nodes.fontFace; + this.fontColor = constants.nodes.fontColor; + + this.color = constants.nodes.color; + + // set defaults for the properties + this.id = undefined; + this.shape = constants.nodes.shape; + this.image = constants.nodes.image; + this.x = 0; + this.y = 0; + this.xFixed = false; + this.yFixed = false; + this.radius = constants.nodes.radius; + this.radiusFixed = false; + this.radiusMin = constants.nodes.radiusMin; + this.radiusMax = constants.nodes.radiusMax; + + this.imagelist = imagelist; + this.grouplist = grouplist; + + this.setProperties(properties, constants); + + // mass, force, velocity + this.mass = 50; // kg (mass is adjusted for the number of connected edges) + this.fx = 0.0; // external force x + this.fy = 0.0; // external force y + this.vx = 0.0; // velocity x + this.vy = 0.0; // velocity y + this.minForce = constants.minForce; + this.damping = 0.9; // damping factor +}; + +/** + * Attach a edge to the node + * @param {Edge} edge + */ +Node.prototype.attachEdge = function(edge) { + if (this.edges.indexOf(edge) == -1) { + this.edges.push(edge); + } + this._updateMass(); +}; + +/** + * Detach a edge from the node + * @param {Edge} edge + */ +Node.prototype.detachEdge = function(edge) { + var index = this.edges.indexOf(edge); + if (index != -1) { + this.edges.splice(index, 1); + } + this._updateMass(); +}; + +/** + * Update the nodes mass, which is determined by the number of edges connecting + * to it (more edges -> heavier node). + * @private + */ +Node.prototype._updateMass = function() { + this.mass = 50 + 20 * this.edges.length; // kg +}; + +/** + * Set or overwrite properties for the node + * @param {Object} properties an object with properties + * @param {Object} constants and object with default, global properties + */ +Node.prototype.setProperties = function(properties, constants) { + if (!properties) { + return; + } + + // basic properties + if (properties.id != undefined) {this.id = properties.id;} + if (properties.label != undefined) {this.label = properties.label;} + if (properties.title != undefined) {this.title = properties.title;} + if (properties.group != undefined) {this.group = properties.group;} + if (properties.x != undefined) {this.x = properties.x;} + if (properties.y != undefined) {this.y = properties.y;} + if (properties.value != undefined) {this.value = properties.value;} + + if (this.id === undefined) { + throw "Node must have an id"; + } + + // copy group properties + if (this.group) { + var groupObj = this.grouplist.get(this.group); + for (var prop in groupObj) { + if (groupObj.hasOwnProperty(prop)) { + this[prop] = groupObj[prop]; + } + } + } + + // individual shape properties + if (properties.shape != undefined) {this.shape = properties.shape;} + if (properties.image != undefined) {this.image = properties.image;} + if (properties.radius != undefined) {this.radius = properties.radius;} + if (properties.color != undefined) {this.color = Node.parseColor(properties.color);} + + if (properties.fontColor != undefined) {this.fontColor = properties.fontColor;} + if (properties.fontSize != undefined) {this.fontSize = properties.fontSize;} + if (properties.fontFace != undefined) {this.fontFace = properties.fontFace;} + + + if (this.image != undefined) { + if (this.imagelist) { + this.imageObj = this.imagelist.load(this.image); + } + else { + throw "No imagelist provided"; + } + } + + this.xFixed = this.xFixed || (properties.x != undefined); + this.yFixed = this.yFixed || (properties.y != undefined); + this.radiusFixed = this.radiusFixed || (properties.radius != undefined); + + if (this.shape == 'image') { + this.radiusMin = constants.nodes.widthMin; + this.radiusMax = constants.nodes.widthMax; + } + + // choose draw method depending on the shape + switch (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; + // TODO: add diamond shape + 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; break; + } + + // reset the size of the node, this can be changed + this._reset(); +}; + +/** + * Parse a color property into an object with border, background, and + * hightlight colors + * @param {Object | String} color + * @return {Object} colorObject + */ +Node.parseColor = function(color) { + var c; + if (util.isString(color)) { + c = { + border: color, + background: color, + highlight: { + border: color, + background: color + } + }; + // TODO: automatically generate a nice highlight color + } + else { + c = {}; + c.background = color.background || 'white'; + c.border = color.border || c.background; + if (util.isString(color.highlight)) { + c.highlight = { + border: color.highlight, + background: color.highlight + } + } + else { + c.highlight = {}; + c.highlight.background = color.highlight && color.highlight.background || c.background; + c.highlight.border = color.highlight && color.highlight.border || c.border; + } + } + return c; +}; + +/** + * select this node + */ +Node.prototype.select = function() { + this.selected = true; + this._reset(); +}; + +/** + * unselect this node + */ +Node.prototype.unselect = function() { + this.selected = false; + this._reset(); +}; + +/** + * Reset the calculated size of the node, forces it to recalculate its size + * @private + */ +Node.prototype._reset = function() { + this.width = undefined; + this.height = undefined; +}; + +/** + * get the title of this node. + * @return {string} title The title of the node, or undefined when no title + * has been set. + */ +Node.prototype.getTitle = function() { + return this.title; +}; + +/** + * Calculate the distance to the border of the Node + * @param {CanvasRenderingContext2D} ctx + * @param {Number} angle Angle in radians + * @returns {number} distance Distance to the border in pixels + */ +Node.prototype.distanceToBorder = function (ctx, angle) { + var borderWidth = 1; + + if (!this.width) { + this.resize(ctx); + } + + //noinspection FallthroughInSwitchStatementJS + switch (this.shape) { + case 'circle': + case 'dot': + return this.radius + borderWidth; + + case 'ellipse': + var a = this.width / 2; + var b = this.height / 2; + var w = (Math.sin(angle) * a); + var h = (Math.cos(angle) * b); + return a * b / Math.sqrt(w * w + h * h); + + // TODO: implement distanceToBorder for database + // TODO: implement distanceToBorder for triangle + // TODO: implement distanceToBorder for triangleDown + + case 'box': + case 'image': + case 'text': + default: + if (this.width) { + return Math.min( + Math.abs(this.width / 2 / Math.cos(angle)), + Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth; + // TODO: reckon with border radius too in case of box + } + else { + return 0; + } + + } + + // TODO: implement calculation of distance to border for all shapes +}; + +/** + * Set forces acting on the node + * @param {number} fx Force in horizontal direction + * @param {number} fy Force in vertical direction + */ +Node.prototype._setForce = function(fx, fy) { + this.fx = fx; + this.fy = fy; +}; + +/** + * Add forces acting on the node + * @param {number} fx Force in horizontal direction + * @param {number} fy Force in vertical direction + * @private + */ +Node.prototype._addForce = function(fx, fy) { + this.fx += fx; + this.fy += fy; +}; + +/** + * Perform one discrete step for the node + * @param {number} interval Time interval in seconds + */ +Node.prototype.discreteStep = function(interval) { + if (!this.xFixed) { + var dx = -this.damping * this.vx; // damping force + var ax = (this.fx + dx) / this.mass; // acceleration + this.vx += ax / interval; // velocity + this.x += this.vx / interval; // position + } + + if (!this.yFixed) { + var dy = -this.damping * this.vy; // damping force + var ay = (this.fy + dy) / this.mass; // acceleration + this.vy += ay / interval; // velocity + this.y += this.vy / interval; // position + } +}; + + +/** + * Check if this node has a fixed x and y position + * @return {boolean} true if fixed, false if not + */ +Node.prototype.isFixed = function() { + return (this.xFixed && this.yFixed); +}; + +/** + * Check if this node is moving + * @param {number} vmin the minimum velocity considered as "moving" + * @return {boolean} true if moving, false if it has no velocity + */ +// TODO: replace this method with calculating the kinetic energy +Node.prototype.isMoving = function(vmin) { + return (Math.abs(this.vx) > vmin || Math.abs(this.vy) > vmin || + (!this.xFixed && Math.abs(this.fx) > this.minForce) || + (!this.yFixed && Math.abs(this.fy) > this.minForce)); +}; + +/** + * check if this node is selecte + * @return {boolean} selected True if node is selected, else false + */ +Node.prototype.isSelected = function() { + return this.selected; +}; + +/** + * Retrieve the value of the node. Can be undefined + * @return {Number} value + */ +Node.prototype.getValue = function() { + return this.value; +}; + +/** + * Calculate the distance from the nodes location to the given location (x,y) + * @param {Number} x + * @param {Number} y + * @return {Number} value + */ +Node.prototype.getDistance = function(x, y) { + var dx = this.x - x, + dy = this.y - y; + return Math.sqrt(dx * dx + dy * dy); +}; + + +/** + * Adjust the value range of the node. The node will adjust it's radius + * based on its value. + * @param {Number} min + * @param {Number} max + */ +Node.prototype.setValueRange = function(min, max) { + if (!this.radiusFixed && this.value !== undefined) { + if (max == min) { + this.radius = (this.radiusMin + this.radiusMax) / 2; + } + else { + var scale = (this.radiusMax - this.radiusMin) / (max - min); + this.radius = (this.value - min) * scale + this.radiusMin; + } + } +}; + +/** + * Draw this node in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + */ +Node.prototype.draw = function(ctx) { + throw "Draw method not initialized for node"; +}; + +/** + * Recalculate the size of this node in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + */ +Node.prototype.resize = function(ctx) { + throw "Resize method not initialized for node"; +}; + +/** + * Check if this object is overlapping with the provided object + * @param {Object} obj an object with parameters left, top, right, bottom + * @return {boolean} True if location is located on node + */ +Node.prototype.isOverlappingWith = function(obj) { + return (this.left < obj.right && + this.left + this.width > obj.left && + this.top < obj.bottom && + this.top + this.height > obj.top); +}; + +Node.prototype._resizeImage = function (ctx) { + // TODO: pre calculate the image size + if (!this.width) { // undefined or 0 + var width, height; + if (this.value) { + var scale = this.imageObj.height / this.imageObj.width; + width = this.radius || this.imageObj.width; + height = this.radius * scale || this.imageObj.height; + } + else { + width = this.imageObj.width; + height = this.imageObj.height; + } + this.width = width; + this.height = height; + } +}; + +Node.prototype._drawImage = function (ctx) { + this._resizeImage(ctx); + + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + var yLabel; + if (this.imageObj) { + ctx.drawImage(this.imageObj, this.left, this.top, this.width, this.height); + yLabel = this.y + this.height / 2; + } + else { + // image still loading... just draw the label for now + yLabel = this.y; + } + + this._label(ctx, this.label, this.x, yLabel, undefined, "top"); +}; + + +Node.prototype._resizeBox = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + this.width = textSize.width + 2 * margin; + this.height = textSize.height + 2 * margin; + } +}; + +Node.prototype._drawBox = function (ctx) { + this._resizeBox(ctx); + + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; + ctx.lineWidth = this.selected ? 2.0 : 1.0; + ctx.roundRect(this.left, this.top, this.width, this.height, this.radius); + ctx.fill(); + ctx.stroke(); + + this._label(ctx, this.label, this.x, this.y); +}; + + +Node.prototype._resizeDatabase = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + var size = textSize.width + 2 * margin; + this.width = size; + this.height = size; + } +}; + +Node.prototype._drawDatabase = function (ctx) { + this._resizeDatabase(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; + ctx.lineWidth = this.selected ? 2.0 : 1.0; + ctx.database(this.x - this.width/2, this.y - this.height*0.5, this.width, this.height); + ctx.fill(); + ctx.stroke(); + + this._label(ctx, this.label, this.x, this.y); +}; + + +Node.prototype._resizeCircle = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + var diameter = Math.max(textSize.width, textSize.height) + 2 * margin; + this.radius = diameter / 2; + + this.width = diameter; + this.height = diameter; + } +}; + +Node.prototype._drawCircle = function (ctx) { + this._resizeCircle(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; + ctx.lineWidth = this.selected ? 2.0 : 1.0; + ctx.circle(this.x, this.y, this.radius); + ctx.fill(); + ctx.stroke(); + + this._label(ctx, this.label, this.x, this.y); +}; + +Node.prototype._resizeEllipse = function (ctx) { + if (!this.width) { + var textSize = this.getTextSize(ctx); + + this.width = textSize.width * 1.5; + this.height = textSize.height * 2; + if (this.width < this.height) { + this.width = this.height; + } + } +}; + +Node.prototype._drawEllipse = function (ctx) { + this._resizeEllipse(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; + ctx.lineWidth = this.selected ? 2.0 : 1.0; + ctx.ellipse(this.left, this.top, this.width, this.height); + ctx.fill(); + ctx.stroke(); + + this._label(ctx, this.label, this.x, this.y); +}; + +Node.prototype._drawDot = function (ctx) { + this._drawShape(ctx, 'circle'); +}; + +Node.prototype._drawTriangle = function (ctx) { + this._drawShape(ctx, 'triangle'); +}; + +Node.prototype._drawTriangleDown = function (ctx) { + this._drawShape(ctx, 'triangleDown'); +}; + +Node.prototype._drawSquare = function (ctx) { + this._drawShape(ctx, 'square'); +}; + +Node.prototype._drawStar = function (ctx) { + this._drawShape(ctx, 'star'); +}; + +Node.prototype._resizeShape = function (ctx) { + if (!this.width) { + var size = 2 * this.radius; + this.width = size; + this.height = size; + } +}; + +Node.prototype._drawShape = function (ctx, shape) { + this._resizeShape(ctx); + + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; + ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; + ctx.lineWidth = this.selected ? 2.0 : 1.0; + + ctx[shape](this.x, this.y, this.radius); + ctx.fill(); + ctx.stroke(); + + if (this.label) { + this._label(ctx, this.label, this.x, this.y + this.height / 2, undefined, 'top'); + } +}; + +Node.prototype._resizeText = function (ctx) { + if (!this.width) { + var margin = 5; + var textSize = this.getTextSize(ctx); + this.width = textSize.width + 2 * margin; + this.height = textSize.height + 2 * margin; + } +}; + +Node.prototype._drawText = function (ctx) { + this._resizeText(ctx); + this.left = this.x - this.width / 2; + this.top = this.y - this.height / 2; + + this._label(ctx, this.label, this.x, this.y); +}; + + +Node.prototype._label = function (ctx, text, x, y, align, baseline) { + if (text) { + ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace; + ctx.fillStyle = this.fontColor || "black"; + ctx.textAlign = align || "center"; + ctx.textBaseline = baseline || "middle"; + + var lines = text.split('\n'), + lineCount = lines.length, + fontSize = (this.fontSize + 4), + yLine = y + (1 - lineCount) / 2 * fontSize; + + for (var i = 0; i < lineCount; i++) { + ctx.fillText(lines[i], x, yLine); + yLine += fontSize; + } + } +}; + + +Node.prototype.getTextSize = function(ctx) { + if (this.label != undefined) { + ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace; + + var lines = this.label.split('\n'), + height = (this.fontSize + 4) * lines.length, + width = 0; + + for (var i = 0, iMax = lines.length; i < iMax; i++) { + width = Math.max(width, ctx.measureText(lines[i]).width); + } + + return {"width": width, "height": height}; + } + else { + return {"width": 0, "height": 0}; + } +}; + +/** + * @class Edge + * + * A edge connects two nodes + * @param {Object} properties Object with properties. Must contain + * At least properties from and to. + * Available properties: from (number), + * to (number), label (string, color (string), + * width (number), style (string), + * length (number), title (string) + * @param {Graph} graph A graph object, used to find and edge to + * nodes. + * @param {Object} constants An object with default values for + * example for the color + */ +function Edge (properties, graph, constants) { + if (!graph) { + throw "No graph provided"; + } + this.graph = graph; + + // initialize constants + this.widthMin = constants.edges.widthMin; + this.widthMax = constants.edges.widthMax; + + // initialize variables + this.id = undefined; + this.fromId = undefined; + this.toId = undefined; + this.style = constants.edges.style; + this.title = undefined; + this.width = constants.edges.width; + this.value = undefined; + this.length = constants.edges.length; + + this.from = null; // a node + this.to = null; // a node + this.connected = false; + + // Added to support dashed lines + // David Jordan + // 2012-08-08 + this.dash = util.extend({}, constants.edges.dash); // contains properties length, gap, altLength + + this.stiffness = undefined; // depends on the length of the edge + this.color = constants.edges.color; + this.widthFixed = false; + this.lengthFixed = false; + + this.setProperties(properties, constants); +} + +/** + * Set or overwrite properties for the edge + * @param {Object} properties an object with properties + * @param {Object} constants and object with default, global properties + */ +Edge.prototype.setProperties = function(properties, constants) { + if (!properties) { + return; + } + + if (properties.from != undefined) {this.fromId = properties.from;} + if (properties.to != undefined) {this.toId = properties.to;} + + if (properties.id != undefined) {this.id = properties.id;} + if (properties.style != undefined) {this.style = properties.style;} + if (properties.label != undefined) {this.label = properties.label;} + if (this.label) { + this.fontSize = constants.edges.fontSize; + this.fontFace = constants.edges.fontFace; + this.fontColor = constants.edges.fontColor; + if (properties.fontColor != undefined) {this.fontColor = properties.fontColor;} + if (properties.fontSize != undefined) {this.fontSize = properties.fontSize;} + if (properties.fontFace != undefined) {this.fontFace = properties.fontFace;} + } + if (properties.title != undefined) {this.title = properties.title;} + if (properties.width != undefined) {this.width = properties.width;} + if (properties.value != undefined) {this.value = properties.value;} + if (properties.length != undefined) {this.length = properties.length;} + + // Added to support dashed lines + // David Jordan + // 2012-08-08 + if (properties.dash) { + if (properties.dash.length != undefined) {this.dash.length = properties.dash.length;} + if (properties.dash.gap != undefined) {this.dash.gap = properties.dash.gap;} + if (properties.dash.altLength != undefined) {this.dash.altLength = properties.dash.altLength;} + } + + if (properties.color != undefined) {this.color = properties.color;} + + // A node is connected when it has a from and to node. + this.connect(); + + this.widthFixed = this.widthFixed || (properties.width != undefined); + this.lengthFixed = this.lengthFixed || (properties.length != undefined); + this.stiffness = 1 / this.length; + + // set draw method based on style + switch (this.style) { + case 'line': this.draw = this._drawLine; break; + case 'arrow': this.draw = this._drawArrow; break; + case 'arrow-center': this.draw = this._drawArrowCenter; break; + case 'dash-line': this.draw = this._drawDashLine; break; + default: this.draw = this._drawLine; break; + } +}; + +/** + * Connect an edge to its nodes + */ +Edge.prototype.connect = function () { + this.disconnect(); + + this.from = this.graph.nodes[this.fromId] || null; + this.to = this.graph.nodes[this.toId] || null; + this.connected = (this.from && this.to); + + if (this.connected) { + this.from.attachEdge(this); + this.to.attachEdge(this); + } + else { + if (this.from) { + this.from.detachEdge(this); + } + if (this.to) { + this.to.detachEdge(this); + } + } +}; + +/** + * Disconnect an edge from its nodes + */ +Edge.prototype.disconnect = function () { + if (this.from) { + this.from.detachEdge(this); + this.from = null; + } + if (this.to) { + this.to.detachEdge(this); + this.to = null; + } + + this.connected = false; +}; + +/** + * get the title of this edge. + * @return {string} title The title of the edge, or undefined when no title + * has been set. + */ +Edge.prototype.getTitle = function() { + return this.title; +}; + + +/** + * Retrieve the value of the edge. Can be undefined + * @return {Number} value + */ +Edge.prototype.getValue = function() { + return this.value; +}; + +/** + * Adjust the value range of the edge. The edge will adjust it's width + * based on its value. + * @param {Number} min + * @param {Number} max + */ +Edge.prototype.setValueRange = function(min, max) { + if (!this.widthFixed && this.value !== undefined) { + var scale = (this.widthMax - this.widthMin) / (max - min); + this.width = (this.value - min) * scale + this.widthMin; + } +}; + +/** + * Redraw a edge + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + */ +Edge.prototype.draw = function(ctx) { + throw "Method draw not initialized in edge"; +}; + +/** + * Check if this object is overlapping with the provided object + * @param {Object} obj an object with parameters left, top + * @return {boolean} True if location is located on the edge + */ +Edge.prototype.isOverlappingWith = function(obj) { + var distMax = 10; + + var xFrom = this.from.x; + var yFrom = this.from.y; + var xTo = this.to.x; + var yTo = this.to.y; + var xObj = obj.left; + var yObj = obj.top; + + + var dist = Edge._dist(xFrom, yFrom, xTo, yTo, xObj, yObj); + + return (dist < distMax); +}; + + +/** + * Redraw a edge as a line + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Edge.prototype._drawLine = function(ctx) { + // set style + ctx.strokeStyle = this.color; + ctx.lineWidth = this._getLineWidth(); + + var point; + if (this.from != this.to) { + // draw line + this._line(ctx); + + // draw label + if (this.label) { + point = this._pointOnLine(0.5); + this._label(ctx, this.label, point.x, point.y); + } + } + else { + var x, y; + var radius = this.length / 4; + var node = this.from; + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width / 2; + y = node.y - radius; + } + else { + x = node.x + radius; + y = node.y - node.height / 2; + } + this._circle(ctx, x, y, radius); + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); + } +}; + +/** + * Get the line width of the edge. Depends on width and whether one of the + * connected nodes is selected. + * @return {Number} width + * @private + */ +Edge.prototype._getLineWidth = function() { + if (this.from.selected || this.to.selected) { + return Math.min(this.width * 2, this.widthMax); + } + else { + return this.width; + } +}; + +/** + * Draw a line between two nodes + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Edge.prototype._line = function (ctx) { + // draw a straight line + ctx.beginPath(); + ctx.moveTo(this.from.x, this.from.y); + ctx.lineTo(this.to.x, this.to.y); + ctx.stroke(); +}; + +/** + * Draw a line from a node to itself, a circle + * @param {CanvasRenderingContext2D} ctx + * @param {Number} x + * @param {Number} y + * @param {Number} radius + * @private + */ +Edge.prototype._circle = function (ctx, x, y, radius) { + // draw a circle + ctx.beginPath(); + ctx.arc(x, y, radius, 0, 2 * Math.PI, false); + ctx.stroke(); +}; + +/** + * Draw label with white background and with the middle at (x, y) + * @param {CanvasRenderingContext2D} ctx + * @param {String} text + * @param {Number} x + * @param {Number} y + * @private + */ +Edge.prototype._label = function (ctx, text, x, y) { + if (text) { + // TODO: cache the calculated size + ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") + + this.fontSize + "px " + this.fontFace; + ctx.fillStyle = 'white'; + var width = ctx.measureText(text).width; + var height = this.fontSize; + var left = x - width / 2; + var top = y - height / 2; + + ctx.fillRect(left, top, width, height); + + // draw text + ctx.fillStyle = this.fontColor || "black"; + ctx.textAlign = "left"; + ctx.textBaseline = "top"; + ctx.fillText(text, left, top); + } +}; + +/** + * Redraw a edge as a dashed line + * Draw this edge in the given canvas + * @author David Jordan + * @date 2012-08-08 + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Edge.prototype._drawDashLine = function(ctx) { + // set style + ctx.strokeStyle = this.color; + ctx.lineWidth = this._getLineWidth(); + + // draw dashed line + ctx.beginPath(); + ctx.lineCap = 'round'; + if (this.dash.altLength != undefined) //If an alt dash value has been set add to the array this value + { + ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, + [this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]); + } + else if (this.dash.length != undefined && this.dash.gap != undefined) //If a dash and gap value has been set add to the array this value + { + ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, + [this.dash.length,this.dash.gap]); + } + else //If all else fails draw a line + { + ctx.moveTo(this.from.x, this.from.y); + ctx.lineTo(this.to.x, this.to.y); + } + ctx.stroke(); + + // draw label + if (this.label) { + var point = this._pointOnLine(0.5); + this._label(ctx, this.label, point.x, point.y); + } +}; + +/** + * Get a point on a line + * @param {Number} percentage. Value between 0 (line start) and 1 (line end) + * @return {Object} point + * @private + */ +Edge.prototype._pointOnLine = function (percentage) { + return { + x: (1 - percentage) * this.from.x + percentage * this.to.x, + y: (1 - percentage) * this.from.y + percentage * this.to.y + } +}; + +/** + * Get a point on a circle + * @param {Number} x + * @param {Number} y + * @param {Number} radius + * @param {Number} percentage. Value between 0 (line start) and 1 (line end) + * @return {Object} point + * @private + */ +Edge.prototype._pointOnCircle = function (x, y, radius, percentage) { + var angle = (percentage - 3/8) * 2 * Math.PI; + return { + x: x + radius * Math.cos(angle), + y: y - radius * Math.sin(angle) + } +}; + +/** + * Redraw a edge as a line with an arrow halfway the line + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Edge.prototype._drawArrowCenter = function(ctx) { + var point; + // set style + ctx.strokeStyle = this.color; + ctx.fillStyle = this.color; + ctx.lineWidth = this._getLineWidth(); + + if (this.from != this.to) { + // draw line + this._line(ctx); + + // draw an arrow halfway the line + 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? + point = this._pointOnLine(0.5); + ctx.arrow(point.x, point.y, angle, length); + ctx.fill(); + ctx.stroke(); + + // draw label + if (this.label) { + point = this._pointOnLine(0.5); + this._label(ctx, this.label, point.x, point.y); + } + } + else { + // draw circle + var x, y; + var radius = this.length / 4; + var node = this.from; + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width / 2; + y = node.y - radius; + } + else { + x = node.x + radius; + y = node.y - node.height / 2; + } + this._circle(ctx, x, y, radius); + + // draw all arrows + var angle = 0.2 * Math.PI; + var length = 10 + 5 * this.width; // TODO: make customizable? + point = this._pointOnCircle(x, y, radius, 0.5); + ctx.arrow(point.x, point.y, angle, length); + ctx.fill(); + ctx.stroke(); + + // draw label + if (this.label) { + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); + } + } +}; + + + +/** + * Redraw a edge as a line with an arrow + * Draw this edge in the given canvas + * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Edge.prototype._drawArrow = function(ctx) { + // set style + ctx.strokeStyle = this.color; + ctx.fillStyle = this.color; + ctx.lineWidth = this._getLineWidth(); + + // draw line + var angle, length; + if (this.from != this.to) { + // calculate length and angle of the line + angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); + var dx = (this.to.x - this.from.x); + var dy = (this.to.y - this.from.y); + var lEdge = Math.sqrt(dx * dx + dy * dy); + + var lFrom = this.from.distanceToBorder(ctx, angle + Math.PI); + var pFrom = (lEdge - lFrom) / lEdge; + var xFrom = (pFrom) * this.from.x + (1 - pFrom) * this.to.x; + var yFrom = (pFrom) * this.from.y + (1 - pFrom) * this.to.y; + + var lTo = this.to.distanceToBorder(ctx, angle); + var pTo = (lEdge - lTo) / lEdge; + var xTo = (1 - pTo) * this.from.x + pTo * this.to.x; + var yTo = (1 - pTo) * this.from.y + pTo * this.to.y; + + ctx.beginPath(); + ctx.moveTo(xFrom, yFrom); + ctx.lineTo(xTo, yTo); + ctx.stroke(); + + // draw arrow at the end of the line + length = 10 + 5 * this.width; // TODO: make customizable? + ctx.arrow(xTo, yTo, angle, length); + ctx.fill(); + ctx.stroke(); + + // draw label + if (this.label) { + var point = this._pointOnLine(0.5); + this._label(ctx, this.label, point.x, point.y); + } + } + else { + // draw circle + var node = this.from; + var x, y, arrow; + var radius = this.length / 4; + if (!node.width) { + node.resize(ctx); + } + if (node.width > node.height) { + x = node.x + node.width / 2; + y = node.y - radius; + arrow = { + x: x, + y: node.y, + angle: 0.9 * Math.PI + }; + } + else { + x = node.x + radius; + y = node.y - node.height / 2; + arrow = { + x: node.x, + y: y, + angle: 0.6 * Math.PI + }; + } + ctx.beginPath(); + // TODO: do not draw a circle, but an arc + // TODO: similarly, for a line without arrows, draw to the border of the nodes instead of the center + ctx.arc(x, y, radius, 0, 2 * Math.PI, false); + ctx.stroke(); + + // draw all arrows + length = 10 + 5 * this.width; // TODO: make customizable? + ctx.arrow(arrow.x, arrow.y, arrow.angle, length); + ctx.fill(); + ctx.stroke(); + + // draw label + if (this.label) { + point = this._pointOnCircle(x, y, radius, 0.5); + this._label(ctx, this.label, point.x, point.y); + } + } +}; + + + +/** + * Calculate the distance between a point (x3,y3) and a line segment from + * (x1,y1) to (x2,y2). + * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment + * @param {number} x1 + * @param {number} y1 + * @param {number} x2 + * @param {number} y2 + * @param {number} x3 + * @param {number} y3 + * @private + */ +Edge._dist = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point + var px = x2-x1, + py = y2-y1, + something = px*px + py*py, + u = ((x3 - x1) * px + (y3 - y1) * py) / something; + + if (u > 1) { + u = 1; + } + else if (u < 0) { + u = 0; + } + + var x = x1 + u * px, + y = y1 + u * py, + dx = x - x3, + dy = y - y3; + + //# Note: If the actual distance does not matter, + //# if you only want to compare what this function + //# returns to other results of this function, you + //# can just return the squared distance instead + //# (i.e. remove the sqrt) to gain a little performance + + return Math.sqrt(dx*dx + dy*dy); +}; + +/** + * Popup is a class to create a popup window with some text + * @param {Element} container The container object. + * @param {Number} [x] + * @param {Number} [y] + * @param {String} [text] + */ +function Popup(container, x, y, text) { + if (container) { + this.container = container; + } + else { + this.container = document.body; + } + this.x = 0; + this.y = 0; + this.padding = 5; + + if (x !== undefined && y !== undefined ) { + this.setPosition(x, y); + } + if (text !== undefined) { + this.setText(text); + } + + // create the frame + this.frame = document.createElement("div"); + var style = this.frame.style; + style.position = "absolute"; + style.visibility = "hidden"; + style.border = "1px solid #666"; + style.color = "black"; + style.padding = this.padding + "px"; + style.backgroundColor = "#FFFFC6"; + style.borderRadius = "3px"; + style.MozBorderRadius = "3px"; + style.WebkitBorderRadius = "3px"; + style.boxShadow = "3px 3px 10px rgba(128, 128, 128, 0.5)"; + style.whiteSpace = "nowrap"; + this.container.appendChild(this.frame); +}; + +/** + * @param {number} x Horizontal position of the popup window + * @param {number} y Vertical position of the popup window + */ +Popup.prototype.setPosition = function(x, y) { + this.x = parseInt(x); + this.y = parseInt(y); +}; + +/** + * Set the text for the popup window. This can be HTML code + * @param {string} text + */ +Popup.prototype.setText = function(text) { + this.frame.innerHTML = text; +}; + +/** + * Show the popup window + * @param {boolean} show Optional. Show or hide the window + */ +Popup.prototype.show = function (show) { + if (show === undefined) { + show = true; + } + + if (show) { + var height = this.frame.clientHeight; + var width = this.frame.clientWidth; + var maxHeight = this.frame.parentNode.clientHeight; + var maxWidth = this.frame.parentNode.clientWidth; + + var top = (this.y - height); + if (top + height + this.padding > maxHeight) { + top = maxHeight - height - this.padding; + } + if (top < this.padding) { + top = this.padding; + } + + var left = this.x; + if (left + width + this.padding > maxWidth) { + left = maxWidth - width - this.padding; + } + if (left < this.padding) { + left = this.padding; + } + + this.frame.style.left = left + "px"; + this.frame.style.top = top + "px"; + this.frame.style.visibility = "visible"; + } + else { + this.hide(); + } +}; + +/** + * Hide the popup window + */ +Popup.prototype.hide = function () { + this.frame.style.visibility = "hidden"; +}; + +/** + * @class Groups + * This class can store groups and properties specific for groups. + */ +Groups = function () { + this.clear(); + this.defaultIndex = 0; +}; + + +/** + * default constants for group colors + */ +Groups.DEFAULT = [ + {border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}}, // blue + {border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}}, // yellow + {border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}}, // red + {border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}}, // green + {border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}}, // magenta + {border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}}, // purple + {border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}}, // orange + {border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}}, // darkblue + {border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}}, // pink + {border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}} // mint +]; + + +/** + * Clear all groups + */ +Groups.prototype.clear = function () { + this.groups = {}; + this.groups.length = function() + { + var i = 0; + for ( var p in this ) { + if (this.hasOwnProperty(p)) { + i++; + } + } + return i; + } +}; + + +/** + * get group properties of a groupname. If groupname is not found, a new group + * is added. + * @param {*} groupname Can be a number, string, Date, etc. + * @return {Object} group The created group, containing all group properties + */ +Groups.prototype.get = function (groupname) { + var group = this.groups[groupname]; + + if (group == undefined) { + // create new group + var index = this.defaultIndex % Groups.DEFAULT.length; + this.defaultIndex++; + group = {}; + group.color = Groups.DEFAULT[index]; + this.groups[groupname] = group; + } + + return group; +}; + +/** + * Add a custom group style + * @param {String} groupname + * @param {Object} style An object containing borderColor, + * backgroundColor, etc. + * @return {Object} group The created group object + */ +Groups.prototype.add = function (groupname, style) { + this.groups[groupname] = style; + if (style.color) { + style.color = Node.parseColor(style.color); + } + return style; +}; + +/** + * @class Images + * This class loads images and keeps them stored. + */ +Images = function () { + this.images = {}; + + this.callback = undefined; +}; + +/** + * Set an onload callback function. This will be called each time an image + * is loaded + * @param {function} callback + */ +Images.prototype.setOnloadCallback = function(callback) { + this.callback = callback; +}; + +/** + * + * @param {string} url Url of the image + * @return {Image} img The image object + */ +Images.prototype.load = function(url) { + var img = this.images[url]; + if (img == undefined) { + // create the image + var images = this; + img = new Image(); + this.images[url] = img; + img.onload = function() { + if (images.callback) { + images.callback(this); + } + }; + img.src = url; + } + + return img; +}; + +/** + * @constructor Graph + * Create a graph visualization, displaying nodes and edges. + * + * @param {Element} container The DOM element in which the Graph will + * be created. Normally a div element. + * @param {Object} data An object containing parameters + * {Array} nodes + * {Array} edges + * @param {Object} options Options + */ +function Graph (container, data, options) { + // create variables and set default values + this.containerElement = container; + this.width = '100%'; + this.height = '100%'; + this.refreshRate = 50; // milliseconds + this.stabilize = true; // stabilize before displaying the graph + this.selectable = true; + + // set constant values + this.constants = { + nodes: { + radiusMin: 5, + radiusMax: 20, + radius: 5, + distance: 100, // px + shape: 'ellipse', + image: undefined, + widthMin: 16, // px + widthMax: 64, // px + fontColor: 'black', + fontSize: 14, // px + //fontFace: verdana, + fontFace: 'arial', + color: { + border: '#2B7CE9', + background: '#97C2FC', + highlight: { + border: '#2B7CE9', + background: '#D2E5FF' + } + }, + borderColor: '#2B7CE9', + backgroundColor: '#97C2FC', + highlightColor: '#D2E5FF', + group: undefined + }, + edges: { + widthMin: 1, + widthMax: 15, + width: 1, + style: 'line', + color: '#343434', + fontColor: '#343434', + fontSize: 14, // px + fontFace: 'arial', + //distance: 100, //px + length: 100, // px + dash: { + length: 10, + gap: 5, + altLength: undefined + } + }, + minForce: 0.05, + minVelocity: 0.02, // px/s + maxIterations: 1000 // maximum number of iteration to stabilize + }; + + var graph = this; + this.nodes = {}; // object with Node objects + this.edges = {}; // object with Edge objects + // TODO: create a counter to keep track on the number of nodes having values + // TODO: create a counter to keep track on the number of nodes currently moving + // TODO: create a counter to keep track on the number of edges having values + + this.nodesData = null; // A DataSet or DataView + this.edgesData = null; // A DataSet or DataView + + // create event listeners used to subscribe on the DataSets of the nodes and edges + var me = this; + this.nodesListeners = { + 'add': function (event, params) { + me._addNodes(params.items); + me.start(); + }, + 'update': function (event, params) { + me._updateNodes(params.items); + me.start(); + }, + 'remove': function (event, params) { + me._removeNodes(params.items); + me.start(); + } + }; + this.edgesListeners = { + 'add': function (event, params) { + me._addEdges(params.items); + me.start(); + }, + 'update': function (event, params) { + me._updateEdges(params.items); + me.start(); + }, + 'remove': function (event, params) { + me._removeEdges(params.items); + me.start(); + } + }; + + this.groups = new Groups(); // object with groups + this.images = new Images(); // object with images + this.images.setOnloadCallback(function () { + graph._redraw(); + }); + + // properties of the data + this.moving = false; // True if any of the nodes have an undefined position + + this.selection = []; + this.timer = undefined; + + // create a frame and canvas + this._create(); + + // apply options + this.setOptions(options); + + // draw data + this.setData(data); +} + +/** + * Set nodes and edges, and optionally options as well. + * + * @param {Object} data Object containing parameters: + * {Array | DataSet | DataView} [nodes] Array with nodes + * {Array | DataSet | DataView} [edges] Array with edges + * {String} [dot] String containing data in DOT format + * {Options} [options] Object with options + */ +Graph.prototype.setData = function(data) { + if (data && data.dot && (data.nodes || data.edges)) { + throw new SyntaxError('Data must contain either parameter "dot" or ' + + ' parameter pair "nodes" and "edges", but not both.'); + } + + // set options + this.setOptions(data && data.options); + + // set all data + if (data && data.dot) { + // parse DOT file + if(data && data.dot) { + var dotData = vis.util.DOTToGraph(data.dot); + this.setData(dotData); + return; + } + } + else { + this._setNodes(data && data.nodes); + this._setEdges(data && data.edges); + } + + // find a stable position or start animating to a stable position + if (this.stabilize) { + this._doStabilize(); + } + this.start(); +}; + +/** + * Set options + * @param {Object} options + */ +Graph.prototype.setOptions = function (options) { + if (options) { + // retrieve parameter values + if (options.width != undefined) {this.width = options.width;} + if (options.height != undefined) {this.height = options.height;} + if (options.stabilize != undefined) {this.stabilize = options.stabilize;} + if (options.selectable != undefined) {this.selectable = options.selectable;} + + // TODO: work out these options and document them + if (options.edges) { + for (var prop in options.edges) { + if (options.edges.hasOwnProperty(prop)) { + this.constants.edges[prop] = options.edges[prop]; + } + } + + if (options.edges.length != undefined && + options.nodes && options.nodes.distance == undefined) { + this.constants.edges.length = options.edges.length; + this.constants.nodes.distance = options.edges.length * 1.25; + } + + if (!options.edges.fontColor) { + this.constants.edges.fontColor = options.edges.color; + } + + // Added to support dashed lines + // David Jordan + // 2012-08-08 + if (options.edges.dash) { + if (options.edges.dash.length != undefined) { + this.constants.edges.dash.length = options.edges.dash.length; + } + if (options.edges.dash.gap != undefined) { + this.constants.edges.dash.gap = options.edges.dash.gap; + } + if (options.edges.dash.altLength != undefined) { + this.constants.edges.dash.altLength = options.edges.dash.altLength; + } + } + } + + if (options.nodes) { + for (prop in options.nodes) { + if (options.nodes.hasOwnProperty(prop)) { + this.constants.nodes[prop] = options.nodes[prop]; + } + } + + if (options.nodes.color) { + this.constants.nodes.color = Node.parseColor(options.nodes.color); + } + + /* + if (options.nodes.widthMin) this.constants.nodes.radiusMin = options.nodes.widthMin; + if (options.nodes.widthMax) this.constants.nodes.radiusMax = options.nodes.widthMax; + */ + } + + if (options.groups) { + for (var groupname in options.groups) { + if (options.groups.hasOwnProperty(groupname)) { + var group = options.groups[groupname]; + this.groups.add(groupname, group); + } + } + } + } + + this.setSize(this.width, this.height); + this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2); + this._setScale(1); +}; + +/** + * fire an event + * @param {String} event The name of an event, for example 'select' + * @param {Object} params Optional object with event parameters + * @private + */ +Graph.prototype._trigger = function (event, params) { + events.trigger(this, event, params); +}; + + +/** + * Create the main frame for the Graph. + * This function is executed once when a Graph object is created. The frame + * contains a canvas, and this canvas contains all objects like the axis and + * nodes. + * @private + */ +Graph.prototype._create = function () { + // remove all elements from the container element. + while (this.containerElement.hasChildNodes()) { + this.containerElement.removeChild(this.containerElement.firstChild); + } + + this.frame = document.createElement('div'); + this.frame.className = 'graph-frame'; + this.frame.style.position = 'relative'; + this.frame.style.overflow = 'hidden'; + + // create the graph canvas (HTML canvas element) + this.frame.canvas = document.createElement( 'canvas' ); + this.frame.canvas.style.position = 'relative'; + this.frame.appendChild(this.frame.canvas); + if (!this.frame.canvas.getContext) { + var noCanvas = document.createElement( 'DIV' ); + noCanvas.style.color = 'red'; + noCanvas.style.fontWeight = 'bold' ; + noCanvas.style.padding = '10px'; + noCanvas.innerHTML = 'Error: your browser does not support HTML canvas'; + this.frame.canvas.appendChild(noCanvas); + } + + var me = this; + this.drag = {}; + this.pinch = {}; + this.hammer = Hammer(this.frame.canvas, { + prevent_default: true + }); + this.hammer.on('tap', me._onTap.bind(me) ); + this.hammer.on('hold', me._onHold.bind(me) ); + this.hammer.on('pinch', me._onPinch.bind(me) ); + this.hammer.on('touch', me._onTouch.bind(me) ); + this.hammer.on('dragstart', me._onDragStart.bind(me) ); + this.hammer.on('drag', me._onDrag.bind(me) ); + this.hammer.on('dragend', me._onDragEnd.bind(me) ); + this.hammer.on('mousewheel',me._onMouseWheel.bind(me) ); + this.hammer.on('DOMMouseScroll',me._onMouseWheel.bind(me) ); // for FF + this.hammer.on('mousemove', me._onMouseMoveTitle.bind(me) ); + + // add the frame to the container element + this.containerElement.appendChild(this.frame); +}; + +/** + * + * @param {{x: Number, y: Number}} pointer + * @return {Number | null} node + * @private + */ +Graph.prototype._getNodeAt = function (pointer) { + var x = this._canvasToX(pointer.x); + var y = this._canvasToY(pointer.y); + + var obj = { + left: x, + top: y, + right: x, + bottom: y + }; + + // if there are overlapping nodes, select the last one, this is the + // one which is drawn on top of the others + var overlappingNodes = this._getNodesOverlappingWith(obj); + return (overlappingNodes.length > 0) ? + overlappingNodes[overlappingNodes.length - 1] : null; +}; + +/** + * Get the pointer location from a touch location + * @param {{pageX: Number, pageY: Number}} touch + * @return {{x: Number, y: Number}} pointer + * @private + */ +Graph.prototype._getPointer = function (touch) { + return { + x: touch.pageX - vis.util.getAbsoluteLeft(this.frame.canvas), + y: touch.pageY - vis.util.getAbsoluteTop(this.frame.canvas) + }; +}; + +/** + * On start of a touch gesture, store the pointer + * @param event + * @private + */ +Graph.prototype._onTouch = function (event) { + this.drag.pointer = this._getPointer(event.gesture.touches[0]); + this.drag.pinched = false; + this.pinch.scale = this._getScale(); +}; + +/** + * handle drag start event + * @private + */ +Graph.prototype._onDragStart = function () { + var drag = this.drag; + + drag.selection = []; + drag.translation = this._getTranslation(); + drag.nodeId = this._getNodeAt(drag.pointer); + // note: drag.pointer is set in _onTouch to get the initial touch location + + var node = this.nodes[drag.nodeId]; + if (node) { + // select the clicked node if not yet selected + if (!node.isSelected()) { + this._selectNodes([drag.nodeId]); + } + + // create an array with the selected nodes and their original location and status + var me = this; + this.selection.forEach(function (id) { + var node = me.nodes[id]; + if (node) { + var s = { + id: id, + node: node, + + // store original x, y, xFixed and yFixed, make the node temporarily Fixed + x: node.x, + y: node.y, + xFixed: node.xFixed, + yFixed: node.yFixed + }; + + node.xFixed = true; + node.yFixed = true; + + drag.selection.push(s); + } + }); + + } +}; + +/** + * handle drag event + * @private + */ +Graph.prototype._onDrag = function (event) { + if (this.drag.pinched) { + return; + } + + var pointer = this._getPointer(event.gesture.touches[0]); + + var me = this, + drag = this.drag, + selection = drag.selection; + if (selection && selection.length) { + // calculate delta's and new location + var deltaX = pointer.x - drag.pointer.x, + deltaY = pointer.y - drag.pointer.y; + + // update position of all selected nodes + selection.forEach(function (s) { + var node = s.node; + + if (!s.xFixed) { + node.x = me._canvasToX(me._xToCanvas(s.x) + deltaX); + } + + if (!s.yFixed) { + node.y = me._canvasToY(me._yToCanvas(s.y) + deltaY); + } + }); + + // start animation if not yet running + if (!this.moving) { + this.moving = true; + this.start(); + } + } + else { + // move the graph + var diffX = pointer.x - this.drag.pointer.x; + var diffY = pointer.y - this.drag.pointer.y; + + this._setTranslation( + this.drag.translation.x + diffX, + this.drag.translation.y + diffY); + this._redraw(); + + this.moved = true; + } +}; + +/** + * handle drag start event + * @private + */ +Graph.prototype._onDragEnd = function () { + var selection = this.drag.selection; + if (selection) { + selection.forEach(function (s) { + // restore original xFixed and yFixed + s.node.xFixed = s.xFixed; + s.node.yFixed = s.yFixed; + }); + } +}; + +/** + * handle tap/click event: select/unselect a node + * @private + */ +Graph.prototype._onTap = function (event) { + var pointer = this._getPointer(event.gesture.touches[0]); + + var nodeId = this._getNodeAt(pointer); + var node = this.nodes[nodeId]; + if (node) { + // select this node + this._selectNodes([nodeId]); + + if (!this.moving) { + this._redraw(); + } + } + else { + // remove selection + this._unselectNodes(); + this._redraw(); + } +}; + +/** + * handle long tap event: multi select nodes + * @private + */ +Graph.prototype._onHold = function (event) { + var pointer = this._getPointer(event.gesture.touches[0]); + var nodeId = this._getNodeAt(pointer); + var node = this.nodes[nodeId]; + if (node) { + if (!node.isSelected()) { + // select this node, keep previous selection + var append = true; + this._selectNodes([nodeId], append); + } + else { + this._unselectNodes([nodeId]); + } + + if (!this.moving) { + this._redraw(); + } + } + else { + // Do nothing + } +}; + +/** + * Handle pinch event + * @param event + * @private + */ +Graph.prototype._onPinch = function (event) { + var pointer = this._getPointer(event.gesture.center); + + this.drag.pinched = true; + if (!('scale' in this.pinch)) { + this.pinch.scale = 1; + } + + // TODO: enable moving while pinching? + var scale = this.pinch.scale * event.gesture.scale; + this._zoom(scale, pointer) +}; + +/** + * Zoom the graph in or out + * @param {Number} scale a number around 1, and between 0.01 and 10 + * @param {{x: Number, y: Number}} pointer + * @return {Number} appliedScale scale is limited within the boundaries + * @private + */ +Graph.prototype._zoom = function(scale, pointer) { + var scaleOld = this._getScale(); + if (scale < 0.01) { + scale = 0.01; + } + if (scale > 10) { + scale = 10; + } + + var translation = this._getTranslation(); + var scaleFrac = scale / scaleOld; + var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac; + var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac; + + this._setScale(scale); + this._setTranslation(tx, ty); + this._redraw(); + + return scale; +}; + +/** + * Event handler for mouse wheel event, used to zoom the timeline + * See http://adomas.org/javascript-mouse-wheel/ + * https://github.com/EightMedia/hammer.js/issues/256 + * @param {MouseEvent} event + * @private + */ +Graph.prototype._onMouseWheel = function(event) { + // retrieve delta + var delta = 0; + if (event.wheelDelta) { /* IE/Opera. */ + delta = event.wheelDelta/120; + } else if (event.detail) { /* Mozilla case. */ + // In Mozilla, sign of delta is different than in IE. + // Also, delta is multiple of 3. + delta = -event.detail/3; + } + + // If delta is nonzero, handle it. + // Basically, delta is now positive if wheel was scrolled up, + // and negative, if wheel was scrolled down. + if (delta) { + if (!('mouswheelScale' in this.pinch)) { + this.pinch.mouswheelScale = 1; + } + + // calculate the new scale + var scale = this.pinch.mouswheelScale; + var zoom = delta / 10; + if (delta < 0) { + zoom = zoom / (1 - zoom); + } + scale *= (1 + zoom); + + // calculate the pointer location + var gesture = util.fakeGesture(this, event); + var pointer = this._getPointer(gesture.center); + + // apply the new scale + scale = this._zoom(scale, pointer); + + // store the new, applied scale + this.pinch.mouswheelScale = scale; + } + + // Prevent default actions caused by mouse wheel. + event.preventDefault(); +}; + + +/** + * Mouse move handler for checking whether the title moves over a node with a title. + * @param {Event} event + * @private + */ +Graph.prototype._onMouseMoveTitle = function (event) { + var gesture = util.fakeGesture(this, event); + var pointer = this._getPointer(gesture.center); + + // check if the previously selected node is still selected + if (this.popupNode) { + this._checkHidePopup(pointer); + } + + // start a timeout that will check if the mouse is positioned above + // an element + var me = this; + var checkShow = function() { + me._checkShowPopup(pointer); + }; + if (this.popupTimer) { + clearInterval(this.popupTimer); // stop any running timer + } + if (!this.leftButtonDown) { + this.popupTimer = setTimeout(checkShow, 300); + } +}; + +/** + * Check if there is an element on the given position in the graph + * (a node or edge). If so, and if this element has a title, + * show a popup window with its title. + * + * @param {{x:Number, y:Number}} pointer + * @private + */ +Graph.prototype._checkShowPopup = function (pointer) { + var obj = { + left: this._canvasToX(pointer.x), + top: this._canvasToY(pointer.y), + right: this._canvasToX(pointer.x), + bottom: this._canvasToY(pointer.y) + }; + + var id; + var lastPopupNode = this.popupNode; + + if (this.popupNode == undefined) { + // search the nodes for overlap, select the top one in case of multiple nodes + var nodes = this.nodes; + for (id in nodes) { + if (nodes.hasOwnProperty(id)) { + var node = nodes[id]; + if (node.getTitle() != undefined && node.isOverlappingWith(obj)) { + this.popupNode = node; + break; + } + } + } + } + + if (this.popupNode == undefined) { + // search the edges for overlap + var edges = this.edges; + for (id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + if (edge.connected && (edge.getTitle() != undefined) && + edge.isOverlappingWith(obj)) { + this.popupNode = edge; + break; + } + } + } + } + + if (this.popupNode) { + // show popup message window + if (this.popupNode != lastPopupNode) { + var me = this; + if (!me.popup) { + me.popup = new Popup(me.frame); + } + + // adjust a small offset such that the mouse cursor is located in the + // bottom left location of the popup, and you can easily move over the + // popup area + me.popup.setPosition(pointer.x - 3, pointer.y - 3); + me.popup.setText(me.popupNode.getTitle()); + me.popup.show(); + } + } + else { + if (this.popup) { + this.popup.hide(); + } + } +}; + +/** + * Check if the popup must be hided, which is the case when the mouse is no + * longer hovering on the object + * @param {{x:Number, y:Number}} pointer + * @private + */ +Graph.prototype._checkHidePopup = function (pointer) { + if (!this.popupNode || !this._getNodeAt(pointer) ) { + this.popupNode = undefined; + if (this.popup) { + this.popup.hide(); + } + } +}; + +/** + * Unselect selected nodes. If no selection array is provided, all nodes + * are unselected + * @param {Object[]} selection Array with selection objects, each selection + * object has a parameter row. Optional + * @param {Boolean} triggerSelect If true (default), the select event + * is triggered when nodes are unselected + * @return {Boolean} changed True if the selection is changed + * @private + */ +Graph.prototype._unselectNodes = function(selection, triggerSelect) { + var changed = false; + var i, iMax, id; + + if (selection) { + // remove provided selections + for (i = 0, iMax = selection.length; i < iMax; i++) { + id = selection[i]; + this.nodes[id].unselect(); + + var j = 0; + while (j < this.selection.length) { + if (this.selection[j] == id) { + this.selection.splice(j, 1); + changed = true; + } + else { + j++; + } + } + } + } + else if (this.selection && this.selection.length) { + // remove all selections + for (i = 0, iMax = this.selection.length; i < iMax; i++) { + id = this.selection[i]; + this.nodes[id].unselect(); + changed = true; + } + this.selection = []; + } + + if (changed && (triggerSelect == true || triggerSelect == undefined)) { + // fire the select event + this._trigger('select'); + } + + return changed; +}; + +/** + * select all nodes on given location x, y + * @param {Array} selection an array with node ids + * @param {boolean} append If true, the new selection will be appended to the + * current selection (except for duplicate entries) + * @return {Boolean} changed True if the selection is changed + * @private + */ +Graph.prototype._selectNodes = function(selection, append) { + var changed = false; + var i, iMax; + + // TODO: the selectNodes method is a little messy, rework this + + // check if the current selection equals the desired selection + var selectionAlreadyThere = true; + if (selection.length != this.selection.length) { + selectionAlreadyThere = false; + } + else { + for (i = 0, iMax = Math.min(selection.length, this.selection.length); i < iMax; i++) { + if (selection[i] != this.selection[i]) { + selectionAlreadyThere = false; + break; + } + } + } + if (selectionAlreadyThere) { + return changed; + } + + if (append == undefined || append == false) { + // first deselect any selected node + var triggerSelect = false; + changed = this._unselectNodes(undefined, triggerSelect); + } + + for (i = 0, iMax = selection.length; i < iMax; i++) { + // add each of the new selections, but only when they are not duplicate + var id = selection[i]; + var isDuplicate = (this.selection.indexOf(id) != -1); + if (!isDuplicate) { + this.nodes[id].select(); + this.selection.push(id); + changed = true; + } + } + + if (changed) { + // fire the select event + this._trigger('select'); + } + + return changed; +}; + +/** + * retrieve all nodes overlapping with given object + * @param {Object} obj An object with parameters left, top, right, bottom + * @return {Number[]} An array with id's of the overlapping nodes + * @private + */ +Graph.prototype._getNodesOverlappingWith = function (obj) { + var nodes = this.nodes, + overlappingNodes = []; + + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + if (nodes[id].isOverlappingWith(obj)) { + overlappingNodes.push(id); + } + } + } + + return overlappingNodes; +}; + +/** + * retrieve the currently selected nodes + * @return {Number[] | String[]} selection An array with the ids of the + * selected nodes. + */ +Graph.prototype.getSelection = function() { + return this.selection.concat([]); +}; + +/** + * select zero or more nodes + * @param {Number[] | String[]} selection An array with the ids of the + * selected nodes. + */ +Graph.prototype.setSelection = function(selection) { + var i, iMax, id; + + if (!selection || (selection.length == undefined)) + throw 'Selection must be an array with ids'; + + // first unselect any selected node + for (i = 0, iMax = this.selection.length; i < iMax; i++) { + id = this.selection[i]; + this.nodes[id].unselect(); + } + + this.selection = []; + + for (i = 0, iMax = selection.length; i < iMax; i++) { + id = selection[i]; + + var node = this.nodes[id]; + if (!node) { + throw new RangeError('Node with id "' + id + '" not found'); + } + node.select(); + this.selection.push(id); + } + + this.redraw(); +}; + +/** + * Validate the selection: remove ids of nodes which no longer exist + * @private + */ +Graph.prototype._updateSelection = function () { + var i = 0; + while (i < this.selection.length) { + var id = this.selection[i]; + if (!this.nodes[id]) { + this.selection.splice(i, 1); + } + else { + i++; + } + } +}; + +/** + * Temporary method to test calculating a hub value for the nodes + * @param {number} level Maximum number edges between two nodes in order + * to call them connected. Optional, 1 by default + * @return {Number[]} connectioncount array with the connection count + * for each node + * @private + */ +Graph.prototype._getConnectionCount = function(level) { + if (level == undefined) { + level = 1; + } + + // get the nodes connected to given nodes + function getConnectedNodes(nodes) { + var connectedNodes = []; + + for (var j = 0, jMax = nodes.length; j < jMax; j++) { + var node = nodes[j]; + + // find all nodes connected to this node + var edges = node.edges; + for (var i = 0, iMax = edges.length; i < iMax; i++) { + var edge = edges[i]; + var other = null; + + // check if connected + if (edge.from == node) + other = edge.to; + else if (edge.to == node) + other = edge.from; + + // check if the other node is not already in the list with nodes + var k, kMax; + if (other) { + for (k = 0, kMax = nodes.length; k < kMax; k++) { + if (nodes[k] == other) { + other = null; + break; + } + } + } + if (other) { + for (k = 0, kMax = connectedNodes.length; k < kMax; k++) { + if (connectedNodes[k] == other) { + other = null; + break; + } + } + } + + if (other) + connectedNodes.push(other); + } + } + + return connectedNodes; + } + + var connections = []; + var nodes = this.nodes; + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + var c = [nodes[id]]; + for (var l = 0; l < level; l++) { + c = c.concat(getConnectedNodes(c)); + } + connections.push(c); + } + } + + var hubs = []; + for (var i = 0, len = connections.length; i < len; i++) { + hubs.push(connections[i].length); + } + + return hubs; +}; + + +/** + * Set a new size for the graph + * @param {string} width Width in pixels or percentage (for example '800px' + * or '50%') + * @param {string} height Height in pixels or percentage (for example '400px' + * or '30%') + */ +Graph.prototype.setSize = function(width, height) { + this.frame.style.width = width; + this.frame.style.height = height; + + 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; +}; + +/** + * Set a data set with nodes for the graph + * @param {Array | DataSet | DataView} nodes The data containing the nodes. + * @private + */ +Graph.prototype._setNodes = function(nodes) { + var oldNodesData = this.nodesData; + + if (nodes instanceof DataSet || nodes instanceof DataView) { + this.nodesData = nodes; + } + else if (nodes instanceof Array) { + this.nodesData = new DataSet(); + this.nodesData.add(nodes); + } + else if (!nodes) { + this.nodesData = new DataSet(); + } + else { + throw new TypeError('Array or DataSet expected'); + } + + if (oldNodesData) { + // unsubscribe from old dataset + util.forEach(this.nodesListeners, function (callback, event) { + oldNodesData.unsubscribe(event, callback); + }); + } + + // remove drawn nodes + this.nodes = {}; + + if (this.nodesData) { + // subscribe to new dataset + var me = this; + util.forEach(this.nodesListeners, function (callback, event) { + me.nodesData.subscribe(event, callback); + }); + + // draw all new nodes + var ids = this.nodesData.getIds(); + this._addNodes(ids); + } + + this._updateSelection(); +}; + +/** + * Add nodes + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._addNodes = function(ids) { + var id; + for (var i = 0, len = ids.length; i < len; i++) { + id = ids[i]; + var data = this.nodesData.get(id); + var node = new Node(data, this.images, this.groups, this.constants); + this.nodes[id] = node; // note: this may replace an existing node + + if (!node.isFixed()) { + // TODO: position new nodes in a smarter way! + var radius = this.constants.edges.length * 2; + var count = ids.length; + var angle = 2 * Math.PI * (i / count); + node.x = radius * Math.cos(angle); + node.y = radius * Math.sin(angle); + + // note: no not use node.isMoving() here, as that gives the current + // velocity of the node, which is zero after creation of the node. + this.moving = true; + } + } + + this._reconnectEdges(); + this._updateValueRange(this.nodes); +}; + +/** + * Update existing nodes, or create them when not yet existing + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._updateNodes = function(ids) { + var nodes = this.nodes, + nodesData = this.nodesData; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + var node = nodes[id]; + var data = nodesData.get(id); + if (node) { + // update node + node.setProperties(data, this.constants); + } + else { + // create node + node = new Node(properties, this.images, this.groups, this.constants); + nodes[id] = node; + + if (!node.isFixed()) { + this.moving = true; + } + } + } + + this._reconnectEdges(); + this._updateValueRange(nodes); +}; + +/** + * Remove existing nodes. If nodes do not exist, the method will just ignore it. + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._removeNodes = function(ids) { + var nodes = this.nodes; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + delete nodes[id]; + } + + this._reconnectEdges(); + this._updateSelection(); + this._updateValueRange(nodes); +}; + +/** + * Load edges by reading the data table + * @param {Array | DataSet | DataView} edges The data containing the edges. + * @private + * @private + */ +Graph.prototype._setEdges = function(edges) { + var oldEdgesData = this.edgesData; + + if (edges instanceof DataSet || edges instanceof DataView) { + this.edgesData = edges; + } + else if (edges instanceof Array) { + this.edgesData = new DataSet(); + this.edgesData.add(edges); + } + else if (!edges) { + this.edgesData = new DataSet(); + } + else { + throw new TypeError('Array or DataSet expected'); + } + + if (oldEdgesData) { + // unsubscribe from old dataset + util.forEach(this.edgesListeners, function (callback, event) { + oldEdgesData.unsubscribe(event, callback); + }); + } + + // remove drawn edges + this.edges = {}; + + if (this.edgesData) { + // subscribe to new dataset + var me = this; + util.forEach(this.edgesListeners, function (callback, event) { + me.edgesData.subscribe(event, callback); + }); + + // draw all new nodes + var ids = this.edgesData.getIds(); + this._addEdges(ids); + } + + this._reconnectEdges(); +}; + +/** + * Add edges + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._addEdges = function (ids) { + var edges = this.edges, + edgesData = this.edgesData; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + + var oldEdge = edges[id]; + if (oldEdge) { + oldEdge.disconnect(); + } + + var data = edgesData.get(id); + edges[id] = new Edge(data, this, this.constants); + } + + this.moving = true; + this._updateValueRange(edges); +}; + +/** + * Update existing edges, or create them when not yet existing + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._updateEdges = function (ids) { + var edges = this.edges, + edgesData = this.edgesData; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + + var data = edgesData.get(id); + var edge = edges[id]; + if (edge) { + // update edge + edge.disconnect(); + edge.setProperties(data, this.constants); + edge.connect(); + } + else { + // create edge + edge = new Edge(data, this, this.constants); + this.edges[id] = edge; + } + } + + this.moving = true; + this._updateValueRange(edges); +}; + +/** + * Remove existing edges. Non existing ids will be ignored + * @param {Number[] | String[]} ids + * @private + */ +Graph.prototype._removeEdges = function (ids) { + var edges = this.edges; + for (var i = 0, len = ids.length; i < len; i++) { + var id = ids[i]; + var edge = edges[id]; + if (edge) { + edge.disconnect(); + delete edges[id]; + } + } + + this.moving = true; + this._updateValueRange(edges); +}; + +/** + * Reconnect all edges + * @private + */ +Graph.prototype._reconnectEdges = function() { + var id, + nodes = this.nodes, + edges = this.edges; + for (id in nodes) { + if (nodes.hasOwnProperty(id)) { + nodes[id].edges = []; + } + } + + for (id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + edge.from = null; + edge.to = null; + edge.connect(); + } + } +}; + +/** + * Update the values of all object in the given array according to the current + * value range of the objects in the array. + * @param {Object} obj An object containing a set of Edges or Nodes + * The objects must have a method getValue() and + * setValueRange(min, max). + * @private + */ +Graph.prototype._updateValueRange = function(obj) { + var id; + + // determine the range of the objects + var valueMin = undefined; + var valueMax = undefined; + for (id in obj) { + if (obj.hasOwnProperty(id)) { + var value = obj[id].getValue(); + if (value !== undefined) { + valueMin = (valueMin === undefined) ? value : Math.min(value, valueMin); + valueMax = (valueMax === undefined) ? value : Math.max(value, valueMax); + } + } + } + + // adjust the range of all objects + if (valueMin !== undefined && valueMax !== undefined) { + for (id in obj) { + if (obj.hasOwnProperty(id)) { + obj[id].setValueRange(valueMin, valueMax); + } + } + } +}; + +/** + * Redraw the graph with the current data + * chart will be resized too. + */ +Graph.prototype.redraw = function() { + this.setSize(this.width, this.height); + + this._redraw(); +}; + +/** + * Redraw the graph with the current data + * @private + */ +Graph.prototype._redraw = function() { + var ctx = this.frame.canvas.getContext('2d'); + + // clear the canvas + var w = this.frame.canvas.width; + var h = this.frame.canvas.height; + ctx.clearRect(0, 0, w, h); + + // set scaling and translation + ctx.save(); + ctx.translate(this.translation.x, this.translation.y); + ctx.scale(this.scale, this.scale); + + this._drawEdges(ctx); + this._drawNodes(ctx); + + // restore original scaling and translation + ctx.restore(); +}; + +/** + * Set the translation of the graph + * @param {Number} offsetX Horizontal offset + * @param {Number} offsetY Vertical offset + * @private + */ +Graph.prototype._setTranslation = function(offsetX, offsetY) { + if (this.translation === undefined) { + this.translation = { + x: 0, + y: 0 + }; + } + + if (offsetX !== undefined) { + this.translation.x = offsetX; + } + if (offsetY !== undefined) { + this.translation.y = offsetY; + } +}; + +/** + * Get the translation of the graph + * @return {Object} translation An object with parameters x and y, both a number + * @private + */ +Graph.prototype._getTranslation = function() { + return { + x: this.translation.x, + y: this.translation.y + }; +}; + +/** + * Scale the graph + * @param {Number} scale Scaling factor 1.0 is unscaled + * @private + */ +Graph.prototype._setScale = function(scale) { + this.scale = scale; +}; +/** + * Get the current scale of the graph + * @return {Number} scale Scaling factor 1.0 is unscaled + * @private + */ +Graph.prototype._getScale = function() { + return this.scale; +}; + +/** + * Convert a horizontal point on the HTML canvas to the x-value of the model + * @param {number} x + * @returns {number} + * @private + */ +Graph.prototype._canvasToX = function(x) { + return (x - this.translation.x) / this.scale; +}; + +/** + * Convert an x-value in the model to a horizontal point on the HTML canvas + * @param {number} x + * @returns {number} + * @private + */ +Graph.prototype._xToCanvas = function(x) { + return x * this.scale + this.translation.x; +}; + +/** + * Convert a vertical point on the HTML canvas to the y-value of the model + * @param {number} y + * @returns {number} + * @private + */ +Graph.prototype._canvasToY = function(y) { + return (y - this.translation.y) / this.scale; +}; + +/** + * Convert an y-value in the model to a vertical point on the HTML canvas + * @param {number} y + * @returns {number} + * @private + */ +Graph.prototype._yToCanvas = function(y) { + return y * this.scale + this.translation.y ; +}; + +/** + * Redraw all nodes + * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Graph.prototype._drawNodes = function(ctx) { + // first draw the unselected nodes + var nodes = this.nodes; + var selected = []; + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + if (nodes[id].isSelected()) { + selected.push(id); + } + else { + nodes[id].draw(ctx); + } + } + } + + // draw the selected nodes on top + for (var s = 0, sMax = selected.length; s < sMax; s++) { + nodes[selected[s]].draw(ctx); + } +}; + +/** + * Redraw all edges + * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); + * @param {CanvasRenderingContext2D} ctx + * @private + */ +Graph.prototype._drawEdges = function(ctx) { + var edges = this.edges; + for (var id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + if (edge.connected) { + edges[id].draw(ctx); + } + } + } +}; + +/** + * Find a stable position for all nodes + * @private + */ +Graph.prototype._doStabilize = function() { + var start = new Date(); + + // find stable position + var count = 0; + var vmin = this.constants.minVelocity; + var stable = false; + while (!stable && count < this.constants.maxIterations) { + this._calculateForces(); + this._discreteStepNodes(); + stable = !this._isMoving(vmin); + count++; + } + + var end = new Date(); + + // console.log('Stabilized in ' + (end-start) + ' ms, ' + count + ' iterations' ); // TODO: cleanup +}; + +/** + * Calculate the external forces acting on the nodes + * Forces are caused by: edges, repulsing forces between nodes, gravity + * @private + */ +Graph.prototype._calculateForces = function() { + // create a local edge to the nodes and edges, that is faster + var id, dx, dy, angle, distance, fx, fy, + repulsingForce, springForce, length, edgeLength, + nodes = this.nodes, + edges = this.edges; + + // gravity, add a small constant force to pull the nodes towards the center of + // the graph + // Also, the forces are reset to zero in this loop by using _setForce instead + // of _addForce + var gravity = 0.01, + gx = this.frame.canvas.clientWidth / 2, + gy = this.frame.canvas.clientHeight / 2; + for (id in nodes) { + if (nodes.hasOwnProperty(id)) { + var node = nodes[id]; + dx = gx - node.x; + dy = gy - node.y; + angle = Math.atan2(dy, dx); + fx = Math.cos(angle) * gravity; + fy = Math.sin(angle) * gravity; + + node._setForce(fx, fy); + } + } + + // repulsing forces between nodes + var minimumDistance = this.constants.nodes.distance, + steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance + + for (var id1 in nodes) { + if (nodes.hasOwnProperty(id1)) { + var node1 = nodes[id1]; + for (var id2 in nodes) { + if (nodes.hasOwnProperty(id2)) { + var node2 = nodes[id2]; + // calculate normally distributed force + dx = node2.x - node1.x; + dy = node2.y - node1.y; + distance = Math.sqrt(dx * dx + dy * dy); + angle = Math.atan2(dy, dx); + + // TODO: correct factor for repulsing force + //repulsingForce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force + //repulsingForce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force + repulsingForce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)); // TODO: customize the repulsing force + fx = Math.cos(angle) * repulsingForce; + fy = Math.sin(angle) * repulsingForce; + + node1._addForce(-fx, -fy); + node2._addForce(fx, fy); + } + } + } + } + + /* TODO: re-implement repulsion of edges + for (var n = 0; n < nodes.length; n++) { + for (var l = 0; l < edges.length; l++) { + var lx = edges[l].from.x+(edges[l].to.x - edges[l].from.x)/2, + ly = edges[l].from.y+(edges[l].to.y - edges[l].from.y)/2, + + // calculate normally distributed force + dx = nodes[n].x - lx, + dy = nodes[n].y - ly, + distance = Math.sqrt(dx * dx + dy * dy), + angle = Math.atan2(dy, dx), + + + // TODO: correct factor for repulsing force + //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force + //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force + repulsingforce = 1 / (1 + Math.exp((distance / (minimumDistance / 2) - 1) * steepness)), // TODO: customize the repulsing force + fx = Math.cos(angle) * repulsingforce, + fy = Math.sin(angle) * repulsingforce; + nodes[n]._addForce(fx, fy); + edges[l].from._addForce(-fx/2,-fy/2); + edges[l].to._addForce(-fx/2,-fy/2); + } + } + */ + + // forces caused by the edges, modelled as springs + for (id in edges) { + if (edges.hasOwnProperty(id)) { + var edge = edges[id]; + if (edge.connected) { + dx = (edge.to.x - edge.from.x); + dy = (edge.to.y - edge.from.y); + //edgeLength = (edge.from.width + edge.from.height + edge.to.width + edge.to.height)/2 || edge.length; // TODO: dmin + //edgeLength = (edge.from.width + edge.to.width)/2 || edge.length; // TODO: dmin + //edgeLength = 20 + ((edge.from.width + edge.to.width) || 0) / 2; + edgeLength = edge.length; + length = Math.sqrt(dx * dx + dy * dy); + angle = Math.atan2(dy, dx); + + springForce = edge.stiffness * (edgeLength - length); + + fx = Math.cos(angle) * springForce; + fy = Math.sin(angle) * springForce; + + edge.from._addForce(-fx, -fy); + edge.to._addForce(fx, fy); + } + } + } + + /* TODO: re-implement repulsion of edges + // repulsing forces between edges + var minimumDistance = this.constants.edges.distance, + steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance + for (var l = 0; l < edges.length; l++) { + //Keep distance from other edge centers + for (var l2 = l + 1; l2 < this.edges.length; l2++) { + //var dmin = (nodes[n].width + nodes[n].height + nodes[n2].width + nodes[n2].height) / 1 || minimumDistance, // TODO: dmin + //var dmin = (nodes[n].width + nodes[n2].width)/2 || minimumDistance, // TODO: dmin + //dmin = 40 + ((nodes[n].width/2 + nodes[n2].width/2) || 0), + var lx = edges[l].from.x+(edges[l].to.x - edges[l].from.x)/2, + ly = edges[l].from.y+(edges[l].to.y - edges[l].from.y)/2, + l2x = edges[l2].from.x+(edges[l2].to.x - edges[l2].from.x)/2, + l2y = edges[l2].from.y+(edges[l2].to.y - edges[l2].from.y)/2, + + // calculate normally distributed force + dx = l2x - lx, + dy = l2y - ly, + distance = Math.sqrt(dx * dx + dy * dy), + angle = Math.atan2(dy, dx), + + + // TODO: correct factor for repulsing force + //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force + //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force + repulsingforce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)), // TODO: customize the repulsing force + fx = Math.cos(angle) * repulsingforce, + fy = Math.sin(angle) * repulsingforce; + + edges[l].from._addForce(-fx, -fy); + edges[l].to._addForce(-fx, -fy); + edges[l2].from._addForce(fx, fy); + edges[l2].to._addForce(fx, fy); + } + } + */ +}; + + +/** + * Check if any of the nodes is still moving + * @param {number} vmin the minimum velocity considered as 'moving' + * @return {boolean} true if moving, false if non of the nodes is moving + * @private + */ +Graph.prototype._isMoving = function(vmin) { + // TODO: ismoving does not work well: should check the kinetic energy, not its velocity + var nodes = this.nodes; + for (var id in nodes) { + if (nodes.hasOwnProperty(id) && nodes[id].isMoving(vmin)) { + return true; + } + } + return false; +}; + + +/** + * Perform one discrete step for all nodes + * @private + */ +Graph.prototype._discreteStepNodes = function() { + var interval = this.refreshRate / 1000.0; // in seconds + var nodes = this.nodes; + for (var id in nodes) { + if (nodes.hasOwnProperty(id)) { + nodes[id].discreteStep(interval); + } + } +}; + +/** + * Start animating nodes and edges + */ +Graph.prototype.start = function() { + if (this.moving) { + this._calculateForces(); + this._discreteStepNodes(); + + var vmin = this.constants.minVelocity; + this.moving = this._isMoving(vmin); + } + + if (this.moving) { + // start animation. only start timer if it is not already running + if (!this.timer) { + var graph = this; + this.timer = window.setTimeout(function () { + graph.timer = undefined; + graph.start(); + graph._redraw(); + }, this.refreshRate); + } + } + else { + this._redraw(); + } +}; + +/** + * Stop animating nodes and edges. + */ +Graph.prototype.stop = function () { + if (this.timer) { + window.clearInterval(this.timer); + this.timer = undefined; + } +}; + +/** + * vis.js module exports + */ +var vis = { + util: util, + events: events, + + Controller: Controller, + DataSet: DataSet, + DataView: DataView, + Range: Range, + Stack: Stack, + TimeStep: TimeStep, + EventBus: EventBus, + + components: { + items: { + Item: Item, + ItemBox: ItemBox, + ItemPoint: ItemPoint, + ItemRange: ItemRange + }, + + Component: Component, + Panel: Panel, + RootPanel: RootPanel, + ItemSet: ItemSet, + TimeAxis: TimeAxis + }, + + graph: { + Node: Node, + Edge: Edge, + Popup: Popup, + Groups: Groups, + Images: Images + }, + + Timeline: Timeline, + Graph: Graph +}; + +/** + * CommonJS module exports + */ +if (typeof exports !== 'undefined') { + exports = vis; +} +if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { + module.exports = vis; +} + +/** + * AMD module exports + */ +if (typeof(define) === 'function') { + define(function () { + return vis; + }); +} + +/** + * Window exports + */ +if (typeof window !== 'undefined') { + // attach the module to the window, load as a regular javascript file + window['vis'] = vis; +} + + +},{"hammerjs":2,"moment":3}],2:[function(require,module,exports){ +/*! Hammer.JS - v1.0.5 - 2013-04-07 + * http://eightmedia.github.com/hammer.js + * + * Copyright (c) 2013 Jorik Tangelder ; + * Licensed under the MIT license */ + +(function(window, undefined) { + 'use strict'; + +/** + * Hammer + * use this to create instances + * @param {HTMLElement} element + * @param {Object} options + * @returns {Hammer.Instance} + * @constructor + */ +var Hammer = function(element, options) { + return new Hammer.Instance(element, options || {}); +}; + +// default settings +Hammer.defaults = { + // add styles and attributes to the element to prevent the browser from doing + // its native behavior. this doesnt prevent the scrolling, but cancels + // the contextmenu, tap highlighting etc + // set to false to disable this + stop_browser_behavior: { + // this also triggers onselectstart=false for IE + userSelect: 'none', + // this makes the element blocking in IE10 >, you could experiment with the value + // see for more options this issue; https://github.com/EightMedia/hammer.js/issues/241 + touchAction: 'none', + touchCallout: 'none', + contentZooming: 'none', + userDrag: 'none', + tapHighlightColor: 'rgba(0,0,0,0)' + } + + // more settings are defined per gesture at gestures.js +}; + +// detect touchevents +Hammer.HAS_POINTEREVENTS = navigator.pointerEnabled || navigator.msPointerEnabled; +Hammer.HAS_TOUCHEVENTS = ('ontouchstart' in window); + +// dont use mouseevents on mobile devices +Hammer.MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i; +Hammer.NO_MOUSEEVENTS = Hammer.HAS_TOUCHEVENTS && navigator.userAgent.match(Hammer.MOBILE_REGEX); + +// eventtypes per touchevent (start, move, end) +// are filled by Hammer.event.determineEventTypes on setup +Hammer.EVENT_TYPES = {}; + +// direction defines +Hammer.DIRECTION_DOWN = 'down'; +Hammer.DIRECTION_LEFT = 'left'; +Hammer.DIRECTION_UP = 'up'; +Hammer.DIRECTION_RIGHT = 'right'; + +// pointer type +Hammer.POINTER_MOUSE = 'mouse'; +Hammer.POINTER_TOUCH = 'touch'; +Hammer.POINTER_PEN = 'pen'; + +// touch event defines +Hammer.EVENT_START = 'start'; +Hammer.EVENT_MOVE = 'move'; +Hammer.EVENT_END = 'end'; + +// hammer document where the base events are added at +Hammer.DOCUMENT = document; + +// plugins namespace +Hammer.plugins = {}; + +// if the window events are set... +Hammer.READY = false; + +/** + * setup events to detect gestures on the document + */ +function setup() { + if(Hammer.READY) { + return; + } + + // find what eventtypes we add listeners to + Hammer.event.determineEventTypes(); + + // Register all gestures inside Hammer.gestures + for(var name in Hammer.gestures) { + if(Hammer.gestures.hasOwnProperty(name)) { + Hammer.detection.register(Hammer.gestures[name]); + } + } + + // Add touch events on the document + Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_MOVE, Hammer.detection.detect); + Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_END, Hammer.detection.detect); + + // Hammer is ready...! + Hammer.READY = true; +} + +/** + * create new hammer instance + * all methods should return the instance itself, so it is chainable. + * @param {HTMLElement} element + * @param {Object} [options={}] + * @returns {Hammer.Instance} + * @constructor + */ +Hammer.Instance = function(element, options) { + var self = this; + + // setup HammerJS window events and register all gestures + // this also sets up the default options + setup(); + + this.element = element; + + // start/stop detection option + this.enabled = true; + + // merge options + this.options = Hammer.utils.extend( + Hammer.utils.extend({}, Hammer.defaults), + options || {}); + + // add some css to the element to prevent the browser from doing its native behavoir + if(this.options.stop_browser_behavior) { + Hammer.utils.stopDefaultBrowserBehavior(this.element, this.options.stop_browser_behavior); + } + + // start detection on touchstart + Hammer.event.onTouch(element, Hammer.EVENT_START, function(ev) { + if(self.enabled) { + Hammer.detection.startDetect(self, ev); + } + }); + + // return instance + return this; +}; + + +Hammer.Instance.prototype = { + /** + * bind events to the instance + * @param {String} gesture + * @param {Function} handler + * @returns {Hammer.Instance} + */ + on: function onEvent(gesture, handler){ + var gestures = gesture.split(' '); + for(var t=0; t 0 && eventType == Hammer.EVENT_END) { + eventType = Hammer.EVENT_MOVE; + } + // no touches, force the end event + else if(!count_touches) { + eventType = Hammer.EVENT_END; + } + + // because touchend has no touches, and we often want to use these in our gestures, + // we send the last move event as our eventData in touchend + if(!count_touches && last_move_event !== null) { + ev = last_move_event; + } + // store the last move event + else { + last_move_event = ev; + } + + // trigger the handler + handler.call(Hammer.detection, self.collectEventData(element, eventType, ev)); + + // remove pointerevent from list + if(Hammer.HAS_POINTEREVENTS && eventType == Hammer.EVENT_END) { + count_touches = Hammer.PointerEvent.updatePointer(eventType, ev); + } + } + + //debug(sourceEventType +" "+ eventType); + + // on the end we reset everything + if(!count_touches) { + last_move_event = null; + enable_detect = false; + touch_triggered = false; + Hammer.PointerEvent.reset(); + } + }); + }, + + + /** + * we have different events for each device/browser + * determine what we need and set them in the Hammer.EVENT_TYPES constant + */ + determineEventTypes: function determineEventTypes() { + // determine the eventtype we want to set + var types; + + // pointerEvents magic + if(Hammer.HAS_POINTEREVENTS) { + types = Hammer.PointerEvent.getEvents(); + } + // on Android, iOS, blackberry, windows mobile we dont want any mouseevents + else if(Hammer.NO_MOUSEEVENTS) { + types = [ + 'touchstart', + 'touchmove', + 'touchend touchcancel']; + } + // for non pointer events browsers and mixed browsers, + // like chrome on windows8 touch laptop + else { + types = [ + 'touchstart mousedown', + 'touchmove mousemove', + 'touchend touchcancel mouseup']; + } + + Hammer.EVENT_TYPES[Hammer.EVENT_START] = types[0]; + Hammer.EVENT_TYPES[Hammer.EVENT_MOVE] = types[1]; + Hammer.EVENT_TYPES[Hammer.EVENT_END] = types[2]; + }, + + + /** + * create touchlist depending on the event + * @param {Object} ev + * @param {String} eventType used by the fakemultitouch plugin + */ + getTouchList: function getTouchList(ev/*, eventType*/) { + // get the fake pointerEvent touchlist + if(Hammer.HAS_POINTEREVENTS) { + return Hammer.PointerEvent.getTouchList(); + } + // get the touchlist + else if(ev.touches) { + return ev.touches; + } + // make fake touchlist from mouse position + else { + return [{ + identifier: 1, + pageX: ev.pageX, + pageY: ev.pageY, + target: ev.target + }]; + } + }, + + + /** + * collect event data for Hammer js + * @param {HTMLElement} element + * @param {String} eventType like Hammer.EVENT_MOVE + * @param {Object} eventData + */ + collectEventData: function collectEventData(element, eventType, ev) { + var touches = this.getTouchList(ev, eventType); + + // find out pointerType + var pointerType = Hammer.POINTER_TOUCH; + if(ev.type.match(/mouse/) || Hammer.PointerEvent.matchType(Hammer.POINTER_MOUSE, ev)) { + pointerType = Hammer.POINTER_MOUSE; + } + + return { + center : Hammer.utils.getCenter(touches), + timeStamp : new Date().getTime(), + target : ev.target, + touches : touches, + eventType : eventType, + pointerType : pointerType, + srcEvent : ev, + + /** + * prevent the browser default actions + * mostly used to disable scrolling of the browser + */ + preventDefault: function() { + if(this.srcEvent.preventManipulation) { + this.srcEvent.preventManipulation(); + } + + if(this.srcEvent.preventDefault) { + this.srcEvent.preventDefault(); + } + }, + + /** + * stop bubbling the event up to its parents + */ + stopPropagation: function() { + this.srcEvent.stopPropagation(); + }, + + /** + * immediately stop gesture detection + * might be useful after a swipe was detected + * @return {*} + */ + stopDetect: function() { + return Hammer.detection.stopDetect(); + } + }; + } +}; + +Hammer.PointerEvent = { + /** + * holds all pointers + * @type {Object} + */ + pointers: {}, + + /** + * get a list of pointers + * @returns {Array} touchlist + */ + getTouchList: function() { + var self = this; + var touchlist = []; + + // we can use forEach since pointerEvents only is in IE10 + Object.keys(self.pointers).sort().forEach(function(id) { + touchlist.push(self.pointers[id]); + }); + return touchlist; + }, + + /** + * update the position of a pointer + * @param {String} type Hammer.EVENT_END + * @param {Object} pointerEvent + */ + updatePointer: function(type, pointerEvent) { + if(type == Hammer.EVENT_END) { + this.pointers = {}; + } + else { + pointerEvent.identifier = pointerEvent.pointerId; + this.pointers[pointerEvent.pointerId] = pointerEvent; + } + + return Object.keys(this.pointers).length; + }, + + /** + * check if ev matches pointertype + * @param {String} pointerType Hammer.POINTER_MOUSE + * @param {PointerEvent} ev + */ + matchType: function(pointerType, ev) { + if(!ev.pointerType) { + return false; + } + + var types = {}; + types[Hammer.POINTER_MOUSE] = (ev.pointerType == ev.MSPOINTER_TYPE_MOUSE || ev.pointerType == Hammer.POINTER_MOUSE); + types[Hammer.POINTER_TOUCH] = (ev.pointerType == ev.MSPOINTER_TYPE_TOUCH || ev.pointerType == Hammer.POINTER_TOUCH); + types[Hammer.POINTER_PEN] = (ev.pointerType == ev.MSPOINTER_TYPE_PEN || ev.pointerType == Hammer.POINTER_PEN); + return types[pointerType]; + }, + + + /** + * get events + */ + getEvents: function() { + return [ + 'pointerdown MSPointerDown', + 'pointermove MSPointerMove', + 'pointerup pointercancel MSPointerUp MSPointerCancel' + ]; + }, + + /** + * reset the list + */ + reset: function() { + this.pointers = {}; + } +}; + + +Hammer.utils = { + /** + * extend method, + * also used for cloning when dest is an empty object + * @param {Object} dest + * @param {Object} src + * @parm {Boolean} merge do a merge + * @returns {Object} dest + */ + extend: function extend(dest, src, merge) { + for (var key in src) { + if(dest[key] !== undefined && merge) { + continue; + } + dest[key] = src[key]; + } + return dest; + }, + + + /** + * find if a node is in the given parent + * used for event delegation tricks + * @param {HTMLElement} node + * @param {HTMLElement} parent + * @returns {boolean} has_parent + */ + hasParent: function(node, parent) { + while(node){ + if(node == parent) { + return true; + } + node = node.parentNode; + } + return false; + }, + + + /** + * get the center of all the touches + * @param {Array} touches + * @returns {Object} center + */ + getCenter: function getCenter(touches) { + var valuesX = [], valuesY = []; + + for(var t= 0,len=touches.length; t= y) { + return touch1.pageX - touch2.pageX > 0 ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT; + } + else { + return touch1.pageY - touch2.pageY > 0 ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN; + } + }, + + + /** + * calculate the distance between two touches + * @param {Touch} touch1 + * @param {Touch} touch2 + * @returns {Number} distance + */ + getDistance: function getDistance(touch1, touch2) { + var x = touch2.pageX - touch1.pageX, + y = touch2.pageY - touch1.pageY; + return Math.sqrt((x*x) + (y*y)); + }, + + + /** + * calculate the scale factor between two touchLists (fingers) + * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out + * @param {Array} start + * @param {Array} end + * @returns {Number} scale + */ + getScale: function getScale(start, end) { + // need two fingers... + if(start.length >= 2 && end.length >= 2) { + return this.getDistance(end[0], end[1]) / + this.getDistance(start[0], start[1]); + } + return 1; + }, + + + /** + * calculate the rotation degrees between two touchLists (fingers) + * @param {Array} start + * @param {Array} end + * @returns {Number} rotation + */ + getRotation: function getRotation(start, end) { + // need two fingers + if(start.length >= 2 && end.length >= 2) { + return this.getAngle(end[1], end[0]) - + this.getAngle(start[1], start[0]); + } + return 0; + }, + + + /** + * boolean if the direction is vertical + * @param {String} direction + * @returns {Boolean} is_vertical + */ + isVertical: function isVertical(direction) { + return (direction == Hammer.DIRECTION_UP || direction == Hammer.DIRECTION_DOWN); + }, + + + /** + * stop browser default behavior with css props + * @param {HtmlElement} element + * @param {Object} css_props + */ + stopDefaultBrowserBehavior: function stopDefaultBrowserBehavior(element, css_props) { + var prop, + vendors = ['webkit','khtml','moz','ms','o','']; + + if(!css_props || !element.style) { + return; + } + + // with css properties for modern browsers + for(var i = 0; i < vendors.length; i++) { + for(var p in css_props) { + if(css_props.hasOwnProperty(p)) { + prop = p; + + // vender prefix at the property + if(vendors[i]) { + prop = vendors[i] + prop.substring(0, 1).toUpperCase() + prop.substring(1); + } + + // set the style + element.style[prop] = css_props[p]; + } + } + } + + // also the disable onselectstart + if(css_props.userSelect == 'none') { + element.onselectstart = function() { + return false; + }; + } + } +}; + +Hammer.detection = { + // contains all registred Hammer.gestures in the correct order + gestures: [], + + // data of the current Hammer.gesture detection session + current: null, + + // the previous Hammer.gesture session data + // is a full clone of the previous gesture.current object + previous: null, + + // when this becomes true, no gestures are fired + stopped: false, + + + /** + * start Hammer.gesture detection + * @param {Hammer.Instance} inst + * @param {Object} eventData + */ + startDetect: function startDetect(inst, eventData) { + // already busy with a Hammer.gesture detection on an element + if(this.current) { + return; + } + + this.stopped = false; + + this.current = { + inst : inst, // reference to HammerInstance we're working for + startEvent : Hammer.utils.extend({}, eventData), // start eventData for distances, timing etc + lastEvent : false, // last eventData + name : '' // current gesture we're in/detected, can be 'tap', 'hold' etc + }; + + this.detect(eventData); + }, + + + /** + * Hammer.gesture detection + * @param {Object} eventData + * @param {Object} eventData + */ + detect: function detect(eventData) { + if(!this.current || this.stopped) { + return; + } + + // extend event data with calculations about scale, distance etc + eventData = this.extendEventData(eventData); + + // instance options + var inst_options = this.current.inst.options; + + // call Hammer.gesture handlers + for(var g=0,len=this.gestures.length; g b.index) { + return 1; + } + return 0; + }); + + return this.gestures; + } +}; + + +Hammer.gestures = Hammer.gestures || {}; + +/** + * Custom gestures + * ============================== + * + * Gesture object + * -------------------- + * The object structure of a gesture: + * + * { name: 'mygesture', + * index: 1337, + * defaults: { + * mygesture_option: true + * } + * handler: function(type, ev, inst) { + * // trigger gesture event + * inst.trigger(this.name, ev); + * } + * } + + * @param {String} name + * this should be the name of the gesture, lowercase + * it is also being used to disable/enable the gesture per instance config. + * + * @param {Number} [index=1000] + * the index of the gesture, where it is going to be in the stack of gestures detection + * like when you build an gesture that depends on the drag gesture, it is a good + * idea to place it after the index of the drag gesture. + * + * @param {Object} [defaults={}] + * the default settings of the gesture. these are added to the instance settings, + * and can be overruled per instance. you can also add the name of the gesture, + * but this is also added by default (and set to true). + * + * @param {Function} handler + * this handles the gesture detection of your custom gesture and receives the + * following arguments: + * + * @param {Object} eventData + * event data containing the following properties: + * timeStamp {Number} time the event occurred + * target {HTMLElement} target element + * touches {Array} touches (fingers, pointers, mouse) on the screen + * pointerType {String} kind of pointer that was used. matches Hammer.POINTER_MOUSE|TOUCH + * center {Object} center position of the touches. contains pageX and pageY + * deltaTime {Number} the total time of the touches in the screen + * deltaX {Number} the delta on x axis we haved moved + * deltaY {Number} the delta on y axis we haved moved + * velocityX {Number} the velocity on the x + * velocityY {Number} the velocity on y + * angle {Number} the angle we are moving + * direction {String} the direction we are moving. matches Hammer.DIRECTION_UP|DOWN|LEFT|RIGHT + * distance {Number} the distance we haved moved + * scale {Number} scaling of the touches, needs 2 touches + * rotation {Number} rotation of the touches, needs 2 touches * + * eventType {String} matches Hammer.EVENT_START|MOVE|END + * srcEvent {Object} the source event, like TouchStart or MouseDown * + * startEvent {Object} contains the same properties as above, + * but from the first touch. this is used to calculate + * distances, deltaTime, scaling etc + * + * @param {Hammer.Instance} inst + * the instance we are doing the detection for. you can get the options from + * the inst.options object and trigger the gesture event by calling inst.trigger + * + * + * Handle gestures + * -------------------- + * inside the handler you can get/set Hammer.detection.current. This is the current + * detection session. It has the following properties + * @param {String} name + * contains the name of the gesture we have detected. it has not a real function, + * only to check in other gestures if something is detected. + * like in the drag gesture we set it to 'drag' and in the swipe gesture we can + * check if the current gesture is 'drag' by accessing Hammer.detection.current.name + * + * @readonly + * @param {Hammer.Instance} inst + * the instance we do the detection for + * + * @readonly + * @param {Object} startEvent + * contains the properties of the first gesture detection in this session. + * Used for calculations about timing, distance, etc. + * + * @readonly + * @param {Object} lastEvent + * contains all the properties of the last gesture detect in this session. + * + * after the gesture detection session has been completed (user has released the screen) + * the Hammer.detection.current object is copied into Hammer.detection.previous, + * this is usefull for gestures like doubletap, where you need to know if the + * previous gesture was a tap + * + * options that have been set by the instance can be received by calling inst.options + * + * You can trigger a gesture event by calling inst.trigger("mygesture", event). + * The first param is the name of your gesture, the second the event argument + * + * + * Register gestures + * -------------------- + * When an gesture is added to the Hammer.gestures object, it is auto registered + * at the setup of the first Hammer instance. You can also call Hammer.detection.register + * manually and pass your gesture object as a param + * + */ + +/** + * Hold + * Touch stays at the same place for x time + * @events hold + */ +Hammer.gestures.Hold = { + name: 'hold', + index: 10, + defaults: { + hold_timeout : 500, + hold_threshold : 1 + }, + timer: null, + handler: function holdGesture(ev, inst) { + switch(ev.eventType) { + case Hammer.EVENT_START: + // clear any running timers + clearTimeout(this.timer); + + // set the gesture so we can check in the timeout if it still is + Hammer.detection.current.name = this.name; + + // set timer and if after the timeout it still is hold, + // we trigger the hold event + this.timer = setTimeout(function() { + if(Hammer.detection.current.name == 'hold') { + inst.trigger('hold', ev); + } + }, inst.options.hold_timeout); + break; + + // when you move or end we clear the timer + case Hammer.EVENT_MOVE: + if(ev.distance > inst.options.hold_threshold) { + clearTimeout(this.timer); + } + break; + + case Hammer.EVENT_END: + clearTimeout(this.timer); + break; + } + } +}; + + +/** + * Tap/DoubleTap + * Quick touch at a place or double at the same place + * @events tap, doubletap + */ +Hammer.gestures.Tap = { + name: 'tap', + index: 100, + defaults: { + tap_max_touchtime : 250, + tap_max_distance : 10, + tap_always : true, + doubletap_distance : 20, + doubletap_interval : 300 + }, + handler: function tapGesture(ev, inst) { + if(ev.eventType == Hammer.EVENT_END) { + // previous gesture, for the double tap since these are two different gesture detections + var prev = Hammer.detection.previous, + did_doubletap = false; + + // when the touchtime is higher then the max touch time + // or when the moving distance is too much + if(ev.deltaTime > inst.options.tap_max_touchtime || + ev.distance > inst.options.tap_max_distance) { + return; + } + + // check if double tap + if(prev && prev.name == 'tap' && + (ev.timeStamp - prev.lastEvent.timeStamp) < inst.options.doubletap_interval && + ev.distance < inst.options.doubletap_distance) { + inst.trigger('doubletap', ev); + did_doubletap = true; + } + + // do a single tap + if(!did_doubletap || inst.options.tap_always) { + Hammer.detection.current.name = 'tap'; + inst.trigger(Hammer.detection.current.name, ev); + } + } + } +}; + + +/** + * Swipe + * triggers swipe events when the end velocity is above the threshold + * @events swipe, swipeleft, swiperight, swipeup, swipedown + */ +Hammer.gestures.Swipe = { + name: 'swipe', + index: 40, + defaults: { + // set 0 for unlimited, but this can conflict with transform + swipe_max_touches : 1, + swipe_velocity : 0.7 + }, + handler: function swipeGesture(ev, inst) { + if(ev.eventType == Hammer.EVENT_END) { + // max touches + if(inst.options.swipe_max_touches > 0 && + ev.touches.length > inst.options.swipe_max_touches) { + return; + } + + // when the distance we moved is too small we skip this gesture + // or we can be already in dragging + if(ev.velocityX > inst.options.swipe_velocity || + ev.velocityY > inst.options.swipe_velocity) { + // trigger swipe events + inst.trigger(this.name, ev); + inst.trigger(this.name + ev.direction, ev); + } + } + } +}; + + +/** + * Drag + * Move with x fingers (default 1) around on the page. Blocking the scrolling when + * moving left and right is a good practice. When all the drag events are blocking + * you disable scrolling on that area. + * @events drag, drapleft, dragright, dragup, dragdown + */ +Hammer.gestures.Drag = { + name: 'drag', + index: 50, + defaults: { + drag_min_distance : 10, + // set 0 for unlimited, but this can conflict with transform + drag_max_touches : 1, + // prevent default browser behavior when dragging occurs + // be careful with it, it makes the element a blocking element + // when you are using the drag gesture, it is a good practice to set this true + drag_block_horizontal : false, + drag_block_vertical : false, + // drag_lock_to_axis keeps the drag gesture on the axis that it started on, + // It disallows vertical directions if the initial direction was horizontal, and vice versa. + drag_lock_to_axis : false, + // drag lock only kicks in when distance > drag_lock_min_distance + // This way, locking occurs only when the distance has become large enough to reliably determine the direction + drag_lock_min_distance : 25 + }, + triggered: false, + handler: function dragGesture(ev, inst) { + // current gesture isnt drag, but dragged is true + // this means an other gesture is busy. now call dragend + if(Hammer.detection.current.name != this.name && this.triggered) { + inst.trigger(this.name +'end', ev); + this.triggered = false; + return; + } + + // max touches + if(inst.options.drag_max_touches > 0 && + ev.touches.length > inst.options.drag_max_touches) { + return; + } + + switch(ev.eventType) { + case Hammer.EVENT_START: + this.triggered = false; + break; + + case Hammer.EVENT_MOVE: + // when the distance we moved is too small we skip this gesture + // or we can be already in dragging + if(ev.distance < inst.options.drag_min_distance && + Hammer.detection.current.name != this.name) { + return; + } + + // we are dragging! + Hammer.detection.current.name = this.name; + + // lock drag to axis? + if(Hammer.detection.current.lastEvent.drag_locked_to_axis || (inst.options.drag_lock_to_axis && inst.options.drag_lock_min_distance<=ev.distance)) { + ev.drag_locked_to_axis = true; + } + var last_direction = Hammer.detection.current.lastEvent.direction; + if(ev.drag_locked_to_axis && last_direction !== ev.direction) { + // keep direction on the axis that the drag gesture started on + if(Hammer.utils.isVertical(last_direction)) { + ev.direction = (ev.deltaY < 0) ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN; + } + else { + ev.direction = (ev.deltaX < 0) ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT; + } + } + + // first time, trigger dragstart event + if(!this.triggered) { + inst.trigger(this.name +'start', ev); + this.triggered = true; + } + + // trigger normal event + inst.trigger(this.name, ev); + + // direction event, like dragdown + inst.trigger(this.name + ev.direction, ev); + + // block the browser events + if( (inst.options.drag_block_vertical && Hammer.utils.isVertical(ev.direction)) || + (inst.options.drag_block_horizontal && !Hammer.utils.isVertical(ev.direction))) { + ev.preventDefault(); + } + break; + + case Hammer.EVENT_END: + // trigger dragend + if(this.triggered) { + inst.trigger(this.name +'end', ev); + } + + this.triggered = false; + break; + } + } +}; + + +/** + * Transform + * User want to scale or rotate with 2 fingers + * @events transform, pinch, pinchin, pinchout, rotate + */ +Hammer.gestures.Transform = { + name: 'transform', + index: 45, + defaults: { + // factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1 + transform_min_scale : 0.01, + // rotation in degrees + transform_min_rotation : 1, + // prevent default browser behavior when two touches are on the screen + // but it makes the element a blocking element + // when you are using the transform gesture, it is a good practice to set this true + transform_always_block : false + }, + triggered: false, + handler: function transformGesture(ev, inst) { + // current gesture isnt drag, but dragged is true + // this means an other gesture is busy. now call dragend + if(Hammer.detection.current.name != this.name && this.triggered) { + inst.trigger(this.name +'end', ev); + this.triggered = false; + return; + } + + // atleast multitouch + if(ev.touches.length < 2) { + return; + } + + // prevent default when two fingers are on the screen + if(inst.options.transform_always_block) { + ev.preventDefault(); + } + + switch(ev.eventType) { + case Hammer.EVENT_START: + this.triggered = false; + break; + + case Hammer.EVENT_MOVE: + var scale_threshold = Math.abs(1-ev.scale); + var rotation_threshold = Math.abs(ev.rotation); + + // when the distance we moved is too small we skip this gesture + // or we can be already in dragging + if(scale_threshold < inst.options.transform_min_scale && + rotation_threshold < inst.options.transform_min_rotation) { + return; + } + + // we are transforming! + Hammer.detection.current.name = this.name; + + // first time, trigger dragstart event + if(!this.triggered) { + inst.trigger(this.name +'start', ev); + this.triggered = true; + } + + inst.trigger(this.name, ev); // basic transform event + + // trigger rotate event + if(rotation_threshold > inst.options.transform_min_rotation) { + inst.trigger('rotate', ev); + } + + // trigger pinch event + if(scale_threshold > inst.options.transform_min_scale) { + inst.trigger('pinch', ev); + inst.trigger('pinch'+ ((ev.scale < 1) ? 'in' : 'out'), ev); + } + break; + + case Hammer.EVENT_END: + // trigger dragend + if(this.triggered) { + inst.trigger(this.name +'end', ev); + } + + this.triggered = false; + break; + } + } +}; + + +/** + * Touch + * Called as first, tells the user has touched the screen + * @events touch + */ +Hammer.gestures.Touch = { + name: 'touch', + index: -Infinity, + defaults: { + // call preventDefault at touchstart, and makes the element blocking by + // disabling the scrolling of the page, but it improves gestures like + // transforming and dragging. + // be careful with using this, it can be very annoying for users to be stuck + // on the page + prevent_default: false, + + // disable mouse events, so only touch (or pen!) input triggers events + prevent_mouseevents: false + }, + handler: function touchGesture(ev, inst) { + if(inst.options.prevent_mouseevents && ev.pointerType == Hammer.POINTER_MOUSE) { + ev.stopDetect(); + return; + } + + if(inst.options.prevent_default) { + ev.preventDefault(); + } + + if(ev.eventType == Hammer.EVENT_START) { + inst.trigger(this.name, ev); + } + } +}; + + +/** + * Release + * Called as last, tells the user has released the screen + * @events release + */ +Hammer.gestures.Release = { + name: 'release', + index: Infinity, + handler: function releaseGesture(ev, inst) { + if(ev.eventType == Hammer.EVENT_END) { + inst.trigger(this.name, ev); + } + } +}; + +// node export +if(typeof module === 'object' && typeof module.exports === 'object'){ + module.exports = Hammer; +} +// just window export +else { + window.Hammer = Hammer; + + // requireJS module definition + if(typeof window.define === 'function' && window.define.amd) { + window.define('hammer', [], function() { + return Hammer; + }); + } +} +})(this); +},{}],3:[function(require,module,exports){ +//! moment.js +//! version : 2.5.0 +//! authors : Tim Wood, Iskren Chernev, Moment.js contributors +//! license : MIT +//! momentjs.com + +(function (undefined) { + + /************************************ + Constants + ************************************/ + + var moment, + VERSION = "2.5.0", + global = this, + round = Math.round, + i, + + YEAR = 0, + MONTH = 1, + DATE = 2, + HOUR = 3, + MINUTE = 4, + SECOND = 5, + MILLISECOND = 6, + + // internal storage for language config files + languages = {}, + + // check for nodeJS + hasModule = (typeof module !== 'undefined' && module.exports && typeof require !== 'undefined'), + + // ASP.NET json date format regex + aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, + aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/, + + // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html + // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere + isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/, + + // format tokens + formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g, + localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g, + + // parsing token regexes + parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 + parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 + parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999 + parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 + parseTokenDigits = /\d+/, // nonzero number of digits + parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic. + parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z + parseTokenT = /T/i, // T (ISO separator) + parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 + + //strict parsing regexes + parseTokenOneDigit = /\d/, // 0 - 9 + parseTokenTwoDigits = /\d\d/, // 00 - 99 + parseTokenThreeDigits = /\d{3}/, // 000 - 999 + parseTokenFourDigits = /\d{4}/, // 0000 - 9999 + parseTokenSixDigits = /[+\-]?\d{6}/, // -999,999 - 999,999 + + // iso 8601 regex + // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) + isoRegex = /^\s*\d{4}-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/, + + isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', + + isoDates = [ + 'YYYY-MM-DD', + 'GGGG-[W]WW', + 'GGGG-[W]WW-E', + 'YYYY-DDD' + ], + + // iso time formats and regexes + isoTimes = [ + ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d{1,3}/], + ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], + ['HH:mm', /(T| )\d\d:\d\d/], + ['HH', /(T| )\d\d/] + ], + + // timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"] + parseTimezoneChunker = /([\+\-]|\d\d)/gi, + + // getter and setter names + proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), + unitMillisecondFactors = { + 'Milliseconds' : 1, + 'Seconds' : 1e3, + 'Minutes' : 6e4, + 'Hours' : 36e5, + 'Days' : 864e5, + 'Months' : 2592e6, + 'Years' : 31536e6 + }, + + unitAliases = { + ms : 'millisecond', + s : 'second', + m : 'minute', + h : 'hour', + d : 'day', + D : 'date', + w : 'week', + W : 'isoWeek', + M : 'month', + y : 'year', + DDD : 'dayOfYear', + e : 'weekday', + E : 'isoWeekday', + gg: 'weekYear', + GG: 'isoWeekYear' + }, + + camelFunctions = { + dayofyear : 'dayOfYear', + isoweekday : 'isoWeekday', + isoweek : 'isoWeek', + weekyear : 'weekYear', + isoweekyear : 'isoWeekYear' + }, + + // format function strings + formatFunctions = {}, + + // tokens to ordinalize and pad + ordinalizeTokens = 'DDD w W M D d'.split(' '), + paddedTokens = 'M D H h m s w W'.split(' '), + + formatTokenFunctions = { + M : function () { + return this.month() + 1; + }, + MMM : function (format) { + return this.lang().monthsShort(this, format); + }, + MMMM : function (format) { + return this.lang().months(this, format); + }, + D : function () { + return this.date(); + }, + DDD : function () { + return this.dayOfYear(); + }, + d : function () { + return this.day(); + }, + dd : function (format) { + return this.lang().weekdaysMin(this, format); + }, + ddd : function (format) { + return this.lang().weekdaysShort(this, format); + }, + dddd : function (format) { + return this.lang().weekdays(this, format); + }, + w : function () { + return this.week(); + }, + W : function () { + return this.isoWeek(); + }, + YY : function () { + return leftZeroFill(this.year() % 100, 2); + }, + YYYY : function () { + return leftZeroFill(this.year(), 4); + }, + YYYYY : function () { + return leftZeroFill(this.year(), 5); + }, + YYYYYY : function () { + var y = this.year(), sign = y >= 0 ? '+' : '-'; + return sign + leftZeroFill(Math.abs(y), 6); + }, + gg : function () { + return leftZeroFill(this.weekYear() % 100, 2); + }, + gggg : function () { + return this.weekYear(); + }, + ggggg : function () { + return leftZeroFill(this.weekYear(), 5); + }, + GG : function () { + return leftZeroFill(this.isoWeekYear() % 100, 2); + }, + GGGG : function () { + return this.isoWeekYear(); + }, + GGGGG : function () { + return leftZeroFill(this.isoWeekYear(), 5); + }, + e : function () { + return this.weekday(); + }, + E : function () { + return this.isoWeekday(); + }, + a : function () { + return this.lang().meridiem(this.hours(), this.minutes(), true); + }, + A : function () { + return this.lang().meridiem(this.hours(), this.minutes(), false); + }, + H : function () { + return this.hours(); + }, + h : function () { + return this.hours() % 12 || 12; + }, + m : function () { + return this.minutes(); + }, + s : function () { + return this.seconds(); + }, + S : function () { + return toInt(this.milliseconds() / 100); + }, + SS : function () { + return leftZeroFill(toInt(this.milliseconds() / 10), 2); + }, + SSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + SSSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + Z : function () { + var a = -this.zone(), + b = "+"; + if (a < 0) { + a = -a; + b = "-"; + } + return b + leftZeroFill(toInt(a / 60), 2) + ":" + leftZeroFill(toInt(a) % 60, 2); + }, + ZZ : function () { + var a = -this.zone(), + b = "+"; + if (a < 0) { + a = -a; + b = "-"; + } + return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2); + }, + z : function () { + return this.zoneAbbr(); + }, + zz : function () { + return this.zoneName(); + }, + X : function () { + return this.unix(); + }, + Q : function () { + return this.quarter(); + } + }, + + lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin']; + + function padToken(func, count) { + return function (a) { + return leftZeroFill(func.call(this, a), count); + }; + } + function ordinalizeToken(func, period) { + return function (a) { + return this.lang().ordinal(func.call(this, a), period); + }; + } + + while (ordinalizeTokens.length) { + i = ordinalizeTokens.pop(); + formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i); + } + while (paddedTokens.length) { + i = paddedTokens.pop(); + formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); + } + formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); + + + /************************************ + Constructors + ************************************/ + + function Language() { + + } + + // Moment prototype object + function Moment(config) { + checkOverflow(config); + extend(this, config); + } + + // Duration Constructor + function Duration(duration) { + var normalizedInput = normalizeObjectUnits(duration), + years = normalizedInput.year || 0, + months = normalizedInput.month || 0, + weeks = normalizedInput.week || 0, + days = normalizedInput.day || 0, + hours = normalizedInput.hour || 0, + minutes = normalizedInput.minute || 0, + seconds = normalizedInput.second || 0, + milliseconds = normalizedInput.millisecond || 0; + + // representation for dateAddRemove + this._milliseconds = +milliseconds + + seconds * 1e3 + // 1000 + minutes * 6e4 + // 1000 * 60 + hours * 36e5; // 1000 * 60 * 60 + // Because of dateAddRemove treats 24 hours as different from a + // day when working around DST, we need to store them separately + this._days = +days + + weeks * 7; + // It is impossible translate months into days without knowing + // which months you are are talking about, so we have to store + // it separately. + this._months = +months + + years * 12; + + this._data = {}; + + this._bubble(); + } + + /************************************ + Helpers + ************************************/ + + + function extend(a, b) { + for (var i in b) { + if (b.hasOwnProperty(i)) { + a[i] = b[i]; + } + } + + if (b.hasOwnProperty("toString")) { + a.toString = b.toString; + } + + if (b.hasOwnProperty("valueOf")) { + a.valueOf = b.valueOf; + } + + return a; + } + + function absRound(number) { + if (number < 0) { + return Math.ceil(number); + } else { + return Math.floor(number); + } + } + + // left zero fill a number + // see http://jsperf.com/left-zero-filling for performance comparison + function leftZeroFill(number, targetLength, forceSign) { + var output = Math.abs(number) + '', + sign = number >= 0; + + while (output.length < targetLength) { + output = '0' + output; + } + return (sign ? (forceSign ? '+' : '') : '-') + output; + } + + // helper function for _.addTime and _.subtractTime + function addOrSubtractDurationFromMoment(mom, duration, isAdding, ignoreUpdateOffset) { + var milliseconds = duration._milliseconds, + days = duration._days, + months = duration._months, + minutes, + hours; + + if (milliseconds) { + mom._d.setTime(+mom._d + milliseconds * isAdding); + } + // store the minutes and hours so we can restore them + if (days || months) { + minutes = mom.minute(); + hours = mom.hour(); + } + if (days) { + mom.date(mom.date() + days * isAdding); + } + if (months) { + mom.month(mom.month() + months * isAdding); + } + if (milliseconds && !ignoreUpdateOffset) { + moment.updateOffset(mom); + } + // restore the minutes and hours after possibly changing dst + if (days || months) { + mom.minute(minutes); + mom.hour(hours); + } + } + + // check if is an array + function isArray(input) { + return Object.prototype.toString.call(input) === '[object Array]'; + } + + function isDate(input) { + return Object.prototype.toString.call(input) === '[object Date]' || + input instanceof Date; + } + + // compare two arrays, return the number of differences + function compareArrays(array1, array2, dontConvert) { + var len = Math.min(array1.length, array2.length), + lengthDiff = Math.abs(array1.length - array2.length), + diffs = 0, + i; + for (i = 0; i < len; i++) { + if ((dontConvert && array1[i] !== array2[i]) || + (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { + diffs++; + } + } + return diffs + lengthDiff; + } + + function normalizeUnits(units) { + if (units) { + var lowered = units.toLowerCase().replace(/(.)s$/, '$1'); + units = unitAliases[units] || camelFunctions[lowered] || lowered; + } + return units; + } + + function normalizeObjectUnits(inputObject) { + var normalizedInput = {}, + normalizedProp, + prop; + + for (prop in inputObject) { + if (inputObject.hasOwnProperty(prop)) { + normalizedProp = normalizeUnits(prop); + if (normalizedProp) { + normalizedInput[normalizedProp] = inputObject[prop]; + } + } + } + + return normalizedInput; + } + + function makeList(field) { + var count, setter; + + if (field.indexOf('week') === 0) { + count = 7; + setter = 'day'; + } + else if (field.indexOf('month') === 0) { + count = 12; + setter = 'month'; + } + else { + return; + } + + moment[field] = function (format, index) { + var i, getter, + method = moment.fn._lang[field], + results = []; + + if (typeof format === 'number') { + index = format; + format = undefined; + } + + getter = function (i) { + var m = moment().utc().set(setter, i); + return method.call(moment.fn._lang, m, format || ''); + }; + + if (index != null) { + return getter(index); + } + else { + for (i = 0; i < count; i++) { + results.push(getter(i)); + } + return results; + } + }; + } + + function toInt(argumentForCoercion) { + var coercedNumber = +argumentForCoercion, + value = 0; + + if (coercedNumber !== 0 && isFinite(coercedNumber)) { + if (coercedNumber >= 0) { + value = Math.floor(coercedNumber); + } else { + value = Math.ceil(coercedNumber); + } + } + + return value; + } + + function daysInMonth(year, month) { + return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); + } + + function daysInYear(year) { + return isLeapYear(year) ? 366 : 365; + } + + function isLeapYear(year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; + } + + function checkOverflow(m) { + var overflow; + if (m._a && m._pf.overflow === -2) { + overflow = + m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH : + m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE : + m._a[HOUR] < 0 || m._a[HOUR] > 23 ? HOUR : + m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE : + m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND : + m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND : + -1; + + if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { + overflow = DATE; + } + + m._pf.overflow = overflow; + } + } + + function initializeParsingFlags(config) { + config._pf = { + empty : false, + unusedTokens : [], + unusedInput : [], + overflow : -2, + charsLeftOver : 0, + nullInput : false, + invalidMonth : null, + invalidFormat : false, + userInvalidated : false, + iso: false + }; + } + + function isValid(m) { + if (m._isValid == null) { + m._isValid = !isNaN(m._d.getTime()) && + m._pf.overflow < 0 && + !m._pf.empty && + !m._pf.invalidMonth && + !m._pf.nullInput && + !m._pf.invalidFormat && + !m._pf.userInvalidated; + + if (m._strict) { + m._isValid = m._isValid && + m._pf.charsLeftOver === 0 && + m._pf.unusedTokens.length === 0; + } + } + return m._isValid; + } + + function normalizeLanguage(key) { + return key ? key.toLowerCase().replace('_', '-') : key; + } + + // Return a moment from input, that is local/utc/zone equivalent to model. + function makeAs(input, model) { + return model._isUTC ? moment(input).zone(model._offset || 0) : + moment(input).local(); + } + + /************************************ + Languages + ************************************/ + + + extend(Language.prototype, { + + set : function (config) { + var prop, i; + for (i in config) { + prop = config[i]; + if (typeof prop === 'function') { + this[i] = prop; + } else { + this['_' + i] = prop; + } + } + }, + + _months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), + months : function (m) { + return this._months[m.month()]; + }, + + _monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"), + monthsShort : function (m) { + return this._monthsShort[m.month()]; + }, + + monthsParse : function (monthName) { + var i, mom, regex; + + if (!this._monthsParse) { + this._monthsParse = []; + } + + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + if (!this._monthsParse[i]) { + mom = moment.utc([2000, i]); + regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); + this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (this._monthsParse[i].test(monthName)) { + return i; + } + } + }, + + _weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), + weekdays : function (m) { + return this._weekdays[m.day()]; + }, + + _weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"), + weekdaysShort : function (m) { + return this._weekdaysShort[m.day()]; + }, + + _weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"), + weekdaysMin : function (m) { + return this._weekdaysMin[m.day()]; + }, + + weekdaysParse : function (weekdayName) { + var i, mom, regex; + + if (!this._weekdaysParse) { + this._weekdaysParse = []; + } + + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + if (!this._weekdaysParse[i]) { + mom = moment([2000, 1]).day(i); + regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); + this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (this._weekdaysParse[i].test(weekdayName)) { + return i; + } + } + }, + + _longDateFormat : { + LT : "h:mm A", + L : "MM/DD/YYYY", + LL : "MMMM D YYYY", + LLL : "MMMM D YYYY LT", + LLLL : "dddd, MMMM D YYYY LT" + }, + longDateFormat : function (key) { + var output = this._longDateFormat[key]; + if (!output && this._longDateFormat[key.toUpperCase()]) { + output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { + return val.slice(1); + }); + this._longDateFormat[key] = output; + } + return output; + }, + + isPM : function (input) { + // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays + // Using charAt should be more compatible. + return ((input + '').toLowerCase().charAt(0) === 'p'); + }, + + _meridiemParse : /[ap]\.?m?\.?/i, + meridiem : function (hours, minutes, isLower) { + if (hours > 11) { + return isLower ? 'pm' : 'PM'; + } else { + return isLower ? 'am' : 'AM'; + } + }, + + _calendar : { + sameDay : '[Today at] LT', + nextDay : '[Tomorrow at] LT', + nextWeek : 'dddd [at] LT', + lastDay : '[Yesterday at] LT', + lastWeek : '[Last] dddd [at] LT', + sameElse : 'L' + }, + calendar : function (key, mom) { + var output = this._calendar[key]; + return typeof output === 'function' ? output.apply(mom) : output; + }, + + _relativeTime : { + future : "in %s", + past : "%s ago", + s : "a few seconds", + m : "a minute", + mm : "%d minutes", + h : "an hour", + hh : "%d hours", + d : "a day", + dd : "%d days", + M : "a month", + MM : "%d months", + y : "a year", + yy : "%d years" + }, + relativeTime : function (number, withoutSuffix, string, isFuture) { + var output = this._relativeTime[string]; + return (typeof output === 'function') ? + output(number, withoutSuffix, string, isFuture) : + output.replace(/%d/i, number); + }, + pastFuture : function (diff, output) { + var format = this._relativeTime[diff > 0 ? 'future' : 'past']; + return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); + }, + + ordinal : function (number) { + return this._ordinal.replace("%d", number); + }, + _ordinal : "%d", + + preparse : function (string) { + return string; + }, + + postformat : function (string) { + return string; + }, + + week : function (mom) { + return weekOfYear(mom, this._week.dow, this._week.doy).week; + }, + + _week : { + dow : 0, // Sunday is the first day of the week. + doy : 6 // The week that contains Jan 1st is the first week of the year. + }, + + _invalidDate: 'Invalid date', + invalidDate: function () { + return this._invalidDate; + } + }); + + // Loads a language definition into the `languages` cache. The function + // takes a key and optionally values. If not in the browser and no values + // are provided, it will load the language file module. As a convenience, + // this function also returns the language values. + function loadLang(key, values) { + values.abbr = key; + if (!languages[key]) { + languages[key] = new Language(); + } + languages[key].set(values); + return languages[key]; + } + + // Remove a language from the `languages` cache. Mostly useful in tests. + function unloadLang(key) { + delete languages[key]; + } + + // Determines which language definition to use and returns it. + // + // With no parameters, it will return the global language. If you + // pass in a language key, such as 'en', it will return the + // definition for 'en', so long as 'en' has already been loaded using + // moment.lang. + function getLangDefinition(key) { + var i = 0, j, lang, next, split, + get = function (k) { + if (!languages[k] && hasModule) { + try { + require('./lang/' + k); + } catch (e) { } + } + return languages[k]; + }; + + if (!key) { + return moment.fn._lang; + } + + if (!isArray(key)) { + //short-circuit everything else + lang = get(key); + if (lang) { + return lang; + } + key = [key]; + } + + //pick the language from the array + //try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each + //substring from most specific to least, but move to the next array item if it's a more specific variant than the current root + while (i < key.length) { + split = normalizeLanguage(key[i]).split('-'); + j = split.length; + next = normalizeLanguage(key[i + 1]); + next = next ? next.split('-') : null; + while (j > 0) { + lang = get(split.slice(0, j).join('-')); + if (lang) { + return lang; + } + if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) { + //the next array item is better than a shallower substring of this one + break; + } + j--; + } + i++; + } + return moment.fn._lang; + } + + /************************************ + Formatting + ************************************/ + + + function removeFormattingTokens(input) { + if (input.match(/\[[\s\S]/)) { + return input.replace(/^\[|\]$/g, ""); + } + return input.replace(/\\/g, ""); + } + + function makeFormatFunction(format) { + var array = format.match(formattingTokens), i, length; + + for (i = 0, length = array.length; i < length; i++) { + if (formatTokenFunctions[array[i]]) { + array[i] = formatTokenFunctions[array[i]]; + } else { + array[i] = removeFormattingTokens(array[i]); + } + } + + return function (mom) { + var output = ""; + for (i = 0; i < length; i++) { + output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; + } + return output; + }; + } + + // format date using native date object + function formatMoment(m, format) { + + if (!m.isValid()) { + return m.lang().invalidDate(); + } + + format = expandFormat(format, m.lang()); + + if (!formatFunctions[format]) { + formatFunctions[format] = makeFormatFunction(format); + } + + return formatFunctions[format](m); + } + + function expandFormat(format, lang) { + var i = 5; + + function replaceLongDateFormatTokens(input) { + return lang.longDateFormat(input) || input; + } + + localFormattingTokens.lastIndex = 0; + while (i >= 0 && localFormattingTokens.test(format)) { + format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); + localFormattingTokens.lastIndex = 0; + i -= 1; + } + + return format; + } + + + /************************************ + Parsing + ************************************/ + + + // get the regex to find the next token + function getParseRegexForToken(token, config) { + var a, strict = config._strict; + switch (token) { + case 'DDDD': + return parseTokenThreeDigits; + case 'YYYY': + case 'GGGG': + case 'gggg': + return strict ? parseTokenFourDigits : parseTokenOneToFourDigits; + case 'YYYYYY': + case 'YYYYY': + case 'GGGGG': + case 'ggggg': + return strict ? parseTokenSixDigits : parseTokenOneToSixDigits; + case 'S': + if (strict) { return parseTokenOneDigit; } + /* falls through */ + case 'SS': + if (strict) { return parseTokenTwoDigits; } + /* falls through */ + case 'SSS': + case 'DDD': + return strict ? parseTokenThreeDigits : parseTokenOneToThreeDigits; + case 'MMM': + case 'MMMM': + case 'dd': + case 'ddd': + case 'dddd': + return parseTokenWord; + case 'a': + case 'A': + return getLangDefinition(config._l)._meridiemParse; + case 'X': + return parseTokenTimestampMs; + case 'Z': + case 'ZZ': + return parseTokenTimezone; + case 'T': + return parseTokenT; + case 'SSSS': + return parseTokenDigits; + case 'MM': + case 'DD': + case 'YY': + case 'GG': + case 'gg': + case 'HH': + case 'hh': + case 'mm': + case 'ss': + case 'ww': + case 'WW': + return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits; + case 'M': + case 'D': + case 'd': + case 'H': + case 'h': + case 'm': + case 's': + case 'w': + case 'W': + case 'e': + case 'E': + return strict ? parseTokenOneDigit : parseTokenOneOrTwoDigits; + default : + a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), "i")); + return a; + } + } + + function timezoneMinutesFromString(string) { + string = string || ""; + var possibleTzMatches = (string.match(parseTokenTimezone) || []), + tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [], + parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0], + minutes = +(parts[1] * 60) + toInt(parts[2]); + + return parts[0] === '+' ? -minutes : minutes; + } + + // function to convert string input to date + function addTimeToArrayFromToken(token, input, config) { + var a, datePartArray = config._a; + + switch (token) { + // MONTH + case 'M' : // fall through to MM + case 'MM' : + if (input != null) { + datePartArray[MONTH] = toInt(input) - 1; + } + break; + case 'MMM' : // fall through to MMMM + case 'MMMM' : + a = getLangDefinition(config._l).monthsParse(input); + // if we didn't find a month name, mark the date as invalid. + if (a != null) { + datePartArray[MONTH] = a; + } else { + config._pf.invalidMonth = input; + } + break; + // DAY OF MONTH + case 'D' : // fall through to DD + case 'DD' : + if (input != null) { + datePartArray[DATE] = toInt(input); + } + break; + // DAY OF YEAR + case 'DDD' : // fall through to DDDD + case 'DDDD' : + if (input != null) { + config._dayOfYear = toInt(input); + } + + break; + // YEAR + case 'YY' : + datePartArray[YEAR] = toInt(input) + (toInt(input) > 68 ? 1900 : 2000); + break; + case 'YYYY' : + case 'YYYYY' : + case 'YYYYYY' : + datePartArray[YEAR] = toInt(input); + break; + // AM / PM + case 'a' : // fall through to A + case 'A' : + config._isPm = getLangDefinition(config._l).isPM(input); + break; + // 24 HOUR + case 'H' : // fall through to hh + case 'HH' : // fall through to hh + case 'h' : // fall through to hh + case 'hh' : + datePartArray[HOUR] = toInt(input); + break; + // MINUTE + case 'm' : // fall through to mm + case 'mm' : + datePartArray[MINUTE] = toInt(input); + break; + // SECOND + case 's' : // fall through to ss + case 'ss' : + datePartArray[SECOND] = toInt(input); + break; + // MILLISECOND + case 'S' : + case 'SS' : + case 'SSS' : + case 'SSSS' : + datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000); + break; + // UNIX TIMESTAMP WITH MS + case 'X': + config._d = new Date(parseFloat(input) * 1000); + break; + // TIMEZONE + case 'Z' : // fall through to ZZ + case 'ZZ' : + config._useUTC = true; + config._tzm = timezoneMinutesFromString(input); + break; + case 'w': + case 'ww': + case 'W': + case 'WW': + case 'd': + case 'dd': + case 'ddd': + case 'dddd': + case 'e': + case 'E': + token = token.substr(0, 1); + /* falls through */ + case 'gg': + case 'gggg': + case 'GG': + case 'GGGG': + case 'GGGGG': + token = token.substr(0, 2); + if (input) { + config._w = config._w || {}; + config._w[token] = input; + } + break; + } + } + + // convert an array to a date. + // the array should mirror the parameters below + // note: all values past the year are optional and will default to the lowest possible value. + // [year, month, day , hour, minute, second, millisecond] + function dateFromConfig(config) { + var i, date, input = [], currentDate, + yearToUse, fixYear, w, temp, lang, weekday, week; + + if (config._d) { + return; + } + + currentDate = currentDateArray(config); + + //compute day of the year from weeks and weekdays + if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { + fixYear = function (val) { + var int_val = parseInt(val, 10); + return val ? + (val.length < 3 ? (int_val > 68 ? 1900 + int_val : 2000 + int_val) : int_val) : + (config._a[YEAR] == null ? moment().weekYear() : config._a[YEAR]); + }; + + w = config._w; + if (w.GG != null || w.W != null || w.E != null) { + temp = dayOfYearFromWeeks(fixYear(w.GG), w.W || 1, w.E, 4, 1); + } + else { + lang = getLangDefinition(config._l); + weekday = w.d != null ? parseWeekday(w.d, lang) : + (w.e != null ? parseInt(w.e, 10) + lang._week.dow : 0); + + week = parseInt(w.w, 10) || 1; + + //if we're parsing 'd', then the low day numbers may be next week + if (w.d != null && weekday < lang._week.dow) { + week++; + } + + temp = dayOfYearFromWeeks(fixYear(w.gg), week, weekday, lang._week.doy, lang._week.dow); + } + + config._a[YEAR] = temp.year; + config._dayOfYear = temp.dayOfYear; + } + + //if the day of the year is set, figure out what it is + if (config._dayOfYear) { + yearToUse = config._a[YEAR] == null ? currentDate[YEAR] : config._a[YEAR]; + + if (config._dayOfYear > daysInYear(yearToUse)) { + config._pf._overflowDayOfYear = true; + } + + date = makeUTCDate(yearToUse, 0, config._dayOfYear); + config._a[MONTH] = date.getUTCMonth(); + config._a[DATE] = date.getUTCDate(); + } + + // Default to current date. + // * if no year, month, day of month are given, default to today + // * if day of month is given, default month and year + // * if month is given, default only year + // * if year is given, don't default anything + for (i = 0; i < 3 && config._a[i] == null; ++i) { + config._a[i] = input[i] = currentDate[i]; + } + + // Zero out whatever was not defaulted, including time + for (; i < 7; i++) { + config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; + } + + // add the offsets to the time to be parsed so that we can have a clean array for checking isValid + input[HOUR] += toInt((config._tzm || 0) / 60); + input[MINUTE] += toInt((config._tzm || 0) % 60); + + config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input); + } + + function dateFromObject(config) { + var normalizedInput; + + if (config._d) { + return; + } + + normalizedInput = normalizeObjectUnits(config._i); + config._a = [ + normalizedInput.year, + normalizedInput.month, + normalizedInput.day, + normalizedInput.hour, + normalizedInput.minute, + normalizedInput.second, + normalizedInput.millisecond + ]; + + dateFromConfig(config); + } + + function currentDateArray(config) { + var now = new Date(); + if (config._useUTC) { + return [ + now.getUTCFullYear(), + now.getUTCMonth(), + now.getUTCDate() + ]; + } else { + return [now.getFullYear(), now.getMonth(), now.getDate()]; + } + } + + // date from string and format string + function makeDateFromStringAndFormat(config) { + + config._a = []; + config._pf.empty = true; + + // This array is used to make a Date, either with `new Date` or `Date.UTC` + var lang = getLangDefinition(config._l), + string = '' + config._i, + i, parsedInput, tokens, token, skipped, + stringLength = string.length, + totalParsedInputLength = 0; + + tokens = expandFormat(config._f, lang).match(formattingTokens) || []; + + for (i = 0; i < tokens.length; i++) { + token = tokens[i]; + parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; + if (parsedInput) { + skipped = string.substr(0, string.indexOf(parsedInput)); + if (skipped.length > 0) { + config._pf.unusedInput.push(skipped); + } + string = string.slice(string.indexOf(parsedInput) + parsedInput.length); + totalParsedInputLength += parsedInput.length; + } + // don't parse if it's not a known token + if (formatTokenFunctions[token]) { + if (parsedInput) { + config._pf.empty = false; + } + else { + config._pf.unusedTokens.push(token); + } + addTimeToArrayFromToken(token, parsedInput, config); + } + else if (config._strict && !parsedInput) { + config._pf.unusedTokens.push(token); + } + } + + // add remaining unparsed input length to the string + config._pf.charsLeftOver = stringLength - totalParsedInputLength; + if (string.length > 0) { + config._pf.unusedInput.push(string); + } + + // handle am pm + if (config._isPm && config._a[HOUR] < 12) { + config._a[HOUR] += 12; + } + // if is 12 am, change hours to 0 + if (config._isPm === false && config._a[HOUR] === 12) { + config._a[HOUR] = 0; + } + + dateFromConfig(config); + checkOverflow(config); + } + + function unescapeFormat(s) { + return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { + return p1 || p2 || p3 || p4; + }); + } + + // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript + function regexpEscape(s) { + return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } + + // date from string and array of format strings + function makeDateFromStringAndArray(config) { + var tempConfig, + bestMoment, + + scoreToBeat, + i, + currentScore; + + if (config._f.length === 0) { + config._pf.invalidFormat = true; + config._d = new Date(NaN); + return; + } + + for (i = 0; i < config._f.length; i++) { + currentScore = 0; + tempConfig = extend({}, config); + initializeParsingFlags(tempConfig); + tempConfig._f = config._f[i]; + makeDateFromStringAndFormat(tempConfig); + + if (!isValid(tempConfig)) { + continue; + } + + // if there is any input that was not parsed add a penalty for that format + currentScore += tempConfig._pf.charsLeftOver; + + //or tokens + currentScore += tempConfig._pf.unusedTokens.length * 10; + + tempConfig._pf.score = currentScore; + + if (scoreToBeat == null || currentScore < scoreToBeat) { + scoreToBeat = currentScore; + bestMoment = tempConfig; + } + } + + extend(config, bestMoment || tempConfig); + } + + // date from iso format + function makeDateFromString(config) { + var i, + string = config._i, + match = isoRegex.exec(string); + + if (match) { + config._pf.iso = true; + for (i = 4; i > 0; i--) { + if (match[i]) { + // match[5] should be "T" or undefined + config._f = isoDates[i - 1] + (match[6] || " "); + break; + } + } + for (i = 0; i < 4; i++) { + if (isoTimes[i][1].exec(string)) { + config._f += isoTimes[i][0]; + break; + } + } + if (string.match(parseTokenTimezone)) { + config._f += "Z"; + } + makeDateFromStringAndFormat(config); + } + else { + config._d = new Date(string); + } + } + + function makeDateFromInput(config) { + var input = config._i, + matched = aspNetJsonRegex.exec(input); + + if (input === undefined) { + config._d = new Date(); + } else if (matched) { + config._d = new Date(+matched[1]); + } else if (typeof input === 'string') { + makeDateFromString(config); + } else if (isArray(input)) { + config._a = input.slice(0); + dateFromConfig(config); + } else if (isDate(input)) { + config._d = new Date(+input); + } else if (typeof(input) === 'object') { + dateFromObject(config); + } else { + config._d = new Date(input); + } + } + + function makeDate(y, m, d, h, M, s, ms) { + //can't just apply() to create a date: + //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply + var date = new Date(y, m, d, h, M, s, ms); + + //the date constructor doesn't accept years < 1970 + if (y < 1970) { + date.setFullYear(y); + } + return date; + } + + function makeUTCDate(y) { + var date = new Date(Date.UTC.apply(null, arguments)); + if (y < 1970) { + date.setUTCFullYear(y); + } + return date; + } + + function parseWeekday(input, language) { + if (typeof input === 'string') { + if (!isNaN(input)) { + input = parseInt(input, 10); + } + else { + input = language.weekdaysParse(input); + if (typeof input !== 'number') { + return null; + } + } + } + return input; + } + + /************************************ + Relative Time + ************************************/ + + + // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize + function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) { + return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture); + } + + function relativeTime(milliseconds, withoutSuffix, lang) { + var seconds = round(Math.abs(milliseconds) / 1000), + minutes = round(seconds / 60), + hours = round(minutes / 60), + days = round(hours / 24), + years = round(days / 365), + args = seconds < 45 && ['s', seconds] || + minutes === 1 && ['m'] || + minutes < 45 && ['mm', minutes] || + hours === 1 && ['h'] || + hours < 22 && ['hh', hours] || + days === 1 && ['d'] || + days <= 25 && ['dd', days] || + days <= 45 && ['M'] || + days < 345 && ['MM', round(days / 30)] || + years === 1 && ['y'] || ['yy', years]; + args[2] = withoutSuffix; + args[3] = milliseconds > 0; + args[4] = lang; + return substituteTimeAgo.apply({}, args); + } + + + /************************************ + Week of Year + ************************************/ + + + // firstDayOfWeek 0 = sun, 6 = sat + // the day of the week that starts the week + // (usually sunday or monday) + // firstDayOfWeekOfYear 0 = sun, 6 = sat + // the first week is the week that contains the first + // of this day of the week + // (eg. ISO weeks use thursday (4)) + function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { + var end = firstDayOfWeekOfYear - firstDayOfWeek, + daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), + adjustedMoment; + + + if (daysToDayOfWeek > end) { + daysToDayOfWeek -= 7; + } + + if (daysToDayOfWeek < end - 7) { + daysToDayOfWeek += 7; + } + + adjustedMoment = moment(mom).add('d', daysToDayOfWeek); + return { + week: Math.ceil(adjustedMoment.dayOfYear() / 7), + year: adjustedMoment.year() + }; + } + + //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday + function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { + // The only solid way to create an iso date from year is to use + // a string format (Date.UTC handles only years > 1900). Don't ask why + // it doesn't need Z at the end. + var d = new Date(leftZeroFill(year, 6, true) + '-01-01').getUTCDay(), + daysToAdd, dayOfYear; + + weekday = weekday != null ? weekday : firstDayOfWeek; + daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0); + dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; + + return { + year: dayOfYear > 0 ? year : year - 1, + dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear + }; + } + + /************************************ + Top Level Functions + ************************************/ + + function makeMoment(config) { + var input = config._i, + format = config._f; + + if (typeof config._pf === 'undefined') { + initializeParsingFlags(config); + } + + if (input === null) { + return moment.invalid({nullInput: true}); + } + + if (typeof input === 'string') { + config._i = input = getLangDefinition().preparse(input); + } + + if (moment.isMoment(input)) { + config = extend({}, input); + + config._d = new Date(+input._d); + } else if (format) { + if (isArray(format)) { + makeDateFromStringAndArray(config); + } else { + makeDateFromStringAndFormat(config); + } + } else { + makeDateFromInput(config); + } + + return new Moment(config); + } + + moment = function (input, format, lang, strict) { + if (typeof(lang) === "boolean") { + strict = lang; + lang = undefined; + } + return makeMoment({ + _i : input, + _f : format, + _l : lang, + _strict : strict, + _isUTC : false + }); + }; + + // creating with utc + moment.utc = function (input, format, lang, strict) { + var m; + + if (typeof(lang) === "boolean") { + strict = lang; + lang = undefined; + } + m = makeMoment({ + _useUTC : true, + _isUTC : true, + _l : lang, + _i : input, + _f : format, + _strict : strict + }).utc(); + + return m; + }; + + // creating with unix timestamp (in seconds) + moment.unix = function (input) { + return moment(input * 1000); + }; + + // duration + moment.duration = function (input, key) { + var duration = input, + // matching against regexp is expensive, do it on demand + match = null, + sign, + ret, + parseIso; + + if (moment.isDuration(input)) { + duration = { + ms: input._milliseconds, + d: input._days, + M: input._months + }; + } else if (typeof input === 'number') { + duration = {}; + if (key) { + duration[key] = input; + } else { + duration.milliseconds = input; + } + } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) { + sign = (match[1] === "-") ? -1 : 1; + duration = { + y: 0, + d: toInt(match[DATE]) * sign, + h: toInt(match[HOUR]) * sign, + m: toInt(match[MINUTE]) * sign, + s: toInt(match[SECOND]) * sign, + ms: toInt(match[MILLISECOND]) * sign + }; + } else if (!!(match = isoDurationRegex.exec(input))) { + sign = (match[1] === "-") ? -1 : 1; + parseIso = function (inp) { + // We'd normally use ~~inp for this, but unfortunately it also + // converts floats to ints. + // inp may be undefined, so careful calling replace on it. + var res = inp && parseFloat(inp.replace(',', '.')); + // apply sign while we're at it + return (isNaN(res) ? 0 : res) * sign; + }; + duration = { + y: parseIso(match[2]), + M: parseIso(match[3]), + d: parseIso(match[4]), + h: parseIso(match[5]), + m: parseIso(match[6]), + s: parseIso(match[7]), + w: parseIso(match[8]) + }; + } + + ret = new Duration(duration); + + if (moment.isDuration(input) && input.hasOwnProperty('_lang')) { + ret._lang = input._lang; + } + + return ret; + }; + + // version number + moment.version = VERSION; + + // default format + moment.defaultFormat = isoFormat; + + // This function will be called whenever a moment is mutated. + // It is intended to keep the offset in sync with the timezone. + moment.updateOffset = function () {}; + + // This function will load languages and then set the global language. If + // no arguments are passed in, it will simply return the current global + // language key. + moment.lang = function (key, values) { + var r; + if (!key) { + return moment.fn._lang._abbr; + } + if (values) { + loadLang(normalizeLanguage(key), values); + } else if (values === null) { + unloadLang(key); + key = 'en'; + } else if (!languages[key]) { + getLangDefinition(key); + } + r = moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key); + return r._abbr; + }; + + // returns language data + moment.langData = function (key) { + if (key && key._lang && key._lang._abbr) { + key = key._lang._abbr; + } + return getLangDefinition(key); + }; + + // compare moment object + moment.isMoment = function (obj) { + return obj instanceof Moment; + }; + + // for typechecking Duration objects + moment.isDuration = function (obj) { + return obj instanceof Duration; + }; + + for (i = lists.length - 1; i >= 0; --i) { + makeList(lists[i]); + } + + moment.normalizeUnits = function (units) { + return normalizeUnits(units); + }; + + moment.invalid = function (flags) { + var m = moment.utc(NaN); + if (flags != null) { + extend(m._pf, flags); + } + else { + m._pf.userInvalidated = true; + } + + return m; + }; + + moment.parseZone = function (input) { + return moment(input).parseZone(); + }; + + /************************************ + Moment Prototype + ************************************/ + + + extend(moment.fn = Moment.prototype, { + + clone : function () { + return moment(this); + }, + + valueOf : function () { + return +this._d + ((this._offset || 0) * 60000); + }, + + unix : function () { + return Math.floor(+this / 1000); + }, + + 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 m = moment(this).utc(); + if (0 < m.year() && m.year() <= 9999) { + return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } else { + return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } + }, + + toArray : function () { + var m = this; + return [ + m.year(), + m.month(), + m.date(), + m.hours(), + m.minutes(), + m.seconds(), + m.milliseconds() + ]; + }, + + isValid : function () { + return isValid(this); + }, + + isDSTShifted : function () { + + if (this._a) { + return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0; + } + + return false; + }, + + parsingFlags : function () { + return extend({}, this._pf); + }, + + invalidAt: function () { + return this._pf.overflow; + }, + + utc : function () { + return this.zone(0); + }, + + local : function () { + this.zone(0); + this._isUTC = false; + return this; + }, + + format : function (inputString) { + var output = formatMoment(this, inputString || moment.defaultFormat); + return this.lang().postformat(output); + }, + + add : function (input, val) { + var dur; + // switch args to support add('s', 1) and add(1, 's') + if (typeof input === 'string') { + dur = moment.duration(+val, input); + } else { + dur = moment.duration(input, val); + } + addOrSubtractDurationFromMoment(this, dur, 1); + return this; + }, + + subtract : function (input, val) { + var dur; + // switch args to support subtract('s', 1) and subtract(1, 's') + if (typeof input === 'string') { + dur = moment.duration(+val, input); + } else { + dur = moment.duration(input, val); + } + addOrSubtractDurationFromMoment(this, dur, -1); + return this; + }, + + diff : function (input, units, asFloat) { + var that = makeAs(input, this), + zoneDiff = (this.zone() - that.zone()) * 6e4, + diff, output; + + units = normalizeUnits(units); + + if (units === 'year' || units === 'month') { + // average number of days in the months in the given dates + diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2 + // difference in months + output = ((this.year() - that.year()) * 12) + (this.month() - that.month()); + // adjust by taking difference in days, average number of days + // and dst in the given months. + output += ((this - moment(this).startOf('month')) - + (that - moment(that).startOf('month'))) / diff; + // same as above but with zones, to negate all dst + output -= ((this.zone() - moment(this).startOf('month').zone()) - + (that.zone() - moment(that).startOf('month').zone())) * 6e4 / diff; + if (units === 'year') { + output = output / 12; + } + } else { + diff = (this - that); + output = units === 'second' ? diff / 1e3 : // 1000 + units === 'minute' ? diff / 6e4 : // 1000 * 60 + units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 + units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst + units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst + diff; + } + return asFloat ? output : absRound(output); + }, + + from : function (time, withoutSuffix) { + return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix); + }, + + fromNow : function (withoutSuffix) { + return this.from(moment(), withoutSuffix); + }, + + calendar : function () { + // We want to compare the start of today, vs this. + // Getting start-of-today depends on whether we're zone'd or not. + var sod = makeAs(moment(), this).startOf('day'), + diff = this.diff(sod, 'days', true), + format = diff < -6 ? 'sameElse' : + diff < -1 ? 'lastWeek' : + diff < 0 ? 'lastDay' : + diff < 1 ? 'sameDay' : + diff < 2 ? 'nextDay' : + diff < 7 ? 'nextWeek' : 'sameElse'; + return this.format(this.lang().calendar(format, this)); + }, + + isLeapYear : function () { + return isLeapYear(this.year()); + }, + + isDST : function () { + return (this.zone() < this.clone().month(0).zone() || + this.zone() < this.clone().month(5).zone()); + }, + + day : function (input) { + var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); + if (input != null) { + input = parseWeekday(input, this.lang()); + return this.add({ d : input - day }); + } else { + return day; + } + }, + + month : function (input) { + var utc = this._isUTC ? 'UTC' : '', + dayOfMonth; + + if (input != null) { + if (typeof input === 'string') { + input = this.lang().monthsParse(input); + if (typeof input !== 'number') { + return this; + } + } + + dayOfMonth = this.date(); + this.date(1); + this._d['set' + utc + 'Month'](input); + this.date(Math.min(dayOfMonth, this.daysInMonth())); + + moment.updateOffset(this); + return this; + } else { + return this._d['get' + utc + 'Month'](); + } + }, + + startOf: function (units) { + units = normalizeUnits(units); + // the following switch intentionally omits break keywords + // to utilize falling through the cases. + switch (units) { + case 'year': + this.month(0); + /* falls through */ + case 'month': + this.date(1); + /* falls through */ + case 'week': + case 'isoWeek': + case 'day': + this.hours(0); + /* falls through */ + case 'hour': + this.minutes(0); + /* falls through */ + case 'minute': + this.seconds(0); + /* falls through */ + case 'second': + this.milliseconds(0); + /* falls through */ + } + + // weeks are a special case + if (units === 'week') { + this.weekday(0); + } else if (units === 'isoWeek') { + this.isoWeekday(1); + } + + return this; + }, + + endOf: function (units) { + units = normalizeUnits(units); + return this.startOf(units).add((units === 'isoWeek' ? 'week' : units), 1).subtract('ms', 1); + }, + + isAfter: function (input, units) { + units = typeof units !== 'undefined' ? units : 'millisecond'; + return +this.clone().startOf(units) > +moment(input).startOf(units); + }, + + isBefore: function (input, units) { + units = typeof units !== 'undefined' ? units : 'millisecond'; + return +this.clone().startOf(units) < +moment(input).startOf(units); + }, + + isSame: function (input, units) { + units = units || 'ms'; + return +this.clone().startOf(units) === +makeAs(input, this).startOf(units); + }, + + min: function (other) { + other = moment.apply(null, arguments); + return other < this ? this : other; + }, + + max: function (other) { + other = moment.apply(null, arguments); + return other > this ? this : other; + }, + + zone : function (input) { + var offset = this._offset || 0; + if (input != null) { + if (typeof input === "string") { + input = timezoneMinutesFromString(input); + } + if (Math.abs(input) < 16) { + input = input * 60; + } + this._offset = input; + this._isUTC = true; + if (offset !== input) { + addOrSubtractDurationFromMoment(this, moment.duration(offset - input, 'm'), 1, true); + } + } else { + return this._isUTC ? offset : this._d.getTimezoneOffset(); + } + return this; + }, + + zoneAbbr : function () { + return this._isUTC ? "UTC" : ""; + }, + + zoneName : function () { + return this._isUTC ? "Coordinated Universal Time" : ""; + }, + + parseZone : function () { + if (this._tzm) { + this.zone(this._tzm); + } else if (typeof this._i === 'string') { + this.zone(this._i); + } + return this; + }, + + hasAlignedHourOffset : function (input) { + if (!input) { + input = 0; + } + else { + input = moment(input).zone(); + } + + return (this.zone() - input) % 60 === 0; + }, + + daysInMonth : function () { + return daysInMonth(this.year(), this.month()); + }, + + dayOfYear : function (input) { + var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; + return input == null ? dayOfYear : this.add("d", (input - dayOfYear)); + }, + + quarter : function () { + return Math.ceil((this.month() + 1.0) / 3.0); + }, + + weekYear : function (input) { + var year = weekOfYear(this, this.lang()._week.dow, this.lang()._week.doy).year; + return input == null ? year : this.add("y", (input - year)); + }, + + isoWeekYear : function (input) { + var year = weekOfYear(this, 1, 4).year; + return input == null ? year : this.add("y", (input - year)); + }, + + week : function (input) { + var week = this.lang().week(this); + return input == null ? week : this.add("d", (input - week) * 7); + }, + + isoWeek : function (input) { + var week = weekOfYear(this, 1, 4).week; + return input == null ? week : this.add("d", (input - week) * 7); + }, + + weekday : function (input) { + var weekday = (this.day() + 7 - this.lang()._week.dow) % 7; + return input == null ? weekday : this.add("d", input - weekday); + }, + + isoWeekday : function (input) { + // behaves the same as moment#day except + // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) + // as a setter, sunday should belong to the previous week. + return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); + }, + + get : function (units) { + units = normalizeUnits(units); + return this[units](); + }, + + set : function (units, value) { + units = normalizeUnits(units); + if (typeof this[units] === 'function') { + this[units](value); + } + return this; + }, + + // If passed a language key, it will set the language for this + // instance. Otherwise, it will return the language configuration + // variables for this instance. + lang : function (key) { + if (key === undefined) { + return this._lang; + } else { + this._lang = getLangDefinition(key); + return this; + } + } + }); + + // helper for adding shortcuts + function makeGetterAndSetter(name, key) { + moment.fn[name] = moment.fn[name + 's'] = function (input) { + var utc = this._isUTC ? 'UTC' : ''; + if (input != null) { + this._d['set' + utc + key](input); + moment.updateOffset(this); + return this; + } else { + return this._d['get' + utc + key](); + } + }; + } + + // loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds) + for (i = 0; i < proxyGettersAndSetters.length; i ++) { + makeGetterAndSetter(proxyGettersAndSetters[i].toLowerCase().replace(/s$/, ''), proxyGettersAndSetters[i]); + } + + // add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear') + makeGetterAndSetter('year', 'FullYear'); + + // add plural methods + moment.fn.days = moment.fn.day; + moment.fn.months = moment.fn.month; + moment.fn.weeks = moment.fn.week; + moment.fn.isoWeeks = moment.fn.isoWeek; + + // add aliased format methods + moment.fn.toJSON = moment.fn.toISOString; + + /************************************ + Duration Prototype + ************************************/ + + + extend(moment.duration.fn = Duration.prototype, { + + _bubble : function () { + var milliseconds = this._milliseconds, + days = this._days, + months = this._months, + data = this._data, + seconds, minutes, hours, years; + + // The following code bubbles up values, see the tests for + // examples of what that means. + data.milliseconds = milliseconds % 1000; + + seconds = absRound(milliseconds / 1000); + data.seconds = seconds % 60; + + minutes = absRound(seconds / 60); + data.minutes = minutes % 60; + + hours = absRound(minutes / 60); + data.hours = hours % 24; + + days += absRound(hours / 24); + data.days = days % 30; + + months += absRound(days / 30); + data.months = months % 12; + + years = absRound(months / 12); + data.years = years; + }, + + weeks : function () { + return absRound(this.days() / 7); + }, + + valueOf : function () { + return this._milliseconds + + this._days * 864e5 + + (this._months % 12) * 2592e6 + + toInt(this._months / 12) * 31536e6; + }, + + humanize : function (withSuffix) { + var difference = +this, + output = relativeTime(difference, !withSuffix, this.lang()); + + if (withSuffix) { + output = this.lang().pastFuture(difference, output); + } + + return this.lang().postformat(output); + }, + + add : function (input, val) { + // supports only 2.0-style add(1, 's') or add(moment) + var dur = moment.duration(input, val); + + this._milliseconds += dur._milliseconds; + this._days += dur._days; + this._months += dur._months; + + this._bubble(); + + return this; + }, + + subtract : function (input, val) { + var dur = moment.duration(input, val); + + this._milliseconds -= dur._milliseconds; + this._days -= dur._days; + this._months -= dur._months; + + this._bubble(); + + return this; + }, + + get : function (units) { + units = normalizeUnits(units); + return this[units.toLowerCase() + 's'](); + }, + + as : function (units) { + units = normalizeUnits(units); + return this['as' + units.charAt(0).toUpperCase() + units.slice(1) + 's'](); + }, + + lang : moment.fn.lang, + + toIsoString : function () { + // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js + var years = Math.abs(this.years()), + months = Math.abs(this.months()), + days = Math.abs(this.days()), + hours = Math.abs(this.hours()), + minutes = Math.abs(this.minutes()), + seconds = Math.abs(this.seconds() + this.milliseconds() / 1000); + + if (!this.asSeconds()) { + // this is the same as C#'s (Noda) and python (isodate)... + // but not other JS (goog.date) + return 'P0D'; + } + + return (this.asSeconds() < 0 ? '-' : '') + + 'P' + + (years ? years + 'Y' : '') + + (months ? months + 'M' : '') + + (days ? days + 'D' : '') + + ((hours || minutes || seconds) ? 'T' : '') + + (hours ? hours + 'H' : '') + + (minutes ? minutes + 'M' : '') + + (seconds ? seconds + 'S' : ''); + } + }); + + function makeDurationGetter(name) { + moment.duration.fn[name] = function () { + return this._data[name]; + }; + } + + function makeDurationAsGetter(name, factor) { + moment.duration.fn['as' + name] = function () { + return +this / factor; + }; + } + + for (i in unitMillisecondFactors) { + if (unitMillisecondFactors.hasOwnProperty(i)) { + makeDurationAsGetter(i, unitMillisecondFactors[i]); + makeDurationGetter(i.toLowerCase()); + } + } + + makeDurationAsGetter('Weeks', 6048e5); + moment.duration.fn.asMonths = function () { + return (+this - this.years() * 31536e6) / 2592e6 + this.years() * 12; + }; + + + /************************************ + Default Lang + ************************************/ + + + // Set default language, other languages will inherit from English. + moment.lang('en', { + ordinal : function (number) { + var b = number % 10, + output = (toInt(number % 100 / 10) === 1) ? 'th' : + (b === 1) ? 'st' : + (b === 2) ? 'nd' : + (b === 3) ? 'rd' : 'th'; + return number + output; + } + }); + + /* EMBED_LANGUAGES */ + + /************************************ + Exposing Moment + ************************************/ + + function makeGlobal(deprecate) { + var warned = false, local_moment = moment; + /*global ender:false */ + if (typeof ender !== 'undefined') { + return; + } + // here, `this` means `window` in the browser, or `global` on the server + // add `moment` as a global object via a string identifier, + // for Closure Compiler "advanced" mode + if (deprecate) { + global.moment = function () { + if (!warned && console && console.warn) { + warned = true; + console.warn( + "Accessing Moment through the global scope is " + + "deprecated, and will be removed in an upcoming " + + "release."); + } + return local_moment.apply(null, arguments); + }; + extend(global.moment, local_moment); + } else { + global['moment'] = moment; + } + } + + // CommonJS module is defined + if (hasModule) { + module.exports = moment; + makeGlobal(true); + } else if (typeof define === "function" && define.amd) { + define("moment", function (require, exports, module) { + if (module.config && module.config() && module.config().noGlobal !== true) { + // If user provided noGlobal, he is aware of global + makeGlobal(module.config().noGlobal === undefined); + } + + return moment; + }); + } else { + makeGlobal(); + } +}).call(this); + +},{}]},{},[1]) +(1) +}); \ No newline at end of file diff --git a/dist/vis.min.js b/dist/vis.min.js new file mode 100644 index 00000000..8ca53878 --- /dev/null +++ b/dist/vis.min.js @@ -0,0 +1,29 @@ +/** + * vis.js + * https://github.com/almende/vis + * + * A dynamic, browser-based visualization library. + * + * @version 0.3.0 + * @date 2014-01-14 + * + * @license + * Copyright (C) 2011-2013 Almende B.V, http://almende.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * 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 t;return function e(t,i,n){function s(o,a){if(!i[o]){if(!t[o]){var h="function"==typeof require&&require;if(!a&&h)return h(o,!0);if(r)return r(o,!0);throw new Error("Cannot find module '"+o+"'")}var d=i[o]={exports:{}};t[o][0].call(d.exports,function(e){var i=t[o][1][e];return s(i?i:e)},d,d.exports,e,t,i,n)}return i[o].exports}for(var r="function"==typeof require&&require,o=0;oi;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,n,s;if(null==this)throw new TypeError(" this is null or not defined");var r=Object(this),o=r.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),n=new Array(o),s=0;o>s;){var a,h;s in r&&(a=r[s],h=t.call(i,a,s,r),n[s]=h),s++}return n}),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 n=[],s=arguments[1],r=0;i>r;r++)if(r in e){var o=e[r];t.call(s,o,r,e)&&n.push(o)}return n}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=i.length;return function(s){if("object"!=typeof s&&"function"!=typeof s||null===s)throw new TypeError("Object.keys called on non-object");var r=[];for(var o in s)t.call(s,o)&&r.push(o);if(e)for(var a=0;n>a;a++)t.call(s,i[a])&&r.push(i[a]);return r}}()),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,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s}),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,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var A={};A.isNumber=function(t){return t instanceof Number||"number"==typeof t},A.isString=function(t){return t instanceof String||"string"==typeof t},A.isDate=function(t){if(t instanceof Date)return!0;if(A.isString(t)){var e=P.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},A.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},A.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},A.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var n=arguments[e];for(var s in n)n.hasOwnProperty(s)&&void 0!==n[s]&&(t[s]=n[s])}return t},A.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(A.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(I.isMoment(t))return new Date(t.valueOf());if(A.isString(t))return i=P.exec(t),i?new Date(Number(i[1])):I(t).toDate();throw new Error("Cannot convert object of type "+A.getType(t)+" to type Date");case"Moment":if(A.isNumber(t))return I(t);if(t instanceof Date)return I(t.valueOf());if(I.isMoment(t))return I(t);if(A.isString(t))return i=P.exec(t),i?I(Number(i[1])):I(t);throw new Error("Cannot convert object of type "+A.getType(t)+" to type Date");case"ISODate":if(A.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(I.isMoment(t))return t.toDate().toISOString();if(A.isString(t))return i=P.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw new Error("Cannot convert object of type "+A.getType(t)+" to type ISODate");case"ASPDate":if(A.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(A.isString(t)){i=P.exec(t);var n;return n=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+n+")/"}throw new Error("Cannot convert object of type "+A.getType(t)+" to type ASPDate");default:throw new Error("Cannot convert object of type "+A.getType(t)+' to type "'+e+'"')}};var P=/^\/?Date\((\-?\d+)/i;A.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},A.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetLeft,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetLeft,n-=s.scrollLeft,s=s.offsetParent;return n},A.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetTop,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetTop,n-=s.scrollTop,s=s.offsetParent;return n},A.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,n=document.body;return e+(i&&i.scrollTop||n&&n.scrollTop||0)-(i&&i.clientTop||n&&n.clientTop||0)},A.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,n=document.body;return e+(i&&i.scrollLeft||n&&n.scrollLeft||0)-(i&&i.clientLeft||n&&n.clientLeft||0)},A.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},A.removeClassName=function(t,e){var i=t.className.split(" "),n=i.indexOf(e);-1!=n&&(i.splice(n,1),t.className=i.join(" "))},A.forEach=function(t,e){var i,n;if(t instanceof Array)for(i=0,n=t.length;n>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},A.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},A.addEventListener=function(t,e,i,n){t.addEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,n)):t.attachEvent("on"+e,i)},A.removeEventListener=function(t,e,i,n){t.removeEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,n)):t.detachEvent("on"+e,i)},A.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},A.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},A.fakeGesture=function(t,e){var i=null;return L.event.collectEventData(this,i,e)},A.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},A.option={},A.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},A.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},A.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?String(t):e||null},A.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),A.isString(t)?t:A.isNumber(t)?t+"px":e||null},A.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null};var Y={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,n=this.listeners.length;n>i;i++){var s=e[i];if(s&&s.object==t)return i}return-1},addListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];s||(s={object:t,events:{}},this.listeners.push(s));var r=s.events[e];r||(r=[],s.events[e]=r),-1==r.indexOf(i)&&r.push(i)},removeListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var r=s.events[e];r&&(n=r.indexOf(i),-1!=n&&r.splice(n,1),0==r.length&&delete s.events[e]);var o=0,a=s.events;for(var h in a)a.hasOwnProperty(h)&&o++;0==o&&delete this.listeners[n]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var r=s.events[e];if(r)for(var o=0,a=r.length;a>o;o++)r[o](i)}}};s.prototype.on=function(t,e,i){var n=t instanceof RegExp?t:new RegExp(t.replace("*","\\w+")),s={id:A.randomUUID(),event:t,regexp:n,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(s),s.id},s.prototype.off=function(t){for(var e=0;er;r++)i=s._addItem(t[r]),n.push(i);else if(A.isDataTable(t))for(var a=this._getColumnNames(t),h=0,d=t.getNumberOfRows();d>h;h++){for(var c={},u=0,l=a.length;l>u;u++){var p=a[u];c[p]=t.getValue(h,u)}i=s._addItem(c),n.push(i)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");i=s._addItem(t),n.push(i)}return n.length&&this._trigger("add",{items:n},e),n},r.prototype.update=function(t,e){var i=[],n=[],s=this,r=s.fieldId,o=function(t){var e=t[r];s.data[e]?(e=s._updateItem(t),n.push(e)):(e=s._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)o(t[a]);else if(A.isDataTable(t))for(var d=this._getColumnNames(t),c=0,u=t.getNumberOfRows();u>c;c++){for(var l={},p=0,f=d.length;f>p;p++){var m=d[p];l[m]=t.getValue(c,p)}o(l)}else{if(!(t instanceof Object))throw new Error("Unknown dataType");o(t)}return i.length&&this._trigger("add",{items:i},e),n.length&&this._trigger("update",{items:n},e),i.concat(n)},r.prototype.get=function(){var t,e,i,n,s=this,r=A.getType(arguments[0]);"String"==r||"Number"==r?(t=arguments[0],i=arguments[1],n=arguments[2]):"Array"==r?(e=arguments[0],i=arguments[1],n=arguments[2]):(i=arguments[0],n=arguments[1]);var o;if(i&&i.type){if(o="DataTable"==i.type?"DataTable":"Array",n&&o!=A.getType(n))throw new Error('Type of parameter "data" ('+A.getType(n)+") does not correspond with specified options.type ("+i.type+")");if("DataTable"==o&&!A.isDataTable(n))throw new Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else o=n?"DataTable"==A.getType(n)?"DataTable":"Array":"Array";var a,h,d,c,u=i&&i.convert||this.options.convert,l=i&&i.filter,p=[];if(void 0!=t)a=s._getItem(t,u),l&&!l(a)&&(a=null);else if(void 0!=e)for(d=0,c=e.length;c>d;d++)a=s._getItem(e[d],u),(!l||l(a))&&p.push(a);else for(h in this.data)this.data.hasOwnProperty(h)&&(a=s._getItem(h,u),(!l||l(a))&&p.push(a));if(i&&i.order&&void 0==t&&this._sort(p,i.order),i&&i.fields){var f=i.fields;if(void 0!=t)a=this._filterFields(a,f);else for(d=0,c=p.length;c>d;d++)p[d]=this._filterFields(p[d],f)}if("DataTable"==o){var m=this._getColumnNames(n);if(void 0!=t)s._appendRow(n,m,a);else for(d=0,c=p.length;c>d;d++)s._appendRow(n,m,p[d]);return n}if(void 0!=t)return a;if(n){for(d=0,c=p.length;c>d;d++)n.push(p[d]);return n}return p},r.prototype.getIds=function(t){var e,i,n,s,r,o=this.data,a=t&&t.filter,h=t&&t.order,d=t&&t.convert||this.options.convert,c=[];if(a)if(h){r=[];for(n in o)o.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&r.push(s));for(this._sort(r,h),e=0,i=r.length;i>e;e++)c[e]=r[e][this.fieldId]}else for(n in o)o.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&c.push(s[this.fieldId]));else if(h){r=[];for(n in o)o.hasOwnProperty(n)&&r.push(o[n]);for(this._sort(r,h),e=0,i=r.length;i>e;e++)c[e]=r[e][this.fieldId]}else for(n in o)o.hasOwnProperty(n)&&(s=o[n],c.push(s[this.fieldId]));return c},r.prototype.forEach=function(t,e){var i,n,s=e&&e.filter,r=e&&e.convert||this.options.convert,o=this.data;if(e&&e.order)for(var a=this.get(e),h=0,d=a.length;d>h;h++)i=a[h],n=i[this.fieldId],t(i,n);else for(n in o)o.hasOwnProperty(n)&&(i=this._getItem(n,r),(!s||s(i))&&t(i,n))},r.prototype.map=function(t,e){var i,n=e&&e.filter,s=e&&e.convert||this.options.convert,r=[],o=this.data;for(var a in o)o.hasOwnProperty(a)&&(i=this._getItem(a,s),(!n||n(i))&&r.push(t(i,a)));return e&&e.order&&this._sort(r,e.order),r},r.prototype._filterFields=function(t,e){var i={};for(var n in t)t.hasOwnProperty(n)&&-1!=e.indexOf(n)&&(i[n]=t[n]);return i},r.prototype._sort=function(t,e){if(A.isString(e)){var i=e;t.sort(function(t,e){var n=t[i],s=e[i];return n>s?1:s>n?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},r.prototype.remove=function(t,e){var i,n,s,r=[];if(t instanceof Array)for(i=0,n=t.length;n>i;i++)s=this._remove(t[i]),null!=s&&r.push(s);else s=this._remove(t),null!=s&&r.push(s);return r.length&&this._trigger("remove",{items:r},e),r},r.prototype._remove=function(t){if(A.isNumber(t)||A.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},r.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},r.prototype.max=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var r=e[s],o=r[t];null!=o&&(!i||o>n)&&(i=r,n=o)}return i},r.prototype.min=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var r=e[s],o=r[t];null!=o&&(!i||n>o)&&(i=r,n=o)}return i},r.prototype.distinct=function(t){var e=this.data,i=[],n=this.options.convert[t],s=0;for(var r in e)if(e.hasOwnProperty(r)){for(var o=e[r],a=A.convert(o[t],n),h=!1,d=0;s>d;d++)if(i[d]==a){h=!0;break}h||(i[s]=a,s++)}return i},r.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=A.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=A.convert(t[n],s)}return this.data[e]=i,e},r.prototype._getItem=function(t,e){var i,n,s=this.data[t];if(!s)return null;var r={},o=this.fieldId,a=this.internalIds;if(e)for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==o&&n in a||(r[i]=A.convert(n,e[i])));else for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==o&&n in a||(r[i]=n));return r},r.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 n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=A.convert(t[n],s)}return e},r.prototype._getColumnNames=function(t){for(var e=[],i=0,n=t.getNumberOfColumns();n>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},r.prototype._appendRow=function(t,e,i){for(var n=t.addRow(),s=0,r=e.length;r>s;s++){var o=e[s];t.setValue(n,s,i[o])}},o.prototype.setData=function(t){var e,i,n;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var s in this.ids)this.ids.hasOwnProperty(s)&&e.push(s);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,n=e.length;n>i;i++)s=e[i],this.ids[s]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},o.prototype.get=function(){var t,e,i,n=this,s=A.getType(arguments[0]);"String"==s||"Number"==s||"Array"==s?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var r=A.extend({},this.options,e);this.options.filter&&e&&e.filter&&(r.filter=function(t){return n.options.filter(t)&&e.filter(t)});var o=[];return void 0!=t&&o.push(t),o.push(r),o.push(i),this.data&&this.data.get.apply(this.data,o)},o.prototype.getIds=function(t){var e;if(this.data){var i,n=this.options.filter;i=t&&t.filter?n?function(e){return n(e)&&t.filter(e)}:t.filter:n,e=this.data.getIds({filter:i,order:t&&t.order})}else e=[];return e},o.prototype._onEvent=function(t,e,i){var n,s,r,o,a=e&&e.items,h=this.data,d=[],c=[],u=[];if(a&&h){switch(t){case"add":for(n=0,s=a.length;s>n;n++)r=a[n],o=this.get(r),o&&(this.ids[r]=!0,d.push(r));break;case"update":for(n=0,s=a.length;s>n;n++)r=a[n],o=this.get(r),o?this.ids[r]?c.push(r):(this.ids[r]=!0,d.push(r)):this.ids[r]&&(delete this.ids[r],u.push(r));break;case"remove":for(n=0,s=a.length;s>n;n++)r=a[n],this.ids[r]&&(delete this.ids[r],u.push(r))}d.length&&this._trigger("add",{items:d},i),c.length&&this._trigger("update",{items:c},i),u.length&&this._trigger("remove",{items:u},i)}},o.prototype.subscribe=r.prototype.subscribe,o.prototype.unsubscribe=r.prototype.unsubscribe,o.prototype._trigger=r.prototype._trigger,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,n=864e5,s=36e5,r=6e4,o=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),n/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),r>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*o>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*o>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*o>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),o>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1)}},TimeStep.prototype.snap=function(t){if(this.scale==TimeStep.SCALE.YEAR){var e=t.getFullYear()+Math.round(t.getMonth()/12);t.setFullYear(Math.round(e/this.step)*this.step),t.setMonth(0),t.setDate(0),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MONTH)t.getDate()>15?(t.setDate(1),t.setMonth(t.getMonth()+1)):t.setDate(1),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0);else if(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){switch(this.step){case 5:case 2:t.setHours(24*Math.round(t.getHours()/24));break;default:t.setHours(12*Math.round(t.getHours()/12))}t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.HOUR){switch(this.step){case 4:t.setMinutes(60*Math.round(t.getMinutes()/60));break;default:t.setMinutes(30*Math.round(t.getMinutes()/30))}t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MINUTE){switch(this.step){case 15:case 10:t.setMinutes(5*Math.round(t.getMinutes()/5)),t.setSeconds(0);break;case 5:t.setSeconds(60*Math.round(t.getSeconds()/60));break;default:t.setSeconds(30*Math.round(t.getSeconds()/30))}t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.SECOND)switch(this.step){case 15:case 10:t.setSeconds(5*Math.round(t.getSeconds()/5)),t.setMilliseconds(0);break;case 5:t.setMilliseconds(1e3*Math.round(t.getMilliseconds()/1e3));break;default:t.setMilliseconds(500*Math.round(t.getMilliseconds()/500))}else if(this.scale==TimeStep.SCALE.MILLISECOND){var i=this.step>5?this.step/2:1;t.setMilliseconds(Math.round(t.getMilliseconds()/i)*i)}},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 I(t).format("SSS");case TimeStep.SCALE.SECOND:return I(t).format("s");case TimeStep.SCALE.MINUTE:return I(t).format("HH:mm");case TimeStep.SCALE.HOUR:return I(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return I(t).format("ddd D");case TimeStep.SCALE.DAY:return I(t).format("D");case TimeStep.SCALE.MONTH:return I(t).format("MMM");case TimeStep.SCALE.YEAR:return I(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return I(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return I(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return I(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return I(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return I(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},a.prototype.setOptions=function(t){A.extend(this.options,t)},a.prototype.update=function(){this._order(),this._stack()},a.prototype._order=function(){var t=this.parent.items;if(!t)throw new Error("Cannot stack items: parent does not contain items");var e=[],i=0;A.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var n=this.options.order||this.defaultOptions.order;if("function"!=typeof n)throw new Error("Option order must be a function");e.sort(n),this.ordered=e},a.prototype._stack=function(){var t,e,i,n=this.ordered,s=this.options,r=s.orientation||this.defaultOptions.orientation,o="top"==r;for(i=s.margin&&void 0!==s.margin.item?s.margin.item:this.defaultOptions.margin.item,t=0,e=n.length;e>t;t++){var a=n[t],h=null;do h=this.checkOverlap(n,t,0,t-1,i),null!=h&&(a.top=o?h.top+h.height+i:h.top-a.height-i);while(h)}},a.prototype.checkOverlap=function(t,e,i,n,s){for(var r=this.collision,o=t[e],a=n;a>=i;a--){var h=t[a];if(r(o,h,s)&&a!=e)return h}return null},a.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},h.prototype.setOptions=function(t){A.extend(this.options,t),null!==this.start&&null!==this.end&&this.setRange(this.start,this.end)},h.prototype.subscribe=function(t,e,i){function n(e){s._onMouseWheel(e,t,i)}var s=this;if("move"==e)t.on("dragstart",function(e){s._onDragStart(e,t)}),t.on("drag",function(e){s._onDrag(e,t,i)}),t.on("dragend",function(e){s._onDragEnd(e,t)});else{if("zoom"!=e)throw new TypeError('Unknown event "'+e+'". Choose "move" or "zoom".');t.on("mousewheel",n),t.on("DOMMouseScroll",n),t.on("touch",function(){s._onTouch()}),t.on("pinch",function(e){s._onPinch(e,t,i)})}},h.prototype.on=function(t,e){Y.addListener(this,t,e)},h.prototype._trigger=function(t){Y.trigger(this,t,{start:this.start,end:this.end})},h.prototype.setRange=function(t,e){var i=this._applyRange(t,e);i&&(this._trigger("rangechange"),this._trigger("rangechanged"))},h.prototype._applyRange=function(t,e){var i,n=null!=t?A.convert(t,"Number"):this.start,s=null!=e?A.convert(e,"Number"):this.end,r=null!=this.options.max?A.convert(this.options.max,"Date").valueOf():null,o=null!=this.options.min?A.convert(this.options.min,"Date").valueOf():null;if(isNaN(n)||null===n)throw new Error('Invalid start "'+t+'"');if(isNaN(s)||null===s)throw new Error('Invalid end "'+e+'"');if(n>s&&(s=n),null!==o&&o>n&&(i=o-n,n+=i,s+=i,null!=r&&s>r&&(s=r)),null!==r&&s>r&&(i=s-r,n-=i,s-=i,null!=o&&o>n&&(n=o)),null!==this.options.zoomMin){var a=parseFloat(this.options.zoomMin);0>a&&(a=0),a>s-n&&(this.end-this.start===a?(n=this.start,s=this.end):(i=a-(s-n),n-=i/2,s+=i/2))}if(null!==this.options.zoomMax){var h=parseFloat(this.options.zoomMax);0>h&&(h=0),s-n>h&&(this.end-this.start===h?(n=this.start,s=this.end):(i=s-n-h,n+=i/2,s-=i/2))}var d=this.start!=n||this.end!=s;return this.start=n,this.end=s,d},h.prototype.getRange=function(){return{start:this.start,end:this.end}},h.prototype.conversion=function(t){return h.conversion(this.start,this.end,t)},h.conversion=function(t,e,i){return 0!=i&&e-t!=0?{offset:t,scale:i/(e-t)}:{offset:0,scale:1}};var F={};h.prototype._onDragStart=function(t,e){if(!F.pinching){F.start=this.start,F.end=this.end;var i=e.frame;i&&(i.style.cursor="move")}},h.prototype._onDrag=function(t,e,i){if(d(i),!F.pinching){var n="horizontal"==i?t.gesture.deltaX:t.gesture.deltaY,s=F.end-F.start,r="horizontal"==i?e.width:e.height,o=-n/r*s;this._applyRange(F.start+o,F.end+o),this._trigger("rangechange")}},h.prototype._onDragEnd=function(t,e){F.pinching||(e.frame&&(e.frame.style.cursor="auto"),this._trigger("rangechanged"))},h.prototype._onMouseWheel=function(t,e,i){d(i);var n=0;if(t.wheelDelta?n=t.wheelDelta/120:t.detail&&(n=-t.detail/3),n){var s;s=0>n?1-n/5:1/(1+n/5);var r=A.fakeGesture(this,t),o=c(r.touches[0],e.frame),a=this._pointerToDate(e,i,o);this.zoom(s,a)}A.preventDefault(t)},h.prototype._onTouch=function(){F.start=this.start,F.end=this.end,F.pinching=!1,F.center=null},h.prototype._onPinch=function(t,e,i){if(F.pinching=!0,t.gesture.touches.length>1){F.center||(F.center=c(t.gesture.center,e.frame));var n=1/t.gesture.scale,s=this._pointerToDate(e,i,F.center),r=c(t.gesture.center,e.frame),o=(this._pointerToDate(e,i,r),parseInt(s+(F.start-s)*n)),a=parseInt(s+(F.end-s)*n);this.setRange(o,a)}},h.prototype._pointerToDate=function(t,e,i){var n;if("horizontal"==e){var s=t.width;return n=this.conversion(s),i.x/n.scale+n.offset}var r=t.height;return n=this.conversion(r),i.y/n.scale+n.offset},h.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2);var i=e+(this.start-e)*t,n=e+(this.end-e)*t;this.setRange(i,n)},h.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,n=this.end+e*t;this.start=i,this.end=n},h.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,n=this.start-i,s=this.end-i;this.setRange(n,s)},u.prototype.add=function(t){if(void 0==t.id)throw new Error("Component has no field id");if(!(t instanceof l||t instanceof u))throw new TypeError("Component must be an instance of prototype Component or Controller");t.controller=this,this.components[t.id]=t},u.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]==t))break;e&&delete this.components[e]},u.prototype.requestReflow=function(t){if(t)this.reflow();else if(!this.reflowTimer){var e=this;this.reflowTimer=setTimeout(function(){e.reflowTimer=void 0,e.reflow()},0)}},u.prototype.requestRepaint=function(t){if(t)this.repaint();else if(!this.repaintTimer){var e=this;this.repaintTimer=setTimeout(function(){e.repaintTimer=void 0,e.repaint()},0)}},u.prototype.repaint=function H(){function H(i,n){n in e||(i.depends&&i.depends.forEach(function(t){H(t,t.id)}),i.parent&&H(i.parent,i.parent.id),t=i.repaint()||t,e[n]=!0)}var t=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var e={};A.forEach(this.components,H),t&&this.reflow()},u.prototype.reflow=function z(){function z(i,n){n in e||(i.depends&&i.depends.forEach(function(t){z(t,t.id)}),i.parent&&z(i.parent,i.parent.id),t=i.reflow()||t,e[n]=!0)}var t=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var e={};A.forEach(this.components,z),t&&this.repaint()},l.prototype.setOptions=function(t){t&&(A.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},l.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},l.prototype.getContainer=function(){return null},l.prototype.getFrame=function(){return this.frame},l.prototype.repaint=function(){return!1},l.prototype.reflow=function(){return!1},l.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},l.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},l.prototype.requestRepaint=function(){if(!this.controller)throw new Error("Cannot request a repaint: no controller configured");this.controller.requestRepaint()},l.prototype.requestReflow=function(){if(!this.controller)throw new Error("Cannot request a reflow: no controller configured");this.controller.requestReflow()},p.prototype=new l,p.prototype.setOptions=l.prototype.setOptions,p.prototype.getContainer=function(){return this.frame},p.prototype.repaint=function(){var t=0,e=A.updateProperty,i=A.option.asSize,n=this.options,s=this.frame;if(!s){s=document.createElement("div"),s.className="panel";var r=n.className;r&&("function"==typeof r?A.addClassName(s,String(r())):A.addClassName(s,String(r))),this.frame=s,t+=1}if(!s.parentNode){if(!this.parent)throw new Error("Cannot repaint panel: no parent attached");var o=this.parent.getContainer();if(!o)throw new Error("Cannot repaint panel: parent has no container element");o.appendChild(s),t+=1}return t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),t>0},p.prototype.reflow=function(){var t=0,e=A.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},f.prototype=new p,f.prototype.setOptions=l.prototype.setOptions,f.prototype.repaint=function(){var t=0,e=A.updateProperty,i=A.option.asSize,n=this.options,s=this.frame;if(s||(s=document.createElement("div"),this.frame=s,t+=1),!s.parentNode){if(!this.container)throw new Error("Cannot repaint root panel: no container attached");this.container.appendChild(s),t+=1}s.className="vis timeline rootpanel "+n.orientation;var r=n.className;return r&&A.addClassName(s,A.option.asString(r)),t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),this._updateEventEmitters(),this._updateWatch(),t>0},f.prototype.reflow=function(){var t=0,e=A.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},f.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},f.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow(),void 0):(t._unwatch(),void 0)};A.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},f.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},f.prototype.on=function(t,e){var i=this.listeners[t];i||(i=[],this.listeners[t]=i),i.push(e),this._updateEventEmitters()},f.prototype._updateEventEmitters=function(){if(this.listeners){var t=this;A.forEach(this.listeners,function(e,i){if(t.emitters||(t.emitters={}),!(i in t.emitters)){var n=t.frame;if(n){var s=function(t){e.forEach(function(e){e(t)})};t.emitters[i]=s,t.hammer||(t.hammer=L(n,{prevent_default:!0})),t.hammer.on(i,s)}}})}},m.prototype=new l,m.prototype.setOptions=l.prototype.setOptions,m.prototype.setRange=function(t){if(!(t instanceof h||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},m.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},m.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},m.prototype.repaint=function(){var t=0,e=A.updateProperty,i=A.option.asSize,n=this.options,s=this.getOption("orientation"),r=this.props,o=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis",!a.parentNode){if(!this.parent)throw new Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw new Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var d=a.parentNode;if(d){var c=a.nextSibling;d.removeChild(a);var u="bottom"==s&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px";if(t+=e(a.style,"top",i(n.top,u)),t+=e(a.style,"left",i(n.left,"0px")),t+=e(a.style,"width",i(n.width,"100%")),t+=e(a.style,"height",i(n.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),o.first();for(var l=void 0,p=0;o.hasNext()&&1e3>p;){p++;var f=o.getCurrent(),m=this.toScreen(f),g=o.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(m,o.getLabelMinor()),g&&this.getOption("showMajorLabels")?(m>0&&(void 0==l&&(l=m),this._repaintMajorText(m,o.getLabelMajor())),this._repaintMajorLine(m)):this._repaintMinorLine(m),o.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=o.getLabelMajor(v),w=y.length*(r.majorCharWidth||10)+10;(void 0==l||l>w)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),c?d.insertBefore(a,c):d.appendChild(a)}return t>0},m.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},m.prototype._repaintEnd=function(){A.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},m.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var n=document.createTextNode("");i=document.createElement("div"),i.appendChild(n),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},m.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var n=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(n),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},m.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},m.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},m.prototype._repaintLine=function(){{var t=this.dom.line,e=this.frame;this.options}this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&t.parentElement&&(e.removeChild(t.line),delete this.dom.line)},m.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var n=document.createElement("DIV");n.className="text major measure",n.appendChild(t),this.frame.appendChild(n),e.measureCharMajor=n}},m.prototype.reflow=function(){var t=0,e=A.updateProperty,i=this.frame,n=this.range;if(!n)throw new Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var s=this.props,r=this.getOption("showMinorLabels"),o=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(s.minorCharHeight=a.clientHeight,s.minorCharWidth=a.clientWidth),h&&(s.majorCharHeight=h.clientHeight,s.majorCharWidth=h.clientWidth);var d=i.parentNode?i.parentNode.offsetHeight:0;switch(d!=s.parentHeight&&(s.parentHeight=d,t+=1),this.getOption("orientation")){case"bottom":s.minorLabelHeight=r?s.minorCharHeight:0,s.majorLabelHeight=o?s.majorCharHeight:0,s.minorLabelTop=0,s.majorLabelTop=s.minorLabelTop+s.minorLabelHeight,s.minorLineTop=-this.top,s.minorLineHeight=Math.max(this.top+s.majorLabelHeight,0),s.minorLineWidth=1,s.majorLineTop=-this.top,s.majorLineHeight=Math.max(this.top+s.minorLabelHeight+s.majorLabelHeight,0),s.majorLineWidth=1,s.lineTop=0;break;case"top":s.minorLabelHeight=r?s.minorCharHeight:0,s.majorLabelHeight=o?s.majorCharHeight:0,s.majorLabelTop=0,s.minorLabelTop=s.majorLabelTop+s.majorLabelHeight,s.minorLineTop=s.minorLabelTop,s.minorLineHeight=Math.max(d-s.majorLabelHeight-this.top),s.minorLineWidth=1,s.majorLineTop=0,s.majorLineHeight=Math.max(d-this.top),s.majorLineWidth=1,s.lineTop=s.majorLabelHeight+s.minorLabelHeight;break;default:throw new Error('Unkown orientation "'+this.getOption("orientation")+'"')}var c=s.minorLabelHeight+s.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",c),this._updateConversion();var u=A.convert(n.start,"Number"),l=A.convert(n.end,"Number"),p=this.toTime(5*(s.minorCharWidth||10)).valueOf()-this.toTime(0).valueOf();this.step=new TimeStep(new Date(u),new Date(l),p),t+=e(s.range,"start",u),t+=e(s.range,"end",l),t+=e(s.range,"minimumStep",p.valueOf())}return t>0},m.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},g.prototype=new l,g.prototype.setOptions=l.prototype.setOptions,g.prototype.getContainer=function(){return this.frame},g.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCurrentTime"))return t&&(i.removeChild(t),delete this.frame),void 0;t||(t=document.createElement("div"),t.className="currenttime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t),this.frame=t),e.conversion||e._updateConversion();var n=new Date,s=e.toScreen(n);t.style.left=s+"px",t.title="Current time: "+n,void 0!==this.currentTimeTimer&&(clearTimeout(this.currentTimeTimer),delete this.currentTimeTimer);var r=this,o=1/e.conversion.scale/2;return 30>o&&(o=30),this.currentTimeTimer=setTimeout(function(){r.repaint()},o),!1},v.prototype=new l,v.prototype.setOptions=l.prototype.setOptions,v.prototype.getContainer=function(){return this.frame},v.prototype.repaint=function(){var t=this.frame,e=this.parent,i=e.parent.getContainer();if(!e)throw new Error("Cannot repaint bar: no parent attached");if(!i)throw new Error("Cannot repaint bar: parent has no container element");if(!this.getOption("showCustomTime"))return t&&(i.removeChild(t),delete this.frame),void 0;if(!t){t=document.createElement("div"),t.className="customtime",t.style.position="absolute",t.style.top="0px",t.style.height="100%",i.appendChild(t);var n=document.createElement("div");n.style.position="relative",n.style.top="0px",n.style.left="-10px",n.style.height="100%",n.style.width="20px",t.appendChild(n),this.frame=t,this.subscribe(this,"movetime")}e.conversion||e._updateConversion();var s=e.toScreen(this.customTime);return t.style.left=s+"px",t.title="Time: "+this.customTime,!1},v.prototype._setCustomTime=function(t){this.customTime=new Date(t.valueOf()),this.repaint()},v.prototype._getCustomTime=function(){return new Date(this.customTime.valueOf())},v.prototype.subscribe=function(t,e){var i=this,n={component:t,event:e,callback:function(t){i._onMouseDown(t,n)},params:{}};t.on("mousedown",n.callback),i.listeners.push(n)},v.prototype.on=function(t,e){var i=this.frame;if(!i)throw new Error("Cannot add event listener: no parent attached");Y.addListener(this,t,e),A.addEventListener(i,t,e)},v.prototype._onMouseDown=function(t,e){t=t||window.event;var i=e.params,n=t.which?1==t.which:1==t.button;if(n){i.mouseX=A.getPageX(t),i.moved=!1,i.customTime=this.customTime;var s=this;i.onMouseMove||(i.onMouseMove=function(t){s._onMouseMove(t,e)},A.addEventListener(document,"mousemove",i.onMouseMove)),i.onMouseUp||(i.onMouseUp=function(t){s._onMouseUp(t,e)},A.addEventListener(document,"mouseup",i.onMouseUp)),A.stopPropagation(t),A.preventDefault(t)}},v.prototype._onMouseMove=function(t,e){t=t||window.event;var i=e.params,n=this.parent,s=A.getPageX(t);void 0===i.mouseX&&(i.mouseX=s);var r=s-i.mouseX;Math.abs(r)>=1&&(i.moved=!0);var o=n.toScreen(i.customTime),a=o+r,h=n.toTime(a);this._setCustomTime(h),Y.trigger(this,"timechange",{customTime:this.customTime}),A.preventDefault(t)},v.prototype._onMouseUp=function(t,e){t=t||window.event;var i=e.params;i.onMouseMove&&(A.removeEventListener(document,"mousemove",i.onMouseMove),i.onMouseMove=null),i.onMouseUp&&(A.removeEventListener(document,"mouseup",i.onMouseUp),i.onMouseUp=null),i.moved&&Y.trigger(this,"timechanged",{customTime:this.customTime})},y.prototype=new p,y.types={box:_,range:E,rangeoverflow:T,point:b},y.prototype.setOptions=l.prototype.setOptions,y.prototype.setRange=function(t){if(!(t instanceof h||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},y.prototype.repaint=function(){var t=0,e=A.updateProperty,i=A.option.asSize,n=this.options,s=this.getOption("orientation"),r=this.defaultOptions,o=this.frame;if(!o){o=document.createElement("div"),o.className="itemset";var a=n.className;a&&A.addClassName(o,A.option.asString(a));var h=document.createElement("div");h.className="background",o.appendChild(h),this.dom.background=h;var d=document.createElement("div");d.className="foreground",o.appendChild(d),this.dom.foreground=d;var c=document.createElement("div");c.className="itemset-axis",this.dom.axis=c,this.frame=o,t+=1}if(!this.parent)throw new Error("Cannot repaint itemset: no parent attached");var u=this.parent.getContainer();if(!u)throw new Error("Cannot repaint itemset: parent has no container element");o.parentNode||(u.appendChild(o),t+=1),this.dom.axis.parentNode||(u.appendChild(this.dom.axis),t+=1),t+=e(o.style,"left",i(n.left,"0px")),t+=e(o.style,"top",i(n.top,"0px")),t+=e(o.style,"width",i(n.width,"100%")),t+=e(o.style,"height",i(n.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(n.left,"0px")),t+=e(this.dom.axis.style,"width",i(n.width,"100%")),t+="bottom"==s?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var l=this,p=this.queue,f=this.itemsData,m=this.items,g={};return Object.keys(p).forEach(function(e){var i=p[e],s=m[e];switch(i){case"add":case"update":var o=f&&f.get(e,g);if(o){var a=o.type||o.start&&o.end&&"range"||n.type||"box",h=y.types[a];if(s&&(h&&s instanceof h?(s.data=o,t++):(t+=s.hide(),s=null)),!s){if(!h)throw new TypeError('Unknown item type "'+a+'"');s=new h(l,o,n,r),t++}s.repaint(),m[e]=s}delete p[e];break;case"remove":s&&(t+=s.hide()),delete m[e],delete p[e];break;default:console.log('Error: unknown action "'+i+'"')}}),A.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},y.prototype.getForeground=function(){return this.dom.foreground},y.prototype.getBackground=function(){return this.dom.background},y.prototype.getAxis=function(){return this.dom.axis},y.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&e.margin.axis||this.defaultOptions.margin.axis,n=e.margin&&e.margin.item||this.defaultOptions.margin.item,s=A.updateProperty,r=A.option.asNumber,o=A.option.asSize,a=this.frame;if(a){this._updateConversion(),A.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,d=r(e.maxHeight),c=null!=o(e.height);if(c)h=a.offsetHeight;else{var u=this.stack.ordered;if(u.length){var l=u[0].top,p=u[0].top+u[0].height;A.forEach(u,function(t){l=Math.min(l,t.top),p=Math.max(p,t.top+t.height)}),h=p-l+i+n}else h=i+n}null!=d&&(h=Math.min(h,d)),t+=s(this,"height",h),t+=s(this,"top",a.offsetTop),t+=s(this,"left",a.offsetLeft),t+=s(this,"width",a.offsetWidth)}else t+=1;return t>0},y.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t},y.prototype.setItems=function(t){var e,i=this,n=this.itemsData;if(t){if(!(t instanceof r||t instanceof o))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(n&&(A.forEach(this.listeners,function(t,e){n.unsubscribe(e,t)}),e=n.getIds(),this._onRemove(e)),this.itemsData){var s=this.id;A.forEach(this.listeners,function(t,e){i.itemsData.subscribe(e,t,s)}),e=this.itemsData.getIds(),this._onAdd(e)}},y.prototype.getItems=function(){return this.itemsData},y.prototype._onUpdate=function(t){this._toQueue("update",t)},y.prototype._onAdd=function(t){this._toQueue("add",t)},y.prototype._onRemove=function(t){this._toQueue("remove",t)},y.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]=t}),this.controller&&this.requestRepaint()},y.prototype._updateConversion=function(){var t=this.range;if(!t)throw new Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},y.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.scale+e.offset)},y.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.scale},w.prototype.select=function(){this.selected=!0},w.prototype.unselect=function(){this.selected=!1},w.prototype.show=function(){return!1},w.prototype.hide=function(){return!1},w.prototype.repaint=function(){return!1},w.prototype.reflow=function(){return!1},w.prototype.getWidth=function(){return this.width},_.prototype=new w(null,null),_.prototype.select=function(){this.selected=!0},_.prototype.unselect=function(){this.selected=!1},_.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");if(!e.box.parentNode){var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");i.appendChild(e.box),t=!0}if(!e.line.parentNode){var n=this.parent.getBackground();if(!n)throw new Error("Cannot repaint time axis: parent has no background container element");n.appendChild(e.line),t=!0}if(!e.dot.parentNode){var s=this.parent.getAxis();if(!n)throw new Error("Cannot repaint time axis: parent has no axis container element");s.appendChild(e.dot),t=!0}if(this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var r=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=r&&(this.className=r,e.box.className="item box"+r,e.line.className="item line"+r,e.dot.className="item dot"+r,t=!0)}return t},_.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint() +},_.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},_.prototype.reflow=function(){var t,e,i,n,s,r,o,a,h,d,c,u,l=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(c=this.data,u=this.parent&&this.parent.range,c&&u){var p=u.end-u.start;this.visible=c.start>u.start-p&&c.start0},_.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot")},_.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var n=t.box,s=t.line,r=t.dot;n.style.left=this.left+"px",n.style.top=this.top+"px",s.style.left=e.line.left+"px","top"==i?(s.style.top="0px",s.style.height=this.top+"px"):(s.style.top=this.top+this.height+"px",s.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),r.style.left=e.dot.left+"px",r.style.top=e.dot.top+"px"}},b.prototype=new w(null,null),b.prototype.select=function(){this.selected=!0},b.prototype.unselect=function(){this.selected=!1},b.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.point.className="item point"+n,t=!0)}return t},b.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},b.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},b.prototype.reflow=function(){var t,e,i,n,s,r,o,a,h,d,c=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(h=this.data,d=this.parent&&this.parent.range,h&&d){var u=d.end-d.start;this.visible=h.start>d.start-u&&h.start0},b.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot))},b.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},E.prototype=new w(null,null),E.prototype.select=function(){this.selected=!0},E.prototype.unselect=function(){this.selected=!1},E.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=this.data.className?" "+this.data.className:"";this.className!=n&&(this.className=n,e.box.className="item range"+n,t=!0)}return t},E.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},E.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},E.prototype.reflow=function(){var t,e,i,n,s,r,o,a,h,d,c,u,l,p,f,m,g=0;if(void 0==this.data.start)throw new Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw new Error('Property "end" missing in item '+this.data.id);return h=this.data,d=this.parent&&this.parent.range,this.visible=h&&d?h.startd.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,r=this.parent,o=r.toScreen(this.data.start),a=r.toScreen(this.data.end),c=A.updateProperty,u=t.box,l=r.width,f=i.orientation||this.defaultOptions.orientation,n=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,s=i.padding||this.defaultOptions.padding,g+=c(e.content,"width",t.content.offsetWidth),g+=c(this,"height",u.offsetHeight),-l>o&&(o=-l),a>2*l&&(a=2*l),p=0>o?Math.min(-o,a-o-e.content.width-2*s):0,g+=c(e.content,"left",p),"top"==f?(m=n,g+=c(this,"top",m)):(m=r.height-this.height-n,g+=c(this,"top",m)),g+=c(this,"left",o),g+=c(this,"width",Math.max(a-o,1))):g+=1),g>0},E.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content))},E.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},T.prototype=new E(null,null),T.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw new Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw new Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw new Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=this.data.className?" "+this.data.className:"";this.className!=n&&(this.className=n,e.box.className="item rangeoverflow"+n,t=!0)}return t},T.prototype.getWidth=function(){return void 0!==this.props.content&&this.width0},x.prototype=new p,x.prototype.setOptions=l.prototype.setOptions,x.prototype.setRange=function(){},x.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},x.prototype.getItems=function(){return this.itemsData},x.prototype.setRange=function(t){this.range=t},x.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(A.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof r?this.groupsData=t:(this.groupsData=new r({convert:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var n=this.id;A.forEach(this.listeners,function(t,e){i.groupsData.subscribe(e,t,n)}),e=this.groupsData.getIds(),this._onAdd(e)}},x.prototype.getGroups=function(){return this.groupsData},x.prototype.repaint=function(){var t,e,i,n,s=0,r=A.updateProperty,o=A.option.asSize,a=A.option.asElement,h=this.options,d=this.dom.frame,c=this.dom.labels,u=this.dom.labelSet;if(!this.parent)throw new Error("Cannot repaint groupset: no parent attached");var l=this.parent.getContainer();if(!l)throw new Error("Cannot repaint groupset: parent has no container element");if(!d){d=document.createElement("div"),d.className="groupset",this.dom.frame=d;var p=h.className;p&&A.addClassName(d,A.option.asString(p)),s+=1}d.parentNode||(l.appendChild(d),s+=1);var f=a(h.labelContainer);if(!f)throw new Error('Cannot repaint groupset: option "labelContainer" not defined');c||(c=document.createElement("div"),c.className="labels",this.dom.labels=c),u||(u=document.createElement("div"),u.className="label-set",c.appendChild(u),this.dom.labelSet=u),c.parentNode&&c.parentNode==f||(c.parentNode&&c.parentNode.removeChild(c.parentNode),f.appendChild(c)),s+=r(d.style,"height",o(h.height,this.height+"px")),s+=r(d.style,"top",o(h.top,"0px")),s+=r(d.style,"left",o(h.left,"0px")),s+=r(d.style,"width",o(h.width,"100%")),s+=r(u.style,"top",o(h.top,"0px")),s+=r(u.style,"height",o(h.height,this.height+"px"));var m=this,g=this.queue,v=this.groups,y=this.groupsData,w=Object.keys(g);if(w.length){w.forEach(function(t){var e=g[t],i=v[t];switch(e){case"add":case"update":if(!i){var n=Object.create(m.options);A.extend(n,{height:null,maxHeight:null}),i=new S(m,t,n),i.setItems(m.itemsData),v[t]=i,m.controller.add(i)}i.data=y.get(t),delete g[t];break;case"remove":i&&(i.setItems(),delete v[t],m.controller.remove(i)),delete g[t];break;default:console.log('Error: unknown action "'+e+'"')}});var _=this.groupsData.getIds({order:this.options.groupOrder});for(t=0;t<_.length;t++)!function(t,e){var i=0;e&&(i=function(){return e.top+e.height}),t.setOptions({top:i})}(v[_[t]],v[_[t-1]]);for(;u.firstChild;)u.removeChild(u.firstChild);for(t=0;t<_.length;t++)e=_[t],n=this._createLabel(e),u.appendChild(n);s++}for(e in v)v.hasOwnProperty(e)&&(i=v[e],n=i.label,n&&(n.style.top=i.top+"px",n.style.height=i.height+"px"));return s>0},x.prototype._createLabel=function(t){var e=this.groups[t],i=document.createElement("div");i.className="label";var n=document.createElement("div");n.className="inner",i.appendChild(n);var s=e.data&&e.data.content;s instanceof Element?n.appendChild(s):void 0!=s&&(n.innerHTML=s);var r=e.data&&e.data.className;return r&&A.addClassName(i,r),e.label=i,i},x.prototype.getContainer=function(){return this.dom.frame},x.prototype.getLabelsWidth=function(){return this.props.labels.width},x.prototype.reflow=function(){var t,e,i=0,n=this.options,s=A.updateProperty,r=A.option.asNumber,o=A.option.asSize,a=this.dom.frame;if(a){var h,d=r(n.maxHeight),c=null!=o(n.height);if(c)h=a.offsetHeight;else{h=0;for(t in this.groups)this.groups.hasOwnProperty(t)&&(e=this.groups[t],h+=e.height)}null!=d&&(h=Math.min(h,d)),i+=s(this,"height",h),i+=s(this,"top",a.offsetTop),i+=s(this,"left",a.offsetLeft),i+=s(this,"width",a.offsetWidth)}var u=0;for(t in this.groups)if(this.groups.hasOwnProperty(t)){e=this.groups[t];var l=e.props&&e.props.label&&e.props.label.width||0;u=Math.max(u,l)}return i+=s(this.props.labels,"width",u),i>0},x.prototype.hide=function(){return this.dom.frame&&this.dom.frame.parentNode?(this.dom.frame.parentNode.removeChild(this.dom.frame),!0):!1},x.prototype.show=function(){return this.dom.frame&&this.dom.frame.parentNode?!1:this.repaint()},x.prototype._onUpdate=function(t){this._toQueue(t,"update")},x.prototype._onAdd=function(t){this._toQueue(t,"add")},x.prototype._onRemove=function(t){this._toQueue(t,"remove")},x.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},D.prototype.setOptions=function(t){A.extend(this.options,t),this.range.setRange(),this.controller.reflow(),this.controller.repaint()},D.prototype.setCustomTime=function(t){this.customtime._setCustomTime(t)},D.prototype.getCustomTime=function(){return new Date(this.customtime.customTime.valueOf())},D.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof r&&(e=t):e=null,t instanceof r||(e=new r({convert:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var n=this.getItemRange(),s=n.min,o=n.max;if(null!=s&&null!=o){var a=o.valueOf()-s.valueOf();0>=a&&(a=864e5),s=new Date(s.valueOf()-.05*a),o=new Date(o.valueOf()+.05*a)}void 0!=this.options.start&&(s=A.convert(this.options.start,"Date")),void 0!=this.options.end&&(o=A.convert(this.options.end,"Date")),(null!=s||null!=o)&&this.range.setRange(s,o)}},D.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?x:y;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var n=Object.create(this.options);A.extend(n,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.itemPanel.height-e.timeaxis.height-e.content.height},left:null,width:"100%",height:function(){return e.options.height?e.itemPanel.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!A.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null},labelContainer:function(){return e.labelPanel.getContainer()}}),this.content=new i(this.itemPanel,[this.timeaxis],n),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},D.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var n=t.min("start");e=n?n.start.valueOf():null;var s=t.max("start");s&&(i=s.start.valueOf());var r=t.max("end");r&&(i=null==i?r.end.valueOf():Math.max(i,r.end.valueOf()))}return{min:null!=e?new Date(e):null,max:null!=i?new Date(i):null}},function(t){function e(t){return D=t,l()}function i(){M=0,C=D.charAt(0)}function n(){M++,C=D.charAt(M)}function s(){return D.charAt(M+1)}function r(t){return L.test(t)}function o(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t,e,i){for(var n=e.split("."),s=t;n.length;){var r=n.shift();n.length?(s[r]||(s[r]={}),s=s[r]):s[r]=i}}function h(t,e){for(var i,n,s=null,r=[t],a=t;a.parent;)r.push(a.parent),a=a.parent;if(a.nodes)for(i=0,n=a.nodes.length;n>i;i++)if(e.id===a.nodes[i].id){s=a.nodes[i];break}for(s||(s={id:e.id},t.node&&(s.attr=o(s.attr,t.node))),i=r.length-1;i>=0;i--){var h=r[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(s)&&h.nodes.push(s)}e.attr&&(s.attr=o(s.attr,e.attr))}function d(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=o({},t.edge);e.attr=o(i,e.attr)}}function c(t,e,i,n,s){var r={from:e,to:i,type:n};return t.edge&&(r.attr=o({},t.edge)),r.attr=o(r.attr||{},s),r}function u(){for(N=S.NULL,O="";" "==C||" "==C||"\n"==C||"\r"==C;)n();do{var t=!1;if("#"==C){for(var e=M-1;" "==D.charAt(e)||" "==D.charAt(e);)e--;if("\n"==D.charAt(e)||""==D.charAt(e)){for(;""!=C&&"\n"!=C;)n();t=!0}}if("/"==C&&"/"==s()){for(;""!=C&&"\n"!=C;)n();t=!0}if("/"==C&&"*"==s()){for(;""!=C;){if("*"==C&&"/"==s()){n(),n();break}n()}t=!0}for(;" "==C||" "==C||"\n"==C||"\r"==C;)n()}while(t);if(""==C)return N=S.DELIMITER,void 0;var i=C+s();if(x[i])return N=S.DELIMITER,O=i,n(),n(),void 0;if(x[C])return N=S.DELIMITER,O=C,n(),void 0;if(r(C)||"-"==C){for(O+=C,n();r(C);)O+=C,n();return"false"==O?O=!1:"true"==O?O=!0:isNaN(Number(O))||(O=Number(O)),N=S.IDENTIFIER,void 0}if('"'==C){for(n();""!=C&&('"'!=C||'"'==C&&'"'==s());)O+=C,'"'==C&&n(),n();if('"'!=C)throw _('End of string " expected');return n(),N=S.IDENTIFIER,void 0}for(N=S.UNKNOWN;""!=C;)O+=C,n();throw new SyntaxError('Syntax error in part "'+b(O,30)+'"')}function l(){var t={};if(i(),u(),"strict"==O&&(t.strict=!0,u()),("graph"==O||"digraph"==O)&&(t.type=O,u()),N==S.IDENTIFIER&&(t.id=O,u()),"{"!=O)throw _("Angle bracket { expected");if(u(),p(t),"}"!=O)throw _("Angle bracket } expected");if(u(),""!==O)throw _("End of file expected");return u(),delete t.node,delete t.edge,delete t.graph,t}function p(t){for(;""!==O&&"}"!=O;)f(t),";"==O&&u()}function f(t){var e=m(t);if(e)return y(t,e),void 0;var i=g(t);if(!i){if(N!=S.IDENTIFIER)throw _("Identifier expected");var n=O;if(u(),"="==O){if(u(),N!=S.IDENTIFIER)throw _("Identifier expected");t[n]=O,u()}else v(t,n)}}function m(t){var e=null;if("subgraph"==O&&(e={},e.type="subgraph",u(),N==S.IDENTIFIER&&(e.id=O,u())),"{"==O){if(u(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,p(e),"}"!=O)throw _("Angle bracket } expected");u(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function g(t){return"node"==O?(u(),t.node=w(),"node"):"edge"==O?(u(),t.edge=w(),"edge"):"graph"==O?(u(),t.graph=w(),"graph"):null}function v(t,e){var i={id:e},n=w();n&&(i.attr=n),h(t,i),y(t,e)}function y(t,e){for(;"->"==O||"--"==O;){var i,n=O;u();var s=m(t);if(s)i=s;else{if(N!=S.IDENTIFIER)throw _("Identifier or subgraph expected");i=O,h(t,{id:i}),u()}var r=w(),o=c(t,e,i,n,r);d(t,o),e=i}}function w(){for(var t=null;"["==O;){for(u(),t={};""!==O&&"]"!=O;){if(N!=S.IDENTIFIER)throw _("Attribute name expected");var e=O;if(u(),"="!=O)throw _("Equal sign = expected");if(u(),N!=S.IDENTIFIER)throw _("Attribute value expected");var i=O;a(t,e,i),u(),","==O&&u()}if("]"!=O)throw _("Bracket ] expected");u()}return t}function _(t){return new SyntaxError(t+', got "'+b(O,30)+'" (char '+M+")")}function b(t,e){return t.length<=e?t:t.substr(0,27)+"..."}function E(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 T(t){function i(t){var e={from:t.from,to:t.to};return o(e,t.attr),e.style="->"==t.type?"arrow":"line",e}var n=e(t),s={nodes:[],edges:[],options:{}};return n.nodes&&n.nodes.forEach(function(t){var e={id:t.id,label:String(t.label||t.id)};o(e,t.attr),e.image&&(e.shape="image"),s.nodes.push(e)}),n.edges&&n.edges.forEach(function(t){var e,n;e=t.from instanceof Object?t.from.nodes:{id:t.from},n=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);s.edges.push(e)}),E(e,n,function(e,n){var r=c(s,e.id,n.id,t.type,t.attr),o=i(r);s.edges.push(o)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=i(t);s.edges.push(e)})}),n.attr&&(s.options=n.attr),s}var S={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},x={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},D="",M=0,C="",O="",N=S.NULL,L=/[a-zA-Z_0-9.:#]/;t.parseDOT=e,t.DOTToGraph=T}("undefined"!=typeof A?A:n),"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 n=2*i,s=n/2,r=Math.sqrt(3)/6*n,o=Math.sqrt(n*n-s*s);this.moveTo(t,e-(o-r)),this.lineTo(t+s,e+r),this.lineTo(t-s,e+r),this.lineTo(t,e-(o-r)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var n=2*i,s=n/2,r=Math.sqrt(3)/6*n,o=Math.sqrt(n*n-s*s);this.moveTo(t,e+(o-r)),this.lineTo(t+s,e-r),this.lineTo(t-s,e-r),this.lineTo(t,e+(o-r)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var n=0;10>n;n++){var s=n%2===0?1.3*i:.5*i;this.lineTo(t+s*Math.sin(2*n*Math.PI/10),e-s*Math.cos(2*n*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,n,s){var r=Math.PI/180;0>i-2*s&&(s=i/2),0>n-2*s&&(s=n/2),this.beginPath(),this.moveTo(t+s,e),this.lineTo(t+i-s,e),this.arc(t+i-s,e+s,s,270*r,360*r,!1),this.lineTo(t+i,e+n-s),this.arc(t+i-s,e+n-s,s,0,90*r,!1),this.lineTo(t+s,e+n),this.arc(t+s,e+n-s,s,90*r,180*r,!1),this.lineTo(t,e+s),this.arc(t+s,e+s,s,180*r,270*r,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,n){var s=.5522848,r=i/2*s,o=n/2*s,a=t+i,h=e+n,d=t+i/2,c=e+n/2;this.beginPath(),this.moveTo(t,c),this.bezierCurveTo(t,c-o,d-r,e,d,e),this.bezierCurveTo(d+r,e,a,c-o,a,c),this.bezierCurveTo(a,c+o,d+r,h,d,h),this.bezierCurveTo(d-r,h,t,c+o,t,c)},CanvasRenderingContext2D.prototype.database=function(t,e,i,n){var s=1/3,r=i,o=n*s,a=.5522848,h=r/2*a,d=o/2*a,c=t+r,u=e+o,l=t+r/2,p=e+o/2,f=e+(n-o/2),m=e+n;this.beginPath(),this.moveTo(c,p),this.bezierCurveTo(c,p+d,l+h,u,l,u),this.bezierCurveTo(l-h,u,t,p+d,t,p),this.bezierCurveTo(t,p-d,l-h,e,l,e),this.bezierCurveTo(l+h,e,c,p-d,c,p),this.lineTo(c,f),this.bezierCurveTo(c,f+d,l+h,m,l,m),this.bezierCurveTo(l-h,m,t,f+d,t,f),this.lineTo(t,p)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,n){var s=t-n*Math.cos(i),r=e-n*Math.sin(i),o=t-.9*n*Math.cos(i),a=e-.9*n*Math.sin(i),h=s+n/3*Math.cos(i+.5*Math.PI),d=r+n/3*Math.sin(i+.5*Math.PI),c=s+n/3*Math.cos(i-.5*Math.PI),u=r+n/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,d),this.lineTo(o,a),this.lineTo(c,u),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,n,s){s||(s=[10,5]),0==l&&(l=.001);var r=s.length;this.moveTo(t,e);for(var o=i-t,a=n-e,h=a/o,d=Math.sqrt(o*o+a*a),c=0,u=!0;d>=.1;){var l=s[c++%r];l>d&&(l=d);var p=Math.sqrt(l*l/(1+h*h));0>o&&(p=-p),t+=p,e+=h*p,this[u?"lineTo":"moveTo"](t,e),d-=l,u=!u}}),M.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),this._updateMass()},M.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&this.edges.splice(e,1),this._updateMass()},M.prototype._updateMass=function(){this.mass=50+20*this.edges.length},M.prototype.setProperties=function(t,e){if(t){if(void 0!=t.id&&(this.id=t.id),void 0!=t.label&&(this.label=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===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var n in i)i.hasOwnProperty(n)&&(this[n]=i[n])}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=M.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){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!=t.x,this.yFixed=this.yFixed||void 0!=t.y,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()}},M.parseColor=function(t){var e;return A.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,A.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)),e},M.prototype.select=function(){this.selected=!0,this._reset()},M.prototype.unselect=function(){this.selected=!1,this._reset()},M.prototype._reset=function(){this.width=void 0,this.height=void 0},M.prototype.getTitle=function(){return this.title},M.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 n=this.width/2,s=this.height/2,r=Math.sin(e)*n,o=Math.cos(e)*s;return n*s/Math.sqrt(r*r+o*o);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}},M.prototype._setForce=function(t,e){this.fx=t,this.fy=e},M.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},M.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 n=-this.damping*this.vy,s=(this.fy+n)/this.mass;this.vy+=s/t,this.y+=this.vy/t}},M.prototype.isFixed=function(){return this.xFixed&&this.yFixed},M.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t||!this.xFixed&&Math.abs(this.fx)>this.minForce||!this.yFixed&&Math.abs(this.fy)>this.minForce},M.prototype.isSelected=function(){return this.selected},M.prototype.getValue=function(){return this.value},M.prototype.getDistance=function(t,e){var i=this.x-t,n=this.y-e;return Math.sqrt(i*i+n*n)},M.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}},M.prototype.draw=function(){throw"Draw method not initialized for node"},M.prototype.resize=function(){throw"Resize method not initialized for node"},M.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},M.prototype._resizeImage=function(){if(!this.width){var t,e;if(this.value){var i=this.imageObj.height/this.imageObj.width;t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e}},M.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;this.imageObj?(t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2):e=this.y,this._label(t,this.label,this.x,e,void 0,"top")},M.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}},M.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,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)},M.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=i.width+2*e;this.width=n,this.height=n}},M.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,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)},M.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=Math.max(i.width,i.height)+2*e;this.radius=n/2,this.width=n,this.height=n}},M.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},M.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.widthc;c++)t.fillText(o[c],i,d),d+=h}},M.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,n=0,s=0,r=e.length;r>s;s++)n=Math.max(n,t.measureText(e[s]).width);return{width:n,height:i}}return{width:0,height:0}},C.prototype.setProperties=function(t,e){if(t)switch(void 0!=t.from&&(this.fromId=t.from),void 0!=t.to&&(this.toId=t.to),void 0!=t.id&&(this.id=t.id),void 0!=t.style&&(this.style=t.style),void 0!=t.label&&(this.label=t.label),this.label&&(this.fontSize=e.edges.fontSize,this.fontFace=e.edges.fontFace,this.fontColor=e.edges.fontColor,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!=t.title&&(this.title=t.title),void 0!=t.width&&(this.width=t.width),void 0!=t.value&&(this.value=t.value),void 0!=t.length&&(this.length=t.length),t.dash&&(void 0!=t.dash.length&&(this.dash.length=t.dash.length),void 0!=t.dash.gap&&(this.dash.gap=t.dash.gap),void 0!=t.dash.altLength&&(this.dash.altLength=t.dash.altLength)),void 0!=t.color&&(this.color=t.color),this.connect(),this.widthFixed=this.widthFixed||void 0!=t.width,this.lengthFixed=this.lengthFixed||void 0!=t.length,this.stiffness=1/this.length,this.style){case"line":this.draw=this._drawLine;break;case"arrow":this.draw=this._drawArrow;break;case"arrow-center":this.draw=this._drawArrowCenter;break;case"dash-line":this.draw=this._drawDashLine;break;default:this.draw=this._drawLine}},C.prototype.connect=function(){this.disconnect(),this.from=this.graph.nodes[this.fromId]||null,this.to=this.graph.nodes[this.toId]||null,this.connected=this.from&&this.to,this.connected?(this.from.attachEdge(this),this.to.attachEdge(this)):(this.from&&this.from.detachEdge(this),this.to&&this.to.detachEdge(this))},C.prototype.disconnect=function(){this.from&&(this.from.detachEdge(this),this.from=null),this.to&&(this.to.detachEdge(this),this.to=null),this.connected=!1},C.prototype.getTitle=function(){return this.title},C.prototype.getValue=function(){return this.value},C.prototype.setValueRange=function(t,e){if(!this.widthFixed&&void 0!==this.value){var i=(this.widthMax-this.widthMin)/(e-t);this.width=(this.value-t)*i+this.widthMin}},C.prototype.draw=function(){throw"Method draw not initialized in edge"},C.prototype.isOverlappingWith=function(t){var e=10,i=this.from.x,n=this.from.y,s=this.to.x,r=this.to.y,o=t.left,a=t.top,h=C._dist(i,n,s,r,o,a);return e>h},C.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,n,s=this.length/4,r=this.from;r.width||r.resize(t),r.width>r.height?(i=r.x+r.width/2,n=r.y-s):(i=r.x+s,n=r.y-r.height/2),this._circle(t,i,n,s),e=this._pointOnCircle(i,n,s,.5),this._label(t,this.label,e.x,e.y)}},C.prototype._getLineWidth=function(){return this.from.selected||this.to.selected?Math.min(2*this.width,this.widthMax):this.width},C.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},C.prototype._circle=function(t,e,i,n){t.beginPath(),t.arc(e,i,n,0,2*Math.PI,!1),t.stroke()},C.prototype._label=function(t,e,i,n){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var s=t.measureText(e).width,r=this.fontSize,o=i-s/2,a=n-r/2;t.fillRect(o,a,s,r),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,o,a)}},C.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),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(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},C.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}},C.prototype._pointOnCircle=function(t,e,i,n){var s=2*(n-3/8)*Math.PI;return{x:t+i*Math.cos(s),y:e-i*Math.sin(s)}},C.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.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),n=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var s,r,o=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(s=a.x+a.width/2,r=a.y-o):(s=a.x+o,r=a.y-a.height/2),this._circle(t,s,r,o);var i=.2*Math.PI,n=10+5*this.width;e=this._pointOnCircle(s,r,o,.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(s,r,o,.5),this._label(t,this.label,e.x,e.y))}},C.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.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 n=this.to.x-this.from.x,s=this.to.y-this.from.y,r=Math.sqrt(n*n+s*s),o=this.from.distanceToBorder(t,e+Math.PI),a=(r-o)/r,h=a*this.from.x+(1-a)*this.to.x,d=a*this.from.y+(1-a)*this.to.y,c=this.to.distanceToBorder(t,e),u=(r-c)/r,l=(1-u)*this.from.x+u*this.to.x,p=(1-u)*this.from.y+u*this.to.y;if(t.beginPath(),t.moveTo(h,d),t.lineTo(l,p),t.stroke(),i=10+5*this.width,t.arrow(l,p,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var m,g,v,y=this.from,w=this.length/4;y.width||y.resize(t),y.width>y.height?(m=y.x+y.width/2,g=y.y-w,v={x:m,y:y.y,angle:.9*Math.PI}):(m=y.x+w,g=y.y-y.height/2,v={x:y.x,y:g,angle:.6*Math.PI}),t.beginPath(),t.arc(m,g,w,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(m,g,w,.5),this._label(t,this.label,f.x,f.y))}},C._dist=function(t,e,i,n,s,r){var o=i-t,a=n-e,h=o*o+a*a,d=((s-t)*o+(r-e)*a)/h;d>1?d=1:0>d&&(d=0);var c=t+d*o,u=e+d*a,l=c-s,p=u-r;return Math.sqrt(l*l+p*p)},O.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},O.prototype.setText=function(t){this.frame.innerHTML=t},O.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,n=this.frame.parentNode.clientHeight,s=this.frame.parentNode.clientWidth,r=this.y-e;r+e+this.padding>n&&(r=n-e-this.padding),rs&&(o=s-i-this.padding),o0?s[s.length-1]:null},N.prototype._getPointer=function(t){return{x:t.pageX-R.util.getAbsoluteLeft(this.frame.canvas),y:t.pageY-R.util.getAbsoluteTop(this.frame.canvas)}},N.prototype._onTouch=function(t){this.drag.pointer=this._getPointer(t.gesture.touches[0]),this.drag.pinched=!1,this.pinch.scale=this._getScale()},N.prototype._onDragStart=function(){var t=this.drag;t.selection=[],t.translation=this._getTranslation(),t.nodeId=this._getNodeAt(t.pointer);var e=this.nodes[t.nodeId];if(e){e.isSelected()||this._selectNodes([t.nodeId]);var i=this;this.selection.forEach(function(e){var n=i.nodes[e];if(n){var s={id:e,node:n,x:n.x,y:n.y,xFixed:n.xFixed,yFixed:n.yFixed};n.xFixed=!0,n.yFixed=!0,t.selection.push(s)}})}},N.prototype._onDrag=function(t){if(!this.drag.pinched){var e=this._getPointer(t.gesture.touches[0]),i=this,n=this.drag,s=n.selection;if(s&&s.length){var r=e.x-n.pointer.x,o=e.y-n.pointer.y;s.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._canvasToX(i._xToCanvas(t.x)+r)),t.yFixed||(e.y=i._canvasToY(i._yToCanvas(t.y)+o))}),this.moving||(this.moving=!0,this.start())}else{var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw(),this.moved=!0}}},N.prototype._onDragEnd=function(){var t=this.drag.selection;t&&t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed})},N.prototype._onTap=function(t){var e=this._getPointer(t.gesture.touches[0]),i=this._getNodeAt(e),n=this.nodes[i];n?(this._selectNodes([i]),this.moving||this._redraw()):(this._unselectNodes(),this._redraw())},N.prototype._onHold=function(t){var e=this._getPointer(t.gesture.touches[0]),i=this._getNodeAt(e),n=this.nodes[i];if(n){if(n.isSelected())this._unselectNodes([i]);else{var s=!0;this._selectNodes([i],s)}this.moving||this._redraw()}},N.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)},N.prototype._zoom=function(t,e){var i=this._getScale();.01>t&&(t=.01),t>10&&(t=10);var n=this._getTranslation(),s=t/i,r=(1-s)*e.x+n.x*s,o=(1-s)*e.y+n.y*s;return this._setScale(t),this._setTranslation(r,o),this._redraw(),t},N.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){"mouswheelScale"in this.pinch||(this.pinch.mouswheelScale=1);var i=this.pinch.mouswheelScale,n=e/10;0>e&&(n/=1-n),i*=1+n;var s=A.fakeGesture(this,t),r=this._getPointer(s.center);i=this._zoom(i,r),this.pinch.mouswheelScale=i}t.preventDefault()},N.prototype._onMouseMoveTitle=function(t){var e=A.fakeGesture(this,t),i=this._getPointer(e.center);this.popupNode&&this._checkHidePopup(i);var n=this,s=function(){n._checkShowPopup(i)};this.popupTimer&&clearInterval(this.popupTimer),this.leftButtonDown||(this.popupTimer=setTimeout(s,300))},N.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)},n=this.popupNode;if(void 0==this.popupNode){var s=this.nodes;for(e in s)if(s.hasOwnProperty(e)){var r=s[e];if(void 0!=r.getTitle()&&r.isOverlappingWith(i)){this.popupNode=r;break}}}if(void 0==this.popupNode){var o=this.edges;for(e in o)if(o.hasOwnProperty(e)){var a=o[e];if(a.connected&&void 0!=a.getTitle()&&a.isOverlappingWith(i)){this.popupNode=a;break}}}if(this.popupNode){if(this.popupNode!=n){var h=this;h.popup||(h.popup=new O(h.frame)),h.popup.setPosition(t.x-3,t.y-3),h.popup.setText(h.popupNode.getTitle()),h.popup.show()}}else this.popup&&this.popup.hide()},N.prototype._checkHidePopup=function(t){this.popupNode&&this._getNodeAt(t)||(this.popupNode=void 0,this.popup&&this.popup.hide())},N.prototype._unselectNodes=function(t,e){var i,n,s,r=!1;if(t)for(i=0,n=t.length;n>i;i++){s=t[i],this.nodes[s].unselect();for(var o=0;oi;i++)s=this.selection[i],this.nodes[s].unselect(),r=!0;this.selection=[]}return!r||1!=e&&void 0!=e||this._trigger("select"),r},N.prototype._selectNodes=function(t,e){var i,n,s=!1,r=!0;if(t.length!=this.selection.length)r=!1;else for(i=0,n=Math.min(t.length,this.selection.length);n>i;i++)if(t[i]!=this.selection[i]){r=!1;break}if(r)return s;if(void 0==e||0==e){var o=!1;s=this._unselectNodes(void 0,o)}for(i=0,n=t.length;n>i;i++){var a=t[i],h=-1!=this.selection.indexOf(a);h||(this.nodes[a].select(),this.selection.push(a),s=!0)}return s&&this._trigger("select"),s},N.prototype._getNodesOverlappingWith=function(t){var e=this.nodes,i=[];for(var n in e)e.hasOwnProperty(n)&&e[n].isOverlappingWith(t)&&i.push(n);return i},N.prototype.getSelection=function(){return this.selection.concat([])},N.prototype.setSelection=function(t){var e,i,n;if(!t||void 0==t.length)throw"Selection must be an array with ids";for(e=0,i=this.selection.length;i>e;e++)n=this.selection[e],this.nodes[n].unselect();for(this.selection=[],e=0,i=t.length;i>e;e++){n=t[e];var s=this.nodes[n];if(!s)throw new RangeError('Node with id "'+n+'" not found');s.select(),this.selection.push(n)}this.redraw()},N.prototype._updateSelection=function(){for(var t=0;ti;i++)for(var s=t[i],r=s.edges,o=0,a=r.length;a>o;o++){var h=r[o],d=null;h.from==s?d=h.to:h.to==s&&(d=h.from);var c,u;if(d)for(c=0,u=t.length;u>c;c++)if(t[c]==d){d=null;break}if(d)for(c=0,u=e.length;u>c;c++)if(e[c]==d){d=null;break}d&&e.push(d)}return e}void 0==t&&(t=1);var i=[],n=this.nodes;for(var s in n)if(n.hasOwnProperty(s)){for(var r=[n[s]],o=0;t>o;o++)r=r.concat(e(r));i.push(r)}for(var a=[],h=0,d=i.length;d>h;h++)a.push(i[h].length);return a},N.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},N.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof r||t instanceof o)this.nodesData=t;else if(t instanceof Array)this.nodesData=new r,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new r}if(e&&A.forEach(this.nodesListeners,function(t,i){e.unsubscribe(i,t)}),this.nodes={},this.nodesData){var i=this;A.forEach(this.nodesListeners,function(t,e){i.nodesData.subscribe(e,t)});var n=this.nodesData.getIds();this._addNodes(n)}this._updateSelection()},N.prototype._addNodes=function(t){for(var e,i=0,n=t.length;n>i;i++){e=t[i];var s=this.nodesData.get(e),r=new M(s,this.images,this.groups,this.constants);if(this.nodes[e]=r,!r.isFixed()){var o=2*this.constants.edges.length,a=t.length,h=2*Math.PI*(i/a);r.x=o*Math.cos(h),r.y=o*Math.sin(h),this.moving=!0}}this._reconnectEdges(),this._updateValueRange(this.nodes)},N.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,n=0,s=t.length;s>n;n++){var r=t[n],o=e[r],a=i.get(r);o?o.setProperties(a,this.constants):(o=new M(properties,this.images,this.groups,this.constants),e[r]=o,o.isFixed()||(this.moving=!0))}this._reconnectEdges(),this._updateValueRange(e)},N.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,n=t.length;n>i;i++){var s=t[i];delete e[s]}this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},N.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof r||t instanceof o)this.edgesData=t;else if(t instanceof Array)this.edgesData=new r,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new r}if(e&&A.forEach(this.edgesListeners,function(t,i){e.unsubscribe(i,t)}),this.edges={},this.edgesData){var i=this;A.forEach(this.edgesListeners,function(t,e){i.edgesData.subscribe(e,t)});var n=this.edgesData.getIds();this._addEdges(n)}this._reconnectEdges()},N.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var r=t[n],o=e[r];o&&o.disconnect();var a=i.get(r);e[r]=new C(a,this,this.constants)}this.moving=!0,this._updateValueRange(e)},N.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var r=t[n],o=i.get(r),a=e[r];a?(a.disconnect(),a.setProperties(o,this.constants),a.connect()):(a=new C(o,this,this.constants),this.edges[r]=a)}this.moving=!0,this._updateValueRange(e)},N.prototype._removeEdges=function(t){for(var e=this.edges,i=0,n=t.length;n>i;i++){var s=t[i],r=e[s];r&&(r.disconnect(),delete e[s])}this.moving=!0,this._updateValueRange(e)},N.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 n=i[t];n.from=null,n.to=null,n.connect()}},N.prototype._updateValueRange=function(t){var e,i=void 0,n=void 0;for(e in t)if(t.hasOwnProperty(e)){var s=t[e].getValue();void 0!==s&&(i=void 0===i?s:Math.min(s,i),n=void 0===n?s:Math.max(s,n))}if(void 0!==i&&void 0!==n)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,n)},N.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},N.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._drawEdges(t),this._drawNodes(t),t.restore()},N.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)},N.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},N.prototype._setScale=function(t){this.scale=t},N.prototype._getScale=function(){return this.scale},N.prototype._canvasToX=function(t){return(t-this.translation.x)/this.scale},N.prototype._xToCanvas=function(t){return t*this.scale+this.translation.x},N.prototype._canvasToY=function(t){return(t-this.translation.y)/this.scale},N.prototype._yToCanvas=function(t){return t*this.scale+this.translation.y},N.prototype._drawNodes=function(t){var e=this.nodes,i=[];for(var n in e)e.hasOwnProperty(n)&&(e[n].isSelected()?i.push(n):e[n].draw(t));for(var s=0,r=i.length;r>s;s++)e[i[s]].draw(t)},N.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];n.connected&&e[i].draw(t)}},N.prototype._doStabilize=function(){for(var t=(new Date,0),e=this.constants.minVelocity,i=!1;!i&&t0&&e==s.EVENT_END?e=s.EVENT_MOVE:c||(e=s.EVENT_END),c||null===r?r=h:h=r,i.call(s.detection,n.collectEventData(t,e,h)),s.HAS_POINTEREVENTS&&e==s.EVENT_END&&(c=s.PointerEvent.updatePointer(e,h))),c||(r=null,o=!1,a=!1,s.PointerEvent.reset())}})},determineEventTypes:function(){var t;t=s.HAS_POINTEREVENTS?s.PointerEvent.getEvents():s.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],s.EVENT_TYPES[s.EVENT_START]=t[0],s.EVENT_TYPES[s.EVENT_MOVE]=t[1],s.EVENT_TYPES[s.EVENT_END]=t[2]},getTouchList:function(t){return s.HAS_POINTEREVENTS?s.PointerEvent.getTouchList():t.touches?t.touches:[{identifier:1,pageX:t.pageX,pageY:t.pageY,target:t.target}]},collectEventData:function(t,e,i){var n=this.getTouchList(i,e),r=s.POINTER_TOUCH;return(i.type.match(/mouse/)||s.PointerEvent.matchType(s.POINTER_MOUSE,i))&&(r=s.POINTER_MOUSE),{center:s.utils.getCenter(n),timeStamp:(new Date).getTime(),target:i.target,touches:n,eventType:e,pointerType:r,srcEvent:i,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return s.detection.stopDetect()}}}},s.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==s.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[s.POINTER_MOUSE]=e.pointerType==e.MSPOINTER_TYPE_MOUSE||e.pointerType==s.POINTER_MOUSE,i[s.POINTER_TOUCH]=e.pointerType==e.MSPOINTER_TYPE_TOUCH||e.pointerType==s.POINTER_TOUCH,i[s.POINTER_PEN]=e.pointerType==e.MSPOINTER_TYPE_PEN||e.pointerType==s.POINTER_PEN,i[t]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},s.utils={extend:function(t,e,n){for(var s in e)t[s]!==i&&n||(t[s]=e[s]);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=[],n=0,s=t.length;s>n;n++)e.push(t[n].pageX),i.push(t[n].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,n=e.pageX-t.pageX;return 180*Math.atan2(i,n)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.pageX-e.pageX),n=Math.abs(t.pageY-e.pageY);return i>=n?t.pageX-e.pageX>0?s.DIRECTION_LEFT:s.DIRECTION_RIGHT:t.pageY-e.pageY>0?s.DIRECTION_UP:s.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,n=e.pageY-t.pageY;return Math.sqrt(i*i+n*n)},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==s.DIRECTION_UP||t==s.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){var i,n=["webkit","khtml","moz","ms","o",""];if(e&&t.style){for(var s=0;si;i++){var r=this.gestures[i];if(!this.stopped&&e[r.name]!==!1&&r.handler.call(r,t,this.current.inst)===!1){this.stopDetect();break}}return this.current&&(this.current.lastEvent=t),t.eventType==s.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t}},stopDetect:function(){this.previous=s.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,n=t.touches.length;n>i;i++)e.touches.push(s.utils.extend({},t.touches[i]))}var r=t.timeStamp-e.timeStamp,o=t.center.pageX-e.center.pageX,a=t.center.pageY-e.center.pageY,h=s.utils.getVelocity(r,o,a);return s.utils.extend(t,{deltaTime:r,deltaX:o,deltaY:a,velocityX:h.x,velocityY:h.y,distance:s.utils.getDistance(e.center,t.center),angle:s.utils.getAngle(e.center,t.center),direction:s.utils.getDirection(e.center,t.center),scale:s.utils.getScale(e.touches,t.touches),rotation:s.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),s.utils.extend(s.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}},s.gestures=s.gestures||{},s.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,e){switch(t.eventType){case s.EVENT_START:clearTimeout(this.timer),s.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==s.detection.current.name&&e.trigger("hold",t)},e.options.hold_timeout);break;case s.EVENT_MOVE:t.distance>e.options.hold_threshold&&clearTimeout(this.timer);break;case s.EVENT_END:clearTimeout(this.timer)}}},s.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==s.EVENT_END){var i=s.detection.previous,n=!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))}}},s.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(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),this.triggered=!1,void 0;if(!(e.options.drag_max_touches>0&&t.touches.length>e.options.drag_max_touches))switch(t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.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 s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.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==s.POINTER_MOUSE?(t.stopDetect(),void 0):(e.options.prevent_default&&t.preventDefault(),t.eventType==s.EVENT_START&&e.trigger(this.name,t),void 0)}},s.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==s.EVENT_END&&e.trigger(this.name,t)}},"object"==typeof e&&"object"==typeof e.exports?e.exports=s:(t.Hammer=s,"function"==typeof t.define&&t.define.amd&&t.define("hammer",[],function(){return s}))}(this)},{}],3:[function(e,i){(function(n){function s(t,e){return function(i){return u(t.call(this,i),e)}}function r(t,e){return function(i){return this.lang().ordinal(t.call(this,i),e)}}function o(){}function a(t){T(t),d(this,t)}function h(t){var e=v(t),i=e.year||0,n=e.month||0,s=e.week||0,r=e.day||0,o=e.hour||0,a=e.minute||0,h=e.second||0,d=e.millisecond||0;this._milliseconds=+d+1e3*h+6e4*a+36e5*o,this._days=+r+7*s,this._months=+n+12*i,this._data={},this._bubble()}function d(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 c(t){return 0>t?Math.ceil(t):Math.floor(t)}function u(t,e,i){for(var n=Math.abs(t)+"",s=t>=0;n.lengthn;n++)(i&&t[n]!==e[n]||!i&&w(t[n])!==w(e[n]))&&o++;return o+r}function g(t){if(t){var e=t.toLowerCase().replace(/(.)s$/,"$1");t=Ge[t]||Be[e]||e}return t}function v(t){var e,i,n={};for(i in t)t.hasOwnProperty(i)&&(e=g(i),e&&(n[e]=t[i]));return n}function y(t){var e,i;if(0===t.indexOf("week"))e=7,i="day";else{if(0!==t.indexOf("month"))return;e=12,i="month"}re[t]=function(s,r){var o,a,h=re.fn._lang[t],d=[];if("number"==typeof s&&(r=s,s=n),a=function(t){var e=re().utc().set(i,t);return h.call(re.fn._lang,e,s||"")},null!=r)return a(r);for(o=0;e>o;o++)d.push(a(o));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 _(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function b(t){return E(t)?366:365}function E(t){return t%4===0&&t%100!==0||t%400===0}function T(t){var e;t._a&&-2===t._pf.overflow&&(e=t._a[ue]<0||t._a[ue]>11?ue:t._a[le]<1||t._a[le]>_(t._a[ce],t._a[ue])?le:t._a[pe]<0||t._a[pe]>23?pe:t._a[fe]<0||t._a[fe]>59?fe:t._a[me]<0||t._a[me]>59?me:t._a[ge]<0||t._a[ge]>999?ge:-1,t._pf._overflowDayOfYear&&(ce>e||e>le)&&(e=le),t._pf.overflow=e)}function S(t){t._pf={empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function x(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 D(t){return t?t.toLowerCase().replace("_","-"):t}function M(t,e){return e._isUTC?re(t).zone(e._offset||0):re(t).local()}function C(t,e){return e.abbr=t,ve[t]||(ve[t]=new o),ve[t].set(e),ve[t]}function O(t){delete ve[t]}function N(t){var i,n,s,r,o=0,a=function(t){if(!ve[t]&&ye)try{e("./lang/"+t)}catch(i){}return ve[t]};if(!t)return re.fn._lang;if(!p(t)){if(n=a(t))return n;t=[t]}for(;o0;){if(n=a(r.slice(0,i).join("-")))return n;if(s&&s.length>=i&&m(r,s,!0)>=i-1)break;i--}o++}return re.fn._lang}function L(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function I(t){var e,i,n=t.match(Ee);for(e=0,i=n.length;i>e;e++)n[e]=Ke[n[e]]?Ke[n[e]]:L(n[e]);return function(s){var r="";for(e=0;i>e;e++)r+=n[e]instanceof Function?n[e].call(s,t):n[e];return r}}function k(t,e){return t.isValid()?(e=A(e,t.lang()),qe[e]||(qe[e]=I(e)),qe[e](t)):t.lang().invalidDate()}function A(t,e){function i(t){return e.longDateFormat(t)||t}var n=5;for(Te.lastIndex=0;n>=0&&Te.test(t);)t=t.replace(Te,i),Te.lastIndex=0,n-=1;return t}function P(t,e){var i,n=e._strict;switch(t){case"DDDD":return Pe;case"YYYY":case"GGGG":case"gggg":return n?Ye:De;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return n?Fe:Me;case"S":if(n)return ke;case"SS":if(n)return Ae;case"SSS":case"DDD":return n?Pe:xe;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Oe;case"a":case"A":return N(e._l)._meridiemParse;case"X":return Ie;case"Z":case"ZZ":return Ne;case"T":return Le;case"SSSS":return Ce;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return n?Ae:Se;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return n?ke:Se;default:return i=new RegExp(j(W(t.replace("\\","")),"i"))}}function Y(t){t=t||"";var e=t.match(Ne)||[],i=e[e.length-1]||[],n=(i+"").match(We)||["-",0,0],s=+(60*n[1])+w(n[2]);return"+"===n[0]?-s:s}function F(t,e,i){var n,s=i._a;switch(t){case"M":case"MM":null!=e&&(s[ue]=w(e)-1);break;case"MMM":case"MMMM":n=N(i._l).monthsParse(e),null!=n?s[ue]=n:i._pf.invalidMonth=e;break;case"D":case"DD":null!=e&&(s[le]=w(e));break;case"DDD":case"DDDD":null!=e&&(i._dayOfYear=w(e));break;case"YY":s[ce]=w(e)+(w(e)>68?1900:2e3);break;case"YYYY":case"YYYYY":case"YYYYYY":s[ce]=w(e);break;case"a":case"A":i._isPm=N(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":s[pe]=w(e);break;case"m":case"mm":s[fe]=w(e);break;case"s":case"ss":s[me]=w(e);break;case"S":case"SS":case"SSS":case"SSSS":s[ge]=w(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=Y(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 R(t){var e,i,n,s,r,o,a,h,d,c,u=[];if(!t._d){for(n=z(t),t._w&&null==t._a[le]&&null==t._a[ue]&&(r=function(e){var i=parseInt(e,10);return e?e.length<3?i>68?1900+i:2e3+i:i:null==t._a[ce]?re().weekYear():t._a[ce]},o=t._w,null!=o.GG||null!=o.W||null!=o.E?a=J(r(o.GG),o.W||1,o.E,4,1):(h=N(t._l),d=null!=o.d?Z(o.d,h):null!=o.e?parseInt(o.e,10)+h._week.dow:0,c=parseInt(o.w,10)||1,null!=o.d&&db(s)&&(t._pf._overflowDayOfYear=!0),i=X(s,0,t._dayOfYear),t._a[ue]=i.getUTCMonth(),t._a[le]=i.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=u[e]=n[e];for(;7>e;e++)t._a[e]=u[e]=null==t._a[e]?2===e?1:0:t._a[e];u[pe]+=w((t._tzm||0)/60),u[fe]+=w((t._tzm||0)%60),t._d=(t._useUTC?X:q).apply(null,u)}}function H(t){var e;t._d||(e=v(t._i),t._a=[e.year,e.month,e.day,e.hour,e.minute,e.second,e.millisecond],R(t))}function z(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function U(t){t._a=[],t._pf.empty=!0;var e,i,n,s,r,o=N(t._l),a=""+t._i,h=a.length,d=0;for(n=A(t._f,o).match(Ee)||[],e=0;e0&&t._pf.unusedInput.push(r),a=a.slice(a.indexOf(i)+i.length),d+=i.length),Ke[s]?(i?t._pf.empty=!1:t._pf.unusedTokens.push(s),F(s,i,t)):t._strict&&!i&&t._pf.unusedTokens.push(s);t._pf.charsLeftOver=h-d,a.length>0&&t._pf.unusedInput.push(a),t._isPm&&t._a[pe]<12&&(t._a[pe]+=12),t._isPm===!1&&12===t._a[pe]&&(t._a[pe]=0),R(t),T(t)}function W(t){return t.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,n,s){return e||i||n||s})}function j(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function V(t){var e,i,n,s,r;if(0===t._f.length)return t._pf.invalidFormat=!0,t._d=new Date(0/0),void 0;for(s=0;sr)&&(n=r,i=e));d(t,i||e)}function G(t){var e,i=t._i,n=Re.exec(i);if(n){for(t._pf.iso=!0,e=4;e>0;e--)if(n[e]){t._f=ze[e-1]+(n[6]||" ");break}for(e=0;4>e;e++)if(Ue[e][1].exec(i)){t._f+=Ue[e][0];break}i.match(Ne)&&(t._f+="Z"),U(t)}else t._d=new Date(i)}function B(t){var e=t._i,i=we.exec(e);e===n?t._d=new Date:i?t._d=new Date(+i[1]):"string"==typeof e?G(t):p(e)?(t._a=e.slice(0),R(t)):f(e)?t._d=new Date(+e):"object"==typeof e?H(t):t._d=new Date(e)}function q(t,e,i,n,s,r,o){var a=new Date(t,e,i,n,s,r,o);return 1970>t&&a.setFullYear(t),a}function X(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function Z(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 K(t,e,i,n,s){return s.relativeTime(e||1,!!i,t,n)}function Q(t,e,i){var n=de(Math.abs(t)/1e3),s=de(n/60),r=de(s/60),o=de(r/24),a=de(o/365),h=45>n&&["s",n]||1===s&&["m"]||45>s&&["mm",s]||1===r&&["h"]||22>r&&["hh",r]||1===o&&["d"]||25>=o&&["dd",o]||45>=o&&["M"]||345>o&&["MM",de(o/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,K.apply({},h)}function $(t,e,i){var n,s=i-e,r=i-t.day();return r>s&&(r-=7),s-7>r&&(r+=7),n=re(t).add("d",r),{week:Math.ceil(n.dayOfYear()/7),year:n.year()}}function J(t,e,i,n,s){var r,o,a=new Date(u(t,6,!0)+"-01-01").getUTCDay();return i=null!=i?i:s,r=s-a+(a>n?7:0),o=7*(e-1)+(i-s)+r+1,{year:o>0?t:t-1,dayOfYear:o>0?o:b(t-1)+o}}function te(t){var e=t._i,i=t._f;return"undefined"==typeof t._pf&&S(t),null===e?re.invalid({nullInput:!0}):("string"==typeof e&&(t._i=e=N().preparse(e)),re.isMoment(e)?(t=d({},e),t._d=new Date(+e._d)):i?p(i)?V(t):U(t):B(t),new a(t))}function ee(t,e){re.fn[t]=re.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),re.updateOffset(this),this):this._d["get"+i+e]()}}function ie(t){re.duration.fn[t]=function(){return this._data[t]}}function ne(t,e){re.duration.fn["as"+t]=function(){return+this/e}}function se(t){var e=!1,i=re;"undefined"==typeof ender&&(t?(he.moment=function(){return!e&&console&&console.warn&&(e=!0,console.warn("Accessing Moment through the global scope is deprecated, and will be removed in an upcoming release.")),i.apply(null,arguments)},d(he.moment,i)):he.moment=re)}for(var re,oe,ae="2.5.0",he=this,de=Math.round,ce=0,ue=1,le=2,pe=3,fe=4,me=5,ge=6,ve={},ye="undefined"!=typeof i&&i.exports&&"undefined"!=typeof e,we=/^\/?Date\((\-?\d+)/i,_e=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,be=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,Ee=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,Te=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,Se=/\d\d?/,xe=/\d{1,3}/,De=/\d{1,4}/,Me=/[+\-]?\d{1,6}/,Ce=/\d+/,Oe=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Ne=/Z|[\+\-]\d\d:?\d\d/gi,Le=/T/i,Ie=/[\+\-]?\d+(\.\d{1,3})?/,ke=/\d/,Ae=/\d\d/,Pe=/\d{3}/,Ye=/\d{4}/,Fe=/[+\-]?\d{6}/,Re=/^\s*\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)?)?$/,He="YYYY-MM-DDTHH:mm:ssZ",ze=["YYYY-MM-DD","GGGG-[W]WW","GGGG-[W]WW-E","YYYY-DDD"],Ue=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],We=/([\+\-]|\d\d)/gi,je="Date|Hours|Minutes|Seconds|Milliseconds".split("|"),Ve={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},Ge={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",D:"date",w:"week",W:"isoWeek",M:"month",y:"year",DDD:"dayOfYear",e:"weekday",E:"isoWeekday",gg:"weekYear",GG:"isoWeekYear"},Be={dayofyear:"dayOfYear",isoweekday:"isoWeekday",isoweek:"isoWeek",weekyear:"weekYear",isoweekyear:"isoWeekYear"},qe={},Xe="DDD w W M D d".split(" "),Ze="M D H h m s w W".split(" "),Ke={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 u(this.year()%100,2)},YYYY:function(){return u(this.year(),4)},YYYYY:function(){return u(this.year(),5)},YYYYYY:function(){var t=this.year(),e=t>=0?"+":"-";return e+u(Math.abs(t),6)},gg:function(){return u(this.weekYear()%100,2)},gggg:function(){return this.weekYear()},ggggg:function(){return u(this.weekYear(),5)},GG:function(){return u(this.isoWeekYear()%100,2)},GGGG:function(){return this.isoWeekYear()},GGGGG:function(){return u(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 u(w(this.milliseconds()/10),2)},SSS:function(){return u(this.milliseconds(),3)},SSSS:function(){return u(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+u(w(t/60),2)+":"+u(w(t)%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+u(w(t/60),2)+u(w(t)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},Qe=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];Xe.length;)oe=Xe.pop(),Ke[oe+"o"]=r(Ke[oe],oe);for(;Ze.length;)oe=Ze.pop(),Ke[oe+oe]=s(Ke[oe],2);for(Ke.DDDD=s(Ke.DDD,3),d(o.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,n;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=re.utc([2e3,e]),n="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=new RegExp(n.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,n;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=re([2e3,1]).day(e),n="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=new RegExp(n.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,n){var s=this._relativeTime[i];return"function"==typeof s?s(t,e,i,n):s.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 $(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),re=function(t,e,i,s){return"boolean"==typeof i&&(s=i,i=n),te({_i:t,_f:e,_l:i,_strict:s,_isUTC:!1})},re.utc=function(t,e,i,s){var r;return"boolean"==typeof i&&(s=i,i=n),r=te({_useUTC:!0,_isUTC:!0,_l:i,_i:t,_f:e,_strict:s}).utc()},re.unix=function(t){return re(1e3*t)},re.duration=function(t,e){var i,n,s,r=t,o=null;return re.isDuration(t)?r={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(r={},e?r[e]=t:r.milliseconds=t):(o=_e.exec(t))?(i="-"===o[1]?-1:1,r={y:0,d:w(o[le])*i,h:w(o[pe])*i,m:w(o[fe])*i,s:w(o[me])*i,ms:w(o[ge])*i}):(o=be.exec(t))&&(i="-"===o[1]?-1:1,s=function(t){var e=t&&parseFloat(t.replace(",","."));return(isNaN(e)?0:e)*i},r={y:s(o[2]),M:s(o[3]),d:s(o[4]),h:s(o[5]),m:s(o[6]),s:s(o[7]),w:s(o[8])}),n=new h(r),re.isDuration(t)&&t.hasOwnProperty("_lang")&&(n._lang=t._lang),n},re.version=ae,re.defaultFormat=He,re.updateOffset=function(){},re.lang=function(t,e){var i;return t?(e?C(D(t),e):null===e?(O(t),t="en"):ve[t]||N(t),i=re.duration.fn._lang=re.fn._lang=N(t),i._abbr):re.fn._lang._abbr},re.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),N(t)},re.isMoment=function(t){return t instanceof a},re.isDuration=function(t){return t instanceof h},oe=Qe.length-1;oe>=0;--oe)y(Qe[oe]);for(re.normalizeUnits=function(t){return g(t)},re.invalid=function(t){var e=re.utc(0/0);return null!=t?d(e._pf,t):e._pf.userInvalidated=!0,e},re.parseZone=function(t){return re(t).parseZone()},d(re.fn=a.prototype,{clone:function(){return re(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=re(this).utc();return 00:!1},parsingFlags:function(){return d({},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=k(this,t||re.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?re.duration(+e,t):re.duration(t,e),l(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?re.duration(+e,t):re.duration(t,e),l(this,i,-1),this},diff:function(t,e,i){var n,s,r=M(t,this),o=6e4*(this.zone()-r.zone());return e=g(e),"year"===e||"month"===e?(n=432e5*(this.daysInMonth()+r.daysInMonth()),s=12*(this.year()-r.year())+(this.month()-r.month()),s+=(this-re(this).startOf("month")-(r-re(r).startOf("month")))/n,s-=6e4*(this.zone()-re(this).startOf("month").zone()-(r.zone()-re(r).startOf("month").zone()))/n,"year"===e&&(s/=12)):(n=this-r,s="second"===e?n/1e3:"minute"===e?n/6e4:"hour"===e?n/36e5:"day"===e?(n-o)/864e5:"week"===e?(n-o)/6048e5:n),i?s:c(s)},from:function(t,e){return re.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(re(),t)},calendar:function(){var t=M(re(),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 E(this.year())},isDST:function(){return this.zone()+re(t).startOf(e)},isBefore:function(t,e){return e="undefined"!=typeof e?e:"millisecond",+this.clone().startOf(e)<+re(t).startOf(e)},isSame:function(t,e){return e=e||"ms",+this.clone().startOf(e)===+M(t,this).startOf(e)},min:function(t){return t=re.apply(null,arguments),this>t?this:t},max:function(t){return t=re.apply(null,arguments),t>this?this:t},zone:function(t){var e=this._offset||0;return null==t?this._isUTC?e:this._d.getTimezoneOffset():("string"==typeof t&&(t=Y(t)),Math.abs(t)<16&&(t=60*t),this._offset=t,this._isUTC=!0,e!==t&&l(this,re.duration(e-t,"m"),1,!0),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?re(t).zone():0,(this.zone()-t)%60===0},daysInMonth:function(){return _(this.year(),this.month())},dayOfYear:function(t){var e=de((re(this).startOf("day")-re(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},quarter:function(){return Math.ceil((this.month()+1)/3)},weekYear:function(t){var e=$(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==t?e:this.add("y",t-e)},isoWeekYear:function(t){var e=$(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=$(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)},get:function(t){return t=g(t),this[t]()},set:function(t,e){return t=g(t),"function"==typeof this[t]&&this[t](e),this},lang:function(t){return t===n?this._lang:(this._lang=N(t),this)}}),oe=0;oe img { - border: none; + border: none; } a { - color: #2B7CE9; - text-decoration: none; + color: #2B7CE9; + text-decoration: none; } a:visited { - color: #2E60A4; + color: #2E60A4; } a:hover { - color: red; - text-decoration: underline; + color: red; + text-decoration: underline; } table { - border-collapse: collapse; + border-collapse: collapse; } th { - font-weight: bold; - border: 1px solid lightgray; - background-color: #E5E5E5; - text-align: left; - vertical-align: top; - padding: 5px; + font-weight: bold; + border: 1px solid lightgray; + background-color: #E5E5E5; + text-align: left; + vertical-align: top; + padding: 5px; } td { - border: 1px solid lightgray; - padding: 5px; - vertical-align: top; + border: 1px solid lightgray; + padding: 5px; + vertical-align: top; } diff --git a/docs/dataset.html b/docs/dataset.html index 1847a3b1..e6e8310b 100644 --- a/docs/dataset.html +++ b/docs/dataset.html @@ -2,50 +2,50 @@ - vis.js | DataSet documentation + vis.js | DataSet documentation - - + + - +
-

DataSet documentation

+

DataSet documentation

-

Contents

- +

Contents

+ -

Overview

+

Overview

-

- Vis.js comes with a flexible DataSet, which can be used to hold and - manipulate unstructured data and listen for changes in the data. - The DataSet is key/value based. Data items can be added, updated and - removed from the DatSet, and one can subscribe to changes in the DataSet. - The data in the DataSet can be filtered and ordered, and fields (like - dates) can be converted to a specific type. Data can be normalized when - appending it to the DataSet as well. -

+

+ Vis.js comes with a flexible DataSet, which can be used to hold and + manipulate unstructured data and listen for changes in the data. + The DataSet is key/value based. Data items can be added, updated and + removed from the DatSet, and one can subscribe to changes in the DataSet. + The data in the DataSet can be filtered and ordered, and fields (like + dates) can be converted to a specific type. Data can be normalized when + appending it to the DataSet as well. +

-

Example

+

Example

-

- The following example shows how to use a DataSet. -

+

+ The following example shows how to use a DataSet. +

 // create a DataSet
@@ -55,15 +55,15 @@ var data = new vis.DataSet(options);
 // add items
 // note that the data items can contain different properties and data formats
 data.add([
-    {id: 1, text: 'item 1', date: new Date(2013, 6, 20), group: 1, first: true},
-    {id: 2, text: 'item 2', date: '2013-06-23', group: 2},
-    {id: 3, text: 'item 3', date: '2013-06-25', group: 2},
-    {id: 4, text: 'item 4'}
+  {id: 1, text: 'item 1', date: new Date(2013, 6, 20), group: 1, first: true},
+  {id: 2, text: 'item 2', date: '2013-06-23', group: 2},
+  {id: 3, text: 'item 3', date: '2013-06-25', group: 2},
+  {id: 4, text: 'item 4'}
 ]);
 
 // subscribe to any change in the DataSet
 data.subscribe('*', function (event, params, senderId) {
-    console.log('event', event, params);
+  console.log('event', event, params);
 });
 
 // update an existing item
@@ -82,94 +82,94 @@ console.log('item1', item1);
 
 // retrieve a filtered subset of the data
 var items = data.get({
-    filter: function (item) {
-        return item.group == 1;
-    }
+  filter: function (item) {
+    return item.group == 1;
+  }
 });
 console.log('filtered items', items);
 
 // retrieve formatted items
 var items = data.get({
-    fields: ['id', 'date'],
-    convert: {
-        date: 'ISODate'
-    }
+  fields: ['id', 'date'],
+  convert: {
+    date: 'ISODate'
+  }
 });
 console.log('formatted items', items);
 
-

Construction

+

Construction

-

- A DataSet can be constructed as: -

+

+ A DataSet can be constructed as: +

 var data = new vis.DataSet(options)
 
-

- After construction, data can be added to the DataSet using the methods - add and update, as described in section - Data Manipulation. -

- -

- The parameter options is optional and is an object which can - contain the following properties: -

- - - - - - - - - - - - - - - - - - - - -
NameTypeDefault valueDescription
fieldIdString"id" - The name of the field containing the id of the items. - - When data is fetched from a server which uses some specific - field to identify items, this field name can be specified - in the DataSet using the option fieldId. - For example CouchDB uses the field - "_id" to identify documents. -
convertObject.<String, String>none - An object containing field names as key, and data types as - value. By default, the type of the properties of items are left - unchanged. Item properties can be normalized by specifying a - field type. This is useful for example to automatically convert - stringified dates coming from a server into JavaScript Date - objects. The available data types are listed in section - Data Types. -
- - -

Data Manipulation

- -

- The data in a DataSet can be manipulated using the methods - add, - update, - and remove. - The DataSet can be emptied using the method - clear. -

+

+ After construction, data can be added to the DataSet using the methods + add and update, as described in section + Data Manipulation. +

+ +

+ The parameter options is optional and is an object which can + contain the following properties: +

+ + + + + + + + + + + + + + + + + + + + +
NameTypeDefault valueDescription
fieldIdString"id" + The name of the field containing the id of the items. + + When data is fetched from a server which uses some specific + field to identify items, this field name can be specified + in the DataSet using the option fieldId. + For example CouchDB uses the field + "_id" to identify documents. +
convertObject.<String, String>none + An object containing field names as key, and data types as + value. By default, the type of the properties of items are left + unchanged. Item properties can be normalized by specifying a + field type. This is useful for example to automatically convert + stringified dates coming from a server into JavaScript Date + objects. The available data types are listed in section + Data Types. +
+ + +

Data Manipulation

+ +

+ The data in a DataSet can be manipulated using the methods + add, + update, + and remove. + The DataSet can be emptied using the method + clear. +

 // create a DataSet
@@ -177,9 +177,9 @@ var data = new vis.DataSet();
 
 // add items
 data.add([
-    {id: 1, text: 'item 1'},
-    {id: 2, text: 'item 2'},
-    {id: 3, text: 'item 3'}
+  {id: 1, text: 'item 1'},
+  {id: 2, text: 'item 2'},
+  {id: 3, text: 'item 3'}
 ]);
 
 // update an item
@@ -189,193 +189,193 @@ data.update({id: 2, text: 'item 2 (updated)'});
 data.remove(3);
 
-

Add

- -

- Add a data item or an array with items. -

- - Syntax: -
var addedIds = DataSet.add(data [, senderId])
- - The argument data can contain: -
    -
  • - An Object containing a single item to be - added. The item must contain an id. -
  • -
  • - An Array or - google.visualization.DataTable containing - a list with items to be added. Each item must contain - an id. -
  • -
- -

- After the items are added to the DataSet, the DataSet will - trigger an event add. When a senderId - is provided, this id will be passed with the triggered - event to all subscribers. -

- -

- The method will throw an Error when an item with the same id - as any of the added items already exists. -

- -

Update

- -

- Update a data item or an array with items. -

- - Syntax: -
var updatedIds = DataSet.update(data [, senderId])
- - The argument data can contain: -
    -
  • - An Object containing a single item to be - updated. The item must contain an id. -
  • -
  • - An Array or - google.visualization.DataTable containing - a list with items to be updated. Each item must contain - an id. -
  • -
- -

- The provided properties will be merged in the existing item. - When an item does not exist, it will be created. -

- -

- After the items are updated, the DataSet will - trigger an event add for the added items, and - an event update. When a senderId - is provided, this id will be passed with the triggered - event to all subscribers. -

- -

Remove

- -

- Remove a data item or an array with items. -

- - Syntax: -
var removedIds = DataSet.remove(id [, senderId])
- -

- The argument id can be: -

-
    -
  • - A Number or String containing the id - of a single item to be removed. -
  • -
  • - An Object containing the item to be deleted. - The item will be deleted by its id. -
  • -
  • - An Array containing ids or items to be removed. -
  • -
- -

- The method ignores removal of non-existing items, and returns an array - containing the ids of the items which are actually removed from the - DataSet. -

- -

- After the items are removed, the DataSet will - trigger an event remove for the removed items. - When a senderId is provided, this id will be passed with - the triggered event to all subscribers. -

- - -

Clear

- -

- Clear the complete DataSet. -

- - Syntax: -
var removedIds = DataSet.clear([senderId])
- -

- After the items are removed, the DataSet will - trigger an event remove for all removed items. - When a senderId is provided, this id will be passed with - the triggered event to all subscribers. -

- - -

Data Filtering

- -

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

- -

A single item can be retrieved by its id:

+

Add

+ +

+ Add a data item or an array with items. +

+ +Syntax: +
var addedIds = DataSet.add(data [, senderId])
+ +The argument data can contain: +
    +
  • + An Object containing a single item to be + added. The item must contain an id. +
  • +
  • + An Array or + google.visualization.DataTable containing + a list with items to be added. Each item must contain + an id. +
  • +
+ +

+ After the items are added to the DataSet, the DataSet will + trigger an event add. When a senderId + is provided, this id will be passed with the triggered + event to all subscribers. +

+ +

+ The method will throw an Error when an item with the same id + as any of the added items already exists. +

+ +

Update

+ +

+ Update a data item or an array with items. +

+ +Syntax: +
var updatedIds = DataSet.update(data [, senderId])
+ +The argument data can contain: +
    +
  • + An Object containing a single item to be + updated. The item must contain an id. +
  • +
  • + An Array or + google.visualization.DataTable containing + a list with items to be updated. Each item must contain + an id. +
  • +
+ +

+ The provided properties will be merged in the existing item. + When an item does not exist, it will be created. +

+ +

+ After the items are updated, the DataSet will + trigger an event add for the added items, and + an event update. When a senderId + is provided, this id will be passed with the triggered + event to all subscribers. +

+ +

Remove

+ +

+ Remove a data item or an array with items. +

+ +Syntax: +
var removedIds = DataSet.remove(id [, senderId])
+ +

+ The argument id can be: +

+
    +
  • + A Number or String containing the id + of a single item to be removed. +
  • +
  • + An Object containing the item to be deleted. + The item will be deleted by its id. +
  • +
  • + An Array containing ids or items to be removed. +
  • +
+ +

+ The method ignores removal of non-existing items, and returns an array + containing the ids of the items which are actually removed from the + DataSet. +

+ +

+ After the items are removed, the DataSet will + trigger an event remove for the removed items. + When a senderId is provided, this id will be passed with + the triggered event to all subscribers. +

+ + +

Clear

+ +

+ Clear the complete DataSet. +

+ +Syntax: +
var removedIds = DataSet.clear([senderId])
+ +

+ After the items are removed, the DataSet will + trigger an event remove for all removed items. + When a senderId is provided, this id will be passed with + the triggered event to all subscribers. +

+ + +

Data Filtering

+ +

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

+ +

A single item can be retrieved by its id:

 var item1 = dataset.get(1);
 
-

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

+

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

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

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

+

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

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

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

+

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

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

Data Formatting

+

Data Formatting

-

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

+

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

 var item  = DataSet.get(id, options);   // retrieve a single item
@@ -383,164 +383,171 @@ var items = DataSet.get(ids, options);  // retrieve a selection of items
 var items = DataSet.get(options);       // retrieve all items or a filtered set
 
-

- Where options is an Object which can have the following - properties: -

- - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
fieldsString[ ] - An array with field names. - By default, all properties of the items are emitted. - When fields is defined, only the properties - whose name is specified in fields will be included - in the returned items. -
convertObject.<String, String> - An object containing field names as key, and data types as value. - By default, the type of the properties of an item are left - unchanged. When a field type is specified, this field in the - items will be converted to the specified type. This can be used - for example to convert ISO strings containing a date to a - JavaScript Date object, or convert strings to numbers or vice - versa. The available data types are listed in section - Data Types. -
filterfunctionItems can be filtered on specific properties by providing a filter - function. A filter function is executed for each of the items in the - DataSet, and is called with the item as parameter. The function must - return a boolean. All items for which the filter function returns - true will be emitted. - See section Data Filtering.
- -

- The following example demonstrates formatting properties and filtering - properties from items. -

+

+ Where options is an Object which can have the following + properties: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
fieldsString[ ] + An array with field names. + By default, all properties of the items are emitted. + When fields is defined, only the properties + whose name is specified in fields will be included + in the returned items. +
convertObject.<String, String> + An object containing field names as key, and data types as value. + By default, the type of the properties of an item are left + unchanged. When a field type is specified, this field in the + items will be converted to the specified type. This can be used + for example to convert ISO strings containing a date to a + JavaScript Date object, or convert strings to numbers or vice + versa. The available data types are listed in section + Data Types. +
filterFunctionItems can be filtered on specific properties by providing a filter + function. A filter function is executed for each of the items in the + DataSet, and is called with the item as parameter. The function must + return a boolean. All items for which the filter function returns + true will be emitted. + See section Data Filtering.
orderString | FunctionOrder the items by a field name or custom sort function.
+ +

+ The following example demonstrates formatting properties and filtering + properties from items. +

 // create a DataSet
 var data = new vis.DataSet();
 data.add([
-    {id: 1, text: 'item 1', date: '2013-06-20', group: 1, first: true},
-    {id: 2, text: 'item 2', date: '2013-06-23', group: 2},
-    {id: 3, text: 'item 3', date: '2013-06-25', group: 2},
-    {id: 4, text: 'item 4'}
+  {id: 1, text: 'item 1', date: '2013-06-20', group: 1, first: true},
+  {id: 2, text: 'item 2', date: '2013-06-23', group: 2},
+  {id: 3, text: 'item 3', date: '2013-06-25', group: 2},
+  {id: 4, text: 'item 4'}
 ]);
 
 // retrieve formatted items
 var items = data.get({
-    fields: ['id', 'date', 'group'],    // output the specified fields only
-    convert: {
-        date: 'Date',                   // convert the date fields to Date objects
-        group: 'String'                 // convert the group fields to Strings
-    }
+  fields: ['id', 'date', 'group'],    // output the specified fields only
+  convert: {
+    date: 'Date',                   // convert the date fields to Date objects
+    group: 'String'                 // convert the group fields to Strings
+  }
 });
 
-

Data Types

- -

- DataSet supports the following data types: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDescriptionExamples
BooleanA JavaScript Boolean - true
- false -
NumberA JavaScript Number - 32
- 2.4 -
StringA JavaScript String - "hello world"
- "2013-06-28" -
DateA JavaScript Date object - new Date()
- new Date(2013, 5, 28)
- new Date(1372370400000) -
MomentA Moment object, created with - moment.js - moment()
- moment('2013-06-28') -
ISODateA string containing an ISO Date - new Date().toISOString()
- "2013-06-27T22:00:00.000Z" -
ASPDateA string containing an ASP Date - "/Date(1372370400000)/"
- "/Date(1198908717056-0700)/" -
- - -

Subscriptions

- -

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

+

Data Types

+ +

+ DataSet supports the following data types: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescriptionExamples
BooleanA JavaScript Boolean + true
+ false +
NumberA JavaScript Number + 32
+ 2.4 +
StringA JavaScript String + "hello world"
+ "2013-06-28" +
DateA JavaScript Date object + new Date()
+ new Date(2013, 5, 28)
+ new Date(1372370400000) +
MomentA Moment object, created with + moment.js + moment()
+ moment('2013-06-28') +
ISODateA string containing an ISO Date + new Date().toISOString()
+ "2013-06-27T22:00:00.000Z" +
ASPDateA string containing an ASP Date + "/Date(1372370400000)/"
+ "/Date(1198908717056-0700)/" +
+ + +

Subscriptions

+ +

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

 // create a DataSet
@@ -548,7 +555,7 @@ var data = new vis.DataSet();
 
 // subscribe to any change in the DataSet
 data.subscribe('*', function (event, params, senderId) {
-    console.log('event:', event, 'params:', params, 'senderId:', senderId);
+  console.log('event:', event, 'params:', params, 'senderId:', senderId);
 });
 
 // add an item
@@ -558,144 +565,144 @@ data.remove(1);                                 // triggers an 'remove' event
 
-

Subscribe

- -

- Subscribe to an event. -

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

Unsubscribe

- -

- Unsubscribe from an event. -

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

Events

- -

- The following events are available for subscription: -

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

Callback

- -

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

+

Subscribe

+ +

+ Subscribe to an event. +

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

Unsubscribe

+ +

+ Unsubscribe from an event. +

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

Events

+ +

+ The following events are available for subscription: +

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

Callback

+ +

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

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

- where the parameters are defined as -

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

Data Policy

-

- All code and data is processed and rendered in the browser. - No data is sent to any server. -

+

+ where the parameters are defined as +

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

Data Policy

+

+ All code and data is processed and rendered in the browser. + No data is sent to any server. +

diff --git a/docs/dataview.html b/docs/dataview.html index bb459d9c..1698ffb1 100644 --- a/docs/dataview.html +++ b/docs/dataview.html @@ -2,69 +2,69 @@ - vis.js | DataView documentation + vis.js | DataView documentation - - + + - +
-

DataView documentation

+

DataView documentation

-

Contents

- +

Contents

+ -

Overview

+

Overview

-

- A DataView offers a filtered and/or formatted view on a - DataSet. - One can subscribe on changes in a DataView, and easily get filtered or - formatted data without having to specify filters and field types all - the time. -

+

+ A DataView offers a filtered and/or formatted view on a + DataSet. + One can subscribe on changes in a DataView, and easily get filtered or + formatted data without having to specify filters and field types all + the time. +

-

Example

+

Example

-

- The following example shows how to use a DataView. -

+

+ The following example shows how to use a DataView. +

 // create a DataSet
 var data = new vis.DataSet();
 data.add([
-    {id: 1, text: 'item 1', date: new Date(2013, 6, 20), group: 1, first: true},
-    {id: 2, text: 'item 2', date: '2013-06-23', group: 2},
-    {id: 3, text: 'item 3', date: '2013-06-25', group: 2},
-    {id: 4, text: 'item 4'}
+  {id: 1, text: 'item 1', date: new Date(2013, 6, 20), group: 1, first: true},
+  {id: 2, text: 'item 2', date: '2013-06-23', group: 2},
+  {id: 3, text: 'item 3', date: '2013-06-25', group: 2},
+  {id: 4, text: 'item 4'}
 ]);
 
 // create a DataView
 // the view will only contain items having a property group with value 1,
 // and will only output fields id, text, and date.
 var view = new vis.DataView(data, {
-    filter: function (item) {
-        return (item.group == 1);
-    },
-    fields: ['id', 'text', 'date']
+  filter: function (item) {
+    return (item.group == 1);
+  },
+  fields: ['id', 'text', 'date']
 });
 
 // subscribe to any change in the DataView
 view.subscribe('*', function (event, params, senderId) {
-    console.log('event', event, params);
+  console.log('event', event, params);
 });
 
 // update an item in the data set
@@ -78,131 +78,131 @@ console.log('ids', ids); // will output [1, 2]
 var items = view.get();
 
-

Construction

+

Construction

-

- A DataView can be constructed as: -

+

+ A DataView can be constructed as: +

 var data = new vis.DataView(dataset, options)
 
-

- where: -

- -
    -
  • - dataset is a DataSet or DataView. -
  • -
  • - options is an object which can - contain the following properties. Note that these properties - are exactly the same as the properties available in methods - DataSet.get and DataView.get. - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameTypeDescription
    convertObject.<String, String> - An object containing field names as key, and data types as value. - By default, the type of the properties of an item are left - unchanged. When a field type is specified, this field in the - items will be converted to the specified type. This can be used - for example to convert ISO strings containing a date to a - JavaScript Date object, or convert strings to numbers or vice - versa. The available data types are listed in section - Data Types. -
    fieldsString[ ] - An array with field names. - By default, all properties of the items are emitted. - When fields is defined, only the properties - whose name is specified in fields will be included - in the returned items. -
    filterfunctionItems can be filtered on specific properties by providing a filter - function. A filter function is executed for each of the items in the - DataSet, and is called with the item as parameter. The function must - return a boolean. All items for which the filter function returns - true will be emitted. - See also section Data Filtering.
    -
  • -
- -

Getting Data

- -

- Data of the DataView can be retrieved using the method get. -

+

+ where: +

+ +
    +
  • + dataset is a DataSet or DataView. +
  • +
  • + options is an object which can + contain the following properties. Note that these properties + are exactly the same as the properties available in methods + DataSet.get and DataView.get. + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    convertObject.<String, String> + An object containing field names as key, and data types as value. + By default, the type of the properties of an item are left + unchanged. When a field type is specified, this field in the + items will be converted to the specified type. This can be used + for example to convert ISO strings containing a date to a + JavaScript Date object, or convert strings to numbers or vice + versa. The available data types are listed in section + Data Types. +
    fieldsString[ ] + An array with field names. + By default, all properties of the items are emitted. + When fields is defined, only the properties + whose name is specified in fields will be included + in the returned items. +
    filterfunctionItems can be filtered on specific properties by providing a filter + function. A filter function is executed for each of the items in the + DataSet, and is called with the item as parameter. The function must + return a boolean. All items for which the filter function returns + true will be emitted. + See also section Data Filtering.
    +
  • +
+ +

Getting Data

+ +

+ Data of the DataView can be retrieved using the method get. +

 var items = view.get();
 
-

- Data of a DataView can be filtered and formatted again, in exactly the - same way as in a DataSet. See sections - Data Filtering and - Data Formatting for more - information. -

+

+ Data of a DataView can be filtered and formatted again, in exactly the + same way as in a DataSet. See sections + Data Filtering and + Data Formatting for more + information. +

 var items = view.get({
-    fields: ['id', 'score'],
-    filter: function (item) {
-        return (item.score > 50);
-    }
+  fields: ['id', 'score'],
+  filter: function (item) {
+    return (item.score > 50);
+  }
 });
 
-

Subscriptions

-

- One can subscribe on changes in the DataView. Subscription works exactly - the same as for DataSets. See the documentation on - subscriptions in a DataSet - for more information. -

+

Subscriptions

+

+ One can subscribe on changes in the DataView. Subscription works exactly + the same as for DataSets. See the documentation on + subscriptions in a DataSet + for more information. +

 // create a DataSet and a view on the data set
 var data = new vis.DataSet();
 var view = new vis.DataView({
-    filter: function (item) {
-        return (item.group == 2);
-    }
+  filter: function (item) {
+    return (item.group == 2);
+  }
 });
 
 // subscribe to any change in the DataView
 view.subscribe('*', function (event, params, senderId) {
-    console.log('event:', event, 'params:', params, 'senderId:', senderId);
+  console.log('event:', event, 'params:', params, 'senderId:', senderId);
 });
 
 // add, update, and remove data in the DataSet...
@@ -210,11 +210,11 @@ view.subscribe('*', function (event, params, senderId) {
 
 
 
-    

Data Policy

-

- All code and data is processed and rendered in the browser. - No data is sent to any server. -

+

Data Policy

+

+ All code and data is processed and rendered in the browser. + No data is sent to any server. +

diff --git a/docs/graph.html b/docs/graph.html index f196a732..2c679bc1 100644 --- a/docs/graph.html +++ b/docs/graph.html @@ -2,12 +2,12 @@ - vis.js | graph documentation + vis.js | graph documentation - - + + - + @@ -17,52 +17,58 @@

Contents

Overview

- Graph is a visualization to display graphs and networks consisting of nodes - and edges. The visualization is easy to use and supports custom shapes, - styles, colors, sizes, images, and more. + Graph is a visualization to display graphs and networks consisting of nodes + and edges. The visualization is easy to use and supports custom shapes, + styles, colors, sizes, images, and more.

- The graph visualization works smooth on any modern browser for up to a - few hundred nodes and edges. + The graph visualization works smooth on any modern browser for up to a + few hundred nodes and edges.

- To get started with Graph, install or download the - vis.js library. + To get started with Graph, install or download the + vis.js library.

Example

- Here a basic graph example. More examples can be found in the - examples directory. + Here a basic graph example. Note that unlike the + Timeline, the Graph does not need the vis.css + file. +

+ +

+ More examples can be found in the + examples directory.

<!doctype html>
 <html>
 <head>
-    <title>Graph | Basic usage</title>
+  <title>Graph | Basic usage</title>
 
-    <script type="text/javascript" src="../../vis.js"></script>
+  <script type="text/javascript" src="../../dist/vis.js"></script>
 </head>
 
 <body>
@@ -70,34 +76,34 @@
 <div id="mygraph"></div>
 
 <script type="text/javascript">
-    // create an array with nodes
-    var nodes = [
-        {id: 1, label: 'Node 1'},
-        {id: 2, label: 'Node 2'},
-        {id: 3, label: 'Node 3'},
-        {id: 4, label: 'Node 4'},
-        {id: 5, label: 'Node 5'}
-    ];
-
-    // create an array with edges
-    var edges = [
-        {from: 1, to: 2},
-        {from: 1, to: 3},
-        {from: 2, to: 4},
-        {from: 2, to: 5}
-    ];
-
-    // create a graph
-    var container = document.getElementById('mygraph');
-    var data= {
-        nodes: nodes,
-        edges: edges,
-    };
-    var options = {
-        width: '400px',
-        height: '400px'
-    };
-    var graph = new vis.Graph(container, data, options);
+  // create an array with nodes
+  var nodes = [
+    {id: 1, label: 'Node 1'},
+    {id: 2, label: 'Node 2'},
+    {id: 3, label: 'Node 3'},
+    {id: 4, label: 'Node 4'},
+    {id: 5, label: 'Node 5'}
+  ];
+
+  // create an array with edges
+  var edges = [
+    {from: 1, to: 2},
+    {from: 1, to: 3},
+    {from: 2, to: 4},
+    {from: 2, to: 5}
+  ];
+
+  // create a graph
+  var container = document.getElementById('mygraph');
+  var data= {
+    nodes: nodes,
+    edges: edges,
+  };
+  var options = {
+    width: '400px',
+    height: '400px'
+  };
+  var graph = new vis.Graph(container, data, options);
 </script>
 
 </body>
@@ -107,12 +113,12 @@
 
 

Loading

- Install or download the vis.js library. - in a subfolder of your project. Include the library script in the head of your html code: + Install or download the vis.js library. + in a subfolder of your project. Include the library script in the head of your html code:

-<script type="text/javascript" src="vis/vis.js"></script>
+<script type="text/javascript" src="vis/dist/vis.js"></script>
 
@@ -121,278 +127,278 @@ The constructor of the Graph is vis.Graph. The constructor accepts three parameters:
    -
  • - container is the DOM element in which to create the graph. -
  • -
  • - data is an Object containing properties nodes and - edges, which both contain an array with objects. - Optionally, data may contain an options object. - The parameter data is optional, data can also be set using - the method setData. Section Data Format - describes the data object. -
  • -
  • - options is an optional Object containing a name-value map - with options. Options can also be set using the method - setOptions. - Section Configuration Options - describes the available options. -
  • +
  • + container is the DOM element in which to create the graph. +
  • +
  • + data is an Object containing properties nodes and + edges, which both contain an array with objects. + Optionally, data may contain an options object. + The parameter data is optional, data can also be set using + the method setData. Section Data Format + describes the data object. +
  • +
  • + options is an optional Object containing a name-value map + with options. Options can also be set using the method + setOptions. + Section Configuration Options + describes the available options. +

Data Format

- The data parameter of the Graph constructor is an object - which can contain different types of data. - The following properties are supported in the data object: + The data parameter of the Graph constructor is an object + which can contain different types of data. + The following properties are supported in the data object:

    -
  • - A property pair nodes and edges, - both containing an Array with objects. The data formats are described - in the sections Nodes and Edges. - Example: +
  • + A property pair nodes and edges, + both containing an Array with objects. The data formats are described + in the sections Nodes and Edges. + Example:
     var data = {
    -    nodes: [...],
    -    edges: [...]
    +  nodes: [...],
    +  edges: [...]
     };
     
    -
  • -
  • - A property dot, - containing a string with data in the - DOT language. - DOT support is described in section DOT_language. - - Example: +
  • +
  • + A property dot, + containing a string with data in the + DOT language. + DOT support is described in section DOT_language. + + Example:
     var data = {
    -    dot: '...'
    +  dot: '...'
     };
     
    -
  • -
  • - A property options, - containing an object with global options. - Options can be provided as third parameter in the graph constructor - as well. Section Configuration Options - describes the available options. - -
  • + +
  • + A property options, + containing an object with global options. + Options can be provided as third parameter in the graph constructor + as well. Section Configuration Options + describes the available options. + +

Nodes

- Nodes typically have an id and label. - A node must contain at least a property id. - Nodes can have extra properties, used to define the shape and style of the - nodes. + Nodes typically have an id and label. + A node must contain at least a property id. + Nodes can have extra properties, used to define the shape and style of the + nodes.

- A JavaScript Array with nodes is constructed like: + A JavaScript Array with nodes is constructed like:

 var nodes = [
-    {
-        id: 1,
-        label: 'Node 1'
-    },
-    // ... more nodes
+  {
+    id: 1,
+    label: 'Node 1'
+  },
+  // ... more nodes
 ];
 

- Nodes support the following properties: + Nodes support the following properties:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredDescription
colorString | ObjectnoColor for the node.
color.backgroundStringnoBackground color for the node.
color.borderStringnoBorder color for the node.
color.highlightString | ObjectnoColor of the node when selected.
color.highlight.backgroundStringnoBackground color of the node when selected.
color.highlight.borderStringnoBorder color of the node when selected.
groupNumber | StringnoA group number or name. The type can be number, - string, or an other type. All nodes with the same group get - the same color schema.
fontColorStringnoFont color for label in the node.
fontFaceStringnoFont face for label in the node, for example "verdana" or "arial".
fontSizeNumbernoFont size in pixels for label in the node.
idNumber | StringyesA unique id for this node. - Nodes may not have duplicate id's. - Id's do not need to be consecutive. - An id is normally a number, but may be any type.
imagestringnoUrl of an image. Only applicable when the shape of the node is - image.
radiusnumbernoRadius for the node. Applicable for all shapes except box, - circle, ellipse and database. - The value of radius will override a value in - property value.
shapestringnoDefine the shape for the node. - Choose from - ellipse (default), circle, box, - database, image, label, dot, - star, triangle, triangleDown, and square. -

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

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

- - When a property label is provided, - this label will be displayed inside the shape in case of shapes - box, circle, ellipse, - and database. - For all other shapes, the label will be displayed right below the shape. - -
labelstringnoText label to be displayed in the node or under the image of the node. - Multiple lines can be separated by a newline character \n .
titlestringnoTitle to be displayed when the user hovers over the node. - The title can contain HTML code.
valuenumbernoA value for the node. - The radius of the nodes will be scaled automatically from minimum to - maximum value. - Only applicable when the shape of the node is dot. - If a radius is provided for the node too, it will override the - radius calculated from the value.
xnumbernoHorizontal position in pixels. - The horizontal position of the node will be fixed. - The vertical position y may remain undefined.
ynumbernoVertical position in pixels. - The vertical position of the node will be fixed. - The horizontal position x may remain undefined.
NameTypeRequiredDescription
colorString | ObjectnoColor for the node.
color.backgroundStringnoBackground color for the node.
color.borderStringnoBorder color for the node.
color.highlightString | ObjectnoColor of the node when selected.
color.highlight.backgroundStringnoBackground color of the node when selected.
color.highlight.borderStringnoBorder color of the node when selected.
groupNumber | StringnoA group number or name. The type can be number, + string, or an other type. All nodes with the same group get + the same color schema.
fontColorStringnoFont color for label in the node.
fontFaceStringnoFont face for label in the node, for example "verdana" or "arial".
fontSizeNumbernoFont size in pixels for label in the node.
idNumber | StringyesA unique id for this node. + Nodes may not have duplicate id's. + Id's do not need to be consecutive. + An id is normally a number, but may be any type.
imagestringnoUrl of an image. Only applicable when the shape of the node is + image.
radiusnumbernoRadius for the node. Applicable for all shapes except box, + circle, ellipse and database. + The value of radius will override a value in + property value.
shapestringnoDefine the shape for the node. + Choose from + ellipse (default), circle, box, + database, image, label, dot, + star, triangle, triangleDown, and square. +

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

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

+ + When a property label is provided, + this label will be displayed inside the shape in case of shapes + box, circle, ellipse, + and database. + For all other shapes, the label will be displayed right below the shape. + +
labelstringnoText label to be displayed in the node or under the image of the node. + Multiple lines can be separated by a newline character \n .
titlestringnoTitle to be displayed when the user hovers over the node. + The title can contain HTML code.
valuenumbernoA value for the node. + The radius of the nodes will be scaled automatically from minimum to + maximum value. + Only applicable when the shape of the node is dot. + If a radius is provided for the node too, it will override the + radius calculated from the value.
xnumbernoHorizontal position in pixels. + The horizontal position of the node will be fixed. + The vertical position y may remain undefined.
ynumbernoVertical position in pixels. + The vertical position of the node will be fixed. + The horizontal position x may remain undefined.
@@ -400,176 +406,176 @@ var nodes = [

Edges

- Edges are connections between nodes. - An edge must at least contain properties from and - to, both referring to the id of a node. - Edges can have extra properties, used to define the type and style. + Edges are connections between nodes. + An edge must at least contain properties from and + to, both referring to the id of a node. + Edges can have extra properties, used to define the type and style.

- A JavaScript Array with edges is constructed as: + A JavaScript Array with edges is constructed as:

 var edges = [
-    {
-        from: 1,
-        to: 3
-    },
-    // ... more edges
+  {
+    from: 1,
+    to: 3
+  },
+  // ... more edges
 ];
 

- Edges support the following properties: + Edges support the following properties:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredDescription
colorstringnoA HTML color for the edge.
dashObjectno - Object containing properties for dashed lines. - Available properties: length, gap, - altLength. -
dash.altLengthnumbernoLength of the alternated dash in pixels on a dashed line. - Specifying dash.altLength allows for creating - a dashed line with a dash-dot style, for example when - dash.length=10 and dash.altLength=5. - See also the option dahs.length. - Only applicable when the line style is dash-line.
dash.lengthnumbernoLength of a dash in pixels on a dashed line. - Only applicable when the line style is dash-line.
dash.gapnumbernoLength of a gap in pixels on a dashed line. - Only applicable when the line style is dash-line.
fontColorStringnoFont color for the text label of the edge. - Only applicable when property label is defined.
fontFaceStringnoFont face for the text label of the edge, - for example "verdana" or "arial". - Only applicable when property label is defined.
fontSizeNumbernoFont size in pixels for the text label of the edge. - Only applicable when property label is defined.
fromNumber | StringyesThe id of a node where the edge starts. The type must correspond with - the type of the node id's. This is normally a number, but can be any - type.
lengthnumbernoThe length of the edge in pixels.
stylestringnoDefine a line style for the edge. - Choose from line (default), arrow, - arrow-center, or dash-line. -
labelstringnoText label to be displayed halfway the edge.
titlestringnoTitle to be displayed when the user hovers over the edge. - The title can contain HTML code.
toNumber | StringyesThe id of a node where the edge ends. The type must correspond with - the type of the node id's. This is normally a number, but can be any - type.
valuenumbernoA value for the edge. - The width of the edges will be scaled automatically from minimum to - maximum value. - If a width is provided for the edge too, it will override the - width calculated from the value.
widthnumbernoWidth of the line in pixels. The width will - override a specified value, if a value is - specified too.
NameTypeRequiredDescription
colorstringnoA HTML color for the edge.
dashObjectno + Object containing properties for dashed lines. + Available properties: length, gap, + altLength. +
dash.altLengthnumbernoLength of the alternated dash in pixels on a dashed line. + Specifying dash.altLength allows for creating + a dashed line with a dash-dot style, for example when + dash.length=10 and dash.altLength=5. + See also the option dahs.length. + Only applicable when the line style is dash-line.
dash.lengthnumbernoLength of a dash in pixels on a dashed line. + Only applicable when the line style is dash-line.
dash.gapnumbernoLength of a gap in pixels on a dashed line. + Only applicable when the line style is dash-line.
fontColorStringnoFont color for the text label of the edge. + Only applicable when property label is defined.
fontFaceStringnoFont face for the text label of the edge, + for example "verdana" or "arial". + Only applicable when property label is defined.
fontSizeNumbernoFont size in pixels for the text label of the edge. + Only applicable when property label is defined.
fromNumber | StringyesThe id of a node where the edge starts. The type must correspond with + the type of the node id's. This is normally a number, but can be any + type.
lengthnumbernoThe length of the edge in pixels.
stylestringnoDefine a line style for the edge. + Choose from line (default), arrow, + arrow-center, or dash-line. +
labelstringnoText label to be displayed halfway the edge.
titlestringnoTitle to be displayed when the user hovers over the edge. + The title can contain HTML code.
toNumber | StringyesThe id of a node where the edge ends. The type must correspond with + the type of the node id's. This is normally a number, but can be any + type.
valuenumbernoA value for the edge. + The width of the edges will be scaled automatically from minimum to + maximum value. + If a width is provided for the edge too, it will override the + width calculated from the value.
widthnumbernoWidth of the line in pixels. The width will + override a specified value, if a value is + specified too.
@@ -577,20 +583,20 @@ var edges = [

DOT language

- Graph supports data in the - DOT language. - To provide data in the DOT language, the data object must contain - a property dot with a String containing the data. + Graph supports data in the + DOT language. + To provide data in the DOT language, the data object must contain + a property dot with a String containing the data.

- Example usage: + Example usage:

 // provide data in the DOT language
 var data = {
-    dot: 'digraph {1 -> 1 -> 2; 2 -> 3; 2 -- 4; 2 -> 1 }'
+  dot: 'digraph {1 -> 1 -> 2; 2 -> 3; 2 -- 4; 2 -> 1 }'
 };
 
 // create a graph
@@ -602,252 +608,252 @@ var graph = new vis.Graph(container, data);
 

Configuration Options

- Options can be used to customize the graph. Options are defined as a JSON object. - All options are optional. + Options can be used to customize the graph. Options are defined as a JSON object. + All options are optional.

 var options = {
-    width:  '100%',
-    height: '400px',
-    edges: {
-        color: 'red',
-        width: 2
-    }
+  width:  '100%',
+  height: '400px',
+  edges: {
+    color: 'red',
+    width: 2
+  }
 };
 

- The following options are available. + The following options are available.

- - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + - - - - + + + + - - - - + + + + - - - - + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + +
NameTypeDefaultDescriptionNameTypeDefaultDescription
edges.colorString"#2B7CE9"The default color of a edge.edges.colorString"#2B7CE9"The default color of a edge.
edges.dashObjectObject - Object containing default properties for dashed lines. - Available properties: length, gap, - altLength. - edges.dashObjectObject + Object containing default properties for dashed lines. + Available properties: length, gap, + altLength. +
edges.dash.altLengthnumbernoneDefault length of the alternated dash in pixels on a dashed line. - Specifying dash.altLength allows for creating - a dashed line with a dash-dot style, for example when - dash.length=10 and dash.altLength=5. - See also the option dahs.length. - Only applicable when the line style is dash-line.edges.dash.altLengthnumbernoneDefault length of the alternated dash in pixels on a dashed line. + Specifying dash.altLength allows for creating + a dashed line with a dash-dot style, for example when + dash.length=10 and dash.altLength=5. + See also the option dahs.length. + Only applicable when the line style is dash-line.
edges.dash.lengthnumber10Default length of a dash in pixels on a dashed line. - Only applicable when the line style is dash-line.edges.dash.lengthnumber10Default length of a dash in pixels on a dashed line. + Only applicable when the line style is dash-line.
edges.dash.gapnumber5Default length of a gap in pixels on a dashed line. - Only applicable when the line style is dash-line.edges.dash.gapnumber5Default length of a gap in pixels on a dashed line. + Only applicable when the line style is dash-line.
edges.lengthNumber100The default length of a edge.edges.lengthNumber100The default length of a edge.
edges.styleString"line"The default style of a edge. - Choose from line (default), arrow, - arrow-center, dash-line.edges.styleString"line"The default style of a edge. + Choose from line (default), arrow, + arrow-center, dash-line.
edges.widthNumber1The default width of a edge.edges.widthNumber1The default width of a edge.
groupsObjectnoneIt is possible to specify custom styles for groups. - Each node assigned a group gets the specified style. - See Groups for an overview of the available styles - and an example. - groupsObjectnoneIt is possible to specify custom styles for groups. + Each node assigned a group gets the specified style. + See Groups for an overview of the available styles + and an example. +
heightString"400px"The height of the graph in pixels or as a percentage.heightString"400px"The height of the graph in pixels or as a percentage.
nodes.colorString | ObjectObjectDefault color of the nodes. When color is a string, the color is applied + nodes.colorString | ObjectObjectDefault color of the nodes. When color is a string, the color is applied to both background as well as the border of the node.
nodes.color.backgroundString"#97C2FC"Default background color of the nodesnodes.color.backgroundString"#97C2FC"Default background color of the nodes
nodes.color.borderString"#2B7CE9"Default border color of the nodesnodes.color.borderString"#2B7CE9"Default border color of the nodes
nodes.color.highlightString | ObjectObjectDefault color of the node when the node is selected. Applied to + nodes.color.highlightString | ObjectObjectDefault color of the node when the node is selected. Applied to both border and background of the node.
nodes.color.highlight.backgroundString"#D2E5FF"Default background color of the node when selected.nodes.color.highlight.backgroundString"#D2E5FF"Default background color of the node when selected.
nodes.color.highlight.borderString"#2B7CE9"Default border color of the node when selected.nodes.color.highlight.borderString"#2B7CE9"Default border color of the node when selected.
nodes.fontColorString"black"Default font color for the text label in the nodes.nodes.fontColorString"black"Default font color for the text label in the nodes.
nodes.fontFaceString"sans"Default font face for the text label in the nodes, for example "verdana" or "arial".nodes.fontFaceString"sans"Default font face for the text label in the nodes, for example "verdana" or "arial".
nodes.fontSizeNumber14Default font size in pixels for the text label in the nodes.nodes.fontSizeNumber14Default font size in pixels for the text label in the nodes.
nodes.groupStringnoneDefault group for the nodes.nodes.groupStringnoneDefault group for the nodes.
nodes.imageStringnoneDefault image url for the nodes. only applicable with shape image.nodes.imageStringnoneDefault image url for the nodes. only applicable with shape image.
nodes.widthMinNumber16The minimum width for a scaled image. Only applicable with shape image.nodes.widthMinNumber16The minimum width for a scaled image. Only applicable with shape image.
nodes.widthMaxNumber64The maximum width for a scaled image. Only applicable with shape image.nodes.widthMaxNumber64The maximum width for a scaled image. Only applicable with shape image.
nodes.shapeString"ellipse"The default shape for all nodes. - Choose from - ellipse (default), circle, box, - database, image, label, dot, - star, triangle, triangleDown, and square. - This shape can be overridden by a group shape, or by a shape of an individual node.nodes.shapeString"ellipse"The default shape for all nodes. + Choose from + ellipse (default), circle, box, + database, image, label, dot, + star, triangle, triangleDown, and square. + This shape can be overridden by a group shape, or by a shape of an individual node.
nodes.radiusNumber5The default radius for a node. Only applicable with shape dot.nodes.radiusNumber5The default radius for a node. Only applicable with shape dot.
nodes.radiusMinNumber5The minimum radius for a scaled node. Only applicable with shape dot.nodes.radiusMinNumber5The minimum radius for a scaled node. Only applicable with shape dot.
nodes.radiusMaxNumber20The maximum radius for a scaled node. Only applicable with shape dot.nodes.radiusMaxNumber20The maximum radius for a scaled node. Only applicable with shape dot.
selectableBooleantrueIf true, nodes in the graph can be selected by clicking them. - Long press can be used to select multiple nodes.selectableBooleantrueIf true, nodes in the graph can be selected by clicking them. + Long press can be used to select multiple nodes.
stabilizeBooleantrueIf true, the graph is stabilized before displaying it. If false, - the nodes move to a stabe position visibly in an animated way.stabilizeBooleantrueIf true, the graph is stabilized before displaying it. If false, + the nodes move to a stabe position visibly in an animated way.
widthString"400px"The width of the graph in pixels or as a percentage.widthString"400px"The width of the graph in pixels or as a percentage.
@@ -857,254 +863,254 @@ var options = {

Groups

It is possible to specify custom styles for groups of nodes. - Each node having assigned to this group gets the specified style. - The options groups is an object containing one or multiple groups, - identified by a unique string, the groupname. + Each node having assigned to this group gets the specified style. + The options groups is an object containing one or multiple groups, + identified by a unique string, the groupname.

- A group can have the following styles: + A group can have the following styles:

 var options = {
-    // ...
-
-    groups: {
-        mygroup: {
-            shape: 'circle',
-            color: {
-                border: 'black',
-                background: 'white',
-                highlight: {
-                    border: 'yellow',
-                    background: 'orange'
-                }
-            }
-            fontColor: 'red',
-            fontSize: 18
+  // ...
+
+  groups: {
+    mygroup: {
+      shape: 'circle',
+      color: {
+        border: 'black',
+        background: 'white',
+        highlight: {
+          border: 'yellow',
+          background: 'orange'
         }
-        // add more groups here
+      }
+      fontColor: 'red',
+      fontSize: 18
     }
+    // add more groups here
+  }
 };
 
 var nodes = [
-    {id: 1, label: 'Node 1'},                    // will get the default style
-    {id: 2, label: 'Node 2', group: 'mygroup'},  // will get the style from 'mygroup'
-    // ... more nodes
+  {id: 1, label: 'Node 1'},                    // will get the default style
+  {id: 2, label: 'Node 2', group: 'mygroup'},  // will get the style from 'mygroup'
+  // ... more nodes
 ];
 

The following styles are available for groups:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
colorString | ObjectObjectColor of the node
color.borderString"#2B7CE9"Border color of the node
color.backgroundString"#97C2FC"Background color of the node
color.highlightString"#D2E5FF"Color of the node when selected.
color.highlight.backgroundString"#D2E5FF"Background color of the node when selected.
color.highlight.borderString"#D2E5FF"Border color of the node when selected.
imageStringnoneDefault image for the nodes. Only applicable in combination with - shape image.
fontColorString"black"Font color of the node.
fontFaceString"sans"Font name of the node, for example "verdana" or "arial".
fontSizeNumber14Font size for the node in pixels.
shapeString"ellipse"Choose from - ellipse (default), circle, box, - database, image, label, dot, - star, triangle, triangleDown, and square. - In case of image, a property with name image must be provided, containing - image urls.
radiusNumber5Default radius for the node. Only applicable in combination with - shapes box and dot.
NameTypeDefaultDescription
colorString | ObjectObjectColor of the node
color.borderString"#2B7CE9"Border color of the node
color.backgroundString"#97C2FC"Background color of the node
color.highlightString"#D2E5FF"Color of the node when selected.
color.highlight.backgroundString"#D2E5FF"Background color of the node when selected.
color.highlight.borderString"#D2E5FF"Border color of the node when selected.
imageStringnoneDefault image for the nodes. Only applicable in combination with + shape image.
fontColorString"black"Font color of the node.
fontFaceString"sans"Font name of the node, for example "verdana" or "arial".
fontSizeNumber14Font size for the node in pixels.
shapeString"ellipse"Choose from + ellipse (default), circle, box, + database, image, label, dot, + star, triangle, triangleDown, and square. + In case of image, a property with name image must be provided, containing + image urls.
radiusNumber5Default radius for the node. Only applicable in combination with + shapes box and dot.

Methods

- Graph supports the following methods. + Graph supports the following methods.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodReturn TypeDescription
setData(data)noneLoads data. Parameter data is an object containing - nodes, edges, and options. Parameters nodes, edges are an Array. - Options is a name-value map and is optional. -
setOptions(options)noneSet options for the graph. The available options are described in - the section Configuration Options. -
getSelection()Array of idsReturns an array with the ids of the selected nodes. - Returns an empty array if no nodes are selected. - The selections are not ordered. -
redraw()noneRedraw the graph. Useful when the layout of the webpage changed.
setSelection(selection)noneSelect nodes. - selection is an array with ids of nodes to be selected. - The array selection can contain zero or multiple ids. - Example usage: graph.setSelection([3, 5]); will select - nodes with id 3 and 5. -
setSize(width, height)noneParameters width and height are strings, - containing a new size for the visualization. Size can be provided in pixels - or in percentages.
MethodReturn TypeDescription
setData(data)noneLoads data. Parameter data is an object containing + nodes, edges, and options. Parameters nodes, edges are an Array. + Options is a name-value map and is optional. +
setOptions(options)noneSet options for the graph. The available options are described in + the section Configuration Options. +
getSelection()Array of idsReturns an array with the ids of the selected nodes. + Returns an empty array if no nodes are selected. + The selections are not ordered. +
redraw()noneRedraw the graph. Useful when the layout of the webpage changed.
setSelection(selection)noneSelect nodes. + selection is an array with ids of nodes to be selected. + The array selection can contain zero or multiple ids. + Example usage: graph.setSelection([3, 5]); will select + nodes with id 3 and 5. +
setSize(width, height)noneParameters width and height are strings, + containing a new size for the visualization. Size can be provided in pixels + or in percentages.

Events

- Graph fires events after one or multiple nodes are selected. - The event can be catched by creating a listener. + Graph fires events after one or multiple nodes are selected. + The event can be catched by creating a listener.

- Here an example on how to catch a select event. + Here an example on how to catch a select event.

 function onSelect() {
-    alert('selected nodes: ' + graph.getSelection());
+  alert('selected nodes: ' + graph.getSelection());
 }
 
 vis.events.addListener(graph, 'select', onSelect);
 

- The following events are available. + The following events are available.

- - - - - - - - - - - - - - - + + + + + + + + + + + + + + +
nameDescriptionProperties
selectFired after the user selects or unselects a node by clicking it, - or when selecting a number of nodes by dragging a selection area - around them. Not fired when the method setSelection - is executed. The ids of the selected nodes can be retrieved via the - method getSelection. - none
nameDescriptionProperties
selectFired after the user selects or unselects a node by clicking it, + or when selecting a number of nodes by dragging a selection area + around them. Not fired when the method setSelection + is executed. The ids of the selected nodes can be retrieved via the + method getSelection. + none

Data Policy

- All code and data is processed and rendered in the browser. - No data is sent to any server. + All code and data is processed and rendered in the browser. + No data is sent to any server.

diff --git a/docs/index.html b/docs/index.html index 6f907a0f..bbaf818b 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2,201 +2,204 @@ - vis.js | documentation + vis.js | documentation - - + + - +
-

vis.js documentation

- -

- Vis.js is a dynamic, browser based visualization library. - The library is designed to be easy to use, handle large amounts - of dynamic data, and enable manipulation of the data. -

- -

- The library is developed by - Almende B.V. -

- -

Components

- -

- Vis.js contains of the following components: -

- -
    -
  • - DataSet. - A flexible key/value based data set. - Add, update, and remove items. Subscribe on changes in the data set. - A DataSet can filter and order items, and convert fields of items. -
  • -
  • - DataView. - A filtered and/or formatted view on a DataSet. -
  • -
  • - Graph. - Display a graph or network with nodes and edges. -
  • -
  • - Timeline. - Display different types of data on a timeline. The timeline and the - items on the timeline can be interactively moved, zoomed, and - manipulated. -
  • -
- - - - -

Install

- -

npm

+

vis.js documentation

+ +

+ Vis.js is a dynamic, browser based visualization library. + The library is designed to be easy to use, handle large amounts + of dynamic data, and enable manipulation of the data. +

+ +

+ The library is developed by + Almende B.V. +

+ +

Components

+ +

+ Vis.js contains of the following components: +

+ +
    +
  • + DataSet. + A flexible key/value based data set. + Add, update, and remove items. Subscribe on changes in the data set. + A DataSet can filter and order items, and convert fields of items. +
  • +
  • + DataView. + A filtered and/or formatted view on a DataSet. +
  • +
  • + Graph. + Display a graph or network with nodes and edges. +
  • +
  • + Timeline. + Display different types of data on a timeline. The timeline and the + items on the timeline can be interactively moved, zoomed, and + manipulated. +
  • +
+ + + + +

Install

+ +

npm

 npm install vis
 
-

bower

+

bower

 bower install vis
 
-

download

- Download the library from the website: - http://visjs.org. +

download

+ Download the library from the website: + http://visjs.org. -

Load

+

Load

-

- To use a component, include the javascript file of vis in your web page: -

+

+ To load vis.js, include the javascript and css files of vis in your web page: +

<!DOCTYPE HTML>
 <html>
 <head>
-    <script src="components/vis/vis.js"></script>
+  <script src="components/vis/vis.js"></script>
+  <link href="components/vis/vis.css" rel="stylesheet" type="text/css" />
 </head>
 <body>
 <script type="text/javascript">
-    // ... load a visualization
+  // ... load a visualization
 </script>
 </body>
 </html>
 
-

- or load vis.js using require.js: -

+

+ or load vis.js using require.js: +

 require.config({
-    paths: {
-        vis: 'path/to/vis',
-    }
+  paths: {
+    vis: 'path/to/vis',
+  }
 });
 
 require(['vis'], function (math) {
-    // ... load a visualization
+  // ... load a visualization
 });
 
-

- A timeline can be instantiated as follows. Other components can be - created in a similar way. -

+

+ A timeline can be instantiated as follows. Other components can be + created in a similar way. +

 var timeline = new vis.Timeline(container, data, options);
 
-

- Where container is an HTML element, data is - an Array with data or a DataSet, and options is an optional - object with configuration options for the component. -

+

+ Where container is an HTML element, data is + an Array with data or a DataSet, and options is an optional + object with configuration options for the component. +

-

Use

+

Use

-

+

A basic example on using a Timeline is shown below. More examples can be found in the examples directory of the project. -

+ target="_blank">examples directory of the project. +

 <!DOCTYPE HTML>
 <html>
 <head>
-    <title>Timeline basic demo</title>
-    <script src="components/vis/vis.js"></script>
-
-    <style type="text/css">
-        body, html {
-            font-family: sans-serif;
-        }
-    </style>
+  <title>Timeline basic demo</title>
+
+  <script src="components/vis/vis.js"></script>
+  <link href="components/vis/vis.css" rel="stylesheet" type="text/css" />
+
+  <style type="text/css">
+    body, html {
+      font-family: sans-serif;
+    }
+  </style>
 </head>
 <body>
 <div id="visualization"></div>
 
 <script type="text/javascript">
-    var container = document.getElementById('visualization');
-    var data = [
-        {id: 1, content: 'item 1', start: '2013-04-20'},
-        {id: 2, content: 'item 2', start: '2013-04-14'},
-        {id: 3, content: 'item 3', start: '2013-04-18'},
-        {id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'},
-        {id: 5, content: 'item 5', start: '2013-04-25'},
-        {id: 6, content: 'item 6', start: '2013-04-27'}
-    ];
-    var options = {};
-    var timeline = new vis.Timeline(container, data, options);
+  var container = document.getElementById('visualization');
+  var data = [
+    {id: 1, content: 'item 1', start: '2013-04-20'},
+    {id: 2, content: 'item 2', start: '2013-04-14'},
+    {id: 3, content: 'item 3', start: '2013-04-18'},
+    {id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'},
+    {id: 5, content: 'item 5', start: '2013-04-25'},
+    {id: 6, content: 'item 6', start: '2013-04-27'}
+  ];
+  var options = {};
+  var timeline = new vis.Timeline(container, data, options);
 </script>
 </body>
 </html>
 
-

License

+

License

-

- Copyright (C) 2010-2013 Almende B.V. -

+

+ Copyright (C) 2010-2013 Almende B.V. +

-

- Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at -

+

+ Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at +

-

- http://www.apache.org/licenses/LICENSE-2.0 -

+

+ http://www.apache.org/licenses/LICENSE-2.0 +

-

- Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -

+

+ Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +

diff --git a/docs/timeline.html b/docs/timeline.html index 4bdd9ee7..c2335c60 100644 --- a/docs/timeline.html +++ b/docs/timeline.html @@ -1,12 +1,12 @@ - vis.js | timeline documentation + vis.js | timeline documentation - - + + - + @@ -17,65 +17,66 @@

Contents

Overview

- The Timeline is an interactive visualization chart to visualize data in time. - The data items can take place on a single date, or have a start and end date (a range). - You can freely move and zoom in the timeline by dragging and scrolling in the - Timeline. Items can be created, edited, and deleted in the timeline. - The time scale on the axis is adjusted automatically, and supports scales ranging - from milliseconds to years. + The Timeline is an interactive visualization chart to visualize data in time. + The data items can take place on a single date, or have a start and end date (a range). + You can freely move and zoom in the timeline by dragging and scrolling in the + Timeline. Items can be created, edited, and deleted in the timeline. + The time scale on the axis is adjusted automatically, and supports scales ranging + from milliseconds to years.

Example

- The following code shows how to create a Timeline and provide it with data. - More examples can be found in the examples directory. + The following code shows how to create a Timeline and provide it with data. + More examples can be found in the examples directory.

<!DOCTYPE HTML>
 <html>
 <head>
-    <title>Timeline | Basic demo</title>
+  <title>Timeline | Basic demo</title>
 
-    <style type="text/css">
-        body, html {
-            font-family: sans-serif;
-        }
-    </style>
+  <style type="text/css">
+    body, html {
+      font-family: sans-serif;
+    }
+  </style>
 
-    <script src="../../vis.js"></script>
+  <script src="../../dist/vis.js"></script>
+  <link href="../../dist/vis.css" rel="stylesheet" type="text/css" />
 </head>
 <body>
 <div id="visualization"></div>
 
 <script type="text/javascript">
-    var container = document.getElementById('visualization');
-    var items = [
-        {id: 1, content: 'item 1', start: '2013-04-20'},
-        {id: 2, content: 'item 2', start: '2013-04-14'},
-        {id: 3, content: 'item 3', start: '2013-04-18'},
-        {id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'},
-        {id: 5, content: 'item 5', start: '2013-04-25'},
-        {id: 6, content: 'item 6', start: '2013-04-27'}
-    ];
-    var options = {};
-    var timeline = new vis.Timeline(container, items, options);
+  var container = document.getElementById('visualization');
+  var items = [
+    {id: 1, content: 'item 1', start: '2013-04-20'},
+    {id: 2, content: 'item 2', start: '2013-04-14'},
+    {id: 3, content: 'item 3', start: '2013-04-18'},
+    {id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'},
+    {id: 5, content: 'item 5', start: '2013-04-25'},
+    {id: 6, content: 'item 6', start: '2013-04-27'}
+  ];
+  var options = {};
+  var timeline = new vis.Timeline(container, items, options);
 </script>
 </body>
 </html>
@@ -84,12 +85,14 @@
 
 

Loading

- Install or download the vis.js library. - in a subfolder of your project. Include the library script in the head of your html code: + Install or download the vis.js library. + in a subfolder of your project. Include the libraries script and css files in the + head of your html code:

-<script type="text/javascript" src="vis/vis.js"></script>
+<script src="vis/dist/vis.js"></script>
+<link href="vis/dist/vis.css" rel="stylesheet" type="text/css" />
 
The constructor of the Timeline is vis.Timeline @@ -98,197 +101,199 @@ The constructor of the Timeline is vis.Timeline The constructor accepts three parameters:
    -
  • - container is the DOM element in which to create the graph. -
  • -
  • - items is an Array containing items. The properties of an - item are described in section Data Format. -
  • -
  • - options is an optional Object containing a name-value map - with options. Options can also be set using the method - setOptions. -
  • +
  • + container is the DOM element in which to create the graph. +
  • +
  • + items is an Array containing items. The properties of an + item are described in section Data Format. +
  • +
  • + options is an optional Object containing a name-value map + with options. Options can also be set using the method + setOptions. +

Data Format

- The timeline can be provided with two types of data: + The timeline can be provided with two types of data:

    -
  • Items containing a set of items to be displayed in time.
  • -
  • Groups containing a set of groups used to group items +
  • Items containing a set of items to be displayed in time.
  • +
  • Groups containing a set of groups used to group items together.

Items

- The Timeline uses regular Arrays and Objects as data format. - Data items can contain the properties start, - end (optional), content, - group (optional), and className (optional). + The Timeline uses regular Arrays and Objects as data format. + Data items can contain the properties start, + end (optional), content, + group (optional), and className (optional).

- A table is constructed as: + A table is constructed as:

 var items = [
-    {
-        start: new Date(2010, 7, 15),
-        end: new Date(2010, 8, 2),  // end is optional
-        content: 'Trajectory A'
-        // Optional: fields 'id', 'type', 'group', 'className'
-    }
-    // more items...
+  {
+    start: new Date(2010, 7, 15),
+    end: new Date(2010, 8, 2),  // end is optional
+    content: 'Trajectory A'
+    // Optional: fields 'id', 'type', 'group', 'className'
+  }
+  // more items...
 ]);
 

- The item properties are defined as: + The item properties are defined as:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredDescription
idString | NumbernoAn id for the item. Using an id is not required but highly - recommended. An id is needed when dynamically adding, updating, - and removing items in a DataSet.
startDateyesThe start date of the item, for example new Date(2010,09,23).
endDatenoThe end date of the item. The end date is optional, and can be left null. - If end date is provided, the item is displayed as a range. - If not, the item is displayed as a box.
contentStringyesThe contents of the item. This can be plain text or html code.
typeString'box'The type of the item. Can be 'box' (default), 'range', or 'point'.
groupany typenoThis field is optional. When the group column is provided, - all items with the same group are placed on one line. - A vertical axis is displayed showing the groups. - Grouping items can be useful for example when showing availability of multiple - people, rooms, or other resources next to each other.
-
classNameStringnoThis field is optional. A className can be used to give items - an individual css style. For example, when an item has className - 'red', one can define a css style - - .red { - background-color: red; - border-color: dark-red; - } - . - More details on how to style items can be found in the section - Styles. -
NameTypeRequiredDescription
idString | NumbernoAn id for the item. Using an id is not required but highly + recommended. An id is needed when dynamically adding, updating, + and removing items in a DataSet.
startDateyesThe start date of the item, for example new Date(2010,09,23).
endDatenoThe end date of the item. The end date is optional, and can be left null. + If end date is provided, the item is displayed as a range. + If not, the item is displayed as a box.
contentStringyesThe contents of the item. This can be plain text or html code.
typeString'box'The type of the item. Can be 'box' (default), 'range', or 'point'. + +
groupany typenoThis field is optional. When the group column is provided, + all items with the same group are placed on one line. + A vertical axis is displayed showing the groups. + Grouping items can be useful for example when showing availability of multiple + people, rooms, or other resources next to each other.
+
classNameStringnoThis field is optional. A className can be used to give items + an individual css style. For example, when an item has className + 'red', one can define a css style + + .red { + background-color: red; + border-color: dark-red; + } + . + More details on how to style items can be found in the section + Styles. +

Groups

- Like the items, groups are regular JavaScript Arrays and Objects. - Using groups, items can be grouped together. - Items are filtered per group, and displayed as + Like the items, groups are regular JavaScript Arrays and Objects. + Using groups, items can be grouped together. + Items are filtered per group, and displayed as - Group items can contain the properties id, - content, and className (optional). + Group items can contain the properties id, + content, and className (optional).

- Groups can be applied to a timeline using the method setGroups. - A table with groups can be created like: + Groups can be applied to a timeline using the method setGroups. + A table with groups can be created like:

 var groups = [
-    {
-        id: 1,
-        content: 'Group 1'
-        // Optional: a field 'className'
-    }
-    // more groups...
+  {
+    id: 1,
+    content: 'Group 1'
+    // Optional: a field 'className'
+  }
+  // more groups...
 ]);
 

- Groups can have the following properties: + Groups can have the following properties:

- - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeRequiredDescription
idString | NumberyesAn id for the group. The group will display all items having a - property group which matches the id - of the group.
contentStringyesThe contents of the group. This can be plain text or html code.
classNameStringnoThis field is optional. A className can be used to give groups - an individual css style. For example, when a group has className - 'red', one can define a css style - - .red { - color: red; - } - . - More details on how to style groups can be found in the section - Styles. -
NameTypeRequiredDescription
idString | NumberyesAn id for the group. The group will display all items having a + property group which matches the id + of the group.
contentStringyesThe contents of the group. This can be plain text or html code.
classNameStringnoThis field is optional. A className can be used to give groups + an individual css style. For example, when a group has className + 'red', one can define a css style + + .red { + color: red; + } + . + More details on how to style groups can be found in the section + Styles. +
@@ -296,269 +301,309 @@ var groups = [

Configuration Options

- Options can be used to customize the timeline. - Options are defined as a JSON object. All options are optional. + Options can be used to customize the timeline. + Options are defined as a JSON object. All options are optional.

 var options = {
-    width: '100%',
-    height: '30px'
+  width: '100%',
+  height: '30px'
 };
 

- The following options are available. + The following options are available.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
alignString"center"Alignment of items with type 'box'. Available values are - 'center' (default), 'left', or 'right').
autoResizebooleanfalseIf true, the Timeline will automatically detect when its - container is resized, and redraw itself accordingly.
endDatenoneThe initial end date for the axis of the timeline. - If not provided, the latest date present in the items set is taken as - end date.
heightStringnoneThe height of the timeline in pixels or as a percentage. - When height is undefined or null, the height of the timeline is automatically - adjusted to fit the contents. - It is possible to set a maximum height using option maxHeight - to prevent the timeline from getting too high in case of automatically - calculated height. -
margin.axisNumber20The minimal margin in pixels between items and the time axis.
margin.itemNumber10The minimal margin in pixels between items.
maxDatenoneSet a maximum Date for the visible range. - It will not be possible to move beyond this maximum. -
maxHeightNumbernoneSpecifies a maximum height for the Timeline in pixels. -
minDatenoneSet a minimum Date for the visible range. - It will not be possible to move beyond this minimum. -
orderfunctionnoneProvide a custom sort function to order the items. The order of the - items is determining the way they are stacked. The function - order is called with two parameters, both of type - `vis.components.items.Item`. -
orientationString'bottom'Orientation of the timeline: 'top' or 'bottom' (default). - If orientation is 'bottom', the time axis is drawn at the bottom, - and if 'top', the axis is drawn on top.
paddingNumber5The padding of items, needed to correctly calculate the size - of item ranges. Must correspond with the css of item ranges.
showMajorLabelsbooleantrueBy default, the timeline shows both minor and major date labels on the - time axis. - For example the minor labels show minutes and the major labels show hours. - When showMajorLabels is false, no major labels - are shown.
showMinorLabelsbooleantrueBy default, the timeline shows both minor and major date labels on the - time axis. - For example the minor labels show minutes and the major labels show hours. - When showMinorLabels is false, no minor labels - are shown. When both showMajorLabels and - showMinorLabels are false, no horizontal axis will be - visible.
startDatenoneThe initial start date for the axis of the timeline. - If not provided, the earliest date present in the events is taken as start date.
typeString'box'Specifies the type for the timeline items. Choose from 'dot' or 'point'. - Note that individual items can override this global type. -
widthString'100%'The width of the timeline in pixels or as a percentage.
zoomMaxNumber315360000000000Set a maximum zoom interval for the visible range in milliseconds. - It will not be possible to zoom out further than this maximum. - Default value equals about 10000 years. -
zoomMinNumber10Set a minimum zoom interval for the visible range in milliseconds. - It will not be possible to zoom in further than this minimum. -
NameTypeDefaultDescription
alignString"center"Alignment of items with type 'box'. Available values are + 'center' (default), 'left', or 'right').
autoResizebooleanfalseIf true, the Timeline will automatically detect when its + container is resized, and redraw itself accordingly.
endDatenoneThe initial end date for the axis of the timeline. + If not provided, the latest date present in the items set is taken as + end date.
groupOrderString | FunctionnoneOrder the groups by a field name or custom sort function. + By default, groups are not ordered. +
heightStringnoneThe height of the timeline in pixels or as a percentage. + When height is undefined or null, the height of the timeline is automatically + adjusted to fit the contents. + It is possible to set a maximum height using option maxHeight + to prevent the timeline from getting too high in case of automatically + calculated height. +
margin.axisNumber20The minimal margin in pixels between items and the time axis.
margin.itemNumber10The minimal margin in pixels between items.
maxDatenoneSet a maximum Date for the visible range. + It will not be possible to move beyond this maximum. +
maxHeightNumbernoneSpecifies a maximum height for the Timeline in pixels. +
minDatenoneSet a minimum Date for the visible range. + It will not be possible to move beyond this minimum. +
orderFunctionnoneProvide a custom sort function to order the items. The order of the + items is determining the way they are stacked. The function + order is called with two parameters, both of type + `vis.components.items.Item`. +
orientationString'bottom'Orientation of the timeline: 'top' or 'bottom' (default). + If orientation is 'bottom', the time axis is drawn at the bottom, + and if 'top', the axis is drawn on top.
paddingNumber5The padding of items, needed to correctly calculate the size + of item ranges. Must correspond with the css of item ranges.
showCurrentTimebooleanfalseShow a vertical bar at the current time.
showCustomTimebooleanfalseShow a vertical bar displaying a custom time. This line can be dragged by the user. The custom time can be utilized to show a state in the past or in the future. +
showMajorLabelsbooleantrueBy default, the timeline shows both minor and major date labels on the + time axis. + For example the minor labels show minutes and the major labels show hours. + When showMajorLabels is false, no major labels + are shown.
showMinorLabelsbooleantrueBy default, the timeline shows both minor and major date labels on the + time axis. + For example the minor labels show minutes and the major labels show hours. + When showMinorLabels is false, no minor labels + are shown. When both showMajorLabels and + showMinorLabels are false, no horizontal axis will be + visible.
startDatenoneThe initial start date for the axis of the timeline. + If not provided, the earliest date present in the events is taken as start date.
typeString'box'Specifies the type for the timeline items. Choose from 'dot' or 'point'. + Note that individual items can override this global type. +
widthString'100%'The width of the timeline in pixels or as a percentage.
zoomMaxNumber315360000000000Set a maximum zoom interval for the visible range in milliseconds. + It will not be possible to zoom out further than this maximum. + Default value equals about 10000 years. +
zoomMinNumber10Set a minimum zoom interval for the visible range in milliseconds. + It will not be possible to zoom in further than this minimum. +

Methods

- The Timeline supports the following methods. + The Timeline supports the following methods.

- - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodReturn TypeDescription
setGroups(groups)noneSet a data set with groups for the Timeline. - groups can be an Array with Objects, - a DataSet, or a DataView. For each of the groups, the items of the - timeline are filtered on the property group, which - must correspond with the id of the group. -
setItems(items)noneSet a data set with items for the Timeline. - items can be an Array with Objects, - a DataSet, or a DataView. -
setOptions(options)noneSet or update options. It is possible to change any option - of the timeline at any time. You can for example switch orientation - on the fly. -
MethodReturn TypeDescription
getCustomTime()DateRetrieve the custom time. Only applicable when the option showCustomTime is true. +
setCustomTime(time)noneAdjust the custom time bar. Only applicable when the option showCustomTime is true. time is a Date object. +
setGroups(groups)noneSet a data set with groups for the Timeline. + groups can be an Array with Objects, + a DataSet, or a DataView. For each of the groups, the items of the + timeline are filtered on the property group, which + must correspond with the id of the group. +
setItems(items)noneSet a data set with items for the Timeline. + items can be an Array with Objects, + a DataSet, or a DataView. +
setOptions(options)noneSet or update options. It is possible to change any option + of the timeline at any time. You can for example switch orientation + on the fly. +

Styles

- All parts of the Timeline have a class name and a default css style. - The styles can be overwritten, which enables full customization of the layout - of the Timeline. + All parts of the Timeline have a class name and a default css style. + The styles can be overwritten, which enables full customization of the layout + of the Timeline.

For example, to change the border and background color of all items, include the - following code inside the head of your html code or in a separate stylesheet.

+ following code inside the head of your html code or in a separate stylesheet.

<style>
-    .graph .item {
-      border-color: orange;
-      background-color: yellow;
-    }
+  .graph .item {
+    border-color: orange;
+    background-color: yellow;
+  }
 </style>
 

Data Policy

- All code and data is processed and rendered in the browser. - No data is sent to any server. + All code and data is processed and rendered in the browser. + No data is sent to any server.

diff --git a/download/vis.zip b/download/vis.zip new file mode 100644 index 0000000000000000000000000000000000000000..687e8b81a0b7339e38cf01ba138e178b604a5700 GIT binary patch literal 941597 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

@kYT3AR3>F2juVCv*V%(rHzoC+2?P%RXa z<~EoqYK2oYw=ZC-KKuD+8tIU!v;hq#e_mgkNhNp3%-OP!?Au{>i5mLqNf|e5v?D%o ziRv`wcffFLqg`Wu2U%vD_&v({&iP^UY0LhpDkm;r-OLBu?}lBr6E`~!NRZ6A-38o3 zUv#4=!H;U^5WsMj$?O7dho?wg?uJ?ygCYVn*3j=>)aO36Hw^G@b~>3I=aa0@tlzd= zT{K1kJdLtc-0ErzkP^!DzQMo2BPj$O$S&*ZqgvIA!_oCeO>!qIdwM8bx~|J@1eru) z{Wb>GNT)6OsL5?LmuqnX(pX3!0Bb~E`x1F>w`>$Ra()4MztJ|KJTE2?68k)V1J=tw zUYyUVJ8Zuw99LaoJGA_mq7K?o8?!kY;T2+_E#{Y`>Y%*QLJIgD9?CSfH9$3Ba8sd5 zzJ#_$5j}?dxSW8n4h<7U&Wc||=7N6++~Oau_tm5Tf6oe?MoHOFlcs!AEWjDi!vWxX zhf}7f!!GCERio2grPc{*lA_6!{FsFtk!r4Q1G=bBB*v*VwQZB+8;bwqsXY+NJtl0RHt-mQmTQ^^p z-#>aKgT(+Vs!MwKxrP!Uze3MSn(8M#?r_xO=&S>6k|4887W%PdnJt?r#)9d);T-yM99~&AbibfC&5T$zw zGR#k<$dRy)e+K;(jpcY~KraQwpn*&a?lL@mJd~CXCe>`<>)QO<9}R;!@7Vc3q&N%4 zPtADK*%X{Z1`LnvR^}>w;ch0zTSy0goNo0840I+B^)#rZeW}T&xmL9D4p6eX=^rZEsRPpW!p= z8aST*8~UR!L;>R9qI$LWdJyB(dKZsOw2>e9+shfou1a10fwU8Y5Nrr*>Q|H>$n+bi z8NT6%NOBkv{8VnY5Vsz$BKr+YPCTiIGoI(H-_s`yV~5dRB99CptRAEM=slvLSOXk- z6Hl3i1bcse$aw!iTko!v!*4%nUY;4Sck6K}+FE4w#M1A^Q-r1ZxZn4&yKFhZochC= zHGfGc1v{ueJ-?wR2@Op)V;UNE2=u(6CD$;zCG3I-!IrJ!D2}J-1y!m7UX-p`6_%L<4tE&n}xiV*wcN~!tI7@Nd!e5 z;nwU7baRbd8%6t1r^~+X{yeRsZ?wkd563*-C!Bz7~}Ku2?|?Z7e{P zM2c(BMF43{2A_%d%Q%yXL{ccy7B<+ciiBy7*kZA-Gg40WP*ZWS2!^2|ubC$`yvlY> zTaFZa*M1`LW5U1=GoX`~$^9B<-eFeky^@^PYNKfxsFYlqLa$6_Bl3NBye5%?tQgV) zHXa*;+nzWZ8wdnK;J-Z-!k_;zkcjs#c-5$nYw66b4bAQzJ%1MTFR<4M#0@wqw0XqI zw|^l0Cp0W>5UexA?YEX!mk9*JiAy z(ewDfGiKcv8r`2l2;mLEVD2oRoT%?0J&KPc zbR$5;BfJG9(qRH3RH-XjVO6Ymy&s6EXp=!DY7cqzjC1FAgU)w!sdqdd7`)d}GkTqC zjkY?xzy{AflTZnPLmpi%qG|-sfj^;x+y#2KhPMnlA}=DjLvqcA^_!q#lp(R(d+Dpd z_29?N5#i3US?*oPz7fHJ84{B&FIbe@3Wmzc$E{(3Nyx-f8x7M77{o}R0mN#Lg@;{{ zDX|$r+FU}!QJ&1An_LH}07|jbJG6l{DAJMQdRsy8uhE+si!{KDiZUl(F_pKqnHfPd zv|*khSQdjezEw#NXV>oKj1KVYsJ=YBVzQh*K-b#lg2gX}lInEb!!zSHJ3P6gn_z&`)m};Ut^eW5!guU}v$}P2lnb_U(3p2o# zj|0Vr`?FtHdWg(9c3F#*3a~|qm`L@|Xu1&aGn~${ld_nMvvM5T-`?_F+dz;H{q+9y zr>wD(tThq2%Q(XLsc7h~srCZ^6S%_Yw)sh90bGU#zOc9Pj``j4r>CB8HCTFOH}|#W zFCtqeMDi9yR9CbHNU~otVHrC>%c6*0lZ?K^FoW?m5X314)fgz;Xl+*N6BP{|Ts*&= zenVDOE7v{_s)3N^S1T4{X6JCfOdV^l7i1%eOw_1*jS1}t`el*oyvA~UOR*Y2FNQao z0wtPL#<#i}ofYGYNuky3si^zHE4OW<;x*3CCs3dIu#?;vNJy+Y27LeuUDtX+Lld8y zqv4owDc{lDVysON`pZ2$69`+DEiR^0U>u}7K9Mbh zGE>_L!LApwOZ8euwIfUJl$z^~-D*8aQ(KUc^?9sGuQy?RXm7ALSr1f8T~+WvVn}lq zM}Q@@dD|4*;K$pL)&EgF>?!i`bGY?&U6c2;$xm1&Ast--+ z$z;`yzX)4VG}!1Z9LW5X-7~R~<(Z;@aYZpM#KkG){TM$N%FkhJ3|#+IL+MQ^E)o;^ zyF%m-)bIwvkcGDxr_%ir*B?Kco?hWaQI$Wv`xUM|f2kYnD;>ofcEkINi+P9Zi`(Dt#8wstLvf4UR?$~cXPS?{oGvWw&CIu#MW;vkKg|Izu&9-jq+XS z61t9mmwm3W?-HptOkfdwWmtJO?&kyQ7zLzGn7 z52En$UsT<+7sszM;r%3p71{J<-}n-dayqmDZ-kqcxP@qQ=+6;b$%tWz`~!a2H7N*) z*K|y$58v==G|8*#YuEmDds{S=_~N1h$8Y|1O$!~3Bd`X;!al!Cdv|W{(i~6qT{<8j zc+D@EqNC0U7Qz5lChoP|?2a+50uElKF5YH?@I$~%D5?w#Eelp7!vBU|IXpB=zmHcK z_yUSCB&9480i50`i4SUSD*1wt1`U}Mtd14Q52_xDJEdWlkyV9x=UQWBrBCEk_TC`D~lcK%)$4qFh0QGW$}ytYC#u4UzN8bmByWU}9|O4vQGn?nfJ23B9pwbxEF?(=l*=C zGXN-aAD-ZIKn`g5(xJ{TqrkOMZi^=1@tub7qu=`~v8~Q#7j6UHo|d4xf<@5Q#`4If zD6?{g^o%v1A5QxMGzqbKzr%K7=WW;J2|uECwfHS`pY#vzQHpP`2U=^17m}XKT9*C> zd(KQloki&|Unas@=G)4>yqDR2$pD;^Iy*SH*+!p1r)Jvlci%rzhO`naM)VC)b6?NK zp;Rg^WC`{|KnbR^(E3K`=(Im#l(`W!KRsm|b%EoDf0EG4&@G%K!( z(Zy0itw;Tm*#P%&vu&=JGYWE;PR3-WrKj$E|(fs!fXtk};CgDPT`i%Gp=c_3LEutJjbrm3UFm z4LtN@PJ@g^BrMfh1rYr7i>pyF_jzPl^pRrsY=Gz+uzc$one~j=`aae&W9z%ux) z#4}}Gdue2Z1Jj3Z0KV|6kG*ZRwR-umqNeR+kVxh4Tw~8rOYd2ekMM6D5`SKAZQ-;$ z@*wjXzXljM5r%u1eGfQ^mYmr@9kT>u_CWx4b2-I&Ao=$M_}%!BLkUE?h++fg5mD`p z8OKJZBxdg7#We9>ACeP^=aAq+k{U$~k)c^2@uJgTVpXAO(yABW*}-+_?hNT;x14Pv z>9lKSGO`|T0T9P*bb$=w$dSU!g7?4Q8<%h8T_#dfFB~`_%7GDGp&vI#BHmuFspfcGdW+|?tA0))Ywo@ z)3*H5dnQF3Sn@WkJ>&=3Vm4bEUg>N$85<6UI8swbY%;xHFh%ml$KA>rL4~RpJs=7j zU-%o4jagL`*|%#9A{dUE~Kdt%?!hgd)etU%fnqC-lhpjzm zame*LnB0tgxFMyT8vpl0ZNCe--AGryD`7d>oPhJF|1c!o(lll`%x0upg2Q+Vaqz{P z5~f0r5Crf}B%(gr>d1y9nUF?CAOeddTkr?%xe4t_aS^B=G$DC>UM}G^Fz+W9f1fWY zWy^;nS<{H-53=<)OtyYU+kFYZA^FScNJYSkp^>HuI%TUCMImwg7Wf)~z(1FAq~2_# z=L>t9T*QA1^NU;xgeR0Lcn_vQ4YLb0J+h~OjjBYyiL+wa9NU^bpXvs|S6s0ASi{sX zyCr(0leapXL=L;{*JaC2g?Yqki_%L~jNb4=Tz4d>?f7}ow%`2d)wi7V>|o!gu%qf+ zwqr8G_%tZs-^bZn@dvU%1qTB^655ZRL!E}J8{BV`PD9fCd9w~Qeqr2{Ne|kEd&c0k z`(DBTyDuCe_?KT)qLpQFeY$?!fP-7qTr?6EUx6o9=+7I1446kxFXox%I#Q0qZ?CS8 z9JpY8^5o(hpoy3+OUF)KI#fa%;ZTXfhIu}4?~N16Q;wzC*UE#;y*Ux$co7^u2a+!8 z_oXA2m^Q(^Dp&n915ObxU&NT8$on(Y~Y29c<)~*7rXxDOlpXx+Dfe z1MySXM7ou_pP1y_YIo%wSf~_Lxok3qeXTNgS4U2ts=s<|&N*)8%3Upa58SWA`9*cs zHz~>1kx=!QvVJki8X4^MI1LN8-{gG^25!3rI;h3xk$YL)E?!&NbbRJxl$j5=+TC4Q zNrd4FKTndgc>E^*6|@uX5w*QUStW>N)7Yx?W8+*4?mg1d8igmFfq2Rhq{GSV)G=Pz zF?f|L%;7!5IR)tevzf7Fz#=y$csqEUAPCv@e2S5+GCNhhe{q!4aDtf!mV~2+l*Mff zW;!V+OF~5)csF0TNBdS(T{_a(gtqWH`1{)aVGhaP99fzs^|6p~mY<*3C#(go`Iq>M zaDMT^*csvn7S5>%u5r5IY-yCC2`THZblij=UK1IOwiMjqk0}fzJ3_}2zNYGlN1~#5 z8LXYbms(R4#>D0W6K5ZJ@+`k9n+$2F$KRD14g5f|b$DFP6pJeWkvs4CGUe7pJe+ z?=0mvGOfd`cRX78f+=58C0U#JZ&*)j)D@aQL&O!%I1mJ0>9%AaJ|+MI{5Q;*L`f>) zHNs$A5dLt=@$?<;E3X{LZPRlFlqUeSJ)aU@9r(F||9oS*KzRst;|M$ID3A$4>?~-D zZ`wA3_e;4>naszGpj|PJn{lCI3o-i+cg&E zcEg_PlKL1#j81JE@=wg79rxR1w>Q|M2R<69>>+PIZvIP*aoK(VVk+i0xA8?)j*uhB zxuNUad2;_>(4gi7VEP*$0=6yG6}s$tF}$7w-Wj(cvmqEhkvIW26Z%(*7`iu1in|hFQvkNo3>wO zdhgx-tKpEg>`LWC&7KRqggXsQjtfWRlM|A*n>sS`MR^QCQ;*Ed0*57@5C8zh3MF82 zc!46ox=IDzL3kYdkcx70K69_^^0FLZZts)4a_ostgh|4e=z`u4F4lde_0-b}FAgt| zrMyzaa^CE7eY5*bO?JW-ceCF7s+S%5#~xIQO?sb{jx(j;^b6Z=)FCDHoa?ll-SwR7 z)tv9H=(N!QXd|}`6Ax~wZiGcXVz++~^>Ah6+82NQe zLyX|4EeNX)(E-~__W|Cnp1?Ox*vGPFsdsKOxMmF4eeBg;>#yBa=_4(Aj_F@f@^0mC z`PJRKUdn-Q)dfoKp##7@q@?Sc5cu$OC0I(H^S)~q)hR2Sy>!NZnxzM^FC4!}WG*`< zGZ6R$ESCj24UwF0R8<*>XihOUapk+zGcXTb#69)4Ls3(Bu)?VJuLimc*bYnj+ksFh z7*-Z6H$9$#XVT&sKcY!Hh3>gweYLR{3=*-}zKwr#E z@Lhnv`g_qmz-n%?=2n>#qkI*>ddcOY9QJQlb^+=9RofeKOofH}9sCP9s) zgC6w*PBNU0>IuWK!_Ri;=(DYDmA})m1%rp8DROtmLBt{i2R^(IAT~M2IEy2lVqMo4 zoS4=38Qm$<9H0>;3>Ai}gh`X`bU2^QJ<7&>M^NV8OZYdzgVC)EiUKMh%2GBFe8p7Y zq7MS>KR*bnJOCN2qb~x{Q7tZc@KMz9OLvl+Y`W4G!PdK%7CJI|ZpblajuxiNS8T#B zdi`t+Yz?ck@Rk_?-I<%wK~#zl;D#Cja@P4 z5Ep~-N+2@f`wvxsVf3wbcd6a7Tw;1mRUp*aDqFyUS|h~E&J{Z_mWXr?fF7Fv~}3!!z*6=(qF z8^SWswKj^nqU|~1SVs_%HluLzFL6twKXtf)Zj}iqKVot3_4bM zCvHX@&~A3Htxa1H=7$C{p%vdNkSPKB!GP@1)4z8HGK1_k12VsicLp-)su9Q%03&S@ z0MiPe(k_BeOJ-Vak}=AuLE9#v6hV>Uwqi(uznfhe+Vw?ZLriIFk^My$6z_&G9a|lR zYno!Bi!23tw9u>kJU$-8%rAvem9#VzrqHf6;0hG*d~p&klYG6uK8hUl`fP%w8?TUo z410;z%rpxR8l*z*pFl)XyCvp@pVV$iBJTip?3gj^h&ZmtHa}qVZV!W*+DsraVZYzk z3B+tf?~=uS3^v2(Fr&b80thV@C)gj+s$U#lMl~uS>b#Mg+Y@*t%ipk* zZcjzrs)>=4ioJ$r7V-^c-tfBA7R=(n)MlXdZ}>^|lF1!}d-={g$jXlmcMw`NF&8a6 zh|O-kgSg;^9prVypN`_Yd^0bCE4^AY}o4G`vH=I27);PJBKBGc8Sv2`?j~C)E6=-`s{!Z*3fvtMIvW`dj)3JvlZ-d`cSQ`)h+{8DtV)k zFegjwW#4#0xWP%lYAHO*DV=EI3X%3*|DAMnOcUS zVsmKp*KpNf^u9Uo_Seo(DE=8eV|K3jasV9O~Xz=^no zQ^t_229Y3_(If%0>4-yZaDtJHP8q{(KmavyPcY$fJNY%#hfPXtQ`}}JX7lT{EG1nM z@9z*tjra44YjU&$#TBV|CqW0_#vKHA+T7M!$ARanM1Vog`8aRN&HX#|TD@6VJ@_#x zZ-E?Q8(aXodbo2_*y6Wpa=!Wc|03Vj8#-S`J8`ISUnp$4DO%&Zn5_AMB5*sP{_yd) z(+m1nMBz@)q}?~lZBbG#r;ugfEG)CjV{^;~rK~kJQ=1^z+f44xCq_$mHD5v`$!V3(Q*A}Q-g z4@vdkBRM2<52zt&X~RyF4LZZLt~f+KNJUB6S|X}m@%K$bCD!w=A)yiz`GbP`uoRSR z`R|#4f;If6=qHr|ju-i9w`D=i#H<&^Bwvtf*XaiT4h| zO|c7w>ax;0sc2+{7su6TQ68(v6<`MsD|r)cPEn>P#|Y_fN=3d@>M`o5os@w9K8BbH zvJg<%5{?zqfbxE*!1>s`REcOIEzemP9K=7+hA<0o^>R@bZ#lFKlg+i+hmmPUmdc7fpF4Kmq{ zO`O775J@su<=}}zz-Ze;lO!2Su&YB3YD#rEAm3peCe-6+i2OU7K7)OD6wYEZ}+J=_|2h)}j7~1$9kAOqZyxDe6V# z;pSazq6C2C3qvQaAvfq=Kx|_TYfKn975On81{ulGdi9!1uR9#jTX=Kd$;uuTc6u%G zO6$y%-j^(sp=~&?FwZeue1hqksv?b-%uUJSV58>J;P%r7-{*hPB^=`y>G8 z=G#JFMBFf&Vg&Pigyy^W<`B+0zF02Z7r1MJDO}+f_?4%J0}Y7-_?#h$|Ge*5|LyEh zK5}RHRpBV?FHFU(fWa|9Xih?VYzd|q;`jd+*3Z@aCO<9y+eAjydT-G-k>5jK5WG^U zhZM|yYtW1sobIi_6TMK8kf4rog_?k|`LMyU+>jGdN&T`WaVu19!madA`ql{X7oe^| zVjil1O03|!d3yfe%{$KiyZQT=`^CIA^Y7*!$6zNA%N}e{^V8gf@l~wC5o;e2Z?B~W ziF{Km9OgflV`tyF=_!&TFF}B#3wDG-zeHEO@=TWXkS@j^-t8lw*SB_P+w<;jVbfZ302A~Scx z(L~|SpkTxu{&9Jl71P

Dj;sMlUhDTb|uUG;~{oVZ(&cRL8M@eHe2)`wS6hG*QA` z5I=M+Q&B@}UU&`9H1QKKlzd(i>eGJEv;yjS+B_uriO!czI4Qv;347u5lg06q?ue<= zQ+>{RzM{LUKaY%{EJD5<%DLmM#5@J>d?lCN?_}{o?qmvKevoHBnFFE9Aa2P3V&Tpf zOK^Y$8uvwhk}t~edL>>ilD%TL@AASlJb@A%_c}Qb|NeBIMe|#ce8l|tF`jwr5liYi zj7{YGbvI(%;Y!4|8q@6QvN#8(9x_n^k^y5L$ElR=bA<%xf^yvilG<@u%_sTFP0xXU z4n2`^2u33%2@7T(VP7wl>Uyn$a6&vZc~7BtB}ZkulWuMEhT!~$4UF&aRF4Aj(0NZj zU^sLhA<&}uw464g^#U%>oCp?-O?(WrzB~94;7RbVum@)Tl> zj|xy6^2c=eaV$E|7pLXa2TUh7qyu%4f=M1``$2H@xg&Jl`5b2VwgR;g$CkfVr|f{S zpv{LhKgyT6pe)=%_<#UotlNAA##|bho1i=UnPa<8(X4Yoq21{ZuZ9g0sN&>%Zt}gF zI7m?Kz+opxjxC;=fM0-3nA}E z&_9O_I!k+` zT6BRNrlEy=F}ng_;(QD6g@VeA(xnz&s za+gF!Qw^Cty)?ym7e>BZKpvUtniR%BOPtImZc4Vpd|_U~HC6`in#&lglJHhm%1=e7 zaUoZ+JDm07FlT}X9*#839-hr+RYCj)z9egV>+@^0?d}gAWDi3H_VD0)M5A$)wSBz+ zU6N3J=IG$*bbLekwj5vN6GM%4*c5yO*N*%EY9U)3Y{-B_j`@5(DMxr!T=Ck@_)6$* z$^#ti6+75==#Eo(bX~A{;MaEj+_<6`QWwZ_KYQ@t>NHP@U#-hrH)V;7LxjgrVllM- zJj1#UK$e$9;bS-`RZmZdCL>rgh0I?E*T=!$hBKz8XR{f{6SNc9?>qsfyVef=4b_v= zeqjdxi4zmS%PQ#P|4-BYG~KPWQ17VbV{S%kVyRm*BlaG+( z1F%yndYz&v=xEL)^~2Ts?>)Oip{_J3g%+uEKwB zT!pU^uOgU)|D(1Fd`ZLkmiw#y9?om4b5@aT zZC;UXsZQ!0VYZVE`VoKX4(UlgSaOnZD>*J$+L7BI>xOw+x^}n0egLdBq{wNHc~l>j zPqQCxkp>u$?Gh*_w^bBBMdL$9HyGK(?=S-ik=5k>9*9kaWDp6L7k63ltjJSC0c%hr zC{?1x)r#fG{4@kPhi$=0Sxm-|iL>uVcC@YjF~kZ_F#$xcbokSFqO*H>kNFY!6^KFn zBrizswTKGU-RNv~xqDWQ3$Su2#=Cq7yClLKs}!9DbZ?4P)yFN`PNX<4jVcTy%ukn# zm0LVEcvX%$i#NW3BPIY7WynI^r=fibb;)JeGw!z(PG^o$vL5=Re0DR%Hh1j~9{G8+buh68iYmfMzrg$6N97J^VZ3A1*f zZl1)9QUN7}?&wV|_|XoShlaGN$|8gzN>(j z{c|&vY-XH$2UD&fXTx&su*ogEAYd2!%)={}X)0{Tos%huNPCfxP$4qiE4K`FK1fU< zKzvX-gl0Y+gHDwoUo_GFCrleuOW`AJhhq<@02?;@xyJgYPz_k!kw*y5pQmSQ(^JK> zxZa9R^gux& zY2Y^-d1md-!GkbcK-N2@Tl+x7k^t2ZAT~$}o}IC#kBShXG8Fh}m|^{8LCmb*8H6Kr z4L_+6RiXi_A-eD=y(J1{Q8D6DQ)k`nNX{KpJyksS=t0?JRkcV&0Ch9)(wLq0dwB4N z*##dwzioKx{CgO2NE6jZWaLBy@!1Q&mV_hmv@tUlTPnRRs}khqjwQ&qQn_JR&Tigi zv+;5eL+-}Be9=Y&X<)L#FkJCu`(`oG9$;1vq}L?40H3crxlMIx_<50R}BcK(!} zx3!()6Vu)~RM||vOZt$SgqJ>VAO>!c#0G-cHSx+e#BX){Lr1O{$b?ZN>IZEScsIm& z;MfssWTsa@WUCzMO)}wd2SHX0<+3U!Ct+WRthp;q363d_R7B)j!k5v$KKl z(!u+=SqXBsWd@vD>6lsIjDmpjTn)A5=5KVQ;io6qIhr`XWlt?LPTM(KjNuFov5Ujc zvMGcsyUbU>lbp&+Q%=Y}!}bpwVf(M;QsYA^ft$4zA>~gHlhmh$O;mFvLj2VpN9`uq z%FTBHQ3}qCLPD0)zWW~$$x$H4jOV7YBi;W7Oe@g*=rt#BumqU-U4a8yXFD)9h=L5t zylYTgXt-3Pv9+^K%}o$yy)Oddb>P+Q5K&)zkFHx}QXOM6T3GfF^=kzcZ*A5dlQN1k zmlP(iCEvazM&4TD`fKgT{hKH@k)bxPIgyr$r`-E_c@{&*^?`HfiITj)P15~jVGwA* z*N8UWdTp3-RUIQkw}}3m%Igzo&;dlABfRBYTJsHOK=s;xhiHauL7M%7*Xdd-HE8q& z4_l2sej~AF!W&t|sbjAvo{XP1ieC-)G|5MFwjkd?%Puc+sDe$bS;tyX7rv;nf*)P? zFIlqe?`3h>I0XKlxK2r-0k&x{J>XeHF$wJc7!QPtsdov->*ng2tx3^SY8PqW5pkgn zJjmm78Jf{*p2T%}i!UPZx#LC7A`-%iCE9)meY;or>9`7FyLtmyS3lg2aQn@M`0a2n zJ?y&O3>4yy6}&iu`@3!t*zW2w8aK$j!sEmy!Oq|o!Cd1F3Rl^%MPMrJ_b0*YNhAe^ zX}$3pkSB5Hn|Zz3ZI^EeZqHm``&5ujn4YL{9R(4|3!We4xb8_^pOhMF+gW)FZrB^| zu<*lj_WyzSr|+$nY4hq6j0pF4njplA2xlk9mYN#bRX5EmQr5iFyy$*KQ!|$?HM@m4 zb=4;L&4of439m@k=5FG#Xq@=eS>u!n#K1B%eACE~wQgs=s0Uq$7oS`(uOV2ktc%8_ zRq2yeR~DjTbzHUT!&JZsEF6{|c}bX$<2Rcw7qiL4+cE6!aeLACrg;AF!R8`tiC zTG;2rxwb@ou21QYIMAs$&=1?-qEGg%+Zdq|p@G8&WnWO5LZti|2F&3N+F^q!Am}H6 zk-#3c1oJP8c=vs}d>0n{#Cc|XKJi)0-=q?R)wZYLwv9Ge7#9<tzz0;A*PFSvMjyDgRIiGO+d(Tt;Q~=R#^0AdDGjko z6t~WQkbr&ui%Q}4Fu18oA0`NjhB?u@8ORr~S|DA3FMYG6W)UR&FjwfiY1M6@i)no* z`PML4BHZ2?>#?4aO^HaMvOX#WFj&@PQRL&5h<~@c3C8S>oP|0rQrueJt3EH5&hfmg zT#jdU&x^%;7M}FaD!Kgvy2jpF`g}b5Cg#QhhAIm9su(fLWTL8aJ~CLf-d?DvDkfo zVFyv~Yx>&~TULZ+5UsI_quY9q#I+loOJmn=dd}go9f+nhdaD9-0N%9=hwSuf1%2M^ z-Lh(GY7bnoyh6!mZIe0O{E6#6v76!caGqVzJ5A<1e}nS#;^d?pfuXrnY*G=W(s>6d zyhAeuj!+TlThyYD1*Xs3CsqYkKh-liXz-ukqDr`ygA@W@lF4D&x%;Zxt+kqrGwuLgQAkqgk{`WdHT6Zco~#t-dj+S&g^Et+30E zc$-sk1lNsHE^f$0V2_}J-ssZ%uZmGjOS^4BU89g>(>%MCunw*{ET?V{Fq-iFtY?h+ zZJnB1nM^cksnNK`TFAw=x!7^m7=+XyLyXt5+uXtJ?7XZhpbASiz}5iiI7!vG`7yek zEl`PD0^rso)9!$L{@jfkj_X@EpoI*ix~6{kz(P~`qeqpGLV)sJxt&fp6GxRy9a*`& z3N^=42tNb!PPRboSZ@NK8`}Vu@J+Oh`&9eL6cyr?peBU5fvy}y zO;7xotoEiwF&34>hD1vXTORm)qR)vp(@j3tmhTF47=@~UkU@+D`pWZ{?}g_NSG$>M z&cFjnL_j6zq&6z1UKZHJbRz@oK#fE|qOdlUc}Bxto1V*hS*=h14qfwkx7>tCOmS$e z(I6&XK3YPwAB@9jO)8rWvyLO#h6l0=w-8pS=Hu@Fy$ED2^RY%G(i)?}z>j9m0fsfQ z;0~>-`YmPPy^I|G~>NS~Qo$6D$r8T4p0d{CT6nVs?n7ar&wVTu*S;*AWfIp5xFpV4y zjx3x;gmjoa#&3pVID}{8J3xOo_y}O(QE*A#qff(8{Z^UY?bn9BOcn26){r#Yp-F3& zD~Q#ar`KMAbRS|H8+Ktcwm0_x4?xrfz8N>@BUp;*q~lt+7cwf2x_D^}zt@@w%M06W z39)%}*gBd!+$M(C`x2AQvJ9+B5=3C7&Qzhsj`-ftFuJL;HGBqG;fZi|p|R%HPm5Ao zhF!0-+@6rNcDK{yHZrm=^W%2}@?=i{?VEN)0Jh^hVCA0eAr*E4+67!csu2l$7_Zee z*7DYcq1$0{xC<@zk!RFl#^T%92ZN>=G}sB0nmg}d4ed^q`)S6g*%JRDyLV4Lzmqhf z3du7Tbq0o0BK=eXElt1I#HLg&2w-geztLq9bVZpG^jUL!q(@KxE=)0Wq3or5lhlIL z$cO!45~vTl@0Zg`*dZfD172ZBc`Pw~SN;ZwFgnpn=jR1A9p-4|9${)g4%BgE*Ig4s zc?pcH12gU}XA*VBb0*#AQ|IN8jWwUHME`VAi!EA95M z6+OEHhySB>^0i#1&H+Bxj=|UE2T!Ypn|R%7oJOIi|F8h~msB;+mneQczxQ|F3*D07>nCx0k&f1k=+x;+U+D`k)PcT~03UfvriTbt0% zZ&BSEulNHiT$?d+sIik_fb#2 zAGMx^?hl}Q+)#%a;j31q7~#O1tHo^lUrj;zKGdWtISKm_dNAtC5WAb{fau$=sMS%C zTnF{e0F^A^6gSZGtkVjFa4{ z`r!`8Ld|Wn?0=DJEPnWZ4dqy_1Z5pg$=Y{ zgb&y2zd&P=FGbRubx}@56RMk~igv1PCSr*9+tgqsL}~9^hm}$}`R!`e1f{Ar>XvGN zL-jp2Q-y?7FhzF6-QA{MzU4PKq&jRsFf|3tkH#Ri3XdEbhSsMp_!Vk4f_Z&$Gq&-4$)#{W>oMw8#dySpvcbQL=A zAF7J~0ji3WI^y%J->9qDM*YJFQ9q=8$tdN}zoYJ<_Bj5VJ9@?I{e8Q7{oZsAbyDIc zI)@u+88{=h{}U-w{wvToK(sFzDb_cn)gHz=k@`jXrF>$v`jzpxO8aL0Ym^!Bkf1x* za6s4OccwdWxD;s9YUYqU!HFj;)A|vs_V6kZ*sRZLik4qZC2~`BhlXi0`x|Q+x;kkg zytLFVrk-BtqQVJ`evj(c$`2N}&-^YlIE;i$&+?_A4=!HoQ{x5OR-qDVF+{1-*j239 zN%%T(TeRFiFPHVpMSVCP9+0*R@Lopah5+aStx z7B76yPSU&>nMv=l6FgJ&(wcehAY78+n0 zWc%COM;1m#Z`@{M)Y)UqM3fo)`!7;u#q{KdRAuq;H)yij-Mrq19!rP%P&%u2kFDRT zt|%d${IzsNYkh|56&Vgk3)MRuj{n_sJhG0Yu7?#^NrlflXfWzy{-MeELzD4`CgTrHh8^R7geGIgsPMgN zG&+RsrYuHr)b1wi+#!UwZdpL{xNS2~r(#5+p+3#(4cOifmui(3iAqN-+N;%-2;vRY z)!!g#grz9(Lj&=|S&M(kBx@9=oOn83L)>&HYg&G~5htE7d}wl78Ye;@18!Q$HU5keMSi>;4WPW|E5itU&uJQ1h0yTRjITt)r81DG$llu zl5!hUOgtUcHNv;D3h$O}0(ZGaMCp-W=4Cz5(d-=4pht}$$)!)Ip>2~D66yEiCs$av zc|I*1{l@uheAXSv0+2fd;vN+TsL)kD9wWCny9DvV*j@3;Dle-jS-Xyi02eRDwSK5m zGKeD)^WRe~+M>Um%pr=`NpuMaZKR9EUr`S$(O>fHZRt+HaK)}E=9@E(&$TA^k?&jWRg(QHW`v)^r&8-1B!&sZth64 zz_ETaoJYO8%%(HtshgG1i|enx#RMkHICtj3ny@9yN&5DJH_U-~5qB2M<`6p)cHFQX z_@D)`Fi1;f_Xok`zNE;)lcseJJTZz8bJ&s(o1qyMS_F&t18nFCo9ot-(;2NfLU&W^ z=NF5GHssG@m|n}1y}z_3^`UR>0oSC{+FC2%je+m;@Q~n;YtzhK$^(OKwHi5!3tfyxpNuy4!JC*ytlQGA659MM73YZaxps z^6L5JR46vca~)=YVZz#W1<9|4z9x1snx&PRMLFyJE(vYA@ix7eJoPXdy(Dad0=ieQ z)e5c$!NxC{ToY=MJ@C(sf)HME}GN|V+~?o;;SS0gERQHS)7+wJEA3$zg1u_AT_94%_ z(!1FGe3FmI#wgs2TjBL=AT%t=4y{Cd;uRiz*v;cGZSt$64+|qgh1}m040!LQ-N$b!^!$BWnN5$BPFw5?-#ZjA zNS@nb`Vy4CD3-Mv?wg=wmds+mTg@8sb?Rt3>SEcfBfs9Vu{x|2x=q~7Gm08*KC4hE z-k=E=YyVrg8#0KTK?id(tQx8nWePoWTlF9Ta2KdtRMcb}3#%R}Az_LMy(fa1LzWMv zs87HWLn%_oziG%j-)5ieFtR`&&{$W8xuT5X}B&^~g zCHlTGpiuwW?XaKQ=yJv?(+F5-=Gy@m-VI!+ZWNszzs1m^z0xoB@y*k2ZhhA|09LKf zV#k9m&(xl+4x5@P4exPHZMzI0fdHre@z(t;eU#8it-6UB9v20kWA%of7s;Xl>#MEN zY(A$JVb8kAlWq+fAX;fBJr)Yg^nDO0G07-#yFs!Y_N$`us9&@#?d^5$hwYV z1|5kkIPQpTTzmU_d;f`D)wWXcKz#@W)puWZt*e`zOcTo^A}%lQk`k5p83HLRdt}_d zECID8spBtq(JRwo`eH1hoOTJw$DVj3GS?{g-W02B`;FPEWlL2z(JL*eKS< zAH71!z5sq>do;W)ToyTolfY=VCknY~8* z-*He!Z=h;_(`(CEu^-JJ=jPjah~8#-)2m>6UzM+453+Pgwv+9@ejRdBZU_2{V%sFX zQrad1jq;?(JRRaq0U}Zs3TqT>)WXuRH-He7hQ&)gvXc-PW<&h1;9K9A2kWG2By*Cv zynDBSjt(|SA&8kD&@mwwR#x*#zADCY``pz=cT}Umyni2wL)(k`;bM2FK?4Uf=&?LM zFUF-?nCnR#&LAZg&(~`_w`70E{+s1XI_OMN)KR$81h)8>6e-VRZyDK;SP!dHb6IRs zqOh(SNuHX!6t(cl={EC7$!H*xgtIbokWs!`QooWuD>i&JTu2`qQ7xU)D(g zJ8Ong871=DwkL`OE1h9zj?qD&04&wTxd65|*aQ`u z;XKS7_LM_14}8KrLRQq(M8ZD#4JHz19(Th>+1C)F)+UXGY4{VBL#S`B2FMUuR(#Ue zmNsj#o;?e~oUF0iwTJ4HP_K*3U|Vrmi`Hf$XSD6SF|4W>0?2U7FV7ux1jsK?KLm~? z?eMS(EUbY8r9=dS5-5<7pT3L+T_!)WSIjTJcs@>+qj4-)3hM_8EONS7?%KVV=<;3Y zL=9J`xV$;ET301-ON=`2bg3FQad*=%2`xfng@6+aYw;G!%cf4q-9!0l%tOC7-2xw? zNwli6ylr1Gy3nYHQNM&dxrZC=de=yZyzN0e#HM|JKM@i0>DaN>!pGH3pXl8KgYR-& zb>c9@{?o448-;?=g*U|dVLAK%Knw?;2P%nhi9{kMb+Qi20F|k zW&E`&T*qVnI+>LI@1w1nvjd%+k#HSqcrD@vT*p?u+2qe##<#*>H#tQA zB@+i^`Ox3iMd#zm?KM1Fh>;;Ag`~*Q#yp)p_Z^d+(%;3(>7lH`g zPLQOSPVQUz+u{VXUH;~#+(NZCJ$1_5$)_%!xt-6+R2Jv>`YHJ>^>S|?tKmBC=Q5Vw zBs$V{XavQsy_1+)ES7DF!kHARZNA-q+WT-b2idFF1KU^oA!wI+2*gX-Q@}5skHOZC zRu~lV5hcrN%MVJM4~1`;2xNh|aTJK-X$_dik~s(nDLt8}kp6tr4g1@Tw~(9erLK_C zwyZltyXN*o^qqPHO3~K{+hNF*uICqe4ZEglal_yZaIgJvG;zF@ zd+K45y>Y&(9HqGP(e@CX;+~)Mw+Cw~e{AZysx4l~LKeuAiLNB(J+w1bOZ0fhdq~5A ze8*80KLI+M^lIyDZVkh&X+4|vd-xkY5WPVHfH`8;2NX z3hjRHQnez46&Hu7E-n?EMW%kK8fla-wfHUq@%6y{86j^%7*UVgwN9dN6B1{l1+z#? zJ!tVz!Xr4&Jyl2F@iUWko{|jvqRDn96HL!$7C?z6CIO#=IS9r2j#H3+{S1iZQ+pZB zwSZdRh#VgC`i%*q2o={@ z(z4tBCIuUgcft#-{6!i55H#xZSj+TG?Z- zh_Cn158#Q9`gX4IU9QP&5{|m*U5*`f?d2nT3JlWr)hq|$W|xB2Hh&ODFBwLdKB5{;{6fMRPz{d=zA2F@gztEX12u!e>{C=s5nY zEBn@xLhL4P@ey@59%uLdGppv{qwCPX@yyXSRXHwvn9Fm_h@m}#pwH{W&-1IWFu(H3 zacIffTi6GvTT|x7dF)*!e_w$CFQ>u%rB<}d-0IW&VHO3qEHJ1tKdp)-rbIOf1? zGS(@I6MG!mI2{~0h)P&*r06+F4U)v)?D9}nu4D=Z@2ItxC&6C*)F6MWnb4$bGz=41 z>|Dp|OvFzN12Ows!n8jin0Q0cY`=RvL`!Nbm90krrsZkN_(&?gE>DY<%0;5=Bdz2O z-lGW6wzYE3Ceun?Jib#GkJrb!R`+s@if>(-IOG)Z{Be-iPCF9o3Ham^x`G?5uhX6- zRSIS>p#~c^#dve27aXfiya^X;u(MGGsU9#!(xiM-@OENGosagwtFdYGykS?cBE&if zv85ROB^$*q9A4oBm`RjQWV={g%_+|^s8=gB z8*qH|RtDWR3#6J7?T96_A@fag96;|;u;ianQ4UnpfRyCOXq(VY3on|@!$?h7b=WD$ zqWpYMMq5CIq0M0l_6Qe1$hj}~?~}jhP5NUSM$=z@rTsMt3ViyIdT1=>c_gZtH<<() z5uah&i<5Gq)Q{x?Lts&CNQ{7aBACXx;~YlcRn}rKrOt&L0f!RLqcJ@NHCB^U z_rF17S24mB$%M$tw5wKj3&i4_HsBzD3a(9So=uR^PpTv&E8e z9b%#kEYtEug+@`1FwCmi1;|)U)Hg&?ZhDWNzjRO0^zXm9iW^dA z5N9!r99Lz_%Ne=;9%i#C653Azdg(j=+k#!|DUg)fB&_s^U;>ENz#C_7{0E+ z+@x+Fd1&qWg^u0(xo7R9de`BfufjiHhkqW0f8G!O9O$3)_s(Zw`OXgitqY(`QLxv& zo1W_h~vVuE-U(trb;sU>Y?aH4YhS2Jv7WHNVImMGT_?b-dUTpK2&g zcNBMGo3La-;bI8zfb21fDI}jPHnT`b2qJV3HnUPQds(ExGiL6qW>H|`gbj8;@vxxt(bukFdT!i(Y!Mbu zEW4ZSCnoo@s8E6ivPt#`4z@m@%+DOdwJb-#=^}zGN9iYL6wO_I7Ru@Y^zyZ7yvvtr zQJfZ6w$yFu?yG#~rw2R#_lLcmzYY)oohx#g*nHu57ZQc%mw^<{t7;V-TE>8mf+eA8Ow{y>pM%jUZTO>WHj0?WYz%@ zI7S3vi&#%V(BxT{%^N#+lqgeF?ig+DYM4C%?ZH(JF`f?%DFi<#I6VFlHZFJXFl`2W z+^Guq9xMu53|c57lsw%Y%_g(O@T@#Nn}9H8NU4o)55rm9xuzqi!(6xpI3`uK)>sgk zD!Y%R!)iV$m;K&Q*b>}cSLoW)2M(M8ZKBv!+L^14#noAPvJA!F$z~k1#^Io{n)a58 z>F2X@x(s0Z*6fw*;dKbi^v&EH3&t7E9;>Y3i2NiPW}pM%4mR*adNsfwC`SS~Ll%Pw zZ00feL1QHmJCt#4xCGP%`qAP&r)RBPK%}Tec?>QL>S%^|WjstnERLEkg2Cz#laI&X z64u9t1FU3Wr5t4L_&jU~{d7NK)KA<~L`LNEBx&> z(pkW1d9s|g^9!<;s(Pr_J=%DgyAuO3~sfIinVZxaLp_YW`% zr^|tE381!u17#qiGlYmmaE_l*q@bOhD6GHM#{)4NaqBdO7ze)e2`*3#%i-oR_#l1w z{G_jkE7ho z07n~S7TDqNaDzO0gX)LWh`%gn5dKX6a-AIN#98pt3?B7kt;5GU;9x(JT2KB9CU)Yb zrNP8<2hc7p5I|O#|Ba3RiloJn5?Gz$kxKd@9TLe44 zoMc6ct(l;k@*De9dP$k$p=8@i1;zW zgOCb>(KyZnbRK#Ksx{}E{uU9>AsEz*DB9ts%PB-?Ac?g;6yAzwZ{>k9utrk0~3tGU42(mI9_!u%FyAX6*F;uHeO4E(Rn3*+evm1 z0|j!y2X3@cb~l7WPvUtM&#Tda5nptith`I31Njo}b@4#- z4qm{P*zr)59ukCVB*)*D7G%$LK3m{JHYzI&LtOE)s9Cj3jU3~a%cD12fB_=P=D@h? zu(z%2t_z>_GVJuCeSkPkwH1b!t=3&&j9Kd>eVN$ohxQblh~e??)q4`MAd8(cj!8}* zb*e5EzGpxy$&L}*wuDo1MX)*jiYD~I>u;>G#q-(Y-dOl)le~Y zL^J1sAI~m;-2CUo%<{Gb1h>uhglAQMXZiQrh)}hC`q^^*u7!$hut2 z+;@+y2XM+b<*a}?x3C1P#}DL&H9DmE?)%kx6V70>UYKbBPc#Rb6hpj^&SrDE0E6tK zy=@cgJyJEYtqbvd^vxUD)miVlJq4Rc7@n0_c})zPi8h!Ps><7Q!ld&5flwRu1+#~bIrajV)aII}BOTt5k2G@I8% zqZ2TtfjJ(S^5AtH7CGKi2aCrJqTg6g1Y9A2=g$^CllSz2?ZF|B_?})j9(ENvw6H_N4D3mHe+-Nj%i$#V|7 zQoy0Y@D?8hFHd|qnw4*|ZlD1tgx^0Uh;<)Gy)%e}#ZJt>E$!x0c$pE1Lx`App)fXOp&9O04F z?feJ$<1l;r=>F43*{j~5_d0t;A75v;&9(x0{ zs1rqPn7=c5bUz}G63anmwT>AZcI-OdIR=fu=)e@?yK%qv;F}t(G>YGTQ$uD^rvp+X zTAfI%qwW?;t&LW@DYa&BM-rU6Qcp?|1>1YnP-gcsE(;DTE)-i2JHb;3Hnk9ag2e|G zjF`XSjzVpHSd`S-M|DVXY);PrKjR%KtP_E4?=ah$A#A>?&hmM29};}IGd!71mymAY z{{APg#o+9L>fjjRP*$KGG>2ehu+Q)>Ar7O}Q~i?1@pZMNS~PJs_VGG`$#A@?B_^cH z(}S2VSdJFCXpwg!rv^eE9h-K=GWx@IbNJA7xbnLCHcpeE``39-3PdPV`^y=F@GWeu;f4|bEd!V&MW{(huwD6aXLPJmn!_2dDrJ_QcA zJhlc8V9mv}06&Vt7zE&1UFOTWtcEbl7wvLLgHa%|GbaV zjdmUl82RU^dNbhHv_WQV%1}4SccXIRvq0RXg#PP244jOI<_z zNcnTDDML5rVLEUzGqZv^Rbs{AIMav#jX=$g44_V?NYsz%Gex#~Y(kehjpWwe7DK*~ zRhC#TWq|=wN6RIdUds5*XXXJQy{`b&!b%llxU0)zQ}+{Z$e+DJ|Ni^8_lJ9Xd$$J} zQ6JT8;`qtnd2hDgYI!ngpA0v}yJt@59e++6XkzrLp7l z)p7wY*6x;{Q&1hSoebPGL0F3RW05peY&Xw~s>)BreAAQner4A%V*U0<%jbR~pRrgG z$F)Gq=IHrZiw+KRDlM`ehCw4IyWVz6G563lcCY#gd78VZ`-Z*LMS!-~h(;IPk5b&A?)@M*sA_t@k<2{*dcH80zJszc6CCjq@JGVmxDg_Jm42(t6)vV5Z7c_PX2?c`gpofkN+h|#CMshIms;+AoELx9g8!e|vQ}mE6 zOjJbQ7(t;HGy>fEeQoM4iU~m;0c`b5Xc2BeptWy`=Kw$NA*KUF8>!y`*ZSq`ZzOmg zhoN7HETz0>FTM7Z!vJu&841ZijXj5_LmFNXx8o2ZV9TMwuGkM8fa%Z?S9DB9jXaxE zAW;n^AvVDnMkR8E2|g#_&6V4PXThw$4mnsH$&vQlWLS;|rUYr%!;B71y5+QhWSPv3 zwmtBAI3`Pb9d)4f17h6R|5In@`Dqc+4qAxRGsx|+Rxfq;^=zzD+uvLcwIa^FqNX}h5xdw!?c_9dvaD}0Q;k~BHw zc(}(TWIPU?Ij|3O=-@^}>(~K5;M^f)mNiU5z+;pqO7#c=v<4*)huE{)F)LPp=Z7b| z=P=&vvgcmy9vFZd5U@4^kBul?smtIb)7K`oIl@YY0BbkJz6x|O+qG?^*b3T&fV11% zMXkd(k?*YbXP-pVX>!UA9@k75WdpwY29w2>%~LgC(qW?My#?+w*vjZ;!cVT7J9|M=t8V{xrLvnd zKlV~JUdGLLp!52#V}`g5B<(r7`L~?1l>R2qIQ*7)ZhW$d@WBZs#D07qK-Shwv9{XA zGcmgvM-_8_@NYv6Jmm?VBU5aMsQZSZawmDc-RDG55ciXWLmG0r=a4miK9rueO=`z{ z`Zljf7*=H$Y>EuK@i&q#yJrlA0n|NJ|F&>_10@1MG9Afy@F*Sus#Yk!oz{&mK4o0E-=IMa! z)`_t^N=>)==LP5+{d8-r@>S*&B4s0WP^nj3WdPQY52&@;!hMBIgPdj=iF%*U939GV zPMd5Vui{3Vw{X|L56*XP?^g8B0fT0F;1c2n2Yyq}P@oM8k{?&QSh_>SJJ9b= zHAmptZ39~$zKp^`PP0$5efZagv7r=_2$7E6oo4@;9bhnYTy;P;0gIob(++Z)~! ziqb-aAvpoOxU)M9#O2g=>aLA^_~xm*5&L`FmV?K)HE1@PRq1BjDkNh&Kp$_l+q=;l zaMgu8Te!cN`w$4(-Ti}m_wMZa?SKmYYFA&^gZW^eP!PDy}$?*@=vOeW>LN|1#B z*FpHZd_D(p_3+-kgM+_({1=Y~W)S?ekI=jA)`ArWCdoLx51{P>iwFN4_zoZzUjM9P z2l7m4^DCG=Ah1iDG~PA8+Hot_YAdJ)FW^~JZ533zI+xyHJ_Fm^c{v_W3g6+mbcmFM z?T~ABy*h5g&+Yf);-|7$JiJ)=Vt2D=?o_Vu7doM znFUD)XURC&xS(3=uGd`d-M`@C{pz@-{#0Vg@!I7d*Vlh68*tod2ab8!$94~nlXD8u zQjO=CW~eOUJJX-eFlNy9CP;=ls9_i+NC#OM;}t@-#?=xp%#QFkhQ!A9Mxne~ zBHYGRfryu?G6eCiI*@vt zq-F_OyZmsF+0pIBU1`3XeN-FGl{!AhvmJJHXunFg*TEC*WikuRv4yi)beYXg^K2Gf zW>as!0X2~#RVVKIBvnwlf-+SA!qb4dZRgZp6w4~Rm~*0|>Z}-l1rfFc^7Bc#Tv2Ep zce&IQ?MPO)w?0@GM zOZQx6kMg(WIQy^JVw{Vd4D(7K?Cl@y?ES_4|7NsKC?Ny0`}g;#BK--XfZ^WWJ_?e)%sC{>i~J;ClnPr={h?!4 zDdz`|A@OkAKm{8kDROnNbLHO4G13#OgB@F=n#|CAV!YZNUzvtwwfwd?XX_g)1#^Ag z8N-`DUfpp$+QHoHo`Q|w{k;J~#C;#!LgM7vZa=%fH{9R0!jE8Ubg{3r z1VKjFi^;MCJ9tSKbv66DLS)10(GzDFhc<~Oh;%ZdPm)c)B zUY~I7=c#%X;osh^g=X_@@z0BL0q%V3I;z+Pj_jz&`i*|K>+3$DEBgCOFQ}c*s*)^| zPj1lPivIq)$a8Pjo2-&F9tcV*eijGI!;R9?!Ov~s`fd-h+a$n;-Gv{+CL zv***vN>e0nw40b*S%5e@%Q0;Zc3YngrIO@Dq^3jpC5PG9I1{+N8_s4?xIHi40+yp4 zvi{$7d%*Aq!Wu4furSYTLbJf_7`-{F8_Z1HmjokWiVif(P}>^x6!Q}v_+uOREgSf0 z5}SndOI1wh;jpoNvBU%yN55Z)dx@Wd#|ER>vLm6-^htI+G#DFy;&

czY*mO3{(6 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%0DZz*S*K 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

oz^ZM>Z3_ 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

C9M0*l*)1&vXYY5o{O8ek@|p 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 _RCHf~UrMbWEr^`d`&$Ox@CS~Q9 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
UazUn~^pMaL_%4IclH*y@W6V70xacT|r$)Zf^ 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�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�O1 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�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

Rs=Z?bkK)T=S><`$ZUN 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 XK~^W&Yhu_o_#<$^u - Graph | Basic usage + Graph | Basic usage - + - + @@ -19,31 +19,31 @@

diff --git a/examples/graph/02_random_nodes.html b/examples/graph/02_random_nodes.html index b048a69d..24e5926a 100755 --- a/examples/graph/02_random_nodes.html +++ b/examples/graph/02_random_nodes.html @@ -1,105 +1,105 @@ - Graph | Random nodes + Graph | Random nodes - + - + - + // add event listeners + vis.events.addListener(graph, 'select', function(params) { + document.getElementById('selection').innerHTML = + 'Selection: ' + graph.getSelection(); + }); + } +
- - - + + +

diff --git a/examples/graph/03_images.html b/examples/graph/03_images.html index f0235fb6..f1a16db1 100755 --- a/examples/graph/03_images.html +++ b/examples/graph/03_images.html @@ -1,78 +1,78 @@ - Graph | Images - - - - - - + Graph | Images + + + + + + diff --git a/examples/graph/04_shapes.html b/examples/graph/04_shapes.html index 25b3f3ea..b6db4dd9 100755 --- a/examples/graph/04_shapes.html +++ b/examples/graph/04_shapes.html @@ -1,71 +1,71 @@ - Graph | Shapes + Graph | Shapes - + - + - + } + + // create a graph + var container = document.getElementById('mygraph'); + var data = { + nodes: nodes, + edges: edges + }; + var options = { + stabilize: false + }; + graph = new vis.Graph(container, data, options); + } + diff --git a/examples/graph/05_social_network.html b/examples/graph/05_social_network.html index 480eca6b..2a19aed0 100644 --- a/examples/graph/05_social_network.html +++ b/examples/graph/05_social_network.html @@ -1,76 +1,76 @@ - Graph | Social Network + Graph | Social Network - + - + - + // create a graph + var container = document.getElementById('mygraph'); + var data = { + nodes: nodes, + edges: edges + }; + var options = {}; + graph = new vis.Graph(container, data, options); + } +

- Icons: Scrap Icons by Deleket + Icons: Scrap Icons by Deleket

diff --git a/examples/graph/06_groups.html b/examples/graph/06_groups.html index 59adfb51..546b0c66 100644 --- a/examples/graph/06_groups.html +++ b/examples/graph/06_groups.html @@ -1,156 +1,156 @@ - Graph | Groups + Graph | Groups + + + + + + + - - - + }; + graph = new vis.Graph(container, data, options); + } +
- Number of groups: - - Number of nodes per group: - - + Number of groups: + + Number of nodes per group: + +

diff --git a/examples/graph/07_selections.html b/examples/graph/07_selections.html index 421c3794..25faf4c9 100644 --- a/examples/graph/07_selections.html +++ b/examples/graph/07_selections.html @@ -1,17 +1,17 @@ - Graph | Selections + Graph | Selections - + - + @@ -20,45 +20,45 @@
diff --git a/examples/graph/08_mobile_friendly.html b/examples/graph/08_mobile_friendly.html index de44f4a8..f94ca61e 100755 --- a/examples/graph/08_mobile_friendly.html +++ b/examples/graph/08_mobile_friendly.html @@ -1,105 +1,105 @@ - Graph | Mobile friendly + Graph | Mobile friendly - + #mygraph { + width: 100%; + height: 100%; + } + - - + + - + - + }; + graph = new vis.Graph(container, data, options); + } + diff --git a/examples/graph/09_sizing.html b/examples/graph/09_sizing.html index 67a48f8e..302d5282 100644 --- a/examples/graph/09_sizing.html +++ b/examples/graph/09_sizing.html @@ -1,77 +1,77 @@ - Graph | Sizing + Graph | Sizing - + - + - + }; + graph = new vis.Graph(container, data, options); + } + diff --git a/examples/graph/10_multiline_text.html b/examples/graph/10_multiline_text.html index 695d5fba..1d8a96b2 100755 --- a/examples/graph/10_multiline_text.html +++ b/examples/graph/10_multiline_text.html @@ -1,47 +1,47 @@ - Graph | Multiline text + Graph | Multiline text - + - + - + // create a graph + var container = document.getElementById('mygraph'); + var data = { + nodes: nodes, + edges: edges + }; + var options = {}; + var graph = new vis.Graph(container, data, options); + } + diff --git a/examples/graph/11_custom_style.html b/examples/graph/11_custom_style.html index 20e9dd59..811c1754 100644 --- a/examples/graph/11_custom_style.html +++ b/examples/graph/11_custom_style.html @@ -1,128 +1,128 @@ - Graph | Custom style + Graph | Custom style - + - + - + }; + + // create the graph + var container = document.getElementById('mygraph'); + var data = { + nodes: nodes, + edges: edges + }; + graph = new vis.Graph(container, data, options); + } + diff --git a/examples/graph/12_scalable_images.html b/examples/graph/12_scalable_images.html index 8a3da963..a9890f64 100644 --- a/examples/graph/12_scalable_images.html +++ b/examples/graph/12_scalable_images.html @@ -1,80 +1,80 @@ - Graph | Scalable images + Graph | Scalable images - + - + - + }; + graph = new vis.Graph(container, data, options); + } + diff --git a/examples/graph/13_dashed_lines.html b/examples/graph/13_dashed_lines.html index 6f954672..e69c773a 100644 --- a/examples/graph/13_dashed_lines.html +++ b/examples/graph/13_dashed_lines.html @@ -1,65 +1,65 @@ - Graph | Dashed lines + Graph | Dashed lines - + - + - + // create the graph + var container = document.getElementById('mygraph'); + var data = { + nodes: nodes, + edges: edges + }; + var options = { + nodes: { + shape: 'box' + }, + edges: { + length: 180 + }, + stabilize: false + }; + var graph = new vis.Graph(container, data, options); + } + -

- This example shows the different options for dashed lines. -

+

+ This example shows the different options for dashed lines. +

-
+
diff --git a/examples/graph/14_dot_language.html b/examples/graph/14_dot_language.html index 7d86df95..11bf5763 100644 --- a/examples/graph/14_dot_language.html +++ b/examples/graph/14_dot_language.html @@ -1,18 +1,18 @@ - Graph | DOT Language + Graph | DOT Language - + -
+
- + diff --git a/examples/graph/15_dot_language_playground.html b/examples/graph/15_dot_language_playground.html index bf757cd8..d0c5912b 100644 --- a/examples/graph/15_dot_language_playground.html +++ b/examples/graph/15_dot_language_playground.html @@ -1,201 +1,201 @@ - Graph | DOT language playground - - - - + textarea.example { + display: none; + } + - - - - - - - - - + + + + + + + + +
-

DOT language playground

- -
-
- - -
-
- - -
-
+

DOT language playground

+ +
+
+ + +
+
+ + +
+
diff --git a/examples/graph/16_dynamic_data.html b/examples/graph/16_dynamic_data.html index b4ccb596..d8536f97 100644 --- a/examples/graph/16_dynamic_data.html +++ b/examples/graph/16_dynamic_data.html @@ -1,264 +1,264 @@ - Graph | DataSet + Graph | DataSet - + #graph { + width: 100%; + height: 400px; + border: 1px solid lightgray; + } + - - + + - + // create a graph + var container = $('#graph').get(0); + var data = { + nodes: nodes, + edges: edges + }; + var options = {}; + graph = new vis.Graph(container, data, options); + }); +

- This example demonstrates dynamically adding, updating and removing nodes - and edges using a DataSet. + This example demonstrates dynamically adding, updating and removing nodes + and edges using a DataSet.

Adjust

- - - - + + + +
-

Node

- - - - - - - - - - - - - - - - -
Action - - - -
-
-

Edge

- - - - - - - - - - - - - - - - - - - - - -
Action - - - -
-
+

Node

+ + + + + + + + + + + + + + + + +
Action + + + +
+
+

Edge

+ + + + + + + + + + + + + + + + + + + + + +
Action + + + +
+

View

- - - - - - - + + + + + + + - + - - + +
-

Nodes

-

-        
+

Nodes

+

+    
-

Edges

-

-        
+

Edges

+

+    
-

Graph

-
-
+

Graph

+
+
diff --git a/examples/graph/17_network_info.html b/examples/graph/17_network_info.html index 62cd9eef..ec4379e2 100644 --- a/examples/graph/17_network_info.html +++ b/examples/graph/17_network_info.html @@ -1,149 +1,149 @@ - Graph | Images - - + + + + - - + }; + graph = new vis.Graph(container, data, options); + } + diff --git a/examples/graph/graphviz/graphviz_gallery.html b/examples/graph/graphviz/graphviz_gallery.html index 3260187d..280ba6c5 100644 --- a/examples/graph/graphviz/graphviz_gallery.html +++ b/examples/graph/graphviz/graphviz_gallery.html @@ -1,86 +1,86 @@ - Graph | Graphviz Gallery + Graph | Graphviz Gallery - - + + - +

- The following examples are unmodified copies from the - Graphviz Gallery. + The following examples are unmodified copies from the + Graphviz Gallery.

- Note that some style attributes of Graphviz are not supported by vis.js, - and that vis.js offers options not supported by Graphviz (which could make - some examples look much nicer). + Note that some style attributes of Graphviz are not supported by vis.js, + and that vis.js offers options not supported by Graphviz (which could make + some examples look much nicer).

- - + +

diff --git a/examples/graph/index.html b/examples/graph/index.html index 0fd44cfb..7cb11657 100644 --- a/examples/graph/index.html +++ b/examples/graph/index.html @@ -2,34 +2,34 @@ - vis.js | graph examples + vis.js | graph examples - + diff --git a/examples/timeline/01_basic.html b/examples/timeline/01_basic.html index d8a5f50e..514eefd1 100644 --- a/examples/timeline/01_basic.html +++ b/examples/timeline/01_basic.html @@ -1,31 +1,32 @@ - Timeline | Basic demo + Timeline | Basic demo - + - + +
\ No newline at end of file diff --git a/examples/timeline/02_dataset.html b/examples/timeline/02_dataset.html index 36575945..e493663d 100644 --- a/examples/timeline/02_dataset.html +++ b/examples/timeline/02_dataset.html @@ -1,60 +1,62 @@ - Timeline | Dataset example - - - - - - - + Timeline | Dataset example + + + + + + + +
diff --git a/examples/timeline/03_much_data.html b/examples/timeline/03_much_data.html index 45c4f40e..60005819 100644 --- a/examples/timeline/03_much_data.html +++ b/examples/timeline/03_much_data.html @@ -13,7 +13,8 @@ - + +

diff --git a/examples/timeline/04_html_data.html b/examples/timeline/04_html_data.html index c01dbfcc..47997fd3 100644 --- a/examples/timeline/04_html_data.html +++ b/examples/timeline/04_html_data.html @@ -1,69 +1,74 @@ - Timeline | HTML data + Timeline | HTML data - + + + + -

- Load HTML contents in the Timeline + Load HTML contents in the Timeline

\ No newline at end of file diff --git a/examples/timeline/05_groups.html b/examples/timeline/05_groups.html index d6c9ced4..a103d1a3 100644 --- a/examples/timeline/05_groups.html +++ b/examples/timeline/05_groups.html @@ -1,71 +1,72 @@ - Timeline | Group example + Timeline | Group example - + #visualization { + box-sizing: border-box; + width: 100%; + height: 300px; + } + - - + + - + +

- This example demonstrate using groups. Note that a DataSet is used for both - items and groups, allowing to dynamically add, update or remove both items - and groups via the DataSet. + This example demonstrate using groups. Note that a DataSet is used for both + items and groups, allowing to dynamically add, update or remove both items + and groups via the DataSet.

diff --git a/examples/timeline/index.html b/examples/timeline/index.html index 937d5dab..91b28ffe 100644 --- a/examples/timeline/index.html +++ b/examples/timeline/index.html @@ -2,21 +2,21 @@ - vis.js | timeline examples + vis.js | timeline examples - + diff --git a/examples/timeline/requirejs/requirejs_example.html b/examples/timeline/requirejs/requirejs_example.html index 764a75ba..d4e85f08 100644 --- a/examples/timeline/requirejs/requirejs_example.html +++ b/examples/timeline/requirejs/requirejs_example.html @@ -1,11 +1,13 @@ - Timeline requirejs demo + Timeline requirejs demo - + + + -
+
diff --git a/examples/timeline/requirejs/scripts/main.js b/examples/timeline/requirejs/scripts/main.js index 15e1d872..ff6d5108 100644 --- a/examples/timeline/requirejs/scripts/main.js +++ b/examples/timeline/requirejs/scripts/main.js @@ -1,19 +1,19 @@ require.config({ - paths: { - vis: '../../../../vis' - } + paths: { + vis: '../../../../dist/vis' + } }); require(['vis'], function (vis) { - var container = document.getElementById('visualization'); - var data = [ - {id: 1, content: 'item 1', start: '2013-04-20'}, - {id: 2, content: 'item 2', start: '2013-04-14'}, - {id: 3, content: 'item 3', start: '2013-04-18'}, - {id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'}, - {id: 5, content: 'item 5', start: '2013-04-25'}, - {id: 6, content: 'item 6', start: '2013-04-27'} - ]; - var options = {}; - var timeline = new vis.Timeline(container, data, options); + var container = document.getElementById('visualization'); + var data = [ + {id: 1, content: 'item 1', start: '2013-04-20'}, + {id: 2, content: 'item 2', start: '2013-04-14'}, + {id: 3, content: 'item 3', start: '2013-04-18'}, + {id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'}, + {id: 5, content: 'item 5', start: '2013-04-25'}, + {id: 6, content: 'item 6', start: '2013-04-27'} + ]; + var options = {}; + var timeline = new vis.Timeline(container, data, options); }); diff --git a/index.html b/index.html index 4ba37bae..ae57caf3 100644 --- a/index.html +++ b/index.html @@ -72,26 +72,8 @@ bower install vis

download

- - - - - - - - - -
- Development - (version 0.2.0) - - 441 kB, uncompressed with comments -
- Production - (version 0.2.0) - - 39 kB, minified and gzipped -
+Click here to download vis.js +(version 0.3.0)

Example

@@ -104,30 +86,31 @@ bower install vis
<!doctype html>
 <html>
 <head>
-    <title>Timeline | Basic demo</title>
-    <script src="http://visjs.org/vis.js"></script>
-
-    <style type="text/css">
-        body, html {
-            font-family: sans-serif;
-        }
-    </style>
+  <title>Timeline | Basic demo</title>
+  <script src="http://visjs.org/dist/vis.js"></script>
+  <link href="http://visjs.org/dist/vis.css" rel="stylesheet" type="text/css" />
+
+  <style type="text/css">
+    body, html {
+      font-family: sans-serif;
+    }
+  </style>
 </head>
 <body>
 <div id="mytimeline"></div>
 
 <script type="text/javascript">
-    var container = document.getElementById('mytimeline');
-    var data = [
-        {id: 1, content: 'item 1', start: '2013-04-20'},
-        {id: 2, content: 'item 2', start: '2013-04-14'},
-        {id: 3, content: 'item 3', start: '2013-04-18'},
-        {id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'},
-        {id: 5, content: 'item 5', start: '2013-04-25'},
-        {id: 6, content: 'item 6', start: '2013-04-27'}
-    ];
-    var options = {};
-    var timeline = new vis.Timeline(container, data, options);
+  var container = document.getElementById('mytimeline');
+  var data = [
+    {id: 1, content: 'item 1', start: '2013-04-20'},
+    {id: 2, content: 'item 2', start: '2013-04-14'},
+    {id: 3, content: 'item 3', start: '2013-04-18'},
+    {id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'},
+    {id: 5, content: 'item 5', start: '2013-04-25'},
+    {id: 6, content: 'item 6', start: '2013-04-27'}
+  ];
+  var options = {};
+  var timeline = new vis.Timeline(container, data, options);
 </script>
 </body>
 </html>
@@ -304,7 +287,7 @@ The source code of the examples can be found in the
 

License

- Copyright (C) 2010-2013 Almende B.V. + Copyright (C) 2010-2014 Almende B.V.

diff --git a/package.js b/package.js new file mode 100644 index 00000000..e69de29b diff --git a/updateversion.js b/updateversion.js index 094dfd16..18878b6c 100644 --- a/updateversion.js +++ b/updateversion.js @@ -1,48 +1,14 @@ -// Update the version numbers and library sizes in index.md +// Update the version numbers and library sizes in index.html var fs = require('fs'), zlib = require('zlib'); -var VIS = 'vis.js', - VIS_MIN = 'vis.min.js', +var VIS_ZIP = './dist/vis.js', INDEX = 'index.html'; -// get development size -function developmentSize(callback) { - fs.readFile(VIS, function (err, data) { - if (!err) { - var size = Math.round(data.length / 1024) + ' kB'; - callback(null, size); - } - else { - callback(err); - } - }); -} - -// get (gzipped) production size -function productionSize(callback) { - fs.readFile(VIS_MIN, function (err, data) { - if (!err) { - zlib.gzip(data, function (err, data) { - if (!err) { - var size = Math.round(data.length / 1024) + ' kB'; - callback(null, size) - } - else { - callback(err); - } - }); - } - else { - callback(err); - } - }); -} - -// get version +// read version from dist/vis.js function version(callback) { - fs.readFile(VIS_MIN, function (err, data) { + fs.readFile(VIS_ZIP, function (err, data) { if (!err) { var match = /@version\s*([\w\.-]*)/i.exec(data); var version = undefined; @@ -58,15 +24,10 @@ function version(callback) { } // update version and library sizes in index.md -function updateVersion(developmentSize, productionSize, version, callback) { +function updateVersion(version, callback) { fs.readFile(INDEX, function (err, data) { if (!err) { data = String(data); - data = data.replace(/([\w\s]*)<\/span>/g, - '' + developmentSize + ''); - - data = data.replace(/([\w\s]*)<\/span>/g, - '' + productionSize + ''); data = data.replace(/([\w\.-]*)<\/span>/g, '' + version + ''); @@ -79,24 +40,19 @@ function updateVersion(developmentSize, productionSize, version, callback) { }); } -developmentSize(function (err, devSize) { - console.log('development size: ' + devSize); - productionSize(function (err, prodSize) { - console.log('production size: ' + prodSize); - version(function (err, version) { - console.log('version: ' + version); - if (devSize && prodSize && version) { - updateVersion(devSize, prodSize, version, function (err, res) { - if (err) { - console.log(err); - } - else { - console.log('done'); - } - }); + +version(function (err, version) { + console.log('version: ' + version); + if (version) { + updateVersion(version, function (err, res) { + if (err) { + console.log(err); } else { + console.log('done'); } }); - }); -}); + } + else { + } +}); \ No newline at end of file diff --git a/vis.js b/vis.js deleted file mode 100644 index eeb9980b..00000000 --- a/vis.js +++ /dev/null @@ -1,14667 +0,0 @@ -/** - * vis.js - * https://github.com/almende/vis - * - * A dynamic, browser-based visualization library. - * - * @version 0.2.0 - * @date 2013-09-20 - * - * @license - * Copyright (C) 2011-2013 Almende B.V, http://almende.com - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -(function(e){if("function"==typeof bootstrap)bootstrap("vis",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeVis=e}else"undefined"!=typeof window?window.vis=e():global.vis=e()})(function(){var define,ses,bootstrap,module,exports; -return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o; - * Licensed under the MIT license */ - -(function(window, undefined) { - 'use strict'; - -/** - * Hammer - * use this to create instances - * @param {HTMLElement} element - * @param {Object} options - * @returns {Hammer.Instance} - * @constructor - */ -var Hammer = function(element, options) { - return new Hammer.Instance(element, options || {}); -}; - -// default settings -Hammer.defaults = { - // add styles and attributes to the element to prevent the browser from doing - // its native behavior. this doesnt prevent the scrolling, but cancels - // the contextmenu, tap highlighting etc - // set to false to disable this - stop_browser_behavior: { - // this also triggers onselectstart=false for IE - userSelect: 'none', - // this makes the element blocking in IE10 >, you could experiment with the value - // see for more options this issue; https://github.com/EightMedia/hammer.js/issues/241 - touchAction: 'none', - touchCallout: 'none', - contentZooming: 'none', - userDrag: 'none', - tapHighlightColor: 'rgba(0,0,0,0)' - } - - // more settings are defined per gesture at gestures.js -}; - -// detect touchevents -Hammer.HAS_POINTEREVENTS = navigator.pointerEnabled || navigator.msPointerEnabled; -Hammer.HAS_TOUCHEVENTS = ('ontouchstart' in window); - -// dont use mouseevents on mobile devices -Hammer.MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i; -Hammer.NO_MOUSEEVENTS = Hammer.HAS_TOUCHEVENTS && navigator.userAgent.match(Hammer.MOBILE_REGEX); - -// eventtypes per touchevent (start, move, end) -// are filled by Hammer.event.determineEventTypes on setup -Hammer.EVENT_TYPES = {}; - -// direction defines -Hammer.DIRECTION_DOWN = 'down'; -Hammer.DIRECTION_LEFT = 'left'; -Hammer.DIRECTION_UP = 'up'; -Hammer.DIRECTION_RIGHT = 'right'; - -// pointer type -Hammer.POINTER_MOUSE = 'mouse'; -Hammer.POINTER_TOUCH = 'touch'; -Hammer.POINTER_PEN = 'pen'; - -// touch event defines -Hammer.EVENT_START = 'start'; -Hammer.EVENT_MOVE = 'move'; -Hammer.EVENT_END = 'end'; - -// hammer document where the base events are added at -Hammer.DOCUMENT = document; - -// plugins namespace -Hammer.plugins = {}; - -// if the window events are set... -Hammer.READY = false; - -/** - * setup events to detect gestures on the document - */ -function setup() { - if(Hammer.READY) { - return; - } - - // find what eventtypes we add listeners to - Hammer.event.determineEventTypes(); - - // Register all gestures inside Hammer.gestures - for(var name in Hammer.gestures) { - if(Hammer.gestures.hasOwnProperty(name)) { - Hammer.detection.register(Hammer.gestures[name]); - } - } - - // Add touch events on the document - Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_MOVE, Hammer.detection.detect); - Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_END, Hammer.detection.detect); - - // Hammer is ready...! - Hammer.READY = true; -} - -/** - * create new hammer instance - * all methods should return the instance itself, so it is chainable. - * @param {HTMLElement} element - * @param {Object} [options={}] - * @returns {Hammer.Instance} - * @constructor - */ -Hammer.Instance = function(element, options) { - var self = this; - - // setup HammerJS window events and register all gestures - // this also sets up the default options - setup(); - - this.element = element; - - // start/stop detection option - this.enabled = true; - - // merge options - this.options = Hammer.utils.extend( - Hammer.utils.extend({}, Hammer.defaults), - options || {}); - - // add some css to the element to prevent the browser from doing its native behavoir - if(this.options.stop_browser_behavior) { - Hammer.utils.stopDefaultBrowserBehavior(this.element, this.options.stop_browser_behavior); - } - - // start detection on touchstart - Hammer.event.onTouch(element, Hammer.EVENT_START, function(ev) { - if(self.enabled) { - Hammer.detection.startDetect(self, ev); - } - }); - - // return instance - return this; -}; - - -Hammer.Instance.prototype = { - /** - * bind events to the instance - * @param {String} gesture - * @param {Function} handler - * @returns {Hammer.Instance} - */ - on: function onEvent(gesture, handler){ - var gestures = gesture.split(' '); - for(var t=0; t 0 && eventType == Hammer.EVENT_END) { - eventType = Hammer.EVENT_MOVE; - } - // no touches, force the end event - else if(!count_touches) { - eventType = Hammer.EVENT_END; - } - - // because touchend has no touches, and we often want to use these in our gestures, - // we send the last move event as our eventData in touchend - if(!count_touches && last_move_event !== null) { - ev = last_move_event; - } - // store the last move event - else { - last_move_event = ev; - } - - // trigger the handler - handler.call(Hammer.detection, self.collectEventData(element, eventType, ev)); - - // remove pointerevent from list - if(Hammer.HAS_POINTEREVENTS && eventType == Hammer.EVENT_END) { - count_touches = Hammer.PointerEvent.updatePointer(eventType, ev); - } - } - - //debug(sourceEventType +" "+ eventType); - - // on the end we reset everything - if(!count_touches) { - last_move_event = null; - enable_detect = false; - touch_triggered = false; - Hammer.PointerEvent.reset(); - } - }); - }, - - - /** - * we have different events for each device/browser - * determine what we need and set them in the Hammer.EVENT_TYPES constant - */ - determineEventTypes: function determineEventTypes() { - // determine the eventtype we want to set - var types; - - // pointerEvents magic - if(Hammer.HAS_POINTEREVENTS) { - types = Hammer.PointerEvent.getEvents(); - } - // on Android, iOS, blackberry, windows mobile we dont want any mouseevents - else if(Hammer.NO_MOUSEEVENTS) { - types = [ - 'touchstart', - 'touchmove', - 'touchend touchcancel']; - } - // for non pointer events browsers and mixed browsers, - // like chrome on windows8 touch laptop - else { - types = [ - 'touchstart mousedown', - 'touchmove mousemove', - 'touchend touchcancel mouseup']; - } - - Hammer.EVENT_TYPES[Hammer.EVENT_START] = types[0]; - Hammer.EVENT_TYPES[Hammer.EVENT_MOVE] = types[1]; - Hammer.EVENT_TYPES[Hammer.EVENT_END] = types[2]; - }, - - - /** - * create touchlist depending on the event - * @param {Object} ev - * @param {String} eventType used by the fakemultitouch plugin - */ - getTouchList: function getTouchList(ev/*, eventType*/) { - // get the fake pointerEvent touchlist - if(Hammer.HAS_POINTEREVENTS) { - return Hammer.PointerEvent.getTouchList(); - } - // get the touchlist - else if(ev.touches) { - return ev.touches; - } - // make fake touchlist from mouse position - else { - return [{ - identifier: 1, - pageX: ev.pageX, - pageY: ev.pageY, - target: ev.target - }]; - } - }, - - - /** - * collect event data for Hammer js - * @param {HTMLElement} element - * @param {String} eventType like Hammer.EVENT_MOVE - * @param {Object} eventData - */ - collectEventData: function collectEventData(element, eventType, ev) { - var touches = this.getTouchList(ev, eventType); - - // find out pointerType - var pointerType = Hammer.POINTER_TOUCH; - if(ev.type.match(/mouse/) || Hammer.PointerEvent.matchType(Hammer.POINTER_MOUSE, ev)) { - pointerType = Hammer.POINTER_MOUSE; - } - - return { - center : Hammer.utils.getCenter(touches), - timeStamp : new Date().getTime(), - target : ev.target, - touches : touches, - eventType : eventType, - pointerType : pointerType, - srcEvent : ev, - - /** - * prevent the browser default actions - * mostly used to disable scrolling of the browser - */ - preventDefault: function() { - if(this.srcEvent.preventManipulation) { - this.srcEvent.preventManipulation(); - } - - if(this.srcEvent.preventDefault) { - this.srcEvent.preventDefault(); - } - }, - - /** - * stop bubbling the event up to its parents - */ - stopPropagation: function() { - this.srcEvent.stopPropagation(); - }, - - /** - * immediately stop gesture detection - * might be useful after a swipe was detected - * @return {*} - */ - stopDetect: function() { - return Hammer.detection.stopDetect(); - } - }; - } -}; - -Hammer.PointerEvent = { - /** - * holds all pointers - * @type {Object} - */ - pointers: {}, - - /** - * get a list of pointers - * @returns {Array} touchlist - */ - getTouchList: function() { - var self = this; - var touchlist = []; - - // we can use forEach since pointerEvents only is in IE10 - Object.keys(self.pointers).sort().forEach(function(id) { - touchlist.push(self.pointers[id]); - }); - return touchlist; - }, - - /** - * update the position of a pointer - * @param {String} type Hammer.EVENT_END - * @param {Object} pointerEvent - */ - updatePointer: function(type, pointerEvent) { - if(type == Hammer.EVENT_END) { - this.pointers = {}; - } - else { - pointerEvent.identifier = pointerEvent.pointerId; - this.pointers[pointerEvent.pointerId] = pointerEvent; - } - - return Object.keys(this.pointers).length; - }, - - /** - * check if ev matches pointertype - * @param {String} pointerType Hammer.POINTER_MOUSE - * @param {PointerEvent} ev - */ - matchType: function(pointerType, ev) { - if(!ev.pointerType) { - return false; - } - - var types = {}; - types[Hammer.POINTER_MOUSE] = (ev.pointerType == ev.MSPOINTER_TYPE_MOUSE || ev.pointerType == Hammer.POINTER_MOUSE); - types[Hammer.POINTER_TOUCH] = (ev.pointerType == ev.MSPOINTER_TYPE_TOUCH || ev.pointerType == Hammer.POINTER_TOUCH); - types[Hammer.POINTER_PEN] = (ev.pointerType == ev.MSPOINTER_TYPE_PEN || ev.pointerType == Hammer.POINTER_PEN); - return types[pointerType]; - }, - - - /** - * get events - */ - getEvents: function() { - return [ - 'pointerdown MSPointerDown', - 'pointermove MSPointerMove', - 'pointerup pointercancel MSPointerUp MSPointerCancel' - ]; - }, - - /** - * reset the list - */ - reset: function() { - this.pointers = {}; - } -}; - - -Hammer.utils = { - /** - * extend method, - * also used for cloning when dest is an empty object - * @param {Object} dest - * @param {Object} src - * @parm {Boolean} merge do a merge - * @returns {Object} dest - */ - extend: function extend(dest, src, merge) { - for (var key in src) { - if(dest[key] !== undefined && merge) { - continue; - } - dest[key] = src[key]; - } - return dest; - }, - - - /** - * find if a node is in the given parent - * used for event delegation tricks - * @param {HTMLElement} node - * @param {HTMLElement} parent - * @returns {boolean} has_parent - */ - hasParent: function(node, parent) { - while(node){ - if(node == parent) { - return true; - } - node = node.parentNode; - } - return false; - }, - - - /** - * get the center of all the touches - * @param {Array} touches - * @returns {Object} center - */ - getCenter: function getCenter(touches) { - var valuesX = [], valuesY = []; - - for(var t= 0,len=touches.length; t= y) { - return touch1.pageX - touch2.pageX > 0 ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT; - } - else { - return touch1.pageY - touch2.pageY > 0 ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN; - } - }, - - - /** - * calculate the distance between two touches - * @param {Touch} touch1 - * @param {Touch} touch2 - * @returns {Number} distance - */ - getDistance: function getDistance(touch1, touch2) { - var x = touch2.pageX - touch1.pageX, - y = touch2.pageY - touch1.pageY; - return Math.sqrt((x*x) + (y*y)); - }, - - - /** - * calculate the scale factor between two touchLists (fingers) - * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out - * @param {Array} start - * @param {Array} end - * @returns {Number} scale - */ - getScale: function getScale(start, end) { - // need two fingers... - if(start.length >= 2 && end.length >= 2) { - return this.getDistance(end[0], end[1]) / - this.getDistance(start[0], start[1]); - } - return 1; - }, - - - /** - * calculate the rotation degrees between two touchLists (fingers) - * @param {Array} start - * @param {Array} end - * @returns {Number} rotation - */ - getRotation: function getRotation(start, end) { - // need two fingers - if(start.length >= 2 && end.length >= 2) { - return this.getAngle(end[1], end[0]) - - this.getAngle(start[1], start[0]); - } - return 0; - }, - - - /** - * boolean if the direction is vertical - * @param {String} direction - * @returns {Boolean} is_vertical - */ - isVertical: function isVertical(direction) { - return (direction == Hammer.DIRECTION_UP || direction == Hammer.DIRECTION_DOWN); - }, - - - /** - * stop browser default behavior with css props - * @param {HtmlElement} element - * @param {Object} css_props - */ - stopDefaultBrowserBehavior: function stopDefaultBrowserBehavior(element, css_props) { - var prop, - vendors = ['webkit','khtml','moz','ms','o','']; - - if(!css_props || !element.style) { - return; - } - - // with css properties for modern browsers - for(var i = 0; i < vendors.length; i++) { - for(var p in css_props) { - if(css_props.hasOwnProperty(p)) { - prop = p; - - // vender prefix at the property - if(vendors[i]) { - prop = vendors[i] + prop.substring(0, 1).toUpperCase() + prop.substring(1); - } - - // set the style - element.style[prop] = css_props[p]; - } - } - } - - // also the disable onselectstart - if(css_props.userSelect == 'none') { - element.onselectstart = function() { - return false; - }; - } - } -}; - -Hammer.detection = { - // contains all registred Hammer.gestures in the correct order - gestures: [], - - // data of the current Hammer.gesture detection session - current: null, - - // the previous Hammer.gesture session data - // is a full clone of the previous gesture.current object - previous: null, - - // when this becomes true, no gestures are fired - stopped: false, - - - /** - * start Hammer.gesture detection - * @param {Hammer.Instance} inst - * @param {Object} eventData - */ - startDetect: function startDetect(inst, eventData) { - // already busy with a Hammer.gesture detection on an element - if(this.current) { - return; - } - - this.stopped = false; - - this.current = { - inst : inst, // reference to HammerInstance we're working for - startEvent : Hammer.utils.extend({}, eventData), // start eventData for distances, timing etc - lastEvent : false, // last eventData - name : '' // current gesture we're in/detected, can be 'tap', 'hold' etc - }; - - this.detect(eventData); - }, - - - /** - * Hammer.gesture detection - * @param {Object} eventData - * @param {Object} eventData - */ - detect: function detect(eventData) { - if(!this.current || this.stopped) { - return; - } - - // extend event data with calculations about scale, distance etc - eventData = this.extendEventData(eventData); - - // instance options - var inst_options = this.current.inst.options; - - // call Hammer.gesture handlers - for(var g=0,len=this.gestures.length; g b.index) { - return 1; - } - return 0; - }); - - return this.gestures; - } -}; - - -Hammer.gestures = Hammer.gestures || {}; - -/** - * Custom gestures - * ============================== - * - * Gesture object - * -------------------- - * The object structure of a gesture: - * - * { name: 'mygesture', - * index: 1337, - * defaults: { - * mygesture_option: true - * } - * handler: function(type, ev, inst) { - * // trigger gesture event - * inst.trigger(this.name, ev); - * } - * } - - * @param {String} name - * this should be the name of the gesture, lowercase - * it is also being used to disable/enable the gesture per instance config. - * - * @param {Number} [index=1000] - * the index of the gesture, where it is going to be in the stack of gestures detection - * like when you build an gesture that depends on the drag gesture, it is a good - * idea to place it after the index of the drag gesture. - * - * @param {Object} [defaults={}] - * the default settings of the gesture. these are added to the instance settings, - * and can be overruled per instance. you can also add the name of the gesture, - * but this is also added by default (and set to true). - * - * @param {Function} handler - * this handles the gesture detection of your custom gesture and receives the - * following arguments: - * - * @param {Object} eventData - * event data containing the following properties: - * timeStamp {Number} time the event occurred - * target {HTMLElement} target element - * touches {Array} touches (fingers, pointers, mouse) on the screen - * pointerType {String} kind of pointer that was used. matches Hammer.POINTER_MOUSE|TOUCH - * center {Object} center position of the touches. contains pageX and pageY - * deltaTime {Number} the total time of the touches in the screen - * deltaX {Number} the delta on x axis we haved moved - * deltaY {Number} the delta on y axis we haved moved - * velocityX {Number} the velocity on the x - * velocityY {Number} the velocity on y - * angle {Number} the angle we are moving - * direction {String} the direction we are moving. matches Hammer.DIRECTION_UP|DOWN|LEFT|RIGHT - * distance {Number} the distance we haved moved - * scale {Number} scaling of the touches, needs 2 touches - * rotation {Number} rotation of the touches, needs 2 touches * - * eventType {String} matches Hammer.EVENT_START|MOVE|END - * srcEvent {Object} the source event, like TouchStart or MouseDown * - * startEvent {Object} contains the same properties as above, - * but from the first touch. this is used to calculate - * distances, deltaTime, scaling etc - * - * @param {Hammer.Instance} inst - * the instance we are doing the detection for. you can get the options from - * the inst.options object and trigger the gesture event by calling inst.trigger - * - * - * Handle gestures - * -------------------- - * inside the handler you can get/set Hammer.detection.current. This is the current - * detection session. It has the following properties - * @param {String} name - * contains the name of the gesture we have detected. it has not a real function, - * only to check in other gestures if something is detected. - * like in the drag gesture we set it to 'drag' and in the swipe gesture we can - * check if the current gesture is 'drag' by accessing Hammer.detection.current.name - * - * @readonly - * @param {Hammer.Instance} inst - * the instance we do the detection for - * - * @readonly - * @param {Object} startEvent - * contains the properties of the first gesture detection in this session. - * Used for calculations about timing, distance, etc. - * - * @readonly - * @param {Object} lastEvent - * contains all the properties of the last gesture detect in this session. - * - * after the gesture detection session has been completed (user has released the screen) - * the Hammer.detection.current object is copied into Hammer.detection.previous, - * this is usefull for gestures like doubletap, where you need to know if the - * previous gesture was a tap - * - * options that have been set by the instance can be received by calling inst.options - * - * You can trigger a gesture event by calling inst.trigger("mygesture", event). - * The first param is the name of your gesture, the second the event argument - * - * - * Register gestures - * -------------------- - * When an gesture is added to the Hammer.gestures object, it is auto registered - * at the setup of the first Hammer instance. You can also call Hammer.detection.register - * manually and pass your gesture object as a param - * - */ - -/** - * Hold - * Touch stays at the same place for x time - * @events hold - */ -Hammer.gestures.Hold = { - name: 'hold', - index: 10, - defaults: { - hold_timeout : 500, - hold_threshold : 1 - }, - timer: null, - handler: function holdGesture(ev, inst) { - switch(ev.eventType) { - case Hammer.EVENT_START: - // clear any running timers - clearTimeout(this.timer); - - // set the gesture so we can check in the timeout if it still is - Hammer.detection.current.name = this.name; - - // set timer and if after the timeout it still is hold, - // we trigger the hold event - this.timer = setTimeout(function() { - if(Hammer.detection.current.name == 'hold') { - inst.trigger('hold', ev); - } - }, inst.options.hold_timeout); - break; - - // when you move or end we clear the timer - case Hammer.EVENT_MOVE: - if(ev.distance > inst.options.hold_threshold) { - clearTimeout(this.timer); - } - break; - - case Hammer.EVENT_END: - clearTimeout(this.timer); - break; - } - } -}; - - -/** - * Tap/DoubleTap - * Quick touch at a place or double at the same place - * @events tap, doubletap - */ -Hammer.gestures.Tap = { - name: 'tap', - index: 100, - defaults: { - tap_max_touchtime : 250, - tap_max_distance : 10, - tap_always : true, - doubletap_distance : 20, - doubletap_interval : 300 - }, - handler: function tapGesture(ev, inst) { - if(ev.eventType == Hammer.EVENT_END) { - // previous gesture, for the double tap since these are two different gesture detections - var prev = Hammer.detection.previous, - did_doubletap = false; - - // when the touchtime is higher then the max touch time - // or when the moving distance is too much - if(ev.deltaTime > inst.options.tap_max_touchtime || - ev.distance > inst.options.tap_max_distance) { - return; - } - - // check if double tap - if(prev && prev.name == 'tap' && - (ev.timeStamp - prev.lastEvent.timeStamp) < inst.options.doubletap_interval && - ev.distance < inst.options.doubletap_distance) { - inst.trigger('doubletap', ev); - did_doubletap = true; - } - - // do a single tap - if(!did_doubletap || inst.options.tap_always) { - Hammer.detection.current.name = 'tap'; - inst.trigger(Hammer.detection.current.name, ev); - } - } - } -}; - - -/** - * Swipe - * triggers swipe events when the end velocity is above the threshold - * @events swipe, swipeleft, swiperight, swipeup, swipedown - */ -Hammer.gestures.Swipe = { - name: 'swipe', - index: 40, - defaults: { - // set 0 for unlimited, but this can conflict with transform - swipe_max_touches : 1, - swipe_velocity : 0.7 - }, - handler: function swipeGesture(ev, inst) { - if(ev.eventType == Hammer.EVENT_END) { - // max touches - if(inst.options.swipe_max_touches > 0 && - ev.touches.length > inst.options.swipe_max_touches) { - return; - } - - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(ev.velocityX > inst.options.swipe_velocity || - ev.velocityY > inst.options.swipe_velocity) { - // trigger swipe events - inst.trigger(this.name, ev); - inst.trigger(this.name + ev.direction, ev); - } - } - } -}; - - -/** - * Drag - * Move with x fingers (default 1) around on the page. Blocking the scrolling when - * moving left and right is a good practice. When all the drag events are blocking - * you disable scrolling on that area. - * @events drag, drapleft, dragright, dragup, dragdown - */ -Hammer.gestures.Drag = { - name: 'drag', - index: 50, - defaults: { - drag_min_distance : 10, - // set 0 for unlimited, but this can conflict with transform - drag_max_touches : 1, - // prevent default browser behavior when dragging occurs - // be careful with it, it makes the element a blocking element - // when you are using the drag gesture, it is a good practice to set this true - drag_block_horizontal : false, - drag_block_vertical : false, - // drag_lock_to_axis keeps the drag gesture on the axis that it started on, - // It disallows vertical directions if the initial direction was horizontal, and vice versa. - drag_lock_to_axis : false, - // drag lock only kicks in when distance > drag_lock_min_distance - // This way, locking occurs only when the distance has become large enough to reliably determine the direction - drag_lock_min_distance : 25 - }, - triggered: false, - handler: function dragGesture(ev, inst) { - // current gesture isnt drag, but dragged is true - // this means an other gesture is busy. now call dragend - if(Hammer.detection.current.name != this.name && this.triggered) { - inst.trigger(this.name +'end', ev); - this.triggered = false; - return; - } - - // max touches - if(inst.options.drag_max_touches > 0 && - ev.touches.length > inst.options.drag_max_touches) { - return; - } - - switch(ev.eventType) { - case Hammer.EVENT_START: - this.triggered = false; - break; - - case Hammer.EVENT_MOVE: - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(ev.distance < inst.options.drag_min_distance && - Hammer.detection.current.name != this.name) { - return; - } - - // we are dragging! - Hammer.detection.current.name = this.name; - - // lock drag to axis? - if(Hammer.detection.current.lastEvent.drag_locked_to_axis || (inst.options.drag_lock_to_axis && inst.options.drag_lock_min_distance<=ev.distance)) { - ev.drag_locked_to_axis = true; - } - var last_direction = Hammer.detection.current.lastEvent.direction; - if(ev.drag_locked_to_axis && last_direction !== ev.direction) { - // keep direction on the axis that the drag gesture started on - if(Hammer.utils.isVertical(last_direction)) { - ev.direction = (ev.deltaY < 0) ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN; - } - else { - ev.direction = (ev.deltaX < 0) ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT; - } - } - - // first time, trigger dragstart event - if(!this.triggered) { - inst.trigger(this.name +'start', ev); - this.triggered = true; - } - - // trigger normal event - inst.trigger(this.name, ev); - - // direction event, like dragdown - inst.trigger(this.name + ev.direction, ev); - - // block the browser events - if( (inst.options.drag_block_vertical && Hammer.utils.isVertical(ev.direction)) || - (inst.options.drag_block_horizontal && !Hammer.utils.isVertical(ev.direction))) { - ev.preventDefault(); - } - break; - - case Hammer.EVENT_END: - // trigger dragend - if(this.triggered) { - inst.trigger(this.name +'end', ev); - } - - this.triggered = false; - break; - } - } -}; - - -/** - * Transform - * User want to scale or rotate with 2 fingers - * @events transform, pinch, pinchin, pinchout, rotate - */ -Hammer.gestures.Transform = { - name: 'transform', - index: 45, - defaults: { - // factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1 - transform_min_scale : 0.01, - // rotation in degrees - transform_min_rotation : 1, - // prevent default browser behavior when two touches are on the screen - // but it makes the element a blocking element - // when you are using the transform gesture, it is a good practice to set this true - transform_always_block : false - }, - triggered: false, - handler: function transformGesture(ev, inst) { - // current gesture isnt drag, but dragged is true - // this means an other gesture is busy. now call dragend - if(Hammer.detection.current.name != this.name && this.triggered) { - inst.trigger(this.name +'end', ev); - this.triggered = false; - return; - } - - // atleast multitouch - if(ev.touches.length < 2) { - return; - } - - // prevent default when two fingers are on the screen - if(inst.options.transform_always_block) { - ev.preventDefault(); - } - - switch(ev.eventType) { - case Hammer.EVENT_START: - this.triggered = false; - break; - - case Hammer.EVENT_MOVE: - var scale_threshold = Math.abs(1-ev.scale); - var rotation_threshold = Math.abs(ev.rotation); - - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(scale_threshold < inst.options.transform_min_scale && - rotation_threshold < inst.options.transform_min_rotation) { - return; - } - - // we are transforming! - Hammer.detection.current.name = this.name; - - // first time, trigger dragstart event - if(!this.triggered) { - inst.trigger(this.name +'start', ev); - this.triggered = true; - } - - inst.trigger(this.name, ev); // basic transform event - - // trigger rotate event - if(rotation_threshold > inst.options.transform_min_rotation) { - inst.trigger('rotate', ev); - } - - // trigger pinch event - if(scale_threshold > inst.options.transform_min_scale) { - inst.trigger('pinch', ev); - inst.trigger('pinch'+ ((ev.scale < 1) ? 'in' : 'out'), ev); - } - break; - - case Hammer.EVENT_END: - // trigger dragend - if(this.triggered) { - inst.trigger(this.name +'end', ev); - } - - this.triggered = false; - break; - } - } -}; - - -/** - * Touch - * Called as first, tells the user has touched the screen - * @events touch - */ -Hammer.gestures.Touch = { - name: 'touch', - index: -Infinity, - defaults: { - // call preventDefault at touchstart, and makes the element blocking by - // disabling the scrolling of the page, but it improves gestures like - // transforming and dragging. - // be careful with using this, it can be very annoying for users to be stuck - // on the page - prevent_default: false, - - // disable mouse events, so only touch (or pen!) input triggers events - prevent_mouseevents: false - }, - handler: function touchGesture(ev, inst) { - if(inst.options.prevent_mouseevents && ev.pointerType == Hammer.POINTER_MOUSE) { - ev.stopDetect(); - return; - } - - if(inst.options.prevent_default) { - ev.preventDefault(); - } - - if(ev.eventType == Hammer.EVENT_START) { - inst.trigger(this.name, ev); - } - } -}; - - -/** - * Release - * Called as last, tells the user has released the screen - * @events release - */ -Hammer.gestures.Release = { - name: 'release', - index: Infinity, - handler: function releaseGesture(ev, inst) { - if(ev.eventType == Hammer.EVENT_END) { - inst.trigger(this.name, ev); - } - } -}; - -// node export -if(typeof module === 'object' && typeof module.exports === 'object'){ - module.exports = Hammer; -} -// just window export -else { - window.Hammer = Hammer; - - // requireJS module definition - if(typeof window.define === 'function' && window.define.amd) { - window.define('hammer', [], function() { - return Hammer; - }); - } -} -})(this); -},{}],2:[function(require,module,exports){ -//! moment.js -//! version : 2.2.1 -//! authors : Tim Wood, Iskren Chernev, Moment.js contributors -//! license : MIT -//! momentjs.com - -(function (undefined) { - - /************************************ - Constants - ************************************/ - - var moment, - VERSION = "2.2.1", - round = Math.round, i, - // internal storage for language config files - languages = {}, - - // check for nodeJS - hasModule = (typeof module !== 'undefined' && module.exports), - - // ASP.NET json date format regex - aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, - aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)\:(\d+)\.?(\d{3})?/, - - // format tokens - formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|SS?S?|X|zz?|ZZ?|.)/g, - localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g, - - // parsing token regexes - parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 - parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 - parseTokenThreeDigits = /\d{3}/, // 000 - 999 - parseTokenFourDigits = /\d{1,4}/, // 0 - 9999 - parseTokenSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 - parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic. - parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/i, // +00:00 -00:00 +0000 -0000 or Z - parseTokenT = /T/i, // T (ISO seperator) - parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 - - // preliminary iso regex - // 0000-00-00 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 - isoRegex = /^\s*\d{4}-\d\d-\d\d((T| )(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/, - isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', - - // iso time formats and regexes - isoTimes = [ - ['HH:mm:ss.S', /(T| )\d\d:\d\d:\d\d\.\d{1,3}/], - ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], - ['HH:mm', /(T| )\d\d:\d\d/], - ['HH', /(T| )\d\d/] - ], - - // timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"] - parseTimezoneChunker = /([\+\-]|\d\d)/gi, - - // getter and setter names - proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), - unitMillisecondFactors = { - 'Milliseconds' : 1, - 'Seconds' : 1e3, - 'Minutes' : 6e4, - 'Hours' : 36e5, - 'Days' : 864e5, - 'Months' : 2592e6, - 'Years' : 31536e6 - }, - - unitAliases = { - ms : 'millisecond', - s : 'second', - m : 'minute', - h : 'hour', - d : 'day', - w : 'week', - W : 'isoweek', - M : 'month', - y : 'year' - }, - - // format function strings - formatFunctions = {}, - - // tokens to ordinalize and pad - ordinalizeTokens = 'DDD w W M D d'.split(' '), - paddedTokens = 'M D H h m s w W'.split(' '), - - formatTokenFunctions = { - M : function () { - return this.month() + 1; - }, - MMM : function (format) { - return this.lang().monthsShort(this, format); - }, - MMMM : function (format) { - return this.lang().months(this, format); - }, - D : function () { - return this.date(); - }, - DDD : function () { - return this.dayOfYear(); - }, - d : function () { - return this.day(); - }, - dd : function (format) { - return this.lang().weekdaysMin(this, format); - }, - ddd : function (format) { - return this.lang().weekdaysShort(this, format); - }, - dddd : function (format) { - return this.lang().weekdays(this, format); - }, - w : function () { - return this.week(); - }, - W : function () { - return this.isoWeek(); - }, - YY : function () { - return leftZeroFill(this.year() % 100, 2); - }, - YYYY : function () { - return leftZeroFill(this.year(), 4); - }, - YYYYY : function () { - return leftZeroFill(this.year(), 5); - }, - gg : function () { - return leftZeroFill(this.weekYear() % 100, 2); - }, - gggg : function () { - return this.weekYear(); - }, - ggggg : function () { - return leftZeroFill(this.weekYear(), 5); - }, - GG : function () { - return leftZeroFill(this.isoWeekYear() % 100, 2); - }, - GGGG : function () { - return this.isoWeekYear(); - }, - GGGGG : function () { - return leftZeroFill(this.isoWeekYear(), 5); - }, - e : function () { - return this.weekday(); - }, - E : function () { - return this.isoWeekday(); - }, - a : function () { - return this.lang().meridiem(this.hours(), this.minutes(), true); - }, - A : function () { - return this.lang().meridiem(this.hours(), this.minutes(), false); - }, - H : function () { - return this.hours(); - }, - h : function () { - return this.hours() % 12 || 12; - }, - m : function () { - return this.minutes(); - }, - s : function () { - return this.seconds(); - }, - S : function () { - return ~~(this.milliseconds() / 100); - }, - SS : function () { - return leftZeroFill(~~(this.milliseconds() / 10), 2); - }, - SSS : function () { - return leftZeroFill(this.milliseconds(), 3); - }, - Z : function () { - var a = -this.zone(), - b = "+"; - if (a < 0) { - a = -a; - b = "-"; - } - return b + leftZeroFill(~~(a / 60), 2) + ":" + leftZeroFill(~~a % 60, 2); - }, - ZZ : function () { - var a = -this.zone(), - b = "+"; - if (a < 0) { - a = -a; - b = "-"; - } - return b + leftZeroFill(~~(10 * a / 6), 4); - }, - z : function () { - return this.zoneAbbr(); - }, - zz : function () { - return this.zoneName(); - }, - X : function () { - return this.unix(); - } - }; - - function padToken(func, count) { - return function (a) { - return leftZeroFill(func.call(this, a), count); - }; - } - function ordinalizeToken(func, period) { - return function (a) { - return this.lang().ordinal(func.call(this, a), period); - }; - } - - while (ordinalizeTokens.length) { - i = ordinalizeTokens.pop(); - formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i); - } - while (paddedTokens.length) { - i = paddedTokens.pop(); - formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); - } - formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); - - - /************************************ - Constructors - ************************************/ - - function Language() { - - } - - // Moment prototype object - function Moment(config) { - extend(this, config); - } - - // Duration Constructor - function Duration(duration) { - var years = duration.years || duration.year || duration.y || 0, - months = duration.months || duration.month || duration.M || 0, - weeks = duration.weeks || duration.week || duration.w || 0, - days = duration.days || duration.day || duration.d || 0, - hours = duration.hours || duration.hour || duration.h || 0, - minutes = duration.minutes || duration.minute || duration.m || 0, - seconds = duration.seconds || duration.second || duration.s || 0, - milliseconds = duration.milliseconds || duration.millisecond || duration.ms || 0; - - // store reference to input for deterministic cloning - this._input = duration; - - // representation for dateAddRemove - this._milliseconds = +milliseconds + - seconds * 1e3 + // 1000 - minutes * 6e4 + // 1000 * 60 - hours * 36e5; // 1000 * 60 * 60 - // Because of dateAddRemove treats 24 hours as different from a - // day when working around DST, we need to store them separately - this._days = +days + - weeks * 7; - // It is impossible translate months into days without knowing - // which months you are are talking about, so we have to store - // it separately. - this._months = +months + - years * 12; - - this._data = {}; - - this._bubble(); - } - - - /************************************ - Helpers - ************************************/ - - - function extend(a, b) { - for (var i in b) { - if (b.hasOwnProperty(i)) { - a[i] = b[i]; - } - } - return a; - } - - function absRound(number) { - if (number < 0) { - return Math.ceil(number); - } else { - return Math.floor(number); - } - } - - // left zero fill a number - // see http://jsperf.com/left-zero-filling for performance comparison - function leftZeroFill(number, targetLength) { - var output = number + ''; - while (output.length < targetLength) { - output = '0' + output; - } - return output; - } - - // helper function for _.addTime and _.subtractTime - function addOrSubtractDurationFromMoment(mom, duration, isAdding, ignoreUpdateOffset) { - var milliseconds = duration._milliseconds, - days = duration._days, - months = duration._months, - minutes, - hours; - - if (milliseconds) { - mom._d.setTime(+mom._d + milliseconds * isAdding); - } - // store the minutes and hours so we can restore them - if (days || months) { - minutes = mom.minute(); - hours = mom.hour(); - } - if (days) { - mom.date(mom.date() + days * isAdding); - } - if (months) { - mom.month(mom.month() + months * isAdding); - } - if (milliseconds && !ignoreUpdateOffset) { - moment.updateOffset(mom); - } - // restore the minutes and hours after possibly changing dst - if (days || months) { - mom.minute(minutes); - mom.hour(hours); - } - } - - // check if is an array - function isArray(input) { - return Object.prototype.toString.call(input) === '[object Array]'; - } - - // compare two arrays, return the number of differences - function compareArrays(array1, array2) { - var len = Math.min(array1.length, array2.length), - lengthDiff = Math.abs(array1.length - array2.length), - diffs = 0, - i; - for (i = 0; i < len; i++) { - if (~~array1[i] !== ~~array2[i]) { - diffs++; - } - } - return diffs + lengthDiff; - } - - function normalizeUnits(units) { - return units ? unitAliases[units] || units.toLowerCase().replace(/(.)s$/, '$1') : units; - } - - - /************************************ - Languages - ************************************/ - - - extend(Language.prototype, { - - set : function (config) { - var prop, i; - for (i in config) { - prop = config[i]; - if (typeof prop === 'function') { - this[i] = prop; - } else { - this['_' + i] = prop; - } - } - }, - - _months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), - months : function (m) { - return this._months[m.month()]; - }, - - _monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"), - monthsShort : function (m) { - return this._monthsShort[m.month()]; - }, - - monthsParse : function (monthName) { - var i, mom, regex; - - if (!this._monthsParse) { - this._monthsParse = []; - } - - for (i = 0; i < 12; i++) { - // make the regex if we don't have it already - if (!this._monthsParse[i]) { - mom = moment.utc([2000, i]); - regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); - this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (this._monthsParse[i].test(monthName)) { - return i; - } - } - }, - - _weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), - weekdays : function (m) { - return this._weekdays[m.day()]; - }, - - _weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"), - weekdaysShort : function (m) { - return this._weekdaysShort[m.day()]; - }, - - _weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"), - weekdaysMin : function (m) { - return this._weekdaysMin[m.day()]; - }, - - weekdaysParse : function (weekdayName) { - var i, mom, regex; - - if (!this._weekdaysParse) { - this._weekdaysParse = []; - } - - for (i = 0; i < 7; i++) { - // make the regex if we don't have it already - if (!this._weekdaysParse[i]) { - mom = moment([2000, 1]).day(i); - regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); - this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (this._weekdaysParse[i].test(weekdayName)) { - return i; - } - } - }, - - _longDateFormat : { - LT : "h:mm A", - L : "MM/DD/YYYY", - LL : "MMMM D YYYY", - LLL : "MMMM D YYYY LT", - LLLL : "dddd, MMMM D YYYY LT" - }, - longDateFormat : function (key) { - var output = this._longDateFormat[key]; - if (!output && this._longDateFormat[key.toUpperCase()]) { - output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { - return val.slice(1); - }); - this._longDateFormat[key] = output; - } - return output; - }, - - isPM : function (input) { - // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays - // Using charAt should be more compatible. - return ((input + '').toLowerCase().charAt(0) === 'p'); - }, - - _meridiemParse : /[ap]\.?m?\.?/i, - meridiem : function (hours, minutes, isLower) { - if (hours > 11) { - return isLower ? 'pm' : 'PM'; - } else { - return isLower ? 'am' : 'AM'; - } - }, - - _calendar : { - sameDay : '[Today at] LT', - nextDay : '[Tomorrow at] LT', - nextWeek : 'dddd [at] LT', - lastDay : '[Yesterday at] LT', - lastWeek : '[Last] dddd [at] LT', - sameElse : 'L' - }, - calendar : function (key, mom) { - var output = this._calendar[key]; - return typeof output === 'function' ? output.apply(mom) : output; - }, - - _relativeTime : { - future : "in %s", - past : "%s ago", - s : "a few seconds", - m : "a minute", - mm : "%d minutes", - h : "an hour", - hh : "%d hours", - d : "a day", - dd : "%d days", - M : "a month", - MM : "%d months", - y : "a year", - yy : "%d years" - }, - relativeTime : function (number, withoutSuffix, string, isFuture) { - var output = this._relativeTime[string]; - return (typeof output === 'function') ? - output(number, withoutSuffix, string, isFuture) : - output.replace(/%d/i, number); - }, - pastFuture : function (diff, output) { - var format = this._relativeTime[diff > 0 ? 'future' : 'past']; - return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); - }, - - ordinal : function (number) { - return this._ordinal.replace("%d", number); - }, - _ordinal : "%d", - - preparse : function (string) { - return string; - }, - - postformat : function (string) { - return string; - }, - - week : function (mom) { - return weekOfYear(mom, this._week.dow, this._week.doy).week; - }, - _week : { - dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. - } - }); - - // Loads a language definition into the `languages` cache. The function - // takes a key and optionally values. If not in the browser and no values - // are provided, it will load the language file module. As a convenience, - // this function also returns the language values. - function loadLang(key, values) { - values.abbr = key; - if (!languages[key]) { - languages[key] = new Language(); - } - languages[key].set(values); - return languages[key]; - } - - // Remove a language from the `languages` cache. Mostly useful in tests. - function unloadLang(key) { - delete languages[key]; - } - - // Determines which language definition to use and returns it. - // - // With no parameters, it will return the global language. If you - // pass in a language key, such as 'en', it will return the - // definition for 'en', so long as 'en' has already been loaded using - // moment.lang. - function getLangDefinition(key) { - if (!key) { - return moment.fn._lang; - } - if (!languages[key] && hasModule) { - try { - require('./lang/' + key); - } catch (e) { - // call with no params to set to default - return moment.fn._lang; - } - } - return languages[key] || moment.fn._lang; - } - - - /************************************ - Formatting - ************************************/ - - - function removeFormattingTokens(input) { - if (input.match(/\[.*\]/)) { - return input.replace(/^\[|\]$/g, ""); - } - return input.replace(/\\/g, ""); - } - - function makeFormatFunction(format) { - var array = format.match(formattingTokens), i, length; - - for (i = 0, length = array.length; i < length; i++) { - if (formatTokenFunctions[array[i]]) { - array[i] = formatTokenFunctions[array[i]]; - } else { - array[i] = removeFormattingTokens(array[i]); - } - } - - return function (mom) { - var output = ""; - for (i = 0; i < length; i++) { - output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; - } - return output; - }; - } - - // format date using native date object - function formatMoment(m, format) { - - format = expandFormat(format, m.lang()); - - if (!formatFunctions[format]) { - formatFunctions[format] = makeFormatFunction(format); - } - - return formatFunctions[format](m); - } - - function expandFormat(format, lang) { - var i = 5; - - function replaceLongDateFormatTokens(input) { - return lang.longDateFormat(input) || input; - } - - while (i-- && (localFormattingTokens.lastIndex = 0, - localFormattingTokens.test(format))) { - format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); - } - - return format; - } - - - /************************************ - Parsing - ************************************/ - - - // get the regex to find the next token - function getParseRegexForToken(token, config) { - switch (token) { - case 'DDDD': - return parseTokenThreeDigits; - case 'YYYY': - return parseTokenFourDigits; - case 'YYYYY': - return parseTokenSixDigits; - case 'S': - case 'SS': - case 'SSS': - case 'DDD': - return parseTokenOneToThreeDigits; - case 'MMM': - case 'MMMM': - case 'dd': - case 'ddd': - case 'dddd': - return parseTokenWord; - case 'a': - case 'A': - return getLangDefinition(config._l)._meridiemParse; - case 'X': - return parseTokenTimestampMs; - case 'Z': - case 'ZZ': - return parseTokenTimezone; - case 'T': - return parseTokenT; - case 'MM': - case 'DD': - case 'YY': - case 'HH': - case 'hh': - case 'mm': - case 'ss': - case 'M': - case 'D': - case 'd': - case 'H': - case 'h': - case 'm': - case 's': - return parseTokenOneOrTwoDigits; - default : - return new RegExp(token.replace('\\', '')); - } - } - - function timezoneMinutesFromString(string) { - var tzchunk = (parseTokenTimezone.exec(string) || [])[0], - parts = (tzchunk + '').match(parseTimezoneChunker) || ['-', 0, 0], - minutes = +(parts[1] * 60) + ~~parts[2]; - - return parts[0] === '+' ? -minutes : minutes; - } - - // function to convert string input to date - function addTimeToArrayFromToken(token, input, config) { - var a, datePartArray = config._a; - - switch (token) { - // MONTH - case 'M' : // fall through to MM - case 'MM' : - if (input != null) { - datePartArray[1] = ~~input - 1; - } - break; - case 'MMM' : // fall through to MMMM - case 'MMMM' : - a = getLangDefinition(config._l).monthsParse(input); - // if we didn't find a month name, mark the date as invalid. - if (a != null) { - datePartArray[1] = a; - } else { - config._isValid = false; - } - break; - // DAY OF MONTH - case 'D' : // fall through to DD - case 'DD' : - if (input != null) { - datePartArray[2] = ~~input; - } - break; - // DAY OF YEAR - case 'DDD' : // fall through to DDDD - case 'DDDD' : - if (input != null) { - datePartArray[1] = 0; - datePartArray[2] = ~~input; - } - break; - // YEAR - case 'YY' : - datePartArray[0] = ~~input + (~~input > 68 ? 1900 : 2000); - break; - case 'YYYY' : - case 'YYYYY' : - datePartArray[0] = ~~input; - break; - // AM / PM - case 'a' : // fall through to A - case 'A' : - config._isPm = getLangDefinition(config._l).isPM(input); - break; - // 24 HOUR - case 'H' : // fall through to hh - case 'HH' : // fall through to hh - case 'h' : // fall through to hh - case 'hh' : - datePartArray[3] = ~~input; - break; - // MINUTE - case 'm' : // fall through to mm - case 'mm' : - datePartArray[4] = ~~input; - break; - // SECOND - case 's' : // fall through to ss - case 'ss' : - datePartArray[5] = ~~input; - break; - // MILLISECOND - case 'S' : - case 'SS' : - case 'SSS' : - datePartArray[6] = ~~ (('0.' + input) * 1000); - break; - // UNIX TIMESTAMP WITH MS - case 'X': - config._d = new Date(parseFloat(input) * 1000); - break; - // TIMEZONE - case 'Z' : // fall through to ZZ - case 'ZZ' : - config._useUTC = true; - config._tzm = timezoneMinutesFromString(input); - break; - } - - // if the input is null, the date is not valid - if (input == null) { - config._isValid = false; - } - } - - // convert an array to a date. - // the array should mirror the parameters below - // note: all values past the year are optional and will default to the lowest possible value. - // [year, month, day , hour, minute, second, millisecond] - function dateFromArray(config) { - var i, date, input = [], currentDate; - - if (config._d) { - return; - } - - // Default to current date. - // * if no year, month, day of month are given, default to today - // * if day of month is given, default month and year - // * if month is given, default only year - // * if year is given, don't default anything - currentDate = currentDateArray(config); - for (i = 0; i < 3 && config._a[i] == null; ++i) { - config._a[i] = input[i] = currentDate[i]; - } - - // Zero out whatever was not defaulted, including time - for (; i < 7; i++) { - config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; - } - - // add the offsets to the time to be parsed so that we can have a clean array for checking isValid - input[3] += ~~((config._tzm || 0) / 60); - input[4] += ~~((config._tzm || 0) % 60); - - date = new Date(0); - - if (config._useUTC) { - date.setUTCFullYear(input[0], input[1], input[2]); - date.setUTCHours(input[3], input[4], input[5], input[6]); - } else { - date.setFullYear(input[0], input[1], input[2]); - date.setHours(input[3], input[4], input[5], input[6]); - } - - config._d = date; - } - - function dateFromObject(config) { - var o = config._i; - - if (config._d) { - return; - } - - config._a = [ - o.years || o.year || o.y, - o.months || o.month || o.M, - o.days || o.day || o.d, - o.hours || o.hour || o.h, - o.minutes || o.minute || o.m, - o.seconds || o.second || o.s, - o.milliseconds || o.millisecond || o.ms - ]; - - dateFromArray(config); - } - - function currentDateArray(config) { - var now = new Date(); - if (config._useUTC) { - return [ - now.getUTCFullYear(), - now.getUTCMonth(), - now.getUTCDate() - ]; - } else { - return [now.getFullYear(), now.getMonth(), now.getDate()]; - } - } - - // date from string and format string - function makeDateFromStringAndFormat(config) { - // This array is used to make a Date, either with `new Date` or `Date.UTC` - var lang = getLangDefinition(config._l), - string = '' + config._i, - i, parsedInput, tokens; - - tokens = expandFormat(config._f, lang).match(formattingTokens); - - config._a = []; - - for (i = 0; i < tokens.length; i++) { - parsedInput = (getParseRegexForToken(tokens[i], config).exec(string) || [])[0]; - if (parsedInput) { - string = string.slice(string.indexOf(parsedInput) + parsedInput.length); - } - // don't parse if its not a known token - if (formatTokenFunctions[tokens[i]]) { - addTimeToArrayFromToken(tokens[i], parsedInput, config); - } - } - - // add remaining unparsed input to the string - if (string) { - config._il = string; - } - - // handle am pm - if (config._isPm && config._a[3] < 12) { - config._a[3] += 12; - } - // if is 12 am, change hours to 0 - if (config._isPm === false && config._a[3] === 12) { - config._a[3] = 0; - } - // return - dateFromArray(config); - } - - // date from string and array of format strings - function makeDateFromStringAndArray(config) { - var tempConfig, - tempMoment, - bestMoment, - - scoreToBeat = 99, - i, - currentScore; - - for (i = 0; i < config._f.length; i++) { - tempConfig = extend({}, config); - tempConfig._f = config._f[i]; - makeDateFromStringAndFormat(tempConfig); - tempMoment = new Moment(tempConfig); - - currentScore = compareArrays(tempConfig._a, tempMoment.toArray()); - - // if there is any input that was not parsed - // add a penalty for that format - if (tempMoment._il) { - currentScore += tempMoment._il.length; - } - - if (currentScore < scoreToBeat) { - scoreToBeat = currentScore; - bestMoment = tempMoment; - } - } - - extend(config, bestMoment); - } - - // date from iso format - function makeDateFromString(config) { - var i, - string = config._i, - match = isoRegex.exec(string); - - if (match) { - // match[2] should be "T" or undefined - config._f = 'YYYY-MM-DD' + (match[2] || " "); - for (i = 0; i < 4; i++) { - if (isoTimes[i][1].exec(string)) { - config._f += isoTimes[i][0]; - break; - } - } - if (parseTokenTimezone.exec(string)) { - config._f += " Z"; - } - makeDateFromStringAndFormat(config); - } else { - config._d = new Date(string); - } - } - - function makeDateFromInput(config) { - var input = config._i, - matched = aspNetJsonRegex.exec(input); - - if (input === undefined) { - config._d = new Date(); - } else if (matched) { - config._d = new Date(+matched[1]); - } else if (typeof input === 'string') { - makeDateFromString(config); - } else if (isArray(input)) { - config._a = input.slice(0); - dateFromArray(config); - } else if (input instanceof Date) { - config._d = new Date(+input); - } else if (typeof(input) === 'object') { - dateFromObject(config); - } else { - config._d = new Date(input); - } - } - - - /************************************ - Relative Time - ************************************/ - - - // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize - function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) { - return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture); - } - - function relativeTime(milliseconds, withoutSuffix, lang) { - var seconds = round(Math.abs(milliseconds) / 1000), - minutes = round(seconds / 60), - hours = round(minutes / 60), - days = round(hours / 24), - years = round(days / 365), - args = seconds < 45 && ['s', seconds] || - minutes === 1 && ['m'] || - minutes < 45 && ['mm', minutes] || - hours === 1 && ['h'] || - hours < 22 && ['hh', hours] || - days === 1 && ['d'] || - days <= 25 && ['dd', days] || - days <= 45 && ['M'] || - days < 345 && ['MM', round(days / 30)] || - years === 1 && ['y'] || ['yy', years]; - args[2] = withoutSuffix; - args[3] = milliseconds > 0; - args[4] = lang; - return substituteTimeAgo.apply({}, args); - } - - - /************************************ - Week of Year - ************************************/ - - - // firstDayOfWeek 0 = sun, 6 = sat - // the day of the week that starts the week - // (usually sunday or monday) - // firstDayOfWeekOfYear 0 = sun, 6 = sat - // the first week is the week that contains the first - // of this day of the week - // (eg. ISO weeks use thursday (4)) - function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { - var end = firstDayOfWeekOfYear - firstDayOfWeek, - daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), - adjustedMoment; - - - if (daysToDayOfWeek > end) { - daysToDayOfWeek -= 7; - } - - if (daysToDayOfWeek < end - 7) { - daysToDayOfWeek += 7; - } - - adjustedMoment = moment(mom).add('d', daysToDayOfWeek); - return { - week: Math.ceil(adjustedMoment.dayOfYear() / 7), - year: adjustedMoment.year() - }; - } - - - /************************************ - Top Level Functions - ************************************/ - - function makeMoment(config) { - var input = config._i, - format = config._f; - - if (input === null || input === '') { - return null; - } - - if (typeof input === 'string') { - config._i = input = getLangDefinition().preparse(input); - } - - if (moment.isMoment(input)) { - config = extend({}, input); - config._d = new Date(+input._d); - } else if (format) { - if (isArray(format)) { - makeDateFromStringAndArray(config); - } else { - makeDateFromStringAndFormat(config); - } - } else { - makeDateFromInput(config); - } - - return new Moment(config); - } - - moment = function (input, format, lang) { - return makeMoment({ - _i : input, - _f : format, - _l : lang, - _isUTC : false - }); - }; - - // creating with utc - moment.utc = function (input, format, lang) { - return makeMoment({ - _useUTC : true, - _isUTC : true, - _l : lang, - _i : input, - _f : format - }).utc(); - }; - - // creating with unix timestamp (in seconds) - moment.unix = function (input) { - return moment(input * 1000); - }; - - // duration - moment.duration = function (input, key) { - var isDuration = moment.isDuration(input), - isNumber = (typeof input === 'number'), - duration = (isDuration ? input._input : (isNumber ? {} : input)), - matched = aspNetTimeSpanJsonRegex.exec(input), - sign, - ret; - - if (isNumber) { - if (key) { - duration[key] = input; - } else { - duration.milliseconds = input; - } - } else if (matched) { - sign = (matched[1] === "-") ? -1 : 1; - duration = { - y: 0, - d: ~~matched[2] * sign, - h: ~~matched[3] * sign, - m: ~~matched[4] * sign, - s: ~~matched[5] * sign, - ms: ~~matched[6] * sign - }; - } - - ret = new Duration(duration); - - if (isDuration && input.hasOwnProperty('_lang')) { - ret._lang = input._lang; - } - - return ret; - }; - - // version number - moment.version = VERSION; - - // default format - moment.defaultFormat = isoFormat; - - // This function will be called whenever a moment is mutated. - // It is intended to keep the offset in sync with the timezone. - moment.updateOffset = function () {}; - - // This function will load languages and then set the global language. If - // no arguments are passed in, it will simply return the current global - // language key. - moment.lang = function (key, values) { - if (!key) { - return moment.fn._lang._abbr; - } - key = key.toLowerCase(); - key = key.replace('_', '-'); - if (values) { - loadLang(key, values); - } else if (values === null) { - unloadLang(key); - key = 'en'; - } else if (!languages[key]) { - getLangDefinition(key); - } - moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key); - }; - - // returns language data - moment.langData = function (key) { - if (key && key._lang && key._lang._abbr) { - key = key._lang._abbr; - } - return getLangDefinition(key); - }; - - // compare moment object - moment.isMoment = function (obj) { - return obj instanceof Moment; - }; - - // for typechecking Duration objects - moment.isDuration = function (obj) { - return obj instanceof Duration; - }; - - - /************************************ - Moment Prototype - ************************************/ - - - extend(moment.fn = Moment.prototype, { - - clone : function () { - return moment(this); - }, - - valueOf : function () { - return +this._d + ((this._offset || 0) * 60000); - }, - - unix : function () { - return Math.floor(+this / 1000); - }, - - toString : function () { - return this.format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ"); - }, - - toDate : function () { - return this._offset ? new Date(+this) : this._d; - }, - - toISOString : function () { - return formatMoment(moment(this).utc(), 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); - }, - - toArray : function () { - var m = this; - return [ - m.year(), - m.month(), - m.date(), - m.hours(), - m.minutes(), - m.seconds(), - m.milliseconds() - ]; - }, - - isValid : function () { - if (this._isValid == null) { - if (this._a) { - this._isValid = !compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()); - } else { - this._isValid = !isNaN(this._d.getTime()); - } - } - return !!this._isValid; - }, - - invalidAt: function () { - var i, arr1 = this._a, arr2 = (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray(); - for (i = 6; i >= 0 && arr1[i] === arr2[i]; --i) { - // empty loop body - } - return i; - }, - - utc : function () { - return this.zone(0); - }, - - local : function () { - this.zone(0); - this._isUTC = false; - return this; - }, - - format : function (inputString) { - var output = formatMoment(this, inputString || moment.defaultFormat); - return this.lang().postformat(output); - }, - - add : function (input, val) { - var dur; - // switch args to support add('s', 1) and add(1, 's') - if (typeof input === 'string') { - dur = moment.duration(+val, input); - } else { - dur = moment.duration(input, val); - } - addOrSubtractDurationFromMoment(this, dur, 1); - return this; - }, - - subtract : function (input, val) { - var dur; - // switch args to support subtract('s', 1) and subtract(1, 's') - if (typeof input === 'string') { - dur = moment.duration(+val, input); - } else { - dur = moment.duration(input, val); - } - addOrSubtractDurationFromMoment(this, dur, -1); - return this; - }, - - diff : function (input, units, asFloat) { - var that = this._isUTC ? moment(input).zone(this._offset || 0) : moment(input).local(), - zoneDiff = (this.zone() - that.zone()) * 6e4, - diff, output; - - units = normalizeUnits(units); - - if (units === 'year' || units === 'month') { - // average number of days in the months in the given dates - diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2 - // difference in months - output = ((this.year() - that.year()) * 12) + (this.month() - that.month()); - // adjust by taking difference in days, average number of days - // and dst in the given months. - output += ((this - moment(this).startOf('month')) - - (that - moment(that).startOf('month'))) / diff; - // same as above but with zones, to negate all dst - output -= ((this.zone() - moment(this).startOf('month').zone()) - - (that.zone() - moment(that).startOf('month').zone())) * 6e4 / diff; - if (units === 'year') { - output = output / 12; - } - } else { - diff = (this - that); - output = units === 'second' ? diff / 1e3 : // 1000 - units === 'minute' ? diff / 6e4 : // 1000 * 60 - units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 - units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst - units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst - diff; - } - return asFloat ? output : absRound(output); - }, - - from : function (time, withoutSuffix) { - return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix); - }, - - fromNow : function (withoutSuffix) { - return this.from(moment(), withoutSuffix); - }, - - calendar : function () { - var diff = this.diff(moment().zone(this.zone()).startOf('day'), 'days', true), - format = diff < -6 ? 'sameElse' : - diff < -1 ? 'lastWeek' : - diff < 0 ? 'lastDay' : - diff < 1 ? 'sameDay' : - diff < 2 ? 'nextDay' : - diff < 7 ? 'nextWeek' : 'sameElse'; - return this.format(this.lang().calendar(format, this)); - }, - - isLeapYear : function () { - var year = this.year(); - return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; - }, - - isDST : function () { - return (this.zone() < this.clone().month(0).zone() || - this.zone() < this.clone().month(5).zone()); - }, - - day : function (input) { - var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); - if (input != null) { - if (typeof input === 'string') { - input = this.lang().weekdaysParse(input); - if (typeof input !== 'number') { - return this; - } - } - return this.add({ d : input - day }); - } else { - return day; - } - }, - - month : function (input) { - var utc = this._isUTC ? 'UTC' : '', - dayOfMonth; - - if (input != null) { - if (typeof input === 'string') { - input = this.lang().monthsParse(input); - if (typeof input !== 'number') { - return this; - } - } - - dayOfMonth = this.date(); - this.date(1); - this._d['set' + utc + 'Month'](input); - this.date(Math.min(dayOfMonth, this.daysInMonth())); - - moment.updateOffset(this); - return this; - } else { - return this._d['get' + utc + 'Month'](); - } - }, - - startOf: function (units) { - units = normalizeUnits(units); - // the following switch intentionally omits break keywords - // to utilize falling through the cases. - switch (units) { - case 'year': - this.month(0); - /* falls through */ - case 'month': - this.date(1); - /* falls through */ - case 'week': - case 'isoweek': - case 'day': - this.hours(0); - /* falls through */ - case 'hour': - this.minutes(0); - /* falls through */ - case 'minute': - this.seconds(0); - /* falls through */ - case 'second': - this.milliseconds(0); - /* falls through */ - } - - // weeks are a special case - if (units === 'week') { - this.weekday(0); - } else if (units === 'isoweek') { - this.isoWeekday(1); - } - - return this; - }, - - endOf: function (units) { - units = normalizeUnits(units); - return this.startOf(units).add((units === 'isoweek' ? 'week' : units), 1).subtract('ms', 1); - }, - - isAfter: function (input, units) { - units = typeof units !== 'undefined' ? units : 'millisecond'; - return +this.clone().startOf(units) > +moment(input).startOf(units); - }, - - isBefore: function (input, units) { - units = typeof units !== 'undefined' ? units : 'millisecond'; - return +this.clone().startOf(units) < +moment(input).startOf(units); - }, - - isSame: function (input, units) { - units = typeof units !== 'undefined' ? units : 'millisecond'; - return +this.clone().startOf(units) === +moment(input).startOf(units); - }, - - min: function (other) { - other = moment.apply(null, arguments); - return other < this ? this : other; - }, - - max: function (other) { - other = moment.apply(null, arguments); - return other > this ? this : other; - }, - - zone : function (input) { - var offset = this._offset || 0; - if (input != null) { - if (typeof input === "string") { - input = timezoneMinutesFromString(input); - } - if (Math.abs(input) < 16) { - input = input * 60; - } - this._offset = input; - this._isUTC = true; - if (offset !== input) { - addOrSubtractDurationFromMoment(this, moment.duration(offset - input, 'm'), 1, true); - } - } else { - return this._isUTC ? offset : this._d.getTimezoneOffset(); - } - return this; - }, - - zoneAbbr : function () { - return this._isUTC ? "UTC" : ""; - }, - - zoneName : function () { - return this._isUTC ? "Coordinated Universal Time" : ""; - }, - - hasAlignedHourOffset : function (input) { - if (!input) { - input = 0; - } - else { - input = moment(input).zone(); - } - - return (this.zone() - input) % 60 === 0; - }, - - daysInMonth : function () { - return moment.utc([this.year(), this.month() + 1, 0]).date(); - }, - - dayOfYear : function (input) { - var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; - return input == null ? dayOfYear : this.add("d", (input - dayOfYear)); - }, - - weekYear : function (input) { - var year = weekOfYear(this, this.lang()._week.dow, this.lang()._week.doy).year; - return input == null ? year : this.add("y", (input - year)); - }, - - isoWeekYear : function (input) { - var year = weekOfYear(this, 1, 4).year; - return input == null ? year : this.add("y", (input - year)); - }, - - week : function (input) { - var week = this.lang().week(this); - return input == null ? week : this.add("d", (input - week) * 7); - }, - - isoWeek : function (input) { - var week = weekOfYear(this, 1, 4).week; - return input == null ? week : this.add("d", (input - week) * 7); - }, - - weekday : function (input) { - var weekday = (this._d.getDay() + 7 - this.lang()._week.dow) % 7; - return input == null ? weekday : this.add("d", input - weekday); - }, - - isoWeekday : function (input) { - // behaves the same as moment#day except - // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) - // as a setter, sunday should belong to the previous week. - return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); - }, - - get : function (units) { - units = normalizeUnits(units); - return this[units.toLowerCase()](); - }, - - set : function (units, value) { - units = normalizeUnits(units); - this[units.toLowerCase()](value); - }, - - // If passed a language key, it will set the language for this - // instance. Otherwise, it will return the language configuration - // variables for this instance. - lang : function (key) { - if (key === undefined) { - return this._lang; - } else { - this._lang = getLangDefinition(key); - return this; - } - } - }); - - // helper for adding shortcuts - function makeGetterAndSetter(name, key) { - moment.fn[name] = moment.fn[name + 's'] = function (input) { - var utc = this._isUTC ? 'UTC' : ''; - if (input != null) { - this._d['set' + utc + key](input); - moment.updateOffset(this); - return this; - } else { - return this._d['get' + utc + key](); - } - }; - } - - // loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds) - for (i = 0; i < proxyGettersAndSetters.length; i ++) { - makeGetterAndSetter(proxyGettersAndSetters[i].toLowerCase().replace(/s$/, ''), proxyGettersAndSetters[i]); - } - - // add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear') - makeGetterAndSetter('year', 'FullYear'); - - // add plural methods - moment.fn.days = moment.fn.day; - moment.fn.months = moment.fn.month; - moment.fn.weeks = moment.fn.week; - moment.fn.isoWeeks = moment.fn.isoWeek; - - // add aliased format methods - moment.fn.toJSON = moment.fn.toISOString; - - /************************************ - Duration Prototype - ************************************/ - - - extend(moment.duration.fn = Duration.prototype, { - - _bubble : function () { - var milliseconds = this._milliseconds, - days = this._days, - months = this._months, - data = this._data, - seconds, minutes, hours, years; - - // The following code bubbles up values, see the tests for - // examples of what that means. - data.milliseconds = milliseconds % 1000; - - seconds = absRound(milliseconds / 1000); - data.seconds = seconds % 60; - - minutes = absRound(seconds / 60); - data.minutes = minutes % 60; - - hours = absRound(minutes / 60); - data.hours = hours % 24; - - days += absRound(hours / 24); - data.days = days % 30; - - months += absRound(days / 30); - data.months = months % 12; - - years = absRound(months / 12); - data.years = years; - }, - - weeks : function () { - return absRound(this.days() / 7); - }, - - valueOf : function () { - return this._milliseconds + - this._days * 864e5 + - (this._months % 12) * 2592e6 + - ~~(this._months / 12) * 31536e6; - }, - - humanize : function (withSuffix) { - var difference = +this, - output = relativeTime(difference, !withSuffix, this.lang()); - - if (withSuffix) { - output = this.lang().pastFuture(difference, output); - } - - return this.lang().postformat(output); - }, - - add : function (input, val) { - // supports only 2.0-style add(1, 's') or add(moment) - var dur = moment.duration(input, val); - - this._milliseconds += dur._milliseconds; - this._days += dur._days; - this._months += dur._months; - - this._bubble(); - - return this; - }, - - subtract : function (input, val) { - var dur = moment.duration(input, val); - - this._milliseconds -= dur._milliseconds; - this._days -= dur._days; - this._months -= dur._months; - - this._bubble(); - - return this; - }, - - get : function (units) { - units = normalizeUnits(units); - return this[units.toLowerCase() + 's'](); - }, - - as : function (units) { - units = normalizeUnits(units); - return this['as' + units.charAt(0).toUpperCase() + units.slice(1) + 's'](); - }, - - lang : moment.fn.lang - }); - - function makeDurationGetter(name) { - moment.duration.fn[name] = function () { - return this._data[name]; - }; - } - - function makeDurationAsGetter(name, factor) { - moment.duration.fn['as' + name] = function () { - return +this / factor; - }; - } - - for (i in unitMillisecondFactors) { - if (unitMillisecondFactors.hasOwnProperty(i)) { - makeDurationAsGetter(i, unitMillisecondFactors[i]); - makeDurationGetter(i.toLowerCase()); - } - } - - makeDurationAsGetter('Weeks', 6048e5); - moment.duration.fn.asMonths = function () { - return (+this - this.years() * 31536e6) / 2592e6 + this.years() * 12; - }; - - - /************************************ - Default Lang - ************************************/ - - - // Set default language, other languages will inherit from English. - moment.lang('en', { - ordinal : function (number) { - var b = number % 10, - output = (~~ (number % 100 / 10) === 1) ? 'th' : - (b === 1) ? 'st' : - (b === 2) ? 'nd' : - (b === 3) ? 'rd' : 'th'; - return number + output; - } - }); - - /* EMBED_LANGUAGES */ - - /************************************ - Exposing Moment - ************************************/ - - - // CommonJS module is defined - if (hasModule) { - module.exports = moment; - } - /*global ender:false */ - if (typeof ender === 'undefined') { - // here, `this` means `window` in the browser, or `global` on the server - // add `moment` as a global object via a string identifier, - // for Closure Compiler "advanced" mode - this['moment'] = moment; - } - /*global define:false */ - if (typeof define === "function" && define.amd) { - define("moment", [], function () { - return moment; - }); - } -}).call(this); - -},{}],3:[function(require,module,exports){ -/** - * vis.js module imports - */ - -// Try to load dependencies from the global window object. -// If not available there, load via require. -var moment = (typeof window !== 'undefined') && window['moment'] || require('moment'); -var Hammer = (typeof window !== 'undefined') && window['Hammer'] || require('hammerjs'); - - -// Internet Explorer 8 and older does not support Array.indexOf, so we define -// it here in that case. -// http://soledadpenades.com/2007/05/17/arrayindexof-in-internet-explorer/ -if(!Array.prototype.indexOf) { - Array.prototype.indexOf = function(obj){ - for(var i = 0; i < this.length; i++){ - if(this[i] == obj){ - return i; - } - } - return -1; - }; - - try { - console.log("Warning: Ancient browser detected. Please update your browser"); - } - catch (err) { - } -} - -// Internet Explorer 8 and older does not support Array.forEach, so we define -// it here in that case. -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach -if (!Array.prototype.forEach) { - Array.prototype.forEach = function(fn, scope) { - for(var i = 0, len = this.length; i < len; ++i) { - fn.call(scope || this, this[i], i, this); - } - } -} - -// Internet Explorer 8 and older does not support Array.map, so we define it -// here in that case. -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map -// Production steps of ECMA-262, Edition 5, 15.4.4.19 -// Reference: http://es5.github.com/#x15.4.4.19 -if (!Array.prototype.map) { - Array.prototype.map = function(callback, thisArg) { - - var T, A, k; - - if (this == null) { - throw new TypeError(" this is null or not defined"); - } - - // 1. Let O be the result of calling ToObject passing the |this| value as the argument. - var O = Object(this); - - // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". - // 3. Let len be ToUint32(lenValue). - var len = O.length >>> 0; - - // 4. If IsCallable(callback) is false, throw a TypeError exception. - // See: http://es5.github.com/#x9.11 - if (typeof callback !== "function") { - throw new TypeError(callback + " is not a function"); - } - - // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. - if (thisArg) { - T = thisArg; - } - - // 6. Let A be a new array created as if by the expression new Array(len) where Array is - // the standard built-in constructor with that name and len is the value of len. - A = new Array(len); - - // 7. Let k be 0 - k = 0; - - // 8. Repeat, while k < len - while(k < len) { - - var kValue, mappedValue; - - // a. Let Pk be ToString(k). - // This is implicit for LHS operands of the in operator - // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. - // This step can be combined with c - // c. If kPresent is true, then - if (k in O) { - - // i. Let kValue be the result of calling the Get internal method of O with argument Pk. - kValue = O[ k ]; - - // ii. Let mappedValue be the result of calling the Call internal method of callback - // with T as the this value and argument list containing kValue, k, and O. - mappedValue = callback.call(T, kValue, k, O); - - // iii. Call the DefineOwnProperty internal method of A with arguments - // Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true}, - // and false. - - // In browsers that support Object.defineProperty, use the following: - // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true }); - - // For best browser support, use the following: - A[ k ] = mappedValue; - } - // d. Increase k by 1. - k++; - } - - // 9. return A - return A; - }; -} - -// Internet Explorer 8 and older does not support Array.filter, so we define it -// here in that case. -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter -if (!Array.prototype.filter) { - Array.prototype.filter = function(fun /*, thisp */) { - "use strict"; - - if (this == null) { - throw new TypeError(); - } - - var t = Object(this); - var len = t.length >>> 0; - if (typeof fun != "function") { - throw new TypeError(); - } - - var res = []; - var thisp = arguments[1]; - for (var i = 0; i < len; i++) { - if (i in t) { - var val = t[i]; // in case fun mutates this - if (fun.call(thisp, val, i, t)) - res.push(val); - } - } - - return res; - }; -} - - -// Internet Explorer 8 and older does not support Object.keys, so we define it -// here in that case. -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys -if (!Object.keys) { - Object.keys = (function () { - var hasOwnProperty = Object.prototype.hasOwnProperty, - hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), - dontEnums = [ - 'toString', - 'toLocaleString', - 'valueOf', - 'hasOwnProperty', - 'isPrototypeOf', - 'propertyIsEnumerable', - 'constructor' - ], - dontEnumsLength = dontEnums.length; - - return function (obj) { - if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) { - throw new TypeError('Object.keys called on non-object'); - } - - var result = []; - - for (var prop in obj) { - if (hasOwnProperty.call(obj, prop)) result.push(prop); - } - - if (hasDontEnumBug) { - for (var i=0; i < dontEnumsLength; i++) { - if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]); - } - } - return result; - } - })() -} - -// Internet Explorer 8 and older does not support Array.isArray, -// so we define it here in that case. -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/isArray -if(!Array.isArray) { - Array.isArray = function (vArg) { - return Object.prototype.toString.call(vArg) === "[object Array]"; - }; -} - -// Internet Explorer 8 and older does not support Function.bind, -// so we define it here in that case. -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind -if (!Function.prototype.bind) { - Function.prototype.bind = function (oThis) { - if (typeof this !== "function") { - // closest thing possible to the ECMAScript 5 internal IsCallable function - throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); - } - - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - fNOP = function () {}, - fBound = function () { - return fToBind.apply(this instanceof fNOP && oThis - ? this - : oThis, - aArgs.concat(Array.prototype.slice.call(arguments))); - }; - - fNOP.prototype = this.prototype; - fBound.prototype = new fNOP(); - - return fBound; - }; -} - -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create -if (!Object.create) { - Object.create = function (o) { - if (arguments.length > 1) { - throw new Error('Object.create implementation only accepts the first parameter.'); - } - function F() {} - F.prototype = o; - return new F(); - }; -} - -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind -if (!Function.prototype.bind) { - Function.prototype.bind = function (oThis) { - if (typeof this !== "function") { - // closest thing possible to the ECMAScript 5 internal IsCallable function - throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); - } - - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - fNOP = function () {}, - fBound = function () { - return fToBind.apply(this instanceof fNOP && oThis - ? this - : oThis, - aArgs.concat(Array.prototype.slice.call(arguments))); - }; - - fNOP.prototype = this.prototype; - fBound.prototype = new fNOP(); - - return fBound; - }; -} - -/** - * utility functions - */ -var util = {}; - -/** - * Test whether given object is a number - * @param {*} object - * @return {Boolean} isNumber - */ -util.isNumber = function isNumber(object) { - return (object instanceof Number || typeof object == 'number'); -}; - -/** - * Test whether given object is a string - * @param {*} object - * @return {Boolean} isString - */ -util.isString = function isString(object) { - return (object instanceof String || typeof object == 'string'); -}; - -/** - * Test whether given object is a Date, or a String containing a Date - * @param {Date | String} object - * @return {Boolean} isDate - */ -util.isDate = function isDate(object) { - if (object instanceof Date) { - return true; - } - else if (util.isString(object)) { - // test whether this string contains a date - var match = ASPDateRegex.exec(object); - if (match) { - return true; - } - else if (!isNaN(Date.parse(object))) { - return true; - } - } - - return false; -}; - -/** - * Test whether given object is an instance of google.visualization.DataTable - * @param {*} object - * @return {Boolean} isDataTable - */ -util.isDataTable = function isDataTable(object) { - return (typeof (google) !== 'undefined') && - (google.visualization) && - (google.visualization.DataTable) && - (object instanceof google.visualization.DataTable); -}; - -/** - * Create a semi UUID - * source: http://stackoverflow.com/a/105074/1262753 - * @return {String} uuid - */ -util.randomUUID = function randomUUID () { - var S4 = function () { - return Math.floor( - Math.random() * 0x10000 /* 65536 */ - ).toString(16); - }; - - return ( - S4() + S4() + '-' + - S4() + '-' + - S4() + '-' + - S4() + '-' + - S4() + S4() + S4() - ); -}; - -/** - * Extend object a with the properties of object b or a series of objects - * Only properties with defined values are copied - * @param {Object} a - * @param {... Object} b - * @return {Object} a - */ -util.extend = function (a, b) { - for (var i = 1, len = arguments.length; i < len; i++) { - var other = arguments[i]; - for (var prop in other) { - if (other.hasOwnProperty(prop) && other[prop] !== undefined) { - a[prop] = other[prop]; - } - } - } - - return a; -}; - -/** - * Convert an object to another type - * @param {Boolean | Number | String | Date | Moment | Null | undefined} object - * @param {String | undefined} type Name of the type. Available types: - * 'Boolean', 'Number', 'String', - * 'Date', 'Moment', ISODate', 'ASPDate'. - * @return {*} object - * @throws Error - */ -util.convert = function convert(object, type) { - var match; - - if (object === undefined) { - return undefined; - } - if (object === null) { - return null; - } - - if (!type) { - return object; - } - if (!(typeof type === 'string') && !(type instanceof String)) { - throw new Error('Type must be a string'); - } - - //noinspection FallthroughInSwitchStatementJS - switch (type) { - case 'boolean': - case 'Boolean': - return Boolean(object); - - case 'number': - case 'Number': - return Number(object.valueOf()); - - case 'string': - case 'String': - return String(object); - - case 'Date': - if (util.isNumber(object)) { - return new Date(object); - } - if (object instanceof Date) { - return new Date(object.valueOf()); - } - else if (moment.isMoment(object)) { - return new Date(object.valueOf()); - } - if (util.isString(object)) { - match = ASPDateRegex.exec(object); - if (match) { - // object is an ASP date - return new Date(Number(match[1])); // parse number - } - else { - return moment(object).toDate(); // parse string - } - } - else { - throw new Error( - 'Cannot convert object of type ' + util.getType(object) + - ' to type Date'); - } - - case 'Moment': - if (util.isNumber(object)) { - return moment(object); - } - if (object instanceof Date) { - return moment(object.valueOf()); - } - else if (moment.isMoment(object)) { - return moment.clone(); - } - if (util.isString(object)) { - match = ASPDateRegex.exec(object); - if (match) { - // object is an ASP date - return moment(Number(match[1])); // parse number - } - else { - return moment(object); // parse string - } - } - else { - throw new Error( - 'Cannot convert object of type ' + util.getType(object) + - ' to type Date'); - } - - case 'ISODate': - if (util.isNumber(object)) { - return new Date(object); - } - else if (object instanceof Date) { - return object.toISOString(); - } - else if (moment.isMoment(object)) { - return object.toDate().toISOString(); - } - else if (util.isString(object)) { - match = ASPDateRegex.exec(object); - if (match) { - // object is an ASP date - return new Date(Number(match[1])).toISOString(); // parse number - } - else { - return new Date(object).toISOString(); // parse string - } - } - else { - throw new Error( - 'Cannot convert object of type ' + util.getType(object) + - ' to type ISODate'); - } - - case 'ASPDate': - if (util.isNumber(object)) { - return '/Date(' + object + ')/'; - } - else if (object instanceof Date) { - return '/Date(' + object.valueOf() + ')/'; - } - else if (util.isString(object)) { - match = ASPDateRegex.exec(object); - var value; - if (match) { - // object is an ASP date - value = new Date(Number(match[1])).valueOf(); // parse number - } - else { - value = new Date(object).valueOf(); // parse string - } - return '/Date(' + value + ')/'; - } - else { - throw new Error( - 'Cannot convert object of type ' + util.getType(object) + - ' to type ASPDate'); - } - - default: - throw new Error('Cannot convert object of type ' + util.getType(object) + - ' to type "' + type + '"'); - } -}; - -// parse ASP.Net Date pattern, -// for example '/Date(1198908717056)/' or '/Date(1198908717056-0700)/' -// code from http://momentjs.com/ -var ASPDateRegex = /^\/?Date\((\-?\d+)/i; - -/** - * Get the type of an object, for example util.getType([]) returns 'Array' - * @param {*} object - * @return {String} type - */ -util.getType = function getType(object) { - var type = typeof object; - - if (type == 'object') { - if (object == null) { - return 'null'; - } - if (object instanceof Boolean) { - return 'Boolean'; - } - if (object instanceof Number) { - return 'Number'; - } - if (object instanceof String) { - return 'String'; - } - if (object instanceof Array) { - return 'Array'; - } - if (object instanceof Date) { - return 'Date'; - } - return 'Object'; - } - else if (type == 'number') { - return 'Number'; - } - else if (type == 'boolean') { - return 'Boolean'; - } - else if (type == 'string') { - return 'String'; - } - - return type; -}; - -/** - * Retrieve the absolute left value of a DOM element - * @param {Element} elem A dom element, for example a div - * @return {number} left The absolute left position of this element - * in the browser page. - */ -util.getAbsoluteLeft = function getAbsoluteLeft (elem) { - var doc = document.documentElement; - var body = document.body; - - var left = elem.offsetLeft; - var e = elem.offsetParent; - while (e != null && e != body && e != doc) { - left += e.offsetLeft; - left -= e.scrollLeft; - e = e.offsetParent; - } - return left; -}; - -/** - * Retrieve the absolute top value of a DOM element - * @param {Element} elem A dom element, for example a div - * @return {number} top The absolute top position of this element - * in the browser page. - */ -util.getAbsoluteTop = function getAbsoluteTop (elem) { - var doc = document.documentElement; - var body = document.body; - - var top = elem.offsetTop; - var e = elem.offsetParent; - while (e != null && e != body && e != doc) { - top += e.offsetTop; - top -= e.scrollTop; - e = e.offsetParent; - } - return top; -}; - -/** - * Get the absolute, vertical mouse position from an event. - * @param {Event} event - * @return {Number} pageY - */ -util.getPageY = function getPageY (event) { - if ('pageY' in event) { - return event.pageY; - } - else { - var clientY; - if (('targetTouches' in event) && event.targetTouches.length) { - clientY = event.targetTouches[0].clientY; - } - else { - clientY = event.clientY; - } - - var doc = document.documentElement; - var body = document.body; - return clientY + - ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - - ( doc && doc.clientTop || body && body.clientTop || 0 ); - } -}; - -/** - * Get the absolute, horizontal mouse position from an event. - * @param {Event} event - * @return {Number} pageX - */ -util.getPageX = function getPageX (event) { - if ('pageY' in event) { - return event.pageX; - } - else { - var clientX; - if (('targetTouches' in event) && event.targetTouches.length) { - clientX = event.targetTouches[0].clientX; - } - else { - clientX = event.clientX; - } - - var doc = document.documentElement; - var body = document.body; - return clientX + - ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); - } -}; - -/** - * add a className to the given elements style - * @param {Element} elem - * @param {String} className - */ -util.addClassName = function addClassName(elem, className) { - var classes = elem.className.split(' '); - if (classes.indexOf(className) == -1) { - classes.push(className); // add the class to the array - elem.className = classes.join(' '); - } -}; - -/** - * add a className to the given elements style - * @param {Element} elem - * @param {String} className - */ -util.removeClassName = function removeClassname(elem, className) { - var classes = elem.className.split(' '); - var index = classes.indexOf(className); - if (index != -1) { - classes.splice(index, 1); // remove the class from the array - elem.className = classes.join(' '); - } -}; - -/** - * For each method for both arrays and objects. - * In case of an array, the built-in Array.forEach() is applied. - * In case of an Object, the method loops over all properties of the object. - * @param {Object | Array} object An Object or Array - * @param {function} callback Callback method, called for each item in - * the object or array with three parameters: - * callback(value, index, object) - */ -util.forEach = function forEach (object, callback) { - var i, - len; - if (object instanceof Array) { - // array - for (i = 0, len = object.length; i < len; i++) { - callback(object[i], i, object); - } - } - else { - // object - for (i in object) { - if (object.hasOwnProperty(i)) { - callback(object[i], i, object); - } - } - } -}; - -/** - * Update a property in an object - * @param {Object} object - * @param {String} key - * @param {*} value - * @return {Boolean} changed - */ -util.updateProperty = function updateProp (object, key, value) { - if (object[key] !== value) { - object[key] = value; - return true; - } - else { - return false; - } -}; - -/** - * Add and event listener. Works for all browsers - * @param {Element} element An html element - * @param {string} action The action, for example "click", - * without the prefix "on" - * @param {function} listener The callback function to be executed - * @param {boolean} [useCapture] - */ -util.addEventListener = function addEventListener(element, action, listener, useCapture) { - if (element.addEventListener) { - if (useCapture === undefined) - useCapture = false; - - if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) { - action = "DOMMouseScroll"; // For Firefox - } - - element.addEventListener(action, listener, useCapture); - } else { - element.attachEvent("on" + action, listener); // IE browsers - } -}; - -/** - * Remove an event listener from an element - * @param {Element} element An html dom element - * @param {string} action The name of the event, for example "mousedown" - * @param {function} listener The listener function - * @param {boolean} [useCapture] - */ -util.removeEventListener = function removeEventListener(element, action, listener, useCapture) { - if (element.removeEventListener) { - // non-IE browsers - if (useCapture === undefined) - useCapture = false; - - if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) { - action = "DOMMouseScroll"; // For Firefox - } - - element.removeEventListener(action, listener, useCapture); - } else { - // IE browsers - element.detachEvent("on" + action, listener); - } -}; - - -/** - * Get HTML element which is the target of the event - * @param {Event} event - * @return {Element} target element - */ -util.getTarget = function getTarget(event) { - // code from http://www.quirksmode.org/js/events_properties.html - if (!event) { - event = window.event; - } - - var target; - - if (event.target) { - target = event.target; - } - else if (event.srcElement) { - target = event.srcElement; - } - - if (target.nodeType != undefined && target.nodeType == 3) { - // defeat Safari bug - target = target.parentNode; - } - - return target; -}; - -/** - * Stop event propagation - */ -util.stopPropagation = function stopPropagation(event) { - if (!event) - event = window.event; - - if (event.stopPropagation) { - event.stopPropagation(); // non-IE browsers - } - else { - event.cancelBubble = true; // IE browsers - } -}; - - -/** - * Cancels the event if it is cancelable, without stopping further propagation of the event. - */ -util.preventDefault = function preventDefault (event) { - if (!event) - event = window.event; - - if (event.preventDefault) { - event.preventDefault(); // non-IE browsers - } - else { - event.returnValue = false; // IE browsers - } -}; - - -util.option = {}; - -/** - * Convert a value into a boolean - * @param {Boolean | function | undefined} value - * @param {Boolean} [defaultValue] - * @returns {Boolean} bool - */ -util.option.asBoolean = function (value, defaultValue) { - if (typeof value == 'function') { - value = value(); - } - - if (value != null) { - return (value != false); - } - - return defaultValue || null; -}; - -/** - * Convert a value into a number - * @param {Boolean | function | undefined} value - * @param {Number} [defaultValue] - * @returns {Number} number - */ -util.option.asNumber = function (value, defaultValue) { - if (typeof value == 'function') { - value = value(); - } - - if (value != null) { - return Number(value) || defaultValue || null; - } - - return defaultValue || null; -}; - -/** - * Convert a value into a string - * @param {String | function | undefined} value - * @param {String} [defaultValue] - * @returns {String} str - */ -util.option.asString = function (value, defaultValue) { - if (typeof value == 'function') { - value = value(); - } - - if (value != null) { - return String(value); - } - - return defaultValue || null; -}; - -/** - * Convert a size or location into a string with pixels or a percentage - * @param {String | Number | function | undefined} value - * @param {String} [defaultValue] - * @returns {String} size - */ -util.option.asSize = function (value, defaultValue) { - if (typeof value == 'function') { - value = value(); - } - - if (util.isString(value)) { - return value; - } - else if (util.isNumber(value)) { - return value + 'px'; - } - else { - return defaultValue || null; - } -}; - -/** - * Convert a value into a DOM element - * @param {HTMLElement | function | undefined} value - * @param {HTMLElement} [defaultValue] - * @returns {HTMLElement | null} dom - */ -util.option.asElement = function (value, defaultValue) { - if (typeof value == 'function') { - value = value(); - } - - return value || defaultValue || null; -}; - -/** - * load css from text - * @param {String} css Text containing css - */ -util.loadCss = function (css) { - if (typeof document === 'undefined') { - return; - } - - // get the script location, and built the css file name from the js file name - // http://stackoverflow.com/a/2161748/1262753 - // var scripts = document.getElementsByTagName('script'); - // var jsFile = scripts[scripts.length-1].src.split('?')[0]; - // var cssFile = jsFile.substring(0, jsFile.length - 2) + 'css'; - - // inject css - // http://stackoverflow.com/questions/524696/how-to-create-a-style-tag-with-javascript - var style = document.createElement('style'); - style.type = 'text/css'; - if (style.styleSheet){ - style.styleSheet.cssText = css; - } else { - style.appendChild(document.createTextNode(css)); - } - - document.getElementsByTagName('head')[0].appendChild(style); -}; - -/** - * Event listener (singleton) - */ -// TODO: replace usage of the event listener for the EventBus -var events = { - 'listeners': [], - - /** - * Find a single listener by its object - * @param {Object} object - * @return {Number} index -1 when not found - */ - 'indexOf': function (object) { - var listeners = this.listeners; - for (var i = 0, iMax = this.listeners.length; i < iMax; i++) { - var listener = listeners[i]; - if (listener && listener.object == object) { - return i; - } - } - return -1; - }, - - /** - * Add an event listener - * @param {Object} object - * @param {String} event The name of an event, for example 'select' - * @param {function} callback The callback method, called when the - * event takes place - */ - 'addListener': function (object, event, callback) { - var index = this.indexOf(object); - var listener = this.listeners[index]; - if (!listener) { - listener = { - 'object': object, - 'events': {} - }; - this.listeners.push(listener); - } - - var callbacks = listener.events[event]; - if (!callbacks) { - callbacks = []; - listener.events[event] = callbacks; - } - - // add the callback if it does not yet exist - if (callbacks.indexOf(callback) == -1) { - callbacks.push(callback); - } - }, - - /** - * Remove an event listener - * @param {Object} object - * @param {String} event The name of an event, for example 'select' - * @param {function} callback The registered callback method - */ - 'removeListener': function (object, event, callback) { - var index = this.indexOf(object); - var listener = this.listeners[index]; - if (listener) { - var callbacks = listener.events[event]; - if (callbacks) { - index = callbacks.indexOf(callback); - if (index != -1) { - callbacks.splice(index, 1); - } - - // remove the array when empty - if (callbacks.length == 0) { - delete listener.events[event]; - } - } - - // count the number of registered events. remove listener when empty - var count = 0; - var events = listener.events; - for (var e in events) { - if (events.hasOwnProperty(e)) { - count++; - } - } - if (count == 0) { - delete this.listeners[index]; - } - } - }, - - /** - * Remove all registered event listeners - */ - 'removeAllListeners': function () { - this.listeners = []; - }, - - /** - * Trigger an event. All registered event handlers will be called - * @param {Object} object - * @param {String} event - * @param {Object} properties (optional) - */ - 'trigger': function (object, event, properties) { - var index = this.indexOf(object); - var listener = this.listeners[index]; - if (listener) { - var callbacks = listener.events[event]; - if (callbacks) { - for (var i = 0, iMax = callbacks.length; i < iMax; i++) { - callbacks[i](properties); - } - } - } - } -}; - -/** - * An event bus can be used to emit events, and to subscribe to events - * @constructor EventBus - */ -function EventBus() { - this.subscriptions = []; -} - -/** - * Subscribe to an event - * @param {String | RegExp} event The event can be a regular expression, or - * a string with wildcards, like 'server.*'. - * @param {function} callback. Callback are called with three parameters: - * {String} event, {*} [data], {*} [source] - * @param {*} [target] - * @returns {String} id A subscription id - */ -EventBus.prototype.on = function (event, callback, target) { - var regexp = (event instanceof RegExp) ? - event : - new RegExp(event.replace('*', '\\w+')); - - var subscription = { - id: util.randomUUID(), - event: event, - regexp: regexp, - callback: (typeof callback === 'function') ? callback : null, - target: target - }; - - this.subscriptions.push(subscription); - - return subscription.id; -}; - -/** - * Unsubscribe from an event - * @param {String | Object} filter Filter for subscriptions to be removed - * Filter can be a string containing a - * subscription id, or an object containing - * one or more of the fields id, event, - * callback, and target. - */ -EventBus.prototype.off = function (filter) { - var i = 0; - while (i < this.subscriptions.length) { - var subscription = this.subscriptions[i]; - - var match = true; - if (filter instanceof Object) { - // filter is an object. All fields must match - for (var prop in filter) { - if (filter.hasOwnProperty(prop)) { - if (filter[prop] !== subscription[prop]) { - match = false; - } - } - } - } - else { - // filter is a string, filter on id - match = (subscription.id == filter); - } - - if (match) { - this.subscriptions.splice(i, 1); - } - else { - i++; - } - } -}; - -/** - * Emit an event - * @param {String} event - * @param {*} [data] - * @param {*} [source] - */ -EventBus.prototype.emit = function (event, data, source) { - for (var i =0; i < this.subscriptions.length; i++) { - var subscription = this.subscriptions[i]; - if (subscription.regexp.test(event)) { - if (subscription.callback) { - subscription.callback(event, data, source); - } - } - } -}; - -/** - * DataSet - * - * Usage: - * var dataSet = new DataSet({ - * fieldId: '_id', - * convert: { - * // ... - * } - * }); - * - * dataSet.add(item); - * dataSet.add(data); - * dataSet.update(item); - * dataSet.update(data); - * dataSet.remove(id); - * dataSet.remove(ids); - * var data = dataSet.get(); - * var data = dataSet.get(id); - * var data = dataSet.get(ids); - * var data = dataSet.get(ids, options, data); - * dataSet.clear(); - * - * A data set can: - * - add/remove/update data - * - gives triggers upon changes in the data - * - can import/export data in various data formats - * - * @param {Object} [options] Available options: - * {String} fieldId Field name of the id in the - * items, 'id' by default. - * {Object.} [convert] - * {String[]} [fields] field names to be returned - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * {Array | DataTable} [data] If provided, items will be appended to this - * array or table. Required in case of Google - * DataTable. - * - * @throws Error - */ -DataSet.prototype.get = function (args) { - var me = this; - - // parse the arguments - var id, ids, options, data; - var firstType = util.getType(arguments[0]); - if (firstType == 'String' || firstType == 'Number') { - // get(id [, options] [, data]) - id = arguments[0]; - options = arguments[1]; - data = arguments[2]; - } - else if (firstType == 'Array') { - // get(ids [, options] [, data]) - ids = arguments[0]; - options = arguments[1]; - data = arguments[2]; - } - else { - // get([, options] [, data]) - options = arguments[0]; - data = arguments[1]; - } - - // determine the return type - var type; - if (options && options.type) { - type = (options.type == 'DataTable') ? 'DataTable' : 'Array'; - - if (data && (type != util.getType(data))) { - throw new Error('Type of parameter "data" (' + util.getType(data) + ') ' + - 'does not correspond with specified options.type (' + options.type + ')'); - } - if (type == 'DataTable' && !util.isDataTable(data)) { - throw new Error('Parameter "data" must be a DataTable ' + - 'when options.type is "DataTable"'); - } - } - else if (data) { - type = (util.getType(data) == 'DataTable') ? 'DataTable' : 'Array'; - } - else { - type = 'Array'; - } - - // build options - var convert = options && options.convert || this.options.convert; - var filter = options && options.filter; - var items = [], item, itemId, i, len; - - // convert items - if (id != undefined) { - // return a single item - item = me._getItem(id, convert); - if (filter && !filter(item)) { - item = null; - } - } - else if (ids != undefined) { - // return a subset of items - for (i = 0, len = ids.length; i < len; i++) { - item = me._getItem(ids[i], convert); - if (!filter || filter(item)) { - items.push(item); - } - } - } - else { - // return all items - for (itemId in this.data) { - if (this.data.hasOwnProperty(itemId)) { - item = me._getItem(itemId, convert); - if (!filter || filter(item)) { - items.push(item); - } - } - } - } - - // order the results - if (options && options.order && id == undefined) { - this._sort(items, options.order); - } - - // filter fields of the items - if (options && options.fields) { - var fields = options.fields; - if (id != undefined) { - item = this._filterFields(item, fields); - } - else { - for (i = 0, len = items.length; i < len; i++) { - items[i] = this._filterFields(items[i], fields); - } - } - } - - // return the results - if (type == 'DataTable') { - var columns = this._getColumnNames(data); - if (id != undefined) { - // append a single item to the data table - me._appendRow(data, columns, item); - } - else { - // copy the items to the provided data table - for (i = 0, len = items.length; i < len; i++) { - me._appendRow(data, columns, items[i]); - } - } - return data; - } - else { - // return an array - if (id != undefined) { - // a single item - return item; - } - else { - // multiple items - if (data) { - // copy the items to the provided array - for (i = 0, len = items.length; i < len; i++) { - data.push(items[i]); - } - return data; - } - else { - // just return our array - return items; - } - } - } -}; - -/** - * Get ids of all items or from a filtered set of items. - * @param {Object} [options] An Object with options. Available options: - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * @return {Array} ids - */ -DataSet.prototype.getIds = function (options) { - var data = this.data, - filter = options && options.filter, - order = options && options.order, - convert = options && options.convert || this.options.convert, - i, - len, - id, - item, - items, - ids = []; - - if (filter) { - // get filtered items - if (order) { - // create ordered list - items = []; - for (id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, convert); - if (filter(item)) { - items.push(item); - } - } - } - - this._sort(items, order); - - for (i = 0, len = items.length; i < len; i++) { - ids[i] = items[i][this.fieldId]; - } - } - else { - // create unordered list - for (id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, convert); - if (filter(item)) { - ids.push(item[this.fieldId]); - } - } - } - } - } - else { - // get all items - if (order) { - // create an ordered list - items = []; - for (id in data) { - if (data.hasOwnProperty(id)) { - items.push(data[id]); - } - } - - this._sort(items, order); - - for (i = 0, len = items.length; i < len; i++) { - ids[i] = items[i][this.fieldId]; - } - } - else { - // create unordered list - for (id in data) { - if (data.hasOwnProperty(id)) { - item = data[id]; - ids.push(item[this.fieldId]); - } - } - } - } - - return ids; -}; - -/** - * Execute a callback function for every item in the dataset. - * The order of the items is not determined. - * @param {function} callback - * @param {Object} [options] Available options: - * {Object.} [convert] - * {String[]} [fields] filter fields - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - */ -DataSet.prototype.forEach = function (callback, options) { - var filter = options && options.filter, - convert = options && options.convert || this.options.convert, - data = this.data, - item, - id; - - if (options && options.order) { - // execute forEach on ordered list - var items = this.get(options); - - for (var i = 0, len = items.length; i < len; i++) { - item = items[i]; - id = item[this.fieldId]; - callback(item, id); - } - } - else { - // unordered - for (id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, convert); - if (!filter || filter(item)) { - callback(item, id); - } - } - } - } -}; - -/** - * Map every item in the dataset. - * @param {function} callback - * @param {Object} [options] Available options: - * {Object.} [convert] - * {String[]} [fields] filter fields - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * @return {Object[]} mappedItems - */ -DataSet.prototype.map = function (callback, options) { - var filter = options && options.filter, - convert = options && options.convert || this.options.convert, - mappedItems = [], - data = this.data, - item; - - // convert and filter items - for (var id in data) { - if (data.hasOwnProperty(id)) { - item = this._getItem(id, convert); - if (!filter || filter(item)) { - mappedItems.push(callback(item, id)); - } - } - } - - // order items - if (options && options.order) { - this._sort(mappedItems, options.order); - } - - return mappedItems; -}; - -/** - * Filter the fields of an item - * @param {Object} item - * @param {String[]} fields Field names - * @return {Object} filteredItem - * @private - */ -DataSet.prototype._filterFields = function (item, fields) { - var filteredItem = {}; - - for (var field in item) { - if (item.hasOwnProperty(field) && (fields.indexOf(field) != -1)) { - filteredItem[field] = item[field]; - } - } - - return filteredItem; -}; - -/** - * Sort the provided array with items - * @param {Object[]} items - * @param {String | function} order A field name or custom sort function. - * @private - */ -DataSet.prototype._sort = function (items, order) { - if (util.isString(order)) { - // order by provided field name - var name = order; // field name - items.sort(function (a, b) { - var av = a[name]; - var bv = b[name]; - return (av > bv) ? 1 : ((av < bv) ? -1 : 0); - }); - } - else if (typeof order === 'function') { - // order by sort function - items.sort(order); - } - // TODO: extend order by an Object {field:String, direction:String} - // where direction can be 'asc' or 'desc' - else { - throw new TypeError('Order must be a function or a string'); - } -}; - -/** - * Remove an object by pointer or by id - * @param {String | Number | Object | Array} id Object or id, or an array with - * objects or ids to be removed - * @param {String} [senderId] Optional sender id - * @return {Array} removedIds - */ -DataSet.prototype.remove = function (id, senderId) { - var removedIds = [], - i, len, removedId; - - if (id instanceof Array) { - for (i = 0, len = id.length; i < len; i++) { - removedId = this._remove(id[i]); - if (removedId != null) { - removedIds.push(removedId); - } - } - } - else { - removedId = this._remove(id); - if (removedId != null) { - removedIds.push(removedId); - } - } - - if (removedIds.length) { - this._trigger('remove', {items: removedIds}, senderId); - } - - return removedIds; -}; - -/** - * Remove an item by its id - * @param {Number | String | Object} id id or item - * @returns {Number | String | null} id - * @private - */ -DataSet.prototype._remove = function (id) { - if (util.isNumber(id) || util.isString(id)) { - if (this.data[id]) { - delete this.data[id]; - delete this.internalIds[id]; - return id; - } - } - else if (id instanceof Object) { - var itemId = id[this.fieldId]; - if (itemId && this.data[itemId]) { - delete this.data[itemId]; - delete this.internalIds[itemId]; - return itemId; - } - } - return null; -}; - -/** - * Clear the data - * @param {String} [senderId] Optional sender id - * @return {Array} removedIds The ids of all removed items - */ -DataSet.prototype.clear = function (senderId) { - var ids = Object.keys(this.data); - - this.data = {}; - this.internalIds = {}; - - this._trigger('remove', {items: ids}, senderId); - - return ids; -}; - -/** - * Find the item with maximum value of a specified field - * @param {String} field - * @return {Object | null} item Item containing max value, or null if no items - */ -DataSet.prototype.max = function (field) { - var data = this.data, - max = null, - maxField = null; - - for (var id in data) { - if (data.hasOwnProperty(id)) { - var item = data[id]; - var itemField = item[field]; - if (itemField != null && (!max || itemField > maxField)) { - max = item; - maxField = itemField; - } - } - } - - return max; -}; - -/** - * Find the item with minimum value of a specified field - * @param {String} field - * @return {Object | null} item Item containing max value, or null if no items - */ -DataSet.prototype.min = function (field) { - var data = this.data, - min = null, - minField = null; - - for (var id in data) { - if (data.hasOwnProperty(id)) { - var item = data[id]; - var itemField = item[field]; - if (itemField != null && (!min || itemField < minField)) { - min = item; - minField = itemField; - } - } - } - - return min; -}; - -/** - * Find all distinct values of a specified field - * @param {String} field - * @return {Array} values Array containing all distinct values. If the data - * items do not contain the specified field, an array - * containing a single value undefined is returned. - * The returned array is unordered. - */ -DataSet.prototype.distinct = function (field) { - var data = this.data, - values = [], - fieldType = this.options.convert[field], - count = 0; - - for (var prop in data) { - if (data.hasOwnProperty(prop)) { - var item = data[prop]; - var value = util.convert(item[field], fieldType); - var exists = false; - for (var i = 0; i < count; i++) { - if (values[i] == value) { - exists = true; - break; - } - } - if (!exists) { - values[count] = value; - count++; - } - } - } - - return values; -}; - -/** - * Add a single item. Will fail when an item with the same id already exists. - * @param {Object} item - * @return {String} id - * @private - */ -DataSet.prototype._addItem = function (item) { - var id = item[this.fieldId]; - - if (id != undefined) { - // check whether this id is already taken - if (this.data[id]) { - // item already exists - throw new Error('Cannot add item: item with id ' + id + ' already exists'); - } - } - else { - // generate an id - id = util.randomUUID(); - item[this.fieldId] = id; - this.internalIds[id] = item; - } - - var d = {}; - for (var field in item) { - if (item.hasOwnProperty(field)) { - var fieldType = this.convert[field]; // type may be undefined - d[field] = util.convert(item[field], fieldType); - } - } - this.data[id] = d; - - return id; -}; - -/** - * Get an item. Fields can be converted to a specific type - * @param {String} id - * @param {Object.} [convert] field types to convert - * @return {Object | null} item - * @private - */ -DataSet.prototype._getItem = function (id, convert) { - var field, value; - - // get the item from the dataset - var raw = this.data[id]; - if (!raw) { - return null; - } - - // convert the items field types - var converted = {}, - fieldId = this.fieldId, - internalIds = this.internalIds; - if (convert) { - for (field in raw) { - if (raw.hasOwnProperty(field)) { - value = raw[field]; - // output all fields, except internal ids - if ((field != fieldId) || !(value in internalIds)) { - converted[field] = util.convert(value, convert[field]); - } - } - } - } - else { - // no field types specified, no converting needed - for (field in raw) { - if (raw.hasOwnProperty(field)) { - value = raw[field]; - // output all fields, except internal ids - if ((field != fieldId) || !(value in internalIds)) { - converted[field] = value; - } - } - } - } - - return converted; -}; - -/** - * Update a single item: merge with existing item. - * Will fail when the item has no id, or when there does not exist an item - * with the same id. - * @param {Object} item - * @return {String} id - * @private - */ -DataSet.prototype._updateItem = function (item) { - var id = item[this.fieldId]; - if (id == undefined) { - throw new Error('Cannot update item: item has no id (item: ' + JSON.stringify(item) + ')'); - } - var d = this.data[id]; - if (!d) { - // item doesn't exist - throw new Error('Cannot update item: no item with id ' + id + ' found'); - } - - // merge with current item - for (var field in item) { - if (item.hasOwnProperty(field)) { - var fieldType = this.convert[field]; // type may be undefined - d[field] = util.convert(item[field], fieldType); - } - } - - return id; -}; - -/** - * Get an array with the column names of a Google DataTable - * @param {DataTable} dataTable - * @return {String[]} columnNames - * @private - */ -DataSet.prototype._getColumnNames = function (dataTable) { - var columns = []; - for (var col = 0, cols = dataTable.getNumberOfColumns(); col < cols; col++) { - columns[col] = dataTable.getColumnId(col) || dataTable.getColumnLabel(col); - } - return columns; -}; - -/** - * Append an item as a row to the dataTable - * @param dataTable - * @param columns - * @param item - * @private - */ -DataSet.prototype._appendRow = function (dataTable, columns, item) { - var row = dataTable.addRow(); - - for (var col = 0, cols = columns.length; col < cols; col++) { - var field = columns[col]; - dataTable.setValue(row, col, item[field]); - } -}; - -/** - * DataView - * - * a dataview offers a filtered view on a dataset or an other dataview. - * - * @param {DataSet | DataView} data - * @param {Object} [options] Available options: see method get - * - * @constructor DataView - */ -function DataView (data, options) { - this.id = util.randomUUID(); - - this.data = null; - this.ids = {}; // ids of the items currently in memory (just contains a boolean true) - this.options = options || {}; - this.fieldId = 'id'; // name of the field containing id - this.subscribers = {}; // event subscribers - - var me = this; - this.listener = function () { - me._onEvent.apply(me, arguments); - }; - - this.setData(data); -} - -/** - * Set a data source for the view - * @param {DataSet | DataView} data - */ -DataView.prototype.setData = function (data) { - var ids, dataItems, i, len; - - if (this.data) { - // unsubscribe from current dataset - if (this.data.unsubscribe) { - this.data.unsubscribe('*', this.listener); - } - - // trigger a remove of all items in memory - ids = []; - for (var id in this.ids) { - if (this.ids.hasOwnProperty(id)) { - ids.push(id); - } - } - this.ids = {}; - this._trigger('remove', {items: ids}); - } - - this.data = data; - - if (this.data) { - // update fieldId - this.fieldId = this.options.fieldId || - (this.data && this.data.options && this.data.options.fieldId) || - 'id'; - - // trigger an add of all added items - ids = this.data.getIds({filter: this.options && this.options.filter}); - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - this.ids[id] = true; - } - this._trigger('add', {items: ids}); - - // subscribe to new dataset - if (this.data.subscribe) { - this.data.subscribe('*', this.listener); - } - } -}; - -/** - * Get data from the data view - * - * Usage: - * - * get() - * get(options: Object) - * get(options: Object, data: Array | DataTable) - * - * get(id: Number) - * get(id: Number, options: Object) - * get(id: Number, options: Object, data: Array | DataTable) - * - * get(ids: Number[]) - * get(ids: Number[], options: Object) - * get(ids: Number[], options: Object, data: Array | DataTable) - * - * Where: - * - * {Number | String} id The id of an item - * {Number[] | String{}} ids An array with ids of items - * {Object} options An Object with options. Available options: - * {String} [type] Type of data to be returned. Can - * be 'DataTable' or 'Array' (default) - * {Object.} [convert] - * {String[]} [fields] field names to be returned - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * {Array | DataTable} [data] If provided, items will be appended to this - * array or table. Required in case of Google - * DataTable. - * @param args - */ -DataView.prototype.get = function (args) { - var me = this; - - // parse the arguments - var ids, options, data; - var firstType = util.getType(arguments[0]); - if (firstType == 'String' || firstType == 'Number' || firstType == 'Array') { - // get(id(s) [, options] [, data]) - ids = arguments[0]; // can be a single id or an array with ids - options = arguments[1]; - data = arguments[2]; - } - else { - // get([, options] [, data]) - options = arguments[0]; - data = arguments[1]; - } - - // extend the options with the default options and provided options - var viewOptions = util.extend({}, this.options, options); - - // create a combined filter method when needed - if (this.options.filter && options && options.filter) { - viewOptions.filter = function (item) { - return me.options.filter(item) && options.filter(item); - } - } - - // build up the call to the linked data set - var getArguments = []; - if (ids != undefined) { - getArguments.push(ids); - } - getArguments.push(viewOptions); - getArguments.push(data); - - return this.data && this.data.get.apply(this.data, getArguments); -}; - -/** - * Get ids of all items or from a filtered set of items. - * @param {Object} [options] An Object with options. Available options: - * {function} [filter] filter items - * {String | function} [order] Order the items by - * a field name or custom sort function. - * @return {Array} ids - */ -DataView.prototype.getIds = function (options) { - var ids; - - if (this.data) { - var defaultFilter = this.options.filter; - var filter; - - if (options && options.filter) { - if (defaultFilter) { - filter = function (item) { - return defaultFilter(item) && options.filter(item); - } - } - else { - filter = options.filter; - } - } - else { - filter = defaultFilter; - } - - ids = this.data.getIds({ - filter: filter, - order: options && options.order - }); - } - else { - ids = []; - } - - return ids; -}; - -/** - * Event listener. Will propagate all events from the connected data set to - * the subscribers of the DataView, but will filter the items and only trigger - * when there are changes in the filtered data set. - * @param {String} event - * @param {Object | null} params - * @param {String} senderId - * @private - */ -DataView.prototype._onEvent = function (event, params, senderId) { - var i, len, id, item, - ids = params && params.items, - data = this.data, - added = [], - updated = [], - removed = []; - - if (ids && data) { - switch (event) { - case 'add': - // filter the ids of the added items - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - item = this.get(id); - if (item) { - this.ids[id] = true; - added.push(id); - } - } - - break; - - case 'update': - // determine the event from the views viewpoint: an updated - // item can be added, updated, or removed from this view. - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - item = this.get(id); - - if (item) { - if (this.ids[id]) { - updated.push(id); - } - else { - this.ids[id] = true; - added.push(id); - } - } - else { - if (this.ids[id]) { - delete this.ids[id]; - removed.push(id); - } - else { - // nothing interesting for me :-( - } - } - } - - break; - - case 'remove': - // filter the ids of the removed items - for (i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - if (this.ids[id]) { - delete this.ids[id]; - removed.push(id); - } - } - - break; - } - - if (added.length) { - this._trigger('add', {items: added}, senderId); - } - if (updated.length) { - this._trigger('update', {items: updated}, senderId); - } - if (removed.length) { - this._trigger('remove', {items: removed}, senderId); - } - } -}; - -// copy subscription functionality from DataSet -DataView.prototype.subscribe = DataSet.prototype.subscribe; -DataView.prototype.unsubscribe = DataSet.prototype.unsubscribe; -DataView.prototype._trigger = DataSet.prototype._trigger; - -/** - * @constructor TimeStep - * The class TimeStep is an iterator for dates. You provide a start date and an - * end date. The class itself determines the best scale (step size) based on the - * provided start Date, end Date, and minimumStep. - * - * If minimumStep is provided, the step size is chosen as close as possible - * to the minimumStep but larger than minimumStep. If minimumStep is not - * provided, the scale is set to 1 DAY. - * The minimumStep should correspond with the onscreen size of about 6 characters - * - * Alternatively, you can set a scale by hand. - * After creation, you can initialize the class by executing first(). Then you - * can iterate from the start date to the end date via next(). You can check if - * the end date is reached with the function hasNext(). After each step, you can - * retrieve the current date via getCurrent(). - * The TimeStep has scales ranging from milliseconds, seconds, minutes, hours, - * days, to years. - * - * Version: 1.2 - * - * @param {Date} [start] The start date, for example new Date(2010, 9, 21) - * or new Date(2010, 9, 21, 23, 45, 00) - * @param {Date} [end] The end date - * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds - */ -TimeStep = function(start, end, minimumStep) { - // variables - this.current = new Date(); - this._start = new Date(); - this._end = new Date(); - - this.autoScale = true; - this.scale = TimeStep.SCALE.DAY; - this.step = 1; - - // initialize the range - this.setRange(start, end, minimumStep); -}; - -/// enum scale -TimeStep.SCALE = { - MILLISECOND: 1, - SECOND: 2, - MINUTE: 3, - HOUR: 4, - DAY: 5, - WEEKDAY: 6, - MONTH: 7, - YEAR: 8 -}; - - -/** - * Set a new range - * If minimumStep is provided, the step size is chosen as close as possible - * to the minimumStep but larger than minimumStep. If minimumStep is not - * provided, the scale is set to 1 DAY. - * The minimumStep should correspond with the onscreen size of about 6 characters - * @param {Date} [start] The start date and time. - * @param {Date} [end] The end date and time. - * @param {int} [minimumStep] Optional. Minimum step size in milliseconds - */ -TimeStep.prototype.setRange = function(start, end, minimumStep) { - if (!(start instanceof Date) || !(end instanceof Date)) { - //throw "No legal start or end date in method setRange"; - return; - } - - this._start = (start != undefined) ? new Date(start.valueOf()) : new Date(); - this._end = (end != undefined) ? new Date(end.valueOf()) : new Date(); - - if (this.autoScale) { - this.setMinimumStep(minimumStep); - } -}; - -/** - * Set the range iterator to the start date. - */ -TimeStep.prototype.first = function() { - this.current = new Date(this._start.valueOf()); - this.roundToMinor(); -}; - -/** - * Round the current date to the first minor date value - * This must be executed once when the current date is set to start Date - */ -TimeStep.prototype.roundToMinor = function() { - // round to floor - // IMPORTANT: we have no breaks in this switch! (this is no bug) - //noinspection FallthroughInSwitchStatementJS - switch (this.scale) { - case 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: // intentional fall through - 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); - //case TimeStep.SCALE.MILLISECOND: // nothing to do for milliseconds - } - - if (this.step != 1) { - // round down to the first minor value that is a multiple of the current step size - switch (this.scale) { - case 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: // intentional fall through - 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); break; - default: break; - } - } -}; - -/** - * Check if the there is a next step - * @return {boolean} true if the current date has not passed the end date - */ -TimeStep.prototype.hasNext = function () { - return (this.current.valueOf() <= this._end.valueOf()); -}; - -/** - * Do the next step - */ -TimeStep.prototype.next = function() { - var prev = this.current.valueOf(); - - // Two cases, needed to prevent issues with switching daylight savings - // (end of March and end of October) - if (this.current.getMonth() < 6) { - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: - - this.current = new Date(this.current.valueOf() + this.step); break; - case TimeStep.SCALE.SECOND: this.current = new Date(this.current.valueOf() + this.step * 1000); break; - case TimeStep.SCALE.MINUTE: this.current = new Date(this.current.valueOf() + this.step * 1000 * 60); break; - case TimeStep.SCALE.HOUR: - this.current = new Date(this.current.valueOf() + this.step * 1000 * 60 * 60); - // in case of skipping an hour for daylight savings, adjust the hour again (else you get: 0h 5h 9h ... instead of 0h 4h 8h ...) - var h = this.current.getHours(); - this.current.setHours(h - (h % this.step)); - break; - case TimeStep.SCALE.WEEKDAY: // intentional fall through - 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); break; - default: break; - } - } - 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: // intentional fall through - 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); break; - default: break; - } - } - - if (this.step != 1) { - // round down to the correct major value - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: if(this.current.getMilliseconds() < this.step) this.current.setMilliseconds(0); break; - case TimeStep.SCALE.SECOND: if(this.current.getSeconds() < this.step) this.current.setSeconds(0); break; - case TimeStep.SCALE.MINUTE: if(this.current.getMinutes() < this.step) this.current.setMinutes(0); break; - case TimeStep.SCALE.HOUR: if(this.current.getHours() < this.step) this.current.setHours(0); break; - case TimeStep.SCALE.WEEKDAY: // intentional fall through - case TimeStep.SCALE.DAY: if(this.current.getDate() < this.step+1) this.current.setDate(1); break; - case TimeStep.SCALE.MONTH: if(this.current.getMonth() < this.step) this.current.setMonth(0); break; - case TimeStep.SCALE.YEAR: break; // nothing to do for year - default: break; - } - } - - // safety mechanism: if current time is still unchanged, move to the end - if (this.current.valueOf() == prev) { - this.current = new Date(this._end.valueOf()); - } -}; - - -/** - * Get the current datetime - * @return {Date} current The current date - */ -TimeStep.prototype.getCurrent = function() { - return this.current; -}; - -/** - * Set a custom scale. Autoscaling will be disabled. - * For example setScale(SCALE.MINUTES, 5) will result - * in minor steps of 5 minutes, and major steps of an hour. - * - * @param {TimeStep.SCALE} newScale - * A scale. Choose from SCALE.MILLISECOND, - * SCALE.SECOND, SCALE.MINUTE, SCALE.HOUR, - * SCALE.WEEKDAY, SCALE.DAY, SCALE.MONTH, - * SCALE.YEAR. - * @param {Number} newStep A step size, by default 1. Choose for - * example 1, 2, 5, or 10. - */ -TimeStep.prototype.setScale = function(newScale, newStep) { - this.scale = newScale; - - if (newStep > 0) { - this.step = newStep; - } - - this.autoScale = false; -}; - -/** - * Enable or disable autoscaling - * @param {boolean} enable If true, autoascaling is set true - */ -TimeStep.prototype.setAutoScale = function (enable) { - this.autoScale = enable; -}; - - -/** - * Automatically determine the scale that bests fits the provided minimum step - * @param {Number} [minimumStep] The minimum step size in milliseconds - */ -TimeStep.prototype.setMinimumStep = function(minimumStep) { - if (minimumStep == undefined) { - return; - } - - var stepYear = (1000 * 60 * 60 * 24 * 30 * 12); - var stepMonth = (1000 * 60 * 60 * 24 * 30); - var stepDay = (1000 * 60 * 60 * 24); - var stepHour = (1000 * 60 * 60); - var stepMinute = (1000 * 60); - var stepSecond = (1000); - var stepMillisecond= (1); - - // find the smallest step that is larger than the provided minimumStep - if (stepYear*1000 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 1000;} - if (stepYear*500 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 500;} - if (stepYear*100 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 100;} - if (stepYear*50 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 50;} - if (stepYear*10 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 10;} - if (stepYear*5 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 5;} - if (stepYear > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 1;} - if (stepMonth*3 > minimumStep) {this.scale = TimeStep.SCALE.MONTH; this.step = 3;} - if (stepMonth > minimumStep) {this.scale = TimeStep.SCALE.MONTH; this.step = 1;} - if (stepDay*5 > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 5;} - if (stepDay*2 > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 2;} - if (stepDay > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 1;} - if (stepDay/2 > minimumStep) {this.scale = TimeStep.SCALE.WEEKDAY; this.step = 1;} - if (stepHour*4 > minimumStep) {this.scale = TimeStep.SCALE.HOUR; this.step = 4;} - if (stepHour > minimumStep) {this.scale = TimeStep.SCALE.HOUR; this.step = 1;} - if (stepMinute*15 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 15;} - if (stepMinute*10 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 10;} - if (stepMinute*5 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 5;} - if (stepMinute > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 1;} - if (stepSecond*15 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 15;} - if (stepSecond*10 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 10;} - if (stepSecond*5 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 5;} - if (stepSecond > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 1;} - if (stepMillisecond*200 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 200;} - if (stepMillisecond*100 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 100;} - if (stepMillisecond*50 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 50;} - if (stepMillisecond*10 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 10;} - if (stepMillisecond*5 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 5;} - if (stepMillisecond > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 1;} -}; - -/** - * Snap a date to a rounded value. The snap intervals are dependent on the - * current scale and step. - * @param {Date} date the date to be snapped - */ -TimeStep.prototype.snap = function(date) { - if (this.scale == TimeStep.SCALE.YEAR) { - var year = date.getFullYear() + Math.round(date.getMonth() / 12); - date.setFullYear(Math.round(year / this.step) * this.step); - date.setMonth(0); - date.setDate(0); - date.setHours(0); - date.setMinutes(0); - date.setSeconds(0); - date.setMilliseconds(0); - } - else if (this.scale == TimeStep.SCALE.MONTH) { - if (date.getDate() > 15) { - date.setDate(1); - date.setMonth(date.getMonth() + 1); - // important: first set Date to 1, after that change the month. - } - else { - date.setDate(1); - } - - date.setHours(0); - date.setMinutes(0); - date.setSeconds(0); - date.setMilliseconds(0); - } - else if (this.scale == TimeStep.SCALE.DAY || - this.scale == TimeStep.SCALE.WEEKDAY) { - //noinspection FallthroughInSwitchStatementJS - switch (this.step) { - case 5: - case 2: - date.setHours(Math.round(date.getHours() / 24) * 24); break; - default: - date.setHours(Math.round(date.getHours() / 12) * 12); break; - } - date.setMinutes(0); - date.setSeconds(0); - date.setMilliseconds(0); - } - else if (this.scale == TimeStep.SCALE.HOUR) { - switch (this.step) { - case 4: - date.setMinutes(Math.round(date.getMinutes() / 60) * 60); break; - default: - date.setMinutes(Math.round(date.getMinutes() / 30) * 30); break; - } - date.setSeconds(0); - date.setMilliseconds(0); - } else if (this.scale == TimeStep.SCALE.MINUTE) { - //noinspection FallthroughInSwitchStatementJS - switch (this.step) { - case 15: - case 10: - date.setMinutes(Math.round(date.getMinutes() / 5) * 5); - date.setSeconds(0); - break; - case 5: - date.setSeconds(Math.round(date.getSeconds() / 60) * 60); break; - default: - date.setSeconds(Math.round(date.getSeconds() / 30) * 30); break; - } - date.setMilliseconds(0); - } - else if (this.scale == TimeStep.SCALE.SECOND) { - //noinspection FallthroughInSwitchStatementJS - switch (this.step) { - case 15: - case 10: - date.setSeconds(Math.round(date.getSeconds() / 5) * 5); - date.setMilliseconds(0); - break; - case 5: - date.setMilliseconds(Math.round(date.getMilliseconds() / 1000) * 1000); break; - default: - date.setMilliseconds(Math.round(date.getMilliseconds() / 500) * 500); break; - } - } - else if (this.scale == TimeStep.SCALE.MILLISECOND) { - var step = this.step > 5 ? this.step / 2 : 1; - date.setMilliseconds(Math.round(date.getMilliseconds() / step) * step); - } -}; - -/** - * Check if the current value is a major value (for example when the step - * is DAY, a major value is each first day of the MONTH) - * @return {boolean} true if current date is major, else false. - */ -TimeStep.prototype.isMajor = function() { - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: - return (this.current.getMilliseconds() == 0); - case TimeStep.SCALE.SECOND: - return (this.current.getSeconds() == 0); - case TimeStep.SCALE.MINUTE: - return (this.current.getHours() == 0) && (this.current.getMinutes() == 0); - // Note: this is no bug. Major label is equal for both minute and hour scale - case TimeStep.SCALE.HOUR: - return (this.current.getHours() == 0); - case TimeStep.SCALE.WEEKDAY: // intentional fall through - case TimeStep.SCALE.DAY: - return (this.current.getDate() == 1); - case TimeStep.SCALE.MONTH: - return (this.current.getMonth() == 0); - case TimeStep.SCALE.YEAR: - return false; - default: - return false; - } -}; - - -/** - * Returns formatted text for the minor axislabel, depending on the current - * date and the scale. For example when scale is MINUTE, the current time is - * formatted as "hh:mm". - * @param {Date} [date] custom date. if not provided, current date is taken - */ -TimeStep.prototype.getLabelMinor = function(date) { - if (date == undefined) { - date = this.current; - } - - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND: return moment(date).format('SSS'); - case TimeStep.SCALE.SECOND: return moment(date).format('s'); - case TimeStep.SCALE.MINUTE: return moment(date).format('HH:mm'); - case TimeStep.SCALE.HOUR: return moment(date).format('HH:mm'); - case TimeStep.SCALE.WEEKDAY: return moment(date).format('ddd D'); - case TimeStep.SCALE.DAY: return moment(date).format('D'); - case TimeStep.SCALE.MONTH: return moment(date).format('MMM'); - case TimeStep.SCALE.YEAR: return moment(date).format('YYYY'); - default: return ''; - } -}; - - -/** - * Returns formatted text for the major axis label, depending on the current - * date and the scale. For example when scale is MINUTE, the major scale is - * hours, and the hour will be formatted as "hh". - * @param {Date} [date] custom date. if not provided, current date is taken - */ -TimeStep.prototype.getLabelMajor = function(date) { - if (date == undefined) { - date = this.current; - } - - //noinspection FallthroughInSwitchStatementJS - switch (this.scale) { - case TimeStep.SCALE.MILLISECOND:return moment(date).format('HH:mm:ss'); - case TimeStep.SCALE.SECOND: return moment(date).format('D MMMM HH:mm'); - case TimeStep.SCALE.MINUTE: - case TimeStep.SCALE.HOUR: return moment(date).format('ddd D MMMM'); - case TimeStep.SCALE.WEEKDAY: - case TimeStep.SCALE.DAY: return moment(date).format('MMMM YYYY'); - case TimeStep.SCALE.MONTH: return moment(date).format('YYYY'); - case TimeStep.SCALE.YEAR: return ''; - default: return ''; - } -}; - -/** - * @constructor Stack - * Stacks items on top of each other. - * @param {ItemSet} parent - * @param {Object} [options] - */ -function Stack (parent, options) { - this.parent = parent; - - this.options = options || {}; - this.defaultOptions = { - order: function (a, b) { - //return (b.width - a.width) || (a.left - b.left); // TODO: cleanup - // Order: ranges over non-ranges, ranged ordered by width, and - // lastly ordered by start. - if (a instanceof ItemRange) { - if (b instanceof ItemRange) { - var aInt = (a.data.end - a.data.start); - var bInt = (b.data.end - b.data.start); - return (aInt - bInt) || (a.data.start - b.data.start); - } - else { - return -1; - } - } - else { - if (b instanceof ItemRange) { - return 1; - } - else { - return (a.data.start - b.data.start); - } - } - }, - margin: { - item: 10 - } - }; - - this.ordered = []; // ordered items -} - -/** - * Set options for the stack - * @param {Object} options Available options: - * {ItemSet} parent - * {Number} margin - * {function} order Stacking order - */ -Stack.prototype.setOptions = function setOptions (options) { - util.extend(this.options, options); - - // TODO: register on data changes at the connected parent itemset, and update the changed part only and immediately -}; - -/** - * Stack the items such that they don't overlap. The items will have a minimal - * distance equal to options.margin.item. - */ -Stack.prototype.update = function update() { - this._order(); - this._stack(); -}; - -/** - * Order the items. The items are ordered by width first, and by left position - * second. - * If a custom order function has been provided via the options, then this will - * be used. - * @private - */ -Stack.prototype._order = function _order () { - var items = this.parent.items; - if (!items) { - throw new Error('Cannot stack items: parent does not contain items'); - } - - // TODO: store the sorted items, to have less work later on - var ordered = []; - var index = 0; - // items is a map (no array) - util.forEach(items, function (item) { - if (item.visible) { - ordered[index] = item; - index++; - } - }); - - //if a customer stack order function exists, use it. - var order = this.options.order || this.defaultOptions.order; - if (!(typeof order === 'function')) { - throw new Error('Option order must be a function'); - } - - ordered.sort(order); - - this.ordered = ordered; -}; - -/** - * Adjust vertical positions of the events such that they don't overlap each - * other. - * @private - */ -Stack.prototype._stack = function _stack () { - var i, - iMax, - ordered = this.ordered, - options = this.options, - orientation = options.orientation || this.defaultOptions.orientation, - axisOnTop = (orientation == 'top'), - margin; - - if (options.margin && options.margin.item !== undefined) { - margin = options.margin.item; - } - else { - margin = this.defaultOptions.margin.item - } - - // calculate new, non-overlapping positions - for (i = 0, iMax = ordered.length; i < iMax; i++) { - var item = ordered[i]; - var collidingItem = null; - do { - // TODO: optimize checking for overlap. when there is a gap without items, - // you only need to check for items from the next item on, not from zero - collidingItem = this.checkOverlap(ordered, i, 0, i - 1, margin); - if (collidingItem != null) { - // There is a collision. Reposition the event above the colliding element - if (axisOnTop) { - item.top = collidingItem.top + collidingItem.height + margin; - } - else { - item.top = collidingItem.top - item.height - margin; - } - } - } while (collidingItem); - } -}; - -/** - * Check if the destiny position of given item overlaps with any - * of the other items from index itemStart to itemEnd. - * @param {Array} items Array with items - * @param {int} itemIndex Number of the item to be checked for overlap - * @param {int} itemStart First item to be checked. - * @param {int} itemEnd Last item to be checked. - * @return {Object | null} colliding item, or undefined when no collisions - * @param {Number} margin A minimum required margin. - * If margin is provided, the two items will be - * marked colliding when they overlap or - * when the margin between the two is smaller than - * the requested margin. - */ -Stack.prototype.checkOverlap = function checkOverlap (items, itemIndex, - itemStart, itemEnd, margin) { - var collision = this.collision; - - // we loop from end to start, as we suppose that the chance of a - // collision is larger for items at the end, so check these first. - var a = items[itemIndex]; - for (var i = itemEnd; i >= itemStart; i--) { - var b = items[i]; - if (collision(a, b, margin)) { - if (i != itemIndex) { - return b; - } - } - } - - return null; -}; - -/** - * Test if the two provided items collide - * The items must have parameters left, width, top, and height. - * @param {Component} a The first item - * @param {Component} b The second item - * @param {Number} margin A minimum required margin. - * If margin is provided, the two items will be - * marked colliding when they overlap or - * when the margin between the two is smaller than - * the requested margin. - * @return {boolean} true if a and b collide, else false - */ -Stack.prototype.collision = function collision (a, b, margin) { - return ((a.left - margin) < (b.left + b.width) && - (a.left + a.width + margin) > b.left && - (a.top - margin) < (b.top + b.height) && - (a.top + a.height + margin) > b.top); -}; - -/** - * @constructor Range - * A Range controls a numeric range with a start and end value. - * The Range adjusts the range based on mouse events or programmatic changes, - * and triggers events when the range is changing or has been changed. - * @param {Object} [options] See description at Range.setOptions - * @extends Controller - */ -function Range(options) { - this.id = util.randomUUID(); - this.start = 0; // Number - this.end = 0; // Number - - // this.options = options || {}; // TODO: fix range options - this.options = { - min: null, - max: null, - zoomMin: null, - zoomMax: null - }; - - this.listeners = []; - - this.setOptions(options); -} - -/** - * Set options for the range controller - * @param {Object} options Available options: - * {Number} start Set start value of the range - * {Number} end Set end value of the range - * {Number} min Minimum value for start - * {Number} max Maximum value for end - * {Number} zoomMin Set a minimum value for - * (end - start). - * {Number} zoomMax Set a maximum value for - * (end - start). - */ -Range.prototype.setOptions = function (options) { - util.extend(this.options, options); - - if (options.start != null || options.end != null) { - this.setRange(options.start, options.end); - } -}; - -/** - * Add listeners for mouse and touch events to the component - * @param {Component} component - * @param {String} event Available events: 'move', 'zoom' - * @param {String} direction Available directions: 'horizontal', 'vertical' - */ -Range.prototype.subscribe = function (component, event, direction) { - var me = this; - var listener; - - if (direction != 'horizontal' && direction != 'vertical') { - throw new TypeError('Unknown direction "' + direction + '". ' + - 'Choose "horizontal" or "vertical".'); - } - - //noinspection FallthroughInSwitchStatementJS - if (event == 'move') { - listener = { - component: component, - event: event, - direction: direction, - callback: function (event) { - me._onMouseDown(event, listener); - }, - params: {} - }; - - component.on('mousedown', listener.callback); - me.listeners.push(listener); - } - else if (event == 'zoom') { - listener = { - component: component, - event: event, - direction: direction, - callback: function (event) { - me._onMouseWheel(event, listener); - }, - params: {} - }; - - component.on('mousewheel', listener.callback); - me.listeners.push(listener); - } - else { - throw new TypeError('Unknown event "' + event + '". ' + - 'Choose "move" or "zoom".'); - } -}; - -/** - * Event handler - * @param {String} event name of the event, for example 'click', 'mousemove' - * @param {function} callback callback handler, invoked with the raw HTML Event - * as parameter. - */ -Range.prototype.on = function (event, callback) { - events.addListener(this, event, callback); -}; - -/** - * Trigger an event - * @param {String} event name of the event, available events: 'rangechange', - * 'rangechanged' - * @private - */ -Range.prototype._trigger = function (event) { - events.trigger(this, event, { - start: this.start, - end: this.end - }); -}; - -/** - * Set a new start and end range - * @param {Number} start - * @param {Number} end - */ -Range.prototype.setRange = function(start, end) { - var changed = this._applyRange(start, end); - if (changed) { - this._trigger('rangechange'); - this._trigger('rangechanged'); - } -}; - -/** - * Set a new start and end range. This method is the same as setRange, but - * does not trigger a range change and range changed event, and it returns - * true when the range is changed - * @param {Number} start - * @param {Number} end - * @return {Boolean} changed - * @private - */ -Range.prototype._applyRange = function(start, end) { - var newStart = (start != null) ? util.convert(start, 'Number') : this.start; - var newEnd = (end != null) ? util.convert(end, 'Number') : this.end; - var diff; - - // check for valid number - if (isNaN(newStart)) { - throw new Error('Invalid start "' + start + '"'); - } - if (isNaN(newEnd)) { - throw new Error('Invalid end "' + end + '"'); - } - - // prevent start < end - if (newEnd < newStart) { - newEnd = newStart; - } - - // prevent start < min - if (this.options.min != null) { - var min = this.options.min.valueOf(); - if (newStart < min) { - diff = (min - newStart); - newStart += diff; - newEnd += diff; - } - } - - // prevent end > max - if (this.options.max != null) { - var max = this.options.max.valueOf(); - if (newEnd > max) { - diff = (newEnd - max); - newStart -= diff; - newEnd -= diff; - } - } - - // prevent (end-start) > zoomMin - if (this.options.zoomMin != null) { - var zoomMin = this.options.zoomMin.valueOf(); - if (zoomMin < 0) { - zoomMin = 0; - } - if ((newEnd - newStart) < zoomMin) { - if ((this.end - this.start) > zoomMin) { - // zoom to the minimum - diff = (zoomMin - (newEnd - newStart)); - newStart -= diff / 2; - newEnd += diff / 2; - } - else { - // ingore this action, we are already zoomed to the minimum - newStart = this.start; - newEnd = this.end; - } - } - } - - // prevent (end-start) > zoomMin - if (this.options.zoomMax != null) { - var zoomMax = this.options.zoomMax.valueOf(); - if (zoomMax < 0) { - zoomMax = 0; - } - if ((newEnd - newStart) > zoomMax) { - if ((this.end - this.start) < zoomMax) { - // zoom to the maximum - diff = ((newEnd - newStart) - zoomMax); - newStart += diff / 2; - newEnd -= diff / 2; - } - else { - // ingore this action, we are already zoomed to the maximum - newStart = this.start; - newEnd = this.end; - } - } - } - - var changed = (this.start != newStart || this.end != newEnd); - - this.start = newStart; - this.end = newEnd; - - return changed; -}; - -/** - * Retrieve the current range. - * @return {Object} An object with start and end properties - */ -Range.prototype.getRange = function() { - return { - start: this.start, - end: this.end - }; -}; - -/** - * Calculate the conversion offset and factor for current range, based on - * the provided width - * @param {Number} width - * @returns {{offset: number, factor: number}} conversion - */ -Range.prototype.conversion = function (width) { - var start = this.start; - var end = this.end; - - return Range.conversion(this.start, this.end, width); -}; - -/** - * Static method to calculate the conversion offset and factor for a range, - * based on the provided start, end, and width - * @param {Number} start - * @param {Number} end - * @param {Number} width - * @returns {{offset: number, factor: number}} conversion - */ -Range.conversion = function (start, end, width) { - if (width != 0 && (end - start != 0)) { - return { - offset: start, - factor: width / (end - start) - } - } - else { - return { - offset: 0, - factor: 1 - }; - } -}; - -/** - * Start moving horizontally or vertically - * @param {Event} event - * @param {Object} listener Listener containing the component and params - * @private - */ -Range.prototype._onMouseDown = function(event, listener) { - event = event || window.event; - var params = listener.params; - - // only react on left mouse button down - var leftButtonDown = event.which ? (event.which == 1) : (event.button == 1); - if (!leftButtonDown) { - return; - } - - // get mouse position - params.mouseX = util.getPageX(event); - params.mouseY = util.getPageY(event); - params.previousLeft = 0; - params.previousOffset = 0; - - params.moved = false; - params.start = this.start; - params.end = this.end; - - var frame = listener.component.frame; - if (frame) { - frame.style.cursor = 'move'; - } - - // add event listeners to handle moving the contents - // we store the function onmousemove and onmouseup in the timeaxis, - // so we can remove the eventlisteners lateron in the function onmouseup - var me = this; - if (!params.onMouseMove) { - params.onMouseMove = function (event) { - me._onMouseMove(event, listener); - }; - util.addEventListener(document, "mousemove", params.onMouseMove); - } - if (!params.onMouseUp) { - params.onMouseUp = function (event) { - me._onMouseUp(event, listener); - }; - util.addEventListener(document, "mouseup", params.onMouseUp); - } - - util.preventDefault(event); -}; - -/** - * Perform moving operating. - * This function activated from within the funcion TimeAxis._onMouseDown(). - * @param {Event} event - * @param {Object} listener - * @private - */ -Range.prototype._onMouseMove = function (event, listener) { - event = event || window.event; - - var params = listener.params; - - // calculate change in mouse position - var mouseX = util.getPageX(event); - var mouseY = util.getPageY(event); - - if (params.mouseX == undefined) { - params.mouseX = mouseX; - } - if (params.mouseY == undefined) { - params.mouseY = mouseY; - } - - var diffX = mouseX - params.mouseX; - var diffY = mouseY - params.mouseY; - var diff = (listener.direction == 'horizontal') ? diffX : diffY; - - // if mouse movement is big enough, register it as a "moved" event - if (Math.abs(diff) >= 1) { - params.moved = true; - } - - var interval = (params.end - params.start); - var width = (listener.direction == 'horizontal') ? - listener.component.width : listener.component.height; - var diffRange = -diff / width * interval; - this._applyRange(params.start + diffRange, params.end + diffRange); - - // fire a rangechange event - this._trigger('rangechange'); - - util.preventDefault(event); -}; - -/** - * Stop moving operating. - * This function activated from within the function Range._onMouseDown(). - * @param {event} event - * @param {Object} listener - * @private - */ -Range.prototype._onMouseUp = function (event, listener) { - event = event || window.event; - - var params = listener.params; - - if (listener.component.frame) { - listener.component.frame.style.cursor = 'auto'; - } - - // remove event listeners here, important for Safari - if (params.onMouseMove) { - util.removeEventListener(document, "mousemove", params.onMouseMove); - params.onMouseMove = null; - } - if (params.onMouseUp) { - util.removeEventListener(document, "mouseup", params.onMouseUp); - params.onMouseUp = null; - } - //util.preventDefault(event); - - if (params.moved) { - // fire a rangechanged event - this._trigger('rangechanged'); - } -}; - -/** - * Event handler for mouse wheel event, used to zoom - * Code from http://adomas.org/javascript-mouse-wheel/ - * @param {Event} event - * @param {Object} listener - * @private - */ -Range.prototype._onMouseWheel = function(event, listener) { - event = event || window.event; - - // retrieve delta - var delta = 0; - if (event.wheelDelta) { /* IE/Opera. */ - delta = event.wheelDelta / 120; - } else if (event.detail) { /* Mozilla case. */ - // In Mozilla, sign of delta is different than in IE. - // Also, delta is multiple of 3. - delta = -event.detail / 3; - } - - // If delta is nonzero, handle it. - // Basically, delta is now positive if wheel was scrolled up, - // and negative, if wheel was scrolled down. - if (delta) { - var me = this; - var zoom = function () { - // perform the zoom action. Delta is normally 1 or -1 - var zoomFactor = delta / 5.0; - var zoomAround = null; - var frame = listener.component.frame; - if (frame) { - var size, conversion; - if (listener.direction == 'horizontal') { - size = listener.component.width; - conversion = me.conversion(size); - var frameLeft = util.getAbsoluteLeft(frame); - var mouseX = util.getPageX(event); - zoomAround = (mouseX - frameLeft) / conversion.factor + conversion.offset; - } - else { - size = listener.component.height; - conversion = me.conversion(size); - var frameTop = util.getAbsoluteTop(frame); - var mouseY = util.getPageY(event); - zoomAround = ((frameTop + size - mouseY) - frameTop) / conversion.factor + conversion.offset; - } - } - - me.zoom(zoomFactor, zoomAround); - }; - - zoom(); - } - - // Prevent default actions caused by mouse wheel. - // That might be ugly, but we handle scrolls somehow - // anyway, so don't bother here... - util.preventDefault(event); -}; - - -/** - * Zoom the range the given zoomfactor in or out. Start and end date will - * be adjusted, and the timeline will be redrawn. You can optionally give a - * date around which to zoom. - * For example, try zoomfactor = 0.1 or -0.1 - * @param {Number} zoomFactor Zooming amount. Positive value will zoom in, - * negative value will zoom out - * @param {Number} zoomAround Value around which will be zoomed. Optional - */ -Range.prototype.zoom = function(zoomFactor, zoomAround) { - // if zoomAroundDate is not provided, take it half between start Date and end Date - if (zoomAround == null) { - zoomAround = (this.start + this.end) / 2; - } - - // prevent zoom factor larger than 1 or smaller than -1 (larger than 1 will - // result in a start>=end ) - if (zoomFactor >= 1) { - zoomFactor = 0.9; - } - if (zoomFactor <= -1) { - zoomFactor = -0.9; - } - - // adjust a negative factor such that zooming in with 0.1 equals zooming - // out with a factor -0.1 - if (zoomFactor < 0) { - zoomFactor = zoomFactor / (1 + zoomFactor); - } - - // zoom start and end relative to the zoomAround value - var startDiff = (this.start - zoomAround); - var endDiff = (this.end - zoomAround); - - // calculate new start and end - var newStart = this.start - startDiff * zoomFactor; - var newEnd = this.end - endDiff * zoomFactor; - - this.setRange(newStart, newEnd); -}; - -/** - * Move the range with a given factor to the left or right. Start and end - * value will be adjusted. For example, try moveFactor = 0.1 or -0.1 - * @param {Number} moveFactor Moving amount. Positive value will move right, - * negative value will move left - */ -Range.prototype.move = function(moveFactor) { - // zoom start Date and end Date relative to the zoomAroundDate - var diff = (this.end - this.start); - - // apply new values - var newStart = this.start + diff * moveFactor; - var newEnd = this.end + diff * moveFactor; - - // TODO: reckon with min and max range - - this.start = newStart; - this.end = newEnd; -}; - -/** - * Move the range to a new center point - * @param {Number} moveTo New center point of the range - */ -Range.prototype.moveTo = function(moveTo) { - var center = (this.start + this.end) / 2; - - var diff = center - moveTo; - - // calculate new start and end - var newStart = this.start - diff; - var newEnd = this.end - diff; - - this.setRange(newStart, newEnd); -} - -/** - * @constructor Controller - * - * A Controller controls the reflows and repaints of all visual components - */ -function Controller () { - this.id = util.randomUUID(); - this.components = {}; - - this.repaintTimer = undefined; - this.reflowTimer = undefined; -} - -/** - * Add a component to the controller - * @param {Component} component - */ -Controller.prototype.add = function add(component) { - // validate the component - if (component.id == undefined) { - throw new Error('Component has no field id'); - } - if (!(component instanceof Component) && !(component instanceof Controller)) { - throw new TypeError('Component must be an instance of ' + - 'prototype Component or Controller'); - } - - // add the component - component.controller = this; - this.components[component.id] = component; -}; - -/** - * Remove a component from the controller - * @param {Component | String} component - */ -Controller.prototype.remove = function remove(component) { - var id; - for (id in this.components) { - if (this.components.hasOwnProperty(id)) { - if (id == component || this.components[id] == component) { - break; - } - } - } - - if (id) { - delete this.components[id]; - } -}; - -/** - * Request a reflow. The controller will schedule a reflow - * @param {Boolean} [force] If true, an immediate reflow is forced. Default - * is false. - */ -Controller.prototype.requestReflow = function requestReflow(force) { - if (force) { - this.reflow(); - } - else { - if (!this.reflowTimer) { - var me = this; - this.reflowTimer = setTimeout(function () { - me.reflowTimer = undefined; - me.reflow(); - }, 0); - } - } -}; - -/** - * Request a repaint. The controller will schedule a repaint - * @param {Boolean} [force] If true, an immediate repaint is forced. Default - * is false. - */ -Controller.prototype.requestRepaint = function requestRepaint(force) { - if (force) { - this.repaint(); - } - else { - if (!this.repaintTimer) { - var me = this; - this.repaintTimer = setTimeout(function () { - me.repaintTimer = undefined; - me.repaint(); - }, 0); - } - } -}; - -/** - * Repaint all components - */ -Controller.prototype.repaint = function repaint() { - var changed = false; - - // cancel any running repaint request - if (this.repaintTimer) { - clearTimeout(this.repaintTimer); - this.repaintTimer = undefined; - } - - var done = {}; - - function repaint(component, id) { - if (!(id in done)) { - // first repaint the components on which this component is dependent - if (component.depends) { - component.depends.forEach(function (dep) { - repaint(dep, dep.id); - }); - } - if (component.parent) { - repaint(component.parent, component.parent.id); - } - - // repaint the component itself and mark as done - changed = component.repaint() || changed; - done[id] = true; - } - } - - util.forEach(this.components, repaint); - - // immediately reflow when needed - if (changed) { - this.reflow(); - } - // TODO: limit the number of nested reflows/repaints, prevent loop -}; - -/** - * Reflow all components - */ -Controller.prototype.reflow = function reflow() { - var resized = false; - - // cancel any running repaint request - if (this.reflowTimer) { - clearTimeout(this.reflowTimer); - this.reflowTimer = undefined; - } - - var done = {}; - - function reflow(component, id) { - if (!(id in done)) { - // first reflow the components on which this component is dependent - if (component.depends) { - component.depends.forEach(function (dep) { - reflow(dep, dep.id); - }); - } - if (component.parent) { - reflow(component.parent, component.parent.id); - } - - // reflow the component itself and mark as done - resized = component.reflow() || resized; - done[id] = true; - } - } - - util.forEach(this.components, reflow); - - // immediately repaint when needed - if (resized) { - this.repaint(); - } - // TODO: limit the number of nested reflows/repaints, prevent loop -}; - -/** - * Prototype for visual components - */ -function Component () { - this.id = null; - this.parent = null; - this.depends = null; - this.controller = null; - this.options = null; - - this.frame = null; // main DOM element - this.top = 0; - this.left = 0; - this.width = 0; - this.height = 0; -} - -/** - * Set parameters for the frame. Parameters will be merged in current parameter - * set. - * @param {Object} options Available parameters: - * {String | function} [className] - * {EventBus} [eventBus] - * {String | Number | function} [left] - * {String | Number | function} [top] - * {String | Number | function} [width] - * {String | Number | function} [height] - */ -Component.prototype.setOptions = function setOptions(options) { - if (options) { - util.extend(this.options, options); - - if (this.controller) { - this.requestRepaint(); - this.requestReflow(); - } - } -}; - -/** - * Get an option value by name - * The function will first check this.options object, and else will check - * this.defaultOptions. - * @param {String} name - * @return {*} value - */ -Component.prototype.getOption = function getOption(name) { - var value; - if (this.options) { - value = this.options[name]; - } - if (value === undefined && this.defaultOptions) { - value = this.defaultOptions[name]; - } - return value; -}; - -/** - * Get the container element of the component, which can be used by a child to - * add its own widgets. Not all components do have a container for childs, in - * that case null is returned. - * @returns {HTMLElement | null} container - */ -// TODO: get rid of the getContainer and getFrame methods, provide these via the options -Component.prototype.getContainer = function getContainer() { - // should be implemented by the component - return null; -}; - -/** - * Get the frame element of the component, the outer HTML DOM element. - * @returns {HTMLElement | null} frame - */ -Component.prototype.getFrame = function getFrame() { - return this.frame; -}; - -/** - * Repaint the component - * @return {Boolean} changed - */ -Component.prototype.repaint = function repaint() { - // should be implemented by the component - return false; -}; - -/** - * Reflow the component - * @return {Boolean} resized - */ -Component.prototype.reflow = function reflow() { - // should be implemented by the component - return false; -}; - -/** - * Hide the component from the DOM - * @return {Boolean} changed - */ -Component.prototype.hide = function hide() { - if (this.frame && this.frame.parentNode) { - this.frame.parentNode.removeChild(this.frame); - return true; - } - else { - return false; - } -}; - -/** - * Show the component in the DOM (when not already visible). - * A repaint will be executed when the component is not visible - * @return {Boolean} changed - */ -Component.prototype.show = function show() { - if (!this.frame || !this.frame.parentNode) { - return this.repaint(); - } - else { - return false; - } -}; - -/** - * Request a repaint. The controller will schedule a repaint - */ -Component.prototype.requestRepaint = function requestRepaint() { - if (this.controller) { - this.controller.requestRepaint(); - } - else { - throw new Error('Cannot request a repaint: no controller configured'); - // TODO: just do a repaint when no parent is configured? - } -}; - -/** - * Request a reflow. The controller will schedule a reflow - */ -Component.prototype.requestReflow = function requestReflow() { - if (this.controller) { - this.controller.requestReflow(); - } - else { - throw new Error('Cannot request a reflow: no controller configured'); - // TODO: just do a reflow when no parent is configured? - } -}; - -/** - * A panel can contain components - * @param {Component} [parent] - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) - * @param {Object} [options] Available parameters: - * {String | Number | function} [left] - * {String | Number | function} [top] - * {String | Number | function} [width] - * {String | Number | function} [height] - * {String | function} [className] - * @constructor Panel - * @extends Component - */ -function Panel(parent, depends, options) { - this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; - - this.options = options || {}; -} - -Panel.prototype = new Component(); - -/** - * Set options. Will extend the current options. - * @param {Object} [options] Available parameters: - * {String | function} [className] - * {String | Number | function} [left] - * {String | Number | function} [top] - * {String | Number | function} [width] - * {String | Number | function} [height] - */ -Panel.prototype.setOptions = Component.prototype.setOptions; - -/** - * Get the container element of the panel, which can be used by a child to - * add its own widgets. - * @returns {HTMLElement} container - */ -Panel.prototype.getContainer = function () { - return this.frame; -}; - -/** - * Repaint the component - * @return {Boolean} changed - */ -Panel.prototype.repaint = function () { - var changed = 0, - update = util.updateProperty, - asSize = util.option.asSize, - options = this.options, - frame = this.frame; - if (!frame) { - frame = document.createElement('div'); - frame.className = 'panel'; - - var className = options.className; - if (className) { - if (typeof className == 'function') { - util.addClassName(frame, String(className())); - } - else { - util.addClassName(frame, String(className)); - } - } - - this.frame = frame; - changed += 1; - } - if (!frame.parentNode) { - if (!this.parent) { - throw new Error('Cannot repaint panel: no parent attached'); - } - var parentContainer = this.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint panel: parent has no container element'); - } - parentContainer.appendChild(frame); - changed += 1; - } - - changed += update(frame.style, 'top', asSize(options.top, '0px')); - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - changed += update(frame.style, 'height', asSize(options.height, '100%')); - - return (changed > 0); -}; - -/** - * Reflow the component - * @return {Boolean} resized - */ -Panel.prototype.reflow = function () { - var changed = 0, - update = util.updateProperty, - frame = this.frame; - - if (frame) { - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - changed += update(this, 'width', frame.offsetWidth); - changed += update(this, 'height', frame.offsetHeight); - } - else { - changed += 1; - } - - return (changed > 0); -}; - -/** - * A root panel can hold components. The root panel must be initialized with - * a DOM element as container. - * @param {HTMLElement} container - * @param {Object} [options] Available parameters: see RootPanel.setOptions. - * @constructor RootPanel - * @extends Panel - */ -function RootPanel(container, options) { - this.id = util.randomUUID(); - this.container = container; - - this.options = options || {}; - this.defaultOptions = { - autoResize: true - }; - - this.listeners = {}; // event listeners -} - -RootPanel.prototype = new Panel(); - -/** - * Set options. Will extend the current options. - * @param {Object} [options] Available parameters: - * {String | function} [className] - * {String | Number | function} [left] - * {String | Number | function} [top] - * {String | Number | function} [width] - * {String | Number | function} [height] - * {Boolean | function} [autoResize] - */ -RootPanel.prototype.setOptions = Component.prototype.setOptions; - -/** - * Repaint the component - * @return {Boolean} changed - */ -RootPanel.prototype.repaint = function () { - var changed = 0, - update = util.updateProperty, - asSize = util.option.asSize, - options = this.options, - frame = this.frame; - - if (!frame) { - frame = document.createElement('div'); - frame.className = 'vis timeline rootpanel'; - - var className = options.className; - if (className) { - util.addClassName(frame, util.option.asString(className)); - } - - this.frame = frame; - - changed += 1; - } - if (!frame.parentNode) { - if (!this.container) { - throw new Error('Cannot repaint root panel: no container attached'); - } - this.container.appendChild(frame); - changed += 1; - } - - changed += update(frame.style, 'top', asSize(options.top, '0px')); - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - changed += update(frame.style, 'height', asSize(options.height, '100%')); - - this._updateEventEmitters(); - this._updateWatch(); - - return (changed > 0); -}; - -/** - * Reflow the component - * @return {Boolean} resized - */ -RootPanel.prototype.reflow = function () { - var changed = 0, - update = util.updateProperty, - frame = this.frame; - - if (frame) { - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - changed += update(this, 'width', frame.offsetWidth); - changed += update(this, 'height', frame.offsetHeight); - } - else { - changed += 1; - } - - return (changed > 0); -}; - -/** - * Update watching for resize, depending on the current option - * @private - */ -RootPanel.prototype._updateWatch = function () { - var autoResize = this.getOption('autoResize'); - if (autoResize) { - this._watch(); - } - else { - this._unwatch(); - } -}; - -/** - * Watch for changes in the size of the frame. On resize, the Panel will - * automatically redraw itself. - * @private - */ -RootPanel.prototype._watch = function () { - var me = this; - - this._unwatch(); - - var checkSize = function () { - var autoResize = me.getOption('autoResize'); - if (!autoResize) { - // stop watching when the option autoResize is changed to false - me._unwatch(); - return; - } - - if (me.frame) { - // check whether the frame is resized - if ((me.frame.clientWidth != me.width) || - (me.frame.clientHeight != me.height)) { - me.requestReflow(); - } - } - }; - - // TODO: automatically cleanup the event listener when the frame is deleted - util.addEventListener(window, 'resize', checkSize); - - this.watchTimer = setInterval(checkSize, 1000); -}; - -/** - * Stop watching for a resize of the frame. - * @private - */ -RootPanel.prototype._unwatch = function () { - if (this.watchTimer) { - clearInterval(this.watchTimer); - this.watchTimer = undefined; - } - - // TODO: remove event listener on window.resize -}; - -/** - * Event handler - * @param {String} event name of the event, for example 'click', 'mousemove' - * @param {function} callback callback handler, invoked with the raw HTML Event - * as parameter. - */ -RootPanel.prototype.on = function (event, callback) { - // register the listener at this component - var arr = this.listeners[event]; - if (!arr) { - arr = []; - this.listeners[event] = arr; - } - arr.push(callback); - - this._updateEventEmitters(); -}; - -/** - * Update the event listeners for all event emitters - * @private - */ -RootPanel.prototype._updateEventEmitters = function () { - if (this.listeners) { - var me = this; - util.forEach(this.listeners, function (listeners, event) { - if (!me.emitters) { - me.emitters = {}; - } - if (!(event in me.emitters)) { - // create event - var frame = me.frame; - if (frame) { - //console.log('Created a listener for event ' + event + ' on component ' + me.id); // TODO: cleanup logging - var callback = function(event) { - listeners.forEach(function (listener) { - // TODO: filter on event target! - listener(event); - }); - }; - me.emitters[event] = callback; - util.addEventListener(frame, event, callback); - } - } - }); - - // TODO: be able to delete event listeners - // TODO: be able to move event listeners to a parent when available - } -}; - -/** - * A horizontal time axis - * @param {Component} parent - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) - * @param {Object} [options] See TimeAxis.setOptions for the available - * options. - * @constructor TimeAxis - * @extends Component - */ -function TimeAxis (parent, depends, options) { - this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; - - this.dom = { - majorLines: [], - majorTexts: [], - minorLines: [], - minorTexts: [], - redundant: { - majorLines: [], - majorTexts: [], - minorLines: [], - minorTexts: [] - } - }; - this.props = { - range: { - start: 0, - end: 0, - minimumStep: 0 - }, - lineTop: 0 - }; - - this.options = options || {}; - this.defaultOptions = { - orientation: 'bottom', // supported: 'top', 'bottom' - // TODO: implement timeaxis orientations 'left' and 'right' - showMinorLabels: true, - showMajorLabels: true - }; - - this.conversion = null; - this.range = null; -} - -TimeAxis.prototype = new Component(); - -// TODO: comment options -TimeAxis.prototype.setOptions = Component.prototype.setOptions; - -/** - * Set a range (start and end) - * @param {Range | Object} range A Range or an object containing start and end. - */ -TimeAxis.prototype.setRange = function (range) { - if (!(range instanceof Range) && (!range || !range.start || !range.end)) { - throw new TypeError('Range must be an instance of Range, ' + - 'or an object containing start and end.'); - } - this.range = range; -}; - -/** - * Convert a position on screen (pixels) to a datetime - * @param {int} x Position on the screen in pixels - * @return {Date} time The datetime the corresponds with given position x - */ -TimeAxis.prototype.toTime = function(x) { - var conversion = this.conversion; - return new Date(x / conversion.factor + conversion.offset); -}; - -/** - * Convert a datetime (Date object) into a position on the screen - * @param {Date} time A date - * @return {int} x The position on the screen in pixels which corresponds - * with the given date. - * @private - */ -TimeAxis.prototype.toScreen = function(time) { - var conversion = this.conversion; - return (time.valueOf() - conversion.offset) * conversion.factor; -}; - -/** - * Repaint the component - * @return {Boolean} changed - */ -TimeAxis.prototype.repaint = function () { - var changed = 0, - update = util.updateProperty, - asSize = util.option.asSize, - options = this.options, - orientation = this.getOption('orientation'), - props = this.props, - step = this.step; - - var frame = this.frame; - if (!frame) { - frame = document.createElement('div'); - this.frame = frame; - changed += 1; - } - frame.className = 'axis ' + orientation; - // TODO: custom className? - - if (!frame.parentNode) { - if (!this.parent) { - throw new Error('Cannot repaint time axis: no parent attached'); - } - var parentContainer = this.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint time axis: parent has no container element'); - } - parentContainer.appendChild(frame); - - changed += 1; - } - - var parent = frame.parentNode; - if (parent) { - var beforeChild = frame.nextSibling; - parent.removeChild(frame); // take frame offline while updating (is almost twice as fast) - - var defaultTop = (orientation == 'bottom' && this.props.parentHeight && this.height) ? - (this.props.parentHeight - this.height) + 'px' : - '0px'; - changed += update(frame.style, 'top', asSize(options.top, defaultTop)); - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); - - // get characters width and height - this._repaintMeasureChars(); - - if (this.step) { - this._repaintStart(); - - step.first(); - var xFirstMajorLabel = undefined; - var max = 0; - while (step.hasNext() && max < 1000) { - max++; - var cur = step.getCurrent(), - x = this.toScreen(cur), - isMajor = step.isMajor(); - - // TODO: lines must have a width, such that we can create css backgrounds - - if (this.getOption('showMinorLabels')) { - this._repaintMinorText(x, step.getLabelMinor()); - } - - if (isMajor && this.getOption('showMajorLabels')) { - if (x > 0) { - if (xFirstMajorLabel == undefined) { - xFirstMajorLabel = x; - } - this._repaintMajorText(x, step.getLabelMajor()); - } - this._repaintMajorLine(x); - } - else { - this._repaintMinorLine(x); - } - - step.next(); - } - - // create a major label on the left when needed - if (this.getOption('showMajorLabels')) { - var leftTime = this.toTime(0), - leftText = step.getLabelMajor(leftTime), - widthText = leftText.length * (props.majorCharWidth || 10) + 10; // upper bound estimation - - if (xFirstMajorLabel == undefined || widthText < xFirstMajorLabel) { - this._repaintMajorText(0, leftText); - } - } - - this._repaintEnd(); - } - - this._repaintLine(); - - // put frame online again - if (beforeChild) { - parent.insertBefore(frame, beforeChild); - } - else { - parent.appendChild(frame) - } - } - - return (changed > 0); -}; - -/** - * Start a repaint. Move all DOM elements to a redundant list, where they - * can be picked for re-use, or can be cleaned up in the end - * @private - */ -TimeAxis.prototype._repaintStart = function () { - var dom = this.dom, - redundant = dom.redundant; - - redundant.majorLines = dom.majorLines; - redundant.majorTexts = dom.majorTexts; - redundant.minorLines = dom.minorLines; - redundant.minorTexts = dom.minorTexts; - - dom.majorLines = []; - dom.majorTexts = []; - dom.minorLines = []; - dom.minorTexts = []; -}; - -/** - * End a repaint. Cleanup leftover DOM elements in the redundant list - * @private - */ -TimeAxis.prototype._repaintEnd = function () { - util.forEach(this.dom.redundant, function (arr) { - while (arr.length) { - var elem = arr.pop(); - if (elem && elem.parentNode) { - elem.parentNode.removeChild(elem); - } - } - }); -}; - - -/** - * Create a minor label for the axis at position x - * @param {Number} x - * @param {String} text - * @private - */ -TimeAxis.prototype._repaintMinorText = function (x, text) { - // reuse redundant label - var label = this.dom.redundant.minorTexts.shift(); - - if (!label) { - // create new label - var content = document.createTextNode(''); - label = document.createElement('div'); - label.appendChild(content); - label.className = 'text minor'; - this.frame.appendChild(label); - } - this.dom.minorTexts.push(label); - - label.childNodes[0].nodeValue = text; - label.style.left = x + 'px'; - label.style.top = this.props.minorLabelTop + 'px'; - //label.title = title; // TODO: this is a heavy operation -}; - -/** - * Create a Major label for the axis at position x - * @param {Number} x - * @param {String} text - * @private - */ -TimeAxis.prototype._repaintMajorText = function (x, text) { - // reuse redundant label - var label = this.dom.redundant.majorTexts.shift(); - - if (!label) { - // create label - var content = document.createTextNode(text); - label = document.createElement('div'); - label.className = 'text major'; - label.appendChild(content); - this.frame.appendChild(label); - } - this.dom.majorTexts.push(label); - - label.childNodes[0].nodeValue = text; - label.style.top = this.props.majorLabelTop + 'px'; - label.style.left = x + 'px'; - //label.title = title; // TODO: this is a heavy operation -}; - -/** - * Create a minor line for the axis at position x - * @param {Number} x - * @private - */ -TimeAxis.prototype._repaintMinorLine = function (x) { - // reuse redundant line - var line = this.dom.redundant.minorLines.shift(); - - if (!line) { - // create vertical line - line = document.createElement('div'); - line.className = 'grid vertical minor'; - this.frame.appendChild(line); - } - this.dom.minorLines.push(line); - - var props = this.props; - line.style.top = props.minorLineTop + 'px'; - line.style.height = props.minorLineHeight + 'px'; - line.style.left = (x - props.minorLineWidth / 2) + 'px'; -}; - -/** - * Create a Major line for the axis at position x - * @param {Number} x - * @private - */ -TimeAxis.prototype._repaintMajorLine = function (x) { - // reuse redundant line - var line = this.dom.redundant.majorLines.shift(); - - if (!line) { - // create vertical line - line = document.createElement('DIV'); - line.className = 'grid vertical major'; - this.frame.appendChild(line); - } - this.dom.majorLines.push(line); - - var props = this.props; - line.style.top = props.majorLineTop + 'px'; - line.style.left = (x - props.majorLineWidth / 2) + 'px'; - line.style.height = props.majorLineHeight + 'px'; -}; - - -/** - * Repaint the horizontal line for the axis - * @private - */ -TimeAxis.prototype._repaintLine = function() { - var line = this.dom.line, - frame = this.frame, - options = this.options; - - // line before all axis elements - if (this.getOption('showMinorLabels') || this.getOption('showMajorLabels')) { - if (line) { - // put this line at the end of all childs - frame.removeChild(line); - frame.appendChild(line); - } - else { - // create the axis line - line = document.createElement('div'); - line.className = 'grid horizontal major'; - frame.appendChild(line); - this.dom.line = line; - } - - line.style.top = this.props.lineTop + 'px'; - } - else { - if (line && axis.parentElement) { - frame.removeChild(axis.line); - delete this.dom.line; - } - } -}; - -/** - * Create characters used to determine the size of text on the axis - * @private - */ -TimeAxis.prototype._repaintMeasureChars = function () { - // calculate the width and height of a single character - // this is used to calculate the step size, and also the positioning of the - // axis - var dom = this.dom, - text; - - if (!dom.measureCharMinor) { - text = document.createTextNode('0'); - var measureCharMinor = document.createElement('DIV'); - measureCharMinor.className = 'text minor measure'; - measureCharMinor.appendChild(text); - this.frame.appendChild(measureCharMinor); - - dom.measureCharMinor = measureCharMinor; - } - - if (!dom.measureCharMajor) { - text = document.createTextNode('0'); - var measureCharMajor = document.createElement('DIV'); - measureCharMajor.className = 'text major measure'; - measureCharMajor.appendChild(text); - this.frame.appendChild(measureCharMajor); - - dom.measureCharMajor = measureCharMajor; - } -}; - -/** - * Reflow the component - * @return {Boolean} resized - */ -TimeAxis.prototype.reflow = function () { - var changed = 0, - update = util.updateProperty, - frame = this.frame, - range = this.range; - - if (!range) { - throw new Error('Cannot repaint time axis: no range configured'); - } - - if (frame) { - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - - // calculate size of a character - var props = this.props, - showMinorLabels = this.getOption('showMinorLabels'), - showMajorLabels = this.getOption('showMajorLabels'), - measureCharMinor = this.dom.measureCharMinor, - measureCharMajor = this.dom.measureCharMajor; - if (measureCharMinor) { - props.minorCharHeight = measureCharMinor.clientHeight; - props.minorCharWidth = measureCharMinor.clientWidth; - } - if (measureCharMajor) { - props.majorCharHeight = measureCharMajor.clientHeight; - props.majorCharWidth = measureCharMajor.clientWidth; - } - - var parentHeight = frame.parentNode ? frame.parentNode.offsetHeight : 0; - if (parentHeight != props.parentHeight) { - props.parentHeight = parentHeight; - changed += 1; - } - switch (this.getOption('orientation')) { - case 'bottom': - props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; - props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; - - props.minorLabelTop = 0; - props.majorLabelTop = props.minorLabelTop + props.minorLabelHeight; - - props.minorLineTop = -this.top; - props.minorLineHeight = Math.max(this.top + props.majorLabelHeight, 0); - props.minorLineWidth = 1; // TODO: really calculate width - - props.majorLineTop = -this.top; - props.majorLineHeight = Math.max(this.top + props.minorLabelHeight + props.majorLabelHeight, 0); - props.majorLineWidth = 1; // TODO: really calculate width - - props.lineTop = 0; - - break; - - case 'top': - props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; - props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; - - props.majorLabelTop = 0; - props.minorLabelTop = props.majorLabelTop + props.majorLabelHeight; - - props.minorLineTop = props.minorLabelTop; - props.minorLineHeight = Math.max(parentHeight - props.majorLabelHeight - this.top); - props.minorLineWidth = 1; // TODO: really calculate width - - props.majorLineTop = 0; - props.majorLineHeight = Math.max(parentHeight - this.top); - props.majorLineWidth = 1; // TODO: really calculate width - - props.lineTop = props.majorLabelHeight + props.minorLabelHeight; - - break; - - default: - throw new Error('Unkown orientation "' + this.getOption('orientation') + '"'); - } - - var height = props.minorLabelHeight + props.majorLabelHeight; - changed += update(this, 'width', frame.offsetWidth); - changed += update(this, 'height', height); - - // calculate range and step - this._updateConversion(); - - var start = util.convert(range.start, 'Date'), - end = util.convert(range.end, 'Date'), - minimumStep = this.toTime((props.minorCharWidth || 10) * 5) - this.toTime(0); - this.step = new TimeStep(start, end, minimumStep); - changed += update(props.range, 'start', start.valueOf()); - changed += update(props.range, 'end', end.valueOf()); - changed += update(props.range, 'minimumStep', minimumStep.valueOf()); - } - - return (changed > 0); -}; - -/** - * Calculate the factor and offset to convert a position on screen to the - * corresponding date and vice versa. - * After the method _updateConversion is executed once, the methods toTime - * and toScreen can be used. - * @private - */ -TimeAxis.prototype._updateConversion = function() { - var range = this.range; - if (!range) { - throw new Error('No range configured'); - } - - if (range.conversion) { - this.conversion = range.conversion(this.width); - } - else { - this.conversion = Range.conversion(range.start, range.end, this.width); - } -}; - -/** - * An ItemSet holds a set of items and ranges which can be displayed in a - * range. The width is determined by the parent of the ItemSet, and the height - * is determined by the size of the items. - * @param {Component} parent - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) - * @param {Object} [options] See ItemSet.setOptions for the available - * options. - * @constructor ItemSet - * @extends Panel - */ -// TODO: improve performance by replacing all Array.forEach with a for loop -function ItemSet(parent, depends, options) { - this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; - - // one options object is shared by this itemset and all its items - this.options = options || {}; - this.defaultOptions = { - type: 'box', - align: 'center', - orientation: 'bottom', - margin: { - axis: 20, - item: 10 - }, - padding: 5 - }; - - this.dom = {}; - - var me = this; - this.itemsData = null; // DataSet - this.range = null; // Range or Object {start: number, end: number} - - this.listeners = { - 'add': function (event, params, senderId) { - if (senderId != me.id) { - me._onAdd(params.items); - } - }, - 'update': function (event, params, senderId) { - if (senderId != me.id) { - me._onUpdate(params.items); - } - }, - 'remove': function (event, params, senderId) { - if (senderId != me.id) { - me._onRemove(params.items); - } - } - }; - - this.items = {}; // object with an Item for every data item - this.queue = {}; // queue with id/actions: 'add', 'update', 'delete' - this.stack = new Stack(this, Object.create(this.options)); - this.conversion = null; - - // TODO: ItemSet should also attach event listeners for rangechange and rangechanged, like timeaxis -} - -ItemSet.prototype = new Panel(); - -// available item types will be registered here -ItemSet.types = { - box: ItemBox, - range: ItemRange, - point: ItemPoint -}; - -/** - * Set options for the ItemSet. Existing options will be extended/overwritten. - * @param {Object} [options] The following options are available: - * {String | function} [className] - * class name for the itemset - * {String} [type] - * Default type for the items. Choose from 'box' - * (default), 'point', or 'range'. The default - * Style can be overwritten by individual items. - * {String} align - * Alignment for the items, only applicable for - * ItemBox. Choose 'center' (default), 'left', or - * 'right'. - * {String} orientation - * Orientation of the item set. Choose 'top' or - * 'bottom' (default). - * {Number} margin.axis - * Margin between the axis and the items in pixels. - * Default is 20. - * {Number} margin.item - * Margin between items in pixels. Default is 10. - * {Number} padding - * Padding of the contents of an item in pixels. - * Must correspond with the items css. Default is 5. - */ -ItemSet.prototype.setOptions = Component.prototype.setOptions; - -/** - * Set range (start and end). - * @param {Range | Object} range A Range or an object containing start and end. - */ -ItemSet.prototype.setRange = function setRange(range) { - if (!(range instanceof Range) && (!range || !range.start || !range.end)) { - throw new TypeError('Range must be an instance of Range, ' + - 'or an object containing start and end.'); - } - this.range = range; -}; - -/** - * Repaint the component - * @return {Boolean} changed - */ -ItemSet.prototype.repaint = function repaint() { - var changed = 0, - update = util.updateProperty, - asSize = util.option.asSize, - options = this.options, - orientation = this.getOption('orientation'), - defaultOptions = this.defaultOptions, - frame = this.frame; - - if (!frame) { - frame = document.createElement('div'); - frame.className = 'itemset'; - - var className = options.className; - if (className) { - util.addClassName(frame, util.option.asString(className)); - } - - // create background panel - var background = document.createElement('div'); - background.className = 'background'; - frame.appendChild(background); - this.dom.background = background; - - // create foreground panel - var foreground = document.createElement('div'); - foreground.className = 'foreground'; - frame.appendChild(foreground); - this.dom.foreground = foreground; - - // create axis panel - var axis = document.createElement('div'); - axis.className = 'itemset-axis'; - //frame.appendChild(axis); - this.dom.axis = axis; - - this.frame = frame; - changed += 1; - } - - if (!this.parent) { - throw new Error('Cannot repaint itemset: no parent attached'); - } - var parentContainer = this.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint itemset: parent has no container element'); - } - if (!frame.parentNode) { - parentContainer.appendChild(frame); - changed += 1; - } - if (!this.dom.axis.parentNode) { - parentContainer.appendChild(this.dom.axis); - changed += 1; - } - - // reposition frame - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'top', asSize(options.top, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); - - // reposition axis - changed += update(this.dom.axis.style, 'left', asSize(options.left, '0px')); - changed += update(this.dom.axis.style, 'width', asSize(options.width, '100%')); - if (orientation == 'bottom') { - changed += update(this.dom.axis.style, 'top', (this.height + this.top) + 'px'); - } - else { // orientation == 'top' - changed += update(this.dom.axis.style, 'top', this.top + 'px'); - } - - this._updateConversion(); - - var me = this, - queue = this.queue, - itemsData = this.itemsData, - items = this.items, - dataOptions = { - // TODO: cleanup - // fields: [(itemsData && itemsData.fieldId || 'id'), 'start', 'end', 'content', 'type', 'className'] - }; - - // show/hide added/changed/removed items - Object.keys(queue).forEach(function (id) { - //var entry = queue[id]; - var action = queue[id]; - var item = items[id]; - //var item = entry.item; - //noinspection FallthroughInSwitchStatementJS - switch (action) { - case 'add': - case 'update': - var itemData = itemsData && itemsData.get(id, dataOptions); - - if (itemData) { - var type = itemData.type || - (itemData.start && itemData.end && 'range') || - options.type || - 'box'; - var constructor = ItemSet.types[type]; - - // TODO: how to handle items with invalid data? hide them and give a warning? or throw an error? - if (item) { - // update item - if (!constructor || !(item instanceof constructor)) { - // item type has changed, hide and delete the item - changed += item.hide(); - item = null; - } - else { - item.data = itemData; // TODO: create a method item.setData ? - changed++; - } - } - - if (!item) { - // create item - if (constructor) { - item = new constructor(me, itemData, options, defaultOptions); - changed++; - } - else { - throw new TypeError('Unknown item type "' + type + '"'); - } - } - - // force a repaint (not only a reposition) - item.repaint(); - - items[id] = item; - } - - // update queue - delete queue[id]; - break; - - case 'remove': - if (item) { - // remove DOM of the item - changed += item.hide(); - } - - // update lists - delete items[id]; - delete queue[id]; - break; - - default: - console.log('Error: unknown action "' + action + '"'); - } - }); - - // reposition all items. Show items only when in the visible area - util.forEach(this.items, function (item) { - if (item.visible) { - changed += item.show(); - item.reposition(); - } - else { - changed += item.hide(); - } - }); - - return (changed > 0); -}; - -/** - * Get the foreground container element - * @return {HTMLElement} foreground - */ -ItemSet.prototype.getForeground = function getForeground() { - return this.dom.foreground; -}; - -/** - * Get the background container element - * @return {HTMLElement} background - */ -ItemSet.prototype.getBackground = function getBackground() { - return this.dom.background; -}; - -/** - * Get the axis container element - * @return {HTMLElement} axis - */ -ItemSet.prototype.getAxis = function getAxis() { - return this.dom.axis; -}; - -/** - * Reflow the component - * @return {Boolean} resized - */ -ItemSet.prototype.reflow = function reflow () { - var changed = 0, - options = this.options, - marginAxis = options.margin && options.margin.axis || this.defaultOptions.margin.axis, - marginItem = options.margin && options.margin.item || this.defaultOptions.margin.item, - update = util.updateProperty, - asNumber = util.option.asNumber, - asSize = util.option.asSize, - frame = this.frame; - - if (frame) { - this._updateConversion(); - - util.forEach(this.items, function (item) { - changed += item.reflow(); - }); - - // TODO: stack.update should be triggered via an event, in stack itself - // TODO: only update the stack when there are changed items - this.stack.update(); - - var maxHeight = asNumber(options.maxHeight); - var fixedHeight = (asSize(options.height) != null); - var height; - if (fixedHeight) { - height = frame.offsetHeight; - } - else { - // height is not specified, determine the height from the height and positioned items - var visibleItems = this.stack.ordered; // TODO: not so nice way to get the filtered items - if (visibleItems.length) { - var min = visibleItems[0].top; - var max = visibleItems[0].top + visibleItems[0].height; - util.forEach(visibleItems, function (item) { - min = Math.min(min, item.top); - max = Math.max(max, (item.top + item.height)); - }); - height = (max - min) + marginAxis + marginItem; - } - else { - height = marginAxis + marginItem; - } - } - if (maxHeight != null) { - height = Math.min(height, maxHeight); - } - changed += update(this, 'height', height); - - // calculate height from items - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - changed += update(this, 'width', frame.offsetWidth); - } - else { - changed += 1; - } - - return (changed > 0); -}; - -/** - * Hide this component from the DOM - * @return {Boolean} changed - */ -ItemSet.prototype.hide = function hide() { - var changed = false; - - // remove the DOM - if (this.frame && this.frame.parentNode) { - this.frame.parentNode.removeChild(this.frame); - changed = true; - } - if (this.dom.axis && this.dom.axis.parentNode) { - this.dom.axis.parentNode.removeChild(this.dom.axis); - changed = true; - } - - return changed; -}; - -/** - * Set items - * @param {vis.DataSet | null} items - */ -ItemSet.prototype.setItems = function setItems(items) { - var me = this, - ids, - oldItemsData = this.itemsData; - - // replace the dataset - if (!items) { - this.itemsData = null; - } - else if (items instanceof DataSet || items instanceof DataView) { - this.itemsData = items; - } - else { - throw new TypeError('Data must be an instance of DataSet'); - } - - if (oldItemsData) { - // unsubscribe from old dataset - util.forEach(this.listeners, function (callback, event) { - oldItemsData.unsubscribe(event, callback); - }); - - // remove all drawn items - ids = oldItemsData.getIds(); - this._onRemove(ids); - } - - if (this.itemsData) { - // subscribe to new dataset - var id = this.id; - util.forEach(this.listeners, function (callback, event) { - me.itemsData.subscribe(event, callback, id); - }); - - // draw all new items - ids = this.itemsData.getIds(); - this._onAdd(ids); - } -}; - -/** - * Get the current items items - * @returns {vis.DataSet | null} - */ -ItemSet.prototype.getItems = function getItems() { - return this.itemsData; -}; - -/** - * Handle updated items - * @param {Number[]} ids - * @private - */ -ItemSet.prototype._onUpdate = function _onUpdate(ids) { - this._toQueue('update', ids); -}; - -/** - * Handle changed items - * @param {Number[]} ids - * @private - */ -ItemSet.prototype._onAdd = function _onAdd(ids) { - this._toQueue('add', ids); -}; - -/** - * Handle removed items - * @param {Number[]} ids - * @private - */ -ItemSet.prototype._onRemove = function _onRemove(ids) { - this._toQueue('remove', ids); -}; - -/** - * Put items in the queue to be added/updated/remove - * @param {String} action can be 'add', 'update', 'remove' - * @param {Number[]} ids - */ -ItemSet.prototype._toQueue = function _toQueue(action, ids) { - var queue = this.queue; - ids.forEach(function (id) { - queue[id] = action; - }); - - if (this.controller) { - //this.requestReflow(); - this.requestRepaint(); - } -}; - -/** - * Calculate the factor and offset to convert a position on screen to the - * corresponding date and vice versa. - * After the method _updateConversion is executed once, the methods toTime - * and toScreen can be used. - * @private - */ -ItemSet.prototype._updateConversion = function _updateConversion() { - var range = this.range; - if (!range) { - throw new Error('No range configured'); - } - - if (range.conversion) { - this.conversion = range.conversion(this.width); - } - else { - this.conversion = Range.conversion(range.start, range.end, this.width); - } -}; - -/** - * Convert a position on screen (pixels) to a datetime - * Before this method can be used, the method _updateConversion must be - * executed once. - * @param {int} x Position on the screen in pixels - * @return {Date} time The datetime the corresponds with given position x - */ -ItemSet.prototype.toTime = function toTime(x) { - var conversion = this.conversion; - return new Date(x / conversion.factor + conversion.offset); -}; - -/** - * Convert a datetime (Date object) into a position on the screen - * Before this method can be used, the method _updateConversion must be - * executed once. - * @param {Date} time A date - * @return {int} x The position on the screen in pixels which corresponds - * with the given date. - */ -ItemSet.prototype.toScreen = function toScreen(time) { - var conversion = this.conversion; - return (time.valueOf() - conversion.offset) * conversion.factor; -}; - -/** - * @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; - this.data = data; - this.dom = null; - this.options = options || {}; - this.defaultOptions = defaultOptions || {}; - - this.selected = false; - this.visible = false; - this.top = 0; - this.left = 0; - this.width = 0; - this.height = 0; -} - -/** - * Select current item - */ -Item.prototype.select = function select() { - this.selected = true; -}; - -/** - * Unselect current item - */ -Item.prototype.unselect = function unselect() { - this.selected = false; -}; - -/** - * Show the Item in the DOM (when not already visible) - * @return {Boolean} changed - */ -Item.prototype.show = function show() { - return false; -}; - -/** - * Hide the Item from the DOM (when visible) - * @return {Boolean} changed - */ -Item.prototype.hide = function hide() { - return false; -}; - -/** - * Repaint the item - * @return {Boolean} changed - */ -Item.prototype.repaint = function repaint() { - // should be implemented by the item - return false; -}; - -/** - * Reflow the item - * @return {Boolean} resized - */ -Item.prototype.reflow = function reflow() { - // should be implemented by the item - return false; -}; - -/** - * @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) { - this.props = { - dot: { - left: 0, - top: 0, - width: 0, - height: 0 - }, - line: { - top: 0, - left: 0, - width: 0, - height: 0 - } - }; - - Item.call(this, parent, data, options, defaultOptions); -} - -ItemBox.prototype = new Item (null, null); - -/** - * Select the item - * @override - */ -ItemBox.prototype.select = function select() { - this.selected = true; - // TODO: select and unselect -}; - -/** - * Unselect the item - * @override - */ -ItemBox.prototype.unselect = function unselect() { - this.selected = false; - // TODO: select and unselect -}; - -/** - * Repaint the item - * @return {Boolean} changed - */ -ItemBox.prototype.repaint = function repaint() { - // TODO: make an efficient repaint - var changed = false; - var dom = this.dom; - - if (!dom) { - this._create(); - dom = this.dom; - changed = true; - } - - if (dom) { - if (!this.parent) { - throw new Error('Cannot repaint item: no parent attached'); - } - var foreground = this.parent.getForeground(); - if (!foreground) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no foreground container element'); - } - var background = this.parent.getBackground(); - if (!background) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no background container element'); - } - var axis = this.parent.getAxis(); - if (!background) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no axis container element'); - } - - if (!dom.box.parentNode) { - foreground.appendChild(dom.box); - changed = true; - } - if (!dom.line.parentNode) { - background.appendChild(dom.line); - changed = true; - } - if (!dom.dot.parentNode) { - axis.appendChild(dom.dot); - changed = true; - } - - // update contents - if (this.data.content != this.content) { - this.content = this.data.content; - if (this.content instanceof Element) { - dom.content.innerHTML = ''; - dom.content.appendChild(this.content); - } - else if (this.data.content != undefined) { - dom.content.innerHTML = this.content; - } - else { - throw new Error('Property "content" missing in item ' + this.data.id); - } - changed = true; - } - - // update class - var className = (this.data.className? ' ' + this.data.className : '') + - (this.selected ? ' selected' : ''); - if (this.className != className) { - this.className = className; - dom.box.className = 'item box' + className; - dom.line.className = 'item line' + className; - dom.dot.className = 'item dot' + className; - changed = true; - } - } - - return changed; -}; - -/** - * Show the item in the DOM (when not already visible). The items DOM will - * be created when needed. - * @return {Boolean} changed - */ -ItemBox.prototype.show = function show() { - if (!this.dom || !this.dom.box.parentNode) { - return this.repaint(); - } - else { - return false; - } -}; - -/** - * Hide the item from the DOM (when visible) - * @return {Boolean} changed - */ -ItemBox.prototype.hide = function hide() { - var changed = false, - dom = this.dom; - if (dom) { - if (dom.box.parentNode) { - dom.box.parentNode.removeChild(dom.box); - changed = true; - } - if (dom.line.parentNode) { - dom.line.parentNode.removeChild(dom.line); - } - if (dom.dot.parentNode) { - dom.dot.parentNode.removeChild(dom.dot); - } - } - return changed; -}; - -/** - * Reflow the item: calculate its actual size and position from the DOM - * @return {boolean} resized returns true if the axis is resized - * @override - */ -ItemBox.prototype.reflow = function reflow() { - var changed = 0, - update, - dom, - props, - options, - margin, - start, - align, - orientation, - top, - left, - data, - range; - - if (this.data.start == undefined) { - throw new Error('Property "start" missing in item ' + this.data.id); - } - - data = this.data; - range = this.parent && this.parent.range; - if (data && range) { - // TODO: account for the width of the item - var interval = (range.end - range.start); - this.visible = (data.start > range.start - interval) && (data.start < range.end + interval); - } - else { - this.visible = false; - } - - if (this.visible) { - dom = this.dom; - if (dom) { - update = util.updateProperty; - props = this.props; - options = this.options; - start = this.parent.toScreen(this.data.start); - align = options.align || this.defaultOptions.align; - margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; - orientation = options.orientation || this.defaultOptions.orientation; - - changed += update(props.dot, 'height', dom.dot.offsetHeight); - changed += update(props.dot, 'width', dom.dot.offsetWidth); - changed += update(props.line, 'width', dom.line.offsetWidth); - changed += update(props.line, 'height', dom.line.offsetHeight); - changed += update(props.line, 'top', dom.line.offsetTop); - changed += update(this, 'width', dom.box.offsetWidth); - changed += update(this, 'height', dom.box.offsetHeight); - if (align == 'right') { - left = start - this.width; - } - else if (align == 'left') { - left = start; - } - else { - // default or 'center' - left = start - this.width / 2; - } - changed += update(this, 'left', left); - - changed += update(props.line, 'left', start - props.line.width / 2); - changed += update(props.dot, 'left', start - props.dot.width / 2); - changed += update(props.dot, 'top', -props.dot.height / 2); - if (orientation == 'top') { - top = margin; - - changed += update(this, 'top', top); - } - else { - // default or 'bottom' - var parentHeight = this.parent.height; - top = parentHeight - this.height - margin; - - changed += update(this, 'top', top); - } - } - else { - changed += 1; - } - } - - return (changed > 0); -}; - -/** - * Create an items DOM - * @private - */ -ItemBox.prototype._create = function _create() { - var dom = this.dom; - if (!dom) { - this.dom = dom = {}; - - // create the box - dom.box = document.createElement('DIV'); - // className is updated in repaint() - - // contents box (inside the background box). used for making margins - dom.content = document.createElement('DIV'); - dom.content.className = 'content'; - dom.box.appendChild(dom.content); - - // line to axis - dom.line = document.createElement('DIV'); - dom.line.className = 'line'; - - // dot on axis - dom.dot = document.createElement('DIV'); - dom.dot.className = 'dot'; - } -}; - -/** - * Reposition the item, recalculate its left, top, and width, using the current - * range and size of the items itemset - * @override - */ -ItemBox.prototype.reposition = function reposition() { - var dom = this.dom, - props = this.props, - orientation = this.options.orientation || this.defaultOptions.orientation; - - if (dom) { - var box = dom.box, - line = dom.line, - dot = dom.dot; - - box.style.left = this.left + 'px'; - box.style.top = this.top + 'px'; - - line.style.left = props.line.left + 'px'; - if (orientation == 'top') { - line.style.top = 0 + 'px'; - line.style.height = this.top + 'px'; - } - else { - // orientation 'bottom' - line.style.top = (this.top + this.height) + 'px'; - line.style.height = Math.max(this.parent.height - this.top - this.height + - this.props.dot.height / 2, 0) + 'px'; - } - - dot.style.left = props.dot.left + 'px'; - dot.style.top = props.dot.top + 'px'; - } -}; - -/** - * @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) { - this.props = { - dot: { - top: 0, - width: 0, - height: 0 - }, - content: { - height: 0, - marginLeft: 0 - } - }; - - Item.call(this, parent, data, options, defaultOptions); -} - -ItemPoint.prototype = new Item (null, null); - -/** - * Select the item - * @override - */ -ItemPoint.prototype.select = function select() { - this.selected = true; - // TODO: select and unselect -}; - -/** - * Unselect the item - * @override - */ -ItemPoint.prototype.unselect = function unselect() { - this.selected = false; - // TODO: select and unselect -}; - -/** - * Repaint the item - * @return {Boolean} changed - */ -ItemPoint.prototype.repaint = function repaint() { - // TODO: make an efficient repaint - var changed = false; - var dom = this.dom; - - if (!dom) { - this._create(); - dom = this.dom; - changed = true; - } - - if (dom) { - if (!this.parent) { - throw new Error('Cannot repaint item: no parent attached'); - } - var foreground = this.parent.getForeground(); - if (!foreground) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no foreground container element'); - } - - if (!dom.point.parentNode) { - foreground.appendChild(dom.point); - foreground.appendChild(dom.point); - changed = true; - } - - // update contents - if (this.data.content != this.content) { - this.content = this.data.content; - if (this.content instanceof Element) { - dom.content.innerHTML = ''; - dom.content.appendChild(this.content); - } - else if (this.data.content != undefined) { - dom.content.innerHTML = this.content; - } - else { - throw new Error('Property "content" missing in item ' + this.data.id); - } - changed = true; - } - - // update class - var className = (this.data.className? ' ' + this.data.className : '') + - (this.selected ? ' selected' : ''); - if (this.className != className) { - this.className = className; - dom.point.className = 'item point' + className; - changed = true; - } - } - - return changed; -}; - -/** - * Show the item in the DOM (when not already visible). The items DOM will - * be created when needed. - * @return {Boolean} changed - */ -ItemPoint.prototype.show = function show() { - if (!this.dom || !this.dom.point.parentNode) { - return this.repaint(); - } - else { - return false; - } -}; - -/** - * Hide the item from the DOM (when visible) - * @return {Boolean} changed - */ -ItemPoint.prototype.hide = function hide() { - var changed = false, - dom = this.dom; - if (dom) { - if (dom.point.parentNode) { - dom.point.parentNode.removeChild(dom.point); - changed = true; - } - } - return changed; -}; - -/** - * Reflow the item: calculate its actual size from the DOM - * @return {boolean} resized returns true if the axis is resized - * @override - */ -ItemPoint.prototype.reflow = function reflow() { - var changed = 0, - update, - dom, - props, - options, - margin, - orientation, - start, - top, - data, - range; - - if (this.data.start == undefined) { - throw new Error('Property "start" missing in item ' + this.data.id); - } - - data = this.data; - range = this.parent && this.parent.range; - if (data && range) { - // TODO: account for the width of the item - var interval = (range.end - range.start); - this.visible = (data.start > range.start - interval) && (data.start < range.end); - } - else { - this.visible = false; - } - - if (this.visible) { - dom = this.dom; - if (dom) { - update = util.updateProperty; - props = this.props; - options = this.options; - orientation = options.orientation || this.defaultOptions.orientation; - margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; - start = this.parent.toScreen(this.data.start); - - changed += update(this, 'width', dom.point.offsetWidth); - changed += update(this, 'height', dom.point.offsetHeight); - changed += update(props.dot, 'width', dom.dot.offsetWidth); - changed += update(props.dot, 'height', dom.dot.offsetHeight); - changed += update(props.content, 'height', dom.content.offsetHeight); - - if (orientation == 'top') { - top = margin; - } - else { - // default or 'bottom' - var parentHeight = this.parent.height; - top = Math.max(parentHeight - this.height - margin, 0); - } - changed += update(this, 'top', top); - changed += update(this, 'left', start - props.dot.width / 2); - changed += update(props.content, 'marginLeft', 1.5 * props.dot.width); - //changed += update(props.content, 'marginRight', 0.5 * props.dot.width); // TODO - - changed += update(props.dot, 'top', (this.height - props.dot.height) / 2); - } - else { - changed += 1; - } - } - - return (changed > 0); -}; - -/** - * Create an items DOM - * @private - */ -ItemPoint.prototype._create = function _create() { - var dom = this.dom; - if (!dom) { - this.dom = dom = {}; - - // background box - dom.point = document.createElement('div'); - // className is updated in repaint() - - // contents box, right from the dot - dom.content = document.createElement('div'); - dom.content.className = 'content'; - dom.point.appendChild(dom.content); - - // dot at start - dom.dot = document.createElement('div'); - dom.dot.className = 'dot'; - dom.point.appendChild(dom.dot); - } -}; - -/** - * Reposition the item, recalculate its left, top, and width, using the current - * range and size of the items itemset - * @override - */ -ItemPoint.prototype.reposition = function reposition() { - var dom = this.dom, - props = this.props; - - if (dom) { - dom.point.style.top = this.top + 'px'; - dom.point.style.left = this.left + 'px'; - - dom.content.style.marginLeft = props.content.marginLeft + 'px'; - //dom.content.style.marginRight = props.content.marginRight + 'px'; // TODO - - dom.dot.style.top = props.dot.top + 'px'; - } -}; - -/** - * @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) { - this.props = { - content: { - left: 0, - width: 0 - } - }; - - Item.call(this, parent, data, options, defaultOptions); -} - -ItemRange.prototype = new Item (null, null); - -/** - * Select the item - * @override - */ -ItemRange.prototype.select = function select() { - this.selected = true; - // TODO: select and unselect -}; - -/** - * Unselect the item - * @override - */ -ItemRange.prototype.unselect = function unselect() { - this.selected = false; - // TODO: select and unselect -}; - -/** - * Repaint the item - * @return {Boolean} changed - */ -ItemRange.prototype.repaint = function repaint() { - // TODO: make an efficient repaint - var changed = false; - var dom = this.dom; - - if (!dom) { - this._create(); - dom = this.dom; - changed = true; - } - - if (dom) { - if (!this.parent) { - throw new Error('Cannot repaint item: no parent attached'); - } - var foreground = this.parent.getForeground(); - if (!foreground) { - throw new Error('Cannot repaint time axis: ' + - 'parent has no foreground container element'); - } - - if (!dom.box.parentNode) { - foreground.appendChild(dom.box); - changed = true; - } - - // update content - if (this.data.content != this.content) { - this.content = this.data.content; - if (this.content instanceof Element) { - dom.content.innerHTML = ''; - dom.content.appendChild(this.content); - } - else if (this.data.content != undefined) { - dom.content.innerHTML = this.content; - } - else { - throw new Error('Property "content" missing in item ' + this.data.id); - } - changed = true; - } - - // update class - var className = this.data.className ? (' ' + this.data.className) : ''; - if (this.className != className) { - this.className = className; - dom.box.className = 'item range' + className; - changed = true; - } - } - - return changed; -}; - -/** - * Show the item in the DOM (when not already visible). The items DOM will - * be created when needed. - * @return {Boolean} changed - */ -ItemRange.prototype.show = function show() { - if (!this.dom || !this.dom.box.parentNode) { - return this.repaint(); - } - else { - return false; - } -}; - -/** - * Hide the item from the DOM (when visible) - * @return {Boolean} changed - */ -ItemRange.prototype.hide = function hide() { - var changed = false, - dom = this.dom; - if (dom) { - if (dom.box.parentNode) { - dom.box.parentNode.removeChild(dom.box); - changed = true; - } - } - return changed; -}; - -/** - * Reflow the item: calculate its actual size from the DOM - * @return {boolean} resized returns true if the axis is resized - * @override - */ -ItemRange.prototype.reflow = function reflow() { - var changed = 0, - dom, - props, - options, - margin, - padding, - parent, - start, - end, - data, - range, - update, - box, - parentWidth, - contentLeft, - orientation, - top; - - if (this.data.start == undefined) { - throw new Error('Property "start" missing in item ' + this.data.id); - } - if (this.data.end == undefined) { - throw new Error('Property "end" missing in item ' + this.data.id); - } - - data = this.data; - range = this.parent && this.parent.range; - if (data && range) { - // TODO: account for the width of the item. Take some margin - this.visible = (data.start < range.end) && (data.end > range.start); - } - else { - this.visible = false; - } - - if (this.visible) { - dom = this.dom; - if (dom) { - props = this.props; - options = this.options; - parent = this.parent; - start = parent.toScreen(this.data.start); - end = parent.toScreen(this.data.end); - update = util.updateProperty; - box = dom.box; - parentWidth = parent.width; - orientation = options.orientation || this.defaultOptions.orientation; - margin = options.margin && options.margin.axis || this.defaultOptions.margin.axis; - padding = options.padding || this.defaultOptions.padding; - - changed += update(props.content, 'width', dom.content.offsetWidth); - - changed += update(this, 'height', box.offsetHeight); - - // limit the width of the this, as browsers cannot draw very wide divs - if (start < -parentWidth) { - start = -parentWidth; - } - if (end > 2 * parentWidth) { - end = 2 * parentWidth; - } - - // when range exceeds left of the window, position the contents at the left of the visible area - if (start < 0) { - contentLeft = Math.min(-start, - (end - start - props.content.width - 2 * padding)); - // TODO: remove the need for options.padding. it's terrible. - } - else { - contentLeft = 0; - } - changed += update(props.content, 'left', contentLeft); - - if (orientation == 'top') { - top = margin; - changed += update(this, 'top', top); - } - else { - // default or 'bottom' - top = parent.height - this.height - margin; - changed += update(this, 'top', top); - } - - changed += update(this, 'left', start); - changed += update(this, 'width', Math.max(end - start, 1)); // TODO: reckon with border width; - } - else { - changed += 1; - } - } - - return (changed > 0); -}; - -/** - * Create an items DOM - * @private - */ -ItemRange.prototype._create = function _create() { - var dom = this.dom; - if (!dom) { - this.dom = dom = {}; - // background box - dom.box = document.createElement('div'); - // className is updated in repaint() - - // contents box - dom.content = document.createElement('div'); - dom.content.className = 'content'; - dom.box.appendChild(dom.content); - } -}; - -/** - * Reposition the item, recalculate its left, top, and width, using the current - * range and size of the items itemset - * @override - */ -ItemRange.prototype.reposition = function reposition() { - var dom = this.dom, - props = this.props; - - if (dom) { - dom.box.style.top = this.top + 'px'; - dom.box.style.left = this.left + 'px'; - dom.box.style.width = this.width + 'px'; - - dom.content.style.left = props.content.left + 'px'; - } -}; - -/** - * @constructor Group - * @param {GroupSet} parent - * @param {Number | String} groupId - * @param {Object} [options] Options to set initial property values - * // TODO: describe available options - * @extends Component - */ -function Group (parent, groupId, options) { - this.id = util.randomUUID(); - this.parent = parent; - - this.groupId = groupId; - this.itemset = null; // ItemSet - this.options = options || {}; - this.options.top = 0; - - this.props = { - label: { - width: 0, - height: 0 - } - }; - - this.top = 0; - this.left = 0; - this.width = 0; - this.height = 0; -} - -Group.prototype = new Component(); - -// TODO: comment -Group.prototype.setOptions = Component.prototype.setOptions; - -/** - * Get the container element of the panel, which can be used by a child to - * add its own widgets. - * @returns {HTMLElement} container - */ -Group.prototype.getContainer = function () { - return this.parent.getContainer(); -}; - -/** - * Set item set for the group. The group will create a view on the itemset, - * filtered by the groups id. - * @param {DataSet | DataView} items - */ -Group.prototype.setItems = function setItems(items) { - if (this.itemset) { - // remove current item set - this.itemset.hide(); - this.itemset.setItems(); - - this.parent.controller.remove(this.itemset); - this.itemset = null; - } - - if (items) { - var groupId = this.groupId; - - var itemsetOptions = Object.create(this.options); - this.itemset = new ItemSet(this, null, itemsetOptions); - this.itemset.setRange(this.parent.range); - - this.view = new DataView(items, { - filter: function (item) { - return item.group == groupId; - } - }); - this.itemset.setItems(this.view); - - this.parent.controller.add(this.itemset); - } -}; - -/** - * Repaint the item - * @return {Boolean} changed - */ -Group.prototype.repaint = function repaint() { - return false; -}; - -/** - * Reflow the item - * @return {Boolean} resized - */ -Group.prototype.reflow = function reflow() { - var changed = 0, - update = util.updateProperty; - - changed += update(this, 'top', this.itemset ? this.itemset.top : 0); - changed += update(this, 'height', this.itemset ? this.itemset.height : 0); - - // TODO: reckon with the height of the group label - - if (this.label) { - var inner = this.label.firstChild; - changed += update(this.props.label, 'width', inner.clientWidth); - changed += update(this.props.label, 'height', inner.clientHeight); - } - else { - changed += update(this.props.label, 'width', 0); - changed += update(this.props.label, 'height', 0); - } - - return (changed > 0); -}; - -/** - * An GroupSet holds a set of groups - * @param {Component} parent - * @param {Component[]} [depends] Components on which this components depends - * (except for the parent) - * @param {Object} [options] See GroupSet.setOptions for the available - * options. - * @constructor GroupSet - * @extends Panel - */ -function GroupSet(parent, depends, options) { - this.id = util.randomUUID(); - this.parent = parent; - this.depends = depends; - - 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.dom = {}; - this.props = { - labels: { - width: 0 - } - }; - - // TODO: implement right orientation of the labels - - // changes in groups are queued key/value map containing id/action - this.queue = {}; - - 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); - } - }; -} - -GroupSet.prototype = new Panel(); - -/** - * 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; - -GroupSet.prototype.setRange = function (range) { - // TODO: implement setRange -}; - -/** - * 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]; - 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.subscribe(event, callback, id); - }); - - // draw all new groups - ids = this.groupsData.getIds(); - this._onAdd(ids); - } -}; - -/** - * Get groups - * @return {vis.DataSet | null} groups - */ -GroupSet.prototype.getGroups = function getGroups() { - return this.groupsData; -}; - -/** - * Repaint the component - * @return {Boolean} changed - */ -GroupSet.prototype.repaint = function repaint() { - var changed = 0, - i, id, group, label, - update = util.updateProperty, - asSize = util.option.asSize, - asElement = util.option.asElement, - options = this.options, - frame = this.dom.frame, - labels = this.dom.labels; - - // create frame - if (!this.parent) { - throw new Error('Cannot repaint groupset: no parent attached'); - } - var parentContainer = this.parent.getContainer(); - if (!parentContainer) { - throw new Error('Cannot repaint groupset: parent has no container element'); - } - if (!frame) { - frame = document.createElement('div'); - frame.className = 'groupset'; - this.dom.frame = frame; - - var className = options.className; - if (className) { - util.addClassName(frame, util.option.asString(className)); - } - - changed += 1; - } - if (!frame.parentNode) { - parentContainer.appendChild(frame); - changed += 1; - } - - // create labels - var labelContainer = asElement(options.labelContainer); - if (!labelContainer) { - throw new Error('Cannot repaint groupset: option "labelContainer" not defined'); - } - if (!labels) { - labels = document.createElement('div'); - labels.className = 'labels'; - //frame.appendChild(labels); - this.dom.labels = labels; - } - if (!labels.parentNode || labels.parentNode != labelContainer) { - if (labels.parentNode) { - labels.parentNode.removeChild(labels.parentNode); - } - labelContainer.appendChild(labels); - } - - // reposition frame - changed += update(frame.style, 'height', asSize(options.height, this.height + 'px')); - changed += update(frame.style, 'top', asSize(options.top, '0px')); - changed += update(frame.style, 'left', asSize(options.left, '0px')); - changed += update(frame.style, 'width', asSize(options.width, '100%')); - - // reposition labels - changed += update(labels.style, 'top', asSize(options.top, '0px')); - - var me = this, - queue = this.queue, - groups = this.groups, - groupsData = this.groupsData; - - // show/hide added/changed/removed groups - var ids = Object.keys(queue); - if (ids.length) { - ids.forEach(function (id) { - var action = queue[id]; - var group = groups[id]; - - //noinspection FallthroughInSwitchStatementJS - switch (action) { - case 'add': - case 'update': - if (!group) { - var groupOptions = Object.create(me.options); - group = new Group(me, id, groupOptions); - group.setItems(me.itemsData); // attach items data - groups[id] = group; - - me.controller.add(group); - } - - // TODO: update group data - group.data = groupsData.get(id); - - delete queue[id]; - break; - - case 'remove': - if (group) { - group.setItems(); // detach items data - delete groups[id]; - - me.controller.remove(group); - } - - // update lists - delete queue[id]; - break; - - default: - console.log('Error: unknown action "' + action + '"'); - } - }); - - // the groupset depends on each of the groups - //this.depends = this.groups; // TODO: gives a circular reference through the parent - - // TODO: apply dependencies of the groupset - - // update the top positions of the groups in the correct order - var orderedGroups = this.groupsData.getIds({ - order: this.options.groupsOrder - }); - for (i = 0; i < orderedGroups.length; i++) { - (function (group, prevGroup) { - var top = 0; - if (prevGroup) { - top = function () { - // TODO: top must reckon with options.maxHeight - return prevGroup.top + prevGroup.height; - } - } - group.setOptions({ - top: top - }); - })(groups[orderedGroups[i]], groups[orderedGroups[i - 1]]); - } - - // (re)create the labels - while (labels.firstChild) { - labels.removeChild(labels.firstChild); - } - for (i = 0; i < orderedGroups.length; i++) { - id = orderedGroups[i]; - label = this._createLabel(id); - labels.appendChild(label); - } - - changed++; - } - - // reposition the labels - // TODO: labels are not displayed correctly when orientation=='top' - // TODO: width of labelPanel is not immediately updated on a change in groups - for (id in groups) { - if (groups.hasOwnProperty(id)) { - group = groups[id]; - label = group.label; - if (label) { - label.style.top = group.top + 'px'; - label.style.height = group.height + 'px'; - } - } - } - - return (changed > 0); -}; - -/** - * Create a label for group with given id - * @param {Number} id - * @return {Element} label - * @private - */ -GroupSet.prototype._createLabel = function(id) { - var group = this.groups[id]; - var label = document.createElement('div'); - label.className = 'label'; - var inner = document.createElement('div'); - inner.className = 'inner'; - label.appendChild(inner); - - var content = group.data && group.data.content; - if (content instanceof Element) { - inner.appendChild(content); - } - else if (content != undefined) { - inner.innerHTML = content; - } - - var className = group.data && group.data.className; - if (className) { - util.addClassName(label, className); - } - - group.label = label; // TODO: not so nice, parking labels in the group this way!!! - - return label; -}; - -/** - * Get container element - * @return {HTMLElement} container - */ -GroupSet.prototype.getContainer = function getContainer() { - return this.dom.frame; -}; - -/** - * Get the width of the group labels - * @return {Number} width - */ -GroupSet.prototype.getLabelsWidth = function getContainer() { - return this.props.labels.width; -}; - -/** - * Reflow the component - * @return {Boolean} resized - */ -GroupSet.prototype.reflow = function reflow() { - var changed = 0, - id, group, - options = this.options, - update = util.updateProperty, - asNumber = util.option.asNumber, - asSize = util.option.asSize, - frame = this.dom.frame; - - if (frame) { - var maxHeight = asNumber(options.maxHeight); - var fixedHeight = (asSize(options.height) != null); - var height; - if (fixedHeight) { - height = frame.offsetHeight; - } - else { - // height is not specified, calculate the sum of the height of all groups - height = 0; - - for (id in this.groups) { - if (this.groups.hasOwnProperty(id)) { - group = this.groups[id]; - height += group.height; - } - } - } - if (maxHeight != null) { - height = Math.min(height, maxHeight); - } - changed += update(this, 'height', height); - - changed += update(this, 'top', frame.offsetTop); - changed += update(this, 'left', frame.offsetLeft); - changed += update(this, 'width', frame.offsetWidth); - } - - // calculate the maximum width of the labels - var width = 0; - for (id in this.groups) { - if (this.groups.hasOwnProperty(id)) { - group = this.groups[id]; - var labelWidth = group.props && group.props.label && group.props.label.width || 0; - width = Math.max(width, labelWidth); - } - } - changed += update(this.props.labels, 'width', width); - - return (changed > 0); -}; - -/** - * Hide the component from the DOM - * @return {Boolean} changed - */ -GroupSet.prototype.hide = function hide() { - if (this.dom.frame && this.dom.frame.parentNode) { - this.dom.frame.parentNode.removeChild(this.dom.frame); - return true; - } - else { - return false; - } -}; - -/** - * Show the component in the DOM (when not already visible). - * A repaint will be executed when the component is not visible - * @return {Boolean} changed - */ -GroupSet.prototype.show = function show() { - if (!this.dom.frame || !this.dom.frame.parentNode) { - return this.repaint(); - } - else { - return false; - } -}; - -/** - * Handle updated groups - * @param {Number[]} ids - * @private - */ -GroupSet.prototype._onUpdate = function _onUpdate(ids) { - this._toQueue(ids, 'update'); -}; - -/** - * Handle changed groups - * @param {Number[]} ids - * @private - */ -GroupSet.prototype._onAdd = function _onAdd(ids) { - this._toQueue(ids, 'add'); -}; - -/** - * Handle removed groups - * @param {Number[]} ids - * @private - */ -GroupSet.prototype._onRemove = function _onRemove(ids) { - this._toQueue(ids, 'remove'); -}; - -/** - * Put groups in the queue to be added/updated/remove - * @param {Number[]} ids - * @param {String} action can be 'add', 'update', 'remove' - */ -GroupSet.prototype._toQueue = function _toQueue(ids, action) { - var queue = this.queue; - ids.forEach(function (id) { - queue[id] = action; - }); - - if (this.controller) { - //this.requestReflow(); - this.requestRepaint(); - } -}; - -/** - * Create a timeline visualization - * @param {HTMLElement} container - * @param {vis.DataSet | Array | DataTable} [items] - * @param {Object} [options] See Timeline.setOptions for the available options. - * @constructor - */ -function Timeline (container, items, options) { - var me = this; - this.options = util.extend({ - orientation: 'bottom', - min: null, - max: null, - zoomMin: 10, // milliseconds - zoomMax: 1000 * 60 * 60 * 24 * 365 * 10000, // milliseconds - // moveable: true, // TODO: option moveable - // zoomable: true, // TODO: option zoomable - showMinorLabels: true, - showMajorLabels: true, - autoResize: false - }, options); - - // controller - this.controller = new Controller(); - - // root panel - if (!container) { - throw new Error('No container element provided'); - } - var rootOptions = Object.create(this.options); - rootOptions.height = function () { - if (me.options.height) { - // fixed height - return me.options.height; - } - else { - // auto height - return me.timeaxis.height + me.content.height; - } - }; - this.rootPanel = new RootPanel(container, rootOptions); - this.controller.add(this.rootPanel); - - // item panel - var itemOptions = Object.create(this.options); - itemOptions.left = function () { - return me.labelPanel.width; - }; - itemOptions.width = function () { - return me.rootPanel.width - me.labelPanel.width; - }; - itemOptions.top = null; - itemOptions.height = null; - this.itemPanel = new Panel(this.rootPanel, [], itemOptions); - this.controller.add(this.itemPanel); - - // label panel - var labelOptions = Object.create(this.options); - labelOptions.top = null; - labelOptions.left = null; - labelOptions.height = null; - labelOptions.width = function () { - if (me.content && typeof me.content.getLabelsWidth === 'function') { - return me.content.getLabelsWidth(); - } - else { - return 0; - } - }; - this.labelPanel = new Panel(this.rootPanel, [], labelOptions); - this.controller.add(this.labelPanel); - - // range - var now = moment().hours(0).minutes(0).seconds(0).milliseconds(0); - this.range = new Range({ - start: now.clone().add('days', -3).valueOf(), - end: now.clone().add('days', 4).valueOf() - }); - /* TODO: fix range options - var rangeOptions = Object.create(this.options); - this.range = new Range(rangeOptions); - this.range.setRange( - now.clone().add('days', -3).valueOf(), - now.clone().add('days', 4).valueOf() - ); - */ - // TODO: reckon with options moveable and zoomable - this.range.subscribe(this.rootPanel, 'move', 'horizontal'); - this.range.subscribe(this.rootPanel, 'zoom', 'horizontal'); - this.range.on('rangechange', function () { - var force = true; - me.controller.requestReflow(force); - }); - this.range.on('rangechanged', function () { - var force = true; - me.controller.requestReflow(force); - }); - - // TODO: put the listeners in setOptions, be able to dynamically change with options moveable and zoomable - - // time axis - var timeaxisOptions = Object.create(rootOptions); - timeaxisOptions.range = this.range; - timeaxisOptions.left = null; - timeaxisOptions.top = null; - timeaxisOptions.width = '100%'; - timeaxisOptions.height = null; - this.timeaxis = new TimeAxis(this.itemPanel, [], timeaxisOptions); - this.timeaxis.setRange(this.range); - this.controller.add(this.timeaxis); - - // create itemset or groupset - this.setGroups(null); - - this.itemsData = null; // DataSet - this.groupsData = null; // DataSet - - // set data - if (items) { - this.setItems(items); - } -} - -/** - * Set options - * @param {Object} options TODO: describe the available options - */ -Timeline.prototype.setOptions = function (options) { - if (options) { - util.extend(this.options, options); - } - - // TODO: apply range min,max - - this.controller.reflow(); - this.controller.repaint(); -}; - -/** - * Set items - * @param {vis.DataSet | Array | DataTable | null} items - */ -Timeline.prototype.setItems = function(items) { - var initialLoad = (this.itemsData == null); - - // convert to type DataSet when needed - var newItemSet; - if (!items) { - newItemSet = null; - } - else if (items instanceof DataSet) { - newItemSet = items; - } - if (!(items instanceof DataSet)) { - newItemSet = new DataSet({ - convert: { - start: 'Date', - end: 'Date' - } - }); - newItemSet.add(items); - } - - // set items - this.itemsData = newItemSet; - this.content.setItems(newItemSet); - - if (initialLoad && (this.options.start == undefined || this.options.end == undefined)) { - // apply the data range as range - var dataRange = this.getItemRange(); - - // add 5% on both sides - var min = dataRange.min; - var max = dataRange.max; - if (min != null && max != null) { - var interval = (max.valueOf() - min.valueOf()); - if (interval <= 0) { - // prevent an empty interval - interval = 24 * 60 * 60 * 1000; // 1 day - } - min = new Date(min.valueOf() - interval * 0.05); - max = new Date(max.valueOf() + interval * 0.05); - } - - // override specified start and/or end date - if (this.options.start != undefined) { - min = new Date(this.options.start.valueOf()); - } - if (this.options.end != undefined) { - max = new Date(this.options.end.valueOf()); - } - - // apply range if there is a min or max available - if (min != null || max != null) { - this.range.setRange(min, max); - } - } -}; - -/** - * Set groups - * @param {vis.DataSet | Array | DataTable} groups - */ -Timeline.prototype.setGroups = function(groups) { - var me = this; - this.groupsData = groups; - - // switch content type between ItemSet or GroupSet when needed - var type = this.groupsData ? GroupSet : ItemSet; - if (!(this.content instanceof type)) { - // remove old content set - if (this.content) { - this.content.hide(); - if (this.content.setItems) { - this.content.setItems(); // disconnect from items - } - if (this.content.setGroups) { - this.content.setGroups(); // disconnect from groups - } - this.controller.remove(this.content); - } - - // create new content set - var options = Object.create(this.options); - util.extend(options, { - top: function () { - if (me.options.orientation == 'top') { - return me.timeaxis.height; - } - else { - return me.itemPanel.height - me.timeaxis.height - me.content.height; - } - }, - left: null, - width: '100%', - height: function () { - if (me.options.height) { - return me.itemPanel.height - me.timeaxis.height; - } - else { - return null; - } - }, - maxHeight: function () { - if (me.options.maxHeight) { - if (!util.isNumber(me.options.maxHeight)) { - throw new TypeError('Number expected for property maxHeight'); - } - return me.options.maxHeight - me.timeaxis.height; - } - else { - return null; - } - }, - labelContainer: function () { - return me.labelPanel.getContainer(); - } - }); - this.content = new type(this.itemPanel, [this.timeaxis], options); - if (this.content.setRange) { - this.content.setRange(this.range); - } - if (this.content.setItems) { - this.content.setItems(this.itemsData); - } - if (this.content.setGroups) { - this.content.setGroups(this.groupsData); - } - this.controller.add(this.content); - } -}; - -/** - * Get the data range of the item set. - * @returns {{min: Date, max: Date}} range A range with a start and end Date. - * When no minimum is found, min==null - * When no maximum is found, max==null - */ -Timeline.prototype.getItemRange = function getItemRange() { - // calculate min from start filed - var itemsData = this.itemsData, - min = null, - max = null; - - if (itemsData) { - // calculate the minimum value of the field 'start' - var minItem = itemsData.min('start'); - min = minItem ? minItem.start.valueOf() : null; - - // calculate maximum value of fields 'start' and 'end' - var maxStartItem = itemsData.max('start'); - if (maxStartItem) { - max = maxStartItem.start.valueOf(); - } - var maxEndItem = itemsData.max('end'); - if (maxEndItem) { - if (max == null) { - max = maxEndItem.end.valueOf(); - } - else { - max = Math.max(max, maxEndItem.end.valueOf()); - } - } - } - - return { - min: (min != null) ? new Date(min) : null, - max: (max != null) ? new Date(max) : null - }; -}; - -(function(exports) { - /** - * Parse a text source containing data in DOT language into a JSON object. - * The object contains two lists: one with nodes and one with edges. - * - * DOT language reference: http://www.graphviz.org/doc/info/lang.html - * - * @param {String} data Text containing a graph in DOT-notation - * @return {Object} graph An object containing two parameters: - * {Object[]} nodes - * {Object[]} edges - */ - function parseDOT (data) { - dot = data; - return parseGraph(); - } - - // token types enumeration - var TOKENTYPE = { - NULL : 0, - DELIMITER : 1, - IDENTIFIER: 2, - UNKNOWN : 3 - }; - - // map with all delimiters - var DELIMITERS = { - '{': true, - '}': true, - '[': true, - ']': true, - ';': true, - '=': true, - ',': true, - - '->': true, - '--': true - }; - - var dot = ''; // current dot file - var index = 0; // current index in dot file - var c = ''; // current token character in expr - var token = ''; // current token - var tokenType = TOKENTYPE.NULL; // type of the token - - /** - * Get the first character from the dot file. - * The character is stored into the char c. If the end of the dot file is - * reached, the function puts an empty string in c. - */ - function first() { - index = 0; - c = dot.charAt(0); - } - - /** - * Get the next character from the dot file. - * The character is stored into the char c. If the end of the dot file is - * reached, the function puts an empty string in c. - */ - function next() { - index++; - c = dot.charAt(index); - } - - /** - * Preview the next character from the dot file. - * @return {String} cNext - */ - function nextPreview() { - return dot.charAt(index + 1); - } - - /** - * Test whether given character is alphabetic or numeric - * @param {String} c - * @return {Boolean} isAlphaNumeric - */ - var regexAlphaNumeric = /[a-zA-Z_0-9.:#]/; - function isAlphaNumeric(c) { - return regexAlphaNumeric.test(c); - } - - /** - * Merge all properties of object b into object b - * @param {Object} a - * @param {Object} b - * @return {Object} a - */ - function merge (a, b) { - if (!a) { - a = {}; - } - - if (b) { - for (var name in b) { - if (b.hasOwnProperty(name)) { - a[name] = b[name]; - } - } - } - return a; - } - - /** - * Set a value in an object, where the provided parameter name can be a - * path with nested parameters. For example: - * - * var obj = {a: 2}; - * setValue(obj, 'b.c', 3); // obj = {a: 2, b: {c: 3}} - * - * @param {Object} obj - * @param {String} path A parameter name or dot-separated parameter path, - * like "color.highlight.border". - * @param {*} value - */ - function setValue(obj, path, value) { - var keys = path.split('.'); - var o = obj; - while (keys.length) { - var key = keys.shift(); - if (keys.length) { - // this isn't the end point - if (!o[key]) { - o[key] = {}; - } - o = o[key]; - } - else { - // this is the end point - o[key] = value; - } - } - } - - /** - * Add a node to a graph object. If there is already a node with - * the same id, their attributes will be merged. - * @param {Object} graph - * @param {Object} node - */ - function addNode(graph, node) { - var i, len; - var current = null; - - // find root graph (in case of subgraph) - var graphs = [graph]; // list with all graphs from current graph to root graph - var root = graph; - while (root.parent) { - graphs.push(root.parent); - root = root.parent; - } - - // find existing node (at root level) by its id - if (root.nodes) { - for (i = 0, len = root.nodes.length; i < len; i++) { - if (node.id === root.nodes[i].id) { - current = root.nodes[i]; - break; - } - } - } - - if (!current) { - // this is a new node - current = { - id: node.id - }; - if (graph.node) { - // clone default attributes - current.attr = merge(current.attr, graph.node); - } - } - - // add node to this (sub)graph and all its parent graphs - for (i = graphs.length - 1; i >= 0; i--) { - var g = graphs[i]; - - if (!g.nodes) { - g.nodes = []; - } - if (g.nodes.indexOf(current) == -1) { - g.nodes.push(current); - } - } - - // merge attributes - if (node.attr) { - current.attr = merge(current.attr, node.attr); - } - } - - /** - * Add an edge to a graph object - * @param {Object} graph - * @param {Object} edge - */ - function addEdge(graph, edge) { - if (!graph.edges) { - graph.edges = []; - } - graph.edges.push(edge); - if (graph.edge) { - var attr = merge({}, graph.edge); // clone default attributes - edge.attr = merge(attr, edge.attr); // merge attributes - } - } - - /** - * Create an edge to a graph object - * @param {Object} graph - * @param {String | Number | Object} from - * @param {String | Number | Object} to - * @param {String} type - * @param {Object | null} attr - * @return {Object} edge - */ - function createEdge(graph, from, to, type, attr) { - var edge = { - from: from, - to: to, - type: type - }; - - if (graph.edge) { - edge.attr = merge({}, graph.edge); // clone default attributes - } - edge.attr = merge(edge.attr || {}, attr); // merge attributes - - return edge; - } - - /** - * Get next token in the current dot file. - * The token and token type are available as token and tokenType - */ - function getToken() { - tokenType = TOKENTYPE.NULL; - token = ''; - - // skip over whitespaces - while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter - next(); - } - - do { - var isComment = false; - - // skip comment - if (c == '#') { - // find the previous non-space character - var i = index - 1; - while (dot.charAt(i) == ' ' || dot.charAt(i) == '\t') { - i--; - } - if (dot.charAt(i) == '\n' || dot.charAt(i) == '') { - // the # is at the start of a line, this is indeed a line comment - while (c != '' && c != '\n') { - next(); - } - isComment = true; - } - } - if (c == '/' && nextPreview() == '/') { - // skip line comment - while (c != '' && c != '\n') { - next(); - } - isComment = true; - } - if (c == '/' && nextPreview() == '*') { - // skip block comment - while (c != '') { - if (c == '*' && nextPreview() == '/') { - // end of block comment found. skip these last two characters - next(); - next(); - break; - } - else { - next(); - } - } - isComment = true; - } - - // skip over whitespaces - while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { // space, tab, enter - next(); - } - } - while (isComment); - - // check for end of dot file - if (c == '') { - // token is still empty - tokenType = TOKENTYPE.DELIMITER; - return; - } - - // check for delimiters consisting of 2 characters - var c2 = c + nextPreview(); - if (DELIMITERS[c2]) { - tokenType = TOKENTYPE.DELIMITER; - token = c2; - next(); - next(); - return; - } - - // check for delimiters consisting of 1 character - if (DELIMITERS[c]) { - tokenType = TOKENTYPE.DELIMITER; - token = c; - next(); - return; - } - - // check for an identifier (number or string) - // TODO: more precise parsing of numbers/strings (and the port separator ':') - if (isAlphaNumeric(c) || c == '-') { - token += c; - next(); - - while (isAlphaNumeric(c)) { - token += c; - next(); - } - if (token == 'false') { - token = false; // convert to boolean - } - else if (token == 'true') { - token = true; // convert to boolean - } - else if (!isNaN(Number(token))) { - token = Number(token); // convert to number - } - tokenType = TOKENTYPE.IDENTIFIER; - return; - } - - // check for a string enclosed by double quotes - if (c == '"') { - next(); - while (c != '' && (c != '"' || (c == '"' && nextPreview() == '"'))) { - token += c; - if (c == '"') { // skip the escape character - next(); - } - next(); - } - if (c != '"') { - throw newSyntaxError('End of string " expected'); - } - next(); - tokenType = TOKENTYPE.IDENTIFIER; - return; - } - - // something unknown is found, wrong characters, a syntax error - tokenType = TOKENTYPE.UNKNOWN; - while (c != '') { - token += c; - next(); - } - throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"'); - } - - /** - * Parse a graph. - * @returns {Object} graph - */ - function parseGraph() { - var graph = {}; - - first(); - getToken(); - - // optional strict keyword - if (token == 'strict') { - graph.strict = true; - getToken(); - } - - // graph or digraph keyword - if (token == 'graph' || token == 'digraph') { - graph.type = token; - getToken(); - } - - // optional graph id - if (tokenType == TOKENTYPE.IDENTIFIER) { - graph.id = token; - getToken(); - } - - // open angle bracket - if (token != '{') { - throw newSyntaxError('Angle bracket { expected'); - } - getToken(); - - // statements - parseStatements(graph); - - // close angle bracket - if (token != '}') { - throw newSyntaxError('Angle bracket } expected'); - } - getToken(); - - // end of file - if (token !== '') { - throw newSyntaxError('End of file expected'); - } - getToken(); - - // remove temporary default properties - delete graph.node; - delete graph.edge; - delete graph.graph; - - return graph; - } - - /** - * Parse a list with statements. - * @param {Object} graph - */ - function parseStatements (graph) { - while (token !== '' && token != '}') { - parseStatement(graph); - if (token == ';') { - getToken(); - } - } - } - - /** - * Parse a single statement. Can be a an attribute statement, node - * statement, a series of node statements and edge statements, or a - * parameter. - * @param {Object} graph - */ - function parseStatement(graph) { - // parse subgraph - var subgraph = parseSubgraph(graph); - if (subgraph) { - // edge statements - parseEdge(graph, subgraph); - - return; - } - - // parse an attribute statement - var attr = parseAttributeStatement(graph); - if (attr) { - return; - } - - // parse node - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier expected'); - } - var id = token; // id can be a string or a number - getToken(); - - if (token == '=') { - // id statement - getToken(); - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier expected'); - } - graph[id] = token; - getToken(); - // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] " - } - else { - parseNodeStatement(graph, id); - } - } - - /** - * Parse a subgraph - * @param {Object} graph parent graph object - * @return {Object | null} subgraph - */ - function parseSubgraph (graph) { - var subgraph = null; - - // optional subgraph keyword - if (token == 'subgraph') { - subgraph = {}; - subgraph.type = 'subgraph'; - getToken(); - - // optional graph id - if (tokenType == TOKENTYPE.IDENTIFIER) { - subgraph.id = token; - getToken(); - } - } - - // open angle bracket - if (token == '{') { - getToken(); - - if (!subgraph) { - subgraph = {}; - } - subgraph.parent = graph; - subgraph.node = graph.node; - subgraph.edge = graph.edge; - subgraph.graph = graph.graph; - - // statements - parseStatements(subgraph); - - // close angle bracket - if (token != '}') { - throw newSyntaxError('Angle bracket } expected'); - } - getToken(); - - // remove temporary default properties - delete subgraph.node; - delete subgraph.edge; - delete subgraph.graph; - delete subgraph.parent; - - // register at the parent graph - if (!graph.subgraphs) { - graph.subgraphs = []; - } - graph.subgraphs.push(subgraph); - } - - return subgraph; - } - - /** - * parse an attribute statement like "node [shape=circle fontSize=16]". - * Available keywords are 'node', 'edge', 'graph'. - * The previous list with default attributes will be replaced - * @param {Object} graph - * @returns {String | null} keyword Returns the name of the parsed attribute - * (node, edge, graph), or null if nothing - * is parsed. - */ - function parseAttributeStatement (graph) { - // attribute statements - if (token == 'node') { - getToken(); - - // node attributes - graph.node = parseAttributeList(); - return 'node'; - } - else if (token == 'edge') { - getToken(); - - // edge attributes - graph.edge = parseAttributeList(); - return 'edge'; - } - else if (token == 'graph') { - getToken(); - - // graph attributes - graph.graph = parseAttributeList(); - return 'graph'; - } - - return null; - } - - /** - * parse a node statement - * @param {Object} graph - * @param {String | Number} id - */ - function parseNodeStatement(graph, id) { - // node statement - var node = { - id: id - }; - var attr = parseAttributeList(); - if (attr) { - node.attr = attr; - } - addNode(graph, node); - - // edge statements - parseEdge(graph, id); - } - - /** - * Parse an edge or a series of edges - * @param {Object} graph - * @param {String | Number} from Id of the from node - */ - function parseEdge(graph, from) { - while (token == '->' || token == '--') { - var to; - var type = token; - getToken(); - - var subgraph = parseSubgraph(graph); - if (subgraph) { - to = subgraph; - } - else { - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Identifier or subgraph expected'); - } - to = token; - addNode(graph, { - id: to - }); - getToken(); - } - - // parse edge attributes - var attr = parseAttributeList(); - - // create edge - var edge = createEdge(graph, from, to, type, attr); - addEdge(graph, edge); - - from = to; - } - } - - /** - * Parse a set with attributes, - * for example [label="1.000", shape=solid] - * @return {Object | null} attr - */ - function parseAttributeList() { - var attr = null; - - while (token == '[') { - getToken(); - attr = {}; - while (token !== '' && token != ']') { - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Attribute name expected'); - } - var name = token; - - getToken(); - if (token != '=') { - throw newSyntaxError('Equal sign = expected'); - } - getToken(); - - if (tokenType != TOKENTYPE.IDENTIFIER) { - throw newSyntaxError('Attribute value expected'); - } - var value = token; - setValue(attr, name, value); // name can be a path - - getToken(); - if (token ==',') { - getToken(); - } - } - - if (token != ']') { - throw newSyntaxError('Bracket ] expected'); - } - getToken(); - } - - return attr; - } - - /** - * Create a syntax error with extra information on current token and index. - * @param {String} message - * @returns {SyntaxError} err - */ - function newSyntaxError(message) { - return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ')'); - } - - /** - * Chop off text after a maximum length - * @param {String} text - * @param {Number} maxLength - * @returns {String} - */ - function chop (text, maxLength) { - return (text.length <= maxLength) ? text : (text.substr(0, 27) + '...'); - } - - /** - * Execute a function fn for each pair of elements in two arrays - * @param {Array | *} array1 - * @param {Array | *} array2 - * @param {function} fn - */ - function forEach2(array1, array2, fn) { - if (array1 instanceof Array) { - array1.forEach(function (elem1) { - if (array2 instanceof Array) { - array2.forEach(function (elem2) { - fn(elem1, elem2); - }); - } - else { - fn(elem1, array2); - } - }); - } - else { - if (array2 instanceof Array) { - array2.forEach(function (elem2) { - fn(array1, elem2); - }); - } - else { - fn(array1, array2); - } - } - } - - /** - * Convert a string containing a graph in DOT language into a map containing - * with nodes and edges in the format of graph. - * @param {String} data Text containing a graph in DOT-notation - * @return {Object} graphData - */ - function DOTToGraph (data) { - // parse the DOT file - var dotData = parseDOT(data); - var graphData = { - nodes: [], - edges: [], - options: {} - }; - - // copy the nodes - if (dotData.nodes) { - dotData.nodes.forEach(function (dotNode) { - var graphNode = { - id: dotNode.id, - label: String(dotNode.label || dotNode.id) - }; - merge(graphNode, dotNode.attr); - if (graphNode.image) { - graphNode.shape = 'image'; - } - graphData.nodes.push(graphNode); - }); - } - - // copy the edges - if (dotData.edges) { - /** - * Convert an edge in DOT format to an edge with VisGraph format - * @param {Object} dotEdge - * @returns {Object} graphEdge - */ - function convertEdge(dotEdge) { - var graphEdge = { - from: dotEdge.from, - to: dotEdge.to - }; - merge(graphEdge, dotEdge.attr); - graphEdge.style = (dotEdge.type == '->') ? 'arrow' : 'line'; - return graphEdge; - } - - dotData.edges.forEach(function (dotEdge) { - var from, to; - if (dotEdge.from instanceof Object) { - from = dotEdge.from.nodes; - } - else { - from = { - id: dotEdge.from - } - } - - if (dotEdge.to instanceof Object) { - to = dotEdge.to.nodes; - } - else { - to = { - id: dotEdge.to - } - } - - if (dotEdge.from instanceof Object && dotEdge.from.edges) { - dotEdge.from.edges.forEach(function (subEdge) { - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - } - - forEach2(from, to, function (from, to) { - var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr); - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - - if (dotEdge.to instanceof Object && dotEdge.to.edges) { - dotEdge.to.edges.forEach(function (subEdge) { - var graphEdge = convertEdge(subEdge); - graphData.edges.push(graphEdge); - }); - } - }); - } - - // copy the options - if (dotData.attr) { - graphData.options = dotData.attr; - } - - return graphData; - } - - // exports - exports.parseDOT = parseDOT; - exports.DOTToGraph = DOTToGraph; - -})(typeof util !== 'undefined' ? util : exports); - -/** - * Canvas shapes used by the Graph - */ -if (typeof CanvasRenderingContext2D !== 'undefined') { - - /** - * Draw a circle shape - */ - CanvasRenderingContext2D.prototype.circle = function(x, y, r) { - this.beginPath(); - this.arc(x, y, r, 0, 2*Math.PI, false); - }; - - /** - * Draw a square shape - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r size, width and height of the square - */ - CanvasRenderingContext2D.prototype.square = function(x, y, r) { - this.beginPath(); - this.rect(x - r, y - r, r * 2, r * 2); - }; - - /** - * Draw a triangle shape - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r radius, half the length of the sides of the triangle - */ - CanvasRenderingContext2D.prototype.triangle = function(x, y, r) { - // http://en.wikipedia.org/wiki/Equilateral_triangle - this.beginPath(); - - var s = r * 2; - var s2 = s / 2; - var ir = Math.sqrt(3) / 6 * s; // radius of inner circle - var h = Math.sqrt(s * s - s2 * s2); // height - - this.moveTo(x, y - (h - ir)); - this.lineTo(x + s2, y + ir); - this.lineTo(x - s2, y + ir); - this.lineTo(x, y - (h - ir)); - this.closePath(); - }; - - /** - * Draw a triangle shape in downward orientation - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r radius - */ - CanvasRenderingContext2D.prototype.triangleDown = function(x, y, r) { - // http://en.wikipedia.org/wiki/Equilateral_triangle - this.beginPath(); - - var s = r * 2; - var s2 = s / 2; - var ir = Math.sqrt(3) / 6 * s; // radius of inner circle - var h = Math.sqrt(s * s - s2 * s2); // height - - this.moveTo(x, y + (h - ir)); - this.lineTo(x + s2, y - ir); - this.lineTo(x - s2, y - ir); - this.lineTo(x, y + (h - ir)); - this.closePath(); - }; - - /** - * Draw a star shape, a star with 5 points - * @param {Number} x horizontal center - * @param {Number} y vertical center - * @param {Number} r radius, half the length of the sides of the triangle - */ - CanvasRenderingContext2D.prototype.star = function(x, y, r) { - // http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/ - this.beginPath(); - - for (var n = 0; n < 10; n++) { - var radius = (n % 2 === 0) ? r * 1.3 : r * 0.5; - this.lineTo( - x + radius * Math.sin(n * 2 * Math.PI / 10), - y - radius * Math.cos(n * 2 * Math.PI / 10) - ); - } - - this.closePath(); - }; - - /** - * http://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas - */ - CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) { - var r2d = Math.PI/180; - if( w - ( 2 * r ) < 0 ) { r = ( w / 2 ); } //ensure that the radius isn't too large for x - if( h - ( 2 * r ) < 0 ) { r = ( h / 2 ); } //ensure that the radius isn't too large for y - this.beginPath(); - this.moveTo(x+r,y); - this.lineTo(x+w-r,y); - this.arc(x+w-r,y+r,r,r2d*270,r2d*360,false); - this.lineTo(x+w,y+h-r); - this.arc(x+w-r,y+h-r,r,0,r2d*90,false); - this.lineTo(x+r,y+h); - this.arc(x+r,y+h-r,r,r2d*90,r2d*180,false); - this.lineTo(x,y+r); - this.arc(x+r,y+r,r,r2d*180,r2d*270,false); - }; - - /** - * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - */ - CanvasRenderingContext2D.prototype.ellipse = function(x, y, w, h) { - var kappa = .5522848, - ox = (w / 2) * kappa, // control point offset horizontal - oy = (h / 2) * kappa, // control point offset vertical - xe = x + w, // x-end - ye = y + h, // y-end - xm = x + w / 2, // x-middle - ym = y + h / 2; // y-middle - - this.beginPath(); - this.moveTo(x, ym); - this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - }; - - - - /** - * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - */ - CanvasRenderingContext2D.prototype.database = function(x, y, w, h) { - var f = 1/3; - var wEllipse = w; - var hEllipse = h * f; - - var kappa = .5522848, - ox = (wEllipse / 2) * kappa, // control point offset horizontal - oy = (hEllipse / 2) * kappa, // control point offset vertical - xe = x + wEllipse, // x-end - ye = y + hEllipse, // y-end - xm = x + wEllipse / 2, // x-middle - ym = y + hEllipse / 2, // y-middle - ymb = y + (h - hEllipse/2), // y-midlle, bottom ellipse - yeb = y + h; // y-end, bottom ellipse - - this.beginPath(); - this.moveTo(xe, ym); - - this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - - this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - - this.lineTo(xe, ymb); - - this.bezierCurveTo(xe, ymb + oy, xm + ox, yeb, xm, yeb); - this.bezierCurveTo(xm - ox, yeb, x, ymb + oy, x, ymb); - - this.lineTo(x, ym); - }; - - - /** - * Draw an arrow point (no line) - */ - CanvasRenderingContext2D.prototype.arrow = function(x, y, angle, length) { - // tail - var xt = x - length * Math.cos(angle); - var yt = y - length * Math.sin(angle); - - // inner tail - // TODO: allow to customize different shapes - var xi = x - length * 0.9 * Math.cos(angle); - var yi = y - length * 0.9 * Math.sin(angle); - - // left - var xl = xt + length / 3 * Math.cos(angle + 0.5 * Math.PI); - var yl = yt + length / 3 * Math.sin(angle + 0.5 * Math.PI); - - // right - var xr = xt + length / 3 * Math.cos(angle - 0.5 * Math.PI); - var yr = yt + length / 3 * Math.sin(angle - 0.5 * Math.PI); - - this.beginPath(); - this.moveTo(x, y); - this.lineTo(xl, yl); - this.lineTo(xi, yi); - this.lineTo(xr, yr); - this.closePath(); - }; - - /** - * Sets up the dashedLine functionality for drawing - * Original code came from http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas - * @author David Jordan - * @date 2012-08-08 - */ - CanvasRenderingContext2D.prototype.dashedLine = function(x,y,x2,y2,dashArray){ - if (!dashArray) dashArray=[10,5]; - if (dashLength==0) dashLength = 0.001; // Hack for Safari - var dashCount = dashArray.length; - this.moveTo(x, y); - var dx = (x2-x), dy = (y2-y); - var slope = dy/dx; - var distRemaining = Math.sqrt( dx*dx + dy*dy ); - var dashIndex=0, draw=true; - while (distRemaining>=0.1){ - var dashLength = dashArray[dashIndex++%dashCount]; - if (dashLength > distRemaining) dashLength = distRemaining; - var xStep = Math.sqrt( dashLength*dashLength / (1 + slope*slope) ); - if (dx<0) xStep = -xStep; - x += xStep; - y += slope*xStep; - this[draw ? 'lineTo' : 'moveTo'](x,y); - distRemaining -= dashLength; - draw = !draw; - } - }; - - // TODO: add diamond shape -} - -/** - * @class Node - * A node. A node can be connected to other nodes via one or multiple edges. - * @param {object} properties An object containing properties for the node. All - * properties are optional, except for the id. - * {number} id Id of the node. Required - * {string} label Text label for the node - * {number} x Horizontal position of the node - * {number} y Vertical position of the node - * {string} shape Node shape, available: - * "database", "circle", "ellipse", - * "box", "image", "text", "dot", - * "star", "triangle", "triangleDown", - * "square" - * {string} image An image url - * {string} title An title text, can be HTML - * {anytype} group A group name or number - * @param {Graph.Images} imagelist A list with images. Only needed - * when the node has an image - * @param {Graph.Groups} grouplist A list with groups. Needed for - * retrieving group properties - * @param {Object} constants An object with default values for - * example for the color - */ -function Node(properties, imagelist, grouplist, constants) { - this.selected = false; - - this.edges = []; // all edges connected to this node - this.group = constants.nodes.group; - - this.fontSize = constants.nodes.fontSize; - this.fontFace = constants.nodes.fontFace; - this.fontColor = constants.nodes.fontColor; - - this.color = constants.nodes.color; - - // set defaults for the properties - this.id = undefined; - this.shape = constants.nodes.shape; - this.image = constants.nodes.image; - this.x = 0; - this.y = 0; - this.xFixed = false; - this.yFixed = false; - this.radius = constants.nodes.radius; - this.radiusFixed = false; - this.radiusMin = constants.nodes.radiusMin; - this.radiusMax = constants.nodes.radiusMax; - - this.imagelist = imagelist; - this.grouplist = grouplist; - - this.setProperties(properties, constants); - - // mass, force, velocity - this.mass = 50; // kg (mass is adjusted for the number of connected edges) - this.fx = 0.0; // external force x - this.fy = 0.0; // external force y - this.vx = 0.0; // velocity x - this.vy = 0.0; // velocity y - this.minForce = constants.minForce; - this.damping = 0.9; // damping factor -}; - -/** - * Attach a edge to the node - * @param {Edge} edge - */ -Node.prototype.attachEdge = function(edge) { - if (this.edges.indexOf(edge) == -1) { - this.edges.push(edge); - } - this._updateMass(); -}; - -/** - * Detach a edge from the node - * @param {Edge} edge - */ -Node.prototype.detachEdge = function(edge) { - var index = this.edges.indexOf(edge); - if (index != -1) { - this.edges.splice(index, 1); - } - this._updateMass(); -}; - -/** - * Update the nodes mass, which is determined by the number of edges connecting - * to it (more edges -> heavier node). - * @private - */ -Node.prototype._updateMass = function() { - this.mass = 50 + 20 * this.edges.length; // kg -}; - -/** - * Set or overwrite properties for the node - * @param {Object} properties an object with properties - * @param {Object} constants and object with default, global properties - */ -Node.prototype.setProperties = function(properties, constants) { - if (!properties) { - return; - } - - // basic properties - if (properties.id != undefined) {this.id = properties.id;} - if (properties.label != undefined) {this.label = properties.label;} - if (properties.title != undefined) {this.title = properties.title;} - if (properties.group != undefined) {this.group = properties.group;} - if (properties.x != undefined) {this.x = properties.x;} - if (properties.y != undefined) {this.y = properties.y;} - if (properties.value != undefined) {this.value = properties.value;} - - if (this.id === undefined) { - throw "Node must have an id"; - } - - // copy group properties - if (this.group) { - var groupObj = this.grouplist.get(this.group); - for (var prop in groupObj) { - if (groupObj.hasOwnProperty(prop)) { - this[prop] = groupObj[prop]; - } - } - } - - // individual shape properties - if (properties.shape != undefined) {this.shape = properties.shape;} - if (properties.image != undefined) {this.image = properties.image;} - if (properties.radius != undefined) {this.radius = properties.radius;} - if (properties.color != undefined) {this.color = Node.parseColor(properties.color);} - - if (properties.fontColor != undefined) {this.fontColor = properties.fontColor;} - if (properties.fontSize != undefined) {this.fontSize = properties.fontSize;} - if (properties.fontFace != undefined) {this.fontFace = properties.fontFace;} - - - if (this.image != undefined) { - if (this.imagelist) { - this.imageObj = this.imagelist.load(this.image); - } - else { - throw "No imagelist provided"; - } - } - - this.xFixed = this.xFixed || (properties.x != undefined); - this.yFixed = this.yFixed || (properties.y != undefined); - this.radiusFixed = this.radiusFixed || (properties.radius != undefined); - - if (this.shape == 'image') { - this.radiusMin = constants.nodes.widthMin; - this.radiusMax = constants.nodes.widthMax; - } - - // choose draw method depending on the shape - switch (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; - // TODO: add diamond shape - 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; break; - } - - // reset the size of the node, this can be changed - this._reset(); -}; - -/** - * Parse a color property into an object with border, background, and - * hightlight colors - * @param {Object | String} color - * @return {Object} colorObject - */ -Node.parseColor = function(color) { - var c; - if (util.isString(color)) { - c = { - border: color, - background: color, - highlight: { - border: color, - background: color - } - }; - // TODO: automatically generate a nice highlight color - } - else { - c = {}; - c.background = color.background || 'white'; - c.border = color.border || c.background; - if (util.isString(color.highlight)) { - c.highlight = { - border: color.highlight, - background: color.highlight - } - } - else { - c.highlight = {}; - c.highlight.background = color.highlight && color.highlight.background || c.background; - c.highlight.border = color.highlight && color.highlight.border || c.border; - } - } - return c; -}; - -/** - * select this node - */ -Node.prototype.select = function() { - this.selected = true; - this._reset(); -}; - -/** - * unselect this node - */ -Node.prototype.unselect = function() { - this.selected = false; - this._reset(); -}; - -/** - * Reset the calculated size of the node, forces it to recalculate its size - * @private - */ -Node.prototype._reset = function() { - this.width = undefined; - this.height = undefined; -}; - -/** - * get the title of this node. - * @return {string} title The title of the node, or undefined when no title - * has been set. - */ -Node.prototype.getTitle = function() { - return this.title; -}; - -/** - * Calculate the distance to the border of the Node - * @param {CanvasRenderingContext2D} ctx - * @param {Number} angle Angle in radians - * @returns {number} distance Distance to the border in pixels - */ -Node.prototype.distanceToBorder = function (ctx, angle) { - var borderWidth = 1; - - if (!this.width) { - this.resize(ctx); - } - - //noinspection FallthroughInSwitchStatementJS - switch (this.shape) { - case 'circle': - case 'dot': - return this.radius + borderWidth; - - case 'ellipse': - var a = this.width / 2; - var b = this.height / 2; - var w = (Math.sin(angle) * a); - var h = (Math.cos(angle) * b); - return a * b / Math.sqrt(w * w + h * h); - - // TODO: implement distanceToBorder for database - // TODO: implement distanceToBorder for triangle - // TODO: implement distanceToBorder for triangleDown - - case 'box': - case 'image': - case 'text': - default: - if (this.width) { - return Math.min( - Math.abs(this.width / 2 / Math.cos(angle)), - Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth; - // TODO: reckon with border radius too in case of box - } - else { - return 0; - } - - } - - // TODO: implement calculation of distance to border for all shapes -}; - -/** - * Set forces acting on the node - * @param {number} fx Force in horizontal direction - * @param {number} fy Force in vertical direction - */ -Node.prototype._setForce = function(fx, fy) { - this.fx = fx; - this.fy = fy; -}; - -/** - * Add forces acting on the node - * @param {number} fx Force in horizontal direction - * @param {number} fy Force in vertical direction - * @private - */ -Node.prototype._addForce = function(fx, fy) { - this.fx += fx; - this.fy += fy; -}; - -/** - * Perform one discrete step for the node - * @param {number} interval Time interval in seconds - */ -Node.prototype.discreteStep = function(interval) { - if (!this.xFixed) { - var dx = -this.damping * this.vx; // damping force - var ax = (this.fx + dx) / this.mass; // acceleration - this.vx += ax / interval; // velocity - this.x += this.vx / interval; // position - } - - if (!this.yFixed) { - var dy = -this.damping * this.vy; // damping force - var ay = (this.fy + dy) / this.mass; // acceleration - this.vy += ay / interval; // velocity - this.y += this.vy / interval; // position - } -}; - - -/** - * Check if this node has a fixed x and y position - * @return {boolean} true if fixed, false if not - */ -Node.prototype.isFixed = function() { - return (this.xFixed && this.yFixed); -}; - -/** - * Check if this node is moving - * @param {number} vmin the minimum velocity considered as "moving" - * @return {boolean} true if moving, false if it has no velocity - */ -// TODO: replace this method with calculating the kinetic energy -Node.prototype.isMoving = function(vmin) { - return (Math.abs(this.vx) > vmin || Math.abs(this.vy) > vmin || - (!this.xFixed && Math.abs(this.fx) > this.minForce) || - (!this.yFixed && Math.abs(this.fy) > this.minForce)); -}; - -/** - * check if this node is selecte - * @return {boolean} selected True if node is selected, else false - */ -Node.prototype.isSelected = function() { - return this.selected; -}; - -/** - * Retrieve the value of the node. Can be undefined - * @return {Number} value - */ -Node.prototype.getValue = function() { - return this.value; -}; - -/** - * Calculate the distance from the nodes location to the given location (x,y) - * @param {Number} x - * @param {Number} y - * @return {Number} value - */ -Node.prototype.getDistance = function(x, y) { - var dx = this.x - x, - dy = this.y - y; - return Math.sqrt(dx * dx + dy * dy); -}; - - -/** - * Adjust the value range of the node. The node will adjust it's radius - * based on its value. - * @param {Number} min - * @param {Number} max - */ -Node.prototype.setValueRange = function(min, max) { - if (!this.radiusFixed && this.value !== undefined) { - var scale = (this.radiusMax - this.radiusMin) / (max - min); - this.radius = (this.value - min) * scale + this.radiusMin; - } -}; - -/** - * Draw this node in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - */ -Node.prototype.draw = function(ctx) { - throw "Draw method not initialized for node"; -}; - -/** - * Recalculate the size of this node in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - */ -Node.prototype.resize = function(ctx) { - throw "Resize method not initialized for node"; -}; - -/** - * Check if this object is overlapping with the provided object - * @param {Object} obj an object with parameters left, top, right, bottom - * @return {boolean} True if location is located on node - */ -Node.prototype.isOverlappingWith = function(obj) { - return (this.left < obj.right && - this.left + this.width > obj.left && - this.top < obj.bottom && - this.top + this.height > obj.top); -}; - -Node.prototype._resizeImage = function (ctx) { - // TODO: pre calculate the image size - if (!this.width) { // undefined or 0 - var width, height; - if (this.value) { - var scale = this.imageObj.height / this.imageObj.width; - width = this.radius || this.imageObj.width; - height = this.radius * scale || this.imageObj.height; - } - else { - width = this.imageObj.width; - height = this.imageObj.height; - } - this.width = width; - this.height = height; - } -}; - -Node.prototype._drawImage = function (ctx) { - this._resizeImage(ctx); - - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - var yLabel; - if (this.imageObj) { - ctx.drawImage(this.imageObj, this.left, this.top, this.width, this.height); - yLabel = this.y + this.height / 2; - } - else { - // image still loading... just draw the label for now - yLabel = this.y; - } - - this._label(ctx, this.label, this.x, yLabel, undefined, "top"); -}; - - -Node.prototype._resizeBox = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - this.width = textSize.width + 2 * margin; - this.height = textSize.height + 2 * margin; - } -}; - -Node.prototype._drawBox = function (ctx) { - this._resizeBox(ctx); - - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; - ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.lineWidth = this.selected ? 2.0 : 1.0; - ctx.roundRect(this.left, this.top, this.width, this.height, this.radius); - ctx.fill(); - ctx.stroke(); - - this._label(ctx, this.label, this.x, this.y); -}; - - -Node.prototype._resizeDatabase = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - var size = textSize.width + 2 * margin; - this.width = size; - this.height = size; - } -}; - -Node.prototype._drawDatabase = function (ctx) { - this._resizeDatabase(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; - ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.lineWidth = this.selected ? 2.0 : 1.0; - ctx.database(this.x - this.width/2, this.y - this.height*0.5, this.width, this.height); - ctx.fill(); - ctx.stroke(); - - this._label(ctx, this.label, this.x, this.y); -}; - - -Node.prototype._resizeCircle = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - var diameter = Math.max(textSize.width, textSize.height) + 2 * margin; - this.radius = diameter / 2; - - this.width = diameter; - this.height = diameter; - } -}; - -Node.prototype._drawCircle = function (ctx) { - this._resizeCircle(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; - ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.lineWidth = this.selected ? 2.0 : 1.0; - ctx.circle(this.x, this.y, this.radius); - ctx.fill(); - ctx.stroke(); - - this._label(ctx, this.label, this.x, this.y); -}; - -Node.prototype._resizeEllipse = function (ctx) { - if (!this.width) { - var textSize = this.getTextSize(ctx); - - this.width = textSize.width * 1.5; - this.height = textSize.height * 2; - if (this.width < this.height) { - this.width = this.height; - } - } -}; - -Node.prototype._drawEllipse = function (ctx) { - this._resizeEllipse(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; - ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.lineWidth = this.selected ? 2.0 : 1.0; - ctx.ellipse(this.left, this.top, this.width, this.height); - ctx.fill(); - ctx.stroke(); - - this._label(ctx, this.label, this.x, this.y); -}; - -Node.prototype._drawDot = function (ctx) { - this._drawShape(ctx, 'circle'); -}; - -Node.prototype._drawTriangle = function (ctx) { - this._drawShape(ctx, 'triangle'); -}; - -Node.prototype._drawTriangleDown = function (ctx) { - this._drawShape(ctx, 'triangleDown'); -}; - -Node.prototype._drawSquare = function (ctx) { - this._drawShape(ctx, 'square'); -}; - -Node.prototype._drawStar = function (ctx) { - this._drawShape(ctx, 'star'); -}; - -Node.prototype._resizeShape = function (ctx) { - if (!this.width) { - var size = 2 * this.radius; - this.width = size; - this.height = size; - } -}; - -Node.prototype._drawShape = function (ctx, shape) { - this._resizeShape(ctx); - - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - ctx.strokeStyle = this.selected ? this.color.highlight.border : this.color.border; - ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background; - ctx.lineWidth = this.selected ? 2.0 : 1.0; - - ctx[shape](this.x, this.y, this.radius); - ctx.fill(); - ctx.stroke(); - - if (this.label) { - this._label(ctx, this.label, this.x, this.y + this.height / 2, undefined, 'top'); - } -}; - -Node.prototype._resizeText = function (ctx) { - if (!this.width) { - var margin = 5; - var textSize = this.getTextSize(ctx); - this.width = textSize.width + 2 * margin; - this.height = textSize.height + 2 * margin; - } -}; - -Node.prototype._drawText = function (ctx) { - this._resizeText(ctx); - this.left = this.x - this.width / 2; - this.top = this.y - this.height / 2; - - this._label(ctx, this.label, this.x, this.y); -}; - - -Node.prototype._label = function (ctx, text, x, y, align, baseline) { - if (text) { - ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace; - ctx.fillStyle = this.fontColor || "black"; - ctx.textAlign = align || "center"; - ctx.textBaseline = baseline || "middle"; - - var lines = text.split('\n'), - lineCount = lines.length, - fontSize = (this.fontSize + 4), - yLine = y + (1 - lineCount) / 2 * fontSize; - - for (var i = 0; i < lineCount; i++) { - ctx.fillText(lines[i], x, yLine); - yLine += fontSize; - } - } -}; - - -Node.prototype.getTextSize = function(ctx) { - if (this.label != undefined) { - ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace; - - var lines = this.label.split('\n'), - height = (this.fontSize + 4) * lines.length, - width = 0; - - for (var i = 0, iMax = lines.length; i < iMax; i++) { - width = Math.max(width, ctx.measureText(lines[i]).width); - } - - return {"width": width, "height": height}; - } - else { - return {"width": 0, "height": 0}; - } -}; - -/** - * @class Edge - * - * A edge connects two nodes - * @param {Object} properties Object with properties. Must contain - * At least properties from and to. - * Available properties: from (number), - * to (number), label (string, color (string), - * width (number), style (string), - * length (number), title (string) - * @param {Graph} graph A graph object, used to find and edge to - * nodes. - * @param {Object} constants An object with default values for - * example for the color - */ -function Edge (properties, graph, constants) { - if (!graph) { - throw "No graph provided"; - } - this.graph = graph; - - // initialize constants - this.widthMin = constants.edges.widthMin; - this.widthMax = constants.edges.widthMax; - - // initialize variables - this.id = undefined; - this.fromId = undefined; - this.toId = undefined; - this.style = constants.edges.style; - this.title = undefined; - this.width = constants.edges.width; - this.value = undefined; - this.length = constants.edges.length; - - this.from = null; // a node - this.to = null; // a node - this.connected = false; - - // Added to support dashed lines - // David Jordan - // 2012-08-08 - this.dash = util.extend({}, constants.edges.dash); // contains properties length, gap, altLength - - this.stiffness = undefined; // depends on the length of the edge - this.color = constants.edges.color; - this.widthFixed = false; - this.lengthFixed = false; - - this.setProperties(properties, constants); -} - -/** - * Set or overwrite properties for the edge - * @param {Object} properties an object with properties - * @param {Object} constants and object with default, global properties - */ -Edge.prototype.setProperties = function(properties, constants) { - if (!properties) { - return; - } - - if (properties.from != undefined) {this.fromId = properties.from;} - if (properties.to != undefined) {this.toId = properties.to;} - - if (properties.id != undefined) {this.id = properties.id;} - if (properties.style != undefined) {this.style = properties.style;} - if (properties.label != undefined) {this.label = properties.label;} - if (this.label) { - this.fontSize = constants.edges.fontSize; - this.fontFace = constants.edges.fontFace; - this.fontColor = constants.edges.fontColor; - if (properties.fontColor != undefined) {this.fontColor = properties.fontColor;} - if (properties.fontSize != undefined) {this.fontSize = properties.fontSize;} - if (properties.fontFace != undefined) {this.fontFace = properties.fontFace;} - } - if (properties.title != undefined) {this.title = properties.title;} - if (properties.width != undefined) {this.width = properties.width;} - if (properties.value != undefined) {this.value = properties.value;} - if (properties.length != undefined) {this.length = properties.length;} - - // Added to support dashed lines - // David Jordan - // 2012-08-08 - if (properties.dash) { - if (properties.dash.length != undefined) {this.dash.length = properties.dash.length;} - if (properties.dash.gap != undefined) {this.dash.gap = properties.dash.gap;} - if (properties.dash.altLength != undefined) {this.dash.altLength = properties.dash.altLength;} - } - - if (properties.color != undefined) {this.color = properties.color;} - - // A node is connected when it has a from and to node. - this.connect(); - - this.widthFixed = this.widthFixed || (properties.width != undefined); - this.lengthFixed = this.lengthFixed || (properties.length != undefined); - this.stiffness = 1 / this.length; - - // set draw method based on style - switch (this.style) { - case 'line': this.draw = this._drawLine; break; - case 'arrow': this.draw = this._drawArrow; break; - case 'arrow-center': this.draw = this._drawArrowCenter; break; - case 'dash-line': this.draw = this._drawDashLine; break; - default: this.draw = this._drawLine; break; - } -}; - -/** - * Connect an edge to its nodes - */ -Edge.prototype.connect = function () { - this.disconnect(); - - this.from = this.graph.nodes[this.fromId] || null; - this.to = this.graph.nodes[this.toId] || null; - this.connected = (this.from && this.to); - - if (this.connected) { - this.from.attachEdge(this); - this.to.attachEdge(this); - } - else { - if (this.from) { - this.from.detachEdge(this); - } - if (this.to) { - this.to.detachEdge(this); - } - } -}; - -/** - * Disconnect an edge from its nodes - */ -Edge.prototype.disconnect = function () { - if (this.from) { - this.from.detachEdge(this); - this.from = null; - } - if (this.to) { - this.to.detachEdge(this); - this.to = null; - } - - this.connected = false; -}; - -/** - * get the title of this edge. - * @return {string} title The title of the edge, or undefined when no title - * has been set. - */ -Edge.prototype.getTitle = function() { - return this.title; -}; - - -/** - * Retrieve the value of the edge. Can be undefined - * @return {Number} value - */ -Edge.prototype.getValue = function() { - return this.value; -}; - -/** - * Adjust the value range of the edge. The edge will adjust it's width - * based on its value. - * @param {Number} min - * @param {Number} max - */ -Edge.prototype.setValueRange = function(min, max) { - if (!this.widthFixed && this.value !== undefined) { - var factor = (this.widthMax - this.widthMin) / (max - min); - this.width = (this.value - min) * factor + this.widthMin; - } -}; - -/** - * Redraw a edge - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - */ -Edge.prototype.draw = function(ctx) { - throw "Method draw not initialized in edge"; -}; - -/** - * Check if this object is overlapping with the provided object - * @param {Object} obj an object with parameters left, top - * @return {boolean} True if location is located on the edge - */ -Edge.prototype.isOverlappingWith = function(obj) { - var distMax = 10; - - var xFrom = this.from.x; - var yFrom = this.from.y; - var xTo = this.to.x; - var yTo = this.to.y; - var xObj = obj.left; - var yObj = obj.top; - - - var dist = Edge._dist(xFrom, yFrom, xTo, yTo, xObj, yObj); - - return (dist < distMax); -}; - - -/** - * Redraw a edge as a line - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Edge.prototype._drawLine = function(ctx) { - // set style - ctx.strokeStyle = this.color; - ctx.lineWidth = this._getLineWidth(); - - var point; - if (this.from != this.to) { - // draw line - this._line(ctx); - - // draw label - if (this.label) { - point = this._pointOnLine(0.5); - this._label(ctx, this.label, point.x, point.y); - } - } - else { - var x, y; - var radius = this.length / 4; - var node = this.from; - if (!node.width) { - node.resize(ctx); - } - if (node.width > node.height) { - x = node.x + node.width / 2; - y = node.y - radius; - } - else { - x = node.x + radius; - y = node.y - node.height / 2; - } - this._circle(ctx, x, y, radius); - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); - } -}; - -/** - * Get the line width of the edge. Depends on width and whether one of the - * connected nodes is selected. - * @return {Number} width - * @private - */ -Edge.prototype._getLineWidth = function() { - if (this.from.selected || this.to.selected) { - return Math.min(this.width * 2, this.widthMax); - } - else { - return this.width; - } -}; - -/** - * Draw a line between two nodes - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Edge.prototype._line = function (ctx) { - // draw a straight line - ctx.beginPath(); - ctx.moveTo(this.from.x, this.from.y); - ctx.lineTo(this.to.x, this.to.y); - ctx.stroke(); -}; - -/** - * Draw a line from a node to itself, a circle - * @param {CanvasRenderingContext2D} ctx - * @param {Number} x - * @param {Number} y - * @param {Number} radius - * @private - */ -Edge.prototype._circle = function (ctx, x, y, radius) { - // draw a circle - ctx.beginPath(); - ctx.arc(x, y, radius, 0, 2 * Math.PI, false); - ctx.stroke(); -}; - -/** - * Draw label with white background and with the middle at (x, y) - * @param {CanvasRenderingContext2D} ctx - * @param {String} text - * @param {Number} x - * @param {Number} y - * @private - */ -Edge.prototype._label = function (ctx, text, x, y) { - if (text) { - // TODO: cache the calculated size - ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") + - this.fontSize + "px " + this.fontFace; - ctx.fillStyle = 'white'; - var width = ctx.measureText(text).width; - var height = this.fontSize; - var left = x - width / 2; - var top = y - height / 2; - - ctx.fillRect(left, top, width, height); - - // draw text - ctx.fillStyle = this.fontColor || "black"; - ctx.textAlign = "left"; - ctx.textBaseline = "top"; - ctx.fillText(text, left, top); - } -}; - -/** - * Redraw a edge as a dashed line - * Draw this edge in the given canvas - * @author David Jordan - * @date 2012-08-08 - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Edge.prototype._drawDashLine = function(ctx) { - // set style - ctx.strokeStyle = this.color; - ctx.lineWidth = this._getLineWidth(); - - // draw dashed line - ctx.beginPath(); - ctx.lineCap = 'round'; - if (this.dash.altLength != undefined) //If an alt dash value has been set add to the array this value - { - ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, - [this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]); - } - else if (this.dash.length != undefined && this.dash.gap != undefined) //If a dash and gap value has been set add to the array this value - { - ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, - [this.dash.length,this.dash.gap]); - } - else //If all else fails draw a line - { - ctx.moveTo(this.from.x, this.from.y); - ctx.lineTo(this.to.x, this.to.y); - } - ctx.stroke(); - - // draw label - if (this.label) { - var point = this._pointOnLine(0.5); - this._label(ctx, this.label, point.x, point.y); - } -}; - -/** - * Get a point on a line - * @param {Number} percentage. Value between 0 (line start) and 1 (line end) - * @return {Object} point - * @private - */ -Edge.prototype._pointOnLine = function (percentage) { - return { - x: (1 - percentage) * this.from.x + percentage * this.to.x, - y: (1 - percentage) * this.from.y + percentage * this.to.y - } -}; - -/** - * Get a point on a circle - * @param {Number} x - * @param {Number} y - * @param {Number} radius - * @param {Number} percentage. Value between 0 (line start) and 1 (line end) - * @return {Object} point - * @private - */ -Edge.prototype._pointOnCircle = function (x, y, radius, percentage) { - var angle = (percentage - 3/8) * 2 * Math.PI; - return { - x: x + radius * Math.cos(angle), - y: y - radius * Math.sin(angle) - } -}; - -/** - * Redraw a edge as a line with an arrow halfway the line - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Edge.prototype._drawArrowCenter = function(ctx) { - var point; - // set style - ctx.strokeStyle = this.color; - ctx.fillStyle = this.color; - ctx.lineWidth = this._getLineWidth(); - - if (this.from != this.to) { - // draw line - this._line(ctx); - - // draw an arrow halfway the line - 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? - point = this._pointOnLine(0.5); - ctx.arrow(point.x, point.y, angle, length); - ctx.fill(); - ctx.stroke(); - - // draw label - if (this.label) { - point = this._pointOnLine(0.5); - this._label(ctx, this.label, point.x, point.y); - } - } - else { - // draw circle - var x, y; - var radius = this.length / 4; - var node = this.from; - if (!node.width) { - node.resize(ctx); - } - if (node.width > node.height) { - x = node.x + node.width / 2; - y = node.y - radius; - } - else { - x = node.x + radius; - y = node.y - node.height / 2; - } - this._circle(ctx, x, y, radius); - - // draw all arrows - var angle = 0.2 * Math.PI; - var length = 10 + 5 * this.width; // TODO: make customizable? - point = this._pointOnCircle(x, y, radius, 0.5); - ctx.arrow(point.x, point.y, angle, length); - ctx.fill(); - ctx.stroke(); - - // draw label - if (this.label) { - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); - } - } -}; - - - -/** - * Redraw a edge as a line with an arrow - * Draw this edge in the given canvas - * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d"); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Edge.prototype._drawArrow = function(ctx) { - // set style - ctx.strokeStyle = this.color; - ctx.fillStyle = this.color; - ctx.lineWidth = this._getLineWidth(); - - // draw line - var angle, length; - if (this.from != this.to) { - // calculate length and angle of the line - angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); - var dx = (this.to.x - this.from.x); - var dy = (this.to.y - this.from.y); - var lEdge = Math.sqrt(dx * dx + dy * dy); - - var lFrom = this.from.distanceToBorder(ctx, angle + Math.PI); - var pFrom = (lEdge - lFrom) / lEdge; - var xFrom = (pFrom) * this.from.x + (1 - pFrom) * this.to.x; - var yFrom = (pFrom) * this.from.y + (1 - pFrom) * this.to.y; - - var lTo = this.to.distanceToBorder(ctx, angle); - var pTo = (lEdge - lTo) / lEdge; - var xTo = (1 - pTo) * this.from.x + pTo * this.to.x; - var yTo = (1 - pTo) * this.from.y + pTo * this.to.y; - - ctx.beginPath(); - ctx.moveTo(xFrom, yFrom); - ctx.lineTo(xTo, yTo); - ctx.stroke(); - - // draw arrow at the end of the line - length = 10 + 5 * this.width; // TODO: make customizable? - ctx.arrow(xTo, yTo, angle, length); - ctx.fill(); - ctx.stroke(); - - // draw label - if (this.label) { - var point = this._pointOnLine(0.5); - this._label(ctx, this.label, point.x, point.y); - } - } - else { - // draw circle - var node = this.from; - var x, y, arrow; - var radius = this.length / 4; - if (!node.width) { - node.resize(ctx); - } - if (node.width > node.height) { - x = node.x + node.width / 2; - y = node.y - radius; - arrow = { - x: x, - y: node.y, - angle: 0.9 * Math.PI - }; - } - else { - x = node.x + radius; - y = node.y - node.height / 2; - arrow = { - x: node.x, - y: y, - angle: 0.6 * Math.PI - }; - } - ctx.beginPath(); - // TODO: do not draw a circle, but an arc - // TODO: similarly, for a line without arrows, draw to the border of the nodes instead of the center - ctx.arc(x, y, radius, 0, 2 * Math.PI, false); - ctx.stroke(); - - // draw all arrows - length = 10 + 5 * this.width; // TODO: make customizable? - ctx.arrow(arrow.x, arrow.y, arrow.angle, length); - ctx.fill(); - ctx.stroke(); - - // draw label - if (this.label) { - point = this._pointOnCircle(x, y, radius, 0.5); - this._label(ctx, this.label, point.x, point.y); - } - } -}; - - - -/** - * Calculate the distance between a point (x3,y3) and a line segment from - * (x1,y1) to (x2,y2). - * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment - * @param {number} x1 - * @param {number} y1 - * @param {number} x2 - * @param {number} y2 - * @param {number} x3 - * @param {number} y3 - * @private - */ -Edge._dist = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point - var px = x2-x1, - py = y2-y1, - something = px*px + py*py, - u = ((x3 - x1) * px + (y3 - y1) * py) / something; - - if (u > 1) { - u = 1; - } - else if (u < 0) { - u = 0; - } - - var x = x1 + u * px, - y = y1 + u * py, - dx = x - x3, - dy = y - y3; - - //# Note: If the actual distance does not matter, - //# if you only want to compare what this function - //# returns to other results of this function, you - //# can just return the squared distance instead - //# (i.e. remove the sqrt) to gain a little performance - - return Math.sqrt(dx*dx + dy*dy); -}; - -/** - * Popup is a class to create a popup window with some text - * @param {Element} container The container object. - * @param {Number} [x] - * @param {Number} [y] - * @param {String} [text] - */ -function Popup(container, x, y, text) { - if (container) { - this.container = container; - } - else { - this.container = document.body; - } - this.x = 0; - this.y = 0; - this.padding = 5; - - if (x !== undefined && y !== undefined ) { - this.setPosition(x, y); - } - if (text !== undefined) { - this.setText(text); - } - - // create the frame - this.frame = document.createElement("div"); - var style = this.frame.style; - style.position = "absolute"; - style.visibility = "hidden"; - style.border = "1px solid #666"; - style.color = "black"; - style.padding = this.padding + "px"; - style.backgroundColor = "#FFFFC6"; - style.borderRadius = "3px"; - style.MozBorderRadius = "3px"; - style.WebkitBorderRadius = "3px"; - style.boxShadow = "3px 3px 10px rgba(128, 128, 128, 0.5)"; - style.whiteSpace = "nowrap"; - this.container.appendChild(this.frame); -}; - -/** - * @param {number} x Horizontal position of the popup window - * @param {number} y Vertical position of the popup window - */ -Popup.prototype.setPosition = function(x, y) { - this.x = parseInt(x); - this.y = parseInt(y); -}; - -/** - * Set the text for the popup window. This can be HTML code - * @param {string} text - */ -Popup.prototype.setText = function(text) { - this.frame.innerHTML = text; -}; - -/** - * Show the popup window - * @param {boolean} show Optional. Show or hide the window - */ -Popup.prototype.show = function (show) { - if (show === undefined) { - show = true; - } - - if (show) { - var height = this.frame.clientHeight; - var width = this.frame.clientWidth; - var maxHeight = this.frame.parentNode.clientHeight; - var maxWidth = this.frame.parentNode.clientWidth; - - var top = (this.y - height); - if (top + height + this.padding > maxHeight) { - top = maxHeight - height - this.padding; - } - if (top < this.padding) { - top = this.padding; - } - - var left = this.x; - if (left + width + this.padding > maxWidth) { - left = maxWidth - width - this.padding; - } - if (left < this.padding) { - left = this.padding; - } - - this.frame.style.left = left + "px"; - this.frame.style.top = top + "px"; - this.frame.style.visibility = "visible"; - } - else { - this.hide(); - } -}; - -/** - * Hide the popup window - */ -Popup.prototype.hide = function () { - this.frame.style.visibility = "hidden"; -}; - -/** - * @class Groups - * This class can store groups and properties specific for groups. - */ -Groups = function () { - this.clear(); - this.defaultIndex = 0; -}; - - -/** - * default constants for group colors - */ -Groups.DEFAULT = [ - {border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}}, // blue - {border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}}, // yellow - {border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}}, // red - {border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}}, // green - {border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}}, // magenta - {border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}}, // purple - {border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}}, // orange - {border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}}, // darkblue - {border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}}, // pink - {border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}} // mint -]; - - -/** - * Clear all groups - */ -Groups.prototype.clear = function () { - this.groups = {}; - this.groups.length = function() - { - var i = 0; - for ( var p in this ) { - if (this.hasOwnProperty(p)) { - i++; - } - } - return i; - } -}; - - -/** - * get group properties of a groupname. If groupname is not found, a new group - * is added. - * @param {*} groupname Can be a number, string, Date, etc. - * @return {Object} group The created group, containing all group properties - */ -Groups.prototype.get = function (groupname) { - var group = this.groups[groupname]; - - if (group == undefined) { - // create new group - var index = this.defaultIndex % Groups.DEFAULT.length; - this.defaultIndex++; - group = {}; - group.color = Groups.DEFAULT[index]; - this.groups[groupname] = group; - } - - return group; -}; - -/** - * Add a custom group style - * @param {String} groupname - * @param {Object} style An object containing borderColor, - * backgroundColor, etc. - * @return {Object} group The created group object - */ -Groups.prototype.add = function (groupname, style) { - this.groups[groupname] = style; - if (style.color) { - style.color = Node.parseColor(style.color); - } - return style; -}; - -/** - * @class Images - * This class loads images and keeps them stored. - */ -Images = function () { - this.images = {}; - - this.callback = undefined; -}; - -/** - * Set an onload callback function. This will be called each time an image - * is loaded - * @param {function} callback - */ -Images.prototype.setOnloadCallback = function(callback) { - this.callback = callback; -}; - -/** - * - * @param {string} url Url of the image - * @return {Image} img The image object - */ -Images.prototype.load = function(url) { - var img = this.images[url]; - if (img == undefined) { - // create the image - var images = this; - img = new Image(); - this.images[url] = img; - img.onload = function() { - if (images.callback) { - images.callback(this); - } - }; - img.src = url; - } - - return img; -}; - -/** - * @constructor Graph - * Create a graph visualization, displaying nodes and edges. - * - * @param {Element} container The DOM element in which the Graph will - * be created. Normally a div element. - * @param {Object} data An object containing parameters - * {Array} nodes - * {Array} edges - * @param {Object} options Options - */ -function Graph (container, data, options) { - // create variables and set default values - this.containerElement = container; - this.width = '100%'; - this.height = '100%'; - this.refreshRate = 50; // milliseconds - this.stabilize = true; // stabilize before displaying the graph - this.selectable = true; - - // set constant values - this.constants = { - nodes: { - radiusMin: 5, - radiusMax: 20, - radius: 5, - distance: 100, // px - shape: 'ellipse', - image: undefined, - widthMin: 16, // px - widthMax: 64, // px - fontColor: 'black', - fontSize: 14, // px - //fontFace: verdana, - fontFace: 'arial', - color: { - border: '#2B7CE9', - background: '#97C2FC', - highlight: { - border: '#2B7CE9', - background: '#D2E5FF' - } - }, - borderColor: '#2B7CE9', - backgroundColor: '#97C2FC', - highlightColor: '#D2E5FF', - group: undefined - }, - edges: { - widthMin: 1, - widthMax: 15, - width: 1, - style: 'line', - color: '#343434', - fontColor: '#343434', - fontSize: 14, // px - fontFace: 'arial', - //distance: 100, //px - length: 100, // px - dash: { - length: 10, - gap: 5, - altLength: undefined - } - }, - minForce: 0.05, - minVelocity: 0.02, // px/s - maxIterations: 1000 // maximum number of iteration to stabilize - }; - - var graph = this; - this.nodes = {}; // object with Node objects - this.edges = {}; // object with Edge objects - // TODO: create a counter to keep track on the number of nodes having values - // TODO: create a counter to keep track on the number of nodes currently moving - // TODO: create a counter to keep track on the number of edges having values - - this.nodesData = null; // A DataSet or DataView - this.edgesData = null; // A DataSet or DataView - - // create event listeners used to subscribe on the DataSets of the nodes and edges - var me = this; - this.nodesListeners = { - 'add': function (event, params) { - me._addNodes(params.items); - me.start(); - }, - 'update': function (event, params) { - me._updateNodes(params.items); - me.start(); - }, - 'remove': function (event, params) { - me._removeNodes(params.items); - me.start(); - } - }; - this.edgesListeners = { - 'add': function (event, params) { - me._addEdges(params.items); - me.start(); - }, - 'update': function (event, params) { - me._updateEdges(params.items); - me.start(); - }, - 'remove': function (event, params) { - me._removeEdges(params.items); - me.start(); - } - }; - - this.groups = new Groups(); // object with groups - this.images = new Images(); // object with images - this.images.setOnloadCallback(function () { - graph._redraw(); - }); - - // properties of the data - this.moving = false; // True if any of the nodes have an undefined position - - this.selection = []; - this.timer = undefined; - - // create a frame and canvas - this._create(); - - // apply options - this.setOptions(options); - - // draw data - this.setData(data); -} - -/** - * Set nodes and edges, and optionally options as well. - * - * @param {Object} data Object containing parameters: - * {Array | DataSet | DataView} [nodes] Array with nodes - * {Array | DataSet | DataView} [edges] Array with edges - * {String} [dot] String containing data in DOT format - * {Options} [options] Object with options - */ -Graph.prototype.setData = function(data) { - if (data && data.dot && (data.nodes || data.edges)) { - throw new SyntaxError('Data must contain either parameter "dot" or ' + - ' parameter pair "nodes" and "edges", but not both.'); - } - - // set options - this.setOptions(data && data.options); - - // set all data - if (data && data.dot) { - // parse DOT file - if(data && data.dot) { - var dotData = vis.util.DOTToGraph(data.dot); - this.setData(dotData); - return; - } - } - else { - this._setNodes(data && data.nodes); - this._setEdges(data && data.edges); - } - - // find a stable position or start animating to a stable position - if (this.stabilize) { - this._doStabilize(); - } - this.start(); -}; - -/** - * Set options - * @param {Object} options - */ -Graph.prototype.setOptions = function (options) { - if (options) { - // retrieve parameter values - if (options.width != undefined) {this.width = options.width;} - if (options.height != undefined) {this.height = options.height;} - if (options.stabilize != undefined) {this.stabilize = options.stabilize;} - if (options.selectable != undefined) {this.selectable = options.selectable;} - - // TODO: work out these options and document them - if (options.edges) { - for (var prop in options.edges) { - if (options.edges.hasOwnProperty(prop)) { - this.constants.edges[prop] = options.edges[prop]; - } - } - - if (options.edges.length != undefined && - options.nodes && options.nodes.distance == undefined) { - this.constants.edges.length = options.edges.length; - this.constants.nodes.distance = options.edges.length * 1.25; - } - - if (!options.edges.fontColor) { - this.constants.edges.fontColor = options.edges.color; - } - - // Added to support dashed lines - // David Jordan - // 2012-08-08 - if (options.edges.dash) { - if (options.edges.dash.length != undefined) { - this.constants.edges.dash.length = options.edges.dash.length; - } - if (options.edges.dash.gap != undefined) { - this.constants.edges.dash.gap = options.edges.dash.gap; - } - if (options.edges.dash.altLength != undefined) { - this.constants.edges.dash.altLength = options.edges.dash.altLength; - } - } - } - - if (options.nodes) { - for (prop in options.nodes) { - if (options.nodes.hasOwnProperty(prop)) { - this.constants.nodes[prop] = options.nodes[prop]; - } - } - - if (options.nodes.color) { - this.constants.nodes.color = Node.parseColor(options.nodes.color); - } - - /* - if (options.nodes.widthMin) this.constants.nodes.radiusMin = options.nodes.widthMin; - if (options.nodes.widthMax) this.constants.nodes.radiusMax = options.nodes.widthMax; - */ - } - - if (options.groups) { - for (var groupname in options.groups) { - if (options.groups.hasOwnProperty(groupname)) { - var group = options.groups[groupname]; - this.groups.add(groupname, group); - } - } - } - } - - this.setSize(this.width, this.height); - this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2); - this._setScale(1); -}; - -/** - * fire an event - * @param {String} event The name of an event, for example 'select' - * @param {Object} params Optional object with event parameters - * @private - */ -Graph.prototype._trigger = function (event, params) { - events.trigger(this, event, params); -}; - - -/** - * Create the main frame for the Graph. - * This function is executed once when a Graph object is created. The frame - * contains a canvas, and this canvas contains all objects like the axis and - * nodes. - * @private - */ -Graph.prototype._create = function () { - // remove all elements from the container element. - while (this.containerElement.hasChildNodes()) { - this.containerElement.removeChild(this.containerElement.firstChild); - } - - this.frame = document.createElement('div'); - this.frame.className = 'graph-frame'; - this.frame.style.position = 'relative'; - this.frame.style.overflow = 'hidden'; - - // create the graph canvas (HTML canvas element) - this.frame.canvas = document.createElement( 'canvas' ); - this.frame.canvas.style.position = 'relative'; - this.frame.appendChild(this.frame.canvas); - if (!this.frame.canvas.getContext) { - var noCanvas = document.createElement( 'DIV' ); - noCanvas.style.color = 'red'; - noCanvas.style.fontWeight = 'bold' ; - noCanvas.style.padding = '10px'; - noCanvas.innerHTML = 'Error: your browser does not support HTML canvas'; - this.frame.canvas.appendChild(noCanvas); - } - - var me = this; - this.drag = {}; - this.pinch = {}; - this.hammer = Hammer(this.frame.canvas, { - prevent_default: true - }); - this.hammer.on('tap', me._onTap.bind(me) ); - this.hammer.on('hold', me._onHold.bind(me) ); - this.hammer.on('pinch', me._onPinch.bind(me) ); - this.hammer.on('touch', me._onTouch.bind(me) ); - this.hammer.on('dragstart', me._onDragStart.bind(me) ); - this.hammer.on('drag', me._onDrag.bind(me) ); - this.hammer.on('dragend', me._onDragEnd.bind(me) ); - this.hammer.on('mousewheel',me._onMouseWheel.bind(me) ); - this.hammer.on('mousemove', me._onMouseMoveTitle.bind(me) ); - - // add the frame to the container element - this.containerElement.appendChild(this.frame); -}; - -/** - * - * @param {{x: Number, y: Number}} pointer - * @return {Number | null} node - * @private - */ -Graph.prototype._getNodeAt = function (pointer) { - var x = this._canvasToX(pointer.x); - var y = this._canvasToY(pointer.y); - - var obj = { - left: x, - top: y, - right: x, - bottom: y - }; - - // if there are overlapping nodes, select the last one, this is the - // one which is drawn on top of the others - var overlappingNodes = this._getNodesOverlappingWith(obj); - return (overlappingNodes.length > 0) ? - overlappingNodes[overlappingNodes.length - 1] : null; -}; - -/** - * Get the pointer location from a touch location - * @param {{pageX: Number, pageY: Number}} touch - * @return {{x: Number, y: Number}} pointer - * @private - */ -Graph.prototype._getPointer = function (touch) { - return { - x: touch.pageX - vis.util.getAbsoluteLeft(this.frame.canvas), - y: touch.pageY - vis.util.getAbsoluteTop(this.frame.canvas) - }; -}; - -/** - * On start of a touch gesture, store the pointer - * @param event - * @private - */ -Graph.prototype._onTouch = function (event) { - this.drag.pointer = this._getPointer(event.gesture.touches[0]); - this.drag.pinched = false; - this.pinch.scale = this._getScale(); -}; - -/** - * handle drag start event - * @private - */ -Graph.prototype._onDragStart = function () { - var drag = this.drag; - - drag.selection = []; - drag.translation = this._getTranslation(); - drag.nodeId = this._getNodeAt(drag.pointer); - // note: drag.pointer is set in _onTouch to get the initial touch location - - var node = this.nodes[drag.nodeId]; - if (node) { - // select the clicked node if not yet selected - if (!node.isSelected()) { - this._selectNodes([drag.nodeId]); - } - - // create an array with the selected nodes and their original location and status - var me = this; - this.selection.forEach(function (id) { - var node = me.nodes[id]; - if (node) { - var s = { - id: id, - node: node, - - // store original x, y, xFixed and yFixed, make the node temporarily Fixed - x: node.x, - y: node.y, - xFixed: node.xFixed, - yFixed: node.yFixed - }; - - node.xFixed = true; - node.yFixed = true; - - drag.selection.push(s); - } - }); - - } -}; - -/** - * handle drag event - * @private - */ -Graph.prototype._onDrag = function (event) { - if (this.drag.pinched) { - return; - } - - var pointer = this._getPointer(event.gesture.touches[0]); - - var me = this, - drag = this.drag, - selection = drag.selection; - if (selection && selection.length) { - // calculate delta's and new location - var deltaX = pointer.x - drag.pointer.x, - deltaY = pointer.y - drag.pointer.y; - - // update position of all selected nodes - selection.forEach(function (s) { - var node = s.node; - - if (!s.xFixed) { - node.x = me._canvasToX(me._xToCanvas(s.x) + deltaX); - } - - if (!s.yFixed) { - node.y = me._canvasToY(me._yToCanvas(s.y) + deltaY); - } - }); - - // start animation if not yet running - if (!this.moving) { - this.moving = true; - this.start(); - } - } - else { - // move the graph - var diffX = pointer.x - this.drag.pointer.x; - var diffY = pointer.y - this.drag.pointer.y; - - this._setTranslation( - this.drag.translation.x + diffX, - this.drag.translation.y + diffY); - this._redraw(); - - this.moved = true; - } -}; - -/** - * handle drag start event - * @private - */ -Graph.prototype._onDragEnd = function () { - var selection = this.drag.selection; - if (selection) { - selection.forEach(function (s) { - // restore original xFixed and yFixed - s.node.xFixed = s.xFixed; - s.node.yFixed = s.yFixed; - }); - } -}; - -/** - * handle tap/click event: select/unselect a node - * @private - */ -Graph.prototype._onTap = function (event) { - var pointer = this._getPointer(event.gesture.touches[0]); - - var nodeId = this._getNodeAt(pointer); - var node = this.nodes[nodeId]; - if (node) { - // select this node - this._selectNodes([nodeId]); - - if (!this.moving) { - this._redraw(); - } - } - else { - // remove selection - this._unselectNodes(); - this._redraw(); - } -}; - -/** - * handle long tap event: multi select nodes - * @private - */ -Graph.prototype._onHold = function (event) { - var pointer = this._getPointer(event.gesture.touches[0]); - var nodeId = this._getNodeAt(pointer); - var node = this.nodes[nodeId]; - if (node) { - if (!node.isSelected()) { - // select this node, keep previous selection - var append = true; - this._selectNodes([nodeId], append); - } - else { - this._unselectNodes([nodeId]); - } - - if (!this.moving) { - this._redraw(); - } - } - else { - // Do nothing - } -}; - -/** - * Handle pinch event - * @param event - * @private - */ -Graph.prototype._onPinch = function (event) { - var pointer = this._getPointer(event.gesture.center); - - this.drag.pinched = true; - if (!('scale' in this.pinch)) { - this.pinch.scale = 1; - } - - // TODO: enable moving while pinching? - var scale = this.pinch.scale * event.gesture.scale; - this._zoom(scale, pointer) -}; - -/** - * Zoom the graph in or out - * @param {Number} scale a number around 1, and between 0.01 and 10 - * @param {{x: Number, y: Number}} pointer - * @return {Number} appliedScale scale is limited within the boundaries - * @private - */ -Graph.prototype._zoom = function(scale, pointer) { - var scaleOld = this._getScale(); - if (scale < 0.01) { - scale = 0.01; - } - if (scale > 10) { - scale = 10; - } - - var translation = this._getTranslation(); - var scaleFrac = scale / scaleOld; - var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac; - var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac; - - this._setScale(scale); - this._setTranslation(tx, ty); - this._redraw(); - - return scale; -}; - -/** - * Event handler for mouse wheel event, used to zoom the timeline - * See http://adomas.org/javascript-mouse-wheel/ - * https://github.com/EightMedia/hammer.js/issues/256 - * @param {MouseEvent} event - * @private - */ -Graph.prototype._onMouseWheel = function(event) { - // retrieve delta - var delta = 0; - if (event.wheelDelta) { /* IE/Opera. */ - delta = event.wheelDelta/120; - } else if (event.detail) { /* Mozilla case. */ - // In Mozilla, sign of delta is different than in IE. - // Also, delta is multiple of 3. - delta = -event.detail/3; - } - - // If delta is nonzero, handle it. - // Basically, delta is now positive if wheel was scrolled up, - // and negative, if wheel was scrolled down. - if (delta) { - if (!('mouswheelScale' in this.pinch)) { - this.pinch.mouswheelScale = 1; - } - - // calculate the new scale - var scale = this.pinch.mouswheelScale; - var zoom = delta / 10; - if (delta < 0) { - zoom = zoom / (1 - zoom); - } - scale *= (1 + zoom); - - // calculate the pointer location - var gesture = Hammer.event.collectEventData(this, 'scroll', event); - var pointer = this._getPointer(gesture.center); - - // apply the new scale - scale = this._zoom(scale, pointer); - - // store the new, applied scale - this.pinch.mouswheelScale = scale; - } - - // Prevent default actions caused by mouse wheel. - event.preventDefault(); -}; - - -/** - * Mouse move handler for checking whether the title moves over a node with a title. - * @param {Event} event - * @private - */ -Graph.prototype._onMouseMoveTitle = function (event) { - var gesture = Hammer.event.collectEventData(this, 'mousemove', event); - var pointer = this._getPointer(gesture.center); - - // check if the previously selected node is still selected - if (this.popupNode) { - this._checkHidePopup(pointer); - } - - // start a timeout that will check if the mouse is positioned above - // an element - var me = this; - var checkShow = function() { - me._checkShowPopup(pointer); - }; - if (this.popupTimer) { - clearInterval(this.popupTimer); // stop any running timer - } - if (!this.leftButtonDown) { - this.popupTimer = setTimeout(checkShow, 300); - } -}; - -/** - * Check if there is an element on the given position in the graph - * (a node or edge). If so, and if this element has a title, - * show a popup window with its title. - * - * @param {{x:Number, y:Number}} pointer - * @private - */ -Graph.prototype._checkShowPopup = function (pointer) { - var obj = { - left: this._canvasToX(pointer.x), - top: this._canvasToY(pointer.y), - right: this._canvasToX(pointer.x), - bottom: this._canvasToY(pointer.y) - }; - - var id; - var lastPopupNode = this.popupNode; - - if (this.popupNode == undefined) { - // search the nodes for overlap, select the top one in case of multiple nodes - var nodes = this.nodes; - for (id in nodes) { - if (nodes.hasOwnProperty(id)) { - var node = nodes[id]; - if (node.getTitle() != undefined && node.isOverlappingWith(obj)) { - this.popupNode = node; - break; - } - } - } - } - - if (this.popupNode == undefined) { - // search the edges for overlap - var edges = this.edges; - for (id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - if (edge.connected && (edge.getTitle() != undefined) && - edge.isOverlappingWith(obj)) { - this.popupNode = edge; - break; - } - } - } - } - - if (this.popupNode) { - // show popup message window - if (this.popupNode != lastPopupNode) { - var me = this; - if (!me.popup) { - me.popup = new Popup(me.frame); - } - - // adjust a small offset such that the mouse cursor is located in the - // bottom left location of the popup, and you can easily move over the - // popup area - me.popup.setPosition(pointer.x - 3, pointer.y - 3); - me.popup.setText(me.popupNode.getTitle()); - me.popup.show(); - } - } - else { - if (this.popup) { - this.popup.hide(); - } - } -}; - -/** - * Check if the popup must be hided, which is the case when the mouse is no - * longer hovering on the object - * @param {{x:Number, y:Number}} pointer - * @private - */ -Graph.prototype._checkHidePopup = function (pointer) { - if (!this.popupNode || !this._getNodeAt(pointer) ) { - this.popupNode = undefined; - if (this.popup) { - this.popup.hide(); - } - } -}; - -/** - * Unselect selected nodes. If no selection array is provided, all nodes - * are unselected - * @param {Object[]} selection Array with selection objects, each selection - * object has a parameter row. Optional - * @param {Boolean} triggerSelect If true (default), the select event - * is triggered when nodes are unselected - * @return {Boolean} changed True if the selection is changed - * @private - */ -Graph.prototype._unselectNodes = function(selection, triggerSelect) { - var changed = false; - var i, iMax, id; - - if (selection) { - // remove provided selections - for (i = 0, iMax = selection.length; i < iMax; i++) { - id = selection[i]; - this.nodes[id].unselect(); - - var j = 0; - while (j < this.selection.length) { - if (this.selection[j] == id) { - this.selection.splice(j, 1); - changed = true; - } - else { - j++; - } - } - } - } - else if (this.selection && this.selection.length) { - // remove all selections - for (i = 0, iMax = this.selection.length; i < iMax; i++) { - id = this.selection[i]; - this.nodes[id].unselect(); - changed = true; - } - this.selection = []; - } - - if (changed && (triggerSelect == true || triggerSelect == undefined)) { - // fire the select event - this._trigger('select'); - } - - return changed; -}; - -/** - * select all nodes on given location x, y - * @param {Array} selection an array with node ids - * @param {boolean} append If true, the new selection will be appended to the - * current selection (except for duplicate entries) - * @return {Boolean} changed True if the selection is changed - * @private - */ -Graph.prototype._selectNodes = function(selection, append) { - var changed = false; - var i, iMax; - - // TODO: the selectNodes method is a little messy, rework this - - // check if the current selection equals the desired selection - var selectionAlreadyThere = true; - if (selection.length != this.selection.length) { - selectionAlreadyThere = false; - } - else { - for (i = 0, iMax = Math.min(selection.length, this.selection.length); i < iMax; i++) { - if (selection[i] != this.selection[i]) { - selectionAlreadyThere = false; - break; - } - } - } - if (selectionAlreadyThere) { - return changed; - } - - if (append == undefined || append == false) { - // first deselect any selected node - var triggerSelect = false; - changed = this._unselectNodes(undefined, triggerSelect); - } - - for (i = 0, iMax = selection.length; i < iMax; i++) { - // add each of the new selections, but only when they are not duplicate - var id = selection[i]; - var isDuplicate = (this.selection.indexOf(id) != -1); - if (!isDuplicate) { - this.nodes[id].select(); - this.selection.push(id); - changed = true; - } - } - - if (changed) { - // fire the select event - this._trigger('select'); - } - - return changed; -}; - -/** - * retrieve all nodes overlapping with given object - * @param {Object} obj An object with parameters left, top, right, bottom - * @return {Number[]} An array with id's of the overlapping nodes - * @private - */ -Graph.prototype._getNodesOverlappingWith = function (obj) { - var nodes = this.nodes, - overlappingNodes = []; - - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - if (nodes[id].isOverlappingWith(obj)) { - overlappingNodes.push(id); - } - } - } - - return overlappingNodes; -}; - -/** - * retrieve the currently selected nodes - * @return {Number[] | String[]} selection An array with the ids of the - * selected nodes. - */ -Graph.prototype.getSelection = function() { - return this.selection.concat([]); -}; - -/** - * select zero or more nodes - * @param {Number[] | String[]} selection An array with the ids of the - * selected nodes. - */ -Graph.prototype.setSelection = function(selection) { - var i, iMax, id; - - if (!selection || (selection.length == undefined)) - throw 'Selection must be an array with ids'; - - // first unselect any selected node - for (i = 0, iMax = this.selection.length; i < iMax; i++) { - id = this.selection[i]; - this.nodes[id].unselect(); - } - - this.selection = []; - - for (i = 0, iMax = selection.length; i < iMax; i++) { - id = selection[i]; - - var node = this.nodes[id]; - if (!node) { - throw new RangeError('Node with id "' + id + '" not found'); - } - node.select(); - this.selection.push(id); - } - - this.redraw(); -}; - -/** - * Validate the selection: remove ids of nodes which no longer exist - * @private - */ -Graph.prototype._updateSelection = function () { - var i = 0; - while (i < this.selection.length) { - var id = this.selection[i]; - if (!this.nodes[id]) { - this.selection.splice(i, 1); - } - else { - i++; - } - } -}; - -/** - * Temporary method to test calculating a hub value for the nodes - * @param {number} level Maximum number edges between two nodes in order - * to call them connected. Optional, 1 by default - * @return {Number[]} connectioncount array with the connection count - * for each node - * @private - */ -Graph.prototype._getConnectionCount = function(level) { - if (level == undefined) { - level = 1; - } - - // get the nodes connected to given nodes - function getConnectedNodes(nodes) { - var connectedNodes = []; - - for (var j = 0, jMax = nodes.length; j < jMax; j++) { - var node = nodes[j]; - - // find all nodes connected to this node - var edges = node.edges; - for (var i = 0, iMax = edges.length; i < iMax; i++) { - var edge = edges[i]; - var other = null; - - // check if connected - if (edge.from == node) - other = edge.to; - else if (edge.to == node) - other = edge.from; - - // check if the other node is not already in the list with nodes - var k, kMax; - if (other) { - for (k = 0, kMax = nodes.length; k < kMax; k++) { - if (nodes[k] == other) { - other = null; - break; - } - } - } - if (other) { - for (k = 0, kMax = connectedNodes.length; k < kMax; k++) { - if (connectedNodes[k] == other) { - other = null; - break; - } - } - } - - if (other) - connectedNodes.push(other); - } - } - - return connectedNodes; - } - - var connections = []; - var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - var c = [nodes[id]]; - for (var l = 0; l < level; l++) { - c = c.concat(getConnectedNodes(c)); - } - connections.push(c); - } - } - - var hubs = []; - for (var i = 0, len = connections.length; i < len; i++) { - hubs.push(connections[i].length); - } - - return hubs; -}; - - -/** - * Set a new size for the graph - * @param {string} width Width in pixels or percentage (for example '800px' - * or '50%') - * @param {string} height Height in pixels or percentage (for example '400px' - * or '30%') - */ -Graph.prototype.setSize = function(width, height) { - this.frame.style.width = width; - this.frame.style.height = height; - - 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; -}; - -/** - * Set a data set with nodes for the graph - * @param {Array | DataSet | DataView} nodes The data containing the nodes. - * @private - */ -Graph.prototype._setNodes = function(nodes) { - var oldNodesData = this.nodesData; - - if (nodes instanceof DataSet || nodes instanceof DataView) { - this.nodesData = nodes; - } - else if (nodes instanceof Array) { - this.nodesData = new DataSet(); - this.nodesData.add(nodes); - } - else if (!nodes) { - this.nodesData = new DataSet(); - } - else { - throw new TypeError('Array or DataSet expected'); - } - - if (oldNodesData) { - // unsubscribe from old dataset - util.forEach(this.nodesListeners, function (callback, event) { - oldNodesData.unsubscribe(event, callback); - }); - } - - // remove drawn nodes - this.nodes = {}; - - if (this.nodesData) { - // subscribe to new dataset - var me = this; - util.forEach(this.nodesListeners, function (callback, event) { - me.nodesData.subscribe(event, callback); - }); - - // draw all new nodes - var ids = this.nodesData.getIds(); - this._addNodes(ids); - } - - this._updateSelection(); -}; - -/** - * Add nodes - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._addNodes = function(ids) { - var id; - for (var i = 0, len = ids.length; i < len; i++) { - id = ids[i]; - var data = this.nodesData.get(id); - var node = new Node(data, this.images, this.groups, this.constants); - this.nodes[id] = node; // note: this may replace an existing node - - if (!node.isFixed()) { - // TODO: position new nodes in a smarter way! - var radius = this.constants.edges.length * 2; - var count = ids.length; - var angle = 2 * Math.PI * (i / count); - node.x = radius * Math.cos(angle); - node.y = radius * Math.sin(angle); - - // note: no not use node.isMoving() here, as that gives the current - // velocity of the node, which is zero after creation of the node. - this.moving = true; - } - } - - this._reconnectEdges(); - this._updateValueRange(this.nodes); -}; - -/** - * Update existing nodes, or create them when not yet existing - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._updateNodes = function(ids) { - var nodes = this.nodes, - nodesData = this.nodesData; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - var node = nodes[id]; - var data = nodesData.get(id); - if (node) { - // update node - node.setProperties(data, this.constants); - } - else { - // create node - node = new Node(properties, this.images, this.groups, this.constants); - nodes[id] = node; - - if (!node.isFixed()) { - this.moving = true; - } - } - } - - this._reconnectEdges(); - this._updateValueRange(nodes); -}; - -/** - * Remove existing nodes. If nodes do not exist, the method will just ignore it. - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._removeNodes = function(ids) { - var nodes = this.nodes; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - delete nodes[id]; - } - - this._reconnectEdges(); - this._updateSelection(); - this._updateValueRange(nodes); -}; - -/** - * Load edges by reading the data table - * @param {Array | DataSet | DataView} edges The data containing the edges. - * @private - * @private - */ -Graph.prototype._setEdges = function(edges) { - var oldEdgesData = this.edgesData; - - if (edges instanceof DataSet || edges instanceof DataView) { - this.edgesData = edges; - } - else if (edges instanceof Array) { - this.edgesData = new DataSet(); - this.edgesData.add(edges); - } - else if (!edges) { - this.edgesData = new DataSet(); - } - else { - throw new TypeError('Array or DataSet expected'); - } - - if (oldEdgesData) { - // unsubscribe from old dataset - util.forEach(this.edgesListeners, function (callback, event) { - oldEdgesData.unsubscribe(event, callback); - }); - } - - // remove drawn edges - this.edges = {}; - - if (this.edgesData) { - // subscribe to new dataset - var me = this; - util.forEach(this.edgesListeners, function (callback, event) { - me.edgesData.subscribe(event, callback); - }); - - // draw all new nodes - var ids = this.edgesData.getIds(); - this._addEdges(ids); - } - - this._reconnectEdges(); -}; - -/** - * Add edges - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._addEdges = function (ids) { - var edges = this.edges, - edgesData = this.edgesData; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - - var oldEdge = edges[id]; - if (oldEdge) { - oldEdge.disconnect(); - } - - var data = edgesData.get(id); - edges[id] = new Edge(data, this, this.constants); - } - - this.moving = true; - this._updateValueRange(edges); -}; - -/** - * Update existing edges, or create them when not yet existing - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._updateEdges = function (ids) { - var edges = this.edges, - edgesData = this.edgesData; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - - var data = edgesData.get(id); - var edge = edges[id]; - if (edge) { - // update edge - edge.disconnect(); - edge.setProperties(data, this.constants); - edge.connect(); - } - else { - // create edge - edge = new Edge(data, this, this.constants); - this.edges[id] = edge; - } - } - - this.moving = true; - this._updateValueRange(edges); -}; - -/** - * Remove existing edges. Non existing ids will be ignored - * @param {Number[] | String[]} ids - * @private - */ -Graph.prototype._removeEdges = function (ids) { - var edges = this.edges; - for (var i = 0, len = ids.length; i < len; i++) { - var id = ids[i]; - var edge = edges[id]; - if (edge) { - edge.disconnect(); - delete edges[id]; - } - } - - this.moving = true; - this._updateValueRange(edges); -}; - -/** - * Reconnect all edges - * @private - */ -Graph.prototype._reconnectEdges = function() { - var id, - nodes = this.nodes, - edges = this.edges; - for (id in nodes) { - if (nodes.hasOwnProperty(id)) { - nodes[id].edges = []; - } - } - - for (id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - edge.from = null; - edge.to = null; - edge.connect(); - } - } -}; - -/** - * Update the values of all object in the given array according to the current - * value range of the objects in the array. - * @param {Object} obj An object containing a set of Edges or Nodes - * The objects must have a method getValue() and - * setValueRange(min, max). - * @private - */ -Graph.prototype._updateValueRange = function(obj) { - var id; - - // determine the range of the objects - var valueMin = undefined; - var valueMax = undefined; - for (id in obj) { - if (obj.hasOwnProperty(id)) { - var value = obj[id].getValue(); - if (value !== undefined) { - valueMin = (valueMin === undefined) ? value : Math.min(value, valueMin); - valueMax = (valueMax === undefined) ? value : Math.max(value, valueMax); - } - } - } - - // adjust the range of all objects - if (valueMin !== undefined && valueMax !== undefined) { - for (id in obj) { - if (obj.hasOwnProperty(id)) { - obj[id].setValueRange(valueMin, valueMax); - } - } - } -}; - -/** - * Redraw the graph with the current data - * chart will be resized too. - */ -Graph.prototype.redraw = function() { - this.setSize(this.width, this.height); - - this._redraw(); -}; - -/** - * Redraw the graph with the current data - * @private - */ -Graph.prototype._redraw = function() { - var ctx = this.frame.canvas.getContext('2d'); - - // clear the canvas - var w = this.frame.canvas.width; - var h = this.frame.canvas.height; - ctx.clearRect(0, 0, w, h); - - // set scaling and translation - ctx.save(); - ctx.translate(this.translation.x, this.translation.y); - ctx.scale(this.scale, this.scale); - - this._drawEdges(ctx); - this._drawNodes(ctx); - - // restore original scaling and translation - ctx.restore(); -}; - -/** - * Set the translation of the graph - * @param {Number} offsetX Horizontal offset - * @param {Number} offsetY Vertical offset - * @private - */ -Graph.prototype._setTranslation = function(offsetX, offsetY) { - if (this.translation === undefined) { - this.translation = { - x: 0, - y: 0 - }; - } - - if (offsetX !== undefined) { - this.translation.x = offsetX; - } - if (offsetY !== undefined) { - this.translation.y = offsetY; - } -}; - -/** - * Get the translation of the graph - * @return {Object} translation An object with parameters x and y, both a number - * @private - */ -Graph.prototype._getTranslation = function() { - return { - x: this.translation.x, - y: this.translation.y - }; -}; - -/** - * Scale the graph - * @param {Number} scale Scaling factor 1.0 is unscaled - * @private - */ -Graph.prototype._setScale = function(scale) { - this.scale = scale; -}; -/** - * Get the current scale of the graph - * @return {Number} scale Scaling factor 1.0 is unscaled - * @private - */ -Graph.prototype._getScale = function() { - return this.scale; -}; - -/** - * Convert a horizontal point on the HTML canvas to the x-value of the model - * @param {number} x - * @returns {number} - * @private - */ -Graph.prototype._canvasToX = function(x) { - return (x - this.translation.x) / this.scale; -}; - -/** - * Convert an x-value in the model to a horizontal point on the HTML canvas - * @param {number} x - * @returns {number} - * @private - */ -Graph.prototype._xToCanvas = function(x) { - return x * this.scale + this.translation.x; -}; - -/** - * Convert a vertical point on the HTML canvas to the y-value of the model - * @param {number} y - * @returns {number} - * @private - */ -Graph.prototype._canvasToY = function(y) { - return (y - this.translation.y) / this.scale; -}; - -/** - * Convert an y-value in the model to a vertical point on the HTML canvas - * @param {number} y - * @returns {number} - * @private - */ -Graph.prototype._yToCanvas = function(y) { - return y * this.scale + this.translation.y ; -}; - -/** - * Redraw all nodes - * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Graph.prototype._drawNodes = function(ctx) { - // first draw the unselected nodes - var nodes = this.nodes; - var selected = []; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - if (nodes[id].isSelected()) { - selected.push(id); - } - else { - nodes[id].draw(ctx); - } - } - } - - // draw the selected nodes on top - for (var s = 0, sMax = selected.length; s < sMax; s++) { - nodes[selected[s]].draw(ctx); - } -}; - -/** - * Redraw all edges - * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d'); - * @param {CanvasRenderingContext2D} ctx - * @private - */ -Graph.prototype._drawEdges = function(ctx) { - var edges = this.edges; - for (var id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - if (edge.connected) { - edges[id].draw(ctx); - } - } - } -}; - -/** - * Find a stable position for all nodes - * @private - */ -Graph.prototype._doStabilize = function() { - var start = new Date(); - - // find stable position - var count = 0; - var vmin = this.constants.minVelocity; - var stable = false; - while (!stable && count < this.constants.maxIterations) { - this._calculateForces(); - this._discreteStepNodes(); - stable = !this._isMoving(vmin); - count++; - } - - var end = new Date(); - - // console.log('Stabilized in ' + (end-start) + ' ms, ' + count + ' iterations' ); // TODO: cleanup -}; - -/** - * Calculate the external forces acting on the nodes - * Forces are caused by: edges, repulsing forces between nodes, gravity - * @private - */ -Graph.prototype._calculateForces = function() { - // create a local edge to the nodes and edges, that is faster - var id, dx, dy, angle, distance, fx, fy, - repulsingForce, springForce, length, edgeLength, - nodes = this.nodes, - edges = this.edges; - - // gravity, add a small constant force to pull the nodes towards the center of - // the graph - // Also, the forces are reset to zero in this loop by using _setForce instead - // of _addForce - var gravity = 0.01, - gx = this.frame.canvas.clientWidth / 2, - gy = this.frame.canvas.clientHeight / 2; - for (id in nodes) { - if (nodes.hasOwnProperty(id)) { - var node = nodes[id]; - dx = gx - node.x; - dy = gy - node.y; - angle = Math.atan2(dy, dx); - fx = Math.cos(angle) * gravity; - fy = Math.sin(angle) * gravity; - - node._setForce(fx, fy); - } - } - - // repulsing forces between nodes - var minimumDistance = this.constants.nodes.distance, - steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance - - for (var id1 in nodes) { - if (nodes.hasOwnProperty(id1)) { - var node1 = nodes[id1]; - for (var id2 in nodes) { - if (nodes.hasOwnProperty(id2)) { - var node2 = nodes[id2]; - // calculate normally distributed force - dx = node2.x - node1.x; - dy = node2.y - node1.y; - distance = Math.sqrt(dx * dx + dy * dy); - angle = Math.atan2(dy, dx); - - // TODO: correct factor for repulsing force - //repulsingForce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - //repulsingForce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - repulsingForce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)); // TODO: customize the repulsing force - fx = Math.cos(angle) * repulsingForce; - fy = Math.sin(angle) * repulsingForce; - - node1._addForce(-fx, -fy); - node2._addForce(fx, fy); - } - } - } - } - - /* TODO: re-implement repulsion of edges - for (var n = 0; n < nodes.length; n++) { - for (var l = 0; l < edges.length; l++) { - var lx = edges[l].from.x+(edges[l].to.x - edges[l].from.x)/2, - ly = edges[l].from.y+(edges[l].to.y - edges[l].from.y)/2, - - // calculate normally distributed force - dx = nodes[n].x - lx, - dy = nodes[n].y - ly, - distance = Math.sqrt(dx * dx + dy * dy), - angle = Math.atan2(dy, dx), - - - // TODO: correct factor for repulsing force - //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force - repulsingforce = 1 / (1 + Math.exp((distance / (minimumDistance / 2) - 1) * steepness)), // TODO: customize the repulsing force - fx = Math.cos(angle) * repulsingforce, - fy = Math.sin(angle) * repulsingforce; - nodes[n]._addForce(fx, fy); - edges[l].from._addForce(-fx/2,-fy/2); - edges[l].to._addForce(-fx/2,-fy/2); - } - } - */ - - // forces caused by the edges, modelled as springs - for (id in edges) { - if (edges.hasOwnProperty(id)) { - var edge = edges[id]; - if (edge.connected) { - dx = (edge.to.x - edge.from.x); - dy = (edge.to.y - edge.from.y); - //edgeLength = (edge.from.width + edge.from.height + edge.to.width + edge.to.height)/2 || edge.length; // TODO: dmin - //edgeLength = (edge.from.width + edge.to.width)/2 || edge.length; // TODO: dmin - //edgeLength = 20 + ((edge.from.width + edge.to.width) || 0) / 2; - edgeLength = edge.length; - length = Math.sqrt(dx * dx + dy * dy); - angle = Math.atan2(dy, dx); - - springForce = edge.stiffness * (edgeLength - length); - - fx = Math.cos(angle) * springForce; - fy = Math.sin(angle) * springForce; - - edge.from._addForce(-fx, -fy); - edge.to._addForce(fx, fy); - } - } - } - - /* TODO: re-implement repulsion of edges - // repulsing forces between edges - var minimumDistance = this.constants.edges.distance, - steepness = 10; // higher value gives steeper slope of the force around the given minimumDistance - for (var l = 0; l < edges.length; l++) { - //Keep distance from other edge centers - for (var l2 = l + 1; l2 < this.edges.length; l2++) { - //var dmin = (nodes[n].width + nodes[n].height + nodes[n2].width + nodes[n2].height) / 1 || minimumDistance, // TODO: dmin - //var dmin = (nodes[n].width + nodes[n2].width)/2 || minimumDistance, // TODO: dmin - //dmin = 40 + ((nodes[n].width/2 + nodes[n2].width/2) || 0), - var lx = edges[l].from.x+(edges[l].to.x - edges[l].from.x)/2, - ly = edges[l].from.y+(edges[l].to.y - edges[l].from.y)/2, - l2x = edges[l2].from.x+(edges[l2].to.x - edges[l2].from.x)/2, - l2y = edges[l2].from.y+(edges[l2].to.y - edges[l2].from.y)/2, - - // calculate normally distributed force - dx = l2x - lx, - dy = l2y - ly, - distance = Math.sqrt(dx * dx + dy * dy), - angle = Math.atan2(dy, dx), - - - // TODO: correct factor for repulsing force - //var repulsingforce = 2 * Math.exp(-5 * (distance * distance) / (dmin * dmin) ); // TODO: customize the repulsing force - //repulsingforce = Math.exp(-1 * (distance * distance) / (dmin * dmin) ), // TODO: customize the repulsing force - repulsingforce = 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)), // TODO: customize the repulsing force - fx = Math.cos(angle) * repulsingforce, - fy = Math.sin(angle) * repulsingforce; - - edges[l].from._addForce(-fx, -fy); - edges[l].to._addForce(-fx, -fy); - edges[l2].from._addForce(fx, fy); - edges[l2].to._addForce(fx, fy); - } - } - */ -}; - - -/** - * Check if any of the nodes is still moving - * @param {number} vmin the minimum velocity considered as 'moving' - * @return {boolean} true if moving, false if non of the nodes is moving - * @private - */ -Graph.prototype._isMoving = function(vmin) { - // TODO: ismoving does not work well: should check the kinetic energy, not its velocity - var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id) && nodes[id].isMoving(vmin)) { - return true; - } - } - return false; -}; - - -/** - * Perform one discrete step for all nodes - * @private - */ -Graph.prototype._discreteStepNodes = function() { - var interval = this.refreshRate / 1000.0; // in seconds - var nodes = this.nodes; - for (var id in nodes) { - if (nodes.hasOwnProperty(id)) { - nodes[id].discreteStep(interval); - } - } -}; - -/** - * Start animating nodes and edges - */ -Graph.prototype.start = function() { - if (this.moving) { - this._calculateForces(); - this._discreteStepNodes(); - - var vmin = this.constants.minVelocity; - this.moving = this._isMoving(vmin); - } - - if (this.moving) { - // start animation. only start timer if it is not already running - if (!this.timer) { - var graph = this; - this.timer = window.setTimeout(function () { - graph.timer = undefined; - graph.start(); - graph._redraw(); - }, this.refreshRate); - } - } - else { - this._redraw(); - } -}; - -/** - * Stop animating nodes and edges. - */ -Graph.prototype.stop = function () { - if (this.timer) { - window.clearInterval(this.timer); - this.timer = undefined; - } -}; - -/** - * vis.js module exports - */ -var vis = { - util: util, - events: events, - - Controller: Controller, - DataSet: DataSet, - DataView: DataView, - Range: Range, - Stack: Stack, - TimeStep: TimeStep, - EventBus: EventBus, - - components: { - items: { - Item: Item, - ItemBox: ItemBox, - ItemPoint: ItemPoint, - ItemRange: ItemRange - }, - - Component: Component, - Panel: Panel, - RootPanel: RootPanel, - ItemSet: ItemSet, - TimeAxis: TimeAxis - }, - - graph: { - Node: Node, - Edge: Edge, - Popup: Popup, - Groups: Groups, - Images: Images - }, - - Timeline: Timeline, - Graph: Graph -}; - -/** - * CommonJS module exports - */ -if (typeof exports !== 'undefined') { - exports = vis; -} -if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { - module.exports = vis; -} - -/** - * AMD module exports - */ -if (typeof(define) === 'function') { - define(function () { - return vis; - }); -} - -/** - * Window exports - */ -if (typeof window !== 'undefined') { - // attach the module to the window, load as a regular javascript file - window['vis'] = vis; -} - -// inject css -util.loadCss("/* vis.js stylesheet */\n.vis.timeline {\n}\n\n\n.vis.timeline.rootpanel {\n position: relative;\n overflow: hidden;\n\n border: 1px solid #bfbfbf;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n\n.vis.timeline .panel {\n position: absolute;\n overflow: hidden;\n}\n\n\n.vis.timeline .groupset {\n position: absolute;\n padding: 0;\n margin: 0;\n}\n\n.vis.timeline .labels {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n\n padding: 0;\n margin: 0;\n\n border-right: 1px solid #bfbfbf;\n box-sizing: border-box;\n -moz-box-sizing: border-box;\n}\n\n.vis.timeline .labels .label {\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n border-bottom: 1px solid #bfbfbf;\n color: #4d4d4d;\n}\n\n.vis.timeline .labels .label .inner {\n display: inline-block;\n padding: 5px;\n}\n\n\n.vis.timeline .itemset {\n position: absolute;\n padding: 0;\n margin: 0;\n overflow: hidden;\n}\n\n.vis.timeline .background {\n}\n\n.vis.timeline .foreground {\n}\n\n.vis.timeline .itemset-axis {\n position: absolute;\n}\n\n.vis.timeline .groupset .itemset-axis {\n border-top: 1px solid #bfbfbf;\n}\n\n/* TODO: with orientation=='bottom', this will more or less overlap with timeline axis\n.vis.timeline .groupset .itemset-axis:last-child {\n border-top: none;\n}\n*/\n\n\n.vis.timeline .item {\n position: absolute;\n color: #1A1A1A;\n border-color: #97B0F8;\n background-color: #D5DDF6;\n display: inline-block;\n}\n\n.vis.timeline .item.selected {\n border-color: #FFC200;\n background-color: #FFF785;\n z-index: 999;\n}\n\n.vis.timeline .item.cluster {\n /* TODO: use another color or pattern? */\n background: #97B0F8 url('img/cluster_bg.png');\n color: white;\n}\n.vis.timeline .item.cluster.point {\n border-color: #D5DDF6;\n}\n\n.vis.timeline .item.box {\n text-align: center;\n border-style: solid;\n border-width: 1px;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.point {\n background: none;\n}\n\n.vis.timeline .dot {\n border: 5px solid #97B0F8;\n position: absolute;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.range {\n overflow: hidden;\n border-style: solid;\n border-width: 1px;\n border-radius: 2px;\n -moz-border-radius: 2px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.range .drag-left {\n cursor: w-resize;\n z-index: 1000;\n}\n\n.vis.timeline .item.range .drag-right {\n cursor: e-resize;\n z-index: 1000;\n}\n\n.vis.timeline .item.range .content {\n position: relative;\n display: inline-block;\n}\n\n.vis.timeline .item.line {\n position: absolute;\n width: 0;\n border-left-width: 1px;\n border-left-style: solid;\n}\n\n.vis.timeline .item .content {\n margin: 5px;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.vis.timeline .axis {\n position: relative;\n}\n\n.vis.timeline .axis .text {\n position: absolute;\n color: #4d4d4d;\n padding: 3px;\n white-space: nowrap;\n}\n\n.vis.timeline .axis .text.measure {\n position: absolute;\n padding-left: 0;\n padding-right: 0;\n margin-left: 0;\n margin-right: 0;\n visibility: hidden;\n}\n\n.vis.timeline .axis .grid.vertical {\n position: absolute;\n width: 0;\n border-right: 1px solid;\n}\n\n.vis.timeline .axis .grid.horizontal {\n position: absolute;\n left: 0;\n width: 100%;\n height: 0;\n border-bottom: 1px solid;\n}\n\n.vis.timeline .axis .grid.minor {\n border-color: #e5e5e5;\n}\n\n.vis.timeline .axis .grid.major {\n border-color: #bfbfbf;\n}\n\n"); - -},{"hammerjs":1,"moment":2}]},{},[3]) -(3) -}); -; \ No newline at end of file diff --git a/vis.min.js b/vis.min.js deleted file mode 100644 index 3f3d76a8..00000000 --- a/vis.min.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * vis.js - * https://github.com/almende/vis - * - * A dynamic, browser-based visualization library. - * - * @version 0.2.0 - * @date 2013-09-20 - * - * @license - * Copyright (C) 2011-2013 Almende B.V, http://almende.com - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -(function(t){if("function"==typeof bootstrap)bootstrap("vis",t);else if("object"==typeof exports)module.exports=t();else if("function"==typeof define&&define.amd)define(t);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeVis=t}else"undefined"!=typeof window?window.vis=t():global.vis=t()})(function(){var t;return function e(t,i,n){function s(r,a){if(!i[r]){if(!t[r]){var h="function"==typeof require&&require;if(!a&&h)return h(r,!0);if(o)return o(r,!0);throw Error("Cannot find module '"+r+"'")}var d=i[r]={exports:{}};t[r][0].call(d.exports,function(e){var i=t[r][1][e];return s(i?i:e)},d,d.exports,e,t,i,n)}return i[r].exports}for(var o="function"==typeof require&&require,r=0;n.length>r;r++)s(n[r]);return s}({1:[function(t,e){(function(t,i){"use strict";function n(){if(!s.READY){s.event.determineEventTypes();for(var t in s.gestures)s.gestures.hasOwnProperty(t)&&s.detection.register(s.gestures[t]);s.event.onTouch(s.DOCUMENT,s.EVENT_MOVE,s.detection.detect),s.event.onTouch(s.DOCUMENT,s.EVENT_END,s.detection.detect),s.READY=!0}}var s=function(t,e){return new s.Instance(t,e||{})};s.defaults={stop_browser_behavior:{userSelect:"none",touchAction:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}},s.HAS_POINTEREVENTS=navigator.pointerEnabled||navigator.msPointerEnabled,s.HAS_TOUCHEVENTS="ontouchstart"in t,s.MOBILE_REGEX=/mobile|tablet|ip(ad|hone|od)|android/i,s.NO_MOUSEEVENTS=s.HAS_TOUCHEVENTS&&navigator.userAgent.match(s.MOBILE_REGEX),s.EVENT_TYPES={},s.DIRECTION_DOWN="down",s.DIRECTION_LEFT="left",s.DIRECTION_UP="up",s.DIRECTION_RIGHT="right",s.POINTER_MOUSE="mouse",s.POINTER_TOUCH="touch",s.POINTER_PEN="pen",s.EVENT_START="start",s.EVENT_MOVE="move",s.EVENT_END="end",s.DOCUMENT=document,s.plugins={},s.READY=!1,s.Instance=function(t,e){var i=this;return n(),this.element=t,this.enabled=!0,this.options=s.utils.extend(s.utils.extend({},s.defaults),e||{}),this.options.stop_browser_behavior&&s.utils.stopDefaultBrowserBehavior(this.element,this.options.stop_browser_behavior),s.event.onTouch(t,s.EVENT_START,function(t){i.enabled&&s.detection.startDetect(i,t)}),this},s.Instance.prototype={on:function(t,e){for(var i=t.split(" "),n=0;i.length>n;n++)this.element.addEventListener(i[n],e,!1);return this},off:function(t,e){for(var i=t.split(" "),n=0;i.length>n;n++)this.element.removeEventListener(i[n],e,!1);return this},trigger:function(t,e){var i=s.DOCUMENT.createEvent("Event");i.initEvent(t,!0,!0),i.gesture=e;var n=this.element;return s.utils.hasParent(e.target,n)&&(n=e.target),n.dispatchEvent(i),this},enable:function(t){return this.enabled=t,this}};var o=null,r=!1,a=!1;s.event={bindDom:function(t,e,i){for(var n=e.split(" "),s=0;n.length>s;s++)t.addEventListener(n[s],i,!1)},onTouch:function(t,e,i){var n=this;this.bindDom(t,s.EVENT_TYPES[e],function(h){var d=h.type.toLowerCase();if(!d.match(/mouse/)||!a){(d.match(/touch/)||d.match(/pointerdown/)||d.match(/mouse/)&&1===h.which)&&(r=!0),d.match(/touch|pointer/)&&(a=!0);var l=0;r&&(s.HAS_POINTEREVENTS&&e!=s.EVENT_END?l=s.PointerEvent.updatePointer(e,h):d.match(/touch/)?l=h.touches.length:a||(l=d.match(/up/)?0:1),l>0&&e==s.EVENT_END?e=s.EVENT_MOVE:l||(e=s.EVENT_END),l||null===o?o=h:h=o,i.call(s.detection,n.collectEventData(t,e,h)),s.HAS_POINTEREVENTS&&e==s.EVENT_END&&(l=s.PointerEvent.updatePointer(e,h))),l||(o=null,r=!1,a=!1,s.PointerEvent.reset())}})},determineEventTypes:function(){var t;t=s.HAS_POINTEREVENTS?s.PointerEvent.getEvents():s.NO_MOUSEEVENTS?["touchstart","touchmove","touchend touchcancel"]:["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],s.EVENT_TYPES[s.EVENT_START]=t[0],s.EVENT_TYPES[s.EVENT_MOVE]=t[1],s.EVENT_TYPES[s.EVENT_END]=t[2]},getTouchList:function(t){return s.HAS_POINTEREVENTS?s.PointerEvent.getTouchList():t.touches?t.touches:[{identifier:1,pageX:t.pageX,pageY:t.pageY,target:t.target}]},collectEventData:function(t,e,i){var n=this.getTouchList(i,e),o=s.POINTER_TOUCH;return(i.type.match(/mouse/)||s.PointerEvent.matchType(s.POINTER_MOUSE,i))&&(o=s.POINTER_MOUSE),{center:s.utils.getCenter(n),timeStamp:(new Date).getTime(),target:i.target,touches:n,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 s.detection.stopDetect()}}}},s.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==s.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[s.POINTER_MOUSE]=e.pointerType==e.MSPOINTER_TYPE_MOUSE||e.pointerType==s.POINTER_MOUSE,i[s.POINTER_TOUCH]=e.pointerType==e.MSPOINTER_TYPE_TOUCH||e.pointerType==s.POINTER_TOUCH,i[s.POINTER_PEN]=e.pointerType==e.MSPOINTER_TYPE_PEN||e.pointerType==s.POINTER_PEN,i[t]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},s.utils={extend:function(t,e,n){for(var s in e)t[s]!==i&&n||(t[s]=e[s]);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=[],n=0,s=t.length;s>n;n++)e.push(t[n].pageX),i.push(t[n].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,n=e.pageX-t.pageX;return 180*Math.atan2(i,n)/Math.PI},getDirection:function(t,e){var i=Math.abs(t.pageX-e.pageX),n=Math.abs(t.pageY-e.pageY);return i>=n?t.pageX-e.pageX>0?s.DIRECTION_LEFT:s.DIRECTION_RIGHT:t.pageY-e.pageY>0?s.DIRECTION_UP:s.DIRECTION_DOWN},getDistance:function(t,e){var i=e.pageX-t.pageX,n=e.pageY-t.pageY;return Math.sqrt(i*i+n*n)},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==s.DIRECTION_UP||t==s.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,e){var i,n=["webkit","khtml","moz","ms","o",""];if(e&&t.style){for(var s=0;n.length>s;s++)for(var o in e)e.hasOwnProperty(o)&&(i=o,n[s]&&(i=n[s]+i.substring(0,1).toUpperCase()+i.substring(1)),t.style[i]=e[o]);"none"==e.userSelect&&(t.onselectstart=function(){return!1})}}},s.detection={gestures:[],current:null,previous:null,stopped:!1,startDetect:function(t,e){this.current||(this.stopped=!1,this.current={inst:t,startEvent:s.utils.extend({},e),lastEvent:!1,name:""},this.detect(e))},detect:function(t){if(this.current&&!this.stopped){t=this.extendEventData(t);for(var e=this.current.inst.options,i=0,n=this.gestures.length;n>i;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==s.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t}},stopDetect:function(){this.previous=s.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,n=t.touches.length;n>i;i++)e.touches.push(s.utils.extend({},t.touches[i]))}var o=t.timeStamp-e.timeStamp,r=t.center.pageX-e.center.pageX,a=t.center.pageY-e.center.pageY,h=s.utils.getVelocity(o,r,a);return s.utils.extend(t,{deltaTime:o,deltaX:r,deltaY:a,velocityX:h.x,velocityY:h.y,distance:s.utils.getDistance(e.center,t.center),angle:s.utils.getAngle(e.center,t.center),direction:s.utils.getDirection(e.center,t.center),scale:s.utils.getScale(e.touches,t.touches),rotation:s.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),s.utils.extend(s.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}},s.gestures=s.gestures||{},s.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,e){switch(t.eventType){case s.EVENT_START:clearTimeout(this.timer),s.detection.current.name=this.name,this.timer=setTimeout(function(){"hold"==s.detection.current.name&&e.trigger("hold",t)},e.options.hold_timeout);break;case s.EVENT_MOVE:t.distance>e.options.hold_threshold&&clearTimeout(this.timer);break;case s.EVENT_END:clearTimeout(this.timer)}}},s.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==s.EVENT_END){var i=s.detection.previous,n=!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))}}},s.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(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),this.triggered=!1,i;if(!(e.options.drag_max_touches>0&&t.touches.length>e.options.drag_max_touches))switch(t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.EVENT_MOVE:if(t.distancet.deltaY?s.DIRECTION_UP:s.DIRECTION_DOWN:0>t.deltaX?s.DIRECTION_LEFT:s.DIRECTION_RIGHT),this.triggered||(e.trigger(this.name+"start",t),this.triggered=!0),e.trigger(this.name,t),e.trigger(this.name+t.direction,t),(e.options.drag_block_vertical&&s.utils.isVertical(t.direction)||e.options.drag_block_horizontal&&!s.utils.isVertical(t.direction))&&t.preventDefault();break;case s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.gestures.Transform={name:"transform",index:45,defaults:{transform_min_scale:.01,transform_min_rotation:1,transform_always_block:!1},triggered:!1,handler:function(t,e){if(s.detection.current.name!=this.name&&this.triggered)return e.trigger(this.name+"end",t),this.triggered=!1,i;if(!(2>t.touches.length))switch(e.options.transform_always_block&&t.preventDefault(),t.eventType){case s.EVENT_START:this.triggered=!1;break;case s.EVENT_MOVE:var n=Math.abs(1-t.scale),o=Math.abs(t.rotation);if(e.options.transform_min_scale>n&&e.options.transform_min_rotation>o)return;s.detection.current.name=this.name,this.triggered||(e.trigger(this.name+"start",t),this.triggered=!0),e.trigger(this.name,t),o>e.options.transform_min_rotation&&e.trigger("rotate",t),n>e.options.transform_min_scale&&(e.trigger("pinch",t),e.trigger("pinch"+(1>t.scale?"in":"out"),t));break;case s.EVENT_END:this.triggered&&e.trigger(this.name+"end",t),this.triggered=!1}}},s.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==s.POINTER_MOUSE?(t.stopDetect(),i):(e.options.prevent_default&&t.preventDefault(),t.eventType==s.EVENT_START&&e.trigger(this.name,t),i)}},s.gestures.Release={name:"release",index:1/0,handler:function(t,e){t.eventType==s.EVENT_END&&e.trigger(this.name,t)}},"object"==typeof e&&"object"==typeof e.exports?e.exports=s:(t.Hammer=s,"function"==typeof t.define&&t.define.amd&&t.define("hammer",[],function(){return s}))})(this)},{}],2:[function(e,i){(function(n){function s(t,e){return function(i){return p(t.call(this,i),e)}}function o(t,e){return function(i){return this.lang().ordinal(t.call(this,i),e)}}function r(){}function a(t){d(this,t)}function h(t){var e=t.years||t.year||t.y||0,i=t.months||t.month||t.M||0,n=t.weeks||t.week||t.w||0,s=t.days||t.day||t.d||0,o=t.hours||t.hour||t.h||0,r=t.minutes||t.minute||t.m||0,a=t.seconds||t.second||t.s||0,h=t.milliseconds||t.millisecond||t.ms||0;this._input=t,this._milliseconds=+h+1e3*a+6e4*r+36e5*o,this._days=+s+7*n,this._months=+i+12*e,this._data={},this._bubble()}function d(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function l(t){return 0>t?Math.ceil(t):Math.floor(t)}function p(t,e){for(var i=t+"";e>i.length;)i="0"+i;return i}function c(t,e,i,n){var s,o,r=e._milliseconds,a=e._days,h=e._months;r&&t._d.setTime(+t._d+r*i),(a||h)&&(s=t.minute(),o=t.hour()),a&&t.date(t.date()+a*i),h&&t.month(t.month()+h*i),r&&!n&&H.updateOffset(t),(a||h)&&(t.minute(s),t.hour(o))}function u(t){return"[object Array]"===Object.prototype.toString.call(t)}function f(t,e){var i,n=Math.min(t.length,e.length),s=Math.abs(t.length-e.length),o=0;for(i=0;n>i;i++)~~t[i]!==~~e[i]&&o++;return o+s}function m(t){return t?pe[t]||t.toLowerCase().replace(/(.)s$/,"$1"):t}function g(t,e){return e.abbr=t,V[t]||(V[t]=new r),V[t].set(e),V[t]}function v(t){delete V[t]}function y(t){if(!t)return H.fn._lang;if(!V[t]&&B)try{e("./lang/"+t)}catch(i){return H.fn._lang}return V[t]||H.fn._lang}function b(t){return t.match(/\[.*\]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function w(t){var e,i,n=t.match(X);for(e=0,i=n.length;i>e;e++)n[e]=me[n[e]]?me[n[e]]:b(n[e]);return function(s){var o="";for(e=0;i>e;e++)o+=n[e]instanceof Function?n[e].call(s,t):n[e];return o}}function _(t,e){return e=E(e,t.lang()),ce[e]||(ce[e]=w(e)),ce[e](t)}function E(t,e){function i(t){return e.longDateFormat(t)||t}for(var n=5;n--&&(Z.lastIndex=0,Z.test(t));)t=t.replace(Z,i);return t}function T(t,e){switch(t){case"DDDD":return Q;case"YYYY":return $;case"YYYYY":return te;case"S":case"SS":case"SSS":case"DDD":return J;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return ee;case"a":case"A":return y(e._l)._meridiemParse;case"X":return se;case"Z":case"ZZ":return ie;case"T":return ne;case"MM":case"DD":case"YY":case"HH":case"hh":case"mm":case"ss":case"M":case"D":case"d":case"H":case"h":case"m":case"s":return K;default:return RegExp(t.replace("\\",""))}}function x(t){var e=(ie.exec(t)||[])[0],i=(e+"").match(he)||["-",0,0],n=+(60*i[1])+~~i[2];return"+"===i[0]?-n:n}function S(t,e,i){var n,s=i._a;switch(t){case"M":case"MM":null!=e&&(s[1]=~~e-1);break;case"MMM":case"MMMM":n=y(i._l).monthsParse(e),null!=n?s[1]=n:i._isValid=!1;break;case"D":case"DD":null!=e&&(s[2]=~~e);break;case"DDD":case"DDDD":null!=e&&(s[1]=0,s[2]=~~e);break;case"YY":s[0]=~~e+(~~e>68?1900:2e3);break;case"YYYY":case"YYYYY":s[0]=~~e;break;case"a":case"A":i._isPm=y(i._l).isPM(e);break;case"H":case"HH":case"h":case"hh":s[3]=~~e;break;case"m":case"mm":s[4]=~~e;break;case"s":case"ss":s[5]=~~e;break;case"S":case"SS":case"SSS":s[6]=~~(1e3*("0."+e));break;case"X":i._d=new Date(1e3*parseFloat(e));break;case"Z":case"ZZ":i._useUTC=!0,i._tzm=x(e)}null==e&&(i._isValid=!1)}function M(t){var e,i,n,s=[];if(!t._d){for(n=C(t),e=0;3>e&&null==t._a[e];++e)t._a[e]=s[e]=n[e];for(;7>e;e++)t._a[e]=s[e]=null==t._a[e]?2===e?1:0:t._a[e];s[3]+=~~((t._tzm||0)/60),s[4]+=~~((t._tzm||0)%60),i=new Date(0),t._useUTC?(i.setUTCFullYear(s[0],s[1],s[2]),i.setUTCHours(s[3],s[4],s[5],s[6])):(i.setFullYear(s[0],s[1],s[2]),i.setHours(s[3],s[4],s[5],s[6])),t._d=i}}function D(t){var e=t._i;t._d||(t._a=[e.years||e.year||e.y,e.months||e.month||e.M,e.days||e.day||e.d,e.hours||e.hour||e.h,e.minutes||e.minute||e.m,e.seconds||e.second||e.s,e.milliseconds||e.millisecond||e.ms],M(t))}function C(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function O(t){var e,i,n,s=y(t._l),o=""+t._i;for(n=E(t._f,s).match(X),t._a=[],e=0;n.length>e;e++)i=(T(n[e],t).exec(o)||[])[0],i&&(o=o.slice(o.indexOf(i)+i.length)),me[n[e]]&&S(n[e],i,t);o&&(t._il=o),t._isPm&&12>t._a[3]&&(t._a[3]+=12),t._isPm===!1&&12===t._a[3]&&(t._a[3]=0),M(t)}function N(t){var e,i,n,s,o,r=99;for(s=0;t._f.length>s;s++)e=d({},t),e._f=t._f[s],O(e),i=new a(e),o=f(e._a,i.toArray()),i._il&&(o+=i._il.length),r>o&&(r=o,n=i);d(t,n)}function L(t){var e,i=t._i,n=oe.exec(i);if(n){for(t._f="YYYY-MM-DD"+(n[2]||" "),e=0;4>e;e++)if(ae[e][1].exec(i)){t._f+=ae[e][0];break}ie.exec(i)&&(t._f+=" Z"),O(t)}else t._d=new Date(i)}function k(t){var e=t._i,i=q.exec(e);e===n?t._d=new Date:i?t._d=new Date(+i[1]):"string"==typeof e?L(t):u(e)?(t._a=e.slice(0),M(t)):e instanceof Date?t._d=new Date(+e):"object"==typeof e?D(t):t._d=new Date(e)}function I(t,e,i,n,s){return s.relativeTime(e||1,!!i,t,n)}function A(t,e,i){var n=W(Math.abs(t)/1e3),s=W(n/60),o=W(s/60),r=W(o/24),a=W(r/365),h=45>n&&["s",n]||1===s&&["m"]||45>s&&["mm",s]||1===o&&["h"]||22>o&&["hh",o]||1===r&&["d"]||25>=r&&["dd",r]||45>=r&&["M"]||345>r&&["MM",W(r/30)]||1===a&&["y"]||["yy",a];return h[2]=e,h[3]=t>0,h[4]=i,I.apply({},h)}function P(t,e,i){var n,s=i-e,o=i-t.day();return o>s&&(o-=7),s-7>o&&(o+=7),n=H(t).add("d",o),{week:Math.ceil(n.dayOfYear()/7),year:n.year()}}function F(t){var e=t._i,i=t._f;return null===e||""===e?null:("string"==typeof e&&(t._i=e=y().preparse(e)),H.isMoment(e)?(t=d({},e),t._d=new Date(+e._d)):i?u(i)?N(t):O(t):k(t),new a(t))}function Y(t,e){H.fn[t]=H.fn[t+"s"]=function(t){var i=this._isUTC?"UTC":"";return null!=t?(this._d["set"+i+e](t),H.updateOffset(this),this):this._d["get"+i+e]()}}function R(t){H.duration.fn[t]=function(){return this._data[t]}}function z(t,e){H.duration.fn["as"+t]=function(){return+this/e}}for(var H,U,j="2.2.1",W=Math.round,V={},B=i!==n&&i.exports,q=/^\/?Date\((\-?\d+)/i,G=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)\:(\d+)\.?(\d{3})?/,X=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|SS?S?|X|zz?|ZZ?|.)/g,Z=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,K=/\d\d?/,J=/\d{1,3}/,Q=/\d{3}/,$=/\d{1,4}/,te=/[+\-]?\d{1,6}/,ee=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,ie=/Z|[\+\-]\d\d:?\d\d/i,ne=/T/i,se=/[\+\-]?\d+(\.\d{1,3})?/,oe=/^\s*\d{4}-\d\d-\d\d((T| )(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/,re="YYYY-MM-DDTHH:mm:ssZ",ae=[["HH:mm:ss.S",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],he=/([\+\-]|\d\d)/gi,de="Date|Hours|Minutes|Seconds|Milliseconds".split("|"),le={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},pe={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",w:"week",W:"isoweek",M:"month",y:"year"},ce={},ue="DDD w W M D d".split(" "),fe="M D H h m s w W".split(" "),me={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 p(this.year()%100,2)},YYYY:function(){return p(this.year(),4)},YYYYY:function(){return p(this.year(),5)},gg:function(){return p(this.weekYear()%100,2)},gggg:function(){return this.weekYear()},ggggg:function(){return p(this.weekYear(),5)},GG:function(){return p(this.isoWeekYear()%100,2)},GGGG:function(){return this.isoWeekYear()},GGGGG:function(){return p(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~~(this.milliseconds()/100)},SS:function(){return p(~~(this.milliseconds()/10),2)},SSS:function(){return p(this.milliseconds(),3)},Z:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(~~(t/60),2)+":"+p(~~t%60,2)},ZZ:function(){var t=-this.zone(),e="+";return 0>t&&(t=-t,e="-"),e+p(~~(10*t/6),4)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()}};ue.length;)U=ue.pop(),me[U+"o"]=o(me[U],U);for(;fe.length;)U=fe.pop(),me[U+U]=s(me[U],2);for(me.DDDD=s(me.DDD,3),d(r.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,n;for(this._monthsParse||(this._monthsParse=[]),e=0;12>e;e++)if(this._monthsParse[e]||(i=H.utc([2e3,e]),n="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[e]=RegExp(n.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,n;for(this._weekdaysParse||(this._weekdaysParse=[]),e=0;7>e;e++)if(this._weekdaysParse[e]||(i=H([2e3,1]).day(e),n="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[e]=RegExp(n.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,n){var s=this._relativeTime[i];return"function"==typeof s?s(t,e,i,n):s.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 P(t,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6}}),H=function(t,e,i){return F({_i:t,_f:e,_l:i,_isUTC:!1})},H.utc=function(t,e,i){return F({_useUTC:!0,_isUTC:!0,_l:i,_i:t,_f:e}).utc()},H.unix=function(t){return H(1e3*t)},H.duration=function(t,e){var i,n,s=H.isDuration(t),o="number"==typeof t,r=s?t._input:o?{}:t,a=G.exec(t);return o?e?r[e]=t:r.milliseconds=t:a&&(i="-"===a[1]?-1:1,r={y:0,d:~~a[2]*i,h:~~a[3]*i,m:~~a[4]*i,s:~~a[5]*i,ms:~~a[6]*i}),n=new h(r),s&&t.hasOwnProperty("_lang")&&(n._lang=t._lang),n},H.version=j,H.defaultFormat=re,H.updateOffset=function(){},H.lang=function(t,e){return t?(t=t.toLowerCase(),t=t.replace("_","-"),e?g(t,e):null===e?(v(t),t="en"):V[t]||y(t),H.duration.fn._lang=H.fn._lang=y(t),n):H.fn._lang._abbr},H.langData=function(t){return t&&t._lang&&t._lang._abbr&&(t=t._lang._abbr),y(t)},H.isMoment=function(t){return t instanceof a},H.isDuration=function(t){return t instanceof h},d(H.fn=a.prototype,{clone:function(){return H(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){return _(H(this).utc(),"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]")},toArray:function(){var t=this;return[t.year(),t.month(),t.date(),t.hours(),t.minutes(),t.seconds(),t.milliseconds()]},isValid:function(){return null==this._isValid&&(this._isValid=this._a?!f(this._a,(this._isUTC?H.utc(this._a):H(this._a)).toArray()):!isNaN(this._d.getTime())),!!this._isValid},invalidAt:function(){var t,e=this._a,i=(this._isUTC?H.utc(this._a):H(this._a)).toArray();for(t=6;t>=0&&e[t]===i[t];--t);return t},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(t){var e=_(this,t||H.defaultFormat);return this.lang().postformat(e)},add:function(t,e){var i;return i="string"==typeof t?H.duration(+e,t):H.duration(t,e),c(this,i,1),this},subtract:function(t,e){var i;return i="string"==typeof t?H.duration(+e,t):H.duration(t,e),c(this,i,-1),this},diff:function(t,e,i){var n,s,o=this._isUTC?H(t).zone(this._offset||0):H(t).local(),r=6e4*(this.zone()-o.zone());return e=m(e),"year"===e||"month"===e?(n=432e5*(this.daysInMonth()+o.daysInMonth()),s=12*(this.year()-o.year())+(this.month()-o.month()),s+=(this-H(this).startOf("month")-(o-H(o).startOf("month")))/n,s-=6e4*(this.zone()-H(this).startOf("month").zone()-(o.zone()-H(o).startOf("month").zone()))/n,"year"===e&&(s/=12)):(n=this-o,s="second"===e?n/1e3:"minute"===e?n/6e4:"hour"===e?n/36e5:"day"===e?(n-r)/864e5:"week"===e?(n-r)/6048e5:n),i?s:l(s)},from:function(t,e){return H.duration(this.diff(t)).lang(this.lang()._abbr).humanize(!e)},fromNow:function(t){return this.from(H(),t)},calendar:function(){var t=this.diff(H().zone(this.zone()).startOf("day"),"days",!0),e=-6>t?"sameElse":-1>t?"lastWeek":0>t?"lastDay":1>t?"sameDay":2>t?"nextDay":7>t?"nextWeek":"sameElse";return this.format(this.lang().calendar(e,this))},isLeapYear:function(){var t=this.year();return 0===t%4&&0!==t%100||0===t%400},isDST:function(){return this.zone()+H(t).startOf(e)},isBefore:function(t,e){return e=e!==n?e:"millisecond",+this.clone().startOf(e)<+H(t).startOf(e)},isSame:function(t,e){return e=e!==n?e:"millisecond",+this.clone().startOf(e)===+H(t).startOf(e)},min:function(t){return t=H.apply(null,arguments),this>t?this:t},max:function(t){return t=H.apply(null,arguments),t>this?this:t},zone:function(t){var e=this._offset||0;return null==t?this._isUTC?e:this._d.getTimezoneOffset():("string"==typeof t&&(t=x(t)),16>Math.abs(t)&&(t=60*t),this._offset=t,this._isUTC=!0,e!==t&&c(this,H.duration(e-t,"m"),1,!0),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},hasAlignedHourOffset:function(t){return t=t?H(t).zone():0,0===(this.zone()-t)%60},daysInMonth:function(){return H.utc([this.year(),this.month()+1,0]).date()},dayOfYear:function(t){var e=W((H(this).startOf("day")-H(this).startOf("year"))/864e5)+1;return null==t?e:this.add("d",t-e)},weekYear:function(t){var e=P(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==t?e:this.add("y",t-e)},isoWeekYear:function(t){var e=P(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=P(this,1,4).week;return null==t?e:this.add("d",7*(t-e))},weekday:function(t){var e=(this._d.getDay()+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)},get:function(t){return t=m(t),this[t.toLowerCase()]()},set:function(t,e){t=m(t),this[t.toLowerCase()](e)},lang:function(t){return t===n?this._lang:(this._lang=y(t),this)}}),U=0;de.length>U;U++)Y(de[U].toLowerCase().replace(/s$/,""),de[U]);Y("year","FullYear"),H.fn.days=H.fn.day,H.fn.months=H.fn.month,H.fn.weeks=H.fn.week,H.fn.isoWeeks=H.fn.isoWeek,H.fn.toJSON=H.fn.toISOString,d(H.duration.fn=h.prototype,{_bubble:function(){var t,e,i,n,s=this._milliseconds,o=this._days,r=this._months,a=this._data;a.milliseconds=s%1e3,t=l(s/1e3),a.seconds=t%60,e=l(t/60),a.minutes=e%60,i=l(e/60),a.hours=i%24,o+=l(i/24),a.days=o%30,r+=l(o/30),a.months=r%12,n=l(r/12),a.years=n},weeks:function(){return l(this.days()/7)},valueOf:function(){return this._milliseconds+864e5*this._days+2592e6*(this._months%12)+31536e6*~~(this._months/12)},humanize:function(t){var e=+this,i=A(e,!t,this.lang());return t&&(i=this.lang().pastFuture(e,i)),this.lang().postformat(i)},add:function(t,e){var i=H.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=H.duration(t,e);return this._milliseconds-=i._milliseconds,this._days-=i._days,this._months-=i._months,this._bubble(),this},get:function(t){return t=m(t),this[t.toLowerCase()+"s"]()},as:function(t){return t=m(t),this["as"+t.charAt(0).toUpperCase()+t.slice(1)+"s"]()},lang:H.fn.lang});for(U in le)le.hasOwnProperty(U)&&(z(U,le[U]),R(U.toLowerCase()));z("Weeks",6048e5),H.duration.fn.asMonths=function(){return(+this-31536e6*this.years())/2592e6+12*this.years()},H.lang("en",{ordinal:function(t){var e=t%10,i=1===~~(t%100/10)?"th":1===e?"st":2===e?"nd":3===e?"rd":"th";return t+i}}),B&&(i.exports=H),"undefined"==typeof ender&&(this.moment=H),"function"==typeof t&&t.amd&&t("moment",[],function(){return H})}).call(this)},{}],3:[function(e,i,n){function s(){this.subscriptions=[]}function o(t){if(this.id=O.randomUUID(),this.options=t||{},this.data={},this.fieldId=this.options.fieldId||"id",this.convert={},this.options.convert)for(var e in this.options.convert)if(this.options.convert.hasOwnProperty(e)){var i=this.options.convert[e];this.convert[e]="Date"==i||"ISODate"==i||"ASPDate"==i?"Date":i -}this.subscribers={},this.internalIds={}}function r(t,e){this.id=O.randomUUID(),this.data=null,this.ids={},this.options=e||{},this.fieldId="id",this.subscribers={};var i=this;this.listener=function(){i._onEvent.apply(i,arguments)},this.setData(t)}function a(t,e){this.parent=t,this.options=e||{},this.defaultOptions={order:function(t,e){if(t instanceof y){if(e instanceof y){var i=t.data.end-t.data.start,n=e.data.end-e.data.start;return i-n||t.data.start-e.data.start}return-1}return e instanceof y?1:t.data.start-e.data.start},margin:{item:10}},this.ordered=[]}function h(t){this.id=O.randomUUID(),this.start=0,this.end=0,this.options={min:null,max:null,zoomMin:null,zoomMax:null},this.listeners=[],this.setOptions(t)}function d(){this.id=O.randomUUID(),this.components={},this.repaintTimer=void 0,this.reflowTimer=void 0}function l(){this.id=null,this.parent=null,this.depends=null,this.controller=null,this.options=null,this.frame=null,this.top=0,this.left=0,this.width=0,this.height=0}function p(t,e,i){this.id=O.randomUUID(),this.parent=t,this.depends=e,this.options=i||{}}function c(t,e){this.id=O.randomUUID(),this.container=t,this.options=e||{},this.defaultOptions={autoResize:!0},this.listeners={}}function u(t,e,i){this.id=O.randomUUID(),this.parent=t,this.depends=e,this.dom={majorLines:[],majorTexts:[],minorLines:[],minorTexts:[],redundant:{majorLines:[],majorTexts:[],minorLines:[],minorTexts:[]}},this.props={range:{start:0,end:0,minimumStep:0},lineTop:0},this.options=i||{},this.defaultOptions={orientation:"bottom",showMinorLabels:!0,showMajorLabels:!0},this.conversion=null,this.range=null}function f(t,e,i){this.id=O.randomUUID(),this.parent=t,this.depends=e,this.options=i||{},this.defaultOptions={type:"box",align:"center",orientation:"bottom",margin:{axis:20,item:10},padding:5},this.dom={};var n=this;this.itemsData=null,this.range=null,this.listeners={add:function(t,e,i){i!=n.id&&n._onAdd(e.items)},update:function(t,e,i){i!=n.id&&n._onUpdate(e.items)},remove:function(t,e,i){i!=n.id&&n._onRemove(e.items)}},this.items={},this.queue={},this.stack=new a(this,Object.create(this.options)),this.conversion=null}function m(t,e,i,n){this.parent=t,this.data=e,this.dom=null,this.options=i||{},this.defaultOptions=n||{},this.selected=!1,this.visible=!1,this.top=0,this.left=0,this.width=0,this.height=0}function g(t,e,i,n){this.props={dot:{left:0,top:0,width:0,height:0},line:{top:0,left:0,width:0,height:0}},m.call(this,t,e,i,n)}function v(t,e,i,n){this.props={dot:{top:0,width:0,height:0},content:{height:0,marginLeft:0}},m.call(this,t,e,i,n)}function y(t,e,i,n){this.props={content:{left:0,width:0}},m.call(this,t,e,i,n)}function b(t,e,i){this.id=O.randomUUID(),this.parent=t,this.groupId=e,this.itemset=null,this.options=i||{},this.options.top=0,this.props={label:{width:0,height:0}},this.top=0,this.left=0,this.width=0,this.height=0}function w(t,e,i){this.id=O.randomUUID(),this.parent=t,this.depends=e,this.options=i||{},this.range=null,this.itemsData=null,this.groupsData=null,this.groups={},this.dom={},this.props={labels:{width:0}},this.queue={};var n=this;this.listeners={add:function(t,e){n._onAdd(e.items)},update:function(t,e){n._onUpdate(e.items)},remove:function(t,e){n._onRemove(e.items)}}}function _(t,e,i){var n=this;if(this.options=O.extend({orientation:"bottom",min:null,max:null,zoomMin:10,zoomMax:31536e10,showMinorLabels:!0,showMajorLabels:!0,autoResize:!1},i),this.controller=new d,!t)throw Error("No container element provided");var s=Object.create(this.options);s.height=function(){return n.options.height?n.options.height:n.timeaxis.height+n.content.height},this.rootPanel=new c(t,s),this.controller.add(this.rootPanel);var o=Object.create(this.options);o.left=function(){return n.labelPanel.width},o.width=function(){return n.rootPanel.width-n.labelPanel.width},o.top=null,o.height=null,this.itemPanel=new p(this.rootPanel,[],o),this.controller.add(this.itemPanel);var r=Object.create(this.options);r.top=null,r.left=null,r.height=null,r.width=function(){return n.content&&"function"==typeof n.content.getLabelsWidth?n.content.getLabelsWidth():0},this.labelPanel=new p(this.rootPanel,[],r),this.controller.add(this.labelPanel);var a=M().hours(0).minutes(0).seconds(0).milliseconds(0);this.range=new h({start:a.clone().add("days",-3).valueOf(),end:a.clone().add("days",4).valueOf()}),this.range.subscribe(this.rootPanel,"move","horizontal"),this.range.subscribe(this.rootPanel,"zoom","horizontal"),this.range.on("rangechange",function(){var t=!0;n.controller.requestReflow(t)}),this.range.on("rangechanged",function(){var t=!0;n.controller.requestReflow(t)});var l=Object.create(s);l.range=this.range,l.left=null,l.top=null,l.width="100%",l.height=null,this.timeaxis=new u(this.itemPanel,[],l),this.timeaxis.setRange(this.range),this.controller.add(this.timeaxis),this.setGroups(null),this.itemsData=null,this.groupsData=null,e&&this.setItems(e)}function E(t,e,i,n){this.selected=!1,this.edges=[],this.group=n.nodes.group,this.fontSize=n.nodes.fontSize,this.fontFace=n.nodes.fontFace,this.fontColor=n.nodes.fontColor,this.color=n.nodes.color,this.id=void 0,this.shape=n.nodes.shape,this.image=n.nodes.image,this.x=0,this.y=0,this.xFixed=!1,this.yFixed=!1,this.radius=n.nodes.radius,this.radiusFixed=!1,this.radiusMin=n.nodes.radiusMin,this.radiusMax=n.nodes.radiusMax,this.imagelist=e,this.grouplist=i,this.setProperties(t,n),this.mass=50,this.fx=0,this.fy=0,this.vx=0,this.vy=0,this.minForce=n.minForce,this.damping=.9}function T(t,e,i){if(!e)throw"No graph provided";this.graph=e,this.widthMin=i.edges.widthMin,this.widthMax=i.edges.widthMax,this.id=void 0,this.fromId=void 0,this.toId=void 0,this.style=i.edges.style,this.title=void 0,this.width=i.edges.width,this.value=void 0,this.length=i.edges.length,this.from=null,this.to=null,this.connected=!1,this.dash=O.extend({},i.edges.dash),this.stiffness=void 0,this.color=i.edges.color,this.widthFixed=!1,this.lengthFixed=!1,this.setProperties(t,i)}function x(t,e,i,n){this.container=t?t:document.body,this.x=0,this.y=0,this.padding=5,void 0!==e&&void 0!==i&&this.setPosition(e,i),void 0!==n&&this.setText(n),this.frame=document.createElement("div");var s=this.frame.style;s.position="absolute",s.visibility="hidden",s.border="1px solid #666",s.color="black",s.padding=this.padding+"px",s.backgroundColor="#FFFFC6",s.borderRadius="3px",s.MozBorderRadius="3px",s.WebkitBorderRadius="3px",s.boxShadow="3px 3px 10px rgba(128, 128, 128, 0.5)",s.whiteSpace="nowrap",this.container.appendChild(this.frame)}function S(t,e,i){this.containerElement=t,this.width="100%",this.height="100%",this.refreshRate=50,this.stabilize=!0,this.selectable=!0,this.constants={nodes:{radiusMin:5,radiusMax:20,radius:5,distance:100,shape:"ellipse",image:void 0,widthMin:16,widthMax:64,fontColor:"black",fontSize:14,fontFace:"arial",color:{border:"#2B7CE9",background:"#97C2FC",highlight:{border:"#2B7CE9",background:"#D2E5FF"}},borderColor:"#2B7CE9",backgroundColor:"#97C2FC",highlightColor:"#D2E5FF",group:void 0},edges:{widthMin:1,widthMax:15,width:1,style:"line",color:"#343434",fontColor:"#343434",fontSize:14,fontFace:"arial",length:100,dash:{length:10,gap:5,altLength:void 0}},minForce:.05,minVelocity:.02,maxIterations:1e3};var n=this;this.nodes={},this.edges={},this.nodesData=null,this.edgesData=null;var s=this;this.nodesListeners={add:function(t,e){s._addNodes(e.items),s.start()},update:function(t,e){s._updateNodes(e.items),s.start()},remove:function(t,e){s._removeNodes(e.items),s.start()}},this.edgesListeners={add:function(t,e){s._addEdges(e.items),s.start()},update:function(t,e){s._updateEdges(e.items),s.start()},remove:function(t,e){s._removeEdges(e.items),s.start()}},this.groups=new Groups,this.images=new Images,this.images.setOnloadCallback(function(){n._redraw()}),this.moving=!1,this.selection=[],this.timer=void 0,this._create(),this.setOptions(i),this.setData(e)}var M="undefined"!=typeof window&&window.moment||e("moment"),D="undefined"!=typeof window&&window.Hammer||e("hammerjs");if(!Array.prototype.indexOf){Array.prototype.indexOf=function(t){for(var e=0;this.length>e;e++)if(this[e]==t)return e;return-1};try{console.log("Warning: Ancient browser detected. Please update your browser")}catch(C){}}Array.prototype.forEach||(Array.prototype.forEach=function(t,e){for(var i=0,n=this.length;n>i;++i)t.call(e||this,this[i],i,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var i,n,s;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),r=o.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(i=e),n=Array(r),s=0;r>s;){var a,h;s in o&&(a=o[s],h=t.call(i,a,s,o),n[s]=h),s++}return n}),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 n=[],s=arguments[1],o=0;i>o;o++)if(o in e){var r=e[o];t.call(s,r,o,e)&&n.push(r)}return n}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),i=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=i.length;return function(s){if("object"!=typeof s&&"function"!=typeof s||null===s)throw new TypeError("Object.keys called on non-object");var o=[];for(var r in s)t.call(s,r)&&o.push(r);if(e)for(var a=0;n>a;a++)t.call(s,i[a])&&o.push(i[a]);return o}}()),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s}),Object.create||(Object.create=function(t){function e(){}if(arguments.length>1)throw 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,n=function(){},s=function(){return i.apply(this instanceof n&&t?this:t,e.concat(Array.prototype.slice.call(arguments)))};return n.prototype=this.prototype,s.prototype=new n,s});var O={};O.isNumber=function(t){return t instanceof Number||"number"==typeof t},O.isString=function(t){return t instanceof String||"string"==typeof t},O.isDate=function(t){if(t instanceof Date)return!0;if(O.isString(t)){var e=N.exec(t);if(e)return!0;if(!isNaN(Date.parse(t)))return!0}return!1},O.isDataTable=function(t){return"undefined"!=typeof google&&google.visualization&&google.visualization.DataTable&&t instanceof google.visualization.DataTable},O.randomUUID=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},O.extend=function(t){for(var e=1,i=arguments.length;i>e;e++){var n=arguments[e];for(var s in n)n.hasOwnProperty(s)&&void 0!==n[s]&&(t[s]=n[s])}return t},O.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 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 t+"";case"Date":if(O.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(M.isMoment(t))return new Date(t.valueOf());if(O.isString(t))return i=N.exec(t),i?new Date(Number(i[1])):M(t).toDate();throw Error("Cannot convert object of type "+O.getType(t)+" to type Date");case"Moment":if(O.isNumber(t))return M(t);if(t instanceof Date)return M(t.valueOf());if(M.isMoment(t))return M.clone();if(O.isString(t))return i=N.exec(t),i?M(Number(i[1])):M(t);throw Error("Cannot convert object of type "+O.getType(t)+" to type Date");case"ISODate":if(O.isNumber(t))return new Date(t);if(t instanceof Date)return t.toISOString();if(M.isMoment(t))return t.toDate().toISOString();if(O.isString(t))return i=N.exec(t),i?new Date(Number(i[1])).toISOString():new Date(t).toISOString();throw Error("Cannot convert object of type "+O.getType(t)+" to type ISODate");case"ASPDate":if(O.isNumber(t))return"/Date("+t+")/";if(t instanceof Date)return"/Date("+t.valueOf()+")/";if(O.isString(t)){i=N.exec(t);var n;return n=i?new Date(Number(i[1])).valueOf():new Date(t).valueOf(),"/Date("+n+")/"}throw Error("Cannot convert object of type "+O.getType(t)+" to type ASPDate");default:throw Error("Cannot convert object of type "+O.getType(t)+' to type "'+e+'"')}};var N=/^\/?Date\((\-?\d+)/i;O.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},O.getAbsoluteLeft=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetLeft,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetLeft,n-=s.scrollLeft,s=s.offsetParent;return n},O.getAbsoluteTop=function(t){for(var e=document.documentElement,i=document.body,n=t.offsetTop,s=t.offsetParent;null!=s&&s!=i&&s!=e;)n+=s.offsetTop,n-=s.scrollTop,s=s.offsetParent;return n},O.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,n=document.body;return e+(i&&i.scrollTop||n&&n.scrollTop||0)-(i&&i.clientTop||n&&n.clientTop||0)},O.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,n=document.body;return e+(i&&i.scrollLeft||n&&n.scrollLeft||0)-(i&&i.clientLeft||n&&n.clientLeft||0)},O.addClassName=function(t,e){var i=t.className.split(" ");-1==i.indexOf(e)&&(i.push(e),t.className=i.join(" "))},O.removeClassName=function(t,e){var i=t.className.split(" "),n=i.indexOf(e);-1!=n&&(i.splice(n,1),t.className=i.join(" "))},O.forEach=function(t,e){var i,n;if(t instanceof Array)for(i=0,n=t.length;n>i;i++)e(t[i],i,t);else for(i in t)t.hasOwnProperty(i)&&e(t[i],i,t)},O.updateProperty=function(t,e,i){return t[e]!==i?(t[e]=i,!0):!1},O.addEventListener=function(t,e,i,n){t.addEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.addEventListener(e,i,n)):t.attachEvent("on"+e,i)},O.removeEventListener=function(t,e,i,n){t.removeEventListener?(void 0===n&&(n=!1),"mousewheel"===e&&navigator.userAgent.indexOf("Firefox")>=0&&(e="DOMMouseScroll"),t.removeEventListener(e,i,n)):t.detachEvent("on"+e,i)},O.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},O.stopPropagation=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},O.preventDefault=function(t){t||(t=window.event),t.preventDefault?t.preventDefault():t.returnValue=!1},O.option={},O.option.asBoolean=function(t,e){return"function"==typeof t&&(t=t()),null!=t?0!=t:e||null},O.option.asNumber=function(t,e){return"function"==typeof t&&(t=t()),null!=t?Number(t)||e||null:e||null},O.option.asString=function(t,e){return"function"==typeof t&&(t=t()),null!=t?t+"":e||null},O.option.asSize=function(t,e){return"function"==typeof t&&(t=t()),O.isString(t)?t:O.isNumber(t)?t+"px":e||null},O.option.asElement=function(t,e){return"function"==typeof t&&(t=t()),t||e||null},O.loadCss=function(t){if("undefined"!=typeof document){var e=document.createElement("style");e.type="text/css",e.styleSheet?e.styleSheet.cssText=t:e.appendChild(document.createTextNode(t)),document.getElementsByTagName("head")[0].appendChild(e)}};var L={listeners:[],indexOf:function(t){for(var e=this.listeners,i=0,n=this.listeners.length;n>i;i++){var s=e[i];if(s&&s.object==t)return i}return-1},addListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];s||(s={object:t,events:{}},this.listeners.push(s));var o=s.events[e];o||(o=[],s.events[e]=o),-1==o.indexOf(i)&&o.push(i)},removeListener:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];o&&(n=o.indexOf(i),-1!=n&&o.splice(n,1),0==o.length&&delete s.events[e]);var r=0,a=s.events;for(var h in a)a.hasOwnProperty(h)&&r++;0==r&&delete this.listeners[n]}},removeAllListeners:function(){this.listeners=[]},trigger:function(t,e,i){var n=this.indexOf(t),s=this.listeners[n];if(s){var o=s.events[e];if(o)for(var r=0,a=o.length;a>r;r++)o[r](i)}}};s.prototype.on=function(t,e,i){var n=t instanceof RegExp?t:RegExp(t.replace("*","\\w+")),s={id:O.randomUUID(),event:t,regexp:n,callback:"function"==typeof e?e:null,target:i};return this.subscriptions.push(s),s.id},s.prototype.off=function(t){for(var e=0;this.subscriptions.length>e;){var i=this.subscriptions[e],n=!0;if(t instanceof Object)for(var s in t)t.hasOwnProperty(s)&&t[s]!==i[s]&&(n=!1);else n=i.id==t;n?this.subscriptions.splice(e,1):e++}},s.prototype.emit=function(t,e,i){for(var n=0;this.subscriptions.length>n;n++){var s=this.subscriptions[n];s.regexp.test(t)&&s.callback&&s.callback(t,e,i)}},o.prototype.subscribe=function(t,e){var i=this.subscribers[t];i||(i=[],this.subscribers[t]=i),i.push({callback:e})},o.prototype.unsubscribe=function(t,e){var i=this.subscribers[t];i&&(this.subscribers[t]=i.filter(function(t){return t.callback!=e}))},o.prototype._trigger=function(t,e,i){if("*"==t)throw Error("Cannot trigger event *");var n=[];t in this.subscribers&&(n=n.concat(this.subscribers[t])),"*"in this.subscribers&&(n=n.concat(this.subscribers["*"]));for(var s=0;n.length>s;s++){var o=n[s];o.callback&&o.callback(t,e,i||null)}},o.prototype.add=function(t,e){var i,n=[],s=this;if(t instanceof Array)for(var o=0,r=t.length;r>o;o++)i=s._addItem(t[o]),n.push(i);else if(O.isDataTable(t))for(var a=this._getColumnNames(t),h=0,d=t.getNumberOfRows();d>h;h++){for(var l={},p=0,c=a.length;c>p;p++){var u=a[p];l[u]=t.getValue(h,p)}i=s._addItem(l),n.push(i)}else{if(!(t instanceof Object))throw Error("Unknown dataType");i=s._addItem(t),n.push(i)}return n.length&&this._trigger("add",{items:n},e),n},o.prototype.update=function(t,e){var i=[],n=[],s=this,o=s.fieldId,r=function(t){var e=t[o];s.data[e]?(e=s._updateItem(t),n.push(e)):(e=s._addItem(t),i.push(e))};if(t instanceof Array)for(var a=0,h=t.length;h>a;a++)r(t[a]);else if(O.isDataTable(t))for(var d=this._getColumnNames(t),l=0,p=t.getNumberOfRows();p>l;l++){for(var c={},u=0,f=d.length;f>u;u++){var m=d[u];c[m]=t.getValue(l,u)}r(c)}else{if(!(t instanceof Object))throw Error("Unknown dataType");r(t)}return i.length&&this._trigger("add",{items:i},e),n.length&&this._trigger("update",{items:n},e),i.concat(n)},o.prototype.get=function(){var t,e,i,n,s=this,o=O.getType(arguments[0]);"String"==o||"Number"==o?(t=arguments[0],i=arguments[1],n=arguments[2]):"Array"==o?(e=arguments[0],i=arguments[1],n=arguments[2]):(i=arguments[0],n=arguments[1]);var r;if(i&&i.type){if(r="DataTable"==i.type?"DataTable":"Array",n&&r!=O.getType(n))throw Error('Type of parameter "data" ('+O.getType(n)+") "+"does not correspond with specified options.type ("+i.type+")");if("DataTable"==r&&!O.isDataTable(n))throw Error('Parameter "data" must be a DataTable when options.type is "DataTable"')}else r=n?"DataTable"==O.getType(n)?"DataTable":"Array":"Array";var a,h,d,l,p=i&&i.convert||this.options.convert,c=i&&i.filter,u=[];if(void 0!=t)a=s._getItem(t,p),c&&!c(a)&&(a=null);else if(void 0!=e)for(d=0,l=e.length;l>d;d++)a=s._getItem(e[d],p),(!c||c(a))&&u.push(a);else for(h in this.data)this.data.hasOwnProperty(h)&&(a=s._getItem(h,p),(!c||c(a))&&u.push(a));if(i&&i.order&&void 0==t&&this._sort(u,i.order),i&&i.fields){var f=i.fields;if(void 0!=t)a=this._filterFields(a,f);else for(d=0,l=u.length;l>d;d++)u[d]=this._filterFields(u[d],f)}if("DataTable"==r){var m=this._getColumnNames(n);if(void 0!=t)s._appendRow(n,m,a);else for(d=0,l=u.length;l>d;d++)s._appendRow(n,m,u[d]);return n}if(void 0!=t)return a;if(n){for(d=0,l=u.length;l>d;d++)n.push(u[d]);return n}return u},o.prototype.getIds=function(t){var e,i,n,s,o,r=this.data,a=t&&t.filter,h=t&&t.order,d=t&&t.convert||this.options.convert,l=[];if(a)if(h){o=[];for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&o.push(s));for(this._sort(o,h),e=0,i=o.length;i>e;e++)l[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=this._getItem(n,d),a(s)&&l.push(s[this.fieldId]));else if(h){o=[];for(n in r)r.hasOwnProperty(n)&&o.push(r[n]);for(this._sort(o,h),e=0,i=o.length;i>e;e++)l[e]=o[e][this.fieldId]}else for(n in r)r.hasOwnProperty(n)&&(s=r[n],l.push(s[this.fieldId]));return l},o.prototype.forEach=function(t,e){var i,n,s=e&&e.filter,o=e&&e.convert||this.options.convert,r=this.data;if(e&&e.order)for(var a=this.get(e),h=0,d=a.length;d>h;h++)i=a[h],n=i[this.fieldId],t(i,n);else for(n in r)r.hasOwnProperty(n)&&(i=this._getItem(n,o),(!s||s(i))&&t(i,n))},o.prototype.map=function(t,e){var i,n=e&&e.filter,s=e&&e.convert||this.options.convert,o=[],r=this.data;for(var a in r)r.hasOwnProperty(a)&&(i=this._getItem(a,s),(!n||n(i))&&o.push(t(i,a)));return e&&e.order&&this._sort(o,e.order),o},o.prototype._filterFields=function(t,e){var i={};for(var n in t)t.hasOwnProperty(n)&&-1!=e.indexOf(n)&&(i[n]=t[n]);return i},o.prototype._sort=function(t,e){if(O.isString(e)){var i=e;t.sort(function(t,e){var n=t[i],s=e[i];return n>s?1:s>n?-1:0})}else{if("function"!=typeof e)throw new TypeError("Order must be a function or a string");t.sort(e)}},o.prototype.remove=function(t,e){var i,n,s,o=[];if(t instanceof Array)for(i=0,n=t.length;n>i;i++)s=this._remove(t[i]),null!=s&&o.push(s);else s=this._remove(t),null!=s&&o.push(s);return o.length&&this._trigger("remove",{items:o},e),o},o.prototype._remove=function(t){if(O.isNumber(t)||O.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},o.prototype.clear=function(t){var e=Object.keys(this.data);return this.data={},this.internalIds={},this._trigger("remove",{items:e},t),e},o.prototype.max=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||r>n)&&(i=o,n=r)}return i},o.prototype.min=function(t){var e=this.data,i=null,n=null;for(var s in e)if(e.hasOwnProperty(s)){var o=e[s],r=o[t];null!=r&&(!i||n>r)&&(i=o,n=r)}return i},o.prototype.distinct=function(t){var e=this.data,i=[],n=this.options.convert[t],s=0;for(var o in e)if(e.hasOwnProperty(o)){for(var r=e[o],a=O.convert(r[t],n),h=!1,d=0;s>d;d++)if(i[d]==a){h=!0;break}h||(i[s]=a,s++)}return i},o.prototype._addItem=function(t){var e=t[this.fieldId];if(void 0!=e){if(this.data[e])throw Error("Cannot add item: item with id "+e+" already exists")}else e=O.randomUUID(),t[this.fieldId]=e,this.internalIds[e]=t;var i={};for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=O.convert(t[n],s)}return this.data[e]=i,e},o.prototype._getItem=function(t,e){var i,n,s=this.data[t];if(!s)return null;var o={},r=this.fieldId,a=this.internalIds;if(e)for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a||(o[i]=O.convert(n,e[i])));else for(i in s)s.hasOwnProperty(i)&&(n=s[i],i==r&&n in a||(o[i]=n));return o},o.prototype._updateItem=function(t){var e=t[this.fieldId];if(void 0==e)throw Error("Cannot update item: item has no id (item: "+JSON.stringify(t)+")");var i=this.data[e];if(!i)throw Error("Cannot update item: no item with id "+e+" found");for(var n in t)if(t.hasOwnProperty(n)){var s=this.convert[n];i[n]=O.convert(t[n],s)}return e},o.prototype._getColumnNames=function(t){for(var e=[],i=0,n=t.getNumberOfColumns();n>i;i++)e[i]=t.getColumnId(i)||t.getColumnLabel(i);return e},o.prototype._appendRow=function(t,e,i){for(var n=t.addRow(),s=0,o=e.length;o>s;s++){var r=e[s];t.setValue(n,s,i[r])}},r.prototype.setData=function(t){var e,i,n;if(this.data){this.data.unsubscribe&&this.data.unsubscribe("*",this.listener),e=[];for(var s in this.ids)this.ids.hasOwnProperty(s)&&e.push(s);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,n=e.length;n>i;i++)s=e[i],this.ids[s]=!0;this._trigger("add",{items:e}),this.data.subscribe&&this.data.subscribe("*",this.listener)}},r.prototype.get=function(){var t,e,i,n=this,s=O.getType(arguments[0]);"String"==s||"Number"==s||"Array"==s?(t=arguments[0],e=arguments[1],i=arguments[2]):(e=arguments[0],i=arguments[1]);var o=O.extend({},this.options,e);this.options.filter&&e&&e.filter&&(o.filter=function(t){return n.options.filter(t)&&e.filter(t)});var r=[];return void 0!=t&&r.push(t),r.push(o),r.push(i),this.data&&this.data.get.apply(this.data,r)},r.prototype.getIds=function(t){var e;if(this.data){var i,n=this.options.filter;i=t&&t.filter?n?function(e){return n(e)&&t.filter(e)}:t.filter:n,e=this.data.getIds({filter:i,order:t&&t.order})}else e=[];return e},r.prototype._onEvent=function(t,e,i){var n,s,o,r,a=e&&e.items,h=this.data,d=[],l=[],p=[];if(a&&h){switch(t){case"add":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r&&(this.ids[o]=!0,d.push(o));break;case"update":for(n=0,s=a.length;s>n;n++)o=a[n],r=this.get(o),r?this.ids[o]?l.push(o):(this.ids[o]=!0,d.push(o)):this.ids[o]&&(delete this.ids[o],p.push(o));break;case"remove":for(n=0,s=a.length;s>n;n++)o=a[n],this.ids[o]&&(delete this.ids[o],p.push(o))}d.length&&this._trigger("add",{items:d},i),l.length&&this._trigger("update",{items:l},i),p.length&&this._trigger("remove",{items:p},i)}},r.prototype.subscribe=o.prototype.subscribe,r.prototype.unsubscribe=o.prototype.unsubscribe,r.prototype._trigger=o.prototype._trigger,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){t instanceof Date&&e instanceof Date&&(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);break;default:}},TimeStep.prototype.hasNext=function(){return this.current.valueOf()<=this._end.valueOf()},TimeStep.prototype.next=function(){var t=this.current.valueOf();if(6>this.current.getMonth())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()+60*1e3*this.step);break;case TimeStep.SCALE.HOUR:this.current=new Date(this.current.valueOf()+60*60*1e3*this.step);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);break;default:}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);break;default:}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,n=864e5,s=36e5,o=6e4,r=1e3,a=1;1e3*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1e3),500*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=500),100*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=100),50*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=50),10*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=10),5*e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=5),e>t&&(this.scale=TimeStep.SCALE.YEAR,this.step=1),3*i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=3),i>t&&(this.scale=TimeStep.SCALE.MONTH,this.step=1),5*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=5),2*n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=2),n>t&&(this.scale=TimeStep.SCALE.DAY,this.step=1),n/2>t&&(this.scale=TimeStep.SCALE.WEEKDAY,this.step=1),4*s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=4),s>t&&(this.scale=TimeStep.SCALE.HOUR,this.step=1),15*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=15),10*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=10),5*o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=5),o>t&&(this.scale=TimeStep.SCALE.MINUTE,this.step=1),15*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=15),10*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=10),5*r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=5),r>t&&(this.scale=TimeStep.SCALE.SECOND,this.step=1),200*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=200),100*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=100),50*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=50),10*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=10),5*a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=5),a>t&&(this.scale=TimeStep.SCALE.MILLISECOND,this.step=1) -}},TimeStep.prototype.snap=function(t){if(this.scale==TimeStep.SCALE.YEAR){var e=t.getFullYear()+Math.round(t.getMonth()/12);t.setFullYear(Math.round(e/this.step)*this.step),t.setMonth(0),t.setDate(0),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MONTH)t.getDate()>15?(t.setDate(1),t.setMonth(t.getMonth()+1)):t.setDate(1),t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0);else if(this.scale==TimeStep.SCALE.DAY||this.scale==TimeStep.SCALE.WEEKDAY){switch(this.step){case 5:case 2:t.setHours(24*Math.round(t.getHours()/24));break;default:t.setHours(12*Math.round(t.getHours()/12))}t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.HOUR){switch(this.step){case 4:t.setMinutes(60*Math.round(t.getMinutes()/60));break;default:t.setMinutes(30*Math.round(t.getMinutes()/30))}t.setSeconds(0),t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.MINUTE){switch(this.step){case 15:case 10:t.setMinutes(5*Math.round(t.getMinutes()/5)),t.setSeconds(0);break;case 5:t.setSeconds(60*Math.round(t.getSeconds()/60));break;default:t.setSeconds(30*Math.round(t.getSeconds()/30))}t.setMilliseconds(0)}else if(this.scale==TimeStep.SCALE.SECOND)switch(this.step){case 15:case 10:t.setSeconds(5*Math.round(t.getSeconds()/5)),t.setMilliseconds(0);break;case 5:t.setMilliseconds(1e3*Math.round(t.getMilliseconds()/1e3));break;default:t.setMilliseconds(500*Math.round(t.getMilliseconds()/500))}else if(this.scale==TimeStep.SCALE.MILLISECOND){var i=this.step>5?this.step/2:1;t.setMilliseconds(Math.round(t.getMilliseconds()/i)*i)}},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 M(t).format("SSS");case TimeStep.SCALE.SECOND:return M(t).format("s");case TimeStep.SCALE.MINUTE:return M(t).format("HH:mm");case TimeStep.SCALE.HOUR:return M(t).format("HH:mm");case TimeStep.SCALE.WEEKDAY:return M(t).format("ddd D");case TimeStep.SCALE.DAY:return M(t).format("D");case TimeStep.SCALE.MONTH:return M(t).format("MMM");case TimeStep.SCALE.YEAR:return M(t).format("YYYY");default:return""}},TimeStep.prototype.getLabelMajor=function(t){switch(void 0==t&&(t=this.current),this.scale){case TimeStep.SCALE.MILLISECOND:return M(t).format("HH:mm:ss");case TimeStep.SCALE.SECOND:return M(t).format("D MMMM HH:mm");case TimeStep.SCALE.MINUTE:case TimeStep.SCALE.HOUR:return M(t).format("ddd D MMMM");case TimeStep.SCALE.WEEKDAY:case TimeStep.SCALE.DAY:return M(t).format("MMMM YYYY");case TimeStep.SCALE.MONTH:return M(t).format("YYYY");case TimeStep.SCALE.YEAR:return"";default:return""}},a.prototype.setOptions=function(t){O.extend(this.options,t)},a.prototype.update=function(){this._order(),this._stack()},a.prototype._order=function(){var t=this.parent.items;if(!t)throw Error("Cannot stack items: parent does not contain items");var e=[],i=0;O.forEach(t,function(t){t.visible&&(e[i]=t,i++)});var n=this.options.order||this.defaultOptions.order;if("function"!=typeof n)throw Error("Option order must be a function");e.sort(n),this.ordered=e},a.prototype._stack=function(){var t,e,i,n=this.ordered,s=this.options,o=s.orientation||this.defaultOptions.orientation,r="top"==o;for(i=s.margin&&void 0!==s.margin.item?s.margin.item:this.defaultOptions.margin.item,t=0,e=n.length;e>t;t++){var a=n[t],h=null;do h=this.checkOverlap(n,t,0,t-1,i),null!=h&&(a.top=r?h.top+h.height+i:h.top-a.height-i);while(h)}},a.prototype.checkOverlap=function(t,e,i,n,s){for(var o=this.collision,r=t[e],a=n;a>=i;a--){var h=t[a];if(o(r,h,s)&&a!=e)return h}return null},a.prototype.collision=function(t,e,i){return t.left-ie.left&&t.top-ie.top},h.prototype.setOptions=function(t){O.extend(this.options,t),(null!=t.start||null!=t.end)&&this.setRange(t.start,t.end)},h.prototype.subscribe=function(t,e,i){var n,s=this;if("horizontal"!=i&&"vertical"!=i)throw new TypeError('Unknown direction "'+i+'". '+'Choose "horizontal" or "vertical".');if("move"==e)n={component:t,event:e,direction:i,callback:function(t){s._onMouseDown(t,n)},params:{}},t.on("mousedown",n.callback),s.listeners.push(n);else{if("zoom"!=e)throw new TypeError('Unknown event "'+e+'". '+'Choose "move" or "zoom".');n={component:t,event:e,direction:i,callback:function(t){s._onMouseWheel(t,n)},params:{}},t.on("mousewheel",n.callback),s.listeners.push(n)}},h.prototype.on=function(t,e){L.addListener(this,t,e)},h.prototype._trigger=function(t){L.trigger(this,t,{start:this.start,end:this.end})},h.prototype.setRange=function(t,e){var i=this._applyRange(t,e);i&&(this._trigger("rangechange"),this._trigger("rangechanged"))},h.prototype._applyRange=function(t,e){var i,n=null!=t?O.convert(t,"Number"):this.start,s=null!=e?O.convert(e,"Number"):this.end;if(isNaN(n))throw Error('Invalid start "'+t+'"');if(isNaN(s))throw Error('Invalid end "'+e+'"');if(n>s&&(s=n),null!=this.options.min){var o=this.options.min.valueOf();o>n&&(i=o-n,n+=i,s+=i)}if(null!=this.options.max){var r=this.options.max.valueOf();s>r&&(i=s-r,n-=i,s-=i)}if(null!=this.options.zoomMin){var a=this.options.zoomMin.valueOf();0>a&&(a=0),a>s-n&&(this.end-this.start>a?(i=a-(s-n),n-=i/2,s+=i/2):(n=this.start,s=this.end))}if(null!=this.options.zoomMax){var h=this.options.zoomMax.valueOf();0>h&&(h=0),s-n>h&&(h>this.end-this.start?(i=s-n-h,n+=i/2,s-=i/2):(n=this.start,s=this.end))}var d=this.start!=n||this.end!=s;return this.start=n,this.end=s,d},h.prototype.getRange=function(){return{start:this.start,end:this.end}},h.prototype.conversion=function(t){return this.start,this.end,h.conversion(this.start,this.end,t)},h.conversion=function(t,e,i){return 0!=i&&0!=e-t?{offset:t,factor:i/(e-t)}:{offset:0,factor:1}},h.prototype._onMouseDown=function(t,e){t=t||window.event;var i=e.params,n=t.which?1==t.which:1==t.button;if(n){i.mouseX=O.getPageX(t),i.mouseY=O.getPageY(t),i.previousLeft=0,i.previousOffset=0,i.moved=!1,i.start=this.start,i.end=this.end;var s=e.component.frame;s&&(s.style.cursor="move");var o=this;i.onMouseMove||(i.onMouseMove=function(t){o._onMouseMove(t,e)},O.addEventListener(document,"mousemove",i.onMouseMove)),i.onMouseUp||(i.onMouseUp=function(t){o._onMouseUp(t,e)},O.addEventListener(document,"mouseup",i.onMouseUp)),O.preventDefault(t)}},h.prototype._onMouseMove=function(t,e){t=t||window.event;var i=e.params,n=O.getPageX(t),s=O.getPageY(t);void 0==i.mouseX&&(i.mouseX=n),void 0==i.mouseY&&(i.mouseY=s);var o=n-i.mouseX,r=s-i.mouseY,a="horizontal"==e.direction?o:r;Math.abs(a)>=1&&(i.moved=!0);var h=i.end-i.start,d="horizontal"==e.direction?e.component.width:e.component.height,l=-a/d*h;this._applyRange(i.start+l,i.end+l),this._trigger("rangechange"),O.preventDefault(t)},h.prototype._onMouseUp=function(t,e){t=t||window.event;var i=e.params;e.component.frame&&(e.component.frame.style.cursor="auto"),i.onMouseMove&&(O.removeEventListener(document,"mousemove",i.onMouseMove),i.onMouseMove=null),i.onMouseUp&&(O.removeEventListener(document,"mouseup",i.onMouseUp),i.onMouseUp=null),i.moved&&this._trigger("rangechanged")},h.prototype._onMouseWheel=function(t,e){t=t||window.event;var i=0;if(t.wheelDelta?i=t.wheelDelta/120:t.detail&&(i=-t.detail/3),i){var n=this,s=function(){var s=i/5,o=null,r=e.component.frame;if(r){var a,h;if("horizontal"==e.direction){a=e.component.width,h=n.conversion(a);var d=O.getAbsoluteLeft(r),l=O.getPageX(t);o=(l-d)/h.factor+h.offset}else{a=e.component.height,h=n.conversion(a);var p=O.getAbsoluteTop(r),c=O.getPageY(t);o=(p+a-c-p)/h.factor+h.offset}}n.zoom(s,o)};s()}O.preventDefault(t)},h.prototype.zoom=function(t,e){null==e&&(e=(this.start+this.end)/2),t>=1&&(t=.9),-1>=t&&(t=-.9),0>t&&(t/=1+t);var i=this.start-e,n=this.end-e,s=this.start-i*t,o=this.end-n*t;this.setRange(s,o)},h.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,n=this.end+e*t;this.start=i,this.end=n},h.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,n=this.start-i,s=this.end-i;this.setRange(n,s)},d.prototype.add=function(t){if(void 0==t.id)throw Error("Component has no field id");if(!(t instanceof l||t instanceof d))throw new TypeError("Component must be an instance of prototype Component or Controller");t.controller=this,this.components[t.id]=t},d.prototype.remove=function(t){var e;for(e in this.components)if(this.components.hasOwnProperty(e)&&(e==t||this.components[e]==t))break;e&&delete this.components[e]},d.prototype.requestReflow=function(t){if(t)this.reflow();else if(!this.reflowTimer){var e=this;this.reflowTimer=setTimeout(function(){e.reflowTimer=void 0,e.reflow()},0)}},d.prototype.requestRepaint=function(t){if(t)this.repaint();else if(!this.repaintTimer){var e=this;this.repaintTimer=setTimeout(function(){e.repaintTimer=void 0,e.repaint()},0)}},d.prototype.repaint=function(){function t(n,s){s in i||(n.depends&&n.depends.forEach(function(e){t(e,e.id)}),n.parent&&t(n.parent,n.parent.id),e=n.repaint()||e,i[s]=!0)}var e=!1;this.repaintTimer&&(clearTimeout(this.repaintTimer),this.repaintTimer=void 0);var i={};O.forEach(this.components,t),e&&this.reflow()},d.prototype.reflow=function(){function t(n,s){s in i||(n.depends&&n.depends.forEach(function(e){t(e,e.id)}),n.parent&&t(n.parent,n.parent.id),e=n.reflow()||e,i[s]=!0)}var e=!1;this.reflowTimer&&(clearTimeout(this.reflowTimer),this.reflowTimer=void 0);var i={};O.forEach(this.components,t),e&&this.repaint()},l.prototype.setOptions=function(t){t&&(O.extend(this.options,t),this.controller&&(this.requestRepaint(),this.requestReflow()))},l.prototype.getOption=function(t){var e;return this.options&&(e=this.options[t]),void 0===e&&this.defaultOptions&&(e=this.defaultOptions[t]),e},l.prototype.getContainer=function(){return null},l.prototype.getFrame=function(){return this.frame},l.prototype.repaint=function(){return!1},l.prototype.reflow=function(){return!1},l.prototype.hide=function(){return this.frame&&this.frame.parentNode?(this.frame.parentNode.removeChild(this.frame),!0):!1},l.prototype.show=function(){return this.frame&&this.frame.parentNode?!1:this.repaint()},l.prototype.requestRepaint=function(){if(!this.controller)throw Error("Cannot request a repaint: no controller configured");this.controller.requestRepaint()},l.prototype.requestReflow=function(){if(!this.controller)throw Error("Cannot request a reflow: no controller configured");this.controller.requestReflow()},p.prototype=new l,p.prototype.setOptions=l.prototype.setOptions,p.prototype.getContainer=function(){return this.frame},p.prototype.repaint=function(){var t=0,e=O.updateProperty,i=O.option.asSize,n=this.options,s=this.frame;if(!s){s=document.createElement("div"),s.className="panel";var o=n.className;o&&("function"==typeof o?O.addClassName(s,o()+""):O.addClassName(s,o+"")),this.frame=s,t+=1}if(!s.parentNode){if(!this.parent)throw Error("Cannot repaint panel: no parent attached");var r=this.parent.getContainer();if(!r)throw Error("Cannot repaint panel: parent has no container element");r.appendChild(s),t+=1}return t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),t>0},p.prototype.reflow=function(){var t=0,e=O.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},c.prototype=new p,c.prototype.setOptions=l.prototype.setOptions,c.prototype.repaint=function(){var t=0,e=O.updateProperty,i=O.option.asSize,n=this.options,s=this.frame;if(!s){s=document.createElement("div"),s.className="vis timeline rootpanel";var o=n.className;o&&O.addClassName(s,O.option.asString(o)),this.frame=s,t+=1}if(!s.parentNode){if(!this.container)throw Error("Cannot repaint root panel: no container attached");this.container.appendChild(s),t+=1}return t+=e(s.style,"top",i(n.top,"0px")),t+=e(s.style,"left",i(n.left,"0px")),t+=e(s.style,"width",i(n.width,"100%")),t+=e(s.style,"height",i(n.height,"100%")),this._updateEventEmitters(),this._updateWatch(),t>0},c.prototype.reflow=function(){var t=0,e=O.updateProperty,i=this.frame;return i?(t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft),t+=e(this,"width",i.offsetWidth),t+=e(this,"height",i.offsetHeight)):t+=1,t>0},c.prototype._updateWatch=function(){var t=this.getOption("autoResize");t?this._watch():this._unwatch()},c.prototype._watch=function(){var t=this;this._unwatch();var e=function(){var e=t.getOption("autoResize");return e?(t.frame&&(t.frame.clientWidth!=t.width||t.frame.clientHeight!=t.height)&&t.requestReflow(),void 0):(t._unwatch(),void 0)};O.addEventListener(window,"resize",e),this.watchTimer=setInterval(e,1e3)},c.prototype._unwatch=function(){this.watchTimer&&(clearInterval(this.watchTimer),this.watchTimer=void 0)},c.prototype.on=function(t,e){var i=this.listeners[t];i||(i=[],this.listeners[t]=i),i.push(e),this._updateEventEmitters()},c.prototype._updateEventEmitters=function(){if(this.listeners){var t=this;O.forEach(this.listeners,function(e,i){if(t.emitters||(t.emitters={}),!(i in t.emitters)){var n=t.frame;if(n){var s=function(t){e.forEach(function(e){e(t)})};t.emitters[i]=s,O.addEventListener(n,i,s)}}})}},u.prototype=new l,u.prototype.setOptions=l.prototype.setOptions,u.prototype.setRange=function(t){if(!(t instanceof h||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},u.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.factor+e.offset)},u.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.factor},u.prototype.repaint=function(){var t=0,e=O.updateProperty,i=O.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.props,r=this.step,a=this.frame;if(a||(a=document.createElement("div"),this.frame=a,t+=1),a.className="axis "+s,!a.parentNode){if(!this.parent)throw Error("Cannot repaint time axis: no parent attached");var h=this.parent.getContainer();if(!h)throw Error("Cannot repaint time axis: parent has no container element");h.appendChild(a),t+=1}var d=a.parentNode;if(d){var l=a.nextSibling;d.removeChild(a);var p="bottom"==s&&this.props.parentHeight&&this.height?this.props.parentHeight-this.height+"px":"0px";if(t+=e(a.style,"top",i(n.top,p)),t+=e(a.style,"left",i(n.left,"0px")),t+=e(a.style,"width",i(n.width,"100%")),t+=e(a.style,"height",i(n.height,this.height+"px")),this._repaintMeasureChars(),this.step){this._repaintStart(),r.first();for(var c=void 0,u=0;r.hasNext()&&1e3>u;){u++;var f=r.getCurrent(),m=this.toScreen(f),g=r.isMajor();this.getOption("showMinorLabels")&&this._repaintMinorText(m,r.getLabelMinor()),g&&this.getOption("showMajorLabels")?(m>0&&(void 0==c&&(c=m),this._repaintMajorText(m,r.getLabelMajor())),this._repaintMajorLine(m)):this._repaintMinorLine(m),r.next()}if(this.getOption("showMajorLabels")){var v=this.toTime(0),y=r.getLabelMajor(v),b=y.length*(o.majorCharWidth||10)+10;(void 0==c||c>b)&&this._repaintMajorText(0,y)}this._repaintEnd()}this._repaintLine(),l?d.insertBefore(a,l):d.appendChild(a)}return t>0},u.prototype._repaintStart=function(){var t=this.dom,e=t.redundant;e.majorLines=t.majorLines,e.majorTexts=t.majorTexts,e.minorLines=t.minorLines,e.minorTexts=t.minorTexts,t.majorLines=[],t.majorTexts=[],t.minorLines=[],t.minorTexts=[]},u.prototype._repaintEnd=function(){O.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},u.prototype._repaintMinorText=function(t,e){var i=this.dom.redundant.minorTexts.shift();if(!i){var n=document.createTextNode("");i=document.createElement("div"),i.appendChild(n),i.className="text minor",this.frame.appendChild(i)}this.dom.minorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.left=t+"px",i.style.top=this.props.minorLabelTop+"px"},u.prototype._repaintMajorText=function(t,e){var i=this.dom.redundant.majorTexts.shift();if(!i){var n=document.createTextNode(e);i=document.createElement("div"),i.className="text major",i.appendChild(n),this.frame.appendChild(i)}this.dom.majorTexts.push(i),i.childNodes[0].nodeValue=e,i.style.top=this.props.majorLabelTop+"px",i.style.left=t+"px"},u.prototype._repaintMinorLine=function(t){var e=this.dom.redundant.minorLines.shift();e||(e=document.createElement("div"),e.className="grid vertical minor",this.frame.appendChild(e)),this.dom.minorLines.push(e);var i=this.props;e.style.top=i.minorLineTop+"px",e.style.height=i.minorLineHeight+"px",e.style.left=t-i.minorLineWidth/2+"px"},u.prototype._repaintMajorLine=function(t){var e=this.dom.redundant.majorLines.shift();e||(e=document.createElement("DIV"),e.className="grid vertical major",this.frame.appendChild(e)),this.dom.majorLines.push(e);var i=this.props;e.style.top=i.majorLineTop+"px",e.style.left=t-i.majorLineWidth/2+"px",e.style.height=i.majorLineHeight+"px"},u.prototype._repaintLine=function(){var t=this.dom.line,e=this.frame;this.options,this.getOption("showMinorLabels")||this.getOption("showMajorLabels")?(t?(e.removeChild(t),e.appendChild(t)):(t=document.createElement("div"),t.className="grid horizontal major",e.appendChild(t),this.dom.line=t),t.style.top=this.props.lineTop+"px"):t&&axis.parentElement&&(e.removeChild(axis.line),delete this.dom.line)},u.prototype._repaintMeasureChars=function(){var t,e=this.dom;if(!e.measureCharMinor){t=document.createTextNode("0");var i=document.createElement("DIV");i.className="text minor measure",i.appendChild(t),this.frame.appendChild(i),e.measureCharMinor=i}if(!e.measureCharMajor){t=document.createTextNode("0");var n=document.createElement("DIV");n.className="text major measure",n.appendChild(t),this.frame.appendChild(n),e.measureCharMajor=n}},u.prototype.reflow=function(){var t=0,e=O.updateProperty,i=this.frame,n=this.range;if(!n)throw Error("Cannot repaint time axis: no range configured");if(i){t+=e(this,"top",i.offsetTop),t+=e(this,"left",i.offsetLeft);var s=this.props,o=this.getOption("showMinorLabels"),r=this.getOption("showMajorLabels"),a=this.dom.measureCharMinor,h=this.dom.measureCharMajor;a&&(s.minorCharHeight=a.clientHeight,s.minorCharWidth=a.clientWidth),h&&(s.majorCharHeight=h.clientHeight,s.majorCharWidth=h.clientWidth);var d=i.parentNode?i.parentNode.offsetHeight:0;switch(d!=s.parentHeight&&(s.parentHeight=d,t+=1),this.getOption("orientation")){case"bottom":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.minorLabelTop=0,s.majorLabelTop=s.minorLabelTop+s.minorLabelHeight,s.minorLineTop=-this.top,s.minorLineHeight=Math.max(this.top+s.majorLabelHeight,0),s.minorLineWidth=1,s.majorLineTop=-this.top,s.majorLineHeight=Math.max(this.top+s.minorLabelHeight+s.majorLabelHeight,0),s.majorLineWidth=1,s.lineTop=0;break;case"top":s.minorLabelHeight=o?s.minorCharHeight:0,s.majorLabelHeight=r?s.majorCharHeight:0,s.majorLabelTop=0,s.minorLabelTop=s.majorLabelTop+s.majorLabelHeight,s.minorLineTop=s.minorLabelTop,s.minorLineHeight=Math.max(d-s.majorLabelHeight-this.top),s.minorLineWidth=1,s.majorLineTop=0,s.majorLineHeight=Math.max(d-this.top),s.majorLineWidth=1,s.lineTop=s.majorLabelHeight+s.minorLabelHeight;break;default:throw Error('Unkown orientation "'+this.getOption("orientation")+'"')}var l=s.minorLabelHeight+s.majorLabelHeight;t+=e(this,"width",i.offsetWidth),t+=e(this,"height",l),this._updateConversion();var p=O.convert(n.start,"Date"),c=O.convert(n.end,"Date"),u=this.toTime(5*(s.minorCharWidth||10))-this.toTime(0);this.step=new TimeStep(p,c,u),t+=e(s.range,"start",p.valueOf()),t+=e(s.range,"end",c.valueOf()),t+=e(s.range,"minimumStep",u.valueOf())}return t>0},u.prototype._updateConversion=function(){var t=this.range;if(!t)throw Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},f.prototype=new p,f.types={box:g,range:y,point:v},f.prototype.setOptions=l.prototype.setOptions,f.prototype.setRange=function(t){if(!(t instanceof h||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},f.prototype.repaint=function(){var t=0,e=O.updateProperty,i=O.option.asSize,n=this.options,s=this.getOption("orientation"),o=this.defaultOptions,r=this.frame;if(!r){r=document.createElement("div"),r.className="itemset";var a=n.className;a&&O.addClassName(r,O.option.asString(a));var h=document.createElement("div");h.className="background",r.appendChild(h),this.dom.background=h;var d=document.createElement("div");d.className="foreground",r.appendChild(d),this.dom.foreground=d;var l=document.createElement("div");l.className="itemset-axis",this.dom.axis=l,this.frame=r,t+=1}if(!this.parent)throw Error("Cannot repaint itemset: no parent attached");var p=this.parent.getContainer();if(!p)throw Error("Cannot repaint itemset: parent has no container element");r.parentNode||(p.appendChild(r),t+=1),this.dom.axis.parentNode||(p.appendChild(this.dom.axis),t+=1),t+=e(r.style,"left",i(n.left,"0px")),t+=e(r.style,"top",i(n.top,"0px")),t+=e(r.style,"width",i(n.width,"100%")),t+=e(r.style,"height",i(n.height,this.height+"px")),t+=e(this.dom.axis.style,"left",i(n.left,"0px")),t+=e(this.dom.axis.style,"width",i(n.width,"100%")),t+="bottom"==s?e(this.dom.axis.style,"top",this.height+this.top+"px"):e(this.dom.axis.style,"top",this.top+"px"),this._updateConversion();var c=this,u=this.queue,m=this.itemsData,g=this.items,v={};return Object.keys(u).forEach(function(e){var i=u[e],s=g[e];switch(i){case"add":case"update":var r=m&&m.get(e,v);if(r){var a=r.type||r.start&&r.end&&"range"||n.type||"box",h=f.types[a];if(s&&(h&&s instanceof h?(s.data=r,t++):(t+=s.hide(),s=null)),!s){if(!h)throw new TypeError('Unknown item type "'+a+'"');s=new h(c,r,n,o),t++}s.repaint(),g[e]=s}delete u[e];break;case"remove":s&&(t+=s.hide()),delete g[e],delete u[e];break;default:console.log('Error: unknown action "'+i+'"')}}),O.forEach(this.items,function(e){e.visible?(t+=e.show(),e.reposition()):t+=e.hide()}),t>0},f.prototype.getForeground=function(){return this.dom.foreground},f.prototype.getBackground=function(){return this.dom.background},f.prototype.getAxis=function(){return this.dom.axis},f.prototype.reflow=function(){var t=0,e=this.options,i=e.margin&&e.margin.axis||this.defaultOptions.margin.axis,n=e.margin&&e.margin.item||this.defaultOptions.margin.item,s=O.updateProperty,o=O.option.asNumber,r=O.option.asSize,a=this.frame;if(a){this._updateConversion(),O.forEach(this.items,function(e){t+=e.reflow()}),this.stack.update();var h,d=o(e.maxHeight),l=null!=r(e.height);if(l)h=a.offsetHeight;else{var p=this.stack.ordered;if(p.length){var c=p[0].top,u=p[0].top+p[0].height;O.forEach(p,function(t){c=Math.min(c,t.top),u=Math.max(u,t.top+t.height)}),h=u-c+i+n}else h=i+n}null!=d&&(h=Math.min(h,d)),t+=s(this,"height",h),t+=s(this,"top",a.offsetTop),t+=s(this,"left",a.offsetLeft),t+=s(this,"width",a.offsetWidth)}else t+=1;return t>0},f.prototype.hide=function(){var t=!1;return this.frame&&this.frame.parentNode&&(this.frame.parentNode.removeChild(this.frame),t=!0),this.dom.axis&&this.dom.axis.parentNode&&(this.dom.axis.parentNode.removeChild(this.dom.axis),t=!0),t},f.prototype.setItems=function(t){var e,i=this,n=this.itemsData;if(t){if(!(t instanceof o||t instanceof r))throw new TypeError("Data must be an instance of DataSet");this.itemsData=t}else this.itemsData=null;if(n&&(O.forEach(this.listeners,function(t,e){n.unsubscribe(e,t)}),e=n.getIds(),this._onRemove(e)),this.itemsData){var s=this.id;O.forEach(this.listeners,function(t,e){i.itemsData.subscribe(e,t,s)}),e=this.itemsData.getIds(),this._onAdd(e)}},f.prototype.getItems=function(){return this.itemsData},f.prototype._onUpdate=function(t){this._toQueue("update",t)},f.prototype._onAdd=function(t){this._toQueue("add",t)},f.prototype._onRemove=function(t){this._toQueue("remove",t)},f.prototype._toQueue=function(t,e){var i=this.queue;e.forEach(function(e){i[e]=t}),this.controller&&this.requestRepaint()},f.prototype._updateConversion=function(){var t=this.range;if(!t)throw Error("No range configured");this.conversion=t.conversion?t.conversion(this.width):h.conversion(t.start,t.end,this.width)},f.prototype.toTime=function(t){var e=this.conversion;return new Date(t/e.factor+e.offset)},f.prototype.toScreen=function(t){var e=this.conversion;return(t.valueOf()-e.offset)*e.factor},m.prototype.select=function(){this.selected=!0},m.prototype.unselect=function(){this.selected=!1},m.prototype.show=function(){return!1},m.prototype.hide=function(){return!1},m.prototype.repaint=function(){return!1},m.prototype.reflow=function(){return!1},g.prototype=new m(null,null),g.prototype.select=function(){this.selected=!0},g.prototype.unselect=function(){this.selected=!1},g.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw Error("Cannot repaint time axis: parent has no foreground container element");var n=this.parent.getBackground();if(!n)throw Error("Cannot repaint time axis: parent has no background container element");var s=this.parent.getAxis();if(!n)throw Error("Cannot repaint time axis: parent has no axis container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),e.line.parentNode||(n.appendChild(e.line),t=!0),e.dot.parentNode||(s.appendChild(e.dot),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var o=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=o&&(this.className=o,e.box.className="item box"+o,e.line.className="item line"+o,e.dot.className="item dot"+o,t=!0)}return t},g.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},g.prototype.hide=function(){var t=!1,e=this.dom;return e&&(e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),e.line.parentNode&&e.line.parentNode.removeChild(e.line),e.dot.parentNode&&e.dot.parentNode.removeChild(e.dot)),t},g.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,l,p,c=0;if(void 0==this.data.start)throw Error('Property "start" missing in item '+this.data.id);if(l=this.data,p=this.parent&&this.parent.range,l&&p){var u=p.end-p.start;this.visible=l.start>p.start-u&&l.start0},g.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("DIV"),t.content=document.createElement("DIV"),t.content.className="content",t.box.appendChild(t.content),t.line=document.createElement("DIV"),t.line.className="line",t.dot=document.createElement("DIV"),t.dot.className="dot")},g.prototype.reposition=function(){var t=this.dom,e=this.props,i=this.options.orientation||this.defaultOptions.orientation;if(t){var n=t.box,s=t.line,o=t.dot;n.style.left=this.left+"px",n.style.top=this.top+"px",s.style.left=e.line.left+"px","top"==i?(s.style.top="0px",s.style.height=this.top+"px"):(s.style.top=this.top+this.height+"px",s.style.height=Math.max(this.parent.height-this.top-this.height+this.props.dot.height/2,0)+"px"),o.style.left=e.dot.left+"px",o.style.top=e.dot.top+"px"}},v.prototype=new m(null,null),v.prototype.select=function(){this.selected=!0},v.prototype.unselect=function(){this.selected=!1},v.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw Error("Cannot repaint time axis: parent has no foreground container element");if(e.point.parentNode||(i.appendChild(e.point),i.appendChild(e.point),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw Error('Property "content" missing in item '+this.data.id);e.content.innerHTML=this.content}t=!0}var n=(this.data.className?" "+this.data.className:"")+(this.selected?" selected":"");this.className!=n&&(this.className=n,e.point.className="item point"+n,t=!0)}return t},v.prototype.show=function(){return this.dom&&this.dom.point.parentNode?!1:this.repaint()},v.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.point.parentNode&&(e.point.parentNode.removeChild(e.point),t=!0),t},v.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,l=0;if(void 0==this.data.start)throw Error('Property "start" missing in item '+this.data.id);if(h=this.data,d=this.parent&&this.parent.range,h&&d){var p=d.end-d.start;this.visible=h.start>d.start-p&&h.start0},v.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.point=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.point.appendChild(t.content),t.dot=document.createElement("div"),t.dot.className="dot",t.point.appendChild(t.dot))},v.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.point.style.top=this.top+"px",t.point.style.left=this.left+"px",t.content.style.marginLeft=e.content.marginLeft+"px",t.dot.style.top=e.dot.top+"px")},y.prototype=new m(null,null),y.prototype.select=function(){this.selected=!0},y.prototype.unselect=function(){this.selected=!1},y.prototype.repaint=function(){var t=!1,e=this.dom;if(e||(this._create(),e=this.dom,t=!0),e){if(!this.parent)throw Error("Cannot repaint item: no parent attached");var i=this.parent.getForeground();if(!i)throw Error("Cannot repaint time axis: parent has no foreground container element");if(e.box.parentNode||(i.appendChild(e.box),t=!0),this.data.content!=this.content){if(this.content=this.data.content,this.content instanceof Element)e.content.innerHTML="",e.content.appendChild(this.content);else{if(void 0==this.data.content)throw Error('Property "content" missing in item '+this.data.id); -e.content.innerHTML=this.content}t=!0}var n=this.data.className?" "+this.data.className:"";this.className!=n&&(this.className=n,e.box.className="item range"+n,t=!0)}return t},y.prototype.show=function(){return this.dom&&this.dom.box.parentNode?!1:this.repaint()},y.prototype.hide=function(){var t=!1,e=this.dom;return e&&e.box.parentNode&&(e.box.parentNode.removeChild(e.box),t=!0),t},y.prototype.reflow=function(){var t,e,i,n,s,o,r,a,h,d,l,p,c,u,f,m,g=0;if(void 0==this.data.start)throw Error('Property "start" missing in item '+this.data.id);if(void 0==this.data.end)throw Error('Property "end" missing in item '+this.data.id);return h=this.data,d=this.parent&&this.parent.range,this.visible=h&&d?h.startd.start:!1,this.visible&&(t=this.dom,t?(e=this.props,i=this.options,o=this.parent,r=o.toScreen(this.data.start),a=o.toScreen(this.data.end),l=O.updateProperty,p=t.box,c=o.width,f=i.orientation||this.defaultOptions.orientation,n=i.margin&&i.margin.axis||this.defaultOptions.margin.axis,s=i.padding||this.defaultOptions.padding,g+=l(e.content,"width",t.content.offsetWidth),g+=l(this,"height",p.offsetHeight),-c>r&&(r=-c),a>2*c&&(a=2*c),u=0>r?Math.min(-r,a-r-e.content.width-2*s):0,g+=l(e.content,"left",u),"top"==f?(m=n,g+=l(this,"top",m)):(m=o.height-this.height-n,g+=l(this,"top",m)),g+=l(this,"left",r),g+=l(this,"width",Math.max(a-r,1))):g+=1),g>0},y.prototype._create=function(){var t=this.dom;t||(this.dom=t={},t.box=document.createElement("div"),t.content=document.createElement("div"),t.content.className="content",t.box.appendChild(t.content))},y.prototype.reposition=function(){var t=this.dom,e=this.props;t&&(t.box.style.top=this.top+"px",t.box.style.left=this.left+"px",t.box.style.width=this.width+"px",t.content.style.left=e.content.left+"px")},b.prototype=new l,b.prototype.setOptions=l.prototype.setOptions,b.prototype.getContainer=function(){return this.parent.getContainer()},b.prototype.setItems=function(t){if(this.itemset&&(this.itemset.hide(),this.itemset.setItems(),this.parent.controller.remove(this.itemset),this.itemset=null),t){var e=this.groupId,i=Object.create(this.options);this.itemset=new f(this,null,i),this.itemset.setRange(this.parent.range),this.view=new r(t,{filter:function(t){return t.group==e}}),this.itemset.setItems(this.view),this.parent.controller.add(this.itemset)}},b.prototype.repaint=function(){return!1},b.prototype.reflow=function(){var t=0,e=O.updateProperty;if(t+=e(this,"top",this.itemset?this.itemset.top:0),t+=e(this,"height",this.itemset?this.itemset.height:0),this.label){var i=this.label.firstChild;t+=e(this.props.label,"width",i.clientWidth),t+=e(this.props.label,"height",i.clientHeight)}else t+=e(this.props.label,"width",0),t+=e(this.props.label,"height",0);return t>0},w.prototype=new p,w.prototype.setOptions=l.prototype.setOptions,w.prototype.setRange=function(){},w.prototype.setItems=function(t){this.itemsData=t;for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];i.setItems(t)}},w.prototype.getItems=function(){return this.itemsData},w.prototype.setRange=function(t){this.range=t},w.prototype.setGroups=function(t){var e,i=this;if(this.groupsData&&(O.forEach(this.listeners,function(t,e){i.groupsData.unsubscribe(e,t)}),e=this.groupsData.getIds(),this._onRemove(e)),t?t instanceof o?this.groupsData=t:(this.groupsData=new o({convert:{start:"Date",end:"Date"}}),this.groupsData.add(t)):this.groupsData=null,this.groupsData){var n=this.id;O.forEach(this.listeners,function(t,e){i.groupsData.subscribe(e,t,n)}),e=this.groupsData.getIds(),this._onAdd(e)}},w.prototype.getGroups=function(){return this.groupsData},w.prototype.repaint=function(){var t,e,i,n,s=0,o=O.updateProperty,r=O.option.asSize,a=O.option.asElement,h=this.options,d=this.dom.frame,l=this.dom.labels;if(!this.parent)throw Error("Cannot repaint groupset: no parent attached");var p=this.parent.getContainer();if(!p)throw Error("Cannot repaint groupset: parent has no container element");if(!d){d=document.createElement("div"),d.className="groupset",this.dom.frame=d;var c=h.className;c&&O.addClassName(d,O.option.asString(c)),s+=1}d.parentNode||(p.appendChild(d),s+=1);var u=a(h.labelContainer);if(!u)throw Error('Cannot repaint groupset: option "labelContainer" not defined');l||(l=document.createElement("div"),l.className="labels",this.dom.labels=l),l.parentNode&&l.parentNode==u||(l.parentNode&&l.parentNode.removeChild(l.parentNode),u.appendChild(l)),s+=o(d.style,"height",r(h.height,this.height+"px")),s+=o(d.style,"top",r(h.top,"0px")),s+=o(d.style,"left",r(h.left,"0px")),s+=o(d.style,"width",r(h.width,"100%")),s+=o(l.style,"top",r(h.top,"0px"));var f=this,m=this.queue,g=this.groups,v=this.groupsData,y=Object.keys(m);if(y.length){y.forEach(function(t){var e=m[t],i=g[t];switch(e){case"add":case"update":if(!i){var n=Object.create(f.options);i=new b(f,t,n),i.setItems(f.itemsData),g[t]=i,f.controller.add(i)}i.data=v.get(t),delete m[t];break;case"remove":i&&(i.setItems(),delete g[t],f.controller.remove(i)),delete m[t];break;default:console.log('Error: unknown action "'+e+'"')}});var w=this.groupsData.getIds({order:this.options.groupsOrder});for(t=0;w.length>t;t++)(function(t,e){var i=0;e&&(i=function(){return e.top+e.height}),t.setOptions({top:i})})(g[w[t]],g[w[t-1]]);for(;l.firstChild;)l.removeChild(l.firstChild);for(t=0;w.length>t;t++)e=w[t],n=this._createLabel(e),l.appendChild(n);s++}for(e in g)g.hasOwnProperty(e)&&(i=g[e],n=i.label,n&&(n.style.top=i.top+"px",n.style.height=i.height+"px"));return s>0},w.prototype._createLabel=function(t){var e=this.groups[t],i=document.createElement("div");i.className="label";var n=document.createElement("div");n.className="inner",i.appendChild(n);var s=e.data&&e.data.content;s instanceof Element?n.appendChild(s):void 0!=s&&(n.innerHTML=s);var o=e.data&&e.data.className;return o&&O.addClassName(i,o),e.label=i,i},w.prototype.getContainer=function(){return this.dom.frame},w.prototype.getLabelsWidth=function(){return this.props.labels.width},w.prototype.reflow=function(){var t,e,i=0,n=this.options,s=O.updateProperty,o=O.option.asNumber,r=O.option.asSize,a=this.dom.frame;if(a){var h,d=o(n.maxHeight),l=null!=r(n.height);if(l)h=a.offsetHeight;else{h=0;for(t in this.groups)this.groups.hasOwnProperty(t)&&(e=this.groups[t],h+=e.height)}null!=d&&(h=Math.min(h,d)),i+=s(this,"height",h),i+=s(this,"top",a.offsetTop),i+=s(this,"left",a.offsetLeft),i+=s(this,"width",a.offsetWidth)}var p=0;for(t in this.groups)if(this.groups.hasOwnProperty(t)){e=this.groups[t];var c=e.props&&e.props.label&&e.props.label.width||0;p=Math.max(p,c)}return i+=s(this.props.labels,"width",p),i>0},w.prototype.hide=function(){return this.dom.frame&&this.dom.frame.parentNode?(this.dom.frame.parentNode.removeChild(this.dom.frame),!0):!1},w.prototype.show=function(){return this.dom.frame&&this.dom.frame.parentNode?!1:this.repaint()},w.prototype._onUpdate=function(t){this._toQueue(t,"update")},w.prototype._onAdd=function(t){this._toQueue(t,"add")},w.prototype._onRemove=function(t){this._toQueue(t,"remove")},w.prototype._toQueue=function(t,e){var i=this.queue;t.forEach(function(t){i[t]=e}),this.controller&&this.requestRepaint()},_.prototype.setOptions=function(t){t&&O.extend(this.options,t),this.controller.reflow(),this.controller.repaint()},_.prototype.setItems=function(t){var e,i=null==this.itemsData;if(t?t instanceof o&&(e=t):e=null,t instanceof o||(e=new o({convert:{start:"Date",end:"Date"}}),e.add(t)),this.itemsData=e,this.content.setItems(e),i&&(void 0==this.options.start||void 0==this.options.end)){var n=this.getItemRange(),s=n.min,r=n.max;if(null!=s&&null!=r){var a=r.valueOf()-s.valueOf();0>=a&&(a=864e5),s=new Date(s.valueOf()-.05*a),r=new Date(r.valueOf()+.05*a)}void 0!=this.options.start&&(s=new Date(this.options.start.valueOf())),void 0!=this.options.end&&(r=new Date(this.options.end.valueOf())),(null!=s||null!=r)&&this.range.setRange(s,r)}},_.prototype.setGroups=function(t){var e=this;this.groupsData=t;var i=this.groupsData?w:f;if(!(this.content instanceof i)){this.content&&(this.content.hide(),this.content.setItems&&this.content.setItems(),this.content.setGroups&&this.content.setGroups(),this.controller.remove(this.content));var n=Object.create(this.options);O.extend(n,{top:function(){return"top"==e.options.orientation?e.timeaxis.height:e.itemPanel.height-e.timeaxis.height-e.content.height},left:null,width:"100%",height:function(){return e.options.height?e.itemPanel.height-e.timeaxis.height:null},maxHeight:function(){if(e.options.maxHeight){if(!O.isNumber(e.options.maxHeight))throw new TypeError("Number expected for property maxHeight");return e.options.maxHeight-e.timeaxis.height}return null},labelContainer:function(){return e.labelPanel.getContainer()}}),this.content=new i(this.itemPanel,[this.timeaxis],n),this.content.setRange&&this.content.setRange(this.range),this.content.setItems&&this.content.setItems(this.itemsData),this.content.setGroups&&this.content.setGroups(this.groupsData),this.controller.add(this.content)}},_.prototype.getItemRange=function(){var t=this.itemsData,e=null,i=null;if(t){var n=t.min("start");e=n?n.start.valueOf():null;var s=t.max("start");s&&(i=s.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}},function(t){function e(t){return M=t,c()}function i(){D=0,C=M.charAt(0)}function n(){D++,C=M.charAt(D)}function s(){return M.charAt(D+1)}function o(t){return L.test(t)}function r(t,e){if(t||(t={}),e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t,e,i){for(var n=e.split("."),s=t;n.length;){var o=n.shift();n.length?(s[o]||(s[o]={}),s=s[o]):s[o]=i}}function h(t,e){for(var i,n,s=null,o=[t],a=t;a.parent;)o.push(a.parent),a=a.parent;if(a.nodes)for(i=0,n=a.nodes.length;n>i;i++)if(e.id===a.nodes[i].id){s=a.nodes[i];break}for(s||(s={id:e.id},t.node&&(s.attr=r(s.attr,t.node))),i=o.length-1;i>=0;i--){var h=o[i];h.nodes||(h.nodes=[]),-1==h.nodes.indexOf(s)&&h.nodes.push(s)}e.attr&&(s.attr=r(s.attr,e.attr))}function d(t,e){if(t.edges||(t.edges=[]),t.edges.push(e),t.edge){var i=r({},t.edge);e.attr=r(i,e.attr)}}function l(t,e,i,n,s){var o={from:e,to:i,type:n};return t.edge&&(o.attr=r({},t.edge)),o.attr=r(o.attr||{},s),o}function p(){for(N=x.NULL,O="";" "==C||" "==C||"\n"==C||"\r"==C;)n();do{var t=!1;if("#"==C){for(var e=D-1;" "==M.charAt(e)||" "==M.charAt(e);)e--;if("\n"==M.charAt(e)||""==M.charAt(e)){for(;""!=C&&"\n"!=C;)n();t=!0}}if("/"==C&&"/"==s()){for(;""!=C&&"\n"!=C;)n();t=!0}if("/"==C&&"*"==s()){for(;""!=C;){if("*"==C&&"/"==s()){n(),n();break}n()}t=!0}for(;" "==C||" "==C||"\n"==C||"\r"==C;)n()}while(t);if(""==C)return N=x.DELIMITER,void 0;var i=C+s();if(S[i])return N=x.DELIMITER,O=i,n(),n(),void 0;if(S[C])return N=x.DELIMITER,O=C,n(),void 0;if(o(C)||"-"==C){for(O+=C,n();o(C);)O+=C,n();return"false"==O?O=!1:"true"==O?O=!0:isNaN(Number(O))||(O=Number(O)),N=x.IDENTIFIER,void 0}if('"'==C){for(n();""!=C&&('"'!=C||'"'==C&&'"'==s());)O+=C,'"'==C&&n(),n();if('"'!=C)throw w('End of string " expected');return n(),N=x.IDENTIFIER,void 0}for(N=x.UNKNOWN;""!=C;)O+=C,n();throw new SyntaxError('Syntax error in part "'+_(O,30)+'"')}function c(){var t={};if(i(),p(),"strict"==O&&(t.strict=!0,p()),("graph"==O||"digraph"==O)&&(t.type=O,p()),N==x.IDENTIFIER&&(t.id=O,p()),"{"!=O)throw w("Angle bracket { expected");if(p(),u(t),"}"!=O)throw w("Angle bracket } expected");if(p(),""!==O)throw w("End of file expected");return p(),delete t.node,delete t.edge,delete t.graph,t}function u(t){for(;""!==O&&"}"!=O;)f(t),";"==O&&p()}function f(t){var e=m(t);if(e)return y(t,e),void 0;var i=g(t);if(!i){if(N!=x.IDENTIFIER)throw w("Identifier expected");var n=O;if(p(),"="==O){if(p(),N!=x.IDENTIFIER)throw w("Identifier expected");t[n]=O,p()}else v(t,n)}}function m(t){var e=null;if("subgraph"==O&&(e={},e.type="subgraph",p(),N==x.IDENTIFIER&&(e.id=O,p())),"{"==O){if(p(),e||(e={}),e.parent=t,e.node=t.node,e.edge=t.edge,e.graph=t.graph,u(e),"}"!=O)throw w("Angle bracket } expected");p(),delete e.node,delete e.edge,delete e.graph,delete e.parent,t.subgraphs||(t.subgraphs=[]),t.subgraphs.push(e)}return e}function g(t){return"node"==O?(p(),t.node=b(),"node"):"edge"==O?(p(),t.edge=b(),"edge"):"graph"==O?(p(),t.graph=b(),"graph"):null}function v(t,e){var i={id:e},n=b();n&&(i.attr=n),h(t,i),y(t,e)}function y(t,e){for(;"->"==O||"--"==O;){var i,n=O;p();var s=m(t);if(s)i=s;else{if(N!=x.IDENTIFIER)throw w("Identifier or subgraph expected");i=O,h(t,{id:i}),p()}var o=b(),r=l(t,e,i,n,o);d(t,r),e=i}}function b(){for(var t=null;"["==O;){for(p(),t={};""!==O&&"]"!=O;){if(N!=x.IDENTIFIER)throw w("Attribute name expected");var e=O;if(p(),"="!=O)throw w("Equal sign = expected");if(p(),N!=x.IDENTIFIER)throw w("Attribute value expected");var i=O;a(t,e,i),p(),","==O&&p()}if("]"!=O)throw w("Bracket ] expected");p()}return t}function w(t){return new SyntaxError(t+', got "'+_(O,30)+'" (char '+D+")")}function _(t,e){return e>=t.length?t:t.substr(0,27)+"..."}function E(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 T(t){function i(t){var e={from:t.from,to:t.to};return r(e,t.attr),e.style="->"==t.type?"arrow":"line",e}var n=e(t),s={nodes:[],edges:[],options:{}};return n.nodes&&n.nodes.forEach(function(t){var e={id:t.id,label:(t.label||t.id)+""};r(e,t.attr),e.image&&(e.shape="image"),s.nodes.push(e)}),n.edges&&n.edges.forEach(function(t){var e,n;e=t.from instanceof Object?t.from.nodes:{id:t.from},n=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);s.edges.push(e)}),E(e,n,function(e,n){var o=l(s,e.id,n.id,t.type,t.attr),r=i(o);s.edges.push(r)}),t.to instanceof Object&&t.to.edges&&t.to.edges.forEach(function(t){var e=i(t);s.edges.push(e)})}),n.attr&&(s.options=n.attr),s}var x={NULL:0,DELIMITER:1,IDENTIFIER:2,UNKNOWN:3},S={"{":!0,"}":!0,"[":!0,"]":!0,";":!0,"=":!0,",":!0,"->":!0,"--":!0},M="",D=0,C="",O="",N=x.NULL,L=/[a-zA-Z_0-9.:#]/;t.parseDOT=e,t.DOTToGraph=T}(O!==void 0?O:n),"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 n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e-(r-o)),this.lineTo(t+s,e+o),this.lineTo(t-s,e+o),this.lineTo(t,e-(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.triangleDown=function(t,e,i){this.beginPath();var n=2*i,s=n/2,o=Math.sqrt(3)/6*n,r=Math.sqrt(n*n-s*s);this.moveTo(t,e+(r-o)),this.lineTo(t+s,e-o),this.lineTo(t-s,e-o),this.lineTo(t,e+(r-o)),this.closePath()},CanvasRenderingContext2D.prototype.star=function(t,e,i){this.beginPath();for(var n=0;10>n;n++){var s=0===n%2?1.3*i:.5*i;this.lineTo(t+s*Math.sin(2*n*Math.PI/10),e-s*Math.cos(2*n*Math.PI/10))}this.closePath()},CanvasRenderingContext2D.prototype.roundRect=function(t,e,i,n,s){var o=Math.PI/180;0>i-2*s&&(s=i/2),0>n-2*s&&(s=n/2),this.beginPath(),this.moveTo(t+s,e),this.lineTo(t+i-s,e),this.arc(t+i-s,e+s,s,270*o,360*o,!1),this.lineTo(t+i,e+n-s),this.arc(t+i-s,e+n-s,s,0,90*o,!1),this.lineTo(t+s,e+n),this.arc(t+s,e+n-s,s,90*o,180*o,!1),this.lineTo(t,e+s),this.arc(t+s,e+s,s,180*o,270*o,!1)},CanvasRenderingContext2D.prototype.ellipse=function(t,e,i,n){var s=.5522848,o=i/2*s,r=n/2*s,a=t+i,h=e+n,d=t+i/2,l=e+n/2;this.beginPath(),this.moveTo(t,l),this.bezierCurveTo(t,l-r,d-o,e,d,e),this.bezierCurveTo(d+o,e,a,l-r,a,l),this.bezierCurveTo(a,l+r,d+o,h,d,h),this.bezierCurveTo(d-o,h,t,l+r,t,l)},CanvasRenderingContext2D.prototype.database=function(t,e,i,n){var s=1/3,o=i,r=n*s,a=.5522848,h=o/2*a,d=r/2*a,l=t+o,p=e+r,c=t+o/2,u=e+r/2,f=e+(n-r/2),m=e+n;this.beginPath(),this.moveTo(l,u),this.bezierCurveTo(l,u+d,c+h,p,c,p),this.bezierCurveTo(c-h,p,t,u+d,t,u),this.bezierCurveTo(t,u-d,c-h,e,c,e),this.bezierCurveTo(c+h,e,l,u-d,l,u),this.lineTo(l,f),this.bezierCurveTo(l,f+d,c+h,m,c,m),this.bezierCurveTo(c-h,m,t,f+d,t,f),this.lineTo(t,u)},CanvasRenderingContext2D.prototype.arrow=function(t,e,i,n){var s=t-n*Math.cos(i),o=e-n*Math.sin(i),r=t-.9*n*Math.cos(i),a=e-.9*n*Math.sin(i),h=s+n/3*Math.cos(i+.5*Math.PI),d=o+n/3*Math.sin(i+.5*Math.PI),l=s+n/3*Math.cos(i-.5*Math.PI),p=o+n/3*Math.sin(i-.5*Math.PI);this.beginPath(),this.moveTo(t,e),this.lineTo(h,d),this.lineTo(r,a),this.lineTo(l,p),this.closePath()},CanvasRenderingContext2D.prototype.dashedLine=function(t,e,i,n,s){s||(s=[10,5]),0==c&&(c=.001);var o=s.length;this.moveTo(t,e);for(var r=i-t,a=n-e,h=a/r,d=Math.sqrt(r*r+a*a),l=0,p=!0;d>=.1;){var c=s[l++%o];c>d&&(c=d);var u=Math.sqrt(c*c/(1+h*h));0>r&&(u=-u),t+=u,e+=h*u,this[p?"lineTo":"moveTo"](t,e),d-=c,p=!p}}),E.prototype.attachEdge=function(t){-1==this.edges.indexOf(t)&&this.edges.push(t),this._updateMass()},E.prototype.detachEdge=function(t){var e=this.edges.indexOf(t);-1!=e&&this.edges.splice(e,1),this._updateMass()},E.prototype._updateMass=function(){this.mass=50+20*this.edges.length},E.prototype.setProperties=function(t,e){if(t){if(void 0!=t.id&&(this.id=t.id),void 0!=t.label&&(this.label=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===this.id)throw"Node must have an id";if(this.group){var i=this.grouplist.get(this.group);for(var n in i)i.hasOwnProperty(n)&&(this[n]=i[n])}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=E.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){if(!this.imagelist)throw"No imagelist provided";this.imageObj=this.imagelist.load(this.image)}switch(this.xFixed=this.xFixed||void 0!=t.x,this.yFixed=this.yFixed||void 0!=t.y,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()}},E.parseColor=function(t){var e;return O.isString(t)?e={border:t,background:t,highlight:{border:t,background:t}}:(e={},e.background=t.background||"white",e.border=t.border||e.background,O.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)),e},E.prototype.select=function(){this.selected=!0,this._reset()},E.prototype.unselect=function(){this.selected=!1,this._reset()},E.prototype._reset=function(){this.width=void 0,this.height=void 0},E.prototype.getTitle=function(){return this.title},E.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 n=this.width/2,s=this.height/2,o=Math.sin(e)*n,r=Math.cos(e)*s;return n*s/Math.sqrt(o*o+r*r);case"box":case"image":case"text":default:return this.width?Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(this.height/2/Math.sin(e)))+i:0}},E.prototype._setForce=function(t,e){this.fx=t,this.fy=e},E.prototype._addForce=function(t,e){this.fx+=t,this.fy+=e},E.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 n=-this.damping*this.vy,s=(this.fy+n)/this.mass;this.vy+=s/t,this.y+=this.vy/t}},E.prototype.isFixed=function(){return this.xFixed&&this.yFixed},E.prototype.isMoving=function(t){return Math.abs(this.vx)>t||Math.abs(this.vy)>t||!this.xFixed&&Math.abs(this.fx)>this.minForce||!this.yFixed&&Math.abs(this.fy)>this.minForce},E.prototype.isSelected=function(){return this.selected},E.prototype.getValue=function(){return this.value},E.prototype.getDistance=function(t,e){var i=this.x-t,n=this.y-e;return Math.sqrt(i*i+n*n)},E.prototype.setValueRange=function(t,e){if(!this.radiusFixed&&void 0!==this.value){var i=(this.radiusMax-this.radiusMin)/(e-t);this.radius=(this.value-t)*i+this.radiusMin}},E.prototype.draw=function(){throw"Draw method not initialized for node"},E.prototype.resize=function(){throw"Resize method not initialized for node"},E.prototype.isOverlappingWith=function(t){return this.leftt.left&&this.topt.top},E.prototype._resizeImage=function(){if(!this.width){var t,e;if(this.value){var i=this.imageObj.height/this.imageObj.width;t=this.radius||this.imageObj.width,e=this.radius*i||this.imageObj.height}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e}},E.prototype._drawImage=function(t){this._resizeImage(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2;var e;this.imageObj?(t.drawImage(this.imageObj,this.left,this.top,this.width,this.height),e=this.y+this.height/2):e=this.y,this._label(t,this.label,this.x,e,void 0,"top")},E.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}},E.prototype._drawBox=function(t){this._resizeBox(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,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)},E.prototype._resizeDatabase=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=i.width+2*e;this.width=n,this.height=n}},E.prototype._drawDatabase=function(t){this._resizeDatabase(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,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)},E.prototype._resizeCircle=function(t){if(!this.width){var e=5,i=this.getTextSize(t),n=Math.max(i.width,i.height)+2*e;this.radius=n/2,this.width=n,this.height=n}},E.prototype._drawCircle=function(t){this._resizeCircle(t),this.left=this.x-this.width/2,this.top=this.y-this.height/2,t.strokeStyle=this.selected?this.color.highlight.border:this.color.border,t.fillStyle=this.selected?this.color.highlight.background:this.color.background,t.lineWidth=this.selected?2:1,t.circle(this.x,this.y,this.radius),t.fill(),t.stroke(),this._label(t,this.label,this.x,this.y)},E.prototype._resizeEllipse=function(t){if(!this.width){var e=this.getTextSize(t);this.width=1.5*e.width,this.height=2*e.height,this.widthl;l++)t.fillText(r[l],i,d),d+=h}},E.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,n=0,s=0,o=e.length;o>s;s++)n=Math.max(n,t.measureText(e[s]).width);return{width:n,height:i}}return{width:0,height:0}},T.prototype.setProperties=function(t,e){if(t)switch(void 0!=t.from&&(this.fromId=t.from),void 0!=t.to&&(this.toId=t.to),void 0!=t.id&&(this.id=t.id),void 0!=t.style&&(this.style=t.style),void 0!=t.label&&(this.label=t.label),this.label&&(this.fontSize=e.edges.fontSize,this.fontFace=e.edges.fontFace,this.fontColor=e.edges.fontColor,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!=t.title&&(this.title=t.title),void 0!=t.width&&(this.width=t.width),void 0!=t.value&&(this.value=t.value),void 0!=t.length&&(this.length=t.length),t.dash&&(void 0!=t.dash.length&&(this.dash.length=t.dash.length),void 0!=t.dash.gap&&(this.dash.gap=t.dash.gap),void 0!=t.dash.altLength&&(this.dash.altLength=t.dash.altLength)),void 0!=t.color&&(this.color=t.color),this.connect(),this.widthFixed=this.widthFixed||void 0!=t.width,this.lengthFixed=this.lengthFixed||void 0!=t.length,this.stiffness=1/this.length,this.style){case"line":this.draw=this._drawLine;break;case"arrow":this.draw=this._drawArrow;break;case"arrow-center":this.draw=this._drawArrowCenter;break;case"dash-line":this.draw=this._drawDashLine;break;default:this.draw=this._drawLine}},T.prototype.connect=function(){this.disconnect(),this.from=this.graph.nodes[this.fromId]||null,this.to=this.graph.nodes[this.toId]||null,this.connected=this.from&&this.to,this.connected?(this.from.attachEdge(this),this.to.attachEdge(this)):(this.from&&this.from.detachEdge(this),this.to&&this.to.detachEdge(this))},T.prototype.disconnect=function(){this.from&&(this.from.detachEdge(this),this.from=null),this.to&&(this.to.detachEdge(this),this.to=null),this.connected=!1},T.prototype.getTitle=function(){return this.title},T.prototype.getValue=function(){return this.value},T.prototype.setValueRange=function(t,e){if(!this.widthFixed&&void 0!==this.value){var i=(this.widthMax-this.widthMin)/(e-t);this.width=(this.value-t)*i+this.widthMin}},T.prototype.draw=function(){throw"Method draw not initialized in edge"},T.prototype.isOverlappingWith=function(t){var e=10,i=this.from.x,n=this.from.y,s=this.to.x,o=this.to.y,r=t.left,a=t.top,h=T._dist(i,n,s,o,r,a);return e>h},T.prototype._drawLine=function(t){t.strokeStyle=this.color,t.lineWidth=this._getLineWidth();var e;if(this.from!=this.to)this._line(t),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y));else{var i,n,s=this.length/4,o=this.from;o.width||o.resize(t),o.width>o.height?(i=o.x+o.width/2,n=o.y-s):(i=o.x+s,n=o.y-o.height/2),this._circle(t,i,n,s),e=this._pointOnCircle(i,n,s,.5),this._label(t,this.label,e.x,e.y)}},T.prototype._getLineWidth=function(){return this.from.selected||this.to.selected?Math.min(2*this.width,this.widthMax):this.width},T.prototype._line=function(t){t.beginPath(),t.moveTo(this.from.x,this.from.y),t.lineTo(this.to.x,this.to.y),t.stroke()},T.prototype._circle=function(t,e,i,n){t.beginPath(),t.arc(e,i,n,0,2*Math.PI,!1),t.stroke()},T.prototype._label=function(t,e,i,n){if(e){t.font=(this.from.selected||this.to.selected?"bold ":"")+this.fontSize+"px "+this.fontFace,t.fillStyle="white";var s=t.measureText(e).width,o=this.fontSize,r=i-s/2,a=n-o/2;t.fillRect(r,a,s,o),t.fillStyle=this.fontColor||"black",t.textAlign="left",t.textBaseline="top",t.fillText(e,r,a)}},T.prototype._drawDashLine=function(t){if(t.strokeStyle=this.color,t.lineWidth=this._getLineWidth(),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(),this.label){var e=this._pointOnLine(.5);this._label(t,this.label,e.x,e.y)}},T.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}},T.prototype._pointOnCircle=function(t,e,i,n){var s=2*(n-3/8)*Math.PI;return{x:t+i*Math.cos(s),y:e-i*Math.sin(s)}},T.prototype._drawArrowCenter=function(t){var e;if(t.strokeStyle=this.color,t.fillStyle=this.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),n=10+5*this.width;e=this._pointOnLine(.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnLine(.5),this._label(t,this.label,e.x,e.y))}else{var s,o,r=this.length/4,a=this.from;a.width||a.resize(t),a.width>a.height?(s=a.x+a.width/2,o=a.y-r):(s=a.x+r,o=a.y-a.height/2),this._circle(t,s,o,r);var i=.2*Math.PI,n=10+5*this.width;e=this._pointOnCircle(s,o,r,.5),t.arrow(e.x,e.y,i,n),t.fill(),t.stroke(),this.label&&(e=this._pointOnCircle(s,o,r,.5),this._label(t,this.label,e.x,e.y))}},T.prototype._drawArrow=function(t){t.strokeStyle=this.color,t.fillStyle=this.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 n=this.to.x-this.from.x,s=this.to.y-this.from.y,o=Math.sqrt(n*n+s*s),r=this.from.distanceToBorder(t,e+Math.PI),a=(o-r)/o,h=a*this.from.x+(1-a)*this.to.x,d=a*this.from.y+(1-a)*this.to.y,l=this.to.distanceToBorder(t,e),p=(o-l)/o,c=(1-p)*this.from.x+p*this.to.x,u=(1-p)*this.from.y+p*this.to.y;if(t.beginPath(),t.moveTo(h,d),t.lineTo(c,u),t.stroke(),i=10+5*this.width,t.arrow(c,u,e,i),t.fill(),t.stroke(),this.label){var f=this._pointOnLine(.5);this._label(t,this.label,f.x,f.y)}}else{var m,g,v,y=this.from,b=this.length/4;y.width||y.resize(t),y.width>y.height?(m=y.x+y.width/2,g=y.y-b,v={x:m,y:y.y,angle:.9*Math.PI}):(m=y.x+b,g=y.y-y.height/2,v={x:y.x,y:g,angle:.6*Math.PI}),t.beginPath(),t.arc(m,g,b,0,2*Math.PI,!1),t.stroke(),i=10+5*this.width,t.arrow(v.x,v.y,v.angle,i),t.fill(),t.stroke(),this.label&&(f=this._pointOnCircle(m,g,b,.5),this._label(t,this.label,f.x,f.y)) -}},T._dist=function(t,e,i,n,s,o){var r=i-t,a=n-e,h=r*r+a*a,d=((s-t)*r+(o-e)*a)/h;d>1?d=1:0>d&&(d=0);var l=t+d*r,p=e+d*a,c=l-s,u=p-o;return Math.sqrt(c*c+u*u)},x.prototype.setPosition=function(t,e){this.x=parseInt(t),this.y=parseInt(e)},x.prototype.setText=function(t){this.frame.innerHTML=t},x.prototype.show=function(t){if(void 0===t&&(t=!0),t){var e=this.frame.clientHeight,i=this.frame.clientWidth,n=this.frame.parentNode.clientHeight,s=this.frame.parentNode.clientWidth,o=this.y-e;o+e+this.padding>n&&(o=n-e-this.padding),this.padding>o&&(o=this.padding);var r=this.x;r+i+this.padding>s&&(r=s-i-this.padding),this.padding>r&&(r=this.padding),this.frame.style.left=r+"px",this.frame.style.top=o+"px",this.frame.style.visibility="visible"}else this.hide()},x.prototype.hide=function(){this.frame.style.visibility="hidden"},Groups=function(){this.clear(),this.defaultIndex=0},Groups.DEFAULT=[{border:"#2B7CE9",background:"#97C2FC",highlight:{border:"#2B7CE9",background:"#D2E5FF"}},{border:"#FFA500",background:"#FFFF00",highlight:{border:"#FFA500",background:"#FFFFA3"}},{border:"#FA0A10",background:"#FB7E81",highlight:{border:"#FA0A10",background:"#FFAFB1"}},{border:"#41A906",background:"#7BE141",highlight:{border:"#41A906",background:"#A1EC76"}},{border:"#E129F0",background:"#EB7DF4",highlight:{border:"#E129F0",background:"#F0B3F5"}},{border:"#7C29F0",background:"#AD85E4",highlight:{border:"#7C29F0",background:"#D3BDF0"}},{border:"#C37F00",background:"#FFA807",highlight:{border:"#C37F00",background:"#FFCA66"}},{border:"#4220FB",background:"#6E6EFD",highlight:{border:"#4220FB",background:"#9B9BFD"}},{border:"#FD5A77",background:"#FFC0CB",highlight:{border:"#FD5A77",background:"#FFD1D9"}},{border:"#4AD63A",background:"#C2FABC",highlight:{border:"#4AD63A",background:"#E6FFE3"}}],Groups.prototype.clear=function(){this.groups={},this.groups.length=function(){var t=0;for(var e in this)this.hasOwnProperty(e)&&t++;return t}},Groups.prototype.get=function(t){var e=this.groups[t];if(void 0==e){var i=this.defaultIndex%Groups.DEFAULT.length;this.defaultIndex++,e={},e.color=Groups.DEFAULT[i],this.groups[t]=e}return e},Groups.prototype.add=function(t,e){return this.groups[t]=e,e.color&&(e.color=E.parseColor(e.color)),e},Images=function(){this.images={},this.callback=void 0},Images.prototype.setOnloadCallback=function(t){this.callback=t},Images.prototype.load=function(t){var e=this.images[t];if(void 0==e){var i=this;e=new Image,this.images[t]=e,e.onload=function(){i.callback&&i.callback(this)},e.src=t}return e},S.prototype.setData=function(t){if(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 e=k.util.DOTToGraph(t.dot);return this.setData(e),void 0}}else this._setNodes(t&&t.nodes),this._setEdges(t&&t.edges);this.stabilize&&this._doStabilize(),this.start()},S.prototype.setOptions=function(t){if(t){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),t.edges){for(var e in t.edges)t.edges.hasOwnProperty(e)&&(this.constants.edges[e]=t.edges[e]);void 0!=t.edges.length&&t.nodes&&void 0==t.nodes.distance&&(this.constants.edges.length=t.edges.length,this.constants.nodes.distance=1.25*t.edges.length),t.edges.fontColor||(this.constants.edges.fontColor=t.edges.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=E.parseColor(t.nodes.color))}if(t.groups)for(var i in t.groups)if(t.groups.hasOwnProperty(i)){var n=t.groups[i];this.groups.add(i,n)}}this.setSize(this.width,this.height),this._setTranslation(this.frame.clientWidth/2,this.frame.clientHeight/2),this._setScale(1)},S.prototype._trigger=function(t,e){L.trigger(this,t,e)},S.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=D(this.frame.canvas,{prevent_default:!0}),this.hammer.on("tap",e._onTap.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("mousewheel",e._onMouseWheel.bind(e)),this.hammer.on("mousemove",e._onMouseMoveTitle.bind(e)),this.containerElement.appendChild(this.frame)},S.prototype._getNodeAt=function(t){var e=this._canvasToX(t.x),i=this._canvasToY(t.y),n={left:e,top:i,right:e,bottom:i},s=this._getNodesOverlappingWith(n);return s.length>0?s[s.length-1]:null},S.prototype._getPointer=function(t){return{x:t.pageX-k.util.getAbsoluteLeft(this.frame.canvas),y:t.pageY-k.util.getAbsoluteTop(this.frame.canvas)}},S.prototype._onTouch=function(t){this.drag.pointer=this._getPointer(t.gesture.touches[0]),this.drag.pinched=!1,this.pinch.scale=this._getScale()},S.prototype._onDragStart=function(){var t=this.drag;t.selection=[],t.translation=this._getTranslation(),t.nodeId=this._getNodeAt(t.pointer);var e=this.nodes[t.nodeId];if(e){e.isSelected()||this._selectNodes([t.nodeId]);var i=this;this.selection.forEach(function(e){var n=i.nodes[e];if(n){var s={id:e,node:n,x:n.x,y:n.y,xFixed:n.xFixed,yFixed:n.yFixed};n.xFixed=!0,n.yFixed=!0,t.selection.push(s)}})}},S.prototype._onDrag=function(t){if(!this.drag.pinched){var e=this._getPointer(t.gesture.touches[0]),i=this,n=this.drag,s=n.selection;if(s&&s.length){var o=e.x-n.pointer.x,r=e.y-n.pointer.y;s.forEach(function(t){var e=t.node;t.xFixed||(e.x=i._canvasToX(i._xToCanvas(t.x)+o)),t.yFixed||(e.y=i._canvasToY(i._yToCanvas(t.y)+r))}),this.moving||(this.moving=!0,this.start())}else{var a=e.x-this.drag.pointer.x,h=e.y-this.drag.pointer.y;this._setTranslation(this.drag.translation.x+a,this.drag.translation.y+h),this._redraw(),this.moved=!0}}},S.prototype._onDragEnd=function(){var t=this.drag.selection;t&&t.forEach(function(t){t.node.xFixed=t.xFixed,t.node.yFixed=t.yFixed})},S.prototype._onTap=function(t){var e=this._getPointer(t.gesture.touches[0]),i=this._getNodeAt(e),n=this.nodes[i];n?(this._selectNodes([i]),this.moving||this._redraw()):(this._unselectNodes(),this._redraw())},S.prototype._onHold=function(t){var e=this._getPointer(t.gesture.touches[0]),i=this._getNodeAt(e),n=this.nodes[i];if(n){if(n.isSelected())this._unselectNodes([i]);else{var s=!0;this._selectNodes([i],s)}this.moving||this._redraw()}},S.prototype._onPinch=function(t){var e=this._getPointer(t.gesture.center);this.drag.pinched=!0,"scale"in this.pinch||(this.pinch.scale=1);var i=this.pinch.scale*t.gesture.scale;this._zoom(i,e)},S.prototype._zoom=function(t,e){var i=this._getScale();.01>t&&(t=.01),t>10&&(t=10);var n=this._getTranslation(),s=t/i,o=(1-s)*e.x+n.x*s,r=(1-s)*e.y+n.y*s;return this._setScale(t),this._setTranslation(o,r),this._redraw(),t},S.prototype._onMouseWheel=function(t){var e=0;if(t.wheelDelta?e=t.wheelDelta/120:t.detail&&(e=-t.detail/3),e){"mouswheelScale"in this.pinch||(this.pinch.mouswheelScale=1);var i=this.pinch.mouswheelScale,n=e/10;0>e&&(n/=1-n),i*=1+n;var s=D.event.collectEventData(this,"scroll",t),o=this._getPointer(s.center);i=this._zoom(i,o),this.pinch.mouswheelScale=i}t.preventDefault()},S.prototype._onMouseMoveTitle=function(t){var e=D.event.collectEventData(this,"mousemove",t),i=this._getPointer(e.center);this.popupNode&&this._checkHidePopup(i);var n=this,s=function(){n._checkShowPopup(i)};this.popupTimer&&clearInterval(this.popupTimer),this.leftButtonDown||(this.popupTimer=setTimeout(s,300))},S.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)},n=this.popupNode;if(void 0==this.popupNode){var s=this.nodes;for(e in s)if(s.hasOwnProperty(e)){var o=s[e];if(void 0!=o.getTitle()&&o.isOverlappingWith(i)){this.popupNode=o;break}}}if(void 0==this.popupNode){var r=this.edges;for(e in r)if(r.hasOwnProperty(e)){var a=r[e];if(a.connected&&void 0!=a.getTitle()&&a.isOverlappingWith(i)){this.popupNode=a;break}}}if(this.popupNode){if(this.popupNode!=n){var h=this;h.popup||(h.popup=new x(h.frame)),h.popup.setPosition(t.x-3,t.y-3),h.popup.setText(h.popupNode.getTitle()),h.popup.show()}}else this.popup&&this.popup.hide()},S.prototype._checkHidePopup=function(t){this.popupNode&&this._getNodeAt(t)||(this.popupNode=void 0,this.popup&&this.popup.hide())},S.prototype._unselectNodes=function(t,e){var i,n,s,o=!1;if(t)for(i=0,n=t.length;n>i;i++){s=t[i],this.nodes[s].unselect();for(var r=0;this.selection.length>r;)this.selection[r]==s?(this.selection.splice(r,1),o=!0):r++}else if(this.selection&&this.selection.length){for(i=0,n=this.selection.length;n>i;i++)s=this.selection[i],this.nodes[s].unselect(),o=!0;this.selection=[]}return!o||1!=e&&void 0!=e||this._trigger("select"),o},S.prototype._selectNodes=function(t,e){var i,n,s=!1,o=!0;if(t.length!=this.selection.length)o=!1;else for(i=0,n=Math.min(t.length,this.selection.length);n>i;i++)if(t[i]!=this.selection[i]){o=!1;break}if(o)return s;if(void 0==e||0==e){var r=!1;s=this._unselectNodes(void 0,r)}for(i=0,n=t.length;n>i;i++){var a=t[i],h=-1!=this.selection.indexOf(a);h||(this.nodes[a].select(),this.selection.push(a),s=!0)}return s&&this._trigger("select"),s},S.prototype._getNodesOverlappingWith=function(t){var e=this.nodes,i=[];for(var n in e)e.hasOwnProperty(n)&&e[n].isOverlappingWith(t)&&i.push(n);return i},S.prototype.getSelection=function(){return this.selection.concat([])},S.prototype.setSelection=function(t){var e,i,n;if(!t||void 0==t.length)throw"Selection must be an array with ids";for(e=0,i=this.selection.length;i>e;e++)n=this.selection[e],this.nodes[n].unselect();for(this.selection=[],e=0,i=t.length;i>e;e++){n=t[e];var s=this.nodes[n];if(!s)throw new RangeError('Node with id "'+n+'" not found');s.select(),this.selection.push(n)}this.redraw()},S.prototype._updateSelection=function(){for(var t=0;this.selection.length>t;){var e=this.selection[t];this.nodes[e]?t++:this.selection.splice(t,1)}},S.prototype._getConnectionCount=function(t){function e(t){for(var e=[],i=0,n=t.length;n>i;i++)for(var s=t[i],o=s.edges,r=0,a=o.length;a>r;r++){var h=o[r],d=null;h.from==s?d=h.to:h.to==s&&(d=h.from);var l,p;if(d)for(l=0,p=t.length;p>l;l++)if(t[l]==d){d=null;break}if(d)for(l=0,p=e.length;p>l;l++)if(e[l]==d){d=null;break}d&&e.push(d)}return e}void 0==t&&(t=1);var i=[],n=this.nodes;for(var s in n)if(n.hasOwnProperty(s)){for(var o=[n[s]],r=0;t>r;r++)o=o.concat(e(o));i.push(o)}for(var a=[],h=0,d=i.length;d>h;h++)a.push(i[h].length);return a},S.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},S.prototype._setNodes=function(t){var e=this.nodesData;if(t instanceof o||t instanceof r)this.nodesData=t;else if(t instanceof Array)this.nodesData=new o,this.nodesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.nodesData=new o}if(e&&O.forEach(this.nodesListeners,function(t,i){e.unsubscribe(i,t)}),this.nodes={},this.nodesData){var i=this;O.forEach(this.nodesListeners,function(t,e){i.nodesData.subscribe(e,t)});var n=this.nodesData.getIds();this._addNodes(n)}this._updateSelection()},S.prototype._addNodes=function(t){for(var e,i=0,n=t.length;n>i;i++){e=t[i];var s=this.nodesData.get(e),o=new E(s,this.images,this.groups,this.constants);if(this.nodes[e]=o,!o.isFixed()){var r=2*this.constants.edges.length,a=t.length,h=2*Math.PI*(i/a);o.x=r*Math.cos(h),o.y=r*Math.sin(h),this.moving=!0}}this._reconnectEdges(),this._updateValueRange(this.nodes)},S.prototype._updateNodes=function(t){for(var e=this.nodes,i=this.nodesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o],a=i.get(o);r?r.setProperties(a,this.constants):(r=new E(properties,this.images,this.groups,this.constants),e[o]=r,r.isFixed()||(this.moving=!0))}this._reconnectEdges(),this._updateValueRange(e)},S.prototype._removeNodes=function(t){for(var e=this.nodes,i=0,n=t.length;n>i;i++){var s=t[i];delete e[s]}this._reconnectEdges(),this._updateSelection(),this._updateValueRange(e)},S.prototype._setEdges=function(t){var e=this.edgesData;if(t instanceof o||t instanceof r)this.edgesData=t;else if(t instanceof Array)this.edgesData=new o,this.edgesData.add(t);else{if(t)throw new TypeError("Array or DataSet expected");this.edgesData=new o}if(e&&O.forEach(this.edgesListeners,function(t,i){e.unsubscribe(i,t)}),this.edges={},this.edgesData){var i=this;O.forEach(this.edgesListeners,function(t,e){i.edgesData.subscribe(e,t)});var n=this.edgesData.getIds();this._addEdges(n)}this._reconnectEdges()},S.prototype._addEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=e[o];r&&r.disconnect();var a=i.get(o);e[o]=new T(a,this,this.constants)}this.moving=!0,this._updateValueRange(e)},S.prototype._updateEdges=function(t){for(var e=this.edges,i=this.edgesData,n=0,s=t.length;s>n;n++){var o=t[n],r=i.get(o),a=e[o];a?(a.disconnect(),a.setProperties(r,this.constants),a.connect()):(a=new T(r,this,this.constants),this.edges[o]=a)}this.moving=!0,this._updateValueRange(e)},S.prototype._removeEdges=function(t){for(var e=this.edges,i=0,n=t.length;n>i;i++){var s=t[i],o=e[s];o&&(o.disconnect(),delete e[s])}this.moving=!0,this._updateValueRange(e)},S.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 n=i[t];n.from=null,n.to=null,n.connect()}},S.prototype._updateValueRange=function(t){var e,i=void 0,n=void 0;for(e in t)if(t.hasOwnProperty(e)){var s=t[e].getValue();void 0!==s&&(i=void 0===i?s:Math.min(s,i),n=void 0===n?s:Math.max(s,n))}if(void 0!==i&&void 0!==n)for(e in t)t.hasOwnProperty(e)&&t[e].setValueRange(i,n)},S.prototype.redraw=function(){this.setSize(this.width,this.height),this._redraw()},S.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._drawEdges(t),this._drawNodes(t),t.restore()},S.prototype._setTranslation=function(t,e){void 0===this.translation&&(this.translation={x:0,y:0}),void 0!==t&&(this.translation.x=t),void 0!==e&&(this.translation.y=e)},S.prototype._getTranslation=function(){return{x:this.translation.x,y:this.translation.y}},S.prototype._setScale=function(t){this.scale=t},S.prototype._getScale=function(){return this.scale},S.prototype._canvasToX=function(t){return(t-this.translation.x)/this.scale},S.prototype._xToCanvas=function(t){return t*this.scale+this.translation.x},S.prototype._canvasToY=function(t){return(t-this.translation.y)/this.scale},S.prototype._yToCanvas=function(t){return t*this.scale+this.translation.y},S.prototype._drawNodes=function(t){var e=this.nodes,i=[];for(var n in e)e.hasOwnProperty(n)&&(e[n].isSelected()?i.push(n):e[n].draw(t));for(var s=0,o=i.length;o>s;s++)e[i[s]].draw(t)},S.prototype._drawEdges=function(t){var e=this.edges;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];n.connected&&e[i].draw(t)}},S.prototype._doStabilize=function(){new Date;for(var t=0,e=this.constants.minVelocity,i=!1;!i&&this.constants.maxIterations>t;)this._calculateForces(),this._discreteStepNodes(),i=!this._isMoving(e),t++;new Date},S.prototype._calculateForces=function(){var t,e,i,n,s,o,r,a,h,d,l,p=this.nodes,c=this.edges,u=.01,f=this.frame.canvas.clientWidth/2,m=this.frame.canvas.clientHeight/2;for(t in p)if(p.hasOwnProperty(t)){var g=p[t];e=f-g.x,i=m-g.y,n=Math.atan2(i,e),o=Math.cos(n)*u,r=Math.sin(n)*u,g._setForce(o,r)}var v=this.constants.nodes.distance,y=10;for(var b in p)if(p.hasOwnProperty(b)){var w=p[b];for(var _ in p)if(p.hasOwnProperty(_)){var E=p[_];e=E.x-w.x,i=E.y-w.y,s=Math.sqrt(e*e+i*i),n=Math.atan2(i,e),a=1/(1+Math.exp((s/v-1)*y)),o=Math.cos(n)*a,r=Math.sin(n)*a,w._addForce(-o,-r),E._addForce(o,r)}}for(t in c)if(c.hasOwnProperty(t)){var T=c[t];T.connected&&(e=T.to.x-T.from.x,i=T.to.y-T.from.y,l=T.length,d=Math.sqrt(e*e+i*i),n=Math.atan2(i,e),h=T.stiffness*(l-d),o=Math.cos(n)*h,r=Math.sin(n)*h,T.from._addForce(-o,-r),T.to._addForce(o,r))}},S.prototype._isMoving=function(t){var e=this.nodes;for(var i in e)if(e.hasOwnProperty(i)&&e[i].isMoving(t))return!0;return!1},S.prototype._discreteStepNodes=function(){var t=this.refreshRate/1e3,e=this.nodes;for(var i in e)e.hasOwnProperty(i)&&e[i].discreteStep(t)},S.prototype.start=function(){if(this.moving){this._calculateForces(),this._discreteStepNodes();var t=this.constants.minVelocity;this.moving=this._isMoving(t)}if(this.moving){if(!this.timer){var e=this;this.timer=window.setTimeout(function(){e.timer=void 0,e.start(),e._redraw()},this.refreshRate)}}else this._redraw()},S.prototype.stop=function(){this.timer&&(window.clearInterval(this.timer),this.timer=void 0)};var k={util:O,events:L,Controller:d,DataSet:o,DataView:r,Range:h,Stack:a,TimeStep:TimeStep,EventBus:s,components:{items:{Item:m,ItemBox:g,ItemPoint:v,ItemRange:y},Component:l,Panel:p,RootPanel:c,ItemSet:f,TimeAxis:u},graph:{Node:E,Edge:T,Popup:x,Groups:Groups,Images:Images},Timeline:_,Graph:S};n!==void 0&&(n=k),i!==void 0&&i.exports!==void 0&&(i.exports=k),"function"==typeof t&&t(function(){return k}),"undefined"!=typeof window&&(window.vis=k),O.loadCss("/* vis.js stylesheet */\n.vis.timeline {\n}\n\n\n.vis.timeline.rootpanel {\n position: relative;\n overflow: hidden;\n\n border: 1px solid #bfbfbf;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n\n.vis.timeline .panel {\n position: absolute;\n overflow: hidden;\n}\n\n\n.vis.timeline .groupset {\n position: absolute;\n padding: 0;\n margin: 0;\n}\n\n.vis.timeline .labels {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n\n padding: 0;\n margin: 0;\n\n border-right: 1px solid #bfbfbf;\n box-sizing: border-box;\n -moz-box-sizing: border-box;\n}\n\n.vis.timeline .labels .label {\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n border-bottom: 1px solid #bfbfbf;\n color: #4d4d4d;\n}\n\n.vis.timeline .labels .label .inner {\n display: inline-block;\n padding: 5px;\n}\n\n\n.vis.timeline .itemset {\n position: absolute;\n padding: 0;\n margin: 0;\n overflow: hidden;\n}\n\n.vis.timeline .background {\n}\n\n.vis.timeline .foreground {\n}\n\n.vis.timeline .itemset-axis {\n position: absolute;\n}\n\n.vis.timeline .groupset .itemset-axis {\n border-top: 1px solid #bfbfbf;\n}\n\n/* TODO: with orientation=='bottom', this will more or less overlap with timeline axis\n.vis.timeline .groupset .itemset-axis:last-child {\n border-top: none;\n}\n*/\n\n\n.vis.timeline .item {\n position: absolute;\n color: #1A1A1A;\n border-color: #97B0F8;\n background-color: #D5DDF6;\n display: inline-block;\n}\n\n.vis.timeline .item.selected {\n border-color: #FFC200;\n background-color: #FFF785;\n z-index: 999;\n}\n\n.vis.timeline .item.cluster {\n /* TODO: use another color or pattern? */\n background: #97B0F8 url('img/cluster_bg.png');\n color: white;\n}\n.vis.timeline .item.cluster.point {\n border-color: #D5DDF6;\n}\n\n.vis.timeline .item.box {\n text-align: center;\n border-style: solid;\n border-width: 1px;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.point {\n background: none;\n}\n\n.vis.timeline .dot {\n border: 5px solid #97B0F8;\n position: absolute;\n border-radius: 5px;\n -moz-border-radius: 5px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.range {\n overflow: hidden;\n border-style: solid;\n border-width: 1px;\n border-radius: 2px;\n -moz-border-radius: 2px; /* For Firefox 3.6 and older */\n}\n\n.vis.timeline .item.range .drag-left {\n cursor: w-resize;\n z-index: 1000;\n}\n\n.vis.timeline .item.range .drag-right {\n cursor: e-resize;\n z-index: 1000;\n}\n\n.vis.timeline .item.range .content {\n position: relative;\n display: inline-block;\n}\n\n.vis.timeline .item.line {\n position: absolute;\n width: 0;\n border-left-width: 1px;\n border-left-style: solid;\n}\n\n.vis.timeline .item .content {\n margin: 5px;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.vis.timeline .axis {\n position: relative;\n}\n\n.vis.timeline .axis .text {\n position: absolute;\n color: #4d4d4d;\n padding: 3px;\n white-space: nowrap;\n}\n\n.vis.timeline .axis .text.measure {\n position: absolute;\n padding-left: 0;\n padding-right: 0;\n margin-left: 0;\n margin-right: 0;\n visibility: hidden;\n}\n\n.vis.timeline .axis .grid.vertical {\n position: absolute;\n width: 0;\n border-right: 1px solid;\n}\n\n.vis.timeline .axis .grid.horizontal {\n position: absolute;\n left: 0;\n width: 100%;\n height: 0;\n border-bottom: 1px solid;\n}\n\n.vis.timeline .axis .grid.minor {\n border-color: #e5e5e5;\n}\n\n.vis.timeline .axis .grid.major {\n border-color: #bfbfbf;\n}\n\n")},{hammerjs:1,moment:2}]},{},[3])(3)}); \ No newline at end of file

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