Browse Source

Merge branch 'master' of https://github.com/yotamberk/vis into develop

codeClimate
Yotam Berkowitz 8 years ago
parent
commit
16cfa8c112
25 changed files with 825 additions and 245 deletions
  1. +16
    -0
      dist/vis.css
  2. +350
    -119
      dist/vis.js
  3. +1
    -1
      dist/vis.min.css
  4. +1
    -1
      docs/data/dataset.html
  5. +1
    -0
      examples/timeline/groups/groupsEditable.html
  6. +1
    -1
      examples/timeline/interaction/animateWindow.html
  7. +77
    -0
      examples/timeline/other/rtl.html
  8. +6
    -1
      lib/network/modules/ManipulationSystem.js
  9. +10
    -2
      lib/timeline/Core.js
  10. +28
    -11
      lib/timeline/Range.js
  11. +16
    -8
      lib/timeline/Stack.js
  12. +31
    -12
      lib/timeline/Timeline.js
  13. +7
    -2
      lib/timeline/component/CurrentTime.js
  14. +2
    -2
      lib/timeline/component/DataAxis.js
  15. +2
    -3
      lib/timeline/component/Group.js
  16. +99
    -29
      lib/timeline/component/ItemSet.js
  17. +34
    -9
      lib/timeline/component/TimeAxis.js
  18. +11
    -0
      lib/timeline/component/css/item.css
  19. +5
    -0
      lib/timeline/component/css/timeaxis.css
  20. +46
    -19
      lib/timeline/component/item/BoxItem.js
  21. +7
    -1
      lib/timeline/component/item/Item.js
  22. +24
    -9
      lib/timeline/component/item/PointItem.js
  23. +44
    -14
      lib/timeline/component/item/RangeItem.js
  24. +2
    -1
      lib/timeline/optionsTimeline.js
  25. +4
    -0
      lib/util.js

+ 16
- 0
dist/vis.css View File

