Browse Source

Merge remote-tracking branch 'origin/v4' into v4

flowchartTest
Alex de Mulder 9 years ago
parent
commit
fd13122212
14 changed files with 291 additions and 32 deletions
  1. +1
    -1
      HISTORY.md
  2. +7
    -0
      docs/timeline/index.html
  3. +12
    -3
      lib/timeline/Core.js
  4. +3
    -3
      lib/timeline/TimeStep.js
  5. +36
    -3
      lib/timeline/Timeline.js
  6. +9
    -7
      lib/timeline/component/ItemSet.js
  7. +13
    -9
      lib/timeline/component/TimeAxis.js
  8. +1
    -1
      lib/timeline/component/item/BackgroundItem.js
  9. +1
    -1
      lib/timeline/component/item/BoxItem.js
  10. +2
    -2
      lib/timeline/component/item/PointItem.js
  11. +2
    -2
      lib/timeline/component/item/RangeItem.js
  12. +201
    -0
      lib/timeline/options.js
  13. +2
    -0
      test/timeline.html
  14. +1
    -0
      test/timeline_groups.html

+ 1
- 1
HISTORY.md View File

@ -11,9 +11,9 @@ http://visjs.org
When creating a custom bundle using browserify, one now needs to add a
transform step using `6to5ify`, this is described in README.md.
### Timeline
- Integrated an option configurator and validator.
- Implemented option `multiselect`, which is false by default.
- Added method `setData({groups: groups, items: items})`.
- Fixed range items not being displayed smaller than 10 pixels (twice the

+ 7
- 0
docs/timeline/index.html View File

@ -477,6 +477,13 @@ var options = {
When active, a blue shadow border is displayed around the Timeline. The Timeline is set active by clicking on it, and is changed to inactive again by clicking outside the Timeline or by pressing the ESC key.</td>
</tr>
<tr>
<td>configure</td>
<td class="mid">boolean</td>
<td class="mid"><code>false</code></td>
<td>When true, a configurator is loaded where all configuration options of the Timeline can be changed live.</td>
</tr>
<tr>
<td>dataAttributes</td>
<td class="mid">string[] or 'all'</string></td>

+ 12
- 3
lib/timeline/Core.js View File

@ -13,9 +13,6 @@ var CustomTime = require('./component/CustomTime');
/**
* Create a timeline visualization
* @param {HTMLElement} container
* @param {vis.DataSet | Array} [items]
* @param {Object} [options] See Core.setOptions for the available options.
* @constructor
*/
function Core () {}
@ -284,6 +281,18 @@ Core.prototype.setOptions = function (options) {
// propagate options to all components
this.components.forEach(component => component.setOptions(options));
// enable/disable configure
if (this.configurationSystem) {
this.configurationSystem.setOptions(options.configure);
// collect the settings of all components, and pass them to the configuration system
var appliedOptions = util.deepExtend({}, this.options);
this.components.forEach(function (component) {
util.deepExtend(appliedOptions, component.options);
});
this.configurationSystem.setModuleOptions({global: appliedOptions});
}
// redraw everything
this._redraw();
};

+ 3
- 3
lib/timeline/TimeStep.js View File

@ -80,7 +80,7 @@ TimeStep.FORMAT = {
/**
* Set custom formatting for the minor an major labels of the TimeStep.
* Both `minorLabels` and `majorLabels` are an Object with properties:
* 'millisecond, 'second, 'minute', 'hour', 'weekday, 'day, 'month, 'year'.
* 'millisecond', 'second', 'minute', 'hour', 'weekday', 'day', 'month', 'year'.
* @param {{minorLabels: Object, majorLabels: Object}} format
*/
TimeStep.prototype.setFormat = function (format) {
@ -246,7 +246,7 @@ TimeStep.prototype.getCurrent = function() {
* @param {{scale: string, step: number}} params
* An object containing two properties:
* - A string 'scale'. Choose from 'millisecond', 'second',
* 'minute', 'hour', 'weekday, 'day, 'month, 'year'.
* 'minute', 'hour', 'weekday', 'day', 'month', 'year'.
* - A number 'step'. A step size, by default 1.
* Choose for example 1, 2, 5, or 10.
*/
@ -324,7 +324,7 @@ TimeStep.prototype.setMinimumStep = function(minimumStep) {
* Static function
* @param {Date} date the date to be snapped.
* @param {string} scale Current scale, can be 'millisecond', 'second',
* 'minute', 'hour', 'weekday, 'day, 'month, 'year'.
* 'minute', 'hour', 'weekday, 'day', 'month', 'year'.
* @param {number} step Current step (1, 2, 4, 5, ...
* @return {Date} snappedDate
*/

+ 36
- 3
lib/timeline/Timeline.js View File

@ -10,6 +10,12 @@ var CurrentTime = require('./component/CurrentTime');
var CustomTime = require('./component/CustomTime');
var ItemSet = require('./component/ItemSet');
var ConfigurationSystem = require('../network/modules/ConfigurationSystem');
var Validator = require('../network/modules/Validator').default;
var printStyle = require('../network/modules/Validator').printStyle;
var allOptions = require('./options').allOptions;
var configureOptions = require('./options').configureOptions;
/**
* Create a timeline visualization
* @param {HTMLElement} container
@ -111,6 +117,9 @@ function Timeline (container, items, groups, options) {
me.emit('contextmenu', me.getEventProperties(event))
};
// setup configuration system
this.configurationSystem = new ConfigurationSystem(this, container, configureOptions);
// apply options
if (options) {
this.setOptions(options);
@ -143,6 +152,30 @@ Timeline.prototype.redraw = function() {
this._redraw();
};
Timeline.prototype.setOptions = function (options) {
// validate options
let errorFound = Validator.validate(options, allOptions);
if (errorFound === true) {
options = {};
console.log('%cErrors have been found in the supplied options object. None of the options will be used.', printStyle);
}
Core.prototype.setOptions.call(this, options);
if ('type' in options) {
if (options.type !== this.options.type) {
this.options.type = options.type;
// force recreation of all items
var itemsData = this.itemsData;
if (itemsData) {
this.setItems(null); // remove all
this.setItems(itemsData); // add all
}
}
}
};
/**
* Set items
* @param {vis.DataSet | Array | null} items
@ -317,9 +350,9 @@ Timeline.prototype.focus = function(id, options) {
*/
Timeline.prototype.getItemRange = function() {
// calculate min from start filed
var dataset = this.itemsData.getDataSet(),
min = null,
max = null;
var dataset = this.itemsData && this.itemsData.getDataSet();
var min = null;
var max = null;
if (dataset) {
// calculate the minimum value of the field 'start'

+ 9
- 7
lib/timeline/component/ItemSet.js View File

@ -29,7 +29,9 @@ function ItemSet(body, options) {
this.defaultOptions = {
type: null, // 'box', 'point', 'range', 'background'
orientation: 'bottom', // item orientation: 'top' or 'bottom'
orientation: {
item: 'bottom' // item orientation: 'top' or 'bottom'
},
align: 'auto', // alignment of box items
stack: true,
groupOrder: null,
@ -222,7 +224,7 @@ ItemSet.prototype._create = function(){
* Alignment for the items, only applicable for
* BoxItem. Choose 'center' (default), 'left', or
* 'right'.
* {String} orientation
* {String} orientation.item
* Orientation of the item set. Choose 'top' or
* 'bottom' (default).
* {Function} groupOrder
@ -282,10 +284,10 @@ ItemSet.prototype.setOptions = function(options) {
if ('orientation' in options) {
if (typeof options.orientation === 'string') {
this.options.orientation = options.orientation;
this.options.orientation.item = options.orientation === 'top' ? 'top' : 'bottom';
}
else if (typeof options.orientation === 'object' && 'item' in options.orientation) {
this.options.orientation = options.orientation.item;
this.options.orientation.item = options.orientation.item;
}
}
@ -504,7 +506,7 @@ ItemSet.prototype.redraw = function() {
range = this.body.range,
asSize = util.option.asSize,
options = this.options,
orientation = options.orientation,
orientation = options.orientation.item,
resized = false,
frame = this.dom.frame,
editable = options.editable.updateTime || options.editable.updateGroup;
@ -578,7 +580,7 @@ ItemSet.prototype.redraw = function() {
* @private
*/
ItemSet.prototype._firstGroup = function() {
var firstGroupIndex = (this.options.orientation == 'top') ? 0 : (this.groupIds.length - 1);
var firstGroupIndex = (this.options.orientation.item == 'top') ? 0 : (this.groupIds.length - 1);
var firstGroupId = this.groupIds[firstGroupIndex];
var firstGroup = this.groups[firstGroupId] || this.groups[UNGROUPED];
@ -1593,7 +1595,7 @@ ItemSet.prototype.groupFromTarget = function(event) {
return group;
}
if (this.options.orientation === 'top') {
if (this.options.orientation.item === 'top') {
if (i === this.groupIds.length - 1 && pageY > top) {
return group;
}

+ 13
- 9
lib/timeline/component/TimeAxis.js View File

@ -34,10 +34,12 @@ function TimeAxis (body, options) {
};
this.defaultOptions = {
orientation: 'bottom', // axis orientation: 'top' or 'bottom'
orientation: {
axis: 'bottom'
}, // axis orientation: 'top' or 'bottom'
showMinorLabels: true,
showMajorLabels: true,
format: null,
format: TimeStep.FORMAT,
timeAxis: null
};
this.options = util.extend({}, this.defaultOptions);
@ -56,7 +58,7 @@ TimeAxis.prototype = new Component();
* Set options for the TimeAxis.
* Parameters will be merged in current options.
* @param {Object} options Available options:
* {string} [orientation]
* {string} [orientation.axis]
* {boolean} [showMinorLabels]
* {boolean} [showMajorLabels]
*/
@ -67,16 +69,18 @@ TimeAxis.prototype.setOptions = function(options) {
'showMinorLabels',
'showMajorLabels',
'hiddenDates',
'format',
'timeAxis'
], this.options, options);
// deep copy the format options
util.selectiveDeepExtend(['format'], this.options, options);
if ('orientation' in options) {
if (typeof options.orientation === 'string') {
this.options.orientation = options.orientation;
this.options.orientation.axis = options.orientation;
}
else if (typeof options.orientation === 'object' && 'axis' in options.orientation) {
this.options.orientation = options.orientation.axis;
this.options.orientation.axis = options.orientation.axis;
}
}
@ -131,7 +135,7 @@ TimeAxis.prototype.redraw = function () {
var background = this.dom.background;
// determine the correct parent DOM element (depending on option orientation)
var parent = (options.orientation == 'top') ? this.body.dom.top : this.body.dom.bottom;
var parent = (options.orientation.axis == 'top') ? this.body.dom.top : this.body.dom.bottom;
var parentChanged = (foreground.parentNode !== parent);
// calculate character width and height
@ -148,7 +152,7 @@ TimeAxis.prototype.redraw = function () {
props.width = foreground.offsetWidth;
props.minorLineHeight = this.body.domProps.root.height - props.majorLabelHeight -
(options.orientation == 'top' ? this.body.domProps.bottom.height : this.body.domProps.top.height);
(options.orientation.axis == 'top' ? this.body.domProps.bottom.height : this.body.domProps.top.height);
props.minorLineWidth = 1; // TODO: really calculate width
props.majorLineHeight = props.minorLineHeight + props.majorLabelHeight;
props.majorLineWidth = 1; // TODO: really calculate width
@ -185,7 +189,7 @@ TimeAxis.prototype.redraw = function () {
* @private
*/
TimeAxis.prototype._repaintLabels = function () {
var orientation = this.options.orientation;
var orientation = this.options.orientation.axis;
// calculate range and step (step such that we have space for 7 characters per label)
var start = util.convert(this.body.range.start, 'Number');

+ 1
- 1
lib/timeline/component/item/BackgroundItem.js View File

@ -143,7 +143,7 @@ BackgroundItem.prototype.repositionX = RangeItem.prototype.repositionX;
* @Override
*/
BackgroundItem.prototype.repositionY = function(margin) {
var onTop = this.options.orientation === 'top';
var onTop = this.options.orientation.item === 'top';
this.dom.content.style.top = onTop ? '' : '0';
this.dom.content.style.bottom = onTop ? '0' : '';
var height;

+ 1
- 1
lib/timeline/component/item/BoxItem.js View File

@ -191,7 +191,7 @@ BoxItem.prototype.repositionX = function() {
* @Override
*/
BoxItem.prototype.repositionY = function() {
var orientation = this.options.orientation;
var orientation = this.options.orientation.item;
var box = this.dom.box;
var line = this.dom.line;
var dot = this.dom.dot;

+ 2
- 2
lib/timeline/component/item/PointItem.js View File

@ -166,8 +166,8 @@ PointItem.prototype.repositionX = function() {
* @Override
*/
PointItem.prototype.repositionY = function() {
var orientation = this.options.orientation,
point = this.dom.point;
var orientation = this.options.orientation.item;
var point = this.dom.point;
if (orientation == 'top') {
point.style.top = this.top + 'px';

+ 2
- 2
lib/timeline/component/item/RangeItem.js View File

@ -234,8 +234,8 @@ RangeItem.prototype.repositionX = function(limitSize) {
* @Override
*/
RangeItem.prototype.repositionY = function() {
var orientation = this.options.orientation,
box = this.dom.box;
var orientation = this.options.orientation.item;
var box = this.dom.box;
if (orientation == 'top') {
box.style.top = this.top + 'px';

+ 201
- 0
lib/timeline/options.js View File

@ -0,0 +1,201 @@
/**
* This object contains all possible options. It will check if the types are correct, if required if the option is one
* of the allowed values.
*
* __any__ means that the name of the property does not matter.
* __type__ is a required field for all objects and contains the allowed types of all objects
*/
let string = 'string';
let boolean = 'boolean';
let number = 'number';
let array = 'array';
let date = 'date';
let object = 'object'; // should only be in a __type__ property
let dom = 'dom';
let moment = 'moment';
let fn = 'function';
let nada = 'null';
let undef = 'undefined';
let any = 'any';
let allOptions = {
configure: {
enabled: {boolean},
filter: {boolean,string,array},
container: {dom},
__type__: {object,boolean,string,array}
},
//globals :
align: {string},
autoResize: {boolean},
clickToUse: {boolean},
dataAttributes: {string, array},
editable: {boolean, object},
end: {number, date, string, moment},
format: {
minorLabels: {
millisecond: {string,undef},
second: {string,undef},
minute: {string,undef},
hour: {string,undef},
weekday: {string,undef},
day: {string,undef},
month: {string,undef},
year: {string,undef},
__type__: {object}
},
majorLabels: {
millisecond: {string,undef},
second: {string,undef},
minute: {string,undef},
hour: {string,undef},
weekday: {string,undef},
day: {string,undef},
month: {string,undef},
year: {string,undef},
__type__: {object}
},
__type__: {object}
},
groupOrder: {string, fn},
height: {string, number},
hiddenDates: {object, array},
locale:{string},
locales:{
__any__: {object},
__type__: {object}
},
margin: {
axis: {number},
item: {
horizontal: {number},
vertical: {number},
__type__: {object,number}
},
__type__: {object,number}
},
max: {date, number, string, moment},
maxHeight: {number, string},
min: {date, number, string, moment},
minHeight: {number, string},
moveable: {boolean},
multiselect: {boolean},
onAdd: {fn},
onUpdate: {fn},
onMove: {fn},
onMoving: {fn},
onRemove: {fn},
order: {fn},
orientation: {
axis: {string},
item: {string},
__type__: {string, object}
},
selectable: {boolean},
showCurrentTime: {boolean},
showMajorLabels: {boolean},
showMinorLabels: {boolean},
stack: {boolean},
snap: {fn, nada},
start: {date, number, string, moment},
template: {fn},
timeAxis: {
scale: {string},
step: {number},
__type__: {object}
},
type: {string},
width: {string, number},
zoomable: {boolean},
zoomMax: {number},
zoomMin: {number},
__type__: {object}
};
let configureOptions = {
global: {
align: ['center', 'left', 'right'],
autoResize: true,
clickToUse: false,
// dataAttributes: ['all'], // FIXME: can be 'all' or string[]
editable: {
add: false,
remove: false,
updateGroup: false,
updateTime: false
},
end: '',
format: {
minorLabels: {
millisecond:'SSS',
second: 's',
minute: 'HH:mm',
hour: 'HH:mm',
weekday: 'ddd D',
day: 'D',
month: 'MMM',
year: 'YYYY'
},
majorLabels: {
millisecond:'HH:mm:ss',
second: 'D MMMM HH:mm',
minute: 'ddd D MMMM',
hour: 'ddd D MMMM',
weekday: 'MMMM YYYY',
day: 'MMMM YYYY',
month: 'YYYY',
year: ''
}
},
//groupOrder: {string, fn},
height: '',
//hiddenDates: {object, array},
locale: '',
margin: {
axis: [20, 0, 100, 1],
item: {
horizontal: [10, 0, 100, 1],
vertical: [10, 0, 100, 1]
}
},
max: '',
maxHeight: '',
min: '',
minHeight: '',
moveable: false,
multiselect: false,
//onAdd: {fn},
//onUpdate: {fn},
//onMove: {fn},
//onMoving: {fn},
//onRename: {fn},
//order: {fn},
orientation: {
axis: ['both', 'bottom', 'top'],
item: ['bottom', 'top']
},
selectable: true,
showCurrentTime: false,
showMajorLabels: true,
showMinorLabels: true,
stack: true,
//snap: {fn, nada},
start: '',
//template: {fn},
//timeAxis: {
// scale: ['millisecond', 'second', 'minute', 'hour', 'weekday', 'day', 'month', 'year'],
// step: [1, 1, 10, 1]
//},
type: ['box', 'point', 'range', 'background'],
width: '100%',
zoomable: true,
zoomMax: [315360000000000, 10, 315360000000000, 1],
zoomMin: [10, 10, 315360000000000, 1]
}
};
export {allOptions, configureOptions};

+ 2
- 0
test/timeline.html View File

@ -142,6 +142,8 @@
var container = document.getElementById('visualization');
var options = {
configure: true,
multiselect: true,
editable: true,
//orientation: 'top',
orientation: 'both',

+ 1
- 0
test/timeline_groups.html View File

@ -90,6 +90,7 @@
var container = document.getElementById('visualization');
var options = {
//orientation: 'top',
multiselect: true,
editable: {
add: true,
remove: true,

Loading…
Cancel
Save