initial commit
This commit is contained in:
57
node_modules/vis/lib/timeline/component/BackgroundGroup.js
generated
vendored
Normal file
57
node_modules/vis/lib/timeline/component/BackgroundGroup.js
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
var Group = require('./Group');
|
||||
|
||||
/**
|
||||
* @constructor BackgroundGroup
|
||||
* @param {number | string} groupId
|
||||
* @param {Object} data
|
||||
* @param {ItemSet} itemSet
|
||||
* @extends Group
|
||||
*/
|
||||
function BackgroundGroup (groupId, data, itemSet) {
|
||||
Group.call(this, groupId, data, itemSet);
|
||||
|
||||
this.width = 0;
|
||||
this.height = 0;
|
||||
this.top = 0;
|
||||
this.left = 0;
|
||||
}
|
||||
|
||||
BackgroundGroup.prototype = Object.create(Group.prototype);
|
||||
|
||||
/**
|
||||
* Repaint this group
|
||||
* @param {{start: number, end: number}} range
|
||||
* @param {{item: {horizontal: number, vertical: number}, axis: number}} margin
|
||||
* @param {boolean} [forceRestack=false] Force restacking of all items
|
||||
* @return {boolean} Returns true if the group is resized
|
||||
*/
|
||||
BackgroundGroup.prototype.redraw = function(range, margin, forceRestack) { // eslint-disable-line no-unused-vars
|
||||
var resized = false;
|
||||
|
||||
this.visibleItems = this._updateItemsInRange(this.orderedItems, this.visibleItems, range);
|
||||
|
||||
// calculate actual size
|
||||
this.width = this.dom.background.offsetWidth;
|
||||
|
||||
// apply new height (just always zero for BackgroundGroup
|
||||
this.dom.background.style.height = '0';
|
||||
|
||||
// update vertical position of items after they are re-stacked and the height of the group is calculated
|
||||
for (var i = 0, ii = this.visibleItems.length; i < ii; i++) {
|
||||
var item = this.visibleItems[i];
|
||||
item.repositionY(margin);
|
||||
}
|
||||
|
||||
return resized;
|
||||
};
|
||||
|
||||
/**
|
||||
* Show this group: attach to the DOM
|
||||
*/
|
||||
BackgroundGroup.prototype.show = function() {
|
||||
if (!this.dom.background.parentNode) {
|
||||
this.itemSet.dom.background.appendChild(this.dom.background);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = BackgroundGroup;
|
||||
56
node_modules/vis/lib/timeline/component/Component.js
generated
vendored
Normal file
56
node_modules/vis/lib/timeline/component/Component.js
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
var util = require('../../util');
|
||||
|
||||
/**
|
||||
* Prototype for visual components
|
||||
* @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} [body]
|
||||
* @param {Object} [options]
|
||||
*/
|
||||
function Component (body, options) { // eslint-disable-line no-unused-vars
|
||||
this.options = null;
|
||||
this.props = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set options for the component. The new options will be merged into the
|
||||
* current options.
|
||||
* @param {Object} options
|
||||
*/
|
||||
Component.prototype.setOptions = function(options) {
|
||||
if (options) {
|
||||
util.extend(this.options, options);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Repaint the component
|
||||
* @return {boolean} Returns true if the component is resized
|
||||
*/
|
||||
Component.prototype.redraw = function() {
|
||||
// should be implemented by the component
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroy the component. Cleanup DOM and event listeners
|
||||
*/
|
||||
Component.prototype.destroy = function() {
|
||||
// should be implemented by the component
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether the component is resized since the last time _isResized() was
|
||||
* called.
|
||||
* @return {Boolean} Returns true if the component is resized
|
||||
* @protected
|
||||
*/
|
||||
Component.prototype._isResized = function() {
|
||||
var resized = (this.props._previousWidth !== this.props.width ||
|
||||
this.props._previousHeight !== this.props.height);
|
||||
|
||||
this.props._previousWidth = this.props.width;
|
||||
this.props._previousHeight = this.props.height;
|
||||
|
||||
return resized;
|
||||
};
|
||||
|
||||
module.exports = Component;
|
||||
180
node_modules/vis/lib/timeline/component/CurrentTime.js
generated
vendored
Normal file
180
node_modules/vis/lib/timeline/component/CurrentTime.js
generated
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
var util = require('../../util');
|
||||
var Component = require('./Component');
|
||||
var moment = require('../../module/moment');
|
||||
var locales = require('../locales');
|
||||
|
||||
/**
|
||||
* A current time bar
|
||||
* @param {{range: Range, dom: Object, domProps: Object}} body
|
||||
* @param {Object} [options] Available parameters:
|
||||
* {Boolean} [showCurrentTime]
|
||||
* @constructor CurrentTime
|
||||
* @extends Component
|
||||
*/
|
||||
function CurrentTime (body, options) {
|
||||
this.body = body;
|
||||
|
||||
// default options
|
||||
this.defaultOptions = {
|
||||
rtl: false,
|
||||
showCurrentTime: true,
|
||||
|
||||
moment: moment,
|
||||
locales: locales,
|
||||
locale: 'en'
|
||||
};
|
||||
this.options = util.extend({}, this.defaultOptions);
|
||||
this.offset = 0;
|
||||
|
||||
this._create();
|
||||
|
||||
this.setOptions(options);
|
||||
}
|
||||
|
||||
CurrentTime.prototype = new Component();
|
||||
|
||||
/**
|
||||
* Create the HTML DOM for the current time bar
|
||||
* @private
|
||||
*/
|
||||
CurrentTime.prototype._create = function() {
|
||||
var bar = document.createElement('div');
|
||||
bar.className = 'vis-current-time';
|
||||
bar.style.position = 'absolute';
|
||||
bar.style.top = '0px';
|
||||
bar.style.height = '100%';
|
||||
|
||||
this.bar = bar;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroy the CurrentTime bar
|
||||
*/
|
||||
CurrentTime.prototype.destroy = function () {
|
||||
this.options.showCurrentTime = false;
|
||||
this.redraw(); // will remove the bar from the DOM and stop refreshing
|
||||
|
||||
this.body = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set options for the component. Options will be merged in current options.
|
||||
* @param {Object} options Available parameters:
|
||||
* {boolean} [showCurrentTime]
|
||||
*/
|
||||
CurrentTime.prototype.setOptions = function(options) {
|
||||
if (options) {
|
||||
// copy all options that we know
|
||||
util.selectiveExtend(['rtl', 'showCurrentTime', 'moment', 'locale', 'locales'], this.options, options);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Repaint the component
|
||||
* @return {boolean} Returns true if the component is resized
|
||||
*/
|
||||
CurrentTime.prototype.redraw = function() {
|
||||
if (this.options.showCurrentTime) {
|
||||
var parent = this.body.dom.backgroundVertical;
|
||||
if (this.bar.parentNode != parent) {
|
||||
// attach to the dom
|
||||
if (this.bar.parentNode) {
|
||||
this.bar.parentNode.removeChild(this.bar);
|
||||
}
|
||||
parent.appendChild(this.bar);
|
||||
|
||||
this.start();
|
||||
}
|
||||
|
||||
var now = this.options.moment(new Date().valueOf() + this.offset);
|
||||
var x = this.body.util.toScreen(now);
|
||||
|
||||
var locale = this.options.locales[this.options.locale];
|
||||
if (!locale) {
|
||||
if (!this.warned) {
|
||||
console.log('WARNING: options.locales[\'' + this.options.locale + '\'] not found. See http://visjs.org/docs/timeline/#Localization');
|
||||
this.warned = true;
|
||||
}
|
||||
locale = this.options.locales['en']; // fall back on english when not available
|
||||
}
|
||||
var title = locale.current + ' ' + locale.time + ': ' + now.format('dddd, MMMM Do YYYY, H:mm:ss');
|
||||
title = title.charAt(0).toUpperCase() + title.substring(1);
|
||||
|
||||
if (this.options.rtl) {
|
||||
this.bar.style.right = x + 'px';
|
||||
} else {
|
||||
this.bar.style.left = x + 'px';
|
||||
}
|
||||
this.bar.title = title;
|
||||
}
|
||||
else {
|
||||
// remove the line from the DOM
|
||||
if (this.bar.parentNode) {
|
||||
this.bar.parentNode.removeChild(this.bar);
|
||||
}
|
||||
this.stop();
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Start auto refreshing the current time bar
|
||||
*/
|
||||
CurrentTime.prototype.start = function() {
|
||||
var me = this;
|
||||
|
||||
/**
|
||||
* Updates the current time.
|
||||
*/
|
||||
function update () {
|
||||
me.stop();
|
||||
|
||||
// determine interval to refresh
|
||||
var scale = me.body.range.conversion(me.body.domProps.center.width).scale;
|
||||
var interval = 1 / scale / 10;
|
||||
if (interval < 30) interval = 30;
|
||||
if (interval > 1000) interval = 1000;
|
||||
|
||||
me.redraw();
|
||||
me.body.emitter.emit('currentTimeTick');
|
||||
|
||||
// start a renderTimer to adjust for the new time
|
||||
me.currentTimeTimer = setTimeout(update, interval);
|
||||
}
|
||||
|
||||
update();
|
||||
};
|
||||
|
||||
/**
|
||||
* Stop auto refreshing the current time bar
|
||||
*/
|
||||
CurrentTime.prototype.stop = function() {
|
||||
if (this.currentTimeTimer !== undefined) {
|
||||
clearTimeout(this.currentTimeTimer);
|
||||
delete this.currentTimeTimer;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set a current time. This can be used for example to ensure that a client's
|
||||
* time is synchronized with a shared server time.
|
||||
* @param {Date | string | number} time A Date, unix timestamp, or
|
||||
* ISO date string.
|
||||
*/
|
||||
CurrentTime.prototype.setCurrentTime = function(time) {
|
||||
var t = util.convert(time, 'Date').valueOf();
|
||||
var now = new Date().valueOf();
|
||||
this.offset = t - now;
|
||||
this.redraw();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current time.
|
||||
* @return {Date} Returns the current time.
|
||||
*/
|
||||
CurrentTime.prototype.getCurrentTime = function() {
|
||||
return new Date(new Date().valueOf() + this.offset);
|
||||
};
|
||||
|
||||
module.exports = CurrentTime;
|
||||
265
node_modules/vis/lib/timeline/component/CustomTime.js
generated
vendored
Normal file
265
node_modules/vis/lib/timeline/component/CustomTime.js
generated
vendored
Normal file
@@ -0,0 +1,265 @@
|
||||
var Hammer = require('../../module/hammer');
|
||||
var util = require('../../util');
|
||||
var Component = require('./Component');
|
||||
var moment = require('../../module/moment');
|
||||
var locales = require('../locales');
|
||||
|
||||
/**
|
||||
* A custom time bar
|
||||
* @param {{range: Range, dom: Object}} body
|
||||
* @param {Object} [options] Available parameters:
|
||||
* {number | string} id
|
||||
* {string} locales
|
||||
* {string} locale
|
||||
* @constructor CustomTime
|
||||
* @extends Component
|
||||
*/
|
||||
function CustomTime (body, options) {
|
||||
this.body = body;
|
||||
|
||||
// default options
|
||||
this.defaultOptions = {
|
||||
moment: moment,
|
||||
locales: locales,
|
||||
locale: 'en',
|
||||
id: undefined,
|
||||
title: undefined
|
||||
};
|
||||
this.options = util.extend({}, this.defaultOptions);
|
||||
|
||||
if (options && options.time) {
|
||||
this.customTime = options.time;
|
||||
} else {
|
||||
this.customTime = new Date();
|
||||
}
|
||||
|
||||
this.eventParams = {}; // stores state parameters while dragging the bar
|
||||
|
||||
this.setOptions(options);
|
||||
|
||||
// create the DOM
|
||||
this._create();
|
||||
}
|
||||
|
||||
CustomTime.prototype = new Component();
|
||||
|
||||
/**
|
||||
* Set options for the component. Options will be merged in current options.
|
||||
* @param {Object} options Available parameters:
|
||||
* {number | string} id
|
||||
* {string} locales
|
||||
* {string} locale
|
||||
*/
|
||||
CustomTime.prototype.setOptions = function(options) {
|
||||
if (options) {
|
||||
// copy all options that we know
|
||||
util.selectiveExtend(['moment', 'locale', 'locales', 'id'], this.options, options);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the DOM for the custom time
|
||||
* @private
|
||||
*/
|
||||
CustomTime.prototype._create = function() {
|
||||
var bar = document.createElement('div');
|
||||
bar['custom-time'] = this;
|
||||
bar.className = 'vis-custom-time ' + (this.options.id || '');
|
||||
bar.style.position = 'absolute';
|
||||
bar.style.top = '0px';
|
||||
bar.style.height = '100%';
|
||||
this.bar = bar;
|
||||
|
||||
var drag = document.createElement('div');
|
||||
drag.style.position = 'relative';
|
||||
drag.style.top = '0px';
|
||||
drag.style.left = '-10px';
|
||||
drag.style.height = '100%';
|
||||
drag.style.width = '20px';
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {WheelEvent} e
|
||||
*/
|
||||
function onMouseWheel (e) {
|
||||
this.body.range._onMouseWheel(e);
|
||||
}
|
||||
|
||||
if (drag.addEventListener) {
|
||||
// IE9, Chrome, Safari, Opera
|
||||
drag.addEventListener("mousewheel", onMouseWheel.bind(this), false);
|
||||
// Firefox
|
||||
drag.addEventListener("DOMMouseScroll", onMouseWheel.bind(this), false);
|
||||
} else {
|
||||
// IE 6/7/8
|
||||
drag.attachEvent("onmousewheel", onMouseWheel.bind(this));
|
||||
}
|
||||
|
||||
bar.appendChild(drag);
|
||||
// attach event listeners
|
||||
this.hammer = new Hammer(drag);
|
||||
this.hammer.on('panstart', this._onDragStart.bind(this));
|
||||
this.hammer.on('panmove', this._onDrag.bind(this));
|
||||
this.hammer.on('panend', this._onDragEnd.bind(this));
|
||||
this.hammer.get('pan').set({threshold:5, direction: Hammer.DIRECTION_HORIZONTAL});
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroy the CustomTime bar
|
||||
*/
|
||||
CustomTime.prototype.destroy = function () {
|
||||
this.hide();
|
||||
|
||||
this.hammer.destroy();
|
||||
this.hammer = null;
|
||||
|
||||
this.body = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Repaint the component
|
||||
* @return {boolean} Returns true if the component is resized
|
||||
*/
|
||||
CustomTime.prototype.redraw = function () {
|
||||
var parent = this.body.dom.backgroundVertical;
|
||||
if (this.bar.parentNode != parent) {
|
||||
// attach to the dom
|
||||
if (this.bar.parentNode) {
|
||||
this.bar.parentNode.removeChild(this.bar);
|
||||
}
|
||||
parent.appendChild(this.bar);
|
||||
}
|
||||
|
||||
var x = this.body.util.toScreen(this.customTime);
|
||||
|
||||
var locale = this.options.locales[this.options.locale];
|
||||
if (!locale) {
|
||||
if (!this.warned) {
|
||||
console.log('WARNING: options.locales[\'' + this.options.locale + '\'] not found. See http://visjs.org/docs/timeline/#Localization');
|
||||
this.warned = true;
|
||||
}
|
||||
locale = this.options.locales['en']; // fall back on english when not available
|
||||
}
|
||||
|
||||
var title = this.options.title;
|
||||
// To hide the title completely use empty string ''.
|
||||
if (title === undefined) {
|
||||
title = locale.time + ': ' + this.options.moment(this.customTime).format('dddd, MMMM Do YYYY, H:mm:ss');
|
||||
title = title.charAt(0).toUpperCase() + title.substring(1);
|
||||
} else if (typeof title === "function") {
|
||||
title = title.call(this.customTime);
|
||||
}
|
||||
|
||||
this.bar.style.left = x + 'px';
|
||||
this.bar.title = title;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the CustomTime from the DOM
|
||||
*/
|
||||
CustomTime.prototype.hide = function () {
|
||||
// remove the line from the DOM
|
||||
if (this.bar.parentNode) {
|
||||
this.bar.parentNode.removeChild(this.bar);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set custom time.
|
||||
* @param {Date | number | string} time
|
||||
*/
|
||||
CustomTime.prototype.setCustomTime = function(time) {
|
||||
this.customTime = util.convert(time, 'Date');
|
||||
this.redraw();
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the current custom time.
|
||||
* @return {Date} customTime
|
||||
*/
|
||||
CustomTime.prototype.getCustomTime = function() {
|
||||
return new Date(this.customTime.valueOf());
|
||||
};
|
||||
|
||||
/**
|
||||
* Set custom title.
|
||||
* @param {Date | number | string} title
|
||||
*/
|
||||
CustomTime.prototype.setCustomTitle = function(title) {
|
||||
this.options.title = title;
|
||||
};
|
||||
|
||||
/**
|
||||
* Start moving horizontally
|
||||
* @param {Event} event
|
||||
* @private
|
||||
*/
|
||||
CustomTime.prototype._onDragStart = function(event) {
|
||||
this.eventParams.dragging = true;
|
||||
this.eventParams.customTime = this.customTime;
|
||||
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
/**
|
||||
* Perform moving operating.
|
||||
* @param {Event} event
|
||||
* @private
|
||||
*/
|
||||
CustomTime.prototype._onDrag = function (event) {
|
||||
if (!this.eventParams.dragging) return;
|
||||
|
||||
var x = this.body.util.toScreen(this.eventParams.customTime) + event.deltaX;
|
||||
var time = this.body.util.toTime(x);
|
||||
|
||||
this.setCustomTime(time);
|
||||
|
||||
// fire a timechange event
|
||||
this.body.emitter.emit('timechange', {
|
||||
id: this.options.id,
|
||||
time: new Date(this.customTime.valueOf()),
|
||||
event: event
|
||||
});
|
||||
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
/**
|
||||
* Stop moving operating.
|
||||
* @param {Event} event
|
||||
* @private
|
||||
*/
|
||||
CustomTime.prototype._onDragEnd = function (event) {
|
||||
if (!this.eventParams.dragging) return;
|
||||
|
||||
// fire a timechanged event
|
||||
this.body.emitter.emit('timechanged', {
|
||||
id: this.options.id,
|
||||
time: new Date(this.customTime.valueOf()),
|
||||
event: event
|
||||
});
|
||||
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
/**
|
||||
* Find a custom time from an event target:
|
||||
* searches for the attribute 'custom-time' in the event target's element tree
|
||||
* @param {Event} event
|
||||
* @return {CustomTime | null} customTime
|
||||
*/
|
||||
CustomTime.customTimeFromTarget = function(event) {
|
||||
var target = event.target;
|
||||
while (target) {
|
||||
if (target.hasOwnProperty('custom-time')) {
|
||||
return target['custom-time'];
|
||||
}
|
||||
target = target.parentNode;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
module.exports = CustomTime;
|
||||
593
node_modules/vis/lib/timeline/component/DataAxis.js
generated
vendored
Normal file
593
node_modules/vis/lib/timeline/component/DataAxis.js
generated
vendored
Normal file
@@ -0,0 +1,593 @@
|
||||
var util = require('../../util');
|
||||
var DOMutil = require('../../DOMutil');
|
||||
var Component = require('./Component');
|
||||
var DataScale = require('./DataScale');
|
||||
/**
|
||||
* A horizontal time axis
|
||||
* @param {Object} body
|
||||
* @param {Object} [options] See DataAxis.setOptions for the available
|
||||
* options.
|
||||
* @param {SVGElement} svg
|
||||
* @param {vis.LineGraph.options} linegraphOptions
|
||||
* @constructor DataAxis
|
||||
* @extends Component
|
||||
*/
|
||||
function DataAxis(body, options, svg, linegraphOptions) {
|
||||
this.id = util.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 (value) {
|
||||
return '' + parseFloat(value.toPrecision(3));
|
||||
},
|
||||
title: {text: undefined, style: undefined}
|
||||
},
|
||||
right: {
|
||||
range: {min: undefined, max: undefined},
|
||||
format: function (value) {
|
||||
return '' + 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 = util.extend({}, this.defaultOptions);
|
||||
this.conversionFactor = 1;
|
||||
|
||||
this.setOptions(options);
|
||||
this.width = Number(('' + 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();
|
||||
this.framework = {svg: this.svg, svgElements: this.svgElements, options: this.options, groups: this.groups};
|
||||
|
||||
var me = this;
|
||||
this.body.emitter.on("verticalDrag", function () {
|
||||
me.dom.lineContainer.style.top = me.body.domProps.scrollTop + 'px';
|
||||
});
|
||||
}
|
||||
|
||||
DataAxis.prototype = new Component();
|
||||
|
||||
|
||||
DataAxis.prototype.addGroup = function (label, graphOptions) {
|
||||
if (!this.groups.hasOwnProperty(label)) {
|
||||
this.groups[label] = graphOptions;
|
||||
}
|
||||
this.amountOfGroups += 1;
|
||||
};
|
||||
|
||||
DataAxis.prototype.updateGroup = function (label, graphOptions) {
|
||||
if (!this.groups.hasOwnProperty(label)) {
|
||||
this.amountOfGroups += 1;
|
||||
}
|
||||
this.groups[label] = graphOptions;
|
||||
};
|
||||
|
||||
DataAxis.prototype.removeGroup = function (label) {
|
||||
if (this.groups.hasOwnProperty(label)) {
|
||||
delete this.groups[label];
|
||||
this.amountOfGroups -= 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
DataAxis.prototype.setOptions = function (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.selectiveDeepExtend(fields, this.options, options);
|
||||
|
||||
this.minWidth = Number(('' + this.options.width).replace("px", ""));
|
||||
if (redraw === true && this.dom.frame) {
|
||||
this.hide();
|
||||
this.show();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML DOM for the DataAxis
|
||||
*/
|
||||
DataAxis.prototype._create = function () {
|
||||
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';
|
||||
|
||||
// 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);
|
||||
};
|
||||
|
||||
DataAxis.prototype._redrawGroupIcons = function () {
|
||||
DOMutil.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);
|
||||
groupArray.sort(function (a, b) {
|
||||
return (a < b ? -1 : 1);
|
||||
})
|
||||
|
||||
for (var i = 0; i < groupArray.length; i++) {
|
||||
var groupId = groupArray[i];
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
DOMutil.cleanupElements(this.svgElements);
|
||||
this.iconsRemoved = false;
|
||||
};
|
||||
|
||||
DataAxis.prototype._cleanupIcons = function () {
|
||||
if (this.iconsRemoved === false) {
|
||||
DOMutil.prepareElements(this.svgElements);
|
||||
DOMutil.cleanupElements(this.svgElements);
|
||||
this.iconsRemoved = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the HTML DOM for the DataAxis
|
||||
*/
|
||||
DataAxis.prototype.show = function () {
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the HTML DOM for the DataAxis
|
||||
*/
|
||||
DataAxis.prototype.hide = function () {
|
||||
this.hidden = true;
|
||||
if (this.dom.frame.parentNode) {
|
||||
this.dom.frame.parentNode.removeChild(this.dom.frame);
|
||||
}
|
||||
|
||||
if (this.dom.lineContainer.parentNode) {
|
||||
this.dom.lineContainer.parentNode.removeChild(this.dom.lineContainer);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set a range (start and end)
|
||||
* @param {number} start
|
||||
* @param {number} end
|
||||
*/
|
||||
DataAxis.prototype.setRange = function (start, end) {
|
||||
this.range.start = start;
|
||||
this.range.end = end;
|
||||
};
|
||||
|
||||
/**
|
||||
* Repaint the component
|
||||
* @return {boolean} Returns true if the component is resized
|
||||
*/
|
||||
DataAxis.prototype.redraw = function () {
|
||||
var resized = false;
|
||||
var activeGroups = 0;
|
||||
|
||||
// Make sure the line container adheres to the vertical scrolling.
|
||||
this.dom.lineContainer.style.top = 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 = this.height + 'px';
|
||||
this.width = this.options.visible === true ? Number(('' + 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;
|
||||
|
||||
// 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 = this.body.dom.backgroundHorizontal.offsetWidth - this.lineOffset - this.width + 2 * this.options.minorLinesOffset;
|
||||
props.minorLineHeight = 1;
|
||||
props.majorLineWidth = this.body.dom.backgroundHorizontal.offsetWidth - 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 = this.width + 'px';
|
||||
frame.style.height = 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 = this.width + 'px';
|
||||
frame.style.height = 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
|
||||
*/
|
||||
DataAxis.prototype._redrawLabels = function () {
|
||||
var resized = false;
|
||||
DOMutil.prepareElements(this.DOMelements.lines);
|
||||
DOMutil.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);
|
||||
}
|
||||
|
||||
//Is updated in side-effect of _redrawLabel():
|
||||
this.maxLabelSize = 0;
|
||||
|
||||
var lines = this.scale.getLines();
|
||||
lines.forEach(
|
||||
line=> {
|
||||
var y = line.y;
|
||||
var isMajor = line.major;
|
||||
if (this.options['showMinorLabels'] && isMajor === false) {
|
||||
this._redrawLabel(y - 2, line.val, orientation, 'vis-y-axis vis-minor', this.props.minorCharHeight);
|
||||
}
|
||||
if (isMajor) {
|
||||
if (y >= 0) {
|
||||
this._redrawLabel(y - 2, line.val, orientation, 'vis-y-axis vis-major', this.props.majorCharHeight);
|
||||
}
|
||||
}
|
||||
if (this.master === true) {
|
||||
if (isMajor) {
|
||||
this._redrawLine(y, orientation, 'vis-grid vis-horizontal vis-major', this.options.majorLinesOffset, this.props.majorLineWidth);
|
||||
}
|
||||
else {
|
||||
this._redrawLine(y, orientation, 'vis-grid vis-horizontal vis-minor', this.options.minorLinesOffset, this.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 = this.width + "px";
|
||||
DOMutil.cleanupElements(this.DOMelements.lines);
|
||||
DOMutil.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 = this.width + "px";
|
||||
DOMutil.cleanupElements(this.DOMelements.lines);
|
||||
DOMutil.cleanupElements(this.DOMelements.labels);
|
||||
this.redraw();
|
||||
resized = true;
|
||||
}
|
||||
else {
|
||||
DOMutil.cleanupElements(this.DOMelements.lines);
|
||||
DOMutil.cleanupElements(this.DOMelements.labels);
|
||||
resized = false;
|
||||
}
|
||||
|
||||
return resized;
|
||||
};
|
||||
|
||||
DataAxis.prototype.convertValue = function (value) {
|
||||
return this.scale.convertValue(value);
|
||||
};
|
||||
|
||||
DataAxis.prototype.screenToValue = function (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
|
||||
*/
|
||||
DataAxis.prototype._redrawLabel = function (y, text, orientation, className, characterHeight) {
|
||||
// reuse redundant label
|
||||
var label = DOMutil.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 = '-' + this.options.labelOffsetX + 'px';
|
||||
label.style.textAlign = "right";
|
||||
}
|
||||
else {
|
||||
label.style.right = '-' + this.options.labelOffsetX + 'px';
|
||||
label.style.textAlign = "left";
|
||||
}
|
||||
|
||||
label.style.top = 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
|
||||
*/
|
||||
DataAxis.prototype._redrawLine = function (y, orientation, className, offset, width) {
|
||||
if (this.master === true) {
|
||||
var line = DOMutil.getDOMElement('div', this.DOMelements.lines, this.dom.lineContainer);//this.dom.redundant.lines.shift();
|
||||
line.className = className;
|
||||
line.innerHTML = '';
|
||||
|
||||
if (orientation === 'left') {
|
||||
line.style.left = (this.width - offset) + 'px';
|
||||
}
|
||||
else {
|
||||
line.style.right = (this.width - offset) + 'px';
|
||||
}
|
||||
|
||||
line.style.width = width + 'px';
|
||||
line.style.top = y + 'px';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a title for the axis
|
||||
* @private
|
||||
* @param {'top'|'right'|'bottom'|'left'} orientation
|
||||
*/
|
||||
DataAxis.prototype._redrawTitle = function (orientation) {
|
||||
DOMutil.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 = DOMutil.getDOMElement('div', this.DOMelements.title, this.dom.frame);
|
||||
title.className = 'vis-y-axis vis-title vis-' + orientation;
|
||||
title.innerHTML = this.options[orientation].title.text;
|
||||
|
||||
// Add style - if provided
|
||||
if (this.options[orientation].title.style !== undefined) {
|
||||
util.addCssText(title, this.options[orientation].title.style);
|
||||
}
|
||||
|
||||
if (orientation === 'left') {
|
||||
title.style.left = this.props.titleCharHeight + 'px';
|
||||
}
|
||||
else {
|
||||
title.style.right = this.props.titleCharHeight + 'px';
|
||||
}
|
||||
|
||||
title.style.width = this.height + 'px';
|
||||
}
|
||||
|
||||
// we need to clean up in case we did not use all elements.
|
||||
DOMutil.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
|
||||
*/
|
||||
DataAxis.prototype._calculateCharSize = function () {
|
||||
// determine the char width and height on the minor axis
|
||||
if (!('minorCharHeight' in this.props)) {
|
||||
var textMinor = document.createTextNode('0');
|
||||
var measureCharMinor = document.createElement('div');
|
||||
measureCharMinor.className = '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);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = DataAxis;
|
||||
244
node_modules/vis/lib/timeline/component/DataScale.js
generated
vendored
Normal file
244
node_modules/vis/lib/timeline/component/DataScale.js
generated
vendored
Normal file
@@ -0,0 +1,244 @@
|
||||
/**
|
||||
*
|
||||
* @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, zeroAlign = false, formattingFunction=false) {
|
||||
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 (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();
|
||||
}
|
||||
}
|
||||
|
||||
DataScale.prototype.setCharHeight = function (majorCharHeight) {
|
||||
this.majorCharHeight = majorCharHeight;
|
||||
};
|
||||
|
||||
DataScale.prototype.setHeight = function (containerHeight) {
|
||||
this.containerHeight = containerHeight;
|
||||
};
|
||||
|
||||
DataScale.prototype.determineScale = function () {
|
||||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
DataScale.prototype.is_major = function (value) {
|
||||
return (value % (this.magnitudefactor * this.majorSteps[this.minorStepIdx]) === 0);
|
||||
};
|
||||
|
||||
DataScale.prototype.getStep = function(){
|
||||
return this.magnitudefactor * this.minorSteps[this.minorStepIdx];
|
||||
};
|
||||
|
||||
DataScale.prototype.getFirstMajor = function(){
|
||||
var majorStep = this.magnitudefactor * this.majorSteps[this.minorStepIdx];
|
||||
return this.convertValue(this._start + ((majorStep - (this._start % majorStep)) % majorStep));
|
||||
};
|
||||
|
||||
DataScale.prototype.formatValue = function(current) {
|
||||
var returnValue = current.toPrecision(5);
|
||||
if (typeof this.formattingFunction === 'function') {
|
||||
returnValue = this.formattingFunction(current);
|
||||
}
|
||||
|
||||
if (typeof returnValue === 'number') {
|
||||
return '' + returnValue;
|
||||
}
|
||||
else if (typeof returnValue === 'string') {
|
||||
return returnValue;
|
||||
}
|
||||
else {
|
||||
return current.toPrecision(5);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
DataScale.prototype.getLines = function () {
|
||||
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;
|
||||
};
|
||||
|
||||
DataScale.prototype.followScale = function (other) {
|
||||
var oldStepIdx = this.minorStepIdx;
|
||||
var oldStart = this._start;
|
||||
var oldEnd = this._end;
|
||||
|
||||
var me = this;
|
||||
var increaseMagnitude = function () {
|
||||
me.magnitudefactor *= 2;
|
||||
};
|
||||
var decreaseMagnitude = function () {
|
||||
me.magnitudefactor /= 2;
|
||||
};
|
||||
|
||||
if ((other.minorStepIdx <= 1 && this.minorStepIdx <= 1) || (other.minorStepIdx > 1 && this.minorStepIdx > 1)) {
|
||||
//easy, no need to change stepIdx nor multiplication factor
|
||||
} 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;
|
||||
}
|
||||
};
|
||||
|
||||
DataScale.prototype.convertValue = function (value) {
|
||||
return this.containerHeight - ((value - this._start) * this.scale);
|
||||
};
|
||||
|
||||
DataScale.prototype.screenToValue = function (pixels) {
|
||||
return ((this.containerHeight - pixels) / this.scale) + this._start;
|
||||
};
|
||||
|
||||
module.exports = DataScale;
|
||||
160
node_modules/vis/lib/timeline/component/GraphGroup.js
generated
vendored
Normal file
160
node_modules/vis/lib/timeline/component/GraphGroup.js
generated
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
var util = require('../../util');
|
||||
var Bars = require('./graph2d_types/bar');
|
||||
var Lines = require('./graph2d_types/line');
|
||||
var Points = require('./graph2d_types/points');
|
||||
|
||||
/**
|
||||
* /**
|
||||
* @param {object} group | the object of the group from the dataset
|
||||
* @param {string} groupId | ID of the group
|
||||
* @param {object} options | the default options
|
||||
* @param {array} groupsUsingDefaultStyles | this array has one entree.
|
||||
* It is passed as an array so it is passed by reference.
|
||||
* It enumerates through the default styles
|
||||
* @constructor GraphGroup
|
||||
*/
|
||||
function GraphGroup(group, groupId, options, groupsUsingDefaultStyles) {
|
||||
this.id = groupId;
|
||||
var fields = ['sampling', 'style', 'sort', 'yAxisOrientation', 'barChart', 'drawPoints', 'shaded', 'interpolation', 'zIndex','excludeFromStacking', 'excludeFromLegend'];
|
||||
this.options = util.selectiveBridgeObject(fields, options);
|
||||
this.usingDefaultStyle = group.className === undefined;
|
||||
this.groupsUsingDefaultStyles = groupsUsingDefaultStyles;
|
||||
this.zeroPosition = 0;
|
||||
this.update(group);
|
||||
if (this.usingDefaultStyle == true) {
|
||||
this.groupsUsingDefaultStyles[0] += 1;
|
||||
}
|
||||
this.itemsData = [];
|
||||
this.visible = group.visible === undefined ? true : group.visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* this loads a reference to all items in this group into this group.
|
||||
* @param {array} items
|
||||
*/
|
||||
GraphGroup.prototype.setItems = function (items) {
|
||||
if (items != null) {
|
||||
this.itemsData = items;
|
||||
if (this.options.sort == true) {
|
||||
util.insertSort(this.itemsData,function (a, b) {
|
||||
return a.x > b.x ? 1 : -1;
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.itemsData = [];
|
||||
}
|
||||
};
|
||||
|
||||
GraphGroup.prototype.getItems = function () {
|
||||
return this.itemsData;
|
||||
};
|
||||
|
||||
/**
|
||||
* this is used for barcharts and shading, this way, we only have to calculate it once.
|
||||
* @param {number} pos
|
||||
*/
|
||||
GraphGroup.prototype.setZeroPosition = function (pos) {
|
||||
this.zeroPosition = pos;
|
||||
};
|
||||
|
||||
/**
|
||||
* set the options of the graph group over the default options.
|
||||
* @param {Object} options
|
||||
*/
|
||||
GraphGroup.prototype.setOptions = function (options) {
|
||||
if (options !== undefined) {
|
||||
var fields = ['sampling', 'style', 'sort', 'yAxisOrientation', 'barChart', 'zIndex','excludeFromStacking', 'excludeFromLegend'];
|
||||
util.selectiveDeepExtend(fields, this.options, options);
|
||||
|
||||
// if the group's drawPoints is a function delegate the callback to the onRender property
|
||||
if (typeof options.drawPoints == 'function') {
|
||||
options.drawPoints = {
|
||||
onRender: options.drawPoints
|
||||
}
|
||||
}
|
||||
|
||||
util.mergeOptions(this.options, options, 'interpolation');
|
||||
util.mergeOptions(this.options, options, 'drawPoints');
|
||||
util.mergeOptions(this.options, options, 'shaded');
|
||||
|
||||
if (options.interpolation) {
|
||||
if (typeof options.interpolation == 'object') {
|
||||
if (options.interpolation.parametrization) {
|
||||
if (options.interpolation.parametrization == 'uniform') {
|
||||
this.options.interpolation.alpha = 0;
|
||||
}
|
||||
else if (options.interpolation.parametrization == 'chordal') {
|
||||
this.options.interpolation.alpha = 1.0;
|
||||
}
|
||||
else {
|
||||
this.options.interpolation.parametrization = 'centripetal';
|
||||
this.options.interpolation.alpha = 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* this updates the current group class with the latest group dataset entree, used in _updateGroup in linegraph
|
||||
* @param {vis.Group} group
|
||||
*/
|
||||
GraphGroup.prototype.update = function (group) {
|
||||
this.group = group;
|
||||
this.content = group.content || 'graph';
|
||||
this.className = group.className || this.className || 'vis-graph-group' + this.groupsUsingDefaultStyles[0] % 10;
|
||||
this.visible = group.visible === undefined ? true : group.visible;
|
||||
this.style = group.style;
|
||||
this.setOptions(group.options);
|
||||
};
|
||||
|
||||
/**
|
||||
* return the legend entree for this group.
|
||||
*
|
||||
* @param {number} iconWidth
|
||||
* @param {number} iconHeight
|
||||
* @param {{svg: (*|Element), svgElements: Object, options: Object, groups: Array.<Object>}} framework
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @returns {{icon: (*|Element), label: (*|string), orientation: *}}
|
||||
*/
|
||||
GraphGroup.prototype.getLegend = function (iconWidth, iconHeight, framework, x, y) {
|
||||
if (framework == undefined || framework == null) {
|
||||
var svg = document.createElementNS('http://www.w3.org/2000/svg', "svg");
|
||||
framework = {svg: svg, svgElements:{}, options: this.options, groups: [this]}
|
||||
}
|
||||
if (x == undefined || x == null){
|
||||
x = 0;
|
||||
}
|
||||
if (y == undefined || y == null){
|
||||
y = 0.5 * iconHeight;
|
||||
}
|
||||
switch (this.options.style){
|
||||
case "line":
|
||||
Lines.drawIcon(this, x, y, iconWidth, iconHeight, framework);
|
||||
break;
|
||||
case "points": //explicit no break
|
||||
case "point":
|
||||
Points.drawIcon(this, x, y, iconWidth, iconHeight, framework);
|
||||
break;
|
||||
case "bar":
|
||||
Bars.drawIcon(this, x, y, iconWidth, iconHeight, framework);
|
||||
break;
|
||||
}
|
||||
return {icon: framework.svg, label: this.content, orientation: this.options.yAxisOrientation};
|
||||
};
|
||||
|
||||
GraphGroup.prototype.getYRange = function (groupData) {
|
||||
var yMin = groupData[0].y;
|
||||
var yMax = groupData[0].y;
|
||||
for (var j = 0; j < groupData.length; j++) {
|
||||
yMin = yMin > groupData[j].y ? groupData[j].y : yMin;
|
||||
yMax = yMax < groupData[j].y ? groupData[j].y : yMax;
|
||||
}
|
||||
return {min: yMin, max: yMax, yAxisOrientation: this.options.yAxisOrientation};
|
||||
};
|
||||
|
||||
module.exports = GraphGroup;
|
||||
931
node_modules/vis/lib/timeline/component/Group.js
generated
vendored
Normal file
931
node_modules/vis/lib/timeline/component/Group.js
generated
vendored
Normal file
@@ -0,0 +1,931 @@
|
||||
var util = require('../../util');
|
||||
var stack = require('../Stack');
|
||||
|
||||
/**
|
||||
* @param {number | string} groupId
|
||||
* @param {Object} data
|
||||
* @param {ItemSet} itemSet
|
||||
* @constructor Group
|
||||
*/
|
||||
function Group (groupId, data, itemSet) {
|
||||
this.groupId = groupId;
|
||||
this.subgroups = {};
|
||||
this.subgroupStack = {};
|
||||
this.subgroupStackAll = false;
|
||||
this.doInnerStack = false;
|
||||
this.subgroupIndex = 0;
|
||||
this.subgroupOrderer = data && data.subgroupOrder;
|
||||
this.itemSet = itemSet;
|
||||
this.isVisible = null;
|
||||
this.stackDirty = true; // if true, items will be restacked on next redraw
|
||||
|
||||
if (data && data.nestedGroups) {
|
||||
this.nestedGroups = data.nestedGroups;
|
||||
if (data.showNested == false) {
|
||||
this.showNested = false;
|
||||
} else {
|
||||
this.showNested = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (data && data.subgroupStack) {
|
||||
if (typeof data.subgroupStack === "boolean") {
|
||||
this.doInnerStack = data.subgroupStack;
|
||||
this.subgroupStackAll = data.subgroupStack;
|
||||
}
|
||||
else {
|
||||
// We might be doing stacking on specific sub groups, but only
|
||||
// if at least one is set to do stacking
|
||||
for(var key in data.subgroupStack) {
|
||||
this.subgroupStack[key] = data.subgroupStack[key];
|
||||
this.doInnerStack = this.doInnerStack || data.subgroupStack[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.nestedInGroup = null;
|
||||
|
||||
this.dom = {};
|
||||
this.props = {
|
||||
label: {
|
||||
width: 0,
|
||||
height: 0
|
||||
}
|
||||
};
|
||||
this.className = null;
|
||||
|
||||
this.items = {}; // items filtered by groupId of this group
|
||||
this.visibleItems = []; // items currently visible in window
|
||||
this.itemsInRange = []; // items currently in range
|
||||
this.orderedItems = {
|
||||
byStart: [],
|
||||
byEnd: []
|
||||
};
|
||||
this.checkRangedItems = false; // needed to refresh the ranged items if the window is programatically changed with NO overlap.
|
||||
var me = this;
|
||||
this.itemSet.body.emitter.on("checkRangedItems", function () {
|
||||
me.checkRangedItems = true;
|
||||
})
|
||||
|
||||
this._create();
|
||||
|
||||
this.setData(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create DOM elements for the group
|
||||
* @private
|
||||
*/
|
||||
Group.prototype._create = function() {
|
||||
var label = document.createElement('div');
|
||||
if (this.itemSet.options.groupEditable.order) {
|
||||
label.className = 'vis-label draggable';
|
||||
} else {
|
||||
label.className = 'vis-label';
|
||||
}
|
||||
this.dom.label = label;
|
||||
|
||||
var inner = document.createElement('div');
|
||||
inner.className = 'vis-inner';
|
||||
label.appendChild(inner);
|
||||
this.dom.inner = inner;
|
||||
|
||||
var foreground = document.createElement('div');
|
||||
foreground.className = 'vis-group';
|
||||
foreground['timeline-group'] = this;
|
||||
this.dom.foreground = foreground;
|
||||
|
||||
this.dom.background = document.createElement('div');
|
||||
this.dom.background.className = 'vis-group';
|
||||
|
||||
this.dom.axis = document.createElement('div');
|
||||
this.dom.axis.className = 'vis-group';
|
||||
|
||||
// create a hidden marker to detect when the Timelines container is attached
|
||||
// to the DOM, or the style of a parent of the Timeline is changed from
|
||||
// display:none is changed to visible.
|
||||
this.dom.marker = document.createElement('div');
|
||||
this.dom.marker.style.visibility = 'hidden';
|
||||
this.dom.marker.style.position = 'absolute';
|
||||
this.dom.marker.innerHTML = '';
|
||||
this.dom.background.appendChild(this.dom.marker);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the group data for this group
|
||||
* @param {Object} data Group data, can contain properties content and className
|
||||
*/
|
||||
Group.prototype.setData = function(data) {
|
||||
// update contents
|
||||
var content;
|
||||
var templateFunction;
|
||||
|
||||
if (this.itemSet.options && this.itemSet.options.groupTemplate) {
|
||||
templateFunction = this.itemSet.options.groupTemplate.bind(this);
|
||||
content = templateFunction(data, this.dom.inner);
|
||||
} else {
|
||||
content = data && data.content;
|
||||
}
|
||||
|
||||
if (content instanceof Element) {
|
||||
this.dom.inner.appendChild(content);
|
||||
while (this.dom.inner.firstChild) {
|
||||
this.dom.inner.removeChild(this.dom.inner.firstChild);
|
||||
}
|
||||
this.dom.inner.appendChild(content);
|
||||
} else if (content instanceof Object) {
|
||||
templateFunction(data, this.dom.inner);
|
||||
} else if (content !== undefined && content !== null) {
|
||||
this.dom.inner.innerHTML = content;
|
||||
} else {
|
||||
this.dom.inner.innerHTML = this.groupId || ''; // groupId can be null
|
||||
}
|
||||
|
||||
// update title
|
||||
this.dom.label.title = data && data.title || '';
|
||||
if (!this.dom.inner.firstChild) {
|
||||
util.addClassName(this.dom.inner, 'vis-hidden');
|
||||
}
|
||||
else {
|
||||
util.removeClassName(this.dom.inner, 'vis-hidden');
|
||||
}
|
||||
|
||||
if (data && data.nestedGroups) {
|
||||
if (!this.nestedGroups || this.nestedGroups != data.nestedGroups) {
|
||||
this.nestedGroups = data.nestedGroups;
|
||||
}
|
||||
|
||||
if (data.showNested !== undefined || this.showNested === undefined) {
|
||||
if (data.showNested == false) {
|
||||
this.showNested = false;
|
||||
} else {
|
||||
this.showNested = true;
|
||||
}
|
||||
}
|
||||
|
||||
util.addClassName(this.dom.label, 'vis-nesting-group');
|
||||
var collapsedDirClassName = this.itemSet.options.rtl ? 'collapsed-rtl' : 'collapsed'
|
||||
if (this.showNested) {
|
||||
util.removeClassName(this.dom.label, collapsedDirClassName);
|
||||
util.addClassName(this.dom.label, 'expanded');
|
||||
} else {
|
||||
util.removeClassName(this.dom.label, 'expanded');
|
||||
util.addClassName(this.dom.label, collapsedDirClassName);
|
||||
}
|
||||
} else if (this.nestedGroups) {
|
||||
this.nestedGroups = null;
|
||||
collapsedDirClassName = this.itemSet.options.rtl ? 'collapsed-rtl' : 'collapsed'
|
||||
util.removeClassName(this.dom.label, collapsedDirClassName);
|
||||
util.removeClassName(this.dom.label, 'expanded');
|
||||
util.removeClassName(this.dom.label, 'vis-nesting-group');
|
||||
}
|
||||
|
||||
if (data && data.nestedInGroup) {
|
||||
util.addClassName(this.dom.label, 'vis-nested-group');
|
||||
if (this.itemSet.options && this.itemSet.options.rtl) {
|
||||
this.dom.inner.style.paddingRight = '30px';
|
||||
} else {
|
||||
this.dom.inner.style.paddingLeft = '30px';
|
||||
}
|
||||
}
|
||||
|
||||
// update className
|
||||
var className = data && data.className || null;
|
||||
if (className != this.className) {
|
||||
if (this.className) {
|
||||
util.removeClassName(this.dom.label, this.className);
|
||||
util.removeClassName(this.dom.foreground, this.className);
|
||||
util.removeClassName(this.dom.background, this.className);
|
||||
util.removeClassName(this.dom.axis, this.className);
|
||||
}
|
||||
util.addClassName(this.dom.label, className);
|
||||
util.addClassName(this.dom.foreground, className);
|
||||
util.addClassName(this.dom.background, className);
|
||||
util.addClassName(this.dom.axis, className);
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
// update style
|
||||
if (this.style) {
|
||||
util.removeCssText(this.dom.label, this.style);
|
||||
this.style = null;
|
||||
}
|
||||
if (data && data.style) {
|
||||
util.addCssText(this.dom.label, data.style);
|
||||
this.style = data.style;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the width of the group label
|
||||
* @return {number} width
|
||||
*/
|
||||
Group.prototype.getLabelWidth = function() {
|
||||
return this.props.label.width;
|
||||
};
|
||||
|
||||
Group.prototype._didMarkerHeightChange = function() {
|
||||
var markerHeight = this.dom.marker.clientHeight;
|
||||
if (markerHeight != this.lastMarkerHeight) {
|
||||
this.lastMarkerHeight = markerHeight;
|
||||
var redrawQueue = {};
|
||||
var redrawQueueLength = 0;
|
||||
|
||||
util.forEach(this.items, function (item, key) {
|
||||
item.dirty = true;
|
||||
if (item.displayed) {
|
||||
var returnQueue = true;
|
||||
redrawQueue[key] = item.redraw(returnQueue);
|
||||
redrawQueueLength = redrawQueue[key].length;
|
||||
}
|
||||
})
|
||||
|
||||
var needRedraw = redrawQueueLength > 0;
|
||||
if (needRedraw) {
|
||||
// redraw all regular items
|
||||
for (var i = 0; i < redrawQueueLength; i++) {
|
||||
util.forEach(redrawQueue, function (fns) {
|
||||
fns[i]();
|
||||
});
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Group.prototype._calculateGroupSizeAndPosition = function() {
|
||||
var offsetTop = this.dom.foreground.offsetTop
|
||||
var offsetLeft = this.dom.foreground.offsetLeft
|
||||
var offsetWidth = this.dom.foreground.offsetWidth
|
||||
this.top = offsetTop;
|
||||
this.right = offsetLeft;
|
||||
this.width = offsetWidth;
|
||||
}
|
||||
|
||||
Group.prototype._redrawItems = function(forceRestack, lastIsVisible, margin, range) {
|
||||
var restack = forceRestack || this.stackDirty || this.isVisible && !lastIsVisible;
|
||||
|
||||
// if restacking, reposition visible items vertically
|
||||
if (restack) {
|
||||
var visibleSubgroups = {};
|
||||
var subgroup = null;
|
||||
|
||||
if (typeof this.itemSet.options.order === 'function') {
|
||||
// a custom order function
|
||||
// brute force restack of all items
|
||||
|
||||
// show all items
|
||||
var me = this;
|
||||
var limitSize = false;
|
||||
|
||||
var redrawQueue = {};
|
||||
var redrawQueueLength = 0;
|
||||
|
||||
util.forEach(this.items, function (item, key) {
|
||||
if (!item.displayed) {
|
||||
var returnQueue = true;
|
||||
redrawQueue[key] = item.redraw(returnQueue);
|
||||
redrawQueueLength = redrawQueue[key].length;
|
||||
me.visibleItems.push(item);
|
||||
}
|
||||
})
|
||||
|
||||
var needRedraw = redrawQueueLength > 0;
|
||||
if (needRedraw) {
|
||||
// redraw all regular items
|
||||
for (var i = 0; i < redrawQueueLength; i++) {
|
||||
util.forEach(redrawQueue, function (fns) {
|
||||
fns[i]();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
util.forEach(this.items, function (item) {
|
||||
item.repositionX(limitSize);
|
||||
});
|
||||
|
||||
if (this.doInnerStack && this.itemSet.options.stackSubgroups) {
|
||||
// Order the items within each subgroup
|
||||
for(subgroup in this.subgroups) {
|
||||
visibleSubgroups[subgroup] = this.subgroups[subgroup].items.slice().sort(function (a, b) {
|
||||
return me.itemSet.options.order(a.data, b.data);
|
||||
});
|
||||
}
|
||||
|
||||
stack.stackSubgroupsWithInnerStack(visibleSubgroups, margin, this.subgroups);
|
||||
}
|
||||
else {
|
||||
// order all items and force a restacking
|
||||
var customOrderedItems = this.orderedItems.byStart.slice().sort(function (a, b) {
|
||||
return me.itemSet.options.order(a.data, b.data);
|
||||
});
|
||||
stack.stack(customOrderedItems, margin, true /* restack=true */);
|
||||
}
|
||||
|
||||
this.visibleItems = this._updateItemsInRange(this.orderedItems, this.visibleItems, range);
|
||||
} else {
|
||||
// no custom order function, lazy stacking
|
||||
this.visibleItems = this._updateItemsInRange(this.orderedItems, this.visibleItems, range);
|
||||
|
||||
if (this.itemSet.options.stack) {
|
||||
if (this.doInnerStack && this.itemSet.options.stackSubgroups) {
|
||||
for(subgroup in this.subgroups) {
|
||||
visibleSubgroups[subgroup] = this.subgroups[subgroup].items;
|
||||
}
|
||||
|
||||
stack.stackSubgroupsWithInnerStack(visibleSubgroups, margin, this.subgroups);
|
||||
}
|
||||
else {
|
||||
// TODO: ugly way to access options...
|
||||
stack.stack(this.visibleItems, margin, true /* restack=true */);
|
||||
}
|
||||
} else {
|
||||
// no stacking
|
||||
stack.nostack(this.visibleItems, margin, this.subgroups, this.itemSet.options.stackSubgroups);
|
||||
}
|
||||
}
|
||||
|
||||
this.stackDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
Group.prototype._didResize = function(resized, height) {
|
||||
resized = util.updateProperty(this, 'height', height) || resized;
|
||||
// recalculate size of label
|
||||
var labelWidth = this.dom.inner.clientWidth;
|
||||
var labelHeight = this.dom.inner.clientHeight;
|
||||
resized = util.updateProperty(this.props.label, 'width', labelWidth) || resized;
|
||||
resized = util.updateProperty(this.props.label, 'height', labelHeight) || resized;
|
||||
return resized;
|
||||
}
|
||||
|
||||
Group.prototype._applyGroupHeight = function(height) {
|
||||
this.dom.background.style.height = height + 'px';
|
||||
this.dom.foreground.style.height = height + 'px';
|
||||
this.dom.label.style.height = height + 'px';
|
||||
}
|
||||
|
||||
// update vertical position of items after they are re-stacked and the height of the group is calculated
|
||||
Group.prototype._updateItemsVerticalPosition = function(margin) {
|
||||
for (var i = 0, ii = this.visibleItems.length; i < ii; i++) {
|
||||
var item = this.visibleItems[i];
|
||||
item.repositionY(margin);
|
||||
if (!this.isVisible && this.groupId != "__background__") {
|
||||
if (item.displayed) item.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Repaint this group
|
||||
* @param {{start: number, end: number}} range
|
||||
* @param {{item: {horizontal: number, vertical: number}, axis: number}} margin
|
||||
* @param {boolean} [forceRestack=false] Force restacking of all items
|
||||
* @param {boolean} [returnQueue=false] return the queue or if the group resized
|
||||
* @return {boolean} Returns true if the group is resized or the redraw queue if returnQueue=true
|
||||
*/
|
||||
Group.prototype.redraw = function(range, margin, forceRestack, returnQueue) {
|
||||
var resized = false;
|
||||
var lastIsVisible = this.isVisible;
|
||||
var height;
|
||||
|
||||
var queue = [
|
||||
// force recalculation of the height of the items when the marker height changed
|
||||
// (due to the Timeline being attached to the DOM or changed from display:none to visible)
|
||||
(function () {
|
||||
forceRestack = this._didMarkerHeightChange.bind(this);
|
||||
}).bind(this),
|
||||
|
||||
// recalculate the height of the subgroups
|
||||
this._updateSubGroupHeights.bind(this, margin),
|
||||
|
||||
// calculate actual size and position
|
||||
this._calculateGroupSizeAndPosition.bind(this),
|
||||
|
||||
// check if group is visible
|
||||
(function() {
|
||||
this.isVisible = this._isGroupVisible.bind(this)(range, margin);
|
||||
}).bind(this),
|
||||
|
||||
// redraw Items if needed
|
||||
(function() {
|
||||
this._redrawItems.bind(this)(forceRestack, lastIsVisible, margin, range)
|
||||
}).bind(this),
|
||||
|
||||
// update subgroups
|
||||
this._updateSubgroupsSizes.bind(this),
|
||||
|
||||
// recalculate the height of the group
|
||||
(function() {
|
||||
height = this._calculateHeight.bind(this)(margin);
|
||||
}).bind(this),
|
||||
|
||||
// calculate actual size and position again
|
||||
this._calculateGroupSizeAndPosition.bind(this),
|
||||
|
||||
// check if resized
|
||||
(function() {
|
||||
resized = this._didResize.bind(this)(resized, height)
|
||||
}).bind(this),
|
||||
|
||||
// apply group height
|
||||
(function() {
|
||||
this._applyGroupHeight.bind(this)(height)
|
||||
}).bind(this),
|
||||
|
||||
// update vertical position of items after they are re-stacked and the height of the group is calculated
|
||||
(function() {
|
||||
this._updateItemsVerticalPosition.bind(this)(margin)
|
||||
}).bind(this),
|
||||
|
||||
function() {
|
||||
if (!this.isVisible && this.height) {
|
||||
resized = false;
|
||||
}
|
||||
return resized
|
||||
}
|
||||
]
|
||||
|
||||
if (returnQueue) {
|
||||
return queue;
|
||||
} else {
|
||||
var result;
|
||||
queue.forEach(function (fn) {
|
||||
result = fn();
|
||||
});
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* recalculate the height of the subgroups
|
||||
*
|
||||
* @param {{item: vis.Item}} margin
|
||||
* @private
|
||||
*/
|
||||
Group.prototype._updateSubGroupHeights = function (margin) {
|
||||
if (Object.keys(this.subgroups).length > 0) {
|
||||
var me = this;
|
||||
|
||||
this.resetSubgroups();
|
||||
|
||||
util.forEach(this.visibleItems, function (item) {
|
||||
if (item.data.subgroup !== undefined) {
|
||||
me.subgroups[item.data.subgroup].height = Math.max(me.subgroups[item.data.subgroup].height, item.height + margin.item.vertical);
|
||||
me.subgroups[item.data.subgroup].visible = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* check if group is visible
|
||||
*
|
||||
* @param {vis.Range} range
|
||||
* @param {{axis: vis.DataAxis}} margin
|
||||
* @returns {boolean} is visible
|
||||
* @private
|
||||
*/
|
||||
Group.prototype._isGroupVisible = function (range, margin) {
|
||||
return (this.top <= range.body.domProps.centerContainer.height - range.body.domProps.scrollTop + margin.axis)
|
||||
&& (this.top + this.height + margin.axis >= - range.body.domProps.scrollTop);
|
||||
};
|
||||
|
||||
/**
|
||||
* recalculate the height of the group
|
||||
* @param {{item: {horizontal: number, vertical: number}, axis: number}} margin
|
||||
* @returns {number} Returns the height
|
||||
* @private
|
||||
*/
|
||||
Group.prototype._calculateHeight = function (margin) {
|
||||
// recalculate the height of the group
|
||||
var height;
|
||||
var itemsInRange = this.visibleItems;
|
||||
if (itemsInRange.length > 0) {
|
||||
var min = itemsInRange[0].top;
|
||||
var max = itemsInRange[0].top + itemsInRange[0].height;
|
||||
util.forEach(itemsInRange, function (item) {
|
||||
min = Math.min(min, item.top);
|
||||
max = Math.max(max, (item.top + item.height));
|
||||
});
|
||||
if (min > margin.axis) {
|
||||
// there is an empty gap between the lowest item and the axis
|
||||
var offset = min - margin.axis;
|
||||
max -= offset;
|
||||
util.forEach(itemsInRange, function (item) {
|
||||
item.top -= offset;
|
||||
});
|
||||
}
|
||||
height = max + margin.item.vertical / 2;
|
||||
}
|
||||
else {
|
||||
height = 0;
|
||||
}
|
||||
height = Math.max(height, this.props.label.height);
|
||||
|
||||
return height;
|
||||
};
|
||||
|
||||
/**
|
||||
* Show this group: attach to the DOM
|
||||
*/
|
||||
Group.prototype.show = function() {
|
||||
if (!this.dom.label.parentNode) {
|
||||
this.itemSet.dom.labelSet.appendChild(this.dom.label);
|
||||
}
|
||||
|
||||
if (!this.dom.foreground.parentNode) {
|
||||
this.itemSet.dom.foreground.appendChild(this.dom.foreground);
|
||||
}
|
||||
|
||||
if (!this.dom.background.parentNode) {
|
||||
this.itemSet.dom.background.appendChild(this.dom.background);
|
||||
}
|
||||
|
||||
if (!this.dom.axis.parentNode) {
|
||||
this.itemSet.dom.axis.appendChild(this.dom.axis);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide this group: remove from the DOM
|
||||
*/
|
||||
Group.prototype.hide = function() {
|
||||
var label = this.dom.label;
|
||||
if (label.parentNode) {
|
||||
label.parentNode.removeChild(label);
|
||||
}
|
||||
|
||||
var foreground = this.dom.foreground;
|
||||
if (foreground.parentNode) {
|
||||
foreground.parentNode.removeChild(foreground);
|
||||
}
|
||||
|
||||
var background = this.dom.background;
|
||||
if (background.parentNode) {
|
||||
background.parentNode.removeChild(background);
|
||||
}
|
||||
|
||||
var axis = this.dom.axis;
|
||||
if (axis.parentNode) {
|
||||
axis.parentNode.removeChild(axis);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add an item to the group
|
||||
* @param {Item} item
|
||||
*/
|
||||
Group.prototype.add = function(item) {
|
||||
this.items[item.id] = item;
|
||||
item.setParent(this);
|
||||
this.stackDirty = true;
|
||||
// add to
|
||||
if (item.data.subgroup !== undefined) {
|
||||
this._addToSubgroup(item);
|
||||
this.orderSubgroups();
|
||||
}
|
||||
|
||||
if (this.visibleItems.indexOf(item) == -1) {
|
||||
var range = this.itemSet.body.range; // TODO: not nice accessing the range like this
|
||||
this._checkIfVisible(item, this.visibleItems, range);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Group.prototype._addToSubgroup = function(item, subgroupId) {
|
||||
subgroupId = subgroupId || item.data.subgroup;
|
||||
if (subgroupId != undefined && this.subgroups[subgroupId] === undefined) {
|
||||
this.subgroups[subgroupId] = {
|
||||
height:0,
|
||||
top: 0,
|
||||
start: item.data.start,
|
||||
end: item.data.end || item.data.start,
|
||||
visible: false,
|
||||
index:this.subgroupIndex,
|
||||
items: [],
|
||||
stack: this.subgroupStackAll || this.subgroupStack[subgroupId] || false
|
||||
};
|
||||
this.subgroupIndex++;
|
||||
}
|
||||
|
||||
|
||||
if (new Date(item.data.start) < new Date(this.subgroups[subgroupId].start)) {
|
||||
this.subgroups[subgroupId].start = item.data.start;
|
||||
}
|
||||
|
||||
var itemEnd = item.data.end || item.data.start;
|
||||
if (new Date(itemEnd) > new Date(this.subgroups[subgroupId].end)) {
|
||||
this.subgroups[subgroupId].end = itemEnd;
|
||||
}
|
||||
|
||||
this.subgroups[subgroupId].items.push(item);
|
||||
|
||||
};
|
||||
|
||||
Group.prototype._updateSubgroupsSizes = function () {
|
||||
var me = this;
|
||||
if (me.subgroups) {
|
||||
for (var subgroup in me.subgroups) {
|
||||
var initialEnd = me.subgroups[subgroup].items[0].data.end || me.subgroups[subgroup].items[0].data.start;
|
||||
var newStart = me.subgroups[subgroup].items[0].data.start;
|
||||
var newEnd = initialEnd - 1;
|
||||
|
||||
me.subgroups[subgroup].items.forEach(function(item) {
|
||||
if (new Date(item.data.start) < new Date(newStart)) {
|
||||
newStart = item.data.start;
|
||||
}
|
||||
|
||||
var itemEnd = item.data.end || item.data.start;
|
||||
if (new Date(itemEnd) > new Date(newEnd)) {
|
||||
newEnd = itemEnd;
|
||||
}
|
||||
})
|
||||
|
||||
me.subgroups[subgroup].start = newStart;
|
||||
me.subgroups[subgroup].end = new Date(newEnd - 1) // -1 to compensate for colliding end to start subgroups;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Group.prototype.orderSubgroups = function() {
|
||||
if (this.subgroupOrderer !== undefined) {
|
||||
var sortArray = [];
|
||||
var subgroup;
|
||||
if (typeof this.subgroupOrderer == 'string') {
|
||||
for (subgroup in this.subgroups) {
|
||||
sortArray.push({subgroup: subgroup, sortField: this.subgroups[subgroup].items[0].data[this.subgroupOrderer]})
|
||||
}
|
||||
sortArray.sort(function (a, b) {
|
||||
return a.sortField - b.sortField;
|
||||
})
|
||||
}
|
||||
else if (typeof this.subgroupOrderer == 'function') {
|
||||
for (subgroup in this.subgroups) {
|
||||
sortArray.push(this.subgroups[subgroup].items[0].data);
|
||||
}
|
||||
sortArray.sort(this.subgroupOrderer);
|
||||
}
|
||||
|
||||
if (sortArray.length > 0) {
|
||||
for (var i = 0; i < sortArray.length; i++) {
|
||||
this.subgroups[sortArray[i].subgroup].index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Group.prototype.resetSubgroups = function() {
|
||||
for (var subgroup in this.subgroups) {
|
||||
if (this.subgroups.hasOwnProperty(subgroup)) {
|
||||
this.subgroups[subgroup].visible = false;
|
||||
this.subgroups[subgroup].height = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove an item from the group
|
||||
* @param {Item} item
|
||||
*/
|
||||
Group.prototype.remove = function(item) {
|
||||
delete this.items[item.id];
|
||||
item.setParent(null);
|
||||
this.stackDirty = true;
|
||||
|
||||
// remove from visible items
|
||||
var index = this.visibleItems.indexOf(item);
|
||||
if (index != -1) this.visibleItems.splice(index, 1);
|
||||
|
||||
if(item.data.subgroup !== undefined){
|
||||
this._removeFromSubgroup(item);
|
||||
this.orderSubgroups();
|
||||
}
|
||||
};
|
||||
|
||||
Group.prototype._removeFromSubgroup = function(item, subgroupId) {
|
||||
subgroupId = subgroupId || item.data.subgroup;
|
||||
if (subgroupId != undefined) {
|
||||
var subgroup = this.subgroups[subgroupId];
|
||||
if (subgroup){
|
||||
var itemIndex = subgroup.items.indexOf(item);
|
||||
// Check the item is actually in this subgroup. How should items not in the group be handled?
|
||||
if (itemIndex >= 0) {
|
||||
subgroup.items.splice(itemIndex,1);
|
||||
if (!subgroup.items.length){
|
||||
delete this.subgroups[subgroupId];
|
||||
} else {
|
||||
this._updateSubgroupsSizes();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove an item from the corresponding DataSet
|
||||
* @param {Item} item
|
||||
*/
|
||||
Group.prototype.removeFromDataSet = function(item) {
|
||||
this.itemSet.removeItem(item.id);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Reorder the items
|
||||
*/
|
||||
Group.prototype.order = function() {
|
||||
var array = util.toArray(this.items);
|
||||
var startArray = [];
|
||||
var endArray = [];
|
||||
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
if (array[i].data.end !== undefined) {
|
||||
endArray.push(array[i]);
|
||||
}
|
||||
startArray.push(array[i]);
|
||||
}
|
||||
this.orderedItems = {
|
||||
byStart: startArray,
|
||||
byEnd: endArray
|
||||
};
|
||||
|
||||
stack.orderByStart(this.orderedItems.byStart);
|
||||
stack.orderByEnd(this.orderedItems.byEnd);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Update the visible items
|
||||
* @param {{byStart: Item[], byEnd: Item[]}} orderedItems All items ordered by start date and by end date
|
||||
* @param {Item[]} oldVisibleItems The previously visible items.
|
||||
* @param {{start: number, end: number}} range Visible range
|
||||
* @return {Item[]} visibleItems The new visible items.
|
||||
* @private
|
||||
*/
|
||||
Group.prototype._updateItemsInRange = function(orderedItems, oldVisibleItems, range) {
|
||||
var visibleItems = [];
|
||||
var visibleItemsLookup = {}; // we keep this to quickly look up if an item already exists in the list without using indexOf on visibleItems
|
||||
|
||||
var interval = (range.end - range.start) / 4;
|
||||
var lowerBound = range.start - interval;
|
||||
var upperBound = range.end + interval;
|
||||
|
||||
// this function is used to do the binary search.
|
||||
var searchFunction = function (value) {
|
||||
if (value < lowerBound) {return -1;}
|
||||
else if (value <= upperBound) {return 0;}
|
||||
else {return 1;}
|
||||
};
|
||||
|
||||
// first check if the items that were in view previously are still in view.
|
||||
// IMPORTANT: this handles the case for the items with startdate before the window and enddate after the window!
|
||||
// also cleans up invisible items.
|
||||
if (oldVisibleItems.length > 0) {
|
||||
for (var i = 0; i < oldVisibleItems.length; i++) {
|
||||
this._checkIfVisibleWithReference(oldVisibleItems[i], visibleItems, visibleItemsLookup, range);
|
||||
}
|
||||
}
|
||||
|
||||
// we do a binary search for the items that have only start values.
|
||||
var initialPosByStart = util.binarySearchCustom(orderedItems.byStart, searchFunction, 'data','start');
|
||||
|
||||
// trace the visible items from the inital start pos both ways until an invisible item is found, we only look at the start values.
|
||||
this._traceVisible(initialPosByStart, orderedItems.byStart, visibleItems, visibleItemsLookup, function (item) {
|
||||
return (item.data.start < lowerBound || item.data.start > upperBound);
|
||||
});
|
||||
|
||||
// if the window has changed programmatically without overlapping the old window, the ranged items with start < lowerBound and end > upperbound are not shown.
|
||||
// We therefore have to brute force check all items in the byEnd list
|
||||
if (this.checkRangedItems == true) {
|
||||
this.checkRangedItems = false;
|
||||
for (i = 0; i < orderedItems.byEnd.length; i++) {
|
||||
this._checkIfVisibleWithReference(orderedItems.byEnd[i], visibleItems, visibleItemsLookup, range);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// we do a binary search for the items that have defined end times.
|
||||
var initialPosByEnd = util.binarySearchCustom(orderedItems.byEnd, searchFunction, 'data','end');
|
||||
|
||||
// trace the visible items from the inital start pos both ways until an invisible item is found, we only look at the end values.
|
||||
this._traceVisible(initialPosByEnd, orderedItems.byEnd, visibleItems, visibleItemsLookup, function (item) {
|
||||
return (item.data.end < lowerBound || item.data.end > upperBound);
|
||||
});
|
||||
}
|
||||
|
||||
var redrawQueue = {};
|
||||
var redrawQueueLength = 0;
|
||||
|
||||
for (i = 0; i < visibleItems.length; i++) {
|
||||
var item = visibleItems[i];
|
||||
if (!item.displayed) {
|
||||
var returnQueue = true;
|
||||
redrawQueue[i] = item.redraw(returnQueue);
|
||||
redrawQueueLength = redrawQueue[i].length;
|
||||
}
|
||||
}
|
||||
|
||||
var needRedraw = redrawQueueLength > 0;
|
||||
if (needRedraw) {
|
||||
// redraw all regular items
|
||||
for (var j = 0; j < redrawQueueLength; j++) {
|
||||
util.forEach(redrawQueue, function (fns) {
|
||||
fns[j]();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < visibleItems.length; i++) {
|
||||
visibleItems[i].repositionX();
|
||||
}
|
||||
return visibleItems;
|
||||
};
|
||||
|
||||
Group.prototype._traceVisible = function (initialPos, items, visibleItems, visibleItemsLookup, breakCondition) {
|
||||
if (initialPos != -1) {
|
||||
var i, item;
|
||||
for (i = initialPos; i >= 0; i--) {
|
||||
item = items[i];
|
||||
if (breakCondition(item)) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (visibleItemsLookup[item.id] === undefined) {
|
||||
visibleItemsLookup[item.id] = true;
|
||||
visibleItems.push(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = initialPos + 1; i < items.length; i++) {
|
||||
item = items[i];
|
||||
if (breakCondition(item)) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (visibleItemsLookup[item.id] === undefined) {
|
||||
visibleItemsLookup[item.id] = true;
|
||||
visibleItems.push(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* this function is very similar to the _checkIfInvisible() but it does not
|
||||
* return booleans, hides the item if it should not be seen and always adds to
|
||||
* the visibleItems.
|
||||
* this one is for brute forcing and hiding.
|
||||
*
|
||||
* @param {Item} item
|
||||
* @param {Array} visibleItems
|
||||
* @param {{start:number, end:number}} range
|
||||
* @private
|
||||
*/
|
||||
Group.prototype._checkIfVisible = function(item, visibleItems, range) {
|
||||
if (item.isVisible(range)) {
|
||||
if (!item.displayed) item.show();
|
||||
// reposition item horizontally
|
||||
item.repositionX();
|
||||
visibleItems.push(item);
|
||||
}
|
||||
else {
|
||||
if (item.displayed) item.hide();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* this function is very similar to the _checkIfInvisible() but it does not
|
||||
* return booleans, hides the item if it should not be seen and always adds to
|
||||
* the visibleItems.
|
||||
* this one is for brute forcing and hiding.
|
||||
*
|
||||
* @param {Item} item
|
||||
* @param {Array.<vis.Item>} visibleItems
|
||||
* @param {Object<number, boolean>} visibleItemsLookup
|
||||
* @param {{start:number, end:number}} range
|
||||
* @private
|
||||
*/
|
||||
Group.prototype._checkIfVisibleWithReference = function(item, visibleItems, visibleItemsLookup, range) {
|
||||
if (item.isVisible(range)) {
|
||||
if (visibleItemsLookup[item.id] === undefined) {
|
||||
visibleItemsLookup[item.id] = true;
|
||||
visibleItems.push(item);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (item.displayed) item.hide();
|
||||
}
|
||||
};
|
||||
|
||||
Group.prototype.changeSubgroup = function(item, oldSubgroup, newSubgroup) {
|
||||
this._removeFromSubgroup(item, oldSubgroup);
|
||||
this._addToSubgroup(item, newSubgroup);
|
||||
this.orderSubgroups();
|
||||
};
|
||||
|
||||
module.exports = Group;
|
||||
2384
node_modules/vis/lib/timeline/component/ItemSet.js
generated
vendored
Normal file
2384
node_modules/vis/lib/timeline/component/ItemSet.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
222
node_modules/vis/lib/timeline/component/Legend.js
generated
vendored
Normal file
222
node_modules/vis/lib/timeline/component/Legend.js
generated
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
var util = require('../../util');
|
||||
var DOMutil = require('../../DOMutil');
|
||||
var Component = require('./Component');
|
||||
|
||||
/**
|
||||
* Legend for Graph2d
|
||||
*
|
||||
* @param {vis.Graph2d.body} body
|
||||
* @param {vis.Graph2d.options} options
|
||||
* @param {number} side
|
||||
* @param {vis.LineGraph.options} linegraphOptions
|
||||
* @constructor Legend
|
||||
* @extends Component
|
||||
*/
|
||||
function Legend(body, options, side, linegraphOptions) {
|
||||
this.body = body;
|
||||
this.defaultOptions = {
|
||||
enabled: false,
|
||||
icons: true,
|
||||
iconSize: 20,
|
||||
iconSpacing: 6,
|
||||
left: {
|
||||
visible: true,
|
||||
position: 'top-left' // top/bottom - left,center,right
|
||||
},
|
||||
right: {
|
||||
visible: true,
|
||||
position: 'top-right' // top/bottom - left,center,right
|
||||
}
|
||||
};
|
||||
|
||||
this.side = side;
|
||||
this.options = util.extend({}, this.defaultOptions);
|
||||
this.linegraphOptions = linegraphOptions;
|
||||
|
||||
this.svgElements = {};
|
||||
this.dom = {};
|
||||
this.groups = {};
|
||||
this.amountOfGroups = 0;
|
||||
this._create();
|
||||
this.framework = {svg: this.svg, svgElements: this.svgElements, options: this.options, groups: this.groups};
|
||||
|
||||
this.setOptions(options);
|
||||
}
|
||||
|
||||
Legend.prototype = new Component();
|
||||
|
||||
Legend.prototype.clear = function() {
|
||||
this.groups = {};
|
||||
this.amountOfGroups = 0;
|
||||
};
|
||||
|
||||
Legend.prototype.addGroup = function(label, graphOptions) {
|
||||
|
||||
// Include a group only if the group option 'excludeFromLegend: false' is not set.
|
||||
if (graphOptions.options.excludeFromLegend != true) {
|
||||
if (!this.groups.hasOwnProperty(label)) {
|
||||
this.groups[label] = graphOptions;
|
||||
}
|
||||
this.amountOfGroups += 1;
|
||||
}
|
||||
};
|
||||
|
||||
Legend.prototype.updateGroup = function(label, graphOptions) {
|
||||
this.groups[label] = graphOptions;
|
||||
};
|
||||
|
||||
Legend.prototype.removeGroup = function(label) {
|
||||
if (this.groups.hasOwnProperty(label)) {
|
||||
delete this.groups[label];
|
||||
this.amountOfGroups -= 1;
|
||||
}
|
||||
};
|
||||
|
||||
Legend.prototype._create = function() {
|
||||
this.dom.frame = document.createElement('div');
|
||||
this.dom.frame.className = 'vis-legend';
|
||||
this.dom.frame.style.position = "absolute";
|
||||
this.dom.frame.style.top = "10px";
|
||||
this.dom.frame.style.display = "block";
|
||||
|
||||
this.dom.textArea = document.createElement('div');
|
||||
this.dom.textArea.className = 'vis-legend-text';
|
||||
this.dom.textArea.style.position = "relative";
|
||||
this.dom.textArea.style.top = "0px";
|
||||
|
||||
this.svg = document.createElementNS('http://www.w3.org/2000/svg',"svg");
|
||||
this.svg.style.position = 'absolute';
|
||||
this.svg.style.top = 0 +'px';
|
||||
this.svg.style.width = this.options.iconSize + 5 + 'px';
|
||||
this.svg.style.height = '100%';
|
||||
|
||||
this.dom.frame.appendChild(this.svg);
|
||||
this.dom.frame.appendChild(this.dom.textArea);
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide the component from the DOM
|
||||
*/
|
||||
Legend.prototype.hide = function() {
|
||||
// remove the frame containing the items
|
||||
if (this.dom.frame.parentNode) {
|
||||
this.dom.frame.parentNode.removeChild(this.dom.frame);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Show the component in the DOM (when not already visible).
|
||||
*/
|
||||
Legend.prototype.show = function() {
|
||||
// show frame containing the items
|
||||
if (!this.dom.frame.parentNode) {
|
||||
this.body.dom.center.appendChild(this.dom.frame);
|
||||
}
|
||||
};
|
||||
|
||||
Legend.prototype.setOptions = function(options) {
|
||||
var fields = ['enabled','orientation','icons','left','right'];
|
||||
util.selectiveDeepExtend(fields, this.options, options);
|
||||
};
|
||||
|
||||
Legend.prototype.redraw = function() {
|
||||
var activeGroups = 0;
|
||||
var groupArray = Object.keys(this.groups);
|
||||
groupArray.sort(function (a,b) {
|
||||
return (a < b ? -1 : 1);
|
||||
})
|
||||
|
||||
for (var i = 0; i < groupArray.length; i++) {
|
||||
var groupId = groupArray[i];
|
||||
if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) {
|
||||
activeGroups++;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options[this.side].visible == false || this.amountOfGroups == 0 || this.options.enabled == false || activeGroups == 0) {
|
||||
this.hide();
|
||||
}
|
||||
else {
|
||||
this.show();
|
||||
if (this.options[this.side].position == 'top-left' || this.options[this.side].position == 'bottom-left') {
|
||||
this.dom.frame.style.left = '4px';
|
||||
this.dom.frame.style.textAlign = "left";
|
||||
this.dom.textArea.style.textAlign = "left";
|
||||
this.dom.textArea.style.left = (this.options.iconSize + 15) + 'px';
|
||||
this.dom.textArea.style.right = '';
|
||||
this.svg.style.left = 0 +'px';
|
||||
this.svg.style.right = '';
|
||||
}
|
||||
else {
|
||||
this.dom.frame.style.right = '4px';
|
||||
this.dom.frame.style.textAlign = "right";
|
||||
this.dom.textArea.style.textAlign = "right";
|
||||
this.dom.textArea.style.right = (this.options.iconSize + 15) + 'px';
|
||||
this.dom.textArea.style.left = '';
|
||||
this.svg.style.right = 0 +'px';
|
||||
this.svg.style.left = '';
|
||||
}
|
||||
|
||||
if (this.options[this.side].position == 'top-left' || this.options[this.side].position == 'top-right') {
|
||||
this.dom.frame.style.top = 4 - Number(this.body.dom.center.style.top.replace("px","")) + 'px';
|
||||
this.dom.frame.style.bottom = '';
|
||||
}
|
||||
else {
|
||||
var scrollableHeight = this.body.domProps.center.height - this.body.domProps.centerContainer.height;
|
||||
this.dom.frame.style.bottom = 4 + scrollableHeight + Number(this.body.dom.center.style.top.replace("px","")) + 'px';
|
||||
this.dom.frame.style.top = '';
|
||||
}
|
||||
|
||||
if (this.options.icons == false) {
|
||||
this.dom.frame.style.width = this.dom.textArea.offsetWidth + 10 + 'px';
|
||||
this.dom.textArea.style.right = '';
|
||||
this.dom.textArea.style.left = '';
|
||||
this.svg.style.width = '0px';
|
||||
}
|
||||
else {
|
||||
this.dom.frame.style.width = this.options.iconSize + 15 + this.dom.textArea.offsetWidth + 10 + 'px'
|
||||
this.drawLegendIcons();
|
||||
}
|
||||
|
||||
var content = '';
|
||||
for (i = 0; i < groupArray.length; i++) {
|
||||
groupId = groupArray[i];
|
||||
if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) {
|
||||
content += this.groups[groupId].content + '<br />';
|
||||
}
|
||||
}
|
||||
this.dom.textArea.innerHTML = content;
|
||||
this.dom.textArea.style.lineHeight = ((0.75 * this.options.iconSize) + this.options.iconSpacing) + 'px';
|
||||
}
|
||||
};
|
||||
|
||||
Legend.prototype.drawLegendIcons = function() {
|
||||
if (this.dom.frame.parentNode) {
|
||||
var groupArray = Object.keys(this.groups);
|
||||
groupArray.sort(function (a,b) {
|
||||
return (a < b ? -1 : 1);
|
||||
});
|
||||
|
||||
// this resets the elements so the order is maintained
|
||||
DOMutil.resetElements(this.svgElements);
|
||||
|
||||
var padding = window.getComputedStyle(this.dom.frame).paddingTop;
|
||||
var iconOffset = Number(padding.replace('px',''));
|
||||
var x = iconOffset;
|
||||
var iconWidth = this.options.iconSize;
|
||||
var iconHeight = 0.75 * this.options.iconSize;
|
||||
var y = iconOffset + 0.5 * iconHeight + 3;
|
||||
|
||||
this.svg.style.width = iconWidth + 5 + iconOffset + 'px';
|
||||
|
||||
for (var i = 0; i < groupArray.length; i++) {
|
||||
var groupId = groupArray[i];
|
||||
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 + this.options.iconSpacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Legend;
|
||||
1103
node_modules/vis/lib/timeline/component/LineGraph.js
generated
vendored
Normal file
1103
node_modules/vis/lib/timeline/component/LineGraph.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
514
node_modules/vis/lib/timeline/component/TimeAxis.js
generated
vendored
Normal file
514
node_modules/vis/lib/timeline/component/TimeAxis.js
generated
vendored
Normal file
@@ -0,0 +1,514 @@
|
||||
var util = require('../../util');
|
||||
var Component = require('./Component');
|
||||
var TimeStep = require('../TimeStep');
|
||||
var DateUtil = require('../DateUtil');
|
||||
var moment = require('../../module/moment');
|
||||
|
||||
/**
|
||||
* A horizontal time axis
|
||||
* @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} body
|
||||
* @param {Object} [options] See TimeAxis.setOptions for the available
|
||||
* options.
|
||||
* @constructor TimeAxis
|
||||
* @extends Component
|
||||
*/
|
||||
function TimeAxis (body, options) {
|
||||
this.dom = {
|
||||
foreground: null,
|
||||
lines: [],
|
||||
majorTexts: [],
|
||||
minorTexts: [],
|
||||
redundant: {
|
||||
lines: [],
|
||||
majorTexts: [],
|
||||
minorTexts: []
|
||||
}
|
||||
};
|
||||
this.props = {
|
||||
range: {
|
||||
start: 0,
|
||||
end: 0,
|
||||
minimumStep: 0
|
||||
},
|
||||
lineTop: 0
|
||||
};
|
||||
|
||||
this.defaultOptions = {
|
||||
orientation: {
|
||||
axis: 'bottom'
|
||||
}, // axis orientation: 'top' or 'bottom'
|
||||
showMinorLabels: true,
|
||||
showMajorLabels: true,
|
||||
maxMinorChars: 7,
|
||||
format: TimeStep.FORMAT,
|
||||
moment: moment,
|
||||
timeAxis: null
|
||||
};
|
||||
this.options = util.extend({}, this.defaultOptions);
|
||||
|
||||
this.body = body;
|
||||
|
||||
// create the HTML DOM
|
||||
this._create();
|
||||
|
||||
this.setOptions(options);
|
||||
}
|
||||
|
||||
TimeAxis.prototype = new Component();
|
||||
|
||||
/**
|
||||
* Set options for the TimeAxis.
|
||||
* Parameters will be merged in current options.
|
||||
* @param {Object} options Available options:
|
||||
* {string} [orientation.axis]
|
||||
* {boolean} [showMinorLabels]
|
||||
* {boolean} [showMajorLabels]
|
||||
*/
|
||||
TimeAxis.prototype.setOptions = function(options) {
|
||||
if (options) {
|
||||
// copy all options that we know
|
||||
util.selectiveExtend([
|
||||
'showMinorLabels',
|
||||
'showMajorLabels',
|
||||
'maxMinorChars',
|
||||
'hiddenDates',
|
||||
'timeAxis',
|
||||
'moment',
|
||||
'rtl'
|
||||
], this.options, options);
|
||||
|
||||
// deep copy the format options
|
||||
util.selectiveDeepExtend(['format'], this.options, options);
|
||||
|
||||
if ('orientation' in options) {
|
||||
if (typeof options.orientation === 'string') {
|
||||
this.options.orientation.axis = options.orientation;
|
||||
}
|
||||
else if (typeof options.orientation === 'object' && 'axis' in options.orientation) {
|
||||
this.options.orientation.axis = options.orientation.axis;
|
||||
}
|
||||
}
|
||||
|
||||
// apply locale to moment.js
|
||||
// TODO: not so nice, this is applied globally to moment.js
|
||||
if ('locale' in options) {
|
||||
if (typeof moment.locale === 'function') {
|
||||
// moment.js 2.8.1+
|
||||
moment.locale(options.locale);
|
||||
}
|
||||
else {
|
||||
moment.lang(options.locale);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the HTML DOM for the TimeAxis
|
||||
*/
|
||||
TimeAxis.prototype._create = function() {
|
||||
this.dom.foreground = document.createElement('div');
|
||||
this.dom.background = document.createElement('div');
|
||||
|
||||
this.dom.foreground.className = 'vis-time-axis vis-foreground';
|
||||
this.dom.background.className = 'vis-time-axis vis-background';
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroy the TimeAxis
|
||||
*/
|
||||
TimeAxis.prototype.destroy = function() {
|
||||
// remove from DOM
|
||||
if (this.dom.foreground.parentNode) {
|
||||
this.dom.foreground.parentNode.removeChild(this.dom.foreground);
|
||||
}
|
||||
if (this.dom.background.parentNode) {
|
||||
this.dom.background.parentNode.removeChild(this.dom.background);
|
||||
}
|
||||
|
||||
this.body = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Repaint the component
|
||||
* @return {boolean} Returns true if the component is resized
|
||||
*/
|
||||
TimeAxis.prototype.redraw = function () {
|
||||
var props = this.props;
|
||||
var foreground = this.dom.foreground;
|
||||
var background = this.dom.background;
|
||||
|
||||
// determine the correct parent DOM element (depending on option orientation)
|
||||
var parent = (this.options.orientation.axis == 'top') ? this.body.dom.top : this.body.dom.bottom;
|
||||
var parentChanged = (foreground.parentNode !== parent);
|
||||
|
||||
// calculate character width and height
|
||||
this._calculateCharSize();
|
||||
|
||||
// TODO: recalculate sizes only needed when parent is resized or options is changed
|
||||
var showMinorLabels = this.options.showMinorLabels && this.options.orientation.axis !== 'none';
|
||||
var showMajorLabels = this.options.showMajorLabels && this.options.orientation.axis !== 'none';
|
||||
|
||||
// determine the width and height of the elemens for the axis
|
||||
props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0;
|
||||
props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0;
|
||||
props.height = props.minorLabelHeight + props.majorLabelHeight;
|
||||
props.width = foreground.offsetWidth;
|
||||
|
||||
props.minorLineHeight = this.body.domProps.root.height - props.majorLabelHeight -
|
||||
(this.options.orientation.axis == 'top' ? this.body.domProps.bottom.height : this.body.domProps.top.height);
|
||||
props.minorLineWidth = 1; // TODO: really calculate width
|
||||
props.majorLineHeight = props.minorLineHeight + props.majorLabelHeight;
|
||||
props.majorLineWidth = 1; // TODO: really calculate width
|
||||
|
||||
// take foreground and background offline while updating (is almost twice as fast)
|
||||
var foregroundNextSibling = foreground.nextSibling;
|
||||
var backgroundNextSibling = background.nextSibling;
|
||||
foreground.parentNode && foreground.parentNode.removeChild(foreground);
|
||||
background.parentNode && background.parentNode.removeChild(background);
|
||||
|
||||
foreground.style.height = this.props.height + 'px';
|
||||
|
||||
this._repaintLabels();
|
||||
|
||||
// put DOM online again (at the same place)
|
||||
if (foregroundNextSibling) {
|
||||
parent.insertBefore(foreground, foregroundNextSibling);
|
||||
}
|
||||
else {
|
||||
parent.appendChild(foreground)
|
||||
}
|
||||
if (backgroundNextSibling) {
|
||||
this.body.dom.backgroundVertical.insertBefore(background, backgroundNextSibling);
|
||||
}
|
||||
else {
|
||||
this.body.dom.backgroundVertical.appendChild(background)
|
||||
}
|
||||
return this._isResized() || parentChanged;
|
||||
};
|
||||
|
||||
/**
|
||||
* Repaint major and minor text labels and vertical grid lines
|
||||
* @private
|
||||
*/
|
||||
TimeAxis.prototype._repaintLabels = function () {
|
||||
var orientation = this.options.orientation.axis;
|
||||
|
||||
// calculate range and step (step such that we have space for 7 characters per label)
|
||||
var start = util.convert(this.body.range.start, 'Number');
|
||||
var end = util.convert(this.body.range.end, 'Number');
|
||||
var timeLabelsize = this.body.util.toTime((this.props.minorCharWidth || 10) * this.options.maxMinorChars).valueOf();
|
||||
var minimumStep = timeLabelsize - DateUtil.getHiddenDurationBefore(this.options.moment, this.body.hiddenDates, this.body.range, timeLabelsize);
|
||||
minimumStep -= this.body.util.toTime(0).valueOf();
|
||||
|
||||
var step = new TimeStep(new Date(start), new Date(end), minimumStep, this.body.hiddenDates, this.options);
|
||||
step.setMoment(this.options.moment);
|
||||
if (this.options.format) {
|
||||
step.setFormat(this.options.format);
|
||||
}
|
||||
if (this.options.timeAxis) {
|
||||
step.setScale(this.options.timeAxis);
|
||||
}
|
||||
this.step = step;
|
||||
|
||||
// Move all DOM elements to a "redundant" list, where they
|
||||
// can be picked for re-use, and clear the lists with lines and texts.
|
||||
// At the end of the function _repaintLabels, left over elements will be cleaned up
|
||||
var dom = this.dom;
|
||||
dom.redundant.lines = dom.lines;
|
||||
dom.redundant.majorTexts = dom.majorTexts;
|
||||
dom.redundant.minorTexts = dom.minorTexts;
|
||||
dom.lines = [];
|
||||
dom.majorTexts = [];
|
||||
dom.minorTexts = [];
|
||||
|
||||
var current; // eslint-disable-line no-unused-vars
|
||||
var next;
|
||||
var x;
|
||||
var xNext;
|
||||
var isMajor;
|
||||
var nextIsMajor; // eslint-disable-line no-unused-vars
|
||||
var showMinorGrid;
|
||||
var width = 0, prevWidth;
|
||||
var line;
|
||||
var labelMinor;
|
||||
var xFirstMajorLabel = undefined;
|
||||
var count = 0;
|
||||
const MAX = 1000;
|
||||
var className;
|
||||
|
||||
step.start();
|
||||
next = step.getCurrent();
|
||||
xNext = this.body.util.toScreen(next);
|
||||
while (step.hasNext() && count < MAX) {
|
||||
count++;
|
||||
|
||||
isMajor = step.isMajor();
|
||||
className = step.getClassName();
|
||||
labelMinor = step.getLabelMinor();
|
||||
|
||||
current = next;
|
||||
x = xNext;
|
||||
|
||||
step.next();
|
||||
next = step.getCurrent();
|
||||
nextIsMajor = step.isMajor();
|
||||
xNext = this.body.util.toScreen(next);
|
||||
|
||||
prevWidth = width;
|
||||
width = xNext - x;
|
||||
switch (step.scale) {
|
||||
case 'week': showMinorGrid = true; break;
|
||||
default: showMinorGrid = (width >= prevWidth * 0.4); break; // prevent displaying of the 31th of the month on a scale of 5 days
|
||||
}
|
||||
|
||||
if (this.options.showMinorLabels && showMinorGrid) {
|
||||
var label = this._repaintMinorText(x, labelMinor, orientation, className);
|
||||
label.style.width = width + 'px'; // set width to prevent overflow
|
||||
}
|
||||
|
||||
if (isMajor && this.options.showMajorLabels) {
|
||||
if (x > 0) {
|
||||
if (xFirstMajorLabel == undefined) {
|
||||
xFirstMajorLabel = x;
|
||||
}
|
||||
label = this._repaintMajorText(x, step.getLabelMajor(), orientation, className);
|
||||
}
|
||||
line = this._repaintMajorLine(x, width, orientation, className);
|
||||
}
|
||||
else { // minor line
|
||||
if (showMinorGrid) {
|
||||
line = this._repaintMinorLine(x, width, orientation, className);
|
||||
}
|
||||
else {
|
||||
if (line) {
|
||||
// adjust the width of the previous grid
|
||||
line.style.width = (parseInt (line.style.width) + width) + 'px';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count === MAX && !warnedForOverflow) {
|
||||
console.warn(`Something is wrong with the Timeline scale. Limited drawing of grid lines to ${MAX} lines.`);
|
||||
warnedForOverflow = true;
|
||||
}
|
||||
|
||||
// create a major label on the left when needed
|
||||
if (this.options.showMajorLabels) {
|
||||
var leftTime = this.body.util.toTime(0),
|
||||
leftText = step.getLabelMajor(leftTime),
|
||||
widthText = leftText.length * (this.props.majorCharWidth || 10) + 10; // upper bound estimation
|
||||
|
||||
if (xFirstMajorLabel == undefined || widthText < xFirstMajorLabel) {
|
||||
this._repaintMajorText(0, leftText, orientation, className);
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup leftover DOM elements from the redundant list
|
||||
util.forEach(this.dom.redundant, function (arr) {
|
||||
while (arr.length) {
|
||||
var elem = arr.pop();
|
||||
if (elem && elem.parentNode) {
|
||||
elem.parentNode.removeChild(elem);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a minor label for the axis at position x
|
||||
* @param {number} x
|
||||
* @param {string} text
|
||||
* @param {string} orientation "top" or "bottom" (default)
|
||||
* @param {string} className
|
||||
* @return {Element} Returns the HTML element of the created label
|
||||
* @private
|
||||
*/
|
||||
TimeAxis.prototype._repaintMinorText = function (x, text, orientation, className) {
|
||||
// reuse redundant label
|
||||
var label = this.dom.redundant.minorTexts.shift();
|
||||
|
||||
if (!label) {
|
||||
// create new label
|
||||
var content = document.createTextNode('');
|
||||
label = document.createElement('div');
|
||||
label.appendChild(content);
|
||||
this.dom.foreground.appendChild(label);
|
||||
}
|
||||
this.dom.minorTexts.push(label);
|
||||
label.innerHTML = text;
|
||||
|
||||
label.style.top = (orientation == 'top') ? (this.props.majorLabelHeight + 'px') : '0';
|
||||
|
||||
if (this.options.rtl) {
|
||||
label.style.left = "";
|
||||
label.style.right = x + 'px';
|
||||
} else {
|
||||
label.style.left = x + 'px';
|
||||
}
|
||||
label.className = 'vis-text vis-minor ' + className;
|
||||
//label.title = title; // TODO: this is a heavy operation
|
||||
|
||||
return label;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a Major label for the axis at position x
|
||||
* @param {number} x
|
||||
* @param {string} text
|
||||
* @param {string} orientation "top" or "bottom" (default)
|
||||
* @param {string} className
|
||||
* @return {Element} Returns the HTML element of the created label
|
||||
* @private
|
||||
*/
|
||||
TimeAxis.prototype._repaintMajorText = function (x, text, orientation, className) {
|
||||
// reuse redundant label
|
||||
var label = this.dom.redundant.majorTexts.shift();
|
||||
|
||||
if (!label) {
|
||||
// create label
|
||||
var content = document.createElement('div');
|
||||
label = document.createElement('div');
|
||||
label.appendChild(content);
|
||||
this.dom.foreground.appendChild(label);
|
||||
}
|
||||
|
||||
label.childNodes[0].innerHTML = text;
|
||||
label.className = 'vis-text vis-major ' + className;
|
||||
//label.title = title; // TODO: this is a heavy operation
|
||||
|
||||
label.style.top = (orientation == 'top') ? '0' : (this.props.minorLabelHeight + 'px');
|
||||
if (this.options.rtl) {
|
||||
label.style.left = "";
|
||||
label.style.right = x + 'px';
|
||||
} else {
|
||||
label.style.left = x + 'px';
|
||||
}
|
||||
|
||||
this.dom.majorTexts.push(label);
|
||||
return label;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a minor line for the axis at position x
|
||||
* @param {number} x
|
||||
* @param {number} width
|
||||
* @param {string} orientation "top" or "bottom" (default)
|
||||
* @param {string} className
|
||||
* @return {Element} Returns the created line
|
||||
* @private
|
||||
*/
|
||||
TimeAxis.prototype._repaintMinorLine = function (x, width, orientation, className) {
|
||||
// reuse redundant line
|
||||
var line = this.dom.redundant.lines.shift();
|
||||
if (!line) {
|
||||
// create vertical line
|
||||
line = document.createElement('div');
|
||||
this.dom.background.appendChild(line);
|
||||
}
|
||||
this.dom.lines.push(line);
|
||||
|
||||
var props = this.props;
|
||||
if (orientation == 'top') {
|
||||
line.style.top = props.majorLabelHeight + 'px';
|
||||
}
|
||||
else {
|
||||
line.style.top = this.body.domProps.top.height + 'px';
|
||||
}
|
||||
line.style.height = props.minorLineHeight + 'px';
|
||||
if (this.options.rtl) {
|
||||
line.style.left = "";
|
||||
line.style.right = (x - props.minorLineWidth / 2) + 'px';
|
||||
line.className = 'vis-grid vis-vertical-rtl vis-minor ' + className;
|
||||
} else {
|
||||
line.style.left = (x - props.minorLineWidth / 2) + 'px';
|
||||
line.className = 'vis-grid vis-vertical vis-minor ' + className;
|
||||
}
|
||||
line.style.width = width + 'px';
|
||||
|
||||
|
||||
|
||||
return line;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a Major line for the axis at position x
|
||||
* @param {number} x
|
||||
* @param {number} width
|
||||
* @param {string} orientation "top" or "bottom" (default)
|
||||
* @param {string} className
|
||||
* @return {Element} Returns the created line
|
||||
* @private
|
||||
*/
|
||||
TimeAxis.prototype._repaintMajorLine = function (x, width, orientation, className) {
|
||||
// reuse redundant line
|
||||
var line = this.dom.redundant.lines.shift();
|
||||
if (!line) {
|
||||
// create vertical line
|
||||
line = document.createElement('div');
|
||||
this.dom.background.appendChild(line);
|
||||
}
|
||||
this.dom.lines.push(line);
|
||||
|
||||
var props = this.props;
|
||||
if (orientation == 'top') {
|
||||
line.style.top = '0';
|
||||
}
|
||||
else {
|
||||
line.style.top = this.body.domProps.top.height + 'px';
|
||||
}
|
||||
|
||||
if (this.options.rtl) {
|
||||
line.style.left = "";
|
||||
line.style.right = (x - props.majorLineWidth / 2) + 'px';
|
||||
line.className = 'vis-grid vis-vertical-rtl vis-major ' + className;
|
||||
} else {
|
||||
line.style.left = (x - props.majorLineWidth / 2) + 'px';
|
||||
line.className = 'vis-grid vis-vertical vis-major ' + className;
|
||||
}
|
||||
|
||||
line.style.height = props.majorLineHeight + 'px';
|
||||
line.style.width = width + 'px';
|
||||
|
||||
return line;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine the size of text on the axis (both major and minor axis).
|
||||
* The size is calculated only once and then cached in this.props.
|
||||
* @private
|
||||
*/
|
||||
TimeAxis.prototype._calculateCharSize = function () {
|
||||
// Note: We calculate char size with every redraw. Size may change, for
|
||||
// example when any of the timelines parents had display:none for example.
|
||||
|
||||
// determine the char width and height on the minor axis
|
||||
if (!this.dom.measureCharMinor) {
|
||||
this.dom.measureCharMinor = document.createElement('DIV');
|
||||
this.dom.measureCharMinor.className = 'vis-text vis-minor vis-measure';
|
||||
this.dom.measureCharMinor.style.position = 'absolute';
|
||||
|
||||
this.dom.measureCharMinor.appendChild(document.createTextNode('0'));
|
||||
this.dom.foreground.appendChild(this.dom.measureCharMinor);
|
||||
}
|
||||
this.props.minorCharHeight = this.dom.measureCharMinor.clientHeight;
|
||||
this.props.minorCharWidth = this.dom.measureCharMinor.clientWidth;
|
||||
|
||||
// determine the char width and height on the major axis
|
||||
if (!this.dom.measureCharMajor) {
|
||||
this.dom.measureCharMajor = document.createElement('DIV');
|
||||
this.dom.measureCharMajor.className = 'vis-text vis-major vis-measure';
|
||||
this.dom.measureCharMajor.style.position = 'absolute';
|
||||
|
||||
this.dom.measureCharMajor.appendChild(document.createTextNode('0'));
|
||||
this.dom.foreground.appendChild(this.dom.measureCharMajor);
|
||||
}
|
||||
this.props.majorCharHeight = this.dom.measureCharMajor.clientHeight;
|
||||
this.props.majorCharWidth = this.dom.measureCharMajor.clientWidth;
|
||||
};
|
||||
|
||||
|
||||
var warnedForOverflow = false;
|
||||
|
||||
module.exports = TimeAxis;
|
||||
33
node_modules/vis/lib/timeline/component/css/animation.css
generated
vendored
Normal file
33
node_modules/vis/lib/timeline/component/css/animation.css
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
.vis-timeline {
|
||||
/*
|
||||
-webkit-transition: height .4s ease-in-out;
|
||||
transition: height .4s ease-in-out;
|
||||
*/
|
||||
}
|
||||
|
||||
.vis-panel {
|
||||
/*
|
||||
-webkit-transition: height .4s ease-in-out, top .4s ease-in-out;
|
||||
transition: height .4s ease-in-out, top .4s ease-in-out;
|
||||
*/
|
||||
}
|
||||
|
||||
.vis-axis {
|
||||
/*
|
||||
-webkit-transition: top .4s ease-in-out;
|
||||
transition: top .4s ease-in-out;
|
||||
*/
|
||||
}
|
||||
|
||||
/* TODO: get animation working nicely
|
||||
|
||||
.vis-item {
|
||||
-webkit-transition: top .4s ease-in-out;
|
||||
transition: top .4s ease-in-out;
|
||||
}
|
||||
|
||||
.vis-item.line {
|
||||
-webkit-transition: height .4s ease-in-out, top .4s ease-in-out;
|
||||
transition: height .4s ease-in-out, top .4s ease-in-out;
|
||||
}
|
||||
/**/
|
||||
29
node_modules/vis/lib/timeline/component/css/currenttime.css
generated
vendored
Normal file
29
node_modules/vis/lib/timeline/component/css/currenttime.css
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
.vis-current-time {
|
||||
background-color: #FF7F6E;
|
||||
width: 2px;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.vis-rolling-mode-btn {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
right: 20px;
|
||||
border-radius: 50%;
|
||||
font-size: 28px;
|
||||
cursor: pointer;
|
||||
opacity: 0.8;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
background: #3876c2;
|
||||
}
|
||||
.vis-rolling-mode-btn:before {
|
||||
content: "\26F6";
|
||||
}
|
||||
|
||||
.vis-rolling-mode-btn:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
6
node_modules/vis/lib/timeline/component/css/customtime.css
generated
vendored
Normal file
6
node_modules/vis/lib/timeline/component/css/customtime.css
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
.vis-custom-time {
|
||||
background-color: #6E94FF;
|
||||
width: 2px;
|
||||
cursor: move;
|
||||
z-index: 1;
|
||||
}
|
||||
103
node_modules/vis/lib/timeline/component/css/dataaxis.css
generated
vendored
Normal file
103
node_modules/vis/lib/timeline/component/css/dataaxis.css
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
|
||||
.vis-panel.vis-background.vis-horizontal .vis-grid.vis-horizontal {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
|
||||
.vis-panel.vis-background.vis-horizontal .vis-grid.vis-minor {
|
||||
border-color: #e5e5e5;
|
||||
}
|
||||
|
||||
.vis-panel.vis-background.vis-horizontal .vis-grid.vis-major {
|
||||
border-color: #bfbfbf;
|
||||
}
|
||||
|
||||
|
||||
.vis-data-axis .vis-y-axis.vis-major {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
color: #4d4d4d;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.vis-data-axis .vis-y-axis.vis-major.vis-measure {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
visibility: hidden;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
|
||||
.vis-data-axis .vis-y-axis.vis-minor {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
color: #bebebe;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.vis-data-axis .vis-y-axis.vis-minor.vis-measure {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
visibility: hidden;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.vis-data-axis .vis-y-axis.vis-title {
|
||||
position: absolute;
|
||||
color: #4d4d4d;
|
||||
white-space: nowrap;
|
||||
bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.vis-data-axis .vis-y-axis.vis-title.vis-measure {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
visibility: hidden;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.vis-data-axis .vis-y-axis.vis-title.vis-left {
|
||||
bottom: 0;
|
||||
-webkit-transform-origin: left top;
|
||||
-moz-transform-origin: left top;
|
||||
-ms-transform-origin: left top;
|
||||
-o-transform-origin: left top;
|
||||
transform-origin: left bottom;
|
||||
-webkit-transform: rotate(-90deg);
|
||||
-moz-transform: rotate(-90deg);
|
||||
-ms-transform: rotate(-90deg);
|
||||
-o-transform: rotate(-90deg);
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.vis-data-axis .vis-y-axis.vis-title.vis-right {
|
||||
bottom: 0;
|
||||
-webkit-transform-origin: right bottom;
|
||||
-moz-transform-origin: right bottom;
|
||||
-ms-transform-origin: right bottom;
|
||||
-o-transform-origin: right bottom;
|
||||
transform-origin: right bottom;
|
||||
-webkit-transform: rotate(90deg);
|
||||
-moz-transform: rotate(90deg);
|
||||
-ms-transform: rotate(90deg);
|
||||
-o-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.vis-legend {
|
||||
background-color: rgba(247, 252, 255, 0.65);
|
||||
padding: 5px;
|
||||
border: 1px solid #b3b3b3;
|
||||
box-shadow: 2px 2px 10px rgba(154, 154, 154, 0.55);
|
||||
}
|
||||
|
||||
.vis-legend-text {
|
||||
/*font-size: 10px;*/
|
||||
white-space: nowrap;
|
||||
display: inline-block
|
||||
}
|
||||
195
node_modules/vis/lib/timeline/component/css/item.css
generated
vendored
Normal file
195
node_modules/vis/lib/timeline/component/css/item.css
generated
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
|
||||
.vis-item {
|
||||
position: absolute;
|
||||
color: #1A1A1A;
|
||||
border-color: #97B0F8;
|
||||
border-width: 1px;
|
||||
background-color: #D5DDF6;
|
||||
display: inline-block;
|
||||
z-index: 1;
|
||||
/*overflow: hidden;*/
|
||||
}
|
||||
|
||||
.vis-item.vis-selected {
|
||||
border-color: #FFC200;
|
||||
background-color: #FFF785;
|
||||
|
||||
/* z-index must be higher than the z-index of custom time bar and current time bar */
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.vis-editable.vis-selected {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.vis-item.vis-point.vis-selected {
|
||||
background-color: #FFF785;
|
||||
}
|
||||
|
||||
.vis-item.vis-box {
|
||||
text-align: center;
|
||||
border-style: solid;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.vis-item.vis-point {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.vis-item.vis-dot {
|
||||
position: absolute;
|
||||
padding: 0;
|
||||
border-width: 4px;
|
||||
border-style: solid;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.vis-item.vis-range {
|
||||
border-style: solid;
|
||||
border-radius: 2px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.vis-item.vis-background {
|
||||
border: none;
|
||||
background-color: rgba(213, 221, 246, 0.4);
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.vis-item .vis-item-overflow {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.vis-item-visible-frame {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.vis-item.vis-range .vis-item-content {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.vis-item.vis-background .vis-item-content {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.vis-item.vis-line {
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
width: 0;
|
||||
border-left-width: 1px;
|
||||
border-left-style: solid;
|
||||
}
|
||||
|
||||
.vis-item .vis-item-content {
|
||||
white-space: nowrap;
|
||||
box-sizing: border-box;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.vis-item .vis-onUpdateTime-tooltip {
|
||||
position: absolute;
|
||||
background: #4f81bd;
|
||||
color: white;
|
||||
width: 200px;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
padding: 5px;
|
||||
border-radius: 1px;
|
||||
transition: 0.4s;
|
||||
-o-transition: 0.4s;
|
||||
-moz-transition: 0.4s;
|
||||
-webkit-transition: 0.4s;
|
||||
}
|
||||
|
||||
.vis-item .vis-delete, .vis-item .vis-delete-rtl {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
box-sizing: border-box;
|
||||
padding: 0px 5px;
|
||||
cursor: pointer;
|
||||
|
||||
-webkit-transition: background 0.2s linear;
|
||||
-moz-transition: background 0.2s linear;
|
||||
-ms-transition: background 0.2s linear;
|
||||
-o-transition: background 0.2s linear;
|
||||
transition: background 0.2s linear;
|
||||
}
|
||||
|
||||
.vis-item .vis-delete {
|
||||
right: -24px;
|
||||
}
|
||||
|
||||
.vis-item .vis-delete-rtl {
|
||||
left: -24px;
|
||||
}
|
||||
|
||||
.vis-item .vis-delete:after, .vis-item .vis-delete-rtl:after {
|
||||
content: "\00D7"; /* MULTIPLICATION SIGN */
|
||||
color: red;
|
||||
font-family: arial, sans-serif;
|
||||
font-size: 22px;
|
||||
font-weight: bold;
|
||||
|
||||
-webkit-transition: color 0.2s linear;
|
||||
-moz-transition: color 0.2s linear;
|
||||
-ms-transition: color 0.2s linear;
|
||||
-o-transition: color 0.2s linear;
|
||||
transition: color 0.2s linear;
|
||||
}
|
||||
|
||||
.vis-item .vis-delete:hover, .vis-item .vis-delete-rtl:hover {
|
||||
background: red;
|
||||
}
|
||||
|
||||
.vis-item .vis-delete:hover:after, .vis-item .vis-delete-rtl:hover:after {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.vis-item .vis-drag-center {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0px;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.vis-item.vis-range .vis-drag-left {
|
||||
position: absolute;
|
||||
width: 24px;
|
||||
max-width: 20%;
|
||||
min-width: 2px;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: -4px;
|
||||
|
||||
cursor: w-resize;
|
||||
}
|
||||
|
||||
.vis-item.vis-range .vis-drag-right {
|
||||
position: absolute;
|
||||
width: 24px;
|
||||
max-width: 20%;
|
||||
min-width: 2px;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
right: -4px;
|
||||
|
||||
cursor: e-resize;
|
||||
}
|
||||
|
||||
.vis-range.vis-item.vis-readonly .vis-drag-left,
|
||||
.vis-range.vis-item.vis-readonly .vis-drag-right {
|
||||
cursor: auto;
|
||||
}
|
||||
63
node_modules/vis/lib/timeline/component/css/itemset.css
generated
vendored
Normal file
63
node_modules/vis/lib/timeline/component/css/itemset.css
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
|
||||
.vis-itemset {
|
||||
position: relative;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.vis-itemset .vis-background,
|
||||
.vis-itemset .vis-foreground {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.vis-axis {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.vis-foreground .vis-group {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 1px solid #bfbfbf;
|
||||
}
|
||||
|
||||
.vis-foreground .vis-group:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.vis-nesting-group {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vis-nested-group {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.vis-label.vis-nesting-group.expanded:before {
|
||||
content: "\25BC";
|
||||
}
|
||||
|
||||
.vis-label.vis-nesting-group.collapsed-rtl:before {
|
||||
content: "\25C0";
|
||||
}
|
||||
|
||||
.vis-label.vis-nesting-group.collapsed:before {
|
||||
content: "\25B6";
|
||||
}
|
||||
|
||||
.vis-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 10;
|
||||
}
|
||||
39
node_modules/vis/lib/timeline/component/css/labelset.css
generated
vendored
Normal file
39
node_modules/vis/lib/timeline/component/css/labelset.css
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
.vis-labelset {
|
||||
position: relative;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.vis-labelset .vis-label {
|
||||
position: relative;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
color: #4d4d4d;
|
||||
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.vis-labelset .vis-label {
|
||||
border-bottom: 1px solid #bfbfbf;
|
||||
}
|
||||
|
||||
.vis-labelset .vis-label.draggable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vis-labelset .vis-label:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.vis-labelset .vis-label .vis-inner {
|
||||
display: inline-block;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.vis-labelset .vis-label .vis-inner.vis-hidden {
|
||||
padding: 0;
|
||||
}
|
||||
81
node_modules/vis/lib/timeline/component/css/panel.css
generated
vendored
Normal file
81
node_modules/vis/lib/timeline/component/css/panel.css
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
.vis-panel {
|
||||
position: absolute;
|
||||
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.vis-panel.vis-center,
|
||||
.vis-panel.vis-left,
|
||||
.vis-panel.vis-right,
|
||||
.vis-panel.vis-top,
|
||||
.vis-panel.vis-bottom {
|
||||
border: 1px #bfbfbf;
|
||||
}
|
||||
|
||||
.vis-panel.vis-center,
|
||||
.vis-panel.vis-left,
|
||||
.vis-panel.vis-right {
|
||||
border-top-style: solid;
|
||||
border-bottom-style: solid;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.vis-left.vis-panel.vis-vertical-scroll, .vis-right.vis-panel.vis-vertical-scroll {
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.vis-left.vis-panel.vis-vertical-scroll {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.vis-left.vis-panel.vis-vertical-scroll .vis-content {
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.vis-right.vis-panel.vis-vertical-scroll {
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.vis-right.vis-panel.vis-vertical-scroll .vis-content {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.vis-panel.vis-center,
|
||||
.vis-panel.vis-top,
|
||||
.vis-panel.vis-bottom {
|
||||
border-left-style: solid;
|
||||
border-right-style: solid;
|
||||
}
|
||||
|
||||
.vis-background {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.vis-panel > .vis-content {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.vis-panel .vis-shadow {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
box-shadow: 0 0 10px rgba(0,0,0,0.8);
|
||||
/* TODO: find a nice way to ensure vis-shadows are drawn on top of items
|
||||
z-index: 1;
|
||||
*/
|
||||
}
|
||||
|
||||
.vis-panel .vis-shadow.vis-top {
|
||||
top: -1px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.vis-panel .vis-shadow.vis-bottom {
|
||||
bottom: -1px;
|
||||
left: 0;
|
||||
}
|
||||
106
node_modules/vis/lib/timeline/component/css/pathStyles.css
generated
vendored
Normal file
106
node_modules/vis/lib/timeline/component/css/pathStyles.css
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
.vis-graph-group0 {
|
||||
fill:#4f81bd;
|
||||
fill-opacity:0;
|
||||
stroke-width:2px;
|
||||
stroke: #4f81bd;
|
||||
}
|
||||
|
||||
.vis-graph-group1 {
|
||||
fill:#f79646;
|
||||
fill-opacity:0;
|
||||
stroke-width:2px;
|
||||
stroke: #f79646;
|
||||
}
|
||||
|
||||
.vis-graph-group2 {
|
||||
fill: #8c51cf;
|
||||
fill-opacity:0;
|
||||
stroke-width:2px;
|
||||
stroke: #8c51cf;
|
||||
}
|
||||
|
||||
.vis-graph-group3 {
|
||||
fill: #75c841;
|
||||
fill-opacity:0;
|
||||
stroke-width:2px;
|
||||
stroke: #75c841;
|
||||
}
|
||||
|
||||
.vis-graph-group4 {
|
||||
fill: #ff0100;
|
||||
fill-opacity:0;
|
||||
stroke-width:2px;
|
||||
stroke: #ff0100;
|
||||
}
|
||||
|
||||
.vis-graph-group5 {
|
||||
fill: #37d8e6;
|
||||
fill-opacity:0;
|
||||
stroke-width:2px;
|
||||
stroke: #37d8e6;
|
||||
}
|
||||
|
||||
.vis-graph-group6 {
|
||||
fill: #042662;
|
||||
fill-opacity:0;
|
||||
stroke-width:2px;
|
||||
stroke: #042662;
|
||||
}
|
||||
|
||||
.vis-graph-group7 {
|
||||
fill:#00ff26;
|
||||
fill-opacity:0;
|
||||
stroke-width:2px;
|
||||
stroke: #00ff26;
|
||||
}
|
||||
|
||||
.vis-graph-group8 {
|
||||
fill:#ff00ff;
|
||||
fill-opacity:0;
|
||||
stroke-width:2px;
|
||||
stroke: #ff00ff;
|
||||
}
|
||||
|
||||
.vis-graph-group9 {
|
||||
fill: #8f3938;
|
||||
fill-opacity:0;
|
||||
stroke-width:2px;
|
||||
stroke: #8f3938;
|
||||
}
|
||||
|
||||
.vis-timeline .vis-fill {
|
||||
fill-opacity:0.1;
|
||||
stroke: none;
|
||||
}
|
||||
|
||||
|
||||
.vis-timeline .vis-bar {
|
||||
fill-opacity:0.5;
|
||||
stroke-width:1px;
|
||||
}
|
||||
|
||||
.vis-timeline .vis-point {
|
||||
stroke-width:2px;
|
||||
fill-opacity:1.0;
|
||||
}
|
||||
|
||||
|
||||
.vis-timeline .vis-legend-background {
|
||||
stroke-width:1px;
|
||||
fill-opacity:0.9;
|
||||
fill: #ffffff;
|
||||
stroke: #c2c2c2;
|
||||
}
|
||||
|
||||
|
||||
.vis-timeline .vis-outline {
|
||||
stroke-width:1px;
|
||||
fill-opacity:1;
|
||||
fill: #ffffff;
|
||||
stroke: #e5e5e5;
|
||||
}
|
||||
|
||||
.vis-timeline .vis-icon-fill {
|
||||
fill-opacity:0.3;
|
||||
stroke: none;
|
||||
}
|
||||
55
node_modules/vis/lib/timeline/component/css/timeaxis.css
generated
vendored
Normal file
55
node_modules/vis/lib/timeline/component/css/timeaxis.css
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
.vis-time-axis {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.vis-time-axis.vis-foreground {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.vis-time-axis.vis-background {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.vis-time-axis .vis-text {
|
||||
position: absolute;
|
||||
color: #4d4d4d;
|
||||
padding: 3px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.vis-time-axis .vis-text.vis-measure {
|
||||
position: absolute;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.vis-time-axis .vis-grid.vis-vertical {
|
||||
position: absolute;
|
||||
border-left: 1px solid;
|
||||
}
|
||||
|
||||
.vis-time-axis .vis-grid.vis-vertical-rtl {
|
||||
position: absolute;
|
||||
border-right: 1px solid;
|
||||
}
|
||||
|
||||
.vis-time-axis .vis-grid.vis-minor {
|
||||
border-color: #e5e5e5;
|
||||
}
|
||||
|
||||
.vis-time-axis .vis-grid.vis-major {
|
||||
border-color: #bfbfbf;
|
||||
}
|
||||
11
node_modules/vis/lib/timeline/component/css/timeline.css
generated
vendored
Normal file
11
node_modules/vis/lib/timeline/component/css/timeline.css
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
.vis-timeline {
|
||||
position: relative;
|
||||
border: 1px solid #bfbfbf;
|
||||
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
box-sizing: border-box;
|
||||
}
|
||||
287
node_modules/vis/lib/timeline/component/graph2d_types/bar.js
generated
vendored
Normal file
287
node_modules/vis/lib/timeline/component/graph2d_types/bar.js
generated
vendored
Normal file
@@ -0,0 +1,287 @@
|
||||
var DOMutil = require('../../../DOMutil');
|
||||
var Points = require('./points');
|
||||
|
||||
/**
|
||||
*
|
||||
* @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 = DOMutil.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);
|
||||
|
||||
DOMutil.drawBar(x + 0.5 * barWidth + offset, y + fillHeight - bar1Height - 1, barWidth, bar1Height, group.className + ' vis-bar', framework.svgElements, framework.svg, group.style);
|
||||
DOMutil.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
|
||||
};
|
||||
DOMutil.drawPoint(x + 0.5 * barWidth + offset, y + fillHeight - bar1Height - 1, groupTemplate, framework.svgElements, framework.svg);
|
||||
DOMutil.drawPoint(x + 1.5 * barWidth + offset + 2, y + fillHeight - bar2Height - 1, groupTemplate, framework.svgElements, framework.svg);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* draw a bar graph
|
||||
*
|
||||
* @param {Array.<vis.GraphGroup.id>} groupIds
|
||||
* @param {Object} processedGroupData
|
||||
* @param {{svg: Object, svgElements: Array.<Object>, options: Object, groups: Array.<vis.Group>}} framework
|
||||
*/
|
||||
Bargraph.draw = function (groupIds, processedGroupData, framework) {
|
||||
var combinedData = [];
|
||||
var intersections = {};
|
||||
var coreDistance;
|
||||
var key, drawData;
|
||||
var group;
|
||||
var i, j;
|
||||
var barPoints = 0;
|
||||
|
||||
// combine all barchart data
|
||||
for (i = 0; i < groupIds.length; i++) {
|
||||
group = framework.groups[groupIds[i]];
|
||||
if (group.options.style === 'bar') {
|
||||
if (group.visible === true && (framework.options.groups.visibility[groupIds[i]] === undefined || framework.options.groups.visibility[groupIds[i]] === true)) {
|
||||
for (j = 0; j < processedGroupData[groupIds[i]].length; j++) {
|
||||
combinedData.push({
|
||||
screen_x: processedGroupData[groupIds[i]][j].screen_x,
|
||||
screen_end: processedGroupData[groupIds[i]][j].screen_end,
|
||||
screen_y: processedGroupData[groupIds[i]][j].screen_y,
|
||||
x: processedGroupData[groupIds[i]][j].x,
|
||||
end: processedGroupData[groupIds[i]][j].end,
|
||||
y: processedGroupData[groupIds[i]][j].y,
|
||||
groupId: groupIds[i],
|
||||
label: processedGroupData[groupIds[i]][j].label
|
||||
});
|
||||
barPoints += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (barPoints === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// sort by time and by group
|
||||
combinedData.sort(function (a, b) {
|
||||
if (a.screen_x === b.screen_x) {
|
||||
return a.groupId < b.groupId ? -1 : 1;
|
||||
}
|
||||
else {
|
||||
return a.screen_x - b.screen_x;
|
||||
}
|
||||
});
|
||||
|
||||
// get intersections
|
||||
Bargraph._getDataIntersections(intersections, combinedData);
|
||||
|
||||
// plot barchart
|
||||
for (i = 0; i < combinedData.length; i++) {
|
||||
group = framework.groups[combinedData[i].groupId];
|
||||
var minWidth = group.options.barChart.minWidth != undefined ? group.options.barChart.minWidth : 0.1 * group.options.barChart.width;
|
||||
|
||||
key = combinedData[i].screen_x;
|
||||
var heightOffset = 0;
|
||||
if (intersections[key] === undefined) {
|
||||
if (i + 1 < combinedData.length) {
|
||||
coreDistance = Math.abs(combinedData[i + 1].screen_x - key);
|
||||
}
|
||||
drawData = Bargraph._getSafeDrawData(coreDistance, group, minWidth);
|
||||
}
|
||||
else {
|
||||
var nextKey = i + (intersections[key].amount - intersections[key].resolved);
|
||||
if (nextKey < combinedData.length) {
|
||||
coreDistance = Math.abs(combinedData[nextKey].screen_x - key);
|
||||
}
|
||||
drawData = Bargraph._getSafeDrawData(coreDistance, group, minWidth);
|
||||
intersections[key].resolved += 1;
|
||||
|
||||
if (group.options.stack === true && group.options.excludeFromStacking !== true) {
|
||||
if (combinedData[i].screen_y < group.zeroPosition) {
|
||||
heightOffset = intersections[key].accumulatedNegative;
|
||||
intersections[key].accumulatedNegative += group.zeroPosition - combinedData[i].screen_y;
|
||||
}
|
||||
else {
|
||||
heightOffset = intersections[key].accumulatedPositive;
|
||||
intersections[key].accumulatedPositive += group.zeroPosition - combinedData[i].screen_y;
|
||||
}
|
||||
}
|
||||
else if (group.options.barChart.sideBySide === true) {
|
||||
drawData.width = drawData.width / intersections[key].amount;
|
||||
drawData.offset += (intersections[key].resolved) * drawData.width - (0.5 * drawData.width * (intersections[key].amount + 1));
|
||||
}
|
||||
}
|
||||
|
||||
let dataWidth = drawData.width;
|
||||
let start = combinedData[i].screen_x;
|
||||
|
||||
// are we drawing explicit boxes? (we supplied an end value)
|
||||
if (combinedData[i].screen_end != undefined){
|
||||
dataWidth = combinedData[i].screen_end - combinedData[i].screen_x;
|
||||
start += (dataWidth * 0.5);
|
||||
}
|
||||
else {
|
||||
start += drawData.offset
|
||||
}
|
||||
|
||||
DOMutil.drawBar(start, combinedData[i].screen_y - heightOffset, dataWidth, group.zeroPosition - combinedData[i].screen_y, group.className + ' vis-bar', framework.svgElements, framework.svg, group.style);
|
||||
|
||||
// draw points
|
||||
if (group.options.drawPoints.enabled === true) {
|
||||
let pointData = {
|
||||
screen_x: combinedData[i].screen_x,
|
||||
screen_y: combinedData[i].screen_y - heightOffset,
|
||||
x: combinedData[i].x,
|
||||
y: combinedData[i].y,
|
||||
groupId: combinedData[i].groupId,
|
||||
label: combinedData[i].label
|
||||
};
|
||||
Points.draw([pointData], group, framework, drawData.offset);
|
||||
//DOMutil.drawPoint(combinedData[i].x + drawData.offset, combinedData[i].y, group, framework.svgElements, framework.svg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Fill the intersections object with counters of how many datapoints share the same x coordinates
|
||||
* @param {Object} intersections
|
||||
* @param {Array.<Object>} combinedData
|
||||
* @private
|
||||
*/
|
||||
Bargraph._getDataIntersections = function (intersections, combinedData) {
|
||||
// get intersections
|
||||
var coreDistance;
|
||||
for (var i = 0; i < combinedData.length; i++) {
|
||||
if (i + 1 < combinedData.length) {
|
||||
coreDistance = Math.abs(combinedData[i + 1].screen_x - combinedData[i].screen_x);
|
||||
}
|
||||
if (i > 0) {
|
||||
coreDistance = Math.min(coreDistance, Math.abs(combinedData[i - 1].screen_x - combinedData[i].screen_x));
|
||||
}
|
||||
if (coreDistance === 0) {
|
||||
if (intersections[combinedData[i].screen_x] === undefined) {
|
||||
intersections[combinedData[i].screen_x] = {
|
||||
amount: 0,
|
||||
resolved: 0,
|
||||
accumulatedPositive: 0,
|
||||
accumulatedNegative: 0
|
||||
};
|
||||
}
|
||||
intersections[combinedData[i].screen_x].amount += 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the width and offset for bargraphs based on the coredistance between datapoints
|
||||
*
|
||||
* @param {number} coreDistance
|
||||
* @param {vis.Group} group
|
||||
* @param {number} minWidth
|
||||
* @returns {{width: number, offset: number}}
|
||||
* @private
|
||||
*/
|
||||
Bargraph._getSafeDrawData = function (coreDistance, group, minWidth) {
|
||||
var width, offset;
|
||||
if (coreDistance < group.options.barChart.width && coreDistance > 0) {
|
||||
width = coreDistance < minWidth ? minWidth : coreDistance
|
||||
|
||||
offset = 0; // recalculate offset with the new width;
|
||||
if (group.options.barChart.align === 'left') {
|
||||
offset -= 0.5 * coreDistance;
|
||||
}
|
||||
else if (group.options.barChart.align === 'right') {
|
||||
offset += 0.5 * coreDistance;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// default settings
|
||||
width = group.options.barChart.width;
|
||||
offset = 0;
|
||||
if (group.options.barChart.align === 'left') {
|
||||
offset -= 0.5 * group.options.barChart.width;
|
||||
}
|
||||
else if (group.options.barChart.align === 'right') {
|
||||
offset += 0.5 * group.options.barChart.width;
|
||||
}
|
||||
}
|
||||
|
||||
return {width: width, offset: offset};
|
||||
};
|
||||
|
||||
Bargraph.getStackedYRange = function (combinedData, groupRanges, groupIds, groupLabel, orientation) {
|
||||
if (combinedData.length > 0) {
|
||||
// sort by time and by group
|
||||
combinedData.sort(function (a, b) {
|
||||
if (a.screen_x === b.screen_x) {
|
||||
return a.groupId < b.groupId ? -1 : 1;
|
||||
}
|
||||
else {
|
||||
return a.screen_x - b.screen_x;
|
||||
}
|
||||
});
|
||||
var intersections = {};
|
||||
|
||||
Bargraph._getDataIntersections(intersections, combinedData);
|
||||
groupRanges[groupLabel] = Bargraph._getStackedYRange(intersections, combinedData);
|
||||
groupRanges[groupLabel].yAxisOrientation = orientation;
|
||||
groupIds.push(groupLabel);
|
||||
}
|
||||
};
|
||||
|
||||
Bargraph._getStackedYRange = function (intersections, combinedData) {
|
||||
var key;
|
||||
var yMin = combinedData[0].screen_y;
|
||||
var yMax = combinedData[0].screen_y;
|
||||
for (var i = 0; i < combinedData.length; i++) {
|
||||
key = combinedData[i].screen_x;
|
||||
if (intersections[key] === undefined) {
|
||||
yMin = yMin > combinedData[i].screen_y ? combinedData[i].screen_y : yMin;
|
||||
yMax = yMax < combinedData[i].screen_y ? combinedData[i].screen_y : yMax;
|
||||
}
|
||||
else {
|
||||
if (combinedData[i].screen_y < 0) {
|
||||
intersections[key].accumulatedNegative += combinedData[i].screen_y;
|
||||
}
|
||||
else {
|
||||
intersections[key].accumulatedPositive += combinedData[i].screen_y;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var xpos in intersections) {
|
||||
if (intersections.hasOwnProperty(xpos)) {
|
||||
yMin = yMin > intersections[xpos].accumulatedNegative ? intersections[xpos].accumulatedNegative : yMin;
|
||||
yMin = yMin > intersections[xpos].accumulatedPositive ? intersections[xpos].accumulatedPositive : yMin;
|
||||
yMax = yMax < intersections[xpos].accumulatedNegative ? intersections[xpos].accumulatedNegative : yMax;
|
||||
yMax = yMax < intersections[xpos].accumulatedPositive ? intersections[xpos].accumulatedPositive : yMax;
|
||||
}
|
||||
}
|
||||
|
||||
return {min: yMin, max: yMax};
|
||||
};
|
||||
|
||||
module.exports = Bargraph;
|
||||
309
node_modules/vis/lib/timeline/component/graph2d_types/line.js
generated
vendored
Normal file
309
node_modules/vis/lib/timeline/component/graph2d_types/line.js
generated
vendored
Normal file
@@ -0,0 +1,309 @@
|
||||
var DOMutil = require('../../../DOMutil');
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {vis.GraphGroup.id} groupId
|
||||
* @param {Object} options // TODO: Describe options
|
||||
* @constructor Line
|
||||
*/
|
||||
function Line(groupId, options) { // eslint-disable-line no-unused-vars
|
||||
}
|
||||
|
||||
Line.calcPath = function (dataset, group) {
|
||||
if (dataset != null) {
|
||||
if (dataset.length > 0) {
|
||||
var d = [];
|
||||
|
||||
// construct path from dataset
|
||||
if (group.options.interpolation.enabled == true) {
|
||||
d = Line._catmullRom(dataset, group);
|
||||
}
|
||||
else {
|
||||
d = Line._linear(dataset);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Line.drawIcon = function (group, x, y, iconWidth, iconHeight, framework) {
|
||||
var fillHeight = iconHeight * 0.5;
|
||||
var path, fillPath;
|
||||
|
||||
var outline = DOMutil.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");
|
||||
|
||||
path = DOMutil.getSVGElement("path", framework.svgElements, framework.svg);
|
||||
path.setAttributeNS(null, "class", group.className);
|
||||
if (group.style !== undefined) {
|
||||
path.setAttributeNS(null, "style", group.style);
|
||||
}
|
||||
|
||||
path.setAttributeNS(null, "d", "M" + x + "," + y + " L" + (x + iconWidth) + "," + y + "");
|
||||
if (group.options.shaded.enabled == true) {
|
||||
fillPath = DOMutil.getSVGElement("path", framework.svgElements, framework.svg);
|
||||
if (group.options.shaded.orientation == 'top') {
|
||||
fillPath.setAttributeNS(null, "d", "M" + x + ", " + (y - fillHeight) +
|
||||
"L" + x + "," + y + " L" + (x + iconWidth) + "," + y + " L" + (x + iconWidth) + "," + (y - fillHeight));
|
||||
}
|
||||
else {
|
||||
fillPath.setAttributeNS(null, "d", "M" + x + "," + y + " " +
|
||||
"L" + x + "," + (y + fillHeight) + " " +
|
||||
"L" + (x + iconWidth) + "," + (y + fillHeight) +
|
||||
"L" + (x + iconWidth) + "," + y);
|
||||
}
|
||||
fillPath.setAttributeNS(null, "class", group.className + " vis-icon-fill");
|
||||
if (group.options.shaded.style !== undefined && group.options.shaded.style !== "") {
|
||||
fillPath.setAttributeNS(null, "style", group.options.shaded.style);
|
||||
}
|
||||
}
|
||||
|
||||
if (group.options.drawPoints.enabled == true) {
|
||||
var groupTemplate = {
|
||||
style: group.options.drawPoints.style,
|
||||
styles: group.options.drawPoints.styles,
|
||||
size: group.options.drawPoints.size,
|
||||
className: group.className
|
||||
};
|
||||
DOMutil.drawPoint(x + 0.5 * iconWidth, y, groupTemplate, framework.svgElements, framework.svg);
|
||||
}
|
||||
};
|
||||
|
||||
Line.drawShading = function (pathArray, group, subPathArray, framework) {
|
||||
// append shading to the path
|
||||
if (group.options.shaded.enabled == true) {
|
||||
var svgHeight = Number(framework.svg.style.height.replace('px',''));
|
||||
var fillPath = DOMutil.getSVGElement('path', framework.svgElements, framework.svg);
|
||||
var type = "L";
|
||||
if (group.options.interpolation.enabled == true){
|
||||
type = "C";
|
||||
}
|
||||
var dFill;
|
||||
var zero = 0;
|
||||
if (group.options.shaded.orientation == 'top') {
|
||||
zero = 0;
|
||||
}
|
||||
else if (group.options.shaded.orientation == 'bottom') {
|
||||
zero = svgHeight;
|
||||
}
|
||||
else {
|
||||
zero = Math.min(Math.max(0, group.zeroPosition), svgHeight);
|
||||
}
|
||||
if (group.options.shaded.orientation == 'group' && (subPathArray != null && subPathArray != undefined)) {
|
||||
dFill = 'M' + pathArray[0][0]+ ","+pathArray[0][1] + " " +
|
||||
this.serializePath(pathArray,type,false) +
|
||||
' L'+ subPathArray[subPathArray.length-1][0]+ "," + subPathArray[subPathArray.length-1][1] + " " +
|
||||
this.serializePath(subPathArray,type,true) +
|
||||
subPathArray[0][0]+ ","+subPathArray[0][1] + " Z";
|
||||
}
|
||||
else {
|
||||
dFill = 'M' + pathArray[0][0]+ ","+pathArray[0][1] + " " +
|
||||
this.serializePath(pathArray,type,false) +
|
||||
' V' + zero + ' H'+ pathArray[0][0] + " Z";
|
||||
}
|
||||
|
||||
fillPath.setAttributeNS(null, 'class', group.className + ' vis-fill');
|
||||
if (group.options.shaded.style !== undefined) {
|
||||
fillPath.setAttributeNS(null, 'style', group.options.shaded.style);
|
||||
}
|
||||
fillPath.setAttributeNS(null, 'd', dFill);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* draw a line graph
|
||||
*
|
||||
* @param {Array.<Object>} pathArray
|
||||
* @param {vis.Group} group
|
||||
* @param {{svg: Object, svgElements: Array.<Object>, options: Object, groups: Array.<vis.Group>}} framework
|
||||
*/
|
||||
Line.draw = function (pathArray, group, framework) {
|
||||
if (pathArray != null && pathArray != undefined) {
|
||||
var path = DOMutil.getSVGElement('path', framework.svgElements, framework.svg);
|
||||
path.setAttributeNS(null, "class", group.className);
|
||||
if (group.style !== undefined) {
|
||||
path.setAttributeNS(null, "style", group.style);
|
||||
}
|
||||
|
||||
var type = "L";
|
||||
if (group.options.interpolation.enabled == true){
|
||||
type = "C";
|
||||
}
|
||||
// copy properties to path for drawing.
|
||||
path.setAttributeNS(null, 'd', 'M' + pathArray[0][0]+ ","+pathArray[0][1] + " " + this.serializePath(pathArray,type,false));
|
||||
}
|
||||
};
|
||||
|
||||
Line.serializePath = function(pathArray,type,inverse){
|
||||
if (pathArray.length < 2){
|
||||
//Too little data to create a path.
|
||||
return "";
|
||||
}
|
||||
var d = type;
|
||||
var i;
|
||||
if (inverse){
|
||||
for (i = pathArray.length-2; i > 0; i--){
|
||||
d += pathArray[i][0] + "," + pathArray[i][1] + " ";
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = 1; i < pathArray.length; i++){
|
||||
d += pathArray[i][0] + "," + pathArray[i][1] + " ";
|
||||
}
|
||||
}
|
||||
return d;
|
||||
};
|
||||
|
||||
/**
|
||||
* This uses an uniform parametrization of the interpolation algorithm:
|
||||
* 'On the Parameterization of Catmull-Rom Curves' by Cem Yuksel et al.
|
||||
* @param {Array.<Object>} data
|
||||
* @returns {string}
|
||||
* @private
|
||||
*/
|
||||
Line._catmullRomUniform = function (data) {
|
||||
// catmull rom
|
||||
var p0, p1, p2, p3, bp1, bp2;
|
||||
var d = [];
|
||||
d.push( [ Math.round(data[0].screen_x) , Math.round(data[0].screen_y) ]);
|
||||
var normalization = 1 / 6;
|
||||
var length = data.length;
|
||||
for (var i = 0; i < length - 1; i++) {
|
||||
|
||||
p0 = (i == 0) ? data[0] : data[i - 1];
|
||||
p1 = data[i];
|
||||
p2 = data[i + 1];
|
||||
p3 = (i + 2 < length) ? data[i + 2] : p2;
|
||||
|
||||
|
||||
// Catmull-Rom to Cubic Bezier conversion matrix
|
||||
// 0 1 0 0
|
||||
// -1/6 1 1/6 0
|
||||
// 0 1/6 1 -1/6
|
||||
// 0 0 1 0
|
||||
|
||||
// bp0 = { x: p1.x, y: p1.y };
|
||||
bp1 = {
|
||||
screen_x: ((-p0.screen_x + 6 * p1.screen_x + p2.screen_x) * normalization),
|
||||
screen_y: ((-p0.screen_y + 6 * p1.screen_y + p2.screen_y) * normalization)
|
||||
};
|
||||
bp2 = {
|
||||
screen_x: (( p1.screen_x + 6 * p2.screen_x - p3.screen_x) * normalization),
|
||||
screen_y: (( p1.screen_y + 6 * p2.screen_y - p3.screen_y) * normalization)
|
||||
};
|
||||
// bp0 = { x: p2.x, y: p2.y };
|
||||
|
||||
d.push( [ bp1.screen_x , bp1.screen_y ]);
|
||||
d.push( [ bp2.screen_x , bp2.screen_y ]);
|
||||
d.push( [ p2.screen_x , p2.screen_y ]);
|
||||
}
|
||||
|
||||
return d;
|
||||
};
|
||||
|
||||
/**
|
||||
* This uses either the chordal or centripetal parameterization of the catmull-rom algorithm.
|
||||
* By default, the centripetal parameterization is used because this gives the nicest results.
|
||||
* These parameterizations are relatively heavy because the distance between 4 points have to be calculated.
|
||||
*
|
||||
* One optimization can be used to reuse distances since this is a sliding window approach.
|
||||
* @param {Array.<Object>} data
|
||||
* @param {vis.GraphGroup} group
|
||||
* @returns {string}
|
||||
* @private
|
||||
*/
|
||||
Line._catmullRom = function (data, group) {
|
||||
var alpha = group.options.interpolation.alpha;
|
||||
if (alpha == 0 || alpha === undefined) {
|
||||
return this._catmullRomUniform(data);
|
||||
}
|
||||
else {
|
||||
var p0, p1, p2, p3, bp1, bp2, d1, d2, d3, A, B, N, M;
|
||||
var d3powA, d2powA, d3pow2A, d2pow2A, d1pow2A, d1powA;
|
||||
var d = [];
|
||||
d.push( [ Math.round(data[0].screen_x) , Math.round(data[0].screen_y) ]);
|
||||
var length = data.length;
|
||||
for (var i = 0; i < length - 1; i++) {
|
||||
|
||||
p0 = (i == 0) ? data[0] : data[i - 1];
|
||||
p1 = data[i];
|
||||
p2 = data[i + 1];
|
||||
p3 = (i + 2 < length) ? data[i + 2] : p2;
|
||||
|
||||
d1 = Math.sqrt(Math.pow(p0.screen_x - p1.screen_x, 2) + Math.pow(p0.screen_y - p1.screen_y, 2));
|
||||
d2 = Math.sqrt(Math.pow(p1.screen_x - p2.screen_x, 2) + Math.pow(p1.screen_y - p2.screen_y, 2));
|
||||
d3 = Math.sqrt(Math.pow(p2.screen_x - p3.screen_x, 2) + Math.pow(p2.screen_y - p3.screen_y, 2));
|
||||
|
||||
// Catmull-Rom to Cubic Bezier conversion matrix
|
||||
|
||||
// A = 2d1^2a + 3d1^a * d2^a + d3^2a
|
||||
// B = 2d3^2a + 3d3^a * d2^a + d2^2a
|
||||
|
||||
// [ 0 1 0 0 ]
|
||||
// [ -d2^2a /N A/N d1^2a /N 0 ]
|
||||
// [ 0 d3^2a /M B/M -d2^2a /M ]
|
||||
// [ 0 0 1 0 ]
|
||||
|
||||
d3powA = Math.pow(d3, alpha);
|
||||
d3pow2A = Math.pow(d3, 2 * alpha);
|
||||
d2powA = Math.pow(d2, alpha);
|
||||
d2pow2A = Math.pow(d2, 2 * alpha);
|
||||
d1powA = Math.pow(d1, alpha);
|
||||
d1pow2A = Math.pow(d1, 2 * alpha);
|
||||
|
||||
A = 2 * d1pow2A + 3 * d1powA * d2powA + d2pow2A;
|
||||
B = 2 * d3pow2A + 3 * d3powA * d2powA + d2pow2A;
|
||||
N = 3 * d1powA * (d1powA + d2powA);
|
||||
if (N > 0) {
|
||||
N = 1 / N;
|
||||
}
|
||||
M = 3 * d3powA * (d3powA + d2powA);
|
||||
if (M > 0) {
|
||||
M = 1 / M;
|
||||
}
|
||||
|
||||
bp1 = {
|
||||
screen_x: ((-d2pow2A * p0.screen_x + A * p1.screen_x + d1pow2A * p2.screen_x) * N),
|
||||
screen_y: ((-d2pow2A * p0.screen_y + A * p1.screen_y + d1pow2A * p2.screen_y) * N)
|
||||
};
|
||||
|
||||
bp2 = {
|
||||
screen_x: (( d3pow2A * p1.screen_x + B * p2.screen_x - d2pow2A * p3.screen_x) * M),
|
||||
screen_y: (( d3pow2A * p1.screen_y + B * p2.screen_y - d2pow2A * p3.screen_y) * M)
|
||||
};
|
||||
|
||||
if (bp1.screen_x == 0 && bp1.screen_y == 0) {
|
||||
bp1 = p1;
|
||||
}
|
||||
if (bp2.screen_x == 0 && bp2.screen_y == 0) {
|
||||
bp2 = p2;
|
||||
}
|
||||
d.push( [ bp1.screen_x , bp1.screen_y ]);
|
||||
d.push( [ bp2.screen_x , bp2.screen_y ]);
|
||||
d.push( [ p2.screen_x , p2.screen_y ]);
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* this generates the SVG path for a linear drawing between datapoints.
|
||||
* @param {Array.<Object>} data
|
||||
* @returns {string}
|
||||
* @private
|
||||
*/
|
||||
Line._linear = function (data) {
|
||||
// linear
|
||||
var d = [];
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
d.push([ data[i].screen_x , data[i].screen_y ]);
|
||||
}
|
||||
return d;
|
||||
};
|
||||
|
||||
module.exports = Line;
|
||||
89
node_modules/vis/lib/timeline/component/graph2d_types/points.js
generated
vendored
Normal file
89
node_modules/vis/lib/timeline/component/graph2d_types/points.js
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
var DOMutil = require('../../../DOMutil');
|
||||
|
||||
/**
|
||||
*
|
||||
* @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.
|
||||
DOMutil.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 callbackResult === 'object') {
|
||||
DOMutil.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 = DOMutil.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
|
||||
DOMutil.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;
|
||||
}
|
||||
|
||||
module.exports = Points;
|
||||
236
node_modules/vis/lib/timeline/component/item/BackgroundItem.js
generated
vendored
Normal file
236
node_modules/vis/lib/timeline/component/item/BackgroundItem.js
generated
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
var Item = require('./Item');
|
||||
var BackgroundGroup = require('../BackgroundGroup');
|
||||
var RangeItem = require('./RangeItem');
|
||||
|
||||
/**
|
||||
* @constructor BackgroundItem
|
||||
* @extends Item
|
||||
* @param {Object} data Object containing parameters start, end
|
||||
* content, className.
|
||||
* @param {{toScreen: function, toTime: function}} conversion
|
||||
* Conversion functions from time to screen and vice versa
|
||||
* @param {Object} [options] Configuration options
|
||||
* // TODO: describe options
|
||||
* // TODO: implement support for the BackgroundItem just having a start, then being displayed as a sort of an annotation
|
||||
*/
|
||||
function BackgroundItem (data, conversion, options) {
|
||||
this.props = {
|
||||
content: {
|
||||
width: 0
|
||||
}
|
||||
};
|
||||
this.overflow = false; // if contents can overflow (css styling), this flag is set to true
|
||||
|
||||
// validate data
|
||||
if (data) {
|
||||
if (data.start == undefined) {
|
||||
throw new Error('Property "start" missing in item ' + data.id);
|
||||
}
|
||||
if (data.end == undefined) {
|
||||
throw new Error('Property "end" missing in item ' + data.id);
|
||||
}
|
||||
}
|
||||
|
||||
Item.call(this, data, conversion, options);
|
||||
}
|
||||
|
||||
BackgroundItem.prototype = new Item (null, null, null);
|
||||
|
||||
BackgroundItem.prototype.baseClassName = 'vis-item vis-background';
|
||||
|
||||
BackgroundItem.prototype.stack = false;
|
||||
|
||||
/**
|
||||
* Check whether this item is visible inside given range
|
||||
* @param {vis.Range} range with a timestamp for start and end
|
||||
* @returns {boolean} True if visible
|
||||
*/
|
||||
BackgroundItem.prototype.isVisible = function(range) {
|
||||
// determine visibility
|
||||
return (this.data.start < range.end) && (this.data.end > range.start);
|
||||
};
|
||||
|
||||
BackgroundItem.prototype._createDomElement = function() {
|
||||
if (!this.dom) {
|
||||
// create DOM
|
||||
this.dom = {};
|
||||
|
||||
// background box
|
||||
this.dom.box = document.createElement('div');
|
||||
// className is updated in redraw()
|
||||
|
||||
// frame box (to prevent the item contents from overflowing
|
||||
this.dom.frame = document.createElement('div');
|
||||
this.dom.frame.className = 'vis-item-overflow';
|
||||
this.dom.box.appendChild(this.dom.frame);
|
||||
|
||||
// contents box
|
||||
this.dom.content = document.createElement('div');
|
||||
this.dom.content.className = 'vis-item-content';
|
||||
this.dom.frame.appendChild(this.dom.content);
|
||||
|
||||
// Note: we do NOT attach this item as attribute to the DOM,
|
||||
// such that background items cannot be selected
|
||||
//this.dom.box['timeline-item'] = this;
|
||||
|
||||
this.dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
BackgroundItem.prototype._appendDomElement = function() {
|
||||
if (!this.parent) {
|
||||
throw new Error('Cannot redraw item: no parent attached');
|
||||
}
|
||||
if (!this.dom.box.parentNode) {
|
||||
var background = this.parent.dom.background;
|
||||
if (!background) {
|
||||
throw new Error('Cannot redraw item: parent has no background container element');
|
||||
}
|
||||
background.appendChild(this.dom.box);
|
||||
}
|
||||
this.displayed = true;
|
||||
}
|
||||
|
||||
BackgroundItem.prototype._updateDirtyDomComponents = function() {
|
||||
// update dirty DOM. An item is marked dirty when:
|
||||
// - the item is not yet rendered
|
||||
// - the item's data is changed
|
||||
// - the item is selected/deselected
|
||||
if (this.dirty) {
|
||||
this._updateContents(this.dom.content);
|
||||
this._updateDataAttributes(this.dom.content);
|
||||
this._updateStyle(this.dom.box);
|
||||
|
||||
// update class
|
||||
var className = (this.data.className ? (' ' + this.data.className) : '') +
|
||||
(this.selected ? ' vis-selected' : '');
|
||||
this.dom.box.className = this.baseClassName + className;
|
||||
}
|
||||
}
|
||||
|
||||
BackgroundItem.prototype._getDomComponentsSizes = function() {
|
||||
// determine from css whether this box has overflow
|
||||
this.overflow = window.getComputedStyle(this.dom.content).overflow !== 'hidden';
|
||||
return {
|
||||
content: {
|
||||
width: this.dom.content.offsetWidth
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BackgroundItem.prototype._updateDomComponentsSizes = function(sizes) {
|
||||
// recalculate size
|
||||
this.props.content.width = sizes.content.width;
|
||||
this.height = 0; // set height zero, so this item will be ignored when stacking items
|
||||
|
||||
this.dirty = false;
|
||||
}
|
||||
|
||||
BackgroundItem.prototype._repaintDomAdditionals = function() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Repaint the item
|
||||
* @param {boolean} [returnQueue=false] return the queue
|
||||
* @return {boolean} the redraw result or the redraw queue if returnQueue=true
|
||||
*/
|
||||
BackgroundItem.prototype.redraw = function(returnQueue) {
|
||||
var sizes
|
||||
var queue = [
|
||||
// create item DOM
|
||||
this._createDomElement.bind(this),
|
||||
|
||||
// append DOM to parent DOM
|
||||
this._appendDomElement.bind(this),
|
||||
|
||||
this._updateDirtyDomComponents.bind(this),
|
||||
|
||||
(function() {
|
||||
if (this.dirty) {
|
||||
sizes = this._getDomComponentsSizes.bind(this)();
|
||||
}
|
||||
}).bind(this),
|
||||
|
||||
(function() {
|
||||
if (this.dirty) {
|
||||
this._updateDomComponentsSizes.bind(this)(sizes);
|
||||
}
|
||||
}).bind(this),
|
||||
|
||||
// repaint DOM additionals
|
||||
this._repaintDomAdditionals.bind(this)
|
||||
];
|
||||
|
||||
if (returnQueue) {
|
||||
return queue;
|
||||
} else {
|
||||
var result;
|
||||
queue.forEach(function (fn) {
|
||||
result = fn();
|
||||
});
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Show the item in the DOM (when not already visible). The items DOM will
|
||||
* be created when needed.
|
||||
*/
|
||||
BackgroundItem.prototype.show = RangeItem.prototype.show;
|
||||
|
||||
/**
|
||||
* Hide the item from the DOM (when visible)
|
||||
* @return {Boolean} changed
|
||||
*/
|
||||
BackgroundItem.prototype.hide = RangeItem.prototype.hide;
|
||||
|
||||
/**
|
||||
* Reposition the item horizontally
|
||||
* @Override
|
||||
*/
|
||||
BackgroundItem.prototype.repositionX = RangeItem.prototype.repositionX;
|
||||
|
||||
/**
|
||||
* Reposition the item vertically
|
||||
* @Override
|
||||
*/
|
||||
BackgroundItem.prototype.repositionY = function(margin) { // eslint-disable-line no-unused-vars
|
||||
var height;
|
||||
var orientation = this.options.orientation.item;
|
||||
|
||||
// special positioning for subgroups
|
||||
if (this.data.subgroup !== undefined) {
|
||||
// TODO: instead of calculating the top position of the subgroups here for every BackgroundItem, calculate the top of the subgroup once in Itemset
|
||||
var itemSubgroup = this.data.subgroup;
|
||||
|
||||
this.dom.box.style.height = this.parent.subgroups[itemSubgroup].height + 'px';
|
||||
|
||||
if (orientation == 'top') {
|
||||
this.dom.box.style.top = this.parent.top + this.parent.subgroups[itemSubgroup].top + 'px';
|
||||
} else {
|
||||
this.dom.box.style.top = (this.parent.top + this.parent.height - this.parent.subgroups[itemSubgroup].top - this.parent.subgroups[itemSubgroup].height) + 'px';
|
||||
}
|
||||
this.dom.box.style.bottom = '';
|
||||
}
|
||||
// and in the case of no subgroups:
|
||||
else {
|
||||
// we want backgrounds with groups to only show in groups.
|
||||
if (this.parent instanceof BackgroundGroup) {
|
||||
// if the item is not in a group:
|
||||
height = Math.max(this.parent.height,
|
||||
this.parent.itemSet.body.domProps.center.height,
|
||||
this.parent.itemSet.body.domProps.centerContainer.height);
|
||||
this.dom.box.style.bottom = orientation == 'bottom' ? '0' : '';
|
||||
this.dom.box.style.top = orientation == 'top' ? '0' : '';
|
||||
}
|
||||
else {
|
||||
height = this.parent.height;
|
||||
// same alignment for items when orientation is top or bottom
|
||||
this.dom.box.style.top = this.parent.top + 'px';
|
||||
this.dom.box.style.bottom = '';
|
||||
}
|
||||
}
|
||||
this.dom.box.style.height = height + 'px';
|
||||
};
|
||||
|
||||
module.exports = BackgroundItem;
|
||||
360
node_modules/vis/lib/timeline/component/item/BoxItem.js
generated
vendored
Normal file
360
node_modules/vis/lib/timeline/component/item/BoxItem.js
generated
vendored
Normal file
@@ -0,0 +1,360 @@
|
||||
var Item = require('./Item');
|
||||
|
||||
/**
|
||||
* @constructor BoxItem
|
||||
* @extends Item
|
||||
* @param {Object} data Object containing parameters start
|
||||
* content, className.
|
||||
* @param {{toScreen: function, toTime: function}} conversion
|
||||
* Conversion functions from time to screen and vice versa
|
||||
* @param {Object} [options] Configuration options
|
||||
* // TODO: describe available options
|
||||
*/
|
||||
function BoxItem (data, conversion, options) {
|
||||
this.props = {
|
||||
dot: {
|
||||
width: 0,
|
||||
height: 0
|
||||
},
|
||||
line: {
|
||||
width: 0,
|
||||
height: 0
|
||||
}
|
||||
};
|
||||
this.options = options;
|
||||
// validate data
|
||||
if (data) {
|
||||
if (data.start == undefined) {
|
||||
throw new Error('Property "start" missing in item ' + data);
|
||||
}
|
||||
}
|
||||
|
||||
Item.call(this, data, conversion, options);
|
||||
}
|
||||
|
||||
BoxItem.prototype = new Item (null, null, null);
|
||||
|
||||
/**
|
||||
* Check whether this item is visible inside given range
|
||||
* @param {{start: number, end: number}} range with a timestamp for start and end
|
||||
* @returns {boolean} True if visible
|
||||
*/
|
||||
BoxItem.prototype.isVisible = function(range) {
|
||||
// determine visibility
|
||||
var isVisible;
|
||||
var align = this.options.align;
|
||||
var widthInMs = this.width * range.getMillisecondsPerPixel();
|
||||
|
||||
if (align == 'right') {
|
||||
isVisible = (this.data.start.getTime() > range.start ) && (this.data.start.getTime() - widthInMs < range.end);
|
||||
}
|
||||
else if (align == 'left') {
|
||||
isVisible = (this.data.start.getTime() + widthInMs > range.start ) && (this.data.start.getTime() < range.end);
|
||||
}
|
||||
else {
|
||||
// default or 'center'
|
||||
isVisible = (this.data.start.getTime() + widthInMs/2 > range.start ) && (this.data.start.getTime() - widthInMs/2 < range.end);
|
||||
}
|
||||
return isVisible;
|
||||
};
|
||||
|
||||
BoxItem.prototype._createDomElement = function() {
|
||||
if (!this.dom) {
|
||||
// create DOM
|
||||
this.dom = {};
|
||||
|
||||
// create main box
|
||||
this.dom.box = document.createElement('DIV');
|
||||
|
||||
// contents box (inside the background box). used for making margins
|
||||
this.dom.content = document.createElement('DIV');
|
||||
this.dom.content.className = 'vis-item-content';
|
||||
this.dom.box.appendChild(this.dom.content);
|
||||
|
||||
// line to axis
|
||||
this.dom.line = document.createElement('DIV');
|
||||
this.dom.line.className = 'vis-line';
|
||||
|
||||
// dot on axis
|
||||
this.dom.dot = document.createElement('DIV');
|
||||
this.dom.dot.className = 'vis-dot';
|
||||
|
||||
// attach this item as attribute
|
||||
this.dom.box['timeline-item'] = this;
|
||||
|
||||
this.dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
BoxItem.prototype._appendDomElement = function() {
|
||||
if (!this.parent) {
|
||||
throw new Error('Cannot redraw item: no parent attached');
|
||||
}
|
||||
if (!this.dom.box.parentNode) {
|
||||
var foreground = this.parent.dom.foreground;
|
||||
if (!foreground) throw new Error('Cannot redraw item: parent has no foreground container element');
|
||||
foreground.appendChild(this.dom.box);
|
||||
}
|
||||
if (!this.dom.line.parentNode) {
|
||||
var background = this.parent.dom.background;
|
||||
if (!background) throw new Error('Cannot redraw item: parent has no background container element');
|
||||
background.appendChild(this.dom.line);
|
||||
}
|
||||
if (!this.dom.dot.parentNode) {
|
||||
var axis = this.parent.dom.axis;
|
||||
if (!background) throw new Error('Cannot redraw item: parent has no axis container element');
|
||||
axis.appendChild(this.dom.dot);
|
||||
}
|
||||
this.displayed = true;
|
||||
}
|
||||
|
||||
BoxItem.prototype._updateDirtyDomComponents = function() {
|
||||
// An item is marked dirty when:
|
||||
// - the item is not yet rendered
|
||||
// - the item's data is changed
|
||||
// - the item is selected/deselected
|
||||
if (this.dirty) {
|
||||
this._updateContents(this.dom.content);
|
||||
this._updateDataAttributes(this.dom.box);
|
||||
this._updateStyle(this.dom.box);
|
||||
|
||||
var editable = (this.editable.updateTime || this.editable.updateGroup);
|
||||
|
||||
// update class
|
||||
var className = (this.data.className? ' ' + this.data.className : '') +
|
||||
(this.selected ? ' vis-selected' : '') +
|
||||
(editable ? ' vis-editable' : ' vis-readonly');
|
||||
this.dom.box.className = 'vis-item vis-box' + className;
|
||||
this.dom.line.className = 'vis-item vis-line' + className;
|
||||
this.dom.dot.className = 'vis-item vis-dot' + className;
|
||||
}
|
||||
}
|
||||
|
||||
BoxItem.prototype._getDomComponentsSizes = function() {
|
||||
return {
|
||||
previous: {
|
||||
right: this.dom.box.style.right,
|
||||
left: this.dom.box.style.left
|
||||
},
|
||||
dot: {
|
||||
height: this.dom.dot.offsetHeight,
|
||||
width: this.dom.dot.offsetWidth
|
||||
},
|
||||
line: {
|
||||
width: this.dom.line.offsetWidth
|
||||
},
|
||||
box: {
|
||||
width: this.dom.box.offsetWidth,
|
||||
height: this.dom.box.offsetHeight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BoxItem.prototype._updateDomComponentsSizes = function(sizes) {
|
||||
if (this.options.rtl) {
|
||||
this.dom.box.style.right = "0px";
|
||||
} else {
|
||||
this.dom.box.style.left = "0px";
|
||||
}
|
||||
|
||||
// recalculate size
|
||||
this.props.dot.height = sizes.dot.height;
|
||||
this.props.dot.width = sizes.dot.width;
|
||||
this.props.line.width = sizes.line.width;
|
||||
this.width = sizes.box.width;
|
||||
this.height = sizes.box.height;
|
||||
|
||||
// restore previous position
|
||||
if (this.options.rtl) {
|
||||
this.dom.box.style.right = sizes.previous.right;
|
||||
} else {
|
||||
this.dom.box.style.left = sizes.previous.left;
|
||||
}
|
||||
|
||||
this.dirty = false;
|
||||
}
|
||||
|
||||
BoxItem.prototype._repaintDomAdditionals = function() {
|
||||
this._repaintOnItemUpdateTimeTooltip(this.dom.box);
|
||||
this._repaintDragCenter();
|
||||
this._repaintDeleteButton(this.dom.box);
|
||||
}
|
||||
|
||||
/**
|
||||
* Repaint the item
|
||||
* @param {boolean} [returnQueue=false] return the queue
|
||||
* @return {boolean} the redraw queue if returnQueue=true
|
||||
*/
|
||||
BoxItem.prototype.redraw = function(returnQueue) {
|
||||
var sizes
|
||||
var queue = [
|
||||
// create item DOM
|
||||
this._createDomElement.bind(this),
|
||||
|
||||
// append DOM to parent DOM
|
||||
this._appendDomElement.bind(this),
|
||||
|
||||
// update dirty DOM
|
||||
this._updateDirtyDomComponents.bind(this),
|
||||
|
||||
(function() {
|
||||
if (this.dirty) {
|
||||
sizes = this._getDomComponentsSizes();
|
||||
}
|
||||
}).bind(this),
|
||||
|
||||
(function() {
|
||||
if (this.dirty) {
|
||||
this._updateDomComponentsSizes.bind(this)(sizes);
|
||||
}
|
||||
}).bind(this),
|
||||
|
||||
// repaint DOM additionals
|
||||
this._repaintDomAdditionals.bind(this)
|
||||
];
|
||||
|
||||
if (returnQueue) {
|
||||
return queue;
|
||||
} else {
|
||||
var result;
|
||||
queue.forEach(function (fn) {
|
||||
result = fn();
|
||||
});
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Show the item in the DOM (when not already displayed). The items DOM will
|
||||
* be created when needed.
|
||||
*/
|
||||
BoxItem.prototype.show = function() {
|
||||
if (!this.displayed) {
|
||||
this.redraw();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide the item from the DOM (when visible)
|
||||
*/
|
||||
BoxItem.prototype.hide = function() {
|
||||
if (this.displayed) {
|
||||
var dom = this.dom;
|
||||
|
||||
if (dom.box.parentNode) dom.box.parentNode.removeChild(dom.box);
|
||||
if (dom.line.parentNode) dom.line.parentNode.removeChild(dom.line);
|
||||
if (dom.dot.parentNode) dom.dot.parentNode.removeChild(dom.dot);
|
||||
|
||||
this.displayed = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reposition the item horizontally
|
||||
* @Override
|
||||
*/
|
||||
BoxItem.prototype.repositionX = function() {
|
||||
var start = this.conversion.toScreen(this.data.start);
|
||||
var align = this.options.align;
|
||||
|
||||
// calculate left position of the box
|
||||
if (align == 'right') {
|
||||
if (this.options.rtl) {
|
||||
this.right = start - this.width;
|
||||
|
||||
// reposition box, line, and dot
|
||||
this.dom.box.style.right = this.right + 'px';
|
||||
this.dom.line.style.right = (start - this.props.line.width) + 'px';
|
||||
this.dom.dot.style.right = (start - this.props.line.width / 2 - this.props.dot.width / 2) + 'px';
|
||||
} else {
|
||||
this.left = start - this.width;
|
||||
|
||||
// reposition box, line, and dot
|
||||
this.dom.box.style.left = this.left + 'px';
|
||||
this.dom.line.style.left = (start - this.props.line.width) + 'px';
|
||||
this.dom.dot.style.left = (start - this.props.line.width / 2 - this.props.dot.width / 2) + 'px';
|
||||
}
|
||||
}
|
||||
else if (align == 'left') {
|
||||
if (this.options.rtl) {
|
||||
this.right = start;
|
||||
|
||||
// reposition box, line, and dot
|
||||
this.dom.box.style.right = this.right + 'px';
|
||||
this.dom.line.style.right = start + 'px';
|
||||
this.dom.dot.style.right = (start + this.props.line.width / 2 - this.props.dot.width / 2) + 'px';
|
||||
} else {
|
||||
this.left = start;
|
||||
|
||||
// reposition box, line, and dot
|
||||
this.dom.box.style.left = this.left + 'px';
|
||||
this.dom.line.style.left = start + 'px';
|
||||
this.dom.dot.style.left = (start + this.props.line.width / 2 - this.props.dot.width / 2) + 'px';
|
||||
}
|
||||
}
|
||||
else {
|
||||
// default or 'center'
|
||||
if (this.options.rtl) {
|
||||
this.right = start - this.width / 2;
|
||||
|
||||
// reposition box, line, and dot
|
||||
this.dom.box.style.right = this.right + 'px';
|
||||
this.dom.line.style.right = (start - this.props.line.width) + 'px';
|
||||
this.dom.dot.style.right = (start - this.props.dot.width / 2) + 'px';
|
||||
} else {
|
||||
this.left = start - this.width / 2;
|
||||
|
||||
// reposition box, line, and dot
|
||||
this.dom.box.style.left = this.left + 'px';
|
||||
this.dom.line.style.left = (start - this.props.line.width / 2) + 'px';
|
||||
this.dom.dot.style.left = (start - this.props.dot.width / 2) + 'px';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reposition the item vertically
|
||||
* @Override
|
||||
*/
|
||||
BoxItem.prototype.repositionY = function() {
|
||||
var orientation = this.options.orientation.item;
|
||||
var box = this.dom.box;
|
||||
var line = this.dom.line;
|
||||
var dot = this.dom.dot;
|
||||
|
||||
if (orientation == 'top') {
|
||||
box.style.top = (this.top || 0) + 'px';
|
||||
|
||||
line.style.top = '0';
|
||||
line.style.height = (this.parent.top + this.top + 1) + 'px';
|
||||
line.style.bottom = '';
|
||||
}
|
||||
else { // orientation 'bottom'
|
||||
var itemSetHeight = this.parent.itemSet.props.height; // TODO: this is nasty
|
||||
var lineHeight = itemSetHeight - this.parent.top - this.parent.height + this.top;
|
||||
|
||||
box.style.top = (this.parent.height - this.top - this.height || 0) + 'px';
|
||||
line.style.top = (itemSetHeight - lineHeight) + 'px';
|
||||
line.style.bottom = '0';
|
||||
}
|
||||
|
||||
dot.style.top = (-this.props.dot.height / 2) + 'px';
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the width of the item left from its start date
|
||||
* @return {number}
|
||||
*/
|
||||
BoxItem.prototype.getWidthLeft = function () {
|
||||
return this.width / 2;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the width of the item right from its start date
|
||||
* @return {number}
|
||||
*/
|
||||
BoxItem.prototype.getWidthRight = function () {
|
||||
return this.width / 2;
|
||||
};
|
||||
|
||||
module.exports = BoxItem;
|
||||
519
node_modules/vis/lib/timeline/component/item/Item.js
generated
vendored
Normal file
519
node_modules/vis/lib/timeline/component/item/Item.js
generated
vendored
Normal file
@@ -0,0 +1,519 @@
|
||||
var Hammer = require('../../../module/hammer');
|
||||
var util = require('../../../util');
|
||||
var moment = require('../../../module/moment');
|
||||
|
||||
|
||||
/**
|
||||
* @constructor Item
|
||||
* @param {Object} data Object containing (optional) parameters type,
|
||||
* start, end, content, group, className.
|
||||
* @param {{toScreen: function, toTime: function}} conversion
|
||||
* Conversion functions from time to screen and vice versa
|
||||
* @param {Object} options Configuration options
|
||||
* // TODO: describe available options
|
||||
*/
|
||||
function Item (data, conversion, options) {
|
||||
this.id = null;
|
||||
this.parent = null;
|
||||
this.data = data;
|
||||
this.dom = null;
|
||||
this.conversion = conversion || {};
|
||||
this.options = options || {};
|
||||
this.selected = false;
|
||||
this.displayed = false;
|
||||
this.groupShowing = true;
|
||||
this.dirty = true;
|
||||
|
||||
this.top = null;
|
||||
this.right = null;
|
||||
this.left = null;
|
||||
this.width = null;
|
||||
this.height = null;
|
||||
|
||||
this.editable = null;
|
||||
this._updateEditStatus();
|
||||
}
|
||||
|
||||
Item.prototype.stack = true;
|
||||
|
||||
/**
|
||||
* Select current item
|
||||
*/
|
||||
Item.prototype.select = function() {
|
||||
this.selected = true;
|
||||
this.dirty = true;
|
||||
if (this.displayed) this.redraw();
|
||||
};
|
||||
|
||||
/**
|
||||
* Unselect current item
|
||||
*/
|
||||
Item.prototype.unselect = function() {
|
||||
this.selected = false;
|
||||
this.dirty = true;
|
||||
if (this.displayed) this.redraw();
|
||||
};
|
||||
|
||||
/**
|
||||
* Set data for the item. Existing data will be updated. The id should not
|
||||
* be changed. When the item is displayed, it will be redrawn immediately.
|
||||
* @param {Object} data
|
||||
*/
|
||||
Item.prototype.setData = function(data) {
|
||||
var groupChanged = data.group != undefined && this.data.group != data.group;
|
||||
if (groupChanged && this.parent != null) {
|
||||
this.parent.itemSet._moveToGroup(this, data.group);
|
||||
}
|
||||
|
||||
if (this.parent) {
|
||||
this.parent.stackDirty = true;
|
||||
}
|
||||
|
||||
var subGroupChanged = data.subgroup != undefined && this.data.subgroup != data.subgroup;
|
||||
if (subGroupChanged && this.parent != null) {
|
||||
this.parent.changeSubgroup(this, this.data.subgroup, data.subgroup);
|
||||
}
|
||||
|
||||
this.data = data;
|
||||
this._updateEditStatus();
|
||||
this.dirty = true;
|
||||
if (this.displayed) this.redraw();
|
||||
};
|
||||
|
||||
/**
|
||||
* Set a parent for the item
|
||||
* @param {Group} parent
|
||||
*/
|
||||
Item.prototype.setParent = function(parent) {
|
||||
if (this.displayed) {
|
||||
this.hide();
|
||||
this.parent = parent;
|
||||
if (this.parent) {
|
||||
this.show();
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.parent = parent;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check whether this item is visible inside given range
|
||||
* @param {vis.Range} range with a timestamp for start and end
|
||||
* @returns {boolean} True if visible
|
||||
*/
|
||||
Item.prototype.isVisible = function(range) { // eslint-disable-line no-unused-vars
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Show the Item in the DOM (when not already visible)
|
||||
* @return {Boolean} changed
|
||||
*/
|
||||
Item.prototype.show = function() {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide the Item from the DOM (when visible)
|
||||
* @return {Boolean} changed
|
||||
*/
|
||||
Item.prototype.hide = function() {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Repaint the item
|
||||
*/
|
||||
Item.prototype.redraw = function() {
|
||||
// should be implemented by the item
|
||||
};
|
||||
|
||||
/**
|
||||
* Reposition the Item horizontally
|
||||
*/
|
||||
Item.prototype.repositionX = function() {
|
||||
// should be implemented by the item
|
||||
};
|
||||
|
||||
/**
|
||||
* Reposition the Item vertically
|
||||
*/
|
||||
Item.prototype.repositionY = function() {
|
||||
// should be implemented by the item
|
||||
};
|
||||
|
||||
/**
|
||||
* Repaint a drag area on the center of the item when the item is selected
|
||||
* @protected
|
||||
*/
|
||||
Item.prototype._repaintDragCenter = function () {
|
||||
if (this.selected && this.options.editable.updateTime && !this.dom.dragCenter) {
|
||||
var me = this;
|
||||
// create and show drag area
|
||||
var dragCenter = document.createElement('div');
|
||||
dragCenter.className = 'vis-drag-center';
|
||||
dragCenter.dragCenterItem = this;
|
||||
var hammer = new Hammer(dragCenter);
|
||||
|
||||
hammer.on('tap', function (event) {
|
||||
me.parent.itemSet.body.emitter.emit('click', {
|
||||
event: event,
|
||||
item: me.id
|
||||
});
|
||||
});
|
||||
hammer.on('doubletap', function (event) {
|
||||
event.stopPropagation();
|
||||
me.parent.itemSet._onUpdateItem(me);
|
||||
me.parent.itemSet.body.emitter.emit('doubleClick', {
|
||||
event: event,
|
||||
item: me.id
|
||||
});
|
||||
});
|
||||
|
||||
if (this.dom.box) {
|
||||
if (this.dom.dragLeft) {
|
||||
this.dom.box.insertBefore(dragCenter, this.dom.dragLeft);
|
||||
}
|
||||
else {
|
||||
this.dom.box.appendChild(dragCenter);
|
||||
}
|
||||
}
|
||||
else if (this.dom.point) {
|
||||
this.dom.point.appendChild(dragCenter);
|
||||
}
|
||||
|
||||
this.dom.dragCenter = dragCenter;
|
||||
}
|
||||
else if (!this.selected && this.dom.dragCenter) {
|
||||
// delete drag area
|
||||
if (this.dom.dragCenter.parentNode) {
|
||||
this.dom.dragCenter.parentNode.removeChild(this.dom.dragCenter);
|
||||
}
|
||||
this.dom.dragCenter = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Repaint a delete button on the top right of the item when the item is selected
|
||||
* @param {HTMLElement} anchor
|
||||
* @protected
|
||||
*/
|
||||
Item.prototype._repaintDeleteButton = function (anchor) {
|
||||
var editable = ((this.options.editable.overrideItems || this.editable == null) && this.options.editable.remove) ||
|
||||
(!this.options.editable.overrideItems && this.editable != null && this.editable.remove);
|
||||
|
||||
if (this.selected && editable && !this.dom.deleteButton) {
|
||||
// create and show button
|
||||
var me = this;
|
||||
|
||||
var deleteButton = document.createElement('div');
|
||||
|
||||
if (this.options.rtl) {
|
||||
deleteButton.className = 'vis-delete-rtl';
|
||||
} else {
|
||||
deleteButton.className = 'vis-delete';
|
||||
}
|
||||
deleteButton.title = 'Delete this item';
|
||||
|
||||
// TODO: be able to destroy the delete button
|
||||
new Hammer(deleteButton).on('tap', function (event) {
|
||||
event.stopPropagation();
|
||||
me.parent.removeFromDataSet(me);
|
||||
});
|
||||
|
||||
anchor.appendChild(deleteButton);
|
||||
this.dom.deleteButton = deleteButton;
|
||||
}
|
||||
else if (!this.selected && this.dom.deleteButton) {
|
||||
// remove button
|
||||
if (this.dom.deleteButton.parentNode) {
|
||||
this.dom.deleteButton.parentNode.removeChild(this.dom.deleteButton);
|
||||
}
|
||||
this.dom.deleteButton = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Repaint a onChange tooltip on the top right of the item when the item is selected
|
||||
* @param {HTMLElement} anchor
|
||||
* @protected
|
||||
*/
|
||||
Item.prototype._repaintOnItemUpdateTimeTooltip = function (anchor) {
|
||||
if (!this.options.tooltipOnItemUpdateTime) return;
|
||||
|
||||
var editable = (this.options.editable.updateTime ||
|
||||
this.data.editable === true) &&
|
||||
this.data.editable !== false;
|
||||
|
||||
if (this.selected && editable && !this.dom.onItemUpdateTimeTooltip) {
|
||||
var onItemUpdateTimeTooltip = document.createElement('div');
|
||||
|
||||
onItemUpdateTimeTooltip.className = 'vis-onUpdateTime-tooltip';
|
||||
anchor.appendChild(onItemUpdateTimeTooltip);
|
||||
this.dom.onItemUpdateTimeTooltip = onItemUpdateTimeTooltip;
|
||||
|
||||
} else if (!this.selected && this.dom.onItemUpdateTimeTooltip) {
|
||||
// remove button
|
||||
if (this.dom.onItemUpdateTimeTooltip.parentNode) {
|
||||
this.dom.onItemUpdateTimeTooltip.parentNode.removeChild(this.dom.onItemUpdateTimeTooltip);
|
||||
}
|
||||
this.dom.onItemUpdateTimeTooltip = null;
|
||||
}
|
||||
|
||||
// position onChange tooltip
|
||||
if (this.dom.onItemUpdateTimeTooltip) {
|
||||
|
||||
// only show when editing
|
||||
this.dom.onItemUpdateTimeTooltip.style.visibility = this.parent.itemSet.touchParams.itemIsDragging ? 'visible' : 'hidden';
|
||||
|
||||
// position relative to item's content
|
||||
if (this.options.rtl) {
|
||||
this.dom.onItemUpdateTimeTooltip.style.right = this.dom.content.style.right;
|
||||
} else {
|
||||
this.dom.onItemUpdateTimeTooltip.style.left = this.dom.content.style.left;
|
||||
}
|
||||
|
||||
// position above or below the item depending on the item's position in the window
|
||||
var tooltipOffset = 50; // TODO: should be tooltip height (depends on template)
|
||||
var scrollTop = this.parent.itemSet.body.domProps.scrollTop;
|
||||
|
||||
// TODO: this.top for orientation:true is actually the items distance from the bottom...
|
||||
// (should be this.bottom)
|
||||
var itemDistanceFromTop
|
||||
if (this.options.orientation.item == 'top') {
|
||||
itemDistanceFromTop = this.top;
|
||||
} else {
|
||||
itemDistanceFromTop = (this.parent.height - this.top - this.height)
|
||||
}
|
||||
var isCloseToTop = itemDistanceFromTop + this.parent.top - tooltipOffset < -scrollTop;
|
||||
|
||||
if (isCloseToTop) {
|
||||
this.dom.onItemUpdateTimeTooltip.style.bottom = "";
|
||||
this.dom.onItemUpdateTimeTooltip.style.top = this.height + 2 + "px";
|
||||
} else {
|
||||
this.dom.onItemUpdateTimeTooltip.style.top = "";
|
||||
this.dom.onItemUpdateTimeTooltip.style.bottom = this.height + 2 + "px";
|
||||
}
|
||||
|
||||
// handle tooltip content
|
||||
var content;
|
||||
var templateFunction;
|
||||
|
||||
if (this.options.tooltipOnItemUpdateTime && this.options.tooltipOnItemUpdateTime.template) {
|
||||
templateFunction = this.options.tooltipOnItemUpdateTime.template.bind(this);
|
||||
content = templateFunction(this.data);
|
||||
} else {
|
||||
content = 'start: ' + moment(this.data.start).format('MM/DD/YYYY hh:mm');
|
||||
if (this.data.end) {
|
||||
content += '<br> end: ' + moment(this.data.end).format('MM/DD/YYYY hh:mm');
|
||||
}
|
||||
}
|
||||
this.dom.onItemUpdateTimeTooltip.innerHTML = content;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set HTML contents for the item
|
||||
* @param {Element} element HTML element to fill with the contents
|
||||
* @private
|
||||
*/
|
||||
Item.prototype._updateContents = function (element) {
|
||||
var content;
|
||||
var changed;
|
||||
var templateFunction;
|
||||
var itemVisibleFrameContent;
|
||||
var visibleFrameTemplateFunction;
|
||||
var itemData = this.parent.itemSet.itemsData.get(this.id); // get a clone of the data from the dataset
|
||||
|
||||
var frameElement = this.dom.box || this.dom.point;
|
||||
var itemVisibleFrameContentElement = frameElement.getElementsByClassName('vis-item-visible-frame')[0]
|
||||
|
||||
if (this.options.visibleFrameTemplate) {
|
||||
visibleFrameTemplateFunction = this.options.visibleFrameTemplate.bind(this);
|
||||
itemVisibleFrameContent = visibleFrameTemplateFunction(itemData, frameElement);
|
||||
} else {
|
||||
itemVisibleFrameContent = '';
|
||||
}
|
||||
|
||||
if (itemVisibleFrameContentElement) {
|
||||
if ((itemVisibleFrameContent instanceof Object) && !(itemVisibleFrameContent instanceof Element)) {
|
||||
visibleFrameTemplateFunction(itemData, itemVisibleFrameContentElement)
|
||||
} else {
|
||||
changed = this._contentToString(this.itemVisibleFrameContent) !== this._contentToString(itemVisibleFrameContent);
|
||||
if (changed) {
|
||||
// only replace the content when changed
|
||||
if (itemVisibleFrameContent instanceof Element) {
|
||||
itemVisibleFrameContentElement.innerHTML = '';
|
||||
itemVisibleFrameContentElement.appendChild(itemVisibleFrameContent);
|
||||
}
|
||||
else if (itemVisibleFrameContent != undefined) {
|
||||
itemVisibleFrameContentElement.innerHTML = itemVisibleFrameContent;
|
||||
}
|
||||
else {
|
||||
if (!(this.data.type == 'background' && this.data.content === undefined)) {
|
||||
throw new Error('Property "content" missing in item ' + this.id);
|
||||
}
|
||||
}
|
||||
|
||||
this.itemVisibleFrameContent = itemVisibleFrameContent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.template) {
|
||||
templateFunction = this.options.template.bind(this);
|
||||
content = templateFunction(itemData, element, this.data);
|
||||
} else {
|
||||
content = this.data.content;
|
||||
}
|
||||
|
||||
if ((content instanceof Object) && !(content instanceof Element)) {
|
||||
templateFunction(itemData, element)
|
||||
} else {
|
||||
changed = this._contentToString(this.content) !== this._contentToString(content);
|
||||
if (changed) {
|
||||
// only replace the content when changed
|
||||
if (content instanceof Element) {
|
||||
element.innerHTML = '';
|
||||
element.appendChild(content);
|
||||
}
|
||||
else if (content != undefined) {
|
||||
element.innerHTML = content;
|
||||
}
|
||||
else {
|
||||
if (!(this.data.type == 'background' && this.data.content === undefined)) {
|
||||
throw new Error('Property "content" missing in item ' + this.id);
|
||||
}
|
||||
}
|
||||
this.content = content;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Process dataAttributes timeline option and set as data- attributes on dom.content
|
||||
* @param {Element} element HTML element to which the attributes will be attached
|
||||
* @private
|
||||
*/
|
||||
Item.prototype._updateDataAttributes = function(element) {
|
||||
if (this.options.dataAttributes && this.options.dataAttributes.length > 0) {
|
||||
var attributes = [];
|
||||
|
||||
if (Array.isArray(this.options.dataAttributes)) {
|
||||
attributes = this.options.dataAttributes;
|
||||
}
|
||||
else if (this.options.dataAttributes == 'all') {
|
||||
attributes = Object.keys(this.data);
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < attributes.length; i++) {
|
||||
var name = attributes[i];
|
||||
var value = this.data[name];
|
||||
|
||||
if (value != null) {
|
||||
element.setAttribute('data-' + name, value);
|
||||
}
|
||||
else {
|
||||
element.removeAttribute('data-' + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update custom styles of the element
|
||||
* @param {Element} element
|
||||
* @private
|
||||
*/
|
||||
Item.prototype._updateStyle = function(element) {
|
||||
// remove old styles
|
||||
if (this.style) {
|
||||
util.removeCssText(element, this.style);
|
||||
this.style = null;
|
||||
}
|
||||
|
||||
// append new styles
|
||||
if (this.data.style) {
|
||||
util.addCssText(element, this.data.style);
|
||||
this.style = this.data.style;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Stringify the items contents
|
||||
* @param {string | Element | undefined} content
|
||||
* @returns {string | undefined}
|
||||
* @private
|
||||
*/
|
||||
Item.prototype._contentToString = function (content) {
|
||||
if (typeof content === 'string') return content;
|
||||
if (content && 'outerHTML' in content) return content.outerHTML;
|
||||
return content;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the editability of this item.
|
||||
*/
|
||||
Item.prototype._updateEditStatus = function() {
|
||||
if (this.options) {
|
||||
if(typeof this.options.editable === 'boolean') {
|
||||
this.editable = {
|
||||
updateTime: this.options.editable,
|
||||
updateGroup: this.options.editable,
|
||||
remove: this.options.editable
|
||||
};
|
||||
} else if(typeof this.options.editable === 'object') {
|
||||
this.editable = {};
|
||||
util.selectiveExtend(['updateTime', 'updateGroup', 'remove'], this.editable, this.options.editable);
|
||||
}
|
||||
}
|
||||
// Item data overrides, except if options.editable.overrideItems is set.
|
||||
if (!this.options || !(this.options.editable) || (this.options.editable.overrideItems !== true)) {
|
||||
if (this.data) {
|
||||
if (typeof this.data.editable === 'boolean') {
|
||||
this.editable = {
|
||||
updateTime: this.data.editable,
|
||||
updateGroup: this.data.editable,
|
||||
remove: this.data.editable
|
||||
}
|
||||
} else if (typeof this.data.editable === 'object') {
|
||||
// TODO: in vis.js 5.0, we should change this to not reset options from the timeline configuration.
|
||||
// Basically just remove the next line...
|
||||
this.editable = {};
|
||||
util.selectiveExtend(['updateTime', 'updateGroup', 'remove'], this.editable, this.data.editable);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the width of the item left from its start date
|
||||
* @return {number}
|
||||
*/
|
||||
Item.prototype.getWidthLeft = function () {
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the width of the item right from the max of its start and end date
|
||||
* @return {number}
|
||||
*/
|
||||
Item.prototype.getWidthRight = function () {
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the title of the item
|
||||
* @return {string | undefined}
|
||||
*/
|
||||
Item.prototype.getTitle = function () {
|
||||
return this.data.title;
|
||||
};
|
||||
|
||||
module.exports = Item;
|
||||
281
node_modules/vis/lib/timeline/component/item/PointItem.js
generated
vendored
Normal file
281
node_modules/vis/lib/timeline/component/item/PointItem.js
generated
vendored
Normal file
@@ -0,0 +1,281 @@
|
||||
var Item = require('./Item');
|
||||
|
||||
/**
|
||||
* @constructor PointItem
|
||||
* @extends Item
|
||||
* @param {Object} data Object containing parameters start
|
||||
* content, className.
|
||||
* @param {{toScreen: function, toTime: function}} conversion
|
||||
* Conversion functions from time to screen and vice versa
|
||||
* @param {Object} [options] Configuration options
|
||||
* // TODO: describe available options
|
||||
*/
|
||||
function PointItem (data, conversion, options) {
|
||||
this.props = {
|
||||
dot: {
|
||||
top: 0,
|
||||
width: 0,
|
||||
height: 0
|
||||
},
|
||||
content: {
|
||||
height: 0,
|
||||
marginLeft: 0,
|
||||
marginRight: 0
|
||||
}
|
||||
};
|
||||
this.options = options;
|
||||
// validate data
|
||||
if (data) {
|
||||
if (data.start == undefined) {
|
||||
throw new Error('Property "start" missing in item ' + data);
|
||||
}
|
||||
}
|
||||
|
||||
Item.call(this, data, conversion, options);
|
||||
}
|
||||
|
||||
PointItem.prototype = new Item (null, null, null);
|
||||
|
||||
/**
|
||||
* Check whether this item is visible inside given range
|
||||
* @param {{start: number, end: number}} range with a timestamp for start and end
|
||||
* @returns {boolean} True if visible
|
||||
*/
|
||||
PointItem.prototype.isVisible = function(range) {
|
||||
// determine visibility
|
||||
var widthInMs = this.width * range.getMillisecondsPerPixel();
|
||||
|
||||
return (this.data.start.getTime() + widthInMs > range.start ) && (this.data.start < range.end);
|
||||
};
|
||||
|
||||
|
||||
PointItem.prototype._createDomElement = function() {
|
||||
if (!this.dom) {
|
||||
// create DOM
|
||||
this.dom = {};
|
||||
|
||||
// background box
|
||||
this.dom.point = document.createElement('div');
|
||||
// className is updated in redraw()
|
||||
|
||||
// contents box, right from the dot
|
||||
this.dom.content = document.createElement('div');
|
||||
this.dom.content.className = 'vis-item-content';
|
||||
this.dom.point.appendChild(this.dom.content);
|
||||
|
||||
// dot at start
|
||||
this.dom.dot = document.createElement('div');
|
||||
this.dom.point.appendChild(this.dom.dot);
|
||||
|
||||
// attach this item as attribute
|
||||
this.dom.point['timeline-item'] = this;
|
||||
|
||||
this.dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
PointItem.prototype._appendDomElement = function() {
|
||||
if (!this.parent) {
|
||||
throw new Error('Cannot redraw item: no parent attached');
|
||||
}
|
||||
if (!this.dom.point.parentNode) {
|
||||
var foreground = this.parent.dom.foreground;
|
||||
if (!foreground) {
|
||||
throw new Error('Cannot redraw item: parent has no foreground container element');
|
||||
}
|
||||
foreground.appendChild(this.dom.point);
|
||||
}
|
||||
this.displayed = true;
|
||||
}
|
||||
|
||||
PointItem.prototype._updateDirtyDomComponents = function() {
|
||||
// An item is marked dirty when:
|
||||
// - the item is not yet rendered
|
||||
// - the item's data is changed
|
||||
// - the item is selected/deselected
|
||||
if (this.dirty) {
|
||||
this._updateContents(this.dom.content);
|
||||
this._updateDataAttributes(this.dom.point);
|
||||
this._updateStyle(this.dom.point);
|
||||
|
||||
var editable = (this.editable.updateTime || this.editable.updateGroup);
|
||||
// update class
|
||||
var className = (this.data.className ? ' ' + this.data.className : '') +
|
||||
(this.selected ? ' vis-selected' : '') +
|
||||
(editable ? ' vis-editable' : ' vis-readonly');
|
||||
this.dom.point.className = 'vis-item vis-point' + className;
|
||||
this.dom.dot.className = 'vis-item vis-dot' + className;
|
||||
}
|
||||
}
|
||||
|
||||
PointItem.prototype._getDomComponentsSizes = function() {
|
||||
return {
|
||||
dot: {
|
||||
width: this.dom.dot.offsetWidth,
|
||||
height: this.dom.dot.offsetHeight
|
||||
},
|
||||
content: {
|
||||
width: this.dom.content.offsetWidth,
|
||||
height: this.dom.content.offsetHeight
|
||||
},
|
||||
point: {
|
||||
width: this.dom.point.offsetWidth,
|
||||
height: this.dom.point.offsetHeight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PointItem.prototype._updateDomComponentsSizes = function(sizes) {
|
||||
// recalculate size of dot and contents
|
||||
this.props.dot.width = sizes.dot.width;
|
||||
this.props.dot.height = sizes.dot.height;
|
||||
this.props.content.height = sizes.content.height;
|
||||
|
||||
// resize contents
|
||||
if (this.options.rtl) {
|
||||
this.dom.content.style.marginRight = 2 * this.props.dot.width + 'px';
|
||||
} else {
|
||||
this.dom.content.style.marginLeft = 2 * this.props.dot.width + 'px';
|
||||
}
|
||||
//this.dom.content.style.marginRight = ... + 'px'; // TODO: margin right
|
||||
|
||||
// recalculate size
|
||||
this.width = sizes.point.width;
|
||||
this.height = sizes.point.height;
|
||||
|
||||
// reposition the dot
|
||||
this.dom.dot.style.top = ((this.height - this.props.dot.height) / 2) + 'px';
|
||||
if (this.options.rtl) {
|
||||
this.dom.dot.style.right = (this.props.dot.width / 2) + 'px';
|
||||
} else {
|
||||
this.dom.dot.style.left = (this.props.dot.width / 2) + 'px';
|
||||
}
|
||||
|
||||
this.dirty = false;
|
||||
}
|
||||
|
||||
PointItem.prototype._repaintDomAdditionals = function() {
|
||||
this._repaintOnItemUpdateTimeTooltip(this.dom.point);
|
||||
this._repaintDragCenter();
|
||||
this._repaintDeleteButton(this.dom.point);
|
||||
}
|
||||
|
||||
/**
|
||||
* Repaint the item
|
||||
* @param {boolean} [returnQueue=false] return the queue
|
||||
* @return {boolean} the redraw queue if returnQueue=true
|
||||
*/
|
||||
PointItem.prototype.redraw = function(returnQueue) {
|
||||
var sizes
|
||||
var queue = [
|
||||
// create item DOM
|
||||
this._createDomElement.bind(this),
|
||||
|
||||
// append DOM to parent DOM
|
||||
this._appendDomElement.bind(this),
|
||||
|
||||
// update dirty DOM
|
||||
this._updateDirtyDomComponents.bind(this),
|
||||
|
||||
(function() {
|
||||
if (this.dirty) {
|
||||
sizes = this._getDomComponentsSizes();
|
||||
}
|
||||
}).bind(this),
|
||||
|
||||
(function() {
|
||||
if (this.dirty) {
|
||||
this._updateDomComponentsSizes.bind(this)(sizes);
|
||||
}
|
||||
}).bind(this),
|
||||
|
||||
// repaint DOM additionals
|
||||
this._repaintDomAdditionals.bind(this)
|
||||
];
|
||||
|
||||
if (returnQueue) {
|
||||
return queue;
|
||||
} else {
|
||||
var result;
|
||||
queue.forEach(function (fn) {
|
||||
result = fn();
|
||||
});
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Show the item in the DOM (when not already visible). The items DOM will
|
||||
* be created when needed.
|
||||
*/
|
||||
PointItem.prototype.show = function() {
|
||||
if (!this.displayed) {
|
||||
this.redraw();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide the item from the DOM (when visible)
|
||||
*/
|
||||
PointItem.prototype.hide = function() {
|
||||
if (this.displayed) {
|
||||
if (this.dom.point.parentNode) {
|
||||
this.dom.point.parentNode.removeChild(this.dom.point);
|
||||
}
|
||||
|
||||
this.displayed = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reposition the item horizontally
|
||||
* @Override
|
||||
*/
|
||||
PointItem.prototype.repositionX = function() {
|
||||
var start = this.conversion.toScreen(this.data.start);
|
||||
|
||||
if (this.options.rtl) {
|
||||
this.right = start - this.props.dot.width;
|
||||
|
||||
// reposition point
|
||||
this.dom.point.style.right = this.right + 'px';
|
||||
} else {
|
||||
this.left = start - this.props.dot.width;
|
||||
|
||||
// reposition point
|
||||
this.dom.point.style.left = this.left + 'px';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reposition the item vertically
|
||||
* @Override
|
||||
*/
|
||||
PointItem.prototype.repositionY = function() {
|
||||
var orientation = this.options.orientation.item;
|
||||
var point = this.dom.point;
|
||||
if (orientation == 'top') {
|
||||
point.style.top = this.top + 'px';
|
||||
}
|
||||
else {
|
||||
point.style.top = (this.parent.height - this.top - this.height) + 'px';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the width of the item left from its start date
|
||||
* @return {number}
|
||||
*/
|
||||
PointItem.prototype.getWidthLeft = function () {
|
||||
return this.props.dot.width;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the width of the item right from its start date
|
||||
* @return {number}
|
||||
*/
|
||||
PointItem.prototype.getWidthRight = function () {
|
||||
return this.props.dot.width;
|
||||
};
|
||||
|
||||
module.exports = PointItem;
|
||||
392
node_modules/vis/lib/timeline/component/item/RangeItem.js
generated
vendored
Normal file
392
node_modules/vis/lib/timeline/component/item/RangeItem.js
generated
vendored
Normal file
@@ -0,0 +1,392 @@
|
||||
var Item = require('./Item');
|
||||
|
||||
/**
|
||||
* @constructor RangeItem
|
||||
* @extends Item
|
||||
* @param {Object} data Object containing parameters start, end
|
||||
* content, className.
|
||||
* @param {{toScreen: function, toTime: function}} conversion
|
||||
* Conversion functions from time to screen and vice versa
|
||||
* @param {Object} [options] Configuration options
|
||||
* // TODO: describe options
|
||||
*/
|
||||
function RangeItem (data, conversion, options) {
|
||||
this.props = {
|
||||
content: {
|
||||
width: 0
|
||||
}
|
||||
};
|
||||
this.overflow = false; // if contents can overflow (css styling), this flag is set to true
|
||||
this.options = options;
|
||||
// validate data
|
||||
if (data) {
|
||||
if (data.start == undefined) {
|
||||
throw new Error('Property "start" missing in item ' + data.id);
|
||||
}
|
||||
if (data.end == undefined) {
|
||||
throw new Error('Property "end" missing in item ' + data.id);
|
||||
}
|
||||
}
|
||||
|
||||
Item.call(this, data, conversion, options);
|
||||
}
|
||||
|
||||
RangeItem.prototype = new Item (null, null, null);
|
||||
|
||||
RangeItem.prototype.baseClassName = 'vis-item vis-range';
|
||||
|
||||
/**
|
||||
* Check whether this item is visible inside given range
|
||||
*
|
||||
* @param {vis.Range} range with a timestamp for start and end
|
||||
* @returns {boolean} True if visible
|
||||
*/
|
||||
RangeItem.prototype.isVisible = function(range) {
|
||||
// determine visibility
|
||||
return (this.data.start < range.end) && (this.data.end > range.start);
|
||||
};
|
||||
|
||||
RangeItem.prototype._createDomElement = function() {
|
||||
if (!this.dom) {
|
||||
// create DOM
|
||||
this.dom = {};
|
||||
|
||||
// background box
|
||||
this.dom.box = document.createElement('div');
|
||||
// className is updated in redraw()
|
||||
|
||||
// frame box (to prevent the item contents from overflowing)
|
||||
this.dom.frame = document.createElement('div');
|
||||
this.dom.frame.className = 'vis-item-overflow';
|
||||
this.dom.box.appendChild(this.dom.frame);
|
||||
|
||||
// visible frame box (showing the frame that is always visible)
|
||||
this.dom.visibleFrame = document.createElement('div');
|
||||
this.dom.visibleFrame.className = 'vis-item-visible-frame';
|
||||
this.dom.box.appendChild(this.dom.visibleFrame);
|
||||
|
||||
// contents box
|
||||
this.dom.content = document.createElement('div');
|
||||
this.dom.content.className = 'vis-item-content';
|
||||
this.dom.frame.appendChild(this.dom.content);
|
||||
|
||||
// attach this item as attribute
|
||||
this.dom.box['timeline-item'] = this;
|
||||
|
||||
this.dirty = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RangeItem.prototype._appendDomElement = function() {
|
||||
if (!this.parent) {
|
||||
throw new Error('Cannot redraw item: no parent attached');
|
||||
}
|
||||
if (!this.dom.box.parentNode) {
|
||||
var foreground = this.parent.dom.foreground;
|
||||
if (!foreground) {
|
||||
throw new Error('Cannot redraw item: parent has no foreground container element');
|
||||
}
|
||||
foreground.appendChild(this.dom.box);
|
||||
}
|
||||
this.displayed = true;
|
||||
}
|
||||
|
||||
RangeItem.prototype._updateDirtyDomComponents = function() {
|
||||
// update dirty DOM. An item is marked dirty when:
|
||||
// - the item is not yet rendered
|
||||
// - the item's data is changed
|
||||
// - the item is selected/deselected
|
||||
if (this.dirty) {
|
||||
this._updateContents(this.dom.content);
|
||||
this._updateDataAttributes(this.dom.box);
|
||||
this._updateStyle(this.dom.box);
|
||||
|
||||
var editable = (this.editable.updateTime || this.editable.updateGroup);
|
||||
|
||||
// update class
|
||||
var className = (this.data.className ? (' ' + this.data.className) : '') +
|
||||
(this.selected ? ' vis-selected' : '') +
|
||||
(editable ? ' vis-editable' : ' vis-readonly');
|
||||
this.dom.box.className = this.baseClassName + className;
|
||||
|
||||
// turn off max-width to be able to calculate the real width
|
||||
// this causes an extra browser repaint/reflow, but so be it
|
||||
this.dom.content.style.maxWidth = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
RangeItem.prototype._getDomComponentsSizes = function() {
|
||||
// determine from css whether this box has overflow
|
||||
this.overflow = window.getComputedStyle(this.dom.frame).overflow !== 'hidden';
|
||||
return {
|
||||
content: {
|
||||
width: this.dom.content.offsetWidth,
|
||||
},
|
||||
box: {
|
||||
height: this.dom.box.offsetHeight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RangeItem.prototype._updateDomComponentsSizes = function(sizes) {
|
||||
this.props.content.width = sizes.content.width;
|
||||
this.height = sizes.box.height;
|
||||
this.dom.content.style.maxWidth = '';
|
||||
this.dirty = false;
|
||||
}
|
||||
|
||||
RangeItem.prototype._repaintDomAdditionals = function() {
|
||||
this._repaintOnItemUpdateTimeTooltip(this.dom.box);
|
||||
this._repaintDeleteButton(this.dom.box);
|
||||
this._repaintDragCenter();
|
||||
this._repaintDragLeft();
|
||||
this._repaintDragRight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Repaint the item
|
||||
* @param {boolean} [returnQueue=false] return the queue
|
||||
* @return {boolean} the redraw queue if returnQueue=true
|
||||
*/
|
||||
RangeItem.prototype.redraw = function(returnQueue) {
|
||||
var sizes;
|
||||
var queue = [
|
||||
// create item DOM
|
||||
this._createDomElement.bind(this),
|
||||
|
||||
// append DOM to parent DOM
|
||||
this._appendDomElement.bind(this),
|
||||
|
||||
// update dirty DOM
|
||||
this._updateDirtyDomComponents.bind(this),
|
||||
|
||||
(function() {
|
||||
if (this.dirty) {
|
||||
sizes = this._getDomComponentsSizes.bind(this)();
|
||||
}
|
||||
}).bind(this),
|
||||
|
||||
(function() {
|
||||
if (this.dirty) {
|
||||
this._updateDomComponentsSizes.bind(this)(sizes);
|
||||
}
|
||||
}).bind(this),
|
||||
|
||||
// repaint DOM additionals
|
||||
this._repaintDomAdditionals.bind(this)
|
||||
];
|
||||
|
||||
if (returnQueue) {
|
||||
return queue;
|
||||
} else {
|
||||
var result;
|
||||
queue.forEach(function (fn) {
|
||||
result = fn();
|
||||
});
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Show the item in the DOM (when not already visible). The items DOM will
|
||||
* be created when needed.
|
||||
*/
|
||||
RangeItem.prototype.show = function() {
|
||||
if (!this.displayed) {
|
||||
this.redraw();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide the item from the DOM (when visible)
|
||||
*/
|
||||
RangeItem.prototype.hide = function() {
|
||||
if (this.displayed) {
|
||||
var box = this.dom.box;
|
||||
|
||||
if (box.parentNode) {
|
||||
box.parentNode.removeChild(box);
|
||||
}
|
||||
|
||||
this.displayed = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reposition the item horizontally
|
||||
* @param {boolean} [limitSize=true] If true (default), the width of the range
|
||||
* item will be limited, as the browser cannot
|
||||
* display very wide divs. This means though
|
||||
* that the applied left and width may
|
||||
* not correspond to the ranges start and end
|
||||
* @Override
|
||||
*/
|
||||
RangeItem.prototype.repositionX = function(limitSize) {
|
||||
var parentWidth = this.parent.width;
|
||||
var start = this.conversion.toScreen(this.data.start);
|
||||
var end = this.conversion.toScreen(this.data.end);
|
||||
var align = this.data.align === undefined ? this.options.align : this.data.align;
|
||||
var contentStartPosition;
|
||||
var contentWidth;
|
||||
|
||||
// limit the width of the range, as browsers cannot draw very wide divs
|
||||
// unless limitSize: false is explicitly set in item data
|
||||
if (this.data.limitSize !== false && (limitSize === undefined || limitSize === true)) {
|
||||
if (start < -parentWidth) {
|
||||
start = -parentWidth;
|
||||
}
|
||||
if (end > 2 * parentWidth) {
|
||||
end = 2 * parentWidth;
|
||||
}
|
||||
}
|
||||
|
||||
// add 0.5 to compensate floating-point values rounding
|
||||
var boxWidth = Math.max(end - start + 0.5, 1);
|
||||
|
||||
if (this.overflow) {
|
||||
if (this.options.rtl) {
|
||||
this.right = start;
|
||||
} else {
|
||||
this.left = start;
|
||||
}
|
||||
this.width = boxWidth + this.props.content.width;
|
||||
contentWidth = this.props.content.width;
|
||||
|
||||
// Note: The calculation of width is an optimistic calculation, giving
|
||||
// a width which will not change when moving the Timeline
|
||||
// So no re-stacking needed, which is nicer for the eye;
|
||||
}
|
||||
else {
|
||||
if (this.options.rtl) {
|
||||
this.right = start;
|
||||
} else {
|
||||
this.left = start;
|
||||
}
|
||||
this.width = boxWidth;
|
||||
contentWidth = Math.min(end - start, this.props.content.width);
|
||||
}
|
||||
|
||||
if (this.options.rtl) {
|
||||
this.dom.box.style.right = this.right + 'px';
|
||||
} else {
|
||||
this.dom.box.style.left = this.left + 'px';
|
||||
}
|
||||
this.dom.box.style.width = boxWidth + 'px';
|
||||
|
||||
switch (align) {
|
||||
case 'left':
|
||||
if (this.options.rtl) {
|
||||
this.dom.content.style.right = '0';
|
||||
} else {
|
||||
this.dom.content.style.left = '0';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'right':
|
||||
if (this.options.rtl) {
|
||||
this.dom.content.style.right = Math.max((boxWidth - contentWidth), 0) + 'px';
|
||||
} else {
|
||||
this.dom.content.style.left = Math.max((boxWidth - contentWidth), 0) + 'px';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'center':
|
||||
if (this.options.rtl) {
|
||||
this.dom.content.style.right = Math.max((boxWidth - contentWidth) / 2, 0) + 'px';
|
||||
} else {
|
||||
this.dom.content.style.left = Math.max((boxWidth - contentWidth) / 2, 0) + 'px';
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default: // 'auto'
|
||||
// when range exceeds left of the window, position the contents at the left of the visible area
|
||||
if (this.overflow) {
|
||||
if (end > 0) {
|
||||
contentStartPosition = Math.max(-start, 0);
|
||||
}
|
||||
else {
|
||||
contentStartPosition = -contentWidth; // ensure it's not visible anymore
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (start < 0) {
|
||||
contentStartPosition = -start;
|
||||
}
|
||||
else {
|
||||
contentStartPosition = 0;
|
||||
}
|
||||
}
|
||||
if (this.options.rtl) {
|
||||
this.dom.content.style.right = contentStartPosition + 'px';
|
||||
} else {
|
||||
this.dom.content.style.left = contentStartPosition + 'px';
|
||||
this.dom.content.style.width = 'calc(100% - ' + contentStartPosition + 'px)';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reposition the item vertically
|
||||
* @Override
|
||||
*/
|
||||
RangeItem.prototype.repositionY = function() {
|
||||
var orientation = this.options.orientation.item;
|
||||
var box = this.dom.box;
|
||||
|
||||
if (orientation == 'top') {
|
||||
box.style.top = this.top + 'px';
|
||||
}
|
||||
else {
|
||||
box.style.top = (this.parent.height - this.top - this.height) + 'px';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Repaint a drag area on the left side of the range when the range is selected
|
||||
* @protected
|
||||
*/
|
||||
RangeItem.prototype._repaintDragLeft = function () {
|
||||
if ((this.selected || this.options.itemsAlwaysDraggable.range) && this.options.editable.updateTime && !this.dom.dragLeft) {
|
||||
// create and show drag area
|
||||
var dragLeft = document.createElement('div');
|
||||
dragLeft.className = 'vis-drag-left';
|
||||
dragLeft.dragLeftItem = this;
|
||||
|
||||
this.dom.box.appendChild(dragLeft);
|
||||
this.dom.dragLeft = dragLeft;
|
||||
}
|
||||
else if (!this.selected && !this.options.itemsAlwaysDraggable.range && this.dom.dragLeft) {
|
||||
// delete drag area
|
||||
if (this.dom.dragLeft.parentNode) {
|
||||
this.dom.dragLeft.parentNode.removeChild(this.dom.dragLeft);
|
||||
}
|
||||
this.dom.dragLeft = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Repaint a drag area on the right side of the range when the range is selected
|
||||
* @protected
|
||||
*/
|
||||
RangeItem.prototype._repaintDragRight = function () {
|
||||
if ((this.selected || this.options.itemsAlwaysDraggable.range) && this.options.editable.updateTime && !this.dom.dragRight) {
|
||||
// create and show drag area
|
||||
var dragRight = document.createElement('div');
|
||||
dragRight.className = 'vis-drag-right';
|
||||
dragRight.dragRightItem = this;
|
||||
|
||||
this.dom.box.appendChild(dragRight);
|
||||
this.dom.dragRight = dragRight;
|
||||
}
|
||||
else if (!this.selected && !this.options.itemsAlwaysDraggable.range && this.dom.dragRight) {
|
||||
// delete drag area
|
||||
if (this.dom.dragRight.parentNode) {
|
||||
this.dom.dragRight.parentNode.removeChild(this.dom.dragRight);
|
||||
}
|
||||
this.dom.dragRight = null;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = RangeItem;
|
||||
Reference in New Issue
Block a user