vis-rails 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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
  };