Browse Source

Merge branch 'develop' into es6

flowchartTest
jos 10 years ago
parent
commit
cfe3de2457
19 changed files with 993 additions and 589 deletions
  1. +15
    -0
      HISTORY.md
  2. +383
    -284
      dist/vis.js
  3. +1
    -1
      dist/vis.map
  4. +15
    -15
      dist/vis.min.js
  5. +38
    -0
      docs/network.html
  6. +4
    -2
      docs/timeline.html
  7. +2
    -1
      examples/network/15_dot_language_playground.html
  8. +7
    -2
      examples/network/32_hierarchicaLayoutMethods.html
  9. +63
    -0
      examples/network/35_label_stroke.html
  10. +80
    -0
      examples/network/36_HTML_in_Nodes.html
  11. +2
    -0
      examples/network/index.html
  12. +275
    -209
      lib/network/Edge.js
  13. +48
    -29
      lib/network/Network.js
  14. +9
    -4
      lib/network/Node.js
  15. +11
    -23
      lib/network/mixins/HierarchicalLayoutMixin.js
  16. +18
    -8
      lib/network/mixins/ManipulationMixin.js
  17. +7
    -1
      lib/network/mixins/physics/RepulsionMixin.js
  18. +1
    -2
      lib/timeline/Core.js
  19. +14
    -8
      lib/timeline/Range.js

+ 15
- 0
HISTORY.md View File

@ -8,6 +8,21 @@ http://visjs.org
- reverted change in image class, fixed bug #552
- improved (not neccesarily fixed) the fontFill offset between different browsers. #365
- Fixed dashed lines on firefox on Unix systems
- Altered the Manipulation Mixin to be succesfully destroyed from memory when calling destroy();
- Improved drawing of arrowheads on smooth curves. #349
- Caught case where click originated on external DOM element and drag progressed to vis.
- Added label stroke support to Nodes, Edges & Groups as per-object or global settings. Thank you @klmdb!
- Reverted patch that made nodes return to 'default' setting if no group was assigned to fix issue #561. The correct way to 'remove' a group from a node is to assign it a different one.
- Made the node/edge selected by the popup system the same as selected by the click-to-select system. Thank you @pavlos256!
- Improved edit edge control nodes positions, altered style a little.
- Fixed issue #564 by resetting state to initial when no callback is performed in the return function.
- Added condition to Repulsion similar to BarnesHut to ensure nodes do not overlap.
### Timeline
- Added byUser flag to options of the rangechange and rangechanged event.
## 20145-01-09, version 3.8.0

+ 383
- 284
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


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


+ 38
- 0
docs/network.html View File

