vis-rails 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1ab2d5d6af664775072379c257129f02c0895707
4
- data.tar.gz: 49b0ee9bc14b7cbd5ee8ace9790af0793fd20dfb
3
+ metadata.gz: d28f18ffa726cedf2df18f07ed3f34a5881b8693
4
+ data.tar.gz: 716adb84278baadcd222bbecf802759ddd0a9eb2
5
5
  SHA512:
6
- metadata.gz: f24f212105db1437094cf354652456e0d4a20bbdfc25a0972a13b6d2148826ad4cec7510ea695f20fc313d05d54aa80eeb49c78542914b161e16ea886cdfa16d
7
- data.tar.gz: ed541ec0771e8ea6e3245e2860a08e7a5753316a12d9e84d243b3c6f6f1442ec0aabd02310977586b1a41a431a15fff141e39e6f4515ffdc16e58d675c7ffc41
6
+ metadata.gz: 90d77f98a4d5d2379703b87f96341180716d49e0e124bcc4d2fed368518255b5861863bf5efdd890ee8df7c98ecb753ccb89c40492928695959612cc1c0b38be
7
+ data.tar.gz: 56d1c95072854f202bda9c12dcd197cba4c005009b05cce79f4250d096da5c346ce488d0f6bbd2b01508591074fcdc45e4fa457be32490106400d1b0b68fcd09
@@ -1,5 +1,5 @@
1
1
  module Vis
2
2
  module Rails
3
- VERSION = "1.0.1"
3
+ VERSION = "1.0.2"
4
4
  end
5
5
  end
@@ -179,7 +179,9 @@ function Graph (container, data, options) {
179
179
  border: '#666',
180
180
  background: '#FFFFC6'
181
181
  }
182
- }
182
+ },
183
+ moveable: true,
184
+ zoomable: true
183
185
  };
184
186
  this.editMode = this.constants.dataManipulation.initiallyVisible;
185
187
 
@@ -211,8 +213,11 @@ function Graph (container, data, options) {
211
213
  this._loadHierarchySystem();
212
214
 
213
215
  // apply options
216
+ this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2);
217
+ this._setScale(1);
214
218
  this.setOptions(options);
215
219
 
220
+
216
221
  // other vars
217
222
  this.freezeSimulation = false;// freeze the simulation
218
223
  this.cachedFunctions = {};
@@ -490,15 +495,19 @@ Graph.prototype.setData = function(data, disableStart) {
490
495
  if (!disableStart) {
491
496
  // find a stable position or start animating to a stable position
492
497
  if (this.stabilize) {
493
- this._stabilize();
498
+ var me = this;
499
+ setTimeout(function() {me._stabilize(); me.start();},0)
500
+ }
501
+ else {
502
+ this.start();
494
503
  }
495
- this.start();
496
504
  }
497
505
  };
498
506
 
499
507
  /**
500
508
  * Set options
501
509
  * @param {Object} options
510
+ * @param {Boolean} [initializeView] | set zoom and translation to default.
502
511
  */
