Browse Source

Added new verticalDrag event for internal use, allowing the vertical scrolling of the grid lines on drag.

v3_develop
Alex de Mulder 9 years ago
parent
commit
ca29945fed
5 changed files with 266 additions and 239 deletions
  1. +1
    -0
      HISTORY.md
  2. +251
    -238
      dist/vis.js
  3. +1
    -1
      examples/graph2d/07_scrollingAndSorting.html
  4. +2
    -0
      lib/timeline/Core.js
  5. +11
    -0
      lib/timeline/component/DataAxis.js

+ 1
- 0
HISTORY.md View File

@ -19,6 +19,7 @@ http://visjs.org
- Fixed cleaning up of groups.
- Throw error message when items are added before groups.
- Made graphHeight automatic if height is defined AND if graphHeight is smaller than the center panel when height is defined as well.
- Added new verticalDrag event for internal use, allowing the vertical scrolling of the grid lines on drag.
## 2014-10-28, version 3.6.3

+ 251
- 238
dist/vis.js View File

@ -104,7 +104,7 @@ return /******/ (function(modules) { // webpackBootstrap
exports.Graph2d = __webpack_require__(42);
exports.timeline = {
DateUtil: __webpack_require__(24),
DataStep: __webpack_require__(44),
DataStep: __webpack_require__(47),
Range: __webpack_require__(21),
stack: __webpack_require__(33),
TimeStep: __webpack_require__(27),
@ -121,12 +121,12 @@ return /******/ (function(modules) { // webpackBootstrap
Component: __webpack_require__(23),
CurrentTime: __webpack_require__(28),
CustomTime: __webpack_require__(30),
DataAxis: __webpack_require__(45),
GraphGroup: __webpack_require__(46),
DataAxis: __webpack_require__(44),
GraphGroup: __webpack_require__(45),
Group: __webpack_require__(32),
BackgroundGroup: __webpack_require__(36),
ItemSet: __webpack_require__(31),
Legend: __webpack_require__(47),
Legend: __webpack_require__(46),
LineGraph: __webpack_require__(43),
TimeAxis: __webpack_require__(26)
}
@ -14046,8 +14046,10 @@ return /******/ (function(modules) { // webpackBootstrap
var oldScrollTop = this._getScrollTop();
var newScrollTop = this._setScrollTop(this.touch.initialScrollTop + delta);
if (newScrollTop != oldScrollTop) {
this.redraw(); // TODO: this causes two redraws when dragging, the other is triggered by rangechange already
this.emit("verticalDrag");
}
};
@ -20031,9 +20033,9 @@ 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 GraphGroup = __webpack_require__(46);
var Legend = __webpack_require__(47);
var DataAxis = __webpack_require__(44);
var GraphGroup = __webpack_require__(45);
var Legend = __webpack_require__(46);
var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items
@ -21350,240 +21352,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) {
// 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.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) {
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;
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() {
var toPrecision = '' + Number(this.current).toPrecision(5);
if (toPrecision.indexOf(",") != -1 || toPrecision.indexOf(".") != -1) {
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__(47);
/**
* A horizontal time axis
@ -21647,6 +21421,11 @@ return /******/ (function(modules) { // webpackBootstrap
// create the HTML DOM
this._create();
var me = this;
this.body.emitter.on("verticalDrag", function() {
me.dom.lineContainer.style.top = me.body.domProps.scrollTop + 'px';
});
}
DataAxis.prototype = new Component();
@ -21715,6 +21494,7 @@ return /******/ (function(modules) { // webpackBootstrap
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");
@ -21803,6 +21583,9 @@ return /******/ (function(modules) { // webpackBootstrap
DataAxis.prototype.redraw = function () {
var changeCalled = false;
var activeGroups = 0;
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)) {
@ -21911,6 +21694,7 @@ return /******/ (function(modules) { // webpackBootstrap
this.maxLabelSize = 0;
var y = 0;
while (max < Math.round(amountOfSteps)) {
step.next();
y = Math.round(max * stepPixels);
marginStartPos = max * stepPixels;
@ -21942,6 +21726,7 @@ return /******/ (function(modules) { // webpackBootstrap
}
var offset = this.options.icons == true ? this.options.iconWidth + this.options.labelOffsetX + 15 : this.options.labelOffsetX + 15;
// this will resize the yAxis to accomodate the labels.
if (this.maxLabelSize > (this.width - offset) && this.options.visible == true) {
this.width = this.maxLabelSize + offset;
@ -22084,7 +21869,7 @@ return /******/ (function(modules) { // webpackBootstrap
/***/ },
/* 46 */
/* 45 */
/***/ function(module, exports, __webpack_require__) {
var util = __webpack_require__(1);
@ -22225,7 +22010,7 @@ return /******/ (function(modules) { // webpackBootstrap
/***/ },
/* 47 */
/* 46 */
/***/ function(module, exports, __webpack_require__) {
var util = __webpack_require__(1);
@ -22432,6 +22217,234 @@ return /******/ (function(modules) { // webpackBootstrap
module.exports = Legend;
/***/ },
/* 47 */
/***/ 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) {
// 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.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) {
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;
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() {
var toPrecision = '' + Number(this.current).toPrecision(5);
if (toPrecision.indexOf(",") != -1 || toPrecision.indexOf(".") != -1) {
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;
/***/ },
/* 48 */
/***/ function(module, exports, __webpack_require__) {

+ 1
- 1
examples/graph2d/07_scrollingAndSorting.html View File

@ -59,7 +59,7 @@
var dataset = new vis.DataSet(items);
var options = {
legend: true,
legend: {left: {position: 'bottom-left'}},
sort: false,
defaultGroup: 'doodle',
graphHeight: '1500px',

+ 2
- 0
lib/timeline/Core.js View File

@ -792,8 +792,10 @@ Core.prototype._onDrag = function (event) {
var oldScrollTop = this._getScrollTop();
var newScrollTop = this._setScrollTop(this.touch.initialScrollTop + delta);
if (newScrollTop != oldScrollTop) {
this.redraw(); // TODO: this causes two redraws when dragging, the other is triggered by rangechange already
this.emit("verticalDrag");
}
};

+ 11
- 0
lib/timeline/component/DataAxis.js View File

@ -65,6 +65,11 @@ function DataAxis (body, options, svg, linegraphOptions) {
// create the HTML DOM
this._create();
var me = this;
this.body.emitter.on("verticalDrag", function() {
me.dom.lineContainer.style.top = me.body.domProps.scrollTop + 'px';
});
}
DataAxis.prototype = new Component();
@ -133,6 +138,7 @@ DataAxis.prototype._create = function() {
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");
@ -221,6 +227,9 @@ DataAxis.prototype.setRange = function (start, end) {
DataAxis.prototype.redraw = function () {
var changeCalled = false;
var activeGroups = 0;
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)) {
@ -329,6 +338,7 @@ DataAxis.prototype._redrawLabels = function () {
this.maxLabelSize = 0;
var y = 0;
while (max < Math.round(amountOfSteps)) {
step.next();
y = Math.round(max * stepPixels);
marginStartPos = max * stepPixels;
@ -360,6 +370,7 @@ DataAxis.prototype._redrawLabels = function () {
}
var offset = this.options.icons == true ? this.options.iconWidth + this.options.labelOffsetX + 15 : this.options.labelOffsetX + 15;
// this will resize the yAxis to accomodate the labels.
if (this.maxLabelSize > (this.width - offset) && this.options.visible == true) {
this.width = this.maxLabelSize + offset;

Loading…
Cancel
Save