@ -932,6 +932,18 @@ All options defined per-node override these global settings.
<td>undefined</td>
<td>If a color is supplied, there will be a background color behind the label. If left undefined, no background color is shown.</td>
</tr>
<tr>
<td class="greenField">fontStrokeWidth</td>
<td>Number</td>
<td>0</td>
<td>The width of the label stroke (border around label's text) in pixels.</td>
</tr>
<tr>
<td class="greenField">fontStrokeColor</td>
<td>String</td>
<td>'white'</td>
<td>The color of the label stroke.</td>
</tr>
<tr>
<td class="greenField">shape</td>
@ -1156,6 +1168,20 @@ var options = {
<td>Font fill for the background color of the text label of the edge.
Only applicable when property <code>label</code> is defined.</td>
</tr>
<tr>
<td class="greenField">fontStrokeWidth</td>
<td>Number</td>
<td>0</td>
<td>The width of the label stroke (border around label's text) in pixels.
Only applicable when property <code>label</code> is defined.</td>
</tr>
<tr>
<td class="greenField">fontStrokeColor</td>
<td>String</td>
<td>'white'</td>
<td>The color of the label stroke.
Only applicable when property <code>label</code> is defined.</td>
</tr>
<tr>
<td class="greenField">style</td>
@ -1316,6 +1342,18 @@ var nodes = [
<td>14</td>
<td>Font size for the node in pixels.</td>
</tr>
<tr>
<td>fontStrokeWidth</td>
<td>Number</td>
<td>0</td>
<td>The width of the label stroke (border around label's text) in pixels.</td>
</tr>
<tr>
<td>fontStrokeColor</td>
<td>String</td>
<td>"white"</td>
<td>The color of the label stroke.</td>
</tr>
<tr>
<td>shape</td>
<td>String</td>

+ 4
- 2
docs/timeline.html View File

@ -1053,24 +1053,26 @@ timeline.off('select', onSelect);
<tr>
<td>rangechange</td>
<td>Fired repeatedly when the user is dragging the timeline window.
<td>Fired repeatedly when the timeline window is being changed.
</td>
<td>
<ul>
<li><code>start</code> (Number): timestamp of the current start of the window.</li>
<li><code>end</code> (Number): timestamp of the current end of the window.</li>
<li><code>byUser</code> (Boolean): change happened because of user drag/zoom.</li>
</ul>
</td>
</tr>
<tr>
<td>rangechanged</td>
<td>Fired once after the user has dragged the timeline window.
<td>Fired once after the timeline window has been changed.
</td>
<td>
<ul>
<li><code>start</code> (Number): timestamp of the current start of the window.</li>
<li><code>end</code> (Number): timestamp of the current end of the window.</li>
<li><code>byUser</code> (Boolean): change happened because of user drag/zoom.</li>
</ul>
</td>
</tr>

+ 2
- 1
examples/network/15_dot_language_playground.html View File

@ -80,7 +80,8 @@
</table>
<script type="text/javascript">
var network, data;
var network = null;
var data = null;
var btnDraw = document.getElementById('draw');
var txtData = document.getElementById('data');

+ 7
- 2
examples/network/32_hierarchicaLayoutMethods.html View File

@ -19,7 +19,7 @@
<script type="text/javascript">
var network = null;
var layoutMethod = "hubsize";
var layoutMethod = "direction";
function destroy() {
if (network !== null) {
@ -83,6 +83,10 @@
from: 2,
to: 8
});
edges.push({
from: 10,
to: 2
});
edges.push({
from: 2,
to: 9
@ -130,8 +134,9 @@
</div>
Layout method:
<select id="layout">
<option value="hubsize">hubsize</option>
<option value="direction">direction</option>
<option value="hubsize">hubsize</option>
</select><br/>
<br />

+ 63
- 0
examples/network/35_label_stroke.html View File

@ -0,0 +1,63 @@
<!doctype html>
<html>
<head>
<title>Network | Label stroke</title>
<script type="text/javascript" src="../../dist/vis.js"></script>
<link href="../../dist/vis.css" rel="stylesheet" type="text/css" />
<style type="text/css">
#mynetwork {
width: 400px;
height: 400px;
border: 1px solid lightgray;
background: #d1d1d1;
}
</style>
</head>
<body>
<div id="mynetwork"></div>
<script type="text/javascript">
// create an array with nodes
var nodes = [
{id: 1, label: 'Node 1', fontStrokeWidth : 5, fontStrokeColor: 'white'},
{id: 2, label: 'Node 2'},
{id: 3, label: 'Node 3'},
{id: 4, label: 'Node 4'},
{id: 5, label: 'Node 5'}
];
// create an array with edges
var edges = [
{from: 1, to: 2, label: 'edgeLabel', fontStrokeWidth : 2, fontStrokeColor : '#00ff00'},
{from: 1, to: 3, label: 'edgeLabel'},
{from: 2, to: 4},
{from: 2, to: 5}
];
// create a network
var container = document.getElementById('mynetwork');
var data = {
nodes: nodes,
edges: edges
};
var options = {
nodes : {
shape : 'dot',
fontStrokeWidth : 1,
fontStrokeColor : '#d1d1d1'
},
edges : {
fontStrokeWidth : 1,
fontStrokeColor : '#d1d1d1',
fontFill : 'none'
}
};
var network = new vis.Network(container, data, options);
</script>
</body>
</html>

+ 80
- 0
examples/network/36_HTML_in_Nodes.html View File

@ -0,0 +1,80 @@
<!doctype html>
<html>
<head>
<title>Network | Images</title>
<style type="text/css">
body {
font: 10pt arial;
}
#mynetwork {
width: 600px;
height: 600px;
border: 1px solid lightgray;
background-color:#eeeeee;
}
</style>
<script type="text/javascript" src="../../dist/vis.js"></script>
<link href="../../dist/vis.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
var nodes = null;
var edges = null;
var network = null;
var DIR = 'img/refresh-cl/';
var LENGTH_MAIN = 150;
var LENGTH_SUB = 50;
var data = '<svg xmlns="http://www.w3.org/2000/svg" width="243" height="65">' +
'<rect x="0" y="0" width="100%" height="100%" fill="#7890A7" stroke-width="20" stroke="#ffffff" ></rect>' +
'<foreignObject x="15" y="10" width="100%" height="100%">' +
'<div xmlns="http://www.w3.org/1999/xhtml" style="font-size:40px">' +
'<em>I</em> like' +
'<span style="color:white; text-shadow:0 0 20px #000000;">' +
'cheese</span>' +
'</div>' +
'</foreignObject>' +
'</svg>';
var DOMURL = window.URL || window.webkitURL || window;
var img = new Image();
var svg = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
var url = DOMURL.createObjectURL(svg);
// Called when the Visualization API is loaded.
function draw() {
// Create a data table with nodes.
nodes = [];
// Create a data table with links.
edges = [];
nodes.push({id: 1, label: 'Get HTML', image: url, shape: 'image'});
nodes.push({id: 2, label: 'Using SVG', image: url, shape: 'image'});
edges.push({from: 1, to: 2, length: 300});
// create a network
var container = document.getElementById('mynetwork');
var data = {
nodes: nodes,
edges: edges
};
var options = {
stabilize: false,
smoothCurves:false
};
network = new vis.Network(container, data, options);
}
</script>
</head>
<body onload="draw()">
<div id="mynetwork"></div>
</body>
</html>

+ 2
- 0
examples/network/index.html View File

@ -46,6 +46,8 @@
<p><a href="32_hierarchicaLayoutMethods.html">32_hierarchicaLayoutMethods.html</a></p>
<p><a href="33_animation.html">33_animation.html</a></p>
<p><a href="34_circular_images.html">34_circular_images.html</a></p>
<p><a href="35_label_stroke.html">35_label_stroke.html</a></p>
<p><a href="36_HTML_in_Nodes.html">36_HTML_in_Nodes.html</a></p>
<p><a href="graphviz/graphviz_gallery.html">graphviz_gallery.html</a></p>
</div>

+ 275
- 209
lib/network/Edge.js View File

@ -75,7 +75,7 @@ Edge.prototype.setProperties = function(properties) {
return;
}
var fields = ['style','fontSize','fontFace','fontColor','fontFill','width',
var fields = ['style','fontSize','fontFace','fontColor','fontFill','fontStrokeWidth','fontStrokeColor','width',
'widthSelectionMultiplier','hoverWidth','arrowScaleFactor','dash','inheritColor'
];
util.selectiveDeepExtend(fields, this.options, properties);
@ -322,168 +322,176 @@ Edge.prototype._getLineWidth = function() {
};
Edge.prototype._getViaCoordinates = function () {
var xVia = null;
var yVia = null;
var factor = this.options.smoothCurves.roundness;
var type = this.options.smoothCurves.type;
var dx = Math.abs(this.from.x - this.to.x);
var dy = Math.abs(this.from.y - this.to.y);
if (type == 'discrete' || type == 'diagonalCross') {
if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) {
if (this.from.y > this.to.y) {
if (this.from.x < this.to.x) {
xVia = this.from.x + factor * dy;
yVia = this.from.y - factor * dy;
if (this.options.smoothCurves.dynamic == true && this.options.smoothCurves.enabled == true ) {
return this.via;
}
else if (this.options.smoothCurves.enabled == false) {
return {x:0,y:0};
}
else {
var xVia = null;
var yVia = null;
var factor = this.options.smoothCurves.roundness;
var type = this.options.smoothCurves.type;
var dx = Math.abs(this.from.x - this.to.x);
var dy = Math.abs(this.from.y - this.to.y);
if (type == 'discrete' || type == 'diagonalCross') {
if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) {
if (this.from.y > this.to.y) {
if (this.from.x < this.to.x) {
xVia = this.from.x + factor * dy;
yVia = this.from.y - factor * dy;
}
else if (this.from.x > this.to.x) {
xVia = this.from.x - factor * dy;
yVia = this.from.y - factor * dy;
}
}
else if (this.from.x > this.to.x) {
xVia = this.from.x - factor * dy;
yVia = this.from.y - factor * dy;
else if (this.from.y < this.to.y) {
if (this.from.x < this.to.x) {
xVia = this.from.x + factor * dy;
yVia = this.from.y + factor * dy;
}
else if (this.from.x > this.to.x) {
xVia = this.from.x - factor * dy;
yVia = this.from.y + factor * dy;
}
}
if (type == "discrete") {
xVia = dx < factor * dy ? this.from.x : xVia;
}
}
else if (this.from.y < this.to.y) {
if (this.from.x < this.to.x) {
xVia = this.from.x + factor * dy;
yVia = this.from.y + factor * dy;
else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) {
if (this.from.y > this.to.y) {
if (this.from.x < this.to.x) {
xVia = this.from.x + factor * dx;
yVia = this.from.y - factor * dx;
}
else if (this.from.x > this.to.x) {
xVia = this.from.x - factor * dx;
yVia = this.from.y - factor * dx;
}
}
else if (this.from.x > this.to.x) {
xVia = this.from.x - factor * dy;
yVia = this.from.y + factor * dy;
else if (this.from.y < this.to.y) {
if (this.from.x < this.to.x) {
xVia = this.from.x + factor * dx;
yVia = this.from.y + factor * dx;
}
else if (this.from.x > this.to.x) {
xVia = this.from.x - factor * dx;
yVia = this.from.y + factor * dx;
}
}
if (type == "discrete") {
yVia = dy < factor * dx ? this.from.y : yVia;
}
}
if (type == "discrete") {
xVia = dx < factor * dy ? this.from.x : xVia;
}
}
else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) {
if (this.from.y > this.to.y) {
if (this.from.x < this.to.x) {
xVia = this.from.x + factor * dx;
yVia = this.from.y - factor * dx;
else if (type == "straightCross") {
if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { // up - down
xVia = this.from.x;
if (this.from.y < this.to.y) {
yVia = this.to.y - (1 - factor) * dy;
}
else if (this.from.x > this.to.x) {
xVia = this.from.x - factor * dx;
yVia = this.from.y - factor * dx;
else {
yVia = this.to.y + (1 - factor) * dy;
}
}
else if (this.from.y < this.to.y) {
else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { // left - right
if (this.from.x < this.to.x) {
xVia = this.from.x + factor * dx;
yVia = this.from.y + factor * dx;
xVia = this.to.x - (1 - factor) * dx;
}
else if (this.from.x > this.to.x) {
xVia = this.from.x - factor * dx;
yVia = this.from.y + factor * dx;
else {
xVia = this.to.x + (1 - factor) * dx;
}
}
if (type == "discrete") {
yVia = dy < factor * dx ? this.from.y : yVia;
yVia = this.from.y;
}
}
}
else if (type == "straightCross") {
if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) { // up - down
xVia = this.from.x;
if (this.from.y < this.to.y) {
yVia = this.to.y - (1-factor) * dy;
else if (type == 'horizontal') {
if (this.from.x < this.to.x) {
xVia = this.to.x - (1 - factor) * dx;
}
else {
yVia = this.to.y + (1-factor) * dy;
xVia = this.to.x + (1 - factor) * dx;
}
yVia = this.from.y;
}
else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) { // left - right
if (this.from.x < this.to.x) {
xVia = this.to.x - (1-factor) * dx;
else if (type == 'vertical') {
xVia = this.from.x;
if (this.from.y < this.to.y) {
yVia = this.to.y - (1 - factor) * dy;
}
else {
xVia = this.to.x + (1-factor) * dx;
yVia = this.to.y + (1 - factor) * dy;
}
yVia = this.from.y;
}
}
else if (type == 'horizontal') {
if (this.from.x < this.to.x) {
xVia = this.to.x - (1-factor) * dx;
}
else {
xVia = this.to.x + (1-factor) * dx;
}
yVia = this.from.y;
}
else if (type == 'vertical') {
xVia = this.from.x;
if (this.from.y < this.to.y) {
yVia = this.to.y - (1-factor) * dy;
}
else {
yVia = this.to.y + (1-factor) * dy;
}
}
else { // continuous
if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) {
if (this.from.y > this.to.y) {
if (this.from.x < this.to.x) {
else { // continuous
if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) {
if (this.from.y > this.to.y) {
if (this.from.x < this.to.x) {
// console.log(1)
xVia = this.from.x + factor * dy;
yVia = this.from.y - factor * dy;
xVia = this.to.x < xVia ? this.to.x : xVia;
}
else if (this.from.x > this.to.x) {
xVia = this.from.x + factor * dy;
yVia = this.from.y - factor * dy;
xVia = this.to.x < xVia ? this.to.x : xVia;
}
else if (this.from.x > this.to.x) {
// console.log(2)
xVia = this.from.x - factor * dy;
yVia = this.from.y - factor * dy;
xVia = this.to.x > xVia ? this.to.x :xVia;
xVia = this.from.x - factor * dy;
yVia = this.from.y - factor * dy;
xVia = this.to.x > xVia ? this.to.x : xVia;
}
}
}
else if (this.from.y < this.to.y) {
if (this.from.x < this.to.x) {
else if (this.from.y < this.to.y) {
if (this.from.x < this.to.x) {
// console.log(3)
xVia = this.from.x + factor * dy;
yVia = this.from.y + factor * dy;
xVia = this.to.x < xVia ? this.to.x : xVia;
}
else if (this.from.x > this.to.x) {
xVia = this.from.x + factor * dy;
yVia = this.from.y + factor * dy;
xVia = this.to.x < xVia ? this.to.x : xVia;
}
else if (this.from.x > this.to.x) {
// console.log(4, this.from.x, this.to.x)
xVia = this.from.x - factor * dy;
yVia = this.from.y + factor * dy;
xVia = this.to.x > xVia ? this.to.x : xVia;
xVia = this.from.x - factor * dy;
yVia = this.from.y + factor * dy;
xVia = this.to.x > xVia ? this.to.x : xVia;
}
}
}
}
else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) {
if (this.from.y > this.to.y) {
if (this.from.x < this.to.x) {
else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) {
if (this.from.y > this.to.y) {
if (this.from.x < this.to.x) {
// console.log(5)
xVia = this.from.x + factor * dx;
yVia = this.from.y - factor * dx;
yVia = this.to.y > yVia ? this.to.y : yVia;
}
else if (this.from.x > this.to.x) {
xVia = this.from.x + factor * dx;
yVia = this.from.y - factor * dx;
yVia = this.to.y > yVia ? this.to.y : yVia;
}
else if (this.from.x > this.to.x) {
// console.log(6)
xVia = this.from.x - factor * dx;
yVia = this.from.y - factor * dx;
yVia = this.to.y > yVia ? this.to.y : yVia;
xVia = this.from.x - factor * dx;
yVia = this.from.y - factor * dx;
yVia = this.to.y > yVia ? this.to.y : yVia;
}
}
}
else if (this.from.y < this.to.y) {
if (this.from.x < this.to.x) {
else if (this.from.y < this.to.y) {
if (this.from.x < this.to.x) {
// console.log(7)
xVia = this.from.x + factor * dx;
yVia = this.from.y + factor * dx;
yVia = this.to.y < yVia ? this.to.y : yVia;
}
else if (this.from.x > this.to.x) {
xVia = this.from.x + factor * dx;
yVia = this.from.y + factor * dx;
yVia = this.to.y < yVia ? this.to.y : yVia;
}
else if (this.from.x > this.to.x) {
// console.log(8)
xVia = this.from.x - factor * dx;
yVia = this.from.y + factor * dx;
yVia = this.to.y < yVia ? this.to.y : yVia;
xVia = this.from.x - factor * dx;
yVia = this.from.y + factor * dx;
yVia = this.to.y < yVia ? this.to.y : yVia;
}
}
}
}
}
return {x:xVia, y:yVia};
return {x: xVia, y: yVia};
}
};
/**
@ -585,8 +593,16 @@ Edge.prototype._label = function (ctx, text, x, y) {
ctx.fillStyle = this.options.fontColor || "black";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
if (this.options.fontStrokeWidth > 0){
ctx.lineWidth = this.options.fontStrokeWidth;
ctx.strokeStyle = this.options.fontStrokeColor;
ctx.lineJoin = 'round';
}
yLine = this.labelDimensions.yLine;
for (var i = 0; i < lineCount; i++) {
if(this.options.fontStrokeWidth){
ctx.strokeText(lines[i], x, yLine);
}
ctx.fillText(lines[i], x, yLine);
yLine += fontSize;
}
@ -772,7 +788,69 @@ Edge.prototype._drawArrowCenter = function(ctx) {
}
};
Edge.prototype._pointOnBezier = function(t) {
var via = this._getViaCoordinates();
var x = Math.pow(1-t,2)*this.from.x + (2*t*(1 - t))*via.x + Math.pow(t,2)*this.to.x;
var y = Math.pow(1-t,2)*this.from.y + (2*t*(1 - t))*via.y + Math.pow(t,2)*this.to.y;
return {x:x,y:y};
}
/**
* This function uses binary search to look for the point where the bezier curve crosses the border of the node.
*
* @param from
* @param ctx
* @returns {*}
* @private
*/
Edge.prototype._findBorderPosition = function(from,ctx) {
var maxIterations = 10;
var iteration = 0;
var low = 0;
var high = 1;
var pos,angle,distanceToBorder, distanceToNodes, difference;
var threshold = 0.2;
var node = this.to;
if (from == true) {
node = this.from;
}
while (low <= high && iteration < maxIterations) {
var middle = (low + high) * 0.5;
pos = this._pointOnBezier(middle);
angle = Math.atan2((node.y - pos.y), (node.x - pos.x));
distanceToBorder = node.distanceToBorder(ctx,angle);
distanceToNodes = Math.sqrt(Math.pow(pos.x-node.x,2) + Math.pow(pos.y-node.y,2));
difference = distanceToBorder - distanceToNodes;
if (Math.abs(difference) < threshold) {
break; // found
}
else if (difference < 0) { // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node.
if (from == false) {
low = middle;
}
else {
high = middle;
}
}
else {
if (from == false) {
high = middle;
}
else {
low = middle;
}
}
iteration++;
}
pos.t = middle;
return pos;
};
/**
* Redraw a edge as a line with an arrow
@ -787,59 +865,37 @@ Edge.prototype._drawArrow = function(ctx) {
ctx.fillStyle = ctx.strokeStyle;
ctx.lineWidth = this._getLineWidth();
var angle, length;
//draw a line
if (this.from != this.to) {
angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x));
var dx = (this.to.x - this.from.x);
var dy = (this.to.y - this.from.y);
var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
var fromBorderDist = this.from.distanceToBorder(ctx, angle + Math.PI);
var fromBorderPoint = (edgeSegmentLength - fromBorderDist) / edgeSegmentLength;
var xFrom = (fromBorderPoint) * this.from.x + (1 - fromBorderPoint) * this.to.x;
var yFrom = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y;
var via;
if (this.options.smoothCurves.dynamic == true && this.options.smoothCurves.enabled == true ) {
via = this.via;
}
else if (this.options.smoothCurves.enabled == true) {
via = this._getViaCoordinates();
}
// set vars
var angle, length, arrowPos;
if (this.options.smoothCurves.enabled == true && via.x != null) {
angle = Math.atan2((this.to.y - via.y), (this.to.x - via.x));
dx = (this.to.x - via.x);
dy = (this.to.y - via.y);
edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
}
var toBorderDist = this.to.distanceToBorder(ctx, angle);
var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength;
var xTo,yTo;
if (this.options.smoothCurves.enabled == true && via.x != null) {
xTo = (1 - toBorderPoint) * via.x + toBorderPoint * this.to.x;
yTo = (1 - toBorderPoint) * via.y + toBorderPoint * this.to.y;
}
else {
xTo = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x;
yTo = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y;
}
// if not connected to itself
if (this.from != this.to) {
// draw line
this._line(ctx);
ctx.beginPath();
ctx.moveTo(xFrom,yFrom);
if (this.options.smoothCurves.enabled == true && via.x != null) {
ctx.quadraticCurveTo(via.x,via.y,xTo, yTo);
// draw arrow head
if (this.options.smoothCurves.enabled == true) {
var via = this._getViaCoordinates();
arrowPos = this._findBorderPosition(false, ctx);
var guidePos = this._pointOnBezier(Math.max(0.0, arrowPos.t - 0.1))
angle = Math.atan2((arrowPos.y - guidePos.y), (arrowPos.x - guidePos.x));
}
else {
ctx.lineTo(xTo, yTo);
angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x));
var dx = (this.to.x - this.from.x);
var dy = (this.to.y - this.from.y);
var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
var toBorderDist = this.to.distanceToBorder(ctx, angle);
var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength;
arrowPos = {};
arrowPos.x = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x;
arrowPos.y = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y;
}
ctx.stroke();
// draw arrow at the end of the line
length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor;
ctx.arrow(xTo, yTo, angle, length);
ctx.arrow(arrowPos.x,arrowPos.y, angle, length);
ctx.fill();
ctx.stroke();
@ -847,9 +903,7 @@ Edge.prototype._drawArrow = function(ctx) {
if (this.label) {
var point;
if (this.options.smoothCurves.enabled == true && via != null) {
var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x));
var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y));
point = {x:midpointX, y:midpointY};
point = this._pointOnBezier(0.5);
}
else {
point = this._pointOnLine(0.5);
@ -902,8 +956,6 @@ Edge.prototype._drawArrow = function(ctx) {
}
};
/**
* Calculate the distance between a point (x3,y3) and a line segment from
* (x1,y1) to (x2,y2).
@ -1044,26 +1096,30 @@ Edge.prototype._drawControlNodes = function(ctx) {
var nodeIdFrom = "edgeIdFrom:".concat(this.id);
var nodeIdTo = "edgeIdTo:".concat(this.id);
var constants = {
nodes:{group:'', radius:8},
nodes:{group:'', radius:7, borderWidth:2, borderWidthSelected: 2},
physics:{damping:0},
clustering: {maxNodeSizeIncrements: 0 ,nodeScaling: {width:0, height: 0, radius:0}}
};
this.controlNodes.from = new Node(
{id:nodeIdFrom,
shape:'dot',
color:{background:'#ff4e00', border:'#3c3c3c', highlight: {background:'#07f968'}}
color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}}
},{},{},constants);
this.controlNodes.to = new Node(
{id:nodeIdTo,
shape:'dot',
color:{background:'#ff4e00', border:'#3c3c3c', highlight: {background:'#07f968'}}
color:{background:'#ff0000', border:'#3c3c3c', highlight: {background:'#07f968'}}
},{},{},constants);
}
if (this.controlNodes.from.selected == false && this.controlNodes.to.selected == false) {
this.controlNodes.positions = this.getControlNodePositions(ctx);
this.controlNodes.positions = {};
if (this.controlNodes.from.selected == false) {
this.controlNodes.positions.from = this.getControlNodeFromPosition(ctx);
this.controlNodes.from.x = this.controlNodes.positions.from.x;
this.controlNodes.from.y = this.controlNodes.positions.from.y;
}
if (this.controlNodes.to.selected == false) {
this.controlNodes.positions.to = this.getControlNodeToPosition(ctx);
this.controlNodes.to.x = this.controlNodes.positions.to.x;
this.controlNodes.to.y = this.controlNodes.positions.to.y;
}
@ -1155,46 +1211,56 @@ Edge.prototype._restoreControlNodes = function() {
* this calculates the position of the control nodes on the edges of the parent nodes.
*
* @param ctx
* @returns {{from: {x: number, y: number}, to: {x: *, y: *}}}
* @returns {x: *, y: *}
*/
Edge.prototype.getControlNodePositions = function(ctx) {
var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x));
var dx = (this.to.x - this.from.x);
var dy = (this.to.y - this.from.y);
var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
var fromBorderDist = this.from.distanceToBorder(ctx, angle + Math.PI);
var fromBorderPoint = (edgeSegmentLength - fromBorderDist) / edgeSegmentLength;
var xFrom = (fromBorderPoint) * this.from.x + (1 - fromBorderPoint) * this.to.x;
var yFrom = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y;
var via;
if (this.options.smoothCurves.dynamic == true && this.options.smoothCurves.enabled == true) {
via = this.via;
}
else if (this.options.smoothCurves.enabled == true) {
via = this._getViaCoordinates();
Edge.prototype.getControlNodeFromPosition = function(ctx) {
// draw arrow head
var controlnodeFromPos;
if (this.options.smoothCurves.enabled == true) {
controlnodeFromPos = this._findBorderPosition(true, ctx);
}
else {
var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x));
var dx = (this.to.x - this.from.x);
var dy = (this.to.y - this.from.y);
var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
if (this.options.smoothCurves.enabled == true && via.x != null) {
angle = Math.atan2((this.to.y - via.y), (this.to.x - via.x));
dx = (this.to.x - via.x);
dy = (this.to.y - via.y);
edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
var fromBorderDist = this.from.distanceToBorder(ctx, angle + Math.PI);
var fromBorderPoint = (edgeSegmentLength - fromBorderDist) / edgeSegmentLength;
controlnodeFromPos = {};
controlnodeFromPos.x = (fromBorderPoint) * this.from.x + (1 - fromBorderPoint) * this.to.x;
controlnodeFromPos.y = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y;
}
var toBorderDist = this.to.distanceToBorder(ctx, angle);
var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength;
var xTo,yTo;
if (this.options.smoothCurves.enabled == true && via.x != null) {
xTo = (1 - toBorderPoint) * via.x + toBorderPoint * this.to.x;
yTo = (1 - toBorderPoint) * via.y + toBorderPoint * this.to.y;
return controlnodeFromPos;
};
/**
* this calculates the position of the control nodes on the edges of the parent nodes.
*
* @param ctx
* @returns {{from: {x: number, y: number}, to: {x: *, y: *}}}
*/
Edge.prototype.getControlNodeToPosition = function(ctx) {
// draw arrow head
var controlnodeFromPos,controlnodeToPos;
if (this.options.smoothCurves.enabled == true) {
controlnodeToPos = this._findBorderPosition(false, ctx);
}
else {
xTo = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x;
yTo = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y;
var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x));
var dx = (this.to.x - this.from.x);
var dy = (this.to.y - this.from.y);
var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
var toBorderDist = this.to.distanceToBorder(ctx, angle);
var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength;
controlnodeToPos = {};
controlnodeToPos.x = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x;
controlnodeToPos.y = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y;
}
return {from:{x:xFrom,y:yFrom},to:{x:xTo,y:yTo}};
return controlnodeToPos;
};
module.exports = Edge;

+ 48
- 29
lib/network/Network.js View File

@ -68,6 +68,8 @@ function Network (container, data, options) {
fontSize: 14, // px
fontFace: 'verdana',
fontFill: undefined,
fontStrokeWidth: 0, // px
fontStrokeColor: 'white',
level: -1,
color: {
border: '#2B7CE9',
@ -101,6 +103,8 @@ function Network (container, data, options) {
fontSize: 14, // px
fontFace: 'arial',
fontFill: 'white',
fontStrokeWidth: 0, // px
fontStrokeColor: 'white',
arrowScaleFactor: 1,
dash: {
length: 10,
@ -177,7 +181,7 @@ function Network (container, data, options) {
levelSeparation: 150,
nodeSpacing: 100,
direction: "UD", // UD, DU, LR, RL
layout: "hubsize" // hubsize, directed
layout: "hubsize" // hubsize, directed, uniqueDirected
},
freezeForStabilization: false,
smoothCurves: {
@ -876,18 +880,16 @@ Network.prototype.destroy = function() {
// clear events
this.off();
// remove all elements from the container element.
while (this.frame.hasChildNodes()) {
this.frame.removeChild(this.frame.firstChild);
}
this._recursiveDOMDelete(this.containerElement);
}
// remove all elements from the container element.
while (this.containerElement.hasChildNodes()) {
this.containerElement.removeChild(this.containerElement.firstChild);
Network.prototype._recursiveDOMDelete = function(DOMobject) {
while (DOMobject.hasChildNodes() == true) {
this._recursiveDOMDelete(DOMobject.firstChild);
DOMobject.removeChild(DOMobject.firstChild);
}
}
/**
* Get the pointer location from a touch location
* @param {{pageX: Number, pageY: Number}} touch
@ -923,8 +925,8 @@ Network.prototype._onTouch = function (event) {
* handle drag start event
* @private
*/
Network.prototype._onDragStart = function () {
this._handleDragStart();
Network.prototype._onDragStart = function (event) {
this._handleDragStart(event);
};
@ -934,20 +936,24 @@ Network.prototype._onDragStart = function () {
*
* @private
*/
Network.prototype._handleDragStart = function() {
var drag = this.drag;
var node = this._getNodeAt(drag.pointer);
Network.prototype._handleDragStart = function(event) {
// in case the touch event was triggered on an external div, do the initial touch now.
if (this.drag.pointer === undefined) {
this._onTouch(event);
}
var node = this._getNodeAt(this.drag.pointer);
// note: drag.pointer is set in _onTouch to get the initial touch location
drag.dragging = true;
drag.selection = [];
drag.translation = this._getTranslation();
drag.nodeId = null;
this.drag.dragging = true;
this.drag.selection = [];
this.drag.translation = this._getTranslation();
this.drag.nodeId = null;
this.draggingNodes = false;
if (node != null && this.constants.dragNodes == true) {
this.draggingNodes = true;
drag.nodeId = node.id;
this.drag.nodeId = node.id;
// select the clicked node if not yet selected
if (!node.isSelected()) {
this._selectObject(node,false);
@ -973,7 +979,7 @@ Network.prototype._handleDragStart = function() {
object.xFixed = true;
object.yFixed = true;
drag.selection.push(s);
this.drag.selection.push(s);
}
}
}
@ -1033,8 +1039,13 @@ Network.prototype._handleOnDrag = function(event) {
}
}
else {
// move the network
if (this.constants.dragNetwork == true) {
// move the network
// if the drag was not started properly because the click started outside the network div, start it now.
if (this.drag.pointer === undefined) {
this._handleDragStart(event);
return;
}
var diffX = pointer.x - this.drag.pointer.x;
var diffY = pointer.y - this.drag.pointer.y;
@ -1043,8 +1054,6 @@ Network.prototype._handleOnDrag = function(event) {
this.drag.translation.y + diffY
);
this._redraw();
// this.moving = true;
// this.start();
}
}
};
@ -1327,34 +1336,44 @@ Network.prototype._checkShowPopup = function (pointer) {
if (this.popupObj == undefined) {
// search the nodes for overlap, select the top one in case of multiple nodes
var nodes = this.nodes;
var overlappingNodes = [];
for (id in nodes) {
if (nodes.hasOwnProperty(id)) {
var node = nodes[id];
if (node.isOverlappingWith(obj)) {
if (node.getTitle() !== undefined) {
this.popupObj = node;
break;
overlappingNodes.push(id);
}
// if you hover over a node, the title of the edge is not supposed to be shown.
nodeUnderCursor = true;
}
}
}
if (overlappingNodes.length > 0) {
// if there are overlapping nodes, select the last one, this is the
// one which is drawn on top of the others
this.popupObj = this.nodes[overlappingNodes[overlappingNodes.length - 1]];
// if you hover over a node, the title of the edge is not supposed to be shown.
nodeUnderCursor = true;
}
}
if (this.popupObj === undefined && nodeUnderCursor == false) {
// search the edges for overlap
var edges = this.edges;
var overlappingEdges = [];
for (id in edges) {
if (edges.hasOwnProperty(id)) {
var edge = edges[id];
if (edge.connected && (edge.getTitle() !== undefined) &&
edge.isOverlappingWith(obj)) {
this.popupObj = edge;
break;
overlappingEdges.push(id);
}
}
}
if (overlappingEdges.length > 0) {
this.popupObj = this.edges[overlappingEdges[overlappingEdges.length - 1]];
}
}
if (this.popupObj) {

+ 9
- 4
lib/network/Node.js View File

@ -157,7 +157,7 @@ Node.prototype.setProperties = function(properties, constants) {
}
var fields = ['borderWidth','borderWidthSelected','shape','image','brokenImage','radius','fontColor',
'fontSize','fontFace','fontFill','group','mass'
'fontSize','fontFace','fontFill','fontStrokeWidth','fontStrokeColor','group','mass'
];
util.selectiveDeepExtend(fields, this.options, properties);
@ -186,9 +186,6 @@ Node.prototype.setProperties = function(properties, constants) {
// 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
if (properties.radius !== undefined) {this.baseRadiusValue = this.options.radius;}
@ -1028,7 +1025,15 @@ Node.prototype._label = function (ctx, text, x, y, align, baseline, labelUnderNo
ctx.fillStyle = this.options.fontColor || "black";
ctx.textAlign = align || "center";
ctx.textBaseline = baseline || "middle";
if (this.options.fontStrokeWidth > 0){
ctx.lineWidth = this.options.fontStrokeWidth;
ctx.strokeStyle = this.options.fontStrokeColor;
ctx.lineJoin = 'round';
}
for (var i = 0; i < lineCount; i++) {
if(this.options.fontStrokeWidth){
ctx.strokeText(lines[i], x, yLine);
}
ctx.fillText(lines[i], x, yLine);
yLine += fontSize;
}

+ 11
- 23
lib/network/mixins/HierarchicalLayoutMixin.js View File

@ -218,36 +218,24 @@ exports._determineLevels = function(hubsize) {
}
};
/**
* this function allocates nodes in levels based on the recursive branching from the largest hubs.
* this function allocates nodes in levels based on the direction of the edges
*
* @param hubsize
* @private
*/
exports._determineLevelsDirected = function() {
var nodeId, node;
var nodeId, node, firstNode;
var minLevel = 10000;
// set first node to source
for (nodeId in this.nodes) {
if (this.nodes.hasOwnProperty(nodeId)) {
this.nodes[nodeId].level = 10000;
break;
}
}
// branch from hubs
for (nodeId in this.nodes) {
if (this.nodes.hasOwnProperty(nodeId)) {
node = this.nodes[nodeId];
if (node.level == 10000) {
this._setLevelDirected(10000,node.edges,node.id);
}
}
}
firstNode = this.nodes[this.nodeIndices[0]];
firstNode.level = minLevel;
this._setLevelDirected(minLevel,firstNode.edges,firstNode.id);
// branch from hubs
var minLevel = 10000;
// get the minimum level
for (nodeId in this.nodes) {
if (this.nodes.hasOwnProperty(nodeId)) {
node = this.nodes[nodeId];
@ -255,7 +243,7 @@ exports._determineLevelsDirected = function() {
}
}
// branch from hubs
// subtract the minimum from the set so we have a range starting from 0
for (nodeId in this.nodes) {
if (this.nodes.hasOwnProperty(nodeId)) {
node = this.nodes[nodeId];
@ -361,7 +349,7 @@ exports._setLevel = function(level, edges, parentId) {
/**
* this function is called recursively to enumerate the barnches of the largest hubs and give each node a level.
* this function is called recursively to enumerate the branched of the first node and give each node a level based on edge direction
*
* @param level
* @param edges

+ 18
- 8
lib/network/mixins/ManipulationMixin.js View File

@ -8,9 +8,7 @@ var Edge = require('../Edge');
* @private
*/
exports._clearManipulatorBar = function() {
while (this.manipulationDiv.hasChildNodes()) {
this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);
}
this._recursiveDOMDelete(this.manipulationDiv);
this.manipulationDOM = {};
this._manipulationReleaseOverload = function () {};
@ -30,6 +28,7 @@ exports._restoreOverloadedFunctions = function() {
for (var functionName in this.cachedFunctions) {
if (this.cachedFunctions.hasOwnProperty(functionName)) {
this[functionName] = this.cachedFunctions[functionName];
delete this.cachedFunctions[functionName];
}
}
};
@ -175,7 +174,8 @@ exports._createManipulatorBar = function() {
}
this.closeDiv.onclick = this._toggleEditMode.bind(this);
this.boundFunction = this._createManipulatorBar.bind(this);
var me = this;
this.boundFunction = me._createManipulatorBar;
this.on('select', this.boundFunction);
}
else {
@ -238,7 +238,8 @@ exports._createAddNodeToolbar = function() {
this.manipulationDOM['backSpan'].onclick = this._createManipulatorBar.bind(this);
// we use the boundFunction so we can reference it when we unbind it from the "select" event.
this.boundFunction = this._addNode.bind(this);
var me = this;
this.boundFunction = me._addNode;
this.on('select', this.boundFunction);
};
@ -254,12 +255,12 @@ exports._createAddEdgeToolbar = function() {
this._unselectAll(true);
this.freezeSimulation = true;
var locale = this.constants.locales[this.constants.locale];
if (this.boundFunction) {
this.off('select', this.boundFunction);
}
var locale = this.constants.locales[this.constants.locale];
this._unselectAll();
this.forceAppendSelection = false;
this.blockConnectingEdgeSelection = true;
@ -290,7 +291,8 @@ exports._createAddEdgeToolbar = function() {
this.manipulationDOM['backSpan'].onclick = this._createManipulatorBar.bind(this);
// we use the boundFunction so we can reference it when we unbind it from the "select" event.
this.boundFunction = this._handleConnect.bind(this);
var me = this;
this.boundFunction = me._handleConnect;
this.on('select', this.boundFunction);
// temporarily overload functions
@ -401,14 +403,22 @@ exports._controlNodeDrag = function(event) {
this._redraw();
};
/**
*
* @param pointer
* @private
*/
exports._releaseControlNode = function(pointer) {
var newNode = this._getNodeAt(pointer);
if (newNode !== null) {
if (this.edgeBeingEdited.controlNodes.from.selected == true) {
this.edgeBeingEdited._restoreControlNodes();
this._editEdge(newNode.id, this.edgeBeingEdited.to.id);
this.edgeBeingEdited.controlNodes.from.unselect();
}
if (this.edgeBeingEdited.controlNodes.to.selected == true) {
this.edgeBeingEdited._restoreControlNodes();
this._editEdge(this.edgeBeingEdited.from.id, newNode.id);
this.edgeBeingEdited.controlNodes.to.unselect();
}

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

@ -31,6 +31,12 @@ exports._calculateNodeForces = function () {
dy = node2.y - node1.y;
distance = Math.sqrt(dx * dx + dy * dy);
// same condition as BarnesHut, making sure nodes are never 100% overlapping.
if (distance == 0) {
distance = 0.1*Math.random();
dx = distance;
}
minimumDistance = (combinedClusterSize == 0) ? nodeDistance : (nodeDistance * (1 + combinedClusterSize * this.constants.clustering.distanceAmplification));
var a = a_base / minimumDistance;
if (distance < 2 * minimumDistance) {
@ -40,13 +46,13 @@ exports._calculateNodeForces = function () {
else {
repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness))
}
// amplify the repulsion for clusters.
repulsingForce *= (combinedClusterSize == 0) ? 1 : 1 + combinedClusterSize * this.constants.clustering.forceAmplification;
repulsingForce = repulsingForce / Math.max(distance,0.01*minimumDistance);
fx = dx * repulsingForce;
fy = dy * repulsingForce;
node1.fx -= fx;
node1.fy -= fy;
node2.fx += fx;

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

@ -608,8 +608,7 @@ Core.prototype.redraw = function() {
this.redraw();
}
else {
console.log('WARNING: infinite loop in redraw?')
throw new Error("bla")
console.log('WARNING: infinite loop in redraw?');
}
this.redrawCount = 0;
}

+ 14
- 8
lib/timeline/Range.js View File

@ -112,9 +112,13 @@ function validateDirection (direction) {
* If animate is a number, the
* number is taken as duration
* Default duration is 500 ms.
* @param {Boolean} [byUser=false]
*
*/
Range.prototype.setRange = function(start, end, animate) {
Range.prototype.setRange = function(start, end, animate, byUser) {
if (byUser !== true) {
byUser = false;
}
var _start = start != undefined ? util.convert(start, 'Date').valueOf() : null;
var _end = end != undefined ? util.convert(end, 'Date').valueOf() : null;
this._cancelAnimation();
@ -139,12 +143,12 @@ Range.prototype.setRange = function(start, end, animate) {
DateUtil.updateHiddenDates(me.body, me.options.hiddenDates);
anyChanged = anyChanged || changed;
if (changed) {
me.body.emitter.emit('rangechange', {start: new Date(me.start), end: new Date(me.end)});
me.body.emitter.emit('rangechange', {start: new Date(me.start), end: new Date(me.end), byUser:byUser});
}
if (done) {
if (anyChanged) {
me.body.emitter.emit('rangechanged', {start: new Date(me.start), end: new Date(me.end)});
me.body.emitter.emit('rangechanged', {start: new Date(me.start), end: new Date(me.end), byUser:byUser});
}
}
else {
@ -161,7 +165,7 @@ Range.prototype.setRange = function(start, end, animate) {
var changed = this._applyRange(_start, _end);
DateUtil.updateHiddenDates(this.body, this.options.hiddenDates);
if (changed) {
var params = {start: new Date(this.start), end: new Date(this.end)};
var params = {start: new Date(this.start), end: new Date(this.end), byUser:byUser};
this.body.emitter.emit('rangechange', params);
this.body.emitter.emit('rangechanged', params);
}
@ -412,7 +416,8 @@ Range.prototype._onDrag = function (event) {
// fire a rangechange event
this.body.emitter.emit('rangechange', {
start: new Date(this.start),
end: new Date(this.end)
end: new Date(this.end),
byUser: true
});
};
@ -437,7 +442,8 @@ Range.prototype._onDragEnd = function (event) {
// fire a rangechanged event
this.body.emitter.emit('rangechanged', {
start: new Date(this.start),
end: new Date(this.end)
end: new Date(this.end),
byUser: true
});
};
@ -552,7 +558,7 @@ Range.prototype._onPinch = function (event) {
newEnd = safeEnd;
}
this.setRange(newStart, newEnd);
this.setRange(newStart, newEnd, false, true);
this.startToFront = false; // revert to default
this.endToFront = true; // revert to default
@ -629,7 +635,7 @@ Range.prototype.zoom = function(scale, center, delta) {
newEnd = safeEnd;
}
this.setRange(newStart, newEnd);
this.setRange(newStart, newEnd, false, true);
this.startToFront = false; // revert to default
this.endToFront = true; // revert to default

Loading…
Cancel
Save