@ -565,6 +565,17 @@ input.vis-configuration.vis-config-range:focus::-ms-fill-upper {
cursor: pointer;
}
.vis-item .vis-delete-rtl {
background: url('img/timeline/delete.png') no-repeat center;
position: absolute;
width: 24px;
height: 24px;
top: -4px;
left: -24px;
cursor: pointer;
}
.vis-item.vis-range .vis-drag-left {
position: absolute;
width: 24px;
@ -637,6 +648,11 @@ input.vis-configuration.vis-config-range:focus::-ms-fill-upper {
border-left: 1px solid;
}
.vis-time-axis .vis-grid.vis-vertical-rtl {
position: absolute;
border-right: 1px solid;
}
.vis-time-axis .vis-grid.vis-minor {
border-color: #e5e5e5;
}

+ 350
- 119
dist/vis.js View File

@ -5,7 +5,7 @@
* A dynamic, browser-based visualization library.
*
* @version 4.15.1
* @date 2016-03-08
* @date 2016-03-13
*
* @license
* Copyright (C) 2011-2016 Almende B.V, http://almende.com
@ -723,6 +723,10 @@ return /******/ (function(modules) { // webpackBootstrap
return elem.getBoundingClientRect().left;
};
exports.getAbsoluteRight = function (elem) {
return elem.getBoundingClientRect().right;
};
/**
* Retrieve the absolute top value of a DOM element
* @param {Element} elem A dom element, for example a div
@ -10661,6 +10665,7 @@ return /******/ (function(modules) { // webpackBootstrap
* @extends Core
*/
function Timeline(container, items, groups, options) {
if (!(this instanceof Timeline)) {
throw new SyntaxError('Constructor must be called with the new operator');
}
@ -10684,7 +10689,7 @@ return /******/ (function(modules) { // webpackBootstrap
axis: 'bottom', // axis orientation: 'bottom', 'top', or 'both'
item: 'bottom' // not relevant
},
rtl: false,
moment: moment,
width: null,
@ -10739,7 +10744,7 @@ return /******/ (function(modules) { // webpackBootstrap
this.components.push(this.currentTime);
// item set
this.itemSet = new ItemSet(this.body);
this.itemSet = new ItemSet(this.body, this.options);
this.components.push(this.itemSet);
this.itemsData = null; // DataSet
@ -10822,6 +10827,7 @@ return /******/ (function(modules) { // webpackBootstrap
Timeline.prototype.setOptions = function (options) {
// validate options
var errorFound = _Validator2.default.validate(options, allOptions);
if (errorFound === true) {
console.log('%cErrors have been found in the supplied options object.', printStyle);
}
@ -11051,16 +11057,23 @@ return /******/ (function(modules) { // webpackBootstrap
var start = getStart(item);
var end = getEnd(item);
console.log(start, end);
console.log(this.options);
var left = start - (item.getWidthLeft() + 10) * factor;
var right = end + (item.getWidthRight() + 10) * factor;
if (this.options.rtl) {
var startSide = start - (item.getWidthRight() + 10) * factor;
var endSide = end + (item.getWidthLeft() + 10) * factor;
} else {
var startSide = start - (item.getWidthLeft() + 10) * factor;
var endSide = end + (item.getWidthRight() + 10) * factor;
}
if (left < min) {
min = left;
if (startSide < min) {
min = startSide;
minItem = item;
}
if (right > max) {
max = right;
if (endSide > max) {
max = endSide;
maxItem = item;
}
}.bind(_this));
@ -11071,8 +11084,13 @@ return /******/ (function(modules) { // webpackBootstrap
delta = _this.props.center.width - lhs - rhs; // px
if (delta > 0) {
min = getStart(minItem) - lhs * interval / delta; // ms
max = getEnd(maxItem) + rhs * interval / delta; // ms
if (_this.options.rtl) {
min = getStart(minItem) - rhs * interval / delta; // ms
max = getEnd(maxItem) + lhs * interval / delta; // ms
} else {
min = getStart(minItem) - lhs * interval / delta; // ms
max = getEnd(maxItem) + rhs * interval / delta; // ms
}
}
}
})();
@ -11121,7 +11139,11 @@ return /******/ (function(modules) { // webpackBootstrap
Timeline.prototype.getEventProperties = function (event) {
var clientX = event.center ? event.center.x : event.clientX;
var clientY = event.center ? event.center.y : event.clientY;
var x = clientX - util.getAbsoluteLeft(this.dom.centerContainer);
if (this.options.rtl) {
var x = util.getAbsoluteRight(this.dom.centerContainer) - clientX;
} else {
var x = clientX - util.getAbsoluteLeft(this.dom.centerContainer);
}
var y = clientY - util.getAbsoluteTop(this.dom.centerContainer);
var item = this.itemSet.itemFromTarget(event);
@ -15804,9 +15826,9 @@ return /******/ (function(modules) { // webpackBootstrap
// http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#JavaScript
/*
Copyright (c) 2011 Andrei Mackenzie
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
}, {
@ -15887,6 +15909,7 @@ return /******/ (function(modules) { // webpackBootstrap
// default options
this.defaultOptions = {
rtl: false,
start: null,
end: null,
moment: moment,
@ -15899,7 +15922,6 @@ return /******/ (function(modules) { // webpackBootstrap
zoomMax: 1000 * 60 * 60 * 24 * 365 * 10000 // milliseconds
};
this.options = util.extend({}, this.defaultOptions);
this.props = {
touch: {}
};
@ -15941,7 +15963,7 @@ return /******/ (function(modules) { // webpackBootstrap
Range.prototype.setOptions = function (options) {
if (options) {
// copy the options that we know
var fields = ['direction', 'min', 'max', 'zoomMin', 'zoomMax', 'moveable', 'zoomable', 'moment', 'activate', 'hiddenDates', 'zoomKey'];
var fields = ['direction', 'min', 'max', 'zoomMin', 'zoomMax', 'moveable', 'zoomable', 'moment', 'activate', 'hiddenDates', 'zoomKey', 'rtl'];
util.selectiveExtend(fields, this.options, options);
if ('start' in options || 'end' in options) {
@ -16263,7 +16285,13 @@ return /******/ (function(modules) { // webpackBootstrap
interval -= duration;
var width = direction == 'horizontal' ? this.body.domProps.center.width : this.body.domProps.center.height;
var diffRange = -delta / width * interval;
if (this.options.rtl) {
var diffRange = delta / width * interval;
} else {
var diffRange = -delta / width * interval;
}
var newStart = this.props.touch.start + diffRange;
var newEnd = this.props.touch.end + diffRange;
@ -16365,7 +16393,7 @@ return /******/ (function(modules) { // webpackBootstrap
}
// calculate center, the date to zoom around
var pointer = getPointer({ x: event.clientX, y: event.clientY }, this.body.dom.center);
var pointer = this.getPointer({ x: event.clientX, y: event.clientY }, this.body.dom.center);
var pointerDate = this._pointerToDate(pointer);
this.zoom(scale, pointerDate, delta);
@ -16401,7 +16429,7 @@ return /******/ (function(modules) { // webpackBootstrap
this.props.touch.allowDragging = false;
if (!this.props.touch.center) {
this.props.touch.center = getPointer(event.center, this.body.dom.center);
this.props.touch.center = this.getPointer(event.center, this.body.dom.center);
}
var scale = 1 / (event.scale + this.scaleOffset);
@ -16446,7 +16474,11 @@ return /******/ (function(modules) { // webpackBootstrap
// calculate the time where the mouse is, check whether inside
// and no scroll action should happen.
var clientX = event.center ? event.center.x : event.clientX;
var x = clientX - util.getAbsoluteLeft(this.body.dom.centerContainer);
if (this.options.rtl) {
var x = clientX - util.getAbsoluteLeft(this.body.dom.centerContainer);
} else {
var x = util.getAbsoluteRight(this.body.dom.centerContainer) - clientX;
}
var time = this.body.util.toTime(x);
return time >= this.start && time <= this.end;
@ -16480,12 +16512,19 @@ return /******/ (function(modules) { // webpackBootstrap
* @return {{x: Number, y: Number}} pointer
* @private
*/
function getPointer(touch, element) {
return {
x: touch.x - util.getAbsoluteLeft(element),
y: touch.y - util.getAbsoluteTop(element)
};
}
Range.prototype.getPointer = function (touch, element) {
if (this.options.rtl) {
return {
x: util.getAbsoluteRight(element) - touch.x,
y: touch.y - util.getAbsoluteTop(element)
};
} else {
return {
x: touch.x - util.getAbsoluteLeft(element),
y: touch.y - util.getAbsoluteTop(element)
};
}
};
/**
* Zoom the range the given scale in or out. Start and end date will
@ -17321,9 +17360,17 @@ return /******/ (function(modules) { // webpackBootstrap
Core.prototype.setOptions = function (options) {
if (options) {
// copy the known options
var fields = ['width', 'height', 'minHeight', 'maxHeight', 'autoResize', 'start', 'end', 'clickToUse', 'dataAttributes', 'hiddenDates', 'locale', 'locales', 'moment', 'throttleRedraw'];
var fields = ['width', 'height', 'minHeight', 'maxHeight', 'autoResize', 'start', 'end', 'clickToUse', 'dataAttributes', 'hiddenDates', 'locale', 'locales', 'moment', 'rtl', 'throttleRedraw'];
util.selectiveExtend(fields, this.options, options);
if (this.options.rtl) {
var contentContainer = this.dom.leftContainer;
this.dom.leftContainer = this.dom.rightContainer;
this.dom.rightContainer = contentContainer;
this.dom.container.style.direction = "rtl";
this.dom.backgroundVertical.className = 'vis-panel vis-background vis-vertical-rtl';
}
this.options.orientation = { item: undefined, axis: undefined };
if ('orientation' in options) {
if (typeof options.orientation === 'string') {
@ -17622,7 +17669,7 @@ return /******/ (function(modules) { // webpackBootstrap
var interval = range.max - range.min;
var min = new Date(range.min.valueOf() - interval * 0.01);
var max = new Date(range.max.valueOf() + interval * 0.01);
console.log(min, max);
var animation = options && options.animation !== undefined ? options.animation : true;
this.range.setRange(min, max, animation);
};
@ -18170,8 +18217,8 @@ return /******/ (function(modules) { // webpackBootstrap
*/
function ItemSet(body, options) {
this.body = body;
this.defaultOptions = {
rtl: false,
type: null, // 'box', 'point', 'range', 'background'
orientation: {
item: 'bottom' // item orientation: 'top' or 'bottom'
@ -18374,8 +18421,8 @@ return /******/ (function(modules) { // webpackBootstrap
// add item on doubletap
this.hammer.on('doubletap', this._onAddItem.bind(this));
this.groupHammer = new Hammer(this.body.dom.leftContainer);
this.groupHammer.on('panstart', this._onGroupDragStart.bind(this));
this.groupHammer.on('panmove', this._onGroupDrag.bind(this));
this.groupHammer.on('panend', this._onGroupDragEnd.bind(this));
@ -18452,7 +18499,7 @@ return /******/ (function(modules) { // webpackBootstrap
ItemSet.prototype.setOptions = function (options) {
if (options) {
// copy all options that we know
var fields = ['type', 'align', 'order', 'stack', 'selectable', 'multiselect', 'itemsAlwaysDraggable', 'multiselectPerGroup', 'groupOrder', 'dataAttributes', 'template', 'groupTemplate', 'hide', 'snap', 'groupOrderSwap'];
var fields = ['type', 'rtl', 'align', 'order', 'stack', 'selectable', 'multiselect', 'itemsAlwaysDraggable', 'multiselectPerGroup', 'groupOrder', 'dataAttributes', 'template', 'groupTemplate', 'hide', 'snap', 'groupOrderSwap'];
util.selectiveExtend(fields, this.options, options);
if ('orientation' in options) {
@ -18637,8 +18684,14 @@ return /******/ (function(modules) { // webpackBootstrap
*/
ItemSet.prototype.getVisibleItems = function () {
var range = this.body.range.getRange();
var left = this.body.util.toScreen(range.start);
var right = this.body.util.toScreen(range.end);
if (this.options.rtl) {
var right = this.body.util.toScreen(range.start);
var left = this.body.util.toScreen(range.end);
} else {
var left = this.body.util.toScreen(range.start);
var right = this.body.util.toScreen(range.end);
}
var ids = [];
for (var groupId in this.groups) {
@ -18651,8 +18704,14 @@ return /******/ (function(modules) { // webpackBootstrap
for (var i = 0; i < rawVisibleItems.length; i++) {
var item = rawVisibleItems[i];
// TODO: also check whether visible vertically
if (item.left < right && item.left + item.width > left) {
ids.push(item.id);
if (this.options.rtl) {
if (item.right < left && item.right + item.width > right) {
ids.push(item.id);
}
} else {
if (item.left < right && item.left + item.width > left) {
ids.push(item.id);
}
}
}
}
@ -18692,7 +18751,12 @@ return /******/ (function(modules) { // webpackBootstrap
// recalculate absolute position (before redrawing groups)
this.props.top = this.body.domProps.top.height + this.body.domProps.border.top;
this.props.left = this.body.domProps.left.width + this.body.domProps.border.left;
if (this.options.rtl) {
this.props.right = this.body.domProps.right.width + this.body.domProps.border.right;
} else {
this.props.left = this.body.domProps.left.width + this.body.domProps.border.left;
}
// update class name
frame.className = 'vis-itemset';
@ -18743,7 +18807,11 @@ return /******/ (function(modules) { // webpackBootstrap
// reposition axis
this.dom.axis.style.top = asSize(orientation == 'top' ? this.body.domProps.top.height + this.body.domProps.border.top : this.body.domProps.top.height + this.body.domProps.centerContainer.height);
this.dom.axis.style.left = '0';
if (this.options.rtl) {
this.dom.axis.style.right = '0';
} else {
this.dom.axis.style.left = '0';
}
// check if this component is resized
resized = this._isResized() || resized;
@ -19363,8 +19431,15 @@ return /******/ (function(modules) { // webpackBootstrap
*/
ItemSet.prototype._onDragStartAddItem = function (event) {
var snap = this.options.snap || null;
var xAbs = util.getAbsoluteLeft(this.dom.frame);
var x = event.center.x - xAbs - 10; // minus 10 to compensate for the drag starting as soon as you've moved 10px
if (this.options.rtl) {
var xAbs = util.getAbsoluteRight(this.dom.frame);
var x = xAbs - event.center.x + 10; // plus 10 to compensate for the drag starting as soon as you've moved 10px
} else {
var xAbs = util.getAbsoluteLeft(this.dom.frame);
var x = event.center.x - xAbs - 10; // minus 10 to compensate for the drag starting as soon as you've moved 10px
}
var time = this.body.util.toTime(x);
var scale = this.body.util.getScale();
var step = this.body.util.getStep();
@ -19385,7 +19460,6 @@ return /******/ (function(modules) { // webpackBootstrap
if (group) {
itemData.group = group.groupId;
}
var newItem = new RangeItem(itemData, this.conversion, this.options);
newItem.id = id; // TODO: not so nice setting id afterwards
newItem.data = this._cloneItemData(itemData);
@ -19393,10 +19467,15 @@ return /******/ (function(modules) { // webpackBootstrap
var props = {
item: newItem,
dragRight: true,
initialX: event.center.x,
data: newItem.data
};
if (this.options.rtl) {
props.dragLeft = true;
} else {
props.dragRight = true;
}
this.touchParams.itemProps = [props];
event.stopPropagation();
@ -19413,7 +19492,13 @@ return /******/ (function(modules) { // webpackBootstrap
var me = this;
var snap = this.options.snap || null;
var xOffset = this.body.dom.root.offsetLeft + this.body.domProps.left.width;
if (this.options.rtl) {
var xOffset = this.body.dom.root.offsetLeft + this.body.domProps.right.width;
} else {
var xOffset = this.body.dom.root.offsetLeft + this.body.domProps.left.width;
}
var scale = this.body.util.getScale();
var step = this.body.util.getStep();
@ -19437,7 +19522,12 @@ return /******/ (function(modules) { // webpackBootstrap
this.touchParams.itemProps.forEach(function (props) {
var current = me.body.util.toTime(event.center.x - xOffset);
var initial = me.body.util.toTime(props.initialX - xOffset);
var offset = current - initial; // ms
if (this.options.rtl) {
var offset = -(current - initial); // ms
} else {
var offset = current - initial; // ms
}
var itemData = this._cloneItemData(props.item.data); // clone the data
if (props.item.editable === false) {
@ -19445,27 +19535,45 @@ return /******/ (function(modules) { // webpackBootstrap
}
var updateTimeAllowed = me.options.editable.updateTime || props.item.editable === true;
if (updateTimeAllowed) {
if (props.dragLeft) {
// drag left side of a range item
if (itemData.start != undefined) {
var initialStart = util.convert(props.data.start, 'Date');
var start = new Date(initialStart.valueOf() + offset);
// TODO: pass a Moment instead of a Date to snap(). (Breaking change)
itemData.start = snap ? snap(start, scale, step) : start;
if (this.options.rtl) {
if (itemData.end != undefined) {
var initialEnd = util.convert(props.data.end, 'Date');
var end = new Date(initialEnd.valueOf() + offset);
// TODO: pass a Moment instead of a Date to snap(). (Breaking change)
itemData.end = snap ? snap(end, scale, step) : end;
}
} else {
if (itemData.start != undefined) {
var initialStart = util.convert(props.data.start, 'Date');
var start = new Date(initialStart.valueOf() + offset);
// TODO: pass a Moment instead of a Date to snap(). (Breaking change)
itemData.start = snap ? snap(start, scale, step) : start;
}
}
} else if (props.dragRight) {
// drag right side of a range item
if (itemData.end != undefined) {
var initialEnd = util.convert(props.data.end, 'Date');
var end = new Date(initialEnd.valueOf() + offset);
// TODO: pass a Moment instead of a Date to snap(). (Breaking change)
itemData.end = snap ? snap(end, scale, step) : end;
if (this.options.rtl) {
if (itemData.start != undefined) {
var initialStart = util.convert(props.data.start, 'Date');
var start = new Date(initialStart.valueOf() + offset);
// TODO: pass a Moment instead of a Date to snap(). (Breaking change)
itemData.start = snap ? snap(start, scale, step) : start;
}
} else {
if (itemData.end != undefined) {
var initialEnd = util.convert(props.data.end, 'Date');
var end = new Date(initialEnd.valueOf() + offset);
// TODO: pass a Moment instead of a Date to snap(). (Breaking change)
itemData.end = snap ? snap(end, scale, step) : end;
}
}
} else {
// drag both start and end
if (itemData.start != undefined) {
var initialStart = util.convert(props.data.start, 'Date').valueOf();
var start = new Date(initialStart + offset);
@ -19811,8 +19919,15 @@ return /******/ (function(modules) { // webpackBootstrap
});
} else {
// add item
var xAbs = util.getAbsoluteLeft(this.dom.frame);
var x = event.center.x - xAbs;
if (this.options.rtl) {
var xAbs = util.getAbsoluteRight(this.dom.frame);
var x = xAbs - event.center.x;
} else {
var xAbs = util.getAbsoluteLeft(this.dom.frame);
var x = event.center.x - xAbs;
}
// var xAbs = util.getAbsoluteLeft(this.dom.frame);
// var x = event.center.x - xAbs;
var start = this.body.util.toTime(x);
var scale = this.body.util.getScale();
var step = this.body.util.getStep();
@ -20967,8 +21082,8 @@ return /******/ (function(modules) { // webpackBootstrap
this.visibleItems = this._updateVisibleItems(this.orderedItems, this.visibleItems, range);
} else {
// no custom order function, lazy stacking
this.visibleItems = this._updateVisibleItems(this.orderedItems, this.visibleItems, range);
this.visibleItems = this._updateVisibleItems(this.orderedItems, this.visibleItems, range);
if (this.itemSet.options.stack) {
// TODO: ugly way to access options...
stack.stack(this.visibleItems, margin, restack);
@ -20984,10 +21099,9 @@ return /******/ (function(modules) { // webpackBootstrap
// calculate actual size and position
var foreground = this.dom.foreground;
this.top = foreground.offsetTop;
this.left = foreground.offsetLeft;
this.right = foreground.offsetLeft;
this.width = foreground.offsetWidth;
resized = util.updateProperty(this, 'height', height) || resized;
// recalculate size of label
resized = util.updateProperty(this.props.label, 'width', this.dom.inner.clientWidth) || resized;
resized = util.updateProperty(this.props.label, 'height', this.dom.inner.clientHeight) || resized;
@ -21427,7 +21541,6 @@ return /******/ (function(modules) { // webpackBootstrap
*/
exports.stack = function (items, margin, force) {
var i, iMax;
if (force) {
// reset top position of all items
for (i = 0, iMax = items.length; i < iMax; i++) {
@ -21448,7 +21561,7 @@ return /******/ (function(modules) { // webpackBootstrap
var collidingItem = null;
for (var j = 0, jj = items.length; j < jj; j++) {
var other = items[j];
if (other.top !== null && other !== item && other.stack && exports.collision(item, other, margin.item)) {
if (other.top !== null && other !== item && other.stack && exports.collision(item, other, margin.item, other.options.rtl)) {
collidingItem = other;
break;
}
@ -21501,8 +21614,14 @@ return /******/ (function(modules) { // webpackBootstrap
* minimum required margin.
* @return {boolean} true if a and b collide, else false
*/
exports.collision = function (a, b, margin) {
return a.left - margin.horizontal + EPSILON < b.left + b.width && a.left + a.width + margin.horizontal - EPSILON > b.left && a.top - margin.vertical + EPSILON < b.top + b.height && a.top + a.height + margin.vertical - EPSILON > b.top;
exports.collision = function (a, b, margin, rtl) {
var isCollision = null;
if (rtl) {
isCollision = a.right - margin.horizontal + EPSILON < b.right + b.width && a.right + a.width + margin.horizontal - EPSILON > b.right && a.top - margin.vertical + EPSILON < b.top + b.height && a.top + a.height + margin.vertical - EPSILON > b.top;
} else {
a.left - margin.horizontal + EPSILON < b.left + b.width && a.left + a.width + margin.horizontal - EPSILON > b.left && a.top - margin.vertical + EPSILON < b.top + b.height && a.top + a.height + margin.vertical - EPSILON > b.top;
}
return isCollision;
};
/***/ },
@ -21531,7 +21650,7 @@ return /******/ (function(modules) { // webpackBootstrap
}
};
this.overflow = false; // if contents can overflow (css styling), this flag is set to true
this.options = options;
// validate data
if (data) {
if (data.start == undefined) {
@ -21631,7 +21750,7 @@ return /******/ (function(modules) { // webpackBootstrap
this.dirty = false;
}
console.log("redrawing range");
this._repaintDeleteButton(dom.box);
this._repaintDragLeft();
this._repaintDragRight();
@ -21676,7 +21795,7 @@ return /******/ (function(modules) { // webpackBootstrap
var parentWidth = this.parent.width;
var start = this.conversion.toScreen(this.data.start);
var end = this.conversion.toScreen(this.data.end);
var contentLeft;
var contentStartPosition;
var contentWidth;
// limit the width of the range, as browsers cannot draw very wide divs
@ -21691,7 +21810,11 @@ return /******/ (function(modules) { // webpackBootstrap
var boxWidth = Math.max(end - start, 1);
if (this.overflow) {
this.left = start;
if (this.options.rtl) {
this.right = start;
} else {
this.left = start;
}
this.width = boxWidth + this.props.content.width;
contentWidth = this.props.content.width;
@ -21699,25 +21822,46 @@ return /******/ (function(modules) { // webpackBootstrap
// a width which will not change when moving the Timeline
// So no re-stacking needed, which is nicer for the eye;
} else {
this.left = start;
if (this.options.rtl) {
this.right = start;
} else {
this.left = start;
}
this.width = boxWidth;
contentWidth = Math.min(end - start, this.props.content.width);
}
this.dom.box.style.left = this.left + 'px';
if (this.options.rtl) {
this.dom.box.style.right = this.right + 'px';
} else {
this.dom.box.style.left = this.left + 'px';
}
this.dom.box.style.width = boxWidth + 'px';
switch (this.options.align) {
case 'left':
this.dom.content.style.left = '0';
if (this.options.rtl) {
this.dom.content.style.right = '0';
} else {
this.dom.content.style.left = '0';
}
break;
case 'right':
this.dom.content.style.left = Math.max(boxWidth - contentWidth, 0) + 'px';
if (this.options.rtl) {
this.dom.content.style.right = Math.max(boxWidth - contentWidth, 0) + 'px';
} else {
this.dom.content.style.left = Math.max(boxWidth - contentWidth, 0) + 'px';
}
break;
case 'center':
this.dom.content.style.left = Math.max((boxWidth - contentWidth) / 2, 0) + 'px';
if (this.options.rtl) {
this.dom.content.style.right = Math.max((boxWidth - contentWidth) / 2, 0) + 'px';
} else {
this.dom.content.style.left = Math.max((boxWidth - contentWidth) / 2, 0) + 'px';
}
break;
default:
@ -21725,18 +21869,22 @@ return /******/ (function(modules) { // webpackBootstrap
// when range exceeds left of the window, position the contents at the left of the visible area
if (this.overflow) {
if (end > 0) {
contentLeft = Math.max(-start, 0);
contentStartPosition = Math.max(-start, 0);
} else {
contentLeft = -contentWidth; // ensure it's not visible anymore
contentStartPosition = -contentWidth; // ensure it's not visible anymore
}
} else {
if (start < 0) {
contentLeft = -start;
contentStartPosition = -start;
} else {
contentLeft = 0;
contentStartPosition = 0;
}
}
this.dom.content.style.left = contentLeft + 'px';
if (this.options.rtl) {
this.dom.content.style.right = contentStartPosition + 'px';
} else {
this.dom.content.style.left = contentStartPosition + 'px';
}
}
};
@ -21782,6 +21930,7 @@ return /******/ (function(modules) { // webpackBootstrap
* @protected
*/
RangeItem.prototype._repaintDragRight = function () {
console.log("repainting!!!!");
if (this.selected && this.options.editable.updateTime && !this.dom.dragRight) {
// create and show drag area
var dragRight = document.createElement('div');
@ -21832,6 +21981,7 @@ return /******/ (function(modules) { // webpackBootstrap
this.dirty = true;
this.top = null;
this.right = null;
this.left = null;
this.width = null;
this.height = null;
@ -21958,7 +22108,12 @@ return /******/ (function(modules) { // webpackBootstrap
var me = this;
var deleteButton = document.createElement('div');
deleteButton.className = 'vis-delete';
if (this.options.rtl) {
deleteButton.className = 'vis-delete-rtl';
} else {
deleteButton.className = 'vis-delete';
}
deleteButton.title = 'Delete this item';
// TODO: be able to destroy the delete button
@ -22196,7 +22351,7 @@ return /******/ (function(modules) { // webpackBootstrap
height: 0
}
};
this.options = options;
// validate data
if (data) {
if (data.start == undefined) {
@ -22340,27 +22495,54 @@ return /******/ (function(modules) { // webpackBootstrap
// calculate left position of the box
if (align == 'right') {
this.left = start - this.width;
if (this.options.rtl) {
this.right = start - this.width;
// reposition box, line, and dot
this.dom.box.style.left = this.left + 'px';
this.dom.line.style.left = start - this.props.line.width + 'px';
this.dom.dot.style.left = start - this.props.line.width / 2 - this.props.dot.width / 2 + 'px';
// reposition box, line, and dot
this.dom.box.style.right = this.right + 'px';
this.dom.line.style.right = start - this.props.line.width + 'px';
this.dom.dot.style.right = start - this.props.line.width / 2 - this.props.dot.width / 2 + 'px';
} else {
this.left = start - this.width;
// reposition box, line, and dot
this.dom.box.style.left = this.left + 'px';
this.dom.line.style.left = start - this.props.line.width + 'px';
this.dom.dot.style.left = start - this.props.line.width / 2 - this.props.dot.width / 2 + 'px';
}
} else if (align == 'left') {
this.left = start;
if (this.options.rtl) {
this.right = start;
// reposition box, line, and dot
this.dom.box.style.left = this.left + 'px';
this.dom.line.style.left = start + 'px';
this.dom.dot.style.left = start + this.props.line.width / 2 - this.props.dot.width / 2 + 'px';
// reposition box, line, and dot
this.dom.box.style.right = this.right + 'px';
this.dom.line.style.right = start + 'px';
this.dom.dot.style.right = start + this.props.line.width / 2 - this.props.dot.width / 2 + 'px';
} else {
this.left = start;
// reposition box, line, and dot
this.dom.box.style.left = this.left + 'px';
this.dom.line.style.left = start + 'px';
this.dom.dot.style.left = start + this.props.line.width / 2 - this.props.dot.width / 2 + 'px';
}
} else {
// default or 'center'
this.left = start - this.width / 2;
if (this.options.rtl) {
this.right = start - this.width / 2;
// reposition box, line, and dot
this.dom.box.style.left = this.left + 'px';
this.dom.line.style.left = start - this.props.line.width / 2 + 'px';
this.dom.dot.style.left = start - this.props.dot.width / 2 + 'px';
// reposition box, line, and dot
this.dom.box.style.right = this.right + 'px';
this.dom.line.style.right = start - this.props.line.width + 'px';
this.dom.dot.style.right = start - this.props.dot.width / 2 + 'px';
} else {
this.left = start - this.width / 2;
// reposition box, line, and dot
this.dom.box.style.left = this.left + 'px';
this.dom.line.style.left = start - this.props.line.width / 2 + 'px';
this.dom.dot.style.left = start - this.props.dot.width / 2 + 'px';
}
}
};
@ -22438,10 +22620,11 @@ return /******/ (function(modules) { // webpackBootstrap
},
content: {
height: 0,
marginLeft: 0
marginLeft: 0,
marginRight: 0
}
};
this.options = options;
// validate data
if (data) {
if (data.start == undefined) {
@ -22531,7 +22714,11 @@ return /******/ (function(modules) { // webpackBootstrap
this.props.content.height = dom.content.offsetHeight;
// resize contents
dom.content.style.marginLeft = 2 * this.props.dot.width + 'px';
if (this.options.rtl) {
dom.content.style.marginRight = 2 * this.props.dot.width + 'px';
} else {
dom.content.style.marginLeft = 2 * this.props.dot.width + 'px';
}
//dom.content.style.marginRight = ... + 'px'; // TODO: margin right
// recalculate size
@ -22540,7 +22727,11 @@ return /******/ (function(modules) { // webpackBootstrap
// reposition the dot
dom.dot.style.top = (this.height - this.props.dot.height) / 2 + 'px';
dom.dot.style.left = this.props.dot.width / 2 + 'px';
if (this.options.rtl) {
dom.dot.style.right = this.props.dot.width / 2 + 'px';
} else {
dom.dot.style.left = this.props.dot.width / 2 + 'px';
}
this.dirty = false;
}
@ -22578,10 +22769,17 @@ return /******/ (function(modules) { // webpackBootstrap
PointItem.prototype.repositionX = function () {
var start = this.conversion.toScreen(this.data.start);
this.left = start - this.props.dot.width;
if (this.options.rtl) {
this.right = start - this.props.dot.width;
// reposition point
this.dom.point.style.left = this.left + 'px';
// reposition point
this.dom.point.style.right = this.right + 'px';
} else {
this.left = start - this.props.dot.width;
// reposition point
this.dom.point.style.left = this.left + 'px';
}
};
/**
@ -22591,7 +22789,6 @@ return /******/ (function(modules) { // webpackBootstrap
PointItem.prototype.repositionY = function () {
var orientation = this.options.orientation.item;
var point = this.dom.point;
if (orientation == 'top') {
point.style.top = this.top + 'px';
} else {
@ -22612,7 +22809,7 @@ return /******/ (function(modules) { // webpackBootstrap
* @return {number}
*/
PointItem.prototype.getWidthRight = function () {
return this.width - this.props.dot.width;
return this.props.dot.width;
};
module.exports = PointItem;
@ -22915,7 +23112,7 @@ return /******/ (function(modules) { // webpackBootstrap
TimeAxis.prototype.setOptions = function (options) {
if (options) {
// copy all options that we know
util.selectiveExtend(['showMinorLabels', 'showMajorLabels', 'maxMinorChars', 'hiddenDates', 'timeAxis', 'moment'], this.options, options);
util.selectiveExtend(['showMinorLabels', 'showMajorLabels', 'maxMinorChars', 'hiddenDates', 'timeAxis', 'moment', 'rtl'], this.options, options);
// deep copy the format options
util.selectiveDeepExtend(['format'], this.options, options);
@ -23019,7 +23216,6 @@ return /******/ (function(modules) { // webpackBootstrap
} else {
this.body.dom.backgroundVertical.appendChild(background);
}
return this._isResized() || parentChanged;
};
@ -23172,7 +23368,13 @@ return /******/ (function(modules) { // webpackBootstrap
label.childNodes[0].nodeValue = text;
label.style.top = orientation == 'top' ? this.props.majorLabelHeight + 'px' : '0';
label.style.left = x + 'px';
if (this.options.rtl) {
label.style.left = "";
label.style.right = x + 'px';
} else {
label.style.left = x + 'px';
};
label.className = 'vis-text vis-minor ' + className;
//label.title = title; // TODO: this is a heavy operation
@ -23206,7 +23408,12 @@ return /******/ (function(modules) { // webpackBootstrap
//label.title = title; // TODO: this is a heavy operation
label.style.top = orientation == 'top' ? '0' : this.props.minorLabelHeight + 'px';
label.style.left = x + 'px';
if (this.options.rtl) {
label.style.left = "";
label.style.right = x + 'px';
} else {
label.style.left = x + 'px';
};
return label;
};
@ -23237,11 +23444,16 @@ return /******/ (function(modules) { // webpackBootstrap
line.style.top = this.body.domProps.top.height + 'px';
}
line.style.height = props.minorLineHeight + 'px';
line.style.left = x - props.minorLineWidth / 2 + 'px';
if (this.options.rtl) {
line.style.left = "";
line.style.right = x - props.minorLineWidth / 2 + 'px';
line.className = 'vis-grid vis-vertical-rtl vis-minor ' + className;
} else {
line.style.left = x - props.minorLineWidth / 2 + 'px';
line.className = 'vis-grid vis-vertical vis-minor ' + className;
};
line.style.width = width + 'px';
line.className = 'vis-grid vis-vertical vis-minor ' + className;
return line;
};
@ -23270,12 +23482,19 @@ return /******/ (function(modules) { // webpackBootstrap
} else {
line.style.top = this.body.domProps.top.height + 'px';
}
line.style.left = x - props.majorLineWidth / 2 + 'px';
if (this.options.rtl) {
line.style.left = "";
line.style.right = x - props.majorLineWidth / 2 + 'px';
line.className = 'vis-grid vis-vertical-rtl vis-major ' + className;
} else {
line.style.left = x - props.majorLineWidth / 2 + 'px';
line.className = 'vis-grid vis-vertical vis-major ' + className;
}
line.style.height = props.majorLineHeight + 'px';
line.style.width = width + 'px';
line.className = 'vis-grid vis-vertical vis-major ' + className;
return line;
};
@ -23972,6 +24191,7 @@ return /******/ (function(modules) { // webpackBootstrap
// default options
this.defaultOptions = {
rtl: false,
showCurrentTime: true,
moment: moment,
@ -24020,7 +24240,7 @@ return /******/ (function(modules) { // webpackBootstrap
CurrentTime.prototype.setOptions = function (options) {
if (options) {
// copy all options that we know
util.selectiveExtend(['showCurrentTime', 'moment', 'locale', 'locales'], this.options, options);
util.selectiveExtend(['rtl', 'showCurrentTime', 'moment', 'locale', 'locales'], this.options, options);
}
};
@ -24055,7 +24275,11 @@ return /******/ (function(modules) { // webpackBootstrap
var title = locale.current + ' ' + locale.time + ': ' + now.format('dddd, MMMM Do YYYY, H:mm:ss');
title = title.charAt(0).toUpperCase() + title.substring(1);
this.bar.style.left = x + 'px';
if (this.options.rtl) {
this.bar.style.right = x + 'px';
} else {
this.bar.style.left = x + 'px';
}
this.bar.title = title;
} else {
// remove the line from the DOM
@ -24162,6 +24386,7 @@ return /******/ (function(modules) { // webpackBootstrap
//globals :
align: { string: string },
rtl: { boolean: boolean, 'undefined': 'undefined' },
autoResize: { boolean: boolean },
throttleRedraw: { number: number },
clickToUse: { boolean: boolean },
@ -24279,6 +24504,7 @@ return /******/ (function(modules) { // webpackBootstrap
var configureOptions = {
global: {
align: ['center', 'left', 'right'],
direction: false,
autoResize: true,
throttleRedraw: [10, 0, 1000, 10],
clickToUse: false,
@ -25952,10 +26178,10 @@ return /******/ (function(modules) { // webpackBootstrap
DataAxis.prototype.show = function () {
this.hidden = false;
if (!this.dom.frame.parentNode) {
if (this.options.orientation === 'left') {
if (this.options.rtl) {
this.body.dom.left.appendChild(this.dom.frame);
} else {
this.body.dom.right.appendChild(this.dom.frame);
this.body.dom.left.appendChild(this.dom.frame);
}
}
@ -42865,7 +43091,12 @@ return /******/ (function(modules) { // webpackBootstrap
}, {
key: '_createDeleteButton',
value: function _createDeleteButton(locale) {
var button = this._createButton('delete', 'vis-button vis-delete', locale['del'] || this.options.locales['en']['del']);
if (this.options.rtl) {
var deleteBtnClass = 'vis-button vis-delete-rtl';
} else {
var deleteBtnClass = 'vis-button vis-delete';
}
var button = this._createButton('delete', deleteBtnClass, locale['del'] || this.options.locales['en']['del']);
this.manipulationDiv.appendChild(button);
this._bindHammerToDiv(button, this.deleteSelected.bind(this));
}

+ 1
- 1
dist/vis.min.css
File diff suppressed because it is too large
View File


+ 1
- 1
docs/data/dataset.html View File

@ -431,7 +431,7 @@ var data = new vis.DataSet([data] [, options])
</td>
<td>Number[]</td>
<td>
Update on ore multiple existing items. <code>data</code> can be a single item or an array with items. When an item doesn't exist, it will be created. Returns an array with the ids of the removed items. See section <a href="#Data_Manipulation">Data Manipulation</a>.
Update one or multiple existing items. <code>data</code> can be a single item or an array with items. When an item doesn't exist, it will be created. Returns an array with the ids of the removed items. See section <a href="#Data_Manipulation">Data Manipulation</a>.
</td>
</tr>

+ 1
- 0
examples/timeline/groups/groupsEditable.html View File

@ -299,6 +299,7 @@
a.value = b.value;
b.value = v;
},
orientation: 'both',
editable: true,
groupEditable: true,
start: new Date(2015, 6, 1),

+ 1
- 1
examples/timeline/interaction/animateWindow.html View File

@ -58,7 +58,7 @@
start: '2014-01-10',
end: '2014-02-10',
editable: true,
showCurrentTime: true
showCurrentTime: true,
};
var timeline = new vis.Timeline(container, items, options);

+ 77
- 0
examples/timeline/other/rtl.html View File

@ -0,0 +1,77 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Timeline | RTL example</title>
<style>
body, html {
font-family: arial, sans-serif;
font-size: 11pt;
}
</style>
<script src="../../../dist/vis.js"></script>
<link href="../../../dist/vis.css" rel="stylesheet" type="text/css" />
<script src="../../googleAnalytics.js"></script>
</head>
<body>
<p>An editable timeline allows to drag items around, create new items, and remove items. Changes are logged in the browser console.</p>
<div id="visualization"></div>
<script>
// create a dataset with items
// we specify the type of the fields `start` and `end` here to be strings
// containing an ISO date. The fields will be outputted as ISO dates
// automatically getting data from the DataSet via items.get().
var items = new vis.DataSet({
type: { start: 'ISODate', end: 'ISODate' }
});
// add items to the DataSet
items.add([
{id: 1, content: '2014-01-23 <br>start', start: '2014-01-23'},
{id: 2, content: '2014-01-18', start: '2014-01-18'},
{id: 3, content: '2014-01-21', start: '2014-01-21'},
{id: 4, content: '2014-01-19 - 2014-01-24', start: '2014-01-19', end: '2014-01-24'},
{id: 5, content: '2014-01-28', start: '2014-01-28', type:'point'},
{id: 6, content: '2014-01-26', start: '2014-01-26'}
]);
// log changes to the console
items.on('*', function (event, properties) {
console.log(event, properties.items);
});
var container = document.getElementById('visualization');
var options = {
start: '2014-01-10',
end: '2014-02-10',
height: '300px',
rtl: true,
// allow selecting multiple items using ctrl+click, shift+click, or hold.
multiselect: true,
// allow manipulation of items
editable: true,
/* alternatively, enable/disable individual actions:
editable: {
add: true,
updateTime: true,
updateGroup: true,
remove: true
},
*/
showCurrentTime: true
};
var timeline = new vis.Timeline(container, items, options);
</script>
</body>
</html>

+ 6
- 1
lib/network/modules/ManipulationSystem.js View File

@ -690,7 +690,12 @@ class ManipulationSystem {
}
_createDeleteButton(locale) {
let button = this._createButton('delete', 'vis-button vis-delete', locale['del'] || this.options.locales['en']['del']);
if (this.options.rtl) {
var deleteBtnClass = 'vis-button vis-delete-rtl';
} else {
var deleteBtnClass = 'vis-button vis-delete';
}
let button = this._createButton('delete', deleteBtnClass, locale['del'] || this.options.locales['en']['del']);
this.manipulationDiv.appendChild(button);
this._bindHammerToDiv(button, this.deleteSelected.bind(this));
}

+ 10
- 2
lib/timeline/Core.js View File

@ -222,11 +222,19 @@ Core.prototype.setOptions = function (options) {
var fields = [
'width', 'height', 'minHeight', 'maxHeight', 'autoResize',
'start', 'end', 'clickToUse', 'dataAttributes', 'hiddenDates',
'locale', 'locales', 'moment',
'locale', 'locales', 'moment', 'rtl',
'throttleRedraw'
];
util.selectiveExtend(fields, this.options, options);
if (this.options.rtl) {
var contentContainer = this.dom.leftContainer;
this.dom.leftContainer = this.dom.rightContainer;
this.dom.rightContainer = contentContainer;
this.dom.container.style.direction = "rtl";
this.dom.backgroundVertical.className = 'vis-panel vis-background vis-vertical-rtl'; }
this.options.orientation = {item:undefined,axis:undefined};
if ('orientation' in options) {
if (typeof options.orientation === 'string') {
@ -529,7 +537,7 @@ Core.prototype.fit = function(options) {
var interval = range.max - range.min;
var min = new Date(range.min.valueOf() - interval * 0.01);
var max = new Date(range.max.valueOf() + interval * 0.01);
console.log(min, max);
var animation = (options && options.animation !== undefined) ? options.animation : true;
this.range.setRange(min, max, animation);
};

+ 28
- 11
lib/timeline/Range.js View File

@ -25,6 +25,7 @@ function Range(body, options) {
// default options
this.defaultOptions = {
rtl: false,
start: null,
end: null,
moment: moment,
@ -37,7 +38,6 @@ function Range(body, options) {
zoomMax: 1000 * 60 * 60 * 24 * 365 * 10000 // milliseconds
};
this.options = util.extend({}, this.defaultOptions);
this.props = {
touch: {}
};
@ -81,7 +81,7 @@ Range.prototype.setOptions = function (options) {
// copy the options that we know
var fields = [
'direction', 'min', 'max', 'zoomMin', 'zoomMax', 'moveable', 'zoomable',
'moment', 'activate', 'hiddenDates', 'zoomKey'
'moment', 'activate', 'hiddenDates', 'zoomKey', 'rtl'
];
util.selectiveExtend(fields, this.options, options);
@ -411,7 +411,13 @@ Range.prototype._onDrag = function (event) {
interval -= duration;
var width = (direction == 'horizontal') ? this.body.domProps.center.width : this.body.domProps.center.height;
var diffRange = -delta / width * interval;
if (this.options.rtl) {
var diffRange = delta / width * interval;
} else {
var diffRange = -delta / width * interval;
}
var newStart = this.props.touch.start + diffRange;
var newEnd = this.props.touch.end + diffRange;
@ -513,7 +519,7 @@ Range.prototype._onMouseWheel = function(event) {
}
// calculate center, the date to zoom around
var pointer = getPointer({x: event.clientX, y: event.clientY}, this.body.dom.center);
var pointer = this.getPointer({x: event.clientX, y: event.clientY}, this.body.dom.center);
var pointerDate = this._pointerToDate(pointer);
this.zoom(scale, pointerDate, delta);
@ -549,7 +555,7 @@ Range.prototype._onPinch = function (event) {
this.props.touch.allowDragging = false;
if (!this.props.touch.center) {
this.props.touch.center = getPointer(event.center, this.body.dom.center);
this.props.touch.center = this.getPointer(event.center, this.body.dom.center);
}
var scale = 1 / (event.scale + this.scaleOffset);
@ -594,7 +600,11 @@ Range.prototype._isInsideRange = function(event) {
// calculate the time where the mouse is, check whether inside
// and no scroll action should happen.
var clientX = event.center ? event.center.x : event.clientX;
var x = clientX - util.getAbsoluteLeft(this.body.dom.centerContainer);
if (this.options.rtl) {
var x = clientX - util.getAbsoluteLeft(this.body.dom.centerContainer);
} else {
var x = util.getAbsoluteRight(this.body.dom.centerContainer) - clientX;
}
var time = this.body.util.toTime(x);
return time >= this.start && time <= this.end;
@ -629,11 +639,18 @@ Range.prototype._pointerToDate = function (pointer) {
* @return {{x: Number, y: Number}} pointer
* @private
*/
function getPointer (touch, element) {
return {
x: touch.x - util.getAbsoluteLeft(element),
y: touch.y - util.getAbsoluteTop(element)
};
Range.prototype.getPointer = function (touch, element) {
if (this.options.rtl) {
return {
x: util.getAbsoluteRight(element) - touch.x,
y: touch.y - util.getAbsoluteTop(element)
};
} else {
return {
x: touch.x - util.getAbsoluteLeft(element),
y: touch.y - util.getAbsoluteTop(element)
};
}
}
/**

+ 16
- 8
lib/timeline/Stack.js View File

@ -37,8 +37,7 @@ exports.orderByEnd = function(items) {
* items having a top===null will be re-stacked
*/
exports.stack = function(items, margin, force) {
var i, iMax;
var i, iMax;
if (force) {
// reset top position of all items
for (i = 0, iMax = items.length; i < iMax; i++) {
@ -59,7 +58,7 @@ exports.stack = function(items, margin, force) {
var collidingItem = null;
for (var j = 0, jj = items.length; j < jj; j++) {
var other = items[j];
if (other.top !== null && other !== item && other.stack && exports.collision(item, other, margin.item)) {
if (other.top !== null && other !== item && other.stack && exports.collision(item, other, margin.item, other.options.rtl)) {
collidingItem = other;
break;
}
@ -114,9 +113,18 @@ exports.nostack = function(items, margin, subgroups) {
* minimum required margin.
* @return {boolean} true if a and b collide, else false
*/
exports.collision = function(a, b, margin) {
return ((a.left - margin.horizontal + EPSILON) < (b.left + b.width) &&
(a.left + a.width + margin.horizontal - EPSILON) > b.left &&
(a.top - margin.vertical + EPSILON) < (b.top + b.height) &&
(a.top + a.height + margin.vertical - EPSILON) > b.top);
exports.collision = function(a, b, margin, rtl) {
var isCollision = null;
if (rtl) {
isCollision = ((a.right - margin.horizontal + EPSILON) < (b.right + b.width) &&
(a.right + a.width + margin.horizontal - EPSILON) > b.right &&
(a.top - margin.vertical + EPSILON) < (b.top + b.height) &&
(a.top + a.height + margin.vertical - EPSILON) > b.top);
} else {
((a.left - margin.horizontal + EPSILON) < (b.left + b.width) &&
(a.left + a.width + margin.horizontal - EPSILON) > b.left &&
(a.top - margin.vertical + EPSILON) < (b.top + b.height) &&
(a.top + a.height + margin.vertical - EPSILON) > b.top);
}
return isCollision;
};

+ 31
- 12
lib/timeline/Timeline.js View File

@ -29,6 +29,7 @@ import Validator from '../shared/Validator';
* @extends Core
*/
function Timeline (container, items, groups, options) {
if (!(this instanceof Timeline)) {
throw new SyntaxError('Constructor must be called with the new operator');
}
@ -52,7 +53,7 @@ function Timeline (container, items, groups, options) {
axis: 'bottom', // axis orientation: 'bottom', 'top', or 'both'
item: 'bottom' // not relevant
},
rtl: false,
moment: moment,
width: null,
@ -107,7 +108,7 @@ function Timeline (container, items, groups, options) {
this.components.push(this.currentTime);
// item set
this.itemSet = new ItemSet(this.body);
this.itemSet = new ItemSet(this.body, this.options);
this.components.push(this.itemSet);
this.itemsData = null; // DataSet
@ -191,6 +192,7 @@ Timeline.prototype.redraw = function() {
Timeline.prototype.setOptions = function (options) {
// validate options
let errorFound = Validator.validate(options, allOptions);
if (errorFound === true) {
console.log('%cErrors have been found in the supplied options object.', printStyle);
}
@ -413,16 +415,24 @@ Timeline.prototype.getItemRange = function () {
var start = getStart(item);
var end = getEnd(item);
console.log(start, end)
console.log(this.options);
if (this.options.rtl) {
var startSide = start - (item.getWidthRight() + 10) * factor;
var endSide = end + (item.getWidthLeft() + 10) * factor;
} else {
var startSide = start - (item.getWidthLeft() + 10) * factor;
var endSide = end + (item.getWidthRight() + 10) * factor;
}
var left = start - (item.getWidthLeft() + 10) * factor;
var right = end + (item.getWidthRight() + 10) * factor;
if (left < min) {
min = left;
if (startSide < min) {
min = startSide;
minItem = item;
}
if (right > max) {
max = right;
if (endSide > max) {
max = endSide;
maxItem = item;
}
}.bind(this));
@ -433,8 +443,13 @@ Timeline.prototype.getItemRange = function () {
var delta = this.props.center.width - lhs - rhs; // px
if (delta > 0) {
min = getStart(minItem) - lhs * interval / delta; // ms
max = getEnd(maxItem) + rhs * interval / delta; // ms
if (this.options.rtl) {
min = getStart(minItem) - rhs * interval / delta; // ms
max = getEnd(maxItem) + lhs * interval / delta; // ms
} else {
min = getStart(minItem) - lhs * interval / delta; // ms
max = getEnd(maxItem) + rhs * interval / delta; // ms
}
}
}
}
@ -482,7 +497,11 @@ Timeline.prototype.getDataRange = function() {
Timeline.prototype.getEventProperties = function (event) {
var clientX = event.center ? event.center.x : event.clientX;
var clientY = event.center ? event.center.y : event.clientY;
var x = clientX - util.getAbsoluteLeft(this.dom.centerContainer);
if (this.options.rtl) {
var x = util.getAbsoluteRight(this.dom.centerContainer) - clientX;
} else {
var x = clientX - util.getAbsoluteLeft(this.dom.centerContainer);
}
var y = clientY - util.getAbsoluteTop(this.dom.centerContainer);
var item = this.itemSet.itemFromTarget(event);

+ 7
- 2
lib/timeline/component/CurrentTime.js View File

@ -16,6 +16,7 @@ function CurrentTime (body, options) {
// default options
this.defaultOptions = {
rtl: false,
showCurrentTime: true,
moment: moment,
@ -64,7 +65,7 @@ CurrentTime.prototype.destroy = function () {
CurrentTime.prototype.setOptions = function(options) {
if (options) {
// copy all options that we know
util.selectiveExtend(['showCurrentTime', 'moment', 'locale', 'locales'], this.options, options);
util.selectiveExtend(['rtl', 'showCurrentTime', 'moment', 'locale', 'locales'], this.options, options);
}
};
@ -99,7 +100,11 @@ CurrentTime.prototype.redraw = function() {
var title = locale.current + ' ' + locale.time + ': ' + now.format('dddd, MMMM Do YYYY, H:mm:ss');
title = title.charAt(0).toUpperCase() + title.substring(1);
this.bar.style.left = x + 'px';
if (this.options.rtl) {
this.bar.style.right = x + 'px';
} else {
this.bar.style.left = x + 'px';
}
this.bar.title = title;
}
else {

+ 2
- 2
lib/timeline/component/DataAxis.js View File

@ -212,11 +212,11 @@ DataAxis.prototype._cleanupIcons = function() {
DataAxis.prototype.show = function() {
this.hidden = false;
if (!this.dom.frame.parentNode) {
if (this.options.orientation === 'left') {
if (this.options.rtl) {
this.body.dom.left.appendChild(this.dom.frame);
}
else {
this.body.dom.right.appendChild(this.dom.frame);
this.body.dom.left.appendChild(this.dom.frame);
}
}

+ 2
- 3
lib/timeline/component/Group.js View File

@ -209,8 +209,8 @@ Group.prototype.redraw = function(range, margin, restack) {
}
else {
// no custom order function, lazy stacking
this.visibleItems = this._updateVisibleItems(this.orderedItems, this.visibleItems, range);
this.visibleItems = this._updateVisibleItems(this.orderedItems, this.visibleItems, range);
if (this.itemSet.options.stack) { // TODO: ugly way to access options...
stack.stack(this.visibleItems, margin, restack);
}
@ -225,10 +225,9 @@ Group.prototype.redraw = function(range, margin, restack) {
// calculate actual size and position
var foreground = this.dom.foreground;
this.top = foreground.offsetTop;
this.left = foreground.offsetLeft;
this.right = foreground.offsetLeft;
this.width = foreground.offsetWidth;
resized = util.updateProperty(this, 'height', height) || resized;
// recalculate size of label
resized = util.updateProperty(this.props.label, 'width', this.dom.inner.clientWidth) || resized;
resized = util.updateProperty(this.props.label, 'height', this.dom.inner.clientHeight) || resized;

+ 99
- 29
lib/timeline/component/ItemSet.js View File

@ -26,8 +26,8 @@ var BACKGROUND = '__background__'; // reserved group id for background items wit
*/
function ItemSet(body, options) {
this.body = body;
this.defaultOptions = {
rtl: false,
type: null, // 'box', 'point', 'range', 'background'
orientation: {
item: 'bottom' // item orientation: 'top' or 'bottom'
@ -96,7 +96,7 @@ function ItemSet(body, options) {
// options is shared by this ItemSet and all its items
this.options = util.extend({}, this.defaultOptions);
// options for getting items from the DataSet with the correct type
this.itemOptions = {
type: {start: 'Date', end: 'Date'}
@ -230,8 +230,8 @@ ItemSet.prototype._create = function(){
// add item on doubletap
this.hammer.on('doubletap', this._onAddItem.bind(this));
this.groupHammer = new Hammer(this.body.dom.leftContainer);
this.groupHammer.on('panstart', this._onGroupDragStart.bind(this));
this.groupHammer.on('panmove', this._onGroupDrag.bind(this));
this.groupHammer.on('panend', this._onGroupDragEnd.bind(this));
@ -308,7 +308,7 @@ ItemSet.prototype._create = function(){
ItemSet.prototype.setOptions = function(options) {
if (options) {
// copy all options that we know
var fields = ['type', 'align', 'order', 'stack', 'selectable', 'multiselect', 'itemsAlwaysDraggable', 'multiselectPerGroup', 'groupOrder', 'dataAttributes', 'template', 'groupTemplate', 'hide', 'snap', 'groupOrderSwap'];
var fields = ['type', 'rtl', 'align', 'order', 'stack', 'selectable', 'multiselect', 'itemsAlwaysDraggable', 'multiselectPerGroup', 'groupOrder', 'dataAttributes', 'template', 'groupTemplate', 'hide', 'snap', 'groupOrderSwap'];
util.selectiveExtend(fields, this.options, options);
if ('orientation' in options) {
@ -498,8 +498,14 @@ ItemSet.prototype.getSelection = function() {
*/
ItemSet.prototype.getVisibleItems = function() {
var range = this.body.range.getRange();
var left = this.body.util.toScreen(range.start);
var right = this.body.util.toScreen(range.end);
if (this.options.rtl) {
var right = this.body.util.toScreen(range.start);
var left = this.body.util.toScreen(range.end);
} else {
var left = this.body.util.toScreen(range.start);
var right = this.body.util.toScreen(range.end);
}
var ids = [];
for (var groupId in this.groups) {
@ -512,8 +518,14 @@ ItemSet.prototype.getVisibleItems = function() {
for (var i = 0; i < rawVisibleItems.length; i++) {
var item = rawVisibleItems[i];
// TODO: also check whether visible vertically
if ((item.left < right) && (item.left + item.width > left)) {
ids.push(item.id);
if (this.options.rtl) {
if ((item.right < left) && (item.right + item.width > right)) {
ids.push(item.id);
}
} else {
if ((item.left < right) && (item.left + item.width > left)) {
ids.push(item.id);
}
}
}
}
@ -552,7 +564,12 @@ ItemSet.prototype.redraw = function() {
// recalculate absolute position (before redrawing groups)
this.props.top = this.body.domProps.top.height + this.body.domProps.border.top;
this.props.left = this.body.domProps.left.width + this.body.domProps.border.left;
if (this.options.rtl) {
this.props.right = this.body.domProps.right.width + this.body.domProps.border.right;
} else {
this.props.left = this.body.domProps.left.width + this.body.domProps.border.left;
}
// update class name
frame.className = 'vis-itemset';
@ -605,7 +622,11 @@ ItemSet.prototype.redraw = function() {
this.dom.axis.style.top = asSize((orientation == 'top') ?
(this.body.domProps.top.height + this.body.domProps.border.top) :
(this.body.domProps.top.height + this.body.domProps.centerContainer.height));
this.dom.axis.style.left = '0';
if (this.options.rtl) {
this.dom.axis.style.right = '0';
} else {
this.dom.axis.style.left = '0';
}
// check if this component is resized
resized = this._isResized() || resized;
@ -1245,8 +1266,15 @@ ItemSet.prototype._onDragStart = function (event) {
*/
ItemSet.prototype._onDragStartAddItem = function (event) {
var snap = this.options.snap || null;
var xAbs = util.getAbsoluteLeft(this.dom.frame);
var x = event.center.x - xAbs - 10; // minus 10 to compensate for the drag starting as soon as you've moved 10px
if (this.options.rtl) {
var xAbs = util.getAbsoluteRight(this.dom.frame);
var x = xAbs - event.center.x + 10; // plus 10 to compensate for the drag starting as soon as you've moved 10px
} else {
var xAbs = util.getAbsoluteLeft(this.dom.frame);
var x = event.center.x - xAbs - 10; // minus 10 to compensate for the drag starting as soon as you've moved 10px
}
var time = this.body.util.toTime(x);
var scale = this.body.util.getScale();
var step = this.body.util.getStep();
@ -1267,7 +1295,6 @@ ItemSet.prototype._onDragStartAddItem = function (event) {
if (group) {
itemData.group = group.groupId;
}
var newItem = new RangeItem(itemData, this.conversion, this.options);
newItem.id = id; // TODO: not so nice setting id afterwards
newItem.data = this._cloneItemData(itemData);
@ -1275,10 +1302,15 @@ ItemSet.prototype._onDragStartAddItem = function (event) {
var props = {
item: newItem,
dragRight: true,
initialX: event.center.x,
data: newItem.data
};
if (this.options.rtl) {
props.dragLeft = true;
} else {
props.dragRight = true;
}
this.touchParams.itemProps = [props];
event.stopPropagation();
@ -1295,7 +1327,13 @@ ItemSet.prototype._onDrag = function (event) {
var me = this;
var snap = this.options.snap || null;
var xOffset = this.body.dom.root.offsetLeft + this.body.domProps.left.width;
if (this.options.rtl) {
var xOffset = this.body.dom.root.offsetLeft + this.body.domProps.right.width;
} else {
var xOffset = this.body.dom.root.offsetLeft + this.body.domProps.left.width;
}
var scale = this.body.util.getScale();
var step = this.body.util.getStep();
@ -1319,7 +1357,12 @@ ItemSet.prototype._onDrag = function (event) {
this.touchParams.itemProps.forEach(function (props) {
var current = me.body.util.toTime(event.center.x - xOffset);
var initial = me.body.util.toTime(props.initialX - xOffset);
var offset = current - initial; // ms
if (this.options.rtl) {
var offset = -(current - initial); // ms
} else {
var offset = (current - initial); // ms
}
var itemData = this._cloneItemData(props.item.data); // clone the data
if (props.item.editable === false) {
@ -1328,29 +1371,47 @@ ItemSet.prototype._onDrag = function (event) {
var updateTimeAllowed = me.options.editable.updateTime ||
props.item.editable === true;
if (updateTimeAllowed) {
if (props.dragLeft) {
// drag left side of a range item
if (itemData.start != undefined) {
var initialStart = util.convert(props.data.start, 'Date');
var start = new Date(initialStart.valueOf() + offset);
// TODO: pass a Moment instead of a Date to snap(). (Breaking change)
itemData.start = snap ? snap(start, scale, step) : start;
if (this.options.rtl) {
if (itemData.end != undefined) {
var initialEnd = util.convert(props.data.end, 'Date');
var end = new Date(initialEnd.valueOf() + offset);
// TODO: pass a Moment instead of a Date to snap(). (Breaking change)
itemData.end = snap ? snap(end, scale, step) : end;
}
} else {
if (itemData.start != undefined) {
var initialStart = util.convert(props.data.start, 'Date');
var start = new Date(initialStart.valueOf() + offset);
// TODO: pass a Moment instead of a Date to snap(). (Breaking change)
itemData.start = snap ? snap(start, scale, step) : start;
}
}
}
else if (props.dragRight) {
// drag right side of a range item
if (itemData.end != undefined) {
var initialEnd = util.convert(props.data.end, 'Date');
var end = new Date(initialEnd.valueOf() + offset);
// TODO: pass a Moment instead of a Date to snap(). (Breaking change)
itemData.end = snap ? snap(end, scale, step) : end;
if (this.options.rtl) {
if (itemData.start != undefined) {
var initialStart = util.convert(props.data.start, 'Date');
var start = new Date(initialStart.valueOf() + offset);
// TODO: pass a Moment instead of a Date to snap(). (Breaking change)
itemData.start = snap ? snap(start, scale, step) : start;
}
} else {
if (itemData.end != undefined) {
var initialEnd = util.convert(props.data.end, 'Date');
var end = new Date(initialEnd.valueOf() + offset);
// TODO: pass a Moment instead of a Date to snap(). (Breaking change)
itemData.end = snap ? snap(end, scale, step) : end;
}
}
}
else {
// drag both start and end
if (itemData.start != undefined) {
var initialStart = util.convert(props.data.start, 'Date').valueOf();
var start = new Date(initialStart + offset);
@ -1366,6 +1427,8 @@ ItemSet.prototype._onDrag = function (event) {
// TODO: pass a Moment instead of a Date to snap(). (Breaking change)
itemData.start = snap ? snap(start, scale, step) : start;
}
}
}
}
@ -1706,8 +1769,15 @@ ItemSet.prototype._onAddItem = function (event) {
}
else {
// add item
var xAbs = util.getAbsoluteLeft(this.dom.frame);
var x = event.center.x - xAbs;
if (this.options.rtl) {
var xAbs = util.getAbsoluteRight(this.dom.frame);
var x = xAbs - event.center.x;
} else {
var xAbs = util.getAbsoluteLeft(this.dom.frame);
var x = event.center.x - xAbs;
}
// var xAbs = util.getAbsoluteLeft(this.dom.frame);
// var x = event.center.x - xAbs;
var start = this.body.util.toTime(x);
var scale = this.body.util.getScale();
var step = this.body.util.getStep();

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

@ -73,7 +73,8 @@ TimeAxis.prototype.setOptions = function(options) {
'maxMinorChars',
'hiddenDates',
'timeAxis',
'moment'
'moment',
'rtl'
], this.options, options);
// deep copy the format options
@ -183,7 +184,6 @@ TimeAxis.prototype.redraw = function () {
else {
this.body.dom.backgroundVertical.appendChild(background)
}
return this._isResized() || parentChanged;
};
@ -336,7 +336,13 @@ TimeAxis.prototype._repaintMinorText = function (x, text, orientation, className
label.childNodes[0].nodeValue = text;
label.style.top = (orientation == 'top') ? (this.props.majorLabelHeight + 'px') : '0';
label.style.left = x + 'px';
if (this.options.rtl) {
label.style.left = "";
label.style.right = x + 'px';
} else {
label.style.left = x + 'px';
};
label.className = 'vis-text vis-minor ' + className;
//label.title = title; // TODO: this is a heavy operation
@ -370,7 +376,12 @@ TimeAxis.prototype._repaintMajorText = function (x, text, orientation, className
//label.title = title; // TODO: this is a heavy operation
label.style.top = (orientation == 'top') ? '0' : (this.props.minorLabelHeight + 'px');
label.style.left = x + 'px';
if (this.options.rtl) {
label.style.left = "";
label.style.right = x + 'px';
} else {
label.style.left = x + 'px';
};
return label;
};
@ -402,10 +413,17 @@ TimeAxis.prototype._repaintMinorLine = function (x, width, orientation, classNam
line.style.top = this.body.domProps.top.height + 'px';
}
line.style.height = props.minorLineHeight + 'px';
line.style.left = (x - props.minorLineWidth / 2) + 'px';
if (this.options.rtl) {
line.style.left = "";
line.style.right = (x - props.minorLineWidth / 2) + 'px';
line.className = 'vis-grid vis-vertical-rtl vis-minor ' + className;
} else {
line.style.left = (x - props.minorLineWidth / 2) + 'px';
line.className = 'vis-grid vis-vertical vis-minor ' + className;
};
line.style.width = width + 'px';
line.className = 'vis-grid vis-vertical vis-minor ' + className;
return line;
};
@ -436,12 +454,19 @@ TimeAxis.prototype._repaintMajorLine = function (x, width, orientation, classNam
else {
line.style.top = this.body.domProps.top.height + 'px';
}
line.style.left = (x - props.majorLineWidth / 2) + 'px';
if (this.options.rtl) {
line.style.left = "";
line.style.right = (x - props.majorLineWidth / 2) + 'px';
line.className = 'vis-grid vis-vertical-rtl vis-major ' + className;
} else {
line.style.left = (x - props.majorLineWidth / 2) + 'px';
line.className = 'vis-grid vis-vertical vis-major ' + className;
}
line.style.height = props.majorLineHeight + 'px';
line.style.width = width + 'px';
line.className = 'vis-grid vis-vertical vis-major ' + className;
return line;
};

+ 11
- 0
lib/timeline/component/css/item.css View File

@ -100,6 +100,17 @@
cursor: pointer;
}
.vis-item .vis-delete-rtl {
background: url('img/timeline/delete.png') no-repeat center;
position: absolute;
width: 24px;
height: 24px;
top: -4px;
left: -24px;
cursor: pointer;
}
.vis-item.vis-range .vis-drag-left {
position: absolute;
width: 24px;

+ 5
- 0
lib/timeline/component/css/timeaxis.css View File

@ -41,6 +41,11 @@
border-left: 1px solid;
}
.vis-time-axis .vis-grid.vis-vertical-rtl {
position: absolute;
border-right: 1px solid;
}
.vis-time-axis .vis-grid.vis-minor {
border-color: #e5e5e5;
}

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

@ -22,7 +22,7 @@ function BoxItem (data, conversion, options) {
height: 0
}
};
this.options = options;
// validate data
if (data) {
if (data.start == undefined) {
@ -171,29 +171,56 @@ BoxItem.prototype.repositionX = function() {
// calculate left position of the box
if (align == 'right') {
this.left = start - this.width;
// reposition box, line, and dot
this.dom.box.style.left = this.left + 'px';
this.dom.line.style.left = (start - this.props.line.width) + 'px';
this.dom.dot.style.left = (start - this.props.line.width / 2 - this.props.dot.width / 2) + 'px';
if (this.options.rtl) {
this.right = start - this.width;
// reposition box, line, and dot
this.dom.box.style.right = this.right + 'px';
this.dom.line.style.right = (start - this.props.line.width) + 'px';
this.dom.dot.style.right = (start - this.props.line.width / 2 - this.props.dot.width / 2) + 'px';
} else {
this.left = start - this.width;
// reposition box, line, and dot
this.dom.box.style.left = this.left + 'px';
this.dom.line.style.left = (start - this.props.line.width) + 'px';
this.dom.dot.style.left = (start - this.props.line.width / 2 - this.props.dot.width / 2) + 'px';
}
}
else if (align == 'left') {
this.left = start;
// reposition box, line, and dot
this.dom.box.style.left = this.left + 'px';
this.dom.line.style.left = start + 'px';
this.dom.dot.style.left = (start + this.props.line.width / 2 - this.props.dot.width / 2) + 'px';
if (this.options.rtl) {
this.right = start;
// reposition box, line, and dot
this.dom.box.style.right = this.right + 'px';
this.dom.line.style.right = start + 'px';
this.dom.dot.style.right = (start + this.props.line.width / 2 - this.props.dot.width / 2) + 'px';
} else {
this.left = start;
// reposition box, line, and dot
this.dom.box.style.left = this.left + 'px';
this.dom.line.style.left = start + 'px';
this.dom.dot.style.left = (start + this.props.line.width / 2 - this.props.dot.width / 2) + 'px';
}
}
else {
// default or 'center'
this.left = start - this.width / 2;
// reposition box, line, and dot
this.dom.box.style.left = this.left + 'px';
this.dom.line.style.left = (start - this.props.line.width / 2) + 'px';
this.dom.dot.style.left = (start - this.props.dot.width / 2) + 'px';
if (this.options.rtl) {
this.right = start - this.width / 2;
// reposition box, line, and dot
this.dom.box.style.right = this.right + 'px';
this.dom.line.style.right = (start - this.props.line.width) + 'px';
this.dom.dot.style.right = (start - this.props.dot.width / 2) + 'px';
} else {
this.left = start - this.width / 2;
// reposition box, line, and dot
this.dom.box.style.left = this.left + 'px';
this.dom.line.style.left = (start - this.props.line.width / 2) + 'px';
this.dom.dot.style.left = (start - this.props.dot.width / 2) + 'px';
}
}
};

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

@ -23,6 +23,7 @@ function Item (data, conversion, options) {
this.dirty = true;
this.top = null;
this.right = null;
this.left = null;
this.width = null;
this.height = null;
@ -154,7 +155,12 @@ Item.prototype._repaintDeleteButton = function (anchor) {
var me = this;
var deleteButton = document.createElement('div');
deleteButton.className = 'vis-delete';
if (this.options.rtl) {
deleteButton.className = 'vis-delete-rtl';
} else {
deleteButton.className = 'vis-delete';
}
deleteButton.title = 'Delete this item';
// TODO: be able to destroy the delete button

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

@ -19,10 +19,11 @@ function PointItem (data, conversion, options) {
},
content: {
height: 0,
marginLeft: 0
marginLeft: 0,
marginRight: 0
}
};
this.options = options;
// validate data
if (data) {
if (data.start == undefined) {
@ -117,7 +118,11 @@ PointItem.prototype.redraw = function() {
this.props.content.height = dom.content.offsetHeight;
// resize contents
dom.content.style.marginLeft = 2 * this.props.dot.width + 'px';
if (this.options.rtl) {
dom.content.style.marginRight = 2 * this.props.dot.width + 'px';
} else {
dom.content.style.marginLeft = 2 * this.props.dot.width + 'px';
}
//dom.content.style.marginRight = ... + 'px'; // TODO: margin right
// recalculate size
@ -126,7 +131,11 @@ PointItem.prototype.redraw = function() {
// reposition the dot
dom.dot.style.top = ((this.height - this.props.dot.height) / 2) + 'px';
dom.dot.style.left = (this.props.dot.width / 2) + 'px';
if (this.options.rtl) {
dom.dot.style.right = (this.props.dot.width / 2) + 'px';
} else {
dom.dot.style.left = (this.props.dot.width / 2) + 'px';
}
this.dirty = false;
}
@ -164,10 +173,17 @@ PointItem.prototype.hide = function() {
PointItem.prototype.repositionX = function() {
var start = this.conversion.toScreen(this.data.start);
this.left = start - this.props.dot.width;
if (this.options.rtl) {
this.right = start - this.props.dot.width;
// reposition point
this.dom.point.style.right = this.right + 'px';
} else {
this.left = start - this.props.dot.width;
// reposition point
this.dom.point.style.left = this.left + 'px';
// reposition point
this.dom.point.style.left = this.left + 'px';
}
};
/**
@ -177,7 +193,6 @@ PointItem.prototype.repositionX = function() {
PointItem.prototype.repositionY = function() {
var orientation = this.options.orientation.item;
var point = this.dom.point;
if (orientation == 'top') {
point.style.top = this.top + 'px';
}
@ -199,7 +214,7 @@ PointItem.prototype.getWidthLeft = function () {
* @return {number}
*/
PointItem.prototype.getWidthRight = function () {
return this.width - this.props.dot.width;
return this.props.dot.width;
};
module.exports = PointItem;

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

@ -18,7 +18,7 @@ function RangeItem (data, conversion, options) {
}
};
this.overflow = false; // if contents can overflow (css styling), this flag is set to true
this.options = options;
// validate data
if (data) {
if (data.start == undefined) {
@ -123,7 +123,7 @@ RangeItem.prototype.redraw = function() {
this.dirty = false;
}
console.log("redrawing range");
this._repaintDeleteButton(dom.box);
this._repaintDragLeft();
this._repaintDragRight();
@ -168,7 +168,7 @@ RangeItem.prototype.repositionX = function(limitSize) {
var parentWidth = this.parent.width;
var start = this.conversion.toScreen(this.data.start);
var end = this.conversion.toScreen(this.data.end);
var contentLeft;
var contentStartPosition;
var contentWidth;
// limit the width of the range, as browsers cannot draw very wide divs
@ -183,7 +183,11 @@ RangeItem.prototype.repositionX = function(limitSize) {
var boxWidth = Math.max(end - start, 1);
if (this.overflow) {
this.left = start;
if (this.options.rtl) {
this.right = start;
} else {
this.left = start;
}
this.width = boxWidth + this.props.content.width;
contentWidth = this.props.content.width;
@ -192,46 +196,71 @@ RangeItem.prototype.repositionX = function(limitSize) {
// So no re-stacking needed, which is nicer for the eye;
}
else {
this.left = start;
if (this.options.rtl) {
this.right = start;
} else {
this.left = start;
}
this.width = boxWidth;
contentWidth = Math.min(end - start, this.props.content.width);
}
this.dom.box.style.left = this.left + 'px';
if (this.options.rtl) {
this.dom.box.style.right = this.right + 'px';
} else {
this.dom.box.style.left = this.left + 'px';
}
this.dom.box.style.width = boxWidth + 'px';
switch (this.options.align) {
case 'left':
this.dom.content.style.left = '0';
if (this.options.rtl) {
this.dom.content.style.right = '0';
} else {
this.dom.content.style.left = '0';
}
break;
case 'right':
this.dom.content.style.left = Math.max((boxWidth - contentWidth), 0) + 'px';
if (this.options.rtl) {
this.dom.content.style.right = Math.max((boxWidth - contentWidth), 0) + 'px';
} else {
this.dom.content.style.left = Math.max((boxWidth - contentWidth), 0) + 'px';
}
break;
case 'center':
this.dom.content.style.left = Math.max((boxWidth - contentWidth) / 2, 0) + 'px';
if (this.options.rtl) {
this.dom.content.style.right = Math.max((boxWidth - contentWidth) / 2, 0) + 'px';
} else {
this.dom.content.style.left = Math.max((boxWidth - contentWidth) / 2, 0) + 'px';
}
break;
default: // 'auto'
// when range exceeds left of the window, position the contents at the left of the visible area
if (this.overflow) {
if (end > 0) {
contentLeft = Math.max(-start, 0);
contentStartPosition = Math.max(-start, 0);
}
else {
contentLeft = -contentWidth; // ensure it's not visible anymore
contentStartPosition = -contentWidth; // ensure it's not visible anymore
}
}
else {
if (start < 0) {
contentLeft = -start;
contentStartPosition = -start;
}
else {
contentLeft = 0;
contentStartPosition = 0;
}
}
this.dom.content.style.left = contentLeft + 'px';
if (this.options.rtl) {
this.dom.content.style.right = contentStartPosition + 'px';
} else {
this.dom.content.style.left = contentStartPosition + 'px';
}
}
};
@ -279,6 +308,7 @@ RangeItem.prototype._repaintDragLeft = function () {
* @protected
*/
RangeItem.prototype._repaintDragRight = function () {
console.log("repainting!!!!");
if (this.selected && this.options.editable.updateTime && !this.dom.dragRight) {
// create and show drag area
var dragRight = document.createElement('div');

+ 2
- 1
lib/timeline/optionsTimeline.js View File

@ -15,7 +15,6 @@ let dom = 'dom';
let moment = 'moment';
let any = 'any';
let allOptions = {
configure: {
enabled: {boolean},
@ -26,6 +25,7 @@ let allOptions = {
//globals :
align: {string},
rtl: {boolean, 'undefined': 'undefined'},
autoResize: {boolean},
throttleRedraw: {number},
clickToUse: {boolean},
@ -143,6 +143,7 @@ let allOptions = {
let configureOptions = {
global: {
align: ['center', 'left', 'right'],
direction: false,
autoResize: true,
throttleRedraw: [10, 0, 1000, 10],
clickToUse: false,

+ 4
- 0
lib/util.js View File

@ -599,6 +599,10 @@ exports.getAbsoluteLeft = function (elem) {
return elem.getBoundingClientRect().left;
};
exports.getAbsoluteRight = function (elem) {
return elem.getBoundingClientRect().right;
};
/**
* Retrieve the absolute top value of a DOM element
* @param {Element} elem A dom element, for example a div

Loading…
Cancel
Save