503
512
  Graph.prototype.setOptions = function (options) {
504
513
  if (options) {
@@ -512,7 +521,8 @@ Graph.prototype.setOptions = function (options) {
512
521
  if (options.freezeForStabilization !== undefined) {this.constants.freezeForStabilization = options.freezeForStabilization;}
513
522
  if (options.configurePhysics !== undefined){this.constants.configurePhysics = options.configurePhysics;}
514
523
  if (options.stabilizationIterations !== undefined) {this.constants.stabilizationIterations = options.stabilizationIterations;}
515
-
524
+ if (options.moveable !== undefined) {this.constants.moveable = options.moveable;}
525
+ if (options.zoomable !== undefined) {this.constants.zoomable = options.zoomable;}
516
526
 
517
527
 
518
528
  if (options.labels !== undefined) {
@@ -557,6 +567,17 @@ Graph.prototype.setOptions = function (options) {
557
567
  }
558
568
  }
559
569
  }
570
+
571
+ if (options.physics.hierarchicalRepulsion) {
572
+ this.constants.hierarchicalLayout.enabled = true;
573
+ this.constants.physics.hierarchicalRepulsion.enabled = true;
574
+ this.constants.physics.barnesHut.enabled = false;
575
+ for (prop in options.physics.hierarchicalRepulsion) {
576
+ if (options.physics.hierarchicalRepulsion.hasOwnProperty(prop)) {
577
+ this.constants.physics.hierarchicalRepulsion[prop] = options.physics.hierarchicalRepulsion[prop];
578
+ }
579
+ }
580
+ }
560
581
  }
561
582
 
562
583
  if (options.hierarchicalLayout) {
@@ -716,11 +737,10 @@ Graph.prototype.setOptions = function (options) {
716
737
 
717
738
  // bind keys. If disabled, this will not do anything;
718
739
  this._createKeyBinds();
719
-
720
740
  this.setSize(this.width, this.height);
721
- this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2);
722
- this._setScale(1);
723
- this._redraw();
741
+ this.moving = true;
742
+ this.start();
743
+
724
744
  };
725
745
 
726
746
  /**
@@ -936,11 +956,11 @@ Graph.prototype._handleOnDrag = function(event) {
936
956
  var node = s.node;
937
957
 
938
958
  if (!s.xFixed) {
939
- node.x = me._canvasToX(me._xToCanvas(s.x) + deltaX);
959
+ node.x = me._XconvertDOMtoCanvas(me._XconvertCanvasToDOM(s.x) + deltaX);
940
960
  }
941
961
 
942
962
  if (!s.yFixed) {
943
- node.y = me._canvasToY(me._yToCanvas(s.y) + deltaY);
963
+ node.y = me._YconvertDOMtoCanvas(me._YconvertCanvasToDOM(s.y) + deltaY);
944
964
  }
945
965
  });
946
966
 
@@ -951,15 +971,18 @@ Graph.prototype._handleOnDrag = function(event) {
951
971
  }
952
972
  }
953
973
  else {
954
- // move the graph
955
- var diffX = pointer.x - this.drag.pointer.x;
956
- var diffY = pointer.y - this.drag.pointer.y;
957
-
958
- this._setTranslation(
959
- this.drag.translation.x + diffX,
960
- this.drag.translation.y + diffY);
961
- this._redraw();
962
- this.moving = true;
974
+ if (this.constants.moveable == true) {
975
+ // move the graph
976
+ var diffX = pointer.x - this.drag.pointer.x;
977
+ var diffY = pointer.y - this.drag.pointer.y;
978
+
979
+ this._setTranslation(
980
+ this.drag.translation.x + diffX,
981
+ this.drag.translation.y + diffY);
982
+ this._redraw();
983
+ this.moving = true;
984
+ this.start();
985
+ }
963
986
  }
964
987
  };
965
988
 
@@ -1047,30 +1070,38 @@ Graph.prototype._onPinch = function (event) {
1047
1070
  * @private
1048
1071
  */
1049
1072
  Graph.prototype._zoom = function(scale, pointer) {
1050
- var scaleOld = this._getScale();
1051
- if (scale < 0.00001) {
1052
- scale = 0.00001;
1053
- }
1054
- if (scale > 10) {
1055
- scale = 10;
1056
- }
1057
- // + this.frame.canvas.clientHeight / 2
1058
- var translation = this._getTranslation();
1073
+ if (this.constants.zoomable == true) {
1074
+ var scaleOld = this._getScale();
1075
+ if (scale < 0.00001) {
1076
+ scale = 0.00001;
1077
+ }
1078
+ if (scale > 10) {
1079
+ scale = 10;
1080
+ }
1081
+ // + this.frame.canvas.clientHeight / 2
1082
+ var translation = this._getTranslation();
1059
1083
 
1060
- var scaleFrac = scale / scaleOld;
1061
- var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac;
1062
- var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac;
1084
+ var scaleFrac = scale / scaleOld;
1085
+ var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac;
1086
+ var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac;
1063
1087
 
1064
- this.areaCenter = {"x" : this._canvasToX(pointer.x),
1065
- "y" : this._canvasToY(pointer.y)};
1088
+ this.areaCenter = {"x" : this._XconvertDOMtoCanvas(pointer.x),
1089
+ "y" : this._YconvertDOMtoCanvas(pointer.y)};
1066
1090
 
1067
- this._setScale(scale);
1068
- this._setTranslation(tx, ty);
1069
- this.updateClustersDefault();
1070
- this._redraw();
1091
+ this._setScale(scale);
1092
+ this._setTranslation(tx, ty);
1093
+ this.updateClustersDefault();
1094
+ this._redraw();
1071
1095
 
1096
+ if (scaleOld < scale) {
1097
+ this.emit("zoom", {direction:"+"});
1098
+ }
1099
+ else {
1100
+ this.emit("zoom", {direction:"-"});
1101
+ }
1072
1102
 
1073
- return scale;
1103
+ return scale;
1104
+ }
1074
1105
  };
1075
1106
 
1076
1107
 
@@ -1156,10 +1187,10 @@ Graph.prototype._onMouseMoveTitle = function (event) {
1156
1187
  */
1157
1188
  Graph.prototype._checkShowPopup = function (pointer) {
1158
1189
  var obj = {
1159
- left: this._canvasToX(pointer.x),
1160
- top: this._canvasToY(pointer.y),
1161
- right: this._canvasToX(pointer.x),
1162
- bottom: this._canvasToY(pointer.y)
1190
+ left: this._XconvertDOMtoCanvas(pointer.x),
1191
+ top: this._YconvertDOMtoCanvas(pointer.y),
1192
+ right: this._XconvertDOMtoCanvas(pointer.x),
1193
+ bottom: this._YconvertDOMtoCanvas(pointer.y)
1163
1194
  };
1164
1195
 
1165
1196
  var id;
@@ -1623,12 +1654,12 @@ Graph.prototype._redraw = function() {
1623
1654
  ctx.scale(this.scale, this.scale);
1624
1655
 
1625
1656
  this.canvasTopLeft = {
1626
- "x": this._canvasToX(0),
1627
- "y": this._canvasToY(0)
1657
+ "x": this._XconvertDOMtoCanvas(0),
1658
+ "y": this._YconvertDOMtoCanvas(0)
1628
1659
  };
1629
1660
  this.canvasBottomRight = {
1630
- "x": this._canvasToX(this.frame.canvas.clientWidth),
1631
- "y": this._canvasToY(this.frame.canvas.clientHeight)
1661
+ "x": this._XconvertDOMtoCanvas(this.frame.canvas.clientWidth),
1662
+ "y": this._YconvertDOMtoCanvas(this.frame.canvas.clientHeight)
1632
1663
  };
1633
1664
 
1634
1665
  this._doInAllSectors("_drawAllSectorNodes",ctx);
@@ -1662,6 +1693,8 @@ Graph.prototype._setTranslation = function(offsetX, offsetY) {
1662
1693
  if (offsetY !== undefined) {
1663
1694
  this.translation.y = offsetY;
1664
1695
  }
1696
+
1697
+ this.emit('viewChanged');
1665
1698
  };
1666
1699
 
1667
1700
  /**
@@ -1695,45 +1728,70 @@ Graph.prototype._getScale = function() {
1695
1728
  };
1696
1729
 
1697
1730
  /**
1698
- * Convert a horizontal point on the HTML canvas to the x-value of the model
1731
+ * Convert the X coordinate in DOM-space (coordinate point in browser relative to the container div) to
1732
+ * the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
1699
1733
  * @param {number} x
1700
1734
  * @returns {number}
1701
1735
  * @private
1702
1736
  */
1703
- Graph.prototype._canvasToX = function(x) {
1737
+ Graph.prototype._XconvertDOMtoCanvas = function(x) {
1704
1738
  return (x - this.translation.x) / this.scale;
1705
1739
  };
1706
1740
 
1707
1741
  /**
1708
- * Convert an x-value in the model to a horizontal point on the HTML canvas
1742
+ * Convert the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
1743
+ * the X coordinate in DOM-space (coordinate point in browser relative to the container div)
1709
1744
  * @param {number} x
1710
1745
  * @returns {number}
1711
1746
  * @private
1712
1747
  */
1713
- Graph.prototype._xToCanvas = function(x) {
1748
+ Graph.prototype._XconvertCanvasToDOM = function(x) {
1714
1749
  return x * this.scale + this.translation.x;
1715
1750
  };
1716
1751
 
1717
1752
  /**
1718
- * Convert a vertical point on the HTML canvas to the y-value of the model
1753
+ * Convert the Y coordinate in DOM-space (coordinate point in browser relative to the container div) to
1754
+ * the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
1719
1755
  * @param {number} y
1720
1756
  * @returns {number}
1721
1757
  * @private
1722
1758
  */
1723
- Graph.prototype._canvasToY = function(y) {
1759
+ Graph.prototype._YconvertDOMtoCanvas = function(y) {
1724
1760
  return (y - this.translation.y) / this.scale;
1725
1761
  };
1726
1762
 
1727
1763
  /**
1728
- * Convert an y-value in the model to a vertical point on the HTML canvas
1764
+ * Convert the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
1765
+ * the Y coordinate in DOM-space (coordinate point in browser relative to the container div)
1729
1766
  * @param {number} y
1730
1767
  * @returns {number}
1731
1768
  * @private
1732
1769
  */
1733
- Graph.prototype._yToCanvas = function(y) {
1770
+ Graph.prototype._YconvertCanvasToDOM = function(y) {
1734
1771
  return y * this.scale + this.translation.y ;
1735
1772
  };
1736
1773
 
1774
+
1775
+ /**
1776
+ *
1777
+ * @param {object} pos = {x: number, y: number}
1778
+ * @returns {{x: number, y: number}}
1779
+ * @constructor
1780
+ */
1781
+ Graph.prototype.canvasToDOM = function(pos) {
1782
+ return {x:this._XconvertCanvasToDOM(pos.x),y:this._YconvertCanvasToDOM(pos.y)};
1783
+ }
1784
+
1785
+ /**
1786
+ *
1787
+ * @param {object} pos = {x: number, y: number}
1788
+ * @returns {{x: number, y: number}}
1789
+ * @constructor
1790
+ */
1791
+ Graph.prototype.DOMtoCanvas = function(pos) {
1792
+ return {x:this._XconvertDOMtoCanvas(pos.x),y:this._YconvertDOMtoCanvas(pos.y)};
1793
+ }
1794
+
1737
1795
  /**
1738
1796
  * Redraw all nodes
1739
1797
  * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d');
@@ -2,10 +2,10 @@
2
2
  * @class Groups
3
3
  * This class can store groups and properties specific for groups.
4
4
  */
5
- Groups = function () {
5
+ function Groups() {
6
6
  this.clear();
7
7
  this.defaultIndex = 0;
8
- };
8
+ }
9
9
 
10
10
 
11
11
  /**
@@ -2,11 +2,11 @@
2
2
  * @class Images
3
3
  * This class loads images and keeps them stored.
4
4
  */
5
- Images = function () {
5
+ function Images() {
6
6
  this.images = {};
7
7
 
8
8
  this.callback = undefined;
9
- };
9
+ }
10
10
 
11
11
  /**
12
12
  * Set an onload callback function. This will be called each time an image
@@ -243,10 +243,10 @@ var manipulationMixin = {
243
243
  this.cachedFunctions["_handleOnDrag"] = this._handleOnDrag;
244
244
  this._handleOnDrag = function(event) {
245
245
  var pointer = this._getPointer(event.gesture.center);
246
- this.sectors['support']['nodes']['targetNode'].x = this._canvasToX(pointer.x);
247
- this.sectors['support']['nodes']['targetNode'].y = this._canvasToY(pointer.y);
248
- this.sectors['support']['nodes']['targetViaNode'].x = 0.5 * (this._canvasToX(pointer.x) + this.edges['connectionEdge'].from.x);
249
- this.sectors['support']['nodes']['targetViaNode'].y = this._canvasToY(pointer.y);
246
+ this.sectors['support']['nodes']['targetNode'].x = this._XconvertDOMtoCanvas(pointer.x);
247
+ this.sectors['support']['nodes']['targetNode'].y = this._YconvertDOMtoCanvas(pointer.y);
248
+ this.sectors['support']['nodes']['targetViaNode'].x = 0.5 * (this._XconvertDOMtoCanvas(pointer.x) + this.edges['connectionEdge'].from.x);
249
+ this.sectors['support']['nodes']['targetViaNode'].y = this._YconvertDOMtoCanvas(pointer.y);
250
250
  };
251
251
 
252
252
  this.moving = true;
@@ -40,8 +40,8 @@ var SelectionMixin = {
40
40
  * @private
41
41
  */
42
42
  _pointerToPositionObject : function(pointer) {
43
- var x = this._canvasToX(pointer.x);
44
- var y = this._canvasToY(pointer.y);
43
+ var x = this._XconvertDOMtoCanvas(pointer.x);
44
+ var y = this._YconvertDOMtoCanvas(pointer.y);
45
45
 
46
46
  return {left: x,
47
47
  top: y,
@@ -433,8 +433,8 @@ var SelectionMixin = {
433
433
  var node = this._getNodeAt(pointer);
434
434
  if (node != null && node !== undefined) {
435
435
  // we reset the areaCenter here so the opening of the node will occur
436
- this.areaCenter = {"x" : this._canvasToX(pointer.x),
437
- "y" : this._canvasToY(pointer.y)};
436
+ this.areaCenter = {"x" : this._XconvertDOMtoCanvas(pointer.x),
437
+ "y" : this._YconvertDOMtoCanvas(pointer.y)};
438
438
  this.openCluster(node);
439
439
  }
440
440
  this.emit("doubleClick", this.getSelection());
@@ -188,7 +188,7 @@ var physicsMixin = {
188
188
  */
189
189
  _calculateSpringForces: function () {
190
190
  var edgeLength, edge, edgeId;
191
- var dx, dy, fx, fy, springForce, length;
191
+ var dx, dy, fx, fy, springForce, distance;
192
192
  var edges = this.edges;
193
193
 
194
194
  // forces caused by the edges, modelled as springs
@@ -204,13 +204,14 @@ var physicsMixin = {
204
204
 
205
205
  dx = (edge.from.x - edge.to.x);
206
206
  dy = (edge.from.y - edge.to.y);
207
- length = Math.sqrt(dx * dx + dy * dy);
207
+ distance = Math.sqrt(dx * dx + dy * dy);
208
208
 
209
- if (length == 0) {
210
- length = 0.01;
209
+ if (distance == 0) {
210
+ distance = 0.01;
211
211
  }
212
212
 
213
- springForce = this.constants.physics.springConstant * (edgeLength - length) / length;
213
+ // the 1/distance is so the fx and fy can be calculated without sine or cosine.
214
+ springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance;
214
215
 
215
216
  fx = dx * springForce;
216
217
  fy = dy * springForce;
@@ -272,17 +273,18 @@ var physicsMixin = {
272
273
  * @private
273
274
  */
274
275
  _calculateSpringForce: function (node1, node2, edgeLength) {
275
- var dx, dy, fx, fy, springForce, length;
276
+ var dx, dy, fx, fy, springForce, distance;
276
277
 
277
278
  dx = (node1.x - node2.x);
278
279
  dy = (node1.y - node2.y);
279
- length = Math.sqrt(dx * dx + dy * dy);
280
+ distance = Math.sqrt(dx * dx + dy * dy);
280
281
 
281
- if (length == 0) {
282
- length = 0.01;
282
+ if (distance == 0) {
283
+ distance = 0.01;
283
284
  }
284
285
 
285
- springForce = this.constants.physics.springConstant * (edgeLength - length) / length;
286
+ // the 1/distance is so the fx and fy can be calculated without sine or cosine.
287
+ springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance;
286
288
 
287
289
  fx = dx * springForce;
288
290
  fy = dy * springForce;
@@ -317,7 +319,7 @@ var physicsMixin = {
317
319
  '<table id="graph_BH_table" style="display:none">' +
318
320
  '<tr><td><b>Barnes Hut</b></td></tr>' +
319
321
  '<tr>' +
320
- '<td width="150px">gravitationalConstant</td><td>0</td><td><input type="range" min="500" max="20000" value="' + (-1 * this.constants.physics.barnesHut.gravitationalConstant) + '" step="25" style="width:300px" id="graph_BH_gc"></td><td width="50px">-20000</td><td><input value="' + (-1 * this.constants.physics.barnesHut.gravitationalConstant) + '" id="graph_BH_gc_value" style="width:60px"></td>' +
322
+ '<td width="150px">gravitationalConstant</td><td>0</td><td><input type="range" min="0" max="20000" value="' + (-1 * this.constants.physics.barnesHut.gravitationalConstant) + '" step="25" style="width:300px" id="graph_BH_gc"></td><td width="50px">-20000</td><td><input value="' + (-1 * this.constants.physics.barnesHut.gravitationalConstant) + '" id="graph_BH_gc_value" style="width:60px"></td>' +
321
323
  '</tr>' +
322
324
  '<tr>' +
323
325
  '<td width="150px">centralGravity</td><td>0</td><td><input type="range" min="0" max="3" value="' + this.constants.physics.barnesHut.centralGravity + '" step="0.05" style="width:300px" id="graph_BH_cg"></td><td>3</td><td><input value="' + this.constants.physics.barnesHut.centralGravity + '" id="graph_BH_cg_value" style="width:60px"></td>' +
@@ -641,10 +643,12 @@ function switchConfigurations () {
641
643
  this.constants.physics.barnesHut.enabled = false;
642
644
  }
643
645
  else if (radioButton == "H") {
644
- this.constants.hierarchicalLayout.enabled = true;
645
- this.constants.physics.hierarchicalRepulsion.enabled = true;
646
- this.constants.physics.barnesHut.enabled = false;
647
- this._setupHierarchicalLayout();
646
+ if (this.constants.hierarchicalLayout.enabled == false) {
647
+ this.constants.hierarchicalLayout.enabled = true;
648
+ this.constants.physics.hierarchicalRepulsion.enabled = true;
649
+ this.constants.physics.barnesHut.enabled = false;
650
+ this._setupHierarchicalLayout();
651
+ }
648
652
  }
649
653
  else {
650
654
  this.constants.hierarchicalLayout.enabled = false;
@@ -3,6 +3,7 @@
3
3
  */
4
4
  var vis = {
5
5
  util: util,
6
+ moment: moment,
6
7
 
7
8
  DataSet: DataSet,
8
9
  DataView: DataView,
@@ -24,7 +24,7 @@
24
24
  * @param {Date} [end] The end date
25
25
  * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds
26
26
  */
27
- TimeStep = function(start, end, minimumStep) {
27
+ function TimeStep(start, end, minimumStep) {
28
28
  // variables
29
29
  this.current = new Date();
30
30
  this._start = new Date();
@@ -36,7 +36,7 @@ TimeStep = function(start, end, minimumStep) {
36
36
 
37
37
  // initialize the range
38
38
  this.setRange(start, end, minimumStep);
39
- };
39
+ }
40
40
 
41
41
  /// enum scale
42
42
  TimeStep.SCALE = {
@@ -314,8 +314,7 @@ TimeStep.prototype.snap = function(date) {
314
314
  clone.setSeconds(0);
315
315
  clone.setMilliseconds(0);
316
316
  }
317
- else if (this.scale == TimeStep.SCALE.DAY ||
318
- this.scale == TimeStep.SCALE.WEEKDAY) {
317
+ else if (this.scale == TimeStep.SCALE.DAY) {
319
318
  //noinspection FallthroughInSwitchStatementJS
320
319
  switch (this.step) {
321
320
  case 5:
@@ -328,6 +327,19 @@ TimeStep.prototype.snap = function(date) {
328
327
  clone.setSeconds(0);
329
328
  clone.setMilliseconds(0);
330
329
  }
330
+ else if (this.scale == TimeStep.SCALE.WEEKDAY) {
331
+ //noinspection FallthroughInSwitchStatementJS
332
+ switch (this.step) {
333
+ case 5:
334
+ case 2:
335
+ clone.setHours(Math.round(clone.getHours() / 12) * 12); break;
336
+ default:
337
+ clone.setHours(Math.round(clone.getHours() / 6) * 6); break;
338
+ }
339
+ clone.setMinutes(0);
340
+ clone.setSeconds(0);
341
+ clone.setMilliseconds(0);
342
+ }
331
343
  else if (this.scale == TimeStep.SCALE.HOUR) {
332
344
  switch (this.step) {
333
345
  case 4:
@@ -11,7 +11,7 @@ function Timeline (container, items, options) {
11
11
 
12
12
  var me = this;
13
13
  var now = moment().hours(0).minutes(0).seconds(0).milliseconds(0);
14
- this.options = {
14
+ this.defaultOptions = {
15
15
  orientation: 'bottom',
16
16
  direction: 'horizontal', // 'horizontal' or 'vertical'
17
17
  autoResize: true,
@@ -25,7 +25,6 @@ function Timeline (container, items, options) {
25
25
  },
26
26
 
27
27
  selectable: true,
28
- snap: null, // will be specified after timeaxis is created
29
28
 
30
29
  min: null,
31
30
  max: null,
@@ -39,6 +38,13 @@ function Timeline (container, items, options) {
39
38
  showCurrentTime: false,
40
39
  showCustomTime: false,
41
40
 
41
+ groupOrder: null,
42
+
43
+ width: null,
44
+ height: null,
45
+ maxHeight: null,
46
+ minHeight: null,
47
+
42
48
  type: 'box',
43
49
  align: 'center',
44
50
  margin: {
@@ -58,11 +64,17 @@ function Timeline (container, items, options) {
58
64
  },
59
65
  onRemove: function (item, callback) {
60
66
  callback(item);
61
- },
67
+ }
68
+ };
69
+
70
+ this.options = {};
71
+ util.deepExtend(this.options, this.defaultOptions);
72
+ util.deepExtend(this.options, {
73
+ snap: null, // will be specified after timeaxis is created
62
74
 
63
75
  toScreen: me._toScreen.bind(me),
64
76
  toTime: me._toTime.bind(me)
65
- };
77
+ });
66
78
 
67
79
  // root panel
68
80
  var rootOptions = util.extend(Object.create(this.options), {
@@ -280,7 +292,7 @@ Emitter(Timeline.prototype);
280
292
  * @param {Object} options TODO: describe the available options
281
293
  */
282
294
  Timeline.prototype.setOptions = function (options) {
283
- util.extend(this.options, options);
295
+ util.deepExtend(this.options, options);
284
296
 
285
297
  if ('editable' in options) {
286
298
  var isBoolean = typeof options.editable === 'boolean';
@@ -439,6 +451,33 @@ Timeline.prototype.setGroups = function setGroups(groups) {
439
451
  this.itemSet.setGroups(newDataSet);
440
452
  };
441
453
 
454
+ /**
455
+ * Clear the Timeline. By Default, items, groups and options are cleared.
456
+ * Example usage:
457
+ *
458
+ * timeline.clear(); // clear items, groups, and options
459
+ * timeline.clear({options: true}); // clear options only
460
+ *
461
+ * @param {Object} [what] Optionally specify what to clear. By default:
462
+ * {items: true, groups: true, options: true}
463
+ */
464
+ Timeline.prototype.clear = function clear(what) {
465
+ // clear items
466
+ if (!what || what.items) {
467
+ this.setItems(null);
468
+ }
469
+
470
+ // clear groups
471
+ if (!what || what.groups) {
472
+ this.setGroups(null);
473
+ }
474
+
475
+ // clear options
476
+ if (!what || what.options) {
477
+ this.setOptions(this.defaultOptions);
478
+ }
479
+ };
480
+
442
481
  /**
443
482
  * Set Timeline window such that it fits all items
444
483
  */
@@ -535,7 +574,7 @@ Timeline.prototype.getSelection = function getSelection() {
535
574
  * Where start and end can be a Date, number, or string, and range is an
536
575
  * object with properties start and end.
537
576
  *
538
- * @param {Date | Number | String} [start] Start date of visible window
577
+ * @param {Date | Number | String | Object} [start] Start date of visible window
539
578
  * @param {Date | Number | String} [end] End date of visible window
540
579
  */
541
580
  Timeline.prototype.setWindow = function setWindow(start, end) {
@@ -560,6 +599,14 @@ Timeline.prototype.getWindow = function setWindow() {
560
599
  };
561
600
  };
562
601
 
602
+ /**
603
+ * Force a repaint of the Timeline. Can be useful to manually repaint when
604
+ * option autoResize=false
605
+ */
606
+ Timeline.prototype.repaint = function repaint() {
607
+ this.rootPanel.repaint();
608
+ };
609
+
563
610
  /**
564
611
  * Handle selecting/deselecting an item when tapping it
565
612
  * @param {Event} event
@@ -626,6 +673,11 @@ Timeline.prototype._onAddItem = function (event) {
626
673
  content: 'new item'
627
674
  };
628
675
 
676
+ // when default type is a range, add a default end date to the new item
677
+ if (this.options.type === 'range' || this.options.type == 'rangeoverflow') {
678
+ newItem.end = this.timeAxis.snap(this._toTime(x + this.rootPanel.width / 5));
679
+ }
680
+
629
681
  var id = util.randomUUID();
630
682
  newItem[this.itemsData.fieldId] = id;
631
683
 
@@ -51,6 +51,14 @@ Group.prototype._create = function() {
51
51
  this.dom.background = document.createElement('div');
52
52
 
53
53
  this.dom.axis = document.createElement('div');
54
+
55
+ // create a hidden marker to detect when the Timelines container is attached
56
+ // to the DOM, or the style of a parent of the Timeline is changed from
57
+ // display:none is changed to visible.
58
+ this.dom.marker = document.createElement('div');
59
+ this.dom.marker.style.visibility = 'hidden';
60
+ this.dom.marker.innerHTML = '?';
61
+ this.dom.background.appendChild(this.dom.marker);
54
62
  };
55
63
 
56
64
  /**
@@ -122,6 +130,20 @@ Group.prototype.repaint = function repaint(range, margin, restack) {
122
130
 
123
131
  this.visibleItems = this._updateVisibleItems(this.orderedItems, this.visibleItems, range);
124
132
 
133
+ // force recalculation of the height of the items when the marker height changed
134
+ // (due to the Timeline being attached to the DOM or changed from display:none to visible)
135
+ var markerHeight = this.dom.marker.clientHeight;
136
+ if (markerHeight != this.lastMarkerHeight) {
137
+ this.lastMarkerHeight = markerHeight;
138
+
139
+ util.forEach(this.items, function (item) {
140
+ item.dirty = true;
141
+ if (item.displayed) item.repaint();
142
+ });
143
+
144
+ restack = true;
145
+ }
146
+
125
147
  // reposition visible items vertically
126
148
  if (this.itemSet.options.stack) { // TODO: ugly way to access options...
127
149
  stack.stack(this.visibleItems, margin, restack);
@@ -129,7 +151,6 @@ Group.prototype.repaint = function repaint(range, margin, restack) {
129
151
  else { // no stacking
130
152
  stack.nostack(this.visibleItems, margin);
131
153
  }
132
- this.stackDirty = false;
133
154
  for (var i = 0, ii = this.visibleItems.length; i < ii; i++) {
134
155
  var item = this.visibleItems[i];
135
156
  item.repositionY();
@@ -519,7 +519,8 @@ ItemSet.prototype.setGroups = function setGroups(groups) {
519
519
 
520
520
  // remove all drawn groups
521
521
  ids = this.groupsData.getIds();
522
- this._onRemoveGroups(ids);
522
+ this.groupsData = null;
523
+ this._onRemoveGroups(ids); // note: this will cause a repaint
523
524
  }
524
525
 
525
526
  // replace the dataset
@@ -770,8 +771,7 @@ ItemSet.prototype._orderGroups = function () {
770
771
  // hide all groups, removes them from the DOM
771
772
  var groups = this.groups;
772
773
  groupIds.forEach(function (groupId) {
773
- var group = groups[groupId];
774
- group.hide();
774
+ groups[groupId].hide();
775
775
  });
776
776
 
777
777
  // show the groups again, attach them to the DOM in correct order
@@ -813,7 +813,9 @@ ItemSet.prototype._updateItem = function _updateItem(item, itemData) {
813
813
  var oldGroupId = item.data.group;
814
814
 
815
815
  item.data = itemData;
816
- item.repaint();
816
+ if (item.displayed) {
817
+ item.repaint();
818
+ }
817
819
 
818
820
  // update group
819
821
  if (oldGroupId != item.data.group) {
@@ -101,6 +101,7 @@ RootPanel.prototype.repaint = function repaint() {
101
101
 
102
102
  // update frame size
103
103
  this.frame.style.maxHeight = util.option.asSize(this.options.maxHeight, '');
104
+ this.frame.style.minHeight = util.option.asSize(this.options.minHeight, '');
104
105
  this._updateSize();
105
106
 
106
107
  // if the root panel or any of its childs is resized, repaint again,
@@ -407,32 +407,32 @@ TimeAxis.prototype._repaintLine = function() {
407
407
  * @private
408
408
  */
409
409
  TimeAxis.prototype._calculateCharSize = function () {
410
- // determine the char width and height on the minor axis
411
- if (!('minorCharHeight' in this.props)) {
412
- var textMinor = document.createTextNode('0');
413
- var measureCharMinor = document.createElement('DIV');
414
- measureCharMinor.className = 'text minor measure';
415
- measureCharMinor.appendChild(textMinor);
416
- this.frame.appendChild(measureCharMinor);
410
+ // Note: We calculate char size with every repaint. Size may change, for
411
+ // example when any of the timelines parents had display:none for example.
417
412
 
418
- this.props.minorCharHeight = measureCharMinor.clientHeight;
419
- this.props.minorCharWidth = measureCharMinor.clientWidth;
413
+ // determine the char width and height on the minor axis
414
+ if (!this.dom.measureCharMinor) {
415
+ this.dom.measureCharMinor = document.createElement('DIV');
416
+ this.dom.measureCharMinor.className = 'text minor measure';
417
+ this.dom.measureCharMinor.style.position = 'absolute';
420
418
 
421
- this.frame.removeChild(measureCharMinor);
419
+ this.dom.measureCharMinor.appendChild(document.createTextNode('0'));
420
+ this.frame.appendChild(this.dom.measureCharMinor);
422
421
  }
422
+ this.props.minorCharHeight = this.dom.measureCharMinor.clientHeight;
423
+ this.props.minorCharWidth = this.dom.measureCharMinor.clientWidth;
423
424
 
424
- if (!('majorCharHeight' in this.props)) {
425
- var textMajor = document.createTextNode('0');
426
- var measureCharMajor = document.createElement('DIV');
427
- measureCharMajor.className = 'text major measure';
428
- measureCharMajor.appendChild(textMajor);
429
- this.frame.appendChild(measureCharMajor);
430
-
431
- this.props.majorCharHeight = measureCharMajor.clientHeight;
432
- this.props.majorCharWidth = measureCharMajor.clientWidth;
425
+ // determine the char width and height on the major axis
426
+ if (!this.dom.measureCharMajor) {
427
+ this.dom.measureCharMajor = document.createElement('DIV');
428
+ this.dom.measureCharMajor.className = 'text minor measure';
429
+ this.dom.measureCharMajor.style.position = 'absolute';
433
430
 
434
- this.frame.removeChild(measureCharMajor);
431
+ this.dom.measureCharMajor.appendChild(document.createTextNode('0'));
432
+ this.frame.appendChild(this.dom.measureCharMajor);
435
433
  }
434
+ this.props.majorCharHeight = this.dom.measureCharMajor.clientHeight;
435
+ this.props.majorCharWidth = this.dom.measureCharMajor.clientWidth;
436
436
  };
437
437
 
438
438
  /**
@@ -46,9 +46,10 @@ ItemRangeOverflow.prototype.repositionX = function repositionX() {
46
46
 
47
47
  this.left = start;
48
48
  var boxWidth = Math.max(end - start, 1);
49
- this.width = (this.props.content.width < boxWidth) ?
50
- boxWidth :
51
- start + contentLeft + this.props.content.width;
49
+ this.width = boxWidth + this.props.content.width;
50
+ // Note: The calculation of width is an optimistic calculation, giving
51
+ // a width which will not change when moving the Timeline
52
+ // So no restacking needed, which is nicer for the eye
52
53
 
53
54
  this.dom.box.style.left = this.left + 'px';
54
55
  this.dom.box.style.width = boxWidth + 'px';
@@ -97,6 +97,40 @@ util.extend = function (a, b) {
97
97
  return a;
98
98
  };
99
99
 
100
+ /**
101
+ * Deep extend an object a with the properties of object b
102
+ * @param {Object} a
103
+ * @param {Object} b
104
+ * @returns {Object}
105
+ */
106
+ util.deepExtend = function deepExtend (a, b) {
107
+ // TODO: add support for Arrays to deepExtend
108
+ if (Array.isArray(b)) {
109
+ throw new TypeError('Arrays are not supported by deepExtend');
110
+ }
111
+
112
+ for (var prop in b) {
113
+ if (b.hasOwnProperty(prop)) {
114
+ if (b[prop] && b[prop].constructor === Object) {
115
+ if (a[prop] === undefined) {
116
+ a[prop] = {};
117
+ }
118
+ if (a[prop].constructor === Object) {
119
+ deepExtend(a[prop], b[prop]);
120
+ }
121
+ else {
122
+ a[prop] = b[prop];
123
+ }
124
+ } else if (Array.isArray(b[prop])) {
125
+ throw new TypeError('Arrays are not supported by deepExtend');
126
+ } else {
127
+ a[prop] = b[prop];
128
+ }
129
+ }
130
+ }
131
+ return a;
132
+ };
133
+
100
134
  /**
101
135
  * Test whether all elements in two arrays are equal.
102
136
  * @param {Array} a
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vis-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - AlexVangelov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-03 00:00:00.000000000 Z
11
+ date: 2014-06-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: momentjs-rails