vendor/assets/vis/timeline/component/TimeAxis.js in vis-rails-1.0.2 vs vendor/assets/vis/timeline/component/TimeAxis.js in vis-rails-2.0.0
- old
+ new
@@ -1,16 +1,16 @@
/**
* 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 (options) {
- this.id = util.randomUUID();
-
+function TimeAxis (body, options) {
this.dom = {
+ foreground: null,
majorLines: [],
majorTexts: [],
minorLines: [],
minorTexts: [],
redundant: {
@@ -27,139 +27,142 @@
minimumStep: 0
},
lineTop: 0
};
- this.options = options || {};
this.defaultOptions = {
orientation: 'bottom', // supported: 'top', 'bottom'
// TODO: implement timeaxis orientations 'left' and 'right'
showMinorLabels: true,
showMajorLabels: true
};
+ this.options = util.extend({}, this.defaultOptions);
- this.range = null;
+ this.body = body;
// create the HTML DOM
this._create();
+
+ this.setOptions(options);
}
TimeAxis.prototype = new Component();
-// TODO: comment options
-TimeAxis.prototype.setOptions = Component.prototype.setOptions;
-
/**
- * Create the HTML DOM for the TimeAxis
+ * Set options for the TimeAxis.
+ * Parameters will be merged in current options.
+ * @param {Object} options Available options:
+ * {string} [orientation]
+ * {boolean} [showMinorLabels]
+ * {boolean} [showMajorLabels]
*/
-TimeAxis.prototype._create = function _create() {
- this.frame = document.createElement('div');
+TimeAxis.prototype.setOptions = function(options) {
+ if (options) {
+ // copy all options that we know
+ util.selectiveExtend(['orientation', 'showMinorLabels', 'showMajorLabels'], this.options, options);
+ }
};
/**
- * Set a range (start and end)
- * @param {Range | Object} range A Range or an object containing start and end.
+ * Create the HTML DOM for the TimeAxis
*/
-TimeAxis.prototype.setRange = function (range) {
- if (!(range instanceof Range) && (!range || !range.start || !range.end)) {
- throw new TypeError('Range must be an instance of Range, ' +
- 'or an object containing start and end.');
- }
- this.range = range;
+TimeAxis.prototype._create = function() {
+ this.dom.foreground = document.createElement('div');
+ this.dom.background = document.createElement('div');
+
+ this.dom.foreground.className = 'timeaxis foreground';
+ this.dom.background.className = 'timeaxis background';
};
/**
- * Get the outer frame of the time axis
- * @return {HTMLElement} frame
+ * Destroy the TimeAxis
*/
-TimeAxis.prototype.getFrame = function getFrame() {
- return this.frame;
+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.repaint = function () {
- var asSize = util.option.asSize,
- options = this.options,
+TimeAxis.prototype.redraw = function () {
+ var options = this.options,
props = this.props,
- frame = this.frame;
+ foreground = this.dom.foreground,
+ background = this.dom.background;
- // update classname
- frame.className = 'timeaxis'; // TODO: add className from options if defined
+ // determine the correct parent DOM element (depending on option orientation)
+ var parent = (options.orientation == 'top') ? this.body.dom.top : this.body.dom.bottom;
+ var parentChanged = (foreground.parentNode !== parent);
- var parent = frame.parentNode;
- if (parent) {
- // calculate character width and height
- this._calculateCharSize();
+ // calculate character width and height
+ this._calculateCharSize();
- // TODO: recalculate sizes only needed when parent is resized or options is changed
- var orientation = this.getOption('orientation'),
- showMinorLabels = this.getOption('showMinorLabels'),
- showMajorLabels = this.getOption('showMajorLabels');
+ // TODO: recalculate sizes only needed when parent is resized or options is changed
+ var orientation = this.options.orientation,
+ showMinorLabels = this.options.showMinorLabels,
+ showMajorLabels = this.options.showMajorLabels;
- // determine the width and height of the elemens for the axis
- var parentHeight = this.parent.height;
- props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0;
- props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0;
- this.height = props.minorLabelHeight + props.majorLabelHeight;
- this.width = frame.offsetWidth; // TODO: only update the width when the frame is resized?
+ // 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 = parentHeight + props.minorLabelHeight;
- props.minorLineWidth = 1; // TODO: really calculate width
- props.majorLineHeight = parentHeight + this.height;
- props.majorLineWidth = 1; // TODO: really calculate width
+ props.minorLineHeight = this.body.domProps.root.height - props.majorLabelHeight -
+ (options.orientation == '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 frame offline while updating (is almost twice as fast)
- var beforeChild = frame.nextSibling;
- parent.removeChild(frame);
+ // 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);
- // TODO: top/bottom positioning should be determined by options set in the Timeline, not here
- if (orientation == 'top') {
- frame.style.top = '0';
- frame.style.left = '0';
- frame.style.bottom = '';
- frame.style.width = asSize(options.width, '100%');
- frame.style.height = this.height + 'px';
- }
- else { // bottom
- frame.style.top = '';
- frame.style.bottom = '0';
- frame.style.left = '0';
- frame.style.width = asSize(options.width, '100%');
- frame.style.height = this.height + 'px';
- }
+ foreground.style.height = this.props.height + 'px';
- this._repaintLabels();
+ this._repaintLabels();
- this._repaintLine();
-
- // put frame online again
- if (beforeChild) {
- parent.insertBefore(frame, beforeChild);
- }
- else {
- parent.appendChild(frame)
- }
+ // 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();
+ return this._isResized() || parentChanged;
};
/**
* Repaint major and minor text labels and vertical grid lines
* @private
*/
TimeAxis.prototype._repaintLabels = function () {
- var orientation = this.getOption('orientation');
+ var orientation = this.options.orientation;
// calculate range and step (step such that we have space for 7 characters per label)
- var start = util.convert(this.range.start, 'Number'),
- end = util.convert(this.range.end, 'Number'),
- minimumStep = this.options.toTime((this.props.minorCharWidth || 10) * 7).valueOf()
- -this.options.toTime(0).valueOf();
+ var start = util.convert(this.body.range.start, 'Number'),
+ end = util.convert(this.body.range.end, 'Number'),
+ minimumStep = this.body.util.toTime((this.props.minorCharWidth || 10) * 7).valueOf()
+ -this.body.util.toTime(0).valueOf();
var step = new TimeStep(new Date(start), new Date(end), minimumStep);
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.
@@ -178,20 +181,20 @@
var xFirstMajorLabel = undefined;
var max = 0;
while (step.hasNext() && max < 1000) {
max++;
var cur = step.getCurrent(),
- x = this.options.toScreen(cur),
+ x = this.body.util.toScreen(cur),
isMajor = step.isMajor();
// TODO: lines must have a width, such that we can create css backgrounds
- if (this.getOption('showMinorLabels')) {
+ if (this.options.showMinorLabels) {
this._repaintMinorText(x, step.getLabelMinor(), orientation);
}
- if (isMajor && this.getOption('showMajorLabels')) {
+ if (isMajor && this.options.showMajorLabels) {
if (x > 0) {
if (xFirstMajorLabel == undefined) {
xFirstMajorLabel = x;
}
this._repaintMajorText(x, step.getLabelMajor(), orientation);
@@ -204,12 +207,12 @@
step.next();
}
// create a major label on the left when needed
- if (this.getOption('showMajorLabels')) {
- var leftTime = this.options.toTime(0),
+ 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);
@@ -242,24 +245,17 @@
// create new label
var content = document.createTextNode('');
label = document.createElement('div');
label.appendChild(content);
label.className = 'text minor';
- this.frame.appendChild(label);
+ this.dom.foreground.appendChild(label);
}
this.dom.minorTexts.push(label);
label.childNodes[0].nodeValue = text;
- if (orientation == 'top') {
- label.style.top = this.props.majorLabelHeight + 'px';
- label.style.bottom = '';
- }
- else {
- label.style.top = '';
- label.style.bottom = this.props.majorLabelHeight + 'px';
- }
+ label.style.top = (orientation == 'top') ? (this.props.majorLabelHeight + 'px') : '0';
label.style.left = x + 'px';
//label.title = title; // TODO: this is a heavy operation
};
/**
@@ -277,25 +273,18 @@
// create label
var content = document.createTextNode(text);
label = document.createElement('div');
label.className = 'text major';
label.appendChild(content);
- this.frame.appendChild(label);
+ this.dom.foreground.appendChild(label);
}
this.dom.majorTexts.push(label);
label.childNodes[0].nodeValue = text;
//label.title = title; // TODO: this is a heavy operation
- if (orientation == 'top') {
- label.style.top = '0px';
- label.style.bottom = '';
- }
- else {
- label.style.top = '';
- label.style.bottom = '0px';
- }
+ label.style.top = (orientation == 'top') ? '0' : (this.props.minorLabelHeight + 'px');
label.style.left = x + 'px';
};
/**
* Create a minor line for the axis at position x
@@ -309,22 +298,20 @@
if (!line) {
// create vertical line
line = document.createElement('div');
line.className = 'grid vertical minor';
- this.frame.appendChild(line);
+ this.dom.background.appendChild(line);
}
this.dom.minorLines.push(line);
var props = this.props;
if (orientation == 'top') {
- line.style.top = this.props.majorLabelHeight + 'px';
- line.style.bottom = '';
+ line.style.top = props.majorLabelHeight + 'px';
}
else {
- line.style.top = '';
- line.style.bottom = this.props.majorLabelHeight + 'px';
+ line.style.top = this.body.domProps.top.height + 'px';
}
line.style.height = props.minorLineHeight + 'px';
line.style.left = (x - props.minorLineWidth / 2) + 'px';
};
@@ -340,86 +327,42 @@
if (!line) {
// create vertical line
line = document.createElement('DIV');
line.className = 'grid vertical major';
- this.frame.appendChild(line);
+ this.dom.background.appendChild(line);
}
this.dom.majorLines.push(line);
var props = this.props;
if (orientation == 'top') {
- line.style.top = '0px';
- line.style.bottom = '';
+ line.style.top = '0';
}
else {
- line.style.top = '';
- line.style.bottom = '0px';
+ line.style.top = this.body.domProps.top.height + 'px';
}
line.style.left = (x - props.majorLineWidth / 2) + 'px';
line.style.height = props.majorLineHeight + 'px';
};
-
/**
- * Repaint the horizontal line for the axis
- * @private
- */
-TimeAxis.prototype._repaintLine = function() {
- var line = this.dom.line,
- frame = this.frame,
- orientation = this.getOption('orientation');
-
- // line before all axis elements
- if (this.getOption('showMinorLabels') || this.getOption('showMajorLabels')) {
- if (line) {
- // put this line at the end of all childs
- frame.removeChild(line);
- frame.appendChild(line);
- }
- else {
- // create the axis line
- line = document.createElement('div');
- line.className = 'grid horizontal major';
- frame.appendChild(line);
- this.dom.line = line;
- }
-
- if (orientation == 'top') {
- line.style.top = this.height + 'px';
- line.style.bottom = '';
- }
- else {
- line.style.top = '';
- line.style.bottom = this.height + 'px';
- }
- }
- else {
- if (line && line.parentNode) {
- line.parentNode.removeChild(line);
- delete this.dom.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 repaint. Size may change, for
+ // 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 = 'text minor measure';
this.dom.measureCharMinor.style.position = 'absolute';
this.dom.measureCharMinor.appendChild(document.createTextNode('0'));
- this.frame.appendChild(this.dom.measureCharMinor);
+ 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
@@ -427,11 +370,11 @@
this.dom.measureCharMajor = document.createElement('DIV');
this.dom.measureCharMajor.className = 'text minor measure';
this.dom.measureCharMajor.style.position = 'absolute';
this.dom.measureCharMajor.appendChild(document.createTextNode('0'));
- this.frame.appendChild(this.dom.measureCharMajor);
+ this.dom.foreground.appendChild(this.dom.measureCharMajor);
}
this.props.majorCharHeight = this.dom.measureCharMajor.clientHeight;
this.props.majorCharWidth = this.dom.measureCharMajor.clientWidth;
};
@@ -439,8 +382,8 @@
* Snap a date to a rounded value.
* The snap intervals are dependent on the current scale and step.
* @param {Date} date the date to be snapped.
* @return {Date} snappedDate
*/
-TimeAxis.prototype.snap = function snap (date) {
+TimeAxis.prototype.snap = function(date) {
return this.step.snap(date);
};