diff --git a/HISTORY.md b/HISTORY.md index f000c549..86ed9a20 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -21,6 +21,7 @@ http://visjs.org See example 18_range_overflow.html. - Fixed invalid css names for time axis grid, renamed hours class names from `4-8h` to `h4-h8`. +- Deprecated option `showCustomTime`. Use method `addCustomTime()` instead. ### Network diff --git a/docs/timeline.html b/docs/timeline.html index 822f8b48..ddde9db9 100644 --- a/docs/timeline.html +++ b/docs/timeline.html @@ -720,13 +720,6 @@ var options = { Show a vertical bar at the current time. - - showCustomTime - boolean - false - Show a vertical bar displaying a custom time. This line can be dragged by the user. The custom time can be utilized to show a state in the past or in the future. When the custom time bar is dragged by the user, the event timechange is fired repeatedly. After the bar is dragged, the event timechanged is fired once. - - showMajorLabels @@ -864,12 +857,13 @@ var options = { - addCustomTime(time[, id]) + addCustomTime([time] [, id]) Number | String - Only applicable when the option showCustomTime is true.
- Add new vertical bar representing custom time that can be dragged by the user. Parameter time can be a Date, Number, or String. Parameter id can be Number or String. If id is provided, it will be used as ID for the new vertical bar, otherwise the ID will be auto generated.
- Returns ID of the newly created bar. + Add new vertical bar representing a custom time that can be dragged by the user. + Parameter time can be a Date, Number, or String, and is new Date() by default. + Parameter id can be Number or String and is undefined by default.
+ Returns id of the created bar. @@ -911,7 +905,7 @@ var options = { getCustomTime([id]) Date - Retrieve the custom time. Only applicable when the option showCustomTime is true. If parameter id is provided, time of the custom time bar under that ID is returned. + Retrieve the custom time from the custom time bar with given id. Id is undefined by default. @@ -1003,7 +997,9 @@ var options = { setCustomTime(time [, id]) none - Adjust the custom time bar. Only applicable when the option showCustomTime is true. Parameter time can be a Date object, numeric timestamp, or ISO date string. Parameter id represents ID of the custom time bar, provided by addCustomTime method and can be a Number or String. + Adjust the time of a custom time bar. + Parameter time can be a Date object, numeric timestamp, or ISO date string. + Parameter id is the idof the custom time bar, and is undefined by default. @@ -1197,8 +1193,8 @@ timeline.off('select', onSelect); @@ -1210,8 +1206,8 @@ timeline.off('select', onSelect); diff --git a/examples/timeline/07_custom_time_bar.html b/examples/timeline/07_custom_time_bar.html deleted file mode 100644 index bc7adba3..00000000 --- a/examples/timeline/07_custom_time_bar.html +++ /dev/null @@ -1,65 +0,0 @@ - - - - Timeline | Show current and custom time bars - - - - - - - - -

- - -

-

- - -

-

- timechange event: -

-

- timechanged event: -

- -
- - - - \ No newline at end of file diff --git a/examples/timeline/34_add_custom_timebar.html b/examples/timeline/07_custom_time_bars.html similarity index 91% rename from examples/timeline/34_add_custom_timebar.html rename to examples/timeline/07_custom_time_bars.html index c2286035..3d3d6032 100644 --- a/examples/timeline/34_add_custom_timebar.html +++ b/examples/timeline/07_custom_time_bars.html @@ -38,7 +38,6 @@ var customDate = new Date(); var options = { showCurrentTime: true, - showCustomTime: true, start: new Date(Date.now() - 1000 * 60 * 60 * 24), end: new Date(Date.now() + 1000 * 60 * 60 * 24 * 6) }; @@ -46,7 +45,7 @@ // Set first time bar customDate = new Date(customDate.getFullYear(), customDate.getMonth(), customDate.getDate() + 1); - timeline.addCustomTime(customDate, 1); + timeline.addCustomTime(customDate, '1'); document.getElementById('add').onclick = function () { customDate = new Date(customDate.getFullYear(), customDate.getMonth(), customDate.getDate() + 1); @@ -56,8 +55,14 @@ }; document.getElementById('remove').onclick = function () { - timeline.removeCustomTime(document.getElementById('barIndex').value); - document.getElementById('barIndex').value = ''; + try { + timeline.removeCustomTime(document.getElementById('barIndex').value); + document.getElementById('barIndex').value = ''; + } + catch (err) { + console.log(err); + alert(err); + } }; timeline.on('timechange', function (properties) { diff --git a/examples/timeline/13_past_and_future.html b/examples/timeline/13_past_and_future.html index 4087406c..87cff2e0 100644 --- a/examples/timeline/13_past_and_future.html +++ b/examples/timeline/13_past_and_future.html @@ -44,14 +44,15 @@ // specify options var options = { - showCurrentTime: true, - showCustomTime: true + showCurrentTime: true }; // create a timeline var container = document.getElementById('mytimeline'); timeline = new vis.Timeline(container, data, options); + timeline.addCustomTime(new Date()); + // add event listener timeline.on('timechange', function (event) { document.getElementById("customTime").innerHTML = "Custom Time: " + event.time; diff --git a/examples/timeline/19_localization.html b/examples/timeline/19_localization.html index 751a1341..6e9552a5 100644 --- a/examples/timeline/19_localization.html +++ b/examples/timeline/19_localization.html @@ -43,12 +43,12 @@ // Configuration for the Timeline var options = { - showCurrentTime: true, - showCustomTime: true + showCurrentTime: true }; // Create a Timeline var timeline = new vis.Timeline(container, items, options); + timeline.addCustomTime(new Date()); timeline.setCustomTime(new Date(new Date().valueOf() + DAY)); diff --git a/examples/timeline/29_hiding_times.html b/examples/timeline/29_hiding_times.html index 0b0e209f..e378ccbc 100644 --- a/examples/timeline/29_hiding_times.html +++ b/examples/timeline/29_hiding_times.html @@ -38,13 +38,12 @@ start: '2014-04-17', end: '2014-05-01', height: '200px', - editable: true, - showCustomTime: true + editable: true }; // Create a Timeline var timeline = new vis.Timeline(container, items, options); - timeline.setCustomTime("2014-04-18 13:00:00"); + timeline.addCustomTime("2014-04-18 13:00:00"); \ No newline at end of file diff --git a/examples/timeline/index.html b/examples/timeline/index.html index ece375ed..48e71c8a 100644 --- a/examples/timeline/index.html +++ b/examples/timeline/index.html @@ -18,7 +18,7 @@

04_html_data.html

05_groups.html

06_event_listeners.html

-

07_custom_time_bar.html

+

07_custom_time_bars.html

08_edit_items.html

09_order_groups.html

10_limit_range_and_zoom.html

@@ -44,7 +44,6 @@

31_background_areas_with_groups.html

32_grid_styling.html

33_custom_snapping.html

-

34_add_custom_timebar.html

35_item_ordering.html

requirejs_example.html

diff --git a/lib/timeline/Core.js b/lib/timeline/Core.js index 2d25fb4e..adc9aac5 100644 --- a/lib/timeline/Core.js +++ b/lib/timeline/Core.js @@ -173,6 +173,8 @@ Core.prototype._create = function (container) { scrollTopMin: 0 }; + this.customTimes = []; + // store state information needed for touch events this.touch = {}; @@ -263,6 +265,10 @@ Core.prototype.setOptions = function (options) { } } + if ('showCustomTime' in options) { + throw new Error('Option `showCustomTime` is deprecated. Create a custom time bar via timeline.addCustomTime(time [, id])'); + } + // enable/disable autoResize this._initAutoResize(); } @@ -327,102 +333,70 @@ Core.prototype.destroy = function () { /** * Set a custom time bar * @param {Date} time - * @param {int} id + * @param {number} [id=undefined] Optional id of the custom time bar to be adjusted. */ Core.prototype.setCustomTime = function (time, id) { - if (!this.customTime) { - throw new Error('Cannot get custom time: Custom time bar is not enabled'); - } + var customTimes = this.customTimes.filter(function (component) { + return id === component.options.id; + }); - var barId = id || 0; + if (customTimes.length === 0) { + throw new Error('No custom time bar found with id ' + JSON.stringify(id)) + } - this.components.forEach(function (element, index, components) { - if (element instanceof CustomTime && element.options.id === barId) { - element.setCustomTime(time); - } - }); + if (customTimes.length > 0) { + customTimes[0].setCustomTime(time); + } }; /** * Retrieve the current custom time. - * @return {Date} customTime - * @param {int} id + * @param {number} [id=undefined] Id of the custom time bar. + * @return {Date | undefined} customTime */ Core.prototype.getCustomTime = function(id) { - if (!this.customTime) { - throw new Error('Cannot get custom time: Custom time bar is not enabled'); - } - - var barId = id || 0, - customTime = this.customTime.getCustomTime(); - - this.components.forEach(function (element, index, components) { - if (element instanceof CustomTime && element.options.id === barId) { - customTime = element.getCustomTime(); - } + var customTimes = this.customTimes.filter(function (component) { + return component.options.id === id; }); - return customTime; + if (customTimes.length === 0) { + throw new Error('No custom time bar found with id ' + JSON.stringify(id)) + } + return customTimes[0].getCustomTime(); }; /** * Add custom vertical bar - * @param {Date | String | Number} time A Date, unix timestamp, or - * ISO date string. Time point where the new bar should be placed - * @param {Number | String} ID of the new bar - * @return {Number | String} ID of the new bar + * @param {Date | String | Number} [time] A Date, unix timestamp, or + * ISO date string. Time point where + * the new bar should be placed. + * If not provided, `new Date()` will + * be used. + * @param {Number | String} [id=undefined] Id of the new bar. Optional + * @return {Number | String} Returns the id of the new bar */ Core.prototype.addCustomTime = function (time, id) { - if (!this.currentTime) { - throw new Error('Option showCurrentTime must be true'); - } + var timestamp = time !== undefined + ? util.convert(time, 'Date').valueOf() + : new Date(); - if (time === undefined) { - throw new Error('Time parameter for the custom bar must be provided'); - } - - var ts = util.convert(time, 'Date').valueOf(), - numIds, customTime, customBarId; - - // All bar IDs are kept in 1 array, mixed types - // Bar with ID 0 is the default bar. - if (!this.customBarIds || this.customBarIds.constructor !== Array) { - this.customBarIds = [0]; - } - - // If the ID is not provided, generate one, otherwise just use it - if (id === undefined) { - - numIds = this.customBarIds.filter(function (element) { - return util.isNumber(element); - }); - - customBarId = numIds.length > 0 ? Math.max.apply(null, numIds) + 1 : 1; - - } else { - - // Check for duplicates - this.customBarIds.forEach(function (element) { - if (element === id) { - throw new Error('Custom time ID already exists'); - } - }); - - customBarId = id; + var exists = this.customTimes.some(function (customTime) { + return customTime.options.id === id; + }); + if (exists) { + throw new Error('A custom time with id ' + JSON.stringify(id) + ' already exists'); } - this.customBarIds.push(customBarId); - - customTime = new CustomTime(this.body, { - showCustomTime : true, - time : ts, - id : customBarId + var customTime = new CustomTime(this.body, { + time : timestamp, + id : id }); + this.customTimes.push(customTime); this.components.push(customTime); this.redraw(); - return customBarId; + return id; }; /** @@ -431,19 +405,19 @@ Core.prototype.addCustomTime = function (time, id) { * @return {boolean} True if the bar exists and is removed, false otherwise */ Core.prototype.removeCustomTime = function (id) { + var customTimes = this.customTimes.filter(function (bar) { + return (bar.options.id === id); + }); - var me = this; + if (customTimes.length === 0) { + throw new Error('No custom time bar found with id ' + JSON.stringify(id)) + } - this.components.forEach(function (bar, index, components) { - if (bar instanceof CustomTime && bar.options.id === id) { - // Only the lines added by the user will be removed - if (bar.options.id !== 0) { - me.customBarIds.splice(me.customBarIds.indexOf(id), 1); - components.splice(index, 1); - bar.destroy(); - } - } - }); + customTimes.forEach(function (customTime) { + this.customTimes.splice(this.customTimes.indexOf(customTime), 1); + this.components.splice(this.components.indexOf(customTime), 1); + customTime.destroy(); + }.bind(this)) }; diff --git a/lib/timeline/Graph2d.js b/lib/timeline/Graph2d.js index 3f8fd7cf..a3cc4aff 100644 --- a/lib/timeline/Graph2d.js +++ b/lib/timeline/Graph2d.js @@ -78,11 +78,6 @@ function Graph2d (container, items, groups, options) { this.currentTime = new CurrentTime(this.body); this.components.push(this.currentTime); - // custom time bar - // Note: time bar will be attached in this.setOptions when selected - this.customTime = new CustomTime(this.body); - this.components.push(this.customTime); - // item set this.linegraph = new LineGraph(this.body); this.components.push(this.linegraph); @@ -270,7 +265,7 @@ Graph2d.prototype.getEventProperties = function (event) { else if (util.hasParent(element, this.linegraph.yAxisRight.dom.frame)) {what = 'data-axis';} else if (util.hasParent(element, this.linegraph.legendLeft.dom.frame)) {what = 'legend';} else if (util.hasParent(element, this.linegraph.legendRight.dom.frame)) {what = 'legend';} - else if (util.hasParent(element, this.customTime.bar)) {what = 'custom-time';} // TODO: fix for multiple custom time bars + else if (CustomTime.customTimeFromTarget(event) != null) {what = 'custom-time';} else if (util.hasParent(element, this.currentTime.bar)) {what = 'current-time';} else if (util.hasParent(element, this.dom.center)) {what = 'background';} diff --git a/lib/timeline/Timeline.js b/lib/timeline/Timeline.js index 7843710d..292cbe0c 100644 --- a/lib/timeline/Timeline.js +++ b/lib/timeline/Timeline.js @@ -90,11 +90,6 @@ function Timeline (container, items, groups, options) { this.currentTime = new CurrentTime(this.body); this.components.push(this.currentTime); - // custom time bar - // Note: time bar will be attached in this.setOptions when selected - this.customTime = new CustomTime(this.body); - this.components.push(this.customTime); - // item set this.itemSet = new ItemSet(this.body); this.components.push(this.itemSet); @@ -362,7 +357,7 @@ Timeline.prototype.getEventProperties = function (event) { else if (util.hasParent(element, this.timeAxis.dom.foreground)) {what = 'axis';} else if (this.timeAxis2 && util.hasParent(element, this.timeAxis2.dom.foreground)) {what = 'axis';} else if (util.hasParent(element, this.itemSet.dom.labelSet)) {what = 'group-label';} - else if (util.hasParent(element, this.customTime.bar)) {what = 'custom-time';} // TODO: fix for multiple custom time bars + else if (CustomTime.customTimeFromTarget(event) != null) {what = 'custom-time';} else if (util.hasParent(element, this.currentTime.bar)) {what = 'current-time';} else if (util.hasParent(element, this.dom.center)) {what = 'background';} diff --git a/lib/timeline/component/CustomTime.js b/lib/timeline/component/CustomTime.js index 722d594f..8efdb8ca 100644 --- a/lib/timeline/component/CustomTime.js +++ b/lib/timeline/component/CustomTime.js @@ -8,7 +8,9 @@ var locales = require('../locales'); * A custom time bar * @param {{range: Range, dom: Object}} body * @param {Object} [options] Available parameters: - * {Boolean} [showCustomTime] + * {number | string} id + * {string} locales + * {string} locale * @constructor CustomTime * @extends Component */ @@ -18,10 +20,9 @@ function CustomTime (body, options) { // default options this.defaultOptions = { - showCustomTime: false, locales: locales, locale: 'en', - id: 0 + id: undefined }; this.options = util.extend({}, this.defaultOptions); @@ -44,17 +45,14 @@ CustomTime.prototype = new Component(); /** * Set options for the component. Options will be merged in current options. * @param {Object} options Available parameters: - * {boolean} [showCustomTime] + * {number | string} id + * {string} locales + * {string} locale */ CustomTime.prototype.setOptions = function(options) { if (options) { // copy all options that we know - util.selectiveExtend(['showCustomTime', 'locale', 'locales', 'id'], this.options, options); - - // Triggered by addCustomTimeBar, redraw to add new bar - if (this.options.id) { - this.redraw(); - } + util.selectiveExtend(['locale', 'locales', 'id'], this.options, options); } }; @@ -64,6 +62,7 @@ CustomTime.prototype.setOptions = function(options) { */ CustomTime.prototype._create = function() { var bar = document.createElement('div'); + bar['custom-time'] = this; bar.className = 'vis-custom-time'; bar.style.position = 'absolute'; bar.style.top = '0px'; @@ -93,10 +92,9 @@ CustomTime.prototype._create = function() { * Destroy the CustomTime bar */ CustomTime.prototype.destroy = function () { - this.options.showCustomTime = false; - this.redraw(); // will remove the bar from the DOM + this.hide(); - this.hammer.enable(false); + this.hammer.destroy(); this.hammer = null; this.body = null; @@ -107,42 +105,44 @@ CustomTime.prototype.destroy = function () { * @return {boolean} Returns true if the component is resized */ CustomTime.prototype.redraw = function () { - if (this.options.showCustomTime) { - var parent = this.body.dom.backgroundVertical; - if (this.bar.parentNode != parent) { - // attach to the dom - if (this.bar.parentNode) { - this.bar.parentNode.removeChild(this.bar); - } - parent.appendChild(this.bar); + var parent = this.body.dom.backgroundVertical; + if (this.bar.parentNode != parent) { + // attach to the dom + if (this.bar.parentNode) { + this.bar.parentNode.removeChild(this.bar); } + parent.appendChild(this.bar); + } - var x = this.body.util.toScreen(this.customTime); - - var locale = this.options.locales[this.options.locale]; - if (!locale) { - if (!this.warned) { - console.log('WARNING: options.locales[\'' + this.options.locale + '\'] not found. See http://visjs.org/docs/timeline.html#Localization'); - this.warned = true; - } - locale = this.options.locales['en']; // fall back on english when not available - } - var title = locale.time + ': ' + moment(this.customTime).format('dddd, MMMM Do YYYY, H:mm:ss'); - title = title.charAt(0).toUpperCase() + title.substring(1); + var x = this.body.util.toScreen(this.customTime); - this.bar.style.left = x + 'px'; - this.bar.title = title; - } - else { - // remove the line from the DOM - if (this.bar.parentNode) { - this.bar.parentNode.removeChild(this.bar); + var locale = this.options.locales[this.options.locale]; + if (!locale) { + if (!this.warned) { + console.log('WARNING: options.locales[\'' + this.options.locale + '\'] not found. See http://visjs.org/docs/timeline.html#Localization'); + this.warned = true; } + locale = this.options.locales['en']; // fall back on english when not available } + var title = locale.time + ': ' + moment(this.customTime).format('dddd, MMMM Do YYYY, H:mm:ss'); + title = title.charAt(0).toUpperCase() + title.substring(1); + + this.bar.style.left = x + 'px'; + this.bar.title = title; return false; }; +/** + * Remove the CustomTime from the DOM + */ +CustomTime.prototype.hide = function () { + // remove the line from the DOM + if (this.bar.parentNode) { + this.bar.parentNode.removeChild(this.bar); + } +}; + /** * Set custom time. * @param {Date | number | string} time @@ -211,4 +211,22 @@ CustomTime.prototype._onDragEnd = function (event) { event.stopPropagation(); }; +/** + * Find a custom time from an event target: + * searches for the attribute 'custom-time' in the event target's element tree + * @param {Event} event + * @return {CustomTime | null} customTime + */ +CustomTime.customTimeFromTarget = function(event) { + var target = event.target; + while (target) { + if (target.hasOwnProperty('custom-time')) { + return target['custom-time']; + } + target = target.parentNode; + } + + return null; +}; + module.exports = CustomTime; diff --git a/lib/timeline/locales.js b/lib/timeline/locales.js index 436aaecc..fade73eb 100644 --- a/lib/timeline/locales.js +++ b/lib/timeline/locales.js @@ -8,7 +8,7 @@ exports['en_US'] = exports['en']; // Dutch exports['nl'] = { - current: 'aangepaste', + current: 'huidige', time: 'tijd' }; exports['nl_NL'] = exports['nl']; diff --git a/test/timeline.html b/test/timeline.html index add85cdd..bc6769cb 100644 --- a/test/timeline.html +++ b/test/timeline.html @@ -150,7 +150,6 @@ //maxHeight: 200, //height: 200, showCurrentTime: true, - showCustomTime: true, format: { minorLabels: { 'weekday': 'dddd D', @@ -178,6 +177,8 @@ var timeline = new vis.Timeline(container, items, options); console.timeEnd('create timeline'); + timeline.addCustomTime(moment().add(1, 'day')); + timeline.on('select', function (selection) { console.log('select', selection); });