} 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 = ' + _JSON$stringify(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;
}();
function _createSuper$1(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$1(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = _Reflect$construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
function _isNativeReflectConstruct$1() { if (typeof Reflect === "undefined" || !_Reflect$construct) return false; if (_Reflect$construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(_Reflect$construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
/**
* Create a timeline visualization
* @extends Core
*/
var Timeline = /*#__PURE__*/function (_Core) {
_inherits(Timeline, _Core);
var _super = _createSuper$1(Timeline);
/**
* @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(this, Timeline);
_this = _super.call(this);
_this.initTime = new Date();
_this.itemsDone = false;
if (!(_assertThisInitialized(_this) instanceof Timeline)) {
throw new SyntaxError('Constructor must be called with the new operator');
} // if the third element is options, the forth is groups (optionally);
if (!(_Array$isArray(groups) || isDataViewLike(groups)) && 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(_this);
_this.defaultOptions = {
autoResize: true,
longSelectPressTime: 251,
orientation: {
axis: 'bottom',
// axis orientation: 'bottom', 'top', or 'both'
item: 'bottom' // not relevant
},
moment: moment$2
};
_this.options = availableUtils.deepExtend({}, _this.defaultOptions);
options && availableUtils.setupXSSProtection(options.xss); // 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 = _bindInstanceProperty$1(_context = _this.options.loadingScreenTemplate).call(_context, _assertThisInitialized(_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 = availableUtils.xss(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: _bindInstanceProperty$1(_context2 = _this.on).call(_context2, _assertThisInitialized(_this)),
off: _bindInstanceProperty$1(_context3 = _this.off).call(_context3, _assertThisInitialized(_this)),
emit: _bindInstanceProperty$1(_context4 = _this.emit).call(_context4, _assertThisInitialized(_this))
},
hiddenDates: [],
util: {
getScale: function getScale() {
return me.timeAxis.step.scale;
},
getStep: function getStep() {
return me.timeAxis.step.step;
},
toScreen: _bindInstanceProperty$1(_context5 = me._toScreen).call(_context5, me),
toGlobalScreen: _bindInstanceProperty$1(_context6 = me._toGlobalScreen).call(_context6, me),
// this refers to the root.width
toTime: _bindInstanceProperty$1(_context7 = me._toTime).call(_context7, me),
toGlobalTime: _bindInstanceProperty$1(_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
function emit(eventName, event) {
if (!me.hasListeners(eventName)) {
return;
}
me.emit(eventName, me.getEventProperties(event));
}
_this.dom.root.onclick = function (event) {
emit('click', event);
};
_this.dom.root.ondblclick = function (event) {
emit('doubleClick', event);
};
_this.dom.root.oncontextmenu = function (event) {
emit('contextmenu', event);
};
_this.dom.root.onmouseover = function (event) {
emit('mouseOver', event);
};
if (window.PointerEvent) {
_this.dom.root.onpointerdown = function (event) {
emit('mouseDown', event);
};
_this.dom.root.onpointermove = function (event) {
emit('mouseMove', event);
};
_this.dom.root.onpointerup = function (event) {
emit('mouseUp', event);
};
} else {
_this.dom.root.onmousemove = function (event) {
emit('mouseMove', event);
};
_this.dom.root.onmousedown = function (event) {
emit('mouseDown', event);
};
_this.dom.root.onmouseup = function (event) {
emit('mouseUp', 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(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(Timeline, [{
key: "_createConfigurator",
value: function _createConfigurator() {
return new Configurator(this, this.dom.container, configureOptions$1);
}
/**
* 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.rawDS); // 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 (isDataViewLike(items)) {
newDataSet = typeCoerceDataSet(items);
} else {
// turn an array into a dataset
newDataSet = typeCoerceDataSet(new DataSet(items));
} // set items
if (this.itemsData) {
// stop maintaining a coerced version of the old data set
this.itemsData.dispose();
}
this.itemsData = newDataSet;
this.itemSet && this.itemSet.setItems(newDataSet != null ? newDataSet.rawDS : null);
}
/**
* Set groups
* @param {vis.DataSet | Array} groups
*/
}, {
key: "setGroups",
value: function setGroups(groups) {
// convert to type DataSet when needed
var newDataSet;
var filter = function filter(group) {
return group.visible !== false;
};
if (!groups) {
newDataSet = null;
} else {
// If groups is array, turn to DataSet & build dataview from that
if (_Array$isArray(groups)) groups = new DataSet(groups);
newDataSet = new DataView(groups, {
filter: filter
});
} // This looks weird but it's necessary to prevent memory leaks.
//
// The problem is that the DataView will exist as long as the DataSet it's
// connected to. This will force it to swap the groups DataSet for it's own
// DataSet. In this arrangement it will become unreferenced from the outside
// and garbage collected.
//
// IMPORTANT NOTE: If `this.groupsData` is a DataView was created in this
// method. Even if the original is a DataView already a new one has been
// created and assigned to `this.groupsData`. In case this changes in the
// future it will be necessary to rework this!!!!
if (this.groupsData != null && typeof this.groupsData.setData === "function") {
this.groupsData.setData(null);
}
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 = _Array$isArray(id) ? id : [id]; // get the specified item(s)
var itemsData = this.itemsData.get(ids); // calculate minimum start and maximum end of specified items
var start = null;
var end = null;
_forEachInstanceProperty(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(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;
if (this.itemsData.length === 1 && this.itemsData.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
_forEachInstanceProperty(availableUtils).call(availableUtils, 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) {
_forEachInstanceProperty(availableUtils).call(availableUtils, 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
_forEachInstanceProperty(availableUtils).call(availableUtils, 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;
if (this.itemsData) {
var _context9;
_forEachInstanceProperty(_context9 = this.itemsData).call(_context9, function (item) {
var start = availableUtils.convert(item.start, 'Date').valueOf();
var end = availableUtils.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 = availableUtils.getTarget(event);
var what = null;
if (item != null) {
what = 'item';
} else if (customTime != null) {
what = 'custom-time';
} else if (availableUtils.hasParent(element, this.timeAxis.dom.foreground)) {
what = 'axis';
} else if (this.timeAxis2 && availableUtils.hasParent(element, this.timeAxis2.dom.foreground)) {
what = 'axis';
} else if (availableUtils.hasParent(element, this.itemSet.dom.labelSet)) {
what = 'group-label';
} else if (availableUtils.hasParent(element, this.currentTime.bar)) {
what = 'current-time';
} else if (availableUtils.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 availableUtils.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 availableUtils.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(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(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;
}();
var css_248z = "\n.vis-panel.vis-background.vis-horizontal .vis-grid.vis-horizontal {\n position: absolute;\n width: 100%;\n height: 0;\n border-bottom: 1px solid;\n}\n\n.vis-panel.vis-background.vis-horizontal .vis-grid.vis-minor {\n border-color: #e5e5e5;\n}\n\n.vis-panel.vis-background.vis-horizontal .vis-grid.vis-major {\n border-color: #bfbfbf;\n}\n\n\n.vis-data-axis .vis-y-axis.vis-major {\n width: 100%;\n position: absolute;\n color: #4d4d4d;\n white-space: nowrap;\n}\n\n.vis-data-axis .vis-y-axis.vis-major.vis-measure {\n padding: 0;\n margin: 0;\n border: 0;\n visibility: hidden;\n width: auto;\n}\n\n\n.vis-data-axis .vis-y-axis.vis-minor {\n position: absolute;\n width: 100%;\n color: #bebebe;\n white-space: nowrap;\n}\n\n.vis-data-axis .vis-y-axis.vis-minor.vis-measure {\n padding: 0;\n margin: 0;\n border: 0;\n visibility: hidden;\n width: auto;\n}\n\n.vis-data-axis .vis-y-axis.vis-title {\n position: absolute;\n color: #4d4d4d;\n white-space: nowrap;\n bottom: 20px;\n text-align: center;\n}\n\n.vis-data-axis .vis-y-axis.vis-title.vis-measure {\n padding: 0;\n margin: 0;\n visibility: hidden;\n width: auto;\n}\n\n.vis-data-axis .vis-y-axis.vis-title.vis-left {\n bottom: 0;\n -webkit-transform-origin: left top;\n -moz-transform-origin: left top;\n -ms-transform-origin: left top;\n -o-transform-origin: left top;\n transform-origin: left bottom;\n -webkit-transform: rotate(-90deg);\n -moz-transform: rotate(-90deg);\n -ms-transform: rotate(-90deg);\n -o-transform: rotate(-90deg);\n transform: rotate(-90deg);\n}\n\n.vis-data-axis .vis-y-axis.vis-title.vis-right {\n bottom: 0;\n -webkit-transform-origin: right bottom;\n -moz-transform-origin: right bottom;\n -ms-transform-origin: right bottom;\n -o-transform-origin: right bottom;\n transform-origin: right bottom;\n -webkit-transform: rotate(90deg);\n -moz-transform: rotate(90deg);\n -ms-transform: rotate(90deg);\n -o-transform: rotate(90deg);\n transform: rotate(90deg);\n}\n\n.vis-legend {\n background-color: rgba(247, 252, 255, 0.65);\n padding: 5px;\n border: 1px solid #b3b3b3;\n box-shadow: 2px 2px 10px rgba(154, 154, 154, 0.55);\n}\n\n.vis-legend-text {\n /*font-size: 10px;*/\n white-space: nowrap;\n display: inline-block\n}";
styleInject(css_248z);
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof _Symbol !== "undefined" && _getIteratorMethod(o) || o["@@iterator"]; if (!it) { if (_Array$isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
function _unsupportedIterableToArray(o, minLen) { var _context; if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = _sliceInstanceProperty(_context = Object.prototype.toString.call(o)).call(_context, 8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return _Array$from$1(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = _Reflect$construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !_Reflect$construct) return false; if (_Reflect$construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(_Reflect$construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
/** A horizontal time axis */
var DataAxis = /*#__PURE__*/function (_Component) {
_inherits(DataAxis, _Component);
var _super = _createSuper(DataAxis);
/**
* @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(this, DataAxis);
_this = _super.call(this);
_this.id = v4();
_this.body = body;
_this.defaultOptions = {
orientation: 'left',
// supported: 'left', 'right'
showMinorLabels: true,
showMajorLabels: true,
showWeekScale: false,
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(value.toPrecision(3)));
},
title: {
text: undefined,
style: undefined
}
},
right: {
range: {
min: undefined,
max: undefined
},
format: function format(value) {
return "".concat(_parseFloat(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 = availableUtils.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(_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(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'];
availableUtils.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 = _Object$keys(this.groups);
_sortInstanceProperty(groupArray).call(groupArray, function (a, b) {
return a < b ? -1 : 1;
});
var _iterator = _createForOfIteratorHelper(groupArray),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
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) {
_iterator.e(err);
} finally {
_iterator.f();
}
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();
_forEachInstanceProperty(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 = availableUtils.xss(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 = availableUtils.xss(this.options[orientation].title.text); // Add style - if provided
if (this.options[orientation].title.style !== undefined) {
availableUtils.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(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.