Browse Source

Merge remote-tracking branch 'origin/develop' into develop

Conflicts:
	lib/timeline/component/TimeAxis.js
v3_develop
jos 10 years ago
parent
commit
f925a9fb2e
31 changed files with 2557 additions and 2207 deletions
  1. +24
    -0
      HISTORY.md
  2. +2106
    -1977
      dist/vis.js
  3. +1
    -1
      dist/vis.map
  4. +14
    -14
      dist/vis.min.js
  5. +0
    -12
      docs/graph2d.html
  6. +10
    -4
      docs/network.html
  7. +0
    -18
      docs/timeline.html
  8. +10
    -1
      examples/network/02_random_nodes.html
  9. +13
    -3
      examples/network/06_groups.html
  10. +8
    -0
      examples/network/15_dot_language_playground.html
  11. +9
    -0
      examples/network/18_fully_random_nodes_clustering.html
  12. +9
    -0
      examples/network/19_scale_free_graph_clustering.html
  13. +9
    -0
      examples/network/20_navigation.html
  14. +7
    -1
      examples/network/23_hierarchical_layout.html
  15. +8
    -0
      examples/network/24_hierarchical_layout_userdefined.html
  16. +8
    -0
      examples/network/31_localization.html
  17. +9
    -0
      examples/network/32_hierarchicaLayoutMethods.html
  18. +7
    -0
      examples/network/33_animation.html
  19. +3
    -2
      lib/graph3d/Graph3d.js
  20. +0
    -3
      lib/network/Groups.js
  21. +29
    -16
      lib/network/Images.js
  22. +125
    -77
      lib/network/Network.js
  23. +52
    -12
      lib/network/Node.js
  24. +3
    -0
      lib/network/mixins/MixinLoader.js
  25. +2
    -2
      lib/network/mixins/physics/BarnesHutMixin.js
  26. +13
    -0
      lib/network/mixins/physics/PhysicsMixin.js
  27. +2
    -2
      lib/network/mixins/physics/RepulsionMixin.js
  28. +3
    -1
      lib/timeline/Core.js
  29. +17
    -14
      lib/timeline/component/DataAxis.js
  30. +49
    -44
      lib/timeline/component/LineGraph.js
  31. +7
    -3
      lib/timeline/component/TimeAxis.js

+ 24
- 0
HISTORY.md View File

@ -8,16 +8,40 @@ http://visjs.org
- Fixed flipping of hierarchical network on update when using RL and DU. - Fixed flipping of hierarchical network on update when using RL and DU.
- Added zoomExtentOnStabilize option to network. - Added zoomExtentOnStabilize option to network.
- Improved destroy function, added them to the examples.
- Nodes now have bounding boxes that are used for zoomExtent.
- Made physics more stable (albeit a little slower).
- Added a check so only one 'activator' overlay is created on clickToUse.
- Made global color options for edges overrule the inheritColors.
- Improved cleaning up of the physics configuration on destroy and in options.
- Made nodes who lost their group revert back to default color.
- Changed group behaviour, groups now extend the options, not replace. This allows partial defines of color.
- Fixed bug where box shaped nodes did not use hover color.
- Fixed Locales docs.
- When hovering over a node that does not have a title, the title of one of the connected edges that HAS a title is no longer shown.
- Fixed error in repulsion physics model.
- Improved physics handling for smoother network simulation.
- Fixed infinite loop when an image can not be found and no brokenImage is provided.
- Added getBoundingBox method.
- Community fix for SVG images in IE11, thanks @dponch!
### Graph2d ### Graph2d
- Fixed round-off errors of zero on the y-axis. - Fixed round-off errors of zero on the y-axis.
- added show major/minor lines options to dataAxis. - added show major/minor lines options to dataAxis.
- Fixed adapting to width and height changes.
- Added a check so only one 'activator' overlay is created on clickToUse.
- DataAxis width option now draws correctly.
### Timeline ### Timeline
- Support for custom date formatting of the labels on the time axis. - Support for custom date formatting of the labels on the time axis.
- added show major/minor lines options to timeline. - added show major/minor lines options to timeline.
- Added a check so only one 'activator' overlay is created on clickToUse.
### Graph3d
- Fixed mouse coordinates for tooltips.
## 2014-12-09, version 3.7.2 ## 2014-12-09, version 3.7.2

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


+ 1
- 1
dist/vis.map
File diff suppressed because it is too large
View File


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


+ 0
- 12
docs/graph2d.html View File

@ -452,18 +452,6 @@ The options colored in green can also be used as options for the groups. All opt
<td>true</td> <td>true</td>
<td>Toggle the drawing of the major labels on the Y axis.</td> <td>Toggle the drawing of the major labels on the Y axis.</td>
</tr> </tr>
<tr>
<td>dataAxis.showMajorLines</td>
<td>Boolean</td>
<td>true</td>
<td>Toggle the drawing of the major lines on the Y axis.</td>
</tr>
<tr>
<td>dataAxis.showMinorLines</td>
<td>Boolean</td>
<td>true</td>
<td>Toggle the drawing of the major lines on the Y axis.</td>
</tr>
<tr> <tr>
<td>dataAxis.icons</td> <td>dataAxis.icons</td>
<td>Boolean</td> <td>Boolean</td>

+ 10
- 4
docs/network.html View File

