} path
+ * @param {{}} optionsObj
+ * @returns {{}}
+ * @private
+ */
+
+ }, {
+ key: "_constructOptions",
+ value: function _constructOptions(value, path) {
+ var optionsObj = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
+ var pointer = optionsObj; // when dropdown boxes can be string or boolean, we typecast it into correct types
+
+ value = value === 'true' ? true : value;
+ value = value === 'false' ? false : value;
+
+ for (var i = 0; i < path.length; i++) {
+ if (path[i] !== 'global') {
+ if (pointer[path[i]] === undefined) {
+ pointer[path[i]] = {};
+ }
+
+ if (i !== path.length - 1) {
+ pointer = pointer[path[i]];
+ } else {
+ pointer[path[i]] = value;
+ }
+ }
+ }
+
+ return optionsObj;
+ }
+ /**
+ * @private
+ */
+
+ }, {
+ key: "_printOptions",
+ value: function _printOptions() {
+ var options = this.getOptions();
+ this.optionsContainer.innerHTML = 'var options = ' + stringify$2(options, null, 2) + '
';
+ }
+ /**
+ *
+ * @returns {{}} options
+ */
+
+ }, {
+ key: "getOptions",
+ value: function getOptions() {
+ var options = {};
+
+ for (var i = 0; i < this.changedOptions.length; i++) {
+ this._constructOptions(this.changedOptions[i].value, this.changedOptions[i].path, options);
+ }
+
+ return options;
+ }
+ }]);
+
+ return Configurator;
+}();
+
+/**
+ * Create a timeline visualization
+ * @extends Core
+ */
+
+var Timeline =
+/*#__PURE__*/
+function (_Core) {
+ inherits$1(Timeline, _Core);
+
+ /**
+ * @param {HTMLElement} container
+ * @param {vis.DataSet | vis.DataView | Array} [items]
+ * @param {vis.DataSet | vis.DataView | Array} [groups]
+ * @param {Object} [options] See Timeline.setOptions for the available options.
+ * @constructor Timeline
+ */
+ function Timeline(container, items, groups, options) {
+ var _context2, _context3, _context4, _context5, _context6, _context7, _context8;
+
+ var _this;
+
+ classCallCheck$1(this, Timeline);
+
+ _this = possibleConstructorReturn$1(this, getPrototypeOf$4(Timeline).call(this));
+ _this.initTime = new Date();
+ _this.itemsDone = false;
+
+ if (!(assertThisInitialized$1(_this) instanceof Timeline)) {
+ throw new SyntaxError('Constructor must be called with the new operator');
+ } // if the third element is options, the forth is groups (optionally);
+
+
+ if (!(isArray$3(groups) || groups instanceof DataSet || groups instanceof DataView) && groups instanceof Object) {
+ var forthArgument = options;
+ options = groups;
+ groups = forthArgument;
+ } // TODO: REMOVE THIS in the next MAJOR release
+ // see https://github.com/almende/vis/issues/2511
+
+
+ if (options && options.throttleRedraw) {
+ console.warn("Timeline option \"throttleRedraw\" is DEPRICATED and no longer supported. It will be removed in the next MAJOR release.");
+ }
+
+ var me = assertThisInitialized$1(_this);
+
+ _this.defaultOptions = {
+ autoResize: true,
+ orientation: {
+ axis: 'bottom',
+ // axis orientation: 'bottom', 'top', or 'both'
+ item: 'bottom' // not relevant
+
+ },
+ moment: moment$3
+ };
+ _this.options = util$2.deepExtend({}, _this.defaultOptions); // Create the DOM, props, and emitter
+
+ _this._create(container);
+
+ if (!options || options && typeof options.rtl == "undefined") {
+ _this.dom.root.style.visibility = 'hidden';
+ var directionFromDom;
+ var domNode = _this.dom.root;
+
+ while (!directionFromDom && domNode) {
+ directionFromDom = window.getComputedStyle(domNode, null).direction;
+ domNode = domNode.parentElement;
+ }
+
+ _this.options.rtl = directionFromDom && directionFromDom.toLowerCase() == "rtl";
+ } else {
+ _this.options.rtl = options.rtl;
+ }
+
+ if (options) {
+ if (options.rollingMode) {
+ _this.options.rollingMode = options.rollingMode;
+ }
+
+ if (options.onInitialDrawComplete) {
+ _this.options.onInitialDrawComplete = options.onInitialDrawComplete;
+ }
+
+ if (options.onTimeout) {
+ _this.options.onTimeout = options.onTimeout;
+ }
+
+ if (options.loadingScreenTemplate) {
+ _this.options.loadingScreenTemplate = options.loadingScreenTemplate;
+ }
+ } // Prepare loading screen
+
+
+ var loadingScreenFragment = document.createElement('div');
+
+ if (_this.options.loadingScreenTemplate) {
+ var _context;
+
+ var templateFunction = bind$2(_context = _this.options.loadingScreenTemplate).call(_context, assertThisInitialized$1(_this));
+
+ var loadingScreen = templateFunction(_this.dom.loadingScreen);
+
+ if (loadingScreen instanceof Object && !(loadingScreen instanceof Element)) {
+ templateFunction(loadingScreenFragment);
+ } else {
+ if (loadingScreen instanceof Element) {
+ loadingScreenFragment.innerHTML = '';
+ loadingScreenFragment.appendChild(loadingScreen);
+ } else if (loadingScreen != undefined) {
+ loadingScreenFragment.innerHTML = loadingScreen;
+ }
+ }
+ }
+
+ _this.dom.loadingScreen.appendChild(loadingScreenFragment); // all components listed here will be repainted automatically
+
+
+ _this.components = [];
+ _this.body = {
+ dom: _this.dom,
+ domProps: _this.props,
+ emitter: {
+ on: bind$2(_context2 = _this.on).call(_context2, assertThisInitialized$1(_this)),
+ off: bind$2(_context3 = _this.off).call(_context3, assertThisInitialized$1(_this)),
+ emit: bind$2(_context4 = _this.emit).call(_context4, assertThisInitialized$1(_this))
+ },
+ hiddenDates: [],
+ util: {
+ getScale: function getScale() {
+ return me.timeAxis.step.scale;
+ },
+ getStep: function getStep() {
+ return me.timeAxis.step.step;
+ },
+ toScreen: bind$2(_context5 = me._toScreen).call(_context5, me),
+ toGlobalScreen: bind$2(_context6 = me._toGlobalScreen).call(_context6, me),
+ // this refers to the root.width
+ toTime: bind$2(_context7 = me._toTime).call(_context7, me),
+ toGlobalTime: bind$2(_context8 = me._toGlobalTime).call(_context8, me)
+ }
+ }; // range
+
+ _this.range = new Range(_this.body, _this.options);
+
+ _this.components.push(_this.range);
+
+ _this.body.range = _this.range; // time axis
+
+ _this.timeAxis = new TimeAxis(_this.body, _this.options);
+ _this.timeAxis2 = null; // used in case of orientation option 'both'
+
+ _this.components.push(_this.timeAxis); // current time bar
+
+
+ _this.currentTime = new CurrentTime(_this.body, _this.options);
+
+ _this.components.push(_this.currentTime); // item set
+
+
+ _this.itemSet = new ItemSet(_this.body, _this.options);
+
+ _this.components.push(_this.itemSet);
+
+ _this.itemsData = null; // DataSet
+
+ _this.groupsData = null; // DataSet
+
+ _this.dom.root.onclick = function (event) {
+ me.emit('click', me.getEventProperties(event));
+ };
+
+ _this.dom.root.ondblclick = function (event) {
+ me.emit('doubleClick', me.getEventProperties(event));
+ };
+
+ _this.dom.root.oncontextmenu = function (event) {
+ me.emit('contextmenu', me.getEventProperties(event));
+ };
+
+ _this.dom.root.onmouseover = function (event) {
+ me.emit('mouseOver', me.getEventProperties(event));
+ };
+
+ if (window.PointerEvent) {
+ _this.dom.root.onpointerdown = function (event) {
+ me.emit('mouseDown', me.getEventProperties(event));
+ };
+
+ _this.dom.root.onpointermove = function (event) {
+ me.emit('mouseMove', me.getEventProperties(event));
+ };
+
+ _this.dom.root.onpointerup = function (event) {
+ me.emit('mouseUp', me.getEventProperties(event));
+ };
+ } else {
+ _this.dom.root.onmousemove = function (event) {
+ me.emit('mouseMove', me.getEventProperties(event));
+ };
+
+ _this.dom.root.onmousedown = function (event) {
+ me.emit('mouseDown', me.getEventProperties(event));
+ };
+
+ _this.dom.root.onmouseup = function (event) {
+ me.emit('mouseUp', me.getEventProperties(event));
+ };
+ } //Single time autoscale/fit
+
+
+ _this.initialFitDone = false;
+
+ _this.on('changed', function () {
+ if (me.itemsData == null) return;
+
+ if (!me.initialFitDone && !me.options.rollingMode) {
+ me.initialFitDone = true;
+
+ if (me.options.start != undefined || me.options.end != undefined) {
+ if (me.options.start == undefined || me.options.end == undefined) {
+ var range = me.getItemRange();
+ }
+
+ var start = me.options.start != undefined ? me.options.start : range.min;
+ var end = me.options.end != undefined ? me.options.end : range.max;
+ me.setWindow(start, end, {
+ animation: false
+ });
+ } else {
+ me.fit({
+ animation: false
+ });
+ }
+ }
+
+ if (!me.initialDrawDone && (me.initialRangeChangeDone || !me.options.start && !me.options.end || me.options.rollingMode)) {
+ me.initialDrawDone = true;
+ me.itemSet.initialDrawDone = true;
+ me.dom.root.style.visibility = 'visible';
+ me.dom.loadingScreen.parentNode.removeChild(me.dom.loadingScreen);
+
+ if (me.options.onInitialDrawComplete) {
+ setTimeout$2(function () {
+ return me.options.onInitialDrawComplete();
+ }, 0);
+ }
+ }
+ });
+
+ _this.on('destroyTimeline', function () {
+ me.destroy();
+ }); // apply options
+
+
+ if (options) {
+ _this.setOptions(options);
+ }
+
+ _this.body.emitter.on('fit', function (args) {
+ _this._onFit(args);
+
+ _this.redraw();
+ }); // IMPORTANT: THIS HAPPENS BEFORE SET ITEMS!
+
+
+ if (groups) {
+ _this.setGroups(groups);
+ } // create itemset
+
+
+ if (items) {
+ _this.setItems(items);
+ } // draw for the first time
+
+
+ _this._redraw();
+
+ return _this;
+ }
+ /**
+ * Load a configurator
+ * @return {Object}
+ * @private
+ */
+
+
+ createClass$1(Timeline, [{
+ key: "_createConfigurator",
+ value: function _createConfigurator() {
+ return new Configurator(this, this.dom.container, configureOptions);
+ }
+ /**
+ * Force a redraw. The size of all items will be recalculated.
+ * Can be useful to manually redraw when option autoResize=false and the window
+ * has been resized, or when the items CSS has been changed.
+ *
+ * Note: this function will be overridden on construction with a trottled version
+ */
+
+ }, {
+ key: "redraw",
+ value: function redraw() {
+ this.itemSet && this.itemSet.markDirty({
+ refreshItems: true
+ });
+
+ this._redraw();
+ }
+ /**
+ * Remove an item from the group
+ * @param {object} options
+ */
+
+ }, {
+ key: "setOptions",
+ value: function setOptions(options) {
+ // validate options
+ var errorFound = Validator.validate(options, allOptions$1);
+
+ if (errorFound === true) {
+ console.log('%cErrors have been found in the supplied options object.', printStyle);
+ }
+
+ Core.prototype.setOptions.call(this, options);
+
+ if ('type' in options) {
+ if (options.type !== this.options.type) {
+ this.options.type = options.type; // force recreation of all items
+
+ var itemsData = this.itemsData;
+
+ if (itemsData) {
+ var selection = this.getSelection();
+ this.setItems(null); // remove all
+
+ this.setItems(itemsData); // add all
+
+ this.setSelection(selection); // restore selection
+ }
+ }
+ }
+ }
+ /**
+ * Set items
+ * @param {vis.DataSet | Array | null} items
+ */
+
+ }, {
+ key: "setItems",
+ value: function setItems(items) {
+ this.itemsDone = false; // convert to type DataSet when needed
+
+ var newDataSet;
+
+ if (!items) {
+ newDataSet = null;
+ } else if (items instanceof DataSet || items instanceof DataView) {
+ newDataSet = items;
+ } else {
+ // turn an array into a dataset
+ newDataSet = new DataSet(items, {
+ type: {
+ start: 'Date',
+ end: 'Date'
+ }
+ });
+ } // set items
+
+
+ this.itemsData = newDataSet;
+ this.itemSet && this.itemSet.setItems(newDataSet);
+ }
+ /**
+ * Set groups
+ * @param {vis.DataSet | Array} groups
+ */
+
+ }, {
+ key: "setGroups",
+ value: function setGroups(groups) {
+ // convert to type DataSet when needed
+ var newDataSet;
+
+ if (!groups) {
+ newDataSet = null;
+ } else {
+ var filter = function filter(group) {
+ return group.visible !== false;
+ };
+
+ if (groups instanceof DataSet || groups instanceof DataView) {
+ newDataSet = new DataView(groups, {
+ filter: filter
+ });
+ } else {
+ // turn an array into a dataset
+ newDataSet = new DataSet(filter$2(groups).call(groups, filter));
+ }
+ }
+
+ this.groupsData = newDataSet;
+ this.itemSet.setGroups(newDataSet);
+ }
+ /**
+ * Set both items and groups in one go
+ * @param {{items: (Array | vis.DataSet), groups: (Array | vis.DataSet)}} data
+ */
+
+ }, {
+ key: "setData",
+ value: function setData(data) {
+ if (data && data.groups) {
+ this.setGroups(data.groups);
+ }
+
+ if (data && data.items) {
+ this.setItems(data.items);
+ }
+ }
+ /**
+ * Set selected items by their id. Replaces the current selection
+ * Unknown id's are silently ignored.
+ * @param {string[] | string} [ids] An array with zero or more id's of the items to be
+ * selected. If ids is an empty array, all items will be
+ * unselected.
+ * @param {Object} [options] Available options:
+ * `focus: boolean`
+ * If true, focus will be set to the selected item(s)
+ * `animation: boolean | {duration: number, easingFunction: string}`
+ * If true (default), the range is animated
+ * smoothly to the new window. An object can be
+ * provided to specify duration and easing function.
+ * Default duration is 500 ms, and default easing
+ * function is 'easeInOutQuad'.
+ * Only applicable when option focus is true.
+ */
+
+ }, {
+ key: "setSelection",
+ value: function setSelection(ids, options) {
+ this.itemSet && this.itemSet.setSelection(ids);
+
+ if (options && options.focus) {
+ this.focus(ids, options);
+ }
+ }
+ /**
+ * Get the selected items by their id
+ * @return {Array} ids The ids of the selected items
+ */
+
+ }, {
+ key: "getSelection",
+ value: function getSelection() {
+ return this.itemSet && this.itemSet.getSelection() || [];
+ }
+ /**
+ * Adjust the visible window such that the selected item (or multiple items)
+ * are centered on screen.
+ * @param {string | String[]} id An item id or array with item ids
+ * @param {Object} [options] Available options:
+ * `animation: boolean | {duration: number, easingFunction: string}`
+ * If true (default), the range is animated
+ * smoothly to the new window. An object can be
+ * provided to specify duration and easing function.
+ * Default duration is 500 ms, and default easing
+ * function is 'easeInOutQuad'.
+ * `zoom: boolean`
+ * If true (default), the timeline will
+ * zoom on the element after focus it.
+ */
+
+ }, {
+ key: "focus",
+ value: function focus(id, options) {
+ if (!this.itemsData || id == undefined) return;
+ var ids = isArray$3(id) ? id : [id]; // get the specified item(s)
+
+ var itemsData = this.itemsData.getDataSet().get(ids, {
+ type: {
+ start: 'Date',
+ end: 'Date'
+ }
+ }); // calculate minimum start and maximum end of specified items
+
+ var start = null;
+ var end = null;
+
+ forEach$3(itemsData).call(itemsData, function (itemData) {
+ var s = itemData.start.valueOf();
+ var e = 'end' in itemData ? itemData.end.valueOf() : itemData.start.valueOf();
+
+ if (start === null || s < start) {
+ start = s;
+ }
+
+ if (end === null || e > end) {
+ end = e;
+ }
+ });
+
+ if (start !== null && end !== null) {
+ var me = this; // Use the first item for the vertical focus
+
+ var item = this.itemSet.items[ids[0]];
+ var startPos = this._getScrollTop() * -1;
+ var initialVerticalScroll = null; // Setup a handler for each frame of the vertical scroll
+
+ var verticalAnimationFrame = function verticalAnimationFrame(ease, willDraw, done) {
+ var verticalScroll = getItemVerticalScroll(me, item);
+
+ if (verticalScroll === false) {
+ return; // We don't need to scroll, so do nothing
+ }
+
+ if (!initialVerticalScroll) {
+ initialVerticalScroll = verticalScroll;
+ }
+
+ if (initialVerticalScroll.itemTop == verticalScroll.itemTop && !initialVerticalScroll.shouldScroll) {
+ return; // We don't need to scroll, so do nothing
+ } else if (initialVerticalScroll.itemTop != verticalScroll.itemTop && verticalScroll.shouldScroll) {
+ // The redraw shifted elements, so reset the animation to correct
+ initialVerticalScroll = verticalScroll;
+ startPos = me._getScrollTop() * -1;
+ }
+
+ var from = startPos;
+ var to = initialVerticalScroll.scrollOffset;
+ var scrollTop = done ? to : from + (to - from) * ease;
+
+ me._setScrollTop(-scrollTop);
+
+ if (!willDraw) {
+ me._redraw();
+ }
+ }; // Enforces the final vertical scroll position
+
+
+ var setFinalVerticalPosition = function setFinalVerticalPosition() {
+ var finalVerticalScroll = getItemVerticalScroll(me, item);
+
+ if (finalVerticalScroll.shouldScroll && finalVerticalScroll.itemTop != initialVerticalScroll.itemTop) {
+ me._setScrollTop(-finalVerticalScroll.scrollOffset);
+
+ me._redraw();
+ }
+ }; // Perform one last check at the end to make sure the final vertical
+ // position is correct
+
+
+ var finalVerticalCallback = function finalVerticalCallback() {
+ // Double check we ended at the proper scroll position
+ setFinalVerticalPosition(); // Let the redraw settle and finalize the position.
+
+ setTimeout$2(setFinalVerticalPosition, 100);
+ }; // calculate the new middle and interval for the window
+
+
+ var zoom = options && options.zoom !== undefined ? options.zoom : true;
+ var middle = (start + end) / 2;
+ var interval = zoom ? (end - start) * 1.1 : Math.max(this.range.end - this.range.start, (end - start) * 1.1);
+ var animation = options && options.animation !== undefined ? options.animation : true;
+
+ if (!animation) {
+ // We aren't animating so set a default so that the final callback forces the vertical location
+ initialVerticalScroll = {
+ shouldScroll: false,
+ scrollOffset: -1,
+ itemTop: -1
+ };
+ }
+
+ this.range.setRange(middle - interval / 2, middle + interval / 2, {
+ animation: animation
+ }, finalVerticalCallback, verticalAnimationFrame);
+ }
+ }
+ /**
+ * Set Timeline window such that it fits all items
+ * @param {Object} [options] Available options:
+ * `animation: boolean | {duration: number, easingFunction: string}`
+ * If true (default), the range is animated
+ * smoothly to the new window. An object can be
+ * provided to specify duration and easing function.
+ * Default duration is 500 ms, and default easing
+ * function is 'easeInOutQuad'.
+ * @param {function} [callback]
+ */
+
+ }, {
+ key: "fit",
+ value: function fit(options, callback) {
+ var animation = options && options.animation !== undefined ? options.animation : true;
+ var range;
+ var dataset = this.itemsData && this.itemsData.getDataSet();
+
+ if (dataset.length === 1 && dataset.get()[0].end === undefined) {
+ // a single item -> don't fit, just show a range around the item from -4 to +3 days
+ range = this.getDataRange();
+ this.moveTo(range.min.valueOf(), {
+ animation: animation
+ }, callback);
+ } else {
+ // exactly fit the items (plus a small margin)
+ range = this.getItemRange();
+ this.range.setRange(range.min, range.max, {
+ animation: animation
+ }, callback);
+ }
+ }
+ /**
+ * Determine the range of the items, taking into account their actual width
+ * and a margin of 10 pixels on both sides.
+ *
+ * @returns {{min: Date, max: Date}}
+ */
+
+ }, {
+ key: "getItemRange",
+ value: function getItemRange() {
+ var _this2 = this;
+
+ // get a rough approximation for the range based on the items start and end dates
+ var range = this.getDataRange();
+ var min = range.min !== null ? range.min.valueOf() : null;
+ var max = range.max !== null ? range.max.valueOf() : null;
+ var minItem = null;
+ var maxItem = null;
+
+ if (min != null && max != null) {
+ var interval = max - min; // ms
+
+ if (interval <= 0) {
+ interval = 10;
+ }
+
+ var factor = interval / this.props.center.width;
+ var redrawQueue = {};
+ var redrawQueueLength = 0; // collect redraw functions
+
+ forEach$3(util$2).call(util$2, this.itemSet.items, function (item, key) {
+ if (item.groupShowing) {
+ var returnQueue = true;
+ redrawQueue[key] = item.redraw(returnQueue);
+ redrawQueueLength = redrawQueue[key].length;
+ }
+ });
+
+ var needRedraw = redrawQueueLength > 0;
+
+ if (needRedraw) {
+ var _loop = function _loop(i) {
+ forEach$3(util$2).call(util$2, redrawQueue, function (fns) {
+ fns[i]();
+ });
+ };
+
+ // redraw all regular items
+ for (var i = 0; i < redrawQueueLength; i++) {
+ _loop(i);
+ }
+ } // calculate the date of the left side and right side of the items given
+
+
+ forEach$3(util$2).call(util$2, this.itemSet.items, function (item) {
+ var start = getStart(item);
+ var end = getEnd(item);
+ var startSide;
+ var endSide;
+
+ if (_this2.options.rtl) {
+ startSide = start - (item.getWidthRight() + 10) * factor;
+ endSide = end + (item.getWidthLeft() + 10) * factor;
+ } else {
+ startSide = start - (item.getWidthLeft() + 10) * factor;
+ endSide = end + (item.getWidthRight() + 10) * factor;
+ }
+
+ if (startSide < min) {
+ min = startSide;
+ minItem = item;
+ }
+
+ if (endSide > max) {
+ max = endSide;
+ maxItem = item;
+ }
+ });
+
+ if (minItem && maxItem) {
+ var lhs = minItem.getWidthLeft() + 10;
+ var rhs = maxItem.getWidthRight() + 10;
+ var delta = this.props.center.width - lhs - rhs; // px
+
+ if (delta > 0) {
+ if (this.options.rtl) {
+ min = getStart(minItem) - rhs * interval / delta; // ms
+
+ max = getEnd(maxItem) + lhs * interval / delta; // ms
+ } else {
+ min = getStart(minItem) - lhs * interval / delta; // ms
+
+ max = getEnd(maxItem) + rhs * interval / delta; // ms
+ }
+ }
+ }
+ }
+
+ return {
+ min: min != null ? new Date(min) : null,
+ max: max != null ? new Date(max) : null
+ };
+ }
+ /**
+ * Calculate the data range of the items start and end dates
+ * @returns {{min: Date, max: Date}}
+ */
+
+ }, {
+ key: "getDataRange",
+ value: function getDataRange() {
+ var min = null;
+ var max = null;
+ var dataset = this.itemsData && this.itemsData.getDataSet();
+
+ if (dataset) {
+ forEach$3(dataset).call(dataset, function (item) {
+ var start = util$2.convert(item.start, 'Date').valueOf();
+ var end = util$2.convert(item.end != undefined ? item.end : item.start, 'Date').valueOf();
+
+ if (min === null || start < min) {
+ min = start;
+ }
+
+ if (max === null || end > max) {
+ max = end;
+ }
+ });
+ }
+
+ return {
+ min: min != null ? new Date(min) : null,
+ max: max != null ? new Date(max) : null
+ };
+ }
+ /**
+ * Generate Timeline related information from an event
+ * @param {Event} event
+ * @return {Object} An object with related information, like on which area
+ * The event happened, whether clicked on an item, etc.
+ */
+
+ }, {
+ key: "getEventProperties",
+ value: function getEventProperties(event) {
+ var clientX = event.center ? event.center.x : event.clientX;
+ var clientY = event.center ? event.center.y : event.clientY;
+ var centerContainerRect = this.dom.centerContainer.getBoundingClientRect();
+ var x = this.options.rtl ? centerContainerRect.right - clientX : clientX - centerContainerRect.left;
+ var y = clientY - centerContainerRect.top;
+ var item = this.itemSet.itemFromTarget(event);
+ var group = this.itemSet.groupFromTarget(event);
+ var customTime = CustomTime.customTimeFromTarget(event);
+ var snap = this.itemSet.options.snap || null;
+ var scale = this.body.util.getScale();
+ var step = this.body.util.getStep();
+
+ var time = this._toTime(x);
+
+ var snappedTime = snap ? snap(time, scale, step) : time;
+ var element = util$2.getTarget(event);
+ var what = null;
+
+ if (item != null) {
+ what = 'item';
+ } else if (customTime != null) {
+ what = 'custom-time';
+ } else if (util$2.hasParent(element, this.timeAxis.dom.foreground)) {
+ what = 'axis';
+ } else if (this.timeAxis2 && util$2.hasParent(element, this.timeAxis2.dom.foreground)) {
+ what = 'axis';
+ } else if (util$2.hasParent(element, this.itemSet.dom.labelSet)) {
+ what = 'group-label';
+ } else if (util$2.hasParent(element, this.currentTime.bar)) {
+ what = 'current-time';
+ } else if (util$2.hasParent(element, this.dom.center)) {
+ what = 'background';
+ }
+
+ return {
+ event: event,
+ item: item ? item.id : null,
+ isCluster: item ? !!item.isCluster : false,
+ items: item ? item.items || [] : null,
+ group: group ? group.groupId : null,
+ customTime: customTime ? customTime.options.id : null,
+ what: what,
+ pageX: event.srcEvent ? event.srcEvent.pageX : event.pageX,
+ pageY: event.srcEvent ? event.srcEvent.pageY : event.pageY,
+ x: x,
+ y: y,
+ time: time,
+ snappedTime: snappedTime
+ };
+ }
+ /**
+ * Toggle Timeline rolling mode
+ */
+
+ }, {
+ key: "toggleRollingMode",
+ value: function toggleRollingMode() {
+ if (this.range.rolling) {
+ this.range.stopRolling();
+ } else {
+ if (this.options.rollingMode == undefined) {
+ this.setOptions(this.options);
+ }
+
+ this.range.startRolling();
+ }
+ }
+ /**
+ * redraw
+ * @private
+ */
+
+ }, {
+ key: "_redraw",
+ value: function _redraw() {
+ Core.prototype._redraw.call(this);
+ }
+ /**
+ * on fit callback
+ * @param {object} args
+ * @private
+ */
+
+ }, {
+ key: "_onFit",
+ value: function _onFit(args) {
+ var start = args.start,
+ end = args.end,
+ animation = args.animation;
+
+ if (!end) {
+ this.moveTo(start.valueOf(), {
+ animation: animation
+ });
+ } else {
+ this.range.setRange(start, end, {
+ animation: animation
+ });
+ }
+ }
+ }]);
+
+ return Timeline;
+}(Core);
+
+function getStart(item) {
+ return util$2.convert(item.data.start, 'Date').valueOf();
+}
+/**
+ *
+ * @param {timeline.Item} item
+ * @returns {number}
+ */
+
+
+function getEnd(item) {
+ var end = item.data.end != undefined ? item.data.end : item.data.start;
+ return util$2.convert(end, 'Date').valueOf();
+}
+/**
+ * @param {vis.Timeline} timeline
+ * @param {timeline.Item} item
+ * @return {{shouldScroll: bool, scrollOffset: number, itemTop: number}}
+ */
+
+
+function getItemVerticalScroll(timeline, item) {
+ if (!item.parent) {
+ // The item no longer exists, so ignore this focus.
+ return false;
+ }
+
+ var itemsetHeight = timeline.options.rtl ? timeline.props.rightContainer.height : timeline.props.leftContainer.height;
+ var contentHeight = timeline.props.center.height;
+ var group = item.parent;
+ var offset = group.top;
+ var shouldScroll = true;
+ var orientation = timeline.timeAxis.options.orientation.axis;
+
+ var itemTop = function itemTop() {
+ if (orientation == "bottom") {
+ return group.height - item.top - item.height;
+ } else {
+ return item.top;
+ }
+ };
+
+ var currentScrollHeight = timeline._getScrollTop() * -1;
+ var targetOffset = offset + itemTop();
+ var height = item.height;
+
+ if (targetOffset < currentScrollHeight) {
+ if (offset + itemsetHeight <= offset + itemTop() + height) {
+ offset += itemTop() - timeline.itemSet.options.margin.item.vertical;
+ }
+ } else if (targetOffset + height > currentScrollHeight + itemsetHeight) {
+ offset += itemTop() + height - itemsetHeight + timeline.itemSet.options.margin.item.vertical;
+ } else {
+ shouldScroll = false;
+ }
+
+ offset = Math.min(offset, contentHeight - itemsetHeight);
+ return {
+ shouldScroll: shouldScroll,
+ scrollOffset: offset,
+ itemTop: targetOffset
+ };
+}
+
+/** DataScale */
+var DataScale =
+/*#__PURE__*/
+function () {
+ /**
+ *
+ * @param {number} start
+ * @param {number} end
+ * @param {boolean} autoScaleStart
+ * @param {boolean} autoScaleEnd
+ * @param {number} containerHeight
+ * @param {number} majorCharHeight
+ * @param {boolean} zeroAlign
+ * @param {function} formattingFunction
+ * @constructor DataScale
+ */
+ function DataScale(start, end, autoScaleStart, autoScaleEnd, containerHeight, majorCharHeight) {
+ var zeroAlign = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : false;
+ var formattingFunction = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : false;
+
+ classCallCheck$1(this, DataScale);
+
+ this.majorSteps = [1, 2, 5, 10];
+ this.minorSteps = [0.25, 0.5, 1, 2];
+ this.customLines = null;
+ this.containerHeight = containerHeight;
+ this.majorCharHeight = majorCharHeight;
+ this._start = start;
+ this._end = end;
+ this.scale = 1;
+ this.minorStepIdx = -1;
+ this.magnitudefactor = 1;
+ this.determineScale();
+ this.zeroAlign = zeroAlign;
+ this.autoScaleStart = autoScaleStart;
+ this.autoScaleEnd = autoScaleEnd;
+ this.formattingFunction = formattingFunction;
+
+ if (autoScaleStart || autoScaleEnd) {
+ var me = this;
+
+ var roundToMinor = function roundToMinor(value) {
+ var rounded = value - value % (me.magnitudefactor * me.minorSteps[me.minorStepIdx]);
+
+ if (value % (me.magnitudefactor * me.minorSteps[me.minorStepIdx]) > 0.5 * (me.magnitudefactor * me.minorSteps[me.minorStepIdx])) {
+ return rounded + me.magnitudefactor * me.minorSteps[me.minorStepIdx];
+ } else {
+ return rounded;
+ }
+ };
+
+ if (autoScaleStart) {
+ this._start -= this.magnitudefactor * 2 * this.minorSteps[this.minorStepIdx];
+ this._start = roundToMinor(this._start);
+ }
+
+ if (autoScaleEnd) {
+ this._end += this.magnitudefactor * this.minorSteps[this.minorStepIdx];
+ this._end = roundToMinor(this._end);
+ }
+
+ this.determineScale();
+ }
+ }
+ /**
+ * set chart height
+ * @param {number} majorCharHeight
+ */
+
+
+ createClass$1(DataScale, [{
+ key: "setCharHeight",
+ value: function setCharHeight(majorCharHeight) {
+ this.majorCharHeight = majorCharHeight;
+ }
+ /**
+ * set height
+ * @param {number} containerHeight
+ */
+
+ }, {
+ key: "setHeight",
+ value: function setHeight(containerHeight) {
+ this.containerHeight = containerHeight;
+ }
+ /**
+ * determine scale
+ */
+
+ }, {
+ key: "determineScale",
+ value: function determineScale() {
+ var range = this._end - this._start;
+ this.scale = this.containerHeight / range;
+ var minimumStepValue = this.majorCharHeight / this.scale;
+ var orderOfMagnitude = range > 0 ? Math.round(Math.log(range) / Math.LN10) : 0;
+ this.minorStepIdx = -1;
+ this.magnitudefactor = Math.pow(10, orderOfMagnitude);
+ var start = 0;
+
+ if (orderOfMagnitude < 0) {
+ start = orderOfMagnitude;
+ }
+
+ var solutionFound = false;
+
+ for (var l = start; Math.abs(l) <= Math.abs(orderOfMagnitude); l++) {
+ this.magnitudefactor = Math.pow(10, l);
+
+ for (var j = 0; j < this.minorSteps.length; j++) {
+ var stepSize = this.magnitudefactor * this.minorSteps[j];
+
+ if (stepSize >= minimumStepValue) {
+ solutionFound = true;
+ this.minorStepIdx = j;
+ break;
+ }
+ }
+
+ if (solutionFound === true) {
+ break;
+ }
+ }
+ }
+ /**
+ * returns if value is major
+ * @param {number} value
+ * @returns {boolean}
+ */
+
+ }, {
+ key: "is_major",
+ value: function is_major(value) {
+ return value % (this.magnitudefactor * this.majorSteps[this.minorStepIdx]) === 0;
+ }
+ /**
+ * returns step size
+ * @returns {number}
+ */
+
+ }, {
+ key: "getStep",
+ value: function getStep() {
+ return this.magnitudefactor * this.minorSteps[this.minorStepIdx];
+ }
+ /**
+ * returns first major
+ * @returns {number}
+ */
+
+ }, {
+ key: "getFirstMajor",
+ value: function getFirstMajor() {
+ var majorStep = this.magnitudefactor * this.majorSteps[this.minorStepIdx];
+ return this.convertValue(this._start + (majorStep - this._start % majorStep) % majorStep);
+ }
+ /**
+ * returns first major
+ * @param {date} current
+ * @returns {date} formatted date
+ */
+
+ }, {
+ key: "formatValue",
+ value: function formatValue(current) {
+ var returnValue = current.toPrecision(5);
+
+ if (typeof this.formattingFunction === 'function') {
+ returnValue = this.formattingFunction(current);
+ }
+
+ if (typeof returnValue === 'number') {
+ return "".concat(returnValue);
+ } else if (typeof returnValue === 'string') {
+ return returnValue;
+ } else {
+ return current.toPrecision(5);
+ }
+ }
+ /**
+ * returns lines
+ * @returns {object} lines
+ */
+
+ }, {
+ key: "getLines",
+ value: function getLines() {
+ var lines = [];
+ var step = this.getStep();
+ var bottomOffset = (step - this._start % step) % step;
+
+ for (var i = this._start + bottomOffset; this._end - i > 0.00001; i += step) {
+ if (i != this._start) {
+ //Skip the bottom line
+ lines.push({
+ major: this.is_major(i),
+ y: this.convertValue(i),
+ val: this.formatValue(i)
+ });
+ }
+ }
+
+ return lines;
+ }
+ /**
+ * follow scale
+ * @param {object} other
+ */
+
+ }, {
+ key: "followScale",
+ value: function followScale(other) {
+ var oldStepIdx = this.minorStepIdx;
+ var oldStart = this._start;
+ var oldEnd = this._end;
+ var me = this;
+
+ var increaseMagnitude = function increaseMagnitude() {
+ me.magnitudefactor *= 2;
+ };
+
+ var decreaseMagnitude = function decreaseMagnitude() {
+ me.magnitudefactor /= 2;
+ };
+
+ if (other.minorStepIdx <= 1 && this.minorStepIdx <= 1 || other.minorStepIdx > 1 && this.minorStepIdx > 1) ; else if (other.minorStepIdx < this.minorStepIdx) {
+ //I'm 5, they are 4 per major.
+ this.minorStepIdx = 1;
+
+ if (oldStepIdx == 2) {
+ increaseMagnitude();
+ } else {
+ increaseMagnitude();
+ increaseMagnitude();
+ }
+ } else {
+ //I'm 4, they are 5 per major
+ this.minorStepIdx = 2;
+
+ if (oldStepIdx == 1) {
+ decreaseMagnitude();
+ } else {
+ decreaseMagnitude();
+ decreaseMagnitude();
+ }
+ } //Get masters stats:
+
+
+ var otherZero = other.convertValue(0);
+ var otherStep = other.getStep() * other.scale;
+ var done = false;
+ var count = 0; //Loop until magnitude is correct for given constrains.
+
+ while (!done && count++ < 5) {
+ //Get my stats:
+ this.scale = otherStep / (this.minorSteps[this.minorStepIdx] * this.magnitudefactor);
+ var newRange = this.containerHeight / this.scale; //For the case the magnitudefactor has changed:
+
+ this._start = oldStart;
+ this._end = this._start + newRange;
+ var myOriginalZero = this._end * this.scale;
+ var majorStep = this.magnitudefactor * this.majorSteps[this.minorStepIdx];
+ var majorOffset = this.getFirstMajor() - other.getFirstMajor();
+
+ if (this.zeroAlign) {
+ var zeroOffset = otherZero - myOriginalZero;
+ this._end += zeroOffset / this.scale;
+ this._start = this._end - newRange;
+ } else {
+ if (!this.autoScaleStart) {
+ this._start += majorStep - majorOffset / this.scale;
+ this._end = this._start + newRange;
+ } else {
+ this._start -= majorOffset / this.scale;
+ this._end = this._start + newRange;
+ }
+ }
+
+ if (!this.autoScaleEnd && this._end > oldEnd + 0.00001) {
+ //Need to decrease magnitude to prevent scale overshoot! (end)
+ decreaseMagnitude();
+ done = false;
+ continue;
+ }
+
+ if (!this.autoScaleStart && this._start < oldStart - 0.00001) {
+ if (this.zeroAlign && oldStart >= 0) {
+ console.warn("Can't adhere to given 'min' range, due to zeroalign");
+ } else {
+ //Need to decrease magnitude to prevent scale overshoot! (start)
+ decreaseMagnitude();
+ done = false;
+ continue;
+ }
+ }
+
+ if (this.autoScaleStart && this.autoScaleEnd && newRange < oldEnd - oldStart) {
+ increaseMagnitude();
+ done = false;
+ continue;
+ }
+
+ done = true;
+ }
+ }
+ /**
+ * convert value
+ * @param {number} value
+ * @returns {number}
+ */
+
+ }, {
+ key: "convertValue",
+ value: function convertValue(value) {
+ return this.containerHeight - (value - this._start) * this.scale;
+ }
+ /**
+ * returns screen to value
+ * @param {number} pixels
+ * @returns {number}
+ */
+
+ }, {
+ key: "screenToValue",
+ value: function screenToValue(pixels) {
+ return (this.containerHeight - pixels) / this.scale + this._start;
+ }
+ }]);
+
+ return DataScale;
+}();
+
+/** A horizontal time axis */
+
+var DataAxis =
+/*#__PURE__*/
+function (_Component) {
+ inherits$1(DataAxis, _Component);
+
+ /**
+ * @param {Object} body
+ * @param {Object} [options] See DataAxis.setOptions for the available
+ * options.
+ * @param {SVGElement} svg
+ * @param {timeline.LineGraph.options} linegraphOptions
+ * @constructor DataAxis
+ * @extends Component
+ */
+ function DataAxis(body, options, svg, linegraphOptions) {
+ var _this;
+
+ classCallCheck$1(this, DataAxis);
+
+ _this = possibleConstructorReturn$1(this, getPrototypeOf$4(DataAxis).call(this));
+ _this.id = util$2.randomUUID();
+ _this.body = body;
+ _this.defaultOptions = {
+ orientation: 'left',
+ // supported: 'left', 'right'
+ showMinorLabels: true,
+ showMajorLabels: true,
+ icons: false,
+ majorLinesOffset: 7,
+ minorLinesOffset: 4,
+ labelOffsetX: 10,
+ labelOffsetY: 2,
+ iconWidth: 20,
+ width: '40px',
+ visible: true,
+ alignZeros: true,
+ left: {
+ range: {
+ min: undefined,
+ max: undefined
+ },
+ format: function format(value) {
+ return "".concat(_parseFloat$3(value.toPrecision(3)));
+ },
+ title: {
+ text: undefined,
+ style: undefined
+ }
+ },
+ right: {
+ range: {
+ min: undefined,
+ max: undefined
+ },
+ format: function format(value) {
+ return "".concat(_parseFloat$3(value.toPrecision(3)));
+ },
+ title: {
+ text: undefined,
+ style: undefined
+ }
+ }
+ };
+ _this.linegraphOptions = linegraphOptions;
+ _this.linegraphSVG = svg;
+ _this.props = {};
+ _this.DOMelements = {
+ // dynamic elements
+ lines: {},
+ labels: {},
+ title: {}
+ };
+ _this.dom = {};
+ _this.scale = undefined;
+ _this.range = {
+ start: 0,
+ end: 0
+ };
+ _this.options = util$2.extend({}, _this.defaultOptions);
+ _this.conversionFactor = 1;
+
+ _this.setOptions(options);
+
+ _this.width = Number("".concat(_this.options.width).replace("px", ""));
+ _this.minWidth = _this.width;
+ _this.height = _this.linegraphSVG.getBoundingClientRect().height;
+ _this.hidden = false;
+ _this.stepPixels = 25;
+ _this.zeroCrossing = -1;
+ _this.amountOfSteps = -1;
+ _this.lineOffset = 0;
+ _this.master = true;
+ _this.masterAxis = null;
+ _this.svgElements = {};
+ _this.iconsRemoved = false;
+ _this.groups = {};
+ _this.amountOfGroups = 0; // create the HTML DOM
+
+ _this._create();
+
+ if (_this.scale == undefined) {
+ _this._redrawLabels();
+ }
+
+ _this.framework = {
+ svg: _this.svg,
+ svgElements: _this.svgElements,
+ options: _this.options,
+ groups: _this.groups
+ };
+
+ var me = assertThisInitialized$1(_this);
+
+ _this.body.emitter.on("verticalDrag", function () {
+ me.dom.lineContainer.style.top = "".concat(me.body.domProps.scrollTop, "px");
+ });
+
+ return _this;
+ }
+ /**
+ * Adds group to data axis
+ * @param {string} label
+ * @param {object} graphOptions
+ */
+
+
+ createClass$1(DataAxis, [{
+ key: "addGroup",
+ value: function addGroup(label, graphOptions) {
+ if (!this.groups.hasOwnProperty(label)) {
+ this.groups[label] = graphOptions;
+ }
+
+ this.amountOfGroups += 1;
+ }
+ /**
+ * updates group of data axis
+ * @param {string} label
+ * @param {object} graphOptions
+ */
+
+ }, {
+ key: "updateGroup",
+ value: function updateGroup(label, graphOptions) {
+ if (!this.groups.hasOwnProperty(label)) {
+ this.amountOfGroups += 1;
+ }
+
+ this.groups[label] = graphOptions;
+ }
+ /**
+ * removes group of data axis
+ * @param {string} label
+ */
+
+ }, {
+ key: "removeGroup",
+ value: function removeGroup(label) {
+ if (this.groups.hasOwnProperty(label)) {
+ delete this.groups[label];
+ this.amountOfGroups -= 1;
+ }
+ }
+ /**
+ * sets options
+ * @param {object} options
+ */
+
+ }, {
+ key: "setOptions",
+ value: function setOptions(options) {
+ if (options) {
+ var redraw = false;
+
+ if (this.options.orientation != options.orientation && options.orientation !== undefined) {
+ redraw = true;
+ }
+
+ var fields = ['orientation', 'showMinorLabels', 'showMajorLabels', 'icons', 'majorLinesOffset', 'minorLinesOffset', 'labelOffsetX', 'labelOffsetY', 'iconWidth', 'width', 'visible', 'left', 'right', 'alignZeros'];
+ util$2.selectiveDeepExtend(fields, this.options, options);
+ this.minWidth = Number("".concat(this.options.width).replace("px", ""));
+
+ if (redraw === true && this.dom.frame) {
+ this.hide();
+ this.show();
+ }
+ }
+ }
+ /**
+ * Create the HTML DOM for the DataAxis
+ */
+
+ }, {
+ key: "_create",
+ value: function _create() {
+ this.dom.frame = document.createElement('div');
+ this.dom.frame.style.width = this.options.width;
+ this.dom.frame.style.height = this.height;
+ this.dom.lineContainer = document.createElement('div');
+ this.dom.lineContainer.style.width = '100%';
+ this.dom.lineContainer.style.height = this.height;
+ this.dom.lineContainer.style.position = 'relative';
+ this.dom.lineContainer.style.visibility = 'visible';
+ this.dom.lineContainer.style.display = 'block'; // create svg element for graph drawing.
+
+ this.svg = document.createElementNS('http://www.w3.org/2000/svg', "svg");
+ this.svg.style.position = "absolute";
+ this.svg.style.top = '0px';
+ this.svg.style.height = '100%';
+ this.svg.style.width = '100%';
+ this.svg.style.display = "block";
+ this.dom.frame.appendChild(this.svg);
+ }
+ /**
+ * redraws groups icons
+ */
+
+ }, {
+ key: "_redrawGroupIcons",
+ value: function _redrawGroupIcons() {
+ prepareElements(this.svgElements);
+ var x;
+ var iconWidth = this.options.iconWidth;
+ var iconHeight = 15;
+ var iconOffset = 4;
+ var y = iconOffset + 0.5 * iconHeight;
+
+ if (this.options.orientation === 'left') {
+ x = iconOffset;
+ } else {
+ x = this.width - iconWidth - iconOffset;
+ }
+
+ var groupArray = keys$3(this.groups);
+
+ sort$2(groupArray).call(groupArray, function (a, b) {
+ return a < b ? -1 : 1;
+ });
+
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = getIterator$2(groupArray), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var groupId = _step.value;
+
+ if (this.groups[groupId].visible === true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] === true)) {
+ this.groups[groupId].getLegend(iconWidth, iconHeight, this.framework, x, y);
+ y += iconHeight + iconOffset;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ cleanupElements(this.svgElements);
+ this.iconsRemoved = false;
+ }
+ /**
+ * Cleans up icons
+ */
+
+ }, {
+ key: "_cleanupIcons",
+ value: function _cleanupIcons() {
+ if (this.iconsRemoved === false) {
+ prepareElements(this.svgElements);
+ cleanupElements(this.svgElements);
+ this.iconsRemoved = true;
+ }
+ }
+ /**
+ * Create the HTML DOM for the DataAxis
+ */
+
+ }, {
+ key: "show",
+ value: function show() {
+ this.hidden = false;
+
+ if (!this.dom.frame.parentNode) {
+ if (this.options.orientation === 'left') {
+ this.body.dom.left.appendChild(this.dom.frame);
+ } else {
+ this.body.dom.right.appendChild(this.dom.frame);
+ }
+ }
+
+ if (!this.dom.lineContainer.parentNode) {
+ this.body.dom.backgroundHorizontal.appendChild(this.dom.lineContainer);
+ }
+
+ this.dom.lineContainer.style.display = 'block';
+ }
+ /**
+ * Create the HTML DOM for the DataAxis
+ */
+
+ }, {
+ key: "hide",
+ value: function hide() {
+ this.hidden = true;
+
+ if (this.dom.frame.parentNode) {
+ this.dom.frame.parentNode.removeChild(this.dom.frame);
+ }
+
+ this.dom.lineContainer.style.display = 'none';
+ }
+ /**
+ * Set a range (start and end)
+ * @param {number} start
+ * @param {number} end
+ */
+
+ }, {
+ key: "setRange",
+ value: function setRange(start, end) {
+ this.range.start = start;
+ this.range.end = end;
+ }
+ /**
+ * Repaint the component
+ * @return {boolean} Returns true if the component is resized
+ */
+
+ }, {
+ key: "redraw",
+ value: function redraw() {
+ var resized = false;
+ var activeGroups = 0; // Make sure the line container adheres to the vertical scrolling.
+
+ this.dom.lineContainer.style.top = "".concat(this.body.domProps.scrollTop, "px");
+
+ for (var groupId in this.groups) {
+ if (this.groups.hasOwnProperty(groupId)) {
+ if (this.groups[groupId].visible === true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] === true)) {
+ activeGroups++;
+ }
+ }
+ }
+
+ if (this.amountOfGroups === 0 || activeGroups === 0) {
+ this.hide();
+ } else {
+ this.show();
+ this.height = Number(this.linegraphSVG.style.height.replace("px", "")); // svg offsetheight did not work in firefox and explorer...
+
+ this.dom.lineContainer.style.height = "".concat(this.height, "px");
+ this.width = this.options.visible === true ? Number("".concat(this.options.width).replace("px", "")) : 0;
+ var props = this.props;
+ var frame = this.dom.frame; // update classname
+
+ frame.className = 'vis-data-axis'; // calculate character width and height
+
+ this._calculateCharSize();
+
+ var orientation = this.options.orientation;
+ var showMinorLabels = this.options.showMinorLabels;
+ var showMajorLabels = this.options.showMajorLabels;
+ var backgroundHorizontalOffsetWidth = this.body.dom.backgroundHorizontal.offsetWidth; // determine the width and height of the elements for the axis
+
+ props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0;
+ props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0;
+ props.minorLineWidth = backgroundHorizontalOffsetWidth - this.lineOffset - this.width + 2 * this.options.minorLinesOffset;
+ props.minorLineHeight = 1;
+ props.majorLineWidth = backgroundHorizontalOffsetWidth - this.lineOffset - this.width + 2 * this.options.majorLinesOffset;
+ props.majorLineHeight = 1; // take frame offline while updating (is almost twice as fast)
+
+ if (orientation === 'left') {
+ frame.style.top = '0';
+ frame.style.left = '0';
+ frame.style.bottom = '';
+ frame.style.width = "".concat(this.width, "px");
+ frame.style.height = "".concat(this.height, "px");
+ this.props.width = this.body.domProps.left.width;
+ this.props.height = this.body.domProps.left.height;
+ } else {
+ // right
+ frame.style.top = '';
+ frame.style.bottom = '0';
+ frame.style.left = '0';
+ frame.style.width = "".concat(this.width, "px");
+ frame.style.height = "".concat(this.height, "px");
+ this.props.width = this.body.domProps.right.width;
+ this.props.height = this.body.domProps.right.height;
+ }
+
+ resized = this._redrawLabels();
+ resized = this._isResized() || resized;
+
+ if (this.options.icons === true) {
+ this._redrawGroupIcons();
+ } else {
+ this._cleanupIcons();
+ }
+
+ this._redrawTitle(orientation);
+ }
+
+ return resized;
+ }
+ /**
+ * Repaint major and minor text labels and vertical grid lines
+ *
+ * @returns {boolean}
+ * @private
+ */
+
+ }, {
+ key: "_redrawLabels",
+ value: function _redrawLabels() {
+ var _this2 = this;
+
+ var resized = false;
+ prepareElements(this.DOMelements.lines);
+ prepareElements(this.DOMelements.labels);
+ var orientation = this.options['orientation'];
+ var customRange = this.options[orientation].range != undefined ? this.options[orientation].range : {}; //Override range with manual options:
+
+ var autoScaleEnd = true;
+
+ if (customRange.max != undefined) {
+ this.range.end = customRange.max;
+ autoScaleEnd = false;
+ }
+
+ var autoScaleStart = true;
+
+ if (customRange.min != undefined) {
+ this.range.start = customRange.min;
+ autoScaleStart = false;
+ }
+
+ this.scale = new DataScale(this.range.start, this.range.end, autoScaleStart, autoScaleEnd, this.dom.frame.offsetHeight, this.props.majorCharHeight, this.options.alignZeros, this.options[orientation].format);
+
+ if (this.master === false && this.masterAxis != undefined) {
+ this.scale.followScale(this.masterAxis.scale);
+ this.dom.lineContainer.style.display = 'none';
+ } else {
+ this.dom.lineContainer.style.display = 'block';
+ } //Is updated in side-effect of _redrawLabel():
+
+
+ this.maxLabelSize = 0;
+ var lines = this.scale.getLines();
+
+ forEach$3(lines).call(lines, function (line) {
+ var y = line.y;
+ var isMajor = line.major;
+
+ if (_this2.options['showMinorLabels'] && isMajor === false) {
+ _this2._redrawLabel(y - 2, line.val, orientation, 'vis-y-axis vis-minor', _this2.props.minorCharHeight);
+ }
+
+ if (isMajor) {
+ if (y >= 0) {
+ _this2._redrawLabel(y - 2, line.val, orientation, 'vis-y-axis vis-major', _this2.props.majorCharHeight);
+ }
+ }
+
+ if (_this2.master === true) {
+ if (isMajor) {
+ _this2._redrawLine(y, orientation, 'vis-grid vis-horizontal vis-major', _this2.options.majorLinesOffset, _this2.props.majorLineWidth);
+ } else {
+ _this2._redrawLine(y, orientation, 'vis-grid vis-horizontal vis-minor', _this2.options.minorLinesOffset, _this2.props.minorLineWidth);
+ }
+ }
+ }); // Note that title is rotated, so we're using the height, not width!
+
+
+ var titleWidth = 0;
+
+ if (this.options[orientation].title !== undefined && this.options[orientation].title.text !== undefined) {
+ titleWidth = this.props.titleCharHeight;
+ }
+
+ var offset = this.options.icons === true ? Math.max(this.options.iconWidth, titleWidth) + this.options.labelOffsetX + 15 : titleWidth + this.options.labelOffsetX + 15; // this will resize the yAxis to accommodate the labels.
+
+ if (this.maxLabelSize > this.width - offset && this.options.visible === true) {
+ this.width = this.maxLabelSize + offset;
+ this.options.width = "".concat(this.width, "px");
+ cleanupElements(this.DOMelements.lines);
+ cleanupElements(this.DOMelements.labels);
+ this.redraw();
+ resized = true;
+ } // this will resize the yAxis if it is too big for the labels.
+ else if (this.maxLabelSize < this.width - offset && this.options.visible === true && this.width > this.minWidth) {
+ this.width = Math.max(this.minWidth, this.maxLabelSize + offset);
+ this.options.width = "".concat(this.width, "px");
+ cleanupElements(this.DOMelements.lines);
+ cleanupElements(this.DOMelements.labels);
+ this.redraw();
+ resized = true;
+ } else {
+ cleanupElements(this.DOMelements.lines);
+ cleanupElements(this.DOMelements.labels);
+ resized = false;
+ }
+
+ return resized;
+ }
+ /**
+ * converts value
+ * @param {number} value
+ * @returns {number} converted number
+ */
+
+ }, {
+ key: "convertValue",
+ value: function convertValue(value) {
+ return this.scale.convertValue(value);
+ }
+ /**
+ * converts value
+ * @param {number} x
+ * @returns {number} screen value
+ */
+
+ }, {
+ key: "screenToValue",
+ value: function screenToValue(x) {
+ return this.scale.screenToValue(x);
+ }
+ /**
+ * Create a label for the axis at position x
+ *
+ * @param {number} y
+ * @param {string} text
+ * @param {'top'|'right'|'bottom'|'left'} orientation
+ * @param {string} className
+ * @param {number} characterHeight
+ * @private
+ */
+
+ }, {
+ key: "_redrawLabel",
+ value: function _redrawLabel(y, text, orientation, className, characterHeight) {
+ // reuse redundant label
+ var label = getDOMElement('div', this.DOMelements.labels, this.dom.frame); //this.dom.redundant.labels.shift();
+
+ label.className = className;
+ label.innerHTML = text;
+
+ if (orientation === 'left') {
+ label.style.left = "-".concat(this.options.labelOffsetX, "px");
+ label.style.textAlign = "right";
+ } else {
+ label.style.right = "-".concat(this.options.labelOffsetX, "px");
+ label.style.textAlign = "left";
+ }
+
+ label.style.top = "".concat(y - 0.5 * characterHeight + this.options.labelOffsetY, "px");
+ text += '';
+ var largestWidth = Math.max(this.props.majorCharWidth, this.props.minorCharWidth);
+
+ if (this.maxLabelSize < text.length * largestWidth) {
+ this.maxLabelSize = text.length * largestWidth;
+ }
+ }
+ /**
+ * Create a minor line for the axis at position y
+ * @param {number} y
+ * @param {'top'|'right'|'bottom'|'left'} orientation
+ * @param {string} className
+ * @param {number} offset
+ * @param {number} width
+ */
+
+ }, {
+ key: "_redrawLine",
+ value: function _redrawLine(y, orientation, className, offset, width) {
+ if (this.master === true) {
+ var line = getDOMElement('div', this.DOMelements.lines, this.dom.lineContainer); //this.dom.redundant.lines.shift();
+
+ line.className = className;
+ line.innerHTML = '';
+
+ if (orientation === 'left') {
+ line.style.left = "".concat(this.width - offset, "px");
+ } else {
+ line.style.right = "".concat(this.width - offset, "px");
+ }
+
+ line.style.width = "".concat(width, "px");
+ line.style.top = "".concat(y, "px");
+ }
+ }
+ /**
+ * Create a title for the axis
+ * @private
+ * @param {'top'|'right'|'bottom'|'left'} orientation
+ */
+
+ }, {
+ key: "_redrawTitle",
+ value: function _redrawTitle(orientation) {
+ prepareElements(this.DOMelements.title); // Check if the title is defined for this axes
+
+ if (this.options[orientation].title !== undefined && this.options[orientation].title.text !== undefined) {
+ var title = getDOMElement('div', this.DOMelements.title, this.dom.frame);
+ title.className = "vis-y-axis vis-title vis-".concat(orientation);
+ title.innerHTML = this.options[orientation].title.text; // Add style - if provided
+
+ if (this.options[orientation].title.style !== undefined) {
+ util$2.addCssText(title, this.options[orientation].title.style);
+ }
+
+ if (orientation === 'left') {
+ title.style.left = "".concat(this.props.titleCharHeight, "px");
+ } else {
+ title.style.right = "".concat(this.props.titleCharHeight, "px");
+ }
+
+ title.style.width = "".concat(this.height, "px");
+ } // we need to clean up in case we did not use all elements.
+
+
+ cleanupElements(this.DOMelements.title);
+ }
+ /**
+ * Determine the size of text on the axis (both major and minor axis).
+ * The size is calculated only once and then cached in this.props.
+ * @private
+ */
+
+ }, {
+ key: "_calculateCharSize",
+ value: function _calculateCharSize() {
+ // determine the char width and height on the minor axis
+ if (!('minorCharHeight' in this.props)) {
+ var textMinor = document.createTextNode('0');
+ var measureCharMinor = document.createElement('div');
+ measureCharMinor.className = 'vis-y-axis vis-minor vis-measure';
+ measureCharMinor.appendChild(textMinor);
+ this.dom.frame.appendChild(measureCharMinor);
+ this.props.minorCharHeight = measureCharMinor.clientHeight;
+ this.props.minorCharWidth = measureCharMinor.clientWidth;
+ this.dom.frame.removeChild(measureCharMinor);
+ }
+
+ if (!('majorCharHeight' in this.props)) {
+ var textMajor = document.createTextNode('0');
+ var measureCharMajor = document.createElement('div');
+ measureCharMajor.className = 'vis-y-axis vis-major vis-measure';
+ measureCharMajor.appendChild(textMajor);
+ this.dom.frame.appendChild(measureCharMajor);
+ this.props.majorCharHeight = measureCharMajor.clientHeight;
+ this.props.majorCharWidth = measureCharMajor.clientWidth;
+ this.dom.frame.removeChild(measureCharMajor);
+ }
+
+ if (!('titleCharHeight' in this.props)) {
+ var textTitle = document.createTextNode('0');
+ var measureCharTitle = document.createElement('div');
+ measureCharTitle.className = 'vis-y-axis vis-title vis-measure';
+ measureCharTitle.appendChild(textTitle);
+ this.dom.frame.appendChild(measureCharTitle);
+ this.props.titleCharHeight = measureCharTitle.clientHeight;
+ this.props.titleCharWidth = measureCharTitle.clientWidth;
+ this.dom.frame.removeChild(measureCharTitle);
+ }
+ }
+ }]);
+
+ return DataAxis;
+}(Component);
+
+/**
+ *
+ * @param {number | string} groupId
+ * @param {Object} options // TODO: Describe options
+ *
+ * @constructor Points
+ */
+
+function Points(groupId, options) {} // eslint-disable-line no-unused-vars
+
+/**
+ * draw the data points
+ *
+ * @param {Array} dataset
+ * @param {GraphGroup} group
+ * @param {Object} framework | SVG DOM element
+ * @param {number} [offset]
+ */
+
+
+Points.draw = function (dataset, group, framework, offset) {
+ offset = offset || 0;
+ var callback = getCallback(framework, group);
+
+ for (var i = 0; i < dataset.length; i++) {
+ if (!callback) {
+ // draw the point the simple way.
+ drawPoint(dataset[i].screen_x + offset, dataset[i].screen_y, getGroupTemplate(group), framework.svgElements, framework.svg, dataset[i].label);
+ } else {
+ var callbackResult = callback(dataset[i], group); // result might be true, false or an object
+
+ if (callbackResult === true || _typeof_1$2(callbackResult) === 'object') {
+ drawPoint(dataset[i].screen_x + offset, dataset[i].screen_y, getGroupTemplate(group, callbackResult), framework.svgElements, framework.svg, dataset[i].label);
+ }
+ }
+ }
+};
+
+Points.drawIcon = function (group, x, y, iconWidth, iconHeight, framework) {
+ var fillHeight = iconHeight * 0.5;
+ var outline = getSVGElement("rect", framework.svgElements, framework.svg);
+ outline.setAttributeNS(null, "x", x);
+ outline.setAttributeNS(null, "y", y - fillHeight);
+ outline.setAttributeNS(null, "width", iconWidth);
+ outline.setAttributeNS(null, "height", 2 * fillHeight);
+ outline.setAttributeNS(null, "class", "vis-outline"); //Don't call callback on icon
+
+ drawPoint(x + 0.5 * iconWidth, y, getGroupTemplate(group), framework.svgElements, framework.svg);
+};
+/**
+ *
+ * @param {vis.Group} group
+ * @param {any} callbackResult
+ * @returns {{style: *, styles: (*|string), size: *, className: *}}
+ */
+
+
+function getGroupTemplate(group, callbackResult) {
+ callbackResult = typeof callbackResult === 'undefined' ? {} : callbackResult;
+ return {
+ style: callbackResult.style || group.options.drawPoints.style,
+ styles: callbackResult.styles || group.options.drawPoints.styles,
+ size: callbackResult.size || group.options.drawPoints.size,
+ className: callbackResult.className || group.className
+ };
+}
+/**
+ *
+ * @param {Object} framework | SVG DOM element
+ * @param {vis.Group} group
+ * @returns {function}
+ */
+
+
+function getCallback(framework, group) {
+ var callback = undefined; // check for the graph2d onRender
+
+ if (framework.options && framework.options.drawPoints && framework.options.drawPoints.onRender && typeof framework.options.drawPoints.onRender == 'function') {
+ callback = framework.options.drawPoints.onRender;
+ } // override it with the group onRender if defined
+
+
+ if (group.group.options && group.group.options.drawPoints && group.group.options.drawPoints.onRender && typeof group.group.options.drawPoints.onRender == 'function') {
+ callback = group.group.options.drawPoints.onRender;
+ }
+
+ return callback;
+}
+
+/**
+ *
+ * @param {vis.GraphGroup.id} groupId
+ * @param {Object} options // TODO: Describe options
+ * @constructor Bargraph
+ */
+
+function Bargraph(groupId, options) {// eslint-disable-line no-unused-vars
+}
+
+Bargraph.drawIcon = function (group, x, y, iconWidth, iconHeight, framework) {
+ var fillHeight = iconHeight * 0.5;
+ var outline = getSVGElement("rect", framework.svgElements, framework.svg);
+ outline.setAttributeNS(null, "x", x);
+ outline.setAttributeNS(null, "y", y - fillHeight);
+ outline.setAttributeNS(null, "width", iconWidth);
+ outline.setAttributeNS(null, "height", 2 * fillHeight);
+ outline.setAttributeNS(null, "class", "vis-outline");
+ var barWidth = Math.round(0.3 * iconWidth);
+ var originalWidth = group.options.barChart.width;
+ var scale = originalWidth / barWidth;
+ var bar1Height = Math.round(0.4 * iconHeight);
+ var bar2Height = Math.round(0.75 * iconHeight);
+ var offset = Math.round((iconWidth - 2 * barWidth) / 3);
+ drawBar(x + 0.5 * barWidth + offset, y + fillHeight - bar1Height - 1, barWidth, bar1Height, group.className + ' vis-bar', framework.svgElements, framework.svg, group.style);
+ drawBar(x + 1.5 * barWidth + offset + 2, y + fillHeight - bar2Height - 1, barWidth, bar2Height, group.className + ' vis-bar', framework.svgElements, framework.svg, group.style);
+
+ if (group.options.drawPoints.enabled == true) {
+ var groupTemplate = {
+ style: group.options.drawPoints.style,
+ styles: group.options.drawPoints.styles,
+ size: group.options.drawPoints.size / scale,
+ className: group.className
+ };
+ drawPoint(x + 0.5 * barWidth + offset, y + fillHeight - bar1Height - 1, groupTemplate, framework.svgElements, framework.svg);
+ drawPoint(x + 1.5 * barWidth + offset + 2, y + fillHeight - bar2Height - 1, groupTemplate, framework.svgElements, framework.svg);
+ }
+};
+/**
+ * draw a bar graph
+ *
+ * @param {Array.} groupIds
+ * @param {Object} processedGroupData
+ * @param {{svg: Object, svgElements: Array.