vis.js is a dynamic, browser-based visualization library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

287 lines
8.4 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. var Emitter = require('emitter-component');
  2. var Hammer = require('../module/hammer');
  3. var util = require('../util');
  4. var DataSet = require('../DataSet');
  5. var DataView = require('../DataView');
  6. var Range = require('./Range');
  7. var Core = require('./Core');
  8. var TimeAxis = require('./component/TimeAxis');
  9. var CurrentTime = require('./component/CurrentTime');
  10. var CustomTime = require('./component/CustomTime');
  11. var LineGraph = require('./component/LineGraph');
  12. /**
  13. * Create a timeline visualization
  14. * @param {HTMLElement} container
  15. * @param {vis.DataSet | Array | google.visualization.DataTable} [items]
  16. * @param {Object} [options] See Graph2d.setOptions for the available options.
  17. * @constructor
  18. */
  19. function Graph2d (container, items, options, groups) {
  20. for (var coreProp in Core.prototype) {
  21. if (Core.prototype.hasOwnProperty(coreProp) && !Graph2d.prototype.hasOwnProperty(coreProp)) {
  22. Graph2d.prototype[coreProp] = Core.prototype[coreProp];
  23. }
  24. }
  25. var me = this;
  26. this.defaultOptions = {
  27. start: null,
  28. end: null,
  29. autoResize: true,
  30. orientation: 'bottom',
  31. width: null,
  32. height: null,
  33. maxHeight: null,
  34. minHeight: null
  35. };
  36. this.options = util.deepExtend({}, this.defaultOptions);
  37. // Create the DOM, props, and emitter
  38. this._create(container);
  39. // all components listed here will be repainted automatically
  40. this.components = [];
  41. this.body = {
  42. dom: this.dom,
  43. domProps: this.props,
  44. emitter: {
  45. on: this.on.bind(this),
  46. off: this.off.bind(this),
  47. emit: this.emit.bind(this)
  48. },
  49. util: {
  50. snap: null, // will be specified after TimeAxis is created
  51. toScreen: me._toScreen.bind(me),
  52. toGlobalScreen: me._toGlobalScreen.bind(me), // this refers to the root.width
  53. toTime: me._toTime.bind(me),
  54. toGlobalTime : me._toGlobalTime.bind(me)
  55. }
  56. };
  57. // range
  58. this.range = new Range(this.body);
  59. this.components.push(this.range);
  60. this.body.range = this.range;
  61. // time axis
  62. this.timeAxis = new TimeAxis(this.body);
  63. this.components.push(this.timeAxis);
  64. this.body.util.snap = this.timeAxis.snap.bind(this.timeAxis);
  65. // current time bar
  66. this.currentTime = new CurrentTime(this.body);
  67. this.components.push(this.currentTime);
  68. // custom time bar
  69. // Note: time bar will be attached in this.setOptions when selected
  70. this.customTime = new CustomTime(this.body);
  71. this.components.push(this.customTime);
  72. // item set
  73. this.linegraph = new LineGraph(this.body);
  74. this.components.push(this.linegraph);
  75. this.itemsData = null; // DataSet
  76. this.groupsData = null; // DataSet
  77. // apply options
  78. if (options) {
  79. this.setOptions(options);
  80. }
  81. // IMPORTANT: THIS HAPPENS BEFORE SET ITEMS!
  82. if (groups) {
  83. this.setGroups(groups);
  84. }
  85. // create itemset
  86. if (items) {
  87. this.setItems(items);
  88. }
  89. else {
  90. this.redraw();
  91. }
  92. }
  93. /**
  94. * Set options. Options will be passed to all components loaded in the Graph2d.
  95. * @param {Object} [options]
  96. * {String} orientation
  97. * Vertical orientation for the Graph2d,
  98. * can be 'bottom' (default) or 'top'.
  99. * {String | Number} width
  100. * Width for the timeline, a number in pixels or
  101. * a css string like '1000px' or '75%'. '100%' by default.
  102. * {String | Number} height
  103. * Fixed height for the Graph2d, a number in pixels or
  104. * a css string like '400px' or '75%'. If undefined,
  105. * The Graph2d will automatically size such that
  106. * its contents fit.
  107. * {String | Number} minHeight
  108. * Minimum height for the Graph2d, a number in pixels or
  109. * a css string like '400px' or '75%'.
  110. * {String | Number} maxHeight
  111. * Maximum height for the Graph2d, a number in pixels or
  112. * a css string like '400px' or '75%'.
  113. * {Number | Date | String} start
  114. * Start date for the visible window
  115. * {Number | Date | String} end
  116. * End date for the visible window
  117. */
  118. Graph2d.prototype.setOptions = function (options) {
  119. if (options) {
  120. // copy the known options
  121. var fields = ['width', 'height', 'minHeight', 'maxHeight', 'autoResize', 'start', 'end', 'orientation'];
  122. util.selectiveExtend(fields, this.options, options);
  123. // enable/disable autoResize
  124. this._initAutoResize();
  125. }
  126. // propagate options to all components
  127. this.components.forEach(function (component) {
  128. component.setOptions(options);
  129. });
  130. // TODO: remove deprecation error one day (deprecated since version 0.8.0)
  131. if (options && options.order) {
  132. throw new Error('Option order is deprecated. There is no replacement for this feature.');
  133. }
  134. // redraw everything
  135. this.redraw();
  136. };
  137. /**
  138. * Set items
  139. * @param {vis.DataSet | Array | google.visualization.DataTable | null} items
  140. */
  141. Graph2d.prototype.setItems = function(items) {
  142. var initialLoad = (this.itemsData == null);
  143. // convert to type DataSet when needed
  144. var newDataSet;
  145. if (!items) {
  146. newDataSet = null;
  147. }
  148. else if (items instanceof DataSet || items instanceof DataView) {
  149. newDataSet = items;
  150. }
  151. else {
  152. // turn an array into a dataset
  153. newDataSet = new DataSet(items, {
  154. type: {
  155. start: 'Date',
  156. end: 'Date'
  157. }
  158. });
  159. }
  160. // set items
  161. this.itemsData = newDataSet;
  162. this.linegraph && this.linegraph.setItems(newDataSet);
  163. if (initialLoad && ('start' in this.options || 'end' in this.options)) {
  164. this.fit();
  165. var start = ('start' in this.options) ? util.convert(this.options.start, 'Date') : null;
  166. var end = ('end' in this.options) ? util.convert(this.options.end, 'Date') : null;
  167. this.setWindow(start, end);
  168. }
  169. };
  170. /**
  171. * Set groups
  172. * @param {vis.DataSet | Array | google.visualization.DataTable} groups
  173. */
  174. Graph2d.prototype.setGroups = function(groups) {
  175. // convert to type DataSet when needed
  176. var newDataSet;
  177. if (!groups) {
  178. newDataSet = null;
  179. }
  180. else if (groups instanceof DataSet || groups instanceof DataView) {
  181. newDataSet = groups;
  182. }
  183. else {
  184. // turn an array into a dataset
  185. newDataSet = new DataSet(groups);
  186. }
  187. this.groupsData = newDataSet;
  188. this.linegraph.setGroups(newDataSet);
  189. };
  190. /**
  191. * Returns an object containing an SVG element with the icon of the group (size determined by iconWidth and iconHeight), the label of the group (content) and the yAxisOrientation of the group (left or right).
  192. * @param groupId
  193. * @param width
  194. * @param height
  195. */
  196. Graph2d.prototype.getLegend = function(groupId, width, height) {
  197. if (width === undefined) {width = 15;}
  198. if (height === undefined) {height = 15;}
  199. if (this.linegraph.groups[groupId] !== undefined) {
  200. return this.linegraph.groups[groupId].getLegend(width,height);
  201. }
  202. else {
  203. return "cannot find group:" + groupId;
  204. }
  205. }
  206. /**
  207. * This checks if the visible option of the supplied group (by ID) is true or false.
  208. * @param groupId
  209. * @returns {*}
  210. */
  211. Graph2d.prototype.isGroupVisible = function(groupId) {
  212. if (this.linegraph.groups[groupId] !== undefined) {
  213. return this.linegraph.groups[groupId].visible;
  214. }
  215. else {
  216. return false;
  217. }
  218. }
  219. /**
  220. * Get the data range of the item set.
  221. * @returns {{min: Date, max: Date}} range A range with a start and end Date.
  222. * When no minimum is found, min==null
  223. * When no maximum is found, max==null
  224. */
  225. Graph2d.prototype.getItemRange = function() {
  226. // calculate min from start filed
  227. var dataset = this.itemsData.getDataSet(),
  228. min = null,
  229. max = null;
  230. if (dataset) {
  231. // calculate the minimum value of the field 'start'
  232. var minItem = dataset.min('x');
  233. min = minItem ? util.convert(minItem.x, 'Date').valueOf() : null;
  234. // Note: we convert first to Date and then to number because else
  235. // a conversion from ISODate to Number will fail
  236. // calculate maximum value of fields 'start' and 'end'
  237. var maxStartItem = dataset.max('x');
  238. if (maxStartItem) {
  239. max = util.convert(maxStartItem.x, 'Date').valueOf();
  240. }
  241. }
  242. return {
  243. min: (min != null) ? new Date(min) : null,
  244. max: (max != null) ? new Date(max) : null
  245. };
  246. };
  247. module.exports = Graph2d;