vis-rails 2.0.0 → 2.0.1

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