|
@ -4,8 +4,8 @@ |
|
|
* |
|
|
* |
|
|
* A dynamic, browser-based visualization library. |
|
|
* A dynamic, browser-based visualization library. |
|
|
* |
|
|
* |
|
|
* @version 1.1.0 |
|
|
|
|
|
* @date 2014-06-13 |
|
|
|
|
|
|
|
|
* @version @@version |
|
|
|
|
|
* @date @@date |
|
|
* |
|
|
* |
|
|
* @license |
|
|
* @license |
|
|
* Copyright (C) 2011-2014 Almende B.V, http://almende.com
|
|
|
* Copyright (C) 2011-2014 Almende B.V, http://almende.com
|
|
@ -2544,9 +2544,19 @@ DataView.prototype.unsubscribe = DataView.prototype.off; |
|
|
* @constructor DataAxis |
|
|
* @constructor DataAxis |
|
|
* @extends Component |
|
|
* @extends Component |
|
|
*/ |
|
|
*/ |
|
|
function DataAxis (options) { |
|
|
|
|
|
|
|
|
function DataAxis (body, options) { |
|
|
this.id = util.randomUUID(); |
|
|
this.id = util.randomUUID(); |
|
|
|
|
|
this.body = body; |
|
|
|
|
|
|
|
|
|
|
|
this.defaultOptions = { |
|
|
|
|
|
orientation: 'left', // supported: 'left'
|
|
|
|
|
|
showMinorLabels: true, |
|
|
|
|
|
showMajorLabels: true, |
|
|
|
|
|
width: '90px', |
|
|
|
|
|
height: '300px' |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
this.props = {}; |
|
|
this.dom = { |
|
|
this.dom = { |
|
|
majorLines: [], |
|
|
majorLines: [], |
|
|
majorTexts: [], |
|
|
majorTexts: [], |
|
@ -2559,23 +2569,17 @@ function DataAxis (options) { |
|
|
minorTexts: [] |
|
|
minorTexts: [] |
|
|
} |
|
|
} |
|
|
}; |
|
|
}; |
|
|
this.props = { |
|
|
|
|
|
range: { |
|
|
|
|
|
start: 0, |
|
|
|
|
|
end: 0, |
|
|
|
|
|
minimumStep: 0 |
|
|
|
|
|
}, |
|
|
|
|
|
lineTop: 0 |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
this.options = options || {}; |
|
|
|
|
|
this.defaultOptions = { |
|
|
|
|
|
orientation: 'left', // supported: 'left'
|
|
|
|
|
|
showMinorLabels: true, |
|
|
|
|
|
showMajorLabels: true |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
// this.yRange = new Range(body,{
|
|
|
|
|
|
// direction: 'vertical',
|
|
|
|
|
|
// min: null,
|
|
|
|
|
|
// max: null,
|
|
|
|
|
|
// zoomMin: 1e-5,
|
|
|
|
|
|
// zoomMax: 1e9
|
|
|
|
|
|
// });
|
|
|
|
|
|
this.yRange = {start:0, end:0}; |
|
|
|
|
|
|
|
|
this.range = null; |
|
|
|
|
|
|
|
|
this.options = util.extend({}, this.defaultOptions); |
|
|
this.conversionFactor = 1; |
|
|
this.conversionFactor = 1; |
|
|
|
|
|
|
|
|
// create the HTML DOM
|
|
|
// create the HTML DOM
|
|
@ -2583,71 +2587,95 @@ function DataAxis (options) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
DataAxis.prototype = new Component(); |
|
|
DataAxis.prototype = new Component(); |
|
|
|
|
|
|
|
|
// TODO: comment options
|
|
|
|
|
|
DataAxis.prototype.setOptions = Component.prototype.setOptions; |
|
|
DataAxis.prototype.setOptions = Component.prototype.setOptions; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Create the HTML DOM for the DataAxis |
|
|
* Create the HTML DOM for the DataAxis |
|
|
*/ |
|
|
*/ |
|
|
DataAxis.prototype._create = function _create() { |
|
|
|
|
|
this.frame = document.createElement('div'); |
|
|
|
|
|
|
|
|
DataAxis.prototype._create = function() { |
|
|
|
|
|
this.dom.frame = document.createElement('div'); |
|
|
|
|
|
this.dom.frame.style.width = this.options.width; |
|
|
|
|
|
this.dom.frame.style.height = this.options.height; |
|
|
|
|
|
|
|
|
|
|
|
this.dom.lineContainer = document.createElement('div'); |
|
|
|
|
|
this.dom.lineContainer.style.width = '100%'; |
|
|
|
|
|
this.dom.lineContainer.style.height = this.options.height; |
|
|
|
|
|
|
|
|
|
|
|
this.show(); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 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 DataAxis |
|
|
*/ |
|
|
*/ |
|
|
DataAxis.prototype.setRange = function (range) { |
|
|
|
|
|
if (!(range instanceof Range) && (!range || range.start === undefined || range.end === undefined)) { |
|
|
|
|
|
throw new TypeError('Range must be an instance of Range, ' + |
|
|
|
|
|
'or an object containing start and end.'); |
|
|
|
|
|
|
|
|
DataAxis.prototype.show = function() { |
|
|
|
|
|
if (!this.dom.frame.parentNode) { |
|
|
|
|
|
if (this.options.orientation == 'left') { |
|
|
|
|
|
this.body.dom.left.appendChild(this.dom.frame); |
|
|
|
|
|
} |
|
|
|
|
|
if (this.options.orientation == 'right') { |
|
|
|
|
|
this.body.dom.right.appendChild(this.dom.frame); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (!this.dom.lineContainer.parentNode) { |
|
|
|
|
|
this.body.dom.backgroundHorizontal.appendChild(this.dom.lineContainer); |
|
|
} |
|
|
} |
|
|
this.range = range; |
|
|
|
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Get the outer frame of the time axis |
|
|
|
|
|
* @return {HTMLElement} frame |
|
|
|
|
|
|
|
|
* Create the HTML DOM for the DataAxis |
|
|
*/ |
|
|
*/ |
|
|
DataAxis.prototype.getFrame = function getFrame() { |
|
|
|
|
|
return this.frame; |
|
|
|
|
|
|
|
|
DataAxis.prototype.hide = function() { |
|
|
|
|
|
if (this.dom.frame.parentNode) { |
|
|
|
|
|
this.dom.frame.parentNode.removeChild(this.dom.frame); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (this.dom.lineContainer.parentNode) { |
|
|
|
|
|
this.body.dom.backgroundHorizontal.removeChild(this.dom.lineContainer); |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
/** |
|
|
|
|
|
* Set a range (start and end) |
|
|
|
|
|
* @param {Range | Object} range A Range or an object containing start and end. |
|
|
|
|
|
*/ |
|
|
|
|
|
DataAxis.prototype.setRange = function (range) { |
|
|
|
|
|
if (!(range instanceof Range) && (!range || range.start === undefined || range.end === undefined)) { |
|
|
|
|
|
throw new TypeError('Range must be an instance of Range, ' + 'or an object containing start and end.'); |
|
|
|
|
|
} |
|
|
|
|
|
this.yRange.start = range.start; |
|
|
|
|
|
this.yRange.end = range.end; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Repaint the component |
|
|
* Repaint the component |
|
|
* @return {boolean} Returns true if the component is resized |
|
|
* @return {boolean} Returns true if the component is resized |
|
|
*/ |
|
|
*/ |
|
|
DataAxis.prototype.repaint = function () { |
|
|
|
|
|
var asSize = util.option.asSize; |
|
|
|
|
|
var options = this.options; |
|
|
|
|
|
|
|
|
DataAxis.prototype.redraw = function () { |
|
|
var props = this.props; |
|
|
var props = this.props; |
|
|
var frame = this.frame; |
|
|
|
|
|
|
|
|
var frame = this.dom.frame; |
|
|
|
|
|
|
|
|
// update classname
|
|
|
// update classname
|
|
|
frame.className = 'dataaxis'; // TODO: add className from options if defined
|
|
|
|
|
|
|
|
|
frame.className = 'dataaxis'; |
|
|
|
|
|
|
|
|
// calculate character width and height
|
|
|
// calculate character width and height
|
|
|
this._calculateCharSize(); |
|
|
this._calculateCharSize(); |
|
|
|
|
|
|
|
|
// TODO: recalculate sizes only needed when parent is resized or options is changed
|
|
|
|
|
|
var orientation = this.options['orientation']; |
|
|
|
|
|
var showMinorLabels = this.options['showMinorLabels']; |
|
|
|
|
|
var showMajorLabels = this.options['showMajorLabels']; |
|
|
|
|
|
|
|
|
var orientation = this.options.orientation; |
|
|
|
|
|
var showMinorLabels = this.options.showMinorLabels; |
|
|
|
|
|
var showMajorLabels = this.options.showMajorLabels; |
|
|
|
|
|
|
|
|
// determine the width and height of the elemens for the axis
|
|
|
// determine the width and height of the elemens for the axis
|
|
|
props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; |
|
|
props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0; |
|
|
props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; |
|
|
props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0; |
|
|
this.height = this.options.height; |
|
|
|
|
|
this.width = frame.offsetWidth; // TODO: only update the width when the frame is resized?
|
|
|
|
|
|
|
|
|
|
|
|
props.minorLineWidth = this.options.svg.offsetWidth; |
|
|
|
|
|
props.minorLineHeight = 1; // TODO: really calculate width
|
|
|
|
|
|
props.majorLineWidth = this.options.svg.offsetWidth; |
|
|
|
|
|
props.majorLineHeight = 1; // TODO: really calculate width
|
|
|
|
|
|
|
|
|
props.minorLineWidth = 3000; |
|
|
|
|
|
props.minorLineHeight = 1; |
|
|
|
|
|
props.majorLineWidth = 3000; |
|
|
|
|
|
props.majorLineHeight = 1; |
|
|
|
|
|
|
|
|
// take frame offline while updating (is almost twice as fast)
|
|
|
// take frame offline while updating (is almost twice as fast)
|
|
|
// TODO: top/bottom positioning should be determined by options set in the Timeline, not here
|
|
|
|
|
|
if (orientation == 'left') { |
|
|
if (orientation == 'left') { |
|
|
frame.style.top = '0'; |
|
|
frame.style.top = '0'; |
|
|
frame.style.left = '0'; |
|
|
frame.style.left = '0'; |
|
@ -2663,26 +2691,26 @@ DataAxis.prototype.repaint = function () { |
|
|
frame.style.height = this.height + "px"; |
|
|
frame.style.height = this.height + "px"; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
this._repaintLabels(); |
|
|
|
|
|
|
|
|
this._redrawLabels(); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Repaint major and minor text labels and vertical grid lines |
|
|
* Repaint major and minor text labels and vertical grid lines |
|
|
* @private |
|
|
* @private |
|
|
*/ |
|
|
*/ |
|
|
DataAxis.prototype._repaintLabels = function () { |
|
|
|
|
|
|
|
|
DataAxis.prototype._redrawLabels = function () { |
|
|
var orientation = this.options['orientation']; |
|
|
var orientation = this.options['orientation']; |
|
|
|
|
|
|
|
|
// calculate range and step (step such that we have space for 7 characters per label)
|
|
|
// calculate range and step (step such that we have space for 7 characters per label)
|
|
|
var start = this.range.start; |
|
|
|
|
|
var end = this.range.end; |
|
|
|
|
|
|
|
|
var start = this.yRange.start; |
|
|
|
|
|
var end = this.yRange.end; |
|
|
var minimumStep = (this.props.minorCharHeight || 10); //in pixels
|
|
|
var minimumStep = (this.props.minorCharHeight || 10); //in pixels
|
|
|
var step = new DataStep(start, end, minimumStep, this.options.svg.offsetHeight); |
|
|
|
|
|
|
|
|
var step = new DataStep(start, end, minimumStep, this.dom.frame.offsetHeight); |
|
|
this.step = step; |
|
|
this.step = step; |
|
|
|
|
|
|
|
|
// Move all DOM elements to a "redundant" list, where they
|
|
|
// Move all DOM elements to a "redundant" list, where they
|
|
|
// can be picked for re-use, and clear the lists with lines and texts.
|
|
|
// 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
|
|
|
|
|
|
|
|
|
// At the end of the function _redrawLabels, left over elements will be cleaned up
|
|
|
var dom = this.dom; |
|
|
var dom = this.dom; |
|
|
dom.redundant.majorLines = dom.majorLines; |
|
|
dom.redundant.majorLines = dom.majorLines; |
|
|
dom.redundant.majorTexts = dom.majorTexts; |
|
|
dom.redundant.majorTexts = dom.majorTexts; |
|
@ -2694,7 +2722,7 @@ DataAxis.prototype._repaintLabels = function () { |
|
|
dom.minorTexts = []; |
|
|
dom.minorTexts = []; |
|
|
|
|
|
|
|
|
step.first(); |
|
|
step.first(); |
|
|
var stepPixels = this.options.svg.offsetHeight / ((step.marginRange / step.step) + 1); |
|
|
|
|
|
|
|
|
var stepPixels = this.dom.frame.offsetHeight / ((step.marginRange / step.step) + 1); |
|
|
var xFirstMajorLabel = undefined; |
|
|
var xFirstMajorLabel = undefined; |
|
|
|
|
|
|
|
|
this.valueAtZero = step.marginEnd; |
|
|
this.valueAtZero = step.marginEnd; |
|
@ -2706,7 +2734,7 @@ DataAxis.prototype._repaintLabels = function () { |
|
|
var isMajor = step.isMajor(); |
|
|
var isMajor = step.isMajor(); |
|
|
|
|
|
|
|
|
if (this.options['showMinorLabels'] && isMajor == false) { |
|
|
if (this.options['showMinorLabels'] && isMajor == false) { |
|
|
this._repaintMinorText(y, step.getLabelMinor(), orientation); |
|
|
|
|
|
|
|
|
this._redrawMinorText(y, step.getLabelMinor(), orientation); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (isMajor && this.options['showMajorLabels']) { |
|
|
if (isMajor && this.options['showMajorLabels']) { |
|
@ -2714,12 +2742,12 @@ DataAxis.prototype._repaintLabels = function () { |
|
|
if (xFirstMajorLabel == undefined) { |
|
|
if (xFirstMajorLabel == undefined) { |
|
|
xFirstMajorLabel = y; |
|
|
xFirstMajorLabel = y; |
|
|
} |
|
|
} |
|
|
this._repaintMajorText(y, step.getLabelMajor(), orientation); |
|
|
|
|
|
|
|
|
this._redrawMajorText(y, step.getLabelMajor(), orientation); |
|
|
} |
|
|
} |
|
|
this._repaintMajorLine(y, orientation); |
|
|
|
|
|
|
|
|
this._redrawMajorLine(y, orientation); |
|
|
} |
|
|
} |
|
|
else { |
|
|
else { |
|
|
this._repaintMinorLine(y, orientation); |
|
|
|
|
|
|
|
|
this._redrawMinorLine(y, orientation); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
step.next(); |
|
|
step.next(); |
|
@ -2728,9 +2756,6 @@ DataAxis.prototype._repaintLabels = function () { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
this.conversionFactor = marginStartPos/step.marginRange; |
|
|
this.conversionFactor = marginStartPos/step.marginRange; |
|
|
console.log(marginStartPos, step.marginRange, this.conversionFactor); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// create a major label on the left when needed
|
|
|
// create a major label on the left when needed
|
|
|
if (this.options['showMajorLabels']) { |
|
|
if (this.options['showMajorLabels']) { |
|
@ -2739,7 +2764,7 @@ DataAxis.prototype._repaintLabels = function () { |
|
|
var widthText = leftText.length * (this.props.majorCharWidth || 10) + 10; // upper bound estimation
|
|
|
var widthText = leftText.length * (this.props.majorCharWidth || 10) + 10; // upper bound estimation
|
|
|
|
|
|
|
|
|
if (xFirstMajorLabel == undefined || widthText < xFirstMajorLabel) { |
|
|
if (xFirstMajorLabel == undefined || widthText < xFirstMajorLabel) { |
|
|
this._repaintMajorText(0, leftText, orientation); |
|
|
|
|
|
|
|
|
this._redrawMajorText(0, leftText, orientation); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -2764,7 +2789,7 @@ DataAxis.prototype.convertValues = function(data) { |
|
|
DataAxis.prototype._getPos = function(value) { |
|
|
DataAxis.prototype._getPos = function(value) { |
|
|
var invertedValue = this.valueAtZero - value; |
|
|
var invertedValue = this.valueAtZero - value; |
|
|
var convertedValue = invertedValue * this.conversionFactor; |
|
|
var convertedValue = invertedValue * this.conversionFactor; |
|
|
return convertedValue |
|
|
|
|
|
|
|
|
return convertedValue - 2; // the -2 is to compensate for the borders
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
@ -2774,7 +2799,7 @@ DataAxis.prototype._getPos = function(value) { |
|
|
* @param {String} orientation "top" or "bottom" (default) |
|
|
* @param {String} orientation "top" or "bottom" (default) |
|
|
* @private |
|
|
* @private |
|
|
*/ |
|
|
*/ |
|
|
DataAxis.prototype._repaintMinorText = function (x, text, orientation) { |
|
|
|
|
|
|
|
|
DataAxis.prototype._redrawMinorText = function (x, text, orientation) { |
|
|
// reuse redundant label
|
|
|
// reuse redundant label
|
|
|
var label = this.dom.redundant.minorTexts.shift(); |
|
|
var label = this.dom.redundant.minorTexts.shift(); |
|
|
|
|
|
|
|
@ -2784,7 +2809,7 @@ DataAxis.prototype._repaintMinorText = function (x, text, orientation) { |
|
|
label = document.createElement('div'); |
|
|
label = document.createElement('div'); |
|
|
label.appendChild(content); |
|
|
label.appendChild(content); |
|
|
label.className = 'yAxis minor'; |
|
|
label.className = 'yAxis minor'; |
|
|
this.frame.appendChild(label); |
|
|
|
|
|
|
|
|
this.dom.frame.appendChild(label); |
|
|
} |
|
|
} |
|
|
this.dom.minorTexts.push(label); |
|
|
this.dom.minorTexts.push(label); |
|
|
|
|
|
|
|
@ -2810,7 +2835,7 @@ DataAxis.prototype._repaintMinorText = function (x, text, orientation) { |
|
|
* @param {String} orientation "top" or "bottom" (default) |
|
|
* @param {String} orientation "top" or "bottom" (default) |
|
|
* @private |
|
|
* @private |
|
|
*/ |
|
|
*/ |
|
|
DataAxis.prototype._repaintMajorText = function (x, text, orientation) { |
|
|
|
|
|
|
|
|
DataAxis.prototype._redrawMajorText = function (x, text, orientation) { |
|
|
// reuse redundant label
|
|
|
// reuse redundant label
|
|
|
var label = this.dom.redundant.majorTexts.shift(); |
|
|
var label = this.dom.redundant.majorTexts.shift(); |
|
|
|
|
|
|
|
@ -2820,7 +2845,7 @@ DataAxis.prototype._repaintMajorText = function (x, text, orientation) { |
|
|
label = document.createElement('div'); |
|
|
label = document.createElement('div'); |
|
|
label.className = 'yAxis major'; |
|
|
label.className = 'yAxis major'; |
|
|
label.appendChild(content); |
|
|
label.appendChild(content); |
|
|
this.frame.appendChild(label); |
|
|
|
|
|
|
|
|
this.dom.frame.appendChild(label); |
|
|
} |
|
|
} |
|
|
this.dom.majorTexts.push(label); |
|
|
this.dom.majorTexts.push(label); |
|
|
|
|
|
|
|
@ -2845,7 +2870,7 @@ DataAxis.prototype._repaintMajorText = function (x, text, orientation) { |
|
|
* @param {String} orientation "top" or "bottom" (default) |
|
|
* @param {String} orientation "top" or "bottom" (default) |
|
|
* @private |
|
|
* @private |
|
|
*/ |
|
|
*/ |
|
|
DataAxis.prototype._repaintMinorLine = function (y, orientation) { |
|
|
|
|
|
|
|
|
DataAxis.prototype._redrawMinorLine = function (y, orientation) { |
|
|
// reuse redundant line
|
|
|
// reuse redundant line
|
|
|
var line = this.dom.redundant.minorLines.shift(); |
|
|
var line = this.dom.redundant.minorLines.shift(); |
|
|
|
|
|
|
|
@ -2853,7 +2878,7 @@ DataAxis.prototype._repaintMinorLine = function (y, orientation) { |
|
|
// create vertical line
|
|
|
// create vertical line
|
|
|
line = document.createElement('div'); |
|
|
line = document.createElement('div'); |
|
|
line.className = 'grid horizontal minor'; |
|
|
line.className = 'grid horizontal minor'; |
|
|
this.frame.appendChild(line); |
|
|
|
|
|
|
|
|
this.dom.lineContainer.appendChild(line); |
|
|
} |
|
|
} |
|
|
this.dom.minorLines.push(line); |
|
|
this.dom.minorLines.push(line); |
|
|
|
|
|
|
|
@ -2875,7 +2900,7 @@ DataAxis.prototype._repaintMinorLine = function (y, orientation) { |
|
|
* @param {String} orientation "top" or "bottom" (default) |
|
|
* @param {String} orientation "top" or "bottom" (default) |
|
|
* @private |
|
|
* @private |
|
|
*/ |
|
|
*/ |
|
|
DataAxis.prototype._repaintMajorLine = function (y, orientation) { |
|
|
|
|
|
|
|
|
DataAxis.prototype._redrawMajorLine = function (y, orientation) { |
|
|
// reuse redundant line
|
|
|
// reuse redundant line
|
|
|
var line = this.dom.redundant.majorLines.shift(); |
|
|
var line = this.dom.redundant.majorLines.shift(); |
|
|
|
|
|
|
|
@ -2883,7 +2908,7 @@ DataAxis.prototype._repaintMajorLine = function (y, orientation) { |
|
|
// create vertical line
|
|
|
// create vertical line
|
|
|
line = document.createElement('div'); |
|
|
line = document.createElement('div'); |
|
|
line.className = 'grid horizontal major'; |
|
|
line.className = 'grid horizontal major'; |
|
|
this.frame.appendChild(line); |
|
|
|
|
|
|
|
|
this.dom.lineContainer.appendChild(line); |
|
|
} |
|
|
} |
|
|
this.dom.majorLines.push(line); |
|
|
this.dom.majorLines.push(line); |
|
|
|
|
|
|
|
@ -2911,12 +2936,12 @@ DataAxis.prototype._calculateCharSize = function () { |
|
|
var measureCharMinor = document.createElement('DIV'); |
|
|
var measureCharMinor = document.createElement('DIV'); |
|
|
measureCharMinor.className = 'text minor measure'; |
|
|
measureCharMinor.className = 'text minor measure'; |
|
|
measureCharMinor.appendChild(textMinor); |
|
|
measureCharMinor.appendChild(textMinor); |
|
|
this.frame.appendChild(measureCharMinor); |
|
|
|
|
|
|
|
|
this.dom.frame.appendChild(measureCharMinor); |
|
|
|
|
|
|
|
|
this.props.minorCharHeight = measureCharMinor.clientHeight; |
|
|
this.props.minorCharHeight = measureCharMinor.clientHeight; |
|
|
this.props.minorCharWidth = measureCharMinor.clientWidth; |
|
|
this.props.minorCharWidth = measureCharMinor.clientWidth; |
|
|
|
|
|
|
|
|
this.frame.removeChild(measureCharMinor); |
|
|
|
|
|
|
|
|
this.dom.frame.removeChild(measureCharMinor); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (!('majorCharHeight' in this.props)) { |
|
|
if (!('majorCharHeight' in this.props)) { |
|
@ -2924,12 +2949,12 @@ DataAxis.prototype._calculateCharSize = function () { |
|
|
var measureCharMajor = document.createElement('DIV'); |
|
|
var measureCharMajor = document.createElement('DIV'); |
|
|
measureCharMajor.className = 'text major measure'; |
|
|
measureCharMajor.className = 'text major measure'; |
|
|
measureCharMajor.appendChild(textMajor); |
|
|
measureCharMajor.appendChild(textMajor); |
|
|
this.frame.appendChild(measureCharMajor); |
|
|
|
|
|
|
|
|
this.dom.frame.appendChild(measureCharMajor); |
|
|
|
|
|
|
|
|
this.props.majorCharHeight = measureCharMajor.clientHeight; |
|
|
this.props.majorCharHeight = measureCharMajor.clientHeight; |
|
|
this.props.majorCharWidth = measureCharMajor.clientWidth; |
|
|
this.props.majorCharWidth = measureCharMajor.clientWidth; |
|
|
|
|
|
|
|
|
this.frame.removeChild(measureCharMajor); |
|
|
|
|
|
|
|
|
this.dom.frame.removeChild(measureCharMajor); |
|
|
} |
|
|
} |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
@ -2939,7 +2964,7 @@ DataAxis.prototype._calculateCharSize = function () { |
|
|
* @param {Date} date the date to be snapped. |
|
|
* @param {Date} date the date to be snapped. |
|
|
* @return {Date} snappedDate |
|
|
* @return {Date} snappedDate |
|
|
*/ |
|
|
*/ |
|
|
DataAxis.prototype.snap = function snap (date) { |
|
|
|
|
|
|
|
|
DataAxis.prototype.snap = function(date) { |
|
|
return this.step.snap(date); |
|
|
return this.step.snap(date); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
@ -3014,25 +3039,32 @@ function Linegraph(body, options) { |
|
|
|
|
|
|
|
|
this.items = {}; // object with an Item for every data item
|
|
|
this.items = {}; // object with an Item for every data item
|
|
|
this.selection = []; // list with the ids of all selected nodes
|
|
|
this.selection = []; // list with the ids of all selected nodes
|
|
|
|
|
|
|
|
|
|
|
|
this.lastStart = this.body.range.start; |
|
|
this.touchParams = {}; // stores properties while dragging
|
|
|
this.touchParams = {}; // stores properties while dragging
|
|
|
// create the HTML DOM
|
|
|
// create the HTML DOM
|
|
|
|
|
|
|
|
|
this._create(); |
|
|
this._create(); |
|
|
this.body.emitter.on("drag", this._onDrag.bind(this)) |
|
|
|
|
|
this.body.emitter.on("dragEnd", this._onDragEnd.bind(this)) |
|
|
|
|
|
|
|
|
|
|
|
this.setOptions(options); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
var me = this; |
|
|
|
|
|
|
|
|
Linegraph.prototype._onDrag = function (event) { |
|
|
|
|
|
if (this.svg) { |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
this.body.emitter.on("rangechange",function() { |
|
|
|
|
|
if (me.lastStart != 0) { |
|
|
|
|
|
var offset = me.body.range.start - me.lastStart; |
|
|
|
|
|
var range = me.body.range.end - me.body.range.start; |
|
|
|
|
|
if (me.width != 0) { |
|
|
|
|
|
var rangePerPixelInv = me.width/range; |
|
|
|
|
|
var xOffset = offset * rangePerPixelInv; |
|
|
|
|
|
me.svg.style.left = (-me.width - xOffset) + "px"; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
this.body.emitter.on("rangechanged", function() { |
|
|
|
|
|
me.lastStart = me.body.range.start; |
|
|
|
|
|
me.svg.style.left = util.option.asSize(-me.width); |
|
|
|
|
|
me.updateGraph.apply(me); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
Linegraph.prototype._onDragEnd = function (event) { |
|
|
|
|
|
this.updateGraph(); |
|
|
|
|
|
|
|
|
this.setOptions(options); |
|
|
|
|
|
this.body.emitter.emit("change"); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Linegraph.prototype = new Component(); |
|
|
Linegraph.prototype = new Component(); |
|
@ -3069,6 +3101,7 @@ Linegraph.prototype._create = function(){ |
|
|
this.svg = document.createElementNS('http://www.w3.org/2000/svg',"svg"); |
|
|
this.svg = document.createElementNS('http://www.w3.org/2000/svg',"svg"); |
|
|
this.svg.style.position = "relative" |
|
|
this.svg.style.position = "relative" |
|
|
this.svg.style.height = "300px"; |
|
|
this.svg.style.height = "300px"; |
|
|
|
|
|
// this.svg.style.width =
|
|
|
this.svg.style.display = "block"; |
|
|
this.svg.style.display = "block"; |
|
|
|
|
|
|
|
|
this.path = document.createElementNS('http://www.w3.org/2000/svg',"path"); |
|
|
this.path = document.createElementNS('http://www.w3.org/2000/svg',"path"); |
|
@ -3093,16 +3126,13 @@ Linegraph.prototype._create = function(){ |
|
|
this.svg.appendChild(this.path); |
|
|
this.svg.appendChild(this.path); |
|
|
|
|
|
|
|
|
// panel with time axis
|
|
|
// panel with time axis
|
|
|
var dataAxisOptions = { |
|
|
|
|
|
range: this.body.range, |
|
|
|
|
|
left: null, |
|
|
|
|
|
top: null, |
|
|
|
|
|
width: null, |
|
|
|
|
|
height: 300, |
|
|
|
|
|
svg: this.svg |
|
|
|
|
|
}; |
|
|
|
|
|
this.yAxis = new DataAxis(dataAxisOptions); |
|
|
|
|
|
this.dom.axis = this.yAxis.getFrame(); |
|
|
|
|
|
|
|
|
this.yAxis = new DataAxis(this.body, { |
|
|
|
|
|
orientation: 'left', |
|
|
|
|
|
showMinorLabels: true, |
|
|
|
|
|
showMajorLabels: true, |
|
|
|
|
|
width: '90px', |
|
|
|
|
|
height: this.svg.style.height |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
this.show(); |
|
|
this.show(); |
|
|
}; |
|
|
}; |
|
@ -3110,45 +3140,6 @@ Linegraph.prototype._create = function(){ |
|
|
|
|
|
|
|
|
Linegraph.prototype.setOptions = function(options) { |
|
|
Linegraph.prototype.setOptions = function(options) { |
|
|
if (options) { |
|
|
if (options) { |
|
|
// copy all options that we know
|
|
|
|
|
|
var fields = ['type', 'align', 'orientation', 'padding', 'stack', 'selectable', 'groupOrder']; |
|
|
|
|
|
util.selectiveExtend(fields, this.options, options); |
|
|
|
|
|
|
|
|
|
|
|
if ('margin' in options) { |
|
|
|
|
|
if (typeof options.margin === 'number') { |
|
|
|
|
|
this.options.margin.axis = options.margin; |
|
|
|
|
|
this.options.margin.item = options.margin; |
|
|
|
|
|
} |
|
|
|
|
|
else if (typeof options.margin === 'object'){ |
|
|
|
|
|
util.selectiveExtend(['axis', 'item'], this.options.margin, options.margin); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if ('editable' in options) { |
|
|
|
|
|
if (typeof options.editable === 'boolean') { |
|
|
|
|
|
this.options.editable.updateTime = options.editable; |
|
|
|
|
|
this.options.editable.updateGroup = options.editable; |
|
|
|
|
|
this.options.editable.add = options.editable; |
|
|
|
|
|
this.options.editable.remove = options.editable; |
|
|
|
|
|
} |
|
|
|
|
|
else if (typeof options.editable === 'object') { |
|
|
|
|
|
util.selectiveExtend(['updateTime', 'updateGroup', 'add', 'remove'], this.options.editable, options.editable); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// callback functions
|
|
|
|
|
|
var addCallback = (function (name) { |
|
|
|
|
|
if (name in options) { |
|
|
|
|
|
var fn = options[name]; |
|
|
|
|
|
if (!(fn instanceof Function) || fn.length != 2) { |
|
|
|
|
|
throw new Error('option ' + name + ' must be a function ' + name + '(item, callback)'); |
|
|
|
|
|
} |
|
|
|
|
|
this.options[name] = fn; |
|
|
|
|
|
} |
|
|
|
|
|
}).bind(this); |
|
|
|
|
|
['onAdd', 'onUpdate', 'onRemove', 'onMove'].forEach(addCallback); |
|
|
|
|
|
|
|
|
|
|
|
// force the itemSet to refresh: options like orientation and margins may be changed
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
}; |
|
|
}; |
|
@ -3161,11 +3152,6 @@ Linegraph.prototype.hide = function() { |
|
|
if (this.dom.frame.parentNode) { |
|
|
if (this.dom.frame.parentNode) { |
|
|
this.dom.frame.parentNode.removeChild(this.dom.frame); |
|
|
this.dom.frame.parentNode.removeChild(this.dom.frame); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// remove the labelset containing all group labels
|
|
|
|
|
|
if (this.dom.axis.parentNode) { |
|
|
|
|
|
this.dom.axis.parentNode.removeChild(this.dom.axis); |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
@ -3177,11 +3163,6 @@ Linegraph.prototype.show = function() { |
|
|
if (!this.dom.frame.parentNode) { |
|
|
if (!this.dom.frame.parentNode) { |
|
|
this.body.dom.center.appendChild(this.dom.frame); |
|
|
this.body.dom.center.appendChild(this.dom.frame); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// show labelset containing labels
|
|
|
|
|
|
if (!this.dom.axis.parentNode) { |
|
|
|
|
|
this.body.dom.left.appendChild(this.dom.axis); |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -3229,7 +3210,7 @@ Linegraph.prototype.setItems = function(items) { |
|
|
// ids = this.itemsData.getIds();
|
|
|
// ids = this.itemsData.getIds();
|
|
|
// this._onAdd(ids);
|
|
|
// this._onAdd(ids);
|
|
|
} |
|
|
} |
|
|
this.updateGraph(); |
|
|
|
|
|
|
|
|
this.redraw(); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -3257,7 +3238,11 @@ Linegraph.prototype._onUpdate = function(ids) { |
|
|
* @return {boolean} Returns true if the component is resized |
|
|
* @return {boolean} Returns true if the component is resized |
|
|
*/ |
|
|
*/ |
|
|
Linegraph.prototype.redraw = function() { |
|
|
Linegraph.prototype.redraw = function() { |
|
|
console.log('redraw') |
|
|
|
|
|
|
|
|
var resized = false; |
|
|
|
|
|
|
|
|
|
|
|
if (this.lastWidth === undefined && this.width) { |
|
|
|
|
|
resized = true; |
|
|
|
|
|
} |
|
|
// check whether zoomed (in that case we need to re-stack everything)
|
|
|
// check whether zoomed (in that case we need to re-stack everything)
|
|
|
var visibleInterval = this.body.range.end - this.body.range.start; |
|
|
var visibleInterval = this.body.range.end - this.body.range.start; |
|
|
var zoomed = (visibleInterval != this.lastVisibleInterval) || (this.width != this.lastWidth); |
|
|
var zoomed = (visibleInterval != this.lastVisibleInterval) || (this.width != this.lastWidth); |
|
@ -3268,10 +3253,10 @@ Linegraph.prototype.redraw = function() { |
|
|
this.width = this.dom.frame.offsetWidth; |
|
|
this.width = this.dom.frame.offsetWidth; |
|
|
|
|
|
|
|
|
// check if this component is resized
|
|
|
// check if this component is resized
|
|
|
var resized = this._isResized(); |
|
|
|
|
|
|
|
|
resized = this._isResized() || resized; |
|
|
if (resized) { |
|
|
if (resized) { |
|
|
this.svg.style.width = asSize(3*this.width); |
|
|
|
|
|
this.svg.style.left = asSize(-this.width); |
|
|
|
|
|
|
|
|
this.svg.style.width = util.option.asSize(3*this.width); |
|
|
|
|
|
this.svg.style.left = util.option.asSize(-this.width); |
|
|
} |
|
|
} |
|
|
if (zoomed) { |
|
|
if (zoomed) { |
|
|
this.updateGraph(); |
|
|
this.updateGraph(); |
|
@ -3281,19 +3266,12 @@ Linegraph.prototype.redraw = function() { |
|
|
|
|
|
|
|
|
Linegraph.prototype._extractData = function(dataset) { |
|
|
Linegraph.prototype._extractData = function(dataset) { |
|
|
var extractedData = []; |
|
|
var extractedData = []; |
|
|
|
|
|
|
|
|
var low = dataset[0].y; |
|
|
var low = dataset[0].y; |
|
|
var high = dataset[0].y; |
|
|
var high = dataset[0].y; |
|
|
|
|
|
|
|
|
var range = this.body.range.end - this.body.range.start; |
|
|
|
|
|
var rangePerPixel = range/this.width; |
|
|
|
|
|
var rangePerPixelInv = this.width/range; |
|
|
|
|
|
var xOffset = -this.body.range.start + this.width*rangePerPixel; |
|
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < dataset.length; i++) { |
|
|
for (var i = 0; i < dataset.length; i++) { |
|
|
var val = new Date(dataset[i].x).getTime(); |
|
|
|
|
|
val += xOffset; |
|
|
|
|
|
val *= rangePerPixelInv; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var val = this.body.util.toScreen(new Date(dataset[i].x)) + this.width; |
|
|
extractedData.push({x:val, y:dataset[i].y}); |
|
|
extractedData.push({x:val, y:dataset[i].y}); |
|
|
|
|
|
|
|
|
if (low > dataset[i].y) { |
|
|
if (low > dataset[i].y) { |
|
@ -3318,16 +3296,16 @@ Linegraph.prototype.updateGraph = function() { |
|
|
var data = dataset.data; |
|
|
var data = dataset.data; |
|
|
|
|
|
|
|
|
this.yAxis.setRange({start:dataset.range.low,end:dataset.range.high}); |
|
|
this.yAxis.setRange({start:dataset.range.low,end:dataset.range.high}); |
|
|
this.yAxis.repaint(); |
|
|
|
|
|
|
|
|
this.yAxis.redraw(); |
|
|
data = this.yAxis.convertValues(data); |
|
|
data = this.yAxis.convertValues(data); |
|
|
|
|
|
|
|
|
var d, d2, d3; |
|
|
var d, d2, d3; |
|
|
d = this._catmullRom(data,0.5); |
|
|
d = this._catmullRom(data,0.5); |
|
|
d3 = this._catmullRom(data,0); |
|
|
|
|
|
d2 = this._catmullRom(data,1); |
|
|
|
|
|
|
|
|
d2 = this._catmullRom(data,0); |
|
|
|
|
|
d3 = this._linear(data); |
|
|
|
|
|
|
|
|
this.path.setAttributeNS(null, "d",d); |
|
|
|
|
|
this.path2.setAttributeNS(null, "d",d2); |
|
|
|
|
|
|
|
|
// this.path.setAttributeNS(null, "d",d);
|
|
|
|
|
|
// this.path2.setAttributeNS(null, "d",d2);
|
|
|
this.path3.setAttributeNS(null, "d",d3); |
|
|
this.path3.setAttributeNS(null, "d",d3); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -3487,7 +3465,6 @@ Linegraph.prototype._linear = function(data) { |
|
|
function DataStep(start, end, minimumStep, containerHeight) { |
|
|
function DataStep(start, end, minimumStep, containerHeight) { |
|
|
// variables
|
|
|
// variables
|
|
|
this.current = 0; |
|
|
this.current = 0; |
|
|
this.containerHeight = containerHeight; |
|
|
|
|
|
|
|
|
|
|
|
this.autoScale = true; |
|
|
this.autoScale = true; |
|
|
this.stepIndex = 0; |
|
|
this.stepIndex = 0; |
|
@ -3500,7 +3477,7 @@ function DataStep(start, end, minimumStep, containerHeight) { |
|
|
this.majorSteps = [1, 2, 5, 10]; |
|
|
this.majorSteps = [1, 2, 5, 10]; |
|
|
this.minorSteps = [0.25, 0.5, 1, 2]; |
|
|
this.minorSteps = [0.25, 0.5, 1, 2]; |
|
|
|
|
|
|
|
|
this.setRange(start,end,minimumStep, containerHeight); |
|
|
|
|
|
|
|
|
this.setRange(start, end, minimumStep, containerHeight); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -3619,9 +3596,6 @@ DataStep.prototype.setMinimumStep = function(minimumStep, containerHeight) { |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.stepIndex = minorStepIdx; |
|
|
this.stepIndex = minorStepIdx; |
|
|
this.scale = magnitudefactor; |
|
|
this.scale = magnitudefactor; |
|
|
this.step = magnitudefactor * this.minorSteps[minorStepIdx]; |
|
|
this.step = magnitudefactor * this.minorSteps[minorStepIdx]; |
|
|