Browse Source

Released version 1.0.2

gh-pages
jos 10 years ago
parent
commit
cb05be0d28
9 changed files with 413 additions and 138 deletions
  1. +258
    -119
      dist/vis.js
  2. +11
    -11
      dist/vis.min.js
  3. +16
    -0
      docs/graph.html
  4. +32
    -7
      docs/timeline.html
  5. BIN
      download/vis.zip
  6. +88
    -0
      examples/timeline/16_navigation_menu.html
  7. +1
    -0
      examples/timeline/index.html
  8. BIN
      img/gallery/timeline/16_navigation_menu.png
  9. +7
    -1
      index.html

+ 258
- 119
dist/vis.js View File

@ -4,8 +4,8 @@
*
* A dynamic, browser-based visualization library.
*
* @version 1.0.1
* @date 2014-05-09
* @version 1.0.2
* @date 2014-05-28
*
* @license
* Copyright (C) 2011-2014 Almende B.V, http://almende.com
@ -407,6 +407,40 @@ util.extend = function (a, b) {
return a;
};
/**
* Deep extend an object a with the properties of object b
* @param {Object} a
* @param {Object} b
* @returns {Object}
*/
util.deepExtend = function deepExtend (a, b) {
// TODO: add support for Arrays to deepExtend
if (Array.isArray(b)) {
throw new TypeError('Arrays are not supported by deepExtend');
}
for (var prop in b) {
if (b.hasOwnProperty(prop)) {
if (b[prop] && b[prop].constructor === Object) {
if (a[prop] === undefined) {
a[prop] = {};
}
if (a[prop].constructor === Object) {
deepExtend(a[prop], b[prop]);
}
else {
a[prop] = b[prop];
}
} else if (Array.isArray(b[prop])) {
throw new TypeError('Arrays are not supported by deepExtend');
} else {
a[prop] = b[prop];
}
}
}
return a;
};
/**
* Test whether all elements in two arrays are equal.
* @param {Array} a
@ -2885,8 +2919,7 @@ TimeStep.prototype.snap = function(date) {
clone.setSeconds(0);
clone.setMilliseconds(0);
}
else if (this.scale == TimeStep.SCALE.DAY ||
this.scale == TimeStep.SCALE.WEEKDAY) {
else if (this.scale == TimeStep.SCALE.DAY) {
//noinspection FallthroughInSwitchStatementJS
switch (this.step) {
case 5:
@ -2899,6 +2932,19 @@ TimeStep.prototype.snap = function(date) {
clone.setSeconds(0);
clone.setMilliseconds(0);
}
else if (this.scale == TimeStep.SCALE.WEEKDAY) {
//noinspection FallthroughInSwitchStatementJS
switch (this.step) {
case 5:
case 2:
clone.setHours(Math.round(clone.getHours() / 12) * 12); break;
default:
clone.setHours(Math.round(clone.getHours() / 6) * 6); break;
}
clone.setMinutes(0);
clone.setSeconds(0);
clone.setMilliseconds(0);
}
else if (this.scale == TimeStep.SCALE.HOUR) {
switch (this.step) {
case 4:
@ -3905,6 +3951,7 @@ RootPanel.prototype.repaint = function repaint() {
// update frame size
this.frame.style.maxHeight = util.option.asSize(this.options.maxHeight, '');
this.frame.style.minHeight = util.option.asSize(this.options.minHeight, '');
this._updateSize();
// if the root panel or any of its childs is resized, repaint again,
@ -4387,32 +4434,32 @@ TimeAxis.prototype._repaintLine = function() {
* @private
*/
TimeAxis.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 = 'text minor measure';
measureCharMinor.appendChild(textMinor);
this.frame.appendChild(measureCharMinor);
// Note: We calculate char size with every repaint. Size may change, for
// example when any of the timelines parents had display:none for example.
this.props.minorCharHeight = measureCharMinor.clientHeight;
this.props.minorCharWidth = measureCharMinor.clientWidth;
// determine the char width and height on the minor axis
if (!this.dom.measureCharMinor) {
this.dom.measureCharMinor = document.createElement('DIV');
this.dom.measureCharMinor.className = 'text minor measure';
this.dom.measureCharMinor.style.position = 'absolute';
this.frame.removeChild(measureCharMinor);
this.dom.measureCharMinor.appendChild(document.createTextNode('0'));
this.frame.appendChild(this.dom.measureCharMinor);
}
this.props.minorCharHeight = this.dom.measureCharMinor.clientHeight;
this.props.minorCharWidth = this.dom.measureCharMinor.clientWidth;
if (!('majorCharHeight' in this.props)) {
var textMajor = document.createTextNode('0');
var measureCharMajor = document.createElement('DIV');
measureCharMajor.className = 'text major measure';
measureCharMajor.appendChild(textMajor);
this.frame.appendChild(measureCharMajor);
// determine the char width and height on the major axis
if (!this.dom.measureCharMajor) {
this.dom.measureCharMajor = document.createElement('DIV');
this.dom.measureCharMajor.className = 'text minor measure';
this.dom.measureCharMajor.style.position = 'absolute';
this.props.majorCharHeight = measureCharMajor.clientHeight;
this.props.majorCharWidth = measureCharMajor.clientWidth;
this.frame.removeChild(measureCharMajor);
this.dom.measureCharMajor.appendChild(document.createTextNode('0'));
this.frame.appendChild(this.dom.measureCharMajor);
}
this.props.majorCharHeight = this.dom.measureCharMajor.clientHeight;
this.props.majorCharWidth = this.dom.measureCharMajor.clientWidth;
};
/**
@ -5190,7 +5237,8 @@ ItemSet.prototype.setGroups = function setGroups(groups) {
// remove all drawn groups
ids = this.groupsData.getIds();
this._onRemoveGroups(ids);
this.groupsData = null;
this._onRemoveGroups(ids); // note: this will cause a repaint
}
// replace the dataset
@ -5441,8 +5489,7 @@ ItemSet.prototype._orderGroups = function () {
// hide all groups, removes them from the DOM
var groups = this.groups;
groupIds.forEach(function (groupId) {
var group = groups[groupId];
group.hide();
groups[groupId].hide();
});
// show the groups again, attach them to the DOM in correct order
@ -6742,6 +6789,14 @@ Group.prototype._create = function() {
this.dom.background = document.createElement('div');
this.dom.axis = document.createElement('div');
// create a hidden marker to detect when the Timelines container is attached
// to the DOM, or the style of a parent of the Timeline is changed from
// display:none is changed to visible.
this.dom.marker = document.createElement('div');
this.dom.marker.style.visibility = 'hidden';
this.dom.marker.innerHTML = '?';
this.dom.background.appendChild(this.dom.marker);
};
/**
@ -6813,6 +6868,20 @@ Group.prototype.repaint = function repaint(range, margin, restack) {
this.visibleItems = this._updateVisibleItems(this.orderedItems, this.visibleItems, range);
// force recalculation of the height of the items when the marker height changed
// (due to the Timeline being attached to the DOM or changed from display:none to visible)
var markerHeight = this.dom.marker.clientHeight;
if (markerHeight != this.lastMarkerHeight) {
this.lastMarkerHeight = markerHeight;
util.forEach(this.items, function (item) {
item.dirty = true;
if (item.displayed) item.repaint();
});
restack = true;
}
// reposition visible items vertically
if (this.itemSet.options.stack) { // TODO: ugly way to access options...
stack.stack(this.visibleItems, margin, restack);
@ -6820,7 +6889,6 @@ Group.prototype.repaint = function repaint(range, margin, restack) {
else { // no stacking
stack.nostack(this.visibleItems, margin);
}
this.stackDirty = false;
for (var i = 0, ii = this.visibleItems.length; i < ii; i++) {
var item = this.visibleItems[i];
item.repositionY();
@ -7155,7 +7223,7 @@ function Timeline (container, items, options) {
var me = this;
var now = moment().hours(0).minutes(0).seconds(0).milliseconds(0);
this.options = {
this.defaultOptions = {
orientation: 'bottom',
direction: 'horizontal', // 'horizontal' or 'vertical'
autoResize: true,
@ -7169,7 +7237,6 @@ function Timeline (container, items, options) {
},
selectable: true,
snap: null, // will be specified after timeaxis is created
min: null,
max: null,
@ -7183,6 +7250,13 @@ function Timeline (container, items, options) {
showCurrentTime: false,
showCustomTime: false,
groupOrder: null,
width: null,
height: null,
maxHeight: null,
minHeight: null,
type: 'box',
align: 'center',
margin: {
@ -7202,11 +7276,17 @@ function Timeline (container, items, options) {
},
onRemove: function (item, callback) {
callback(item);
},
}
};
this.options = {};
util.deepExtend(this.options, this.defaultOptions);
util.deepExtend(this.options, {
snap: null, // will be specified after timeaxis is created
toScreen: me._toScreen.bind(me),
toTime: me._toTime.bind(me)
};
});
// root panel
var rootOptions = util.extend(Object.create(this.options), {
@ -7424,7 +7504,7 @@ Emitter(Timeline.prototype);
* @param {Object} options TODO: describe the available options
*/
Timeline.prototype.setOptions = function (options) {
util.extend(this.options, options);
util.deepExtend(this.options, options);
if ('editable' in options) {
var isBoolean = typeof options.editable === 'boolean';
@ -7583,6 +7663,33 @@ Timeline.prototype.setGroups = function setGroups(groups) {
this.itemSet.setGroups(newDataSet);
};
/**
* Clear the Timeline. By Default, items, groups and options are cleared.
* Example usage:
*
* timeline.clear(); // clear items, groups, and options
* timeline.clear({options: true}); // clear options only
*
* @param {Object} [what] Optionally specify what to clear. By default:
* {items: true, groups: true, options: true}
*/
Timeline.prototype.clear = function clear(what) {
// clear items
if (!what || what.items) {
this.setItems(null);
}
// clear groups
if (!what || what.groups) {
this.setGroups(null);
}
// clear options
if (!what || what.options) {
this.setOptions(this.defaultOptions);
}
};
/**
* Set Timeline window such that it fits all items
*/
@ -7679,7 +7786,7 @@ Timeline.prototype.getSelection = function getSelection() {
* Where start and end can be a Date, number, or string, and range is an
* object with properties start and end.
*
* @param {Date | Number | String} [start] Start date of visible window
* @param {Date | Number | String | Object} [start] Start date of visible window
* @param {Date | Number | String} [end] End date of visible window
*/
Timeline.prototype.setWindow = function setWindow(start, end) {
@ -7704,6 +7811,14 @@ Timeline.prototype.getWindow = function setWindow() {
};
};
/**
* Force a repaint of the Timeline. Can be useful to manually repaint when
* option autoResize=false
*/
Timeline.prototype.repaint = function repaint() {
this.rootPanel.repaint();
};
/**
* Handle selecting/deselecting an item when tapping it
* @param {Event} event
@ -7770,6 +7885,11 @@ Timeline.prototype._onAddItem = function (event) {
content: 'new item'
};
// when default type is a range, add a default end date to the new item
if (this.options.type === 'range' || this.options.type == 'rangeoverflow') {
newItem.end = this.timeAxis.snap(this._toTime(x + this.rootPanel.width / 5));
}
var id = util.randomUUID();
newItem[this.itemsData.fieldId] = id;
@ -11091,7 +11211,7 @@ var physicsMixin = {
*/
_calculateSpringForces: function () {
var edgeLength, edge, edgeId;
var dx, dy, fx, fy, springForce, length;
var dx, dy, fx, fy, springForce, distance;
var edges = this.edges;
// forces caused by the edges, modelled as springs
@ -11107,13 +11227,14 @@ var physicsMixin = {
dx = (edge.from.x - edge.to.x);
dy = (edge.from.y - edge.to.y);
length = Math.sqrt(dx * dx + dy * dy);
distance = Math.sqrt(dx * dx + dy * dy);
if (length == 0) {
length = 0.01;
if (distance == 0) {
distance = 0.01;
}
springForce = this.constants.physics.springConstant * (edgeLength - length) / length;
// the 1/distance is so the fx and fy can be calculated without sine or cosine.
springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance;
fx = dx * springForce;
fy = dy * springForce;
@ -11175,17 +11296,18 @@ var physicsMixin = {
* @private
*/
_calculateSpringForce: function (node1, node2, edgeLength) {
var dx, dy, fx, fy, springForce, length;
var dx, dy, fx, fy, springForce, distance;
dx = (node1.x - node2.x);
dy = (node1.y - node2.y);
length = Math.sqrt(dx * dx + dy * dy);
distance = Math.sqrt(dx * dx + dy * dy);
if (length == 0) {
length = 0.01;
if (distance == 0) {
distance = 0.01;
}
springForce = this.constants.physics.springConstant * (edgeLength - length) / length;
// the 1/distance is so the fx and fy can be calculated without sine or cosine.
springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance;
fx = dx * springForce;
fy = dy * springForce;
@ -11220,7 +11342,7 @@ var physicsMixin = {
'<table id="graph_BH_table" style="display:none">' +
'<tr><td><b>Barnes Hut</b></td></tr>' +
'<tr>' +
'<td width="150px">gravitationalConstant</td><td>0</td><td><input type="range" min="500" max="20000" value="' + (-1 * this.constants.physics.barnesHut.gravitationalConstant) + '" step="25" style="width:300px" id="graph_BH_gc"></td><td width="50px">-20000</td><td><input value="' + (-1 * this.constants.physics.barnesHut.gravitationalConstant) + '" id="graph_BH_gc_value" style="width:60px"></td>' +
'<td width="150px">gravitationalConstant</td><td>0</td><td><input type="range" min="0" max="20000" value="' + (-1 * this.constants.physics.barnesHut.gravitationalConstant) + '" step="25" style="width:300px" id="graph_BH_gc"></td><td width="50px">-20000</td><td><input value="' + (-1 * this.constants.physics.barnesHut.gravitationalConstant) + '" id="graph_BH_gc_value" style="width:60px"></td>' +
'</tr>' +
'<tr>' +
'<td width="150px">centralGravity</td><td>0</td><td><input type="range" min="0" max="3" value="' + this.constants.physics.barnesHut.centralGravity + '" step="0.05" style="width:300px" id="graph_BH_cg"></td><td>3</td><td><input value="' + this.constants.physics.barnesHut.centralGravity + '" id="graph_BH_cg_value" style="width:60px"></td>' +
@ -12681,10 +12803,10 @@ var manipulationMixin = {
this.cachedFunctions["_handleOnDrag"] = this._handleOnDrag;
this._handleOnDrag = function(event) {
var pointer = this._getPointer(event.gesture.center);
this.sectors['support']['nodes']['targetNode'].x = this._canvasToX(pointer.x);
this.sectors['support']['nodes']['targetNode'].y = this._canvasToY(pointer.y);
this.sectors['support']['nodes']['targetViaNode'].x = 0.5 * (this._canvasToX(pointer.x) + this.edges['connectionEdge'].from.x);
this.sectors['support']['nodes']['targetViaNode'].y = this._canvasToY(pointer.y);
this.sectors['support']['nodes']['targetNode'].x = this._XconvertDOMtoCanvas(pointer.x);
this.sectors['support']['nodes']['targetNode'].y = this._YconvertDOMtoCanvas(pointer.y);
this.sectors['support']['nodes']['targetViaNode'].x = 0.5 * (this._XconvertDOMtoCanvas(pointer.x) + this.edges['connectionEdge'].from.x);
this.sectors['support']['nodes']['targetViaNode'].y = this._YconvertDOMtoCanvas(pointer.y);
};
this.moving = true;
@ -14607,8 +14729,8 @@ var SelectionMixin = {
* @private
*/
_pointerToPositionObject : function(pointer) {
var x = this._canvasToX(pointer.x);
var y = this._canvasToY(pointer.y);
var x = this._XconvertDOMtoCanvas(pointer.x);
var y = this._YconvertDOMtoCanvas(pointer.y);
return {left: x,
top: y,
@ -15000,8 +15122,8 @@ var SelectionMixin = {
var node = this._getNodeAt(pointer);
if (node != null && node !== undefined) {
// we reset the areaCenter here so the opening of the node will occur
this.areaCenter = {"x" : this._canvasToX(pointer.x),
"y" : this._canvasToY(pointer.y)};
this.areaCenter = {"x" : this._XconvertDOMtoCanvas(pointer.x),
"y" : this._YconvertDOMtoCanvas(pointer.y)};
this.openCluster(node);
}
this.emit("doubleClick", this.getSelection());
@ -15723,7 +15845,9 @@ function Graph (container, data, options) {
border: '#666',
background: '#FFFFC6'
}
}
},
moveable: true,
zoomable: true
};
this.editMode = this.constants.dataManipulation.initiallyVisible;
@ -15755,8 +15879,11 @@ function Graph (container, data, options) {
this._loadHierarchySystem();
// apply options
this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2);
this._setScale(1);
this.setOptions(options);
// other vars
this.freezeSimulation = false;// freeze the simulation
this.cachedFunctions = {};
@ -16034,15 +16161,19 @@ Graph.prototype.setData = function(data, disableStart) {
if (!disableStart) {
// find a stable position or start animating to a stable position
if (this.stabilize) {
this._stabilize();
var me = this;
setTimeout(function() {me._stabilize(); me.start();},0)
}
else {
this.start();
}
this.start();
}
};
/**
* Set options
* @param {Object} options
* @param {Boolean} [initializeView] | set zoom and translation to default.
*/
Graph.prototype.setOptions = function (options) {
if (options) {
@ -16056,7 +16187,8 @@ Graph.prototype.setOptions = function (options) {
if (options.freezeForStabilization !== undefined) {this.constants.freezeForStabilization = options.freezeForStabilization;}
if (options.configurePhysics !== undefined){this.constants.configurePhysics = options.configurePhysics;}
if (options.stabilizationIterations !== undefined) {this.constants.stabilizationIterations = options.stabilizationIterations;}
if (options.moveable !== undefined) {this.constants.moveable = options.moveable;}
if (options.zoomable !== undefined) {this.constants.zoomable = options.zoomable;}
if (options.labels !== undefined) {
@ -16271,11 +16403,10 @@ Graph.prototype.setOptions = function (options) {
// bind keys. If disabled, this will not do anything;
this._createKeyBinds();
this.setSize(this.width, this.height);
this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2);
this._setScale(1);
this._redraw();
this.moving = true;
this.start();
};
/**
@ -16491,11 +16622,11 @@ Graph.prototype._handleOnDrag = function(event) {
var node = s.node;
if (!s.xFixed) {
node.x = me._canvasToX(me._xToCanvas(s.x) + deltaX);
node.x = me._XconvertDOMtoCanvas(me._XconvertCanvasToDOM(s.x) + deltaX);
}
if (!s.yFixed) {
node.y = me._canvasToY(me._yToCanvas(s.y) + deltaY);
node.y = me._YconvertDOMtoCanvas(me._YconvertCanvasToDOM(s.y) + deltaY);
}
});
@ -16506,16 +16637,18 @@ Graph.prototype._handleOnDrag = function(event) {
}
}
else {
// move the graph
var diffX = pointer.x - this.drag.pointer.x;
var diffY = pointer.y - this.drag.pointer.y;
this._setTranslation(
this.drag.translation.x + diffX,
this.drag.translation.y + diffY);
this._redraw();
this.moving = true;
this.start();
if (this.constants.moveable == true) {
// move the graph
var diffX = pointer.x - this.drag.pointer.x;
var diffY = pointer.y - this.drag.pointer.y;
this._setTranslation(
this.drag.translation.x + diffX,
this.drag.translation.y + diffY);
this._redraw();
this.moving = true;
this.start();
}
}
};
@ -16603,37 +16736,38 @@ Graph.prototype._onPinch = function (event) {
* @private
*/
Graph.prototype._zoom = function(scale, pointer) {
var scaleOld = this._getScale();
if (scale < 0.00001) {
scale = 0.00001;
}
if (scale > 10) {
scale = 10;
}
// + this.frame.canvas.clientHeight / 2
var translation = this._getTranslation();
var scaleFrac = scale / scaleOld;
var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac;
var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac;
if (this.constants.zoomable == true) {
var scaleOld = this._getScale();
if (scale < 0.00001) {
scale = 0.00001;
}
if (scale > 10) {
scale = 10;
}
// + this.frame.canvas.clientHeight / 2
var translation = this._getTranslation();
this.areaCenter = {"x" : this._canvasToX(pointer.x),
"y" : this._canvasToY(pointer.y)};
var scaleFrac = scale / scaleOld;
var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac;
var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac;
this._setScale(scale);
this._setTranslation(tx, ty);
this.updateClustersDefault();
this._redraw();
this.areaCenter = {"x" : this._XconvertDOMtoCanvas(pointer.x),
"y" : this._YconvertDOMtoCanvas(pointer.y)};
if (scaleOld < scale) {
this.emit("zoom", {direction:"+"});
}
else {
this.emit("zoom", {direction:"-"});
}
this._setScale(scale);
this._setTranslation(tx, ty);
this.updateClustersDefault();
this._redraw();
if (scaleOld < scale) {
this.emit("zoom", {direction:"+"});
}
else {
this.emit("zoom", {direction:"-"});
}
return scale;
return scale;
}
};
@ -16719,10 +16853,10 @@ Graph.prototype._onMouseMoveTitle = function (event) {
*/
Graph.prototype._checkShowPopup = function (pointer) {
var obj = {
left: this._canvasToX(pointer.x),
top: this._canvasToY(pointer.y),
right: this._canvasToX(pointer.x),
bottom: this._canvasToY(pointer.y)
left: this._XconvertDOMtoCanvas(pointer.x),
top: this._YconvertDOMtoCanvas(pointer.y),
right: this._XconvertDOMtoCanvas(pointer.x),
bottom: this._YconvertDOMtoCanvas(pointer.y)
};
var id;
@ -17186,12 +17320,12 @@ Graph.prototype._redraw = function() {
ctx.scale(this.scale, this.scale);
this.canvasTopLeft = {
"x": this._canvasToX(0),
"y": this._canvasToY(0)
"x": this._XconvertDOMtoCanvas(0),
"y": this._YconvertDOMtoCanvas(0)
};
this.canvasBottomRight = {
"x": this._canvasToX(this.frame.canvas.clientWidth),
"y": this._canvasToY(this.frame.canvas.clientHeight)
"x": this._XconvertDOMtoCanvas(this.frame.canvas.clientWidth),
"y": this._YconvertDOMtoCanvas(this.frame.canvas.clientHeight)
};
this._doInAllSectors("_drawAllSectorNodes",ctx);
@ -17260,42 +17394,46 @@ Graph.prototype._getScale = function() {
};
/**
* Convert a horizontal point on the HTML canvas to the x-value of the model
* Convert the X coordinate in DOM-space (coordinate point in browser relative to the container div) to
* the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
* @param {number} x
* @returns {number}
* @private
*/
Graph.prototype._canvasToX = function(x) {
Graph.prototype._XconvertDOMtoCanvas = function(x) {
return (x - this.translation.x) / this.scale;
};
/**
* Convert an x-value in the model to a horizontal point on the HTML canvas
* Convert the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
* the X coordinate in DOM-space (coordinate point in browser relative to the container div)
* @param {number} x
* @returns {number}
* @private
*/
Graph.prototype._xToCanvas = function(x) {
Graph.prototype._XconvertCanvasToDOM = function(x) {
return x * this.scale + this.translation.x;
};
/**
* Convert a vertical point on the HTML canvas to the y-value of the model
* Convert the Y coordinate in DOM-space (coordinate point in browser relative to the container div) to
* the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
* @param {number} y
* @returns {number}
* @private
*/
Graph.prototype._canvasToY = function(y) {
Graph.prototype._YconvertDOMtoCanvas = function(y) {
return (y - this.translation.y) / this.scale;
};
/**
* Convert an y-value in the model to a vertical point on the HTML canvas
* Convert the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
* the Y coordinate in DOM-space (coordinate point in browser relative to the container div)
* @param {number} y
* @returns {number}
* @private
*/
Graph.prototype._yToCanvas = function(y) {
Graph.prototype._YconvertCanvasToDOM = function(y) {
return y * this.scale + this.translation.y ;
};
@ -17306,8 +17444,8 @@ Graph.prototype._yToCanvas = function(y) {
* @returns {{x: number, y: number}}
* @constructor
*/
Graph.prototype.DOMtoCanvas = function(pos) {
return {x:this._xToCanvas(pos.x),y:this._yToCanvas(pos.y)};
Graph.prototype.canvasToDOM = function(pos) {
return {x:this._XconvertCanvasToDOM(pos.x),y:this._YconvertCanvasToDOM(pos.y)};
}
/**
@ -17316,8 +17454,8 @@ Graph.prototype.DOMtoCanvas = function(pos) {
* @returns {{x: number, y: number}}
* @constructor
*/
Graph.prototype.canvasToDOM = function(pos) {
return {x:this._canvasToX(pos.x),y:this._canvasToY(pos.y)};
Graph.prototype.DOMtoCanvas = function(pos) {
return {x:this._XconvertDOMtoCanvas(pos.x),y:this._YconvertDOMtoCanvas(pos.y)};
}
/**
@ -17727,6 +17865,7 @@ Graph.prototype.storePosition = function() {
*/
var vis = {
util: util,
moment: moment,
DataSet: DataSet,
DataView: DataView,

+ 11
- 11
dist/vis.min.js
File diff suppressed because it is too large
View File


+ 16
- 0
docs/graph.html View File

@ -798,6 +798,14 @@ var options = {
Configuration options for shortcuts keys. Sortcut keys are turned off by default. See section <a href="#Keyboard_navigation">Keyboard navigation</a> for an overview of the available options.
</td>
</tr>
<tr>
<td>moveable</td>
<td>Boolean</td>
<td>true</td>
<td>
Toggle if the graph can be dragged. This will not affect the dragging of nodes.
</td>
</tr>
<tr>
<td><a href="#Navigation_controls">navigation</a></td>
@ -854,6 +862,14 @@ var options = {
<td>"400px"</td>
<td>The width of the graph in pixels or as a percentage.</td>
</tr>
<tr>
<td>zoomable</td>
<td>Boolean</td>
<td>true</td>
<td>
Toggle if the graph can be zoomed.
</td>
</tr>
</table>

+ 32
- 7
docs/timeline.html View File

@ -341,8 +341,7 @@ var options = {
<td>autoResize</td>
<td>boolean</td>
<td>true</td>
<td>If true, the Timeline will automatically detect when its
container is resized, and redraw itself accordingly.</td>
<td>If true, the Timeline will automatically detect when its container is resized, and redraw itself accordingly. If false, the Timeline can be forced to repaint after its container has been resized using the function <code>repaint()</code>.</td>
</tr>
<tr>
@ -402,7 +401,7 @@ var options = {
<tr>
<td>height</td>
<td>String</td>
<td>Number | String</td>
<td>none</td>
<td>The height of the timeline in pixels or as a percentage.
When height is undefined or null, the height of the timeline is automatically
@ -438,10 +437,9 @@ var options = {
<tr>
<td>maxHeight</td>
<td>Number</td>
<td>Number | String</td>
<td>none</td>
<td>Specifies a maximum height for the Timeline in pixels.
</td>
<td>Specifies the maximum height for the Timeline. Can be a number in pixels or a string like "300px".</td>
</tr>
<tr>
@ -453,6 +451,13 @@ var options = {
</td>
</tr>
<tr>
<td>minHeight</td>
<td>Number | String</td>
<td>none</td>
<td>Specifies the minimum height for the Timeline. Can be a number in pixels or a string like "300px".</td>
</tr>
<tr>
<td>onAdd</td>
<td>Function</td>
@ -583,7 +588,7 @@ var options = {
<td>type</td>
<td>String</td>
<td>'box'</td>
<td>Specifies the type for the timeline items. Choose from 'box', 'point', 'range', and 'rangeoverflow'. Note that individual items can override this global type.
<td>Specifies the default type for the timeline items. Choose from 'box', 'point', 'range', and 'rangeoverflow'. Note that individual items can override this default type.
</td>
</tr>
@ -628,6 +633,19 @@ var options = {
<th>Description</th>
</tr>
<tr>
<td>clear([what])</td>
<td>none</td>
<td>
Clear the Timeline. An object can be passed specifying which sections to clear: items, groups,
and/or options. By Default, items, groups and options are cleared, i.e. <code>what = {items: true, groups: true, options: true}</code>. Example usage:
<pre class="prettyprint lang-js">timeline.clear(); // clear items, groups, and options
timeline.clear({options: true}); // clear options only
</pre>
</td>
</tr>
<tr>
<td>fit()</td>
<td>none</td>
@ -673,6 +691,13 @@ var options = {
<td>Remove an event listener created before via function <code>on(event, callback)</code>. See section <a href="#Events">Events for more information</a>.</td>
</tr>
<tr>
<td>repaint()</td>
<td>none</td>
<td>Force a repaint of the Timeline. Can be useful to manually repaint when option autoResize=false.
</td>
</tr>
<tr>
<td>setGroups(groups)</td>
<td>none</td>

BIN
download/vis.zip View File


+ 88
- 0
examples/timeline/16_navigation_menu.html View File

@ -0,0 +1,88 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Timeline | navigation menu</title>
<style type="text/css">
body, html, input {
font-family: sans-serif;
font-size: 12pt;
}
#visualization {
position: relative;
}
.menu {
position: absolute;
top: 0;
right: 0;
margin: 10px;
z-index: 9999;
}
</style>
<script src="../../dist/vis.js"></script>
<link href="../../dist/vis.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="visualization">
<div class="menu">
<input type="button" id="zoomIn" value="Zoom in"/>
<input type="button" id="zoomOut" value="Zoom out"/>
<input type="button" id="moveLeft" value="Move left"/>
<input type="button" id="moveRight" value="Move right"/>
</div>
</div>
<script type="text/javascript">
// create a timeline with some data
var container = document.getElementById('visualization');
var items = [
{id: 1, content: 'item 1', start: '2014-04-20'},
{id: 2, content: 'item 2', start: '2014-04-14'},
{id: 3, content: 'item 3', start: '2014-04-18'},
{id: 4, content: 'item 4', start: '2014-04-16', end: '2014-04-19'},
{id: 5, content: 'item 5', start: '2014-04-25'},
{id: 6, content: 'item 6', start: '2014-04-27', type: 'point'}
];
var options = {};
var timeline = new vis.Timeline(container, items, options);
/**
* Move the timeline a given percentage to left or right
* @param {Number} percentage For example 0.1 (left) or -0.1 (right)
*/
function move (percentage) {
var range = timeline.getWindow();
var interval = range.end - range.start;
timeline.setWindow({
start: range.start.valueOf() - interval * percentage,
end: range.end.valueOf() - interval * percentage
});
}
/**
* Zoom the timeline a given percentage in or out
* @param {Number} percentage For example 0.1 (zoom out) or -0.1 (zoom in)
*/
function zoom (percentage) {
var range = timeline.getWindow();
var interval = range.end - range.start;
timeline.setWindow({
start: range.start.valueOf() - interval * percentage,
end: range.end.valueOf() + interval * percentage
});
}
// attach events to the navigation buttons
document.getElementById('zoomIn').onclick = function () { zoom(-0.2); };
document.getElementById('zoomOut').onclick = function () { zoom( 0.2); };
document.getElementById('moveLeft').onclick = function () { move( 0.2); };
document.getElementById('moveRight').onclick = function () { move(-0.2); };
</script>
</body>
</html>

+ 1
- 0
examples/timeline/index.html View File

@ -27,6 +27,7 @@
<p><a href="13_past_and_future.html">13_past_and_future.html</a></p>
<p><a href="14_a_lot_of_grouped_data.html">14_a_lot_of_grouped_data.html</a></p>
<p><a href="15_item_class_names.html">15_item_class_names.html</a></p>
<p><a href="16_navigation_menu.html">16_navigation_menu.html</a></p>
<p><a href="requirejs/requirejs_example.html">requirejs_example.html</a></p>

BIN
img/gallery/timeline/16_navigation_menu.png View File

Before After
Width: 600  |  Height: 192  |  Size: 11 KiB

+ 7
- 1
index.html View File

@ -74,7 +74,7 @@ bower install vis
<h3>download</h3>
<a href="download/vis.zip">Click here to download vis.js</a>
(version <span class="version">1.0.1</span>)
(version <span class="version">1.0.2</span>)
<h2 id="example">Example</h2>
@ -218,6 +218,12 @@ The source code of the examples can be found in the
<div>item class names</div>
</a>
</div>
<div class="thumb">
<a href="examples/timeline/16_navigation_menu.html">
<img src="img/gallery/timeline/16_navigation_menu.png">
<div>navigation menu</div>
</a>
</div>
</div>
<h3 id="graph">Graph</h3>

Loading…
Cancel
Save