@ -2017,15 +2017,15 @@ To load a locale into the Timeline not supported by default, one can add a new l
locales: { locales: {
// create a new locale (text strings should be replaced with localized strings) // create a new locale (text strings should be replaced with localized strings)
mylocale: { mylocale: {
add: 'Add Node',
edit: 'Edit', edit: 'Edit',
link: 'Add Link',
del: 'Delete selected', del: 'Delete selected',
back: 'Back',
addNode: 'Add Node',
addEdge: 'Add Edge',
editNode: 'Edit Node', editNode: 'Edit Node',
editEdge: 'Edit Edge', editEdge: 'Edit Edge',
back: 'Back',
addDescription: 'Click in an empty space to place a new node.', addDescription: 'Click in an empty space to place a new node.',
linkDescription: 'Click on a node and drag the edge to another node to connect them.',
edgeDescription: 'Click on a node and drag the edge to another node to connect them.',
editEdgeDescription: 'Click on the control points and drag them to a node to connect to it.', editEdgeDescription: 'Click on the control points and drag them to a node to connect to it.',
createEdgeError: 'Cannot link edges to a cluster.', createEdgeError: 'Cannot link edges to a cluster.',
deleteClusterError: 'Clusters cannot be deleted.' deleteClusterError: 'Clusters cannot be deleted.'
@ -2155,6 +2155,12 @@ var options = {
<td>Returns the x and y coodinates of the center of the screen (in canvas space). <td>Returns the x and y coodinates of the center of the screen (in canvas space).
</td> </td>
</tr> </tr>
<tr>
<td>getBoundingBox()</td>
<td>Object</td>
<td>Returns a bounding box for the node including label in the format: {top:Number,left:Number,right:Number,bottom:Number}. These values are in canvas space.
</td>
</tr>
<tr> <tr>
<td>getSelection()</td> <td>getSelection()</td>
<td>Array of ids</td> <td>Array of ids</td>

+ 0
- 18
docs/timeline.html View File

@ -742,24 +742,6 @@ var options = {
<code>showMinorLabels</code> are false, no horizontal axis will be <code>showMinorLabels</code> are false, no horizontal axis will be
visible.</td> visible.</td>
</tr> </tr>
<tr>
<td>showMajorLines</td>
<td>boolean</td>
<td>true</td>
<td>By default, the timeline shows both minor and major date lines on the
time axis. You can use this option to hide the lines from the major dates.
</tr>
<tr>
<td>showMinorLines</td>
<td>boolean</td>
<td>true</td>
<td>By default, the timeline shows both minor and major date lines on the
time axis. You can use this option to hide the lines from the minor dates.
</tr>
<tr> <tr>
<td>stack</td> <td>stack</td>
<td>Boolean</td> <td>Boolean</td>

+ 10
- 1
examples/network/02_random_nodes.html View File

@ -22,7 +22,16 @@
var edges = null; var edges = null;
var network = null; var network = null;
function destroy() {
if (network !== null) {
network.destroy();
network = null;
}
}
function draw() { function draw() {
destroy();
nodes = []; nodes = [];
edges = []; edges = [];
var connectionCount = []; var connectionCount = [];
@ -75,7 +84,7 @@
nodes: nodes, nodes: nodes,
edges: edges edges: edges
}; };
var options = {stabilization:false};
var options = {stabilize:false};
network = new vis.Network(container, data, options); network = new vis.Network(container, data, options);
// add event listeners // add event listeners

+ 13
- 3
examples/network/06_groups.html View File

@ -22,14 +22,24 @@
var nodes = null; var nodes = null;
var edges = null; var edges = null;
var network = null; var network = null;
var nodesData = null;
google.load('visualization', '1'); google.load('visualization', '1');
// Set callback to run when API is loaded // Set callback to run when API is loaded
google.setOnLoadCallback(draw); google.setOnLoadCallback(draw);
function destroy() {
if (network !== null) {
network.destroy();
network = null;
}
}
// Called when the Visualization API is loaded. // Called when the Visualization API is loaded.
function draw() { function draw() {
destroy();
var from, to; var from, to;
nodes = []; nodes = [];
@ -121,11 +131,11 @@
nodeOffset += nodeCount; nodeOffset += nodeCount;
group++; group++;
} }
nodesData = new vis.DataSet(nodes);
// create a network // create a network
var container = document.getElementById('mynetwork'); var container = document.getElementById('mynetwork');
var data = { var data = {
nodes: nodes,
nodes: nodesData,
edges: edges edges: edges
}; };
var options = { var options = {
@ -137,6 +147,7 @@
}; };
network = new vis.Network(container, data, options); network = new vis.Network(container, data, options);
} }
</script> </script>
</head> </head>
@ -149,7 +160,6 @@
<input type="submit" value="Go"> <input type="submit" value="Go">
</form> </form>
<br> <br>
<div id="mynetwork"></div> <div id="mynetwork"></div>
</body> </body>

+ 8
- 0
examples/network/15_dot_language_playground.html View File

@ -92,8 +92,16 @@
network.redraw() network.redraw()
}; };
function destroy() {
if (network !== null) {
network.destroy();
network = null;
}
}
// parse and draw the data // parse and draw the data
function draw () { function draw () {
destroy();
try { try {
txtError.innerHTML = ''; txtError.innerHTML = '';

+ 9
- 0
examples/network/18_fully_random_nodes_clustering.html View File

@ -22,7 +22,16 @@
var edges = null; var edges = null;
var network = null; var network = null;
function destroy() {
if (network !== null) {
network.destroy();
network = null;
}
}
function draw() { function draw() {
destroy();
nodes = []; nodes = [];
edges = []; edges = [];
// randomly create some nodes and edges // randomly create some nodes and edges

+ 9
- 0
examples/network/19_scale_free_graph_clustering.html View File

@ -22,7 +22,16 @@
var edges = null; var edges = null;
var network = null; var network = null;
function destroy() {
if (network !== null) {
network.destroy();
network = null;
}
}
function draw() { function draw() {
destroy();
nodes = []; nodes = [];
edges = []; edges = [];
var connectionCount = []; var connectionCount = [];

+ 9
- 0
examples/network/20_navigation.html View File

@ -41,7 +41,16 @@
var edges = null; var edges = null;
var network = null; var network = null;
function destroy() {
if (network !== null) {
network.destroy();
network = null;
}
}
function draw() { function draw() {
destroy();
nodes = []; nodes = [];
edges = []; edges = [];
var connectionCount = []; var connectionCount = [];

+ 7
- 1
examples/network/23_hierarchical_layout.html View File

@ -22,9 +22,15 @@
var edges = null; var edges = null;
var network = null; var network = null;
function destroy() {
if (network !== null) {
network.destroy();
network = null;
}
}
function draw() { function draw() {
destroy();
nodes = []; nodes = [];
edges = []; edges = [];
var connectionCount = []; var connectionCount = [];

+ 8
- 0
examples/network/24_hierarchical_layout_userdefined.html View File

@ -23,7 +23,15 @@
var network = null; var network = null;
var directionInput = document.getElementById("direction"); var directionInput = document.getElementById("direction");
function destroy() {
if (network !== null) {
network.destroy();
network = null;
}
}
function draw() { function draw() {
destroy();
nodes = []; nodes = [];
edges = []; edges = [];
var connectionCount = []; var connectionCount = [];

+ 8
- 0
examples/network/31_localization.html View File

@ -60,7 +60,15 @@
var edges = null; var edges = null;
var network = null; var network = null;
function destroy() {
if (network !== null) {
network.destroy();
network = null;
}
}
function draw() { function draw() {
destroy();
nodes = []; nodes = [];
edges = []; edges = [];
var connectionCount = []; var connectionCount = [];

+ 9
- 0
examples/network/32_hierarchicaLayoutMethods.html View File

@ -21,7 +21,16 @@
var network = null; var network = null;
var layoutMethod = "hubsize"; var layoutMethod = "hubsize";
function destroy() {
if (network !== null) {
network.destroy();
network = null;
}
}
function draw() { function draw() {
destroy();
var nodes = []; var nodes = [];
var edges = []; var edges = [];
// randomly create some nodes and edges // randomly create some nodes and edges

+ 7
- 0
examples/network/33_animation.html View File

@ -46,8 +46,15 @@
var statusUpdateSpan; var statusUpdateSpan;
var finishMessage = ""; var finishMessage = "";
function destroy() {
if (network !== null) {
network.destroy();
network = null;
}
}
function draw() { function draw() {
destroy();
statusUpdateSpan = document.getElementById("statusUpdate"); statusUpdateSpan = document.getElementById("statusUpdate");
doButton = document.getElementById("btnDo"); doButton = document.getElementById("btnDo");
focusButton = document.getElementById("btnFocus"); focusButton = document.getElementById("btnFocus");

+ 3
- 2
lib/graph3d/Graph3d.js View File

@ -1941,8 +1941,9 @@ Graph3d.prototype._onMouseUp = function (event) {
*/ */
Graph3d.prototype._onTooltip = function (event) { Graph3d.prototype._onTooltip = function (event) {
var delay = 300; // ms var delay = 300; // ms
var mouseX = getMouseX(event) - util.getAbsoluteLeft(this.frame);
var mouseY = getMouseY(event) - util.getAbsoluteTop(this.frame);
var boundingRect = this.frame.getBoundingClientRect();
var mouseX = getMouseX(event) - boundingRect.left;
var mouseY = getMouseY(event) - boundingRect.top;
if (!this.showTooltip) { if (!this.showTooltip) {
return; return;

+ 0
- 3
lib/network/Groups.js View File

@ -74,9 +74,6 @@ Groups.prototype.get = function (groupname) {
*/ */
Groups.prototype.add = function (groupname, style) { Groups.prototype.add = function (groupname, style) {
this.groups[groupname] = style; this.groups[groupname] = style;
if (style.color) {
style.color = util.parseColor(style.color);
}
return style; return style;
}; };

+ 29
- 16
lib/network/Images.js View File

@ -4,7 +4,6 @@
*/ */
function Images() { function Images() {
this.images = {}; this.images = {};
this.callback = undefined; this.callback = undefined;
} }
@ -24,25 +23,39 @@ Images.prototype.setOnloadCallback = function(callback) {
* @return {Image} img The image object * @return {Image} img The image object
*/ */
Images.prototype.load = function(url, brokenUrl) { Images.prototype.load = function(url, brokenUrl) {
var img = this.images[url];
if (img == undefined) {
if (this.images[url] == undefined) {
// create the image // create the image
var images = this;
img = new Image();
this.images[url] = img;
img.onload = function() {
if (images.callback) {
images.callback(this);
var me = this;
var img = new Image();
img.onload = function () {
// IE11 fix -- thanks dponch!
if (this.width == 0) {
document.body.appendChild(this);
this.width = this.offsetWidth;
this.height = this.offsetHeight;
document.body.removeChild(this);
}
if (me.callback) {
me.images[url] = img;
me.callback(this);
} }
}; };
img.onerror = function () { img.onerror = function () {
this.src = brokenUrl;
if (images.callback) {
images.callback(this);
}
};
if (brokenUrl === undefined) {
console.error("Could not load image:", url);
delete this.src;
if (me.callback) {
me.callback(this);
}
}
else {
this.src = brokenUrl;
}
};
img.src = url; img.src = url;
} }

+ 125
- 77
lib/network/Network.js View File

@ -35,6 +35,7 @@ function Network (container, data, options) {
throw new SyntaxError('Constructor must be called with the new operator'); throw new SyntaxError('Constructor must be called with the new operator');
} }
this._determineBrowserMethod();
this._initializeMixinLoaders(); this._initializeMixinLoaders();
// create variables and set default values // create variables and set default values
@ -43,8 +44,8 @@ function Network (container, data, options) {
// render and calculation settings // render and calculation settings
this.renderRefreshRate = 60; // hz (fps) this.renderRefreshRate = 60; // hz (fps)
this.renderTimestep = 1000 / this.renderRefreshRate; // ms -- saves calculation later on this.renderTimestep = 1000 / this.renderRefreshRate; // ms -- saves calculation later on
this.renderTime = 0.5 * this.renderTimestep; // measured time it takes to render a frame
this.maxPhysicsTicksPerRender = 3; // max amount of physics ticks per render step.
this.renderTime = 0; // measured time it takes to render a frame
this.physicsTime = 0; // measured time it takes to render a frame
this.physicsDiscreteStepsize = 0.50; // discrete stepsize of the simulation this.physicsDiscreteStepsize = 0.50; // discrete stepsize of the simulation
this.initializing = true; this.initializing = true;
@ -79,9 +80,6 @@ function Network (container, data, options) {
background: '#D2E5FF' background: '#D2E5FF'
} }
}, },
borderColor: '#2B7CE9',
backgroundColor: '#97C2FC',
highlightColor: '#D2E5FF',
group: undefined, group: undefined,
borderWidth: 1, borderWidth: 1,
borderWidthSelected: undefined borderWidthSelected: undefined
@ -114,7 +112,7 @@ function Network (container, data, options) {
physics: { physics: {
barnesHut: { barnesHut: {
enabled: true, enabled: true,
theta: 1 / 0.6, // inverted to save time during calculation
thetaInverted: 1 / 0.5, // inverted to save time during calculation
gravitationalConstant: -2000, gravitationalConstant: -2000,
centralGravity: 0.3, centralGravity: 0.3,
springLength: 95, springLength: 95,
@ -238,7 +236,7 @@ function Network (container, data, options) {
var network = this; var network = this;
this.groups = new Groups(); // object with groups this.groups = new Groups(); // object with groups
this.images = new Images(); // object with images this.images = new Images(); // object with images
this.images.setOnloadCallback(function () {
this.images.setOnloadCallback(function (status) {
network._redraw(); network._redraw();
}); });
@ -352,6 +350,25 @@ function Network (container, data, options) {
// Extend Network with an Emitter mixin // Extend Network with an Emitter mixin
Emitter(Network.prototype); Emitter(Network.prototype);
/**
* Determine if the browser requires a setTimeout or a requestAnimationFrame. This was required because
* some implementations (safari and IE9) did not support requestAnimationFrame
* @private
*/
Network.prototype._determineBrowserMethod = function() {
var browserType = navigator.userAgent.toLowerCase();
this.requiresTimeout = false;
if (browserType.indexOf('msie 9.0') != -1) { // IE 9
this.requiresTimeout = true;
}
else if (browserType.indexOf('safari') != -1) { // safari
if (browserType.indexOf('chrome') <= -1) {
this.requiresTimeout = true;
}
}
}
/** /**
* Get the script path where the vis.js library is located * Get the script path where the vis.js library is located
* *
@ -385,10 +402,10 @@ Network.prototype._getRange = function() {
for (var nodeId in this.nodes) { for (var nodeId in this.nodes) {
if (this.nodes.hasOwnProperty(nodeId)) { if (this.nodes.hasOwnProperty(nodeId)) {
node = this.nodes[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) { if (minX == 1e9 && maxX == -1e9 && minY == 1e9 && maxY == -1e9) {
@ -416,6 +433,8 @@ Network.prototype._findCenter = function(range) {
* @param {Boolean} [disableStart] | If true, start is not called. * @param {Boolean} [disableStart] | If true, start is not called.
*/ */
Network.prototype.zoomExtent = function(animationOptions, initialZoom, disableStart) { Network.prototype.zoomExtent = function(animationOptions, initialZoom, disableStart) {
this._redraw(true);
if (initialZoom === undefined) { if (initialZoom === undefined) {
initialZoom = false; initialZoom = false;
} }
@ -571,7 +590,6 @@ Network.prototype.setData = function(data, disableStart) {
Network.prototype.setOptions = function (options) { Network.prototype.setOptions = function (options) {
if (options) { if (options) {
var prop; var prop;
var fields = ['nodes','edges','smoothCurves','hierarchicalLayout','clustering','navigation', var fields = ['nodes','edges','smoothCurves','hierarchicalLayout','clustering','navigation',
'keyboard','dataManipulation','onAdd','onEdit','onEditEdge','onConnect','onDelete','clickToUse' 'keyboard','dataManipulation','onAdd','onEdit','onEditEdge','onConnect','onDelete','clickToUse'
]; ];
@ -629,6 +647,7 @@ Network.prototype.setOptions = function (options) {
if (options.edges.color.highlight !== undefined) {this.constants.edges.color.highlight = options.edges.color.highlight;} if (options.edges.color.highlight !== undefined) {this.constants.edges.color.highlight = options.edges.color.highlight;}
if (options.edges.color.hover !== undefined) {this.constants.edges.color.hover = options.edges.color.hover;} if (options.edges.color.hover !== undefined) {this.constants.edges.color.hover = options.edges.color.hover;}
} }
this.constants.edges.inheritColor = false;
} }
if (!options.edges.fontColor) { if (!options.edges.fontColor) {
@ -672,8 +691,10 @@ Network.prototype.setOptions = function (options) {
if ('clickToUse' in options) { if ('clickToUse' in options) {
if (options.clickToUse) { if (options.clickToUse) {
this.activator = new Activator(this.frame);
this.activator.on('change', this._createKeyBinds.bind(this));
if (!this.activator) {
this.activator = new Activator(this.frame);
this.activator.on('change', this._createKeyBinds.bind(this));
}
} }
else { else {
if (this.activator) { if (this.activator) {
@ -686,24 +707,25 @@ Network.prototype.setOptions = function (options) {
if (options.labels) { if (options.labels) {
throw new Error('Option "labels" is deprecated. Use options "locale" and "locales" instead.'); throw new Error('Option "labels" is deprecated. Use options "locale" and "locales" instead.');
} }
}
// (Re)loading the mixins that can be enabled or disabled in the options.
// load the force calculation functions, grouped under the physics system.
this._loadPhysicsSystem();
// load the navigation system.
this._loadNavigationControls();
// load the data manipulation system
this._loadManipulationSystem();
// configure the smooth curves
this._configureSmoothCurves();
// (Re)loading the mixins that can be enabled or disabled in the options.
// load the force calculation functions, grouped under the physics system.
this._loadPhysicsSystem();
// load the navigation system.
this._loadNavigationControls();
// load the data manipulation system
this._loadManipulationSystem();
// configure the smooth curves
this._configureSmoothCurves();
// bind keys. If disabled, this will not do anything;
this._createKeyBinds();
this.setSize(this.constants.width, this.constants.height);
this.moving = true;
this.start();
// bind keys. If disabled, this will not do anything;
this._createKeyBinds();
this.setSize(this.constants.width, this.constants.height);
this.moving = true;
this.start();
}
}; };
@ -730,11 +752,9 @@ Network.prototype._create = function () {
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
this.frame.canvas = document.createElement("canvas"); this.frame.canvas = document.createElement("canvas");
this.frame.canvas.style.position = 'relative'; this.frame.canvas.style.position = 'relative';
this.frame.appendChild(this.frame.canvas); this.frame.appendChild(this.frame.canvas);
if (!this.frame.canvas.getContext) { if (!this.frame.canvas.getContext) {
var noCanvas = document.createElement( 'DIV' ); var noCanvas = document.createElement( 'DIV' );
noCanvas.style.color = 'red'; noCanvas.style.color = 'red';
@ -744,17 +764,13 @@ Network.prototype._create = function () {
this.frame.canvas.appendChild(noCanvas); this.frame.canvas.appendChild(noCanvas);
} }
else { else {
var ctx = this.frame.canvas.getContext("2d"); var ctx = this.frame.canvas.getContext("2d");
this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio || ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio || ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio || ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio || 1); ctx.backingStorePixelRatio || 1);
this.frame.canvas.getContext("2d").setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); this.frame.canvas.getContext("2d").setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
} }
@ -782,7 +798,7 @@ Network.prototype._create = function () {
this.hammerFrame = Hammer(this.frame, { this.hammerFrame = Hammer(this.frame, {
prevent_default: true prevent_default: true
}); });
this.hammerFrame.on('release', me._onRelease.bind(me) );
this.hammerFrame.on('release', me._onRelease.bind(me) );
// add the frame to the container element // add the frame to the container element
this.containerElement.appendChild(this.frame); this.containerElement.appendChild(this.frame);
@ -836,8 +852,20 @@ Network.prototype._createKeyBinds = function() {
} }
}; };
/**
* Cleans up all bindings of the network, removing it fully from the memory IF the variable is set to null after calling this function.
* var network = new vis.Network(..);
* network.destroy();
* network = null;
*/
Network.prototype.destroy = function() { Network.prototype.destroy = function() {
this.start = function () {};
this.redraw = function () {};
this.timer = false;
// cleanup physicsConfiguration if it exists
this._cleanupPhysicsConfiguration();
// remove keybindings // remove keybindings
this.keycharm.reset(); this.keycharm.reset();
@ -847,7 +875,15 @@ Network.prototype.destroy = function() {
// clear events // clear events
this.off(); this.off();
// remove all elements from the container element.
while (this.frame.hasChildNodes()) {
this.frame.removeChild(this.frame.firstChild);
}
// remove all elements from the container element.
while (this.containerElement.hasChildNodes()) {
this.containerElement.removeChild(this.containerElement.firstChild);
}
} }
@ -1285,6 +1321,7 @@ Network.prototype._checkShowPopup = function (pointer) {
var id; var id;
var lastPopupNode = this.popupObj; var lastPopupNode = this.popupObj;
var nodeUnderCursor = false;
if (this.popupObj == undefined) { if (this.popupObj == undefined) {
// search the nodes for overlap, select the top one in case of multiple nodes // search the nodes for overlap, select the top one in case of multiple nodes
@ -1292,15 +1329,19 @@ Network.prototype._checkShowPopup = function (pointer) {
for (id in nodes) { for (id in nodes) {
if (nodes.hasOwnProperty(id)) { if (nodes.hasOwnProperty(id)) {
var node = nodes[id]; var node = nodes[id];
if (node.getTitle() !== undefined && node.isOverlappingWith(obj)) {
this.popupObj = node;
break;
if (node.isOverlappingWith(obj)) {
if (node.getTitle() !== undefined) {
this.popupObj = node;
break;
}
// if you hover over a node, the title of the edge is not supposed to be shown.
nodeUnderCursor = true;
} }
} }
} }
} }
if (this.popupObj === undefined) {
if (this.popupObj === undefined && nodeUnderCursor == false) {
// search the edges for overlap // search the edges for overlap
var edges = this.edges; var edges = this.edges;
for (id in edges) { for (id in edges) {
@ -1741,9 +1782,10 @@ Network.prototype.redraw = function() {
/** /**
* Redraw the network with the current data * 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 * @private
*/ */
Network.prototype._redraw = function() {
Network.prototype._redraw = function(hidden) {
var ctx = this.frame.canvas.getContext('2d'); var ctx = this.frame.canvas.getContext('2d');
ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
@ -1767,18 +1809,21 @@ Network.prototype._redraw = function() {
"y": this._YconvertDOMtoCanvas(this.frame.canvas.clientHeight * this.pixelRatio) "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) { if (this.drag.dragging == false || this.drag.dragging === undefined || this.constants.hideNodesOnDrag == false) {
this._doInAllSectors("_drawNodes",ctx,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); // this._doInSupportSector("_drawNodes",ctx,true);
@ -1786,6 +1831,10 @@ Network.prototype._redraw = function() {
// restore original scaling and translation // restore original scaling and translation
ctx.restore(); ctx.restore();
if (hidden == true) {
ctx.clearRect(0, 0, w, h);
}
}; };
/** /**
@ -2116,6 +2165,7 @@ Network.prototype._physicsTick = function() {
if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) { if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) {
supportMovingStatus = this._doInSupportSector("_discreteStepNodes"); supportMovingStatus = this._doInSupportSector("_discreteStepNodes");
} }
// gather movement data from all sectors, if one moves, we are NOT stabilzied // gather movement data from all sectors, if one moves, we are NOT stabilzied
for (var i = 0; i < mainMoving.length; i++) {mainMovingStatus = mainMoving[0] || mainMovingStatus;} for (var i = 0; i < mainMoving.length; i++) {mainMovingStatus = mainMoving[0] || mainMovingStatus;}
@ -2137,26 +2187,26 @@ Network.prototype._physicsTick = function() {
Network.prototype._animationStep = function() { Network.prototype._animationStep = function() {
// reset the timer so a new scheduled animation step can be set // reset the timer so a new scheduled animation step can be set
this.timer = undefined; this.timer = undefined;
// handle the keyboad movement // handle the keyboad movement
this._handleNavigation(); this._handleNavigation();
// this schedules a new animation step
this.start();
// start the physics simulation
var calculationTime = Date.now();
var maxSteps = 1;
var startTime = Date.now();
this._physicsTick(); this._physicsTick();
var timeRequired = Date.now() - calculationTime;
while (timeRequired < 0.9*(this.renderTimestep - this.renderTime) && maxSteps < this.maxPhysicsTicksPerRender) {
// run double speed if it is a little graph
if (this.renderTimestep - this.renderTime > 2*this.physicsTime) {
this._physicsTick(); this._physicsTick();
timeRequired = Date.now() - calculationTime;
maxSteps++;
} }
// start the rendering process
var renderTime = Date.now();
this.physicsTime = Date.now() - startTime;
var renderStartTime = Date.now();
this._redraw(); this._redraw();
this.renderTime = Date.now() - renderTime;
this.renderTime = Date.now() - renderStartTime;
// this schedules a new animation step
this.start();
}; };
if (typeof window !== 'undefined') { if (typeof window !== 'undefined') {
@ -2175,23 +2225,11 @@ Network.prototype.start = function() {
} }
if (!this.timer) { if (!this.timer) {
var ua = navigator.userAgent.toLowerCase();
var requiresTimeout = false;
if (ua.indexOf('msie 9.0') != -1) { // IE 9
requiresTimeout = true;
}
else if (ua.indexOf('safari') != -1) { // safari
if (ua.indexOf('chrome') <= -1) {
requiresTimeout = true;
}
}
if (requiresTimeout == true) {
if (this.requiresTimeout == true) {
this.timer = window.setTimeout(this._animationStep.bind(this), this.renderTimestep); // wait this.renderTimeStep milliseconds and perform the animation step function this.timer = window.setTimeout(this._animationStep.bind(this), this.renderTimestep); // wait this.renderTimeStep milliseconds and perform the animation step function
} }
else{
this.timer = window.requestAnimationFrame(this._animationStep.bind(this), this.renderTimestep); // wait this.renderTimeStep milliseconds and perform the animation step function
else {
this.timer = window.requestAnimationFrame(this._animationStep.bind(this)); // wait this.renderTimeStep milliseconds and perform the animation step function
} }
} }
} }
@ -2509,7 +2547,10 @@ Network.prototype.animateView = function (options) {
} }
}; };
/**
* used to animate smoothly by hijacking the redraw function.
* @private
*/
Network.prototype._lockedRedraw = function () { Network.prototype._lockedRedraw = function () {
var nodePosition = {x: this.nodes[this.lockedOnNodeId].x, y: this.nodes[this.lockedOnNodeId].y}; var nodePosition = {x: this.nodes[this.lockedOnNodeId].x, y: this.nodes[this.lockedOnNodeId].y};
var viewCenter = this.DOMtoCanvas({x: 0.5 * this.frame.canvas.clientWidth, y: 0.5 * this.frame.canvas.clientHeight}); var viewCenter = this.DOMtoCanvas({x: 0.5 * this.frame.canvas.clientWidth, y: 0.5 * this.frame.canvas.clientHeight});
@ -2607,4 +2648,11 @@ Network.prototype.getCenterCoordinates = function () {
return this.DOMtoCanvas({x: 0.5 * this.frame.canvas.clientWidth, y: 0.5 * this.frame.canvas.clientHeight}); return this.DOMtoCanvas({x: 0.5 * this.frame.canvas.clientWidth, y: 0.5 * this.frame.canvas.clientHeight});
}; };
Network.prototype.getBoundingBox = function(nodeId) {
if (this.nodes[nodeId] !== undefined) {
return this.nodes[nodeId].boundingBox;
}
}
module.exports = Network; module.exports = Network;

+ 52
- 12
lib/network/Node.js View File

@ -53,8 +53,8 @@ function Node(properties, imagelist, grouplist, networkConstants) {
this.level = -1; this.level = -1;
this.preassignedLevel = false; this.preassignedLevel = false;
this.hierarchyEnumerated = 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.imagelist = imagelist;
this.grouplist = grouplist; this.grouplist = grouplist;
@ -166,13 +166,13 @@ Node.prototype.setProperties = function(properties, constants) {
// copy group properties // copy group properties
if (typeof this.options.group === 'number' || (typeof this.options.group === 'string' && this.options.group != '')) { if (typeof this.options.group === 'number' || (typeof this.options.group === 'string' && this.options.group != '')) {
var groupObj = this.grouplist.get(this.options.group); var groupObj = this.grouplist.get(this.options.group);
for (var prop in groupObj) {
if (groupObj.hasOwnProperty(prop)) {
this.options[prop] = groupObj[prop];
}
}
util.deepExtend(this.options, groupObj);
// the color object needs to be completely defined. Since groups can partially overwrite the colors, we parse it again, just in case.
this.options.color = util.parseColor(this.options.color);
}
else if (properties.color === undefined) {
this.options.color = constants.nodes.color;
} }
// individual shape properties // individual shape properties
if (properties.radius !== undefined) {this.baseRadiusValue = this.options.radius;} if (properties.radius !== undefined) {this.baseRadiusValue = this.options.radius;}
@ -211,8 +211,6 @@ Node.prototype.setProperties = function(properties, constants) {
this.options.radiusMax = constants.nodes.widthMax; this.options.radiusMax = constants.nodes.widthMax;
} }
// choose draw method depending on the shape // choose draw method depending on the shape
switch (this.options.shape) { switch (this.options.shape) {
case 'database': this.draw = this._drawDatabase; this.resize = this._resizeDatabase; break; case 'database': this.draw = this._drawDatabase; this.resize = this._resizeDatabase; break;
@ -539,7 +537,6 @@ Node.prototype._resizeImage = function (ctx) {
Node.prototype._drawImage = function (ctx) { Node.prototype._drawImage = function (ctx) {
this._resizeImage(ctx); this._resizeImage(ctx);
this.left = this.x - this.width / 2; this.left = this.x - this.width / 2;
this.top = this.y - this.height / 2; this.top = this.y - this.height / 2;
@ -565,7 +562,16 @@ Node.prototype._drawImage = function (ctx) {
yLabel = this.y; yLabel = 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;
this._label(ctx, this.label, this.x, yLabel, undefined, "top"); this._label(ctx, this.label, this.x, yLabel, undefined, "top");
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);
}; };
@ -609,12 +615,17 @@ Node.prototype._drawBox = function (ctx) {
ctx.lineWidth *= this.networkScaleInv; ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width,ctx.lineWidth); ctx.lineWidth = Math.min(this.width,ctx.lineWidth);
ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.options.color.background;
ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background;
ctx.roundRect(this.left, this.top, this.width, this.height, this.options.radius); ctx.roundRect(this.left, this.top, this.width, this.height, this.options.radius);
ctx.fill(); ctx.fill();
ctx.stroke(); 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); this._label(ctx, this.label, this.x, this.y);
}; };
@ -664,6 +675,11 @@ Node.prototype._drawDatabase = function (ctx) {
ctx.fill(); ctx.fill();
ctx.stroke(); 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); this._label(ctx, this.label, this.x, this.y);
}; };
@ -715,6 +731,11 @@ Node.prototype._drawCircle = function (ctx) {
ctx.fill(); ctx.fill();
ctx.stroke(); 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); this._label(ctx, this.label, this.x, this.y);
}; };
@ -766,6 +787,12 @@ Node.prototype._drawEllipse = function (ctx) {
ctx.ellipse(this.left, this.top, this.width, this.height); ctx.ellipse(this.left, this.top, this.width, this.height);
ctx.fill(); ctx.fill();
ctx.stroke(); 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); this._label(ctx, this.label, this.x, this.y);
}; };
@ -843,8 +870,16 @@ Node.prototype._drawShape = function (ctx, shape) {
ctx.fill(); ctx.fill();
ctx.stroke(); 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) { if (this.label) {
this._label(ctx, this.label, this.x, this.y + this.height / 2, undefined, 'top',true); 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 +904,11 @@ Node.prototype._drawText = function (ctx) {
this.top = this.y - this.height / 2; this.top = this.y - this.height / 2;
this._label(ctx, this.label, this.x, this.y); 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;
}; };

+ 3
- 0
lib/network/mixins/MixinLoader.js View File

@ -47,6 +47,9 @@ exports._loadPhysicsSystem = function () {
if (this.constants.configurePhysics == true) { if (this.constants.configurePhysics == true) {
this._loadPhysicsConfiguration(); this._loadPhysicsConfiguration();
} }
else {
this._cleanupPhysicsConfiguration();
}
}; };

+ 2
- 2
lib/network/mixins/physics/BarnesHutMixin.js View File

@ -49,9 +49,9 @@ exports._getForceContribution = function(parentBranch,node) {
distance = Math.sqrt(dx * dx + dy * dy); distance = Math.sqrt(dx * dx + dy * dy);
// BarnesHut condition // 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 // 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 // duplicate code to reduce function calls to speed up program
if (distance == 0) { if (distance == 0) {
distance = 0.1*Math.random(); distance = 0.1*Math.random();

+ 13
- 0
lib/network/mixins/physics/PhysicsMixin.js View File

@ -305,6 +305,17 @@ exports._calculateSpringForce = function (node1, node2, edgeLength) {
}; };
exports._cleanupPhysicsConfiguration = function() {
if (this.physicsConfiguration !== undefined) {
while (this.physicsConfiguration.hasChildNodes()) {
this.physicsConfiguration.removeChild(this.physicsConfiguration.firstChild);
}
this.physicsConfiguration.parentNode.removeChild(this.physicsConfiguration);
this.physicsConfiguration = undefined;
}
}
/** /**
* Load the HTML for the physics config and bind it * Load the HTML for the physics config and bind it
* @private * @private
@ -706,3 +717,5 @@ function showValueOfRange (id,map,constantsVariableName) {
this.moving = true; this.moving = true;
this.start(); this.start();
} }

+ 2
- 2
lib/network/mixins/physics/RepulsionMixin.js View File

@ -40,10 +40,9 @@ exports._calculateNodeForces = function () {
else { else {
repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness)) repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness))
} }
// amplify the repulsion for clusters. // amplify the repulsion for clusters.
repulsingForce *= (combinedClusterSize == 0) ? 1 : 1 + combinedClusterSize * this.constants.clustering.forceAmplification; repulsingForce *= (combinedClusterSize == 0) ? 1 : 1 + combinedClusterSize * this.constants.clustering.forceAmplification;
repulsingForce = repulsingForce / distance;
repulsingForce = repulsingForce / Math.max(distance,0.01*minimumDistance);
fx = dx * repulsingForce; fx = dx * repulsingForce;
fy = dy * repulsingForce; fy = dy * repulsingForce;
@ -52,6 +51,7 @@ exports._calculateNodeForces = function () {
node1.fy -= fy; node1.fy -= fy;
node2.fx += fx; node2.fx += fx;
node2.fy += fy; node2.fy += fy;
} }
} }
} }

+ 3
- 1
lib/timeline/Core.js View File

@ -197,7 +197,9 @@ Core.prototype.setOptions = function (options) {
if ('clickToUse' in options) { if ('clickToUse' in options) {
if (options.clickToUse) { if (options.clickToUse) {
this.activator = new Activator(this.dom.root);
if (!this.activator) {
this.activator = new Activator(this.dom.root);
}
} }
else { else {
if (this.activator) { if (this.activator) {

+ 17
- 14
lib/timeline/component/DataAxis.js View File

@ -19,8 +19,6 @@ function DataAxis (body, options, svg, linegraphOptions) {
orientation: 'left', // supported: 'left', 'right' orientation: 'left', // supported: 'left', 'right'
showMinorLabels: true, showMinorLabels: true,
showMajorLabels: true, showMajorLabels: true,
showMinorLines: true,
showMajorLines: true,
icons: true, icons: true,
majorLinesOffset: 7, majorLinesOffset: 7,
minorLinesOffset: 4, minorLinesOffset: 4,
@ -120,8 +118,6 @@ DataAxis.prototype.setOptions = function (options) {
'orientation', 'orientation',
'showMinorLabels', 'showMinorLabels',
'showMajorLabels', 'showMajorLabels',
'showMajorLines',
'showMinorLines',
'icons', 'icons',
'majorLinesOffset', 'majorLinesOffset',
'minorLinesOffset', 'minorLinesOffset',
@ -261,7 +257,7 @@ DataAxis.prototype.setRange = function (start, end) {
* @return {boolean} Returns true if the component is resized * @return {boolean} Returns true if the component is resized
*/ */
DataAxis.prototype.redraw = function () { DataAxis.prototype.redraw = function () {
var changeCalled = false;
var resized = false;
var activeGroups = 0; var activeGroups = 0;
// Make sure the line container adheres to the vertical scrolling. // Make sure the line container adheres to the vertical scrolling.
@ -314,6 +310,8 @@ DataAxis.prototype.redraw = function () {
frame.style.bottom = ''; frame.style.bottom = '';
frame.style.width = this.width + 'px'; frame.style.width = this.width + 'px';
frame.style.height = this.height + "px"; frame.style.height = this.height + "px";
this.props.width = this.body.domProps.left.width;
this.props.height = this.body.domProps.left.height;
} }
else { // right else { // right
frame.style.top = ''; frame.style.top = '';
@ -321,8 +319,12 @@ DataAxis.prototype.redraw = function () {
frame.style.left = '0'; frame.style.left = '0';
frame.style.width = this.width + 'px'; frame.style.width = this.width + 'px';
frame.style.height = this.height + "px"; frame.style.height = this.height + "px";
this.props.width = this.body.domProps.right.width;
this.props.height = this.body.domProps.right.height;
} }
changeCalled = this._redrawLabels();
resized = this._redrawLabels();
resized = this._isResized() || resized;
if (this.options.icons == true) { if (this.options.icons == true) {
this._redrawGroupIcons(); this._redrawGroupIcons();
@ -333,7 +335,7 @@ DataAxis.prototype.redraw = function () {
this._redrawTitle(orientation); this._redrawTitle(orientation);
} }
return changeCalled;
return resized;
}; };
/** /**
@ -341,6 +343,7 @@ DataAxis.prototype.redraw = function () {
* @private * @private
*/ */
DataAxis.prototype._redrawLabels = function () { DataAxis.prototype._redrawLabels = function () {
var resized = false;
DOMutil.prepareElements(this.DOMelements.lines); DOMutil.prepareElements(this.DOMelements.lines);
DOMutil.prepareElements(this.DOMelements.labels); DOMutil.prepareElements(this.DOMelements.labels);
@ -421,11 +424,9 @@ DataAxis.prototype._redrawLabels = function () {
if (y >= 0) { if (y >= 0) {
this._redrawLabel(y - 2, step.getCurrent(decimals), orientation, 'yAxis major', this.props.majorCharHeight); this._redrawLabel(y - 2, step.getCurrent(decimals), orientation, 'yAxis major', this.props.majorCharHeight);
} }
if (this.options.showMajorLines == true) {
this._redrawLine(y, orientation, 'grid horizontal major', this.options.majorLinesOffset, this.props.majorLineWidth);
}
this._redrawLine(y, orientation, 'grid horizontal major', this.options.majorLinesOffset, this.props.majorLineWidth);
} }
else if (this.options.showMinorLines == true) {
else {
this._redrawLine(y, orientation, 'grid horizontal minor', this.options.minorLinesOffset, this.props.minorLineWidth); this._redrawLine(y, orientation, 'grid horizontal minor', this.options.minorLinesOffset, this.props.minorLineWidth);
} }
@ -457,7 +458,7 @@ DataAxis.prototype._redrawLabels = function () {
DOMutil.cleanupElements(this.DOMelements.lines); DOMutil.cleanupElements(this.DOMelements.lines);
DOMutil.cleanupElements(this.DOMelements.labels); DOMutil.cleanupElements(this.DOMelements.labels);
this.redraw(); this.redraw();
return true;
resized = true;
} }
// this will resize the yAxis if it is too big for the labels. // this will resize the yAxis if it is too big for the labels.
else if (this.maxLabelSize < (this.width - offset) && this.options.visible == true && this.width > this.minWidth) { else if (this.maxLabelSize < (this.width - offset) && this.options.visible == true && this.width > this.minWidth) {
@ -466,13 +467,15 @@ DataAxis.prototype._redrawLabels = function () {
DOMutil.cleanupElements(this.DOMelements.lines); DOMutil.cleanupElements(this.DOMelements.lines);
DOMutil.cleanupElements(this.DOMelements.labels); DOMutil.cleanupElements(this.DOMelements.labels);
this.redraw(); this.redraw();
return true;
resized = true;
} }
else { else {
DOMutil.cleanupElements(this.DOMelements.lines); DOMutil.cleanupElements(this.DOMelements.lines);
DOMutil.cleanupElements(this.DOMelements.labels); DOMutil.cleanupElements(this.DOMelements.labels);
return false;
resized = false;
} }
return resized;
}; };
DataAxis.prototype.convertValue = function (value) { DataAxis.prototype.convertValue = function (value) {

+ 49
- 44
lib/timeline/component/LineGraph.js View File

@ -50,8 +50,6 @@ function LineGraph(body, options) {
dataAxis: { dataAxis: {
showMinorLabels: true, showMinorLabels: true,
showMajorLabels: true, showMajorLabels: true,
showMinorLines: true,
showMajorLines: true,
icons: false, icons: false,
width: '40px', width: '40px',
visible: true, visible: true,
@ -100,7 +98,7 @@ function LineGraph(body, options) {
this.hammer = null; this.hammer = null;
this.groups = {}; this.groups = {};
this.abortedGraphUpdate = false; this.abortedGraphUpdate = false;
this.autoSizeSVG = false;
this.updateSVGheight = false;
var me = this; var me = this;
this.itemsData = null; // DataSet this.itemsData = null; // DataSet
@ -143,7 +141,7 @@ function LineGraph(body, options) {
this.COUNTER = 0; this.COUNTER = 0;
this.body.emitter.on('rangechanged', function() { this.body.emitter.on('rangechanged', function() {
me.lastStart = me.body.range.start; me.lastStart = me.body.range.start;
me.svg.style.left = util.option.asSize(-me.width);
me.svg.style.left = util.option.asSize(-me.props.width);
me.redraw.call(me,true); me.redraw.call(me,true);
}); });
@ -192,13 +190,13 @@ LineGraph.prototype._create = function(){
*/ */
LineGraph.prototype.setOptions = function(options) { LineGraph.prototype.setOptions = function(options) {
if (options) { if (options) {
var fields = ['sampling','defaultGroup','graphHeight','yAxisOrientation','style','barChart','dataAxis','sort','groups'];
var fields = ['sampling','defaultGroup','height','graphHeight','yAxisOrientation','style','barChart','dataAxis','sort','groups'];
if (options.graphHeight === undefined && options.height !== undefined && this.body.domProps.centerContainer.height !== undefined) { if (options.graphHeight === undefined && options.height !== undefined && this.body.domProps.centerContainer.height !== undefined) {
this.autoSizeSVG = true;
this.updateSVGheight = true;
} }
else if (this.body.domProps.centerContainer.height !== undefined && options.graphHeight !== undefined) { else if (this.body.domProps.centerContainer.height !== undefined && options.graphHeight !== undefined) {
if (parseInt((options.graphHeight + '').replace("px",'')) < this.body.domProps.centerContainer.height) { if (parseInt((options.graphHeight + '').replace("px",'')) < this.body.domProps.centerContainer.height) {
this.autoSizeSVG = true;
this.updateSVGheight = true;
} }
} }
util.selectiveDeepExtend(fields, this.options, options); util.selectiveDeepExtend(fields, this.options, options);
@ -543,49 +541,67 @@ LineGraph.prototype._updateUngrouped = function() {
LineGraph.prototype.redraw = function(forceGraphUpdate) { LineGraph.prototype.redraw = function(forceGraphUpdate) {
var resized = false; var resized = false;
this.svg.style.height = ('' + this.options.graphHeight).replace('px','') + 'px';
if (this.lastWidth === undefined && this.width || this.lastWidth != this.width) {
resized = true;
// calculate actual size and position
this.props.width = this.dom.frame.offsetWidth;
this.props.height = this.body.domProps.centerContainer.height;
// update the graph if there is no lastWidth or with, used for the initial draw
if (this.lastWidth === undefined && this.props.width) {
forceGraphUpdate = true;
} }
// check if this component is resized // check if this component is resized
resized = this._isResized() || resized; resized = this._isResized() || resized;
// 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); // we get this from the range changed event
var zoomed = (visibleInterval != this.lastVisibleInterval);
this.lastVisibleInterval = visibleInterval; this.lastVisibleInterval = visibleInterval;
this.lastWidth = this.width;
// calculate actual size and position
this.width = this.dom.frame.offsetWidth;
// the svg element is three times as big as the width, this allows for fully dragging left and right // the svg element is three times as big as the width, this allows for fully dragging left and right
// without reloading the graph. the controls for this are bound to events in the constructor // without reloading the graph. the controls for this are bound to events in the constructor
if (resized == true) { if (resized == true) {
this.svg.style.width = util.option.asSize(3*this.width);
this.svg.style.left = util.option.asSize(-this.width);
this.svg.style.width = util.option.asSize(3*this.props.width);
this.svg.style.left = util.option.asSize(-this.props.width);
// if the height of the graph is set as proportional, change the height of the svg
if ((this.options.height + '').indexOf("%") != -1) {
this.updateSVGheight = true;
}
}
// update the height of the graph on each redraw of the graph.
if (this.updateSVGheight == true) {
if (this.options.graphHeight != this.body.domProps.centerContainer.height + 'px') {
this.options.graphHeight = this.body.domProps.centerContainer.height + 'px';
this.svg.style.height = this.body.domProps.centerContainer.height + 'px';
}
this.updateSVGheight = false;
}
else {
this.svg.style.height = ('' + this.options.graphHeight).replace('px','') + 'px';
} }
// zoomed is here to ensure that animations are shown correctly. // zoomed is here to ensure that animations are shown correctly.
if (zoomed == true || this.abortedGraphUpdate == true || forceGraphUpdate == true) {
resized = resized || this._updateGraph();
if (resized == true || zoomed == true || this.abortedGraphUpdate == true || forceGraphUpdate == true) {
resized = this._updateGraph() || resized;
} }
else { else {
// move the whole svg while dragging // move the whole svg while dragging
if (this.lastStart != 0) { if (this.lastStart != 0) {
var offset = this.body.range.start - this.lastStart; var offset = this.body.range.start - this.lastStart;
var range = this.body.range.end - this.body.range.start; var range = this.body.range.end - this.body.range.start;
if (this.width != 0) {
var rangePerPixelInv = this.width/range;
if (this.props.width != 0) {
var rangePerPixelInv = this.props.width/range;
var xOffset = offset * rangePerPixelInv; var xOffset = offset * rangePerPixelInv;
this.svg.style.left = (-this.width - xOffset) + 'px';
this.svg.style.left = (-this.props.width - xOffset) + 'px';
} }
} }
} }
this.legendLeft.redraw(); this.legendLeft.redraw();
this.legendRight.redraw(); this.legendRight.redraw();
return resized; return resized;
}; };
@ -597,22 +613,13 @@ LineGraph.prototype.redraw = function(forceGraphUpdate) {
LineGraph.prototype._updateGraph = function () { LineGraph.prototype._updateGraph = function () {
// reset the svg elements // reset the svg elements
DOMutil.prepareElements(this.svgElements); DOMutil.prepareElements(this.svgElements);
if (this.width != 0 && this.itemsData != null) {
if (this.props.width != 0 && this.itemsData != null) {
var group, i; var group, i;
var preprocessedGroupData = {}; var preprocessedGroupData = {};
var processedGroupData = {}; var processedGroupData = {};
var groupRanges = {}; var groupRanges = {};
var changeCalled = false; var changeCalled = false;
// update the height of the graph on each redraw of the graph.
if (this.autoSizeSVG == true) {
if (this.options.graphHeight != this.body.domProps.centerContainer.height + 'px') {
this.options.graphHeight = this.body.domProps.centerContainer.height + 'px';
this.svg.style.height = this.body.domProps.centerContainer.height + 'px';
}
this.autoSizeSVG = false;
}
// getting group Ids // getting group Ids
var groupIds = []; var groupIds = [];
for (var groupId in this.groups) { for (var groupId in this.groups) {
@ -815,7 +822,7 @@ LineGraph.prototype._getYRanges = function (groupIds, groupsData, groupRanges) {
* @private * @private
*/ */
LineGraph.prototype._updateYAxis = function (groupIds, groupRanges) { LineGraph.prototype._updateYAxis = function (groupIds, groupRanges) {
var changeCalled = false;
var resized = false;
var yAxisLeftUsed = false; var yAxisLeftUsed = false;
var yAxisRightUsed = false; var yAxisRightUsed = false;
var minLeft = 1e9, minRight = 1e9, maxLeft = -1e9, maxRight = -1e9, minVal, maxVal; var minLeft = 1e9, minRight = 1e9, maxLeft = -1e9, maxRight = -1e9, minVal, maxVal;
@ -864,9 +871,8 @@ LineGraph.prototype._updateYAxis = function (groupIds, groupRanges) {
this.yAxisRight.setRange(minRight, maxRight); this.yAxisRight.setRange(minRight, maxRight);
} }
} }
changeCalled = this._toggleAxisVisiblity(yAxisLeftUsed , this.yAxisLeft) || changeCalled;
changeCalled = this._toggleAxisVisiblity(yAxisRightUsed, this.yAxisRight) || changeCalled;
resized = this._toggleAxisVisiblity(yAxisLeftUsed , this.yAxisLeft) || resized;
resized = this._toggleAxisVisiblity(yAxisRightUsed, this.yAxisRight) || resized;
if (yAxisRightUsed == true && yAxisLeftUsed == true) { if (yAxisRightUsed == true && yAxisLeftUsed == true) {
this.yAxisLeft.drawIcons = true; this.yAxisLeft.drawIcons = true;
this.yAxisRight.drawIcons = true; this.yAxisRight.drawIcons = true;
@ -875,20 +881,19 @@ LineGraph.prototype._updateYAxis = function (groupIds, groupRanges) {
this.yAxisLeft.drawIcons = false; this.yAxisLeft.drawIcons = false;
this.yAxisRight.drawIcons = false; this.yAxisRight.drawIcons = false;
} }
this.yAxisRight.master = !yAxisLeftUsed; this.yAxisRight.master = !yAxisLeftUsed;
if (this.yAxisRight.master == false) { if (this.yAxisRight.master == false) {
if (yAxisRightUsed == true) {this.yAxisLeft.lineOffset = this.yAxisRight.width;} if (yAxisRightUsed == true) {this.yAxisLeft.lineOffset = this.yAxisRight.width;}
else {this.yAxisLeft.lineOffset = 0;} else {this.yAxisLeft.lineOffset = 0;}
changeCalled = this.yAxisLeft.redraw() || changeCalled;
resized = this.yAxisLeft.redraw() || resized;
this.yAxisRight.stepPixelsForced = this.yAxisLeft.stepPixels; this.yAxisRight.stepPixelsForced = this.yAxisLeft.stepPixels;
this.yAxisRight.zeroCrossing = this.yAxisLeft.zeroCrossing; this.yAxisRight.zeroCrossing = this.yAxisLeft.zeroCrossing;
changeCalled = this.yAxisRight.redraw() || changeCalled;
resized = this.yAxisRight.redraw() || resized;
} }
else { else {
changeCalled = this.yAxisRight.redraw() || changeCalled;
resized = this.yAxisRight.redraw() || resized;
} }
// clean the accumulated lists // clean the accumulated lists
@ -899,7 +904,7 @@ LineGraph.prototype._updateYAxis = function (groupIds, groupRanges) {
groupIds.splice(groupIds.indexOf('__barchartRight'),1); groupIds.splice(groupIds.indexOf('__barchartRight'),1);
} }
return changeCalled;
return resized;
}; };
@ -944,7 +949,7 @@ LineGraph.prototype._convertXcoordinates = function (datapoints) {
var toScreen = this.body.util.toScreen; var toScreen = this.body.util.toScreen;
for (var i = 0; i < datapoints.length; i++) { for (var i = 0; i < datapoints.length; i++) {
xValue = toScreen(datapoints[i].x) + this.width;
xValue = toScreen(datapoints[i].x) + this.props.width;
yValue = datapoints[i].y; yValue = datapoints[i].y;
extractedData.push({x: xValue, y: yValue}); extractedData.push({x: xValue, y: yValue});
} }
@ -974,7 +979,7 @@ LineGraph.prototype._convertYcoordinates = function (datapoints, group) {
} }
for (var i = 0; i < datapoints.length; i++) { for (var i = 0; i < datapoints.length; i++) {
xValue = toScreen(datapoints[i].x) + this.width;
xValue = toScreen(datapoints[i].x) + this.props.width;
yValue = Math.round(axis.convertValue(datapoints[i].y)); yValue = Math.round(axis.convertValue(datapoints[i].y));
extractedData.push({x: xValue, y: yValue}); extractedData.push({x: xValue, y: yValue});
} }

+ 7
- 3
lib/timeline/component/TimeAxis.js View File

@ -38,8 +38,6 @@ function TimeAxis (body, options) {
// TODO: implement timeaxis orientations 'left' and 'right' // TODO: implement timeaxis orientations 'left' and 'right'
showMinorLabels: true, showMinorLabels: true,
showMajorLabels: true, showMajorLabels: true,
showMajorLines: true,
showMinorLines: true,
format: null format: null
}; };
this.options = util.extend({}, this.defaultOptions); this.options = util.extend({}, this.defaultOptions);
@ -65,7 +63,13 @@ TimeAxis.prototype = new Component();
TimeAxis.prototype.setOptions = function(options) { TimeAxis.prototype.setOptions = function(options) {
if (options) { if (options) {
// copy all options that we know // copy all options that we know
util.selectiveExtend(['orientation', 'showMinorLabels', 'showMajorLabels', 'showMinorLines', 'showMajorLines','hiddenDates', 'format'], this.options, options);
util.selectiveExtend([
'orientation',
'showMinorLabels',
'showMajorLabels',
'hiddenDates',
'format'
], this.options, options);
// apply locale to moment.js // apply locale to moment.js
// TODO: not so nice, this is applied globally to moment.js // TODO: not so nice, this is applied globally to moment.js

Loading…
Cancel
Save