vis-rails 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +5 -13
  2. data/lib/vis/rails/version.rb +1 -1
  3. data/vendor/assets/component/emitter.js +162 -0
  4. data/vendor/assets/javascripts/vis.js +1 -0
  5. data/vendor/assets/vis/DataSet.js +8 -2
  6. data/vendor/assets/vis/DataView.js +8 -4
  7. data/vendor/assets/vis/graph/Edge.js +210 -78
  8. data/vendor/assets/vis/graph/Graph.js +474 -652
  9. data/vendor/assets/vis/graph/Node.js +119 -82
  10. data/vendor/assets/vis/graph/css/graph-manipulation.css +128 -0
  11. data/vendor/assets/vis/graph/css/graph-navigation.css +62 -0
  12. data/vendor/assets/vis/graph/graphMixins/ClusterMixin.js +1141 -0
  13. data/vendor/assets/vis/graph/graphMixins/HierarchicalLayoutMixin.js +296 -0
  14. data/vendor/assets/vis/graph/graphMixins/ManipulationMixin.js +433 -0
  15. data/vendor/assets/vis/graph/graphMixins/MixinLoader.js +201 -0
  16. data/vendor/assets/vis/graph/graphMixins/NavigationMixin.js +173 -0
  17. data/vendor/assets/vis/graph/graphMixins/SectorsMixin.js +552 -0
  18. data/vendor/assets/vis/graph/graphMixins/SelectionMixin.js +558 -0
  19. data/vendor/assets/vis/graph/graphMixins/physics/BarnesHut.js +373 -0
  20. data/vendor/assets/vis/graph/graphMixins/physics/HierarchialRepulsion.js +64 -0
  21. data/vendor/assets/vis/graph/graphMixins/physics/PhysicsMixin.js +513 -0
  22. data/vendor/assets/vis/graph/graphMixins/physics/Repulsion.js +66 -0
  23. data/vendor/assets/vis/graph/img/acceptDeleteIcon.png +0 -0
  24. data/vendor/assets/vis/graph/img/addNodeIcon.png +0 -0
  25. data/vendor/assets/vis/graph/img/backIcon.png +0 -0
  26. data/vendor/assets/vis/graph/img/connectIcon.png +0 -0
  27. data/vendor/assets/vis/graph/img/cross.png +0 -0
  28. data/vendor/assets/vis/graph/img/cross2.png +0 -0
  29. data/vendor/assets/vis/graph/img/deleteIcon.png +0 -0
  30. data/vendor/assets/vis/graph/img/downArrow.png +0 -0
  31. data/vendor/assets/vis/graph/img/editIcon.png +0 -0
  32. data/vendor/assets/vis/graph/img/leftArrow.png +0 -0
  33. data/vendor/assets/vis/graph/img/rightArrow.png +0 -0
  34. data/vendor/assets/vis/graph/img/upArrow.png +0 -0
  35. data/vendor/assets/vis/module/exports.js +0 -2
  36. data/vendor/assets/vis/module/header.js +2 -2
  37. data/vendor/assets/vis/module/imports.js +1 -2
  38. data/vendor/assets/vis/timeline/Controller.js +56 -45
  39. data/vendor/assets/vis/timeline/Range.js +68 -62
  40. data/vendor/assets/vis/timeline/Stack.js +11 -13
  41. data/vendor/assets/vis/timeline/TimeStep.js +43 -38
  42. data/vendor/assets/vis/timeline/Timeline.js +215 -93
  43. data/vendor/assets/vis/timeline/component/Component.js +19 -3
  44. data/vendor/assets/vis/timeline/component/CurrentTime.js +1 -1
  45. data/vendor/assets/vis/timeline/component/CustomTime.js +39 -120
  46. data/vendor/assets/vis/timeline/component/GroupSet.js +35 -1
  47. data/vendor/assets/vis/timeline/component/ItemSet.js +272 -9
  48. data/vendor/assets/vis/timeline/component/RootPanel.js +59 -47
  49. data/vendor/assets/vis/timeline/component/TimeAxis.js +10 -0
  50. data/vendor/assets/vis/timeline/component/css/item.css +53 -22
  51. data/vendor/assets/vis/timeline/component/item/Item.js +40 -5
  52. data/vendor/assets/vis/timeline/component/item/ItemBox.js +3 -1
  53. data/vendor/assets/vis/timeline/component/item/ItemPoint.js +3 -1
  54. data/vendor/assets/vis/timeline/component/item/ItemRange.js +67 -3
  55. data/vendor/assets/vis/timeline/component/item/ItemRangeOverflow.js +37 -9
  56. data/vendor/assets/vis/timeline/img/delete.png +0 -0
  57. data/vendor/assets/vis/util.js +169 -30
  58. metadata +39 -12
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MzAwMTY4NzkzNTA5ZGYyYzY0OTg5ZGFlYWZkNjMxNDg3MDk3ZDUzMw==
5
- data.tar.gz: !binary |-
6
- NmZjNDhhYzgxOTVlYmNmNTYzNDg4NWE1YzJkN2U4ZDAyYzY3NzgzYw==
2
+ SHA1:
3
+ metadata.gz: a580d6253ed70eb32d505bf44beff11f114a4f81
4
+ data.tar.gz: 2b0795e57a056c2347a7084bf93ae8e93cdb5e39
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- Mzk1ZjFlMDM5MjcxZTkzZTE3ZTYxM2MwMzEzZDgxN2VhZmJlZmIxNDUxYTBk
10
- Mjk5NGQ3YTUxMTMzNGU4MDQ3M2FkNjM1OWUyZWIzMDRmZmUwOWI1YjEwOTQ2
11
- MzIzNTUxNzE0MDcxMDVkMzc3NmFiNzczZDgzYzU3NTBjZTEwODQ=
12
- data.tar.gz: !binary |-
13
- MTRlNjE0YzNiZDgxOTVhOGY2OWY5NmM0YTAzZGUyZWRmNThkNjZlY2M1MGIz
14
- Nzc1MDhiZTRlNDIyNGQ5MjhkNjE4YTE3ZDliNTM0NzllYmUwMjQyMmJjOTIw
15
- NWY3ODg5MTc0Y2U0NWRhYzQyMGNmOGUxNzA0YjUwYzcwY2UzY2M=
6
+ metadata.gz: f74e570dad14bb4b1be2682f924e6153c7b5d47bc36b5449d43b9ebb99a6692d524ec873c7f1882c1912fdb8f5f6ce4aa47f9c901bd656f227d735c4a994e1a5
7
+ data.tar.gz: 4ac01a2a19d2b44dce0629621dca14eba2b4a77f3ba008cbae56449540c73151443efd9fe21c64f219205a1a6e888e2e801611cf1f6f2b9b0dd39868a29644a0
@@ -1,5 +1,5 @@
1
1
  module Vis
