Browse Source

Integrated an option configurator

flowchartTest
jos 9 years ago
parent
commit
f30a3a4556
14 changed files with 273 additions and 29 deletions
  1. +1
    -1
      HISTORY.md
  2. +7
    -0
      docs/timeline/index.html
  3. +13
    -3
      lib/timeline/Core.js
  4. +3
    -3
      lib/timeline/TimeStep.js
  5. +22
    -0
      lib/timeline/Timeline.js
  6. +9
    -7
      lib/timeline/component/ItemSet.js
  7. +11
    -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. +198
    -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,7 +11,6 @@ http://visjs.org
When creating a custom bundle using browserify, one now needs to add a When creating a custom bundle using browserify, one now needs to add a
transform step using `6to5ify`, this is described in README.md. transform step using `6to5ify`, this is described in README.md.
### Timeline ### Timeline
- Implemented option `multiselect`, which is false by default. - Implemented option `multiselect`, which is false by default.
@ -93,6 +92,7 @@ http://visjs.org
### Timeline ### Timeline
- Integrated an option configurator.
- Implemented orientation option `'both'`, displaying a time axis both on top - Implemented orientation option `'both'`, displaying a time axis both on top
and bottom (#665). and bottom (#665).
- Implemented creating new range items by dragging in an empty space with the - Implemented creating new range items by dragging in an empty space with 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> 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>
<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> <tr>
<td>dataAttributes</td> <td>dataAttributes</td>
<td class="mid">string[] or 'all'</string></td> <td class="mid">string[] or 'all'</string></td>

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

@ -13,9 +13,6 @@ var CustomTime = require('./component/CustomTime');
/** /**
* Create a timeline visualization * Create a timeline visualization
* @param {HTMLElement} container
* @param {vis.DataSet | Array} [items]
* @param {Object} [options] See Core.setOptions for the available options.
* @constructor * @constructor
*/ */
function Core () {} function Core () {}
@ -284,6 +281,19 @@ Core.prototype.setOptions = function (options) {
// propagate options to all components // propagate options to all components
this.components.forEach(component => component.setOptions(options)); 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);
});
console.log('options', appliedOptions)
this.configurationSystem.setModuleOptions({global: appliedOptions});
}
// redraw everything // redraw everything
this._redraw(); 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. * Set custom formatting for the minor an major labels of the TimeStep.
* Both `minorLabels` and `majorLabels` are an Object with properties: * 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 * @param {{minorLabels: Object, majorLabels: Object}} format
*/ */
TimeStep.prototype.setFormat = function (format) { TimeStep.prototype.setFormat = function (format) {
@ -246,7 +246,7 @@ TimeStep.prototype.getCurrent = function() {
* @param {{scale: string, step: number}} params * @param {{scale: string, step: number}} params
* An object containing two properties: * An object containing two properties:
* - A string 'scale'. Choose from 'millisecond', 'second', * - 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. * - A number 'step'. A step size, by default 1.
* Choose for example 1, 2, 5, or 10. * Choose for example 1, 2, 5, or 10.
*/ */
@ -324,7 +324,7 @@ TimeStep.prototype.setMinimumStep = function(minimumStep) {
* Static function * Static function
* @param {Date} date the date to be snapped. * @param {Date} date the date to be snapped.
* @param {string} scale Current scale, can be 'millisecond', 'second', * @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, ... * @param {number} step Current step (1, 2, 4, 5, ...
* @return {Date} snappedDate * @return {Date} snappedDate
*/ */

+ 22
- 0
lib/timeline/Timeline.js View File

@ -9,6 +9,10 @@ var TimeAxis = require('./component/TimeAxis');
var CurrentTime = require('./component/CurrentTime'); var CurrentTime = require('./component/CurrentTime');
var CustomTime = require('./component/CustomTime'); var CustomTime = require('./component/CustomTime');
var ItemSet = require('./component/ItemSet'); var ItemSet = require('./component/ItemSet');
var ConfigurationSystem = require('../network/modules/ConfigurationSystem');
var allOptions = require('./options').allOptions;
var configureOptions = require('./options').configureOptions;
/** /**
* Create a timeline visualization * Create a timeline visualization
@ -111,6 +115,9 @@ function Timeline (container, items, groups, options) {
me.emit('contextmenu', me.getEventProperties(event)) me.emit('contextmenu', me.getEventProperties(event))
}; };
// setup configuration system
this.configurationSystem = new ConfigurationSystem(this, container, configureOptions);
// apply options // apply options
if (options) { if (options) {
this.setOptions(options); this.setOptions(options);
@ -143,6 +150,21 @@ Timeline.prototype.redraw = function() {
this._redraw(); this._redraw();
}; };
Timeline.prototype.setOptions = function (options) {
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;
this.setItems(null); // remove all
this.setItems(itemsData); // add all
}
}
};
/** /**
* Set items * Set items
* @param {vis.DataSet | Array | null} items * @param {vis.DataSet | Array | null} items

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

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

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

@ -34,10 +34,12 @@ function TimeAxis (body, options) {
}; };
this.defaultOptions = { this.defaultOptions = {
orientation: 'bottom', // axis orientation: 'top' or 'bottom'
orientation: {
axis: 'bottom'
}, // axis orientation: 'top' or 'bottom'
showMinorLabels: true, showMinorLabels: true,
showMajorLabels: true, showMajorLabels: true,
format: null,
format: TimeStep.FORMAT,
timeAxis: null timeAxis: null
}; };
this.options = util.extend({}, this.defaultOptions); this.options = util.extend({}, this.defaultOptions);
@ -56,14 +58,14 @@ TimeAxis.prototype = new Component();
* Set options for the TimeAxis. * Set options for the TimeAxis.
* Parameters will be merged in current options. * Parameters will be merged in current options.
* @param {Object} options Available options: * @param {Object} options Available options:
* {string} [orientation]
* {string} [orientation.axis]
* {boolean} [showMinorLabels] * {boolean} [showMinorLabels]
* {boolean} [showMajorLabels] * {boolean} [showMajorLabels]
*/ */
TimeAxis.prototype.setOptions = function(options) { TimeAxis.prototype.setOptions = function(options) {
if (options) { if (options) {
// copy all options that we know // copy all options that we know
util.selectiveExtend([
util.selectiveDeepExtend([
'showMinorLabels', 'showMinorLabels',
'showMajorLabels', 'showMajorLabels',
'hiddenDates', 'hiddenDates',
@ -73,10 +75,10 @@ TimeAxis.prototype.setOptions = function(options) {
if ('orientation' in options) { if ('orientation' in options) {
if (typeof options.orientation === 'string') { 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) { 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 +133,7 @@ TimeAxis.prototype.redraw = function () {
var background = this.dom.background; var background = this.dom.background;
// determine the correct parent DOM element (depending on option orientation) // 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); var parentChanged = (foreground.parentNode !== parent);
// calculate character width and height // calculate character width and height
@ -148,7 +150,7 @@ TimeAxis.prototype.redraw = function () {
props.width = foreground.offsetWidth; props.width = foreground.offsetWidth;
props.minorLineHeight = this.body.domProps.root.height - props.majorLabelHeight - 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.minorLineWidth = 1; // TODO: really calculate width
props.majorLineHeight = props.minorLineHeight + props.majorLabelHeight; props.majorLineHeight = props.minorLineHeight + props.majorLabelHeight;
props.majorLineWidth = 1; // TODO: really calculate width props.majorLineWidth = 1; // TODO: really calculate width
@ -185,7 +187,7 @@ TimeAxis.prototype.redraw = function () {
* @private * @private
*/ */
TimeAxis.prototype._repaintLabels = function () { 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) // calculate range and step (step such that we have space for 7 characters per label)
var start = util.convert(this.body.range.start, 'Number'); 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 * @Override
*/ */
BackgroundItem.prototype.repositionY = function(margin) { 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.top = onTop ? '' : '0';
this.dom.content.style.bottom = onTop ? '0' : ''; this.dom.content.style.bottom = onTop ? '0' : '';
var height; var height;

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

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

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

@ -166,8 +166,8 @@ PointItem.prototype.repositionX = function() {
* @Override * @Override
*/ */
PointItem.prototype.repositionY = function() { 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') { if (orientation == 'top') {
point.style.top = this.top + 'px'; 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 * @Override
*/ */
RangeItem.prototype.repositionY = function() { 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') { if (orientation == 'top') {
box.style.top = this.top + 'px'; box.style.top = this.top + 'px';

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

@ -0,0 +1,198 @@
/**
* 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},
second: {string},
minute: {string},
hour: {string},
weekday: {string},
day: {string},
month: {string},
year: {string}
},
majorLabels: {
millisecond: {string},
second: {string},
minute: {string},
hour: {string},
weekday: {string},
day: {string},
month: {string},
year: {string}
}
},
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},
onRename: {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 container = document.getElementById('visualization');
var options = { var options = {
configure: true,
multiselect: true,
editable: true, editable: true,
//orientation: 'top', //orientation: 'top',
orientation: 'both', orientation: 'both',

+ 1
- 0
test/timeline_groups.html View File

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

Loading…
Cancel
Save