diff --git a/dist/vis.js b/dist/vis.js index 42f3ee98..754bc9bc 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -106,7 +106,7 @@ return /******/ (function(modules) { // webpackBootstrap exports.Graph2d = __webpack_require__(42); exports.timeline = { DateUtil: __webpack_require__(24), - DataStep: __webpack_require__(44), + DataStep: __webpack_require__(45), Range: __webpack_require__(21), stack: __webpack_require__(28), TimeStep: __webpack_require__(38), @@ -123,7 +123,7 @@ return /******/ (function(modules) { // webpackBootstrap Component: __webpack_require__(23), CurrentTime: __webpack_require__(39), CustomTime: __webpack_require__(41), - DataAxis: __webpack_require__(45), + DataAxis: __webpack_require__(44), GraphGroup: __webpack_require__(46), Group: __webpack_require__(27), BackgroundGroup: __webpack_require__(31), @@ -19638,7 +19638,7 @@ return /******/ (function(modules) { // webpackBootstrap var DataSet = __webpack_require__(7); var DataView = __webpack_require__(9); var Component = __webpack_require__(23); - var DataAxis = __webpack_require__(45); + var DataAxis = __webpack_require__(44); var GraphGroup = __webpack_require__(46); var Legend = __webpack_require__(50); var BarGraphFunctions = __webpack_require__(49); @@ -20631,293 +20631,12 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, /* 44 */ -/***/ function(module, exports, __webpack_require__) { - - /** - * @constructor DataStep - * The class DataStep is an iterator for data for the lineGraph. You provide a start data point and an - * end data point. The class itself determines the best scale (step size) based on the - * provided start Date, end Date, and minimumStep. - * - * If minimumStep is provided, the step size is chosen as close as possible - * to the minimumStep but larger than minimumStep. If minimumStep is not - * provided, the scale is set to 1 DAY. - * The minimumStep should correspond with the onscreen size of about 6 characters - * - * Alternatively, you can set a scale by hand. - * After creation, you can initialize the class by executing first(). Then you - * can iterate from the start date to the end date via next(). You can check if - * the end date is reached with the function hasNext(). After each step, you can - * retrieve the current date via getCurrent(). - * The DataStep has scales ranging from milliseconds, seconds, minutes, hours, - * days, to years. - * - * Version: 1.2 - * - * @param {Date} [start] The start date, for example new Date(2010, 9, 21) - * or new Date(2010, 9, 21, 23, 45, 00) - * @param {Date} [end] The end date - * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds - */ - function DataStep(start, end, minimumStep, containerHeight, customRange, alignZeros) { - // variables - this.current = 0; - - this.autoScale = true; - this.stepIndex = 0; - this.step = 1; - this.scale = 1; - - this.marginStart; - this.marginEnd; - this.deadSpace = 0; - - this.majorSteps = [1, 2, 5, 10]; - this.minorSteps = [0.25, 0.5, 1, 2]; - - this.alignZeros = alignZeros; - - this.setRange(start, end, minimumStep, containerHeight, customRange); - } - - - - /** - * Set a new range - * If minimumStep is provided, the step size is chosen as close as possible - * to the minimumStep but larger than minimumStep. If minimumStep is not - * provided, the scale is set to 1 DAY. - * The minimumStep should correspond with the onscreen size of about 6 characters - * @param {Number} [start] The start date and time. - * @param {Number} [end] The end date and time. - * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds - */ - DataStep.prototype.setRange = function(start, end, minimumStep, containerHeight, customRange) { - this._start = customRange.min === undefined ? start : customRange.min; - this._end = customRange.max === undefined ? end : customRange.max; - - if (this._start == this._end) { - this._start -= 0.75; - this._end += 1; - } - - if (this.autoScale == true) { - this.setMinimumStep(minimumStep, containerHeight); - } - - this.setFirst(customRange); - }; - - /** - * Automatically determine the scale that bests fits the provided minimum step - * @param {Number} [minimumStep] The minimum step size in milliseconds - */ - DataStep.prototype.setMinimumStep = function(minimumStep, containerHeight) { - // round to floor - var size = this._end - this._start; - var safeSize = size * 1.2; - var minimumStepValue = minimumStep * (safeSize / containerHeight); - var orderOfMagnitude = Math.round(Math.log(safeSize)/Math.LN10); - - var minorStepIdx = -1; - var magnitudefactor = Math.pow(10,orderOfMagnitude); - - var start = 0; - if (orderOfMagnitude < 0) { - start = orderOfMagnitude; - } - - var solutionFound = false; - for (var i = start; Math.abs(i) <= Math.abs(orderOfMagnitude); i++) { - magnitudefactor = Math.pow(10,i); - for (var j = 0; j < this.minorSteps.length; j++) { - var stepSize = magnitudefactor * this.minorSteps[j]; - if (stepSize >= minimumStepValue) { - solutionFound = true; - minorStepIdx = j; - break; - } - } - if (solutionFound == true) { - break; - } - } - this.stepIndex = minorStepIdx; - this.scale = magnitudefactor; - this.step = magnitudefactor * this.minorSteps[minorStepIdx]; - }; - - - - /** - * Round the current date to the first minor date value - * This must be executed once when the current date is set to start Date - */ - DataStep.prototype.setFirst = function(customRange) { - if (customRange === undefined) { - customRange = {}; - } - - var niceStart = customRange.min === undefined ? this._start - (this.scale * 2 * this.minorSteps[this.stepIndex]) : customRange.min; - var niceEnd = customRange.max === undefined ? this._end + (this.scale * this.minorSteps[this.stepIndex]) : customRange.max; - - this.marginEnd = customRange.max === undefined ? this.roundToMinor(niceEnd) : customRange.max; - this.marginStart = customRange.min === undefined ? this.roundToMinor(niceStart) : customRange.min; - - // if we need to align the zero's we need to make sure that there is a zero to use. - if (this.alignZeros == true && (this.marginEnd - this.marginStart) % this.step != 0) { - this.marginEnd += this.marginEnd % this.step; - } - - this.deadSpace = this.roundToMinor(niceEnd) - niceEnd + this.roundToMinor(niceStart) - niceStart; - this.marginRange = this.marginEnd - this.marginStart; - - - this.current = this.marginEnd; - }; - - DataStep.prototype.roundToMinor = function(value) { - var rounded = value - (value % (this.scale * this.minorSteps[this.stepIndex])); - if (value % (this.scale * this.minorSteps[this.stepIndex]) > 0.5 * (this.scale * this.minorSteps[this.stepIndex])) { - return rounded + (this.scale * this.minorSteps[this.stepIndex]); - } - else { - return rounded; - } - } - - - /** - * Check if the there is a next step - * @return {boolean} true if the current date has not passed the end date - */ - DataStep.prototype.hasNext = function () { - return (this.current >= this.marginStart); - }; - - /** - * Do the next step - */ - DataStep.prototype.next = function() { - var prev = this.current; - this.current -= this.step; - - // safety mechanism: if current time is still unchanged, move to the end - if (this.current == prev) { - this.current = this._end; - } - }; - - /** - * Do the next step - */ - DataStep.prototype.previous = function() { - this.current += this.step; - this.marginEnd += this.step; - this.marginRange = this.marginEnd - this.marginStart; - }; - - - - /** - * Get the current datetime - * @return {String} current The current date - */ - DataStep.prototype.getCurrent = function(decimals) { - // prevent round-off errors when close to zero - var current = (Math.abs(this.current) < this.step / 2) ? 0 : this.current; - var toPrecision = '' + Number(current).toPrecision(5); - - // If decimals is specified, then limit or extend the string as required - if(decimals !== undefined && !isNaN(Number(decimals))) { - // If string includes exponent, then we need to add it to the end - var exp = ""; - var index = toPrecision.indexOf("e"); - if(index != -1) { - // Get the exponent - exp = toPrecision.slice(index); - // Remove the exponent in case we need to zero-extend - toPrecision = toPrecision.slice(0, index); - } - index = Math.max(toPrecision.indexOf(","), toPrecision.indexOf(".")); - if(index === -1) { - // No decimal found - if we want decimals, then we need to add it - if(decimals !== 0) { - toPrecision += '.'; - } - // Calculate how long the string should be - index = toPrecision.length + decimals; - } - else if(decimals !== 0) { - // Calculate how long the string should be - accounting for the decimal place - index += decimals + 1; - } - if(index > toPrecision.length) { - // We need to add zeros! - for(var cnt = index - toPrecision.length; cnt > 0; cnt--) { - toPrecision += '0'; - } - } - else { - // we need to remove characters - toPrecision = toPrecision.slice(0, index); - } - // Add the exponent if there is one - toPrecision += exp; - } - else { - if (toPrecision.indexOf(",") != -1 || toPrecision.indexOf(".") != -1) { - // If no decimal is specified, and there are decimal places, remove trailing zeros - for (var i = toPrecision.length - 1; i > 0; i--) { - if (toPrecision[i] == "0") { - toPrecision = toPrecision.slice(0, i); - } - else if (toPrecision[i] == "." || toPrecision[i] == ",") { - toPrecision = toPrecision.slice(0, i); - break; - } - else { - break; - } - } - } - } - - return toPrecision; - }; - - - - /** - * 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 - */ - DataStep.prototype.snap = function(date) { - - }; - - /** - * Check if the current value is a major value (for example when the step - * is DAY, a major value is each first day of the MONTH) - * @return {boolean} true if current date is major, else false. - */ - DataStep.prototype.isMajor = function() { - return (this.current % (this.scale * this.majorSteps[this.stepIndex]) == 0); - }; - - module.exports = DataStep; - - -/***/ }, -/* 45 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); var DOMutil = __webpack_require__(6); var Component = __webpack_require__(23); - var DataStep = __webpack_require__(44); + var DataStep = __webpack_require__(45); /** * A horizontal time axis @@ -21431,125 +21150,406 @@ return /******/ (function(modules) { // webpackBootstrap }; /** - * Create a minor line for the axis at position y - * @param y - * @param orientation - * @param className - * @param offset - * @param width + * Create a minor line for the axis at position y + * @param y + * @param orientation + * @param className + * @param offset + * @param 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 orientation + */ + DataAxis.prototype._redrawTitle = function (orientation) { + DOMutil.prepareElements(this.DOMelements.title); + + // Check if the title is defined for this axes + if (this.options.title[orientation] !== undefined && this.options.title[orientation].text !== undefined) { + var title = DOMutil.getDOMElement('div', this.DOMelements.title, this.dom.frame); + title.className = 'yAxis title ' + orientation; + title.innerHTML = this.options.title[orientation].text; + + // Add style - if provided + if (this.options.title[orientation].style !== undefined) { + util.addCssText(title, this.options.title[orientation].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 = 'yAxis minor 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 = 'yAxis major 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 = 'yAxis title measure'; + measureCharTitle.appendChild(textTitle); + this.dom.frame.appendChild(measureCharTitle); + + this.props.titleCharHeight = measureCharTitle.clientHeight; + this.props.titleCharWidth = measureCharTitle.clientWidth; + + this.dom.frame.removeChild(measureCharTitle); + } + }; + + /** + * 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 + */ + DataAxis.prototype.snap = function(date) { + return this.step.snap(date); + }; + + module.exports = DataAxis; + + +/***/ }, +/* 45 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * @constructor DataStep + * The class DataStep is an iterator for data for the lineGraph. You provide a start data point and an + * end data point. The class itself determines the best scale (step size) based on the + * provided start Date, end Date, and minimumStep. + * + * If minimumStep is provided, the step size is chosen as close as possible + * to the minimumStep but larger than minimumStep. If minimumStep is not + * provided, the scale is set to 1 DAY. + * The minimumStep should correspond with the onscreen size of about 6 characters + * + * Alternatively, you can set a scale by hand. + * After creation, you can initialize the class by executing first(). Then you + * can iterate from the start date to the end date via next(). You can check if + * the end date is reached with the function hasNext(). After each step, you can + * retrieve the current date via getCurrent(). + * The DataStep has scales ranging from milliseconds, seconds, minutes, hours, + * days, to years. + * + * Version: 1.2 + * + * @param {Date} [start] The start date, for example new Date(2010, 9, 21) + * or new Date(2010, 9, 21, 23, 45, 00) + * @param {Date} [end] The end date + * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds + */ + function DataStep(start, end, minimumStep, containerHeight, customRange, alignZeros) { + // variables + this.current = 0; + + this.autoScale = true; + this.stepIndex = 0; + this.step = 1; + this.scale = 1; + + this.marginStart; + this.marginEnd; + this.deadSpace = 0; + + this.majorSteps = [1, 2, 5, 10]; + this.minorSteps = [0.25, 0.5, 1, 2]; + + this.alignZeros = alignZeros; + + this.setRange(start, end, minimumStep, containerHeight, customRange); + } + + + + /** + * Set a new range + * If minimumStep is provided, the step size is chosen as close as possible + * to the minimumStep but larger than minimumStep. If minimumStep is not + * provided, the scale is set to 1 DAY. + * The minimumStep should correspond with the onscreen size of about 6 characters + * @param {Number} [start] The start date and time. + * @param {Number} [end] The end date and time. + * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds + */ + DataStep.prototype.setRange = function(start, end, minimumStep, containerHeight, customRange) { + this._start = customRange.min === undefined ? start : customRange.min; + this._end = customRange.max === undefined ? end : customRange.max; + + if (this._start == this._end) { + this._start -= 0.75; + this._end += 1; + } + + if (this.autoScale == true) { + this.setMinimumStep(minimumStep, containerHeight); + } + + this.setFirst(customRange); + }; + + /** + * Automatically determine the scale that bests fits the provided minimum step + * @param {Number} [minimumStep] The minimum step size in milliseconds */ - 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 = ''; + DataStep.prototype.setMinimumStep = function(minimumStep, containerHeight) { + // round to floor + var size = this._end - this._start; + var safeSize = size * 1.2; + var minimumStepValue = minimumStep * (safeSize / containerHeight); + var orderOfMagnitude = Math.round(Math.log(safeSize)/Math.LN10); - if (orientation == 'left') { - line.style.left = (this.width - offset) + 'px'; + var minorStepIdx = -1; + var magnitudefactor = Math.pow(10,orderOfMagnitude); + + var start = 0; + if (orderOfMagnitude < 0) { + start = orderOfMagnitude; + } + + var solutionFound = false; + for (var i = start; Math.abs(i) <= Math.abs(orderOfMagnitude); i++) { + magnitudefactor = Math.pow(10,i); + for (var j = 0; j < this.minorSteps.length; j++) { + var stepSize = magnitudefactor * this.minorSteps[j]; + if (stepSize >= minimumStepValue) { + solutionFound = true; + minorStepIdx = j; + break; + } } - else { - line.style.right = (this.width - offset) + 'px'; + if (solutionFound == true) { + break; } - - line.style.width = width + 'px'; - line.style.top = y + 'px'; } + this.stepIndex = minorStepIdx; + this.scale = magnitudefactor; + this.step = magnitudefactor * this.minorSteps[minorStepIdx]; }; + + /** - * Create a title for the axis - * @private - * @param orientation + * Round the current date to the first minor date value + * This must be executed once when the current date is set to start Date */ - DataAxis.prototype._redrawTitle = function (orientation) { - DOMutil.prepareElements(this.DOMelements.title); - - // Check if the title is defined for this axes - if (this.options.title[orientation] !== undefined && this.options.title[orientation].text !== undefined) { - var title = DOMutil.getDOMElement('div', this.DOMelements.title, this.dom.frame); - title.className = 'yAxis title ' + orientation; - title.innerHTML = this.options.title[orientation].text; + DataStep.prototype.setFirst = function(customRange) { + if (customRange === undefined) { + customRange = {}; + } - // Add style - if provided - if (this.options.title[orientation].style !== undefined) { - util.addCssText(title, this.options.title[orientation].style); - } + var niceStart = customRange.min === undefined ? this._start - (this.scale * 2 * this.minorSteps[this.stepIndex]) : customRange.min; + var niceEnd = customRange.max === undefined ? this._end + (this.scale * this.minorSteps[this.stepIndex]) : customRange.max; - if (orientation == 'left') { - title.style.left = this.props.titleCharHeight + 'px'; - } - else { - title.style.right = this.props.titleCharHeight + 'px'; - } + this.marginEnd = customRange.max === undefined ? this.roundToMinor(niceEnd) : customRange.max; + this.marginStart = customRange.min === undefined ? this.roundToMinor(niceStart) : customRange.min; - title.style.width = this.height + 'px'; + // if we need to align the zero's we need to make sure that there is a zero to use. + if (this.alignZeros == true && (this.marginEnd - this.marginStart) % this.step != 0) { + this.marginEnd += this.marginEnd % this.step; } - // we need to clean up in case we did not use all elements. - DOMutil.cleanupElements(this.DOMelements.title); - }; + this.deadSpace = this.roundToMinor(niceEnd) - niceEnd + this.roundToMinor(niceStart) - niceStart; + this.marginRange = this.marginEnd - this.marginStart; + this.current = this.marginEnd; + }; + + DataStep.prototype.roundToMinor = function(value) { + var rounded = value - (value % (this.scale * this.minorSteps[this.stepIndex])); + if (value % (this.scale * this.minorSteps[this.stepIndex]) > 0.5 * (this.scale * this.minorSteps[this.stepIndex])) { + return rounded + (this.scale * this.minorSteps[this.stepIndex]); + } + else { + return rounded; + } + } /** - * 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 + * Check if the there is a next step + * @return {boolean} true if the current date has not passed the end date */ - 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 = 'yAxis minor measure'; - measureCharMinor.appendChild(textMinor); - this.dom.frame.appendChild(measureCharMinor); + DataStep.prototype.hasNext = function () { + return (this.current >= this.marginStart); + }; - this.props.minorCharHeight = measureCharMinor.clientHeight; - this.props.minorCharWidth = measureCharMinor.clientWidth; + /** + * Do the next step + */ + DataStep.prototype.next = function() { + var prev = this.current; + this.current -= this.step; - this.dom.frame.removeChild(measureCharMinor); + // safety mechanism: if current time is still unchanged, move to the end + if (this.current == prev) { + this.current = this._end; } + }; - if (!('majorCharHeight' in this.props)) { - var textMajor = document.createTextNode('0'); - var measureCharMajor = document.createElement('div'); - measureCharMajor.className = 'yAxis major measure'; - measureCharMajor.appendChild(textMajor); - this.dom.frame.appendChild(measureCharMajor); - - this.props.majorCharHeight = measureCharMajor.clientHeight; - this.props.majorCharWidth = measureCharMajor.clientWidth; + /** + * Do the next step + */ + DataStep.prototype.previous = function() { + this.current += this.step; + this.marginEnd += this.step; + this.marginRange = this.marginEnd - this.marginStart; + }; - this.dom.frame.removeChild(measureCharMajor); - } - if (!('titleCharHeight' in this.props)) { - var textTitle = document.createTextNode('0'); - var measureCharTitle = document.createElement('div'); - measureCharTitle.className = 'yAxis title measure'; - measureCharTitle.appendChild(textTitle); - this.dom.frame.appendChild(measureCharTitle); - this.props.titleCharHeight = measureCharTitle.clientHeight; - this.props.titleCharWidth = measureCharTitle.clientWidth; + /** + * Get the current datetime + * @return {String} current The current date + */ + DataStep.prototype.getCurrent = function(decimals) { + // prevent round-off errors when close to zero + var current = (Math.abs(this.current) < this.step / 2) ? 0 : this.current; + var toPrecision = '' + Number(current).toPrecision(5); - this.dom.frame.removeChild(measureCharTitle); + // If decimals is specified, then limit or extend the string as required + if(decimals !== undefined && !isNaN(Number(decimals))) { + // If string includes exponent, then we need to add it to the end + var exp = ""; + var index = toPrecision.indexOf("e"); + if(index != -1) { + // Get the exponent + exp = toPrecision.slice(index); + // Remove the exponent in case we need to zero-extend + toPrecision = toPrecision.slice(0, index); + } + index = Math.max(toPrecision.indexOf(","), toPrecision.indexOf(".")); + if(index === -1) { + // No decimal found - if we want decimals, then we need to add it + if(decimals !== 0) { + toPrecision += '.'; + } + // Calculate how long the string should be + index = toPrecision.length + decimals; + } + else if(decimals !== 0) { + // Calculate how long the string should be - accounting for the decimal place + index += decimals + 1; + } + if(index > toPrecision.length) { + // We need to add zeros! + for(var cnt = index - toPrecision.length; cnt > 0; cnt--) { + toPrecision += '0'; + } + } + else { + // we need to remove characters + toPrecision = toPrecision.slice(0, index); + } + // Add the exponent if there is one + toPrecision += exp; + } + else { + if (toPrecision.indexOf(",") != -1 || toPrecision.indexOf(".") != -1) { + // If no decimal is specified, and there are decimal places, remove trailing zeros + for (var i = toPrecision.length - 1; i > 0; i--) { + if (toPrecision[i] == "0") { + toPrecision = toPrecision.slice(0, i); + } + else if (toPrecision[i] == "." || toPrecision[i] == ",") { + toPrecision = toPrecision.slice(0, i); + break; + } + else { + break; + } + } + } } + + return toPrecision; }; + + /** * 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 */ - DataAxis.prototype.snap = function(date) { - return this.step.snap(date); + DataStep.prototype.snap = function(date) { + }; - module.exports = DataAxis; + /** + * Check if the current value is a major value (for example when the step + * is DAY, a major value is each first day of the MONTH) + * @return {boolean} true if current date is major, else false. + */ + DataStep.prototype.isMajor = function() { + return (this.current % (this.scale * this.majorSteps[this.stepIndex]) == 0); + }; + + module.exports = DataStep; /***/ }, @@ -22593,7 +22593,7 @@ return /******/ (function(modules) { // webpackBootstrap physics: { barnesHut: { enabled: true, - theta: 1 / 0.6, // inverted to save time during calculation + thetaInverted: 1 / 0.5, // inverted to save time during calculation gravitationalConstant: -2000, centralGravity: 0.3, springLength: 95, @@ -22864,10 +22864,10 @@ return /******/ (function(modules) { // webpackBootstrap for (var nodeId in this.nodes) { if (this.nodes.hasOwnProperty(nodeId)) { node = this.nodes[nodeId]; - if (minX > (node.x)) {minX = node.x;} - if (maxX < (node.x)) {maxX = node.x;} - if (minY > (node.y)) {minY = node.y;} - if (maxY < (node.y)) {maxY = node.y;} + if (minX > (node.boundingBox.left)) {minX = node.boundingBox.left;} + if (maxX < (node.boundingBox.right)) {maxX = node.boundingBox.right;} + if (minY > (node.boundingBox.bottom)) {minY = node.boundingBox.bottom;} + if (maxY < (node.boundingBox.top)) {maxY = node.boundingBox.top;} } } if (minX == 1e9 && maxX == -1e9 && minY == 1e9 && maxY == -1e9) { @@ -22895,6 +22895,8 @@ return /******/ (function(modules) { // webpackBootstrap * @param {Boolean} [disableStart] | If true, start is not called. */ Network.prototype.zoomExtent = function(animationOptions, initialZoom, disableStart) { + this._redraw(true); + if (initialZoom === undefined) { initialZoom = false; } @@ -24221,9 +24223,10 @@ return /******/ (function(modules) { // webpackBootstrap /** * Redraw the network with the current data + * @param hidden | used to get the first estimate of the node sizes. only the nodes are drawn after which they are quickly drawn over. * @private */ - Network.prototype._redraw = function() { + Network.prototype._redraw = function(hidden) { var ctx = this.frame.canvas.getContext('2d'); ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); @@ -24247,18 +24250,21 @@ return /******/ (function(modules) { // webpackBootstrap "y": this._YconvertDOMtoCanvas(this.frame.canvas.clientHeight * this.pixelRatio) }; - - this._doInAllSectors("_drawAllSectorNodes",ctx); - if (this.drag.dragging == false || this.drag.dragging === undefined || this.constants.hideEdgesOnDrag == false) { - this._doInAllSectors("_drawEdges",ctx); + if (!(hidden == true)) { + this._doInAllSectors("_drawAllSectorNodes", ctx); + if (this.drag.dragging == false || this.drag.dragging === undefined || this.constants.hideEdgesOnDrag == false) { + this._doInAllSectors("_drawEdges", ctx); + } } if (this.drag.dragging == false || this.drag.dragging === undefined || this.constants.hideNodesOnDrag == false) { this._doInAllSectors("_drawNodes",ctx,false); } - if (this.controlNodesActive == true) { - this._doInAllSectors("_drawControlNodes",ctx); + if (!(hidden == true)) { + if (this.controlNodesActive == true) { + this._doInAllSectors("_drawControlNodes", ctx); + } } // this._doInSupportSector("_drawNodes",ctx,true); @@ -24266,6 +24272,10 @@ return /******/ (function(modules) { // webpackBootstrap // restore original scaling and translation ctx.restore(); + + if (hidden == true) { + ctx.clearRect(0, 0, w, h); + } }; /** @@ -26193,8 +26203,8 @@ return /******/ (function(modules) { // webpackBootstrap this.level = -1; this.preassignedLevel = false; this.hierarchyEnumerated = false; - this.labelDimensions = {top:0,left:0,width:0,height:0,yLine:0}; // could be cached - + this.labelDimensions = {top:0, left:0, width:0, height:0, yLine:0}; // could be cached + this.boundingBox = {top:0, left:0, right:0, bottom:0}; this.imagelist = imagelist; this.grouplist = grouplist; @@ -26755,6 +26765,11 @@ return /******/ (function(modules) { // webpackBootstrap ctx.fill(); ctx.stroke(); + this.boundingBox.top = this.top; + this.boundingBox.left = this.left; + this.boundingBox.right = this.left + this.width; + this.boundingBox.bottom = this.top + this.height; + this._label(ctx, this.label, this.x, this.y); }; @@ -26804,6 +26819,11 @@ return /******/ (function(modules) { // webpackBootstrap ctx.fill(); ctx.stroke(); + this.boundingBox.top = this.top; + this.boundingBox.left = this.left; + this.boundingBox.right = this.left + this.width; + this.boundingBox.bottom = this.top + this.height; + this._label(ctx, this.label, this.x, this.y); }; @@ -26855,6 +26875,11 @@ return /******/ (function(modules) { // webpackBootstrap ctx.fill(); ctx.stroke(); + this.boundingBox.top = this.y - this.options.radius; + this.boundingBox.left = this.x - this.options.radius; + this.boundingBox.right = this.x + this.options.radius; + this.boundingBox.bottom = this.y + this.options.radius; + this._label(ctx, this.label, this.x, this.y); }; @@ -26906,6 +26931,12 @@ return /******/ (function(modules) { // webpackBootstrap ctx.ellipse(this.left, this.top, this.width, this.height); ctx.fill(); ctx.stroke(); + + this.boundingBox.top = this.top; + this.boundingBox.left = this.left; + this.boundingBox.right = this.left + this.width; + this.boundingBox.bottom = this.top + this.height; + this._label(ctx, this.label, this.x, this.y); }; @@ -26983,8 +27014,16 @@ return /******/ (function(modules) { // webpackBootstrap ctx.fill(); ctx.stroke(); + this.boundingBox.top = this.y - this.options.radius; + this.boundingBox.left = this.x - this.options.radius; + this.boundingBox.right = this.x + this.options.radius; + this.boundingBox.bottom = this.y + this.options.radius; + if (this.label) { this._label(ctx, this.label, this.x, this.y + this.height / 2, undefined, 'top',true); + this.boundingBox.left = Math.min(this.boundingBox.left, this.labelDimensions.left) + this.boundingBox.right = Math.max(this.boundingBox.right, this.labelDimensions.left + this.labelDimensions.width) + this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelDimensions.height) } }; @@ -27009,6 +27048,11 @@ return /******/ (function(modules) { // webpackBootstrap this.top = this.y - this.height / 2; this._label(ctx, this.label, this.x, this.y); + + this.boundingBox.top = this.top; + this.boundingBox.left = this.left; + this.boundingBox.right = this.left + this.width; + this.boundingBox.bottom = this.top + this.height; }; @@ -29712,9 +29756,9 @@ return /******/ (function(modules) { // webpackBootstrap distance = Math.sqrt(dx * dx + dy * dy); // BarnesHut condition - // original condition : s/d < theta = passed === d/s > 1/theta = passed + // original condition : s/d < thetaInverted = passed === d/s > 1/theta = passed // calcSize = 1/s --> d * 1/s > 1/theta = passed - if (distance * parentBranch.calcSize > this.constants.physics.barnesHut.theta) { + if (distance * parentBranch.calcSize > this.constants.physics.barnesHut.thetaInverted) { // duplicate code to reduce function calls to speed up program if (distance == 0) { distance = 0.1*Math.random(); diff --git a/lib/network/Network.js b/lib/network/Network.js index 47b2ef95..bda20722 100644 --- a/lib/network/Network.js +++ b/lib/network/Network.js @@ -114,7 +114,7 @@ function Network (container, data, options) { physics: { barnesHut: { enabled: true, - theta: 1 / 0.6, // inverted to save time during calculation + thetaInverted: 1 / 0.5, // inverted to save time during calculation gravitationalConstant: -2000, centralGravity: 0.3, springLength: 95, @@ -385,10 +385,10 @@ Network.prototype._getRange = function() { for (var nodeId in this.nodes) { if (this.nodes.hasOwnProperty(nodeId)) { node = this.nodes[nodeId]; - if (minX > (node.x)) {minX = node.x;} - if (maxX < (node.x)) {maxX = node.x;} - if (minY > (node.y)) {minY = node.y;} - if (maxY < (node.y)) {maxY = node.y;} + if (minX > (node.boundingBox.left)) {minX = node.boundingBox.left;} + if (maxX < (node.boundingBox.right)) {maxX = node.boundingBox.right;} + if (minY > (node.boundingBox.bottom)) {minY = node.boundingBox.bottom;} + if (maxY < (node.boundingBox.top)) {maxY = node.boundingBox.top;} } } if (minX == 1e9 && maxX == -1e9 && minY == 1e9 && maxY == -1e9) { @@ -416,6 +416,8 @@ Network.prototype._findCenter = function(range) { * @param {Boolean} [disableStart] | If true, start is not called. */ Network.prototype.zoomExtent = function(animationOptions, initialZoom, disableStart) { + this._redraw(true); + if (initialZoom === undefined) { initialZoom = false; } @@ -1742,9 +1744,10 @@ Network.prototype.redraw = function() { /** * Redraw the network with the current data + * @param hidden | used to get the first estimate of the node sizes. only the nodes are drawn after which they are quickly drawn over. * @private */ -Network.prototype._redraw = function() { +Network.prototype._redraw = function(hidden) { var ctx = this.frame.canvas.getContext('2d'); ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); @@ -1768,18 +1771,21 @@ Network.prototype._redraw = function() { "y": this._YconvertDOMtoCanvas(this.frame.canvas.clientHeight * this.pixelRatio) }; - - this._doInAllSectors("_drawAllSectorNodes",ctx); - if (this.drag.dragging == false || this.drag.dragging === undefined || this.constants.hideEdgesOnDrag == false) { - this._doInAllSectors("_drawEdges",ctx); + if (!(hidden == true)) { + this._doInAllSectors("_drawAllSectorNodes", ctx); + if (this.drag.dragging == false || this.drag.dragging === undefined || this.constants.hideEdgesOnDrag == false) { + this._doInAllSectors("_drawEdges", ctx); + } } if (this.drag.dragging == false || this.drag.dragging === undefined || this.constants.hideNodesOnDrag == false) { this._doInAllSectors("_drawNodes",ctx,false); } - if (this.controlNodesActive == true) { - this._doInAllSectors("_drawControlNodes",ctx); + if (!(hidden == true)) { + if (this.controlNodesActive == true) { + this._doInAllSectors("_drawControlNodes", ctx); + } } // this._doInSupportSector("_drawNodes",ctx,true); @@ -1787,6 +1793,10 @@ Network.prototype._redraw = function() { // restore original scaling and translation ctx.restore(); + + if (hidden == true) { + ctx.clearRect(0, 0, w, h); + } }; /** diff --git a/lib/network/Node.js b/lib/network/Node.js index e70ec7e1..ba21b2d4 100644 --- a/lib/network/Node.js +++ b/lib/network/Node.js @@ -53,8 +53,8 @@ function Node(properties, imagelist, grouplist, networkConstants) { this.level = -1; this.preassignedLevel = false; this.hierarchyEnumerated = false; - this.labelDimensions = {top:0,left:0,width:0,height:0,yLine:0}; // could be cached - + this.labelDimensions = {top:0, left:0, width:0, height:0, yLine:0}; // could be cached + this.boundingBox = {top:0, left:0, right:0, bottom:0}; this.imagelist = imagelist; this.grouplist = grouplist; @@ -615,6 +615,11 @@ Node.prototype._drawBox = function (ctx) { ctx.fill(); ctx.stroke(); + this.boundingBox.top = this.top; + this.boundingBox.left = this.left; + this.boundingBox.right = this.left + this.width; + this.boundingBox.bottom = this.top + this.height; + this._label(ctx, this.label, this.x, this.y); }; @@ -664,6 +669,11 @@ Node.prototype._drawDatabase = function (ctx) { ctx.fill(); ctx.stroke(); + this.boundingBox.top = this.top; + this.boundingBox.left = this.left; + this.boundingBox.right = this.left + this.width; + this.boundingBox.bottom = this.top + this.height; + this._label(ctx, this.label, this.x, this.y); }; @@ -715,6 +725,11 @@ Node.prototype._drawCircle = function (ctx) { ctx.fill(); ctx.stroke(); + this.boundingBox.top = this.y - this.options.radius; + this.boundingBox.left = this.x - this.options.radius; + this.boundingBox.right = this.x + this.options.radius; + this.boundingBox.bottom = this.y + this.options.radius; + this._label(ctx, this.label, this.x, this.y); }; @@ -766,6 +781,12 @@ Node.prototype._drawEllipse = function (ctx) { ctx.ellipse(this.left, this.top, this.width, this.height); ctx.fill(); ctx.stroke(); + + this.boundingBox.top = this.top; + this.boundingBox.left = this.left; + this.boundingBox.right = this.left + this.width; + this.boundingBox.bottom = this.top + this.height; + this._label(ctx, this.label, this.x, this.y); }; @@ -843,8 +864,16 @@ Node.prototype._drawShape = function (ctx, shape) { ctx.fill(); ctx.stroke(); + this.boundingBox.top = this.y - this.options.radius; + this.boundingBox.left = this.x - this.options.radius; + this.boundingBox.right = this.x + this.options.radius; + this.boundingBox.bottom = this.y + this.options.radius; + if (this.label) { this._label(ctx, this.label, this.x, this.y + this.height / 2, undefined, 'top',true); + this.boundingBox.left = Math.min(this.boundingBox.left, this.labelDimensions.left) + this.boundingBox.right = Math.max(this.boundingBox.right, this.labelDimensions.left + this.labelDimensions.width) + this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelDimensions.height) } }; @@ -869,6 +898,11 @@ Node.prototype._drawText = function (ctx) { this.top = this.y - this.height / 2; this._label(ctx, this.label, this.x, this.y); + + this.boundingBox.top = this.top; + this.boundingBox.left = this.left; + this.boundingBox.right = this.left + this.width; + this.boundingBox.bottom = this.top + this.height; }; diff --git a/lib/network/mixins/physics/BarnesHutMixin.js b/lib/network/mixins/physics/BarnesHutMixin.js index 22d882cf..b70f474c 100644 --- a/lib/network/mixins/physics/BarnesHutMixin.js +++ b/lib/network/mixins/physics/BarnesHutMixin.js @@ -49,9 +49,9 @@ exports._getForceContribution = function(parentBranch,node) { distance = Math.sqrt(dx * dx + dy * dy); // BarnesHut condition - // original condition : s/d < theta = passed === d/s > 1/theta = passed + // original condition : s/d < thetaInverted = passed === d/s > 1/theta = passed // calcSize = 1/s --> d * 1/s > 1/theta = passed - if (distance * parentBranch.calcSize > this.constants.physics.barnesHut.theta) { + if (distance * parentBranch.calcSize > this.constants.physics.barnesHut.thetaInverted) { // duplicate code to reduce function calls to speed up program if (distance == 0) { distance = 0.1*Math.random();