2
2
  module Rails
3
- VERSION = "0.0.4"
3
+ VERSION = "0.0.5"
4
4
  end
5
5
  end
@@ -0,0 +1,162 @@
1
+
2
+ /**
3
+ * Expose `Emitter`.
4
+ */
5
+
6
+ /**
7
+ * Initialize a new `Emitter`.
8
+ *
9
+ * @api public
10
+ */
11
+
12
+ function Emitter(obj) {
13
+ if (obj) return mixin(obj);
14
+ };
15
+
16
+ /**
17
+ * Mixin the emitter properties.
18
+ *
19
+ * @param {Object} obj
20
+ * @return {Object}
21
+ * @api private
22
+ */
23
+
24
+ function mixin(obj) {
25
+ for (var key in Emitter.prototype) {
26
+ obj[key] = Emitter.prototype[key];
27
+ }
28
+ return obj;
29
+ }
30
+
31
+ /**
32
+ * Listen on the given `event` with `fn`.
33
+ *
34
+ * @param {String} event
35
+ * @param {Function} fn
36
+ * @return {Emitter}
37
+ * @api public
38
+ */
39
+
40
+ Emitter.prototype.on =
41
+ Emitter.prototype.addEventListener = function(event, fn){
42
+ this._callbacks = this._callbacks || {};
43
+ (this._callbacks[event] = this._callbacks[event] || [])
44
+ .push(fn);
45
+ return this;
46
+ };
47
+
48
+ /**
49
+ * Adds an `event` listener that will be invoked a single
50
+ * time then automatically removed.
51
+ *
52
+ * @param {String} event
53
+ * @param {Function} fn
54
+ * @return {Emitter}
55
+ * @api public
56
+ */
57
+
58
+ Emitter.prototype.once = function(event, fn){
59
+ var self = this;
60
+ this._callbacks = this._callbacks || {};
61
+
62
+ function on() {
63
+ self.off(event, on);
64
+ fn.apply(this, arguments);
65
+ }
66
+
67
+ on.fn = fn;
68
+ this.on(event, on);
69
+ return this;
70
+ };
71
+
72
+ /**
73
+ * Remove the given callback for `event` or all
74
+ * registered callbacks.
75
+ *
76
+ * @param {String} event
77
+ * @param {Function} fn
78
+ * @return {Emitter}
79
+ * @api public
80
+ */
81
+
82
+ Emitter.prototype.off =
83
+ Emitter.prototype.removeListener =
84
+ Emitter.prototype.removeAllListeners =
85
+ Emitter.prototype.removeEventListener = function(event, fn){
86
+ this._callbacks = this._callbacks || {};
87
+
88
+ // all
89
+ if (0 == arguments.length) {
90
+ this._callbacks = {};
91
+ return this;
92
+ }
93
+
94
+ // specific event
95
+ var callbacks = this._callbacks[event];
96
+ if (!callbacks) return this;
97
+
98
+ // remove all handlers
99
+ if (1 == arguments.length) {
100
+ delete this._callbacks[event];
101
+ return this;
102
+ }
103
+
104
+ // remove specific handler
105
+ var cb;
106
+ for (var i = 0; i < callbacks.length; i++) {
107
+ cb = callbacks[i];
108
+ if (cb === fn || cb.fn === fn) {
109
+ callbacks.splice(i, 1);
110
+ break;
111
+ }
112
+ }
113
+ return this;
114
+ };
115
+
116
+ /**
117
+ * Emit `event` with the given args.
118
+ *
119
+ * @param {String} event
120
+ * @param {Mixed} ...
121
+ * @return {Emitter}
122
+ */
123
+
124
+ Emitter.prototype.emit = function(event){
125
+ this._callbacks = this._callbacks || {};
126
+ var args = [].slice.call(arguments, 1)
127
+ , callbacks = this._callbacks[event];
128
+
129
+ if (callbacks) {
130
+ callbacks = callbacks.slice(0);
131
+ for (var i = 0, len = callbacks.length; i < len; ++i) {
132
+ callbacks[i].apply(this, args);
133
+ }
134
+ }
135
+
136
+ return this;
137
+ };
138
+
139
+ /**
140
+ * Return array of callbacks for `event`.
141
+ *
142
+ * @param {String} event
143
+ * @return {Array}
144
+ * @api public
145
+ */
146
+
147
+ Emitter.prototype.listeners = function(event){
148
+ this._callbacks = this._callbacks || {};
149
+ return this._callbacks[event] || [];
150
+ };
151
+
152
+ /**
153
+ * Check if this emitter has `event` handlers.
154
+ *
155
+ * @param {String} event
156
+ * @return {Boolean}
157
+ * @api public
158
+ */
159
+
160
+ Emitter.prototype.hasListeners = function(event){
161
+ return !! this.listeners(event).length;
162
+ };
@@ -1,6 +1,7 @@
1
1
  //= require ../vis/module/header
