vis-rails 2.0.0 → 2.0.1

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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/lib/vis/rails/version.rb +1 -1
  3. data/vendor/assets/javascripts/vis.js +26 -26
  4. metadata +16 -85
  5. data/vendor/assets/vis/DataSet.js +0 -926
  6. data/vendor/assets/vis/DataView.js +0 -283
  7. data/vendor/assets/vis/graph/Edge.js +0 -957
  8. data/vendor/assets/vis/graph/Graph.js +0 -2291
  9. data/vendor/assets/vis/graph/Groups.js +0 -80
  10. data/vendor/assets/vis/graph/Images.js +0 -41
  11. data/vendor/assets/vis/graph/Node.js +0 -966
  12. data/vendor/assets/vis/graph/Popup.js +0 -132
  13. data/vendor/assets/vis/graph/css/graph-manipulation.css +0 -128
  14. data/vendor/assets/vis/graph/css/graph-navigation.css +0 -66
  15. data/vendor/assets/vis/graph/dotparser.js +0 -829
  16. data/vendor/assets/vis/graph/graphMixins/ClusterMixin.js +0 -1143
  17. data/vendor/assets/vis/graph/graphMixins/HierarchicalLayoutMixin.js +0 -311
  18. data/vendor/assets/vis/graph/graphMixins/ManipulationMixin.js +0 -576
  19. data/vendor/assets/vis/graph/graphMixins/MixinLoader.js +0 -199
  20. data/vendor/assets/vis/graph/graphMixins/NavigationMixin.js +0 -205
  21. data/vendor/assets/vis/graph/graphMixins/SectorsMixin.js +0 -552
  22. data/vendor/assets/vis/graph/graphMixins/SelectionMixin.js +0 -648
  23. data/vendor/assets/vis/graph/graphMixins/physics/BarnesHut.js +0 -398
  24. data/vendor/assets/vis/graph/graphMixins/physics/HierarchialRepulsion.js +0 -64
  25. data/vendor/assets/vis/graph/graphMixins/physics/PhysicsMixin.js +0 -697
  26. data/vendor/assets/vis/graph/graphMixins/physics/Repulsion.js +0 -66
  27. data/vendor/assets/vis/graph/img/acceptDeleteIcon.png +0 -0
  28. data/vendor/assets/vis/graph/img/addNodeIcon.png +0 -0
  29. data/vendor/assets/vis/graph/img/backIcon.png +0 -0
  30. data/vendor/assets/vis/graph/img/connectIcon.png +0 -0
  31. data/vendor/assets/vis/graph/img/cross.png +0 -0
  32. data/vendor/assets/vis/graph/img/cross2.png +0 -0
  33. data/vendor/assets/vis/graph/img/deleteIcon.png +0 -0
  34. data/vendor/assets/vis/graph/img/downArrow.png +0 -0
  35. data/vendor/assets/vis/graph/img/editIcon.png +0 -0
  36. data/vendor/assets/vis/graph/img/leftArrow.png +0 -0
  37. data/vendor/assets/vis/graph/img/minus.png +0 -0
  38. data/vendor/assets/vis/graph/img/plus.png +0 -0
  39. data/vendor/assets/vis/graph/img/rightArrow.png +0 -0
  40. data/vendor/assets/vis/graph/img/upArrow.png +0 -0
  41. data/vendor/assets/vis/graph/img/zoomExtends.png +0 -0
  42. data/vendor/assets/vis/graph/shapes.js +0 -225
  43. data/vendor/assets/vis/graph3d/Graph3d.js +0 -3306
  44. data/vendor/assets/vis/module/exports.js +0 -65
  45. data/vendor/assets/vis/module/header.js +0 -24
  46. data/vendor/assets/vis/module/imports.js +0 -31
  47. data/vendor/assets/vis/shim.js +0 -252
  48. data/vendor/assets/vis/timeline/Range.js +0 -532
  49. data/vendor/assets/vis/timeline/TimeStep.js +0 -466
  50. data/vendor/assets/vis/timeline/Timeline.js +0 -851
  51. data/vendor/assets/vis/timeline/component/Component.js +0 -52
  52. data/vendor/assets/vis/timeline/component/CurrentTime.js +0 -128
  53. data/vendor/assets/vis/timeline/component/CustomTime.js +0 -182
  54. data/vendor/assets/vis/timeline/component/Group.js +0 -470
  55. data/vendor/assets/vis/timeline/component/ItemSet.js +0 -1332
  56. data/vendor/assets/vis/timeline/component/TimeAxis.js +0 -389
  57. data/vendor/assets/vis/timeline/component/css/animation.css +0 -33
  58. data/vendor/assets/vis/timeline/component/css/currenttime.css +0 -5
  59. data/vendor/assets/vis/timeline/component/css/customtime.css +0 -6
  60. data/vendor/assets/vis/timeline/component/css/item.css +0 -107
  61. data/vendor/assets/vis/timeline/component/css/itemset.css +0 -33
  62. data/vendor/assets/vis/timeline/component/css/labelset.css +0 -36
  63. data/vendor/assets/vis/timeline/component/css/panel.css +0 -71
  64. data/vendor/assets/vis/timeline/component/css/timeaxis.css +0 -48
  65. data/vendor/assets/vis/timeline/component/css/timeline.css +0 -2
  66. data/vendor/assets/vis/timeline/component/item/Item.js +0 -139
  67. data/vendor/assets/vis/timeline/component/item/ItemBox.js +0 -230
  68. data/vendor/assets/vis/timeline/component/item/ItemPoint.js +0 -190
  69. data/vendor/assets/vis/timeline/component/item/ItemRange.js +0 -262
  70. data/vendor/assets/vis/timeline/component/item/ItemRangeOverflow.js +0 -57
  71. data/vendor/assets/vis/timeline/img/delete.png +0 -0
  72. data/vendor/assets/vis/timeline/stack.js +0 -112
  73. data/vendor/assets/vis/util.js +0 -990
