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.

265 lines
6.5 KiB

  1. var Hammer = require('../../module/hammer');
  2. var util = require('../../util');
  3. var Component = require('./Component');
  4. var moment = require('../../module/moment');
  5. var locales = require('../locales');
  6. /**
  7. * A custom time bar
  8. * @param {{range: Range, dom: Object}} body
  9. * @param {Object} [options] Available parameters:
  10. * {number | string} id
  11. * {string} locales
  12. * {string} locale
  13. * @constructor CustomTime
  14. * @extends Component
  15. */
  16. function CustomTime (body, options) {
  17. this.body = body;
  18. // default options
  19. this.defaultOptions = {
  20. moment: moment,
  21. locales: locales,
  22. locale: 'en',
  23. id: undefined,
  24. title: undefined
  25. };
  26. this.options = util.extend({}, this.defaultOptions);
  27. if (options && options.time) {
  28. this.customTime = options.time;
  29. } else {
  30. this.customTime = new Date();
  31. }
  32. this.eventParams = {}; // stores state parameters while dragging the bar
  33. this.setOptions(options);
  34. // create the DOM
  35. this._create();
  36. }
  37. CustomTime.prototype = new Component();
  38. /**
  39. * Set options for the component. Options will be merged in current options.
  40. * @param {Object} options Available parameters:
  41. * {number | string} id
  42. * {string} locales
  43. * {string} locale
  44. */
  45. CustomTime.prototype.setOptions = function(options) {
  46. if (options) {
  47. // copy all options that we know
  48. util.selectiveExtend(['moment', 'locale', 'locales', 'id'], this.options, options);
  49. }
  50. };
  51. /**
  52. * Create the DOM for the custom time
  53. * @private
  54. */
  55. CustomTime.prototype._create = function() {
  56. var bar = document.createElement('div');
  57. bar['custom-time'] = this;
  58. bar.className = 'vis-custom-time ' + (this.options.id || '');
  59. bar.style.position = 'absolute';
  60. bar.style.top = '0px';
  61. bar.style.height = '100%';
  62. this.bar = bar;
  63. var drag = document.createElement('div');
  64. drag.style.position = 'relative';
  65. drag.style.top = '0px';
  66. drag.style.left = '-10px';
  67. drag.style.height = '100%';
  68. drag.style.width = '20px';
  69. /**
  70. *
  71. * @param {WheelEvent} e
  72. */
  73. function onMouseWheel (e) {
  74. this.body.range._onMouseWheel(e);
  75. }
  76. if (drag.addEventListener) {
  77. // IE9, Chrome, Safari, Opera
  78. drag.addEventListener("mousewheel", onMouseWheel.bind(this), false);
  79. // Firefox
  80. drag.addEventListener("DOMMouseScroll", onMouseWheel.bind(this), false);
  81. } else {
  82. // IE 6/7/8
  83. drag.attachEvent("onmousewheel", onMouseWheel.bind(this));
  84. }
  85. bar.appendChild(drag);
  86. // attach event listeners
  87. this.hammer = new Hammer(drag);
  88. this.hammer.on('panstart', this._onDragStart.bind(this));
  89. this.hammer.on('panmove', this._onDrag.bind(this));
  90. this.hammer.on('panend', this._onDragEnd.bind(this));
  91. this.hammer.get('pan').set({threshold:5, direction: Hammer.DIRECTION_HORIZONTAL});
  92. };
  93. /**
  94. * Destroy the CustomTime bar
  95. */
  96. CustomTime.prototype.destroy = function () {
  97. this.hide();
  98. this.hammer.destroy();
  99. this.hammer = null;
  100. this.body = null;
  101. };
  102. /**
  103. * Repaint the component
  104. * @return {boolean} Returns true if the component is resized
  105. */
  106. CustomTime.prototype.redraw = function () {
  107. var parent = this.body.dom.backgroundVertical;
  108. if (this.bar.parentNode != parent) {
  109. // attach to the dom
  110. if (this.bar.parentNode) {
  111. this.bar.parentNode.removeChild(this.bar);
  112. }
  113. parent.appendChild(this.bar);
  114. }
  115. var x = this.body.util.toScreen(this.customTime);
  116. var locale = this.options.locales[this.options.locale];
  117. if (!locale) {
  118. if (!this.warned) {
  119. console.log('WARNING: options.locales[\'' + this.options.locale + '\'] not found. See http://visjs.org/docs/timeline/#Localization');
  120. this.warned = true;
  121. }
  122. locale = this.options.locales['en']; // fall back on english when not available
  123. }
  124. var title = this.options.title;
  125. // To hide the title completely use empty string ''.
  126. if (title === undefined) {
  127. title = locale.time + ': ' + this.options.moment(this.customTime).format('dddd, MMMM Do YYYY, H:mm:ss');
  128. title = title.charAt(0).toUpperCase() + title.substring(1);
  129. } else if (typeof title === "function") {
  130. title = title.call(this.customTime);
  131. }
  132. this.bar.style.left = x + 'px';
  133. this.bar.title = title;
  134. return false;
  135. };
  136. /**
  137. * Remove the CustomTime from the DOM
  138. */
  139. CustomTime.prototype.hide = function () {
  140. // remove the line from the DOM
  141. if (this.bar.parentNode) {
  142. this.bar.parentNode.removeChild(this.bar);
  143. }
  144. };
  145. /**
  146. * Set custom time.
  147. * @param {Date | number | string} time
  148. */
  149. CustomTime.prototype.setCustomTime = function(time) {
  150. this.customTime = util.convert(time, 'Date');
  151. this.redraw();
  152. };
  153. /**
  154. * Retrieve the current custom time.
  155. * @return {Date} customTime
  156. */
  157. CustomTime.prototype.getCustomTime = function() {
  158. return new Date(this.customTime.valueOf());
  159. };
  160. /**
  161. * Set custom title.
  162. * @param {Date | number | string} title
  163. */
  164. CustomTime.prototype.setCustomTitle = function(title) {
  165. this.options.title = title;
  166. };
  167. /**
  168. * Start moving horizontally
  169. * @param {Event} event
  170. * @private
  171. */
  172. CustomTime.prototype._onDragStart = function(event) {
  173. this.eventParams.dragging = true;
  174. this.eventParams.customTime = this.customTime;
  175. event.stopPropagation();
  176. };
  177. /**
  178. * Perform moving operating.
  179. * @param {Event} event
  180. * @private
  181. */
  182. CustomTime.prototype._onDrag = function (event) {
  183. if (!this.eventParams.dragging) return;
  184. var x = this.body.util.toScreen(this.eventParams.customTime) + event.deltaX;
  185. var time = this.body.util.toTime(x);
  186. this.setCustomTime(time);
  187. // fire a timechange event
  188. this.body.emitter.emit('timechange', {
  189. id: this.options.id,
  190. time: new Date(this.customTime.valueOf()),
  191. event: event
  192. });
  193. event.stopPropagation();
  194. };
  195. /**
  196. * Stop moving operating.
  197. * @param {Event} event
  198. * @private
  199. */
  200. CustomTime.prototype._onDragEnd = function (event) {
  201. if (!this.eventParams.dragging) return;
  202. // fire a timechanged event
  203. this.body.emitter.emit('timechanged', {
  204. id: this.options.id,
  205. time: new Date(this.customTime.valueOf()),
  206. event: event
  207. });
  208. event.stopPropagation();
  209. };
  210. /**
  211. * Find a custom time from an event target:
  212. * searches for the attribute 'custom-time' in the event target's element tree
  213. * @param {Event} event
  214. * @return {CustomTime | null} customTime
  215. */
  216. CustomTime.customTimeFromTarget = function(event) {
  217. var target = event.target;
  218. while (target) {
  219. if (target.hasOwnProperty('custom-time')) {
  220. return target['custom-time'];
  221. }
  222. target = target.parentNode;
  223. }
  224. return null;
  225. };
  226. module.exports = CustomTime;