2
2
  //= require moment
3
3
  //= require hammer
4
+ //= require ../component/emitter
4
5
 
5
6
  //= require ../vis/shim
6
7
  //= require ../vis/util
@@ -73,7 +73,7 @@ function DataSet (options) {
73
73
  * {Object | null} params
74
74
  * {String | Number} senderId
75
75
  */
76
- DataSet.prototype.subscribe = function (event, callback) {
76
+ DataSet.prototype.on = function on (event, callback) {
77
77
  var subscribers = this.subscribers[event];
78
78
  if (!subscribers) {
79
79
  subscribers = [];
@@ -85,12 +85,15 @@ DataSet.prototype.subscribe = function (event, callback) {
85
85
  });
86
86
  };
87
87
 
88
+ // TODO: make this function deprecated (replaced with `on` since version 0.5)
89
+ DataSet.prototype.subscribe = DataSet.prototype.on;
90
+
88
91
  /**
89
92
  * Unsubscribe from an event, remove an event listener
90
93
  * @param {String} event
91
94
  * @param {function} callback
92
95
  */
93
- DataSet.prototype.unsubscribe = function (event, callback) {
96
+ DataSet.prototype.off = function off(event, callback) {
94
97
  var subscribers = this.subscribers[event];
95
98
  if (subscribers) {
96
99
  this.subscribers[event] = subscribers.filter(function (listener) {
@@ -99,6 +102,9 @@ DataSet.prototype.unsubscribe = function (event, callback) {
99
102
  }
100
103
  };
101
104
 
105
+ // TODO: make this function deprecated (replaced with `on` since version 0.5)
106
+ DataSet.prototype.unsubscribe = DataSet.prototype.off;
107
+
102
108
  /**
103
109
  * Trigger an event
104
110
  * @param {String} event
@@ -69,8 +69,8 @@ DataView.prototype.setData = function (data) {
69
69
  this._trigger('add', {items: ids});
70
70
 
71
71
  // subscribe to new dataset
72
- if (this.data.subscribe) {
73
- this.data.subscribe('*', this.listener);
72
+ if (this.data.on) {
73
+ this.data.on('*', this.listener);
74
74
  }
75
75
  }
76
76
  };
@@ -276,6 +276,10 @@ DataView.prototype._onEvent = function (event, params, senderId) {
276
276
  };
277
277
 
278
278
  // copy subscription functionality from DataSet
279
- DataView.prototype.subscribe = DataSet.prototype.subscribe;
280
- DataView.prototype.unsubscribe = DataSet.prototype.unsubscribe;
279
+ DataView.prototype.on = DataSet.prototype.on;
280
+ DataView.prototype.off = DataSet.prototype.off;
281
281
  DataView.prototype._trigger = DataSet.prototype._trigger;
282
+
283
+ // TODO: make these functions deprecated (replaced with `on` and `off` since version 0.5)
284
+ DataView.prototype.subscribe = DataView.prototype.on;
285
+ DataView.prototype.unsubscribe = DataView.prototype.off;
@@ -31,10 +31,14 @@ function Edge (properties, graph, constants) {
31
31
  this.title = undefined;
32
32
  this.width = constants.edges.width;
33
33
  this.value = undefined;
34
- this.length = constants.edges.length;
34
+ this.length = constants.physics.springLength;
35
+ this.customLength = false;
36
+ this.selected = false;
37
+ this.smooth = constants.smoothCurves;
35
38
 
36
39
  this.from = null; // a node
37
40
  this.to = null; // a node
41
+ this.via = null; // a temp node
38
42
 
39
43
  // we use this to be able to reconnect the edge to a cluster if its node is put into a cluster
40
44
  // by storing the original information we can revert to the original connection when the cluser is opened.
@@ -48,13 +52,11 @@ function Edge (properties, graph, constants) {
48
52
  // 2012-08-08
49
53
  this.dash = util.extend({}, constants.edges.dash); // contains properties length, gap, altLength
50
54
 
51
- this.stiffness = undefined; // depends on the length of the edge
52
55
  this.color = constants.edges.color;
53
56
  this.widthFixed = false;
54
57
  this.lengthFixed = false;
55
58
 
56
59
  this.setProperties(properties, constants);
57
-
58
60
  }
59
61
 
60
62
  /**
@@ -73,6 +75,7 @@ Edge.prototype.setProperties = function(properties, constants) {
73
75
  if (properties.id !== undefined) {this.id = properties.id;}
74
76
  if (properties.style !== undefined) {this.style = properties.style;}
75
77
  if (properties.label !== undefined) {this.label = properties.label;}
78
+
76
79
  if (this.label) {
77
80
  this.fontSize = constants.edges.fontSize;
78
81
  this.fontFace = constants.edges.fontFace;
@@ -81,10 +84,12 @@ Edge.prototype.setProperties = function(properties, constants) {
81
84
  if (properties.fontSize !== undefined) {this.fontSize = properties.fontSize;}
82
85
  if (properties.fontFace !== undefined) {this.fontFace = properties.fontFace;}
83
86
  }
84
- if (properties.title !== undefined) {this.title = properties.title;}
85
- if (properties.width !== undefined) {this.width = properties.width;}
86
- if (properties.value !== undefined) {this.value = properties.value;}
87
- if (properties.length !== undefined) {this.length = properties.length;}
87
+
88
+ if (properties.title !== undefined) {this.title = properties.title;}
89
+ if (properties.width !== undefined) {this.width = properties.width;}
90
+ if (properties.value !== undefined) {this.value = properties.value;}
91
+ if (properties.length !== undefined) {this.length = properties.length;
92
+ this.customLength = true;}
88
93
 
89
94
  // Added to support dashed lines
90
95
  // David Jordan
@@ -102,7 +107,6 @@ Edge.prototype.setProperties = function(properties, constants) {
102
107
 
103
108
  this.widthFixed = this.widthFixed || (properties.width !== undefined);
104
109
  this.lengthFixed = this.lengthFixed || (properties.length !== undefined);
105
- this.stiffness = 1 / this.length;
106
110
 
107
111
  // set draw method based on style
108
112
  switch (this.style) {
@@ -210,8 +214,7 @@ Edge.prototype.isOverlappingWith = function(obj) {
210
214
  var xObj = obj.left;
211
215
  var yObj = obj.top;
212
216
 
213
-
214
- var dist = Edge._dist(xFrom, yFrom, xTo, yTo, xObj, yObj);
217
+ var dist = this._getDistanceToEdge(xFrom, yFrom, xTo, yTo, xObj, yObj);
215
218
 
216
219
  return (dist < distMax);
217
220
  };
@@ -229,14 +232,21 @@ Edge.prototype._drawLine = function(ctx) {
229
232
  ctx.strokeStyle = this.color;
230
233
  ctx.lineWidth = this._getLineWidth();
231
234
 
232
- var point;
233
235
  if (this.from != this.to) {
234
236
  // draw line
235
237
  this._line(ctx);
236
238
 
237
239
  // draw label
240
+ var point;
238
241
  if (this.label) {
239
- point = this._pointOnLine(0.5);
242
+ if (this.smooth == true) {
243
+ var midpointX = 0.5*(0.5*(this.from.x + this.via.x) + 0.5*(this.to.x + this.via.x));
244
+ var midpointY = 0.5*(0.5*(this.from.y + this.via.y) + 0.5*(this.to.y + this.via.y));
245
+ point = {x:midpointX, y:midpointY};
246
+ }
247
+ else {
248
+ point = this._pointOnLine(0.5);
249
+ }
240
250
  this._label(ctx, this.label, point.x, point.y);
241
251
  }
242
252
  }
@@ -268,7 +278,7 @@ Edge.prototype._drawLine = function(ctx) {
268
278
  * @private
269
279
  */
270
280
  Edge.prototype._getLineWidth = function() {
271
- if (this.from.selected || this.to.selected) {
281
+ if (this.selected == true) {
272
282
  return Math.min(this.width * 2, this.widthMax)*this.graphScaleInv;
273
283
  }
274
284
  else {
@@ -285,7 +295,12 @@ Edge.prototype._line = function (ctx) {
285
295
  // draw a straight line
286
296
  ctx.beginPath();
287
297
  ctx.moveTo(this.from.x, this.from.y);
288
- ctx.lineTo(this.to.x, this.to.y);
298
+ if (this.smooth == true) {
299
+ ctx.quadraticCurveTo(this.via.x,this.via.y,this.to.x, this.to.y);
300
+ }
301
+ else {
302
+ ctx.lineTo(this.to.x, this.to.y);
303
+ }
289
304
  ctx.stroke();
290
305
  };
291
306
 
@@ -347,29 +362,82 @@ Edge.prototype._drawDashLine = function(ctx) {
347
362
  ctx.strokeStyle = this.color;
348
363
  ctx.lineWidth = this._getLineWidth();
349
364
 
350
- // draw dashed line
351
- ctx.beginPath();
352
- ctx.lineCap = 'round';
353
- if (this.dash.altLength !== undefined) //If an alt dash value has been set add to the array this value
354
- {
355
- ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,
356
- [this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]);
357
- }
358
- else if (this.dash.length !== undefined && this.dash.gap !== undefined) //If a dash and gap value has been set add to the array this value
359
- {
360
- ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,
361
- [this.dash.length,this.dash.gap]);
362
- }
363
- else //If all else fails draw a line
364
- {
365
+ // only firefox and chrome support this method, else we use the legacy one.
366
+ if (ctx.mozDash !== undefined || ctx.setLineDash !== undefined) {
367
+ ctx.beginPath();
365
368
  ctx.moveTo(this.from.x, this.from.y);
366
- ctx.lineTo(this.to.x, this.to.y);
369
+
370
+ // configure the dash pattern
371
+ var pattern = [0];
372
+ if (this.dash.length !== undefined && this.dash.gap !== undefined) {
373
+ pattern = [this.dash.length,this.dash.gap];
374
+ }
375
+ else {
376
+ pattern = [5,5];
377
+ }
378
+
379
+ // set dash settings for chrome or firefox
380
+ if (typeof ctx.setLineDash !== 'undefined') { //Chrome
381
+ ctx.setLineDash(pattern);
382
+ ctx.lineDashOffset = 0;
383
+
384
+ } else { //Firefox
385
+ ctx.mozDash = pattern;
386
+ ctx.mozDashOffset = 0;
387
+ }
388
+
389
+ // draw the line
390
+ if (this.smooth == true) {
391
+ ctx.quadraticCurveTo(this.via.x,this.via.y,this.to.x, this.to.y);
392
+ }
393
+ else {
394
+ ctx.lineTo(this.to.x, this.to.y);
395
+ }
396
+ ctx.stroke();
397
+
398
+ // restore the dash settings.
399
+ if (typeof ctx.setLineDash !== 'undefined') { //Chrome
400
+ ctx.setLineDash([0]);
401
+ ctx.lineDashOffset = 0;
402
+
403
+ } else { //Firefox
404
+ ctx.mozDash = [0];
405
+ ctx.mozDashOffset = 0;
406
+ }
407
+ }
408
+ else { // unsupporting smooth lines
409
+ // draw dashed line
410
+ ctx.beginPath();
411
+ ctx.lineCap = 'round';
412
+ if (this.dash.altLength !== undefined) //If an alt dash value has been set add to the array this value
413
+ {
414
+ ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,
415
+ [this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]);
416
+ }
417
+ else if (this.dash.length !== undefined && this.dash.gap !== undefined) //If a dash and gap value has been set add to the array this value
418
+ {
419
+ ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,
420
+ [this.dash.length,this.dash.gap]);
421
+ }
422
+ else //If all else fails draw a line
423
+ {
424
+ ctx.moveTo(this.from.x, this.from.y);
425
+ ctx.lineTo(this.to.x, this.to.y);
426
+ }
427
+ ctx.stroke();
367
428
  }
368
- ctx.stroke();
369
429
 
370
430
  // draw label
371
431
  if (this.label) {
372
- var point = this._pointOnLine(0.5);
432
+ var point;
433
+ if (this.smooth == true) {
434
+ var midpointX = 0.5*(0.5*(this.from.x + this.via.x) + 0.5*(this.to.x + this.via.x));
435
+ var midpointY = 0.5*(0.5*(this.from.y + this.via.y) + 0.5*(this.to.y + this.via.y));
436
+ point = {x:midpointX, y:midpointY};
437
+ }
438
+ else {
439
+ point = this._pointOnLine(0.5);
440
+ }
373
441
  this._label(ctx, this.label, point.x, point.y);
374
442
  }
375
443
  };
@@ -422,35 +490,42 @@ Edge.prototype._drawArrowCenter = function(ctx) {
422
490
  // draw line
423
491
  this._line(ctx);
424
492
 
425
- // draw an arrow halfway the line
426
493
  var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x));
427
494
  var length = 10 + 5 * this.width; // TODO: make customizable?
428
- point = this._pointOnLine(0.5);
495
+ // draw an arrow halfway the line
496
+ if (this.smooth == true) {
497
+ var midpointX = 0.5*(0.5*(this.from.x + this.via.x) + 0.5*(this.to.x + this.via.x));
498
+ var midpointY = 0.5*(0.5*(this.from.y + this.via.y) + 0.5*(this.to.y + this.via.y));
499
+ point = {x:midpointX, y:midpointY};
500
+ }
501
+ else {
502
+ point = this._pointOnLine(0.5);
503
+ }
504
+
429
505
  ctx.arrow(point.x, point.y, angle, length);
430
506
  ctx.fill();
431
507
  ctx.stroke();
432
508
 
433
509
  // draw label
434
510
  if (this.label) {
435
- point = this._pointOnLine(0.5);
436
511
  this._label(ctx, this.label, point.x, point.y);
437
512
  }
438
513
  }
439
514
  else {
440
515
  // draw circle
441
516
  var x, y;
442
- var radius = this.length / 4;
517
+ var radius = 0.25 * Math.max(100,this.length);
443
518
  var node = this.from;
444
519
  if (!node.width) {
445
520
  node.resize(ctx);
446
521
  }
447
522
  if (node.width > node.height) {
448
- x = node.x + node.width / 2;
523
+ x = node.x + node.width * 0.5;
449
524
  y = node.y - radius;
450
525
  }
451
526
  else {
452
527
  x = node.x + radius;
453
- y = node.y - node.height / 2;
528
+ y = node.y - node.height * 0.5;
454
529
  }
455
530
  this._circle(ctx, x, y, radius);
456
531
 
@@ -485,39 +560,66 @@ Edge.prototype._drawArrow = function(ctx) {
485
560
  ctx.fillStyle = this.color;
486
561
  ctx.lineWidth = this._getLineWidth();
487
562
 
488
- // draw line
489
563
  var angle, length;
564
+ //draw a line
490
565
  if (this.from != this.to) {
491
- // calculate length and angle of the line
492
566
  angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x));
493
567
  var dx = (this.to.x - this.from.x);
494
568
  var dy = (this.to.y - this.from.y);
495
- var lEdge = Math.sqrt(dx * dx + dy * dy);
569
+ var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
570
+
571
+ var fromBorderDist = this.from.distanceToBorder(ctx, angle + Math.PI);
572
+ var fromBorderPoint = (edgeSegmentLength - fromBorderDist) / edgeSegmentLength;
573
+ var xFrom = (fromBorderPoint) * this.from.x + (1 - fromBorderPoint) * this.to.x;
574
+ var yFrom = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y;
496
575
 
497
- var lFrom = this.from.distanceToBorder(ctx, angle + Math.PI);
498
- var pFrom = (lEdge - lFrom) / lEdge;
499
- var xFrom = (pFrom) * this.from.x + (1 - pFrom) * this.to.x;
500
- var yFrom = (pFrom) * this.from.y + (1 - pFrom) * this.to.y;
501
576
 
502
- var lTo = this.to.distanceToBorder(ctx, angle);
503
- var pTo = (lEdge - lTo) / lEdge;
504
- var xTo = (1 - pTo) * this.from.x + pTo * this.to.x;
505
- var yTo = (1 - pTo) * this.from.y + pTo * this.to.y;
577
+ if (this.smooth == true) {
578
+ angle = Math.atan2((this.to.y - this.via.y), (this.to.x - this.via.x));
579
+ dx = (this.to.x - this.via.x);
580
+ dy = (this.to.y - this.via.y);
581
+ edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
582
+ }
583
+ var toBorderDist = this.to.distanceToBorder(ctx, angle);
584
+ var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength;
585
+
586
+ var xTo,yTo;
587
+ if (this.smooth == true) {
588
+ xTo = (1 - toBorderPoint) * this.via.x + toBorderPoint * this.to.x;
589
+ yTo = (1 - toBorderPoint) * this.via.y + toBorderPoint * this.to.y;
590
+ }
591
+ else {
592
+ xTo = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x;
593
+ yTo = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y;
594
+ }
506
595
 
507
596
  ctx.beginPath();
508
- ctx.moveTo(xFrom, yFrom);
509
- ctx.lineTo(xTo, yTo);
597
+ ctx.moveTo(xFrom,yFrom);
598
+ if (this.smooth == true) {
599
+ ctx.quadraticCurveTo(this.via.x,this.via.y,xTo, yTo);
600
+ }
601
+ else {
602
+ ctx.lineTo(xTo, yTo);
603
+ }
510
604
  ctx.stroke();
511
605
 
512
606
  // draw arrow at the end of the line
513
- length = 10 + 5 * this.width; // TODO: make customizable?
607
+ length = 10 + 5 * this.width;
514
608
  ctx.arrow(xTo, yTo, angle, length);
515
609
  ctx.fill();
516
610
  ctx.stroke();
517
611
 
518
612
  // draw label
519
613
  if (this.label) {
520
- var point = this._pointOnLine(0.5);
614
+ var point;
615
+ if (this.smooth == true) {
616
+ var midpointX = 0.5*(0.5*(this.from.x + this.via.x) + 0.5*(this.to.x + this.via.x));
617
+ var midpointY = 0.5*(0.5*(this.from.y + this.via.y) + 0.5*(this.to.y + this.via.y));
618
+ point = {x:midpointX, y:midpointY};
619
+ }
620
+ else {
621
+ point = this._pointOnLine(0.5);
622
+ }
521
623
  this._label(ctx, this.label, point.x, point.y);
522
624
  }
523
625
  }
@@ -525,12 +627,12 @@ Edge.prototype._drawArrow = function(ctx) {
525
627
  // draw circle
526
628
  var node = this.from;
527
629
  var x, y, arrow;
528
- var radius = this.length / 4;
630
+ var radius = 0.25 * Math.max(100,this.length);
529
631
  if (!node.width) {
530
632
  node.resize(ctx);
531
633
  }
532
634
  if (node.width > node.height) {
533
- x = node.x + node.width / 2;
635
+ x = node.x + node.width * 0.5;
534
636
  y = node.y - radius;
535
637
  arrow = {
536
638
  x: x,
@@ -540,7 +642,7 @@ Edge.prototype._drawArrow = function(ctx) {
540
642
  }
541
643
  else {
542
644
  x = node.x + radius;
543
- y = node.y - node.height / 2;
645
+ y = node.y - node.height * 0.5;
544
646
  arrow = {
545
647
  x: node.x,
546
648
  y: y,
@@ -548,7 +650,6 @@ Edge.prototype._drawArrow = function(ctx) {
548
650
  };
549
651
  }
550
652
  ctx.beginPath();
551
- // TODO: do not draw a circle, but an arc
552
653
  // TODO: similarly, for a line without arrows, draw to the border of the nodes instead of the center
553
654
  ctx.arc(x, y, radius, 0, 2 * Math.PI, false);
554
655
  ctx.stroke();
@@ -581,31 +682,46 @@ Edge.prototype._drawArrow = function(ctx) {
581
682
  * @param {number} y3
582
683
  * @private
583
684
  */
584
- Edge._dist = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point
585
- var px = x2-x1,
586
- py = y2-y1,
587
- something = px*px + py*py,
588
- u = ((x3 - x1) * px + (y3 - y1) * py) / something;
589
-
590
- if (u > 1) {
591
- u = 1;
592
- }
593
- else if (u < 0) {
594
- u = 0;
685
+ Edge.prototype._getDistanceToEdge = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point
686
+ if (this.smooth == true) {
687
+ var minDistance = 1e9;
688
+ var i,t,x,y,dx,dy;
689
+ for (i = 0; i < 10; i++) {
690
+ t = 0.1*i;
691
+ x = Math.pow(1-t,2)*x1 + (2*t*(1 - t))*this.via.x + Math.pow(t,2)*x2;
692
+ y = Math.pow(1-t,2)*y1 + (2*t*(1 - t))*this.via.y + Math.pow(t,2)*y2;
693
+ dx = Math.abs(x3-x);
694
+ dy = Math.abs(y3-y);
695
+ minDistance = Math.min(minDistance,Math.sqrt(dx*dx + dy*dy));
696
+ }
697
+ return minDistance
595
698
  }
699
+ else {
700
+ var px = x2-x1,
701
+ py = y2-y1,
702
+ something = px*px + py*py,
703
+ u = ((x3 - x1) * px + (y3 - y1) * py) / something;
704
+
705
+ if (u > 1) {
706
+ u = 1;
707
+ }
708
+ else if (u < 0) {
709
+ u = 0;
710
+ }
596
711
 
597
- var x = x1 + u * px,
598
- y = y1 + u * py,
599
- dx = x - x3,
600
- dy = y - y3;
712
+ var x = x1 + u * px,
713
+ y = y1 + u * py,
714
+ dx = x - x3,
715
+ dy = y - y3;
601
716
 
602
- //# Note: If the actual distance does not matter,
603
- //# if you only want to compare what this function
604
- //# returns to other results of this function, you
605
- //# can just return the squared distance instead
606
- //# (i.e. remove the sqrt) to gain a little performance
717
+ //# Note: If the actual distance does not matter,
718
+ //# if you only want to compare what this function
719
+ //# returns to other results of this function, you
720
+ //# can just return the squared distance instead
721
+ //# (i.e. remove the sqrt) to gain a little performance
607
722
 
608
- return Math.sqrt(dx*dx + dy*dy);
723
+ return Math.sqrt(dx*dx + dy*dy);
724
+ }
609
725
  };
610
726
 
611
727
 
@@ -617,4 +733,20 @@ Edge._dist = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point
617
733
  */
618
734
  Edge.prototype.setScale = function(scale) {
619
735
  this.graphScaleInv = 1.0/scale;
736
+ };
737
+
738
+
739
+ Edge.prototype.select = function() {
740
+ this.selected = true;
741
+ };
742
+
743
+ Edge.prototype.unselect = function() {
744
+ this.selected = false;
745
+ };
746
+
747
+ Edge.prototype.positionBezierNode = function() {
748
+ if (this.via !== null) {
749
+ this.via.x = 0.5 * (this.from.x + this.to.x);
750
+ this.via.y = 0.5 * (this.from.y + this.to.y);
751
+ }
620
752
  };