@@ -1,283 +0,0 @@
1
- /**
2
- * DataView
3
- *
4
- * a dataview offers a filtered view on a dataset or an other dataview.
5
- *
6
- * @param {DataSet | DataView} data
7
- * @param {Object} [options] Available options: see method get
8
- *
9
- * @constructor DataView
10
- */
11
- function DataView (data, options) {
12
- this._data = null;
13
- this._ids = {}; // ids of the items currently in memory (just contains a boolean true)
14
- this._options = options || {};
15
- this._fieldId = 'id'; // name of the field containing id
16
- this._subscribers = {}; // event subscribers
17
-
18
- var me = this;
19
- this.listener = function () {
20
- me._onEvent.apply(me, arguments);
21
- };
22
-
23
- this.setData(data);
24
- }
25
-
26
- // TODO: implement a function .config() to dynamically update things like configured filter
27
- // and trigger changes accordingly
28
-
29
- /**
30
- * Set a data source for the view
31
- * @param {DataSet | DataView} data
32
- */
33
- DataView.prototype.setData = function (data) {
34
- var ids, i, len;
35
-
36
- if (this._data) {
37
- // unsubscribe from current dataset
38
- if (this._data.unsubscribe) {
39
- this._data.unsubscribe('*', this.listener);
40
- }
41
-
42
- // trigger a remove of all items in memory
43
- ids = [];
44
- for (var id in this._ids) {
45
- if (this._ids.hasOwnProperty(id)) {
46
- ids.push(id);
47
- }
48
- }
49
- this._ids = {};
50
- this._trigger('remove', {items: ids});
51
- }
52
-
53
- this._data = data;
54
-
55
- if (this._data) {
56
- // update fieldId
57
- this._fieldId = this._options.fieldId ||
58
- (this._data && this._data.options && this._data.options.fieldId) ||
59
- 'id';
60
-
61
- // trigger an add of all added items
62
- ids = this._data.getIds({filter: this._options && this._options.filter});
63
- for (i = 0, len = ids.length; i < len; i++) {
64
- id = ids[i];
65
- this._ids[id] = true;
66
- }
67
- this._trigger('add', {items: ids});
68
-
69
- // subscribe to new dataset
70
- if (this._data.on) {
71
- this._data.on('*', this.listener);
72
- }
73
- }
74
- };
75
-
76
- /**
77
- * Get data from the data view
78
- *
79
- * Usage:
80
- *
81
- * get()
82
- * get(options: Object)
83
- * get(options: Object, data: Array | DataTable)
84
- *
85
- * get(id: Number)
86
- * get(id: Number, options: Object)
87
- * get(id: Number, options: Object, data: Array | DataTable)
88
- *
89
- * get(ids: Number[])
90
- * get(ids: Number[], options: Object)
91
- * get(ids: Number[], options: Object, data: Array | DataTable)
92
- *
93
- * Where:
94
- *
95
- * {Number | String} id The id of an item
96
- * {Number[] | String{}} ids An array with ids of items
97
- * {Object} options An Object with options. Available options:
98
- * {String} [type] Type of data to be returned. Can
99
- * be 'DataTable' or 'Array' (default)
100
- * {Object.<String, String>} [convert]
101
- * {String[]} [fields] field names to be returned
102
- * {function} [filter] filter items
103
- * {String | function} [order] Order the items by
104
- * a field name or custom sort function.
105
- * {Array | DataTable} [data] If provided, items will be appended to this
106
- * array or table. Required in case of Google
107
- * DataTable.
108
- * @param args
109
- */
110
- DataView.prototype.get = function (args) {
111
- var me = this;
112
-
113
- // parse the arguments
114
- var ids, options, data;
115
- var firstType = util.getType(arguments[0]);
116
- if (firstType == 'String' || firstType == 'Number' || firstType == 'Array') {
117
- // get(id(s) [, options] [, data])
118
- ids = arguments[0]; // can be a single id or an array with ids
119
- options = arguments[1];
120
- data = arguments[2];
121
- }
122
- else {
123
- // get([, options] [, data])
124
- options = arguments[0];
125
- data = arguments[1];
126
- }
127
-
128
- // extend the options with the default options and provided options
129
- var viewOptions = util.extend({}, this._options, options);
130
-
131
- // create a combined filter method when needed
132
- if (this._options.filter && options && options.filter) {
133
- viewOptions.filter = function (item) {
134
- return me._options.filter(item) && options.filter(item);
135
- }
136
- }
137
-
138
- // build up the call to the linked data set
139
- var getArguments = [];
140
- if (ids != undefined) {
141
- getArguments.push(ids);
142
- }
143
- getArguments.push(viewOptions);
144
- getArguments.push(data);
145
-
146
- return this._data && this._data.get.apply(this._data, getArguments);
147
- };
148
-
149
- /**
150
- * Get ids of all items or from a filtered set of items.
151
- * @param {Object} [options] An Object with options. Available options:
152
- * {function} [filter] filter items
153
- * {String | function} [order] Order the items by
154
- * a field name or custom sort function.
155
- * @return {Array} ids
156
- */
157
- DataView.prototype.getIds = function (options) {
158
- var ids;
159
-
160
- if (this._data) {
161
- var defaultFilter = this._options.filter;
162
- var filter;
163
-
164
- if (options && options.filter) {
165
- if (defaultFilter) {
166
- filter = function (item) {
167
- return defaultFilter(item) && options.filter(item);
168
- }
169
- }
170
- else {
171
- filter = options.filter;
172
- }
173
- }
174
- else {
175
- filter = defaultFilter;
176
- }
177
-
178
- ids = this._data.getIds({
179
- filter: filter,
180
- order: options && options.order
181
- });
182
- }
183
- else {
184
- ids = [];
185
- }
186
-
187
- return ids;
188
- };
189
-
190
- /**
191
- * Event listener. Will propagate all events from the connected data set to
192
- * the subscribers of the DataView, but will filter the items and only trigger
193
- * when there are changes in the filtered data set.
194
- * @param {String} event
195
- * @param {Object | null} params
196
- * @param {String} senderId
197
- * @private
198
- */
199
- DataView.prototype._onEvent = function (event, params, senderId) {
200
- var i, len, id, item,
201
- ids = params && params.items,
202
- data = this._data,
203
- added = [],
204
- updated = [],
205
- removed = [];
206
-
207
- if (ids && data) {
208
- switch (event) {
209
- case 'add':
210
- // filter the ids of the added items
211
- for (i = 0, len = ids.length; i < len; i++) {
212
- id = ids[i];
213
- item = this.get(id);
214
- if (item) {
215
- this._ids[id] = true;
216
- added.push(id);
217
- }
218
- }
219
-
220
- break;
221
-
222
- case 'update':
223
- // determine the event from the views viewpoint: an updated
224
- // item can be added, updated, or removed from this view.
225
- for (i = 0, len = ids.length; i < len; i++) {
226
- id = ids[i];
227
- item = this.get(id);
228
-
229
- if (item) {
230
- if (this._ids[id]) {
231
- updated.push(id);
232
- }
233
- else {
234
- this._ids[id] = true;
235
- added.push(id);
236
- }
237
- }
238
- else {
239
- if (this._ids[id]) {
240
- delete this._ids[id];
241
- removed.push(id);
242
- }
243
- else {
244
- // nothing interesting for me :-(
245
- }
246
- }
247
- }
248
-
249
- break;
250
-
251
- case 'remove':
252
- // filter the ids of the removed items
253
- for (i = 0, len = ids.length; i < len; i++) {
254
- id = ids[i];
255
- if (this._ids[id]) {
256
- delete this._ids[id];
257
- removed.push(id);
258
- }
259
- }
260
-
261
- break;
262
- }
263
-
264
- if (added.length) {
265
- this._trigger('add', {items: added}, senderId);
266
- }
267
- if (updated.length) {
268
- this._trigger('update', {items: updated}, senderId);
269
- }
270
- if (removed.length) {
271
- this._trigger('remove', {items: removed}, senderId);
272
- }
273
- }
274
- };
275
-
276
- // copy subscription functionality from DataSet
277
- DataView.prototype.on = DataSet.prototype.on;
278
- DataView.prototype.off = DataSet.prototype.off;
279
- DataView.prototype._trigger = DataSet.prototype._trigger;
280
-
281
- // TODO: make these functions deprecated (replaced with `on` and `off` since version 0.5)
282
- DataView.prototype.subscribe = DataView.prototype.on;
283
- DataView.prototype.unsubscribe = DataView.prototype.off;
@@ -1,957 +0,0 @@
1
- /**
2
- * @class Edge
3
- *
4
- * A edge connects two nodes
5
- * @param {Object} properties Object with properties. Must contain
6
- * At least properties from and to.
7
- * Available properties: from (number),
8
- * to (number), label (string, color (string),
9
- * width (number), style (string),
10
- * length (number), title (string)
11
- * @param {Graph} graph A graph object, used to find and edge to
12
- * nodes.
13
- * @param {Object} constants An object with default values for
14
- * example for the color
15
- */
16
- function Edge (properties, graph, constants) {
17
- if (!graph) {
18
- throw "No graph provided";
19
- }
20
- this.graph = graph;
21
-
22
- // initialize constants
23
- this.widthMin = constants.edges.widthMin;
24
- this.widthMax = constants.edges.widthMax;
25
-
26
- // initialize variables
27
- this.id = undefined;
28
- this.fromId = undefined;
29
- this.toId = undefined;
30
- this.style = constants.edges.style;
31
- this.title = undefined;
32
- this.width = constants.edges.width;
33
- this.hoverWidth = constants.edges.hoverWidth;
34
- this.value = undefined;
35
- this.length = constants.physics.springLength;
36
- this.customLength = false;
37
- this.selected = false;
38
- this.hover = false;
39
- this.smooth = constants.smoothCurves;
40
- this.arrowScaleFactor = constants.edges.arrowScaleFactor;
41
-
42
- this.from = null; // a node
43
- this.to = null; // a node
44
- this.via = null; // a temp node
45
-
46
- // we use this to be able to reconnect the edge to a cluster if its node is put into a cluster
47
- // by storing the original information we can revert to the original connection when the cluser is opened.
48
- this.originalFromId = [];
49
- this.originalToId = [];
50
-
51
- this.connected = false;
52
-
53
- // Added to support dashed lines
54
- // David Jordan
55
- // 2012-08-08
56
- this.dash = util.extend({}, constants.edges.dash); // contains properties length, gap, altLength
57
-
58
- this.color = {color:constants.edges.color.color,
59
- highlight:constants.edges.color.highlight,
60
- hover:constants.edges.color.hover};
61
- this.widthFixed = false;
62
- this.lengthFixed = false;
63
-
64
- this.setProperties(properties, constants);
65
-
66
- this.controlNodesEnabled = false;
67
- this.controlNodes = {from:null, to:null, positions:{}};
68
- this.connectedNode = null;
69
- }
70
-
71
- /**
72
- * Set or overwrite properties for the edge
73
- * @param {Object} properties an object with properties
74
- * @param {Object} constants and object with default, global properties
75
- */
76
- Edge.prototype.setProperties = function(properties, constants) {
77
- if (!properties) {
78
- return;
79
- }
80
-
81
- if (properties.from !== undefined) {this.fromId = properties.from;}
82
- if (properties.to !== undefined) {this.toId = properties.to;}
83
-
84
- if (properties.id !== undefined) {this.id = properties.id;}
85
- if (properties.style !== undefined) {this.style = properties.style;}
86
- if (properties.label !== undefined) {this.label = properties.label;}
87
-
88
- if (this.label) {
89
- this.fontSize = constants.edges.fontSize;
90
- this.fontFace = constants.edges.fontFace;
91
- this.fontColor = constants.edges.fontColor;
92
- this.fontFill = constants.edges.fontFill;
93
-
94
- if (properties.fontColor !== undefined) {this.fontColor = properties.fontColor;}
95
- if (properties.fontSize !== undefined) {this.fontSize = properties.fontSize;}
96
- if (properties.fontFace !== undefined) {this.fontFace = properties.fontFace;}
97
- if (properties.fontFill !== undefined) {this.fontFill = properties.fontFill;}
98
- }
99
-
100
- if (properties.title !== undefined) {this.title = properties.title;}
101
- if (properties.width !== undefined) {this.width = properties.width;}
102
- if (properties.hoverWidth !== undefined) {this.hoverWidth = properties.hoverWidth;}
103
- if (properties.value !== undefined) {this.value = properties.value;}
104
- if (properties.length !== undefined) {this.length = properties.length;
105
- this.customLength = true;}
106
-
107
- // scale the arrow
108
- if (properties.arrowScaleFactor !== undefined) {this.arrowScaleFactor = properties.arrowScaleFactor;}
109
-
110
- // Added to support dashed lines
111
- // David Jordan
112
- // 2012-08-08
113
- if (properties.dash) {
114
- if (properties.dash.length !== undefined) {this.dash.length = properties.dash.length;}
115
- if (properties.dash.gap !== undefined) {this.dash.gap = properties.dash.gap;}
116
- if (properties.dash.altLength !== undefined) {this.dash.altLength = properties.dash.altLength;}
117
- }
118
-
119
- if (properties.color !== undefined) {
120
- if (util.isString(properties.color)) {
121
- this.color.color = properties.color;
122
- this.color.highlight = properties.color;
123
- }
124
- else {
125
- if (properties.color.color !== undefined) {this.color.color = properties.color.color;}
126
- if (properties.color.highlight !== undefined) {this.color.highlight = properties.color.highlight;}
127
- }
128
- }
129
-
130
- // A node is connected when it has a from and to node.
131
- this.connect();
132
-
133
- this.widthFixed = this.widthFixed || (properties.width !== undefined);
134
- this.lengthFixed = this.lengthFixed || (properties.length !== undefined);
135
-
136
- // set draw method based on style
137
- switch (this.style) {
138
- case 'line': this.draw = this._drawLine; break;
139
- case 'arrow': this.draw = this._drawArrow; break;
140
- case 'arrow-center': this.draw = this._drawArrowCenter; break;
141
- case 'dash-line': this.draw = this._drawDashLine; break;
142
- default: this.draw = this._drawLine; break;
143
- }
144
- };
145
-
146
- /**
147
- * Connect an edge to its nodes
148
- */
149
- Edge.prototype.connect = function () {
150
- this.disconnect();
151
-
152
- this.from = this.graph.nodes[this.fromId] || null;
153
- this.to = this.graph.nodes[this.toId] || null;
154
- this.connected = (this.from && this.to);
155
-
156
- if (this.connected) {
157
- this.from.attachEdge(this);
158
- this.to.attachEdge(this);
159
- }
160
- else {
161
- if (this.from) {
162
- this.from.detachEdge(this);
163
- }
164
- if (this.to) {
165
- this.to.detachEdge(this);
166
- }
167
- }
168
- };
169
-
170
- /**
171
- * Disconnect an edge from its nodes
172
- */
173
- Edge.prototype.disconnect = function () {
174
- if (this.from) {
175
- this.from.detachEdge(this);
176
- this.from = null;
177
- }
178
- if (this.to) {
179
- this.to.detachEdge(this);
180
- this.to = null;
181
- }
182
-
183
- this.connected = false;
184
- };
185
-
186
- /**
187
- * get the title of this edge.
188
- * @return {string} title The title of the edge, or undefined when no title
189
- * has been set.
190
- */
191
- Edge.prototype.getTitle = function() {
192
- return typeof this.title === "function" ? this.title() : this.title;
193
- };
194
-
195
-
196
- /**
197
- * Retrieve the value of the edge. Can be undefined
198
- * @return {Number} value
199
- */
200
- Edge.prototype.getValue = function() {
201
- return this.value;
202
- };
203
-
204
- /**
205
- * Adjust the value range of the edge. The edge will adjust it's width
206
- * based on its value.
207
- * @param {Number} min
208
- * @param {Number} max
209
- */
210
- Edge.prototype.setValueRange = function(min, max) {
211
- if (!this.widthFixed && this.value !== undefined) {
212
- var scale = (this.widthMax - this.widthMin) / (max - min);
213
- this.width = (this.value - min) * scale + this.widthMin;
214
- }
215
- };
216
-
217
- /**
218
- * Redraw a edge
219
- * Draw this edge in the given canvas
220
- * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
221
- * @param {CanvasRenderingContext2D} ctx
222
- */
223
- Edge.prototype.draw = function(ctx) {
224
- throw "Method draw not initialized in edge";
225
- };
226
-
227
- /**
228
- * Check if this object is overlapping with the provided object
229
- * @param {Object} obj an object with parameters left, top
230
- * @return {boolean} True if location is located on the edge
231
- */
232
- Edge.prototype.isOverlappingWith = function(obj) {
233
- if (this.connected) {
234
- var distMax = 10;
235
- var xFrom = this.from.x;
236
- var yFrom = this.from.y;
237
- var xTo = this.to.x;
238
- var yTo = this.to.y;
239
- var xObj = obj.left;
240
- var yObj = obj.top;
241
-
242
- var dist = this._getDistanceToEdge(xFrom, yFrom, xTo, yTo, xObj, yObj);
243
-
244
- return (dist < distMax);
245
- }
246
- else {
247
- return false
248
- }
249
- };
250
-
251
-
252
- /**
253
- * Redraw a edge as a line
254
- * Draw this edge in the given canvas
255
- * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
256
- * @param {CanvasRenderingContext2D} ctx
257
- * @private
258
- */
259
- Edge.prototype._drawLine = function(ctx) {
260
- // set style
261
- if (this.selected == true) {ctx.strokeStyle = this.color.highlight;}
262
- else if (this.hover == true) {ctx.strokeStyle = this.color.hover;}
263
- else {ctx.strokeStyle = this.color.color;}
264
- ctx.lineWidth = this._getLineWidth();
265
-
266
- if (this.from != this.to) {
267
- // draw line
268
- this._line(ctx);
269
-
270
- // draw label
271
- var point;
272
- if (this.label) {
273
- if (this.smooth == true) {
274
- var midpointX = 0.5*(0.5*(this.from.x + this.via.x) + 0.5*(this.to.x + this.via.x));
275
- var midpointY = 0.5*(0.5*(this.from.y + this.via.y) + 0.5*(this.to.y + this.via.y));
276
- point = {x:midpointX, y:midpointY};
277
- }
278
- else {
279
- point = this._pointOnLine(0.5);
280
- }
281
- this._label(ctx, this.label, point.x, point.y);
282
- }
283
- }
284
- else {
285
- var x, y;
286
- var radius = this.length / 4;
287
- var node = this.from;
288
- if (!node.width) {
289
- node.resize(ctx);
290
- }
291
- if (node.width > node.height) {
292
- x = node.x + node.width / 2;
293
- y = node.y - radius;
294
- }
295
- else {
296
- x = node.x + radius;
297
- y = node.y - node.height / 2;
298
- }
299
- this._circle(ctx, x, y, radius);
300
- point = this._pointOnCircle(x, y, radius, 0.5);
301
- this._label(ctx, this.label, point.x, point.y);
302
- }
303
- };
304
-
305
- /**
306
- * Get the line width of the edge. Depends on width and whether one of the
307
- * connected nodes is selected.
308
- * @return {Number} width
309
- * @private
310
- */
311
- Edge.prototype._getLineWidth = function() {
312
- if (this.selected == true) {
313
- return Math.min(this.width * 2, this.widthMax)*this.graphScaleInv;
314
- }
315
- else {
316
- if (this.hover == true) {
317
- return Math.min(this.hoverWidth, this.widthMax)*this.graphScaleInv;
318
- }
319
- else {
320
- return this.width*this.graphScaleInv;
321
- }
322
- }
323
- };
324
-
325
- /**
326
- * Draw a line between two nodes
327
- * @param {CanvasRenderingContext2D} ctx
328
- * @private
329
- */
330
- Edge.prototype._line = function (ctx) {
331
- // draw a straight line
332
- ctx.beginPath();
333
- ctx.moveTo(this.from.x, this.from.y);
334
- if (this.smooth == true) {
335
- ctx.quadraticCurveTo(this.via.x,this.via.y,this.to.x, this.to.y);
336
- }
337
- else {
338
- ctx.lineTo(this.to.x, this.to.y);
339
- }
340
- ctx.stroke();
341
- };
342
-
343
- /**
344
- * Draw a line from a node to itself, a circle
345
- * @param {CanvasRenderingContext2D} ctx
346
- * @param {Number} x
347
- * @param {Number} y
348
- * @param {Number} radius
349
- * @private
350
- */
351
- Edge.prototype._circle = function (ctx, x, y, radius) {
352
- // draw a circle
353
- ctx.beginPath();
354
- ctx.arc(x, y, radius, 0, 2 * Math.PI, false);
355
- ctx.stroke();
356
- };
357
-
358
- /**
359
- * Draw label with white background and with the middle at (x, y)
360
- * @param {CanvasRenderingContext2D} ctx
361
- * @param {String} text
362
- * @param {Number} x
363
- * @param {Number} y
364
- * @private
365
- */
366
- Edge.prototype._label = function (ctx, text, x, y) {
367
- if (text) {
368
- // TODO: cache the calculated size
369
- ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") +
370
- this.fontSize + "px " + this.fontFace;
371
- ctx.fillStyle = this.fontFill;
372
- var width = ctx.measureText(text).width;
373
- var height = this.fontSize;
374
- var left = x - width / 2;
375
- var top = y - height / 2;
376
-
377
- ctx.fillRect(left, top, width, height);
378
-
379
- // draw text
380
- ctx.fillStyle = this.fontColor || "black";
381
- ctx.textAlign = "left";
382
- ctx.textBaseline = "top";
383
- ctx.fillText(text, left, top);
384
- }
385
- };
386
-
387
- /**
388
- * Redraw a edge as a dashed line
389
- * Draw this edge in the given canvas
390
- * @author David Jordan
391
- * @date 2012-08-08
392
- * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
393
- * @param {CanvasRenderingContext2D} ctx
394
- * @private
395
- */
396
- Edge.prototype._drawDashLine = function(ctx) {
397
- // set style
398
- if (this.selected == true) {ctx.strokeStyle = this.color.highlight;}
399
- else if (this.hover == true) {ctx.strokeStyle = this.color.hover;}
400
- else {ctx.strokeStyle = this.color.color;}
401
-
402
- ctx.lineWidth = this._getLineWidth();
403
-
404
- // only firefox and chrome support this method, else we use the legacy one.
405
- if (ctx.mozDash !== undefined || ctx.setLineDash !== undefined) {
406
- ctx.beginPath();
407
- ctx.moveTo(this.from.x, this.from.y);
408
-
409
- // configure the dash pattern
410
- var pattern = [0];
411
- if (this.dash.length !== undefined && this.dash.gap !== undefined) {
412
- pattern = [this.dash.length,this.dash.gap];
413
- }
414
- else {
415
- pattern = [5,5];
416
- }
417
-
418
- // set dash settings for chrome or firefox
419
- if (typeof ctx.setLineDash !== 'undefined') { //Chrome
420
- ctx.setLineDash(pattern);
421
- ctx.lineDashOffset = 0;
422
-
423
- } else { //Firefox
424
- ctx.mozDash = pattern;
425
- ctx.mozDashOffset = 0;
426
- }
427
-
428
- // draw the line
429
- if (this.smooth == true) {
430
- ctx.quadraticCurveTo(this.via.x,this.via.y,this.to.x, this.to.y);
431
- }
432
- else {
433
- ctx.lineTo(this.to.x, this.to.y);
434
- }
435
- ctx.stroke();
436
-
437
- // restore the dash settings.
438
- if (typeof ctx.setLineDash !== 'undefined') { //Chrome
439
- ctx.setLineDash([0]);
440
- ctx.lineDashOffset = 0;
441
-
442
- } else { //Firefox
443
- ctx.mozDash = [0];
444
- ctx.mozDashOffset = 0;
445
- }
446
- }
447
- else { // unsupporting smooth lines
448
- // draw dashed line
449
- ctx.beginPath();
450
- ctx.lineCap = 'round';
451
- if (this.dash.altLength !== undefined) //If an alt dash value has been set add to the array this value
452
- {
453
- ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,
454
- [this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]);
455
- }
456
- 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
457
- {
458
- ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,
459
- [this.dash.length,this.dash.gap]);
460
- }
461
- else //If all else fails draw a line
462
- {
463
- ctx.moveTo(this.from.x, this.from.y);
464
- ctx.lineTo(this.to.x, this.to.y);
465
- }
466
- ctx.stroke();
467
- }
468
-
469
- // draw label
470
- if (this.label) {
471
- var point;
472
- if (this.smooth == true) {
473
- var midpointX = 0.5*(0.5*(this.from.x + this.via.x) + 0.5*(this.to.x + this.via.x));
474
- var midpointY = 0.5*(0.5*(this.from.y + this.via.y) + 0.5*(this.to.y + this.via.y));
475
- point = {x:midpointX, y:midpointY};
476
- }
477
- else {
478
- point = this._pointOnLine(0.5);
479
- }
480
- this._label(ctx, this.label, point.x, point.y);
481
- }
482
- };
483
-
484
- /**
485
- * Get a point on a line
486
- * @param {Number} percentage. Value between 0 (line start) and 1 (line end)
487
- * @return {Object} point
488
- * @private
489
- */
490
- Edge.prototype._pointOnLine = function (percentage) {
491
- return {
492
- x: (1 - percentage) * this.from.x + percentage * this.to.x,
493
- y: (1 - percentage) * this.from.y + percentage * this.to.y
494
- }
495
- };
496
-
497
- /**
498
- * Get a point on a circle
499
- * @param {Number} x
500
- * @param {Number} y
501
- * @param {Number} radius
502
- * @param {Number} percentage. Value between 0 (line start) and 1 (line end)
503
- * @return {Object} point
504
- * @private
505
- */
506
- Edge.prototype._pointOnCircle = function (x, y, radius, percentage) {
507
- var angle = (percentage - 3/8) * 2 * Math.PI;
508
- return {
509
- x: x + radius * Math.cos(angle),
510
- y: y - radius * Math.sin(angle)
511
- }
512
- };
513
-
514
- /**
515
- * Redraw a edge as a line with an arrow halfway the line
516
- * Draw this edge in the given canvas
517
- * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
518
- * @param {CanvasRenderingContext2D} ctx
519
- * @private
520
- */
521
- Edge.prototype._drawArrowCenter = function(ctx) {
522
- var point;
523
- // set style
524
- if (this.selected == true) {ctx.strokeStyle = this.color.highlight; ctx.fillStyle = this.color.highlight;}
525
- else if (this.hover == true) {ctx.strokeStyle = this.color.hover; ctx.fillStyle = this.color.hover;}
526
- else {ctx.strokeStyle = this.color.color; ctx.fillStyle = this.color.color;}
527
- ctx.lineWidth = this._getLineWidth();
528
-
529
- if (this.from != this.to) {
530
- // draw line
531
- this._line(ctx);
532
-
533
- var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x));
534
- var length = (10 + 5 * this.width) * this.arrowScaleFactor;
535
- // draw an arrow halfway the line
536
- if (this.smooth == true) {
537
- var midpointX = 0.5*(0.5*(this.from.x + this.via.x) + 0.5*(this.to.x + this.via.x));
538
- var midpointY = 0.5*(0.5*(this.from.y + this.via.y) + 0.5*(this.to.y + this.via.y));
539
- point = {x:midpointX, y:midpointY};
540
- }
541
- else {
542
- point = this._pointOnLine(0.5);
543
- }
544
-
545
- ctx.arrow(point.x, point.y, angle, length);
546
- ctx.fill();
547
- ctx.stroke();
548
-
549
- // draw label
550
- if (this.label) {
551
- this._label(ctx, this.label, point.x, point.y);
552
- }
553
- }
554
- else {
555
- // draw circle
556
- var x, y;
557
- var radius = 0.25 * Math.max(100,this.length);
558
- var node = this.from;
559
- if (!node.width) {
560
- node.resize(ctx);
561
- }
562
- if (node.width > node.height) {
563
- x = node.x + node.width * 0.5;
564
- y = node.y - radius;
565
- }
566
- else {
567
- x = node.x + radius;
568
- y = node.y - node.height * 0.5;
569
- }
570
- this._circle(ctx, x, y, radius);
571
-
572
- // draw all arrows
573
- var angle = 0.2 * Math.PI;
574
- var length = (10 + 5 * this.width) * this.arrowScaleFactor;
575
- point = this._pointOnCircle(x, y, radius, 0.5);
576
- ctx.arrow(point.x, point.y, angle, length);
577
- ctx.fill();
578
- ctx.stroke();
579
-
580
- // draw label
581
- if (this.label) {
582
- point = this._pointOnCircle(x, y, radius, 0.5);
583
- this._label(ctx, this.label, point.x, point.y);
584
- }
585
- }
586
- };
587
-
588
-
589
-
590
- /**
591
- * Redraw a edge as a line with an arrow
592
- * Draw this edge in the given canvas
593
- * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
594
- * @param {CanvasRenderingContext2D} ctx
595
- * @private
596
- */
597
- Edge.prototype._drawArrow = function(ctx) {
598
- // set style
599
- if (this.selected == true) {ctx.strokeStyle = this.color.highlight; ctx.fillStyle = this.color.highlight;}
600
- else if (this.hover == true) {ctx.strokeStyle = this.color.hover; ctx.fillStyle = this.color.hover;}
601
- else {ctx.strokeStyle = this.color.color; ctx.fillStyle = this.color.color;}
602
-
603
- ctx.lineWidth = this._getLineWidth();
604
-
605
- var angle, length;
606
- //draw a line
607
- if (this.from != this.to) {
608
- angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x));
609
- var dx = (this.to.x - this.from.x);
610
- var dy = (this.to.y - this.from.y);
611
- var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
612
-
613
- var fromBorderDist = this.from.distanceToBorder(ctx, angle + Math.PI);
614
- var fromBorderPoint = (edgeSegmentLength - fromBorderDist) / edgeSegmentLength;
615
- var xFrom = (fromBorderPoint) * this.from.x + (1 - fromBorderPoint) * this.to.x;
616
- var yFrom = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y;
617
-
618
-
619
- if (this.smooth == true) {
620
- angle = Math.atan2((this.to.y - this.via.y), (this.to.x - this.via.x));
621
- dx = (this.to.x - this.via.x);
622
- dy = (this.to.y - this.via.y);
623
- edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
624
- }
625
- var toBorderDist = this.to.distanceToBorder(ctx, angle);
626
- var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength;
627
-
628
- var xTo,yTo;
629
- if (this.smooth == true) {
630
- xTo = (1 - toBorderPoint) * this.via.x + toBorderPoint * this.to.x;
631
- yTo = (1 - toBorderPoint) * this.via.y + toBorderPoint * this.to.y;
632
- }
633
- else {
634
- xTo = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x;
635
- yTo = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y;
636
- }
637
-
638
- ctx.beginPath();
639
- ctx.moveTo(xFrom,yFrom);
640
- if (this.smooth == true) {
641
- ctx.quadraticCurveTo(this.via.x,this.via.y,xTo, yTo);
642
- }
643
- else {
644
- ctx.lineTo(xTo, yTo);
645
- }
646
- ctx.stroke();
647
-
648
- // draw arrow at the end of the line
649
- length = (10 + 5 * this.width) * this.arrowScaleFactor;
650
- ctx.arrow(xTo, yTo, angle, length);
651
- ctx.fill();
652
- ctx.stroke();
653
-
654
- // draw label
655
- if (this.label) {
656
- var point;
657
- if (this.smooth == true) {
658
- var midpointX = 0.5*(0.5*(this.from.x + this.via.x) + 0.5*(this.to.x + this.via.x));
659
- var midpointY = 0.5*(0.5*(this.from.y + this.via.y) + 0.5*(this.to.y + this.via.y));
660
- point = {x:midpointX, y:midpointY};
661
- }
662
- else {
663
- point = this._pointOnLine(0.5);
664
- }
665
- this._label(ctx, this.label, point.x, point.y);
666
- }
667
- }
668
- else {
669
- // draw circle
670
- var node = this.from;
671
- var x, y, arrow;
672
- var radius = 0.25 * Math.max(100,this.length);
673
- if (!node.width) {
674
- node.resize(ctx);
675
- }
676
- if (node.width > node.height) {
677
- x = node.x + node.width * 0.5;
678
- y = node.y - radius;
679
- arrow = {
680
- x: x,
681
- y: node.y,
682
- angle: 0.9 * Math.PI
683
- };
684
- }
685
- else {
686
- x = node.x + radius;
687
- y = node.y - node.height * 0.5;
688
- arrow = {
689
- x: node.x,
690
- y: y,
691
- angle: 0.6 * Math.PI
692
- };
693
- }
694
- ctx.beginPath();
695
- // TODO: similarly, for a line without arrows, draw to the border of the nodes instead of the center
696
- ctx.arc(x, y, radius, 0, 2 * Math.PI, false);
697
- ctx.stroke();
698
-
699
- // draw all arrows
700
- var length = (10 + 5 * this.width) * this.arrowScaleFactor;
701
- ctx.arrow(arrow.x, arrow.y, arrow.angle, length);
702
- ctx.fill();
703
- ctx.stroke();
704
-
705
- // draw label
706
- if (this.label) {
707
- point = this._pointOnCircle(x, y, radius, 0.5);
708
- this._label(ctx, this.label, point.x, point.y);
709
- }
710
- }
711
- };
712
-
713
-
714
-
715
- /**
716
- * Calculate the distance between a point (x3,y3) and a line segment from
717
- * (x1,y1) to (x2,y2).
718
- * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
719
- * @param {number} x1
720
- * @param {number} y1
721
- * @param {number} x2
722
- * @param {number} y2
723
- * @param {number} x3
724
- * @param {number} y3
725
- * @private
726
- */
727
- Edge.prototype._getDistanceToEdge = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point
728
- if (this.from != this.to) {
729
- if (this.smooth == true) {
730
- var minDistance = 1e9;
731
- var i,t,x,y,dx,dy;
732
- for (i = 0; i < 10; i++) {
733
- t = 0.1*i;
734
- x = Math.pow(1-t,2)*x1 + (2*t*(1 - t))*this.via.x + Math.pow(t,2)*x2;
735
- y = Math.pow(1-t,2)*y1 + (2*t*(1 - t))*this.via.y + Math.pow(t,2)*y2;
736
- dx = Math.abs(x3-x);
737
- dy = Math.abs(y3-y);
738
- minDistance = Math.min(minDistance,Math.sqrt(dx*dx + dy*dy));
739
- }
740
- return minDistance
741
- }
742
- else {
743
- var px = x2-x1,
744
- py = y2-y1,
745
- something = px*px + py*py,
746
- u = ((x3 - x1) * px + (y3 - y1) * py) / something;
747
-
748
- if (u > 1) {
749
- u = 1;
750
- }
751
- else if (u < 0) {
752
- u = 0;
753
- }
754
-
755
- var x = x1 + u * px,
756
- y = y1 + u * py,
757
- dx = x - x3,
758
- dy = y - y3;
759
-
760
- //# Note: If the actual distance does not matter,
761
- //# if you only want to compare what this function
762
- //# returns to other results of this function, you
763
- //# can just return the squared distance instead
764
- //# (i.e. remove the sqrt) to gain a little performance
765
-
766
- return Math.sqrt(dx*dx + dy*dy);
767
- }
768
- }
769
- else {
770
- var x, y, dx, dy;
771
- var radius = this.length / 4;
772
- var node = this.from;
773
- if (!node.width) {
774
- node.resize(ctx);
775
- }
776
- if (node.width > node.height) {
777
- x = node.x + node.width / 2;
778
- y = node.y - radius;
779
- }
780
- else {
781
- x = node.x + radius;
782
- y = node.y - node.height / 2;
783
- }
784
- dx = x - x3;
785
- dy = y - y3;
786
- return Math.abs(Math.sqrt(dx*dx + dy*dy) - radius);
787
- }
788
- };
789
-
790
-
791
-
792
- /**
793
- * This allows the zoom level of the graph to influence the rendering
794
- *
795
- * @param scale
796
- */
797
- Edge.prototype.setScale = function(scale) {
798
- this.graphScaleInv = 1.0/scale;
799
- };
800
-
801
-
802
- Edge.prototype.select = function() {
803
- this.selected = true;
804
- };
805
-
806
- Edge.prototype.unselect = function() {
807
- this.selected = false;
808
- };
809
-
810
- Edge.prototype.positionBezierNode = function() {
811
- if (this.via !== null) {
812
- this.via.x = 0.5 * (this.from.x + this.to.x);
813
- this.via.y = 0.5 * (this.from.y + this.to.y);
814
- }
815
- };
816
-
817
- /**
818
- * This function draws the control nodes for the manipulator. In order to enable this, only set the this.controlNodesEnabled to true.
819
- * @param ctx
820
- */
821
- Edge.prototype._drawControlNodes = function(ctx) {
822
- if (this.controlNodesEnabled == true) {
823
- if (this.controlNodes.from === null && this.controlNodes.to === null) {
824
- var nodeIdFrom = "edgeIdFrom:".concat(this.id);
825
- var nodeIdTo = "edgeIdTo:".concat(this.id);
826
- var constants = {
827
- nodes:{group:'', radius:8},
828
- physics:{damping:0},
829
- clustering: {maxNodeSizeIncrements: 0 ,nodeScaling: {width:0, height: 0, radius:0}}
830
- };
831
- this.controlNodes.from = new Node(
832
- {id:nodeIdFrom,
833
- shape:'dot',
834
- color:{background:'#ff4e00', border:'#3c3c3c', highlight: {background:'#07f968'}}
835
- },{},{},constants);
836
- this.controlNodes.to = new Node(
837
- {id:nodeIdTo,
838
- shape:'dot',
839
- color:{background:'#ff4e00', border:'#3c3c3c', highlight: {background:'#07f968'}}
840
- },{},{},constants);
841
- }
842
-
843
- if (this.controlNodes.from.selected == false && this.controlNodes.to.selected == false) {
844
- this.controlNodes.positions = this.getControlNodePositions(ctx);
845
- this.controlNodes.from.x = this.controlNodes.positions.from.x;
846
- this.controlNodes.from.y = this.controlNodes.positions.from.y;
847
- this.controlNodes.to.x = this.controlNodes.positions.to.x;
848
- this.controlNodes.to.y = this.controlNodes.positions.to.y;
849
- }
850
-
851
- this.controlNodes.from.draw(ctx);
852
- this.controlNodes.to.draw(ctx);
853
- }
854
- else {
855
- this.controlNodes = {from:null, to:null, positions:{}};
856
- }
857
- }
858
-
859
- /**
860
- * Enable control nodes.
861
- * @private
862
- */
863
- Edge.prototype._enableControlNodes = function() {
864
- this.controlNodesEnabled = true;
865
- }
866
-
867
- /**
868
- * disable control nodes
869
- * @private
870
- */
871
- Edge.prototype._disableControlNodes = function() {
872
- this.controlNodesEnabled = false;
873
- }
874
-
875
- /**
876
- * This checks if one of the control nodes is selected and if so, returns the control node object. Else it returns null.
877
- * @param x
878
- * @param y
879
- * @returns {null}
880
- * @private
881
- */
882
- Edge.prototype._getSelectedControlNode = function(x,y) {
883
- var positions = this.controlNodes.positions;
884
- var fromDistance = Math.sqrt(Math.pow(x - positions.from.x,2) + Math.pow(y - positions.from.y,2));
885
- var toDistance = Math.sqrt(Math.pow(x - positions.to.x ,2) + Math.pow(y - positions.to.y ,2));
886
-
887
- if (fromDistance < 15) {
888
- this.connectedNode = this.from;
889
- this.from = this.controlNodes.from;
890
- return this.controlNodes.from;
891
- }
892
- else if (toDistance < 15) {
893
- this.connectedNode = this.to;
894
- this.to = this.controlNodes.to;
895
- return this.controlNodes.to;
896
- }
897
- else {
898
- return null;
899
- }
900
- }
901
-
902
-
903
- /**
904
- * this resets the control nodes to their original position.
905
- * @private
906
- */
907
- Edge.prototype._restoreControlNodes = function() {
908
- if (this.controlNodes.from.selected == true) {
909
- this.from = this.connectedNode;
910
- this.connectedNode = null;
911
- this.controlNodes.from.unselect();
912
- }
913
- if (this.controlNodes.to.selected == true) {
914
- this.to = this.connectedNode;
915
- this.connectedNode = null;
916
- this.controlNodes.to.unselect();
917
- }
918
- }
919
-
920
- /**
921
- * this calculates the position of the control nodes on the edges of the parent nodes.
922
- *
923
- * @param ctx
924
- * @returns {{from: {x: number, y: number}, to: {x: *, y: *}}}
925
- */
926
- Edge.prototype.getControlNodePositions = function(ctx) {
927
- var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x));
928
- var dx = (this.to.x - this.from.x);
929
- var dy = (this.to.y - this.from.y);
930
- var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
931
- var fromBorderDist = this.from.distanceToBorder(ctx, angle + Math.PI);
932
- var fromBorderPoint = (edgeSegmentLength - fromBorderDist) / edgeSegmentLength;
933
- var xFrom = (fromBorderPoint) * this.from.x + (1 - fromBorderPoint) * this.to.x;
934
- var yFrom = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y;
935
-
936
-
937
- if (this.smooth == true) {
938
- angle = Math.atan2((this.to.y - this.via.y), (this.to.x - this.via.x));
939
- dx = (this.to.x - this.via.x);
940
- dy = (this.to.y - this.via.y);
941
- edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
942
- }
943
- var toBorderDist = this.to.distanceToBorder(ctx, angle);
944
- var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength;
945
-
946
- var xTo,yTo;
947
- if (this.smooth == true) {
948
- xTo = (1 - toBorderPoint) * this.via.x + toBorderPoint * this.to.x;
949
- yTo = (1 - toBorderPoint) * this.via.y + toBorderPoint * this.to.y;
950
- }
951
- else {
952
- xTo = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x;
953
- yTo = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y;
954
- }
955
-
956
- return {from:{x:xFrom,y:yFrom},to:{x:xTo,y:yTo}};
957
- }